[m-rev.] for review: automatic_include declaration

Peter Ross peter.ross at miscrit.be
Sat Nov 17 01:05:06 AEDT 2001


Hi,


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


Estimated hours taken: 4
Branches: main

Add the `:- automatic_include' declaration.

This declaration allows one to automatically import a sub-module when
the parent module is imported.

This is useful for cases where you have extremely large sub-module
hierachies where each sub-module only contains a small amount of
functionality.  These sort of hierachies are generated by the .NET
interface generation tool.

compiler/modules.m:
    When reading in short and long interfaces recursively read in any
    modules specified by an `:- automatic_include' declaration.
    Check that any `:- automatic_include' declaration in the interface
    refers to an existing visible sub-module.

compiler/make_hlds.m:
compiler/mercury_to_mercury.m:
compiler/module_qual.m:
compiler/prog_data.m:
compiler/prog_io.m:
library/ops.m:
    Small changes to handle the new declaration.

doc/reference_manual.texi:
    Document the `:- automatic_include' declaration.

tests/hard_coded/sub-modules/Mmakefile:
tests/hard_coded/sub-modules/auto_parent.m:
tests/hard_coded/sub-modules/auto_parent.separate.m:
tests/hard_coded/sub-modules/automatic_include.exp:
tests/hard_coded/sub-modules/automatic_include.m:
tests/invalid/Mmakefile:
tests/invalid/automatic_include.err_exp:
tests/invalid/automatic_include.m:
    Test cases.

Index: compiler/make_hlds.m
===================================================================
RCS file: /home/mercury1/repository/mercury/compiler/make_hlds.m,v
retrieving revision 1.391
diff -u -r1.391 make_hlds.m
--- compiler/make_hlds.m	12 Nov 2001 11:08:07 -0000	1.391
+++ compiler/make_hlds.m	16 Nov 2001 13:47:45 -0000
@@ -280,6 +280,9 @@
 			{ module_add_indirectly_imported_module_specifiers(
 				Specifiers, Module0, Module) }
 		)
+	; { ModuleDefn = automatic_include(_) } ->
+		{ Status = Status0 },
+		{ Module = Module0 }
 	; { ModuleDefn = include_module(_) } ->
 		{ Status = Status0 },
 		{ Module = Module0 }
Index: compiler/mercury_to_mercury.m
===================================================================
RCS file: /home/mercury1/repository/mercury/compiler/mercury_to_mercury.m,v
retrieving revision 1.198
diff -u -r1.198 mercury_to_mercury.m
--- compiler/mercury_to_mercury.m	8 Nov 2001 15:30:31 -0000	1.198
+++ compiler/mercury_to_mercury.m	16 Nov 2001 13:47:46 -0000
@@ -762,6 +762,10 @@
 		io__write_string(":- interface.\n")
 	; { ModuleDefn = implementation } ->
 		io__write_string(":- implementation.\n")
+	; { ModuleDefn = automatic_include(IncludedModules) } ->
+		io__write_string(":- automatic_include "),
+		mercury_write_module_spec_list(IncludedModules),
+		io__write_string(".\n")
 	; { ModuleDefn = include_module(IncludedModules) } ->
 		io__write_string(":- include_module "),
 		mercury_write_module_spec_list(IncludedModules),
Index: compiler/module_qual.m
===================================================================
RCS file: /home/mercury1/repository/mercury/compiler/module_qual.m,v
retrieving revision 1.70
diff -u -r1.70 module_qual.m
--- compiler/module_qual.m	6 Nov 2001 15:21:05 -0000	1.70
+++ compiler/module_qual.m	16 Nov 2001 13:47:46 -0000
@@ -311,6 +311,8 @@
 
 process_module_defn(module(ModuleName), Info0, Info) :-
 	add_module_defn(ModuleName, Info0, Info).
+process_module_defn(automatic_include(ModuleNameList), Info0, Info) :-
+	list__foldl(add_module_defn, ModuleNameList, Info0, Info).
 process_module_defn(include_module(ModuleNameList), Info0, Info) :-
 	list__foldl(add_module_defn, ModuleNameList, Info0, Info).
 process_module_defn(interface, Info0, Info) :-
