[m-rev.] for review: mix mercury code with foreign_proc

Tyson Dowd trd at cs.mu.OZ.AU
Tue Jul 31 01:40:56 AEST 2001


Hi,

This should make it easier to avoid writing foreign_procs for all those
"hand-coded for speed" things in the library.

===================================================================


Estimated hours taken: 16
Branches: main

Allow foreign_proc clauses to replace Mercury definitions.
Or alternately viewed, allow the compiler to fall back on Mercury
definitions of procedures if a suitable foreign_proc clause is unavailable.

(This is only possible with mode-specific Mercury procedures).

compiler/hlds_pred.m:
	Add a field to clauses_info to record whether we have any
	foreign_proc clauses.

compiler/make_hlds.m:
	Record errors if we try to add a foreign_proc that will replace
	a Mercury clause that is not mode-specific, or if we try to add
	a non-mode specific Mercury clause that will replace a foreign
	proc.  
	Otherwise, we allow a foreign_proc to replace mode-specific
	Mercury clauses.
	Set the goal type for potentially mixed mercury/foreign_proc
	clauses as "clauses".
	Add Mercury clauses only for modes not yet covered by
	foreign_proc clauses.  Checking this could be a performance
	problem so we check the have_foreign_clauses boolean so
	that we don't need to search all the clauses every time we add a
	Mercury clause (only when there are foreign_clauses to search for).

	Traverse clauses and decide upon our course of action (add
	new foreign_proc clause, ignore new foreign_proc clause, replace
	existing clause, split existing clause and add new clause) 
	all in one go.

compiler/clause_to_proc.m:
compiler/higher_order.m:
compiler/hlds_out.m:
compiler/polymorphism.m:
compiler/unify_proc.m:
	Handle have_foreign_clauses field in clauses_info.

doc/reference_manual.texi:
doc/user_guide.texi:
	Document the ability to mix mode-specific Mercury and
	foreign_proc clauses.

	Document the behaviour of the implementation when it comes to
	specific backends (that is, the preferred foreign languages list).
	Also a few fixes from fjh's review that didn't quite make it
	into the review.
	

Index: compiler/clause_to_proc.m
===================================================================
RCS file: /home/mercury1/repository/mercury/compiler/clause_to_proc.m,v
retrieving revision 1.30
diff -u -r1.30 clause_to_proc.m
--- compiler/clause_to_proc.m	2001/07/20 14:13:20	1.30
+++ compiler/clause_to_proc.m	2001/07/30 15:09:12
@@ -143,7 +143,7 @@
 
 copy_clauses_to_proc(ProcId, ClausesInfo, Proc0, Proc) :-
 	ClausesInfo = clauses_info(VarSet, _, _, VarTypes, HeadVars, Clauses,
-		TI_VarMap, TCI_VarMap),
+		TI_VarMap, TCI_VarMap, _),
 	select_matching_clauses(Clauses, ProcId, MatchingClauses),
 	get_clause_goals(MatchingClauses, GoalList),
 	( GoalList = [SingleGoal] ->
Index: compiler/higher_order.m
===================================================================
RCS file: /home/mercury1/repository/mercury/compiler/higher_order.m,v
retrieving revision 1.90
diff -u -r1.90 higher_order.m
--- compiler/higher_order.m	2001/07/13 12:15:50	1.90
+++ compiler/higher_order.m	2001/07/30 15:09:13
@@ -2500,7 +2500,7 @@
 	% hlds dumps if it's filled in.
 	ClausesInfo = clauses_info(EmptyVarSet, EmptyVarTypes,
 		EmptyTVarNameMap, EmptyVarTypes, [], [],
-		EmptyTIMap, EmptyTCIMap),
+		EmptyTIMap, EmptyTCIMap, no),
 	pred_info_init(PredModule, SymName, Arity, ArgTVarSet, ExistQVars,
 		Types, true, Context, ClausesInfo, Status, MarkerList, GoalType,
 		PredOrFunc, ClassContext, EmptyProofs, Owner, NewPredInfo0),
