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
33 redef class ToolContext
35 readable var _opt_path
: OptionArray = new OptionArray("Set include path for loaders (may be used more than once)", "-I", "--path")
37 # Option --only-metamodel
38 readable var _opt_only_metamodel
: OptionBool = new OptionBool("Stop after meta-model processing", "--only-metamodel")
41 readable var _opt_only_parse
: OptionBool = new OptionBool("Only proceed to parse step of loaders", "--only-parse")
46 option_context
.add_option
(opt_path
, opt_only_parse
, opt_only_metamodel
)
50 # A model builder knows how to load nit source files and build the associated model
51 # The important function is `parse_and_build' that does all the job.
52 # The others function can be used for specific tasks
54 # The model where new modules, classes and properties are added
57 # The toolcontext used to control the interaction with the user (getting options and displaying messages)
58 var toolcontext
: ToolContext
60 # Instantiate a modelbuilder for a model and a toolcontext
61 # Important, the options of the toolcontext must be correctly set (parse_option already called)
62 init(model
: Model, toolcontext
: ToolContext)
65 self.toolcontext
= toolcontext
67 # Setup the paths value
68 paths
.append
(toolcontext
.opt_path
.value
)
70 var path_env
= once
("NIT_PATH".to_symbol
).environ
71 if not path_env
.is_empty
then
72 paths
.append
(path_env
.split_with
(':'))
75 path_env
= once
("NIT_DIR".to_symbol
).environ
76 if not path_env
.is_empty
then
77 var libname
= "{path_env}/lib"
78 if libname
.file_exists
then paths
.add
(libname
)
81 var libname
= "{sys.program_name.dirname}/../lib"
82 if libname
.file_exists
then paths
.add
(libname
.simplify_path
)
85 # Load and analyze a bunch of modules.
86 # `modules' can contains filenames or module names.
87 # Imported modules are automatically loaded, builds and analysed.
88 # The result is the corresponding built modules.
89 # Errors and warnings are printed with the toolcontext.
91 # FIXME: Maybe just let the client do the loop (instead of playing with Sequences)
92 fun parse_and_build
(modules
: Sequence[String]): Array[MModule]
95 # Parse and recursively load
96 self.toolcontext
.info
("*** PARSE ***", 1)
97 var mmodules
= new Array[MModule]
99 var nmodule
= self.load_module
(null, a
)
100 if nmodule
== null then continue # Skip error
101 mmodules
.add
(nmodule
.mmodule
.as(not null))
104 self.toolcontext
.info
("*** END PARSE: {time1-time0} ***", 2)
106 self.toolcontext
.check_errors
109 self.toolcontext
.info
("*** BUILD MODEL ***", 1)
110 self.build_all_classes
112 self.toolcontext
.info
("*** END BUILD MODEL: {time2-time1} ***", 2)
114 self.toolcontext
.check_errors
119 # Return a class named `name' visible by the module `mmodule'.
120 # Visibility in modules is correctly handled.
121 # If no such a class exists, then null is returned.
122 # If more than one class exists, then an error on `anode' is displayed and null is returned.
123 # FIXME: add a way to handle class name conflict
124 fun try_get_mclass_by_name
(anode
: ANode, mmodule
: MModule, name
: String): nullable MClass
126 var classes
= model
.get_mclasses_by_name
(name
)
127 if classes
== null then
131 var res
: nullable MClass = null
132 for mclass
in classes
do
133 if not mmodule
.in_importation
<= mclass
.intro_mmodule
then continue
134 if not mmodule
.is_visible
(mclass
.intro_mmodule
, mclass
.visibility
) then continue
138 error
(anode
, "Ambigous class name '{name}'; conflict between {mclass.full_name} and {res.full_name}")
145 # Return a property named `name' on the type `mtype' visible in the module `mmodule'.
146 # Visibility in modules is correctly handled.
147 # Protected properties are returned (it is up to the caller to check and reject protected properties).
148 # If no such a property exists, then null is returned.
149 # If more than one property exists, then an error on `anode' is displayed and null is returned.
150 # FIXME: add a way to handle property name conflict
151 fun try_get_mproperty_by_name2
(anode
: ANode, mmodule
: MModule, mtype
: MType, name
: String): nullable MProperty
153 var props
= self.model
.get_mproperties_by_name
(name
)
154 if props
== null then
158 var cache
= self.try_get_mproperty_by_name2_cache
[mmodule
, mtype
, name
]
159 if cache
!= null then return cache
161 var res
: nullable MProperty = null
162 var ress
: nullable Array[MProperty] = null
163 for mprop
in props
do
164 if not mtype
.has_mproperty
(mmodule
, mprop
) then continue
165 if not mmodule
.is_visible
(mprop
.intro_mclassdef
.mmodule
, mprop
.visibility
) then continue
169 var restype
= res
.intro_mclassdef
.bound_mtype
170 var mproptype
= mprop
.intro_mclassdef
.bound_mtype
171 if restype
.is_subtype
(mmodule
, null, mproptype
) then
173 else if mproptype
.is_subtype
(mmodule
, null, restype
) then
176 if ress
== null then ress
= new Array[MProperty]
182 var restype
= res
.intro_mclassdef
.bound_mtype
184 var mproptype
= mprop
.intro_mclassdef
.bound_mtype
185 if not restype
.is_subtype
(mmodule
, null, mproptype
) then
186 self.error
(anode
, "Ambigous property name '{name}' for {mtype}; conflict between {mprop.full_name} and {res.full_name}")
192 self.try_get_mproperty_by_name2_cache
[mmodule
, mtype
, name
] = res
196 private var try_get_mproperty_by_name2_cache
: HashMap3[MModule, MType, String, nullable MProperty] = new HashMap3[MModule, MType, String, nullable MProperty]
199 # Alias for try_get_mproperty_by_name2(anode, mclassdef.mmodule, mclassdef.mtype, name)
200 fun try_get_mproperty_by_name
(anode
: ANode, mclassdef
: MClassDef, name
: String): nullable MProperty
202 return try_get_mproperty_by_name2
(anode
, mclassdef
.mmodule
, mclassdef
.bound_mtype
, name
)
205 # The list of directories to search for top level modules
206 # The list is initially set with :
207 # * the toolcontext --path option
208 # * the NIT_PATH environment variable
209 # * some heuristics including the NIT_DIR environment variable and the progname of the process
210 # Path can be added (or removed) by the client
211 var paths
: Array[String] = new Array[String]
213 # Get a module by its short name; if required, the module is loaded, parsed and its hierarchies computed.
214 # If `mmodule' is set, then the module search starts from it up to the top level (see `paths');
215 # if `mmodule' is null then the module is searched in the top level only.
216 # If no module exists or there is a name conflict, then an error on `anode' is displayed and null is returned.
217 # FIXME: add a way to handle module name conflict
218 fun get_mmodule_by_name
(anode
: ANode, mmodule
: nullable MModule, name
: String): nullable MModule
220 var origmmodule
= mmodule
221 var modules
= model
.get_mmodules_by_name
(name
)
223 var lastmodule
= mmodule
224 while mmodule
!= null do
225 var dirname
= mmodule
.location
.file
.filename
.dirname
227 # Determine the owner
228 var owner
: nullable MModule
229 if dirname
.basename
("") != mmodule
.name
then
230 owner
= mmodule
.direct_owner
235 # First, try the already known nested modules
236 if modules
!= null then
237 for candidate
in modules
do
238 if candidate
.direct_owner
== owner
then
244 # Second, try the directory to find a file
245 var try_file
= dirname
+ "/" + name
+ ".nit"
246 if try_file
.file_exists
then
247 var res
= self.load_module
(owner
, try_file
.simplify_path
)
248 if res
== null then return null # Forward error
249 return res
.mmodule
.as(not null)
252 # Third, try if the requested module is itself an owner
253 try_file
= dirname
+ "/" + name
+ "/" + name
+ ".nit"
254 if try_file
.file_exists
then
255 var res
= self.load_module
(owner
, try_file
.simplify_path
)
256 if res
== null then return null # Forward error
257 return res
.mmodule
.as(not null)
261 mmodule
= mmodule
.direct_owner
264 if modules
!= null then
265 for candidate
in modules
do
266 if candidate
.direct_owner
== null then
272 # Look at some known directories
273 var lookpaths
= self.paths
275 # Look in the directory of the last module also (event if not in the path)
276 if lastmodule
!= null then
277 var dirname
= lastmodule
.location
.file
.filename
.dirname
278 if dirname
.basename
("") == lastmodule
.name
then
279 dirname
= dirname
.dirname
281 if not lookpaths
.has
(dirname
) then
282 lookpaths
= lookpaths
.to_a
283 lookpaths
.add
(dirname
)
287 var candidate
: nullable String = null
288 for dirname
in lookpaths
do
289 var try_file
= (dirname
+ "/" + name
+ ".nit").simplify_path
290 if try_file
.file_exists
then
291 if candidate
== null then
293 else if candidate
!= try_file
then
294 error
(anode
, "Error: conflicting module file for {name}: {candidate} {try_file}")
297 try_file
= (dirname
+ "/" + name
+ "/" + name
+ ".nit").simplify_path
298 if try_file
.file_exists
then
299 if candidate
== null then
301 else if candidate
!= try_file
then
302 error
(anode
, "Error: conflicting module file for {name}: {candidate} {try_file}")
306 if candidate
== null then
307 if origmmodule
!= null then
308 error
(anode
, "Error: cannot find module {name} from {origmmodule}")
310 error
(anode
, "Error: cannot find module {name}")
314 var res
= self.load_module
(mmodule
, candidate
)
315 if res
== null then return null # Forward error
316 return res
.mmodule
.as(not null)
319 # Try to load a module using a path.
320 # Display an error if there is a problem (IO / lexer / parser) and return null
321 # Note: usually, you do not need this method, use `get_mmodule_by_name` instead.
322 fun load_module
(owner
: nullable MModule, filename
: String): nullable AModule
324 if not filename
.file_exists
then
325 self.toolcontext
.error
(null, "Error: file {filename} not found.")
329 var x
= if owner
!= null then owner
.to_s
else "."
330 self.toolcontext
.info
("load module {filename} in {x}", 2)
333 var file
= new IFStream.open
(filename
)
334 var lexer
= new Lexer(new SourceFile(filename
, file
))
335 var parser
= new Parser(lexer
)
336 var tree
= parser
.parse
339 # Handle lexer and parser error
340 var nmodule
= tree
.n_base
341 if nmodule
== null then
342 var neof
= tree
.n_eof
343 assert neof
isa AError
344 error
(neof
, neof
.message
)
348 # Check the module name
349 var mod_name
= filename
.basename
(".nit")
350 var decl
= nmodule
.n_moduledecl
352 #warning(nmodule, "Warning: Missing 'module' keyword") #FIXME: NOT YET FOR COMPATIBILITY
354 var decl_name
= decl
.n_name
.n_id
.text
355 if decl_name
!= mod_name
then
356 error
(decl
.n_name
, "Error: module name missmatch; declared {decl_name} file named {mod_name}")
361 var mmodule
= new MModule(model
, owner
, mod_name
, nmodule
.location
)
362 nmodule
.mmodule
= mmodule
363 nmodules
.add
(nmodule
)
364 self.mmodule2nmodule
[mmodule
] = nmodule
366 build_module_importation
(nmodule
)
371 # Analysis the module importation and fill the module_importation_hierarchy
372 private fun build_module_importation
(nmodule
: AModule)
374 if nmodule
.is_importation_done
then return
375 var mmodule
= nmodule
.mmodule
.as(not null)
377 var imported_modules
= new Array[MModule]
378 for aimport
in nmodule
.n_imports
do
380 if not aimport
isa AStdImport then
383 var mod_name
= aimport
.n_name
.n_id
.text
384 var sup
= self.get_mmodule_by_name
(aimport
.n_name
, mmodule
, mod_name
)
385 if sup
== null then continue # Skip error
386 imported_modules
.add
(sup
)
387 var mvisibility
= aimport
.n_visibility
.mvisibility
388 mmodule
.set_visibility_for
(sup
, mvisibility
)
391 var mod_name
= "standard"
392 var sup
= self.get_mmodule_by_name
(nmodule
, null, mod_name
)
393 if sup
!= null then # Skip error
394 imported_modules
.add
(sup
)
395 mmodule
.set_visibility_for
(sup
, public_visibility
)
398 self.toolcontext
.info
("{mmodule} imports {imported_modules.join(", ")}", 3)
399 mmodule
.set_imported_mmodules
(imported_modules
)
400 nmodule
.is_importation_done
= true
403 # All the loaded modules
404 var nmodules
: Array[AModule] = new Array[AModule]
406 # Build the classes of all modules `nmodules'.
407 private fun build_all_classes
409 for nmodule
in self.nmodules
do
410 build_classes
(nmodule
)
414 # Visit the AST and create the MClass objects
415 private fun build_a_mclass
(nmodule
: AModule, nclassdef
: AClassdef)
417 var mmodule
= nmodule
.mmodule
.as(not null)
420 var nkind
: nullable AClasskind
421 var mkind
: MClassKind
422 var nvisibility
: nullable AVisibility
423 var mvisibility
: nullable MVisibility
425 if nclassdef
isa AStdClassdef then
426 name
= nclassdef
.n_id
.text
427 nkind
= nclassdef
.n_classkind
429 nvisibility
= nclassdef
.n_visibility
430 mvisibility
= nvisibility
.mvisibility
431 arity
= nclassdef
.n_formaldefs
.length
432 else if nclassdef
isa ATopClassdef then
435 mkind
= interface_kind
437 mvisibility
= public_visibility
438 else if nclassdef
isa AMainClassdef then
441 mkind
= concrete_kind
443 mvisibility
= public_visibility
448 var mclass
= try_get_mclass_by_name
(nclassdef
, mmodule
, name
)
449 if mclass
== null then
450 mclass
= new MClass(mmodule
, name
, arity
, mkind
, mvisibility
)
451 #print "new class {mclass}"
452 else if nclassdef
isa AStdClassdef and nclassdef
.n_kwredef
== null then
453 error
(nclassdef
, "Redef error: {name} is an imported class. Add the redef keyword to refine it.")
455 else if mclass
.arity
!= arity
then
456 error
(nclassdef
, "Redef error: Formal parameter arity missmatch; got {arity}, expected {mclass.arity}.")
458 else if nkind
!= null and mkind
!= concrete_kind
and mclass
.kind
!= mkind
then
459 error
(nkind
, "Error: refinement changed the kind from a {mclass.kind} to a {mkind}")
460 else if nvisibility
!= null and mvisibility
!= public_visibility
and mclass
.visibility
!= mvisibility
then
461 error
(nvisibility
, "Error: refinement changed the visibility from a {mclass.visibility} to a {mvisibility}")
463 nclassdef
.mclass
= mclass
466 # Visit the AST and create the MClassDef objects
467 private fun build_a_mclassdef
(nmodule
: AModule, nclassdef
: AClassdef)
469 var mmodule
= nmodule
.mmodule
.as(not null)
470 var objectclass
= try_get_mclass_by_name
(nmodule
, mmodule
, "Object")
471 var mclass
= nclassdef
.mclass
.as(not null)
472 #var mclassdef = nclassdef.mclassdef.as(not null)
474 var names
= new Array[String]
475 var bounds
= new Array[MType]
476 if nclassdef
isa AStdClassdef and mclass
.arity
> 0 then
477 # Collect formal parameter names
478 for i
in [0..mclass
.arity
[ do
479 var nfd
= nclassdef
.n_formaldefs
[i
]
480 var ptname
= nfd
.n_id
.text
481 if names
.has
(ptname
) then
482 error
(nfd
, "Error: A formal parameter type `{ptname}' already exists")
488 # Revolve bound for formal parameter names
489 for i
in [0..mclass
.arity
[ do
490 var nfd
= nclassdef
.n_formaldefs
[i
]
491 var nfdt
= nfd
.n_type
493 var bound
= resolve_mtype
(nclassdef
, nfdt
)
494 if bound
== null then return # Forward error
495 if bound
.need_anchor
then
497 error
(nfd
, "Error: Formal parameter type `{names[i]}' bounded with a formal parameter type")
501 else if mclass
.mclassdefs
.is_empty
then
502 # No bound, then implicitely bound by nullable Object
503 bounds
.add
(objectclass
.mclass_type
.as_nullable
)
506 bounds
.add
(mclass
.mclassdefs
.first
.bound_mtype
.as(MGenericType).arguments
[i
])
511 var bound_mtype
= mclass
.get_mtype
(bounds
)
512 var mclassdef
= new MClassDef(mmodule
, bound_mtype
, nclassdef
.location
, names
)
513 nclassdef
.mclassdef
= mclassdef
514 self.mclassdef2nclassdef
[mclassdef
] = nclassdef
516 if mclassdef
.is_intro
then
517 self.toolcontext
.info
("{mclassdef} introduces new {mclass.kind} {mclass.full_name}", 3)
519 self.toolcontext
.info
("{mclassdef} refine {mclass.kind} {mclass.full_name}", 3)
523 # Visit the AST and set the super-types of the MClass objects (ie compute the inheritance)
524 private fun build_a_mclassdef_inheritance
(nmodule
: AModule, nclassdef
: AClassdef)
526 var mmodule
= nmodule
.mmodule
.as(not null)
527 var objectclass
= try_get_mclass_by_name
(nmodule
, mmodule
, "Object")
528 var mclass
= nclassdef
.mclass
.as(not null)
529 var mclassdef
= nclassdef
.mclassdef
.as(not null)
531 var specobject
= true
532 var supertypes
= new Array[MClassType]
533 if nclassdef
isa AStdClassdef then
534 for nsc
in nclassdef
.n_superclasses
do
536 var ntype
= nsc
.n_type
537 var mtype
= resolve_mtype
(nclassdef
, ntype
)
538 if mtype
== null then continue # Skip because of error
539 if not mtype
isa MClassType then
540 error
(ntype
, "Error: supertypes cannot be a formal type")
544 #print "new super : {mclass} < {mtype}"
547 if specobject
and mclass
.name
!= "Object" and objectclass
!= null and mclassdef
.is_intro
then
548 supertypes
.add objectclass
.mclass_type
551 mclassdef
.set_supertypes
(supertypes
)
552 if not supertypes
.is_empty
then self.toolcontext
.info
("{mclassdef} new super-types: {supertypes.join(", ")}", 3)
555 # Check the validity of the specialization heirarchy
556 # FIXME Stub implementation
557 private fun check_supertypes
(nmodule
: AModule, nclassdef
: AClassdef)
559 var mmodule
= nmodule
.mmodule
.as(not null)
560 var objectclass
= try_get_mclass_by_name
(nmodule
, mmodule
, "Object")
561 var mclass
= nclassdef
.mclass
.as(not null)
562 var mclassdef
= nclassdef
.mclassdef
.as(not null)
565 # Build the classes of the module `nmodule'.
566 # REQUIRE: classes of imported modules are already build. (let `build_all_classes' do the job)
567 private fun build_classes
(nmodule
: AModule)
569 # Force building recursively
570 if nmodule
.build_classes_is_done
then return
571 var mmodule
= nmodule
.mmodule
.as(not null)
572 for imp
in mmodule
.in_importation
.direct_greaters
do
573 build_classes
(mmodule2nmodule
[imp
])
577 for nclassdef
in nmodule
.n_classdefs
do
578 self.build_a_mclass
(nmodule
, nclassdef
)
581 # Create all classdefs
582 for nclassdef
in nmodule
.n_classdefs
do
583 self.build_a_mclassdef
(nmodule
, nclassdef
)
586 # Create inheritance on all classdefs
587 for nclassdef
in nmodule
.n_classdefs
do
588 self.build_a_mclassdef_inheritance
(nmodule
, nclassdef
)
591 # TODO: Check that the super-class is not intrusive
593 # TODO: Check that the super-class is not already known (by transitivity)
595 for nclassdef
in nmodule
.n_classdefs
do
596 self.build_properties
(nclassdef
)
599 nmodule
.build_classes_is_done
= true
602 # Register the nmodule associated to each mmodule
603 # FIXME: why not refine the MModule class with a nullable attribute?
604 var mmodule2nmodule
: HashMap[MModule, AModule] = new HashMap[MModule, AModule]
605 # Register the nclassdef associated to each mclassdef
606 # FIXME: why not refine the MClassDef class with a nullable attribute?
607 var mclassdef2nclassdef
: HashMap[MClassDef, AClassdef] = new HashMap[MClassDef, AClassdef]
608 # Register the npropdef associated to each mpropdef
609 # FIXME: why not refine the MPropDef class with a nullable attribute?
610 var mpropdef2npropdef
: HashMap[MPropDef, APropdef] = new HashMap[MPropDef, APropdef]
612 # Build the properties of `nclassdef'.
613 # REQUIRE: all superclasses are built.
614 private fun build_properties
(nclassdef
: AClassdef)
616 # Force building recursively
617 if nclassdef
.build_properties_is_done
then return
618 var mclassdef
= nclassdef
.mclassdef
.as(not null)
619 if mclassdef
.in_hierarchy
== null then return # Skip error
620 for superclassdef
in mclassdef
.in_hierarchy
.direct_greaters
do
621 build_properties
(mclassdef2nclassdef
[superclassdef
])
624 for npropdef
in nclassdef
.n_propdefs
do
625 npropdef
.build_property
(self, nclassdef
)
627 for npropdef
in nclassdef
.n_propdefs
do
628 npropdef
.build_signature
(self, nclassdef
)
630 for npropdef
in nclassdef
.n_propdefs
do
631 npropdef
.check_signature
(self, nclassdef
)
633 process_default_constructors
(nclassdef
)
634 nclassdef
.build_properties_is_done
= true
637 # Introduce or inherit default constructor
638 # This is the last part of `build_properties'.
639 private fun process_default_constructors
(nclassdef
: AClassdef)
641 var mclassdef
= nclassdef
.mclassdef
.as(not null)
643 # Are we a refinement
644 if not mclassdef
.is_intro
then return
646 # Is the class forbid constructors?
647 if not mclassdef
.mclass
.kind
.need_init
then return
649 # Is there already a constructor defined?
650 for mpropdef
in mclassdef
.mpropdefs
do
651 if not mpropdef
isa MMethodDef then continue
652 if mpropdef
.mproperty
.is_init
then return
655 if not nclassdef
isa AStdClassdef then return
657 var mmodule
= nclassdef
.mclassdef
.mmodule
658 # Do we inherit for a constructor?
659 var combine
= new Array[MMethod]
660 var inhc
: nullable MClass = null
661 for st
in mclassdef
.supertypes
do
663 if not c
.kind
.need_init
then continue
664 st
= st
.anchor_to
(mmodule
, nclassdef
.mclassdef
.bound_mtype
)
665 var candidate
= self.try_get_mproperty_by_name2
(nclassdef
, mmodule
, st
, "init").as(nullable MMethod)
666 if candidate
!= null and candidate
.intro
.msignature
.arity
== 0 then
667 combine
.add
(candidate
)
670 var inhc2
= c
.inherit_init_from
671 if inhc2
== null then inhc2
= c
672 if inhc2
== inhc
then continue
674 self.error
(nclassdef
, "Cannot provide a defaut constructor: conflict for {inhc} and {c}")
679 if combine
.is_empty
and inhc
!= null then
680 # TODO: actively inherit the consturctor
681 self.toolcontext
.info
("{mclassdef} inherits all constructors from {inhc}", 3)
682 mclassdef
.mclass
.inherit_init_from
= inhc
685 if not combine
.is_empty
and inhc
!= null then
686 self.error
(nclassdef
, "Cannot provide a defaut constructor: conflict for {combine.join(", ")} and {inhc}")
690 if not combine
.is_empty
then
691 nclassdef
.super_inits
= combine
692 var mprop
= new MMethod(mclassdef
, "init", mclassdef
.mclass
.visibility
)
693 var mpropdef
= new MMethodDef(mclassdef
, mprop
, nclassdef
.location
)
694 var param_names
= new Array[String]
695 var param_types
= new Array[MType]
696 var msignature
= new MSignature(param_names
, param_types
, null, -1)
697 mpropdef
.msignature
= msignature
699 nclassdef
.mfree_init
= mpropdef
700 self.toolcontext
.info
("{mclassdef} gets a free empty constructor {mpropdef}{msignature}", 3)
704 # Collect undefined attributes
705 var param_names
= new Array[String]
706 var param_types
= new Array[MType]
707 for npropdef
in nclassdef
.n_propdefs
do
708 if npropdef
isa AAttrPropdef and npropdef
.n_expr
== null then
709 param_names
.add
(npropdef
.mpropdef
.mproperty
.name
.substring_from
(1))
710 var ret_type
= npropdef
.mpropdef
.static_mtype
711 if ret_type
== null then return
712 param_types
.add
(ret_type
)
716 var mprop
= new MMethod(mclassdef
, "init", mclassdef
.mclass
.visibility
)
717 var mpropdef
= new MMethodDef(mclassdef
, mprop
, nclassdef
.location
)
718 var msignature
= new MSignature(param_names
, param_types
, null, -1)
719 mpropdef
.msignature
= msignature
721 nclassdef
.mfree_init
= mpropdef
722 self.toolcontext
.info
("{mclassdef} gets a free constructor for attributes {mpropdef}{msignature}", 3)
725 # Return the static type associated to the node `ntype'.
726 # `classdef' is the context where the call is made (used to understand formal types)
727 # The mmodule used as context is `nclassdef.mmodule'
728 # In case of problem, an error is displayed on `ntype' and null is returned.
729 # FIXME: the name "resolve_mtype" is awful
730 fun resolve_mtype
(nclassdef
: AClassdef, ntype
: AType): nullable MType
732 var name
= ntype
.n_id
.text
733 var mclassdef
= nclassdef
.mclassdef
734 var mmodule
= nclassdef
.parent
.as(AModule).mmodule
.as(not null)
738 if mclassdef
!= null then
739 var prop
= try_get_mproperty_by_name
(ntype
, mclassdef
, name
).as(nullable MVirtualTypeProp)
741 if not ntype
.n_types
.is_empty
then
742 error
(ntype
, "Type error: formal type {name} cannot have formal parameters.")
744 res
= prop
.mvirtualtype
745 if ntype
.n_kwnullable
!= null then res
= res
.as_nullable
750 # Check parameter type
751 if mclassdef
!= null and mclassdef
.parameter_names
.has
(name
) then
752 if not ntype
.n_types
.is_empty
then
753 error
(ntype
, "Type error: formal type {name} cannot have formal parameters.")
755 for i
in [0..mclassdef
.parameter_names
.length
[ do
756 if mclassdef
.parameter_names
[i
] == name
then
757 res
= mclassdef
.mclass
.mclass_type
.as(MGenericType).arguments
[i
]
758 if ntype
.n_kwnullable
!= null then res
= res
.as_nullable
766 var mclass
= try_get_mclass_by_name
(ntype
, mmodule
, name
)
767 if mclass
!= null then
768 var arity
= ntype
.n_types
.length
769 if arity
!= mclass
.arity
then
771 error
(ntype
, "Type error: '{name}' is a generic class.")
772 else if mclass
.arity
== 0 then
773 error
(ntype
, "Type error: '{name}' is not a generic class.")
775 error
(ntype
, "Type error: '{name}' has {mclass.arity} parameters ({arity} are provided).")
780 res
= mclass
.mclass_type
781 if ntype
.n_kwnullable
!= null then res
= res
.as_nullable
784 var mtypes
= new Array[MType]
785 for nt
in ntype
.n_types
do
786 var mt
= resolve_mtype
(nclassdef
, nt
)
787 if mt
== null then return null # Forward error
790 res
= mclass
.get_mtype
(mtypes
)
791 if ntype
.n_kwnullable
!= null then res
= res
.as_nullable
796 # If everything fail, then give up :(
797 error
(ntype
, "Type error: class {name} not found in module {mmodule}.")
801 # Helper function to display an error on a node.
802 # Alias for `self.toolcontext.error(n.hot_location, text)'
803 fun error
(n
: ANode, text
: String)
805 self.toolcontext
.error
(n
.hot_location
, text
)
808 # Helper function to display a warning on a node.
809 # Alias for: `self.toolcontext.warning(n.hot_location, text)'
810 fun warning
(n
: ANode, text
: String)
812 self.toolcontext
.warning
(n
.hot_location
, text
)
817 # The associated MModule once build by a `ModelBuilder'
818 var mmodule
: nullable MModule
819 # Flag that indicate if the importation is already completed
820 var is_importation_done
: Bool = false
821 # Flag that indicate if the class and prop building is already completed
822 var build_classes_is_done
: Bool = false
826 # The class whose self inherit all the constructors.
827 # 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
828 var inherit_init_from
: nullable MClass = null
831 redef class AClassdef
832 # The associated MClass once build by a `ModelBuilder'
833 var mclass
: nullable MClass
834 # The associated MClassDef once build by a `ModelBuilder'
835 var mclassdef
: nullable MClassDef
836 var build_properties_is_done
: Bool = false
837 # The list of super-constructor to call at the start of the free constructor
838 # 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
839 var super_inits
: nullable Collection[MMethod] = null
841 # The free init (implicitely constructed by the class if required)
842 var mfree_init
: nullable MMethodDef = null
845 redef class AClasskind
846 # The class kind associated with the AST node class
847 private fun mkind
: MClassKind is abstract
849 redef class AConcreteClasskind
850 redef fun mkind
do return concrete_kind
852 redef class AAbstractClasskind
853 redef fun mkind
do return abstract_kind
855 redef class AInterfaceClasskind
856 redef fun mkind
do return interface_kind
858 redef class AEnumClasskind
859 redef fun mkind
do return enum_kind
861 redef class AExternClasskind
862 redef fun mkind
do return extern_kind
865 redef class AVisibility
866 # The visibility level associated with the AST node class
867 private fun mvisibility
: MVisibility is abstract
869 redef class AIntrudeVisibility
870 redef fun mvisibility
do return intrude_visibility
872 redef class APublicVisibility
873 redef fun mvisibility
do return public_visibility
875 redef class AProtectedVisibility
876 redef fun mvisibility
do return protected_visibility
878 redef class APrivateVisibility
879 redef fun mvisibility
do return private_visibility
886 # Join the text of all tokens
887 # Used to get the 'real name' of method definitions.
888 fun collect_text
: String
890 var v
= new TextCollectorVisitor
897 private class TextCollectorVisitor
899 var text
: String = ""
902 if n
isa Token then text
+= n
.text
908 private fun build_property
(modelbuilder
: ModelBuilder, nclassdef
: AClassdef)
911 private fun build_signature
(modelbuilder
: ModelBuilder, nclassdef
: AClassdef)
914 private fun check_signature
(modelbuilder
: ModelBuilder, nclassdef
: AClassdef)
917 private fun new_property_visibility
(modelbuilder
: ModelBuilder, nclassdef
: AClassdef, nvisibility
: nullable AVisibility): MVisibility
919 var mvisibility
= public_visibility
920 if nvisibility
!= null then mvisibility
= nvisibility
.mvisibility
921 if nclassdef
.mclassdef
.mclass
.visibility
== private_visibility
then
922 if mvisibility
== protected_visibility
then
923 assert nvisibility
!= null
924 modelbuilder
.error
(nvisibility
, "Error: The only legal visibility for properties in a private class is private.")
925 else if mvisibility
== private_visibility
then
926 assert nvisibility
!= null
928 # modelbuilder.warning(nvisibility, "Warning: private is unrequired since the only legal visibility for properties in a private class is private.")
930 mvisibility
= private_visibility
935 private fun check_redef_property_visibility
(modelbuilder
: ModelBuilder, nclassdef
: AClassdef, nvisibility
: nullable AVisibility, mprop
: MProperty)
937 if nvisibility
== null then return
938 var mvisibility
= nvisibility
.mvisibility
939 if mvisibility
!= mprop
.visibility
and mvisibility
!= public_visibility
then
940 modelbuilder
.error
(nvisibility
, "Error: redefinition changed the visibility from a {mprop.visibility} to a {mvisibility}")
944 private fun check_redef_keyword
(modelbuilder
: ModelBuilder, nclassdef
: AClassdef, kwredef
: nullable Token, need_redef
: Bool, mprop
: MProperty)
946 if kwredef
== null then
948 modelbuilder
.error
(self, "Redef error: {nclassdef.mclassdef.mclass}::{mprop.name} is an inherited property. To redefine it, add the redef keyword.")
951 if not need_redef
then
952 modelbuilder
.error
(self, "Error: No property {nclassdef.mclassdef.mclass}::{mprop.name} is inherited. Remove the redef keyword to define a new property.")
958 redef class AMethPropdef
959 # The associated MMethodDef once build by a `ModelBuilder'
960 var mpropdef
: nullable MMethodDef
962 # The associated super init if any
963 var super_init
: nullable MMethod
964 redef fun build_property
(modelbuilder
, nclassdef
)
966 var is_init
= self isa AInitPropdef
967 var mclassdef
= nclassdef
.mclassdef
.as(not null)
969 var amethodid
= self.n_methid
971 if amethodid
== null then
972 if self isa AMainMethPropdef then
975 else if self isa AConcreteInitPropdef then
977 name_node
= self.n_kwinit
978 else if self isa AExternInitPropdef then
980 name_node
= self.n_kwnew
984 else if amethodid
isa AIdMethid then
985 name
= amethodid
.n_id
.text
986 name_node
= amethodid
988 # operator, bracket or assign
989 name
= amethodid
.collect_text
990 name_node
= amethodid
992 if name
== "-" and self.n_signature
.n_params
.length
== 0 then
997 var mprop
: nullable MMethod = null
998 if not is_init
or n_kwredef
!= null then mprop
= modelbuilder
.try_get_mproperty_by_name
(name_node
, mclassdef
, name
).as(nullable MMethod)
999 if mprop
== null then
1000 var mvisibility
= new_property_visibility
(modelbuilder
, nclassdef
, self.n_visibility
)
1001 mprop
= new MMethod(mclassdef
, name
, mvisibility
)
1002 mprop
.is_init
= is_init
1003 self.check_redef_keyword
(modelbuilder
, nclassdef
, n_kwredef
, false, mprop
)
1005 if n_kwredef
== null then
1006 if self isa AMainMethPropdef then
1009 self.check_redef_keyword
(modelbuilder
, nclassdef
, n_kwredef
, true, mprop
)
1012 check_redef_property_visibility
(modelbuilder
, nclassdef
, self.n_visibility
, mprop
)
1015 var mpropdef
= new MMethodDef(mclassdef
, mprop
, self.location
)
1017 self.mpropdef
= mpropdef
1018 modelbuilder
.mpropdef2npropdef
[mpropdef
] = self
1019 if mpropdef
.is_intro
then
1020 modelbuilder
.toolcontext
.info
("{mpropdef} introduces new method {mprop.full_name}", 3)
1022 modelbuilder
.toolcontext
.info
("{mpropdef} redefines method {mprop.full_name}", 3)
1026 redef fun build_signature
(modelbuilder
, nclassdef
)
1028 var mpropdef
= self.mpropdef
1029 if mpropdef
== null then return # Error thus skiped
1030 var mmodule
= mpropdef
.mclassdef
.mmodule
1031 var nsig
= self.n_signature
1033 # Retrieve info from the signature AST
1034 var param_names
= new Array[String] # Names of parameters from the AST
1035 var param_types
= new Array[MType] # Types of parameters from the AST
1036 var vararg_rank
= -1
1037 var ret_type
: nullable MType = null # Return type from the AST
1038 if nsig
!= null then
1039 for np
in nsig
.n_params
do
1040 param_names
.add
(np
.n_id
.text
)
1041 var ntype
= np
.n_type
1042 if ntype
!= null then
1043 var mtype
= modelbuilder
.resolve_mtype
(nclassdef
, ntype
)
1044 if mtype
== null then return # Skip error
1045 for i
in [0..param_names
.length-param_types
.length
[ do
1046 param_types
.add
(mtype
)
1048 if np
.n_dotdotdot
!= null then
1049 if vararg_rank
!= -1 then
1050 modelbuilder
.error
(np
, "Error: {param_names[vararg_rank]} is already a vararg")
1052 vararg_rank
= param_names
.length
- 1
1057 var ntype
= nsig
.n_type
1058 if ntype
!= null then
1059 ret_type
= modelbuilder
.resolve_mtype
(nclassdef
, ntype
)
1060 if ret_type
== null then return # Skip errir
1064 # Look for some signature to inherit
1065 # FIXME: do not inherit from the intro, but from the most specific
1066 var msignature
: nullable MSignature = null
1067 if not mpropdef
.is_intro
then
1068 msignature
= mpropdef
.mproperty
.intro
.msignature
1069 if msignature
== null then return # Skip error
1070 else if mpropdef
.mproperty
.is_init
then
1071 # FIXME UGLY: inherit signature from a super-constructor
1072 for msupertype
in nclassdef
.mclassdef
.supertypes
do
1073 msupertype
= msupertype
.anchor_to
(mmodule
, nclassdef
.mclassdef
.bound_mtype
)
1074 var candidate
= modelbuilder
.try_get_mproperty_by_name2
(self, mmodule
, msupertype
, mpropdef
.mproperty
.name
)
1075 if candidate
!= null then
1076 if msignature
== null then
1077 msignature
= candidate
.intro
.as(MMethodDef).msignature
1083 # Inherit the signature
1084 if msignature
!= null and param_names
.length
!= param_types
.length
and param_names
.length
== msignature
.arity
and param_types
.length
== 0 then
1085 # Parameters are untyped, thus inherit them
1086 param_types
= msignature
.parameter_mtypes
1087 vararg_rank
= msignature
.vararg_rank
1089 if msignature
!= null and ret_type
== null then
1090 ret_type
= msignature
.return_mtype
1093 if param_names
.length
!= param_types
.length
then
1094 # Some parameters are typed, other parameters are not typed.
1095 modelbuilder
.warning
(nsig
.n_params
[param_types
.length
], "Error: Untyped parameter `{param_names[param_types.length]}'.")
1099 msignature
= new MSignature(param_names
, param_types
, ret_type
, vararg_rank
)
1100 mpropdef
.msignature
= msignature
1103 redef fun check_signature
(modelbuilder
, nclassdef
)
1105 var mpropdef
= self.mpropdef
1106 if mpropdef
== null then return # Error thus skiped
1107 var mmodule
= mpropdef
.mclassdef
.mmodule
1108 var nsig
= self.n_signature
1109 var mysignature
= self.mpropdef
.msignature
1110 if mysignature
== null then return # Error thus skiped
1112 # Lookup for signature in the precursor
1113 # FIXME all precursors should be considered
1114 if not mpropdef
.is_intro
then
1115 var msignature
= mpropdef
.mproperty
.intro
.msignature
1116 if msignature
== null then return
1118 if mysignature
.arity
!= msignature
.arity
then
1120 if nsig
!= null then node
= nsig
else node
= self
1121 modelbuilder
.error
(node
, "Redef Error: {mysignature.arity} parameters found, {msignature.arity} expected. Signature is {mpropdef}{msignature}")
1124 var precursor_ret_type
= msignature
.return_mtype
1125 var ret_type
= mysignature
.return_mtype
1126 if ret_type
!= null and precursor_ret_type
== null then
1127 modelbuilder
.error
(nsig
.n_type
.as(not null), "Redef Error: {mpropdef.mproperty} is a procedure, not a function.")
1131 if mysignature
.arity
> 0 then
1132 # Check parameters types
1133 for i
in [0..mysignature
.arity
[ do
1134 var myt
= mysignature
.parameter_mtypes
[i
]
1135 var prt
= msignature
.parameter_mtypes
[i
]
1136 if not myt
.is_subtype
(mmodule
, nclassdef
.mclassdef
.bound_mtype
, prt
) and
1137 not prt
.is_subtype
(mmodule
, nclassdef
.mclassdef
.bound_mtype
, myt
) then
1138 modelbuilder
.error
(nsig
.n_params
[i
], "Redef Error: Wrong type for parameter `{mysignature.parameter_names[i]}'. found {myt}, expected {prt}.")
1142 if precursor_ret_type
!= null then
1143 if ret_type
== null then
1144 # Inherit the return type
1145 ret_type
= precursor_ret_type
1146 else if not ret_type
.is_subtype
(mmodule
, nclassdef
.mclassdef
.bound_mtype
, precursor_ret_type
) then
1147 modelbuilder
.error
(nsig
.n_type
.as(not null), "Redef Error: Wrong return type. found {ret_type}, expected {precursor_ret_type}.")
1154 redef class AAttrPropdef
1155 # The associated MAttributeDef once build by a `ModelBuilder'
1156 var mpropdef
: nullable MAttributeDef
1157 # The associated getter (read accessor) if any
1158 var mreadpropdef
: nullable MMethodDef
1159 # The associated setter (write accessor) if any
1160 var mwritepropdef
: nullable MMethodDef
1161 redef fun build_property
(modelbuilder
, nclassdef
)
1163 var mclassdef
= nclassdef
.mclassdef
.as(not null)
1164 var mclass
= mclassdef
.mclass
1167 if self.n_id
!= null then
1168 name
= self.n_id
.text
1170 name
= self.n_id2
.text
1173 if mclass
.kind
== interface_kind
or mclassdef
.mclass
.kind
== enum_kind
then
1174 modelbuilder
.error
(self, "Error: Attempt to define attribute {name} in the interface {mclass}.")
1175 else if mclass
.kind
== enum_kind
then
1176 modelbuilder
.error
(self, "Error: Attempt to define attribute {name} in the enum class {mclass}.")
1181 # Old attribute style
1182 var mprop
= modelbuilder
.try_get_mproperty_by_name
(nid
, mclassdef
, name
)
1183 if mprop
== null then
1184 var mvisibility
= new_property_visibility
(modelbuilder
, nclassdef
, self.n_visibility
)
1185 mprop
= new MAttribute(mclassdef
, name
, mvisibility
)
1186 self.check_redef_keyword
(modelbuilder
, nclassdef
, self.n_kwredef
, false, mprop
)
1188 assert mprop
isa MAttribute
1189 check_redef_property_visibility
(modelbuilder
, nclassdef
, self.n_visibility
, mprop
)
1190 self.check_redef_keyword
(modelbuilder
, nclassdef
, self.n_kwredef
, true, mprop
)
1192 var mpropdef
= new MAttributeDef(mclassdef
, mprop
, self.location
)
1193 self.mpropdef
= mpropdef
1194 modelbuilder
.mpropdef2npropdef
[mpropdef
] = self
1196 var nreadable
= self.n_readable
1197 if nreadable
!= null then
1198 var readname
= name
.substring_from
(1)
1199 var mreadprop
= modelbuilder
.try_get_mproperty_by_name
(nid
, mclassdef
, readname
).as(nullable MMethod)
1200 if mreadprop
== null then
1201 var mvisibility
= new_property_visibility
(modelbuilder
, nclassdef
, nreadable
.n_visibility
)
1202 mreadprop
= new MMethod(mclassdef
, readname
, mvisibility
)
1203 self.check_redef_keyword
(modelbuilder
, nclassdef
, nreadable
.n_kwredef
, false, mreadprop
)
1205 self.check_redef_keyword
(modelbuilder
, nclassdef
, nreadable
.n_kwredef
, true, mreadprop
)
1206 check_redef_property_visibility
(modelbuilder
, nclassdef
, nreadable
.n_visibility
, mreadprop
)
1208 var mreadpropdef
= new MMethodDef(mclassdef
, mreadprop
, self.location
)
1209 self.mreadpropdef
= mreadpropdef
1210 modelbuilder
.mpropdef2npropdef
[mreadpropdef
] = self
1213 var nwritable
= self.n_writable
1214 if nwritable
!= null then
1215 var writename
= name
.substring_from
(1) + "="
1216 var mwriteprop
= modelbuilder
.try_get_mproperty_by_name
(nid
, mclassdef
, writename
).as(nullable MMethod)
1217 if mwriteprop
== null then
1218 var mvisibility
= new_property_visibility
(modelbuilder
, nclassdef
, nwritable
.n_visibility
)
1219 mwriteprop
= new MMethod(mclassdef
, writename
, mvisibility
)
1220 self.check_redef_keyword
(modelbuilder
, nclassdef
, nwritable
.n_kwredef
, false, mwriteprop
)
1222 self.check_redef_keyword
(modelbuilder
, nclassdef
, nwritable
.n_kwredef
, true, mwriteprop
)
1223 check_redef_property_visibility
(modelbuilder
, nclassdef
, nwritable
.n_visibility
, mwriteprop
)
1225 var mwritepropdef
= new MMethodDef(mclassdef
, mwriteprop
, self.location
)
1226 self.mwritepropdef
= mwritepropdef
1227 modelbuilder
.mpropdef2npropdef
[mwritepropdef
] = self
1230 # New attribute style
1231 var nid2
= self.n_id2
.as(not null)
1232 var mprop
= new MAttribute(mclassdef
, "@" + name
, none_visibility
)
1233 var mpropdef
= new MAttributeDef(mclassdef
, mprop
, self.location
)
1234 self.mpropdef
= mpropdef
1235 modelbuilder
.mpropdef2npropdef
[mpropdef
] = self
1238 var mreadprop
= modelbuilder
.try_get_mproperty_by_name
(nid2
, mclassdef
, readname
).as(nullable MMethod)
1239 if mreadprop
== null then
1240 var mvisibility
= new_property_visibility
(modelbuilder
, nclassdef
, self.n_visibility
)
1241 mreadprop
= new MMethod(mclassdef
, readname
, mvisibility
)
1242 self.check_redef_keyword
(modelbuilder
, nclassdef
, n_kwredef
, false, mreadprop
)
1244 self.check_redef_keyword
(modelbuilder
, nclassdef
, n_kwredef
, true, mreadprop
)
1245 check_redef_property_visibility
(modelbuilder
, nclassdef
, self.n_visibility
, mreadprop
)
1247 var mreadpropdef
= new MMethodDef(mclassdef
, mreadprop
, self.location
)
1248 self.mreadpropdef
= mreadpropdef
1249 modelbuilder
.mpropdef2npropdef
[mreadpropdef
] = self
1251 var writename
= name
+ "="
1252 var nwritable
= self.n_writable
1253 var mwriteprop
= modelbuilder
.try_get_mproperty_by_name
(nid2
, mclassdef
, writename
).as(nullable MMethod)
1254 var nwkwredef
: nullable Token = null
1255 if nwritable
!= null then nwkwredef
= nwritable
.n_kwredef
1256 if mwriteprop
== null then
1258 if nwritable
!= null then
1259 mvisibility
= new_property_visibility
(modelbuilder
, nclassdef
, nwritable
.n_visibility
)
1261 mvisibility
= private_visibility
1263 mwriteprop
= new MMethod(mclassdef
, writename
, mvisibility
)
1264 self.check_redef_keyword
(modelbuilder
, nclassdef
, nwkwredef
, false, mwriteprop
)
1266 self.check_redef_keyword
(modelbuilder
, nclassdef
, nwkwredef
, true, mwriteprop
)
1267 if nwritable
!= null then
1268 check_redef_property_visibility
(modelbuilder
, nclassdef
, nwritable
.n_visibility
, mwriteprop
)
1271 var mwritepropdef
= new MMethodDef(mclassdef
, mwriteprop
, self.location
)
1272 self.mwritepropdef
= mwritepropdef
1273 modelbuilder
.mpropdef2npropdef
[mwritepropdef
] = self
1277 redef fun build_signature
(modelbuilder
, nclassdef
)
1279 var mpropdef
= self.mpropdef
1280 if mpropdef
== null then return # Error thus skiped
1281 var mmodule
= mpropdef
.mclassdef
.mmodule
1282 var mtype
: nullable MType = null
1284 var ntype
= self.n_type
1285 if ntype
!= null then
1286 mtype
= modelbuilder
.resolve_mtype
(nclassdef
, ntype
)
1287 if mtype
== null then return
1290 if mtype
== null then
1291 modelbuilder
.warning
(self, "Error: Untyped attribute {mpropdef}")
1295 mpropdef
.static_mtype
= mtype
1297 var mreadpropdef
= self.mreadpropdef
1298 if mreadpropdef
!= null then
1299 var msignature
= new MSignature(new Array[String], new Array[MType], mtype
, -1)
1300 mreadpropdef
.msignature
= msignature
1303 var msritepropdef
= self.mwritepropdef
1304 if mwritepropdef
!= null then
1306 if n_id
!= null then
1307 name
= n_id
.text
.substring_from
(1)
1311 var msignature
= new MSignature([name
], [mtype
], null, -1)
1312 mwritepropdef
.msignature
= msignature
1316 redef fun check_signature
(modelbuilder
, nclassdef
)
1318 var mpropdef
= self.mpropdef
1319 if mpropdef
== null then return # Error thus skiped
1320 var mmodule
= mpropdef
.mclassdef
.mmodule
1321 var ntype
= self.n_type
1322 var mtype
= self.mpropdef
.static_mtype
1323 if mtype
== null then return # Error thus skiped
1325 # Lookup for signature in the precursor
1326 # FIXME all precursors should be considered
1327 if not mpropdef
.is_intro
then
1328 var precursor_type
= mpropdef
.mproperty
.intro
.static_mtype
1329 if precursor_type
== null then return
1331 if mtype
!= precursor_type
then
1332 modelbuilder
.error
(ntype
.as(not null), "Redef Error: Wrong static type. found {mtype}, expected {precursor_type}.")
1337 # FIXME: Check getter ans setter
1341 redef class ATypePropdef
1342 # The associated MVirtualTypeDef once build by a `ModelBuilder'
1343 var mpropdef
: nullable MVirtualTypeDef
1344 redef fun build_property
(modelbuilder
, nclassdef
)
1346 var mclassdef
= nclassdef
.mclassdef
.as(not null)
1347 var name
= self.n_id
.text
1348 var mprop
= modelbuilder
.try_get_mproperty_by_name
(self.n_id
, mclassdef
, name
)
1349 if mprop
== null then
1350 var mvisibility
= new_property_visibility
(modelbuilder
, nclassdef
, self.n_visibility
)
1351 mprop
= new MVirtualTypeProp(mclassdef
, name
, mvisibility
)
1352 self.check_redef_keyword
(modelbuilder
, nclassdef
, self.n_kwredef
, false, mprop
)
1354 self.check_redef_keyword
(modelbuilder
, nclassdef
, self.n_kwredef
, true, mprop
)
1355 assert mprop
isa MVirtualTypeProp
1356 check_redef_property_visibility
(modelbuilder
, nclassdef
, self.n_visibility
, mprop
)
1358 var mpropdef
= new MVirtualTypeDef(mclassdef
, mprop
, self.location
)
1359 self.mpropdef
= mpropdef
1362 redef fun build_signature
(modelbuilder
, nclassdef
)
1364 var mpropdef
= self.mpropdef
1365 if mpropdef
== null then return # Error thus skiped
1366 var mmodule
= mpropdef
.mclassdef
.mmodule
1367 var mtype
: nullable MType = null
1369 var ntype
= self.n_type
1370 mtype
= modelbuilder
.resolve_mtype
(nclassdef
, ntype
)
1371 if mtype
== null then return
1373 mpropdef
.bound
= mtype
1374 # print "{mpropdef}: {mtype}"
1377 redef fun check_signature
(modelbuilder
, nclassdef
)
1379 var bound
= self.mpropdef
.bound
1381 # Fast case: the bound is not a formal type
1382 if not bound
isa MVirtualType then return
1384 var mmodule
= nclassdef
.mclassdef
.mmodule
1385 var anchor
= nclassdef
.mclassdef
.bound_mtype
1387 # Slow case: progress on each resolution until: (i) we loop, or (ii) we found a non formal type
1388 var seen
= [self.mpropdef
.mproperty
.mvirtualtype
]
1390 if seen
.has
(bound
) then
1392 modelbuilder
.error
(self, "Error: circularity of virtual type definition: {seen.join(" -> ")}")
1396 var next
= bound
.lookup_bound
(mmodule
, anchor
)
1397 if not next
isa MVirtualType then return