@@ -627,6 +629,7 @@
 update_import_status(import(_), Info, Info, yes).
 update_import_status(use(_), Info, Info, yes).
 update_import_status(version_numbers(_, _), Info, Info, yes).
+update_import_status(automatic_include(_), Info, Info, yes).
 update_import_status(include_module(_), Info0, Info, yes) :-
 	% The sub-module might make use of *any* of the imported modules.
 	% There's no way for us to tell which ones.
Index: compiler/modules.m
===================================================================
RCS file: /home/mercury1/repository/mercury/compiler/modules.m,v
retrieving revision 1.205
diff -u -r1.205 modules.m
--- compiler/modules.m	15 Nov 2001 16:02:14 -0000	1.205
+++ compiler/modules.m	16 Nov 2001 13:47:48 -0000
@@ -620,7 +620,7 @@
 :- implementation.
 :- import_module llds_out, passes_aux, prog_out, prog_util, mercury_to_mercury.
 :- import_module prog_io_util, options, module_qual, foreign.
-:- import_module recompilation_version.
+:- import_module error_util, recompilation_version.
 
 :- import_module string, map, term, varset, dir, library.
 :- import_module assoc_list, relation, char, require.
@@ -2043,19 +2043,35 @@
 				"endif"
 		]),
 
+		% The .date and .date0 files depend on the .int0 files
+		% for the parent modules, and the .int3 files for the
+		% directly and indirectly imported modules.
+		%
+		% For nested sub-modules, the `.date' files for the
+		% parent modules also depend on the same things as the
+		% `.date' files for this module, since all the `.date'
+		% files will get produced by a single mmc command.
+		% XXX The same is true for the `.date0' files, but
+		% including those dependencies here might result in
+		% cyclic dependencies(?).
+
 		module_name_to_file_name(ModuleName, ".date", no,
 						DateFileName),
 		module_name_to_file_name(ModuleName, ".date0", no,
 						Date0FileName),
 		io__write_strings(DepStream, [
 				"\n\n", DateFileName, " ",
-				Date0FileName, " : ",
+				Date0FileName
+		]),
+		write_dependencies_list(ParentDeps, ".date", DepStream),
+		io__write_strings(DepStream, [
+				" : ",
 				SourceFileName
 		]),
 		write_dependencies_list(ParentDeps, ".int0", DepStream),
 		write_dependencies_list(LongDeps, ".int3", DepStream),
 		write_dependencies_list(ShortDeps, ".int3", DepStream),
-			
+
 		module_name_to_file_name(ModuleName, ".dir", no, DirFileName),
 		module_name_to_split_c_file_name(ModuleName, 0, ".$O",
 			SplitCObj0FileName),
@@ -4687,6 +4703,7 @@
 				ModItems0)
 		),
 		{ get_dependencies(Items, IndirectImports1, IndirectUses1) },
+		{ get_automatic_includes(Items, Includes) },
 		{ list__append(IndirectImports0, IndirectImports1,
 			IndirectImports2) },
 		{ list__append(IndirectImports2, IndirectUses1,
@@ -4697,8 +4714,11 @@
 				      ^ error := ModError },
 
 		process_module_long_interfaces(ReadModules, NeedQualifier,
-			Imports, Ext, IndirectImports3, IndirectImports,
-			Module2, Module)
+			Includes, Ext, IndirectImports3, IndirectImports4,
+			Module2, Module3),
+		process_module_long_interfaces(ReadModules, NeedQualifier,
+			Imports, Ext, IndirectImports4, IndirectImports,
+			Module3, Module)
 	).
 
 :- pred check_module_accessibility(module_name, module_name, item_list,
@@ -4870,14 +4890,17 @@
 
 		{ ModIndirectImports = [Import | ModIndirectImports0] },
 		{ get_dependencies(Items, Imports1, Uses1) },
+		{ get_automatic_includes(Items, Includes) },
 		{ list__append(IndirectImports0, Imports1, IndirectImports1) },
 		{ list__append(IndirectImports1, Uses1, IndirectImports2) },
 		{ list__append(ModItems0, Items, ModItems) },
 		{ Module2 = ((Module1 ^ indirect_deps := ModIndirectImports)
 				      ^ items := ModItems)
 				      ^ error := ModError },
+		process_module_short_interfaces(ReadModules, Includes, Ext,
+			IndirectImports2, IndirectImports3, Module2, Module3),
 		process_module_short_interfaces(ReadModules, Imports, Ext,
-			IndirectImports2, IndirectImports, Module2, Module)
+			IndirectImports3, IndirectImports, Module3, Module)
 	).
 
 strip_off_interface_decl(Items0, Items) :-
@@ -4957,6 +4980,31 @@
 
 %-----------------------------------------------------------------------------%
 
+	% get_automatic_includes(Items, IncludeDeps):
+	%	IncludeDeps is the list of modules referenced by a
+	% 	`:- automatic_include' in Items.
+	%
+:- pred get_automatic_includes(item_list::in, list(module_name)::out) is det.
+
+get_automatic_includes(Items, IncludeDeps) :-
+	get_automatic_includes_2(Items, [], IncludeDeps).
+
+:- pred get_automatic_includes_2(item_list::in,
+		list(module_name)::in, list(module_name)::out) is det.
+
+get_automatic_includes_2([], IncludeDeps, IncludeDeps).
+get_automatic_includes_2([Item - _Ctxt | Items], IncludeDeps0, IncludeDeps) :-
+	( 
+		Item = module_defn(_VarSet, automatic_include(Modules))
+	->
+		list__append(IncludeDeps0, Modules, IncludeDeps1)
+	;
+		IncludeDeps1 = IncludeDeps0
+	),
+	get_automatic_includes_2(Items, IncludeDeps1, IncludeDeps).
+
+%-----------------------------------------------------------------------------%
+
 get_dependencies(Items, ImportDeps, UseDeps) :-
 	get_dependencies_implementation(Items, [], [] , [], [],
 			IntImportDeps, IntUseDeps, ImpImportDeps, ImpUseDeps),