Index: compiler/hlds_out.m
===================================================================
RCS file: /home/mercury1/repository/mercury/compiler/hlds_out.m,v
retrieving revision 1.265
diff -u -r1.265 hlds_out.m
--- compiler/hlds_out.m	2001/07/24 10:47:13	1.265
+++ compiler/hlds_out.m	2001/07/30 15:09:15
@@ -792,7 +792,7 @@
 		[]
 	),
 	{ ClausesInfo = clauses_info(VarSet, _, _, VarTypes, HeadVars, Clauses,
-		TypeInfoMap, TypeClassInfoMap) },
+		TypeInfoMap, TypeClassInfoMap, _) },
 	( { string__contains_char(Verbose, 'C') } ->
 		hlds_out__write_indent(Indent),
 		io__write_string("% pred id: "),
Index: compiler/hlds_pred.m
===================================================================
RCS file: /home/mercury1/repository/mercury/compiler/hlds_pred.m,v
retrieving revision 1.98
diff -u -r1.98 hlds_pred.m
--- compiler/hlds_pred.m	2001/07/20 14:13:29	1.98
+++ compiler/hlds_pred.m	2001/07/30 15:09:16
@@ -147,7 +147,10 @@
 							% fields are computed
 							% by polymorphism.m
 			clause_type_info_varmap	:: type_info_varmap,
-			clause_typeclass_info_varmap :: typeclass_info_varmap
+			clause_typeclass_info_varmap :: typeclass_info_varmap,
+			have_foreign_clauses	::	bool
+							% do we have foreign
+							% language clauses?
 		).
 
 :- type vartypes == map(prog_var, type).
@@ -969,8 +972,10 @@
 	% The empty list of clauses is a little white lie.
 	Clauses = [],
 	map__init(TVarNameMap),
+	HasForeignClauses = no,
 	ClausesInfo = clauses_info(VarSet, VarTypes, TVarNameMap,
-		VarTypes, HeadVars, Clauses, TypeInfoMap, TypeClassInfoMap),
+		VarTypes, HeadVars, Clauses, TypeInfoMap, TypeClassInfoMap,
+		HasForeignClauses),
 	map__init(ClassProofs),
 	term__vars_list(Types, TVars),
 	list__delete_elems(TVars, ExistQVars, HeadTypeParams),
Index: compiler/make_hlds.m
===================================================================
RCS file: /home/mercury1/repository/mercury/compiler/make_hlds.m,v
retrieving revision 1.377
diff -u -r1.377 make_hlds.m
--- compiler/make_hlds.m	2001/07/23 12:22:05	1.377
+++ compiler/make_hlds.m	2001/07/30 15:09:19
@@ -985,8 +985,10 @@
 		map__init(TI_VarMap),
 		map__init(TCI_VarMap),
 		map__init(TVarNameMap),
+		HasForeignClauses = no,
 		Clauses = clauses_info(ArgVarSet, VarTypes0, TVarNameMap,
-			VarTypes0, Args, [Clause], TI_VarMap, TCI_VarMap),
+			VarTypes0, Args, [Clause], TI_VarMap, TCI_VarMap,
+			HasForeignClauses),
 		pred_info_get_markers(PredInfo0, Markers),
 		map__init(Proofs),
 
@@ -2949,8 +2951,10 @@
 	map__init(TVarNameMap),
 	map__init(TI_VarMap),
 	map__init(TCI_VarMap),
+	HasForeignClauses = no,
 	ClausesInfo = clauses_info(VarSet, VarTypes, TVarNameMap, VarTypes,
-				HeadVars, ClauseList, TI_VarMap, TCI_VarMap),
+				HeadVars, ClauseList, TI_VarMap, TCI_VarMap,
+				HasForeignClauses),
 	pred_info_set_clauses_info(PredInfo0, ClausesInfo, PredInfo).
 
 %-----------------------------------------------------------------------------%
