aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--doc/manual.tex4
-rw-r--r--src/corify.sml21
-rw-r--r--src/settings.sig1
-rw-r--r--src/settings.sml1
-rw-r--r--tests/ffi_eff.urs2
-rw-r--r--tests/ffieff.ur6
-rw-r--r--tests/ffieff.urp6
7 files changed, 38 insertions, 3 deletions
diff --git a/doc/manual.tex b/doc/manual.tex
index 5ecf123e..d00fe439 100644
--- a/doc/manual.tex
+++ b/doc/manual.tex
@@ -143,7 +143,7 @@ Here is the complete list of directive forms. ``FFI'' stands for ``foreign func
\item \texttt{coreInline TREESIZE} sets how many nodes the AST of a function definition may have before the optimizer stops trying hard to inline calls to that function. (This is one of two options for one of two intermediate languages within the compiler.)
\item \texttt{database DBSTRING} sets the string to pass to libpq to open a database connection.
\item \texttt{debug} saves some intermediate C files, which is mostly useful to help in debugging the compiler itself.
-\item \texttt{effectful Module.ident} registers an FFI function or transaction as having side effects. The optimizer avoids removing, moving, or duplicating calls to such functions. Every effectful FFI function must be registered, or the optimizer may make invalid transformations. (Note that merely assigning a function a \texttt{transaction}-based type does not mark it as effectful in this way!)
+\item \texttt{effectful Module.ident} registers an FFI function or transaction as having side effects. The optimizer avoids removing, moving, or duplicating calls to such functions. This is the default behavior for \texttt{transaction}-based types.
\item \texttt{exe FILENAME} sets the filename to which to write the output executable. The default for file \texttt{P.urp} is \texttt{P.exe}.
\item \texttt{ffi FILENAME} reads the file \texttt{FILENAME.urs} to determine the interface to a new FFI module. The name of the module is calculated from \texttt{FILENAME} in the same way as for normal source files. See the files \texttt{include/urweb.h} and \texttt{src/c/urweb.c} for examples of C headers and implementations for FFI modules. In general, every type or value \texttt{Module.ident} becomes \texttt{uw\_Module\_ident} in C.
\item \texttt{include FILENAME} adds \texttt{FILENAME} to the list of files to be \texttt{\#include}d in C sources. This is most useful for interfacing with new FFI modules.
@@ -2383,7 +2383,7 @@ It is most convenient to encapsulate an FFI binding with a new \texttt{.urp} fil
\begin{itemize}
\item \texttt{clientOnly Module.ident} registers a value as being allowed only in client-side code.
\item \texttt{clientToServer Module.ident} declares a type as OK to marshal between clients and servers. By default, abstract FFI types are not allowed to be marshalled, since your library might be maintaining invariants that the simple serialization code doesn't check.
-\item \texttt{effectful Module.ident} registers a function that can have side effects. It is important to remember to use this directive for each such function, or else the optimizer might change program semantics. (Note that merely assigning a function a \texttt{transaction}-based type does not mark it as effectful in this way!)
+\item \texttt{effectful Module.ident} registers a function that can have side effects. This is the default for \texttt{transaction}-based types, and, actually, this directive is mostly present for legacy compatibility reasons, since it used to be required explicitly for each \texttt{transaction}al function.
\item \texttt{ffi FILE.urs} names the file giving your library's signature. You can include multiple such files in a single \texttt{.urp} file, and each file \texttt{mod.urp} defines an FFI module \texttt{Mod}.
\item \texttt{include FILE} requests inclusion of a C header file.
\item \texttt{jsFunc Module.ident=name} gives a mapping from an Ur name for a value to a JavaScript name.
diff --git a/src/corify.sml b/src/corify.sml
index 5cfd87b3..4ab45983 100644
--- a/src/corify.sml
+++ b/src/corify.sml
@@ -796,7 +796,7 @@ fun corifyDecl mods (all as (d, loc : EM.span), st) =
end
| L.DFfiStr (m, n, (sgn, _)) =>
- (case sgn of
+ (print ("~~~" ^ m ^ "\n"); case sgn of
L.SgnConst sgis =>
let
val (ds, cmap, conmap, st, _) =
@@ -936,7 +936,26 @@ fun corifyDecl mods (all as (d, loc : EM.span), st) =
in
transactify c
end
+
+ fun isTransactional (c, _) =
+ case c of
+ L'.TFun (_, c) => isTransactional c
+ | L'.CApp ((L'.CFfi ("Basis", "transaction"), _), _) => true
+ | _ => false
in
+ Print.epreface (x, CorePrint.p_con CoreEnv.empty c);
+
+ if isTransactional c then
+ let
+ val ffi = (m, x)
+ in
+ if Settings.isBenignEffectful ffi then
+ ()
+ else
+ Settings.addEffectful ffi
+ end
+ else
+ ();
(ds,
SM.insert (cmap, x, c),
conmap,
diff --git a/src/settings.sig b/src/settings.sig
index 7675b9c8..40cfbacc 100644
--- a/src/settings.sig
+++ b/src/settings.sig
@@ -73,6 +73,7 @@ signature SETTINGS = sig
(* Which FFI functions have side effects? *)
val setEffectful : ffi list -> unit
+ val addEffectful : ffi -> unit
val isEffectful : ffi -> bool
(* Which FFI functions should not have their calls removed or reordered, but cause no lasting effects? *)
diff --git a/src/settings.sml b/src/settings.sml
index afe84617..948906ed 100644
--- a/src/settings.sml
+++ b/src/settings.sml
@@ -152,6 +152,7 @@ val effectfulBase = basis ["dml",
val effectful = ref effectfulBase
fun setEffectful ls = effectful := S.addList (effectfulBase, ls)
fun isEffectful x = S.member (!effectful, x)
+fun addEffectful x = effectful := S.add (!effectful, x)
val benignBase = basis ["get_cookie",
"new_client_source",
diff --git a/tests/ffi_eff.urs b/tests/ffi_eff.urs
new file mode 100644
index 00000000..150c4da3
--- /dev/null
+++ b/tests/ffi_eff.urs
@@ -0,0 +1,2 @@
+val shout : string -> transaction {}
+val sneakyShout : string -> int
diff --git a/tests/ffieff.ur b/tests/ffieff.ur
new file mode 100644
index 00000000..a63fa4bc
--- /dev/null
+++ b/tests/ffieff.ur
@@ -0,0 +1,6 @@
+open Ffi_eff
+
+fun main () : transaction page = return <xml><body>
+ <button value="shout" onclick={fn _ => shout "Hi!"; shout "Bye!"}/>
+ <button value="sneakyShout" onclick={fn _ => let val x = sneakyShout "Whoa" in return () end}/>
+</body></xml>
diff --git a/tests/ffieff.urp b/tests/ffieff.urp
new file mode 100644
index 00000000..9f89cbc4
--- /dev/null
+++ b/tests/ffieff.urp
@@ -0,0 +1,6 @@
+ffi ffi_eff
+jsFunc Ffi_eff.shout=alert
+jsFunc Ffi_eff.sneakyShout=alert
+rewrite all Ffieff/*
+
+ffieff