@@ -5122,12 +5170,37 @@
 	%
 	{ get_children(Items0, NestedSubmodules) },
 	{ assoc_list__keys(ModuleList, SeparateSubModules) },
-	{ Duplicates = set__intersect(set__list_to_set(NestedSubmodules),
-				set__list_to_set(SeparateSubModules)) },
+	{ NestedSubmodulesSet = set__list_to_set(NestedSubmodules) },
+	{ SeparateSubModulesSet = set__list_to_set(SeparateSubModules) },
+	{ Duplicates = NestedSubmodulesSet `intersect` SeparateSubModulesSet },
 	( { set__empty(Duplicates) } ->
 		[]
 	;
 		report_duplicate_modules(Duplicates, Items0)
+	),
+
+	%
+	% Ensure that the automatic_include only refers to public
+	% sub-modules of the current module.
+	% seen by the current module.
+	%
+	( { ModuleList = [ _ - CurrentModuleItems | _ ] } ->
+		{ get_interface(CurrentModuleItems, InterfaceItems) },
+		{ get_automatic_includes(InterfaceItems, AutomaticIncludes) },
+		{ get_children(InterfaceItems, PublicSubModules) },
+		{ AutomaticIncludesSet = set__list_to_set(AutomaticIncludes) },
+		{ PublicSubModulesSet = set__list_to_set(PublicSubModules) },
+		( { AutomaticIncludesSet `subset` PublicSubModulesSet } ->
+			[]
+		;
+			{ ErrorIncludes = to_sorted_list(
+					AutomaticIncludesSet `difference`
+					PublicSubModulesSet) },
+			list__foldl(report_improper_automatic_include(
+					CurrentModuleItems), ErrorIncludes)
+		)
+	;
+		{ unexpected(this_file, "empty module list") }
 	).
 
 :- pred split_into_submodules_2(module_name, item_list, bool, item_list,
@@ -5334,6 +5407,30 @@
 	io__write_string("  a separate sub-module and a nested sub-module.\n"),
 	io__set_exit_status(1).
 
+:- pred report_improper_automatic_include(item_list::in, module_name::in,
+		io__state::di, io__state::uo) is det.
+
+report_improper_automatic_include(Items, ModuleName) -->
+	{ FindContexts = (pred(Context::out) is nondet :-
+		list__member(Item, Items),
+		Item = module_defn(_VarSet, ModuleDefn) - Context,
+		ModuleDefn = automatic_include(AutomaticIncludes),
+		list__member(ModuleName, AutomaticIncludes)
+	  ) },
+	{ WriteError = (pred(Context::in, di, uo) is det -->
+		{ ModuleNameStr = describe_sym_name(ModuleName) },
+		error_util__write_error_pieces(Context, 0,
+				[words("error:"),
+				 words("The automatic_include declaration"),
+				 words("refers to the sub-module "),
+				 words(ModuleNameStr),
+				 words("which doesn't exist or is not"),
+				 words("visible externally.")])
+	) },
+	{ solutions(FindContexts, Contexts) },
+	list__foldl(WriteError, Contexts),
+	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'.
@@ -5556,5 +5653,11 @@
 	;
 		[]
 	).
