[m-rev.] for review: csharp.ssdebug and readme

Peter Wang novalazy at gmail.com
Mon Oct 25 15:23:04 AEDT 2010


Branches: main

Make it possible to install and use the csharp.ssdebug grade.

Mmake.workspace:
        Never try to link with `mer_rt' in C# grades.

browser/Mmakefile:
mdbcomp/Mmakefile:
ssdb/Mmakefile:
        Use `mmc --make' to install these libraries in `csharp' grades.

        Don't add C libraries to MLLIBS in non-C or asm grades. 

browser/Mercury.options:
ssdb/Mercury.options:
        "EXTRA_LIBRARIES-libname" doesn't actually work with `mmc --make',
        but "LIBRARIES-name" does.

library/exception.m:
ssdb/ssdb.m:
        Handle EXCP events in C# grades.

        Trap SIGINT when running ssdb in C# grades.

        Add `exit_process' implementation.

browser/declarative_execution.m:
browser/listing.m:
        Add stubs for C#.

README.CSharp:
        Document the C# backend.

README.DotNet:
        Add a pointer to README.CSharp.

configure.in:
        Make `configure --enable-ssdebug-grades' add `csharp.ssdebug'
        to the list of library grades.

diff --git a/Mmake.workspace b/Mmake.workspace
index bd22f8f..236bdb2 100644
--- a/Mmake.workspace
+++ b/Mmake.workspace
@@ -211,7 +211,12 @@ LINK_RT_LIB_OPTS=
 LINK_STD_LIB_OPTS=
 LINK_TRACE_SSDB_LIB_OPTS=
 ifneq ($(LINK_BOEHM_GC_ONLY),yes)
+ifneq ("$(filter csharp%,$(GRADE))","")
+# There is no separate runtime library for C# grades.
+LINK_RT_LIB_OPTS =
+else
 LINK_RT_LIB_OPTS = -l$(RT_LIB_NAME)
+endif
 ifneq ($(LINK_RUNTIME_ONLY),yes)
 LINK_STD_LIB_OPTS = -l$(STD_LIB_NAME)
 ifneq ($(LINK_STDLIB_ONLY),yes)
