diff: nested modules: allow split int/impl

Fergus Henderson fjh at cs.mu.OZ.AU
Sun Jul 26 05:46:34 AEST 1998


Estimated hours taken: 4

Implement some parts of the support for nested modules that I had
forgotten about.

compiler/modules.m:
	Allow the `:- interface' and `:- implementation' parts of
	nested modules to be separated.
	Check that `:- implementation' declarations for nested
	modules don't occur in the interface section of the parent module.

tests/hard_coded/nested3.m:
tests/hard_coded/nested3.exp:
tests/invalid/nested_impl_in_int.m:
tests/invalid/nested_impl_in_int.err_exp:
	Test cases for the above-mentioned feature.

tests/hard_coded/Mmakefile:
	Add `RM_C=:', so that the nested modules tests work with
	parallel makes, and then enable those tests.

Index: compiler/modules.m
===================================================================
RCS file: /home/mercury1/repository/mercury/compiler/modules.m,v
retrieving revision 1.82
diff -u -r1.82 modules.m
--- modules.m	1998/07/09 22:03:09	1.82
+++ modules.m	1998/07/25 19:38:52
@@ -280,10 +280,14 @@
 
 	% Given a module (well, a list of items), split it into
 	% its constituent sub-modules, in top-down order.
+	% Report an error if the `implementation' section of a sub-module
+	% is contained inside the `interface' section of its parent module.
 
-:- pred split_into_submodules(module_name, item_list,
-				list(pair(module_name, item_list))).
-:- mode split_into_submodules(in, in, out) is det.
+:- type module_list == list(pair(module_name, item_list)).
+
+:- pred split_into_submodules(module_name, item_list, module_list,
+					io__state, io__state).
+:- mode split_into_submodules(in, in, out, di, uo) is det.
 
 %-----------------------------------------------------------------------------%
 
@@ -1775,7 +1779,7 @@
 	read_mod_from_file(FileName, ".m", "Reading file", no,
 		Items, Error, ModuleName),
 	{ string__append(FileName, ".m", SourceFileName) },
-	{ split_into_submodules(ModuleName, Items, SubModuleList) },
+	split_into_submodules(ModuleName, Items, SubModuleList),
 	{ list__map(init_dependencies(SourceFileName, Error), SubModuleList,
 		ModuleImportsList) },
 	{ map__init(DepsMap0) },
@@ -2749,7 +2753,7 @@
 	;
 		{ FileName = FileName0 },
 		{ Items = Items0 },
-		{ split_into_submodules(ModuleName, Items, SubModuleList) }
+		split_into_submodules(ModuleName, Items, SubModuleList)
 	),
 	{ list__map(init_dependencies(FileName, Error), SubModuleList,
 		ModuleImportsList) }.
@@ -3322,79 +3326,172 @@
 
 %-----------------------------------------------------------------------------%
 
+:- type submodule_map == map(module_name, item_list).
+
 	% Given a module (well, a list of items), split it into
 	% its constituent sub-modules, in top-down order.
+split_into_submodules(ModuleName, Items0, ModuleList) -->
+	{ InParentInterface = no },
+	split_into_submodules_2(ModuleName, Items0, InParentInterface,
+		Items, ModuleList),
+	{ require(unify(Items, []), "modules.m: items after end_module") }.
+
+:- pred split_into_submodules_2(module_name, item_list, bool, item_list,
+				module_list, io__state, io__state).
+:- mode split_into_submodules_2(in, in, in, out, out, di, uo) is det.
+
+split_into_submodules_2(ModuleName, Items0, InParentInterface,
+		Items, ModuleList) -->
+	{ InInterface0 = no },
+	split_into_submodules_3(ModuleName, Items0,
+		InParentInterface, InInterface0,
+		ThisModuleItems, Items, SubModules),
+	{ map__to_assoc_list(SubModules, SubModuleList) },
+	{ ModuleList = [ModuleName - ThisModuleItems | SubModuleList] }.
 
