[m-rev.] for review: pragma foreign_import_module on the IL backend

Peter Ross pro at missioncriticalit.com
Wed Dec 11 01:24:54 AEDT 2002


Hi,


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


Estimated hours taken: 8
Branches: main

Get pragma foreign_import_module working on the IL backend.

compiler/foreign.m:
	Add two utility predicates which are used to get the module
	name a foreign_module_import refers to.

compiler/ml_code_gen.m:
	The wanted foreign imports are the imports for every backend
	language.  This is because, for example, managed C++ can refer
	to something defined in IL.

compiler/mlds_to_managed.m:
	For managed C++ output a #using for every module implied by the
	pragma foreign_import_module.
	
compiler/modules.m:
	Factor the code for outputting the dependencies implied by the
	pragma foreign_import_modules so that they work for both the
	IL and C backend.
	For C# add a reference to every module implied by the pragma
	foreign_import_module.

compiler/modules.m:
compiler/prog_io_pragma.m:
	Remove constraints the pragma foreign_import_modules can only
	work on the C backend.

tests/hard_coded/foreign_import_module.exp:
tests/hard_coded/foreign_import_module.m:
tests/hard_coded/foreign_import_module_2.m:
	Adapt the test case so that we test that C# and MC++ code all
	correctly have the correct assembly references passed to them.

Index: compiler/foreign.m
===================================================================
RCS file: /home/mercury1/repository/mercury/compiler/foreign.m,v
retrieving revision 1.22
diff -u -r1.22 foreign.m
--- compiler/foreign.m	5 Aug 2002 21:46:09 -0000	1.22
+++ compiler/foreign.m	10 Dec 2002 13:54:01 -0000
@@ -89,6 +89,26 @@
 :- func foreign__to_type_string(foreign_language, exported_type) = string.
 :- func foreign__to_type_string(foreign_language, module_info, (type)) = string.
 
+	%
+	% foreign__module_name(ForeignImport)
+	%
+	% returns the module name which represents the ForeignImport.
+	%
+	% For instance for the foreign_import_module representing
+	% 	:- foreign_import_module("MC++", module)
+	% would return the module_name
+	% 	unqualified("module__cpp_code")
+	%
+:- func foreign__module_name(foreign_import_module) = module_name.
+
+	% foreign__module_name(ForeignImport, CurrentModule)
+	%
+	% returns the module name needed to refer to ForeignImport from the
+	% CurrentModule.
+	%
+:- func foreign__module_name(foreign_import_module, module_name) =
+		module_name.
+
 	% Filter the decls for the given foreign language. 
 	% The first return value is the list of matches, the second is
 	% the list of mis-matches.
@@ -201,6 +221,7 @@
 :- import_module check_hlds__mode_util, hlds__error_util.
 :- import_module hlds__hlds_data, parse_tree__prog_out.
 :- import_module backend_libs__code_model, libs__globals.
+:- import_module parse_tree__modules.
 
 	% Currently we don't use the globals to compare foreign language
 	% interfaces, but if we added appropriate options we might want
@@ -685,6 +706,53 @@
 	).
 to_type_string(il, mercury(_Type)) = _ :-
 	sorry(this_file, "to_type_string for il").
+
+%-----------------------------------------------------------------------------%
+
+foreign__module_name(foreign_import_module(Lang, ForeignImportModule, _)) =
+		ModuleName :-
+	( Lang = c,
+		ModuleName = ForeignImportModule
+	; Lang = il,
+		ModuleName = ForeignImportModule
+	; Lang = managed_cplusplus,
+		ModuleName = foreign_language_module_name(ForeignImportModule,
+				Lang)
+	; Lang = csharp,
+		ModuleName = foreign_language_module_name(ForeignImportModule,
+				Lang)
+	).
+
+foreign__module_name(ForeignImportModule, CurrentModule) =
+		ModuleName :-
+	ForeignImportModule = foreign_import_module(Lang, _, _),
+	ModuleName1 = ForeignImportModule ^ foreign__module_name,
+	( Lang = c,
+		ModuleName = ModuleName1
+	; Lang = il,
+		ModuleName = handle_std_library(CurrentModule, ModuleName1)
+	; Lang = managed_cplusplus,
+		ModuleName = handle_std_library(CurrentModule, ModuleName1)
+	; Lang = csharp,
+		ModuleName = handle_std_library(CurrentModule, ModuleName1)
+	).
+
+	%
+	% On the il backend, we need to refer to the module "mercury" when
+	% referencing a std library module when we are not actually building
+	% the std library.
+	%
+:- func handle_std_library(module_name, module_name) = module_name.
+
+handle_std_library(CurrentModule, ModuleName0) = ModuleName :-
+	(
+		mercury_std_library_module_name(ModuleName0),
+		\+ mercury_std_library_module_name(CurrentModule)
+	->
+		ModuleName = unqualified("mercury")
+	;
+		ModuleName = ModuleName0
+	).
 
 %-----------------------------------------------------------------------------%
 