diff --git a/README.CSharp b/README.CSharp
new file mode 100644
index 0000000..4fd3702
--- /dev/null
+++ b/README.CSharp
@@ -0,0 +1,131 @@
+-----------------------------------------------------------------------------
+
+INTRODUCTION
+
+This release of Mercury contains a port to the ECMA Common Language
+Infrastructure (CLI), i.e. Microsoft .NET or Mono.  The Mercury
+compiler will generate C# source code that can be compiled into
+bytecode suitable for running in the .NET or Mono runtime systems.
+
+The port is mostly complete, but some parts of the Mercury standard
+library are not yet implemented (for a full list see the FAQ below).
+
+The port is currently targeted at C# 2.0 or higher.
+
+NOTE: a previous backend also targetted the .NET runtime, by generating IL
+(Intermediate Language), rather going via C#.  That backend is out-of-date
+and may be removed in the future.
+
+PREREQUISITES
+
+In order to try this system you will need
+
+        - Either Microsoft.NET or Mono 2.8 or above.
+
+	- The Mercury distribution -- installed as usual.  You can install
+	  from either the source or binary distribution.
+
+	  If you're reading this file from somewhere other than the
+	  Mercury distribution, try the Mercury homepage at
+		<http://www.mercury.csse.unimelb.edu.au>
+
+WARNING
+
+Please note that the C# backend is still an experimental feature.
+
+-----------------------------------------------------------------------------
+
+THE C# GRADE
+
+The Mercury compiler currently supports the grade `csharp'.
+The csharp grade is enabled by using any of the options
+`--grade csharp', `--target csharp', or just `--csharp'.
+
+To run a Mercury program using the csharp grade, you need to build the Mercury
+library and runtime in the csharp grade, using the Mercury source distribution.
+
+You can now build programs such as hello.m or calculator.m in the samples
+directory.
+
+	cd samples
+	mmc --make --csharp hello
+
+Now you can run hello
+
+	./hello
+
+-----------------------------------------------------------------------------
+
+USING C#
+
+The Mercury standard library has not been fully ported to C# yet.
+The use of unimplemented procedures will result in a run-time error,
+with a message such as "Sorry, not implemented: foreign code for this
+function", and a stack trace.
+
+If you find missing functionality, you can interface to C# using Mercury's
+foreign language interface.
+
+For example:
+
+:- pred to_string(T::in, string::out) is det.
+:- pragma foreign_proc("C#", to_string(T::in, Str::out), [],
+"
+        Str = T.ToString();
+").
+
+The implementation will include this C# code in the module's .cs file, and
+you can then call the predicate to_string exactly the same as if it were
+implemented using pure Mercury code.
+
+For more information about the foreign language interface, see the Mercury
+Language Reference Manual, which you can find at:
+
+     <http://www.mercury.csse.unimelb.edu.au/information/documentation.html>
+
+-----------------------------------------------------------------------------
+
+FREQUENTLY ASKED QUESTIONS (FAQS)
+
+Q. What are the advantages of using the C# back-end?
+
+A. The main advantage is easy access to the wide range of libraries for the
+   .NET platform, and the portability you get from using CIL bytecode.
+
+
+Q. What features are not yet implemented for the C# back-end?
+
+A. The following implementation features are not supported:
+
+	Mercury-level debugging (but see next question)
+	Mercury-level profiling
+	trailing
+	tabling
+
+   In addition, the following individual procedures are incompletely
+   implemented:
+
+	io.read_binary/{3,4}:
+	io.write_binary/{3,4}:
+		io.read_binary is broken.
+
+	benchmarking.report_stats/0:
+	benchmarking.report_full_memory_stats/0:
+		Memory usage statistics are not yet available, and cpu time
+		is not the same as in the C backends, as per time.m.
+
+	store.arg_ref/5:
+	store.new_arg_ref/5:
+		Due to the absence of RTTI, dynamic type checking is missing
+		for these predicates.  They should be used with care.
+
+   This list is not complete.
+
+
+Q. How do I debug Mercury programs on .NET?
+
+A. The only Mercury-level debugger available for C# grades is the
+   source-to-source debugger; see README.ssdebug.
+
+
+-----------------------------------------------------------------------------
diff --git a/README.DotNet b/README.DotNet
index be6c1ee..42ecbb5 100644
--- a/README.DotNet
+++ b/README.DotNet
@@ -1,5 +1,10 @@
 -----------------------------------------------------------------------------
 
+WARNING
+
+The .NET backend described herein is out-of-date and may be removed in
+the future.  See README.CSharp about a newer backend that targets C#.
+
 INTRODUCTION
 
 This release of Mercury contains a port to the Microsoft.NET Common
diff --git a/README.ssdebug b/README.ssdebug
index 3e5475e..4e6a8c5 100644
--- a/README.ssdebug
+++ b/README.ssdebug
@@ -18,7 +18,8 @@ INSTALLATION
 To use the source-to-source debugger you must install grades containing the
 ".ssdebug" grade component.  One way to do this is to invoke configure
 with the option `--enable-ssdebug-grades'.  This will add the grades
-hlc.gc.ssdebug and java.ssdebug to the set of library grades to install.
+hlc.gc.ssdebug, csharp.ssdebug and java.ssdebug to the set of library grades
+to install.
 
 -----------------------------------------------------------------------------
 
@@ -59,7 +60,7 @@ increase the stack size, e.g.
 LIMITATIONS
 
 - There are no internal events.  The only events are CALL, EXIT, REDO, FAIL,
-  and, for Java grades, EXCP.
+  and, for Java and C# grades, EXCP.
 
 - Standard library procedures are treated specially.  Events will only be
   generated at the boundaries at which a user procedure calls and returns