@@ -3579,15 +3583,20 @@
 		PredInfo1 = PredInfo0
 	},
 	(
-		{ pred_info_get_goal_type(PredInfo1, pragmas) }
-	->
+		{ pred_info_get_goal_type(PredInfo1, pragmas) },
+		{ get_mode_annotations(Args, _, empty, ModeAnnotations) },
+		{ ModeAnnotations = empty ; ModeAnnotations = none }
+	->
+			% If we have a pragma foreign_proc for this procedure
+			% already, and we are trying to add a non-mode specific
+			% Mercury clause 
 		{ module_info_incr_errors(ModuleInfo1, ModuleInfo) },
 		prog_out__write_context(Context),
-		io__write_string("Error: clause for "),
+		io__write_string("Error: non mode-specific clause for "),
 		hlds_out__write_simple_call_id(PredOrFunc, PredName/Arity),
 		io__write_string("\n"),
 		prog_out__write_context(Context),
-		io__write_string("  with `:- pragma c_code' declaration preceding.\n"),
+		io__write_string("  with `:- pragma foreign_proc' declaration preceding.\n"),
 		{ Info = Info0 }
 	;
 		%
@@ -3869,8 +3878,10 @@
 	map__init(TVarNameMap),
 	map__init(TI_VarMap),
 	map__init(TCI_VarMap),
+	HasForeignClauses = no,
 	ClausesInfo = clauses_info(VarSet, VarTypes, TVarNameMap, VarTypes,
-		HeadVars, [IntroducedClause], TI_VarMap, TCI_VarMap).
+		HeadVars, [IntroducedClause], TI_VarMap, TCI_VarMap,
+		HasForeignClauses).
 
 	% handle the arbitrary clauses syntax
 produce_instance_method_clauses(clauses(InstanceClauses), PredOrFunc,
@@ -4161,20 +4172,23 @@
 		io__write_string(".\n"),
 		{ Info = Info0 }
 	;	
-		{ pred_info_get_goal_type(PredInfo1, clauses) }
+		{ pred_info_get_goal_type(PredInfo1, clauses) },
+		{ pred_info_clauses_info(PredInfo1, CInfo) },
+		{ clauses_info_clauses(CInfo, ClauseList) },
+		{ list__member(clause([], _, mercury, _), ClauseList) }
+
 	->
 		{ module_info_incr_errors(ModuleInfo1, ModuleInfo) },
 		prog_out__write_context(Context),
-		io__write_string("Error: `:- pragma foreign_code' (or `pragma c_code')\n"),
+		io__write_string("Error: `:- pragma foreign_proc' (or `pragma c_code')\n"),
 		prog_out__write_context(Context),
 		io__write_string("declaration for "),
 		hlds_out__write_simple_call_id(PredOrFunc, PredName/Arity),
 		io__write_string("\n"),
 		prog_out__write_context(Context),
-		io__write_string("  with preceding clauses.\n"),
+		io__write_string("  with preceding non-mode specific clauses.\n"),
 		{ Info = Info0 }
 	;
-
 			% Don't add clauses for foreign languages other
 			% than the ones we can generate code for.
 		{ not list__member(PragmaForeignLanguage, BackendForeignLangs) }
@@ -4202,8 +4216,15 @@
 				ModuleInfo2, Info0, Info),
 			{ pred_info_set_clauses_info(PredInfo1, Clauses, 
 				PredInfo2) },
-			{ pred_info_set_goal_type(PredInfo2, pragmas, 
-				PredInfo) },
+					% If we have already seen Mercury
+					% clauses for this, use Mercury clauses
+					% as an appoximation for the goal type.
+			{ pred_info_get_goal_type(PredInfo2, clauses) ->
+				PredInfo = PredInfo2
+			;
+				pred_info_set_goal_type(PredInfo2, pragmas,
+					PredInfo)
+			},
 			{ map__det_update(Preds0, PredId, PredInfo, Preds) },
 			{ predicate_table_set_preds(PredicateTable1, Preds, 
 				PredicateTable) },
@@ -5143,8 +5164,9 @@
 	varset__init(VarSet),
 	map__init(TI_VarMap),
 	map__init(TCI_VarMap),