+
+%-----------------------------------------------------------------------------%
+
+:- func this_file = string.
+
+this_file = "modules.m".
 
 %-----------------------------------------------------------------------------%
Index: compiler/prog_data.m
===================================================================
RCS file: /home/mercury1/repository/mercury/compiler/prog_data.m,v
retrieving revision 1.71
diff -u -r1.71 prog_data.m
--- compiler/prog_data.m	6 Nov 2001 15:21:09 -0000	1.71
+++ compiler/prog_data.m	16 Nov 2001 13:47:49 -0000
@@ -912,6 +912,7 @@
 	;	use(sym_list)
 
 	;	include_module(list(module_name))
+	;	automatic_include(list(module_name))
 
 		% This is used to represent the version numbers
 		% of items in an interface file for use in
Index: compiler/prog_io.m
===================================================================
RCS file: /home/mercury1/repository/mercury/compiler/prog_io.m,v
retrieving revision 1.197
diff -u -r1.197 prog_io.m
--- compiler/prog_io.m	16 Jul 2001 08:21:04 -0000	1.197
+++ compiler/prog_io.m	16 Nov 2001 13:47:50 -0000
@@ -1092,6 +1092,20 @@
 	),
 	check_no_attributes(Result1, Attributes, Result).
 
+process_decl(DefaultModuleName, VarSet0, "automatic_include", [ModuleNames],
+		Attributes, Result) :-
+	parse_list(parse_module_name(DefaultModuleName), ModuleNames, Result0),
+	(	
+		Result0 = ok(ModuleNameSyms), 
+		varset__coerce(VarSet0, VarSet),
+		Result1 = ok(module_defn(VarSet,
+				automatic_include(ModuleNameSyms)))
+	;	
+		Result0 = error(A, B),
+		Result1 = error(A, B)
+	),
+	check_no_attributes(Result1, Attributes, Result).
+
 process_decl(DefaultModuleName, VarSet0, "end_module", [ModuleName],
 		Attributes, Result) :-
 	%
Index: doc/reference_manual.texi
===================================================================
RCS file: /home/mercury1/repository/mercury/doc/reference_manual.texi,v
retrieving revision 1.224
diff -u -r1.224 reference_manual.texi
--- doc/reference_manual.texi	12 Nov 2001 11:08:13 -0000	1.224
+++ doc/reference_manual.texi	16 Nov 2001 13:47:57 -0000
@@ -489,6 +489,7 @@
 end_module        fx        1199
 import_module     fx        1199
 include_module    fx        1199
+automatic_include fx        1199
 instance          fx        1199
 inst              fx        1199
 mode              fx        1199
@@ -541,6 +542,7 @@
 :- implementation
 :- import_module
 :- use_module
+:- automatic_include
 :- include_module
 :- end_module
 @end example
@@ -3657,6 +3659,7 @@
 * Nested sub-modules::
 * Separate sub-modules::
 * Visibility rules::
+* Automatic importation of sub-modules::
 * Implementation bugs and limitations::
 @end menu
 
