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
108 if self.toolcontext
.opt_only_parse
.value
then
109 self.toolcontext
.info
("--only-parse: stop processing", 2)
110 return new Array[MModule]
114 self.toolcontext
.info
("*** BUILD MODEL ***", 1)
115 self.build_all_classes
117 self.toolcontext
.info
("*** END BUILD MODEL: {time2-time1} ***", 2)
119 self.toolcontext
.check_errors
124 # Return a class named `name' visible by the module `mmodule'.
125 # Visibility in modules is correctly handled.
126 # If no such a class exists, then null is returned.
127 # If more than one class exists, then an error on `anode' is displayed and null is returned.
128 # FIXME: add a way to handle class name conflict
129 fun try_get_mclass_by_name
(anode
: ANode, mmodule
: MModule, name
: String): nullable MClass
131 var classes
= model
.get_mclasses_by_name
(name
)
132 if classes
== null then
136 var res
: nullable MClass = null
137 for mclass
in classes
do
138 if not mmodule
.in_importation
<= mclass
.intro_mmodule
then continue
139 if not mmodule
.is_visible
(mclass
.intro_mmodule
, mclass
.visibility
) then continue
143 error
(anode
, "Ambigous class name '{name}'; conflict between {mclass.full_name} and {res.full_name}")
150 # Return a property named `name' on the type `mtype' visible in the module `mmodule'.
151 # Visibility in modules is correctly handled.
152 # Protected properties are returned (it is up to the caller to check and reject protected properties).
153 # If no such a property exists, then null is returned.
154 # If more than one property exists, then an error on `anode' is displayed and null is returned.
155 # FIXME: add a way to handle property name conflict
156 fun try_get_mproperty_by_name2
(anode
: ANode, mmodule
: MModule, mtype
: MType, name
: String): nullable MProperty
158 var props
= self.model
.get_mproperties_by_name
(name
)
159 if props
== null then
163 var cache
= self.try_get_mproperty_by_name2_cache
[mmodule
, mtype
, name
]
164 if cache
!= null then return cache
166 var res
: nullable MProperty = null
167 var ress
: nullable Array[MProperty] = null
168 for mprop
in props
do
169 if not mtype
.has_mproperty
(mmodule
, mprop
) then continue
170 if not mmodule
.is_visible
(mprop
.intro_mclassdef
.mmodule
, mprop
.visibility
) then continue
174 var restype
= res
.intro_mclassdef
.bound_mtype
175 var mproptype
= mprop
.intro_mclassdef
.bound_mtype
176 if restype
.is_subtype
(mmodule
, null, mproptype
) then
178 else if mproptype
.is_subtype
(mmodule
, null, restype
) then
181 if ress
== null then ress
= new Array[MProperty]
187 var restype
= res
.intro_mclassdef
.bound_mtype
189 var mproptype
= mprop
.intro_mclassdef
.bound_mtype
190 if not restype
.is_subtype
(mmodule
, null, mproptype
) then
191 self.error
(anode
, "Ambigous property name '{name}' for {mtype}; conflict between {mprop.full_name} and {res.full_name}")
197 self.try_get_mproperty_by_name2_cache
[mmodule
, mtype
, name
] = res
201 private var try_get_mproperty_by_name2_cache
: HashMap3[MModule, MType, String, nullable MProperty] = new HashMap3[MModule, MType, String, nullable MProperty]
204 # Alias for try_get_mproperty_by_name2(anode, mclassdef.mmodule, mclassdef.mtype, name)
205 fun try_get_mproperty_by_name
(anode
: ANode, mclassdef
: MClassDef, name
: String): nullable MProperty
207 return try_get_mproperty_by_name2
(anode
, mclassdef
.mmodule
, mclassdef
.bound_mtype
, name
)
210 # The list of directories to search for top level modules
211 # The list is initially set with :
212 # * the toolcontext --path option
213 # * the NIT_PATH environment variable
214 # * some heuristics including the NIT_DIR environment variable and the progname of the process
215 # Path can be added (or removed) by the client
216 var paths
: Array[String] = new Array[String]
218 # Get a module by its short name; if required, the module is loaded, parsed and its hierarchies computed.
219 # If `mmodule' is set, then the module search starts from it up to the top level (see `paths');
220 # if `mmodule' is null then the module is searched in the top level only.
221 # If no module exists or there is a name conflict, then an error on `anode' is displayed and null is returned.
222 # FIXME: add a way to handle module name conflict
223 fun get_mmodule_by_name
(anode
: ANode, mmodule
: nullable MModule, name
: String): nullable MModule
225 var origmmodule
= mmodule
226 var modules
= model
.get_mmodules_by_name
(name
)
228 var tries
= new Array[String]
230 var lastmodule
= mmodule
231 while mmodule
!= null do
232 var dirname
= mmodule
.location
.file
.filename
.dirname
234 # Determine the owner
235 var owner
: nullable MModule
236 if dirname
.basename
("") != mmodule
.name
then
237 owner
= mmodule
.direct_owner
242 # First, try the already known nested modules
243 if modules
!= null then
244 for candidate
in modules
do
245 if candidate
.direct_owner
== owner
then
251 # Second, try the directory to find a file
252 var try_file
= dirname
+ "/" + 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)
260 # Third, try if the requested module is itself an owner
261 try_file
= dirname
+ "/" + name
+ "/" + name
+ ".nit"
262 if try_file
.file_exists
then
263 var res
= self.load_module
(owner
, try_file
.simplify_path
)
264 if res
== null then return null # Forward error
265 return res
.mmodule
.as(not null)
269 mmodule
= mmodule
.direct_owner
272 if modules
!= null then
273 for candidate
in modules
do
274 if candidate
.direct_owner
== null then
280 # Look at some known directories
281 var lookpaths
= self.paths
283 # Look in the directory of the last module also (event if not in the path)
284 if lastmodule
!= null then
285 var dirname
= lastmodule
.location
.file
.filename
.dirname
286 if dirname
.basename
("") == lastmodule
.name
then
287 dirname
= dirname
.dirname
289 if not lookpaths
.has
(dirname
) then
290 lookpaths
= lookpaths
.to_a
291 lookpaths
.add
(dirname
)
295 var candidate
: nullable String = null
296 for dirname
in lookpaths
do
297 var try_file
= (dirname
+ "/" + name
+ ".nit").simplify_path
299 if try_file
.file_exists
then
300 if candidate
== null then
302 else if candidate
!= try_file
then
303 error
(anode
, "Error: conflicting module file for {name}: {candidate} {try_file}")
306 try_file
= (dirname
+ "/" + name
+ "/" + name
+ ".nit").simplify_path
307 if try_file
.file_exists
then
308 if candidate
== null then
310 else if candidate
!= try_file
then
311 error
(anode
, "Error: conflicting module file for {name}: {candidate} {try_file}")
315 if candidate
== null then
316 if origmmodule
!= null then
317 error
(anode
, "Error: cannot find module {name} from {origmmodule}. tried {tries.join(", ")}")
319 error
(anode
, "Error: cannot find module {name}. tried {tries.join(", ")}")
323 var res
= self.load_module
(mmodule
, candidate
)
324 if res
== null then return null # Forward error
325 return res
.mmodule
.as(not null)
328 # Try to load a module using a path.
329 # Display an error if there is a problem (IO / lexer / parser) and return null
330 # Note: usually, you do not need this method, use `get_mmodule_by_name` instead.
331 fun load_module
(owner
: nullable MModule, filename
: String): nullable AModule
333 if not filename
.file_exists
then
334 self.toolcontext
.error
(null, "Error: file {filename} not found.")
338 var x
= if owner
!= null then owner
.to_s
else "."
339 self.toolcontext
.info
("load module {filename} in {x}", 2)
342 var file
= new IFStream.open
(filename
)
343 var lexer
= new Lexer(new SourceFile(filename
, file
))
344 var parser
= new Parser(lexer
)
345 var tree
= parser
.parse
348 # Handle lexer and parser error
349 var nmodule
= tree
.n_base
350 if nmodule
== null then
351 var neof
= tree
.n_eof
352 assert neof
isa AError
353 error
(neof
, neof
.message
)
357 # Check the module name
358 var mod_name
= filename
.basename
(".nit")
359 var decl
= nmodule
.n_moduledecl
361 #warning(nmodule, "Warning: Missing 'module' keyword") #FIXME: NOT YET FOR COMPATIBILITY
363 var decl_name
= decl
.n_name
.n_id
.text
364 if decl_name
!= mod_name
then
365 error
(decl
.n_name
, "Error: module name missmatch; declared {decl_name} file named {mod_name}")
370 var mmodule
= new MModule(model
, owner
, mod_name
, nmodule
.location
)
371 nmodule
.mmodule
= mmodule
372 nmodules
.add
(nmodule
)
373 self.mmodule2nmodule
[mmodule
] = nmodule
375 build_module_importation
(nmodule
)
380 # Analysis the module importation and fill the module_importation_hierarchy
381 private fun build_module_importation
(nmodule
: AModule)
383 if nmodule
.is_importation_done
then return
384 var mmodule
= nmodule
.mmodule
.as(not null)
386 var imported_modules
= new Array[MModule]
387 for aimport
in nmodule
.n_imports
do
389 if not aimport
isa AStdImport then
392 var mod_name
= aimport
.n_name
.n_id
.text
393 var sup
= self.get_mmodule_by_name
(aimport
.n_name
, mmodule
, mod_name
)
394 if sup
== null then continue # Skip error
395 imported_modules
.add
(sup
)
396 var mvisibility
= aimport
.n_visibility
.mvisibility
397 mmodule
.set_visibility_for
(sup
, mvisibility
)
400 var mod_name
= "standard"
401 var sup
= self.get_mmodule_by_name
(nmodule
, null, mod_name
)
402 if sup
!= null then # Skip error
403 imported_modules
.add
(sup
)
404 mmodule
.set_visibility_for
(sup
, public_visibility
)
407 self.toolcontext
.info
("{mmodule} imports {imported_modules.join(", ")}", 3)
408 mmodule
.set_imported_mmodules
(imported_modules
)
409 nmodule
.is_importation_done
= true
412 # All the loaded modules
413 var nmodules
: Array[AModule] = new Array[AModule]
415 # Build the classes of all modules `nmodules'.
416 private fun build_all_classes
418 for nmodule
in self.nmodules
do
419 build_classes
(nmodule
)
423 # Visit the AST and create the MClass objects
424 private fun build_a_mclass
(nmodule
: AModule, nclassdef
: AClassdef)
426 var mmodule
= nmodule
.mmodule
.as(not null)
429 var nkind
: nullable AClasskind
430 var mkind
: MClassKind
431 var nvisibility
: nullable AVisibility
432 var mvisibility
: nullable MVisibility
434 if nclassdef
isa AStdClassdef then
435 name
= nclassdef
.n_id
.text
436 nkind
= nclassdef
.n_classkind
438 nvisibility
= nclassdef
.n_visibility
439 mvisibility
= nvisibility
.mvisibility
440 arity
= nclassdef
.n_formaldefs
.length
441 else if nclassdef
isa ATopClassdef then
444 mkind
= interface_kind
446 mvisibility
= public_visibility
447 else if nclassdef
isa AMainClassdef then
450 mkind
= concrete_kind
452 mvisibility
= public_visibility
457 var mclass
= try_get_mclass_by_name
(nclassdef
, mmodule
, name
)
458 if mclass
== null then
459 mclass
= new MClass(mmodule
, name
, arity
, mkind
, mvisibility
)
460 #print "new class {mclass}"
461 else if nclassdef
isa AStdClassdef and nclassdef
.n_kwredef
== null then
462 error
(nclassdef
, "Redef error: {name} is an imported class. Add the redef keyword to refine it.")
464 else if mclass
.arity
!= arity
then
465 error
(nclassdef
, "Redef error: Formal parameter arity missmatch; got {arity}, expected {mclass.arity}.")
467 else if nkind
!= null and mkind
!= concrete_kind
and mclass
.kind
!= mkind
then
468 error
(nkind
, "Error: refinement changed the kind from a {mclass.kind} to a {mkind}")
469 else if nvisibility
!= null and mvisibility
!= public_visibility
and mclass
.visibility
!= mvisibility
then
470 error
(nvisibility
, "Error: refinement changed the visibility from a {mclass.visibility} to a {mvisibility}")
472 nclassdef
.mclass
= mclass
475 # Visit the AST and create the MClassDef objects
476 private fun build_a_mclassdef
(nmodule
: AModule, nclassdef
: AClassdef)
478 var mmodule
= nmodule
.mmodule
.as(not null)
479 var objectclass
= try_get_mclass_by_name
(nmodule
, mmodule
, "Object")
480 var mclass
= nclassdef
.mclass
.as(not null)
481 #var mclassdef = nclassdef.mclassdef.as(not null)
483 var names
= new Array[String]
484 var bounds
= new Array[MType]
485 if nclassdef
isa AStdClassdef and mclass
.arity
> 0 then
486 # Collect formal parameter names
487 for i
in [0..mclass
.arity
[ do
488 var nfd
= nclassdef
.n_formaldefs
[i
]
489 var ptname
= nfd
.n_id
.text
490 if names
.has
(ptname
) then
491 error
(nfd
, "Error: A formal parameter type `{ptname}' already exists")
497 # Revolve bound for formal parameter names
498 for i
in [0..mclass
.arity
[ do
499 var nfd
= nclassdef
.n_formaldefs
[i
]
500 var nfdt
= nfd
.n_type
502 var bound
= resolve_mtype
(nclassdef
, nfdt
)
503 if bound
== null then return # Forward error
504 if bound
.need_anchor
then
506 error
(nfd
, "Error: Formal parameter type `{names[i]}' bounded with a formal parameter type")
510 else if mclass
.mclassdefs
.is_empty
then
511 # No bound, then implicitely bound by nullable Object
512 bounds
.add
(objectclass
.mclass_type
.as_nullable
)
515 bounds
.add
(mclass
.mclassdefs
.first
.bound_mtype
.as(MGenericType).arguments
[i
])
520 var bound_mtype
= mclass
.get_mtype
(bounds
)
521 var mclassdef
= new MClassDef(mmodule
, bound_mtype
, nclassdef
.location
, names
)
522 nclassdef
.mclassdef
= mclassdef
523 self.mclassdef2nclassdef
[mclassdef
] = nclassdef
525 if mclassdef
.is_intro
then
526 self.toolcontext
.info
("{mclassdef} introduces new {mclass.kind} {mclass.full_name}", 3)
528 self.toolcontext
.info
("{mclassdef} refine {mclass.kind} {mclass.full_name}", 3)
532 # Visit the AST and set the super-types of the MClass objects (ie compute the inheritance)
533 private fun build_a_mclassdef_inheritance
(nmodule
: AModule, nclassdef
: AClassdef)
535 var mmodule
= nmodule
.mmodule
.as(not null)
536 var objectclass
= try_get_mclass_by_name
(nmodule
, mmodule
, "Object")
537 var mclass
= nclassdef
.mclass
.as(not null)
538 var mclassdef
= nclassdef
.mclassdef
.as(not null)
540 var specobject
= true
541 var supertypes
= new Array[MClassType]
542 if nclassdef
isa AStdClassdef then
543 for nsc
in nclassdef
.n_superclasses
do
545 var ntype
= nsc
.n_type
546 var mtype
= resolve_mtype
(nclassdef
, ntype
)
547 if mtype
== null then continue # Skip because of error
548 if not mtype
isa MClassType then
549 error
(ntype
, "Error: supertypes cannot be a formal type")
553 #print "new super : {mclass} < {mtype}"
556 if specobject
and mclass
.name
!= "Object" and objectclass
!= null and mclassdef
.is_intro
then
557 supertypes
.add objectclass
.mclass_type
560 mclassdef
.set_supertypes
(supertypes
)
561 if not supertypes
.is_empty
then self.toolcontext
.info
("{mclassdef} new super-types: {supertypes.join(", ")}", 3)
564 # Check the validity of the specialization heirarchy
565 # FIXME Stub implementation
566 private fun check_supertypes
(nmodule
: AModule, nclassdef
: AClassdef)
568 var mmodule
= nmodule
.mmodule
.as(not null)
569 var objectclass
= try_get_mclass_by_name
(nmodule
, mmodule
, "Object")
570 var mclass
= nclassdef
.mclass
.as(not null)
571 var mclassdef
= nclassdef
.mclassdef
.as(not null)
574 # Build the classes of the module `nmodule'.
575 # REQUIRE: classes of imported modules are already build. (let `build_all_classes' do the job)
576 private fun build_classes
(nmodule
: AModule)
578 # Force building recursively
579 if nmodule
.build_classes_is_done
then return
580 var mmodule
= nmodule
.mmodule
.as(not null)
581 for imp
in mmodule
.in_importation
.direct_greaters
do
582 build_classes
(mmodule2nmodule
[imp
])
586 for nclassdef
in nmodule
.n_classdefs
do
587 self.build_a_mclass
(nmodule
, nclassdef
)
590 # Create all classdefs
591 for nclassdef
in nmodule
.n_classdefs
do
592 self.build_a_mclassdef
(nmodule
, nclassdef
)
595 for nclassdef
in nmodule
.n_classdefs
do
596 if nclassdef
.mclassdef
== null then return # forward error
599 # Create inheritance on all classdefs
600 for nclassdef
in nmodule
.n_classdefs
do
601 self.build_a_mclassdef_inheritance
(nmodule
, nclassdef
)
604 # TODO: Check that the super-class is not intrusive
606 # TODO: Check that the super-class is not already known (by transitivity)
608 for nclassdef
in nmodule
.n_classdefs
do
609 self.build_properties
(nclassdef
)
612 nmodule
.build_classes_is_done
= true
615 # Register the nmodule associated to each mmodule
616 # FIXME: why not refine the MModule class with a nullable attribute?
617 var mmodule2nmodule
: HashMap[MModule, AModule] = new HashMap[MModule, AModule]
618 # Register the nclassdef associated to each mclassdef
619 # FIXME: why not refine the MClassDef class with a nullable attribute?
620 var mclassdef2nclassdef
: HashMap[MClassDef, AClassdef] = new HashMap[MClassDef, AClassdef]
621 # Register the npropdef associated to each mpropdef
622 # FIXME: why not refine the MPropDef class with a nullable attribute?
623 var mpropdef2npropdef
: HashMap[MPropDef, APropdef] = new HashMap[MPropDef, APropdef]
625 # Build the properties of `nclassdef'.
626 # REQUIRE: all superclasses are built.
627 private fun build_properties
(nclassdef
: AClassdef)
629 # Force building recursively
630 if nclassdef
.build_properties_is_done
then return
631 var mclassdef
= nclassdef
.mclassdef
.as(not null)
632 if mclassdef
.in_hierarchy
== null then return # Skip error
633 for superclassdef
in mclassdef
.in_hierarchy
.direct_greaters
do
634 build_properties
(mclassdef2nclassdef
[superclassdef
])
637 for npropdef
in nclassdef
.n_propdefs
do
638 npropdef
.build_property
(self, nclassdef
)
640 for npropdef
in nclassdef
.n_propdefs
do
641 npropdef
.build_signature
(self, nclassdef
)
643 for npropdef
in nclassdef
.n_propdefs
do
644 npropdef
.check_signature
(self, nclassdef
)
646 process_default_constructors
(nclassdef
)
647 nclassdef
.build_properties_is_done
= true
650 # Introduce or inherit default constructor
651 # This is the last part of `build_properties'.
652 private fun process_default_constructors
(nclassdef
: AClassdef)
654 var mclassdef
= nclassdef
.mclassdef
.as(not null)
656 # Are we a refinement
657 if not mclassdef
.is_intro
then return
659 # Is the class forbid constructors?
660 if not mclassdef
.mclass
.kind
.need_init
then return
662 # Is there already a constructor defined?
663 for mpropdef
in mclassdef
.mpropdefs
do
664 if not mpropdef
isa MMethodDef then continue
665 if mpropdef
.mproperty
.is_init
then return
668 if not nclassdef
isa AStdClassdef then return
670 var mmodule
= nclassdef
.mclassdef
.mmodule
671 # Do we inherit for a constructor?
672 var combine
= new Array[MMethod]
673 var inhc
: nullable MClass = null
674 for st
in mclassdef
.supertypes
do
676 if not c
.kind
.need_init
then continue
677 st
= st
.anchor_to
(mmodule
, nclassdef
.mclassdef
.bound_mtype
)
678 var candidate
= self.try_get_mproperty_by_name2
(nclassdef
, mmodule
, st
, "init").as(nullable MMethod)
679 if candidate
!= null and candidate
.intro
.msignature
.arity
== 0 then
680 combine
.add
(candidate
)
683 var inhc2
= c
.inherit_init_from
684 if inhc2
== null then inhc2
= c
685 if inhc2
== inhc
then continue
687 self.error
(nclassdef
, "Error: Cannot provide a defaut constructor: conflict for {inhc} and {c}")
692 if combine
.is_empty
and inhc
!= null then
693 # TODO: actively inherit the consturctor
694 self.toolcontext
.info
("{mclassdef} inherits all constructors from {inhc}", 3)
695 mclassdef
.mclass
.inherit_init_from
= inhc
698 if not combine
.is_empty
and inhc
!= null then
699 self.error
(nclassdef
, "Error: Cannot provide a defaut constructor: conflict for {combine.join(", ")} and {inhc}")
703 if not combine
.is_empty
then
704 nclassdef
.super_inits
= combine
705 var mprop
= new MMethod(mclassdef
, "init", mclassdef
.mclass
.visibility
)
706 var mpropdef
= new MMethodDef(mclassdef
, mprop
, nclassdef
.location
)
707 var mparameters
= new Array[MParameter]
708 var msignature
= new MSignature(mparameters
, null)
709 mpropdef
.msignature
= msignature
711 nclassdef
.mfree_init
= mpropdef
712 self.toolcontext
.info
("{mclassdef} gets a free empty constructor {mpropdef}{msignature}", 3)
716 # Collect undefined attributes
717 var mparameters
= new Array[MParameter]
718 for npropdef
in nclassdef
.n_propdefs
do
719 if npropdef
isa AAttrPropdef and npropdef
.n_expr
== null then
720 var paramname
= npropdef
.mpropdef
.mproperty
.name
.substring_from
(1)
721 var ret_type
= npropdef
.mpropdef
.static_mtype
722 if ret_type
== null then return
723 var mparameter
= new MParameter(paramname
, ret_type
, false)
724 mparameters
.add
(mparameter
)
728 var mprop
= new MMethod(mclassdef
, "init", mclassdef
.mclass
.visibility
)
729 var mpropdef
= new MMethodDef(mclassdef
, mprop
, nclassdef
.location
)
730 var msignature
= new MSignature(mparameters
, null)
731 mpropdef
.msignature
= msignature
733 nclassdef
.mfree_init
= mpropdef
734 self.toolcontext
.info
("{mclassdef} gets a free constructor for attributes {mpropdef}{msignature}", 3)
737 # Return the static type associated to the node `ntype'.
738 # `classdef' is the context where the call is made (used to understand formal types)
739 # The mmodule used as context is `nclassdef.mmodule'
740 # In case of problem, an error is displayed on `ntype' and null is returned.
741 # FIXME: the name "resolve_mtype" is awful
742 fun resolve_mtype
(nclassdef
: AClassdef, ntype
: AType): nullable MType
744 var name
= ntype
.n_id
.text
745 var mclassdef
= nclassdef
.mclassdef
746 var mmodule
= nclassdef
.parent
.as(AModule).mmodule
.as(not null)
750 if mclassdef
!= null then
751 var prop
= try_get_mproperty_by_name
(ntype
, mclassdef
, name
).as(nullable MVirtualTypeProp)
753 if not ntype
.n_types
.is_empty
then
754 error
(ntype
, "Type error: formal type {name} cannot have formal parameters.")
756 res
= prop
.mvirtualtype
757 if ntype
.n_kwnullable
!= null then res
= res
.as_nullable
762 # Check parameter type
763 if mclassdef
!= null and mclassdef
.parameter_names
.has
(name
) then
764 if not ntype
.n_types
.is_empty
then
765 error
(ntype
, "Type error: formal type {name} cannot have formal parameters.")
767 for i
in [0..mclassdef
.parameter_names
.length
[ do
768 if mclassdef
.parameter_names
[i
] == name
then
769 res
= mclassdef
.mclass
.mclass_type
.as(MGenericType).arguments
[i
]
770 if ntype
.n_kwnullable
!= null then res
= res
.as_nullable
778 var mclass
= try_get_mclass_by_name
(ntype
, mmodule
, name
)
779 if mclass
!= null then
780 var arity
= ntype
.n_types
.length
781 if arity
!= mclass
.arity
then
783 error
(ntype
, "Type error: '{name}' is a generic class.")
784 else if mclass
.arity
== 0 then
785 error
(ntype
, "Type error: '{name}' is not a generic class.")
787 error
(ntype
, "Type error: '{name}' has {mclass.arity} parameters ({arity} are provided).")
792 res
= mclass
.mclass_type
793 if ntype
.n_kwnullable
!= null then res
= res
.as_nullable
796 var mtypes
= new Array[MType]
797 for nt
in ntype
.n_types
do
798 var mt
= resolve_mtype
(nclassdef
, nt
)
799 if mt
== null then return null # Forward error
802 res
= mclass
.get_mtype
(mtypes
)
803 if ntype
.n_kwnullable
!= null then res
= res
.as_nullable
808 # If everything fail, then give up :(
809 error
(ntype
, "Type error: class {name} not found in module {mmodule}.")
813 # Helper function to display an error on a node.
814 # Alias for `self.toolcontext.error(n.hot_location, text)'
815 fun error
(n
: ANode, text
: String)
817 self.toolcontext
.error
(n
.hot_location
, text
)
820 # Helper function to display a warning on a node.
821 # Alias for: `self.toolcontext.warning(n.hot_location, text)'
822 fun warning
(n
: ANode, text
: String)
824 self.toolcontext
.warning
(n
.hot_location
, text
)
829 # The associated MModule once build by a `ModelBuilder'
830 var mmodule
: nullable MModule
831 # Flag that indicate if the importation is already completed
832 var is_importation_done
: Bool = false
833 # Flag that indicate if the class and prop building is already completed
834 var build_classes_is_done
: Bool = false
838 # The class whose self inherit all the constructors.
839 # 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
840 var inherit_init_from
: nullable MClass = null
843 redef class AClassdef
844 # The associated MClass once build by a `ModelBuilder'
845 var mclass
: nullable MClass
846 # The associated MClassDef once build by a `ModelBuilder'
847 var mclassdef
: nullable MClassDef
848 var build_properties_is_done
: Bool = false
849 # The list of super-constructor to call at the start of the free constructor
850 # 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
851 var super_inits
: nullable Collection[MMethod] = null
853 # The free init (implicitely constructed by the class if required)
854 var mfree_init
: nullable MMethodDef = null
857 redef class AClasskind
858 # The class kind associated with the AST node class
859 private fun mkind
: MClassKind is abstract
861 redef class AConcreteClasskind
862 redef fun mkind
do return concrete_kind
864 redef class AAbstractClasskind
865 redef fun mkind
do return abstract_kind
867 redef class AInterfaceClasskind
868 redef fun mkind
do return interface_kind
870 redef class AEnumClasskind
871 redef fun mkind
do return enum_kind
873 redef class AExternClasskind
874 redef fun mkind
do return extern_kind
877 redef class AVisibility
878 # The visibility level associated with the AST node class
879 private fun mvisibility
: MVisibility is abstract
881 redef class AIntrudeVisibility
882 redef fun mvisibility
do return intrude_visibility
884 redef class APublicVisibility
885 redef fun mvisibility
do return public_visibility
887 redef class AProtectedVisibility
888 redef fun mvisibility
do return protected_visibility
890 redef class APrivateVisibility
891 redef fun mvisibility
do return private_visibility
898 # Join the text of all tokens
899 # Used to get the 'real name' of method definitions.
900 fun collect_text
: String
902 var v
= new TextCollectorVisitor
909 private class TextCollectorVisitor
911 var text
: String = ""
914 if n
isa Token then text
+= n
.text
920 private fun build_property
(modelbuilder
: ModelBuilder, nclassdef
: AClassdef)
923 private fun build_signature
(modelbuilder
: ModelBuilder, nclassdef
: AClassdef)
926 private fun check_signature
(modelbuilder
: ModelBuilder, nclassdef
: AClassdef)
929 private fun new_property_visibility
(modelbuilder
: ModelBuilder, nclassdef
: AClassdef, nvisibility
: nullable AVisibility): MVisibility
931 var mvisibility
= public_visibility
932 if nvisibility
!= null then mvisibility
= nvisibility
.mvisibility
933 if nclassdef
.mclassdef
.mclass
.visibility
== private_visibility
then
934 if mvisibility
== protected_visibility
then
935 assert nvisibility
!= null
936 modelbuilder
.error
(nvisibility
, "Error: The only legal visibility for properties in a private class is private.")
937 else if mvisibility
== private_visibility
then
938 assert nvisibility
!= null
940 # modelbuilder.warning(nvisibility, "Warning: private is unrequired since the only legal visibility for properties in a private class is private.")
942 mvisibility
= private_visibility
947 private fun check_redef_property_visibility
(modelbuilder
: ModelBuilder, nclassdef
: AClassdef, nvisibility
: nullable AVisibility, mprop
: MProperty)
949 if nvisibility
== null then return
950 var mvisibility
= nvisibility
.mvisibility
951 if mvisibility
!= mprop
.visibility
and mvisibility
!= public_visibility
then
952 modelbuilder
.error
(nvisibility
, "Error: redefinition changed the visibility from a {mprop.visibility} to a {mvisibility}")
956 private fun check_redef_keyword
(modelbuilder
: ModelBuilder, nclassdef
: AClassdef, kwredef
: nullable Token, need_redef
: Bool, mprop
: MProperty)
958 if kwredef
== null then
960 modelbuilder
.error
(self, "Redef error: {nclassdef.mclassdef.mclass}::{mprop.name} is an inherited property. To redefine it, add the redef keyword.")
963 if not need_redef
then
964 modelbuilder
.error
(self, "Error: No property {nclassdef.mclassdef.mclass}::{mprop.name} is inherited. Remove the redef keyword to define a new property.")
971 redef class ASignature
972 # Is the model builder has correctly visited the signature
973 var is_visited
= false
974 # Names of parameters from the AST
975 # REQUIRE: is_visited
976 var param_names
= new Array[String]
977 # Types of parameters from the AST
978 # REQUIRE: is_visited
979 var param_types
= new Array[MType]
980 # Rank of the vararg (of -1 if none)
981 # REQUIRE: is_visited
982 var vararg_rank
: Int = -1
984 var ret_type
: nullable MType = null
986 # Visit and fill information about a signature
987 private fun visit_signature
(modelbuilder
: ModelBuilder, nclassdef
: AClassdef): Bool
989 var param_names
= self.param_names
990 var param_types
= self.param_types
991 for np
in self.n_params
do
992 param_names
.add
(np
.n_id
.text
)
993 var ntype
= np
.n_type
994 if ntype
!= null then
995 var mtype
= modelbuilder
.resolve_mtype
(nclassdef
, ntype
)
996 if mtype
== null then return false # Skip error
997 for i
in [0..param_names
.length-param_types
.length
[ do
998 param_types
.add
(mtype
)
1000 if np
.n_dotdotdot
!= null then
1001 if self.vararg_rank
!= -1 then
1002 modelbuilder
.error
(np
, "Error: {param_names[self.vararg_rank]} is already a vararg")
1005 self.vararg_rank
= param_names
.length
- 1
1010 var ntype
= self.n_type
1011 if ntype
!= null then
1012 self.ret_type
= modelbuilder
.resolve_mtype
(nclassdef
, ntype
)
1013 if self.ret_type
== null then return false # Skip errir
1016 for nclosure
in self.n_closure_decls
do
1017 if not nclosure
.n_signature
.visit_signature
(modelbuilder
, nclassdef
) then return false
1020 self.is_visited
= true
1024 # Build a visited signature
1025 fun build_signature
(modelbuilder
: ModelBuilder, nclassdef
: AClassdef): nullable MSignature
1027 if param_names
.length
!= param_types
.length
then
1028 # Some parameters are typed, other parameters are not typed.
1029 modelbuilder
.error
(self.n_params
[param_types
.length
], "Error: Untyped parameter `{param_names[param_types.length]}'.")
1033 var mparameters
= new Array[MParameter]
1034 for i
in [0..param_names
.length
[ do
1035 var mparameter
= new MParameter(param_names
[i
], param_types
[i
], i
== vararg_rank
)
1036 mparameters
.add
(mparameter
)
1039 var msignature
= new MSignature(mparameters
, ret_type
)
1044 redef class AMethPropdef
1045 # The associated MMethodDef once build by a `ModelBuilder'
1046 var mpropdef
: nullable MMethodDef
1048 # The associated super init if any
1049 var super_init
: nullable MMethod
1050 redef fun build_property
(modelbuilder
, nclassdef
)
1052 var is_init
= self isa AInitPropdef
1053 var mclassdef
= nclassdef
.mclassdef
.as(not null)
1055 var amethodid
= self.n_methid
1056 var name_node
: ANode
1057 if amethodid
== null then
1058 if self isa AMainMethPropdef then
1061 else if self isa AConcreteInitPropdef then
1063 name_node
= self.n_kwinit
1064 else if self isa AExternInitPropdef then
1066 name_node
= self.n_kwnew
1070 else if amethodid
isa AIdMethid then
1071 name
= amethodid
.n_id
.text
1072 name_node
= amethodid
1074 # operator, bracket or assign
1075 name
= amethodid
.collect_text
1076 name_node
= amethodid
1078 if name
== "-" and self.n_signature
.n_params
.length
== 0 then
1083 var mprop
: nullable MMethod = null
1084 if not is_init
or n_kwredef
!= null then mprop
= modelbuilder
.try_get_mproperty_by_name
(name_node
, mclassdef
, name
).as(nullable MMethod)
1085 if mprop
== null then
1086 var mvisibility
= new_property_visibility
(modelbuilder
, nclassdef
, self.n_visibility
)
1087 mprop
= new MMethod(mclassdef
, name
, mvisibility
)
1088 mprop
.is_init
= is_init
1089 mprop
.is_new
= self isa AExternInitPropdef
1090 self.check_redef_keyword
(modelbuilder
, nclassdef
, n_kwredef
, false, mprop
)
1092 if n_kwredef
== null then
1093 if self isa AMainMethPropdef then
1096 self.check_redef_keyword
(modelbuilder
, nclassdef
, n_kwredef
, true, mprop
)
1099 check_redef_property_visibility
(modelbuilder
, nclassdef
, self.n_visibility
, mprop
)
1102 var mpropdef
= new MMethodDef(mclassdef
, mprop
, self.location
)
1104 self.mpropdef
= mpropdef
1105 modelbuilder
.mpropdef2npropdef
[mpropdef
] = self
1106 if mpropdef
.is_intro
then
1107 modelbuilder
.toolcontext
.info
("{mpropdef} introduces new method {mprop.full_name}", 3)
1109 modelbuilder
.toolcontext
.info
("{mpropdef} redefines method {mprop.full_name}", 3)
1113 redef fun build_signature
(modelbuilder
, nclassdef
)
1115 var mpropdef
= self.mpropdef
1116 if mpropdef
== null then return # Error thus skiped
1117 var mmodule
= mpropdef
.mclassdef
.mmodule
1118 var nsig
= self.n_signature
1120 # Retrieve info from the signature AST
1121 var param_names
= new Array[String] # Names of parameters from the AST
1122 var param_types
= new Array[MType] # Types of parameters from the AST
1123 var vararg_rank
= -1
1124 var ret_type
: nullable MType = null # Return type from the AST
1125 if nsig
!= null then
1126 if not nsig
.visit_signature
(modelbuilder
, nclassdef
) then return
1127 param_names
= nsig
.param_names
1128 param_types
= nsig
.param_types
1129 vararg_rank
= nsig
.vararg_rank
1130 ret_type
= nsig
.ret_type
1133 # Look for some signature to inherit
1134 # FIXME: do not inherit from the intro, but from the most specific
1135 var msignature
: nullable MSignature = null
1136 if not mpropdef
.is_intro
then
1137 msignature
= mpropdef
.mproperty
.intro
.msignature
1138 if msignature
== null then return # Skip error
1139 else if mpropdef
.mproperty
.is_init
then
1140 # FIXME UGLY: inherit signature from a super-constructor
1141 for msupertype
in nclassdef
.mclassdef
.supertypes
do
1142 msupertype
= msupertype
.anchor_to
(mmodule
, nclassdef
.mclassdef
.bound_mtype
)
1143 var candidate
= modelbuilder
.try_get_mproperty_by_name2
(self, mmodule
, msupertype
, mpropdef
.mproperty
.name
)
1144 if candidate
!= null then
1145 if msignature
== null then
1146 msignature
= candidate
.intro
.as(MMethodDef).msignature
1152 # Inherit the signature
1153 if msignature
!= null and param_names
.length
!= param_types
.length
and param_names
.length
== msignature
.arity
and param_types
.length
== 0 then
1154 # Parameters are untyped, thus inherit them
1155 param_types
= new Array[MType]
1156 for mparameter
in msignature
.mparameters
do
1157 param_types
.add
(mparameter
.mtype
)
1159 vararg_rank
= msignature
.vararg_rank
1161 if msignature
!= null and ret_type
== null then
1162 ret_type
= msignature
.return_mtype
1165 if param_names
.length
!= param_types
.length
then
1166 # Some parameters are typed, other parameters are not typed.
1167 modelbuilder
.error
(nsig
.n_params
[param_types
.length
], "Error: Untyped parameter `{param_names[param_types.length]}'.")
1171 var mparameters
= new Array[MParameter]
1172 for i
in [0..param_names
.length
[ do
1173 var mparameter
= new MParameter(param_names
[i
], param_types
[i
], i
== vararg_rank
)
1174 mparameters
.add
(mparameter
)
1177 msignature
= new MSignature(mparameters
, ret_type
)
1178 mpropdef
.msignature
= msignature
1180 if nsig
!= null then
1181 for nclosure
in nsig
.n_closure_decls
do
1182 var clos_signature
= nclosure
.n_signature
.build_signature
(modelbuilder
, nclassdef
)
1183 if clos_signature
== null then return
1184 var mparameter
= new MParameter(nclosure
.n_id
.text
, clos_signature
, false)
1185 msignature
.mclosures
.add
(mparameter
)
1191 redef fun check_signature
(modelbuilder
, nclassdef
)
1193 var mpropdef
= self.mpropdef
1194 if mpropdef
== null then return # Error thus skiped
1195 var mmodule
= mpropdef
.mclassdef
.mmodule
1196 var nsig
= self.n_signature
1197 var mysignature
= self.mpropdef
.msignature
1198 if mysignature
== null then return # Error thus skiped
1200 # Lookup for signature in the precursor
1201 # FIXME all precursors should be considered
1202 if not mpropdef
.is_intro
then
1203 var msignature
= mpropdef
.mproperty
.intro
.msignature
1204 if msignature
== null then return
1206 if mysignature
.arity
!= msignature
.arity
then
1208 if nsig
!= null then node
= nsig
else node
= self
1209 modelbuilder
.error
(node
, "Redef Error: {mysignature.arity} parameters found, {msignature.arity} expected. Signature is {mpropdef}{msignature}")
1212 var precursor_ret_type
= msignature
.return_mtype
1213 var ret_type
= mysignature
.return_mtype
1214 if ret_type
!= null and precursor_ret_type
== null then
1215 modelbuilder
.error
(nsig
.n_type
.as(not null), "Redef Error: {mpropdef.mproperty} is a procedure, not a function.")
1219 if mysignature
.arity
> 0 then
1220 # Check parameters types
1221 for i
in [0..mysignature
.arity
[ do
1222 var myt
= mysignature
.mparameters
[i
].mtype
1223 var prt
= msignature
.mparameters
[i
].mtype
1224 if not myt
.is_subtype
(mmodule
, nclassdef
.mclassdef
.bound_mtype
, prt
) and
1225 not prt
.is_subtype
(mmodule
, nclassdef
.mclassdef
.bound_mtype
, myt
) then
1226 modelbuilder
.error
(nsig
.n_params
[i
], "Redef Error: Wrong type for parameter `{mysignature.mparameters[i].name}'. found {myt}, expected {prt}.")
1230 if precursor_ret_type
!= null then
1231 if ret_type
== null then
1232 # Inherit the return type
1233 ret_type
= precursor_ret_type
1234 else if not ret_type
.is_subtype
(mmodule
, nclassdef
.mclassdef
.bound_mtype
, precursor_ret_type
) then
1235 modelbuilder
.error
(nsig
.n_type
.as(not null), "Redef Error: Wrong return type. found {ret_type}, expected {precursor_ret_type}.")
1242 redef class AAttrPropdef
1243 # The associated MAttributeDef once build by a `ModelBuilder'
1244 var mpropdef
: nullable MAttributeDef
1245 # The associated getter (read accessor) if any
1246 var mreadpropdef
: nullable MMethodDef
1247 # The associated setter (write accessor) if any
1248 var mwritepropdef
: nullable MMethodDef
1249 redef fun build_property
(modelbuilder
, nclassdef
)
1251 var mclassdef
= nclassdef
.mclassdef
.as(not null)
1252 var mclass
= mclassdef
.mclass
1255 if self.n_id
!= null then
1256 name
= self.n_id
.text
1258 name
= self.n_id2
.text
1261 if mclass
.kind
== interface_kind
or mclassdef
.mclass
.kind
== enum_kind
then
1262 modelbuilder
.error
(self, "Error: Attempt to define attribute {name} in the interface {mclass}.")
1263 else if mclass
.kind
== enum_kind
then
1264 modelbuilder
.error
(self, "Error: Attempt to define attribute {name} in the enum class {mclass}.")
1269 # Old attribute style
1270 var mprop
= modelbuilder
.try_get_mproperty_by_name
(nid
, mclassdef
, name
)
1271 if mprop
== null then
1272 var mvisibility
= new_property_visibility
(modelbuilder
, nclassdef
, self.n_visibility
)
1273 mprop
= new MAttribute(mclassdef
, name
, mvisibility
)
1274 self.check_redef_keyword
(modelbuilder
, nclassdef
, self.n_kwredef
, false, mprop
)
1276 assert mprop
isa MAttribute
1277 check_redef_property_visibility
(modelbuilder
, nclassdef
, self.n_visibility
, mprop
)
1278 self.check_redef_keyword
(modelbuilder
, nclassdef
, self.n_kwredef
, true, mprop
)
1280 var mpropdef
= new MAttributeDef(mclassdef
, mprop
, self.location
)
1281 self.mpropdef
= mpropdef
1282 modelbuilder
.mpropdef2npropdef
[mpropdef
] = self
1284 var nreadable
= self.n_readable
1285 if nreadable
!= null then
1286 var readname
= name
.substring_from
(1)
1287 var mreadprop
= modelbuilder
.try_get_mproperty_by_name
(nid
, mclassdef
, readname
).as(nullable MMethod)
1288 if mreadprop
== null then
1289 var mvisibility
= new_property_visibility
(modelbuilder
, nclassdef
, nreadable
.n_visibility
)
1290 mreadprop
= new MMethod(mclassdef
, readname
, mvisibility
)
1291 self.check_redef_keyword
(modelbuilder
, nclassdef
, nreadable
.n_kwredef
, false, mreadprop
)
1293 self.check_redef_keyword
(modelbuilder
, nclassdef
, nreadable
.n_kwredef
, true, mreadprop
)
1294 check_redef_property_visibility
(modelbuilder
, nclassdef
, nreadable
.n_visibility
, mreadprop
)
1296 var mreadpropdef
= new MMethodDef(mclassdef
, mreadprop
, self.location
)
1297 self.mreadpropdef
= mreadpropdef
1298 modelbuilder
.mpropdef2npropdef
[mreadpropdef
] = self
1301 var nwritable
= self.n_writable
1302 if nwritable
!= null then
1303 var writename
= name
.substring_from
(1) + "="
1304 var mwriteprop
= modelbuilder
.try_get_mproperty_by_name
(nid
, mclassdef
, writename
).as(nullable MMethod)
1305 if mwriteprop
== null then
1306 var mvisibility
= new_property_visibility
(modelbuilder
, nclassdef
, nwritable
.n_visibility
)
1307 mwriteprop
= new MMethod(mclassdef
, writename
, mvisibility
)
1308 self.check_redef_keyword
(modelbuilder
, nclassdef
, nwritable
.n_kwredef
, false, mwriteprop
)
1310 self.check_redef_keyword
(modelbuilder
, nclassdef
, nwritable
.n_kwredef
, true, mwriteprop
)
1311 check_redef_property_visibility
(modelbuilder
, nclassdef
, nwritable
.n_visibility
, mwriteprop
)
1313 var mwritepropdef
= new MMethodDef(mclassdef
, mwriteprop
, self.location
)
1314 self.mwritepropdef
= mwritepropdef
1315 modelbuilder
.mpropdef2npropdef
[mwritepropdef
] = self
1318 # New attribute style
1319 var nid2
= self.n_id2
.as(not null)
1320 var mprop
= new MAttribute(mclassdef
, "@" + name
, none_visibility
)
1321 var mpropdef
= new MAttributeDef(mclassdef
, mprop
, self.location
)
1322 self.mpropdef
= mpropdef
1323 modelbuilder
.mpropdef2npropdef
[mpropdef
] = self
1326 var mreadprop
= modelbuilder
.try_get_mproperty_by_name
(nid2
, mclassdef
, readname
).as(nullable MMethod)
1327 if mreadprop
== null then
1328 var mvisibility
= new_property_visibility
(modelbuilder
, nclassdef
, self.n_visibility
)
1329 mreadprop
= new MMethod(mclassdef
, readname
, mvisibility
)
1330 self.check_redef_keyword
(modelbuilder
, nclassdef
, n_kwredef
, false, mreadprop
)
1332 self.check_redef_keyword
(modelbuilder
, nclassdef
, n_kwredef
, true, mreadprop
)
1333 check_redef_property_visibility
(modelbuilder
, nclassdef
, self.n_visibility
, mreadprop
)
1335 var mreadpropdef
= new MMethodDef(mclassdef
, mreadprop
, self.location
)
1336 self.mreadpropdef
= mreadpropdef
1337 modelbuilder
.mpropdef2npropdef
[mreadpropdef
] = self
1339 var writename
= name
+ "="
1340 var nwritable
= self.n_writable
1341 var mwriteprop
= modelbuilder
.try_get_mproperty_by_name
(nid2
, mclassdef
, writename
).as(nullable MMethod)
1342 var nwkwredef
: nullable Token = null
1343 if nwritable
!= null then nwkwredef
= nwritable
.n_kwredef
1344 if mwriteprop
== null then
1346 if nwritable
!= null then
1347 mvisibility
= new_property_visibility
(modelbuilder
, nclassdef
, nwritable
.n_visibility
)
1349 mvisibility
= private_visibility
1351 mwriteprop
= new MMethod(mclassdef
, writename
, mvisibility
)
1352 self.check_redef_keyword
(modelbuilder
, nclassdef
, nwkwredef
, false, mwriteprop
)
1354 self.check_redef_keyword
(modelbuilder
, nclassdef
, nwkwredef
, true, mwriteprop
)
1355 if nwritable
!= null then
1356 check_redef_property_visibility
(modelbuilder
, nclassdef
, nwritable
.n_visibility
, mwriteprop
)
1359 var mwritepropdef
= new MMethodDef(mclassdef
, mwriteprop
, self.location
)
1360 self.mwritepropdef
= mwritepropdef
1361 modelbuilder
.mpropdef2npropdef
[mwritepropdef
] = self
1365 redef fun build_signature
(modelbuilder
, nclassdef
)
1367 var mpropdef
= self.mpropdef
1368 if mpropdef
== null then return # Error thus skiped
1369 var mmodule
= mpropdef
.mclassdef
.mmodule
1370 var mtype
: nullable MType = null
1372 var ntype
= self.n_type
1373 if ntype
!= null then
1374 mtype
= modelbuilder
.resolve_mtype
(nclassdef
, ntype
)
1375 if mtype
== null then return
1378 if mtype
== null then
1379 var nexpr
= self.n_expr
1380 if nexpr
!= null then
1381 if nexpr
isa ANewExpr then
1382 mtype
= modelbuilder
.resolve_mtype
(nclassdef
, nexpr
.n_type
)
1383 else if nexpr
isa AIntExpr then
1384 var cla
= modelbuilder
.try_get_mclass_by_name
(nexpr
, mmodule
, "Int")
1385 if cla
!= null then mtype
= cla
.mclass_type
1386 else if nexpr
isa AFloatExpr then
1387 var cla
= modelbuilder
.try_get_mclass_by_name
(nexpr
, mmodule
, "Float")
1388 if cla
!= null then mtype
= cla
.mclass_type
1389 else if nexpr
isa ACharExpr then
1390 var cla
= modelbuilder
.try_get_mclass_by_name
(nexpr
, mmodule
, "Char")
1391 if cla
!= null then mtype
= cla
.mclass_type
1392 else if nexpr
isa ABoolExpr then
1393 var cla
= modelbuilder
.try_get_mclass_by_name
(nexpr
, mmodule
, "Bool")
1394 if cla
!= null then mtype
= cla
.mclass_type
1395 else if nexpr
isa ASuperstringExpr then
1396 var cla
= modelbuilder
.try_get_mclass_by_name
(nexpr
, mmodule
, "String")
1397 if cla
!= null then mtype
= cla
.mclass_type
1398 else if nexpr
isa AStringFormExpr then
1399 var cla
= modelbuilder
.try_get_mclass_by_name
(nexpr
, mmodule
, "String")
1400 if cla
!= null then mtype
= cla
.mclass_type
1402 modelbuilder
.error
(self, "Error: Untyped attribute {mpropdef}. Implicit typing allowed only for literals and new.")
1406 modelbuilder
.error
(self, "Error: Untyped attribute {mpropdef}")
1410 if mtype
== null then return
1412 mpropdef
.static_mtype
= mtype
1414 var mreadpropdef
= self.mreadpropdef
1415 if mreadpropdef
!= null then
1416 var msignature
= new MSignature(new Array[MParameter], mtype
)
1417 mreadpropdef
.msignature
= msignature
1420 var msritepropdef
= self.mwritepropdef
1421 if mwritepropdef
!= null then
1423 if n_id
!= null then
1424 name
= n_id
.text
.substring_from
(1)
1428 var mparameter
= new MParameter(name
, mtype
, false)
1429 var msignature
= new MSignature([mparameter
], null)
1430 mwritepropdef
.msignature
= msignature
1434 redef fun check_signature
(modelbuilder
, nclassdef
)
1436 var mpropdef
= self.mpropdef
1437 if mpropdef
== null then return # Error thus skiped
1438 var mmodule
= mpropdef
.mclassdef
.mmodule
1439 var ntype
= self.n_type
1440 var mtype
= self.mpropdef
.static_mtype
1441 if mtype
== null then return # Error thus skiped
1443 # Lookup for signature in the precursor
1444 # FIXME all precursors should be considered
1445 if not mpropdef
.is_intro
then
1446 var precursor_type
= mpropdef
.mproperty
.intro
.static_mtype
1447 if precursor_type
== null then return
1449 if mtype
!= precursor_type
then
1450 modelbuilder
.error
(ntype
.as(not null), "Redef Error: Wrong static type. found {mtype}, expected {precursor_type}.")
1455 # Check getter and setter
1456 var meth
= self.mreadpropdef
1457 if meth
!= null then self.check_method_signature
(modelbuilder
, nclassdef
, meth
)
1458 meth
= self.mwritepropdef
1459 if meth
!= null then self.check_method_signature
(modelbuilder
, nclassdef
, meth
)
1462 private fun check_method_signature
(modelbuilder
: ModelBuilder, nclassdef
: AClassdef, mpropdef
: MMethodDef)
1464 var mmodule
= mpropdef
.mclassdef
.mmodule
1465 var nsig
= self.n_type
1466 var mysignature
= mpropdef
.msignature
1467 if mysignature
== null then return # Error thus skiped
1469 # Lookup for signature in the precursor
1470 # FIXME all precursors should be considered
1471 if not mpropdef
.is_intro
then
1472 var msignature
= mpropdef
.mproperty
.intro
.msignature
1473 if msignature
== null then return
1475 if mysignature
.arity
!= msignature
.arity
then
1477 if nsig
!= null then node
= nsig
else node
= self
1478 modelbuilder
.error
(node
, "Redef Error: {mysignature.arity} parameters found, {msignature.arity} expected. Signature is {mpropdef}{msignature}")
1481 var precursor_ret_type
= msignature
.return_mtype
1482 var ret_type
= mysignature
.return_mtype
1483 if ret_type
!= null and precursor_ret_type
== null then
1485 if nsig
!= null then node
= nsig
else node
= self
1486 modelbuilder
.error
(node
, "Redef Error: {mpropdef.mproperty} is a procedure, not a function.")
1490 if mysignature
.arity
> 0 then
1491 # Check parameters types
1492 for i
in [0..mysignature
.arity
[ do
1493 var myt
= mysignature
.mparameters
[i
].mtype
1494 var prt
= msignature
.mparameters
[i
].mtype
1495 if not myt
.is_subtype
(mmodule
, nclassdef
.mclassdef
.bound_mtype
, prt
) and
1496 not prt
.is_subtype
(mmodule
, nclassdef
.mclassdef
.bound_mtype
, myt
) then
1498 if nsig
!= null then node
= nsig
else node
= self
1499 modelbuilder
.error
(node
, "Redef Error: Wrong type for parameter `{mysignature.mparameters[i].name}'. found {myt}, expected {prt}.")
1503 if precursor_ret_type
!= null then
1504 if ret_type
== null then
1505 # Inherit the return type
1506 ret_type
= precursor_ret_type
1507 else if not ret_type
.is_subtype
(mmodule
, nclassdef
.mclassdef
.bound_mtype
, precursor_ret_type
) then
1509 if nsig
!= null then node
= nsig
else node
= self
1510 modelbuilder
.error
(node
, "Redef Error: Wrong return type. found {ret_type}, expected {precursor_ret_type}.")
1517 redef class ATypePropdef
1518 # The associated MVirtualTypeDef once build by a `ModelBuilder'
1519 var mpropdef
: nullable MVirtualTypeDef
1520 redef fun build_property
(modelbuilder
, nclassdef
)
1522 var mclassdef
= nclassdef
.mclassdef
.as(not null)
1523 var name
= self.n_id
.text
1524 var mprop
= modelbuilder
.try_get_mproperty_by_name
(self.n_id
, mclassdef
, name
)
1525 if mprop
== null then
1526 var mvisibility
= new_property_visibility
(modelbuilder
, nclassdef
, self.n_visibility
)
1527 mprop
= new MVirtualTypeProp(mclassdef
, name
, mvisibility
)
1528 self.check_redef_keyword
(modelbuilder
, nclassdef
, self.n_kwredef
, false, mprop
)
1530 self.check_redef_keyword
(modelbuilder
, nclassdef
, self.n_kwredef
, true, mprop
)
1531 assert mprop
isa MVirtualTypeProp
1532 check_redef_property_visibility
(modelbuilder
, nclassdef
, self.n_visibility
, mprop
)
1534 var mpropdef
= new MVirtualTypeDef(mclassdef
, mprop
, self.location
)
1535 self.mpropdef
= mpropdef
1538 redef fun build_signature
(modelbuilder
, nclassdef
)
1540 var mpropdef
= self.mpropdef
1541 if mpropdef
== null then return # Error thus skiped
1542 var mmodule
= mpropdef
.mclassdef
.mmodule
1543 var mtype
: nullable MType = null
1545 var ntype
= self.n_type
1546 mtype
= modelbuilder
.resolve_mtype
(nclassdef
, ntype
)
1547 if mtype
== null then return
1549 mpropdef
.bound
= mtype
1550 # print "{mpropdef}: {mtype}"
1553 redef fun check_signature
(modelbuilder
, nclassdef
)
1555 var bound
= self.mpropdef
.bound
1557 # Fast case: the bound is not a formal type
1558 if not bound
isa MVirtualType then return
1560 var mmodule
= nclassdef
.mclassdef
.mmodule
1561 var anchor
= nclassdef
.mclassdef
.bound_mtype
1563 # Slow case: progress on each resolution until: (i) we loop, or (ii) we found a non formal type
1564 var seen
= [self.mpropdef
.mproperty
.mvirtualtype
]
1566 if seen
.has
(bound
) then
1568 modelbuilder
.error
(self, "Error: circularity of virtual type definition: {seen.join(" -> ")}")
1572 var next
= bound
.lookup_bound
(mmodule
, anchor
)
1573 if not next
isa MVirtualType then return