+	HasForeignClauses = no,
 	ClausesInfo = clauses_info(VarSet, VarTypes, TVarNameMap, VarTypes,
-		HeadVars, [], TI_VarMap, TCI_VarMap).
+		HeadVars, [], TI_VarMap, TCI_VarMap, HasForeignClauses).
 
 :- pred clauses_info_init(int::in, clauses_info::out) is det.
 
@@ -5155,8 +5177,10 @@
 	make_n_fresh_vars("HeadVar__", Arity, VarSet0, HeadVars, VarSet),
 	map__init(TI_VarMap),
 	map__init(TCI_VarMap),
+	HasForeignClauses = no,
 	ClausesInfo = clauses_info(VarSet, VarTypes, TVarNameMap,
-		VarTypes, HeadVars, [], TI_VarMap, TCI_VarMap).
+		VarTypes, HeadVars, [], TI_VarMap, TCI_VarMap,
+		HasForeignClauses).
 
 :- pred clauses_info_add_clause(clauses_info::in,
 		list(proc_id)::in, prog_varset::in, tvarset::in,
@@ -5167,13 +5191,13 @@
 		module_info::in, module_info::out, qual_info::in,
 		qual_info::out, io__state::di, io__state::uo) is det.
 
-clauses_info_add_clause(ClausesInfo0, ModeIds, CVarSet, TVarSet0,
+clauses_info_add_clause(ClausesInfo0, ModeIds0, CVarSet, TVarSet0,
 		Args, Body, Context, Status, PredOrFunc, Arity, IsAssertion,
 		Goal, VarSet, TVarSet, ClausesInfo, Warnings, Module0, Module,
 		Info0, Info) -->
 	{ ClausesInfo0 = clauses_info(VarSet0, ExplicitVarTypes0, TVarNameMap0,
 				InferredVarTypes, HeadVars, ClauseList0,
-				TI_VarMap, TCI_VarMap) },
+				TI_VarMap, TCI_VarMap, HasForeignClauses) },
 	{ ClauseList0 = [] ->
 		% Create the mapping from type variable name, used to
 		% rename type variables occurring in explicit type
@@ -5209,17 +5233,46 @@
 		{ FoundError = no },
 		{ Goal = Goal0 },
 
+			% If we have foreign clauses, we should only
+			% add this clause for modes *not* covered by the 
+			% foreign clauses.
+		{ HasForeignClauses = yes ->
+			ForeignModeIds = list__condense(list__filter_map(
+				(func(C) = ProcIds is semidet :-
+					C = clause(ProcIds, _, ClauseLang, _),
+					not ClauseLang = mercury
+				),
+				ClauseList0)),
+			ModeIds = list__delete_elems(ModeIds0, ForeignModeIds),
+			( ModeIds = [] ->
+				ClauseList = ClauseList0
+			;
+				% XXX we should avoid append - this gives O(N*N)
+				list__append(ClauseList0, 
+					[clause(ModeIds, Goal, mercury,
+						Context)], ClauseList)
+			)
+		;
 			% XXX we should avoid append - this gives O(N*N)
-		{ list__append(ClauseList0, [clause(ModeIds, Goal, mercury,
-			Context)], ClauseList) },
+			list__append(ClauseList0, [clause(ModeIds0, Goal,
+				mercury, Context)], ClauseList)
+		},
 		{ qual_info_get_var_types(Info, ExplicitVarTypes) },
 		{ ClausesInfo = clauses_info(VarSet, ExplicitVarTypes,
 				TVarNameMap, InferredVarTypes, HeadVars,
-				ClauseList, TI_VarMap, TCI_VarMap) }
+				ClauseList, TI_VarMap, TCI_VarMap,
+				HasForeignClauses) }
 	).
 
 %-----------------------------------------------------------------------------
 
+:- type foreign_proc_action
+	--->	ignore
+	;	add
+	; 	split_add(int, clause)
+	;	replace(int).
+
+
 % Add the pragma_foreign_proc goal to the clauses_info for this procedure.
 % To do so, we must also insert unifications between the variables in the
 % pragma foreign_proc declaration and the head vars of the pred. Also