-split_into_submodules(ModuleName, Items0, ModuleList) :-
-	split_into_submodules_2(ModuleName, Items0, Items, ModuleList),
-	require(unify(Items, []), "modules.m: items after end_module").
-
-:- pred split_into_submodules_2(module_name, item_list, item_list,
-				list(pair(module_name, item_list))).
-:- mode split_into_submodules_2(in, in, out, out) is det.
-
-split_into_submodules_2(ModuleName, Items0, Items, ModuleList) :-
-	split_into_submodules_3(ModuleName, Items0, ThisModuleItems,
-		Items, SubModuleList),
-	ModuleList = [ModuleName - ThisModuleItems | SubModuleList].
-
-:- pred split_into_submodules_3(module_name, item_list, item_list, item_list,
-				list(pair(module_name, item_list))).
-:- mode split_into_submodules_3(in, in, out, out, out) is det.
+:- pred split_into_submodules_3(module_name, item_list, bool, bool,
+			item_list, item_list, map(module_name, item_list),
+			io__state, io__state).
+:- mode split_into_submodules_3(in, in, in, in, out, out, out, di, uo) is det.
 
-split_into_submodules_3(_ModuleName, [], [], [], []).
+split_into_submodules_3(_ModuleName, [], _, _, [], [], SubModules) -->
+	{ map__init(SubModules) }.
 split_into_submodules_3(ModuleName, [Item | Items1],
-		ThisModuleItems, OtherItems, SubModules) :-
+		InParentInterface, InInterface0, 
+		ThisModuleItems, OtherItems, SubModules) -->
 	(
 		%
 		% check for a `module' declaration, which signals
 		% the start of a nested module
 		%
-		Item = module_defn(VarSet, module(SubModuleName)) - Context
+		{ Item = module_defn(VarSet, module(SubModuleName)) - Context }
 	->
 		%
 		% parse in the items for the nested submodule
 		%
-		split_into_submodules_2(SubModuleName, Items1,
+		split_into_submodules_2(SubModuleName, Items1, InInterface0,
 			Items2, SubModules0),
 		%
 		% parse in the remaining items for this module
 		%
-		split_into_submodules_3(ModuleName, Items2,
-			ThisModuleItems0, Items3, SubModules1),
+		split_into_submodules_3(ModuleName, Items2, InParentInterface,
+			InInterface0, ThisModuleItems0, Items3, SubModules1),
+
+		%
+		% combine the sub-module declarations from the prevous two
+		% steps
+		%
+		{ list__foldl(add_submodule, SubModules0, SubModules1,
+			SubModules) },
 		%
 		% replace the nested submodule with an `include_module'
 		% declaration
 		%
-		IncludeSubMod = module_defn(VarSet,
-			include_module([SubModuleName])) - Context,
-		ThisModuleItems = [IncludeSubMod | ThisModuleItems0],
-		OtherItems = Items3,
-		list__append(SubModules0, SubModules1, SubModules)
+		{ IncludeSubMod = module_defn(VarSet,
+			include_module([SubModuleName])) - Context },
+		{ ThisModuleItems = [IncludeSubMod | ThisModuleItems0] },
+		{ OtherItems = Items3 }
 	;
 		%
 		% check for a matching `end_module' declaration
 		%
-		Item = module_defn(_VarSet, end_module(ModuleName)) - _Context
+		{ Item = module_defn(_VarSet, end_module(ModuleName)) - _ }
 	->
 		%
 		% if so, thats the end of this module
 		%
-		ThisModuleItems = [],
-		OtherItems = Items1,
-		SubModules = []
+		{ ThisModuleItems = [] },
+		{ OtherItems = Items1 },
+		{ map__init(SubModules) }
 	;
 		%
-		% otherwise just parse the remaining items for this
-		% module and then put the current item back onto the
-		% front of the item list for this module
+		% otherwise, process the next item in this module
+		%
+
+		%
+		% update the flag which records whether
+		% we're currently in the interface section,
+		% and report an error if there is an `implementation'
+		% section inside an `interface' section.
+		%
+		(
+			{ Item = module_defn(_, interface) - _Context }
+		->
+			{ InInterface1 = yes }
+		;
+			{ Item = module_defn(_, implementation) - Context }
+		->
+			( { InParentInterface = yes } ->
+				report_error_implementation_in_interface(
+					ModuleName, Context)
+			;
+				[]
+			),
+			{ InInterface1 = no }
+		;
+			{ InInterface1 = InInterface0 }
+		),
+		%
+		% parse the remaining items for this module,
 		%
 		split_into_submodules_3(ModuleName, Items1,
+			InParentInterface, InInterface1,
 			ThisModuleItems0, Items2, SubModules),
-		ThisModuleItems = [Item | ThisModuleItems0],
-		OtherItems = Items2
+		%
+		% put the current item back onto the
+		% front of the item list for this module
+		%
+		{ ThisModuleItems = [Item | ThisModuleItems0] },
+		{ OtherItems = Items2 }
 	).
-			
+
+:- pred add_submodule(pair(module_name, item_list),
+			submodule_map, submodule_map).
+:- mode add_submodule(in, in, out) is det.
+
+add_submodule(ModuleName - ModuleItemList, SubModules0, SubModules) :-
+	%
+	% If the same module name occurs twice, then just append
+	% the lists of items together.
+	% Perhaps we should be a bit more strict about this, for
+	% example by only allowing one `:- implementation' section
+	% and one `:- interface' section for each module?
+	%
+	( map__search(SubModules0, ModuleName, ItemList0) ->
+		list__append(ModuleItemList, ItemList0, ItemList),
+		map__det_update(SubModules0, ModuleName, ItemList, SubModules)
+	;
+		map__det_insert(SubModules0, ModuleName, ModuleItemList,
+								SubModules)
+	).
+
+:- pred report_error_implementation_in_interface(module_name, term__context,
+		io__state, io__state).
+:- mode report_error_implementation_in_interface(in, in, di, uo) is det.
+
+report_error_implementation_in_interface(ModuleName, Context) -->
+	{ ModuleName = qualified(ParentModule0, ChildModule0) ->
+		ParentModule = ParentModule0,
+		ChildModule = ChildModule0
+	;
+		error("report_error_implementation_in_interface")
+	},
+	prog_out__write_context(Context),
+	io__write_string("In interface for module `"),
+	prog_out__write_sym_name(ParentModule),
+	io__write_string("':\n"),
+	prog_out__write_context(Context),
+	io__write_string("  in definition of sub-module `"),
+	io__write_string(ChildModule),
+	io__write_string("':\n"),
+	prog_out__write_context(Context),
+	io__write_string(
+		"  error: `:- implementation.' declaration for sub-module\n"),
+	prog_out__write_context(Context),
+	io__write_string(
+		"  occurs in interface section of parent module.\n"),
+	io__set_exit_status(1).
+
 	% Given a module (well, a list of items), extract the interface
 	% part of that module, i.e. all the items between `:- interface'
 	% and `:- implementation'. If IncludeImported is yes, also
@@ -3519,5 +3616,11 @@
 			type_defn(VarSet, abstract_type(Name, Args), Cond)).
 make_abstract_type_defn(type_defn(VarSet, abstract_type(Name, Args), Cond),
 			type_defn(VarSet, abstract_type(Name, Args), Cond)).