@@ -72,13 +73,16 @@ LIMITATIONS
   reach the end of the procedure to retry, the program will simply keep
   executing.  Press ^C to get back the debugger prompt.
 
-- Exceptions are only handled in Java grades.  Only a single EXCP event is
-  generated when an exception is thrown, instead of propagating EXCP events
+- When running on Mono, ^C sometimes causes the program to hang.
+  This appears to be a bug in Mono.
+
+- Exceptions are only handled in Java and C# grades.  Only a single EXCP event
+  is generated when an exception is thrown, instead of propagating EXCP events
   up the call stack to the nearest exception handler.
 
-- In non-Java grades, the debugger's internal state will be inconsistent with
-  the program's execution after an exception, so you had better quit the
-  program and restart.
+- In grades which don't handle exceptions, the debugger's internal state will
+  be inconsistent with the program's execution after an exception, so you had
+  better quit the program and restart.
 
 - Breakpoints currently match procedures by module and name only.  Predicates
   or functions with the same name but different arities will still match.
diff --git a/browser/Mercury.options b/browser/Mercury.options
index 808d4e9..10076f4 100644
--- a/browser/Mercury.options
+++ b/browser/Mercury.options
@@ -23,7 +23,7 @@ MCFLAGS-mdb.declarative_execution = --no-optimize-unused-args
 
 # XXX This line is needed so that `mmake --use-mmc-make libmer_browser'
 # passes `-lmer_mdbcomp' to `mmc --make' in the MLLIBS variable.
-EXTRA_LIBRARIES-libmer_browser = mer_mdbcomp
+LIBRARIES-mer_browser = mer_mdbcomp
 
 # Whereas these lines are needed for plain `mmake'.
 EXTRA_LIBRARIES-libmer_browser.so = mer_mdbcomp
diff --git a/browser/Mmakefile b/browser/Mmakefile
index 6e8e726..17eb5f1 100644
--- a/browser/Mmakefile
+++ b/browser/Mmakefile
@@ -65,8 +65,10 @@ MLFLAGS      += -R$(FINAL_INSTALL_MERC_LIB_DIR)	\
 MCFLAGS      += -R$(FINAL_INSTALL_MERC_LIB_DIR)	\
 		-R$(FINAL_INSTALL_MERC_GC_LIB_DIR)
 endif
+ifeq ("$(filter il% csharp% java% erlang%,$(GRADE))","")
 MLLIBS 	     += $(SOCKET_LIBRARY) $(NSL_LIBRARY) $(DL_LIBRARY) \
 		$(READLINE_LIBRARIES)
+endif
 
 MCFLAGS      += --flags MDB_FLAGS $(CONFIG_OVERRIDE)
 
@@ -252,14 +254,14 @@ realclean_local:
 .PHONY: install
 install: install_library
 
-ifneq ("$(filter il% csharp% erlang%,$(GRADE))","")
+ifneq ("$(filter il% erlang%,$(GRADE))","")
 
 # there is no browser in the .NET or Erlang backends
 
 .PHONY: install_library
 install_library:
 
-else ifneq (,$(findstring java,$(GRADE)))
+else ifeq ($(MMAKE_USE_MMC_MAKE),yes)
 
 .PHONY: install_library
 install_library: lib$(BROWSER_LIB_NAME).install
diff --git a/browser/declarative_execution.m b/browser/declarative_execution.m
index a11a20d..55b7199 100644
--- a/browser/declarative_execution.m
+++ b/browser/declarative_execution.m
@@ -538,6 +538,13 @@ call_node_bytecode_layout(_, _) :-
     }
 ").
 