@@ -5239,85 +5292,88 @@
 		ModuleInfo, Info0, Info) -->
 
 	{ ClausesInfo0 = clauses_info(VarSet0, VarTypes, TVarNameMap,
-		VarTypes1, HeadVars, ClauseList, TI_VarMap, TCI_VarMap) },
+		VarTypes1, HeadVars, ClauseList, TI_VarMap, TCI_VarMap,
+		_HasForeignClauses) },
 
 
 		% Find all the exising clauses for this mode, and
 		% extract their implementation language and clause number
 		% (that is, their index in the list).
 	{ foreign_language(Attributes0, NewLang) },
-	{ list__foldl2(
-		(pred(C::in, Res0::in, Res::out, N0::in, N::out) is det :-
-			( 
-				C = clause(ProcIds, _, ClauseLang, _),
-				list__member(ProcId, ProcIds)
-			->
-				Res = [ClauseLang - N0 | Res0],
-				N = N0 + 1
-			;
-				Res = Res0,
-				N = N0 + 1
-			)
-		), ClauseList, [], LangClauses, 1, _) },
 
 	globals__io_get_globals(Globals),
 	globals__io_get_target(Target),
 
-		% Figure out what to do with this new clause.
-		% We can either add it to the list of clauses, ignore it,
-		% or replace the existing clause with it.
+
+		% We traverse the clauses, and decide which action to perform.
 		%
-		% We create a closure called UpdateClauses which does the
-		% appropriate action at the end of this predicate.
+		% If there are no clauses, we will simply add this clause.
 		%
-		% In the rare case of multiple foreign language
-		% implementations we might do some unnecessary work only
-		% to ignore the new clause.
-	{ 
-		% no clauses -- add it
-		LangClauses = [],
-		UpdateClauses = (pred(NewCl::in, Cs::out) is det :- 
-			Cs = [NewCl|ClauseList])
-	;
-		% was implemented in Mercury, do nothing
-		% XXX if we want to make Mercury implementations a fallback
-		% we should consider making this a replace instead of an
-		% ignore.
-		LangClauses = [mercury - _ | Rest],
-		( Rest = [] ->
-			UpdateClauses = (pred(_NewCl::in, Cs::out) is det :- 
-				Cs = ClauseList)
-		;
-			error("unexpected: multiple matches for foreign " ++
-				"language clauses")
-		)
+		% If there are matching foreign_proc clauses for this proc_id,
+		% we will either replace them or ignore the new clause
+		% (depending on the preference of the two foreign languages).
+		%
+		% If there is a matching Mercury clause for this proc_id, we
+		% will either
+		% 	- replace it if there is only one matching mode in its
+		% 	  proc_id list.
+		%	- remove the matching proc_id from its proc_id list,
+		%	  and add this clause as a new clause for this mode.
 
-	; 
-		LangClauses = [ForeignLang - ClauseNumber | Rest], 
-		ForeignLang = foreign_language(OldLang),
-		( Rest = [] ->
-			PreferNewLang = foreign__prefer_foreign_language(
-				Globals, Target, OldLang, NewLang),
+
+	{ list__foldl2(
+		(pred(C::in, Action0::in, Action::out, N0::in, N::out) is det :-
+			C = clause(ProcIds, B, ClauseLang, D),
 			( 
-				% This language is preferred to the old
-				% language, so we should replace it
-				PreferNewLang = yes ->
-				UpdateClauses = 
-					(pred(NewCl::in, Cs::out) is det :-
-					list__replace_nth_det(ClauseList,
-						ClauseNumber, NewCl, Cs))
+				ClauseLang = mercury,
+				ProcIds = [ProcId]
+			->
+				Action = replace(N0)
 			;
-				% Just ignore it.
-				UpdateClauses = 
-					(pred(_NewCl::in, Cs::out) is det :- 
-						Cs = ClauseList)
-			)
-		;
-			error("unexpected: multiple matches for foreign " ++
-				"language clauses")
+				ClauseLang = mercury,
+				list__delete_first(ProcIds, ProcId,
+					MercuryProcIds)
+			->
+				NewMercuryClause = clause(
+					MercuryProcIds, B, ClauseLang, D),
+				Action = split_add(N0, NewMercuryClause)	
+			;
+				ClauseLang = foreign_language(OldLang),
+				list__member(ProcId, ProcIds)
+			->
+				PreferNewLang = 
+					foreign__prefer_foreign_language(
+						Globals, Target, OldLang,
+						NewLang),
+					% This language is preferred to the old
+					% language, so we should replace it
+				( PreferNewLang = yes ->
+					Action = replace(N0)
+				;
+					% Just ignore it.
+					Action = ignore
+				)
+			;
+				Action = Action0
+			),
+			N = N0 + 1
+		), ClauseList, add, FinalAction, 1, _) },
+
+	{ UpdateClauses = (pred(NewCl::in, Cs::out) is det :-
+		( FinalAction = ignore,
+			Cs = ClauseList
+		; FinalAction = add,
+			Cs = [NewCl|ClauseList]
+		; FinalAction = replace(X),
+			list__replace_nth_det(ClauseList, X, NewCl, Cs)
+		; FinalAction = split_add(X, Clause),
+			list__replace_nth_det(ClauseList, X, Clause, Cs1),
+			Cs = [NewCl|Cs1]
 		)
-	},
-	
+	) },
+
+
+
 	globals__io_get_backend_foreign_languages(BackendForeignLanguages),
 	{ 
 	pragma_get_vars(PVars, Args0),
@@ -5409,9 +5465,10 @@
 		NewClause = clause([ProcId], HldsGoal,
 			foreign_language(NewLang), Context),
 		UpdateClauses(NewClause, NewClauseList),
+		HasForeignClauses = yes,
 		ClausesInfo =  clauses_info(VarSet, VarTypes, TVarNameMap,
 			VarTypes1, HeadVars, NewClauseList,
-			TI_VarMap, TCI_VarMap)
+			TI_VarMap, TCI_VarMap, HasForeignClauses)
 		}
 	).
 
