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 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 mprop
.is_new
= self isa AExternInitPropdef
1004 self.check_redef_keyword
(modelbuilder
, nclassdef
, n_kwredef
, false, mprop
)
1006 if n_kwredef
== null then
1007 if self isa AMainMethPropdef then
1010 self.check_redef_keyword
(modelbuilder
, nclassdef
, n_kwredef
, true, mprop
)
1013 check_redef_property_visibility
(modelbuilder
, nclassdef
, self.n_visibility
, mprop
)
1016 var mpropdef
= new MMethodDef(mclassdef
, mprop
, self.location
)
1018 self.mpropdef
= mpropdef
1019 modelbuilder
.mpropdef2npropdef
[mpropdef
] = self
1020 if mpropdef
.is_intro
then
1021 modelbuilder
.toolcontext
.info
("{mpropdef} introduces new method {mprop.full_name}", 3)
1023 modelbuilder
.toolcontext
.info
("{mpropdef} redefines method {mprop.full_name}", 3)
1027 redef fun build_signature
(modelbuilder
, nclassdef
)
1029 var mpropdef
= self.mpropdef
1030 if mpropdef
== null then return # Error thus skiped
1031 var mmodule
= mpropdef
.mclassdef
.mmodule
1032 var nsig
= self.n_signature
1034 # Retrieve info from the signature AST
1035 var param_names
= new Array[String] # Names of parameters from the AST
1036 var param_types
= new Array[MType] # Types of parameters from the AST
1037 var vararg_rank
= -1
1038 var ret_type
: nullable MType = null # Return type from the AST
1039 if nsig
!= null then
1040 for np
in nsig
.n_params
do
1041 param_names
.add
(np
.n_id
.text
)
1042 var ntype
= np
.n_type
1043 if ntype
!= null then
1044 var mtype
= modelbuilder
.resolve_mtype
(nclassdef
, ntype
)
1045 if mtype
== null then return # Skip error
1046 for i
in [0..param_names
.length-param_types
.length
[ do
1047 param_types
.add
(mtype
)
1049 if np
.n_dotdotdot
!= null then
1050 if vararg_rank
!= -1 then
1051 modelbuilder
.error
(np
, "Error: {param_names[vararg_rank]} is already a vararg")
1053 vararg_rank
= param_names
.length
- 1
1058 var ntype
= nsig
.n_type
1059 if ntype
!= null then
1060 ret_type
= modelbuilder
.resolve_mtype
(nclassdef
, ntype
)
1061 if ret_type
== null then return # Skip errir
1065 # Look for some signature to inherit
1066 # FIXME: do not inherit from the intro, but from the most specific
1067 var msignature
: nullable MSignature = null
1068 if not mpropdef
.is_intro
then
1069 msignature
= mpropdef
.mproperty
.intro
.msignature
1070 if msignature
== null then return # Skip error
1071 else if mpropdef
.mproperty
.is_init
then
1072 # FIXME UGLY: inherit signature from a super-constructor
1073 for msupertype
in nclassdef
.mclassdef
.supertypes
do
1074 msupertype
= msupertype
.anchor_to
(mmodule
, nclassdef
.mclassdef
.bound_mtype
)
1075 var candidate
= modelbuilder
.try_get_mproperty_by_name2
(self, mmodule
, msupertype
, mpropdef
.mproperty
.name
)
1076 if candidate
!= null then
1077 if msignature
== null then
1078 msignature
= candidate
.intro
.as(MMethodDef).msignature
1084 # Inherit the signature
1085 if msignature
!= null and param_names
.length
!= param_types
.length
and param_names
.length
== msignature
.arity
and param_types
.length
== 0 then
1086 # Parameters are untyped, thus inherit them
1087 param_types
= msignature
.parameter_mtypes
1088 vararg_rank
= msignature
.vararg_rank
1090 if msignature
!= null and ret_type
== null then
1091 ret_type
= msignature
.return_mtype
1094 if param_names
.length
!= param_types
.length
then
1095 # Some parameters are typed, other parameters are not typed.
1096 modelbuilder
.warning
(nsig
.n_params
[param_types
.length
], "Error: Untyped parameter `{param_names[param_types.length]}'.")
1100 msignature
= new MSignature(param_names
, param_types
, ret_type
, vararg_rank
)
1101 mpropdef
.msignature
= msignature
1104 redef fun check_signature
(modelbuilder
, nclassdef
)
1106 var mpropdef
= self.mpropdef
1107 if mpropdef
== null then return # Error thus skiped
1108 var mmodule
= mpropdef
.mclassdef
.mmodule
1109 var nsig
= self.n_signature
1110 var mysignature
= self.mpropdef
.msignature
1111 if mysignature
== null then return # Error thus skiped
1113 # Lookup for signature in the precursor
1114 # FIXME all precursors should be considered
1115 if not mpropdef
.is_intro
then
1116 var msignature
= mpropdef
.mproperty
.intro
.msignature
1117 if msignature
== null then return
1119 if mysignature
.arity
!= msignature
.arity
then
1121 if nsig
!= null then node
= nsig
else node
= self
1122 modelbuilder
.error
(node
, "Redef Error: {mysignature.arity} parameters found, {msignature.arity} expected. Signature is {mpropdef}{msignature}")
1125 var precursor_ret_type
= msignature
.return_mtype
1126 var ret_type
= mysignature
.return_mtype
1127 if ret_type
!= null and precursor_ret_type
== null then
1128 modelbuilder
.error
(nsig
.n_type
.as(not null), "Redef Error: {mpropdef.mproperty} is a procedure, not a function.")
1132 if mysignature
.arity
> 0 then
1133 # Check parameters types
1134 for i
in [0..mysignature
.arity
[ do
1135 var myt
= mysignature
.parameter_mtypes
[i
]
1136 var prt
= msignature
.parameter_mtypes
[i
]
1137 if not myt
.is_subtype
(mmodule
, nclassdef
.mclassdef
.bound_mtype
, prt
) and
1138 not prt
.is_subtype
(mmodule
, nclassdef
.mclassdef
.bound_mtype
, myt
) then
1139 modelbuilder
.error
(nsig
.n_params
[i
], "Redef Error: Wrong type for parameter `{mysignature.parameter_names[i]}'. found {myt}, expected {prt}.")
1143 if precursor_ret_type
!= null then
1144 if ret_type
== null then
1145 # Inherit the return type
1146 ret_type
= precursor_ret_type
1147 else if not ret_type
.is_subtype
(mmodule
, nclassdef
.mclassdef
.bound_mtype
, precursor_ret_type
) then
1148 modelbuilder
.error
(nsig
.n_type
.as(not null), "Redef Error: Wrong return type. found {ret_type}, expected {precursor_ret_type}.")
1155 redef class AAttrPropdef
1156 # The associated MAttributeDef once build by a `ModelBuilder'
1157 var mpropdef
: nullable MAttributeDef
1158 # The associated getter (read accessor) if any
1159 var mreadpropdef
: nullable MMethodDef
1160 # The associated setter (write accessor) if any
1161 var mwritepropdef
: nullable MMethodDef
1162 redef fun build_property
(modelbuilder
, nclassdef
)
1164 var mclassdef
= nclassdef
.mclassdef
.as(not null)
1165 var mclass
= mclassdef
.mclass
1168 if self.n_id
!= null then
1169 name
= self.n_id
.text
1171 name
= self.n_id2
.text
1174 if mclass
.kind
== interface_kind
or mclassdef
.mclass
.kind
== enum_kind
then
1175 modelbuilder
.error
(self, "Error: Attempt to define attribute {name} in the interface {mclass}.")
1176 else if mclass
.kind
== enum_kind
then
1177 modelbuilder
.error
(self, "Error: Attempt to define attribute {name} in the enum class {mclass}.")
1182 # Old attribute style
1183 var mprop
= modelbuilder
.try_get_mproperty_by_name
(nid
, mclassdef
, name
)
1184 if mprop
== null then
1185 var mvisibility
= new_property_visibility
(modelbuilder
, nclassdef
, self.n_visibility
)
1186 mprop
= new MAttribute(mclassdef
, name
, mvisibility
)
1187 self.check_redef_keyword
(modelbuilder
, nclassdef
, self.n_kwredef
, false, mprop
)
1189 assert mprop
isa MAttribute
1190 check_redef_property_visibility
(modelbuilder
, nclassdef
, self.n_visibility
, mprop
)
1191 self.check_redef_keyword
(modelbuilder
, nclassdef
, self.n_kwredef
, true, mprop
)
1193 var mpropdef
= new MAttributeDef(mclassdef
, mprop
, self.location
)
1194 self.mpropdef
= mpropdef
1195 modelbuilder
.mpropdef2npropdef
[mpropdef
] = self
1197 var nreadable
= self.n_readable
1198 if nreadable
!= null then
1199 var readname
= name
.substring_from
(1)
1200 var mreadprop
= modelbuilder
.try_get_mproperty_by_name
(nid
, mclassdef
, readname
).as(nullable MMethod)
1201 if mreadprop
== null then
1202 var mvisibility
= new_property_visibility
(modelbuilder
, nclassdef
, nreadable
.n_visibility
)
1203 mreadprop
= new MMethod(mclassdef
, readname
, mvisibility
)
1204 self.check_redef_keyword
(modelbuilder
, nclassdef
, nreadable
.n_kwredef
, false, mreadprop
)
1206 self.check_redef_keyword
(modelbuilder
, nclassdef
, nreadable
.n_kwredef
, true, mreadprop
)
1207 check_redef_property_visibility
(modelbuilder
, nclassdef
, nreadable
.n_visibility
, mreadprop
)
1209 var mreadpropdef
= new MMethodDef(mclassdef
, mreadprop
, self.location
)
1210 self.mreadpropdef
= mreadpropdef
1211 modelbuilder
.mpropdef2npropdef
[mreadpropdef
] = self
1214 var nwritable
= self.n_writable
1215 if nwritable
!= null then
1216 var writename
= name
.substring_from
(1) + "="
1217 var mwriteprop
= modelbuilder
.try_get_mproperty_by_name
(nid
, mclassdef
, writename
).as(nullable MMethod)
1218 if mwriteprop
== null then
1219 var mvisibility
= new_property_visibility
(modelbuilder
, nclassdef
, nwritable
.n_visibility
)
1220 mwriteprop
= new MMethod(mclassdef
, writename
, mvisibility
)
1221 self.check_redef_keyword
(modelbuilder
, nclassdef
, nwritable
.n_kwredef
, false, mwriteprop
)
1223 self.check_redef_keyword
(modelbuilder
, nclassdef
, nwritable
.n_kwredef
, true, mwriteprop
)
1224 check_redef_property_visibility
(modelbuilder
, nclassdef
, nwritable
.n_visibility
, mwriteprop
)
1226 var mwritepropdef
= new MMethodDef(mclassdef
, mwriteprop
, self.location
)
1227 self.mwritepropdef
= mwritepropdef
1228 modelbuilder
.mpropdef2npropdef
[mwritepropdef
] = self
1231 # New attribute style
1232 var nid2
= self.n_id2
.as(not null)
1233 var mprop
= new MAttribute(mclassdef
, "@" + name
, none_visibility
)
1234 var mpropdef
= new MAttributeDef(mclassdef
, mprop
, self.location
)
1235 self.mpropdef
= mpropdef
1236 modelbuilder
.mpropdef2npropdef
[mpropdef
] = self
1239 var mreadprop
= modelbuilder
.try_get_mproperty_by_name
(nid2
, mclassdef
, readname
).as(nullable MMethod)
1240 if mreadprop
== null then
1241 var mvisibility
= new_property_visibility
(modelbuilder
, nclassdef
, self.n_visibility
)
1242 mreadprop
= new MMethod(mclassdef
, readname
, mvisibility
)
1243 self.check_redef_keyword
(modelbuilder
, nclassdef
, n_kwredef
, false, mreadprop
)
1245 self.check_redef_keyword
(modelbuilder
, nclassdef
, n_kwredef
, true, mreadprop
)
1246 check_redef_property_visibility
(modelbuilder
, nclassdef
, self.n_visibility
, mreadprop
)
1248 var mreadpropdef
= new MMethodDef(mclassdef
, mreadprop
, self.location
)
1249 self.mreadpropdef
= mreadpropdef
1250 modelbuilder
.mpropdef2npropdef
[mreadpropdef
] = self
1252 var writename
= name
+ "="
1253 var nwritable
= self.n_writable
1254 var mwriteprop
= modelbuilder
.try_get_mproperty_by_name
(nid2
, mclassdef
, writename
).as(nullable MMethod)
1255 var nwkwredef
: nullable Token = null
1256 if nwritable
!= null then nwkwredef
= nwritable
.n_kwredef
1257 if mwriteprop
== null then
1259 if nwritable
!= null then
1260 mvisibility
= new_property_visibility
(modelbuilder
, nclassdef
, nwritable
.n_visibility
)
1262 mvisibility
= private_visibility
1264 mwriteprop
= new MMethod(mclassdef
, writename
, mvisibility
)
1265 self.check_redef_keyword
(modelbuilder
, nclassdef
, nwkwredef
, false, mwriteprop
)
1267 self.check_redef_keyword
(modelbuilder
, nclassdef
, nwkwredef
, true, mwriteprop
)
1268 if nwritable
!= null then
1269 check_redef_property_visibility
(modelbuilder
, nclassdef
, nwritable
.n_visibility
, mwriteprop
)
1272 var mwritepropdef
= new MMethodDef(mclassdef
, mwriteprop
, self.location
)
1273 self.mwritepropdef
= mwritepropdef
1274 modelbuilder
.mpropdef2npropdef
[mwritepropdef
] = self
1278 redef fun build_signature
(modelbuilder
, nclassdef
)
1280 var mpropdef
= self.mpropdef
1281 if mpropdef
== null then return # Error thus skiped
1282 var mmodule
= mpropdef
.mclassdef
.mmodule
1283 var mtype
: nullable MType = null
1285 var ntype
= self.n_type
1286 if ntype
!= null then
1287 mtype
= modelbuilder
.resolve_mtype
(nclassdef
, ntype
)
1288 if mtype
== null then return
1291 if mtype
== null then
1292 var nexpr
= self.n_expr
1293 if nexpr
!= null then
1294 if nexpr
isa ANewExpr then
1295 mtype
= modelbuilder
.resolve_mtype
(nclassdef
, nexpr
.n_type
)
1296 else if nexpr
isa AIntExpr then
1297 var cla
= modelbuilder
.try_get_mclass_by_name
(nexpr
, mmodule
, "Int")
1298 if cla
!= null then mtype
= cla
.mclass_type
1299 else if nexpr
isa AFloatExpr then
1300 var cla
= modelbuilder
.try_get_mclass_by_name
(nexpr
, mmodule
, "Float")
1301 if cla
!= null then mtype
= cla
.mclass_type
1302 else if nexpr
isa ACharExpr then
1303 var cla
= modelbuilder
.try_get_mclass_by_name
(nexpr
, mmodule
, "Char")
1304 if cla
!= null then mtype
= cla
.mclass_type
1305 else if nexpr
isa ABoolExpr then
1306 var cla
= modelbuilder
.try_get_mclass_by_name
(nexpr
, mmodule
, "Bool")
1307 if cla
!= null then mtype
= cla
.mclass_type
1308 else if nexpr
isa ASuperstringExpr then
1309 var cla
= modelbuilder
.try_get_mclass_by_name
(nexpr
, mmodule
, "String")
1310 if cla
!= null then mtype
= cla
.mclass_type
1311 else if nexpr
isa AStringFormExpr then
1312 var cla
= modelbuilder
.try_get_mclass_by_name
(nexpr
, mmodule
, "String")
1313 if cla
!= null then mtype
= cla
.mclass_type
1315 modelbuilder
.error
(self, "Error: Untyped attribute {mpropdef}. Implicit typing allowed only for literals and new.")
1319 modelbuilder
.error
(self, "Error: Untyped attribute {mpropdef}")
1323 if mtype
== null then return
1325 mpropdef
.static_mtype
= mtype
1327 var mreadpropdef
= self.mreadpropdef
1328 if mreadpropdef
!= null then
1329 var msignature
= new MSignature(new Array[String], new Array[MType], mtype
, -1)
1330 mreadpropdef
.msignature
= msignature
1333 var msritepropdef
= self.mwritepropdef
1334 if mwritepropdef
!= null then
1336 if n_id
!= null then
1337 name
= n_id
.text
.substring_from
(1)
1341 var msignature
= new MSignature([name
], [mtype
], null, -1)
1342 mwritepropdef
.msignature
= msignature
1346 redef fun check_signature
(modelbuilder
, nclassdef
)
1348 var mpropdef
= self.mpropdef
1349 if mpropdef
== null then return # Error thus skiped
1350 var mmodule
= mpropdef
.mclassdef
.mmodule
1351 var ntype
= self.n_type
1352 var mtype
= self.mpropdef
.static_mtype
1353 if mtype
== null then return # Error thus skiped
1355 # Lookup for signature in the precursor
1356 # FIXME all precursors should be considered
1357 if not mpropdef
.is_intro
then
1358 var precursor_type
= mpropdef
.mproperty
.intro
.static_mtype
1359 if precursor_type
== null then return
1361 if mtype
!= precursor_type
then
1362 modelbuilder
.error
(ntype
.as(not null), "Redef Error: Wrong static type. found {mtype}, expected {precursor_type}.")
1367 # FIXME: Check getter ans setter
1371 redef class ATypePropdef
1372 # The associated MVirtualTypeDef once build by a `ModelBuilder'
1373 var mpropdef
: nullable MVirtualTypeDef
1374 redef fun build_property
(modelbuilder
, nclassdef
)
1376 var mclassdef
= nclassdef
.mclassdef
.as(not null)
1377 var name
= self.n_id
.text
1378 var mprop
= modelbuilder
.try_get_mproperty_by_name
(self.n_id
, mclassdef
, name
)
1379 if mprop
== null then
1380 var mvisibility
= new_property_visibility
(modelbuilder
, nclassdef
, self.n_visibility
)
1381 mprop
= new MVirtualTypeProp(mclassdef
, name
, mvisibility
)
1382 self.check_redef_keyword
(modelbuilder
, nclassdef
, self.n_kwredef
, false, mprop
)
1384 self.check_redef_keyword
(modelbuilder
, nclassdef
, self.n_kwredef
, true, mprop
)
1385 assert mprop
isa MVirtualTypeProp
1386 check_redef_property_visibility
(modelbuilder
, nclassdef
, self.n_visibility
, mprop
)
1388 var mpropdef
= new MVirtualTypeDef(mclassdef
, mprop
, self.location
)
1389 self.mpropdef
= mpropdef
1392 redef fun build_signature
(modelbuilder
, nclassdef
)
1394 var mpropdef
= self.mpropdef
1395 if mpropdef
== null then return # Error thus skiped
1396 var mmodule
= mpropdef
.mclassdef
.mmodule
1397 var mtype
: nullable MType = null
1399 var ntype
= self.n_type
1400 mtype
= modelbuilder
.resolve_mtype
(nclassdef
, ntype
)
1401 if mtype
== null then return
1403 mpropdef
.bound
= mtype
1404 # print "{mpropdef}: {mtype}"
1407 redef fun check_signature
(modelbuilder
, nclassdef
)
1409 var bound
= self.mpropdef
.bound
1411 # Fast case: the bound is not a formal type
1412 if not bound
isa MVirtualType then return
1414 var mmodule
= nclassdef
.mclassdef
.mmodule
1415 var anchor
= nclassdef
.mclassdef
.bound_mtype
1417 # Slow case: progress on each resolution until: (i) we loop, or (ii) we found a non formal type
1418 var seen
= [self.mpropdef
.mproperty
.mvirtualtype
]
1420 if seen
.has
(bound
) then
1422 modelbuilder
.error
(self, "Error: circularity of virtual type definition: {seen.join(" -> ")}")
1426 var next
= bound
.lookup_bound
(mmodule
, anchor
)
1427 if not next
isa MVirtualType then return