Index: compiler/ml_code_gen.m
===================================================================
RCS file: /home/mercury1/repository/mercury/compiler/ml_code_gen.m,v
retrieving revision 1.121
diff -u -r1.121 ml_code_gen.m
--- compiler/ml_code_gen.m	14 Jul 2002 04:08:26 -0000	1.121
+++ compiler/ml_code_gen.m	10 Dec 2002 13:54:02 -0000
@@ -817,14 +817,16 @@
 	{ module_info_get_foreign_import_module(ModuleInfo, ForeignImports) },
 	{ module_info_get_foreign_body_code(ModuleInfo, ForeignBodys) },
 	globals__io_get_backend_foreign_languages(BackendForeignLanguages),
-	
+
+	{ WantedForeignImports = list__condense(
+		list__map((func(L) = Imports :-
+			foreign__filter_imports(L, ForeignImports, Imports, _)
+		), BackendForeignLanguages)) },
+
 	{ list__foldl((pred(Lang::in, Map0::in, Map::out) is det :-
 			foreign__filter_decls(Lang,
 				ForeignDecls, WantedForeignDecls, 
 				_OtherForeignDecls),
-			foreign__filter_imports(Lang,
-				ForeignImports, WantedForeignImports, 
-				_OtherForeignImports),
 			foreign__filter_bodys(Lang,
 				ForeignBodys, WantedForeignBodys,
 				_OtherForeignBodys),
Index: compiler/mlds_to_managed.m
===================================================================
RCS file: /home/mercury1/repository/mercury/compiler/mlds_to_managed.m,v
retrieving revision 1.5
diff -u -r1.5 mlds_to_managed.m
--- compiler/mlds_to_managed.m	28 Nov 2002 13:05:20 -0000	1.5
+++ compiler/mlds_to_managed.m	10 Dec 2002 13:54:03 -0000
@@ -89,7 +89,6 @@
 :- mode generate_code(in(managed_lang), in, di, uo) is det.
 
 generate_code(Lang, MLDS) -->
-
 	{ MLDS = mlds(ModuleName, AllForeignCode, Imports, Defns) },
 	{ ClassName = class_name(mercury_module_name_to_mlds(ModuleName), 
 			wrapper_class_name) },
@@ -102,8 +101,7 @@
 
 		% Get the foreign code for the required language.
 	{ ForeignCode = map__lookup(AllForeignCode, Lang) },
-	generate_foreign_header_code(Lang,
-			mercury_module_name_to_mlds(ModuleName), ForeignCode),
+	generate_foreign_header_code(Lang, ModuleName, ForeignCode),
 
 		% Output the namespace.
 	{ generate_namespace_details(Lang, ClassName,
@@ -239,14 +237,32 @@
 	).
 
 
-	% XXX we don't handle `:- pragma foreign_import_module'.
 :- pred generate_foreign_header_code(foreign_language::in(managed_lang),
-		mlds_module_name::in, mlds__foreign_code::in,
+		module_name::in, mlds__foreign_code::in,
 		io__state::di, io__state::uo) is det.
 
-generate_foreign_header_code(Lang, _ModuleName, 
-		mlds__foreign_code(RevHeaderCode, _RevImports, _RevBodyCode,
+generate_foreign_header_code(Lang, ModuleName, 
+		mlds__foreign_code(RevHeaderCode, RevImports, _RevBodyCode,
 			_ExportDefns)) -->
+
+	% Only MC++ can declare which assemblies it refers to in its
+	% source file.  C# declares which assemblies it refers to via
+	% command line arguments to the C# compiler.
+	( { Lang = managed_cplusplus },
+		{ Imports = list__reverse(RevImports) },
+		list__foldl(
+			(pred(ForeignImport::in, di, uo) is det -->
+				module_name_to_search_file_name(
+					foreign__module_name(ForeignImport,
+								ModuleName),
+						".dll", FileName),
+				io__write_strings(["#using """,
+						FileName, """\n"])
+			), Imports)
+	; { Lang = csharp },
+		[]
+	),
+
 	{ HeaderCode = list__reverse(RevHeaderCode) },
 	io__write_list(HeaderCode, "\n", 
 		(pred(foreign_decl_code(CodeLang, Code, Context)::in,
@@ -282,7 +298,6 @@
 		Namespace = Namespace0
 	).
 
-	% XXX we don't handle `:- pragma foreign_import_module'.
 :- pred generate_foreign_code(foreign_language::in(managed_lang),
 		mlds_module_name::in, mlds__foreign_code::in,
 		io__state::di, io__state::uo) is det.
Index: compiler/modules.m
===================================================================
RCS file: /home/mercury1/repository/mercury/compiler/modules.m,v
retrieving revision 1.255
diff -u -r1.255 modules.m
--- compiler/modules.m	10 Dec 2002 07:38:09 -0000	1.255
+++ compiler/modules.m	10 Dec 2002 13:54:13 -0000
@@ -2574,10 +2574,9 @@
 		    % of it sub-modules dlls, as they are referenced from
 		    % inside the top level dll.
 
+		module_name_to_file_name(ModuleName, ".dll", no, DllFileName),
 		{ SubModules = submodules(ModuleName, AllDeps) },
 		( { Target = il, SubModules \= [] } ->
-			module_name_to_file_name(ModuleName, ".dll", no,
-					DllFileName),
 			io__write_strings(DepStream, [DllFileName, " : "]),
 			write_dll_dependencies_list(SubModules, "", DepStream),
 			io__nl(DepStream)
@@ -2599,19 +2598,31 @@
 		% Handle dependencies introduced by
 		% `:- pragma foreign_import_module' declarations.
 		%
-		{ ForeignImportedModules =
-		    list__map(
-			(func(foreign_import_module(_, ForeignImportModule, _))
-				= ForeignImportModule),
-			ForeignImports) },
-		( { ForeignImports = [] } ->
+		{ list__filter_map(
+			(pred(ForeignImportMod::in, Import::out) is semidet :-
+				Import = foreign__module_name(
+						ForeignImportMod,
+						SourceFileModuleName),
+
+				% We can't include mercury.dll as mmake
+				% can't find it, but we know that it exists.
+				Import \= unqualified("mercury")
+			), ForeignImports, ForeignImportedModules) },
+		( { ForeignImportedModules = [] } ->
 			[]
 		;
+			{ Target = il ->
+				ForeignImportTarget = DllFileName,
+				ForeignImportExt = ".dll"
+			;
+				ForeignImportTarget = ObjFileName,
+				ForeignImportExt = ".mh"
+			},
 			io__write_string(DepStream, "\n\n"),
-			io__write_string(DepStream, ObjFileName),
+			io__write_string(DepStream, ForeignImportTarget),
 			io__write_string(DepStream, " : "),
-			write_dependencies_list(ForeignImportedModules, ".mh",
-				DepStream),
+			write_dependencies_list(ForeignImportedModules,
+					ForeignImportExt, DepStream),
 			io__write_string(DepStream, "\n\n")
 		),
 
@@ -2621,7 +2632,7 @@
 		->
 			{ Langs = set__to_sorted_list(LangSet) },
 			list__foldl(write_foreign_dependency_for_il(DepStream,
-				ModuleName, AllDeps), Langs)
+				ModuleName, AllDeps, ForeignImports), Langs)
 		;
 			[]
 		),
@@ -2833,10 +2844,10 @@
 	% scripts/Mmake.rules).
 	% 
 :- pred write_foreign_dependency_for_il(io__output_stream::in,sym_name::in,
-		list(module_name)::in, foreign_language::in,
-		io__state::di, io__state::uo) is det.
-write_foreign_dependency_for_il(DepStream, ModuleName, AllDeps, ForeignLang)
-		-->
+		list(module_name)::in, foreign_import_module_info::in,
+		foreign_language::in, io__state::di, io__state::uo) is det.
+write_foreign_dependency_for_il(DepStream, ModuleName, AllDeps,
+		ForeignImports, ForeignLang) -->
 	( 
 		{ ForeignModuleName = foreign_language_module_name(
 			ModuleName, ForeignLang) },
@@ -2880,8 +2891,13 @@
 			;
 				Prefix = "/r:"
 			},
+			{ ForeignDeps = list__map(
+				(func(M) =
+					foreign__module_name(M, ModuleName)
+				), ForeignImports) },
+			{ Deps = AllDeps ++ ForeignDeps },
 			write_dll_dependencies_list(
-				referenced_dlls(ModuleName, AllDeps),
+				referenced_dlls(ModuleName, Deps),
 				Prefix, DepStream),
 			io__nl(DepStream)
 		;
@@ -4851,11 +4867,8 @@
 		Info = Info1 ^ module_contains_foreign_export :=
 				contains_foreign_export
 	;
-		% XXX handle lang \= c for
-		% `:- pragma foreign_import_module'.
 		Pragma = foreign_import_module(Lang, Import),
-		Lang = c,
-		list__member(c, BackendLangs)
+		list__member(Lang, BackendLangs)
 	->
 		Info = Info0 ^ all_foreign_import_module_info :=
 	    		[foreign_import_module(Lang, Import, Context) | 	
Index: compiler/prog_io_pragma.m
===================================================================
RCS file: /home/mercury1/repository/mercury/compiler/prog_io_pragma.m,v
retrieving revision 1.52
diff -u -r1.52 prog_io_pragma.m
--- compiler/prog_io_pragma.m	26 Jul 2002 04:18:28 -0000	1.52
+++ compiler/prog_io_pragma.m	10 Dec 2002 13:54:14 -0000
@@ -179,12 +179,8 @@
 	    sym_name_and_args(ImportTerm, Import, [])
 	->
 	    ( parse_foreign_language(LangTerm, Language) ->
-		( Language = c ->
-		    Result = ok(pragma(
-		    	foreign_import_module(Language, Import)))
-		;
-		    Result = error("`:- pragma foreign_import_module' not yet supported for languages other than C", LangTerm)
-		)
+	    	Result = ok(pragma(
+			foreign_import_module(Language, Import)))
 	    ;
 		Result = error("invalid foreign language in `:- pragma foreign_import_module' declaration",
 			LangTerm)
Index: tests/hard_coded/foreign_import_module.exp
===================================================================
RCS file: /home/mercury1/repository/tests/hard_coded/foreign_import_module.exp,v
retrieving revision 1.1
diff -u -r1.1 foreign_import_module.exp
--- tests/hard_coded/foreign_import_module.exp	6 Nov 2001 15:21:26 -0000	1.1
+++ tests/hard_coded/foreign_import_module.exp	10 Dec 2002 13:54:14 -0000
@@ -1 +1,2 @@
 42
+42
Index: tests/hard_coded/foreign_import_module.m
===================================================================
RCS file: /home/mercury1/repository/tests/hard_coded/foreign_import_module.m,v
retrieving revision 1.2
diff -u -r1.2 foreign_import_module.m
--- tests/hard_coded/foreign_import_module.m	28 Nov 2002 16:33:44 -0000	1.2
+++ tests/hard_coded/foreign_import_module.m	10 Dec 2002 13:54:14 -0000
@@ -13,15 +13,50 @@
 main -->
 	{ bar(41, X) },
 	io__write(X),
-	io__write_char('\n').
+	io__nl,
 
-:- pragma foreign_import_module("C", foreign_import_module_2).
+	{ bar2(41, Y) },
+	io__write(Y),
+	io__nl.
+
+:- pragma foreign_import_module(c, foreign_import_module_2).
+:- pragma foreign_import_module(il, foreign_import_module_2).
+:- pragma foreign_import_module("MC++", foreign_import_module_2).
 
 :- pragma c_code(bar(X::in, Y::out), may_call_mercury,
 "
 	foo(X, &Y);
 ").
-:- pragma foreign_proc("C#", bar(X::in, Y::out),
+:- pragma foreign_proc("MC++", bar(X::in, Y::out),
 		[may_call_mercury, promise_pure], "
-	foreign_import_module_2.mercury_code.foo(X, ref Y);
+	MR_Integer Y1, Y2;
+
+	foreign_import_module_2::mercury_code::foo(X, &Y1);
+	foreign_import_module_2__cpp_code::mercury_code::foo2(X, &Y2);
+
+	if (Y1 == Y2) {
+		Y = Y1;
+	} else {
+		throw new System::Exception(""Y1 != Y2"");
+	}
+").
+
+:- pred bar2(int::in, int::out) is det.
+:- pragma c_code(bar2(X::in, Y::out), may_call_mercury,
+"
+	foo(X, &Y);
+").
+:- pragma foreign_proc("C#", bar2(X::in, Y::out),
+		[may_call_mercury, promise_pure], "
+	int Y1 = 0, Y2 = 0;
+
+	foreign_import_module_2.mercury_code.foo(X, ref Y1);
+	foreign_import_module_2__cpp_code.mercury_code.foo2(X, ref Y2);
+
+	if (Y1 == Y2) {
+		Y = Y1;
+	} else {
+		throw new System.Exception(""Y1 != Y2"");
+	}
 ").
Index: tests/hard_coded/foreign_import_module_2.m
===================================================================
RCS file: /home/mercury1/repository/tests/hard_coded/foreign_import_module_2.m,v
retrieving revision 1.1
diff -u -r1.1 foreign_import_module_2.m
--- tests/hard_coded/foreign_import_module_2.m	6 Nov 2001 15:21:27 -0000	1.1
+++ tests/hard_coded/foreign_import_module_2.m	10 Dec 2002 13:54:14 -0000
@@ -11,3 +11,10 @@
 :- pragma export(foo(in, out), "foo").
 
 foo(X, X+1).
+
+:- pragma foreign_code("MC++", "
+	static void foo2(MR_Integer X, MR_Ref(MR_Integer) Y)
+	{
+		*Y = X + 1;
+	}
+").

--------------------------------------------------------------------------
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