Index: compiler/polymorphism.m
===================================================================
RCS file: /home/mercury1/repository/mercury/compiler/polymorphism.m,v
retrieving revision 1.215
diff -u -r1.215 polymorphism.m
--- compiler/polymorphism.m	2001/07/20 14:14:18	1.215
+++ compiler/polymorphism.m	2001/07/30 15:09:21
@@ -566,7 +566,8 @@
 	map__init(TVarNameMap), % This is only used while adding the clauses.
 	ClausesInfo = clauses_info(VarSet, ExplicitVarTypes, TVarNameMap,
 				VarTypes, HeadVars, Clauses,
-				TypeInfoMap, TypeClassInfoMap).
+				TypeInfoMap, TypeClassInfoMap,
+				ClausesInfo0 ^ have_foreign_clauses).
 
 :- pred polymorphism__process_clause(pred_info, list(prog_var), list(prog_var),
 		list(tvar), list(prog_var), list(prog_var),
Index: compiler/unify_proc.m
===================================================================
RCS file: /home/mercury1/repository/mercury/compiler/unify_proc.m,v
retrieving revision 1.94
diff -u -r1.94 unify_proc.m
--- compiler/unify_proc.m	2001/07/20 14:14:30	1.94
+++ compiler/unify_proc.m	2001/07/30 15:09:21
@@ -694,8 +694,10 @@
 	map__init(TVarNameMap),
 	map__init(TI_VarMap),
 	map__init(TCI_VarMap),
+	HasForeignClauses = yes,
 	ClauseInfo = clauses_info(VarSet, Types, TVarNameMap,
-			Types, Args, Clauses, TI_VarMap, TCI_VarMap).
+			Types, Args, Clauses, TI_VarMap, TCI_VarMap,
+			HasForeignClauses).
 
 :- pred unify_proc__generate_unify_clauses(hlds_type_body, prog_var, prog_var,
 		prog_context, list(clause), unify_proc_info, unify_proc_info).
