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)
54 var modelize_property_phase
: Phase = new ModelizePropertyPhase(self, [modelize_class_phase
])
57 private class ModelizeClassPhase
60 redef fun process_nmodule
(nmodule
)
62 toolcontext
.modelbuilder
.build_classes
(nmodule
)
66 private class ModelizePropertyPhase
68 redef fun process_nmodule
(nmodule
)
70 for nclassdef
in nmodule
.n_classdefs
do
71 toolcontext
.modelbuilder
.build_properties
(nclassdef
)
76 # A model builder knows how to load nit source files and build the associated model
77 # The important function is `parse_and_build' that does all the job.
78 # The others function can be used for specific tasks
80 # The model where new modules, classes and properties are added
83 # The toolcontext used to control the interaction with the user (getting options and displaying messages)
84 var toolcontext
: ToolContext
88 var mmodules
= model
.mmodules
.to_a
89 model
.mmodule_importation_hierarchy
.sort
(mmodules
)
90 var nmodules
= new Array[AModule]
92 nmodules
.add
(mmodule2nmodule
[mm
])
94 toolcontext
.run_phases
(nmodules
)
97 # Instantiate a modelbuilder for a model and a toolcontext
98 # Important, the options of the toolcontext must be correctly set (parse_option already called)
99 init(model
: Model, toolcontext
: ToolContext)
102 self.toolcontext
= toolcontext
103 assert toolcontext
.modelbuilder_real
== null
104 toolcontext
.modelbuilder_real
= self
106 # Setup the paths value
107 paths
.append
(toolcontext
.opt_path
.value
)
109 var path_env
= "NIT_PATH".environ
110 if not path_env
.is_empty
then
111 paths
.append
(path_env
.split_with
(':'))
114 path_env
= "NIT_DIR".environ
115 if not path_env
.is_empty
then
116 var libname
= "{path_env}/lib"
117 if libname
.file_exists
then paths
.add
(libname
)
120 var libname
= "{sys.program_name.dirname}/../lib"
121 if libname
.file_exists
then paths
.add
(libname
.simplify_path
)
124 # Load and analyze a bunch of modules.
125 # `modules' can contains filenames or module names.
126 # Imported modules are automatically loaded, builds and analysed.
127 # The result is the corresponding built modules.
128 # Errors and warnings are printed with the toolcontext.
130 # FIXME: Maybe just let the client do the loop (instead of playing with Sequences)
131 fun parse_and_build
(modules
: Sequence[String]): Array[MModule]
133 var mmodules
= parse
(modules
)
135 if self.toolcontext
.opt_only_parse
.value
then
136 self.toolcontext
.info
("--only-parse: stop processing", 2)
137 return new Array[MModule]
142 self.toolcontext
.info
("*** BUILD MODEL ***", 1)
143 self.build_all_classes
145 self.toolcontext
.info
("*** END BUILD MODEL: {time2-time1} ***", 2)
147 self.toolcontext
.check_errors
152 fun parse
(modules
: Sequence[String]): Array[MModule]
155 # Parse and recursively load
156 self.toolcontext
.info
("*** PARSE ***", 1)
157 var mmodules
= new Array[MModule]
159 var nmodule
= self.load_module
(null, a
)
160 if nmodule
== null then continue # Skip error
161 mmodules
.add
(nmodule
.mmodule
.as(not null))
164 self.toolcontext
.info
("*** END PARSE: {time1-time0} ***", 2)
166 self.toolcontext
.check_errors
170 # Return a class named `name' visible by the module `mmodule'.
171 # Visibility in modules is correctly handled.
172 # If no such a class exists, then null is returned.
173 # If more than one class exists, then an error on `anode' is displayed and null is returned.
174 # FIXME: add a way to handle class name conflict
175 fun try_get_mclass_by_name
(anode
: ANode, mmodule
: MModule, name
: String): nullable MClass
177 var classes
= model
.get_mclasses_by_name
(name
)
178 if classes
== null then
182 var res
: nullable MClass = null
183 for mclass
in classes
do
184 if not mmodule
.in_importation
<= mclass
.intro_mmodule
then continue
185 if not mmodule
.is_visible
(mclass
.intro_mmodule
, mclass
.visibility
) then continue
189 error
(anode
, "Ambigous class name '{name}'; conflict between {mclass.full_name} and {res.full_name}")
196 # Return a property named `name' on the type `mtype' visible in the module `mmodule'.
197 # Visibility in modules is correctly handled.
198 # Protected properties are returned (it is up to the caller to check and reject protected properties).
199 # If no such a property exists, then null is returned.
200 # If more than one property exists, then an error on `anode' is displayed and null is returned.
201 # FIXME: add a way to handle property name conflict
202 fun try_get_mproperty_by_name2
(anode
: ANode, mmodule
: MModule, mtype
: MType, name
: String): nullable MProperty
204 var props
= self.model
.get_mproperties_by_name
(name
)
205 if props
== null then
209 var cache
= self.try_get_mproperty_by_name2_cache
[mmodule
, mtype
, name
]
210 if cache
!= null then return cache
212 var res
: nullable MProperty = null
213 var ress
: nullable Array[MProperty] = null
214 for mprop
in props
do
215 if not mtype
.has_mproperty
(mmodule
, mprop
) then continue
216 if not mmodule
.is_visible
(mprop
.intro_mclassdef
.mmodule
, mprop
.visibility
) then continue
220 var restype
= res
.intro_mclassdef
.bound_mtype
221 var mproptype
= mprop
.intro_mclassdef
.bound_mtype
222 if restype
.is_subtype
(mmodule
, null, mproptype
) then
224 else if mproptype
.is_subtype
(mmodule
, null, restype
) then
227 if ress
== null then ress
= new Array[MProperty]
233 var restype
= res
.intro_mclassdef
.bound_mtype
235 var mproptype
= mprop
.intro_mclassdef
.bound_mtype
236 if not restype
.is_subtype
(mmodule
, null, mproptype
) then
237 self.error
(anode
, "Ambigous property name '{name}' for {mtype}; conflict between {mprop.full_name} and {res.full_name}")
243 self.try_get_mproperty_by_name2_cache
[mmodule
, mtype
, name
] = res
247 private var try_get_mproperty_by_name2_cache
: HashMap3[MModule, MType, String, nullable MProperty] = new HashMap3[MModule, MType, String, nullable MProperty]
250 # Alias for try_get_mproperty_by_name2(anode, mclassdef.mmodule, mclassdef.mtype, name)
251 fun try_get_mproperty_by_name
(anode
: ANode, mclassdef
: MClassDef, name
: String): nullable MProperty
253 return try_get_mproperty_by_name2
(anode
, mclassdef
.mmodule
, mclassdef
.bound_mtype
, name
)
256 # The list of directories to search for top level modules
257 # The list is initially set with :
258 # * the toolcontext --path option
259 # * the NIT_PATH environment variable
260 # * some heuristics including the NIT_DIR environment variable and the progname of the process
261 # Path can be added (or removed) by the client
262 var paths
: Array[String] = new Array[String]
264 # Get a module by its short name; if required, the module is loaded, parsed and its hierarchies computed.
265 # If `mmodule' is set, then the module search starts from it up to the top level (see `paths');
266 # if `mmodule' is null then the module is searched in the top level only.
267 # If no module exists or there is a name conflict, then an error on `anode' is displayed and null is returned.
268 # FIXME: add a way to handle module name conflict
269 fun get_mmodule_by_name
(anode
: ANode, mmodule
: nullable MModule, name
: String): nullable MModule
271 var origmmodule
= mmodule
272 var modules
= model
.get_mmodules_by_name
(name
)
274 var tries
= new Array[String]
276 var lastmodule
= mmodule
277 while mmodule
!= null do
278 var dirname
= mmodule
.location
.file
.filename
.dirname
280 # Determine the owner
281 var owner
: nullable MModule
282 if dirname
.basename
("") != mmodule
.name
then
283 owner
= mmodule
.direct_owner
288 # First, try the already known nested modules
289 if modules
!= null then
290 for candidate
in modules
do
291 if candidate
.direct_owner
== owner
then
297 # Second, try the directory to find a file
298 var try_file
= dirname
+ "/" + name
+ ".nit"
300 if try_file
.file_exists
then
301 var res
= self.load_module
(owner
, try_file
.simplify_path
)
302 if res
== null then return null # Forward error
303 return res
.mmodule
.as(not null)
306 # Third, try if the requested module is itself an owner
307 try_file
= dirname
+ "/" + name
+ "/" + name
+ ".nit"
308 if try_file
.file_exists
then
309 var res
= self.load_module
(owner
, try_file
.simplify_path
)
310 if res
== null then return null # Forward error
311 return res
.mmodule
.as(not null)
315 mmodule
= mmodule
.direct_owner
318 if modules
!= null then
319 for candidate
in modules
do
320 if candidate
.direct_owner
== null then
326 # Look at some known directories
327 var lookpaths
= self.paths
329 # Look in the directory of the last module also (event if not in the path)
330 if lastmodule
!= null then
331 var dirname
= lastmodule
.location
.file
.filename
.dirname
332 if dirname
.basename
("") == lastmodule
.name
then
333 dirname
= dirname
.dirname
335 if not lookpaths
.has
(dirname
) then
336 lookpaths
= lookpaths
.to_a
337 lookpaths
.add
(dirname
)
341 var candidate
: nullable String = null
342 for dirname
in lookpaths
do
343 var try_file
= (dirname
+ "/" + name
+ ".nit").simplify_path
345 if try_file
.file_exists
then
346 if candidate
== null then
348 else if candidate
!= try_file
then
349 error
(anode
, "Error: conflicting module file for {name}: {candidate} {try_file}")
352 try_file
= (dirname
+ "/" + name
+ "/" + name
+ ".nit").simplify_path
353 if try_file
.file_exists
then
354 if candidate
== null then
356 else if candidate
!= try_file
then
357 error
(anode
, "Error: conflicting module file for {name}: {candidate} {try_file}")
361 if candidate
== null then
362 if origmmodule
!= null then
363 error
(anode
, "Error: cannot find module {name} from {origmmodule}. tried {tries.join(", ")}")
365 error
(anode
, "Error: cannot find module {name}. tried {tries.join(", ")}")
369 var res
= self.load_module
(mmodule
, candidate
)
370 if res
== null then return null # Forward error
371 return res
.mmodule
.as(not null)
374 # Try to load a module using a path.
375 # Display an error if there is a problem (IO / lexer / parser) and return null
376 # Note: usually, you do not need this method, use `get_mmodule_by_name` instead.
377 fun load_module
(owner
: nullable MModule, filename
: String): nullable AModule
379 if not filename
.file_exists
then
380 self.toolcontext
.error
(null, "Error: file {filename} not found.")
384 var x
= if owner
!= null then owner
.to_s
else "."
385 self.toolcontext
.info
("load module {filename} in {x}", 2)
388 var file
= new IFStream.open
(filename
)
389 var lexer
= new Lexer(new SourceFile(filename
, file
))
390 var parser
= new Parser(lexer
)
391 var tree
= parser
.parse
394 # Handle lexer and parser error
395 var nmodule
= tree
.n_base
396 if nmodule
== null then
397 var neof
= tree
.n_eof
398 assert neof
isa AError
399 error
(neof
, neof
.message
)
403 # Check the module name
404 var mod_name
= filename
.basename
(".nit")
405 var decl
= nmodule
.n_moduledecl
407 #warning(nmodule, "Warning: Missing 'module' keyword") #FIXME: NOT YET FOR COMPATIBILITY
409 var decl_name
= decl
.n_name
.n_id
.text
410 if decl_name
!= mod_name
then
411 error
(decl
.n_name
, "Error: module name missmatch; declared {decl_name} file named {mod_name}")
416 var mmodule
= new MModule(model
, owner
, mod_name
, nmodule
.location
)
417 nmodule
.mmodule
= mmodule
418 nmodules
.add
(nmodule
)
419 self.mmodule2nmodule
[mmodule
] = nmodule
421 build_module_importation
(nmodule
)
426 # Analysis the module importation and fill the module_importation_hierarchy
427 private fun build_module_importation
(nmodule
: AModule)
429 if nmodule
.is_importation_done
then return
430 nmodule
.is_importation_done
= true
431 var mmodule
= nmodule
.mmodule
.as(not null)
433 var imported_modules
= new Array[MModule]
434 for aimport
in nmodule
.n_imports
do
436 if not aimport
isa AStdImport then
439 var mod_name
= aimport
.n_name
.n_id
.text
440 var sup
= self.get_mmodule_by_name
(aimport
.n_name
, mmodule
, mod_name
)
441 if sup
== null then continue # Skip error
442 imported_modules
.add
(sup
)
443 var mvisibility
= aimport
.n_visibility
.mvisibility
444 mmodule
.set_visibility_for
(sup
, mvisibility
)
447 var mod_name
= "standard"
448 var sup
= self.get_mmodule_by_name
(nmodule
, null, mod_name
)
449 if sup
!= null then # Skip error
450 imported_modules
.add
(sup
)
451 mmodule
.set_visibility_for
(sup
, public_visibility
)
454 self.toolcontext
.info
("{mmodule} imports {imported_modules.join(", ")}", 3)
455 mmodule
.set_imported_mmodules
(imported_modules
)
458 # All the loaded modules
459 var nmodules
: Array[AModule] = new Array[AModule]
461 # Build the classes of all modules `nmodules'.
462 private fun build_all_classes
464 for nmodule
in self.nmodules
do
465 build_classes
(nmodule
)
466 for nclassdef
in nmodule
.n_classdefs
do
467 build_properties
(nclassdef
)
472 # Visit the AST and create the MClass objects
473 private fun build_a_mclass
(nmodule
: AModule, nclassdef
: AClassdef)
475 var mmodule
= nmodule
.mmodule
.as(not null)
478 var nkind
: nullable AClasskind
479 var mkind
: MClassKind
480 var nvisibility
: nullable AVisibility
481 var mvisibility
: nullable MVisibility
483 if nclassdef
isa AStdClassdef then
484 name
= nclassdef
.n_id
.text
485 nkind
= nclassdef
.n_classkind
487 nvisibility
= nclassdef
.n_visibility
488 mvisibility
= nvisibility
.mvisibility
489 arity
= nclassdef
.n_formaldefs
.length
490 else if nclassdef
isa ATopClassdef then
493 mkind
= interface_kind
495 mvisibility
= public_visibility
496 else if nclassdef
isa AMainClassdef then
499 mkind
= concrete_kind
501 mvisibility
= public_visibility
506 var mclass
= try_get_mclass_by_name
(nclassdef
, mmodule
, name
)
507 if mclass
== null then
508 mclass
= new MClass(mmodule
, name
, arity
, mkind
, mvisibility
)
509 #print "new class {mclass}"
510 else if nclassdef
isa AStdClassdef and nmodule
.mclass2nclassdef
.has_key
(mclass
) then
511 error
(nclassdef
, "Error: A class {name} is already defined at line {nmodule.mclass2nclassdef[mclass].location.line_start}.")
513 else if nclassdef
isa AStdClassdef and nclassdef
.n_kwredef
== null then
514 error
(nclassdef
, "Redef error: {name} is an imported class. Add the redef keyword to refine it.")
516 else if mclass
.arity
!= arity
then
517 error
(nclassdef
, "Redef error: Formal parameter arity missmatch; got {arity}, expected {mclass.arity}.")
519 else if nkind
!= null and mkind
!= concrete_kind
and mclass
.kind
!= mkind
then
520 error
(nkind
, "Error: refinement changed the kind from a {mclass.kind} to a {mkind}")
521 else if nvisibility
!= null and mvisibility
!= public_visibility
and mclass
.visibility
!= mvisibility
then
522 error
(nvisibility
, "Error: refinement changed the visibility from a {mclass.visibility} to a {mvisibility}")
524 nclassdef
.mclass
= mclass
525 nmodule
.mclass2nclassdef
[mclass
] = nclassdef
528 # Visit the AST and create the MClassDef objects
529 private fun build_a_mclassdef
(nmodule
: AModule, nclassdef
: AClassdef)
531 var mmodule
= nmodule
.mmodule
.as(not null)
532 var objectclass
= try_get_mclass_by_name
(nmodule
, mmodule
, "Object")
533 var mclass
= nclassdef
.mclass
534 if mclass
== null then return # Skip error
535 #var mclassdef = nclassdef.mclassdef.as(not null)
537 var names
= new Array[String]
538 var bounds
= new Array[MType]
539 if nclassdef
isa AStdClassdef and mclass
.arity
> 0 then
540 # Collect formal parameter names
541 for i
in [0..mclass
.arity
[ do
542 var nfd
= nclassdef
.n_formaldefs
[i
]
543 var ptname
= nfd
.n_id
.text
544 if names
.has
(ptname
) then
545 error
(nfd
, "Error: A formal parameter type `{ptname}' already exists")
551 # Revolve bound for formal parameter names
552 for i
in [0..mclass
.arity
[ do
553 var nfd
= nclassdef
.n_formaldefs
[i
]
554 var nfdt
= nfd
.n_type
556 var bound
= resolve_mtype_unchecked
(nclassdef
, nfdt
, false)
557 if bound
== null then return # Forward error
558 if bound
.need_anchor
then
560 error
(nfd
, "Error: Formal parameter type `{names[i]}' bounded with a formal parameter type")
564 else if mclass
.mclassdefs
.is_empty
then
565 # No bound, then implicitely bound by nullable Object
566 bounds
.add
(objectclass
.mclass_type
.as_nullable
)
569 bounds
.add
(mclass
.intro
.bound_mtype
.arguments
[i
])
574 var bound_mtype
= mclass
.get_mtype
(bounds
)
575 var mclassdef
= new MClassDef(mmodule
, bound_mtype
, nclassdef
.location
, names
)
576 nclassdef
.mclassdef
= mclassdef
577 self.mclassdef2nclassdef
[mclassdef
] = nclassdef
579 if mclassdef
.is_intro
then
580 self.toolcontext
.info
("{mclassdef} introduces new {mclass.kind} {mclass.full_name}", 3)
582 self.toolcontext
.info
("{mclassdef} refine {mclass.kind} {mclass.full_name}", 3)
586 # Visit the AST and set the super-types of the MClassdef objects
587 private fun collect_a_mclassdef_inheritance
(nmodule
: AModule, nclassdef
: AClassdef)
589 var mmodule
= nmodule
.mmodule
.as(not null)
590 var objectclass
= try_get_mclass_by_name
(nmodule
, mmodule
, "Object")
591 var mclass
= nclassdef
.mclass
.as(not null)
592 var mclassdef
= nclassdef
.mclassdef
.as(not null)
594 var specobject
= true
595 var supertypes
= new Array[MClassType]
596 if nclassdef
isa AStdClassdef then
597 for nsc
in nclassdef
.n_superclasses
do
599 var ntype
= nsc
.n_type
600 var mtype
= resolve_mtype_unchecked
(nclassdef
, ntype
, false)
601 if mtype
== null then continue # Skip because of error
602 if not mtype
isa MClassType then
603 error
(ntype
, "Error: supertypes cannot be a formal type")
607 #print "new super : {mclass} < {mtype}"
610 if specobject
and mclass
.name
!= "Object" and objectclass
!= null and mclassdef
.is_intro
then
611 supertypes
.add objectclass
.mclass_type
614 mclassdef
.set_supertypes
(supertypes
)
615 if not supertypes
.is_empty
then self.toolcontext
.info
("{mclassdef} new super-types: {supertypes.join(", ")}", 3)
618 # Check the validity of the specialization heirarchy
619 private fun check_supertypes
(nmodule
: AModule, nclassdef
: AClassdef)
621 var mmodule
= nmodule
.mmodule
.as(not null)
622 var objectclass
= try_get_mclass_by_name
(nmodule
, mmodule
, "Object")
623 var mclass
= nclassdef
.mclass
.as(not null)
624 var mclassdef
= nclassdef
.mclassdef
.as(not null)
626 for s
in mclassdef
.supertypes
do
627 if s
.is_subtype
(mmodule
, mclassdef
.bound_mtype
, mclassdef
.bound_mtype
) then
628 error
(nclassdef
, "Error: Inheritance loop for class {mclass} with type {s}")
633 # Build the classes of the module `nmodule'.
634 # REQUIRE: classes of imported modules are already build. (let `build_all_classes' do the job)
635 private fun build_classes
(nmodule
: AModule)
637 # Force building recursively
638 if nmodule
.build_classes_is_done
then return
639 nmodule
.build_classes_is_done
= true
640 var mmodule
= nmodule
.mmodule
.as(not null)
641 for imp
in mmodule
.in_importation
.direct_greaters
do
643 build_classes
(mmodule2nmodule
[imp
])
647 for nclassdef
in nmodule
.n_classdefs
do
648 self.build_a_mclass
(nmodule
, nclassdef
)
651 # Create all classdefs
652 for nclassdef
in nmodule
.n_classdefs
do
653 self.build_a_mclassdef
(nmodule
, nclassdef
)
656 for nclassdef
in nmodule
.n_classdefs
do
657 if nclassdef
.mclassdef
== null then return # forward error
660 # Create inheritance on all classdefs
661 for nclassdef
in nmodule
.n_classdefs
do
662 self.collect_a_mclassdef_inheritance
(nmodule
, nclassdef
)
665 # Create the mclassdef hierarchy
666 for nclassdef
in nmodule
.n_classdefs
do
667 var mclassdef
= nclassdef
.mclassdef
.as(not null)
668 mclassdef
.add_in_hierarchy
672 for nclassdef
in nmodule
.n_classdefs
do
673 self.check_supertypes
(nmodule
, nclassdef
)
676 # Check unchecked ntypes
677 for nclassdef
in nmodule
.n_classdefs
do
678 if nclassdef
isa AStdClassdef then
679 # check bound of formal parameter
680 for nfd
in nclassdef
.n_formaldefs
do
681 var nfdt
= nfd
.n_type
682 if nfdt
!= null and nfdt
.mtype
!= null then
683 var bound
= resolve_mtype
(nclassdef
, nfdt
)
684 if bound
== null then return # Forward error
687 # check declared super types
688 for nsc
in nclassdef
.n_superclasses
do
689 var ntype
= nsc
.n_type
690 if ntype
.mtype
!= null then
691 var mtype
= resolve_mtype
(nclassdef
, ntype
)
692 if mtype
== null then return # Forward error
699 # TODO: Check that the super-class is not intrusive
701 # TODO: Check that the super-class is not already known (by transitivity)
704 # Register the nmodule associated to each mmodule
705 # FIXME: why not refine the MModule class with a nullable attribute?
706 var mmodule2nmodule
: HashMap[MModule, AModule] = new HashMap[MModule, AModule]
707 # Register the nclassdef associated to each mclassdef
708 # FIXME: why not refine the MClassDef class with a nullable attribute?
709 var mclassdef2nclassdef
: HashMap[MClassDef, AClassdef] = new HashMap[MClassDef, AClassdef]
710 # Register the npropdef associated to each mpropdef
711 # FIXME: why not refine the MPropDef class with a nullable attribute?
712 var mpropdef2npropdef
: HashMap[MPropDef, APropdef] = new HashMap[MPropDef, APropdef]
714 # Build the properties of `nclassdef'.
715 # REQUIRE: all superclasses are built.
716 private fun build_properties
(nclassdef
: AClassdef)
718 # Force building recursively
719 if nclassdef
.build_properties_is_done
then return
720 nclassdef
.build_properties_is_done
= true
721 var mclassdef
= nclassdef
.mclassdef
.as(not null)
722 if mclassdef
.in_hierarchy
== null then return # Skip error
723 for superclassdef
in mclassdef
.in_hierarchy
.direct_greaters
do
724 build_properties
(mclassdef2nclassdef
[superclassdef
])
727 for npropdef
in nclassdef
.n_propdefs
do
728 npropdef
.build_property
(self, nclassdef
)
730 for npropdef
in nclassdef
.n_propdefs
do
731 npropdef
.build_signature
(self, nclassdef
)
733 for npropdef
in nclassdef
.n_propdefs
do
734 npropdef
.check_signature
(self, nclassdef
)
736 process_default_constructors
(nclassdef
)
739 # Introduce or inherit default constructor
740 # This is the last part of `build_properties'.
741 private fun process_default_constructors
(nclassdef
: AClassdef)
743 var mclassdef
= nclassdef
.mclassdef
.as(not null)
745 # Are we a refinement
746 if not mclassdef
.is_intro
then return
748 # Is the class forbid constructors?
749 if not mclassdef
.mclass
.kind
.need_init
then return
751 # Is there already a constructor defined?
752 for mpropdef
in mclassdef
.mpropdefs
do
753 if not mpropdef
isa MMethodDef then continue
754 if mpropdef
.mproperty
.is_init
then return
757 if not nclassdef
isa AStdClassdef then return
759 var mmodule
= nclassdef
.mclassdef
.mmodule
760 # Do we inherit for a constructor?
761 var combine
= new Array[MMethod]
762 var inhc
: nullable MClass = null
763 for st
in mclassdef
.supertypes
do
765 if not c
.kind
.need_init
then continue
766 st
= st
.anchor_to
(mmodule
, nclassdef
.mclassdef
.bound_mtype
)
767 var candidate
= self.try_get_mproperty_by_name2
(nclassdef
, mmodule
, st
, "init").as(nullable MMethod)
768 if candidate
!= null and candidate
.intro
.msignature
.arity
== 0 then
769 combine
.add
(candidate
)
772 var inhc2
= c
.inherit_init_from
773 if inhc2
== null then inhc2
= c
774 if inhc2
== inhc
then continue
776 self.error
(nclassdef
, "Error: Cannot provide a defaut constructor: conflict for {inhc} and {c}")
781 if combine
.is_empty
and inhc
!= null then
782 # TODO: actively inherit the consturctor
783 self.toolcontext
.info
("{mclassdef} inherits all constructors from {inhc}", 3)
784 mclassdef
.mclass
.inherit_init_from
= inhc
787 if not combine
.is_empty
and inhc
!= null then
788 self.error
(nclassdef
, "Error: Cannot provide a defaut constructor: conflict for {combine.join(", ")} and {inhc}")
792 if not combine
.is_empty
then
793 nclassdef
.super_inits
= combine
794 var mprop
= new MMethod(mclassdef
, "init", mclassdef
.mclass
.visibility
)
795 var mpropdef
= new MMethodDef(mclassdef
, mprop
, nclassdef
.location
)
796 var mparameters
= new Array[MParameter]
797 var msignature
= new MSignature(mparameters
, null)
798 mpropdef
.msignature
= msignature
800 nclassdef
.mfree_init
= mpropdef
801 self.toolcontext
.info
("{mclassdef} gets a free empty constructor {mpropdef}{msignature}", 3)
805 # Collect undefined attributes
806 var mparameters
= new Array[MParameter]
807 for npropdef
in nclassdef
.n_propdefs
do
808 if npropdef
isa AAttrPropdef and npropdef
.n_expr
== null then
809 if npropdef
.mpropdef
== null then return # Skip broken attribute
810 var paramname
= npropdef
.mpropdef
.mproperty
.name
.substring_from
(1)
811 var ret_type
= npropdef
.mpropdef
.static_mtype
812 if ret_type
== null then return
813 var mparameter
= new MParameter(paramname
, ret_type
, false)
814 mparameters
.add
(mparameter
)
818 var mprop
= new MMethod(mclassdef
, "init", mclassdef
.mclass
.visibility
)
819 var mpropdef
= new MMethodDef(mclassdef
, mprop
, nclassdef
.location
)
820 var msignature
= new MSignature(mparameters
, null)
821 mpropdef
.msignature
= msignature
823 nclassdef
.mfree_init
= mpropdef
824 self.toolcontext
.info
("{mclassdef} gets a free constructor for attributes {mpropdef}{msignature}", 3)
827 # Return the static type associated to the node `ntype'.
828 # `classdef' is the context where the call is made (used to understand formal types)
829 # The mmodule used as context is `nclassdef.mmodule'
830 # In case of problem, an error is displayed on `ntype' and null is returned.
831 # FIXME: the name "resolve_mtype" is awful
832 fun resolve_mtype_unchecked
(nclassdef
: AClassdef, ntype
: AType, with_virtual
: Bool): nullable MType
834 var name
= ntype
.n_id
.text
835 var mclassdef
= nclassdef
.mclassdef
836 var mmodule
= nclassdef
.parent
.as(AModule).mmodule
.as(not null)
840 if mclassdef
!= null and with_virtual
then
841 var prop
= try_get_mproperty_by_name
(ntype
, mclassdef
, name
).as(nullable MVirtualTypeProp)
843 if not ntype
.n_types
.is_empty
then
844 error
(ntype
, "Type error: formal type {name} cannot have formal parameters.")
846 res
= prop
.mvirtualtype
847 if ntype
.n_kwnullable
!= null then res
= res
.as_nullable
853 # Check parameter type
854 if mclassdef
!= null and mclassdef
.parameter_names
.has
(name
) then
855 if not ntype
.n_types
.is_empty
then
856 error
(ntype
, "Type error: formal type {name} cannot have formal parameters.")
858 for i
in [0..mclassdef
.parameter_names
.length
[ do
859 if mclassdef
.parameter_names
[i
] == name
then
860 res
= mclassdef
.mclass
.mclass_type
.arguments
[i
]
861 if ntype
.n_kwnullable
!= null then res
= res
.as_nullable
870 var mclass
= try_get_mclass_by_name
(ntype
, mmodule
, name
)
871 if mclass
!= null then
872 var arity
= ntype
.n_types
.length
873 if arity
!= mclass
.arity
then
875 error
(ntype
, "Type error: '{name}' is a generic class.")
876 else if mclass
.arity
== 0 then
877 error
(ntype
, "Type error: '{name}' is not a generic class.")
879 error
(ntype
, "Type error: '{name}' has {mclass.arity} parameters ({arity} are provided).")
884 res
= mclass
.mclass_type
885 if ntype
.n_kwnullable
!= null then res
= res
.as_nullable
889 var mtypes
= new Array[MType]
890 for nt
in ntype
.n_types
do
891 var mt
= resolve_mtype_unchecked
(nclassdef
, nt
, with_virtual
)
892 if mt
== null then return null # Forward error
895 res
= mclass
.get_mtype
(mtypes
)
896 if ntype
.n_kwnullable
!= null then res
= res
.as_nullable
902 # If everything fail, then give up :(
903 error
(ntype
, "Type error: class {name} not found in module {mmodule}.")
907 # Return the static type associated to the node `ntype'.
908 # `classdef' is the context where the call is made (used to understand formal types)
909 # The mmodule used as context is `nclassdef.mmodule'
910 # In case of problem, an error is displayed on `ntype' and null is returned.
911 # FIXME: the name "resolve_mtype" is awful
912 fun resolve_mtype
(nclassdef
: AClassdef, ntype
: AType): nullable MType
914 var mtype
= ntype
.mtype
915 if mtype
== null then mtype
= resolve_mtype_unchecked
(nclassdef
, ntype
, true)
916 if mtype
== null then return null # Forward error
918 if ntype
.checked_mtype
then return mtype
919 if mtype
isa MGenericType then
920 var mmodule
= nclassdef
.parent
.as(AModule).mmodule
.as(not null)
921 var mclassdef
= nclassdef
.mclassdef
922 var mclass
= mtype
.mclass
923 for i
in [0..mclass
.arity
[ do
924 var bound
= mclass
.intro
.bound_mtype
.arguments
[i
]
925 var nt
= ntype
.n_types
[i
]
926 var mt
= resolve_mtype
(nclassdef
, nt
)
927 if mt
== null then return null # forward error
928 if not mt
.is_subtype
(mmodule
, mclassdef
.bound_mtype
, bound
) then
929 error
(nt
, "Type error: expected {bound}, got {mt}")
934 ntype
.checked_mtype
= true
938 # Helper function to display an error on a node.
939 # Alias for `self.toolcontext.error(n.hot_location, text)'
940 fun error
(n
: ANode, text
: String)
942 self.toolcontext
.error
(n
.hot_location
, text
)
945 # Helper function to display a warning on a node.
946 # Alias for: `self.toolcontext.warning(n.hot_location, text)'
947 fun warning
(n
: ANode, text
: String)
949 self.toolcontext
.warning
(n
.hot_location
, text
)
952 # Force to get the primitive method named `name' on the type `recv' or do a fatal error on `n'
953 fun force_get_primitive_method
(n
: ANode, name
: String, recv
: MType, mmodule
: MModule): MMethod
955 var res
= mmodule
.try_get_primitive_method
(name
, recv
)
957 self.toolcontext
.fatal_error
(n
.hot_location
, "Fatal Error: {recv} must have a property named {name}.")
965 # The associated MModule once build by a `ModelBuilder'
966 var mmodule
: nullable MModule
967 # Flag that indicate if the importation is already completed
968 var is_importation_done
: Bool = false
969 # Flag that indicate if the class and prop building is already completed
970 var build_classes_is_done
: Bool = false
971 # What is the AClassdef associated to a MClass?
972 # Used to check multiple definition of a class.
973 var mclass2nclassdef
: Map[MClass, AClassdef] = new HashMap[MClass, AClassdef]
978 # The class whose self inherit all the constructors.
979 # FIXME: this is needed to implement the crazy constructor mixin thing of the of old compiler. We need to think what to do with since this cannot stay in the modelbuilder
980 var inherit_init_from
: nullable MClass = null
983 redef class AClassdef
984 # The associated MClass once build by a `ModelBuilder'
985 var mclass
: nullable MClass
986 # The associated MClassDef once build by a `ModelBuilder'
987 var mclassdef
: nullable MClassDef
988 var build_properties_is_done
: Bool = false
989 # The list of super-constructor to call at the start of the free constructor
990 # FIXME: this is needed to implement the crazy constructor thing of the of old compiler. We need to think what to do with since this cannot stay in the modelbuilder
991 var super_inits
: nullable Collection[MMethod] = null
993 # The free init (implicitely constructed by the class if required)
994 var mfree_init
: nullable MMethodDef = null
996 # What is the APropdef associated to a MProperty?
997 # Used to check multiple definition of a property.
998 var mprop2npropdef
: Map[MProperty, APropdef] = new HashMap[MProperty, APropdef]
1001 redef class AClasskind
1002 # The class kind associated with the AST node class
1003 private fun mkind
: MClassKind is abstract
1005 redef class AConcreteClasskind
1006 redef fun mkind
do return concrete_kind
1008 redef class AAbstractClasskind
1009 redef fun mkind
do return abstract_kind
1011 redef class AInterfaceClasskind
1012 redef fun mkind
do return interface_kind
1014 redef class AEnumClasskind
1015 redef fun mkind
do return enum_kind
1017 redef class AExternClasskind
1018 redef fun mkind
do return extern_kind
1021 redef class AVisibility
1022 # The visibility level associated with the AST node class
1023 private fun mvisibility
: MVisibility is abstract
1025 redef class AIntrudeVisibility
1026 redef fun mvisibility
do return intrude_visibility
1028 redef class APublicVisibility
1029 redef fun mvisibility
do return public_visibility
1031 redef class AProtectedVisibility
1032 redef fun mvisibility
do return protected_visibility
1034 redef class APrivateVisibility
1035 redef fun mvisibility
do return private_visibility
1039 # The mtype associated to the node
1040 var mtype
: nullable MType = null
1042 # Is the mtype a valid one?
1043 var checked_mtype
: Bool = false
1049 # Join the text of all tokens
1050 # Used to get the 'real name' of method definitions.
1051 fun collect_text
: String
1053 var v
= new TextCollectorVisitor
1060 private class TextCollectorVisitor
1062 var text
: String = ""
1065 if n
isa Token then text
+= n
.text
1070 redef class APropdef
1071 private fun build_property
(modelbuilder
: ModelBuilder, nclassdef
: AClassdef)
1074 private fun build_signature
(modelbuilder
: ModelBuilder, nclassdef
: AClassdef)
1077 private fun check_signature
(modelbuilder
: ModelBuilder, nclassdef
: AClassdef)
1080 private fun new_property_visibility
(modelbuilder
: ModelBuilder, nclassdef
: AClassdef, nvisibility
: nullable AVisibility): MVisibility
1082 var mvisibility
= public_visibility
1083 if nvisibility
!= null then mvisibility
= nvisibility
.mvisibility
1084 if nclassdef
.mclassdef
.mclass
.visibility
== private_visibility
then
1085 if mvisibility
== protected_visibility
then
1086 assert nvisibility
!= null
1087 modelbuilder
.error
(nvisibility
, "Error: The only legal visibility for properties in a private class is private.")
1088 else if mvisibility
== private_visibility
then
1089 assert nvisibility
!= null
1091 # modelbuilder.warning(nvisibility, "Warning: private is unrequired since the only legal visibility for properties in a private class is private.")
1093 mvisibility
= private_visibility
1098 private fun check_redef_property_visibility
(modelbuilder
: ModelBuilder, nclassdef
: AClassdef, nvisibility
: nullable AVisibility, mprop
: MProperty)
1100 if nvisibility
== null then return
1101 var mvisibility
= nvisibility
.mvisibility
1102 if mvisibility
!= mprop
.visibility
and mvisibility
!= public_visibility
then
1103 modelbuilder
.error
(nvisibility
, "Error: redefinition changed the visibility from a {mprop.visibility} to a {mvisibility}")
1107 private fun check_redef_keyword
(modelbuilder
: ModelBuilder, nclassdef
: AClassdef, kwredef
: nullable Token, need_redef
: Bool, mprop
: MProperty): Bool
1109 if nclassdef
.mprop2npropdef
.has_key
(mprop
) then
1110 modelbuilder
.error
(self, "Error: A property {mprop} is already defined in class {nclassdef.mclassdef.mclass}.")
1113 if kwredef
== null then
1115 modelbuilder
.error
(self, "Redef error: {nclassdef.mclassdef.mclass}::{mprop.name} is an inherited property. To redefine it, add the redef keyword.")
1119 if not need_redef
then
1120 modelbuilder
.error
(self, "Error: No property {nclassdef.mclassdef.mclass}::{mprop.name} is inherited. Remove the redef keyword to define a new property.")
1129 redef class ASignature
1130 # Is the model builder has correctly visited the signature
1131 var is_visited
= false
1132 # Names of parameters from the AST
1133 # REQUIRE: is_visited
1134 var param_names
= new Array[String]
1135 # Types of parameters from the AST
1136 # REQUIRE: is_visited
1137 var param_types
= new Array[MType]
1138 # Rank of the vararg (of -1 if none)
1139 # REQUIRE: is_visited
1140 var vararg_rank
: Int = -1
1142 var ret_type
: nullable MType = null
1144 # Visit and fill information about a signature
1145 private fun visit_signature
(modelbuilder
: ModelBuilder, nclassdef
: AClassdef): Bool
1147 var param_names
= self.param_names
1148 var param_types
= self.param_types
1149 for np
in self.n_params
do
1150 param_names
.add
(np
.n_id
.text
)
1151 var ntype
= np
.n_type
1152 if ntype
!= null then
1153 var mtype
= modelbuilder
.resolve_mtype
(nclassdef
, ntype
)
1154 if mtype
== null then return false # Skip error
1155 for i
in [0..param_names
.length-param_types
.length
[ do
1156 param_types
.add
(mtype
)
1158 if np
.n_dotdotdot
!= null then
1159 if self.vararg_rank
!= -1 then
1160 modelbuilder
.error
(np
, "Error: {param_names[self.vararg_rank]} is already a vararg")
1163 self.vararg_rank
= param_names
.length
- 1
1168 var ntype
= self.n_type
1169 if ntype
!= null then
1170 self.ret_type
= modelbuilder
.resolve_mtype
(nclassdef
, ntype
)
1171 if self.ret_type
== null then return false # Skip errir
1174 for nclosure
in self.n_closure_decls
do
1175 if not nclosure
.n_signature
.visit_signature
(modelbuilder
, nclassdef
) then return false
1178 self.is_visited
= true
1182 # Build a visited signature
1183 fun build_signature
(modelbuilder
: ModelBuilder, nclassdef
: AClassdef): nullable MSignature
1185 if param_names
.length
!= param_types
.length
then
1186 # Some parameters are typed, other parameters are not typed.
1187 modelbuilder
.error
(self.n_params
[param_types
.length
], "Error: Untyped parameter `{param_names[param_types.length]}'.")
1191 var mparameters
= new Array[MParameter]
1192 for i
in [0..param_names
.length
[ do
1193 var mparameter
= new MParameter(param_names
[i
], param_types
[i
], i
== vararg_rank
)
1194 mparameters
.add
(mparameter
)
1197 var msignature
= new MSignature(mparameters
, ret_type
)
1202 redef class AMethPropdef
1203 # The associated MMethodDef once build by a `ModelBuilder'
1204 var mpropdef
: nullable MMethodDef
1206 # The associated super init if any
1207 var super_init
: nullable MMethod
1208 redef fun build_property
(modelbuilder
, nclassdef
)
1210 var is_init
= self isa AInitPropdef
1211 var mclassdef
= nclassdef
.mclassdef
.as(not null)
1213 var amethodid
= self.n_methid
1214 var name_node
: ANode
1215 if amethodid
== null then
1216 if self isa AMainMethPropdef then
1219 else if self isa AConcreteInitPropdef then
1221 name_node
= self.n_kwinit
1222 else if self isa AExternInitPropdef then
1224 name_node
= self.n_kwnew
1228 else if amethodid
isa AIdMethid then
1229 name
= amethodid
.n_id
.text
1230 name_node
= amethodid
1232 # operator, bracket or assign
1233 name
= amethodid
.collect_text
1234 name_node
= amethodid
1236 if name
== "-" and self.n_signature
.n_params
.length
== 0 then
1241 var mprop
: nullable MMethod = null
1242 if not is_init
or n_kwredef
!= null then mprop
= modelbuilder
.try_get_mproperty_by_name
(name_node
, mclassdef
, name
).as(nullable MMethod)
1243 if mprop
== null then
1244 var mvisibility
= new_property_visibility
(modelbuilder
, nclassdef
, self.n_visibility
)
1245 mprop
= new MMethod(mclassdef
, name
, mvisibility
)
1246 mprop
.is_init
= is_init
1247 mprop
.is_new
= self isa AExternInitPropdef
1248 if not self.check_redef_keyword
(modelbuilder
, nclassdef
, n_kwredef
, false, mprop
) then return
1250 if n_kwredef
== null then
1251 if self isa AMainMethPropdef then
1254 if not self.check_redef_keyword
(modelbuilder
, nclassdef
, n_kwredef
, true, mprop
) then return
1257 check_redef_property_visibility
(modelbuilder
, nclassdef
, self.n_visibility
, mprop
)
1259 nclassdef
.mprop2npropdef
[mprop
] = self
1261 var mpropdef
= new MMethodDef(mclassdef
, mprop
, self.location
)
1263 self.mpropdef
= mpropdef
1264 modelbuilder
.mpropdef2npropdef
[mpropdef
] = self
1265 if mpropdef
.is_intro
then
1266 modelbuilder
.toolcontext
.info
("{mpropdef} introduces new method {mprop.full_name}", 3)
1268 modelbuilder
.toolcontext
.info
("{mpropdef} redefines method {mprop.full_name}", 3)
1272 redef fun build_signature
(modelbuilder
, nclassdef
)
1274 var mpropdef
= self.mpropdef
1275 if mpropdef
== null then return # Error thus skiped
1276 var mmodule
= mpropdef
.mclassdef
.mmodule
1277 var nsig
= self.n_signature
1279 # Retrieve info from the signature AST
1280 var param_names
= new Array[String] # Names of parameters from the AST
1281 var param_types
= new Array[MType] # Types of parameters from the AST
1282 var vararg_rank
= -1
1283 var ret_type
: nullable MType = null # Return type from the AST
1284 if nsig
!= null then
1285 if not nsig
.visit_signature
(modelbuilder
, nclassdef
) then return
1286 param_names
= nsig
.param_names
1287 param_types
= nsig
.param_types
1288 vararg_rank
= nsig
.vararg_rank
1289 ret_type
= nsig
.ret_type
1292 # Look for some signature to inherit
1293 # FIXME: do not inherit from the intro, but from the most specific
1294 var msignature
: nullable MSignature = null
1295 if not mpropdef
.is_intro
then
1296 msignature
= mpropdef
.mproperty
.intro
.msignature
1297 if msignature
== null then return # Skip error
1299 # Check inherited signature arity
1300 if param_names
.length
!= msignature
.arity
then
1302 if nsig
!= null then node
= nsig
else node
= self
1303 modelbuilder
.error
(node
, "Redef error: {mpropdef} redefines {mpropdef.mproperty.intro} with {param_names.length} parameter(s), {msignature.arity} expected. Signature is {mpropdef}{msignature}")
1306 else if mpropdef
.mproperty
.is_init
then
1307 # FIXME UGLY: inherit signature from a super-constructor
1308 for msupertype
in nclassdef
.mclassdef
.supertypes
do
1309 msupertype
= msupertype
.anchor_to
(mmodule
, nclassdef
.mclassdef
.bound_mtype
)
1310 var candidate
= modelbuilder
.try_get_mproperty_by_name2
(self, mmodule
, msupertype
, mpropdef
.mproperty
.name
)
1311 if candidate
!= null then
1312 if msignature
== null then
1313 msignature
= candidate
.intro
.as(MMethodDef).msignature
1320 # Inherit the signature
1321 if msignature
!= null and param_names
.length
!= param_types
.length
and param_names
.length
== msignature
.arity
and param_types
.length
== 0 then
1322 # Parameters are untyped, thus inherit them
1323 param_types
= new Array[MType]
1324 for mparameter
in msignature
.mparameters
do
1325 param_types
.add
(mparameter
.mtype
)
1327 vararg_rank
= msignature
.vararg_rank
1329 if msignature
!= null and ret_type
== null then
1330 ret_type
= msignature
.return_mtype
1333 if param_names
.length
!= param_types
.length
then
1334 # Some parameters are typed, other parameters are not typed.
1335 modelbuilder
.error
(nsig
.n_params
[param_types
.length
], "Error: Untyped parameter `{param_names[param_types.length]}'.")
1339 var mparameters
= new Array[MParameter]
1340 for i
in [0..param_names
.length
[ do
1341 var mparameter
= new MParameter(param_names
[i
], param_types
[i
], i
== vararg_rank
)
1342 mparameters
.add
(mparameter
)
1345 msignature
= new MSignature(mparameters
, ret_type
)
1346 mpropdef
.msignature
= msignature
1348 if nsig
!= null then
1349 for nclosure
in nsig
.n_closure_decls
do
1350 var clos_signature
= nclosure
.n_signature
.build_signature
(modelbuilder
, nclassdef
)
1351 if clos_signature
== null then return
1352 var mparameter
= new MParameter(nclosure
.n_id
.text
, clos_signature
, false)
1353 msignature
.mclosures
.add
(mparameter
)
1359 redef fun check_signature
(modelbuilder
, nclassdef
)
1361 var mpropdef
= self.mpropdef
1362 if mpropdef
== null then return # Error thus skiped
1363 var mmodule
= mpropdef
.mclassdef
.mmodule
1364 var nsig
= self.n_signature
1365 var mysignature
= self.mpropdef
.msignature
1366 if mysignature
== null then return # Error thus skiped
1368 # Lookup for signature in the precursor
1369 # FIXME all precursors should be considered
1370 if not mpropdef
.is_intro
then
1371 var msignature
= mpropdef
.mproperty
.intro
.msignature
1372 if msignature
== null then return
1374 var precursor_ret_type
= msignature
.return_mtype
1375 var ret_type
= mysignature
.return_mtype
1376 if ret_type
!= null and precursor_ret_type
== null then
1377 modelbuilder
.error
(nsig
.n_type
.as(not null), "Redef Error: {mpropdef.mproperty} is a procedure, not a function.")
1381 if mysignature
.arity
> 0 then
1382 # Check parameters types
1383 for i
in [0..mysignature
.arity
[ do
1384 var myt
= mysignature
.mparameters
[i
].mtype
1385 var prt
= msignature
.mparameters
[i
].mtype
1386 if not myt
.is_subtype
(mmodule
, nclassdef
.mclassdef
.bound_mtype
, prt
) and
1387 not prt
.is_subtype
(mmodule
, nclassdef
.mclassdef
.bound_mtype
, myt
) then
1388 modelbuilder
.error
(nsig
.n_params
[i
], "Redef Error: Wrong type for parameter `{mysignature.mparameters[i].name}'. found {myt}, expected {prt}.")
1392 if precursor_ret_type
!= null then
1393 if ret_type
== null then
1394 # Inherit the return type
1395 ret_type
= precursor_ret_type
1396 else if not ret_type
.is_subtype
(mmodule
, nclassdef
.mclassdef
.bound_mtype
, precursor_ret_type
) then
1397 modelbuilder
.error
(nsig
.n_type
.as(not null), "Redef Error: Wrong return type. found {ret_type}, expected {precursor_ret_type}.")
1404 redef class AAttrPropdef
1405 # The associated MAttributeDef once build by a `ModelBuilder'
1406 var mpropdef
: nullable MAttributeDef
1407 # The associated getter (read accessor) if any
1408 var mreadpropdef
: nullable MMethodDef
1409 # The associated setter (write accessor) if any
1410 var mwritepropdef
: nullable MMethodDef
1411 redef fun build_property
(modelbuilder
, nclassdef
)
1413 var mclassdef
= nclassdef
.mclassdef
.as(not null)
1414 var mclass
= mclassdef
.mclass
1417 if self.n_id
!= null then
1418 name
= self.n_id
.text
1420 name
= self.n_id2
.text
1423 if mclass
.kind
== interface_kind
or mclassdef
.mclass
.kind
== enum_kind
then
1424 modelbuilder
.error
(self, "Error: Attempt to define attribute {name} in the interface {mclass}.")
1425 else if mclass
.kind
== enum_kind
then
1426 modelbuilder
.error
(self, "Error: Attempt to define attribute {name} in the enum class {mclass}.")
1427 else if mclass
.kind
== extern_kind
then
1428 modelbuilder
.error
(self, "Error: Attempt to define attribute {name} in the extern class {mclass}.")
1433 # Old attribute style
1434 var mprop
= modelbuilder
.try_get_mproperty_by_name
(nid
, mclassdef
, name
)
1435 if mprop
== null then
1436 var mvisibility
= new_property_visibility
(modelbuilder
, nclassdef
, self.n_visibility
)
1437 mprop
= new MAttribute(mclassdef
, name
, mvisibility
)
1438 if not self.check_redef_keyword
(modelbuilder
, nclassdef
, self.n_kwredef
, false, mprop
) then return
1440 assert mprop
isa MAttribute
1441 check_redef_property_visibility
(modelbuilder
, nclassdef
, self.n_visibility
, mprop
)
1442 if not self.check_redef_keyword
(modelbuilder
, nclassdef
, self.n_kwredef
, true, mprop
) then return
1444 nclassdef
.mprop2npropdef
[mprop
] = self
1446 var mpropdef
= new MAttributeDef(mclassdef
, mprop
, self.location
)
1447 self.mpropdef
= mpropdef
1448 modelbuilder
.mpropdef2npropdef
[mpropdef
] = self
1450 var nreadable
= self.n_readable
1451 if nreadable
!= null then
1452 var readname
= name
.substring_from
(1)
1453 var mreadprop
= modelbuilder
.try_get_mproperty_by_name
(nid
, mclassdef
, readname
).as(nullable MMethod)
1454 if mreadprop
== null then
1455 var mvisibility
= new_property_visibility
(modelbuilder
, nclassdef
, nreadable
.n_visibility
)
1456 mreadprop
= new MMethod(mclassdef
, readname
, mvisibility
)
1457 if not self.check_redef_keyword
(modelbuilder
, nclassdef
, nreadable
.n_kwredef
, false, mreadprop
) then return
1459 if not self.check_redef_keyword
(modelbuilder
, nclassdef
, nreadable
.n_kwredef
, true, mreadprop
) then return
1460 check_redef_property_visibility
(modelbuilder
, nclassdef
, nreadable
.n_visibility
, mreadprop
)
1462 nclassdef
.mprop2npropdef
[mreadprop
] = self
1464 var mreadpropdef
= new MMethodDef(mclassdef
, mreadprop
, self.location
)
1465 self.mreadpropdef
= mreadpropdef
1466 modelbuilder
.mpropdef2npropdef
[mreadpropdef
] = self
1469 var nwritable
= self.n_writable
1470 if nwritable
!= null then
1471 var writename
= name
.substring_from
(1) + "="
1472 var mwriteprop
= modelbuilder
.try_get_mproperty_by_name
(nid
, mclassdef
, writename
).as(nullable MMethod)
1473 if mwriteprop
== null then
1474 var mvisibility
= new_property_visibility
(modelbuilder
, nclassdef
, nwritable
.n_visibility
)
1475 mwriteprop
= new MMethod(mclassdef
, writename
, mvisibility
)
1476 if not self.check_redef_keyword
(modelbuilder
, nclassdef
, nwritable
.n_kwredef
, false, mwriteprop
) then return
1478 if not self.check_redef_keyword
(modelbuilder
, nclassdef
, nwritable
.n_kwredef
, true, mwriteprop
) then return
1479 check_redef_property_visibility
(modelbuilder
, nclassdef
, nwritable
.n_visibility
, mwriteprop
)
1481 nclassdef
.mprop2npropdef
[mwriteprop
] = self
1483 var mwritepropdef
= new MMethodDef(mclassdef
, mwriteprop
, self.location
)
1484 self.mwritepropdef
= mwritepropdef
1485 modelbuilder
.mpropdef2npropdef
[mwritepropdef
] = self
1488 # New attribute style
1489 var nid2
= self.n_id2
.as(not null)
1490 var mprop
= new MAttribute(mclassdef
, "@" + name
, none_visibility
)
1491 var mpropdef
= new MAttributeDef(mclassdef
, mprop
, self.location
)
1492 self.mpropdef
= mpropdef
1493 modelbuilder
.mpropdef2npropdef
[mpropdef
] = self
1496 var mreadprop
= modelbuilder
.try_get_mproperty_by_name
(nid2
, mclassdef
, readname
).as(nullable MMethod)
1497 if mreadprop
== null then
1498 var mvisibility
= new_property_visibility
(modelbuilder
, nclassdef
, self.n_visibility
)
1499 mreadprop
= new MMethod(mclassdef
, readname
, mvisibility
)
1500 if not self.check_redef_keyword
(modelbuilder
, nclassdef
, n_kwredef
, false, mreadprop
) then return
1502 if not self.check_redef_keyword
(modelbuilder
, nclassdef
, n_kwredef
, true, mreadprop
) then return
1503 check_redef_property_visibility
(modelbuilder
, nclassdef
, self.n_visibility
, mreadprop
)
1505 nclassdef
.mprop2npropdef
[mreadprop
] = self
1507 var mreadpropdef
= new MMethodDef(mclassdef
, mreadprop
, self.location
)
1508 self.mreadpropdef
= mreadpropdef
1509 modelbuilder
.mpropdef2npropdef
[mreadpropdef
] = self
1511 var writename
= name
+ "="
1512 var nwritable
= self.n_writable
1513 var mwriteprop
= modelbuilder
.try_get_mproperty_by_name
(nid2
, mclassdef
, writename
).as(nullable MMethod)
1514 var nwkwredef
: nullable Token = null
1515 if nwritable
!= null then nwkwredef
= nwritable
.n_kwredef
1516 if mwriteprop
== null then
1518 if nwritable
!= null then
1519 mvisibility
= new_property_visibility
(modelbuilder
, nclassdef
, nwritable
.n_visibility
)
1521 mvisibility
= private_visibility
1523 mwriteprop
= new MMethod(mclassdef
, writename
, mvisibility
)
1524 if not self.check_redef_keyword
(modelbuilder
, nclassdef
, nwkwredef
, false, mwriteprop
) then return
1526 if not self.check_redef_keyword
(modelbuilder
, nclassdef
, nwkwredef
, true, mwriteprop
) then return
1527 if nwritable
!= null then
1528 check_redef_property_visibility
(modelbuilder
, nclassdef
, nwritable
.n_visibility
, mwriteprop
)
1531 nclassdef
.mprop2npropdef
[mwriteprop
] = self
1533 var mwritepropdef
= new MMethodDef(mclassdef
, mwriteprop
, self.location
)
1534 self.mwritepropdef
= mwritepropdef
1535 modelbuilder
.mpropdef2npropdef
[mwritepropdef
] = self
1539 redef fun build_signature
(modelbuilder
, nclassdef
)
1541 var mpropdef
= self.mpropdef
1542 if mpropdef
== null then return # Error thus skiped
1543 var mmodule
= mpropdef
.mclassdef
.mmodule
1544 var mtype
: nullable MType = null
1546 var ntype
= self.n_type
1547 if ntype
!= null then
1548 mtype
= modelbuilder
.resolve_mtype
(nclassdef
, ntype
)
1549 if mtype
== null then return
1552 if mtype
== null then
1553 var nexpr
= self.n_expr
1554 if nexpr
!= null then
1555 if nexpr
isa ANewExpr then
1556 mtype
= modelbuilder
.resolve_mtype
(nclassdef
, nexpr
.n_type
)
1557 else if nexpr
isa AIntExpr then
1558 var cla
= modelbuilder
.try_get_mclass_by_name
(nexpr
, mmodule
, "Int")
1559 if cla
!= null then mtype
= cla
.mclass_type
1560 else if nexpr
isa AFloatExpr then
1561 var cla
= modelbuilder
.try_get_mclass_by_name
(nexpr
, mmodule
, "Float")
1562 if cla
!= null then mtype
= cla
.mclass_type
1563 else if nexpr
isa ACharExpr then
1564 var cla
= modelbuilder
.try_get_mclass_by_name
(nexpr
, mmodule
, "Char")
1565 if cla
!= null then mtype
= cla
.mclass_type
1566 else if nexpr
isa ABoolExpr then
1567 var cla
= modelbuilder
.try_get_mclass_by_name
(nexpr
, mmodule
, "Bool")
1568 if cla
!= null then mtype
= cla
.mclass_type
1569 else if nexpr
isa ASuperstringExpr then
1570 var cla
= modelbuilder
.try_get_mclass_by_name
(nexpr
, mmodule
, "String")
1571 if cla
!= null then mtype
= cla
.mclass_type
1572 else if nexpr
isa AStringFormExpr then
1573 var cla
= modelbuilder
.try_get_mclass_by_name
(nexpr
, mmodule
, "String")
1574 if cla
!= null then mtype
= cla
.mclass_type
1576 modelbuilder
.error
(self, "Error: Untyped attribute {mpropdef}. Implicit typing allowed only for literals and new.")
1580 modelbuilder
.error
(self, "Error: Untyped attribute {mpropdef}")
1584 if mtype
== null then return
1586 mpropdef
.static_mtype
= mtype
1588 var mreadpropdef
= self.mreadpropdef
1589 if mreadpropdef
!= null then
1590 var msignature
= new MSignature(new Array[MParameter], mtype
)
1591 mreadpropdef
.msignature
= msignature
1594 var msritepropdef
= self.mwritepropdef
1595 if mwritepropdef
!= null then
1597 if n_id
!= null then
1598 name
= n_id
.text
.substring_from
(1)
1602 var mparameter
= new MParameter(name
, mtype
, false)
1603 var msignature
= new MSignature([mparameter
], null)
1604 mwritepropdef
.msignature
= msignature
1608 redef fun check_signature
(modelbuilder
, nclassdef
)
1610 var mpropdef
= self.mpropdef
1611 if mpropdef
== null then return # Error thus skiped
1612 var mmodule
= mpropdef
.mclassdef
.mmodule
1613 var ntype
= self.n_type
1614 var mtype
= self.mpropdef
.static_mtype
1615 if mtype
== null then return # Error thus skiped
1617 # Lookup for signature in the precursor
1618 # FIXME all precursors should be considered
1619 if not mpropdef
.is_intro
then
1620 var precursor_type
= mpropdef
.mproperty
.intro
.static_mtype
1621 if precursor_type
== null then return
1623 if mtype
!= precursor_type
then
1624 modelbuilder
.error
(ntype
.as(not null), "Redef Error: Wrong static type. found {mtype}, expected {precursor_type}.")
1629 # Check getter and setter
1630 var meth
= self.mreadpropdef
1631 if meth
!= null then self.check_method_signature
(modelbuilder
, nclassdef
, meth
)
1632 meth
= self.mwritepropdef
1633 if meth
!= null then self.check_method_signature
(modelbuilder
, nclassdef
, meth
)
1636 private fun check_method_signature
(modelbuilder
: ModelBuilder, nclassdef
: AClassdef, mpropdef
: MMethodDef)
1638 var mmodule
= mpropdef
.mclassdef
.mmodule
1639 var nsig
= self.n_type
1640 var mysignature
= mpropdef
.msignature
1641 if mysignature
== null then return # Error thus skiped
1643 # Lookup for signature in the precursor
1644 # FIXME all precursors should be considered
1645 if not mpropdef
.is_intro
then
1646 var msignature
= mpropdef
.mproperty
.intro
.msignature
1647 if msignature
== null then return
1649 if mysignature
.arity
!= msignature
.arity
then
1651 if nsig
!= null then node
= nsig
else node
= self
1652 modelbuilder
.error
(node
, "Redef Error: {mysignature.arity} parameters found, {msignature.arity} expected. Signature is {mpropdef}{msignature}")
1655 var precursor_ret_type
= msignature
.return_mtype
1656 var ret_type
= mysignature
.return_mtype
1657 if ret_type
!= null and precursor_ret_type
== null then
1659 if nsig
!= null then node
= nsig
else node
= self
1660 modelbuilder
.error
(node
, "Redef Error: {mpropdef.mproperty} is a procedure, not a function.")
1664 if mysignature
.arity
> 0 then
1665 # Check parameters types
1666 for i
in [0..mysignature
.arity
[ do
1667 var myt
= mysignature
.mparameters
[i
].mtype
1668 var prt
= msignature
.mparameters
[i
].mtype
1669 if not myt
.is_subtype
(mmodule
, nclassdef
.mclassdef
.bound_mtype
, prt
) and
1670 not prt
.is_subtype
(mmodule
, nclassdef
.mclassdef
.bound_mtype
, myt
) then
1672 if nsig
!= null then node
= nsig
else node
= self
1673 modelbuilder
.error
(node
, "Redef Error: Wrong type for parameter `{mysignature.mparameters[i].name}'. found {myt}, expected {prt}.")
1677 if precursor_ret_type
!= null then
1678 if ret_type
== null then
1679 # Inherit the return type
1680 ret_type
= precursor_ret_type
1681 else if not ret_type
.is_subtype
(mmodule
, nclassdef
.mclassdef
.bound_mtype
, precursor_ret_type
) then
1683 if nsig
!= null then node
= nsig
else node
= self
1684 modelbuilder
.error
(node
, "Redef Error: Wrong return type. found {ret_type}, expected {precursor_ret_type}.")
1691 redef class ATypePropdef
1692 # The associated MVirtualTypeDef once build by a `ModelBuilder'
1693 var mpropdef
: nullable MVirtualTypeDef
1694 redef fun build_property
(modelbuilder
, nclassdef
)
1696 var mclassdef
= nclassdef
.mclassdef
.as(not null)
1697 var name
= self.n_id
.text
1698 var mprop
= modelbuilder
.try_get_mproperty_by_name
(self.n_id
, mclassdef
, name
)
1699 if mprop
== null then
1700 var mvisibility
= new_property_visibility
(modelbuilder
, nclassdef
, self.n_visibility
)
1701 mprop
= new MVirtualTypeProp(mclassdef
, name
, mvisibility
)
1702 if not self.check_redef_keyword
(modelbuilder
, nclassdef
, self.n_kwredef
, false, mprop
) then return
1704 if not self.check_redef_keyword
(modelbuilder
, nclassdef
, self.n_kwredef
, true, mprop
) then return
1705 assert mprop
isa MVirtualTypeProp
1706 check_redef_property_visibility
(modelbuilder
, nclassdef
, self.n_visibility
, mprop
)
1708 nclassdef
.mprop2npropdef
[mprop
] = self
1710 var mpropdef
= new MVirtualTypeDef(mclassdef
, mprop
, self.location
)
1711 self.mpropdef
= mpropdef
1714 redef fun build_signature
(modelbuilder
, nclassdef
)
1716 var mpropdef
= self.mpropdef
1717 if mpropdef
== null then return # Error thus skiped
1718 var mmodule
= mpropdef
.mclassdef
.mmodule
1719 var mtype
: nullable MType = null
1721 var ntype
= self.n_type
1722 mtype
= modelbuilder
.resolve_mtype
(nclassdef
, ntype
)
1723 if mtype
== null then return
1725 mpropdef
.bound
= mtype
1726 # print "{mpropdef}: {mtype}"
1729 redef fun check_signature
(modelbuilder
, nclassdef
)
1731 var bound
= self.mpropdef
.bound
1733 # Fast case: the bound is not a formal type
1734 if not bound
isa MVirtualType then return
1736 var mmodule
= nclassdef
.mclassdef
.mmodule
1737 var anchor
= nclassdef
.mclassdef
.bound_mtype
1739 # Slow case: progress on each resolution until: (i) we loop, or (ii) we found a non formal type
1740 var seen
= [self.mpropdef
.mproperty
.mvirtualtype
]
1742 if seen
.has
(bound
) then
1744 modelbuilder
.error
(self, "Error: circularity of virtual type definition: {seen.join(" -> ")}")
1748 var next
= bound
.lookup_bound
(mmodule
, anchor
)
1749 if not next
isa MVirtualType then return