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
= "NIT_PATH".environ
71 if not path_env
.is_empty
then
72 paths
.append
(path_env
.split_with
(':'))
75 path_env
= "NIT_DIR".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 tries
= new Array[String]
225 var lastmodule
= mmodule
226 while mmodule
!= null do
227 var dirname
= mmodule
.location
.file
.filename
.dirname
229 # Determine the owner
230 var owner
: nullable MModule
231 if dirname
.basename
("") != mmodule
.name
then
232 owner
= mmodule
.direct_owner
237 # First, try the already known nested modules
238 if modules
!= null then
239 for candidate
in modules
do
240 if candidate
.direct_owner
== owner
then
246 # Second, try the directory to find a file
247 var try_file
= dirname
+ "/" + name
+ ".nit"
249 if try_file
.file_exists
then
250 var res
= self.load_module
(owner
, try_file
.simplify_path
)
251 if res
== null then return null # Forward error
252 return res
.mmodule
.as(not null)
255 # Third, try if the requested module is itself an owner
256 try_file
= dirname
+ "/" + name
+ "/" + name
+ ".nit"
257 if try_file
.file_exists
then
258 var res
= self.load_module
(owner
, try_file
.simplify_path
)
259 if res
== null then return null # Forward error
260 return res
.mmodule
.as(not null)
264 mmodule
= mmodule
.direct_owner
267 if modules
!= null then
268 for candidate
in modules
do
269 if candidate
.direct_owner
== null then
275 # Look at some known directories
276 var lookpaths
= self.paths
278 # Look in the directory of the last module also (event if not in the path)
279 if lastmodule
!= null then
280 var dirname
= lastmodule
.location
.file
.filename
.dirname
281 if dirname
.basename
("") == lastmodule
.name
then
282 dirname
= dirname
.dirname
284 if not lookpaths
.has
(dirname
) then
285 lookpaths
= lookpaths
.to_a
286 lookpaths
.add
(dirname
)
290 var candidate
: nullable String = null
291 for dirname
in lookpaths
do
292 var try_file
= (dirname
+ "/" + name
+ ".nit").simplify_path
294 if try_file
.file_exists
then
295 if candidate
== null then
297 else if candidate
!= try_file
then
298 error
(anode
, "Error: conflicting module file for {name}: {candidate} {try_file}")
301 try_file
= (dirname
+ "/" + name
+ "/" + name
+ ".nit").simplify_path
302 if try_file
.file_exists
then
303 if candidate
== null then
305 else if candidate
!= try_file
then
306 error
(anode
, "Error: conflicting module file for {name}: {candidate} {try_file}")
310 if candidate
== null then
311 if origmmodule
!= null then
312 error
(anode
, "Error: cannot find module {name} from {origmmodule}. tried {tries.join(", ")}")
314 error
(anode
, "Error: cannot find module {name}. tried {tries.join(", ")}")
318 var res
= self.load_module
(mmodule
, candidate
)
319 if res
== null then return null # Forward error
320 return res
.mmodule
.as(not null)
323 # Try to load a module using a path.
324 # Display an error if there is a problem (IO / lexer / parser) and return null
325 # Note: usually, you do not need this method, use `get_mmodule_by_name` instead.
326 fun load_module
(owner
: nullable MModule, filename
: String): nullable AModule
328 if not filename
.file_exists
then
329 self.toolcontext
.error
(null, "Error: file {filename} not found.")
333 var x
= if owner
!= null then owner
.to_s
else "."
334 self.toolcontext
.info
("load module {filename} in {x}", 2)
337 var file
= new IFStream.open
(filename
)
338 var lexer
= new Lexer(new SourceFile(filename
, file
))
339 var parser
= new Parser(lexer
)
340 var tree
= parser
.parse
343 # Handle lexer and parser error
344 var nmodule
= tree
.n_base
345 if nmodule
== null then
346 var neof
= tree
.n_eof
347 assert neof
isa AError
348 error
(neof
, neof
.message
)
352 # Check the module name
353 var mod_name
= filename
.basename
(".nit")
354 var decl
= nmodule
.n_moduledecl
356 #warning(nmodule, "Warning: Missing 'module' keyword") #FIXME: NOT YET FOR COMPATIBILITY
358 var decl_name
= decl
.n_name
.n_id
.text
359 if decl_name
!= mod_name
then
360 error
(decl
.n_name
, "Error: module name missmatch; declared {decl_name} file named {mod_name}")
365 var mmodule
= new MModule(model
, owner
, mod_name
, nmodule
.location
)
366 nmodule
.mmodule
= mmodule
367 nmodules
.add
(nmodule
)
368 self.mmodule2nmodule
[mmodule
] = nmodule
370 build_module_importation
(nmodule
)
375 # Analysis the module importation and fill the module_importation_hierarchy
376 private fun build_module_importation
(nmodule
: AModule)
378 if nmodule
.is_importation_done
then return
379 var mmodule
= nmodule
.mmodule
.as(not null)
381 var imported_modules
= new Array[MModule]
382 for aimport
in nmodule
.n_imports
do
384 if not aimport
isa AStdImport then
387 var mod_name
= aimport
.n_name
.n_id
.text
388 var sup
= self.get_mmodule_by_name
(aimport
.n_name
, mmodule
, mod_name
)
389 if sup
== null then continue # Skip error
390 imported_modules
.add
(sup
)
391 var mvisibility
= aimport
.n_visibility
.mvisibility
392 mmodule
.set_visibility_for
(sup
, mvisibility
)
395 var mod_name
= "standard"
396 var sup
= self.get_mmodule_by_name
(nmodule
, null, mod_name
)
397 if sup
!= null then # Skip error
398 imported_modules
.add
(sup
)
399 mmodule
.set_visibility_for
(sup
, public_visibility
)
402 self.toolcontext
.info
("{mmodule} imports {imported_modules.join(", ")}", 3)
403 mmodule
.set_imported_mmodules
(imported_modules
)
404 nmodule
.is_importation_done
= true
407 # All the loaded modules
408 var nmodules
: Array[AModule] = new Array[AModule]
410 # Build the classes of all modules `nmodules'.
411 private fun build_all_classes
413 for nmodule
in self.nmodules
do
414 build_classes
(nmodule
)
418 # Visit the AST and create the MClass objects
419 private fun build_a_mclass
(nmodule
: AModule, nclassdef
: AClassdef)
421 var mmodule
= nmodule
.mmodule
.as(not null)
424 var nkind
: nullable AClasskind
425 var mkind
: MClassKind
426 var nvisibility
: nullable AVisibility
427 var mvisibility
: nullable MVisibility
429 if nclassdef
isa AStdClassdef then
430 name
= nclassdef
.n_id
.text
431 nkind
= nclassdef
.n_classkind
433 nvisibility
= nclassdef
.n_visibility
434 mvisibility
= nvisibility
.mvisibility
435 arity
= nclassdef
.n_formaldefs
.length
436 else if nclassdef
isa ATopClassdef then
439 mkind
= interface_kind
441 mvisibility
= public_visibility
442 else if nclassdef
isa AMainClassdef then
445 mkind
= concrete_kind
447 mvisibility
= public_visibility
452 var mclass
= try_get_mclass_by_name
(nclassdef
, mmodule
, name
)
453 if mclass
== null then
454 mclass
= new MClass(mmodule
, name
, arity
, mkind
, mvisibility
)
455 #print "new class {mclass}"
456 else if nclassdef
isa AStdClassdef and nclassdef
.n_kwredef
== null then
457 error
(nclassdef
, "Redef error: {name} is an imported class. Add the redef keyword to refine it.")
459 else if mclass
.arity
!= arity
then
460 error
(nclassdef
, "Redef error: Formal parameter arity missmatch; got {arity}, expected {mclass.arity}.")
462 else if nkind
!= null and mkind
!= concrete_kind
and mclass
.kind
!= mkind
then
463 error
(nkind
, "Error: refinement changed the kind from a {mclass.kind} to a {mkind}")
464 else if nvisibility
!= null and mvisibility
!= public_visibility
and mclass
.visibility
!= mvisibility
then
465 error
(nvisibility
, "Error: refinement changed the visibility from a {mclass.visibility} to a {mvisibility}")
467 nclassdef
.mclass
= mclass
470 # Visit the AST and create the MClassDef objects
471 private fun build_a_mclassdef
(nmodule
: AModule, nclassdef
: AClassdef)
473 var mmodule
= nmodule
.mmodule
.as(not null)
474 var objectclass
= try_get_mclass_by_name
(nmodule
, mmodule
, "Object")
475 var mclass
= nclassdef
.mclass
.as(not null)
476 #var mclassdef = nclassdef.mclassdef.as(not null)
478 var names
= new Array[String]
479 var bounds
= new Array[MType]
480 if nclassdef
isa AStdClassdef and mclass
.arity
> 0 then
481 # Collect formal parameter names
482 for i
in [0..mclass
.arity
[ do
483 var nfd
= nclassdef
.n_formaldefs
[i
]
484 var ptname
= nfd
.n_id
.text
485 if names
.has
(ptname
) then
486 error
(nfd
, "Error: A formal parameter type `{ptname}' already exists")
492 # Revolve bound for formal parameter names
493 for i
in [0..mclass
.arity
[ do
494 var nfd
= nclassdef
.n_formaldefs
[i
]
495 var nfdt
= nfd
.n_type
497 var bound
= resolve_mtype
(nclassdef
, nfdt
)
498 if bound
== null then return # Forward error
499 if bound
.need_anchor
then
501 error
(nfd
, "Error: Formal parameter type `{names[i]}' bounded with a formal parameter type")
505 else if mclass
.mclassdefs
.is_empty
then
506 # No bound, then implicitely bound by nullable Object
507 bounds
.add
(objectclass
.mclass_type
.as_nullable
)
510 bounds
.add
(mclass
.mclassdefs
.first
.bound_mtype
.as(MGenericType).arguments
[i
])
515 var bound_mtype
= mclass
.get_mtype
(bounds
)
516 var mclassdef
= new MClassDef(mmodule
, bound_mtype
, nclassdef
.location
, names
)
517 nclassdef
.mclassdef
= mclassdef
518 self.mclassdef2nclassdef
[mclassdef
] = nclassdef
520 if mclassdef
.is_intro
then
521 self.toolcontext
.info
("{mclassdef} introduces new {mclass.kind} {mclass.full_name}", 3)
523 self.toolcontext
.info
("{mclassdef} refine {mclass.kind} {mclass.full_name}", 3)
527 # Visit the AST and set the super-types of the MClass objects (ie compute the inheritance)
528 private fun build_a_mclassdef_inheritance
(nmodule
: AModule, nclassdef
: AClassdef)
530 var mmodule
= nmodule
.mmodule
.as(not null)
531 var objectclass
= try_get_mclass_by_name
(nmodule
, mmodule
, "Object")
532 var mclass
= nclassdef
.mclass
.as(not null)
533 var mclassdef
= nclassdef
.mclassdef
.as(not null)
535 var specobject
= true
536 var supertypes
= new Array[MClassType]
537 if nclassdef
isa AStdClassdef then
538 for nsc
in nclassdef
.n_superclasses
do
540 var ntype
= nsc
.n_type
541 var mtype
= resolve_mtype
(nclassdef
, ntype
)
542 if mtype
== null then continue # Skip because of error
543 if not mtype
isa MClassType then
544 error
(ntype
, "Error: supertypes cannot be a formal type")
548 #print "new super : {mclass} < {mtype}"
551 if specobject
and mclass
.name
!= "Object" and objectclass
!= null and mclassdef
.is_intro
then
552 supertypes
.add objectclass
.mclass_type
555 mclassdef
.set_supertypes
(supertypes
)
556 if not supertypes
.is_empty
then self.toolcontext
.info
("{mclassdef} new super-types: {supertypes.join(", ")}", 3)
559 # Check the validity of the specialization heirarchy
560 # FIXME Stub implementation
561 private fun check_supertypes
(nmodule
: AModule, nclassdef
: AClassdef)
563 var mmodule
= nmodule
.mmodule
.as(not null)
564 var objectclass
= try_get_mclass_by_name
(nmodule
, mmodule
, "Object")
565 var mclass
= nclassdef
.mclass
.as(not null)
566 var mclassdef
= nclassdef
.mclassdef
.as(not null)
569 # Build the classes of the module `nmodule'.
570 # REQUIRE: classes of imported modules are already build. (let `build_all_classes' do the job)
571 private fun build_classes
(nmodule
: AModule)
573 # Force building recursively
574 if nmodule
.build_classes_is_done
then return
575 var mmodule
= nmodule
.mmodule
.as(not null)
576 for imp
in mmodule
.in_importation
.direct_greaters
do
577 build_classes
(mmodule2nmodule
[imp
])
581 for nclassdef
in nmodule
.n_classdefs
do
582 self.build_a_mclass
(nmodule
, nclassdef
)
585 # Create all classdefs
586 for nclassdef
in nmodule
.n_classdefs
do
587 self.build_a_mclassdef
(nmodule
, nclassdef
)
590 # Create inheritance on all classdefs
591 for nclassdef
in nmodule
.n_classdefs
do
592 self.build_a_mclassdef_inheritance
(nmodule
, nclassdef
)
595 # TODO: Check that the super-class is not intrusive
597 # TODO: Check that the super-class is not already known (by transitivity)
599 for nclassdef
in nmodule
.n_classdefs
do
600 self.build_properties
(nclassdef
)
603 nmodule
.build_classes_is_done
= true
606 # Register the nmodule associated to each mmodule
607 # FIXME: why not refine the MModule class with a nullable attribute?
608 var mmodule2nmodule
: HashMap[MModule, AModule] = new HashMap[MModule, AModule]
609 # Register the nclassdef associated to each mclassdef
610 # FIXME: why not refine the MClassDef class with a nullable attribute?
611 var mclassdef2nclassdef
: HashMap[MClassDef, AClassdef] = new HashMap[MClassDef, AClassdef]
612 # Register the npropdef associated to each mpropdef
613 # FIXME: why not refine the MPropDef class with a nullable attribute?
614 var mpropdef2npropdef
: HashMap[MPropDef, APropdef] = new HashMap[MPropDef, APropdef]
616 # Build the properties of `nclassdef'.
617 # REQUIRE: all superclasses are built.
618 private fun build_properties
(nclassdef
: AClassdef)
620 # Force building recursively
621 if nclassdef
.build_properties_is_done
then return
622 var mclassdef
= nclassdef
.mclassdef
.as(not null)
623 if mclassdef
.in_hierarchy
== null then return # Skip error
624 for superclassdef
in mclassdef
.in_hierarchy
.direct_greaters
do
625 build_properties
(mclassdef2nclassdef
[superclassdef
])
628 for npropdef
in nclassdef
.n_propdefs
do
629 npropdef
.build_property
(self, nclassdef
)
631 for npropdef
in nclassdef
.n_propdefs
do
632 npropdef
.build_signature
(self, nclassdef
)
634 for npropdef
in nclassdef
.n_propdefs
do
635 npropdef
.check_signature
(self, nclassdef
)
637 process_default_constructors
(nclassdef
)
638 nclassdef
.build_properties_is_done
= true
641 # Introduce or inherit default constructor
642 # This is the last part of `build_properties'.
643 private fun process_default_constructors
(nclassdef
: AClassdef)
645 var mclassdef
= nclassdef
.mclassdef
.as(not null)
647 # Are we a refinement
648 if not mclassdef
.is_intro
then return
650 # Is the class forbid constructors?
651 if not mclassdef
.mclass
.kind
.need_init
then return
653 # Is there already a constructor defined?
654 for mpropdef
in mclassdef
.mpropdefs
do
655 if not mpropdef
isa MMethodDef then continue
656 if mpropdef
.mproperty
.is_init
then return
659 if not nclassdef
isa AStdClassdef then return
661 var mmodule
= nclassdef
.mclassdef
.mmodule
662 # Do we inherit for a constructor?
663 var combine
= new Array[MMethod]
664 var inhc
: nullable MClass = null
665 for st
in mclassdef
.supertypes
do
667 if not c
.kind
.need_init
then continue
668 st
= st
.anchor_to
(mmodule
, nclassdef
.mclassdef
.bound_mtype
)
669 var candidate
= self.try_get_mproperty_by_name2
(nclassdef
, mmodule
, st
, "init").as(nullable MMethod)
670 if candidate
!= null and candidate
.intro
.msignature
.arity
== 0 then
671 combine
.add
(candidate
)
674 var inhc2
= c
.inherit_init_from
675 if inhc2
== null then inhc2
= c
676 if inhc2
== inhc
then continue
678 self.error
(nclassdef
, "Cannot provide a defaut constructor: conflict for {inhc} and {c}")
683 if combine
.is_empty
and inhc
!= null then
684 # TODO: actively inherit the consturctor
685 self.toolcontext
.info
("{mclassdef} inherits all constructors from {inhc}", 3)
686 mclassdef
.mclass
.inherit_init_from
= inhc
689 if not combine
.is_empty
and inhc
!= null then
690 self.error
(nclassdef
, "Cannot provide a defaut constructor: conflict for {combine.join(", ")} and {inhc}")
694 if not combine
.is_empty
then
695 nclassdef
.super_inits
= combine
696 var mprop
= new MMethod(mclassdef
, "init", mclassdef
.mclass
.visibility
)
697 var mpropdef
= new MMethodDef(mclassdef
, mprop
, nclassdef
.location
)
698 var param_names
= new Array[String]
699 var param_types
= new Array[MType]
700 var msignature
= new MSignature(param_names
, param_types
, null, -1)
701 mpropdef
.msignature
= msignature
703 nclassdef
.mfree_init
= mpropdef
704 self.toolcontext
.info
("{mclassdef} gets a free empty constructor {mpropdef}{msignature}", 3)
708 # Collect undefined attributes
709 var param_names
= new Array[String]
710 var param_types
= new Array[MType]
711 for npropdef
in nclassdef
.n_propdefs
do
712 if npropdef
isa AAttrPropdef and npropdef
.n_expr
== null then
713 param_names
.add
(npropdef
.mpropdef
.mproperty
.name
.substring_from
(1))
714 var ret_type
= npropdef
.mpropdef
.static_mtype
715 if ret_type
== null then return
716 param_types
.add
(ret_type
)
720 var mprop
= new MMethod(mclassdef
, "init", mclassdef
.mclass
.visibility
)
721 var mpropdef
= new MMethodDef(mclassdef
, mprop
, nclassdef
.location
)
722 var msignature
= new MSignature(param_names
, param_types
, null, -1)
723 mpropdef
.msignature
= msignature
725 nclassdef
.mfree_init
= mpropdef
726 self.toolcontext
.info
("{mclassdef} gets a free constructor for attributes {mpropdef}{msignature}", 3)
729 # Return the static type associated to the node `ntype'.
730 # `classdef' is the context where the call is made (used to understand formal types)
731 # The mmodule used as context is `nclassdef.mmodule'
732 # In case of problem, an error is displayed on `ntype' and null is returned.
733 # FIXME: the name "resolve_mtype" is awful
734 fun resolve_mtype
(nclassdef
: AClassdef, ntype
: AType): nullable MType
736 var name
= ntype
.n_id
.text
737 var mclassdef
= nclassdef
.mclassdef
738 var mmodule
= nclassdef
.parent
.as(AModule).mmodule
.as(not null)
742 if mclassdef
!= null then
743 var prop
= try_get_mproperty_by_name
(ntype
, mclassdef
, name
).as(nullable MVirtualTypeProp)
745 if not ntype
.n_types
.is_empty
then
746 error
(ntype
, "Type error: formal type {name} cannot have formal parameters.")
748 res
= prop
.mvirtualtype
749 if ntype
.n_kwnullable
!= null then res
= res
.as_nullable
754 # Check parameter type
755 if mclassdef
!= null and mclassdef
.parameter_names
.has
(name
) then
756 if not ntype
.n_types
.is_empty
then
757 error
(ntype
, "Type error: formal type {name} cannot have formal parameters.")
759 for i
in [0..mclassdef
.parameter_names
.length
[ do
760 if mclassdef
.parameter_names
[i
] == name
then
761 res
= mclassdef
.mclass
.mclass_type
.as(MGenericType).arguments
[i
]
762 if ntype
.n_kwnullable
!= null then res
= res
.as_nullable
770 var mclass
= try_get_mclass_by_name
(ntype
, mmodule
, name
)
771 if mclass
!= null then
772 var arity
= ntype
.n_types
.length
773 if arity
!= mclass
.arity
then
775 error
(ntype
, "Type error: '{name}' is a generic class.")
776 else if mclass
.arity
== 0 then
777 error
(ntype
, "Type error: '{name}' is not a generic class.")
779 error
(ntype
, "Type error: '{name}' has {mclass.arity} parameters ({arity} are provided).")
784 res
= mclass
.mclass_type
785 if ntype
.n_kwnullable
!= null then res
= res
.as_nullable
788 var mtypes
= new Array[MType]
789 for nt
in ntype
.n_types
do
790 var mt
= resolve_mtype
(nclassdef
, nt
)
791 if mt
== null then return null # Forward error
794 res
= mclass
.get_mtype
(mtypes
)
795 if ntype
.n_kwnullable
!= null then res
= res
.as_nullable
800 # If everything fail, then give up :(
801 error
(ntype
, "Type error: class {name} not found in module {mmodule}.")
805 # Helper function to display an error on a node.
806 # Alias for `self.toolcontext.error(n.hot_location, text)'
807 fun error
(n
: ANode, text
: String)
809 self.toolcontext
.error
(n
.hot_location
, text
)
812 # Helper function to display a warning on a node.
813 # Alias for: `self.toolcontext.warning(n.hot_location, text)'
814 fun warning
(n
: ANode, text
: String)
816 self.toolcontext
.warning
(n
.hot_location
, text
)
821 # The associated MModule once build by a `ModelBuilder'
822 var mmodule
: nullable MModule
823 # Flag that indicate if the importation is already completed
824 var is_importation_done
: Bool = false
825 # Flag that indicate if the class and prop building is already completed
826 var build_classes_is_done
: Bool = false
830 # The class whose self inherit all the constructors.
831 # 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
832 var inherit_init_from
: nullable MClass = null
835 redef class AClassdef
836 # The associated MClass once build by a `ModelBuilder'
837 var mclass
: nullable MClass
838 # The associated MClassDef once build by a `ModelBuilder'
839 var mclassdef
: nullable MClassDef
840 var build_properties_is_done
: Bool = false
841 # The list of super-constructor to call at the start of the free constructor
842 # 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
843 var super_inits
: nullable Collection[MMethod] = null
845 # The free init (implicitely constructed by the class if required)
846 var mfree_init
: nullable MMethodDef = null
849 redef class AClasskind
850 # The class kind associated with the AST node class
851 private fun mkind
: MClassKind is abstract
853 redef class AConcreteClasskind
854 redef fun mkind
do return concrete_kind
856 redef class AAbstractClasskind
857 redef fun mkind
do return abstract_kind
859 redef class AInterfaceClasskind
860 redef fun mkind
do return interface_kind
862 redef class AEnumClasskind
863 redef fun mkind
do return enum_kind
865 redef class AExternClasskind
866 redef fun mkind
do return extern_kind
869 redef class AVisibility
870 # The visibility level associated with the AST node class
871 private fun mvisibility
: MVisibility is abstract
873 redef class AIntrudeVisibility
874 redef fun mvisibility
do return intrude_visibility
876 redef class APublicVisibility
877 redef fun mvisibility
do return public_visibility
879 redef class AProtectedVisibility
880 redef fun mvisibility
do return protected_visibility
882 redef class APrivateVisibility
883 redef fun mvisibility
do return private_visibility
890 # Join the text of all tokens
891 # Used to get the 'real name' of method definitions.
892 fun collect_text
: String
894 var v
= new TextCollectorVisitor
901 private class TextCollectorVisitor
903 var text
: String = ""
906 if n
isa Token then text
+= n
.text
912 private fun build_property
(modelbuilder
: ModelBuilder, nclassdef
: AClassdef)
915 private fun build_signature
(modelbuilder
: ModelBuilder, nclassdef
: AClassdef)
918 private fun check_signature
(modelbuilder
: ModelBuilder, nclassdef
: AClassdef)
921 private fun new_property_visibility
(modelbuilder
: ModelBuilder, nclassdef
: AClassdef, nvisibility
: nullable AVisibility): MVisibility
923 var mvisibility
= public_visibility
924 if nvisibility
!= null then mvisibility
= nvisibility
.mvisibility
925 if nclassdef
.mclassdef
.mclass
.visibility
== private_visibility
then
926 if mvisibility
== protected_visibility
then
927 assert nvisibility
!= null
928 modelbuilder
.error
(nvisibility
, "Error: The only legal visibility for properties in a private class is private.")
929 else if mvisibility
== private_visibility
then
930 assert nvisibility
!= null
932 # modelbuilder.warning(nvisibility, "Warning: private is unrequired since the only legal visibility for properties in a private class is private.")
934 mvisibility
= private_visibility
939 private fun check_redef_property_visibility
(modelbuilder
: ModelBuilder, nclassdef
: AClassdef, nvisibility
: nullable AVisibility, mprop
: MProperty)
941 if nvisibility
== null then return
942 var mvisibility
= nvisibility
.mvisibility
943 if mvisibility
!= mprop
.visibility
and mvisibility
!= public_visibility
then
944 modelbuilder
.error
(nvisibility
, "Error: redefinition changed the visibility from a {mprop.visibility} to a {mvisibility}")
948 private fun check_redef_keyword
(modelbuilder
: ModelBuilder, nclassdef
: AClassdef, kwredef
: nullable Token, need_redef
: Bool, mprop
: MProperty)
950 if kwredef
== null then
952 modelbuilder
.error
(self, "Redef error: {nclassdef.mclassdef.mclass}::{mprop.name} is an inherited property. To redefine it, add the redef keyword.")
955 if not need_redef
then
956 modelbuilder
.error
(self, "Error: No property {nclassdef.mclassdef.mclass}::{mprop.name} is inherited. Remove the redef keyword to define a new property.")
962 redef class AMethPropdef
963 # The associated MMethodDef once build by a `ModelBuilder'
964 var mpropdef
: nullable MMethodDef
966 # The associated super init if any
967 var super_init
: nullable MMethod
968 redef fun build_property
(modelbuilder
, nclassdef
)
970 var is_init
= self isa AInitPropdef
971 var mclassdef
= nclassdef
.mclassdef
.as(not null)
973 var amethodid
= self.n_methid
975 if amethodid
== null then
976 if self isa AMainMethPropdef then
979 else if self isa AConcreteInitPropdef then
981 name_node
= self.n_kwinit
982 else if self isa AExternInitPropdef then
984 name_node
= self.n_kwnew
988 else if amethodid
isa AIdMethid then
989 name
= amethodid
.n_id
.text
990 name_node
= amethodid
992 # operator, bracket or assign
993 name
= amethodid
.collect_text
994 name_node
= amethodid
996 if name
== "-" and self.n_signature
.n_params
.length
== 0 then
1001 var mprop
: nullable MMethod = null
1002 if not is_init
or n_kwredef
!= null then mprop
= modelbuilder
.try_get_mproperty_by_name
(name_node
, mclassdef
, name
).as(nullable MMethod)
1003 if mprop
== null then
1004 var mvisibility
= new_property_visibility
(modelbuilder
, nclassdef
, self.n_visibility
)
1005 mprop
= new MMethod(mclassdef
, name
, mvisibility
)
1006 mprop
.is_init
= is_init
1007 mprop
.is_new
= self isa AExternInitPropdef
1008 self.check_redef_keyword
(modelbuilder
, nclassdef
, n_kwredef
, false, mprop
)
1010 if n_kwredef
== null then
1011 if self isa AMainMethPropdef then
1014 self.check_redef_keyword
(modelbuilder
, nclassdef
, n_kwredef
, true, mprop
)
1017 check_redef_property_visibility
(modelbuilder
, nclassdef
, self.n_visibility
, mprop
)
1020 var mpropdef
= new MMethodDef(mclassdef
, mprop
, self.location
)
1022 self.mpropdef
= mpropdef
1023 modelbuilder
.mpropdef2npropdef
[mpropdef
] = self
1024 if mpropdef
.is_intro
then
1025 modelbuilder
.toolcontext
.info
("{mpropdef} introduces new method {mprop.full_name}", 3)
1027 modelbuilder
.toolcontext
.info
("{mpropdef} redefines method {mprop.full_name}", 3)
1031 redef fun build_signature
(modelbuilder
, nclassdef
)
1033 var mpropdef
= self.mpropdef
1034 if mpropdef
== null then return # Error thus skiped
1035 var mmodule
= mpropdef
.mclassdef
.mmodule
1036 var nsig
= self.n_signature
1038 # Retrieve info from the signature AST
1039 var param_names
= new Array[String] # Names of parameters from the AST
1040 var param_types
= new Array[MType] # Types of parameters from the AST
1041 var vararg_rank
= -1
1042 var ret_type
: nullable MType = null # Return type from the AST
1043 if nsig
!= null then
1044 for np
in nsig
.n_params
do
1045 param_names
.add
(np
.n_id
.text
)
1046 var ntype
= np
.n_type
1047 if ntype
!= null then
1048 var mtype
= modelbuilder
.resolve_mtype
(nclassdef
, ntype
)
1049 if mtype
== null then return # Skip error
1050 for i
in [0..param_names
.length-param_types
.length
[ do
1051 param_types
.add
(mtype
)
1053 if np
.n_dotdotdot
!= null then
1054 if vararg_rank
!= -1 then
1055 modelbuilder
.error
(np
, "Error: {param_names[vararg_rank]} is already a vararg")
1057 vararg_rank
= param_names
.length
- 1
1062 var ntype
= nsig
.n_type
1063 if ntype
!= null then
1064 ret_type
= modelbuilder
.resolve_mtype
(nclassdef
, ntype
)
1065 if ret_type
== null then return # Skip errir
1069 # Look for some signature to inherit
1070 # FIXME: do not inherit from the intro, but from the most specific
1071 var msignature
: nullable MSignature = null
1072 if not mpropdef
.is_intro
then
1073 msignature
= mpropdef
.mproperty
.intro
.msignature
1074 if msignature
== null then return # Skip error
1075 else if mpropdef
.mproperty
.is_init
then
1076 # FIXME UGLY: inherit signature from a super-constructor
1077 for msupertype
in nclassdef
.mclassdef
.supertypes
do
1078 msupertype
= msupertype
.anchor_to
(mmodule
, nclassdef
.mclassdef
.bound_mtype
)
1079 var candidate
= modelbuilder
.try_get_mproperty_by_name2
(self, mmodule
, msupertype
, mpropdef
.mproperty
.name
)
1080 if candidate
!= null then
1081 if msignature
== null then
1082 msignature
= candidate
.intro
.as(MMethodDef).msignature
1088 # Inherit the signature
1089 if msignature
!= null and param_names
.length
!= param_types
.length
and param_names
.length
== msignature
.arity
and param_types
.length
== 0 then
1090 # Parameters are untyped, thus inherit them
1091 param_types
= msignature
.parameter_mtypes
1092 vararg_rank
= msignature
.vararg_rank
1094 if msignature
!= null and ret_type
== null then
1095 ret_type
= msignature
.return_mtype
1098 if param_names
.length
!= param_types
.length
then
1099 # Some parameters are typed, other parameters are not typed.
1100 modelbuilder
.warning
(nsig
.n_params
[param_types
.length
], "Error: Untyped parameter `{param_names[param_types.length]}'.")
1104 msignature
= new MSignature(param_names
, param_types
, ret_type
, vararg_rank
)
1105 mpropdef
.msignature
= msignature
1108 redef fun check_signature
(modelbuilder
, nclassdef
)
1110 var mpropdef
= self.mpropdef
1111 if mpropdef
== null then return # Error thus skiped
1112 var mmodule
= mpropdef
.mclassdef
.mmodule
1113 var nsig
= self.n_signature
1114 var mysignature
= self.mpropdef
.msignature
1115 if mysignature
== null then return # Error thus skiped
1117 # Lookup for signature in the precursor
1118 # FIXME all precursors should be considered
1119 if not mpropdef
.is_intro
then
1120 var msignature
= mpropdef
.mproperty
.intro
.msignature
1121 if msignature
== null then return
1123 if mysignature
.arity
!= msignature
.arity
then
1125 if nsig
!= null then node
= nsig
else node
= self
1126 modelbuilder
.error
(node
, "Redef Error: {mysignature.arity} parameters found, {msignature.arity} expected. Signature is {mpropdef}{msignature}")
1129 var precursor_ret_type
= msignature
.return_mtype
1130 var ret_type
= mysignature
.return_mtype
1131 if ret_type
!= null and precursor_ret_type
== null then
1132 modelbuilder
.error
(nsig
.n_type
.as(not null), "Redef Error: {mpropdef.mproperty} is a procedure, not a function.")
1136 if mysignature
.arity
> 0 then
1137 # Check parameters types
1138 for i
in [0..mysignature
.arity
[ do
1139 var myt
= mysignature
.parameter_mtypes
[i
]
1140 var prt
= msignature
.parameter_mtypes
[i
]
1141 if not myt
.is_subtype
(mmodule
, nclassdef
.mclassdef
.bound_mtype
, prt
) and
1142 not prt
.is_subtype
(mmodule
, nclassdef
.mclassdef
.bound_mtype
, myt
) then
1143 modelbuilder
.error
(nsig
.n_params
[i
], "Redef Error: Wrong type for parameter `{mysignature.parameter_names[i]}'. found {myt}, expected {prt}.")
1147 if precursor_ret_type
!= null then
1148 if ret_type
== null then
1149 # Inherit the return type
1150 ret_type
= precursor_ret_type
1151 else if not ret_type
.is_subtype
(mmodule
, nclassdef
.mclassdef
.bound_mtype
, precursor_ret_type
) then
1152 modelbuilder
.error
(nsig
.n_type
.as(not null), "Redef Error: Wrong return type. found {ret_type}, expected {precursor_ret_type}.")
1159 redef class AAttrPropdef
1160 # The associated MAttributeDef once build by a `ModelBuilder'
1161 var mpropdef
: nullable MAttributeDef
1162 # The associated getter (read accessor) if any
1163 var mreadpropdef
: nullable MMethodDef
1164 # The associated setter (write accessor) if any
1165 var mwritepropdef
: nullable MMethodDef
1166 redef fun build_property
(modelbuilder
, nclassdef
)
1168 var mclassdef
= nclassdef
.mclassdef
.as(not null)
1169 var mclass
= mclassdef
.mclass
1172 if self.n_id
!= null then
1173 name
= self.n_id
.text
1175 name
= self.n_id2
.text
1178 if mclass
.kind
== interface_kind
or mclassdef
.mclass
.kind
== enum_kind
then
1179 modelbuilder
.error
(self, "Error: Attempt to define attribute {name} in the interface {mclass}.")
1180 else if mclass
.kind
== enum_kind
then
1181 modelbuilder
.error
(self, "Error: Attempt to define attribute {name} in the enum class {mclass}.")
1186 # Old attribute style
1187 var mprop
= modelbuilder
.try_get_mproperty_by_name
(nid
, mclassdef
, name
)
1188 if mprop
== null then
1189 var mvisibility
= new_property_visibility
(modelbuilder
, nclassdef
, self.n_visibility
)
1190 mprop
= new MAttribute(mclassdef
, name
, mvisibility
)
1191 self.check_redef_keyword
(modelbuilder
, nclassdef
, self.n_kwredef
, false, mprop
)
1193 assert mprop
isa MAttribute
1194 check_redef_property_visibility
(modelbuilder
, nclassdef
, self.n_visibility
, mprop
)
1195 self.check_redef_keyword
(modelbuilder
, nclassdef
, self.n_kwredef
, true, mprop
)
1197 var mpropdef
= new MAttributeDef(mclassdef
, mprop
, self.location
)
1198 self.mpropdef
= mpropdef
1199 modelbuilder
.mpropdef2npropdef
[mpropdef
] = self
1201 var nreadable
= self.n_readable
1202 if nreadable
!= null then
1203 var readname
= name
.substring_from
(1)
1204 var mreadprop
= modelbuilder
.try_get_mproperty_by_name
(nid
, mclassdef
, readname
).as(nullable MMethod)
1205 if mreadprop
== null then
1206 var mvisibility
= new_property_visibility
(modelbuilder
, nclassdef
, nreadable
.n_visibility
)
1207 mreadprop
= new MMethod(mclassdef
, readname
, mvisibility
)
1208 self.check_redef_keyword
(modelbuilder
, nclassdef
, nreadable
.n_kwredef
, false, mreadprop
)
1210 self.check_redef_keyword
(modelbuilder
, nclassdef
, nreadable
.n_kwredef
, true, mreadprop
)
1211 check_redef_property_visibility
(modelbuilder
, nclassdef
, nreadable
.n_visibility
, mreadprop
)
1213 var mreadpropdef
= new MMethodDef(mclassdef
, mreadprop
, self.location
)
1214 self.mreadpropdef
= mreadpropdef
1215 modelbuilder
.mpropdef2npropdef
[mreadpropdef
] = self
1218 var nwritable
= self.n_writable
1219 if nwritable
!= null then
1220 var writename
= name
.substring_from
(1) + "="
1221 var mwriteprop
= modelbuilder
.try_get_mproperty_by_name
(nid
, mclassdef
, writename
).as(nullable MMethod)
1222 if mwriteprop
== null then
1223 var mvisibility
= new_property_visibility
(modelbuilder
, nclassdef
, nwritable
.n_visibility
)
1224 mwriteprop
= new MMethod(mclassdef
, writename
, mvisibility
)
1225 self.check_redef_keyword
(modelbuilder
, nclassdef
, nwritable
.n_kwredef
, false, mwriteprop
)
1227 self.check_redef_keyword
(modelbuilder
, nclassdef
, nwritable
.n_kwredef
, true, mwriteprop
)
1228 check_redef_property_visibility
(modelbuilder
, nclassdef
, nwritable
.n_visibility
, mwriteprop
)
1230 var mwritepropdef
= new MMethodDef(mclassdef
, mwriteprop
, self.location
)
1231 self.mwritepropdef
= mwritepropdef
1232 modelbuilder
.mpropdef2npropdef
[mwritepropdef
] = self
1235 # New attribute style
1236 var nid2
= self.n_id2
.as(not null)
1237 var mprop
= new MAttribute(mclassdef
, "@" + name
, none_visibility
)
1238 var mpropdef
= new MAttributeDef(mclassdef
, mprop
, self.location
)
1239 self.mpropdef
= mpropdef
1240 modelbuilder
.mpropdef2npropdef
[mpropdef
] = self
1243 var mreadprop
= modelbuilder
.try_get_mproperty_by_name
(nid2
, mclassdef
, readname
).as(nullable MMethod)
1244 if mreadprop
== null then
1245 var mvisibility
= new_property_visibility
(modelbuilder
, nclassdef
, self.n_visibility
)
1246 mreadprop
= new MMethod(mclassdef
, readname
, mvisibility
)
1247 self.check_redef_keyword
(modelbuilder
, nclassdef
, n_kwredef
, false, mreadprop
)
1249 self.check_redef_keyword
(modelbuilder
, nclassdef
, n_kwredef
, true, mreadprop
)
1250 check_redef_property_visibility
(modelbuilder
, nclassdef
, self.n_visibility
, mreadprop
)
1252 var mreadpropdef
= new MMethodDef(mclassdef
, mreadprop
, self.location
)
1253 self.mreadpropdef
= mreadpropdef
1254 modelbuilder
.mpropdef2npropdef
[mreadpropdef
] = self
1256 var writename
= name
+ "="
1257 var nwritable
= self.n_writable
1258 var mwriteprop
= modelbuilder
.try_get_mproperty_by_name
(nid2
, mclassdef
, writename
).as(nullable MMethod)
1259 var nwkwredef
: nullable Token = null
1260 if nwritable
!= null then nwkwredef
= nwritable
.n_kwredef
1261 if mwriteprop
== null then
1263 if nwritable
!= null then
1264 mvisibility
= new_property_visibility
(modelbuilder
, nclassdef
, nwritable
.n_visibility
)
1266 mvisibility
= private_visibility
1268 mwriteprop
= new MMethod(mclassdef
, writename
, mvisibility
)
1269 self.check_redef_keyword
(modelbuilder
, nclassdef
, nwkwredef
, false, mwriteprop
)
1271 self.check_redef_keyword
(modelbuilder
, nclassdef
, nwkwredef
, true, mwriteprop
)
1272 if nwritable
!= null then
1273 check_redef_property_visibility
(modelbuilder
, nclassdef
, nwritable
.n_visibility
, mwriteprop
)
1276 var mwritepropdef
= new MMethodDef(mclassdef
, mwriteprop
, self.location
)
1277 self.mwritepropdef
= mwritepropdef
1278 modelbuilder
.mpropdef2npropdef
[mwritepropdef
] = self
1282 redef fun build_signature
(modelbuilder
, nclassdef
)
1284 var mpropdef
= self.mpropdef
1285 if mpropdef
== null then return # Error thus skiped
1286 var mmodule
= mpropdef
.mclassdef
.mmodule
1287 var mtype
: nullable MType = null
1289 var ntype
= self.n_type
1290 if ntype
!= null then
1291 mtype
= modelbuilder
.resolve_mtype
(nclassdef
, ntype
)
1292 if mtype
== null then return
1295 if mtype
== null then
1296 var nexpr
= self.n_expr
1297 if nexpr
!= null then
1298 if nexpr
isa ANewExpr then
1299 mtype
= modelbuilder
.resolve_mtype
(nclassdef
, nexpr
.n_type
)
1300 else if nexpr
isa AIntExpr then
1301 var cla
= modelbuilder
.try_get_mclass_by_name
(nexpr
, mmodule
, "Int")
1302 if cla
!= null then mtype
= cla
.mclass_type
1303 else if nexpr
isa AFloatExpr then
1304 var cla
= modelbuilder
.try_get_mclass_by_name
(nexpr
, mmodule
, "Float")
1305 if cla
!= null then mtype
= cla
.mclass_type
1306 else if nexpr
isa ACharExpr then
1307 var cla
= modelbuilder
.try_get_mclass_by_name
(nexpr
, mmodule
, "Char")
1308 if cla
!= null then mtype
= cla
.mclass_type
1309 else if nexpr
isa ABoolExpr then
1310 var cla
= modelbuilder
.try_get_mclass_by_name
(nexpr
, mmodule
, "Bool")
1311 if cla
!= null then mtype
= cla
.mclass_type
1312 else if nexpr
isa ASuperstringExpr then
1313 var cla
= modelbuilder
.try_get_mclass_by_name
(nexpr
, mmodule
, "String")
1314 if cla
!= null then mtype
= cla
.mclass_type
1315 else if nexpr
isa AStringFormExpr then
1316 var cla
= modelbuilder
.try_get_mclass_by_name
(nexpr
, mmodule
, "String")
1317 if cla
!= null then mtype
= cla
.mclass_type
1319 modelbuilder
.error
(self, "Error: Untyped attribute {mpropdef}. Implicit typing allowed only for literals and new.")
1323 modelbuilder
.error
(self, "Error: Untyped attribute {mpropdef}")
1327 if mtype
== null then return
1329 mpropdef
.static_mtype
= mtype
1331 var mreadpropdef
= self.mreadpropdef
1332 if mreadpropdef
!= null then
1333 var msignature
= new MSignature(new Array[String], new Array[MType], mtype
, -1)
1334 mreadpropdef
.msignature
= msignature
1337 var msritepropdef
= self.mwritepropdef
1338 if mwritepropdef
!= null then
1340 if n_id
!= null then
1341 name
= n_id
.text
.substring_from
(1)
1345 var msignature
= new MSignature([name
], [mtype
], null, -1)
1346 mwritepropdef
.msignature
= msignature
1350 redef fun check_signature
(modelbuilder
, nclassdef
)
1352 var mpropdef
= self.mpropdef
1353 if mpropdef
== null then return # Error thus skiped
1354 var mmodule
= mpropdef
.mclassdef
.mmodule
1355 var ntype
= self.n_type
1356 var mtype
= self.mpropdef
.static_mtype
1357 if mtype
== null then return # Error thus skiped
1359 # Lookup for signature in the precursor
1360 # FIXME all precursors should be considered
1361 if not mpropdef
.is_intro
then
1362 var precursor_type
= mpropdef
.mproperty
.intro
.static_mtype
1363 if precursor_type
== null then return
1365 if mtype
!= precursor_type
then
1366 modelbuilder
.error
(ntype
.as(not null), "Redef Error: Wrong static type. found {mtype}, expected {precursor_type}.")
1371 # FIXME: Check getter ans setter
1375 redef class ATypePropdef
1376 # The associated MVirtualTypeDef once build by a `ModelBuilder'
1377 var mpropdef
: nullable MVirtualTypeDef
1378 redef fun build_property
(modelbuilder
, nclassdef
)
1380 var mclassdef
= nclassdef
.mclassdef
.as(not null)
1381 var name
= self.n_id
.text
1382 var mprop
= modelbuilder
.try_get_mproperty_by_name
(self.n_id
, mclassdef
, name
)
1383 if mprop
== null then
1384 var mvisibility
= new_property_visibility
(modelbuilder
, nclassdef
, self.n_visibility
)
1385 mprop
= new MVirtualTypeProp(mclassdef
, name
, mvisibility
)
1386 self.check_redef_keyword
(modelbuilder
, nclassdef
, self.n_kwredef
, false, mprop
)
1388 self.check_redef_keyword
(modelbuilder
, nclassdef
, self.n_kwredef
, true, mprop
)
1389 assert mprop
isa MVirtualTypeProp
1390 check_redef_property_visibility
(modelbuilder
, nclassdef
, self.n_visibility
, mprop
)
1392 var mpropdef
= new MVirtualTypeDef(mclassdef
, mprop
, self.location
)
1393 self.mpropdef
= mpropdef
1396 redef fun build_signature
(modelbuilder
, nclassdef
)
1398 var mpropdef
= self.mpropdef
1399 if mpropdef
== null then return # Error thus skiped
1400 var mmodule
= mpropdef
.mclassdef
.mmodule
1401 var mtype
: nullable MType = null
1403 var ntype
= self.n_type
1404 mtype
= modelbuilder
.resolve_mtype
(nclassdef
, ntype
)
1405 if mtype
== null then return
1407 mpropdef
.bound
= mtype
1408 # print "{mpropdef}: {mtype}"
1411 redef fun check_signature
(modelbuilder
, nclassdef
)
1413 var bound
= self.mpropdef
.bound
1415 # Fast case: the bound is not a formal type
1416 if not bound
isa MVirtualType then return
1418 var mmodule
= nclassdef
.mclassdef
.mmodule
1419 var anchor
= nclassdef
.mclassdef
.bound_mtype
1421 # Slow case: progress on each resolution until: (i) we loop, or (ii) we found a non formal type
1422 var seen
= [self.mpropdef
.mproperty
.mvirtualtype
]
1424 if seen
.has
(bound
) then
1426 modelbuilder
.error
(self, "Error: circularity of virtual type definition: {seen.join(" -> ")}")
1430 var next
= bound
.lookup_bound
(mmodule
, anchor
)
1431 if not next
isa MVirtualType then return