Index: doc/reference_manual.texi
===================================================================
RCS file: /home/mercury1/repository/mercury/doc/reference_manual.texi,v
retrieving revision 1.212
diff -u -r1.212 reference_manual.texi
--- doc/reference_manual.texi	2001/07/25 15:49:53	1.212
+++ doc/reference_manual.texi	2001/07/30 15:09:26
@@ -4785,6 +4785,13 @@
 (If you use this form, and the C code @emph{does} invoke Mercury code,
 then the behaviour is undefined --- your program may misbehave or crash.)
 
+It is possible to provide both a Mercury definition, and
+a foreign_proc definition for a procedure.
+All such Mercury definitions must use mode-specific clauses (even if
+there is only a single mode for the predicate).
+Suitable foreign_proc definitions will be used first, but
+if no suitable foreign_proc definition is found, the Mercury definition
+will be used instead.
 
 @node Foreign code attributes
 @subsection Foreign code attributes
@@ -4910,6 +4917,8 @@
 
 All Mercury implementations should support interfacing with C.
 The set of other languages supported is implementation-defined.
+A suitable compiler or assembler for the foreign language
+must be available on the system.
 
 The University of Melbourne Mercury implementation supports
 interfacing with the following languages:
Index: doc/user_guide.texi
===================================================================
RCS file: /home/mercury1/repository/mercury/doc/user_guide.texi,v
retrieving revision 1.265
diff -u -r1.265 user_guide.texi
--- doc/user_guide.texi	2001/07/25 14:13:35	1.265
+++ doc/user_guide.texi	2001/07/30 15:09:30
@@ -5697,6 +5697,16 @@
 @node Foreign language interface
 @chapter Foreign language interface
 
+If the compiler generates code for a particular target for which 
+there are multiple applicable foreign languages, it will choose the
+foreign languages according to a builtin ordering. 
+
+If the language is not available for a particular backend, it will be
+ignored. 
+
+Mercury clauses will be used if there are no suitable foreign_proc
+clauses for a particular procedure.
+
 @table @asis
 
 @item @samp{C}
@@ -5704,32 +5714,23 @@
 or assembler.
 Only available on backends that compile to C or assembler.
 
- at item @samp{Managed C++}
-Managed Extensions for C++ is a language based on C++ that
-provide support for writing .NET components, by adding extra
-keywords and syntax.
-
-This is the default foreign language on all backends which compile to IL.
-In the current implementation, this is only available on backends that
-compile to IL.
-Requires a Managed Extensions for C++ compiler installed.
-
-
 @item @samp{C#}
 Only available on backends that compile to IL.
-Requires a C# compiler installed.
-To use it pass mmc @samp{--use-foreign-language csharp} and
- at samp{--backend-foreign-language csharp}.
+This is the second preferred foreign language for IL code generation.
 
 @item @samp{IL}
 IL (or CIL) is the intermediate language of the .NET Common Language
 Runtime.
+Only available on backends that compile to IL.
+This is the preferred foreign language for IL code generation.
 
-Use the string "IL" to set the foreign language to IL.
+ at item @samp{Managed C++}
+Managed Extensions for C++ is a language based on C++ that
+provide support for writing .NET components, by adding extra
+keywords and syntax.
 Only available on backends that compile to IL.
-Requires an IL assembler installed.
-To use it pass mmc @samp{--use-foreign-language il} and
- at samp{--backend-foreign-language il}.
+This is the third preferred foreign language for IL code generation.
+
 
 @end table
 

--------------------------------------------------------------------------
mercury-reviews mailing list
post:  mercury-reviews at cs.mu.oz.au
administrative address: owner-mercury-reviews at cs.mu.oz.au
unsubscribe: Address: mercury-reviews-request at cs.mu.oz.au Message: unsubscribe
subscribe:   Address: mercury-reviews-request at cs.mu.oz.au Message: subscribe
--------------------------------------------------------------------------



More information about the reviews mailing list