+
+	% Given a module (well, a list of items), extract the interface
+	% part of that module, i.e. all the items between `:- interface'
+	% and `:- implementation'. If IncludeImported is yes, also
+	% include all items after a `:- imported'. This is useful for
+	% making the .int file.
 
 %-----------------------------------------------------------------------------%
Index: tests/hard_coded/Mmakefile
===================================================================
RCS file: /home/mercury1/repository/tests/hard_coded/Mmakefile,v
retrieving revision 1.35
diff -u -r1.35 Mmakefile
--- Mmakefile	1998/07/20 10:03:58	1.35
+++ Mmakefile	1998/07/25 19:08:28
@@ -51,6 +51,9 @@
 	minint_bug \
 	mode_choice \
 	name_mangling \
+	nested \
+	nested2 \
+	nested3 \
 	no_fully_strict \
 	no_inline \
 	nullary_ho_func \
@@ -83,7 +86,11 @@
 # Not working:
 # 	cycles - loops when compiled in a non-GC grade with --deforestation.
 # 	cycles2 - loops when compiled in a non-GC grade.
-#	nested, nested2 - sometimes fail if using parallel makes
+
+# The following is required to make the test cases
+#	nested, nested2, and nested3
+# work reliabily with parallel makes -- without this they occaisionally fail.
+RM_C = :
 
 #-----------------------------------------------------------------------------#
 
Index: tests/hard_coded/nested3.exp
===================================================================
RCS file: nested3.exp
diff -N nested3.exp
--- /dev/null	Sun Jul 26 05:45:11 1998
+++ nested3.exp	Sun Jul 26 05:10:13 1998
@@ -0,0 +1,14 @@
+nested3:child:hello
+nested3:child:hello
+nested3:child:hello
+nested3:child2:hello
+t1 = nested3:child:foo
+t2 = nested3:child:foo
+t3 = nested3:child:foo
+t4 = nested3:child2:foo
+t5 = nested3:child2:foo
+has_type_t1 = bar
+has_type_t2 = bar
+has_type_t3 = bar
+has_type_t4 = bar
+has_type_t5 = bar
Index: tests/hard_coded/nested3.m
===================================================================
RCS file: nested3.m
diff -N nested3.m
--- /dev/null	Sun Jul 26 05:45:11 1998
+++ nested3.m	Sun Jul 26 05:06:15 1998
@@ -0,0 +1,100 @@
+% "Hello World" in Mercury, using nested modules.
+
+:- module nested3.
+:- interface.
+:- import_module io.
+
+:- pred main(io__state::di, io__state::uo) is det.
+
+    :- module nested3:child.
+    :- interface.
+	:- import_module io.
+
+	:- type foo ---> bar ; baz(int).
+
+	:- pred hello(io__state::di, io__state::uo) is det.
+
+    :- end_module nested3:child.
+
+:- implementation.
+
+%-----------------------------------------------------------------------------%
+
+    :- module nested3:child2.
+    :- interface.
+        :- import_module io.
+
+        :- type foo ---> bar ; baz(int).
+
+        :- pred hello(io__state::di, io__state::uo) is det.
+    :- end_module nested3:child2.
+
+%-----------------------------------------------------------------------------%
+
+    :- module nested3:child.
+    :- implementation.
+
+        hello --> io__write_string("nested3:child:hello\n").
+
+    :- end_module nested3:child.
+
+    :- module nested3:child2.
+    :- implementation.
+
+        hello --> io__write_string("nested3:child2:hello\n").
+
+    :- end_module nested3:child2.
+
+%-----------------------------------------------------------------------------%
+
+% now we're back in the parent module.
+
+:- import_module nested3:child.
+:- use_module nested3:child2.
+:- import_module std_util, require.
+
+:- type t1 == nested3:child:foo.
+:- type t2 == child:foo.
+:- type t3 == foo.
+:- type t4 == nested3:child2:foo.
+% :- type t5 == child2:foo.	% XXX mixing of use_module and import_module
+				% is not yet supported.
+:- type t5 == nested3:child2:foo.
+
+main -->
+	nested3:child:hello,
+	child:hello,
+	hello,
+	nested3:child2:hello,
+	% child2:hello,		% XXX mixing of use_module and import_module
+				% is not yet supported.
+
+	print("t1 = "), print(type_of(has_type_t1)), nl,
+	print("t2 = "), print(type_of(has_type_t2)), nl,
+	print("t3 = "), print(type_of(has_type_t3)), nl,
+	print("t4 = "), print(type_of(has_type_t4)), nl,
+	print("t5 = "), print(type_of(has_type_t5)), nl,
+
+	print("has_type_t1 = "), print(has_type_t1), nl,
+	print("has_type_t2 = "), print(has_type_t2), nl,
+	print("has_type_t3 = "), print(has_type_t3), nl,
+	print("has_type_t4 = "), print(has_type_t4), nl,
+	print("has_type_t5 = "), print(has_type_t5), nl,
+
+	{ true }.
+
+:- func has_type_t1 = t1.
+:- func has_type_t2 = t2.
+:- func has_type_t3 = t3.
+:- func has_type_t4 = t4.
+:- func has_type_t5 = t5.
+
+has_type_t1 = nested3:child:bar.
+has_type_t2 = child:bar.
+has_type_t3 = bar.
+has_type_t4 = nested3:child2:bar.
+% has_type_t5 = child2:bar.  % XXX mixing of use_module and import_module
+			     % is not yet supported.
+has_type_t5 = nested3:child2:bar.
+
+:- end_module nested3.
Index: tests/invalid/nested_impl_in_int.err_exp
===================================================================
RCS file: nested_impl_in_int.err_exp
diff -N nested_impl_in_int.err_exp
--- /dev/null	Sun Jul 26 05:45:11 1998
+++ nested_impl_in_int.err_exp	Sun Jul 26 05:43:22 1998
@@ -0,0 +1,9 @@
+nested_impl_in_int.m:020: In interface for module `nested_impl_in_int':
+nested_impl_in_int.m:020:   in definition of sub-module `child':
+nested_impl_in_int.m:020:   error: `:- implementation.' declaration for sub-module
+nested_impl_in_int.m:020:   occurs in interface section of parent module.
+nested_impl_in_int.m:037: In interface for module `nested_impl_in_int':
+nested_impl_in_int.m:037:   in definition of sub-module `child2':
+nested_impl_in_int.m:037:   error: `:- implementation.' declaration for sub-module
+nested_impl_in_int.m:037:   occurs in interface section of parent module.
+For more information, try recompiling with `-E'.
Index: tests/invalid/nested_impl_in_int.m
===================================================================
RCS file: nested_impl_in_int.m
diff -N nested_impl_in_int.m
--- /dev/null	Sun Jul 26 05:45:11 1998
+++ nested_impl_in_int.m	Sun Jul 26 05:25:09 1998
@@ -0,0 +1,97 @@
+% "Hello World" in Mercury, using nested modules.
+
+:- module nested_impl_in_int.
+:- interface.
+:- import_module io.
+
+:- pred main(io__state::di, io__state::uo) is det.
+
+    :- module nested_impl_in_int:child.
+    :- interface.
+	:- import_module io.
+
+	:- type foo ---> bar ; baz(int).
+
+	:- pred hello(io__state::di, io__state::uo) is det.
+
+    :- end_module nested_impl_in_int:child.
+
+    :- module nested_impl_in_int:child.
+    :- implementation.
+
+        hello --> io__write_string("nested_impl_in_int:child:hello\n").
+
+    :- end_module nested_impl_in_int:child.
+
+
+%-----------------------------------------------------------------------------%
+
+    :- module nested_impl_in_int:child2.
+    :- interface.
+        :- import_module io.
+
+        :- type foo ---> bar ; baz(int).
+
+        :- pred hello(io__state::di, io__state::uo) is det.
+
+    :- implementation.
+
+        hello --> io__write_string("nested_impl_in_int:child2:hello\n").
+
+    :- end_module nested_impl_in_int:child2.
+
+:- implementation.
+
+%-----------------------------------------------------------------------------%
+
+% now we're back in the parent module.
+
+:- import_module nested_impl_in_int:child.
+:- use_module nested_impl_in_int:child2.
+:- import_module std_util, require.
+
+:- type t1 == nested_impl_in_int:child:foo.
+:- type t2 == child:foo.
+:- type t3 == foo.
+:- type t4 == nested_impl_in_int:child2:foo.
+% :- type t5 == child2:foo.	% XXX mixing of use_module and import_module
+				% is not yet supported.
+:- type t5 == nested_impl_in_int:child2:foo.
+
+main -->
+	nested_impl_in_int:child:hello,
+	child:hello,
+	hello,
+	nested_impl_in_int:child2:hello,
+	% child2:hello,		% XXX mixing of use_module and import_module
+				% is not yet supported.
+
+	print("t1 = "), print(type_of(has_type_t1)), nl,
+	print("t2 = "), print(type_of(has_type_t2)), nl,
+	print("t3 = "), print(type_of(has_type_t3)), nl,
+	print("t4 = "), print(type_of(has_type_t4)), nl,
+	print("t5 = "), print(type_of(has_type_t5)), nl,
+
+	print("has_type_t1 = "), print(has_type_t1), nl,
+	print("has_type_t2 = "), print(has_type_t2), nl,
+	print("has_type_t3 = "), print(has_type_t3), nl,
+	print("has_type_t4 = "), print(has_type_t4), nl,
+	print("has_type_t5 = "), print(has_type_t5), nl,
+
+	{ true }.
+
+:- func has_type_t1 = t1.
+:- func has_type_t2 = t2.
+:- func has_type_t3 = t3.
+:- func has_type_t4 = t4.
+:- func has_type_t5 = t5.
+
+has_type_t1 = nested_impl_in_int:child:bar.
+has_type_t2 = child:bar.
+has_type_t3 = bar.
+has_type_t4 = nested_impl_in_int:child2:bar.
+% has_type_t5 = child2:bar.  % XXX mixing of use_module and import_module
+			     % is not yet supported.
+has_type_t5 = nested_impl_in_int:child2:bar.
+
+:- end_module nested_impl_in_int.

-- 
Fergus Henderson <fjh at cs.mu.oz.au>  |  "I have always known that the pursuit
WWW: <http://www.cs.mu.oz.au/~fjh>  |  of excellence is a lethal habit"
PGP: finger fjh at 128.250.37.3        |     -- the last words of T. S. Garp.



More information about the developers mailing list