nitc :: ModelBuilder
nitc :: ModelBuilder :: _bad_class_names
List of already reported bad class names.nitc :: ModelBuilder :: _conditional_importations
Global list of conditional importation rules.nitc :: ModelBuilder :: _doc_entities
The number ofMEntity
that have some documentation
nitc :: ModelBuilder :: _failed_entities
The number failed docunitsnitc :: ModelBuilder :: _identified_modules
All the currently identified modules.nitc :: ModelBuilder :: _identified_modules_by_path
Cache foridentify_module
by relative and real paths
nitc :: ModelBuilder :: _last_loader_error
Someloader
services are silent and return null
on error.
nitc :: ModelBuilder :: _mclassdef2nclassdef
Registration of the nclassdef associated to each mclassdefnitc :: ModelBuilder :: _mmodule2nmodule
Register the nmodule associated to each mmodulenitc :: ModelBuilder :: _model
The model where new modules, classes and properties are addednitc :: ModelBuilder :: _mpropdef2npropdef
Registration of the npropdef associated to each mpropdef.nitc :: ModelBuilder :: _nb_invok_by_direct
Count number of invocations by direct callnitc :: ModelBuilder :: _nb_invok_by_inline
Count number of invocations by inliningnitc :: ModelBuilder :: _nb_invok_by_tables
Count number of invocations by VFTnitc :: ModelBuilder :: _parsed_modules
All the currently parsed modules.nitc :: ModelBuilder :: _the_root_init_mmethod
the root init of the Object classnitc :: ModelBuilder :: _toolcontext
The toolcontext used to control the interaction with the user (getting options and displaying messages)nitc :: ModelBuilder :: _total_classes
Number of test classes generated.nitc :: ModelBuilder :: _total_entities
Total number analyzedMEntity
nitc :: ModelBuilder :: _unit_entities
The total number of executed docunitsnitc :: ModelBuilder :: apply_conditional_importations
Extends the current importations according to imported rules about conditional importationnitc :: ModelBuilder :: bad_class_names
List of already reported bad class names.nitc :: ModelBuilder :: bad_class_names=
List of already reported bad class names.nitc :: ModelBuilder :: build_a_bound_mtype
Determine the type parameter bounds fornclassdef
.
nitc :: ModelBuilder :: build_a_mclass
Visit the AST and create theMClass
objects
nitc :: ModelBuilder :: build_a_mclassdef
Visit the AST and create theMClassDef
objects
nitc :: ModelBuilder :: build_a_mclassdef_inheritance
Visit the AST and set the super-types of theMClassDef
objects
nitc :: ModelBuilder :: build_a_mmodule
Visit the AST and create theMModule
object
nitc :: ModelBuilder :: build_classes
Build the classes of the modulenmodule
.
nitc :: ModelBuilder :: build_module_importation
Analyze the module importation and fill the module_importation_hierarchynitc :: ModelBuilder :: build_properties
Build the properties ofnclassdef
.
nitc :: ModelBuilder :: build_with_ant
Compile Java sources usingant
nitc :: ModelBuilder :: build_with_make
Compile Java generated files usingmake
nitc :: ModelBuilder :: cache_file
Cache a file as{filepath}.tmp
and replace the original if different
nitc :: ModelBuilder :: check_sametype
Check thatsub
and sup
are equvalent types.
nitc :: ModelBuilder :: check_subtype
Check thatsub
is a subtype of sup
.
nitc :: ModelBuilder :: check_supertypes
Check the validity of the specialization heirarchynitc :: ModelBuilder :: check_virtual_types_circularity
Detect circularity errors for virtual types.nitc :: ModelBuilder :: check_visibility
Check the visibility ofmtype
as an element of the signature of mpropdef
.
nitc :: ModelBuilder :: class_not_found
Print an error and suggest hints when the class identified byqid
in mmodule
is not found.
nitc :: ModelBuilder :: close_cache
Close the writer and move tmp file to original if modifiednitc :: ModelBuilder :: collect_annotations_data
Collect all annotations byname
in mmodule
and its importations (direct and indirect)
nitc :: ModelBuilder :: collect_annotations_on_modules
Collect all annotations byname
assocated to mmodule
and its imported modules.
nitc :: ModelBuilder :: collect_attr_propdef
Retrieve all the attributes nodes localy definiednitc :: ModelBuilder :: collect_supertypes
List the supertypes specified or implied bynclassdef
.
nitc :: ModelBuilder :: compile_antfile
The Antbuild.xml
script used to compile build the final jar
nitc :: ModelBuilder :: conditional_importations
Global list of conditional importation rules.nitc :: ModelBuilder :: conditional_importations=
Global list of conditional importation rules.nitc :: ModelBuilder :: create_attribute_from_name
Creation of a new attribute (AST and model representation) with the given name.nitc :: ModelBuilder :: create_attribute_from_propdef
Creation of a new attribute (AST representation) with the given MAttributeDef.nitc :: ModelBuilder :: create_attribute_from_property
Creation of a new attribute (AST and model representation) with the given MAttribute.nitc :: ModelBuilder :: create_class_from_mclass
Creation of a new class (AST and model representation) with the given MClass.nitc :: ModelBuilder :: create_class_from_mclassdef
Creation of a new class (AST representation) with the given MClassDef.nitc :: ModelBuilder :: create_class_from_name
Creation of a new class (AST and model representation) with the given name.nitc :: ModelBuilder :: create_method_from_name
Creation of a new method (AST and model representation) with the given name.nitc :: ModelBuilder :: create_method_from_property
Creation of a new method (AST and model representation) with the given MMethod.nitc :: ModelBuilder :: defaultinit
nitc :: ModelBuilder :: do_rapid_type_analysis
Performs a rapid-type-analysis on the program associated withmainmodule
.
nitc :: ModelBuilder :: doc_entities
The number ofMEntity
that have some documentation
nitc :: ModelBuilder :: doc_entities=
The number ofMEntity
that have some documentation
nitc :: ModelBuilder :: failed_entities=
The number failed docunitsnitc :: ModelBuilder :: failed_tests=
Number of failed tests.nitc :: ModelBuilder :: filter_nit_source
Remove Nit source files from a list of arguments.nitc :: ModelBuilder :: force_get_primitive_method
Force to get the primitive method namedname
on the type recv
or do a fatal error on n
nitc :: ModelBuilder :: gen_test_unit
Generate NitUnit test file skeleton formmodule
.
nitc :: ModelBuilder :: get_mclass_by_name
Liketry_get_mclass_by_name
but display an error message when the class is not found
nitc :: ModelBuilder :: get_mmethod
Try to get MMethod property if exist in the given mclassdef. return newMMethod
if not exist.
nitc :: ModelBuilder :: get_mmodule_annotation
Return the single annotationname
locally assocated to mmodule
, if any.
nitc :: ModelBuilder :: get_mmodule_by_name
Get a module by its short name; if required, the module is loaded, parsed and its hierarchies computed.nitc :: ModelBuilder :: identified_modules
All the currently identified modules.nitc :: ModelBuilder :: identified_modules=
All the currently identified modules.nitc :: ModelBuilder :: identified_modules_by_path
Cache foridentify_module
by relative and real paths
nitc :: ModelBuilder :: identified_modules_by_path=
Cache foridentify_module
by relative and real paths
nitc :: ModelBuilder :: identify_group
Return the mgroup associated to a directory path.nitc :: ModelBuilder :: identify_module
Identify a source file and load the associated package and groups if required.nitc :: ModelBuilder :: inject_module_subimportation
Load modulefilename
and add it as a conditional importation of mmodule
.
nitc :: ModelBuilder :: last_loader_error
Someloader
services are silent and return null
on error.
nitc :: ModelBuilder :: last_loader_error=
Someloader
services are silent and return null
on error.
nitc :: ModelBuilder :: load_markdown
Load a markdown file as a documentation objectnitc :: ModelBuilder :: load_module
Try to load a module using a path.nitc :: ModelBuilder :: load_module_ast
Try to load a module AST using a path.nitc :: ModelBuilder :: load_rt_module
Injection of a new module without source.nitc :: ModelBuilder :: lookup_annotation_on_modules
Get an annotation by name frommmodule
and its super modules. Will recursively search
nitc :: ModelBuilder :: match_amodulename
Is elements ofn_name
correspond to the group nesting of m
?
nitc :: ModelBuilder :: mclassdef2nclassdef
Registration of the nclassdef associated to each mclassdefnitc :: ModelBuilder :: mclassdef2nclassdef=
Registration of the nclassdef associated to each mclassdefnitc :: ModelBuilder :: mclassdef2node
Retrieve the associated AST node of a mclassdef.nitc :: ModelBuilder :: mentity2node
Retrieve the associated AST node of a mentity.nitc :: ModelBuilder :: mmodule2nmodule
Register the nmodule associated to each mmodulenitc :: ModelBuilder :: mmodule2nmodule=
Register the nmodule associated to each mmodulenitc :: ModelBuilder :: mmodule2node
Retrieve the associated AST node of a mmodule.nitc :: ModelBuilder :: model
The model where new modules, classes and properties are addednitc :: ModelBuilder :: model=
The model where new modules, classes and properties are addednitc :: ModelBuilder :: module_absolute_path
Transform relative paths (starting with '../') into absolute pathsnitc :: ModelBuilder :: mpropdef2node
Retrieve the associated AST node of a mpropertydef.nitc :: ModelBuilder :: mpropdef2npropdef
Registration of the npropdef associated to each mpropdef.nitc :: ModelBuilder :: mpropdef2npropdef=
Registration of the npropdef associated to each mpropdef.nitc :: ModelBuilder :: nb_invok_by_direct
Count number of invocations by direct callnitc :: ModelBuilder :: nb_invok_by_direct=
Count number of invocations by direct callnitc :: ModelBuilder :: nb_invok_by_inline
Count number of invocations by inliningnitc :: ModelBuilder :: nb_invok_by_inline=
Count number of invocations by inliningnitc :: ModelBuilder :: nb_invok_by_tables
Count number of invocations by VFTnitc :: ModelBuilder :: nb_invok_by_tables=
Count number of invocations by VFTnitc :: ModelBuilder :: parse_full
Load a bunch of modules and groups.nitc :: ModelBuilder :: parsed_modules
All the currently parsed modules.nitc :: ModelBuilder :: parsed_modules=
All the currently parsed modules.nitc :: ModelBuilder :: process_default_constructors
Introduce or inherit default constructornitc :: ModelBuilder :: resolve_mtype
Return the static type associated to the nodentype
.
nitc :: ModelBuilder :: resolve_mtype3
Return the static type associated to the nodentype
.
nitc :: ModelBuilder :: resolve_mtype3_unchecked
Return the static type associated to the nodentype
.
nitc :: ModelBuilder :: resolve_mtype_unchecked
Return the static type associated to the nodentype
.
nitc :: ModelBuilder :: run_global_compiler
Entry point to performs a global compilation on the AST of a complete program.nitc :: ModelBuilder :: run_java_compiler
Start the Java compilernitc :: ModelBuilder :: run_naive_interpreter
Execute the program from the entry point (Sys::main
) of the mainmodule
nitc :: ModelBuilder :: scan_group
Force the identification of all MModule of the group and sub-groups in the file system.nitc :: ModelBuilder :: search_group_in_paths
Search groups namedname
from paths lookpaths
.
nitc :: ModelBuilder :: search_mmodule_by_name
Like (and used by)get_mmodule_by_name
but does not force the parsing of the MModule (cf. identify_module
)
nitc :: ModelBuilder :: search_module_by_amodule_name
Resolve the module identification for a givenAModuleName
.
nitc :: ModelBuilder :: search_module_in_paths
Search a modulename
from path lookpaths
.
nitc :: ModelBuilder :: test_group
Extracts and executes all the docunits in the readme of themgroup
nitc :: ModelBuilder :: test_markdown
Extracts and executes all the docunits in themmodule
nitc :: ModelBuilder :: the_root_init_mmethod
the root init of the Object classnitc :: ModelBuilder :: the_root_init_mmethod=
the root init of the Object classnitc :: ModelBuilder :: toolcontext
The toolcontext used to control the interaction with the user (getting options and displaying messages)nitc :: ModelBuilder :: toolcontext=
The toolcontext used to control the interaction with the user (getting options and displaying messages)nitc :: ModelBuilder :: total_classes=
Number of test classes generated.nitc :: ModelBuilder :: total_entities=
Total number analyzedMEntity
nitc :: ModelBuilder :: total_tests=
Number of tests generated.nitc :: ModelBuilder :: try_get_mclass_by_name
Return a class namedname
visible by the module mmodule
.
nitc :: ModelBuilder :: try_get_mclass_by_qid
Return a class identified byqid
visible by the module mmodule
.
nitc :: ModelBuilder :: try_get_mproperty_by_name
Alias for try_get_mproperty_by_name2(anode, mclassdef.mmodule, mclassdef.mtype, name)nitc :: ModelBuilder :: try_get_mproperty_by_name2
Return a property namedname
on the type mtype
visible in the module mmodule
.
nitc :: ModelBuilder :: unit_entities=
The total number of executed docunitsnitc :: ModelBuilder :: unsafe_add_mclassdef2nclassdef
Associate anclassdef
with its mclassdef
nitc :: ModelBuilder :: unsafe_add_mpropdef2npropdef
Associate anpropdef
with its mpropdef
nitc :: ModelBuilder :: write_and_make
Write Java code and compile it into an executable jarnitc :: ModelBuilder :: write_and_make
Simple indirection toToolchain::write_and_make
nitc :: ModelBuilder :: write_java_files
Write files managed bycompiler
into concrete files
nitc :: ModelBuilder :: write_makefile
Write the Makefile used to compile Java generated files into an executable jarnitc :: ModelBuilder :: write_manifest
Write the Java manifest filenitc :: ModelBuilder :: write_poset_to_file
Writeposet
to a C file
nitc :: ModelBuilder :: write_shell_script
Write a simple bash script that runs the jar like it was a binary generated by nitcnitc $ ModelBuilder :: SELF
Type of this instance, automatically specialized in every classnitc :: actors_injection_phase $ ModelBuilder :: build_a_mclass
Visit the AST and create theMClass
objects
nitc :: actors_injection_phase $ ModelBuilder :: build_properties
Build the properties ofnclassdef
.
nitc :: detect_covariance $ ModelBuilder :: check_subtype
Check thatsub
is a subtype of sup
.
nitc :: loader $ ModelBuilder :: init
nitc $ ModelBuilder :: init
Instantiate a modelbuilder for a model and a toolcontextnitc :: test_astbuilder $ ModelBuilder :: run_naive_interpreter
Execute the program from the entry point (Sys::main
) of the mainmodule
nitc :: compiler_serialization $ ModelBuilder :: write_and_make
Simple indirection toToolchain::write_and_make
nitc :: ModelBuilder :: _bad_class_names
List of already reported bad class names.nitc :: ModelBuilder :: _conditional_importations
Global list of conditional importation rules.nitc :: ModelBuilder :: _doc_entities
The number ofMEntity
that have some documentation
nitc :: ModelBuilder :: _failed_entities
The number failed docunitsnitc :: ModelBuilder :: _identified_modules
All the currently identified modules.nitc :: ModelBuilder :: _identified_modules_by_path
Cache foridentify_module
by relative and real paths
nitc :: ModelBuilder :: _last_loader_error
Someloader
services are silent and return null
on error.
nitc :: ModelBuilder :: _mclassdef2nclassdef
Registration of the nclassdef associated to each mclassdefnitc :: ModelBuilder :: _mmodule2nmodule
Register the nmodule associated to each mmodulenitc :: ModelBuilder :: _model
The model where new modules, classes and properties are addednitc :: ModelBuilder :: _mpropdef2npropdef
Registration of the npropdef associated to each mpropdef.nitc :: ModelBuilder :: _nb_invok_by_direct
Count number of invocations by direct callnitc :: ModelBuilder :: _nb_invok_by_inline
Count number of invocations by inliningnitc :: ModelBuilder :: _nb_invok_by_tables
Count number of invocations by VFTnitc :: ModelBuilder :: _parsed_modules
All the currently parsed modules.nitc :: ModelBuilder :: _the_root_init_mmethod
the root init of the Object classnitc :: ModelBuilder :: _toolcontext
The toolcontext used to control the interaction with the user (getting options and displaying messages)nitc :: ModelBuilder :: _total_classes
Number of test classes generated.nitc :: ModelBuilder :: _total_entities
Total number analyzedMEntity
nitc :: ModelBuilder :: _unit_entities
The total number of executed docunitsnitc :: ModelBuilder :: apply_conditional_importations
Extends the current importations according to imported rules about conditional importationnitc :: ModelBuilder :: bad_class_names
List of already reported bad class names.nitc :: ModelBuilder :: bad_class_names=
List of already reported bad class names.nitc :: ModelBuilder :: build_a_bound_mtype
Determine the type parameter bounds fornclassdef
.
nitc :: ModelBuilder :: build_a_mclass
Visit the AST and create theMClass
objects
nitc :: ModelBuilder :: build_a_mclassdef
Visit the AST and create theMClassDef
objects
nitc :: ModelBuilder :: build_a_mclassdef_inheritance
Visit the AST and set the super-types of theMClassDef
objects
nitc :: ModelBuilder :: build_a_mmodule
Visit the AST and create theMModule
object
nitc :: ModelBuilder :: build_classes
Build the classes of the modulenmodule
.
nitc :: ModelBuilder :: build_module_importation
Analyze the module importation and fill the module_importation_hierarchynitc :: ModelBuilder :: build_properties
Build the properties ofnclassdef
.
nitc :: ModelBuilder :: build_with_ant
Compile Java sources usingant
nitc :: ModelBuilder :: build_with_make
Compile Java generated files usingmake
nitc :: ModelBuilder :: cache_file
Cache a file as{filepath}.tmp
and replace the original if different
nitc :: ModelBuilder :: check_sametype
Check thatsub
and sup
are equvalent types.
nitc :: ModelBuilder :: check_subtype
Check thatsub
is a subtype of sup
.
nitc :: ModelBuilder :: check_supertypes
Check the validity of the specialization heirarchynitc :: ModelBuilder :: check_virtual_types_circularity
Detect circularity errors for virtual types.nitc :: ModelBuilder :: check_visibility
Check the visibility ofmtype
as an element of the signature of mpropdef
.
core :: Object :: class_factory
Implementation used byget_class
to create the specific class.
nitc :: ModelBuilder :: class_not_found
Print an error and suggest hints when the class identified byqid
in mmodule
is not found.
nitc :: ModelBuilder :: close_cache
Close the writer and move tmp file to original if modifiednitc :: ModelBuilder :: collect_annotations_data
Collect all annotations byname
in mmodule
and its importations (direct and indirect)
nitc :: ModelBuilder :: collect_annotations_on_modules
Collect all annotations byname
assocated to mmodule
and its imported modules.
nitc :: ModelBuilder :: collect_attr_propdef
Retrieve all the attributes nodes localy definiednitc :: ModelBuilder :: collect_supertypes
List the supertypes specified or implied bynclassdef
.
nitc :: ModelBuilder :: compile_antfile
The Antbuild.xml
script used to compile build the final jar
nitc :: ModelBuilder :: conditional_importations
Global list of conditional importation rules.nitc :: ModelBuilder :: conditional_importations=
Global list of conditional importation rules.nitc :: ModelBuilder :: create_attribute_from_name
Creation of a new attribute (AST and model representation) with the given name.nitc :: ModelBuilder :: create_attribute_from_propdef
Creation of a new attribute (AST representation) with the given MAttributeDef.nitc :: ModelBuilder :: create_attribute_from_property
Creation of a new attribute (AST and model representation) with the given MAttribute.nitc :: ModelBuilder :: create_class_from_mclass
Creation of a new class (AST and model representation) with the given MClass.nitc :: ModelBuilder :: create_class_from_mclassdef
Creation of a new class (AST representation) with the given MClassDef.nitc :: ModelBuilder :: create_class_from_name
Creation of a new class (AST and model representation) with the given name.nitc :: ModelBuilder :: create_method_from_name
Creation of a new method (AST and model representation) with the given name.nitc :: ModelBuilder :: create_method_from_property
Creation of a new method (AST and model representation) with the given MMethod.nitc :: ModelBuilder :: defaultinit
core :: Object :: defaultinit
nitc :: ModelBuilder :: do_rapid_type_analysis
Performs a rapid-type-analysis on the program associated withmainmodule
.
nitc :: ModelBuilder :: doc_entities
The number ofMEntity
that have some documentation
nitc :: ModelBuilder :: doc_entities=
The number ofMEntity
that have some documentation
nitc :: ModelBuilder :: failed_entities=
The number failed docunitsnitc :: ModelBuilder :: failed_tests=
Number of failed tests.nitc :: ModelBuilder :: filter_nit_source
Remove Nit source files from a list of arguments.nitc :: ModelBuilder :: force_get_primitive_method
Force to get the primitive method namedname
on the type recv
or do a fatal error on n
nitc :: ModelBuilder :: gen_test_unit
Generate NitUnit test file skeleton formmodule
.
nitc :: ModelBuilder :: get_mclass_by_name
Liketry_get_mclass_by_name
but display an error message when the class is not found
nitc :: ModelBuilder :: get_mmethod
Try to get MMethod property if exist in the given mclassdef. return newMMethod
if not exist.
nitc :: ModelBuilder :: get_mmodule_annotation
Return the single annotationname
locally assocated to mmodule
, if any.
nitc :: ModelBuilder :: get_mmodule_by_name
Get a module by its short name; if required, the module is loaded, parsed and its hierarchies computed.nitc :: ModelBuilder :: identified_modules
All the currently identified modules.nitc :: ModelBuilder :: identified_modules=
All the currently identified modules.nitc :: ModelBuilder :: identified_modules_by_path
Cache foridentify_module
by relative and real paths
nitc :: ModelBuilder :: identified_modules_by_path=
Cache foridentify_module
by relative and real paths
nitc :: ModelBuilder :: identify_group
Return the mgroup associated to a directory path.nitc :: ModelBuilder :: identify_module
Identify a source file and load the associated package and groups if required.nitc :: ModelBuilder :: inject_module_subimportation
Load modulefilename
and add it as a conditional importation of mmodule
.
core :: Object :: is_same_instance
Return true ifself
and other
are the same instance (i.e. same identity).
core :: Object :: is_same_serialized
Isself
the same as other
in a serialization context?
core :: Object :: is_same_type
Return true ifself
and other
have the same dynamic type.
nitc :: ModelBuilder :: last_loader_error
Someloader
services are silent and return null
on error.
nitc :: ModelBuilder :: last_loader_error=
Someloader
services are silent and return null
on error.
nitc :: ModelBuilder :: load_markdown
Load a markdown file as a documentation objectnitc :: ModelBuilder :: load_module
Try to load a module using a path.nitc :: ModelBuilder :: load_module_ast
Try to load a module AST using a path.nitc :: ModelBuilder :: load_rt_module
Injection of a new module without source.nitc :: ModelBuilder :: lookup_annotation_on_modules
Get an annotation by name frommmodule
and its super modules. Will recursively search
nitc :: ModelBuilder :: match_amodulename
Is elements ofn_name
correspond to the group nesting of m
?
nitc :: ModelBuilder :: mclassdef2nclassdef
Registration of the nclassdef associated to each mclassdefnitc :: ModelBuilder :: mclassdef2nclassdef=
Registration of the nclassdef associated to each mclassdefnitc :: ModelBuilder :: mclassdef2node
Retrieve the associated AST node of a mclassdef.nitc :: ModelBuilder :: mentity2node
Retrieve the associated AST node of a mentity.nitc :: ModelBuilder :: mmodule2nmodule
Register the nmodule associated to each mmodulenitc :: ModelBuilder :: mmodule2nmodule=
Register the nmodule associated to each mmodulenitc :: ModelBuilder :: mmodule2node
Retrieve the associated AST node of a mmodule.nitc :: ModelBuilder :: model
The model where new modules, classes and properties are addednitc :: ModelBuilder :: model=
The model where new modules, classes and properties are addednitc :: ModelBuilder :: module_absolute_path
Transform relative paths (starting with '../') into absolute pathsnitc :: ModelBuilder :: mpropdef2node
Retrieve the associated AST node of a mpropertydef.nitc :: ModelBuilder :: mpropdef2npropdef
Registration of the npropdef associated to each mpropdef.nitc :: ModelBuilder :: mpropdef2npropdef=
Registration of the npropdef associated to each mpropdef.core :: Object :: native_class_name
The class name of the object in CString format.nitc :: ModelBuilder :: nb_invok_by_direct
Count number of invocations by direct callnitc :: ModelBuilder :: nb_invok_by_direct=
Count number of invocations by direct callnitc :: ModelBuilder :: nb_invok_by_inline
Count number of invocations by inliningnitc :: ModelBuilder :: nb_invok_by_inline=
Count number of invocations by inliningnitc :: ModelBuilder :: nb_invok_by_tables
Count number of invocations by VFTnitc :: ModelBuilder :: nb_invok_by_tables=
Count number of invocations by VFTcore :: Object :: output_class_name
Display class name on stdout (debug only).nitc :: ModelBuilder :: parse_full
Load a bunch of modules and groups.nitc :: ModelBuilder :: parsed_modules
All the currently parsed modules.nitc :: ModelBuilder :: parsed_modules=
All the currently parsed modules.nitc :: ModelBuilder :: process_default_constructors
Introduce or inherit default constructornitc :: ModelBuilder :: resolve_mtype
Return the static type associated to the nodentype
.
nitc :: ModelBuilder :: resolve_mtype3
Return the static type associated to the nodentype
.
nitc :: ModelBuilder :: resolve_mtype3_unchecked
Return the static type associated to the nodentype
.
nitc :: ModelBuilder :: resolve_mtype_unchecked
Return the static type associated to the nodentype
.
nitc :: ModelBuilder :: run_global_compiler
Entry point to performs a global compilation on the AST of a complete program.nitc :: ModelBuilder :: run_java_compiler
Start the Java compilernitc :: ModelBuilder :: run_naive_interpreter
Execute the program from the entry point (Sys::main
) of the mainmodule
nitc :: ModelBuilder :: scan_group
Force the identification of all MModule of the group and sub-groups in the file system.nitc :: ModelBuilder :: search_group_in_paths
Search groups namedname
from paths lookpaths
.
nitc :: ModelBuilder :: search_mmodule_by_name
Like (and used by)get_mmodule_by_name
but does not force the parsing of the MModule (cf. identify_module
)
nitc :: ModelBuilder :: search_module_by_amodule_name
Resolve the module identification for a givenAModuleName
.
nitc :: ModelBuilder :: search_module_in_paths
Search a modulename
from path lookpaths
.
nitc :: ModelBuilder :: test_group
Extracts and executes all the docunits in the readme of themgroup
nitc :: ModelBuilder :: test_markdown
Extracts and executes all the docunits in themmodule
nitc :: ModelBuilder :: the_root_init_mmethod
the root init of the Object classnitc :: ModelBuilder :: the_root_init_mmethod=
the root init of the Object classnitc :: ModelBuilder :: toolcontext
The toolcontext used to control the interaction with the user (getting options and displaying messages)nitc :: ModelBuilder :: toolcontext=
The toolcontext used to control the interaction with the user (getting options and displaying messages)nitc :: ModelBuilder :: total_classes=
Number of test classes generated.nitc :: ModelBuilder :: total_entities=
Total number analyzedMEntity
nitc :: ModelBuilder :: total_tests=
Number of tests generated.nitc :: ModelBuilder :: try_get_mclass_by_name
Return a class namedname
visible by the module mmodule
.
nitc :: ModelBuilder :: try_get_mclass_by_qid
Return a class identified byqid
visible by the module mmodule
.
nitc :: ModelBuilder :: try_get_mproperty_by_name
Alias for try_get_mproperty_by_name2(anode, mclassdef.mmodule, mclassdef.mtype, name)nitc :: ModelBuilder :: try_get_mproperty_by_name2
Return a property namedname
on the type mtype
visible in the module mmodule
.
nitc :: ModelBuilder :: unit_entities=
The total number of executed docunitsnitc :: ModelBuilder :: unsafe_add_mclassdef2nclassdef
Associate anclassdef
with its mclassdef
nitc :: ModelBuilder :: unsafe_add_mpropdef2npropdef
Associate anpropdef
with its mpropdef
nitc :: ModelBuilder :: write_and_make
Write Java code and compile it into an executable jarnitc :: ModelBuilder :: write_and_make
Simple indirection toToolchain::write_and_make
nitc :: ModelBuilder :: write_java_files
Write files managed bycompiler
into concrete files
nitc :: ModelBuilder :: write_makefile
Write the Makefile used to compile Java generated files into an executable jarnitc :: ModelBuilder :: write_manifest
Write the Java manifest filenitc :: ModelBuilder :: write_poset_to_file
Writeposet
to a C file
nitc :: ModelBuilder :: write_shell_script
Write a simple bash script that runs the jar like it was a binary generated by nitc
# A model builder knows how to load nit source files and build the associated model
class ModelBuilder
# The model where new modules, classes and properties are added
var model: Model
# The toolcontext used to control the interaction with the user (getting options and displaying messages)
var toolcontext: ToolContext
# Instantiate a modelbuilder for a model and a toolcontext
# Important, the options of the toolcontext must be correctly set (parse_option already called)
init
do
assert toolcontext.modelbuilder_real == null
toolcontext.modelbuilder_real = self
end
# Return a class named `name` visible by the module `mmodule`.
# Visibility in modules is correctly handled.
# If no such a class exists, then null is returned.
# If more than one class exists, then an error on `anode` is displayed and null is returned.
# FIXME: add a way to handle class name conflict
fun try_get_mclass_by_name(anode: nullable ANode, mmodule: MModule, name: String): nullable MClass
do
var classes = model.get_mclasses_by_name(name)
if classes == null then
return null
end
var res: nullable MClass = null
for mclass in classes do
if not mmodule.in_importation <= mclass.intro_mmodule then continue
if not mmodule.is_visible(mclass.intro_mmodule, mclass.visibility) then continue
if res == null then
res = mclass
else
error(anode, "Error: ambiguous class name `{name}`; conflict between `{mclass.full_name}` and `{res.full_name}`.")
return null
end
end
return res
end
# Return a class identified by `qid` visible by the module `mmodule`.
# Visibility in modules and qualified names are correctly handled.
#
# If more than one class exists, then null is silently returned.
# It is up to the caller to post-analysis the result and display a correct error message.
# The method `class_not_found` can be used to display such a message.
fun try_get_mclass_by_qid(qid: AQclassid, mmodule: MModule): nullable MClass
do
var name = qid.n_id.text
var classes = model.get_mclasses_by_name(name)
if classes == null then
return null
end
var res: nullable MClass = null
for mclass in classes do
if not mmodule.in_importation <= mclass.intro_mmodule then continue
if not mmodule.is_visible(mclass.intro_mmodule, mclass.visibility) then continue
if not qid.accept(mclass) then continue
if res == null then
res = mclass
else
return null
end
end
return res
end
# Like `try_get_mclass_by_name` but display an error message when the class is not found
fun get_mclass_by_name(node: nullable ANode, mmodule: MModule, name: String): nullable MClass
do
var mclass = try_get_mclass_by_name(node, mmodule, name)
if mclass == null then
error(node, "Type Error: missing primitive class `{name}'.")
end
return mclass
end
# Return a property named `name` on the type `mtype` visible in the module `mmodule`.
# Visibility in modules is correctly handled.
# Protected properties are returned (it is up to the caller to check and reject protected properties).
# If no such a property exists, then null is returned.
# If more than one property exists, then an error on `anode` is displayed and null is returned.
# FIXME: add a way to handle property name conflict
fun try_get_mproperty_by_name2(anode: nullable ANode, mmodule: MModule, mtype: MType, name: String): nullable MProperty
do
var props = self.model.get_mproperties_by_name(name)
if props == null then
return null
end
var cache = self.try_get_mproperty_by_name2_cache[mmodule, mtype, name]
if cache != null then return cache
var res: nullable MProperty = null
var ress: nullable Array[MProperty] = null
for mprop in props do
if not mtype.has_mproperty(mmodule, mprop) then continue
if not mmodule.is_visible(mprop.intro_mclassdef.mmodule, mprop.visibility) then continue
# new-factories are invisible outside of the class
if mprop isa MMethod and mprop.is_new and (not mtype isa MClassType or mprop.intro_mclassdef.mclass != mtype.mclass) then
continue
end
if res == null then
res = mprop
continue
end
# Two global properties?
# First, special case for init, keep the most specific ones
if res isa MMethod and mprop isa MMethod and res.is_init and mprop.is_init then
var restype = res.intro_mclassdef.bound_mtype
var mproptype = mprop.intro_mclassdef.bound_mtype
if mproptype.is_subtype(mmodule, null, restype) then
# found a most specific constructor, so keep it
res = mprop
continue
end
end
# Ok, just keep all prop in the ress table
if ress == null then
ress = new Array[MProperty]
ress.add(res)
end
ress.add(mprop)
end
# There is conflict?
if ress != null and res isa MMethod and res.is_init then
# special case forinit again
var restype = res.intro_mclassdef.bound_mtype
var ress2 = new Array[MProperty]
for mprop in ress do
var mproptype = mprop.intro_mclassdef.bound_mtype
if not restype.is_subtype(mmodule, null, mproptype) then
ress2.add(mprop)
else if not mprop isa MMethod or not mprop.is_init then
ress2.add(mprop)
end
end
if ress2.is_empty then
ress = null
else
ress = ress2
ress.add(res)
end
end
if ress != null then
assert ress.length > 1
var s = new Array[String]
for mprop in ress do s.add mprop.full_name
self.error(anode, "Error: ambiguous property name `{name}` for `{mtype}`; conflict between {s.join(" and ")}.")
end
self.try_get_mproperty_by_name2_cache[mmodule, mtype, name] = res
return res
end
private var try_get_mproperty_by_name2_cache = new HashMap3[MModule, MType, String, nullable MProperty]
# Alias for try_get_mproperty_by_name2(anode, mclassdef.mmodule, mclassdef.mtype, name)
fun try_get_mproperty_by_name(anode: nullable ANode, mclassdef: MClassDef, name: String): nullable MProperty
do
return try_get_mproperty_by_name2(anode, mclassdef.mmodule, mclassdef.bound_mtype, name)
end
# Helper function to display an error on a node.
# Alias for `self.toolcontext.error(n.hot_location, text)`
#
# This automatically sets `n.is_broken` to true.
fun error(n: nullable ANode, text: String)
do
var l = null
if n != null then
l = n.hot_location
n.is_broken = true
end
self.toolcontext.error(l, text)
end
# Helper function to display a warning on a node.
# Alias for: `self.toolcontext.warning(n.hot_location, text)`
fun warning(n: nullable ANode, tag, text: String)
do
var l = null
if n != null then l = n.hot_location
self.toolcontext.warning(l, tag, text)
end
# Helper function to display an advice on a node.
# Alias for: `self.toolcontext.advice(n.hot_location, text)`
fun advice(n: nullable ANode, tag, text: String)
do
var l = null
if n != null then l = n.hot_location
self.toolcontext.advice(l, tag, text)
end
# Force to get the primitive method named `name` on the type `recv` or do a fatal error on `n`
fun force_get_primitive_method(n: nullable ANode, name: String, recv: MClass, mmodule: MModule): MMethod
do
var res = mmodule.try_get_primitive_method(name, recv)
if res == null then
var l = null
if n != null then l = n.hot_location
self.toolcontext.fatal_error(l, "Fatal Error: `{recv}` must have a property named `{name}`.")
abort
end
return res
end
# Return the static type associated to the node `ntype`.
#
# `mclassdef` is the context where the call is made (used to understand
# formal types).
# In case of problem, an error is displayed on `ntype` and null is returned.
#
# Same as `resolve_mtype_unchecked3`, but get the context (module, class and
# anchor) from `mclassdef`.
#
# SEE: `resolve_mtype`
# SEE: `resolve_mtype3_unchecked`
#
# FIXME: Find a better name for this method.
fun resolve_mtype_unchecked(mclassdef: MClassDef, ntype: AType, with_virtual: Bool): nullable MType
do
return resolve_mtype3_unchecked(
mclassdef.mmodule,
mclassdef.mclass,
mclassdef.bound_mtype,
ntype,
with_virtual
)
end
# Return the static type associated to the node `ntype`.
#
# `mmodule`, `mclass` and `anchor` compose the context where the call is
# made (used to understand formal types).
# In case of problem, an error is displayed on `ntype` and null is returned.
#
# Note: The “3” is for 3 contextual parameters.
#
# SEE: `resolve_mtype`
# SEE: `resolve_mtype_unchecked`
#
# FIXME: Find a better name for this method.
fun resolve_mtype3_unchecked(mmodule: MModule, mclass: nullable MClass, anchor: nullable MClassType, ntype: AType, with_virtual: Bool): nullable MType
do
var qid = ntype.n_qid
var name = qid.n_id.text
var res: MType
# Check virtual type
if anchor != null and with_virtual then
var prop = try_get_mproperty_by_name2(ntype, mmodule, anchor, name).as(nullable MVirtualTypeProp)
if prop != null then
if not ntype.n_types.is_empty then
error(ntype, "Type Error: formal type `{name}` cannot have formal parameters.")
end
res = prop.mvirtualtype
if ntype.n_kwnullable != null then res = res.as_nullable
ntype.mtype = res
return res
end
end
# Check parameter type
if mclass != null then
for p in mclass.mparameters do
if p.name != name then continue
if not ntype.n_types.is_empty then
error(ntype, "Type Error: formal type `{name}` cannot have formal parameters.")
end
res = p
if ntype.n_kwnullable != null then res = res.as_nullable
ntype.mtype = res
return res
end
end
# Check class
var found_class = try_get_mclass_by_qid(qid, mmodule)
if found_class != null then
var arity = ntype.n_types.length
if arity != found_class.arity then
if arity == 0 then
error(ntype, "Type Error: `{found_class.signature_to_s}` is a generic class.")
else if found_class.arity == 0 then
error(ntype, "Type Error: `{name}` is not a generic class.")
else
error(ntype, "Type Error: expected {found_class.arity} formal argument(s) for `{found_class.signature_to_s}`; got {arity}.")
end
return null
end
if arity == 0 then
res = found_class.mclass_type
if ntype.n_kwnullable != null then res = res.as_nullable
ntype.mtype = res
return res
else
var mtypes = new Array[MType]
for nt in ntype.n_types do
var mt = resolve_mtype3_unchecked(mmodule, mclass, anchor, nt, with_virtual)
if mt == null then return null # Forward error
mtypes.add(mt)
end
res = found_class.get_mtype(mtypes)
if ntype.n_kwnullable != null then res = res.as_nullable
ntype.mtype = res
return res
end
end
# If everything fail, then give up with class by proposing things.
#
# TODO Give hints on formal types (param and virtual)
class_not_found(qid, mmodule)
ntype.is_broken = true
return null
end
# Print an error and suggest hints when the class identified by `qid` in `mmodule` is not found.
#
# This just print error messages.
fun class_not_found(qid: AQclassid, mmodule: MModule)
do
var name = qid.n_id.text
var qname = qid.full_name
if bad_class_names[mmodule].has(qname) then
error(qid, "Error: class `{qname}` not found in module `{mmodule}`.")
return
end
bad_class_names[mmodule].add(qname)
var all_classes = model.get_mclasses_by_name(name)
var hints = new Array[String]
# Look for conflicting classes.
if all_classes != null then for c in all_classes do
if not mmodule.is_visible(c.intro_mmodule, c.visibility) then continue
if not qid.accept(c) then continue
hints.add "`{c.full_name}`"
end
if hints.length > 1 then
error(qid, "Error: ambiguous class name `{qname}` in module `{mmodule}`. Conflicts are between {hints.join(",", " and ")}.")
return
end
hints.clear
# Look for imported but invisible classes.
if all_classes != null then for c in all_classes do
if not mmodule.in_importation <= c.intro_mmodule then continue
if mmodule.is_visible(c.intro_mmodule, c.visibility) then continue
if not qid.accept(c) then continue
error(qid, "Error: class `{c.full_name}` not visible in module `{mmodule}`.")
return
end
# Look for not imported but known classes from importable modules
if all_classes != null then for c in all_classes do
if mmodule.in_importation <= c.intro_mmodule then continue
if c.intro_mmodule.in_importation <= mmodule then continue
if c.visibility <= private_visibility then continue
if not qid.accept(c) then continue
hints.add "`{c.intro_mmodule.full_name}`"
end
if hints.not_empty then
error(qid, "Error: class `{qname}` not found in module `{mmodule}`. Maybe import {hints.join(",", " or ")}?")
return
end
# Look for classes with an approximative name.
var bests = new BestDistance[MClass](qname.length - name.length / 2) # limit up to 50% name change
for c in model.mclasses do
if not mmodule.in_importation <= c.intro_mmodule then continue
if not mmodule.is_visible(c.intro_mmodule, c.visibility) then continue
var d = qname.levenshtein_distance(c.name)
bests.update(d, c)
d = qname.levenshtein_distance(c.full_name)
bests.update(d, c)
end
if bests.best_items.not_empty then
for c in bests.best_items do hints.add "`{c.full_name}`"
error(qid, "Error: class `{qname}` not found in module `{mmodule}`. Did you mean {hints.join(",", " or ")}?")
return
end
error(qid, "Error: class `{qname}` not found in module `{mmodule}`.")
end
# List of already reported bad class names.
# Used to not perform and repeat hints again and again.
private var bad_class_names = new MultiHashMap[MModule, String]
# Return the static type associated to the node `ntype`.
#
# `mclassdef` is the context where the call is made (used to understand
# formal types).
# In case of problem, an error is displayed on `ntype` and null is returned.
#
# Same as `resolve_mtype3`, but get the context (module, class and ) from
# `mclassdef`.
#
# SEE: `resolve_mtype3`
# SEE: `resolve_mtype_unchecked`
#
# FIXME: Find a better name for this method.
fun resolve_mtype(mclassdef: MClassDef, ntype: AType): nullable MType
do
return resolve_mtype3(
mclassdef.mmodule,
mclassdef.mclass,
mclassdef.bound_mtype,
ntype
)
end
# Return the static type associated to the node `ntype`.
#
# `mmodule`, `mclass` and `anchor` compose the context where the call is
# made (used to understand formal types).
# In case of problem, an error is displayed on `ntype` and null is returned.
#
# Note: The “3” is for 3 contextual parameters.
#
# SEE: `resolve_mtype`
# SEE: `resolve_mtype_unchecked`
#
# FIXME: Find a better name for this method.
fun resolve_mtype3(mmodule: MModule, mclass: nullable MClass, anchor: nullable MClassType, ntype: AType): nullable MType
do
var mtype = ntype.mtype
if mtype == null then mtype = resolve_mtype3_unchecked(mmodule, mclass, anchor, ntype, true)
if mtype == null then return null # Forward error
if ntype.checked_mtype then return mtype
if mtype isa MGenericType then
var found_class = mtype.mclass
for i in [0..found_class.arity[ do
var intro = found_class.try_intro
if intro == null then return null # skip error
var bound = intro.bound_mtype.arguments[i]
var nt = ntype.n_types[i]
var mt = resolve_mtype3(mmodule, mclass, anchor, nt)
if mt == null then return null # forward error
if not check_subtype(nt, mmodule, anchor, mt, bound) then
error(nt, "Type Error: expected `{bound}`, got `{mt}`.")
return null
end
end
end
ntype.checked_mtype = true
return mtype
end
# Check that `sub` is a subtype of `sup`.
# Do not display an error message.
#
# This method is used a an entry point for the modelize phase to test static subtypes.
# Some refinements could redefine it to collect statictics.
fun check_subtype(node: ANode, mmodule: MModule, anchor: nullable MClassType, sub, sup: MType): Bool
do
return sub.is_subtype(mmodule, anchor, sup)
end
# Check that `sub` and `sup` are equvalent types.
# Do not display an error message.
#
# This method is used a an entry point for the modelize phase to test static equivalent types.
# Some refinements could redefine it to collect statictics.
fun check_sametype(node: ANode, mmodule: MModule, anchor: nullable MClassType, sub, sup: MType): Bool
do
return sub.is_subtype(mmodule, anchor, sup) and sup.is_subtype(mmodule, anchor, sub)
end
end
src/modelbuilder_base.nit:42,1--529,3
redef class ModelBuilder
redef init
do
super
# Setup the paths value
paths.append(toolcontext.opt_path.value)
# Packages managed by nitpm, only use when not testing with tests.sh
if "NIT_TESTING_TESTS_SH".environ != "true" then
paths.add nitpm_lib_dir
end
var path_env = "NIT_PATH".environ
if not path_env.is_empty then
paths.append(path_env.split_with(':'))
end
var nit_dir = toolcontext.nit_dir
if nit_dir != null then
var libname = nit_dir/"lib"
if libname.file_exists then paths.add(libname)
libname = nit_dir/"contrib"
if libname.file_exists then paths.add(libname)
end
end
# Load a bunch of modules.
# `modules` can contains filenames or module names.
# Imported modules are automatically loaded and modelized.
# The result is the corresponding model elements.
# Errors and warnings are printed with the toolcontext.
#
# Note: class and property model elements are not analysed.
fun parse(modules: Sequence[String]): Array[MModule]
do
var time0 = get_time
# Parse and recursively load
self.toolcontext.info("*** PARSE ***", 1)
var mmodules = new ArraySet[MModule]
for a in modules do
var nmodule = self.load_module(a)
if nmodule == null then continue # Skip error
var mmodule = nmodule.mmodule
if mmodule == null then continue # skip error
mmodules.add mmodule
end
var time1 = get_time
self.toolcontext.info("*** END PARSE: {time1-time0} ***", 2)
self.toolcontext.check_errors
if toolcontext.opt_only_parse.value then
self.toolcontext.info("*** ONLY PARSE...", 1)
self.toolcontext.quit
end
return mmodules.to_a
end
# Identify a bunch of modules and groups.
#
# This does the same as `parse_full` but does only the identification (cf. `identify_module`)
fun scan_full(names: Sequence[String]): Array[MModule]
do
var mmodules = new Array[MModule]
for a in names do
# Case of a group (root or sub-directory)
var mgroup = self.identify_group(a)
if mgroup != null then
scan_group(mgroup)
for mg in mgroup.in_nesting.smallers do mmodules.add_all mg.mmodules
continue
end
# Case of a directory that is not a group
var stat = a.to_path.stat
if stat != null and stat.is_dir then
self.toolcontext.info("look in directory {a}", 2)
var fs = a.files
alpha_comparator.sort(fs)
# Try each entry as a group or a module
for f in fs do
if f.first == '.' then continue
var af = a/f
mgroup = identify_group(af)
if mgroup != null then
scan_group(mgroup)
for mg in mgroup.in_nesting.smallers do mmodules.add_all mg.mmodules
continue
end
var mmodule = identify_module(af)
if mmodule != null then
mmodules.add mmodule
else
self.toolcontext.info("ignore file {af}", 2)
end
end
continue
end
var mmodule = identify_module(a)
if mmodule == null then
var le = last_loader_error
if le != null then
toolcontext.error(null, le)
else if a.file_exists then
toolcontext.error(null, "Error: `{a}` is not a Nit source file.")
else
toolcontext.error(null, "Error: cannot find module `{a}`.")
end
continue
end
mmodules.add mmodule
end
return mmodules
end
# Load a bunch of modules and groups.
#
# Each name can be:
#
# * a path to a module, a group or a directory of packages.
# * a short name of a module or a group that are looked in the `paths` (-I)
#
# Then, for each entry, if it is:
#
# * a module, then is it parsed and returned.
# * a group then recursively all its modules are parsed.
# * a directory of packages then all the modules of all packages are parsed.
# * else an error is displayed.
#
# See `parse` for details.
fun parse_full(names: Sequence[String]): Array[MModule]
do
var time0 = get_time
# Parse and recursively load
self.toolcontext.info("*** PARSE ***", 1)
var mmodules = new ArraySet[MModule]
var scans = scan_full(names)
for mmodule in scans do
var ast = mmodule.load(self)
if ast == null then continue # Skip error
mmodules.add mmodule
end
var time1 = get_time
self.toolcontext.info("*** END PARSE: {time1-time0} ***", 2)
self.toolcontext.check_errors
if toolcontext.opt_only_parse.value then
self.toolcontext.info("*** ONLY PARSE...", 1)
self.toolcontext.quit
end
return mmodules.to_a
end
# The list of directories to search for top level modules
# The list is initially set with:
#
# * the toolcontext --path option
# * the NIT_PATH environment variable
# * `toolcontext.nit_dir`
# Path can be added (or removed) by the client
var paths = new Array[String]
# Like (and used by) `get_mmodule_by_name` but does not force the parsing of the MModule (cf. `identify_module`)
fun search_mmodule_by_name(anode: nullable ANode, mgroup: nullable MGroup, name: String): nullable MModule
do
# First, look in groups
var c = mgroup
if c != null then
var r = c.mpackage.root
assert r != null
scan_group(r)
var res = r.mmodules_by_name(name)
if res.not_empty then return res.first
end
# Look at some known directories
var lookpaths = self.paths
# Look in the directory of the group package also (even if not explicitly in the path)
if mgroup != null then
# path of the root group
var dirname = mgroup.mpackage.root.filepath
if dirname != null then
dirname = dirname.join_path("..").simplify_path
if not lookpaths.has(dirname) and dirname.file_exists then
lookpaths = lookpaths.to_a
lookpaths.add(dirname)
end
end
end
if mgroup != null then
var alias = mgroup.mpackage.import_alias(name)
if alias != null then name = alias
end
var loc = null
if anode != null then loc = anode.hot_location
var candidate = search_module_in_paths(loc, name, lookpaths)
if candidate == null then
if mgroup != null then
error(anode, "Error: cannot find module `{name}` from `{mgroup.name}`. Tried: {lookpaths.join(", ")}.")
else
error(anode, "Error: cannot find module `{name}`. Tried: {lookpaths.join(", ")}.")
end
return null
end
return candidate
end
# Get a module by its short name; if required, the module is loaded, parsed and its hierarchies computed.
# If `mgroup` is set, then the module search starts from it up to the top level (see `paths`);
# if `mgroup` is null then the module is searched in the top level only.
# If no module exists or there is a name conflict, then an error on `anode` is displayed and null is returned.
fun get_mmodule_by_name(anode: nullable ANode, mgroup: nullable MGroup, name: String): nullable MModule
do
var mmodule = search_mmodule_by_name(anode, mgroup, name)
if mmodule == null then return null # Forward error
var ast = mmodule.load(self)
if ast == null then return null # Forward error
return mmodule
end
# Search a module `name` from path `lookpaths`.
# If found, the module is returned.
private fun search_module_in_paths(location: nullable Location, name: String, lookpaths: Collection[String]): nullable MModule
do
var name_no_version
if name.has('=') then
name_no_version = name.split('=').first
else name_no_version = name
var res = new ArraySet[MModule]
for dirname in lookpaths do
# Try a single module file
var mp = identify_module((dirname/"{name}.nit").simplify_path)
if mp != null then res.add mp
# Try the default module of a group
var g = identify_group((dirname/name).simplify_path)
if g != null then
scan_group(g)
res.add_all g.mmodules_by_name(name_no_version)
end
end
if res.is_empty then return null
if res.length > 1 then
toolcontext.error(location, "Error: conflicting module files for `{name}`: `{[for x in res do x.filepath or else x.full_name].join("`, `")}`")
end
return res.first
end
# Search groups named `name` from paths `lookpaths`.
private fun search_group_in_paths(name: String, lookpaths: Collection[String]): ArraySet[MGroup]
do
var res = new ArraySet[MGroup]
for dirname in lookpaths do
# try a single group directory
var mg = identify_group(dirname/name)
if mg != null then
res.add mg
end
end
return res
end
# Cache for `identify_module` by relative and real paths
private var identified_modules_by_path = new HashMap[String, nullable MModule]
# All the currently identified modules.
# See `identify_module`.
#
# An identified module exists in the model but might be not yet parsed (no AST), or not yet analysed (no importation).
var identified_modules = new Array[MModule]
# All the currently parsed modules.
#
# A parsed module exists in the model but might be not yet analysed (no importation).
var parsed_modules = new Array[MModule]
# Some `loader` services are silent and return `null` on error.
#
# Those services can set `last_loader_error` to precise an specific error message.
# if `last_loader_error == null` then a generic error message can be used.
#
# See `identified_modules` and `identify_group` for details.
var last_loader_error: nullable String = null
# Identify a source file and load the associated package and groups if required.
#
# This method does what the user expects when giving an argument to a Nit tool.
#
# * If `path` is an existing Nit source file (with the `.nit` extension),
# then the associated MModule is returned
# * If `path` is a directory (with a `/`),
# then the MModule of its default module is returned (if any)
# * If `path` is a simple identifier (eg. `digraph`),
# then the main module of the package `digraph` is searched in `paths` and returned.
#
# Silently return `null` if `path` does not exists or cannot be identified.
# If `null` is returned, `last_loader_error` can be set to a specific error message.
#
# On success, it returns a module that is possibly not yet parsed (no AST), or not yet analysed (no importation).
# If the module was already identified, or loaded, it is returned.
fun identify_module(path: String): nullable MModule
do
last_loader_error = null
# special case for not a nit file
if not path.has_suffix(".nit") then do
# search dirless files in known -I paths
if not path.chars.has('/') then
var res = search_module_in_paths(null, path, self.paths)
if res != null then return res
end
# Found nothing? maybe it is a group...
if path.file_exists then
var mgroup = identify_group(path)
if mgroup != null then
var owner_path = mgroup.filepath.join_path(mgroup.name + ".nit")
if owner_path.file_exists then
path = owner_path
break
end
end
end
# Found nothing? maybe it is a qualified name
if path.chars.has(':') then
var ids = path.split("::")
var g = identify_group(ids.first)
if g != null then
scan_group(g)
var ms = g.mmodules_by_name(ids.last)
# Return exact match
for m in ms do
if m.full_name == path then
return m
end
end
# Where there is only one or two names `foo::bar`
# then accept module that matches `foo::*::bar`
if ids.length <= 2 then
if ms.length == 1 then return ms.first
if ms.length > 1 then
var l = new Array[String]
for m in ms do
var fp = m.filepath
if fp != null then fp = " ({fp})" else fp = ""
l.add "`{m.full_name}`{fp}"
end
last_loader_error = "Error: conflicting module for `{path}`: {l.join(", ")} "
return null
end
end
var bests = new BestDistance[String](path.length / 2)
# We found nothing. But propose something in the package?
for sg in g.mpackage.mgroups do
for m in sg.mmodules do
var d = path.levenshtein_distance(m.full_name)
bests.update(d, m.full_name)
end
end
var last_loader_error = "Error: cannot find module `{path}`."
if bests.best_items.not_empty then
last_loader_error += " Did you mean " + bests.best_items.join(", ", " or ") + "?"
end
self.last_loader_error = last_loader_error
return null
end
end
return null
end
# Does the file exists?
if not path.file_exists then
return null
end
# Fast track, the path is already known
if identified_modules_by_path.has_key(path) then return identified_modules_by_path[path]
var rp = module_absolute_path(path)
if identified_modules_by_path.has_key(rp) then return identified_modules_by_path[rp]
var pn = path.basename(".nit")
# Search for a group
var mgrouppath = path.join_path("..").simplify_path
var mgroup = identify_group(mgrouppath)
if mgroup != null then
var mpackage = mgroup.mpackage
if not mpackage.accept(path) then
mgroup = null
toolcontext.info("module `{path}` excluded from package `{mpackage}`", 2)
end
end
if mgroup == null then
# singleton package
var loc = new Location.opaque_file(path)
var mpackage = new MPackage(pn, model, loc)
mgroup = new MGroup(pn, loc, mpackage, null) # same name for the root group
mpackage.root = mgroup
toolcontext.info("found singleton package `{pn}` at {path}", 2)
# Attach homonymous `ini` file to the package
var inipath = path.dirname / "{pn}.ini"
if inipath.file_exists then
var ini = new IniFile.from_file(inipath)
mpackage.ini = ini
end
end
var loc = new Location.opaque_file(path)
var res = new MModule(model, mgroup, pn, loc)
identified_modules_by_path[rp] = res
identified_modules_by_path[path] = res
identified_modules.add(res)
return res
end
# Groups by path
private var mgroups = new HashMap[String, nullable MGroup]
# Return the mgroup associated to a directory path.
# If the directory is not a group null is returned.
#
# Silently return `null` if `dirpath` does not exists, is not a directory,
# cannot be identified or cannot be attached to a mpackage.
# If `null` is returned, `last_loader_error` can be set to a specific error message.
#
# Note: `paths` is also used to look for mgroups
fun identify_group(dirpath: String): nullable MGroup
do
# Reset error
last_loader_error = null
var stat = dirpath.file_stat
if stat == null or not stat.is_dir then do
# search dirless directories in known -I paths
if dirpath.chars.has('/') then return null
for p in paths do
var try = p / dirpath
stat = try.file_stat
if stat != null then
dirpath = try
break label
end
end
return null
end label
# Filter out non-directories
if not stat.is_dir then
last_loader_error = "Error: `{dirpath}` is not a directory."
return null
end
# Fast track, the path is already known
var rdp = module_absolute_path(dirpath)
if mgroups.has_key(rdp) then
return mgroups[rdp]
end
# By default, the name of the package or group is the base_name of the directory
var pn = rdp.basename
# Check `package.ini` that indicate a package
var ini = null
var parent = null
var inipath = dirpath / "package.ini"
if inipath.file_exists then
ini = new IniFile.from_file(inipath)
end
if ini == null then
# No ini, multiple course of action
# The root of the directory hierarchy in the file system.
if rdp == "/" then
mgroups[rdp] = null
last_loader_error = "Error: `{dirpath}` is not a Nit package."
return null
end
# Special stopper `packages.ini`
if (dirpath/"packages.ini").file_exists then
# dirpath cannot be a package since it is a package directory
mgroups[rdp] = null
last_loader_error = "Error: `{dirpath}` is not a Nit package."
return null
end
# check the parent directory (if it does not contain the stopper file)
var parentpath = dirpath.join_path("..").simplify_path
var stopper = parentpath / "packages.ini"
if not stopper.file_exists then
# Recursively get the parent group
parent = identify_group(parentpath)
if parent != null then do
var mpackage = parent.mpackage
if not mpackage.accept(dirpath) then
toolcontext.info("directory `{dirpath}` excluded from package `{mpackage}`", 2)
parent = null
end
end
if parent == null then
# Parent is not a group, thus we are not a group either
mgroups[rdp] = null
last_loader_error = "Error: `{dirpath}` is not a Nit package."
return null
end
end
end
var loc = new Location.opaque_file(dirpath)
var mgroup
if parent == null then
# no parent, thus new package
if ini != null then pn = ini["package.name"] or else pn
var mpackage = new MPackage(pn, model, loc)
mgroup = new MGroup(pn, loc, mpackage, null) # same name for the root group
mpackage.root = mgroup
toolcontext.info("found package `{mpackage}` at {dirpath}", 2)
mpackage.ini = ini
else
mgroup = new MGroup(pn, loc, parent.mpackage, parent)
toolcontext.info("found sub group `{mgroup.full_name}` at {dirpath}", 2)
end
# search documentation
# in src first so the documentation of the package code can be distinct for the documentation of the package usage
var readme = dirpath.join_path("README.md")
if not readme.file_exists then readme = dirpath.join_path("README")
if readme.file_exists then
var mdoc = load_markdown(readme)
mgroup.mdoc = mdoc
mdoc.original_mentity = mgroup
end
mgroups[rdp] = mgroup
return mgroup
end
# Load a markdown file as a documentation object
fun load_markdown(filepath: String): MDoc
do
var s = new FileReader.open(filepath)
var lines = new Array[String]
var line_starts = new Array[Int]
var len = 1
while not s.eof do
var line = s.read_line
lines.add(line)
line_starts.add(len)
len += line.length + 1
end
s.close
var source = new SourceFile.from_string(filepath, lines.join("\n"))
source.line_starts.add_all line_starts
var mdoc = new MDoc(new Location(source, 1, lines.length, 0, 0))
mdoc.content.add_all(lines)
return mdoc
end
# Force the identification of all MModule of the group and sub-groups in the file system.
#
# When a group is scanned, its sub-groups hierarchy is filled (see `MGroup::in_nesting`)
# and the potential modules (and nested modules) are identified (see `MGroup::modules`).
#
# Basically, this recursively call `identify_group` and `identify_module` on each directory entry.
#
# No-op if the group was already scanned (see `MGroup::scanned`).
fun scan_group(mgroup: MGroup) do
if mgroup.scanned then return
mgroup.scanned = true
var p = mgroup.filepath
# a virtual group has nothing to scan
if p == null then return
var files = p.files
alpha_comparator.sort(files)
for f in files do
if f.first == '.' then continue
var fp = p/f
var g = identify_group(fp)
# Recursively scan for groups of the same package
if g == null then
identify_module(fp)
else if g.mpackage == mgroup.mpackage then
scan_group(g)
end
end
end
# Transform relative paths (starting with '../') into absolute paths
private fun module_absolute_path(path: String): String do
return path.realpath
end
# Try to load a module AST using a path.
# Display an error if there is a problem (IO / lexer / parser) and return null
#
# The AST is loaded as is total independence of the model and its entities.
#
# AST are not cached or reused thus a new AST is returned on success.
fun load_module_ast(filename: String): nullable AModule
do
if not filename.has_suffix(".nit") then
self.toolcontext.error(null, "Error: file `{filename}` is not a valid nit module.")
return null
end
if not filename.file_exists then
self.toolcontext.error(null, "Error: file `{filename}` not found.")
return null
end
self.toolcontext.info("load module {filename}", 2)
# Load the file
var file = new FileReader.open(filename)
var lexer = new Lexer(new SourceFile(filename, file))
var parser = new Parser(lexer)
var tree = parser.parse
file.close
# Handle lexer and parser error
var nmodule = tree.n_base
if nmodule == null then
var neof = tree.n_eof
assert neof isa AError
error(neof, neof.message)
return null
end
return nmodule
end
# Remove Nit source files from a list of arguments.
#
# Items of `args` that can be loaded as a nit file will be removed from `args` and returned.
fun filter_nit_source(args: Array[String]): Array[String]
do
var keep = new Array[String]
var res = new Array[String]
for a in args do
var stat = a.to_path.stat
if stat != null and stat.is_dir then
res.add a
continue
end
var l = identify_module(a)
if l == null then
keep.add a
else
res.add a
end
end
args.clear
args.add_all(keep)
return res
end
# Try to load a module using a path.
# Display an error if there is a problem (IO / lexer / parser) and return null.
# Note: usually, you do not need this method, use `get_mmodule_by_name` instead.
#
# The MModule is located, created, parsed and the importation is performed.
fun load_module(filename: String): nullable AModule
do
# Look for the module
var mmodule = identify_module(filename)
if mmodule == null then
var le = last_loader_error
if le != null then
toolcontext.error(null, le)
else if filename.file_exists then
toolcontext.error(null, "Error: `{filename}` is not a Nit source file.")
else
toolcontext.error(null, "Error: cannot find module `{filename}`.")
end
return null
end
# Load it
return mmodule.load(self)
end
# Injection of a new module without source.
# Used by the interpreter.
fun load_rt_module(parent: nullable MModule, nmodule: AModule, mod_name: String): nullable MModule
do
# Create the module
var mgroup = null
if parent != null then mgroup = parent.mgroup
var mmodule = new MModule(model, mgroup, mod_name, nmodule.location)
nmodule.mmodule = mmodule
nmodules.add(nmodule)
parsed_modules.add mmodule
self.mmodule2nmodule[mmodule] = nmodule
if parent!= null then
var imported_modules = new Array[MModule]
imported_modules.add(parent)
mmodule.set_visibility_for(parent, intrude_visibility)
mmodule.set_imported_mmodules(imported_modules)
end
build_module_importation(nmodule)
return mmodule
end
# Visit the AST and create the `MModule` object
private fun build_a_mmodule(mgroup: nullable MGroup, nmodule: AModule)
do
var mmodule = nmodule.mmodule
assert mmodule != null
# Check the module name
var decl = nmodule.n_moduledecl
if decl != null then
var decl_name = decl.n_name.n_id.text
if decl_name != mmodule.name then
warning(decl.n_name, "module-name-mismatch", "Error: module name mismatch; declared {decl_name} file named {mmodule.name}.")
end
end
# Check for conflicting module names in the package
if mgroup != null then
var others = model.get_mmodules_by_name(mmodule.name)
if others != null then for other in others do
if other != mmodule and mmodule2nmodule.has_key(mmodule) and other.mgroup!= null and other.mgroup.mpackage == mgroup.mpackage then
var node: ANode
if decl == null then node = nmodule else node = decl.n_name
error(node, "Error: a module named `{other.full_name}` already exists at {other.location}.")
break
end
end
end
nmodules.add(nmodule)
self.mmodule2nmodule[mmodule] = nmodule
var source = nmodule.location.file
if source != null then
assert source.mmodule == null
source.mmodule = mmodule
end
if decl != null then
# Extract documentation
var ndoc = decl.n_doc
if ndoc != null then
var mdoc = ndoc.to_mdoc
mmodule.mdoc = mdoc
mdoc.original_mentity = mmodule
end
# Is the module generated?
mmodule.is_generated = not decl.get_annotations("generated").is_empty
end
end
# Resolve the module identification for a given `AModuleName`.
#
# This method handles qualified names as used in `AModuleName`.
fun search_module_by_amodule_name(n_name: AModuleName, mgroup: nullable MGroup): nullable MModule
do
var mod_name = n_name.n_id.text
# If a quad is given, we ignore the starting group (go from path)
if n_name.n_quad != null then mgroup = null
# If name not qualified, just search the name
if n_name.n_path.is_empty then
# Fast search if no n_path
return search_mmodule_by_name(n_name, mgroup, mod_name)
end
# If qualified and in a group
if mgroup != null then
# First search in the package
var r = mgroup.mpackage.root
assert r != null
scan_group(r)
# Get all modules with the final name
var res = r.mmodules_by_name(mod_name)
# Filter out the name that does not match the qualifiers
res = [for x in res do if match_amodulename(n_name, x) then x]
if res.not_empty then
if res.length > 1 then
error(n_name, "Error: conflicting module files for `{mod_name}`: `{[for x in res do x.filepath or else x.full_name].join("`, `")}`")
end
return res.first
end
end
# If no module yet, then assume that the first element of the path
# Is to be searched in the path.
var root_name = n_name.n_path.first.text
# Search for an alias in required external packages
if mgroup != null then
var alias = mgroup.mpackage.import_alias(root_name)
if alias != null then root_name = alias
end
var roots = search_group_in_paths(root_name, paths)
if roots.is_empty then
error(n_name, "Error: cannot find `{root_name}`. Tried: {paths.join(", ")}.")
return null
end
var res = new ArraySet[MModule]
for r in roots do
# Then, for each root, collect modules that matches the qualifiers
scan_group(r)
var root_res = r.mmodules_by_name(mod_name)
for x in root_res do if match_amodulename(n_name, x) then res.add x
end
if res.not_empty then
if res.length > 1 then
error(n_name, "Error: conflicting module files for `{mod_name}`: `{[for x in res do x.filepath or else x.full_name].join("`, `")}`")
end
return res.first
end
# If still nothing, just call a basic search that will fail and will produce an error message
error(n_name, "Error: cannot find module `{mod_name}` from `{root_name}`. Tried: {paths.join(", ")}.")
return null
end
# Is elements of `n_name` correspond to the group nesting of `m`?
#
# Basically it check that `bar::foo` matches `bar/foo.nit` and `bar/baz/foo.nit`
# but not `baz/foo.nit` nor `foo/bar.nit`
#
# Is used by `search_module_by_amodule_name` to validate qualified names.
private fun match_amodulename(n_name: AModuleName, m: MModule): Bool
do
var g: nullable MGroup = m.mgroup
for grp in n_name.n_path.reverse_iterator do
while g != null and grp.text != g.name do
g = g.parent
end
end
return g != null
end
# Analyze the module importation and fill the module_importation_hierarchy
#
# If the importation was already done (`nmodule.is_importation_done`), this method does a no-op.
#
# REQUIRE `nmodule.mmodule != null`
# ENSURE `nmodule.is_importation_done`
fun build_module_importation(nmodule: AModule)
do
if nmodule.is_importation_done then return
nmodule.is_importation_done = true
var mmodule = nmodule.mmodule.as(not null)
var stdimport = true
var imported_modules = new Array[MModule]
for aimport in nmodule.n_imports do
# Do not imports conditional
var atconditionals = aimport.get_annotations("conditional")
if atconditionals.not_empty then continue
stdimport = false
if not aimport isa AStdImport then
continue
end
# Load the imported module
var sup = search_module_by_amodule_name(aimport.n_name, mmodule.mgroup)
if sup == null then
mmodule.is_broken = true
nmodule.mmodule = null # invalidate the module
continue # Skip error
end
var ast = sup.load(self)
if ast == null then
mmodule.is_broken = true
nmodule.mmodule = null # invalidate the module
continue # Skip error
end
aimport.mmodule = sup
imported_modules.add(sup)
var mvisibility = aimport.n_visibility.mvisibility
if mvisibility == protected_visibility then
mmodule.is_broken = true
error(aimport.n_visibility, "Error: only properties can be protected.")
mmodule.is_broken = true
nmodule.mmodule = null # invalidate the module
return
end
if sup == mmodule then
error(aimport.n_name, "Error: dependency loop in module {mmodule}.")
mmodule.is_broken = true
nmodule.mmodule = null # invalidate the module
end
if sup.in_importation < mmodule then
error(aimport.n_name, "Error: dependency loop between modules {mmodule} and {sup}.")
mmodule.is_broken = true
nmodule.mmodule = null # invalidate the module
return
end
mmodule.set_visibility_for(sup, mvisibility)
end
if stdimport then
var mod_name = "core"
var sup = self.get_mmodule_by_name(nmodule, null, mod_name)
if sup == null then
mmodule.is_broken = true
nmodule.mmodule = null # invalidate the module
else # Skip error
imported_modules.add(sup)
mmodule.set_visibility_for(sup, public_visibility)
end
end
# Declare conditional importation
for aimport in nmodule.n_imports do
if not aimport isa AStdImport then continue
var atconditionals = aimport.get_annotations("conditional")
if atconditionals.is_empty then continue
var suppath = search_module_by_amodule_name(aimport.n_name, mmodule.mgroup)
if suppath == null then continue # skip error
for atconditional in atconditionals do
var nargs = atconditional.n_args
if nargs.is_empty then
error(atconditional, "Syntax Error: `conditional` expects module identifiers as arguments.")
continue
end
# The rule
var rule = new Array[MModule]
# First element is the goal, thus
rule.add suppath
# Second element is the first condition, that is to be a client of the current module
rule.add mmodule
# Other condition are to be also a client of each modules indicated as arguments of the annotation
for narg in nargs do
var id = narg.as_id
if id == null then
error(narg, "Syntax Error: `conditional` expects module identifier as arguments.")
continue
end
var mp = search_mmodule_by_name(narg, mmodule.mgroup, id)
if mp == null then continue
rule.add mp
end
conditional_importations.add rule
end
end
mmodule.set_imported_mmodules(imported_modules)
apply_conditional_importations(mmodule)
self.toolcontext.info("{mmodule} imports {mmodule.in_importation.direct_greaters.join(", ")}", 3)
# Force `core` to be public if imported
for sup in mmodule.in_importation.greaters do
if sup.name == "core" then
mmodule.set_visibility_for(sup, public_visibility)
end
end
# TODO: Correctly check for useless importation
# It is even doable?
var directs = mmodule.in_importation.direct_greaters
for nim in nmodule.n_imports do
if not nim isa AStdImport then continue
var im = nim.mmodule
if im == null then continue
if directs.has(im) then continue
# This generates so much noise that it is simpler to just comment it
#warning(nim, "Warning: possible useless importation of {im}")
end
end
# Global list of conditional importation rules.
#
# Each rule is a "Horn clause"-like sequence of modules.
# It means that the first module is the module to automatically import.
# The remaining modules are the conditions of the rule.
#
# Rules are declared by `build_module_importation` and are applied by `apply_conditional_importations`
# (and `build_module_importation` that calls it).
#
# TODO (when the loader will be rewritten): use a better representation and move up rules in the model.
var conditional_importations = new Array[SequenceRead[MModule]]
# Extends the current importations according to imported rules about conditional importation
fun apply_conditional_importations(mmodule: MModule)
do
# Because a conditional importation may cause additional conditional importation, use a fixed point
# The rules are checked naively because we assume that it does not worth to be optimized
var check_conditional_importations = true
while check_conditional_importations do
check_conditional_importations = false
for ci in conditional_importations do
# Check conditions
for i in [1..ci.length[ do
var m = ci[i]
# Is imported?
if mmodule == m or not mmodule.in_importation.greaters.has(m) then continue label
end
# Still here? It means that all conditions modules are loaded and imported
# Identify the module to automatically import
var sup = ci.first
var ast = sup.load(self)
if ast == null then continue
# Do nothing if already imported
if mmodule.in_importation.greaters.has(sup) then continue label
# Import it
self.toolcontext.info("{mmodule} conditionally imports {sup}", 3)
# TODO visibility rules (currently always public)
mmodule.set_visibility_for(sup, public_visibility)
# TODO linearization rules (currently added at the end in the order of the rules)
mmodule.set_imported_mmodules([sup])
# Prepare to reapply the rules
check_conditional_importations = true
end label
end
end
# All the loaded modules
var nmodules = new Array[AModule]
# Register the nmodule associated to each mmodule
#
# Public clients need to use `mmodule2node` to access stuff.
private var mmodule2nmodule = new HashMap[MModule, AModule]
# Retrieve the associated AST node of a mmodule.
# This method is used to associate model entity with syntactic entities.
#
# If the module is not associated with a node, returns null.
fun mmodule2node(mmodule: MModule): nullable AModule
do
return mmodule2nmodule.get_or_null(mmodule)
end
end
src/loader.nit:61,1--1129,3
redef class ModelBuilder
# Run phases on all loaded modules
fun run_phases
do
var mmodules = parsed_modules.to_a
model.mmodule_importation_hierarchy.sort(mmodules)
var nmodules = new Array[AModule]
for mm in mmodules do
if mm.is_fictive then continue
nmodules.add(mmodule2node(mm).as(not null))
end
toolcontext.run_phases(nmodules)
if toolcontext.opt_only_metamodel.value then
self.toolcontext.info("*** ONLY METAMODEL", 1)
toolcontext.quit
end
end
# Load module `filename` and add it as a conditional importation of `mmodule`.
#
# This means that current (and future) submodules of `module` will also import `filename`.
fun inject_module_subimportation(mmodule: MModule, filename: String)
do
var am = load_module(filename)
if am == null then return # forward error
var mm = am.mmodule
if mm == null then return # forward error
# Add the new module before the existing submodules in the hierarchy
for subm in mmodule.in_importation.direct_smallers do
subm.set_imported_mmodules([mm])
end
# Register the new module as a conditional_importations for future submodules
conditional_importations.add([mm, mmodule])
# Register the new amodule to be processed by `run_phases`
toolcontext.todo_nmodules.unshift am
end
end
src/modelbuilder.nit:91,1--128,3
redef class ModelBuilder
# Visit the AST and create the `MClass` objects
private fun build_a_mclass(nmodule: AModule, nclassdef: AClassdef)
do
var mmodule = nmodule.mmodule.as(not null)
var name: String
var nkind: nullable AClasskind
var mkind: MClassKind
var nvisibility: nullable AVisibility
var mvisibility: nullable MVisibility
var arity = 0
var names = new Array[String]
var mclass
if nclassdef isa AStdClassdef then
var qid = nclassdef.n_qid
assert qid != null
name = qid.n_id.text
nkind = nclassdef.n_classkind
mkind = nkind.mkind
nvisibility = nclassdef.n_visibility
mvisibility = nvisibility.mvisibility
arity = nclassdef.n_formaldefs.length
if mvisibility == protected_visibility then
error(nvisibility, "Error: only properties can be protected.")
return
else if mvisibility == intrude_visibility then
error(nvisibility, "Error: intrude is not a legal visibility for classes.")
return
end
# Collect formal parameter names
for i in [0..arity[ do
var nfd = nclassdef.n_formaldefs[i]
var ptname = nfd.n_id.text
if names.has(ptname) then
error(nfd, "Error: a formal parameter type `{ptname}` already exists.")
return
end
for c in ptname.chars do if c >= 'a' and c<= 'z' then
warning(nfd, "formal-type-name", "Warning: lowercase in the formal parameter type `{ptname}`.")
break
end
names.add(ptname)
end
mclass = try_get_mclass_by_qid(qid, mmodule)
if mclass == null and (qid.n_qualified != null or nclassdef.n_kwredef != null) then
class_not_found(qid, mmodule)
nclassdef.is_broken = true
return
end
else if nclassdef isa ATopClassdef and nclassdef.n_propdefs.first.as(AMethPropdef).n_methid.collect_text == "sys" then
# Special case to keep `sys` in object.
# Needed to keep working bootstrap and a working java FFI together.
# TODO: remove once safe to remove
name = "Object"
nkind = null
mkind = interface_kind
nvisibility = null
mvisibility = public_visibility
mclass = try_get_mclass_by_name(nclassdef, mmodule, name)
else
name = "Sys"
nkind = null
mkind = concrete_kind
nvisibility = null
mvisibility = public_visibility
mclass = try_get_mclass_by_name(nclassdef, mmodule, name)
end
if mclass == null then
# Check for conflicting class full-names in the package
if mmodule.mgroup != null and mvisibility >= protected_visibility then
var mclasses = model.get_mclasses_by_name(name)
if mclasses != null then for other in mclasses do
if other.intro_mmodule.mgroup != null and other.intro_mmodule.mgroup.mpackage == mmodule.mgroup.mpackage then
# Skip classes that are buggy
if other.try_intro == null then continue
warning(nclassdef, "full-name-conflict", "Error: a class named `{other.full_name}` is already defined in module `{other.intro_mmodule}` at {other.intro.location}.")
break
end
end
end
mclass = new MClass(mmodule, name, nclassdef.location, names, mkind, mvisibility)
#print "new class {mclass}"
else if nclassdef isa AStdClassdef and nmodule.mclass2nclassdef.has_key(mclass) then
error(nclassdef, "Error: a class `{name}` is already defined at line {nmodule.mclass2nclassdef[mclass].location.line_start}.")
mclass.is_broken = true
return
else if nclassdef isa AStdClassdef and nclassdef.n_kwredef == null then
error(nclassdef, "Redef Error: `{name}` is an imported class. Add the `redef` keyword to refine it.")
mclass.is_broken = true
return
else if arity != 0 and mclass.arity != arity then
error(nclassdef, "Redef Error: expected {mclass.arity} formal parameter(s) for {mclass.signature_to_s}; got {arity}.")
mclass.is_broken = true
return
else if nkind != null and mkind != concrete_kind and mclass.kind != mkind then
error(nkind, "Redef Error: refinement changed the kind from `{mclass.kind}` to `{mkind}`.")
else if nvisibility != null and mvisibility != public_visibility and mclass.visibility != mvisibility then
error(nvisibility, "Redef Error: refinement changed the visibility from `{mclass.visibility}` to `{mvisibility}`")
end
nclassdef.mclass = mclass
if not nmodule.mclass2nclassdef.has_key(mclass) then
nmodule.mclass2nclassdef[mclass] = nclassdef
nclassdef.all_defs = [nclassdef]
else
nmodule.mclass2nclassdef[mclass].all_defs.add(nclassdef)
end
end
# Visit the AST and create the `MClassDef` objects
private fun build_a_mclassdef(nmodule: AModule, nclassdef: AClassdef)
do
var mmodule = nmodule.mmodule.as(not null)
var mclass = nclassdef.mclass
if mclass == null then return # Skip error
# In case of non-standard AClassdef, try to attach to an already existing mclassdef
var other_nclassdef = nmodule.mclass2nclassdef[mclass]
if other_nclassdef != nclassdef then
assert not nclassdef isa AStdClassdef
nclassdef.mclassdef = other_nclassdef.mclassdef
return
end
var bound_mtype = build_a_bound_mtype(nmodule, nclassdef)
if bound_mtype == null then return
var mclassdef = new MClassDef(mmodule, bound_mtype, nclassdef.location)
nclassdef.mclassdef = mclassdef
self.mclassdef2nclassdef[mclassdef] = nclassdef
if nclassdef isa AStdClassdef then
var ndoc = nclassdef.n_doc
if ndoc != null then
var mdoc = ndoc.to_mdoc
mclassdef.mdoc = mdoc
mdoc.original_mentity = mclassdef
else if mclassdef.is_intro and mclass.visibility >= public_visibility then
advice(nclassdef, "missing-doc", "Documentation warning: Undocumented public class `{mclass}`")
end
end
if mclassdef.is_intro then
self.toolcontext.info("{mclassdef} introduces new {mclass.kind} {mclass.full_name}", 3)
else
self.toolcontext.info("{mclassdef} refines {mclass.kind} {mclass.full_name}", 3)
end
end
# Determine the type parameter bounds for `nclassdef`.
#
# In case of error, return `null`.
#
# REQUIRE: `nmodule.mmodule != null`
# REQUIRE: `nclassdef.mclass != null`
private fun build_a_bound_mtype(nmodule: AModule, nclassdef: AClassdef): nullable MClassType
do
var mmodule = nmodule.mmodule.as(not null)
var mclass = nclassdef.mclass.as(not null)
var bounds = new Array[MType]
if nclassdef isa AStdClassdef and mclass.arity > 0 then
var objectclass = try_get_mclass_by_name(nmodule, mmodule, "Object")
# Revolve bound for formal parameters
for i in [0..mclass.arity[ do
if nclassdef.n_formaldefs.is_empty then
# Inherit the bound
var bound = mclass.intro.bound_mtype.arguments[i]
bounds.add(bound)
continue
end
var nfd = nclassdef.n_formaldefs[i]
var pname = mclass.mparameters[i].name
if nfd.n_id.text != pname then
error(nfd.n_id, "Error: formal parameter type #{i} `{nfd.n_id.text}` must be named `{pname}` as in the original definition in module `{mclass.intro.mmodule}`.")
end
var nfdt = nfd.n_type
if nfdt != null then
var bound = resolve_mtype3_unchecked(mmodule, null, null, nfdt, false)
if bound == null then return null # Forward error
if bound.need_anchor then
# No F-bounds!
error(nfd, "Error: formal parameter type `{pname}` bounded with a formal parameter type.")
else
bounds.add(bound)
nfd.bound = bound
end
else if mclass.mclassdefs.is_empty then
if objectclass == null then
error(nfd, "Error: formal parameter type `{pname}` unbounded but no `Object` class exists.")
return null
end
# No bound, then implicitely bound by nullable Object
var bound = objectclass.mclass_type.as_nullable
bounds.add(bound)
nfd.bound = bound
else
# Inherit the bound
var bound = mclass.intro.bound_mtype.arguments[i]
bounds.add(bound)
nfd.bound = bound
end
end
end
return mclass.get_mtype(bounds)
end
# Visit the AST and set the super-types of the `MClassDef` objects
private fun build_a_mclassdef_inheritance(nmodule: AModule, nclassdef: AClassdef)
do
var mmodule = nmodule.mmodule
if mmodule == null then return
var mclass = nclassdef.mclass
if mclass == null then return
var mclassdef = nclassdef.mclassdef
if mclassdef == null then return
var supertypes = collect_supertypes(nmodule, nclassdef, mclassdef.is_intro)
mclassdef.set_supertypes(supertypes)
if not supertypes.is_empty then self.toolcontext.info("{mclassdef} new super-types: {supertypes.join(", ")}", 3)
end
# List the supertypes specified or implied by `nclassdef`.
#
# REQUIRE: `nmodule.mmodule != null`
# REQUIRE: `nclassdef.mclass != null`
private fun collect_supertypes(nmodule: AModule, nclassdef: AClassdef,
is_intro: Bool): Array[MClassType]
do
var mmodule = nmodule.mmodule.as(not null)
var mclass = nclassdef.mclass.as(not null)
var name = mclass.name
var kind = mclass.kind
var objectclass = try_get_mclass_by_name(nmodule, mmodule, "Object")
var pointerclass = try_get_mclass_by_name(nmodule, mmodule, "Pointer")
# Do we need to specify Object as a super class?
var specobject = true
# Do we need to specify Pointer as a super class? (is only valid
# if `nclassdef` is an extern class)
var specpointer = true
var supertypes = new Array[MClassType]
if nclassdef isa AStdClassdef then
for nsc in nclassdef.n_superclasses do
specobject = false
var ntype = nsc.n_type
var mtype = resolve_mtype3_unchecked(mmodule, mclass, null,
ntype, false)
if mtype == null then continue # Skip because of error
if not mtype isa MClassType then
error(ntype, "Error: a supertype cannot be a formal type.")
continue
end
var superclass = mtype.mclass
var super_kind = superclass.kind
if not kind.can_specialize(super_kind) then
error(ntype, "Error: {kind} `{mclass}` cannot specialize {super_kind} `{superclass}`.")
end
supertypes.add mtype
#print "new super : {mclass} < {mtype}"
if super_kind == extern_kind then specpointer = false
end
end
if is_intro and objectclass != null then
if kind == extern_kind and name != "Pointer" then
# it is an extern class, but not a Pointer
if pointerclass == null then
error(nclassdef, "Error: `Pointer` must be defined first.")
return supertypes
end
if specpointer then supertypes.add pointerclass.mclass_type
else if specobject then
if name != "Object" then
# it is a standard class without super class (but is not Object)
supertypes.add objectclass.mclass_type
else if kind != interface_kind then
error(nclassdef, "Error: `Object` must be an {interface_kind}.")
end
end
end
return supertypes
end
# Check the validity of the specialization heirarchy
private fun check_supertypes(nmodule: AModule, nclassdef: AClassdef)
do
var mmodule = nmodule.mmodule
if mmodule == null then return
var mclass = nclassdef.mclass
if mclass == null then return
var mclassdef = nclassdef.mclassdef
if mclassdef == null then return
for s in mclassdef.supertypes do
if s.is_subtype(mmodule, mclassdef.bound_mtype, mclassdef.bound_mtype) then
error(nclassdef, "Error: inheritance loop for class `{mclass}` with type `{s}`.")
end
end
end
# Build the classes of the module `nmodule`.
private fun build_classes(nmodule: AModule)
do
# Force building recursively
if nmodule.build_classes_is_done then return
nmodule.build_classes_is_done = true
var mmodule = nmodule.mmodule
if mmodule == null then return
for imp in mmodule.in_importation.direct_greaters do
var nimp = mmodule2node(imp)
if nimp != null then build_classes(nimp)
end
# Create all classes
# process AStdClassdef before so that non-AStdClassdef classes can be attached to existing ones, if any
for nclassdef in nmodule.n_classdefs do
if not nclassdef isa AStdClassdef then continue
self.build_a_mclass(nmodule, nclassdef)
end
for nclassdef in nmodule.n_classdefs do
if nclassdef isa AStdClassdef then continue
self.build_a_mclass(nmodule, nclassdef)
end
# Create all classdefs
for nclassdef in nmodule.n_classdefs do
if not nclassdef isa AStdClassdef then continue
self.build_a_mclassdef(nmodule, nclassdef)
end
for nclassdef in nmodule.n_classdefs do
if nclassdef isa AStdClassdef then continue
self.build_a_mclassdef(nmodule, nclassdef)
end
# Create inheritance on all classdefs
for nclassdef in nmodule.n_classdefs do
self.build_a_mclassdef_inheritance(nmodule, nclassdef)
end
# Create the mclassdef hierarchy
for mclassdef in mmodule.mclassdefs do
mclassdef.add_in_hierarchy
end
# Check inheritance
for nclassdef in nmodule.n_classdefs do
self.check_supertypes(nmodule, nclassdef)
end
# Check unchecked ntypes
for nclassdef in nmodule.n_classdefs do
if nclassdef isa AStdClassdef then
var mclassdef = nclassdef.mclassdef
var mclass
var anchor
if mclassdef == null then
mclass = null
anchor = null
else
mclass = mclassdef.mclass
anchor = mclassdef.bound_mtype
end
# check bound of formal parameter
for nfd in nclassdef.n_formaldefs do
var nfdt = nfd.n_type
if nfdt != null and nfdt.mtype != null then
var bound = resolve_mtype3(mmodule, mclass, anchor, nfdt)
if bound == null then return # Forward error
end
end
# check declared super types
for nsc in nclassdef.n_superclasses do
var ntype = nsc.n_type
if ntype.mtype != null then
var mtype = resolve_mtype3(mmodule, mclass, anchor, ntype)
if mtype == null then return # Forward error
end
end
end
end
# Check clash of ancestors
for nclassdef in nmodule.n_classdefs do
var mclassdef = nclassdef.mclassdef
if mclassdef == null then continue
var superclasses = new HashMap[MClass, MClassType]
for scd in mclassdef.in_hierarchy.greaters do
for st in scd.supertypes do
if not superclasses.has_key(st.mclass) then
superclasses[st.mclass] = st
else if superclasses[st.mclass] != st then
var st1 = superclasses[st.mclass].resolve_for(mclassdef.mclass.mclass_type, mclassdef.bound_mtype, mmodule, false)
var st2 = st.resolve_for(mclassdef.mclass.mclass_type, mclassdef.bound_mtype, mmodule, false)
if st1 != st2 then
error(nclassdef, "Error: incompatible ancestors for `{mclassdef.mclass}`; conflict: `{st1}` and `{st2}`")
end
end
end
end
end
# TODO: Check that the super-class is not intrusive
# Check that the superclasses are not already known (by transitivity)
for nclassdef in nmodule.n_classdefs do
if not nclassdef isa AStdClassdef or nclassdef.is_broken then continue
var mclassdef = nclassdef.mclassdef
if mclassdef == null then continue
# Get the direct superclasses
# Since we are a mclassdef, just look at the mclassdef hierarchy
var parents = new Array[MClass]
for sup in mclassdef.in_hierarchy.direct_greaters do
parents.add(sup.mclass)
end
# Used to track duplicates of superclasses
var seen_parents = new ArrayMap[MClass, AType]
# The Object class
var objectclass = try_get_mclass_by_name(nmodule, mmodule, "Object")
# Check each declared superclass to see if it belong to the direct superclass
for nsc in nclassdef.n_superclasses do
var ntype = nsc.n_type
var mtype = ntype.mtype
# If the supertype is `null` or don’t refer to a class, we
# already raised an error.
if not mtype isa MClassType then continue
var sc = mtype.mclass
if not parents.has(sc) or sc == objectclass then
# Skip the warning on generated code
if ntype.location.file != null and not ntype.location.file.filename.is_empty then
warning(ntype, "useless-superclass", "Warning: superfluous super-class `{mtype}` in class `{mclassdef.mclass}`.")
end
else if not seen_parents.has_key(sc) then
seen_parents[sc] = ntype
else
warning(ntype, "useless-superclass", "Warning: duplicated super-class `{mtype}` in class `{mclassdef.mclass}`.")
end
end
end
end
# Registration of the nclassdef associated to each mclassdef
private var mclassdef2nclassdef = new HashMap[MClassDef, AClassdef]
# Retrieve the associated AST node of a mclassdef.
#
# This method is used to associate model entity with syntactic entities.
# If the class definition is not associated with a node, returns `null`.
fun mclassdef2node(mclassdef: MClassDef): nullable AClassdef do
return mclassdef2nclassdef.get_or_null(mclassdef)
end
end
src/modelize/modelize_class.nit:36,1--503,3
redef class ModelBuilder
# Collect all annotations by `name` assocated to `mmodule` and its imported modules.
# Note that visibility is not considered.
fun collect_annotations_on_modules(name: String, mmodule: MModule): Array[AAnnotation]
do
var annotations = new Array[AAnnotation]
for mmod in mmodule.in_importation.greaters do
var amod = mmodule2node(mmod)
if amod == null then continue
var module_decl = amod.n_moduledecl
if module_decl == null then continue
var aas = module_decl.get_annotations(name)
annotations.add_all aas
end
return annotations
end
# Return the single annotation `name` locally assocated to `mmodule`, if any.
# Obviously, if there is no ast associated to `mmodule`, then nothing is returned.
fun get_mmodule_annotation(name: String, mmodule: MModule): nullable AAnnotation
do
var amod = mmodule2node(mmodule)
if amod == null then return null
var module_decl = amod.n_moduledecl
if module_decl == null then return null
var res = module_decl.get_single_annotation(name, self)
return res
end
private var collect_annotations_data_cache = new HashMap[String, MModuleData[AAnnotation]]
# Collect all annotations by `name` in `mmodule` and its importations (direct and indirect)
# Note that visibility is not considered.
fun collect_annotations_data(name: String, mmodule: MModule): MModuleData[AAnnotation]
do
var res = collect_annotations_data_cache.get_or_null(name)
if res == null then
res = new MModuleData[AAnnotation](model)
collect_annotations_data_cache[name] = res
end
for mmod in mmodule.in_importation.greaters do
if res.has_mmodule(mmod) then continue
var ass = get_mmodule_annotation(name, mmod)
if ass == null then continue
res[mmod] = ass
end
return res
end
# Get an annotation by name from `mmodule` and its super modules. Will recursively search
# in imported module to find the "latest" declaration and detects priority conflicts.
fun lookup_annotation_on_modules(name: String, mmodule: MModule): nullable AAnnotation
do
var data = collect_annotations_data(name, mmodule)
var annotations = data.lookup_values(mmodule, none_visibility)
if annotations.is_empty then return null
if annotations.length > 1 then
var locs = new Array[Location]
for annot in annotations do locs.add(annot.location)
toolcontext.error(mmodule.location,
"Error: priority conflict on annotation `{name}`, it has been defined in: {locs.join(", ")}.")
end
return annotations.first
end
end
src/annotation.nit:83,1--149,3
redef class ModelBuilder
# Registration of the npropdef associated to each mpropdef.
#
# Public clients need to use `mpropdef2node` to access stuff.
private var mpropdef2npropdef = new HashMap[MPropDef, APropdef]
# Associate a `npropdef` with its `mpropdef`
#
# Be careful, this method is unsafe, no checking is done when it's used.
# The safe way to add method it's to use the `build_property`
#
# See `mpropdef2npropdef`
fun unsafe_add_mpropdef2npropdef(mpropdef: MPropDef,npropdef: APropdef)
do
mpropdef2npropdef[mpropdef] = npropdef
end
# Associate a `nclassdef` with its `mclassdef`
#
# Be careful, this method is unsafe, no checking is done when it's used.
# The safe way to add mclass it's to use the `build_property`
#
# See `mclassdef2nclassdef`
fun unsafe_add_mclassdef2nclassdef(mclassdef: MClassDef, nclassdef: AClassdef)
do
mclassdef2nclassdef[mclassdef] = nclassdef
end
# Retrieve the associated AST node of a mpropertydef.
# This method is used to associate model entity with syntactic entities.
#
# If the property definition is not associated with a node, returns `null`.
fun mpropdef2node(mpropdef: MPropDef): nullable ANode
do
var res
res = mpropdef2npropdef.get_or_null(mpropdef)
if res != null then
# Run the phases on it
toolcontext.run_phases_on_npropdef(res)
return res
end
# Fall back to the class node if any.
res = mclassdef2nclassdef.get_or_null(mpropdef.mclassdef)
if res != null then return res
return null
end
# Retrieve all the attributes nodes localy definied
# FIXME think more about this method and how the separations separate/global and ast/model should be done.
fun collect_attr_propdef(mclassdef: MClassDef): Array[AAttrPropdef]
do
var res = new Array[AAttrPropdef]
var n = mclassdef2nclassdef.get_or_null(mclassdef)
if n == null then return res
for npropdef in n.n_propdefs do
if npropdef isa AAttrPropdef then
# Run the phases on it
toolcontext.run_phases_on_npropdef(npropdef)
res.add(npropdef)
end
end
return res
end
# Build the properties of `nclassdef`.
private fun build_properties(nclassdef: AClassdef)
do
# Force building recursively
if nclassdef.build_properties_is_done then return
nclassdef.build_properties_is_done = true
var mclassdef = nclassdef.mclassdef
if mclassdef == null then return # skip error
if mclassdef.in_hierarchy == null then return # Skip error
for superclassdef in mclassdef.in_hierarchy.direct_greaters do
if not mclassdef2nclassdef.has_key(superclassdef) then continue
build_properties(mclassdef2nclassdef[superclassdef])
end
mclassdef.build_self_type(self, nclassdef)
for nclassdef2 in nclassdef.all_defs do
for npropdef in nclassdef2.n_propdefs do
npropdef.build_property(self, mclassdef)
end
for npropdef in nclassdef2.n_propdefs do
npropdef.build_signature(self)
end
for npropdef in nclassdef2.n_propdefs do
if not npropdef isa ATypePropdef then continue
# Check circularity
var mpropdef = npropdef.mpropdef
if mpropdef == null then continue
if mpropdef.bound == null then continue
if not check_virtual_types_circularity(npropdef, mpropdef.mproperty, mclassdef.bound_mtype, mclassdef.mmodule) then
# Invalidate the bound
mpropdef.is_broken = true
mpropdef.bound = new MErrorType(mclassdef.mmodule.model)
end
end
for npropdef in nclassdef2.n_propdefs do
# Check ATypePropdef first since they may be required for the other properties
if not npropdef isa ATypePropdef then continue
npropdef.check_signature(self)
end
for npropdef in nclassdef2.n_propdefs do
if npropdef isa ATypePropdef then continue
npropdef.check_signature(self)
end
end
process_default_constructors(nclassdef)
end
# the root init of the Object class
# Is usually implicitly defined
# Then explicit or implicit definitions of root-init are attached to it
var the_root_init_mmethod: nullable MMethod
# Introduce or inherit default constructor
# This is the last part of `build_properties`.
private fun process_default_constructors(nclassdef: AClassdef)
do
var mclassdef = nclassdef.mclassdef.as(not null)
# Are we a refinement
if not mclassdef.is_intro then
# Set the default_init of the mclassdef with the intro default_init
mclassdef.default_init = mclassdef.mclass.intro.default_init
return
end
# Look for the init in Object, or create it
if mclassdef.mclass.name == "Object" and the_root_init_mmethod == null then
# Create the implicit root-init method
var mprop = new MMethod(mclassdef, "init", nclassdef.location, mclassdef.mclass.visibility)
mprop.is_root_init = true
var mpropdef = new MMethodDef(mclassdef, mprop, nclassdef.location)
var mparameters = new Array[MParameter]
var msignature = new MSignature(mparameters, null)
mpropdef.msignature = msignature
mprop.is_init = true
self.toolcontext.info("{mclassdef} gets a free empty constructor {mpropdef}{msignature}", 3)
the_root_init_mmethod = mprop
end
# Is there already a constructor defined?
var defined_init: nullable MMethodDef = null
for mpropdef in mclassdef.mpropdefs do
if not mpropdef isa MMethodDef then continue
if not mpropdef.mproperty.is_init then continue
if mpropdef.mproperty.is_root_init then
assert defined_init == null
defined_init = mpropdef
else if mpropdef.name == "defaultinit" then
return
end
end
if mclassdef.default_init != null then return
# If the class is not AStdClassdef or it's an enum just return. No defaultinit is need.
if not nclassdef isa AStdClassdef or nclassdef.n_classkind isa AEnumClasskind then return
# Collect undefined attributes
var mparameters = new Array[MParameter]
var initializers = new Array[MProperty]
for npropdef in nclassdef.n_propdefs do
if npropdef isa AMethPropdef then
if not npropdef.is_autoinit then continue # Skip non tagged autoinit
var mpropdef = npropdef.mpropdef
if mpropdef == null then return # Skip broken method
var sig = mpropdef.msignature
if sig == null then continue # Skip broken method
mparameters.add_all sig.mparameters
initializers.add(mpropdef.mproperty)
mpropdef.mproperty.is_autoinit = true
end
if npropdef isa AAttrPropdef then
var mreadpropdef = npropdef.mreadpropdef
if mreadpropdef == null then return # Skip broken attribute
var msignature = mreadpropdef.msignature
if msignature == null then return # Skip broken attribute
if npropdef.noinit then continue # Skip noinit attribute
var atlateinit = npropdef.get_single_annotation("lateinit", self)
if atlateinit != null then
# For lateinit attributes, call the reader to force
# the lazy initialization of the attribute.
initializers.add(mreadpropdef.mproperty)
mreadpropdef.mproperty.is_autoinit = true
continue
end
if npropdef.has_value and not npropdef.is_optional then continue
var msetter = npropdef.mwritepropdef
if msetter == null then
# No setter, it is a readonly attribute, so just add it
var paramname = mreadpropdef.mproperty.name
var ret_type = msignature.return_mtype
if ret_type == null then return
var mparameter = new MParameter(paramname, ret_type, false)
mparameters.add(mparameter)
initializers.add(npropdef.mpropdef.mproperty)
npropdef.mpropdef.mproperty.is_autoinit = true
else
# Add the setter to the list
mparameters.add_all msetter.msignature.mparameters
initializers.add(msetter.mproperty)
msetter.mproperty.is_autoinit = true
end
end
end
var the_root_init_mmethod = self.the_root_init_mmethod
if the_root_init_mmethod == null then return
# Look for most-specific new-stype init definitions
var spropdefs = new ArraySet[MMethodDef]
for x in mclassdef.get_direct_supermtype do
var y = x.mclass.intro.default_init
if y == null then continue
if y.is_broken or y.msignature == null then return
spropdefs.add y
end
# Look at the autoinit class-annotation
var autoinit = nclassdef.get_single_annotation("autoinit", self)
var noautoinit = nclassdef.get_single_annotation("noautoinit", self)
if autoinit != null then
# Just throws the collected initializers
mparameters.clear
initializers.clear
if noautoinit != null then
error(autoinit, "Error: `autoinit` and `noautoinit` are incompatible.")
end
if autoinit.n_args.is_empty then
error(autoinit, "Syntax Error: `autoinit` expects method identifiers, use `noautoinit` to clear all autoinits.")
end
# Get and check each argument
for narg in autoinit.n_args do
var id = narg.as_id
if id == null then
error(narg, "Syntax Error: `autoinit` expects method identifiers.")
return
end
# Search the property.
# To avoid bad surprises, try to get the setter first.
var p = try_get_mproperty_by_name(narg, mclassdef, id + "=")
if p == null then
p = try_get_mproperty_by_name(narg, mclassdef, id)
end
if p == null then
error(narg, "Error: unknown method `{id}`")
return
end
if not p.is_autoinit then
error(narg, "Error: `{p}` is not an autoinit method")
return
end
# Register the initializer and the parameters
initializers.add(p)
var pd = p.intro
if pd isa MMethodDef then
# Get the signature resolved for the current receiver
var sig = pd.msignature.resolve_for(mclassdef.mclass.mclass_type, mclassdef.bound_mtype, mclassdef.mmodule, false)
mparameters.add_all(sig.mparameters)
else
# TODO attributes?
abort
end
end
else if spropdefs.not_empty then
# Search for inherited manual defaultinit
var manual = null
for s in spropdefs do
if mpropdef2npropdef.has_key(s) then
self.toolcontext.info("{mclassdef} inherits a manual defaultinit {s}", 3)
manual = s
end
end
# Search the longest-one and checks for conflict
var longest = spropdefs.first
if spropdefs.length > 1 then
# part 1. find the longest list
for spd in spropdefs do
if spd.initializers.length > longest.initializers.length then longest = spd
if spd != manual and manual != null then
self.toolcontext.info("{mclassdef} conflict between manual defaultinit {manual} and automatic defaultinit {spd}.", 3)
end
end
# conflict with manual autoinit?
if longest != manual and manual != null then
self.error(nclassdef, "Error: conflict between manual defaultinit {manual} and automatic defaultinit {longest}.")
end
# part 2. compare
# Check for conflict in the order of initializers
# Each initializer list must me a prefix of the longest list
# If `noautoinit` is set, just ignore conflicts
if noautoinit == null then for spd in spropdefs do
var i = 0
for p in spd.initializers do
if p != longest.initializers[i] then
var proposal = new ArraySet[MProperty]
for spd2 in spropdefs do
proposal.add_all spd2.initializers
end
proposal.add_all initializers
self.error(nclassdef, "Error: cannot generate automatic init for class {mclassdef.mclass}. Conflict in the order in inherited initializers {spd}({spd.initializers.join(", ")}) and {longest}({longest.initializers.join(", ")}). Use `autoinit` to order initializers. eg `autoinit {proposal.join(", ")}`")
# TODO: invalidate the initializer to avoid more errors
return
end
i += 1
end
end
end
if noautoinit != null then
# If there is local or inherited initializers, then complain.
if initializers.is_empty and longest.initializers.is_empty then
warning(noautoinit, "useless-noautoinit", "Warning: the list of autoinit is already empty.")
end
# Just clear initializers
mparameters.clear
initializers.clear
else
# Combine the inherited list to what is collected
if longest.initializers.length > 0 then
mparameters.prepend longest.msignature.mparameters
initializers.prepend longest.initializers
end
end
end
# Create a specific new autoinit constructor
do
var mprop = new MMethod(mclassdef, "defaultinit", nclassdef.location, public_visibility)
mprop.is_init = true
var mpropdef = new MMethodDef(mclassdef, mprop, nclassdef.location)
mpropdef.initializers.add_all(initializers)
var msignature = new MSignature(mparameters, null)
mpropdef.msignature = msignature
mclassdef.default_init = mpropdef
self.toolcontext.info("{mclassdef} gets a free auto constructor `{mpropdef}{msignature}`. {spropdefs}", 3)
mclassdef.mclass.the_root_init_mmethod = the_root_init_mmethod
end
end
# Check the visibility of `mtype` as an element of the signature of `mpropdef`.
fun check_visibility(node: ANode, mtype: MType, mpropdef: MPropDef)
do
var mmodule = mpropdef.mclassdef.mmodule
var mproperty = mpropdef.mproperty
# Extract visibility information of the main part of `mtype`
# It is a case-by case
var vis_type: nullable MVisibility = null # The own visibility of the type
var mmodule_type: nullable MModule = null # The original module of the type
mtype = mtype.undecorate
if mtype isa MClassType then
vis_type = mtype.mclass.visibility
mmodule_type = mtype.mclass.intro_mmodule
else if mtype isa MVirtualType then
vis_type = mtype.mproperty.visibility
mmodule_type = mtype.mproperty.intro_mclassdef.mmodule
else if mtype isa MParameterType then
# nothing, always visible
else if mtype isa MNullType then
# nothing to do.
else if mtype isa MBottomType then
# nothing to do.
else if mtype isa MErrorType then
# nothing to do.
else
node.debug "Unexpected type {mtype}"
abort
end
if vis_type != null then
assert mmodule_type != null
var vis_module_type = mmodule.visibility_for(mmodule_type) # the visibility of the original module
if mproperty.visibility > vis_type then
error(node, "Error: the {mproperty.visibility} property `{mproperty}` cannot contain the {vis_type} type `{mtype}`.")
return
else if mproperty.visibility > vis_module_type then
error(node, "Error: the {mproperty.visibility} property `{mproperty}` cannot contain the type `{mtype}` from the {vis_module_type} module `{mmodule_type}`.")
return
end
end
# No error, try to go deeper in generic types
if node isa AType then
for a in node.n_types do
var t = a.mtype
if t == null then continue # Error, thus skipped
check_visibility(a, t, mpropdef)
end
else if mtype isa MGenericType then
for t in mtype.arguments do check_visibility(node, t, mpropdef)
end
end
# Detect circularity errors for virtual types.
fun check_virtual_types_circularity(node: ANode, mproperty: MVirtualTypeProp, recv: MType, mmodule: MModule): Bool
do
# Check circularity
# Slow case: progress on each resolution until we visit all without getting a loop
# The graph used to detect loops
var mtype = mproperty.mvirtualtype
var poset = new POSet[MType]
# The work-list of types to resolve
var todo = new List[MType]
todo.add mtype
while not todo.is_empty do
# The visited type
var t = todo.pop
if not t.need_anchor then continue
# Get the types derived of `t` (subtypes and bounds)
var nexts
if t isa MNullableType then
nexts = [t.mtype]
else if t isa MGenericType then
nexts = t.arguments
else if t isa MVirtualType then
var vt = t.mproperty
# Because `vt` is possibly unchecked, we have to do the bound-lookup manually
var defs = vt.lookup_definitions(mmodule, recv)
if defs.is_empty then return false
nexts = new Array[MType]
for d in defs do
var next = defs.first.bound
if next == null then return false
nexts.add next
end
else if t isa MClassType then
# Basic type, nothing to to
continue
else if t isa MParameterType then
# Parameter types cannot depend on virtual types, so nothing to do
continue
else
abort
end
# For each one
for next in nexts do
if poset.has_edge(next, t) then
if mtype == next then
error(node, "Error: circularity of virtual type definition: {next} <-> {t}.")
else
error(node, "Error: circularity of virtual type definition: {mtype} -> {next} <-> {t}.")
end
return false
else
poset.add_edge(t, next)
todo.add next
end
end
end
return true
end
end
src/modelize/modelize_property.nit:39,1--509,3
redef class ModelBuilder
# Retrieve the associated AST node of a mentity.
# This method is used to associate model entity with syntactic entities.
#
# If the mentity is not associated with a node, returns null.
# This is always the case for MPackage, Mgroup, MClass and MProperty.
# MModule, MClassDef and MPropDef can also have no node associated
# (like fictive modules of generated attributes/methods).
fun mentity2node(mentity: MEntity): nullable ANode
do
if mentity isa MModule then
return mmodule2node(mentity)
else if mentity isa MClassDef then
return mclassdef2node(mentity)
else if mentity isa MPropDef then
return mpropdef2node(mentity)
end
return null
end
end
src/modelize/modelize.nit:20,1--39,3
redef class ModelBuilder
redef fun build_a_mclass(nmodule, nclassdef)
do
super
# Catch the wanted annotation
var at = nclassdef.get_single_annotation("actor", self)
if at == null then return
# Get context information
var mod = nmodule.mmodule
if mod == null then return
var mclass = nclassdef.mclass
if mclass == null then return
if mclass.intro_mmodule != mod then
error(at, "`actor` can only be used at introductions.")
return
end
var l = at.location
var injected_name = "Proxy"
# Create the actor class
var actor_class = new MClass(mod, injected_name + mclass.name, l, null, concrete_kind, public_visibility)
var actor_class_definition = new MClassDef(mod, actor_class.mclass_type, l)
actor_class_definition.set_supertypes([mod.object_type])
var proxy_classes = mclass.model.get_mclasses_by_name("Proxy")
assert proxy_classes != null
var proxy_class = proxy_classes.first
actor_class_definition.supertypes.add(proxy_class.mclass_type)
# Register it
mclass.actor = actor_class
end
redef fun build_properties(nclassdef)
do
if nclassdef.build_properties_is_done then return
super
# Get context information
var mclass = nclassdef.mclass
if mclass == null then return
var mclass_def = nclassdef.mclassdef
if mclass_def == null then return
var actor_mclass = mclass.actor
if actor_mclass == null then return
var actor_mclass_def = actor_mclass.mclassdefs.first
# Adds an `async` attribute in the worker class which is the actor class
if mclass_def.is_intro then
var async = new MMethod(mclass_def, "async", mclass.location, public_visibility)
var async_def = new MMethodDef(mclass_def, async, mclass.location)
async_def.msignature = new MSignature(new Array[MParameter], actor_mclass.mclass_type)
async_def.is_abstract = true
end
# For each introduced property
for method in mclass_def.mpropdefs do
if not method isa MMethodDef then continue
if not method.is_intro then continue
if method.name == "async" then continue
# Create a proxied method
var actor_method = new MMethod(actor_mclass_def, method.name, actor_mclass.location, method.mproperty.visibility)
var actor_method_def = new MMethodDef(actor_mclass_def, actor_method, actor_mclass.location)
# Get the signature of the method ( replacing the return value with a Future if there is one)
var signature = method.msignature
if signature != null then
var parameters = signature.mparameters
var s_return_type = signature.return_mtype
if s_return_type != null then
var future_mclasses = mclass_def.model.get_mclasses_by_name("Future")
assert future_mclasses != null
var future_mclass = future_mclasses.first
var return_type = future_mclass.get_mtype([s_return_type])
actor_method_def.msignature = new MSignature(parameters, return_type)
else
actor_method_def.msignature = new MSignature(parameters, null)
end
end
actor_method_def.is_abstract = true
end
end
end
src/frontend/actors_injection_phase.nit:22,1--109,3
redef class ModelBuilder
# Generate NitUnit test file skeleton for `mmodule`.
fun gen_test_unit(mmodule: MModule) do
var test_file = "test_{mmodule.name}.nit"
if test_file.file_exists and not toolcontext.opt_gen_force.value and not toolcontext.opt_gen_show.value then
toolcontext.info("Skip generation for {mmodule}, file {test_file} already exists", 1)
return
end
var generator = new NitUnitGenerator(toolcontext)
var tpl = generator.gen_unit(mmodule, test_file)
if toolcontext.opt_gen_show.value then
tpl.write_to(sys.stdout)
else
tpl.write_to_file(test_file)
end
end
end
src/testing/testing_gen.nit:157,1--173,3
redef class ModelBuilder
# Try to get MMethod property if exist in the given mclassdef. return new `MMethod` if not exist.
private fun get_mmethod(name: String, mclassdef: MClassDef, visibility: nullable MVisibility): MMethod do
visibility = visibility or else public_visibility
var mproperty = try_get_mproperty_by_name(null, mclassdef, name).as(nullable MMethod)
if mproperty == null then mproperty = new MMethod(mclassdef, name, mclassdef.location, visibility)
return mproperty
end
# Creation of a new method (AST and model representation) with the given name.
# See `create_method_from_property` for more information.
fun create_method_from_name(name: String, mclassdef: MClassDef, is_abstract: Bool, msignature: nullable MSignature, visibility: nullable MVisibility): AMethPropdef do
var mproperty = get_mmethod(name, mclassdef, visibility)
return create_method_from_property(mproperty, mclassdef, is_abstract, msignature)
end
# Creation of a new method (AST and model representation) with the given MMethod.
# Take care, if `is_abstract == false` the AMethPropdef returned has an empty body (potential error if the given signature has an return type).
fun create_method_from_property(mproperty: MMethod, mclassdef: MClassDef, is_abstract: Bool, msignature: nullable MSignature): AMethPropdef do
var m_def = new MMethodDef(mclassdef, mproperty, mclassdef.location)
if msignature == null then msignature = new MSignature(new Array[MParameter])
m_def.msignature = msignature
m_def.is_abstract = true
var n_def = m_def.create_ast_representation
# Association new npropdef to mpropdef
unsafe_add_mpropdef2npropdef(m_def,n_def)
if not is_abstract then
n_def.mpropdef.is_abstract = false
n_def.n_block = new ABlockExpr.make
end
return n_def
end
# Creation of a new attribute (AST and model representation) with the given name.
# See `create_attribute_from_property` for more information.
fun create_attribute_from_name(name: String, mclassdef: MClassDef, mtype: MType, visibility: nullable MVisibility): AAttrPropdef do
if visibility == null then visibility = public_visibility
var mattribute = try_get_mproperty_by_name(null, mclassdef, name)
if mattribute == null then mattribute = new MAttribute(mclassdef, name, mclassdef.location, visibility)
return create_attribute_from_property(mattribute.as(MAttribute), mclassdef, mtype)
end
# Creation of a new attribute (AST and model representation) with the given MAttribute.
# See `create_attribute_from_propdef` for more information.
fun create_attribute_from_property(mattribute: MAttribute, mclassdef: MClassDef, mtype: MType): AAttrPropdef do
var attribut_def = new MAttributeDef(mclassdef, mattribute, mclassdef.location)
attribut_def.static_mtype = mtype
return create_attribute_from_propdef(attribut_def)
end
# Creation of a new attribute (AST representation) with the given MAttributeDef.
fun create_attribute_from_propdef(mattribut_def: MAttributeDef): AAttrPropdef
is
expect(mclassdef2node(mattribut_def.mclassdef) != null)
do
var n_attribute = mattribut_def.create_ast_representation
var nclass = mclassdef2node(mattribut_def.mclassdef)
n_attribute.location = mattribut_def.location
n_attribute.validate
nclass.n_propdefs.unsafe_add_all([n_attribute])
nclass.validate
n_attribute.build_read_property(self, mattribut_def.mclassdef)
n_attribute.build_read_signature
mpropdef2npropdef[mattribut_def] = n_attribute
return n_attribute
end
# Creation of a new class (AST and model representation) with the given name.
# `visibility` : Define the visibility of the method. If it's `null` the default is `public_visibility`
# See `create_class_from_mclass` for more information.
fun create_class_from_name(name: String, super_type: Array[MClassType], mmodule: MModule, visibility: nullable MVisibility): AStdClassdef do
if visibility == null then visibility = public_visibility
var mclass = try_get_mclass_by_name(null, mmodule, name)
if mclass == null then mclass = new MClass(mmodule, name, mmodule.location, new Array[String], concrete_kind, visibility)
return create_class_from_mclass(mclass, super_type, mmodule)
end
# Creation of a new class (AST and model representation) with the given MClass.
# This method creates a new concrete class definition `MClassDef`, and adds it to the class hierarchy.
# See `create_class_from_mclassdef` for more information.
fun create_class_from_mclass(mclass: MClass, super_type: Array[MClassType], mmodule: MModule): AStdClassdef do
var mclassdef = new MClassDef(mmodule, mclass.mclass_type, mmodule.location)
mclassdef.set_supertypes(super_type)
mclassdef.add_in_hierarchy
return create_class_from_mclassdef(mclassdef, mmodule)
end
# Creation of a new class (AST representation) with the given MClassDef.
# Note all the properties of our MClassDef will also generate an AST representation.
# Make an error if the attribute already has a representation in the modelbuilder.
# This method also create the default constructor.
fun create_class_from_mclassdef(mclassdef: MClassDef, mmodule: MModule): AStdClassdef do
var n_classdef = mclassdef.create_ast_representation
n_classdef.location = mclassdef.location
n_classdef.validate
for n_propdef in n_classdef.n_propdefs do
var mpropdef = n_propdef.mpropdef
assert mpropdef != null
var p_npropdef = mpropdef2node(mpropdef)
if p_npropdef != null then error(null, "The property `{mpropdef.name}` already has a representation in the AST.")
unsafe_add_mpropdef2npropdef(mpropdef, n_propdef)
end
process_default_constructors(n_classdef)
unsafe_add_mclassdef2nclassdef(mclassdef, n_classdef)
return n_classdef
end
end
src/astbuilder.nit:1049,1--1169,3
redef class ModelBuilder
# Number of test classes generated.
var total_classes = 0
# Number of tests generated.
var total_tests = 0
# Number of failed tests.
var failed_tests = 0
# Run NitUnit test suite for `mmodule` (if it is one).
fun test_unit(mmodule: MModule): nullable HTMLTag do
# is the module a test_suite?
if not mmodule.is_test then return null
toolcontext.info("nitunit: test-suite {mmodule}", 2)
var tester = new NitUnitTester(self)
var res = tester.test_module_unit(mmodule)
return res.to_xml
end
end
src/testing/testing_suite.nit:580,1--600,3
redef class ModelBuilder
redef fun check_subtype(node, mmodule, anchor, sub, sup)
do
var res = super
var dcp = toolcontext.detect_covariance_phase
if dcp.is_disabled then return res
if res then
dcp.count_types(node, node, sub, sup, mmodule, anchor)
else
dcp.cpt_total_variance.inc("bad mb subtype")
end
return res
end
end
src/metrics/detect_covariance.nit:299,1--315,3
redef class ModelBuilder
# Performs a rapid-type-analysis on the program associated with `mainmodule`.
fun do_rapid_type_analysis(mainmodule: MModule): RapidTypeAnalysis
do
var analysis = new RapidTypeAnalysis(self, mainmodule)
analysis.run_analysis
if toolcontext.opt_log.value then
var basename = toolcontext.log_directory / mainmodule.name
analysis.live_methods_to_tree.write_to_file(basename + ".rta_methods.txt")
analysis.live_types_to_csv.write_to_file(basename + ".rta_types.csv")
end
return analysis
end
end
src/rapid_type_analysis.nit:33,1--48,3
redef class ModelBuilder
# Execute the program from the entry point (`Sys::main`) of the `mainmodule`
# `arguments` are the command-line arguments in order
# REQUIRE that:
# 1. the AST is fully loaded.
# 2. the model is fully built.
# 3. the instructions are fully analysed.
fun run_naive_interpreter(mainmodule: MModule, arguments: Array[String])
do
var time0 = get_time
self.toolcontext.info("*** START INTERPRETING ***", 1)
var interpreter = new NaiveInterpreter(self, mainmodule, arguments)
interpreter.start(mainmodule)
var time1 = get_time
self.toolcontext.info("*** END INTERPRETING: {time1-time0} ***", 2)
end
end
src/interpreter/naive_interpreter.nit:38,1--56,3
redef class ModelBuilder
# Total number analyzed `MEntity`
var total_entities = 0
# The number of `MEntity` that have some documentation
var doc_entities = 0
# The total number of executed docunits
var unit_entities = 0
# The number failed docunits
var failed_entities = 0
# Extracts and executes all the docunits in the `mmodule`
# Returns a JUnit-compatible `<testsuite>` XML element that contains the results of the executions.
fun test_markdown(mmodule: MModule): HTMLTag
do
var ts = new HTMLTag("testsuite")
toolcontext.info("nitunit: doc-unit {mmodule}", 2)
var nmodule = mmodule2node(mmodule)
if nmodule == null then return ts
# usualy, only the original module must be imported in the unit test.
var o = mmodule
var g = o.mgroup
if g != null and g.mpackage.name == "core" then
# except for a unit test in a module of `core`
# in this case, the whole `core` must be imported
o = get_mmodule_by_name(nmodule, g, g.mpackage.name).as(not null)
end
ts.attr("package", mmodule.full_name)
var prefix = toolcontext.test_dir
prefix = prefix.join_path(mmodule.to_s)
var d2m = new NitUnitExecutor(toolcontext, prefix, o, ts, "Docunits of module {mmodule.full_name}")
do
total_entities += 1
var nmoduledecl = nmodule.n_moduledecl
if nmoduledecl == null then break label x
var ndoc = nmoduledecl.n_doc
if ndoc == null then break label x
doc_entities += 1
# NOTE: jenkins expects a '.' in the classname attr
d2m.extract(ndoc.to_mdoc, "nitunit." + mmodule.full_name + ".<module>", "<module>")
end label x
for nclassdef in nmodule.n_classdefs do
var mclassdef = nclassdef.mclassdef
if mclassdef == null then continue
if nclassdef isa AStdClassdef then
total_entities += 1
var ndoc = nclassdef.n_doc
if ndoc != null then
doc_entities += 1
d2m.extract(ndoc.to_mdoc, "nitunit." + mclassdef.full_name.replace("$", "."), "<class>")
end
end
for npropdef in nclassdef.n_propdefs do
var mpropdef = npropdef.mpropdef
if mpropdef == null then continue
total_entities += 1
var ndoc = npropdef.n_doc
if ndoc != null then
doc_entities += 1
var a = mpropdef.full_name.split("$")
d2m.extract(ndoc.to_mdoc, "nitunit." + a[0] + "." + a[1], a[2])
end
end
end
d2m.run_tests
return ts
end
# Extracts and executes all the docunits in the readme of the `mgroup`
# Returns a JUnit-compatible `<testsuite>` XML element that contains the results of the executions.
fun test_group(mgroup: MGroup): HTMLTag
do
var ts = new HTMLTag("testsuite")
toolcontext.info("nitunit: doc-unit group {mgroup}", 2)
# usually, only the default module must be imported in the unit test.
var o = mgroup.default_mmodule
ts.attr("package", mgroup.full_name)
var prefix = toolcontext.test_dir
prefix = prefix.join_path(mgroup.to_s)
var d2m = new NitUnitExecutor(toolcontext, prefix, o, ts, "Docunits of group {mgroup.full_name}")
total_entities += 1
var mdoc = mgroup.mdoc
if mdoc == null then return ts
doc_entities += 1
# NOTE: jenkins expects a '.' in the classname attr
d2m.extract(mdoc, "nitunit." + mgroup.mpackage.name + "." + mgroup.name + ".<group>", "<group>")
d2m.run_tests
return ts
end
# Test a document object unrelated to a Nit entity
fun test_mdoc(mdoc: MDoc): HTMLTag
do
var ts = new HTMLTag("testsuite")
var file = mdoc.location.file.as(not null).filename
toolcontext.info("nitunit: doc-unit file {file}", 2)
ts.attr("package", file)
var prefix = toolcontext.test_dir / "file"
var d2m = new NitUnitExecutor(toolcontext, prefix, null, ts, "Docunits of file {file}")
total_entities += 1
doc_entities += 1
# NOTE: jenkins expects a '.' in the classname attr
d2m.extract(mdoc, "nitunit.<file>", file)
d2m.run_tests
return ts
end
end
src/testing/testing_doc.nit:550,1--678,3
redef class ModelBuilder
fun run_virtual_machine(mainmodule: MModule, arguments: Array[String])
do
var time0 = get_time
self.toolcontext.info("*** NITVM STARTING ***", 1)
var interpreter = new VirtualMachine(self, mainmodule, arguments)
interpreter.start(mainmodule)
var time1 = get_time
self.toolcontext.info("*** NITVM STOPPING : {time1-time0} ***", 2)
end
end
src/vm/virtual_machine.nit:23,1--35,3
redef class ModelBuilder
# Simple indirection to `Toolchain::write_and_make`
protected fun write_and_make(compiler: AbstractCompiler)
do
var platform = compiler.target_platform
var toolchain = platform.toolchain(toolcontext, compiler)
compiler.toolchain = toolchain
toolchain.write_and_make
end
end
src/compiler/abstract_compiler.nit:120,1--129,3
redef class ModelBuilder
# Start the Java compiler
fun run_java_compiler(mainmodule: MModule, runtime_type_analysis: RapidTypeAnalysis) do
var time0 = get_time
toolcontext.info("*** GENERATING JAVA ***", 1)
var compiler = new JavaCompiler(mainmodule, self, runtime_type_analysis)
compiler.do_compilation
var time1 = get_time
toolcontext.info("*** END GENERATING JAVA: {time1-time0} ***", 2)
write_and_make(compiler)
end
# Write Java code and compile it into an executable jar
fun write_and_make(compiler: JavaCompiler) do
var time0 = get_time
toolcontext.info("*** WRITING JAVA ***", 1)
compiler.compile_dir.mkdir
var jfiles = write_java_files(compiler)
var time1 = get_time
toolcontext.info("*** END WRITING JAVA: {time1-time0} ***", 2)
time0 = time1
toolcontext.info("*** COMPILING JAVA ***", 1)
if toolcontext.opt_ant.value then
build_with_ant(compiler, jfiles)
else
build_with_make(compiler, jfiles)
end
write_shell_script(compiler)
time1 = get_time
toolcontext.info("*** END COMPILING JAVA: {time1-time0} ***", 2)
end
# Write files managed by `compiler` into concrete files
fun write_java_files(compiler: JavaCompiler): Array[String] do
var jfiles = new Array[String]
for f in compiler.files do
var filepath = "{compiler.compile_dir}/{f.filename}"
var file = cache_file(filepath)
for line in f.lines do file.write(line)
close_cache(filepath, file)
jfiles.add(f.filename)
end
return jfiles
end
# Cache a file as `{filepath}.tmp` and replace the original if different
private fun cache_file(filepath: String): FileWriter do
if toolcontext.opt_ant.value and filepath.file_exists then
return new FileWriter.open("{filepath}.tmp")
else
return new FileWriter.open(filepath)
end
end
# Close the writer and move tmp file to original if modified
private fun close_cache(filepath: String, file: FileWriter) do
file.close
if "{filepath}.tmp".file_exists then
sys.system("if ! diff {filepath}.tmp {filepath} > /dev/null; then mv {filepath}.tmp {filepath}; else rm {filepath}.tmp; fi")
end
end
# Compile Java generated files using `make`
fun build_with_make(compiler: JavaCompiler, jfiles: Array[String]) do
write_manifest(compiler)
write_makefile(compiler, jfiles)
var compile_dir = compiler.compile_dir
var outname = compiler.outname.to_path.filename
toolcontext.info("make -N -C {compile_dir} -f {outname}.mk", 2)
var res
if toolcontext.verbose_level >= 3 then
res = sys.system("make -B -C {compile_dir} -f {outname}.mk 2>&1")
else
res = sys.system("make -B -C {compile_dir} -f {outname}.mk 2>&1 > /dev/null")
end
if res != 0 then toolcontext.error(null, "make failed! Error code: {res}.")
end
# Compile Java sources using `ant`
fun build_with_ant(compiler: JavaCompiler, jfiles: Array[String]) do
compile_antfile(compiler, jfiles)
var outname = compiler.outname.to_path.filename
var antpath = "{compiler.compile_dir}/{outname}.xml"
self.toolcontext.info("ant jar -f {antpath}", 2)
var res
if self.toolcontext.verbose_level >= 3 then
res = sys.system("ant jar -f {antpath} 2>&1")
else
res = sys.system("ant jar -f {antpath} 2>&1 > /dev/null")
end
if res != 0 then
toolcontext.error(null, "ant compile failed! Error code: {res}.")
end
end
# Write the Makefile used to compile Java generated files into an executable jar
fun write_makefile(compiler: JavaCompiler, jfiles: Array[String]) do
# list class files from jfiles
var ofiles = new List[String]
for f in jfiles do ofiles.add(f.strip_extension(".java") + ".class")
var compile_dir = compiler.compile_dir
var outname = compiler.outname.to_path.filename
var outpath = (sys.getcwd / compiler.outname).simplify_path
var makename = "{compile_dir}/{outname}.mk"
var makefile = new FileWriter.open(makename)
makefile.write("JC = javac\n")
makefile.write("JAR = jar\n\n")
makefile.write("all: {outpath}.jar\n\n")
makefile.write("{outpath}.jar: {compiler.mainmodule.jname}_Main.class\n")
makefile.write("\t$(JAR) cfm {outpath}.jar {outname}.mf {ofiles.join(" ")}\n\n")
makefile.write("{compiler.mainmodule.jname}_Main.class:\n")
makefile.write("\t$(JC) {jfiles.join(" ")}\n\n")
makefile.write("clean:\n")
makefile.write("\trm {ofiles.join(" ")} 2>/dev/null\n\n")
makefile.close
toolcontext.info("Generated makefile: {makename}", 2)
end
# The Ant `build.xml` script used to compile build the final jar
fun compile_antfile(compiler: JavaCompiler, jfiles: Array[String]) do
var compile_dir = compiler.compile_dir
var outname = compiler.outname.to_path.filename
var outpath = (sys.getcwd / compiler.outname).simplify_path
var antname = "{compile_dir}/{outname}.xml"
var antfile = new FileWriter.open(antname)
var jname = compiler.mainmodule.jname
antfile.write("<project>")
antfile.write(" <target name=\"compile\">")
antfile.write(" <mkdir dir=\"classes\"/>")
antfile.write(" <javac includes=\"{compiler.mainmodule.jname}_Main.java {jfiles.join(" ")}\" srcdir=\".\" destdir=\"classes\"/>")
antfile.write(" </target>")
antfile.write(" <target name=\"jar\" depends=\"compile\">")
antfile.write(" <jar destfile=\"{outpath}.jar\" basedir=\"classes\">")
antfile.write(" <manifest>")
antfile.write(" <attribute name=\"Main-Class\" value=\"{jname}_Main\"/>")
antfile.write(" </manifest>")
antfile.write(" </jar>")
antfile.write(" </target>")
antfile.write("</project>")
antfile.close
toolcontext.info("Generated antfile: {antname}", 2)
end
# Write the Java manifest file
private fun write_manifest(compiler: JavaCompiler) do
var compile_dir = compiler.compile_dir
var outname = compiler.outname.to_path.filename
var maniffile = new FileWriter.open("{compile_dir}/{outname}.mf")
maniffile.write("Manifest-Version: 1.0\n")
maniffile.write("Main-Class: {compiler.mainmodule.jname}_Main\n")
maniffile.close
end
# Write a simple bash script that runs the jar like it was a binary generated by nitc
private fun write_shell_script(compiler: JavaCompiler) do
var outname = compiler.outname
var shfile = new FileWriter.open(outname)
shfile.write("#!/bin/bash\n")
shfile.write("java -jar {outname}.jar \"$@\"\n")
shfile.close
sys.system("chmod +x {outname}")
end
end
src/compiler/java_compiler.nit:48,1--226,3
redef class ModelBuilder
# Entry point to performs a global compilation on the AST of a complete program.
# `mainmodule` is the main module of the program
# `runtime_type_analysis` is a already computer type analysis.
fun run_global_compiler(mainmodule: MModule, runtime_type_analysis: RapidTypeAnalysis)
do
var time0 = get_time
self.toolcontext.info("*** GENERATING C ***", 1)
var compiler = new GlobalCompiler(mainmodule, self, runtime_type_analysis)
compiler.do_compilation
compiler.display_stats
var time1 = get_time
self.toolcontext.info("*** END GENERATING C: {time1-time0} ***", 2)
write_and_make(compiler)
end
end
src/compiler/global_compiler.nit:52,1--69,3
redef class ModelBuilder
fun run_separate_compiler(mainmodule: MModule, runtime_type_analysis: nullable RapidTypeAnalysis)
do
var time0 = get_time
self.toolcontext.info("*** GENERATING C ***", 1)
var compiler = new SeparateCompiler(mainmodule, self, runtime_type_analysis)
compiler.do_compilation
compiler.display_stats
var time1 = get_time
self.toolcontext.info("*** END GENERATING C: {time1-time0} ***", 2)
write_and_make(compiler)
end
# Count number of invocations by VFT
private var nb_invok_by_tables = 0
# Count number of invocations by direct call
private var nb_invok_by_direct = 0
# Count number of invocations by inlining
private var nb_invok_by_inline = 0
end
src/compiler/separate_compiler.nit:114,1--135,3
redef class ModelBuilder
redef fun write_and_make(compiler)
do
var uses_json_serialization_read = false
for mod in compiler.mainmodule.in_importation.greaters do
var concern = mod.parent_concern
if mod.name == "serialization_read" and concern != null and concern.name == "json" then
uses_json_serialization_read = true
break
end
end
if uses_json_serialization_read then
write_poset_to_file(compiler, "nit_class_inheritance_metamodel", compiler.mainmodule.flatten_mclass_hierarchy)
end
super
end
# Write `poset` to a C file
private fun write_poset_to_file(compiler: AbstractCompiler, name: String, poset: POSet[Object])
do
var json = poset.to_thin_json
var code = new CodeFile(name)
compiler.files.add code
var writer = new CodeWriter(code)
writer.add """
char *{{{name}}} = "{{{json.escape_to_c}}}";
"""
end
end
src/compiler/compiler_serialization.nit:21,1--53,3
redef class ModelBuilder
fun run_separate_erasure_compiler(mainmodule: MModule, runtime_type_analysis: nullable RapidTypeAnalysis)
do
var time0 = get_time
self.toolcontext.info("*** GENERATING C ***", 1)
var compiler = new SeparateErasureCompiler(mainmodule, self, runtime_type_analysis)
compiler.do_compilation
compiler.display_stats
var time1 = get_time
self.toolcontext.info("*** END GENERATING C: {time1-time0} ***", 2)
write_and_make(compiler)
end
end
src/compiler/separate_erasure_compiler.nit:66,1--79,3
redef class ModelBuilder
redef fun run_naive_interpreter(mainmodule: MModule, arguments: Array[String])
do
var clone_visitor = new CloneVisitor
for nmodule in self.nmodules do
clone_visitor.enter_visit(nmodule)
end
super
end
end
src/test_astbuilder.nit:25,1--34,3