@@ -3747,6 +3750,25 @@
 Note that as mentioned previously, all @samp{:- import_module} and
 @samp{:- use_module} declarations must use fully-qualified module
 names.
+
+ at node Automatic importation of sub-modules
+ at subsection Automatic importation of sub-modules
+
+The @samp{:- automatic_include} declaration allows one to automatically
+import a sub-module when the parent module is imported.
+
+Each module mentioned by an @samp{:- automatic_include} declaration in
+the interface section of a parent module will also be imported when the
+parent module is imported.
+The modules the @samp{:- automatic_include} specifies will be treated as if
+they were imported by the same declaration which imported the parent
+module,
+namely a @samp{:- import_module} or a @samp{:- use_module}.
+It is an error to specify
+a module which is not a direct sub-module of the parent module
+or a sub-module which is not visible externally (an implementation sub-module).
+An @samp{:- automatic_include} declaration which occurs in the
+implementation section of a module is ignored.
 
 @node Implementation bugs and limitations
 @subsection Implementation bugs and limitations
Index: library/ops.m
===================================================================
RCS file: /home/mercury1/repository/mercury/library/ops.m,v
retrieving revision 1.37
diff -u -r1.37 ops.m
--- library/ops.m	12 Nov 2001 11:08:16 -0000	1.37
+++ library/ops.m	16 Nov 2001 13:47:57 -0000
@@ -310,6 +310,7 @@
 ops__op_table("aditi_top_down", before, fx, 500). % Mercury extension
 ops__op_table("all", before, fxy, 950).		% Mercury/NU-Prolog extension
 ops__op_table("and", after, xfy, 720).		% NU-Prolog extension
+ops__op_table("automatic_include", before, fx, 1199). % Mercury extension
 ops__op_table("div", after, yfx, 400).		% standard ISO Prolog
 ops__op_table("else", after, xfy, 1170).	% Mercury/NU-Prolog extension
 ops__op_table("end_module", before, fx, 1199).	% Mercury extension
Index: tests/hard_coded/sub-modules/Mmakefile
===================================================================
RCS file: /home/mercury1/repository/tests/hard_coded/sub-modules/Mmakefile,v
retrieving revision 1.4
diff -u -r1.4 Mmakefile
--- tests/hard_coded/sub-modules/Mmakefile	15 Nov 2001 15:01:30 -0000	1.4
+++ tests/hard_coded/sub-modules/Mmakefile	16 Nov 2001 13:47:58 -0000
@@ -25,7 +25,8 @@
 	nested2 \
 	nested3 \
 	class \
-	nested_intermod_main
+	nested_intermod_main \
+	automatic_include
 
 MCFLAGS-nested_intermod	=	--intermodule-optimization
 MCFLAGS-nested_intermod_main =	--intermodule-optimization
