1 # This file is part of NIT ( http://www.nitlanguage.org ).
3 # Copyright 2012 Jean Privat <jean@pryen.org>
5 # Licensed under the Apache License, Version 2.0 (the "License");
6 # you may not use this file except in compliance with the License.
7 # You may obtain a copy of the License at
9 # http://www.apache.org/licenses/LICENSE-2.0
11 # Unless required by applicable law or agreed to in writing, software
12 # distributed under the License is distributed on an "AS IS" BASIS,
13 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 # See the License for the specific language governing permissions and
15 # limitations under the License.
17 # Load nit source files and build the associated model
21 # FIXME split this module into submodules
22 # FIXME add missing error checks
34 redef class ToolContext
36 readable var _opt_path
: OptionArray = new OptionArray("Set include path for loaders (may be used more than once)", "-I", "--path")
38 # Option --only-metamodel
39 readable var _opt_only_metamodel
: OptionBool = new OptionBool("Stop after meta-model processing", "--only-metamodel")
42 readable var _opt_only_parse
: OptionBool = new OptionBool("Only proceed to parse step of loaders", "--only-parse")
47 option_context
.add_option
(opt_path
, opt_only_parse
, opt_only_metamodel
)
50 fun modelbuilder
: ModelBuilder do return modelbuilder_real
.as(not null)
51 private var modelbuilder_real
: nullable ModelBuilder = null
53 var modelize_class_phase
: Phase = new ModelizeClassPhase(self, null)
56 private class ModelizeClassPhase
59 redef fun process_nmodule
(nmodule
)
61 toolcontext
.modelbuilder
.build_classes
(nmodule
)
65 # A model builder knows how to load nit source files and build the associated model
67 # The model where new modules, classes and properties are added
70 # The toolcontext used to control the interaction with the user (getting options and displaying messages)
71 var toolcontext
: ToolContext
73 # Run phases on all loaded modules
76 var mmodules
= model
.mmodules
.to_a
77 model
.mmodule_importation_hierarchy
.sort
(mmodules
)
78 var nmodules
= new Array[AModule]
80 nmodules
.add
(mmodule2nmodule
[mm
])
82 toolcontext
.run_phases
(nmodules
)
85 # Instantiate a modelbuilder for a model and a toolcontext
86 # Important, the options of the toolcontext must be correctly set (parse_option already called)
87 init(model
: Model, toolcontext
: ToolContext)
90 self.toolcontext
= toolcontext
91 assert toolcontext
.modelbuilder_real
== null
92 toolcontext
.modelbuilder_real
= self
94 # Setup the paths value
95 paths
.append
(toolcontext
.opt_path
.value
)
97 var path_env
= "NIT_PATH".environ
98 if not path_env
.is_empty
then
99 paths
.append
(path_env
.split_with
(':'))
102 path_env
= "NIT_DIR".environ
103 if not path_env
.is_empty
then
104 var libname
= "{path_env}/lib"
105 if libname
.file_exists
then paths
.add
(libname
)
108 var libname
= "{sys.program_name.dirname}/../lib"
109 if libname
.file_exists
then paths
.add
(libname
.simplify_path
)
112 # Load a bunch of modules.
113 # `modules' can contains filenames or module names.
114 # Imported modules are automatically loaded and modelized.
115 # The result is the corresponding model elements.
116 # Errors and warnings are printed with the toolcontext.
118 # Note: class and property model element are not analysed.
119 fun parse
(modules
: Sequence[String]): Array[MModule]
122 # Parse and recursively load
123 self.toolcontext
.info
("*** PARSE ***", 1)
124 var mmodules
= new Array[MModule]
126 var nmodule
= self.load_module
(null, a
)
127 if nmodule
== null then continue # Skip error
128 mmodules
.add
(nmodule
.mmodule
.as(not null))
131 self.toolcontext
.info
("*** END PARSE: {time1-time0} ***", 2)
133 self.toolcontext
.check_errors
137 # Return a class named `name' visible by the module `mmodule'.
138 # Visibility in modules is correctly handled.
139 # If no such a class exists, then null is returned.
140 # If more than one class exists, then an error on `anode' is displayed and null is returned.
141 # FIXME: add a way to handle class name conflict
142 fun try_get_mclass_by_name
(anode
: ANode, mmodule
: MModule, name
: String): nullable MClass
144 var classes
= model
.get_mclasses_by_name
(name
)
145 if classes
== null then
149 var res
: nullable MClass = null
150 for mclass
in classes
do
151 if not mmodule
.in_importation
<= mclass
.intro_mmodule
then continue
152 if not mmodule
.is_visible
(mclass
.intro_mmodule
, mclass
.visibility
) then continue
156 error
(anode
, "Ambigous class name '{name}'; conflict between {mclass.full_name} and {res.full_name}")
163 # Return a property named `name' on the type `mtype' visible in the module `mmodule'.
164 # Visibility in modules is correctly handled.
165 # Protected properties are returned (it is up to the caller to check and reject protected properties).
166 # If no such a property exists, then null is returned.
167 # If more than one property exists, then an error on `anode' is displayed and null is returned.
168 # FIXME: add a way to handle property name conflict
169 fun try_get_mproperty_by_name2
(anode
: ANode, mmodule
: MModule, mtype
: MType, name
: String): nullable MProperty
171 var props
= self.model
.get_mproperties_by_name
(name
)
172 if props
== null then
176 var cache
= self.try_get_mproperty_by_name2_cache
[mmodule
, mtype
, name
]
177 if cache
!= null then return cache
179 var res
: nullable MProperty = null
180 var ress
: nullable Array[MProperty] = null
181 for mprop
in props
do
182 if not mtype
.has_mproperty
(mmodule
, mprop
) then continue
183 if not mmodule
.is_visible
(mprop
.intro_mclassdef
.mmodule
, mprop
.visibility
) then continue
187 var restype
= res
.intro_mclassdef
.bound_mtype
188 var mproptype
= mprop
.intro_mclassdef
.bound_mtype
189 if restype
.is_subtype
(mmodule
, null, mproptype
) then
191 else if mproptype
.is_subtype
(mmodule
, null, restype
) then
194 if ress
== null then ress
= new Array[MProperty]
200 var restype
= res
.intro_mclassdef
.bound_mtype
202 var mproptype
= mprop
.intro_mclassdef
.bound_mtype
203 if not restype
.is_subtype
(mmodule
, null, mproptype
) then
204 self.error
(anode
, "Ambigous property name '{name}' for {mtype}; conflict between {mprop.full_name} and {res.full_name}")
210 self.try_get_mproperty_by_name2_cache
[mmodule
, mtype
, name
] = res
214 private var try_get_mproperty_by_name2_cache
: HashMap3[MModule, MType, String, nullable MProperty] = new HashMap3[MModule, MType, String, nullable MProperty]
217 # Alias for try_get_mproperty_by_name2(anode, mclassdef.mmodule, mclassdef.mtype, name)
218 fun try_get_mproperty_by_name
(anode
: ANode, mclassdef
: MClassDef, name
: String): nullable MProperty
220 return try_get_mproperty_by_name2
(anode
, mclassdef
.mmodule
, mclassdef
.bound_mtype
, name
)
223 # The list of directories to search for top level modules
224 # The list is initially set with :
225 # * the toolcontext --path option
226 # * the NIT_PATH environment variable
227 # * some heuristics including the NIT_DIR environment variable and the progname of the process
228 # Path can be added (or removed) by the client
229 var paths
: Array[String] = new Array[String]
231 # Get a module by its short name; if required, the module is loaded, parsed and its hierarchies computed.
232 # If `mmodule' is set, then the module search starts from it up to the top level (see `paths');
233 # if `mmodule' is null then the module is searched in the top level only.
234 # If no module exists or there is a name conflict, then an error on `anode' is displayed and null is returned.
235 # FIXME: add a way to handle module name conflict
236 fun get_mmodule_by_name
(anode
: ANode, mmodule
: nullable MModule, name
: String): nullable MModule
238 var origmmodule
= mmodule
239 var modules
= model
.get_mmodules_by_name
(name
)
241 var tries
= new Array[String]
243 var lastmodule
= mmodule
244 while mmodule
!= null do
245 var dirname
= mmodule
.location
.file
.filename
.dirname
247 # Determine the owner
248 var owner
: nullable MModule
249 if dirname
.basename
("") != mmodule
.name
then
250 owner
= mmodule
.direct_owner
255 # First, try the already known nested modules
256 if modules
!= null then
257 for candidate
in modules
do
258 if candidate
.direct_owner
== owner
then
264 # Second, try the directory to find a file
265 var try_file
= dirname
+ "/" + name
+ ".nit"
267 if try_file
.file_exists
then
268 var res
= self.load_module
(owner
, try_file
.simplify_path
)
269 if res
== null then return null # Forward error
270 return res
.mmodule
.as(not null)
273 # Third, try if the requested module is itself an owner
274 try_file
= dirname
+ "/" + name
+ "/" + name
+ ".nit"
275 if try_file
.file_exists
then
276 var res
= self.load_module
(owner
, try_file
.simplify_path
)
277 if res
== null then return null # Forward error
278 return res
.mmodule
.as(not null)
282 mmodule
= mmodule
.direct_owner
285 if modules
!= null then
286 for candidate
in modules
do
287 if candidate
.direct_owner
== null then
293 # Look at some known directories
294 var lookpaths
= self.paths
296 # Look in the directory of the last module also (event if not in the path)
297 if lastmodule
!= null then
298 var dirname
= lastmodule
.location
.file
.filename
.dirname
299 if dirname
.basename
("") == lastmodule
.name
then
300 dirname
= dirname
.dirname
302 if not lookpaths
.has
(dirname
) then
303 lookpaths
= lookpaths
.to_a
304 lookpaths
.add
(dirname
)
308 var candidate
: nullable String = null
309 for dirname
in lookpaths
do
310 var try_file
= (dirname
+ "/" + name
+ ".nit").simplify_path
312 if try_file
.file_exists
then
313 if candidate
== null then
315 else if candidate
!= try_file
then
316 error
(anode
, "Error: conflicting module file for {name}: {candidate} {try_file}")
319 try_file
= (dirname
+ "/" + name
+ "/" + name
+ ".nit").simplify_path
320 if try_file
.file_exists
then
321 if candidate
== null then
323 else if candidate
!= try_file
then
324 error
(anode
, "Error: conflicting module file for {name}: {candidate} {try_file}")
328 if candidate
== null then
329 if origmmodule
!= null then
330 error
(anode
, "Error: cannot find module {name} from {origmmodule}. tried {tries.join(", ")}")
332 error
(anode
, "Error: cannot find module {name}. tried {tries.join(", ")}")
336 var res
= self.load_module
(mmodule
, candidate
)
337 if res
== null then return null # Forward error
338 return res
.mmodule
.as(not null)
341 # Try to load a module using a path.
342 # Display an error if there is a problem (IO / lexer / parser) and return null
343 # Note: usually, you do not need this method, use `get_mmodule_by_name` instead.
344 fun load_module
(owner
: nullable MModule, filename
: String): nullable AModule
346 if not filename
.file_exists
then
347 self.toolcontext
.error
(null, "Error: file {filename} not found.")
351 var x
= if owner
!= null then owner
.to_s
else "."
352 self.toolcontext
.info
("load module {filename} in {x}", 2)
355 var file
= new IFStream.open
(filename
)
356 var lexer
= new Lexer(new SourceFile(filename
, file
))
357 var parser
= new Parser(lexer
)
358 var tree
= parser
.parse
361 # Handle lexer and parser error
362 var nmodule
= tree
.n_base
363 if nmodule
== null then
364 var neof
= tree
.n_eof
365 assert neof
isa AError
366 error
(neof
, neof
.message
)
370 # Check the module name
371 var mod_name
= filename
.basename
(".nit")
372 var decl
= nmodule
.n_moduledecl
374 #warning(nmodule, "Warning: Missing 'module' keyword") #FIXME: NOT YET FOR COMPATIBILITY
376 var decl_name
= decl
.n_name
.n_id
.text
377 if decl_name
!= mod_name
then
378 error
(decl
.n_name
, "Error: module name missmatch; declared {decl_name} file named {mod_name}")
383 var mmodule
= new MModule(model
, owner
, mod_name
, nmodule
.location
)
384 nmodule
.mmodule
= mmodule
385 nmodules
.add
(nmodule
)
386 self.mmodule2nmodule
[mmodule
] = nmodule
388 build_module_importation
(nmodule
)
393 # Analysis the module importation and fill the module_importation_hierarchy
394 private fun build_module_importation
(nmodule
: AModule)
396 if nmodule
.is_importation_done
then return
397 nmodule
.is_importation_done
= true
398 var mmodule
= nmodule
.mmodule
.as(not null)
400 var imported_modules
= new Array[MModule]
401 for aimport
in nmodule
.n_imports
do
403 if not aimport
isa AStdImport then
406 var mod_name
= aimport
.n_name
.n_id
.text
407 var sup
= self.get_mmodule_by_name
(aimport
.n_name
, mmodule
, mod_name
)
408 if sup
== null then continue # Skip error
409 imported_modules
.add
(sup
)
410 var mvisibility
= aimport
.n_visibility
.mvisibility
411 mmodule
.set_visibility_for
(sup
, mvisibility
)
414 var mod_name
= "standard"
415 var sup
= self.get_mmodule_by_name
(nmodule
, null, mod_name
)
416 if sup
!= null then # Skip error
417 imported_modules
.add
(sup
)
418 mmodule
.set_visibility_for
(sup
, public_visibility
)
421 self.toolcontext
.info
("{mmodule} imports {imported_modules.join(", ")}", 3)
422 mmodule
.set_imported_mmodules
(imported_modules
)
425 # All the loaded modules
426 var nmodules
: Array[AModule] = new Array[AModule]
428 # Visit the AST and create the MClass objects
429 private fun build_a_mclass
(nmodule
: AModule, nclassdef
: AClassdef)
431 var mmodule
= nmodule
.mmodule
.as(not null)
434 var nkind
: nullable AClasskind
435 var mkind
: MClassKind
436 var nvisibility
: nullable AVisibility
437 var mvisibility
: nullable MVisibility
439 if nclassdef
isa AStdClassdef then
440 name
= nclassdef
.n_id
.text
441 nkind
= nclassdef
.n_classkind
443 nvisibility
= nclassdef
.n_visibility
444 mvisibility
= nvisibility
.mvisibility
445 arity
= nclassdef
.n_formaldefs
.length
446 else if nclassdef
isa ATopClassdef then
449 mkind
= interface_kind
451 mvisibility
= public_visibility
452 else if nclassdef
isa AMainClassdef then
455 mkind
= concrete_kind
457 mvisibility
= public_visibility
462 var mclass
= try_get_mclass_by_name
(nclassdef
, mmodule
, name
)
463 if mclass
== null then
464 mclass
= new MClass(mmodule
, name
, arity
, mkind
, mvisibility
)
465 #print "new class {mclass}"
466 else if nclassdef
isa AStdClassdef and nmodule
.mclass2nclassdef
.has_key
(mclass
) then
467 error
(nclassdef
, "Error: A class {name} is already defined at line {nmodule.mclass2nclassdef[mclass].location.line_start}.")
469 else if nclassdef
isa AStdClassdef and nclassdef
.n_kwredef
== null then
470 error
(nclassdef
, "Redef error: {name} is an imported class. Add the redef keyword to refine it.")
472 else if mclass
.arity
!= arity
then
473 error
(nclassdef
, "Redef error: Formal parameter arity missmatch; got {arity}, expected {mclass.arity}.")
475 else if nkind
!= null and mkind
!= concrete_kind
and mclass
.kind
!= mkind
then
476 error
(nkind
, "Error: refinement changed the kind from a {mclass.kind} to a {mkind}")
477 else if nvisibility
!= null and mvisibility
!= public_visibility
and mclass
.visibility
!= mvisibility
then
478 error
(nvisibility
, "Error: refinement changed the visibility from a {mclass.visibility} to a {mvisibility}")
480 nclassdef
.mclass
= mclass
481 nmodule
.mclass2nclassdef
[mclass
] = nclassdef
484 # Visit the AST and create the MClassDef objects
485 private fun build_a_mclassdef
(nmodule
: AModule, nclassdef
: AClassdef)
487 var mmodule
= nmodule
.mmodule
.as(not null)
488 var objectclass
= try_get_mclass_by_name
(nmodule
, mmodule
, "Object")
489 var mclass
= nclassdef
.mclass
490 if mclass
== null then return # Skip error
491 #var mclassdef = nclassdef.mclassdef.as(not null)
493 var names
= new Array[String]
494 var bounds
= new Array[MType]
495 if nclassdef
isa AStdClassdef and mclass
.arity
> 0 then
496 # Collect formal parameter names
497 for i
in [0..mclass
.arity
[ do
498 var nfd
= nclassdef
.n_formaldefs
[i
]
499 var ptname
= nfd
.n_id
.text
500 if names
.has
(ptname
) then
501 error
(nfd
, "Error: A formal parameter type `{ptname}' already exists")
507 # Revolve bound for formal parameter names
508 for i
in [0..mclass
.arity
[ do
509 var nfd
= nclassdef
.n_formaldefs
[i
]
510 var nfdt
= nfd
.n_type
512 var bound
= resolve_mtype_unchecked
(nclassdef
, nfdt
, false)
513 if bound
== null then return # Forward error
514 if bound
.need_anchor
then
516 error
(nfd
, "Error: Formal parameter type `{names[i]}' bounded with a formal parameter type")
520 else if mclass
.mclassdefs
.is_empty
then
521 # No bound, then implicitely bound by nullable Object
522 bounds
.add
(objectclass
.mclass_type
.as_nullable
)
525 bounds
.add
(mclass
.intro
.bound_mtype
.arguments
[i
])
530 var bound_mtype
= mclass
.get_mtype
(bounds
)
531 var mclassdef
= new MClassDef(mmodule
, bound_mtype
, nclassdef
.location
, names
)
532 nclassdef
.mclassdef
= mclassdef
533 self.mclassdef2nclassdef
[mclassdef
] = nclassdef
535 if mclassdef
.is_intro
then
536 self.toolcontext
.info
("{mclassdef} introduces new {mclass.kind} {mclass.full_name}", 3)
538 self.toolcontext
.info
("{mclassdef} refine {mclass.kind} {mclass.full_name}", 3)
542 # Visit the AST and set the super-types of the MClassdef objects
543 private fun collect_a_mclassdef_inheritance
(nmodule
: AModule, nclassdef
: AClassdef)
545 var mmodule
= nmodule
.mmodule
.as(not null)
546 var objectclass
= try_get_mclass_by_name
(nmodule
, mmodule
, "Object")
547 var mclass
= nclassdef
.mclass
.as(not null)
548 var mclassdef
= nclassdef
.mclassdef
.as(not null)
550 var specobject
= true
551 var supertypes
= new Array[MClassType]
552 if nclassdef
isa AStdClassdef then
553 for nsc
in nclassdef
.n_superclasses
do
555 var ntype
= nsc
.n_type
556 var mtype
= resolve_mtype_unchecked
(nclassdef
, ntype
, false)
557 if mtype
== null then continue # Skip because of error
558 if not mtype
isa MClassType then
559 error
(ntype
, "Error: supertypes cannot be a formal type")
563 #print "new super : {mclass} < {mtype}"
566 if specobject
and mclass
.name
!= "Object" and objectclass
!= null and mclassdef
.is_intro
then
567 supertypes
.add objectclass
.mclass_type
570 mclassdef
.set_supertypes
(supertypes
)
571 if not supertypes
.is_empty
then self.toolcontext
.info
("{mclassdef} new super-types: {supertypes.join(", ")}", 3)
574 # Check the validity of the specialization heirarchy
575 private fun check_supertypes
(nmodule
: AModule, nclassdef
: AClassdef)
577 var mmodule
= nmodule
.mmodule
.as(not null)
578 var objectclass
= try_get_mclass_by_name
(nmodule
, mmodule
, "Object")
579 var mclass
= nclassdef
.mclass
.as(not null)
580 var mclassdef
= nclassdef
.mclassdef
.as(not null)
582 for s
in mclassdef
.supertypes
do
583 if s
.is_subtype
(mmodule
, mclassdef
.bound_mtype
, mclassdef
.bound_mtype
) then
584 error
(nclassdef
, "Error: Inheritance loop for class {mclass} with type {s}")
589 # Build the classes of the module `nmodule'.
590 # REQUIRE: classes of imported modules are already build. (let `phase' do the job)
591 private fun build_classes
(nmodule
: AModule)
593 # Force building recursively
594 if nmodule
.build_classes_is_done
then return
595 nmodule
.build_classes_is_done
= true
596 var mmodule
= nmodule
.mmodule
.as(not null)
597 for imp
in mmodule
.in_importation
.direct_greaters
do
599 build_classes
(mmodule2nmodule
[imp
])
603 for nclassdef
in nmodule
.n_classdefs
do
604 self.build_a_mclass
(nmodule
, nclassdef
)
607 # Create all classdefs
608 for nclassdef
in nmodule
.n_classdefs
do
609 self.build_a_mclassdef
(nmodule
, nclassdef
)
612 for nclassdef
in nmodule
.n_classdefs
do
613 if nclassdef
.mclassdef
== null then return # forward error
616 # Create inheritance on all classdefs
617 for nclassdef
in nmodule
.n_classdefs
do
618 self.collect_a_mclassdef_inheritance
(nmodule
, nclassdef
)
621 # Create the mclassdef hierarchy
622 for nclassdef
in nmodule
.n_classdefs
do
623 var mclassdef
= nclassdef
.mclassdef
.as(not null)
624 mclassdef
.add_in_hierarchy
628 for nclassdef
in nmodule
.n_classdefs
do
629 self.check_supertypes
(nmodule
, nclassdef
)
632 # Check unchecked ntypes
633 for nclassdef
in nmodule
.n_classdefs
do
634 if nclassdef
isa AStdClassdef then
635 # check bound of formal parameter
636 for nfd
in nclassdef
.n_formaldefs
do
637 var nfdt
= nfd
.n_type
638 if nfdt
!= null and nfdt
.mtype
!= null then
639 var bound
= resolve_mtype
(nclassdef
, nfdt
)
640 if bound
== null then return # Forward error
643 # check declared super types
644 for nsc
in nclassdef
.n_superclasses
do
645 var ntype
= nsc
.n_type
646 if ntype
.mtype
!= null then
647 var mtype
= resolve_mtype
(nclassdef
, ntype
)
648 if mtype
== null then return # Forward error
655 # TODO: Check that the super-class is not intrusive
657 # TODO: Check that the super-class is not already known (by transitivity)
660 # Register the nmodule associated to each mmodule
661 # FIXME: why not refine the MModule class with a nullable attribute?
662 var mmodule2nmodule
: HashMap[MModule, AModule] = new HashMap[MModule, AModule]
663 # Register the nclassdef associated to each mclassdef
664 # FIXME: why not refine the MClassDef class with a nullable attribute?
665 var mclassdef2nclassdef
: HashMap[MClassDef, AClassdef] = new HashMap[MClassDef, AClassdef]
667 # Return the static type associated to the node `ntype'.
668 # `classdef' is the context where the call is made (used to understand formal types)
669 # The mmodule used as context is `nclassdef.mmodule'
670 # In case of problem, an error is displayed on `ntype' and null is returned.
671 # FIXME: the name "resolve_mtype" is awful
672 fun resolve_mtype_unchecked
(nclassdef
: AClassdef, ntype
: AType, with_virtual
: Bool): nullable MType
674 var name
= ntype
.n_id
.text
675 var mclassdef
= nclassdef
.mclassdef
676 var mmodule
= nclassdef
.parent
.as(AModule).mmodule
.as(not null)
680 if mclassdef
!= null and with_virtual
then
681 var prop
= try_get_mproperty_by_name
(ntype
, mclassdef
, name
).as(nullable MVirtualTypeProp)
683 if not ntype
.n_types
.is_empty
then
684 error
(ntype
, "Type error: formal type {name} cannot have formal parameters.")
686 res
= prop
.mvirtualtype
687 if ntype
.n_kwnullable
!= null then res
= res
.as_nullable
693 # Check parameter type
694 if mclassdef
!= null and mclassdef
.parameter_names
.has
(name
) then
695 if not ntype
.n_types
.is_empty
then
696 error
(ntype
, "Type error: formal type {name} cannot have formal parameters.")
698 for i
in [0..mclassdef
.parameter_names
.length
[ do
699 if mclassdef
.parameter_names
[i
] == name
then
700 res
= mclassdef
.mclass
.mclass_type
.arguments
[i
]
701 if ntype
.n_kwnullable
!= null then res
= res
.as_nullable
710 var mclass
= try_get_mclass_by_name
(ntype
, mmodule
, name
)
711 if mclass
!= null then
712 var arity
= ntype
.n_types
.length
713 if arity
!= mclass
.arity
then
715 error
(ntype
, "Type error: '{name}' is a generic class.")
716 else if mclass
.arity
== 0 then
717 error
(ntype
, "Type error: '{name}' is not a generic class.")
719 error
(ntype
, "Type error: '{name}' has {mclass.arity} parameters ({arity} are provided).")
724 res
= mclass
.mclass_type
725 if ntype
.n_kwnullable
!= null then res
= res
.as_nullable
729 var mtypes
= new Array[MType]
730 for nt
in ntype
.n_types
do
731 var mt
= resolve_mtype_unchecked
(nclassdef
, nt
, with_virtual
)
732 if mt
== null then return null # Forward error
735 res
= mclass
.get_mtype
(mtypes
)
736 if ntype
.n_kwnullable
!= null then res
= res
.as_nullable
742 # If everything fail, then give up :(
743 error
(ntype
, "Type error: class {name} not found in module {mmodule}.")
747 # Return the static type associated to the node `ntype'.
748 # `classdef' is the context where the call is made (used to understand formal types)
749 # The mmodule used as context is `nclassdef.mmodule'
750 # In case of problem, an error is displayed on `ntype' and null is returned.
751 # FIXME: the name "resolve_mtype" is awful
752 fun resolve_mtype
(nclassdef
: AClassdef, ntype
: AType): nullable MType
754 var mtype
= ntype
.mtype
755 if mtype
== null then mtype
= resolve_mtype_unchecked
(nclassdef
, ntype
, true)
756 if mtype
== null then return null # Forward error
758 if ntype
.checked_mtype
then return mtype
759 if mtype
isa MGenericType then
760 var mmodule
= nclassdef
.parent
.as(AModule).mmodule
.as(not null)
761 var mclassdef
= nclassdef
.mclassdef
762 var mclass
= mtype
.mclass
763 for i
in [0..mclass
.arity
[ do
764 var bound
= mclass
.intro
.bound_mtype
.arguments
[i
]
765 var nt
= ntype
.n_types
[i
]
766 var mt
= resolve_mtype
(nclassdef
, nt
)
767 if mt
== null then return null # forward error
768 if not mt
.is_subtype
(mmodule
, mclassdef
.bound_mtype
, bound
) then
769 error
(nt
, "Type error: expected {bound}, got {mt}")
774 ntype
.checked_mtype
= true
778 # Helper function to display an error on a node.
779 # Alias for `self.toolcontext.error(n.hot_location, text)'
780 fun error
(n
: ANode, text
: String)
782 self.toolcontext
.error
(n
.hot_location
, text
)
785 # Helper function to display a warning on a node.
786 # Alias for: `self.toolcontext.warning(n.hot_location, text)'
787 fun warning
(n
: ANode, text
: String)
789 self.toolcontext
.warning
(n
.hot_location
, text
)
792 # Force to get the primitive method named `name' on the type `recv' or do a fatal error on `n'
793 fun force_get_primitive_method
(n
: ANode, name
: String, recv
: MType, mmodule
: MModule): MMethod
795 var res
= mmodule
.try_get_primitive_method
(name
, recv
)
797 self.toolcontext
.fatal_error
(n
.hot_location
, "Fatal Error: {recv} must have a property named {name}.")
805 # The associated MModule once build by a `ModelBuilder'
806 var mmodule
: nullable MModule
807 # Flag that indicate if the importation is already completed
808 var is_importation_done
: Bool = false
809 # Flag that indicate if the class and prop building is already completed
810 var build_classes_is_done
: Bool = false
811 # What is the AClassdef associated to a MClass?
812 # Used to check multiple definition of a class.
813 var mclass2nclassdef
: Map[MClass, AClassdef] = new HashMap[MClass, AClassdef]
817 redef class AClassdef
818 # The associated MClass once build by a `ModelBuilder'
819 var mclass
: nullable MClass
820 # The associated MClassDef once build by a `ModelBuilder'
821 var mclassdef
: nullable MClassDef
824 redef class AClasskind
825 # The class kind associated with the AST node class
826 private fun mkind
: MClassKind is abstract
828 redef class AConcreteClasskind
829 redef fun mkind
do return concrete_kind
831 redef class AAbstractClasskind
832 redef fun mkind
do return abstract_kind
834 redef class AInterfaceClasskind
835 redef fun mkind
do return interface_kind
837 redef class AEnumClasskind
838 redef fun mkind
do return enum_kind
840 redef class AExternClasskind
841 redef fun mkind
do return extern_kind
844 redef class AVisibility
845 # The visibility level associated with the AST node class
846 fun mvisibility
: MVisibility is abstract
848 redef class AIntrudeVisibility
849 redef fun mvisibility
do return intrude_visibility
851 redef class APublicVisibility
852 redef fun mvisibility
do return public_visibility
854 redef class AProtectedVisibility
855 redef fun mvisibility
do return protected_visibility
857 redef class APrivateVisibility
858 redef fun mvisibility
do return private_visibility
862 # The mtype associated to the node
863 var mtype
: nullable MType = null
865 # Is the mtype a valid one?
866 var checked_mtype
: Bool = false