+:- pragma foreign_proc("C#",
+    call_node_bytecode_layout(_CallLabelLayout::in, _ProcLayout::out),
+    [will_not_call_mercury, thread_safe, promise_pure],
+"
+    if (1 == 1) throw new System.Exception(\"not supported in csharp grade\");
+").
+
 :- pragma foreign_proc("Java",
     call_node_bytecode_layout(_CallLabelLayout::in, _ProcLayout::out),
     [will_not_call_mercury, thread_safe, promise_pure],
@@ -570,6 +577,13 @@ have_cached_proc_defn_rep(_, _) :-
     }
 ").
 
+:- pragma foreign_proc("C#",
+    have_cached_proc_defn_rep(_ProcLayout::in, _ProcDefnRep::out),
+    [will_not_call_mercury, thread_safe, promise_semipure],
+"
+    if (1 == 1) throw new System.Exception(\"not supported in csharp grade\");
+").
+
 :- pragma foreign_proc("Java",
     have_cached_proc_defn_rep(_ProcLayout::in, _ProcDefnRep::out),
     [will_not_call_mercury, thread_safe, promise_semipure],
diff --git a/browser/listing.m b/browser/listing.m
index b847534..3349fbc 100644
--- a/browser/listing.m
+++ b/browser/listing.m
@@ -104,6 +104,7 @@
 
 :- pragma foreign_type("C", c_file_ptr, "FILE *", [can_pass_as_mercury_type]).
     % stub.
+:- pragma foreign_type("C#", c_file_ptr, "object").
 :- pragma foreign_type("Java", c_file_ptr, "java.lang.Object").
 
     % These predicates are called from trace/mercury_trace_internal.c.
diff --git a/configure.in b/configure.in
index 42073b5..f93e59a 100644
--- a/configure.in
+++ b/configure.in
@@ -3599,6 +3599,9 @@ if test "$enable_ssdebug_grades" = yes; then
         *hlc.gc*) LIBGRADES="$LIBGRADES hlc.gc.ssdebug" ;;
     esac
     case "$LIBGRADES" in
+        *csharp*) LIBGRADES="$LIBGRADES csharp.ssdebug" ;;
+    esac
+    case "$LIBGRADES" in
         *java*) LIBGRADES="$LIBGRADES java.ssdebug" ;;
     esac
 fi
diff --git a/library/exception.m b/library/exception.m
index 5caa016..5056f1a 100644
--- a/library/exception.m
+++ b/library/exception.m
@@ -1443,10 +1443,24 @@ mercury__exception__builtin_catch_model_non(MR_Mercury_Type_Info type_info,
 
 %-----------------------------------------------------------------------------%
 
+:- pragma foreign_code("C#", "
+/*
+ * The ssdb module may supply its implementation of these methods at runtime.
+ */
+public class SsdbHooks {
+    public virtual void on_throw_impl(univ.Univ_0 univ) {}
+    public virtual int on_catch_impl() { return 0; }
+    public virtual void on_catch_impl_exception(int CSN) {}
+}
+
+public static SsdbHooks ssdb_hooks = new SsdbHooks();
+").
+
 :- pragma foreign_proc("C#",
     throw_impl(T::in),
     [will_not_call_mercury, promise_pure],
 "
+    exception.ssdb_hooks.on_throw_impl(T);
     throw new runtime.Exception(T);
 ").
 
@@ -1454,22 +1468,27 @@ mercury__exception__builtin_catch_model_non(MR_Mercury_Type_Info type_info,
     catch_impl(Pred::pred(out) is det, Handler::in(handler), T::out),
     [will_not_call_mercury, promise_pure],
 "
+    int CSN = ssdb_hooks.on_catch_impl();
     try {
         T = exception.ML_call_goal_det(TypeInfo_for_T, Pred);
     }
     catch (runtime.Exception ex) {
+        exception.ssdb_hooks.on_catch_impl_exception(CSN);
         T = exception.ML_call_handler_det(TypeInfo_for_T, Handler,
             (univ.Univ_0) ex.exception);
     }
 ").
+
 :- pragma foreign_proc("C#",
     catch_impl(Pred::pred(out) is cc_multi, Handler::in(handler), T::out),
     [will_not_call_mercury, promise_pure],
 "
+    int CSN = ssdb_hooks.on_catch_impl();
     try {
         T = exception.ML_call_goal_det(TypeInfo_for_T, Pred);
     }
     catch (runtime.Exception ex) {
+        exception.ssdb_hooks.on_catch_impl_exception(CSN);
         T = exception.ML_call_handler_det(TypeInfo_for_T, Handler,
             (univ.Univ_0) ex.exception);
     }
@@ -1497,12 +1516,14 @@ mercury__exception__builtin_catch_model_non(MR_Mercury_Type_Info type_info,
     catch_impl(Pred::pred(out) is multi, Handler::in(handler), _T::out),
     [will_not_call_mercury, promise_pure, ordinary_despite_detism],
 "
+    int CSN = ssdb_hooks.on_catch_impl();
     try {
         runtime.MethodPtr3_r0<object, object, object> pred =
             (runtime.MethodPtr3_r0<object, object, object>) Pred[1];
         pred(Pred, cont, cont_env_ptr);
     }
     catch (runtime.Exception ex) {
+        ssdb_hooks.on_catch_impl_exception(CSN);
         object T = exception.ML_call_handler_det(TypeInfo_for_T, Handler,
             (univ.Univ_0) ex.exception);
         ((runtime.MethodPtr2_r0<object, object>) cont)(T, cont_env_ptr);
@@ -1516,12 +1537,14 @@ mercury__exception__builtin_catch_model_non(MR_Mercury_Type_Info type_info,
     catch_impl(Pred::pred(out) is nondet, Handler::in(handler), _T::out),
     [will_not_call_mercury, promise_pure, ordinary_despite_detism],
 "
+    int CSN = ssdb_hooks.on_catch_impl();
     try {
         runtime.MethodPtr3_r0<object, object, object> pred =
             (runtime.MethodPtr3_r0<object, object, object>) Pred[1];
         pred(Pred, cont, cont_env_ptr);
     }
     catch (runtime.Exception ex) {
+        ssdb_hooks.on_catch_impl_exception(CSN);
         object T = exception.ML_call_handler_det(TypeInfo_for_T, Handler,
             (univ.Univ_0) ex.exception);
         ((runtime.MethodPtr2_r0<object, object>) cont)(T, cont_env_ptr);
diff --git a/mdbcomp/Mmakefile b/mdbcomp/Mmakefile
index c7eced3..3aaa7e9 100644
--- a/mdbcomp/Mmakefile
+++ b/mdbcomp/Mmakefile
@@ -56,8 +56,10 @@ MLFLAGS      += -R$(FINAL_INSTALL_MERC_LIB_DIR)	\
 MCFLAGS      += -R$(FINAL_INSTALL_MERC_LIB_DIR)	\
 		-R$(FINAL_INSTALL_MERC_GC_LIB_DIR)
 endif
+ifeq ("$(filter il% csharp% java% erlang%,$(GRADE))","")
 MLLIBS       += $(SOCKET_LIBRARY) $(NSL_LIBRARY) $(DL_LIBRARY) \
 		$(READLINE_LIBRARIES)
+endif
 
 #-----------------------------------------------------------------------------#
 
@@ -211,14 +213,14 @@ realclean_local:
 .PHONY: install
 install: install_library
 
-ifneq ("$(filter il% csharp% erlang%,$(GRADE))","")
+ifneq ("$(filter il% erlang%,$(GRADE))","")
 
 # there is no debugger in the .NET or Erlang backends
 
 .PHONY: install_library
 install_library:
 
-else ifneq (,$(findstring java,$(GRADE)))
+else ifeq ($(MMAKE_USE_MMC_MAKE),yes)
 
 .PHONY: install_library
 install_library: lib$(MDBCOMP_LIB_NAME).install
diff --git a/ssdb/Mercury.options b/ssdb/Mercury.options
index ef03464..1fb394c 100644
--- a/ssdb/Mercury.options
+++ b/ssdb/Mercury.options
@@ -10,7 +10,7 @@ MCFLAGS-mer_ssdb = --no-warn-nothing-exported --no-warn-unused-imports
 
 # XXX This line is needed so that `mmake --use-mmc-make libmer_ssdb'
 # passes `-lmer_mdbcomp' to `mmc --make' in the MLLIBS variable.
-EXTRA_LIBRARIES-libmer_ssdb = mer_mdbcomp mer_browser
+LIBRARIES-mer_ssdb = mer_mdbcomp mer_browser
 
 # Whereas these lines are needed for plain `mmake'.
 EXTRA_LIBRARIES-libmer_ssdb.so = mer_mdbcomp mer_browser
diff --git a/ssdb/Mmakefile b/ssdb/Mmakefile
index d9f35e8..9a0f6d2 100644
--- a/ssdb/Mmakefile
+++ b/ssdb/Mmakefile
@@ -65,8 +65,10 @@ MLFLAGS      += -R$(FINAL_INSTALL_MERC_LIB_DIR)	\
 MCFLAGS      += -R$(FINAL_INSTALL_MERC_LIB_DIR)	\
 		-R$(FINAL_INSTALL_MERC_GC_LIB_DIR)
 endif
+ifeq ("$(filter il% csharp% java% erlang%,$(GRADE))","")
 MLLIBS 	     += $(SOCKET_LIBRARY) $(NSL_LIBRARY) $(DL_LIBRARY) \
 		$(READLINE_LIBRARIES)
+endif
 
 MCFLAGS      += --flags SSDB_FLAGS $(CONFIG_OVERRIDE)
 
@@ -246,14 +248,14 @@ realclean_local:
 .PHONY: install
 install: install_library
 
-ifneq ("$(filter il% csharp% erlang%,$(GRADE))","")
+ifneq ("$(filter il% erlang%,$(GRADE))","")
 
 # there is no ssdb in the .NET or Erlang backends
 
 .PHONY: install_library
 install_library:
 
-else ifneq (,$(findstring java,$(GRADE)))
+else ifeq ($(MMAKE_USE_MMC_MAKE),yes)
 
 .PHONY: install_library
 install_library: lib$(SSDB_LIB_NAME).install
diff --git a/ssdb/ssdb.m b/ssdb/ssdb.m
index dab37c4..ba42a5f 100755
--- a/ssdb/ssdb.m
+++ b/ssdb/ssdb.m
@@ -470,6 +470,27 @@ static void MR_ssdb_sigint_handler(void)
 }
 ").
 
+:- pragma foreign_proc("C#",
+    install_sigint_handler(IO0::di, IO::uo),
+    [will_not_call_mercury, promise_pure, thread_safe, may_not_duplicate],
+"
+    System.Console.TreatControlCAsInput = false;
+    System.Console.CancelKeyPress += new System.ConsoleCancelEventHandler(
+        ssdb.sigint_handler
+    );
+    IO = IO0;
+").
+
+:- pragma foreign_code("C#",
+"
+static void sigint_handler(object sender, System.ConsoleCancelEventArgs args)
+{
+    SSDB_step_next_stop();
+    // Don't terminate the process.
+    args.Cancel = true;
+}
+").
+
 :- pragma foreign_proc("Java",
     install_sigint_handler(IO0::di, IO::uo),
     [will_not_call_mercury, promise_pure, thread_safe, may_not_duplicate],
@@ -496,6 +517,8 @@ public static class SigIntHandler implements sun.misc.SignalHandler {
 
 :- pragma foreign_export("C", step_next_stop(di, uo),
     "SSDB_step_next_stop").
+:- pragma foreign_export("C#", step_next_stop(di, uo),
+    "SSDB_step_next_stop").
 :- pragma foreign_export("Java", step_next_stop(di, uo),
     "SSDB_step_next_stop").
 
@@ -802,6 +825,30 @@ search_nondet_stack_frame_2(ProcId, Depth, N, StackDepth, MaybeStackFrame,
 
 install_exception_hooks(!IO).
 
+:- pragma foreign_proc("C#",
+    install_exception_hooks(_IO0::di, _IO::uo),
+    [will_not_call_mercury, promise_pure, thread_safe, may_not_duplicate],
+"
+    exception.ssdb_hooks = new ssdb.SsdbHooks();
+").
+
+:- pragma foreign_code("C#", "
+private class SsdbHooks : exception.SsdbHooks {
+    public override void on_throw_impl(univ.Univ_0 univ) {
+        ssdb.SSDB_handle_event_excp(""exception"", ""throw_impl"", univ);
+    }
+
+    public override int on_catch_impl() {
+        return ssdb.SSDB_get_cur_ssdb_csn();
+    }
+
+    public override void on_catch_impl_exception(int CSN) {
+        ssdb.SSDB_rollback_stack(CSN);
+        ssdb.SSDB_rollback_nondet_stack(CSN);
+    }
+}
+").
+
 :- pragma foreign_proc("Java",
     install_exception_hooks(_IO0::di, _IO::uo),
     [will_not_call_mercury, promise_pure, thread_safe, may_not_duplicate],
@@ -830,6 +877,8 @@ private static class SsdbHooks extends exception.SsdbHooks {
 ").
 
 :- impure pred handle_event_excp(string::in, string::in, univ::in) is det.
+:- pragma foreign_export("C#", handle_event_excp(in, in, in),
+    "SSDB_handle_event_excp").
 :- pragma foreign_export("Java", handle_event_excp(in, in, in),
     "SSDB_handle_event_excp").
 
@@ -880,6 +929,8 @@ handle_event_excp_2(ProcId, ListVarValue, !IO) :-
 
 %----------------------------------------------------------------------------%
 
+:- pragma foreign_export("C#", get_cur_ssdb_csn(out),
+    "SSDB_get_cur_ssdb_csn").
 :- pragma foreign_export("Java", get_cur_ssdb_csn(out),
     "SSDB_get_cur_ssdb_csn").
 
@@ -1004,6 +1055,8 @@ nondet_stack_pop(!IO) :-
     ).
 
 :- pred rollback_stack(int::in, io::di, io::uo) is det.
+:- pragma foreign_export("C#", rollback_stack(in, di, uo),
+    "SSDB_rollback_stack").
 :- pragma foreign_export("Java", rollback_stack(in, di, uo),
     "SSDB_rollback_stack").
 
@@ -1017,6 +1070,8 @@ rollback_stack(TargetCSN, !IO) :-
     ).
 
 :- pred rollback_nondet_stack(int::in, io::di, io::uo) is det.
+:- pragma foreign_export("C#", rollback_nondet_stack(in, di, uo),
+    "SSDB_rollback_nondet_stack").
 :- pragma foreign_export("Java", rollback_nondet_stack(in, di, uo),
     "SSDB_rollback_nondet_stack").
 
@@ -3365,6 +3420,13 @@ restore_streams(!IO) :-
     IO = IO0;
 ").
 
+:- pragma foreign_proc("C#",
+    exit_process(_IO0::di, _IO::uo),
+    [will_not_call_mercury, promise_pure, tabled_for_io],
+"
+    System.Environment.Exit(0);
+").
+
 :- pragma foreign_proc("Java",
     exit_process(_IO0::di, _IO::uo),
     [will_not_call_mercury, promise_pure, tabled_for_io],

--------------------------------------------------------------------------
mercury-reviews mailing list
Post messages to:       mercury-reviews at csse.unimelb.edu.au
Administrative Queries: owner-mercury-reviews at csse.unimelb.edu.au
Subscriptions:          mercury-reviews-request at csse.unimelb.edu.au
--------------------------------------------------------------------------



More information about the reviews mailing list