Index: tests/hard_coded/sub-modules/auto_parent.m
===================================================================
RCS file: tests/hard_coded/sub-modules/auto_parent.m
diff -N tests/hard_coded/sub-modules/auto_parent.m
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ tests/hard_coded/sub-modules/auto_parent.m	16 Nov 2001 13:47:58 -0000
@@ -0,0 +1,32 @@
+% Test the automatic_include statement.
+% Used by automatic_include.m
+
+:- module auto_parent.
+
+:- interface.
+
+:- import_module io.
+
+:- include_module separate.
+
+:- automatic_include auto_parent__nested, auto_parent__separate.
+
+:- pred hello(io__state::di, io__state::uo) is det.
+
+  :- module auto_parent__nested.
+  :- interface.
+  :- pred hello(io__state::di, io__state::uo) is det.
+  :- end_module auto_parent__nested.
+
+:- implementation.
+
+hello -->
+	io__write_string("auto_parent: hello\n").
+
+:- module auto_parent__nested.
+:- implementation.
+
+hello -->
+	io__write_string("auto_parent__nested: hello\n").
+
+:- end_module auto_parent__nested.
Index: tests/hard_coded/sub-modules/auto_parent.separate.m
===================================================================
RCS file: tests/hard_coded/sub-modules/auto_parent.separate.m
diff -N tests/hard_coded/sub-modules/auto_parent.separate.m
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ tests/hard_coded/sub-modules/auto_parent.separate.m	16 Nov 2001 13:47:58 -0000
@@ -0,0 +1,14 @@
+% Used by automatic_include.m
+
+:- module auto_parent__separate.
+
+:- interface.
+
+% The parent module autos io.
+
+:- pred hello(io__state::di, io__state::uo) is det.
+
+:- implementation.
+
+hello -->
+	io__write_string("auto_parent__separate: hello\n").
Index: tests/hard_coded/sub-modules/automatic_include.exp
===================================================================
RCS file: tests/hard_coded/sub-modules/automatic_include.exp
diff -N tests/hard_coded/sub-modules/automatic_include.exp
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ tests/hard_coded/sub-modules/automatic_include.exp	16 Nov 2001 13:47:58 -0000
@@ -0,0 +1,2 @@
+auto_parent__nested: hello
+auto_parent__separate: hello
Index: tests/hard_coded/sub-modules/automatic_include.m
===================================================================
RCS file: tests/hard_coded/sub-modules/automatic_include.m
diff -N tests/hard_coded/sub-modules/automatic_include.m
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ tests/hard_coded/sub-modules/automatic_include.m	16 Nov 2001 13:47:58 -0000
@@ -0,0 +1,18 @@
+% Test the when importing the module auto_parent that we also get the
+% sub-modules nested and separate automatically imported.
+
+:- module (automatic_include).
+
+:- interface.
+
+:- import_module io.
+
+:- pred main(io__state::di, io__state::uo) is det.
+
+:- implementation.
+
+:- use_module auto_parent.
+
+main -->
+	auto_parent__nested__hello,
+	auto_parent__separate__hello.
Index: tests/invalid/Mmakefile
===================================================================
RCS file: /home/mercury1/repository/tests/invalid/Mmakefile,v
retrieving revision 1.101
diff -u -r1.101 Mmakefile
--- tests/invalid/Mmakefile	15 Nov 2001 13:32:48 -0000	1.101
+++ tests/invalid/Mmakefile	16 Nov 2001 13:47:58 -0000
@@ -32,6 +32,7 @@
 SINGLEMODULE_SOURCES= \
 	any_mode.m \
 	assert_in_interface.m \
+	automatic_include.m \
 	bigtest.m \
 	bind_var_errors.m \
 	builtin_int.m \
@@ -185,6 +186,7 @@
 
 # For these test cases, the bug is caught when generating dependencies,
 # so it is easiest just to do that step.
+MCFLAGS-automatic_include =	--generate-dependencies -E
 MCFLAGS-nested_impl_in_int =	--generate-dependencies
 MCFLAGS-duplicate_module_test =	--generate-dependencies
 
Index: tests/invalid/automatic_include.err_exp
===================================================================
RCS file: tests/invalid/automatic_include.err_exp
diff -N tests/invalid/automatic_include.err_exp
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ tests/invalid/automatic_include.err_exp	16 Nov 2001 13:47:58 -0000
@@ -0,0 +1,6 @@
+automatic_include.m:007: error: The automatic_include declaration refers to the
+automatic_include.m:007:   sub-module `automatic_include:child' which doesn't
+automatic_include.m:007:   exist or is not visible externally.
+automatic_include.m:008: error: The automatic_include declaration refers to the
+automatic_include.m:008:   sub-module `automatic_include:list' which doesn't
+automatic_include.m:008:   exist or is not visible externally.
Index: tests/invalid/automatic_include.m
===================================================================
RCS file: tests/invalid/automatic_include.m
diff -N tests/invalid/automatic_include.m
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ tests/invalid/automatic_include.m	16 Nov 2001 13:47:58 -0000
@@ -0,0 +1,15 @@
+:- module (automatic_include).
+
+:- interface.
+
+:- type t.
+
+:- automatic_include automatic_include__child.	% not visible
+:- automatic_include list.			% doesn't exist
+
+:- implementation.
+
+:- module automatic_include__child.
+:- interface.
+:- type t.
+:- end_module automatic_include__child.

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