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
)
49 fun modelbuilder
: ModelBuilder do return modelbuilder_real
.as(not null)
50 private var modelbuilder_real
: nullable ModelBuilder = null
53 # A model builder knows how to load nit source files and build the associated model
54 # The important function is `parse_and_build' that does all the job.
55 # The others function can be used for specific tasks
57 # The model where new modules, classes and properties are added
60 # The toolcontext used to control the interaction with the user (getting options and displaying messages)
61 var toolcontext
: ToolContext
63 # Instantiate a modelbuilder for a model and a toolcontext
64 # Important, the options of the toolcontext must be correctly set (parse_option already called)
65 init(model
: Model, toolcontext
: ToolContext)
68 self.toolcontext
= toolcontext
69 assert toolcontext
.modelbuilder_real
== null
70 toolcontext
.modelbuilder_real
= self
72 # Setup the paths value
73 paths
.append
(toolcontext
.opt_path
.value
)
75 var path_env
= "NIT_PATH".environ
76 if not path_env
.is_empty
then
77 paths
.append
(path_env
.split_with
(':'))
80 path_env
= "NIT_DIR".environ
81 if not path_env
.is_empty
then
82 var libname
= "{path_env}/lib"
83 if libname
.file_exists
then paths
.add
(libname
)
86 var libname
= "{sys.program_name.dirname}/../lib"
87 if libname
.file_exists
then paths
.add
(libname
.simplify_path
)
90 # Load and analyze a bunch of modules.
91 # `modules' can contains filenames or module names.
92 # Imported modules are automatically loaded, builds and analysed.
93 # The result is the corresponding built modules.
94 # Errors and warnings are printed with the toolcontext.
96 # FIXME: Maybe just let the client do the loop (instead of playing with Sequences)
97 fun parse_and_build
(modules
: Sequence[String]): Array[MModule]
99 var mmodules
= parse
(modules
)
101 if self.toolcontext
.opt_only_parse
.value
then
102 self.toolcontext
.info
("--only-parse: stop processing", 2)
103 return new Array[MModule]
108 self.toolcontext
.info
("*** BUILD MODEL ***", 1)
109 self.build_all_classes
111 self.toolcontext
.info
("*** END BUILD MODEL: {time2-time1} ***", 2)
113 self.toolcontext
.check_errors
118 fun parse
(modules
: Sequence[String]): Array[MModule]
121 # Parse and recursively load
122 self.toolcontext
.info
("*** PARSE ***", 1)
123 var mmodules
= new Array[MModule]
125 var nmodule
= self.load_module
(null, a
)
126 if nmodule
== null then continue # Skip error
127 mmodules
.add
(nmodule
.mmodule
.as(not null))
130 self.toolcontext
.info
("*** END PARSE: {time1-time0} ***", 2)
132 self.toolcontext
.check_errors
136 # Return a class named `name' visible by the module `mmodule'.
137 # Visibility in modules is correctly handled.
138 # If no such a class exists, then null is returned.
139 # If more than one class exists, then an error on `anode' is displayed and null is returned.
140 # FIXME: add a way to handle class name conflict
141 fun try_get_mclass_by_name
(anode
: ANode, mmodule
: MModule, name
: String): nullable MClass
143 var classes
= model
.get_mclasses_by_name
(name
)
144 if classes
== null then
148 var res
: nullable MClass = null
149 for mclass
in classes
do
150 if not mmodule
.in_importation
<= mclass
.intro_mmodule
then continue
151 if not mmodule
.is_visible
(mclass
.intro_mmodule
, mclass
.visibility
) then continue
155 error
(anode
, "Ambigous class name '{name}'; conflict between {mclass.full_name} and {res.full_name}")
162 # Return a property named `name' on the type `mtype' visible in the module `mmodule'.
163 # Visibility in modules is correctly handled.
164 # Protected properties are returned (it is up to the caller to check and reject protected properties).
165 # If no such a property exists, then null is returned.
166 # If more than one property exists, then an error on `anode' is displayed and null is returned.
167 # FIXME: add a way to handle property name conflict
168 fun try_get_mproperty_by_name2
(anode
: ANode, mmodule
: MModule, mtype
: MType, name
: String): nullable MProperty
170 var props
= self.model
.get_mproperties_by_name
(name
)
171 if props
== null then
175 var cache
= self.try_get_mproperty_by_name2_cache
[mmodule
, mtype
, name
]
176 if cache
!= null then return cache
178 var res
: nullable MProperty = null
179 var ress
: nullable Array[MProperty] = null
180 for mprop
in props
do
181 if not mtype
.has_mproperty
(mmodule
, mprop
) then continue
182 if not mmodule
.is_visible
(mprop
.intro_mclassdef
.mmodule
, mprop
.visibility
) then continue
186 var restype
= res
.intro_mclassdef
.bound_mtype
187 var mproptype
= mprop
.intro_mclassdef
.bound_mtype
188 if restype
.is_subtype
(mmodule
, null, mproptype
) then
190 else if mproptype
.is_subtype
(mmodule
, null, restype
) then
193 if ress
== null then ress
= new Array[MProperty]
199 var restype
= res
.intro_mclassdef
.bound_mtype
201 var mproptype
= mprop
.intro_mclassdef
.bound_mtype
202 if not restype
.is_subtype
(mmodule
, null, mproptype
) then
203 self.error
(anode
, "Ambigous property name '{name}' for {mtype}; conflict between {mprop.full_name} and {res.full_name}")
209 self.try_get_mproperty_by_name2_cache
[mmodule
, mtype
, name
] = res
213 private var try_get_mproperty_by_name2_cache
: HashMap3[MModule, MType, String, nullable MProperty] = new HashMap3[MModule, MType, String, nullable MProperty]
216 # Alias for try_get_mproperty_by_name2(anode, mclassdef.mmodule, mclassdef.mtype, name)
217 fun try_get_mproperty_by_name
(anode
: ANode, mclassdef
: MClassDef, name
: String): nullable MProperty
219 return try_get_mproperty_by_name2
(anode
, mclassdef
.mmodule
, mclassdef
.bound_mtype
, name
)
222 # The list of directories to search for top level modules
223 # The list is initially set with :
224 # * the toolcontext --path option
225 # * the NIT_PATH environment variable
226 # * some heuristics including the NIT_DIR environment variable and the progname of the process
227 # Path can be added (or removed) by the client
228 var paths
: Array[String] = new Array[String]
230 # Get a module by its short name; if required, the module is loaded, parsed and its hierarchies computed.
231 # If `mmodule' is set, then the module search starts from it up to the top level (see `paths');
232 # if `mmodule' is null then the module is searched in the top level only.
233 # If no module exists or there is a name conflict, then an error on `anode' is displayed and null is returned.
234 # FIXME: add a way to handle module name conflict
235 fun get_mmodule_by_name
(anode
: ANode, mmodule
: nullable MModule, name
: String): nullable MModule
237 var origmmodule
= mmodule
238 var modules
= model
.get_mmodules_by_name
(name
)
240 var tries
= new Array[String]
242 var lastmodule
= mmodule
243 while mmodule
!= null do
244 var dirname
= mmodule
.location
.file
.filename
.dirname
246 # Determine the owner
247 var owner
: nullable MModule
248 if dirname
.basename
("") != mmodule
.name
then
249 owner
= mmodule
.direct_owner
254 # First, try the already known nested modules
255 if modules
!= null then
256 for candidate
in modules
do
257 if candidate
.direct_owner
== owner
then
263 # Second, try the directory to find a file
264 var try_file
= dirname
+ "/" + name
+ ".nit"
266 if try_file
.file_exists
then
267 var res
= self.load_module
(owner
, try_file
.simplify_path
)
268 if res
== null then return null # Forward error
269 return res
.mmodule
.as(not null)
272 # Third, try if the requested module is itself an owner
273 try_file
= dirname
+ "/" + name
+ "/" + name
+ ".nit"
274 if try_file
.file_exists
then
275 var res
= self.load_module
(owner
, try_file
.simplify_path
)
276 if res
== null then return null # Forward error
277 return res
.mmodule
.as(not null)
281 mmodule
= mmodule
.direct_owner
284 if modules
!= null then
285 for candidate
in modules
do
286 if candidate
.direct_owner
== null then
292 # Look at some known directories
293 var lookpaths
= self.paths
295 # Look in the directory of the last module also (event if not in the path)
296 if lastmodule
!= null then
297 var dirname
= lastmodule
.location
.file
.filename
.dirname
298 if dirname
.basename
("") == lastmodule
.name
then
299 dirname
= dirname
.dirname
301 if not lookpaths
.has
(dirname
) then
302 lookpaths
= lookpaths
.to_a
303 lookpaths
.add
(dirname
)
307 var candidate
: nullable String = null
308 for dirname
in lookpaths
do
309 var try_file
= (dirname
+ "/" + name
+ ".nit").simplify_path
311 if try_file
.file_exists
then
312 if candidate
== null then
314 else if candidate
!= try_file
then
315 error
(anode
, "Error: conflicting module file for {name}: {candidate} {try_file}")
318 try_file
= (dirname
+ "/" + name
+ "/" + name
+ ".nit").simplify_path
319 if try_file
.file_exists
then
320 if candidate
== null then
322 else if candidate
!= try_file
then
323 error
(anode
, "Error: conflicting module file for {name}: {candidate} {try_file}")
327 if candidate
== null then
328 if origmmodule
!= null then
329 error
(anode
, "Error: cannot find module {name} from {origmmodule}. tried {tries.join(", ")}")
331 error
(anode
, "Error: cannot find module {name}. tried {tries.join(", ")}")
335 var res
= self.load_module
(mmodule
, candidate
)
336 if res
== null then return null # Forward error
337 return res
.mmodule
.as(not null)
340 # Try to load a module using a path.
341 # Display an error if there is a problem (IO / lexer / parser) and return null
342 # Note: usually, you do not need this method, use `get_mmodule_by_name` instead.
343 fun load_module
(owner
: nullable MModule, filename
: String): nullable AModule
345 if not filename
.file_exists
then
346 self.toolcontext
.error
(null, "Error: file {filename} not found.")
350 var x
= if owner
!= null then owner
.to_s
else "."
351 self.toolcontext
.info
("load module {filename} in {x}", 2)
354 var file
= new IFStream.open
(filename
)
355 var lexer
= new Lexer(new SourceFile(filename
, file
))
356 var parser
= new Parser(lexer
)
357 var tree
= parser
.parse
360 # Handle lexer and parser error
361 var nmodule
= tree
.n_base
362 if nmodule
== null then
363 var neof
= tree
.n_eof
364 assert neof
isa AError
365 error
(neof
, neof
.message
)
369 # Check the module name
370 var mod_name
= filename
.basename
(".nit")
371 var decl
= nmodule
.n_moduledecl
373 #warning(nmodule, "Warning: Missing 'module' keyword") #FIXME: NOT YET FOR COMPATIBILITY
375 var decl_name
= decl
.n_name
.n_id
.text
376 if decl_name
!= mod_name
then
377 error
(decl
.n_name
, "Error: module name missmatch; declared {decl_name} file named {mod_name}")
382 var mmodule
= new MModule(model
, owner
, mod_name
, nmodule
.location
)
383 nmodule
.mmodule
= mmodule
384 nmodules
.add
(nmodule
)
385 self.mmodule2nmodule
[mmodule
] = nmodule
387 build_module_importation
(nmodule
)
392 # Analysis the module importation and fill the module_importation_hierarchy
393 private fun build_module_importation
(nmodule
: AModule)
395 if nmodule
.is_importation_done
then return
396 nmodule
.is_importation_done
= true
397 var mmodule
= nmodule
.mmodule
.as(not null)
399 var imported_modules
= new Array[MModule]
400 for aimport
in nmodule
.n_imports
do
402 if not aimport
isa AStdImport then
405 var mod_name
= aimport
.n_name
.n_id
.text
406 var sup
= self.get_mmodule_by_name
(aimport
.n_name
, mmodule
, mod_name
)
407 if sup
== null then continue # Skip error
408 imported_modules
.add
(sup
)
409 var mvisibility
= aimport
.n_visibility
.mvisibility
410 mmodule
.set_visibility_for
(sup
, mvisibility
)
413 var mod_name
= "standard"
414 var sup
= self.get_mmodule_by_name
(nmodule
, null, mod_name
)
415 if sup
!= null then # Skip error
416 imported_modules
.add
(sup
)
417 mmodule
.set_visibility_for
(sup
, public_visibility
)
420 self.toolcontext
.info
("{mmodule} imports {imported_modules.join(", ")}", 3)
421 mmodule
.set_imported_mmodules
(imported_modules
)
424 # All the loaded modules
425 var nmodules
: Array[AModule] = new Array[AModule]
427 # Build the classes of all modules `nmodules'.
428 private fun build_all_classes
430 for nmodule
in self.nmodules
do
431 build_classes
(nmodule
)
432 for nclassdef
in nmodule
.n_classdefs
do
433 build_properties
(nclassdef
)
438 # Visit the AST and create the MClass objects
439 private fun build_a_mclass
(nmodule
: AModule, nclassdef
: AClassdef)
441 var mmodule
= nmodule
.mmodule
.as(not null)
444 var nkind
: nullable AClasskind
445 var mkind
: MClassKind
446 var nvisibility
: nullable AVisibility
447 var mvisibility
: nullable MVisibility
449 if nclassdef
isa AStdClassdef then
450 name
= nclassdef
.n_id
.text
451 nkind
= nclassdef
.n_classkind
453 nvisibility
= nclassdef
.n_visibility
454 mvisibility
= nvisibility
.mvisibility
455 arity
= nclassdef
.n_formaldefs
.length
456 else if nclassdef
isa ATopClassdef then
459 mkind
= interface_kind
461 mvisibility
= public_visibility
462 else if nclassdef
isa AMainClassdef then
465 mkind
= concrete_kind
467 mvisibility
= public_visibility
472 var mclass
= try_get_mclass_by_name
(nclassdef
, mmodule
, name
)
473 if mclass
== null then
474 mclass
= new MClass(mmodule
, name
, arity
, mkind
, mvisibility
)
475 #print "new class {mclass}"
476 else if nclassdef
isa AStdClassdef and nmodule
.mclass2nclassdef
.has_key
(mclass
) then
477 error
(nclassdef
, "Error: A class {name} is already defined at line {nmodule.mclass2nclassdef[mclass].location.line_start}.")
479 else if nclassdef
isa AStdClassdef and nclassdef
.n_kwredef
== null then
480 error
(nclassdef
, "Redef error: {name} is an imported class. Add the redef keyword to refine it.")
482 else if mclass
.arity
!= arity
then
483 error
(nclassdef
, "Redef error: Formal parameter arity missmatch; got {arity}, expected {mclass.arity}.")
485 else if nkind
!= null and mkind
!= concrete_kind
and mclass
.kind
!= mkind
then
486 error
(nkind
, "Error: refinement changed the kind from a {mclass.kind} to a {mkind}")
487 else if nvisibility
!= null and mvisibility
!= public_visibility
and mclass
.visibility
!= mvisibility
then
488 error
(nvisibility
, "Error: refinement changed the visibility from a {mclass.visibility} to a {mvisibility}")
490 nclassdef
.mclass
= mclass
491 nmodule
.mclass2nclassdef
[mclass
] = nclassdef
494 # Visit the AST and create the MClassDef objects
495 private fun build_a_mclassdef
(nmodule
: AModule, nclassdef
: AClassdef)
497 var mmodule
= nmodule
.mmodule
.as(not null)
498 var objectclass
= try_get_mclass_by_name
(nmodule
, mmodule
, "Object")
499 var mclass
= nclassdef
.mclass
500 if mclass
== null then return # Skip error
501 #var mclassdef = nclassdef.mclassdef.as(not null)
503 var names
= new Array[String]
504 var bounds
= new Array[MType]
505 if nclassdef
isa AStdClassdef and mclass
.arity
> 0 then
506 # Collect formal parameter names
507 for i
in [0..mclass
.arity
[ do
508 var nfd
= nclassdef
.n_formaldefs
[i
]
509 var ptname
= nfd
.n_id
.text
510 if names
.has
(ptname
) then
511 error
(nfd
, "Error: A formal parameter type `{ptname}' already exists")
517 # Revolve bound for formal parameter names
518 for i
in [0..mclass
.arity
[ do
519 var nfd
= nclassdef
.n_formaldefs
[i
]
520 var nfdt
= nfd
.n_type
522 var bound
= resolve_mtype_unchecked
(nclassdef
, nfdt
, false)
523 if bound
== null then return # Forward error
524 if bound
.need_anchor
then
526 error
(nfd
, "Error: Formal parameter type `{names[i]}' bounded with a formal parameter type")
530 else if mclass
.mclassdefs
.is_empty
then
531 # No bound, then implicitely bound by nullable Object
532 bounds
.add
(objectclass
.mclass_type
.as_nullable
)
535 bounds
.add
(mclass
.intro
.bound_mtype
.arguments
[i
])
540 var bound_mtype
= mclass
.get_mtype
(bounds
)
541 var mclassdef
= new MClassDef(mmodule
, bound_mtype
, nclassdef
.location
, names
)
542 nclassdef
.mclassdef
= mclassdef
543 self.mclassdef2nclassdef
[mclassdef
] = nclassdef
545 if mclassdef
.is_intro
then
546 self.toolcontext
.info
("{mclassdef} introduces new {mclass.kind} {mclass.full_name}", 3)
548 self.toolcontext
.info
("{mclassdef} refine {mclass.kind} {mclass.full_name}", 3)
552 # Visit the AST and set the super-types of the MClassdef objects
553 private fun collect_a_mclassdef_inheritance
(nmodule
: AModule, nclassdef
: AClassdef)
555 var mmodule
= nmodule
.mmodule
.as(not null)
556 var objectclass
= try_get_mclass_by_name
(nmodule
, mmodule
, "Object")
557 var mclass
= nclassdef
.mclass
.as(not null)
558 var mclassdef
= nclassdef
.mclassdef
.as(not null)
560 var specobject
= true
561 var supertypes
= new Array[MClassType]
562 if nclassdef
isa AStdClassdef then
563 for nsc
in nclassdef
.n_superclasses
do
565 var ntype
= nsc
.n_type
566 var mtype
= resolve_mtype_unchecked
(nclassdef
, ntype
, false)
567 if mtype
== null then continue # Skip because of error
568 if not mtype
isa MClassType then
569 error
(ntype
, "Error: supertypes cannot be a formal type")
573 #print "new super : {mclass} < {mtype}"
576 if specobject
and mclass
.name
!= "Object" and objectclass
!= null and mclassdef
.is_intro
then
577 supertypes
.add objectclass
.mclass_type
580 mclassdef
.set_supertypes
(supertypes
)
581 if not supertypes
.is_empty
then self.toolcontext
.info
("{mclassdef} new super-types: {supertypes.join(", ")}", 3)
584 # Check the validity of the specialization heirarchy
585 private fun check_supertypes
(nmodule
: AModule, nclassdef
: AClassdef)
587 var mmodule
= nmodule
.mmodule
.as(not null)
588 var objectclass
= try_get_mclass_by_name
(nmodule
, mmodule
, "Object")
589 var mclass
= nclassdef
.mclass
.as(not null)
590 var mclassdef
= nclassdef
.mclassdef
.as(not null)
592 for s
in mclassdef
.supertypes
do
593 if s
.is_subtype
(mmodule
, mclassdef
.bound_mtype
, mclassdef
.bound_mtype
) then
594 error
(nclassdef
, "Error: Inheritance loop for class {mclass} with type {s}")
599 # Build the classes of the module `nmodule'.
600 # REQUIRE: classes of imported modules are already build. (let `build_all_classes' do the job)
601 private fun build_classes
(nmodule
: AModule)
603 # Force building recursively
604 if nmodule
.build_classes_is_done
then return
605 nmodule
.build_classes_is_done
= true
606 var mmodule
= nmodule
.mmodule
.as(not null)
607 for imp
in mmodule
.in_importation
.direct_greaters
do
609 build_classes
(mmodule2nmodule
[imp
])
613 for nclassdef
in nmodule
.n_classdefs
do
614 self.build_a_mclass
(nmodule
, nclassdef
)
617 # Create all classdefs
618 for nclassdef
in nmodule
.n_classdefs
do
619 self.build_a_mclassdef
(nmodule
, nclassdef
)
622 for nclassdef
in nmodule
.n_classdefs
do
623 if nclassdef
.mclassdef
== null then return # forward error
626 # Create inheritance on all classdefs
627 for nclassdef
in nmodule
.n_classdefs
do
628 self.collect_a_mclassdef_inheritance
(nmodule
, nclassdef
)
631 # Create the mclassdef hierarchy
632 for nclassdef
in nmodule
.n_classdefs
do
633 var mclassdef
= nclassdef
.mclassdef
.as(not null)
634 mclassdef
.add_in_hierarchy
638 for nclassdef
in nmodule
.n_classdefs
do
639 self.check_supertypes
(nmodule
, nclassdef
)
642 # Check unchecked ntypes
643 for nclassdef
in nmodule
.n_classdefs
do
644 if nclassdef
isa AStdClassdef then
645 # check bound of formal parameter
646 for nfd
in nclassdef
.n_formaldefs
do
647 var nfdt
= nfd
.n_type
648 if nfdt
!= null and nfdt
.mtype
!= null then
649 var bound
= resolve_mtype
(nclassdef
, nfdt
)
650 if bound
== null then return # Forward error
653 # check declared super types
654 for nsc
in nclassdef
.n_superclasses
do
655 var ntype
= nsc
.n_type
656 if ntype
.mtype
!= null then
657 var mtype
= resolve_mtype
(nclassdef
, ntype
)
658 if mtype
== null then return # Forward error
665 # TODO: Check that the super-class is not intrusive
667 # TODO: Check that the super-class is not already known (by transitivity)
670 # Register the nmodule associated to each mmodule
671 # FIXME: why not refine the MModule class with a nullable attribute?
672 var mmodule2nmodule
: HashMap[MModule, AModule] = new HashMap[MModule, AModule]
673 # Register the nclassdef associated to each mclassdef
674 # FIXME: why not refine the MClassDef class with a nullable attribute?
675 var mclassdef2nclassdef
: HashMap[MClassDef, AClassdef] = new HashMap[MClassDef, AClassdef]
676 # Register the npropdef associated to each mpropdef
677 # FIXME: why not refine the MPropDef class with a nullable attribute?
678 var mpropdef2npropdef
: HashMap[MPropDef, APropdef] = new HashMap[MPropDef, APropdef]
680 # Build the properties of `nclassdef'.
681 # REQUIRE: all superclasses are built.
682 private fun build_properties
(nclassdef
: AClassdef)
684 # Force building recursively
685 if nclassdef
.build_properties_is_done
then return
686 nclassdef
.build_properties_is_done
= true
687 var mclassdef
= nclassdef
.mclassdef
.as(not null)
688 if mclassdef
.in_hierarchy
== null then return # Skip error
689 for superclassdef
in mclassdef
.in_hierarchy
.direct_greaters
do
690 build_properties
(mclassdef2nclassdef
[superclassdef
])
693 for npropdef
in nclassdef
.n_propdefs
do
694 npropdef
.build_property
(self, nclassdef
)
696 for npropdef
in nclassdef
.n_propdefs
do
697 npropdef
.build_signature
(self, nclassdef
)
699 for npropdef
in nclassdef
.n_propdefs
do
700 npropdef
.check_signature
(self, nclassdef
)
702 process_default_constructors
(nclassdef
)
705 # Introduce or inherit default constructor
706 # This is the last part of `build_properties'.
707 private fun process_default_constructors
(nclassdef
: AClassdef)
709 var mclassdef
= nclassdef
.mclassdef
.as(not null)
711 # Are we a refinement
712 if not mclassdef
.is_intro
then return
714 # Is the class forbid constructors?
715 if not mclassdef
.mclass
.kind
.need_init
then return
717 # Is there already a constructor defined?
718 for mpropdef
in mclassdef
.mpropdefs
do
719 if not mpropdef
isa MMethodDef then continue
720 if mpropdef
.mproperty
.is_init
then return
723 if not nclassdef
isa AStdClassdef then return
725 var mmodule
= nclassdef
.mclassdef
.mmodule
726 # Do we inherit for a constructor?
727 var combine
= new Array[MMethod]
728 var inhc
: nullable MClass = null
729 for st
in mclassdef
.supertypes
do
731 if not c
.kind
.need_init
then continue
732 st
= st
.anchor_to
(mmodule
, nclassdef
.mclassdef
.bound_mtype
)
733 var candidate
= self.try_get_mproperty_by_name2
(nclassdef
, mmodule
, st
, "init").as(nullable MMethod)
734 if candidate
!= null and candidate
.intro
.msignature
.arity
== 0 then
735 combine
.add
(candidate
)
738 var inhc2
= c
.inherit_init_from
739 if inhc2
== null then inhc2
= c
740 if inhc2
== inhc
then continue
742 self.error
(nclassdef
, "Error: Cannot provide a defaut constructor: conflict for {inhc} and {c}")
747 if combine
.is_empty
and inhc
!= null then
748 # TODO: actively inherit the consturctor
749 self.toolcontext
.info
("{mclassdef} inherits all constructors from {inhc}", 3)
750 mclassdef
.mclass
.inherit_init_from
= inhc
753 if not combine
.is_empty
and inhc
!= null then
754 self.error
(nclassdef
, "Error: Cannot provide a defaut constructor: conflict for {combine.join(", ")} and {inhc}")
758 if not combine
.is_empty
then
759 nclassdef
.super_inits
= combine
760 var mprop
= new MMethod(mclassdef
, "init", mclassdef
.mclass
.visibility
)
761 var mpropdef
= new MMethodDef(mclassdef
, mprop
, nclassdef
.location
)
762 var mparameters
= new Array[MParameter]
763 var msignature
= new MSignature(mparameters
, null)
764 mpropdef
.msignature
= msignature
766 nclassdef
.mfree_init
= mpropdef
767 self.toolcontext
.info
("{mclassdef} gets a free empty constructor {mpropdef}{msignature}", 3)
771 # Collect undefined attributes
772 var mparameters
= new Array[MParameter]
773 for npropdef
in nclassdef
.n_propdefs
do
774 if npropdef
isa AAttrPropdef and npropdef
.n_expr
== null then
775 if npropdef
.mpropdef
== null then return # Skip broken attribute
776 var paramname
= npropdef
.mpropdef
.mproperty
.name
.substring_from
(1)
777 var ret_type
= npropdef
.mpropdef
.static_mtype
778 if ret_type
== null then return
779 var mparameter
= new MParameter(paramname
, ret_type
, false)
780 mparameters
.add
(mparameter
)
784 var mprop
= new MMethod(mclassdef
, "init", mclassdef
.mclass
.visibility
)
785 var mpropdef
= new MMethodDef(mclassdef
, mprop
, nclassdef
.location
)
786 var msignature
= new MSignature(mparameters
, null)
787 mpropdef
.msignature
= msignature
789 nclassdef
.mfree_init
= mpropdef
790 self.toolcontext
.info
("{mclassdef} gets a free constructor for attributes {mpropdef}{msignature}", 3)
793 # Return the static type associated to the node `ntype'.
794 # `classdef' is the context where the call is made (used to understand formal types)
795 # The mmodule used as context is `nclassdef.mmodule'
796 # In case of problem, an error is displayed on `ntype' and null is returned.
797 # FIXME: the name "resolve_mtype" is awful
798 fun resolve_mtype_unchecked
(nclassdef
: AClassdef, ntype
: AType, with_virtual
: Bool): nullable MType
800 var name
= ntype
.n_id
.text
801 var mclassdef
= nclassdef
.mclassdef
802 var mmodule
= nclassdef
.parent
.as(AModule).mmodule
.as(not null)
806 if mclassdef
!= null and with_virtual
then
807 var prop
= try_get_mproperty_by_name
(ntype
, mclassdef
, name
).as(nullable MVirtualTypeProp)
809 if not ntype
.n_types
.is_empty
then
810 error
(ntype
, "Type error: formal type {name} cannot have formal parameters.")
812 res
= prop
.mvirtualtype
813 if ntype
.n_kwnullable
!= null then res
= res
.as_nullable
819 # Check parameter type
820 if mclassdef
!= null and mclassdef
.parameter_names
.has
(name
) then
821 if not ntype
.n_types
.is_empty
then
822 error
(ntype
, "Type error: formal type {name} cannot have formal parameters.")
824 for i
in [0..mclassdef
.parameter_names
.length
[ do
825 if mclassdef
.parameter_names
[i
] == name
then
826 res
= mclassdef
.mclass
.mclass_type
.arguments
[i
]
827 if ntype
.n_kwnullable
!= null then res
= res
.as_nullable
836 var mclass
= try_get_mclass_by_name
(ntype
, mmodule
, name
)
837 if mclass
!= null then
838 var arity
= ntype
.n_types
.length
839 if arity
!= mclass
.arity
then
841 error
(ntype
, "Type error: '{name}' is a generic class.")
842 else if mclass
.arity
== 0 then
843 error
(ntype
, "Type error: '{name}' is not a generic class.")
845 error
(ntype
, "Type error: '{name}' has {mclass.arity} parameters ({arity} are provided).")
850 res
= mclass
.mclass_type
851 if ntype
.n_kwnullable
!= null then res
= res
.as_nullable
855 var mtypes
= new Array[MType]
856 for nt
in ntype
.n_types
do
857 var mt
= resolve_mtype_unchecked
(nclassdef
, nt
, with_virtual
)
858 if mt
== null then return null # Forward error
861 res
= mclass
.get_mtype
(mtypes
)
862 if ntype
.n_kwnullable
!= null then res
= res
.as_nullable
868 # If everything fail, then give up :(
869 error
(ntype
, "Type error: class {name} not found in module {mmodule}.")
873 # Return the static type associated to the node `ntype'.
874 # `classdef' is the context where the call is made (used to understand formal types)
875 # The mmodule used as context is `nclassdef.mmodule'
876 # In case of problem, an error is displayed on `ntype' and null is returned.
877 # FIXME: the name "resolve_mtype" is awful
878 fun resolve_mtype
(nclassdef
: AClassdef, ntype
: AType): nullable MType
880 var mtype
= ntype
.mtype
881 if mtype
== null then mtype
= resolve_mtype_unchecked
(nclassdef
, ntype
, true)
882 if mtype
== null then return null # Forward error
884 if ntype
.checked_mtype
then return mtype
885 if mtype
isa MGenericType then
886 var mmodule
= nclassdef
.parent
.as(AModule).mmodule
.as(not null)
887 var mclassdef
= nclassdef
.mclassdef
888 var mclass
= mtype
.mclass
889 for i
in [0..mclass
.arity
[ do
890 var bound
= mclass
.intro
.bound_mtype
.arguments
[i
]
891 var nt
= ntype
.n_types
[i
]
892 var mt
= resolve_mtype
(nclassdef
, nt
)
893 if mt
== null then return null # forward error
894 if not mt
.is_subtype
(mmodule
, mclassdef
.bound_mtype
, bound
) then
895 error
(nt
, "Type error: expected {bound}, got {mt}")
900 ntype
.checked_mtype
= true
904 # Helper function to display an error on a node.
905 # Alias for `self.toolcontext.error(n.hot_location, text)'
906 fun error
(n
: ANode, text
: String)
908 self.toolcontext
.error
(n
.hot_location
, text
)
911 # Helper function to display a warning on a node.
912 # Alias for: `self.toolcontext.warning(n.hot_location, text)'
913 fun warning
(n
: ANode, text
: String)
915 self.toolcontext
.warning
(n
.hot_location
, text
)
918 # Force to get the primitive method named `name' on the type `recv' or do a fatal error on `n'
919 fun force_get_primitive_method
(n
: ANode, name
: String, recv
: MType, mmodule
: MModule): MMethod
921 var res
= mmodule
.try_get_primitive_method
(name
, recv
)
923 self.toolcontext
.fatal_error
(n
.hot_location
, "Fatal Error: {recv} must have a property named {name}.")
931 # The associated MModule once build by a `ModelBuilder'
932 var mmodule
: nullable MModule
933 # Flag that indicate if the importation is already completed
934 var is_importation_done
: Bool = false
935 # Flag that indicate if the class and prop building is already completed
936 var build_classes_is_done
: Bool = false
937 # What is the AClassdef associated to a MClass?
938 # Used to check multiple definition of a class.
939 var mclass2nclassdef
: Map[MClass, AClassdef] = new HashMap[MClass, AClassdef]
944 # The class whose self inherit all the constructors.
945 # 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
946 var inherit_init_from
: nullable MClass = null
949 redef class AClassdef
950 # The associated MClass once build by a `ModelBuilder'
951 var mclass
: nullable MClass
952 # The associated MClassDef once build by a `ModelBuilder'
953 var mclassdef
: nullable MClassDef
954 var build_properties_is_done
: Bool = false
955 # The list of super-constructor to call at the start of the free constructor
956 # 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
957 var super_inits
: nullable Collection[MMethod] = null
959 # The free init (implicitely constructed by the class if required)
960 var mfree_init
: nullable MMethodDef = null
962 # What is the APropdef associated to a MProperty?
963 # Used to check multiple definition of a property.
964 var mprop2npropdef
: Map[MProperty, APropdef] = new HashMap[MProperty, APropdef]
967 redef class AClasskind
968 # The class kind associated with the AST node class
969 private fun mkind
: MClassKind is abstract
971 redef class AConcreteClasskind
972 redef fun mkind
do return concrete_kind
974 redef class AAbstractClasskind
975 redef fun mkind
do return abstract_kind
977 redef class AInterfaceClasskind
978 redef fun mkind
do return interface_kind
980 redef class AEnumClasskind
981 redef fun mkind
do return enum_kind
983 redef class AExternClasskind
984 redef fun mkind
do return extern_kind
987 redef class AVisibility
988 # The visibility level associated with the AST node class
989 private fun mvisibility
: MVisibility is abstract
991 redef class AIntrudeVisibility
992 redef fun mvisibility
do return intrude_visibility
994 redef class APublicVisibility
995 redef fun mvisibility
do return public_visibility
997 redef class AProtectedVisibility
998 redef fun mvisibility
do return protected_visibility
1000 redef class APrivateVisibility
1001 redef fun mvisibility
do return private_visibility
1005 # The mtype associated to the node
1006 var mtype
: nullable MType = null
1008 # Is the mtype a valid one?
1009 var checked_mtype
: Bool = false
1015 # Join the text of all tokens
1016 # Used to get the 'real name' of method definitions.
1017 fun collect_text
: String
1019 var v
= new TextCollectorVisitor
1026 private class TextCollectorVisitor
1028 var text
: String = ""
1031 if n
isa Token then text
+= n
.text
1036 redef class APropdef
1037 private fun build_property
(modelbuilder
: ModelBuilder, nclassdef
: AClassdef)
1040 private fun build_signature
(modelbuilder
: ModelBuilder, nclassdef
: AClassdef)
1043 private fun check_signature
(modelbuilder
: ModelBuilder, nclassdef
: AClassdef)
1046 private fun new_property_visibility
(modelbuilder
: ModelBuilder, nclassdef
: AClassdef, nvisibility
: nullable AVisibility): MVisibility
1048 var mvisibility
= public_visibility
1049 if nvisibility
!= null then mvisibility
= nvisibility
.mvisibility
1050 if nclassdef
.mclassdef
.mclass
.visibility
== private_visibility
then
1051 if mvisibility
== protected_visibility
then
1052 assert nvisibility
!= null
1053 modelbuilder
.error
(nvisibility
, "Error: The only legal visibility for properties in a private class is private.")
1054 else if mvisibility
== private_visibility
then
1055 assert nvisibility
!= null
1057 # modelbuilder.warning(nvisibility, "Warning: private is unrequired since the only legal visibility for properties in a private class is private.")
1059 mvisibility
= private_visibility
1064 private fun check_redef_property_visibility
(modelbuilder
: ModelBuilder, nclassdef
: AClassdef, nvisibility
: nullable AVisibility, mprop
: MProperty)
1066 if nvisibility
== null then return
1067 var mvisibility
= nvisibility
.mvisibility
1068 if mvisibility
!= mprop
.visibility
and mvisibility
!= public_visibility
then
1069 modelbuilder
.error
(nvisibility
, "Error: redefinition changed the visibility from a {mprop.visibility} to a {mvisibility}")
1073 private fun check_redef_keyword
(modelbuilder
: ModelBuilder, nclassdef
: AClassdef, kwredef
: nullable Token, need_redef
: Bool, mprop
: MProperty): Bool
1075 if nclassdef
.mprop2npropdef
.has_key
(mprop
) then
1076 modelbuilder
.error
(self, "Error: A property {mprop} is already defined in class {nclassdef.mclassdef.mclass}.")
1079 if kwredef
== null then
1081 modelbuilder
.error
(self, "Redef error: {nclassdef.mclassdef.mclass}::{mprop.name} is an inherited property. To redefine it, add the redef keyword.")
1085 if not need_redef
then
1086 modelbuilder
.error
(self, "Error: No property {nclassdef.mclassdef.mclass}::{mprop.name} is inherited. Remove the redef keyword to define a new property.")
1095 redef class ASignature
1096 # Is the model builder has correctly visited the signature
1097 var is_visited
= false
1098 # Names of parameters from the AST
1099 # REQUIRE: is_visited
1100 var param_names
= new Array[String]
1101 # Types of parameters from the AST
1102 # REQUIRE: is_visited
1103 var param_types
= new Array[MType]
1104 # Rank of the vararg (of -1 if none)
1105 # REQUIRE: is_visited
1106 var vararg_rank
: Int = -1
1108 var ret_type
: nullable MType = null
1110 # Visit and fill information about a signature
1111 private fun visit_signature
(modelbuilder
: ModelBuilder, nclassdef
: AClassdef): Bool
1113 var param_names
= self.param_names
1114 var param_types
= self.param_types
1115 for np
in self.n_params
do
1116 param_names
.add
(np
.n_id
.text
)
1117 var ntype
= np
.n_type
1118 if ntype
!= null then
1119 var mtype
= modelbuilder
.resolve_mtype
(nclassdef
, ntype
)
1120 if mtype
== null then return false # Skip error
1121 for i
in [0..param_names
.length-param_types
.length
[ do
1122 param_types
.add
(mtype
)
1124 if np
.n_dotdotdot
!= null then
1125 if self.vararg_rank
!= -1 then
1126 modelbuilder
.error
(np
, "Error: {param_names[self.vararg_rank]} is already a vararg")
1129 self.vararg_rank
= param_names
.length
- 1
1134 var ntype
= self.n_type
1135 if ntype
!= null then
1136 self.ret_type
= modelbuilder
.resolve_mtype
(nclassdef
, ntype
)
1137 if self.ret_type
== null then return false # Skip errir
1140 for nclosure
in self.n_closure_decls
do
1141 if not nclosure
.n_signature
.visit_signature
(modelbuilder
, nclassdef
) then return false
1144 self.is_visited
= true
1148 # Build a visited signature
1149 fun build_signature
(modelbuilder
: ModelBuilder, nclassdef
: AClassdef): nullable MSignature
1151 if param_names
.length
!= param_types
.length
then
1152 # Some parameters are typed, other parameters are not typed.
1153 modelbuilder
.error
(self.n_params
[param_types
.length
], "Error: Untyped parameter `{param_names[param_types.length]}'.")
1157 var mparameters
= new Array[MParameter]
1158 for i
in [0..param_names
.length
[ do
1159 var mparameter
= new MParameter(param_names
[i
], param_types
[i
], i
== vararg_rank
)
1160 mparameters
.add
(mparameter
)
1163 var msignature
= new MSignature(mparameters
, ret_type
)
1168 redef class AMethPropdef
1169 # The associated MMethodDef once build by a `ModelBuilder'
1170 var mpropdef
: nullable MMethodDef
1172 # The associated super init if any
1173 var super_init
: nullable MMethod
1174 redef fun build_property
(modelbuilder
, nclassdef
)
1176 var is_init
= self isa AInitPropdef
1177 var mclassdef
= nclassdef
.mclassdef
.as(not null)
1179 var amethodid
= self.n_methid
1180 var name_node
: ANode
1181 if amethodid
== null then
1182 if self isa AMainMethPropdef then
1185 else if self isa AConcreteInitPropdef then
1187 name_node
= self.n_kwinit
1188 else if self isa AExternInitPropdef then
1190 name_node
= self.n_kwnew
1194 else if amethodid
isa AIdMethid then
1195 name
= amethodid
.n_id
.text
1196 name_node
= amethodid
1198 # operator, bracket or assign
1199 name
= amethodid
.collect_text
1200 name_node
= amethodid
1202 if name
== "-" and self.n_signature
.n_params
.length
== 0 then
1207 var mprop
: nullable MMethod = null
1208 if not is_init
or n_kwredef
!= null then mprop
= modelbuilder
.try_get_mproperty_by_name
(name_node
, mclassdef
, name
).as(nullable MMethod)
1209 if mprop
== null then
1210 var mvisibility
= new_property_visibility
(modelbuilder
, nclassdef
, self.n_visibility
)
1211 mprop
= new MMethod(mclassdef
, name
, mvisibility
)
1212 mprop
.is_init
= is_init
1213 mprop
.is_new
= self isa AExternInitPropdef
1214 if not self.check_redef_keyword
(modelbuilder
, nclassdef
, n_kwredef
, false, mprop
) then return
1216 if n_kwredef
== null then
1217 if self isa AMainMethPropdef then
1220 if not self.check_redef_keyword
(modelbuilder
, nclassdef
, n_kwredef
, true, mprop
) then return
1223 check_redef_property_visibility
(modelbuilder
, nclassdef
, self.n_visibility
, mprop
)
1225 nclassdef
.mprop2npropdef
[mprop
] = self
1227 var mpropdef
= new MMethodDef(mclassdef
, mprop
, self.location
)
1229 self.mpropdef
= mpropdef
1230 modelbuilder
.mpropdef2npropdef
[mpropdef
] = self
1231 if mpropdef
.is_intro
then
1232 modelbuilder
.toolcontext
.info
("{mpropdef} introduces new method {mprop.full_name}", 3)
1234 modelbuilder
.toolcontext
.info
("{mpropdef} redefines method {mprop.full_name}", 3)
1238 redef fun build_signature
(modelbuilder
, nclassdef
)
1240 var mpropdef
= self.mpropdef
1241 if mpropdef
== null then return # Error thus skiped
1242 var mmodule
= mpropdef
.mclassdef
.mmodule
1243 var nsig
= self.n_signature
1245 # Retrieve info from the signature AST
1246 var param_names
= new Array[String] # Names of parameters from the AST
1247 var param_types
= new Array[MType] # Types of parameters from the AST
1248 var vararg_rank
= -1
1249 var ret_type
: nullable MType = null # Return type from the AST
1250 if nsig
!= null then
1251 if not nsig
.visit_signature
(modelbuilder
, nclassdef
) then return
1252 param_names
= nsig
.param_names
1253 param_types
= nsig
.param_types
1254 vararg_rank
= nsig
.vararg_rank
1255 ret_type
= nsig
.ret_type
1258 # Look for some signature to inherit
1259 # FIXME: do not inherit from the intro, but from the most specific
1260 var msignature
: nullable MSignature = null
1261 if not mpropdef
.is_intro
then
1262 msignature
= mpropdef
.mproperty
.intro
.msignature
1263 if msignature
== null then return # Skip error
1265 # Check inherited signature arity
1266 if param_names
.length
!= msignature
.arity
then
1268 if nsig
!= null then node
= nsig
else node
= self
1269 modelbuilder
.error
(node
, "Redef error: {mpropdef} redefines {mpropdef.mproperty.intro} with {param_names.length} parameter(s), {msignature.arity} expected. Signature is {mpropdef}{msignature}")
1272 else if mpropdef
.mproperty
.is_init
then
1273 # FIXME UGLY: inherit signature from a super-constructor
1274 for msupertype
in nclassdef
.mclassdef
.supertypes
do
1275 msupertype
= msupertype
.anchor_to
(mmodule
, nclassdef
.mclassdef
.bound_mtype
)
1276 var candidate
= modelbuilder
.try_get_mproperty_by_name2
(self, mmodule
, msupertype
, mpropdef
.mproperty
.name
)
1277 if candidate
!= null then
1278 if msignature
== null then
1279 msignature
= candidate
.intro
.as(MMethodDef).msignature
1286 # Inherit the signature
1287 if msignature
!= null and param_names
.length
!= param_types
.length
and param_names
.length
== msignature
.arity
and param_types
.length
== 0 then
1288 # Parameters are untyped, thus inherit them
1289 param_types
= new Array[MType]
1290 for mparameter
in msignature
.mparameters
do
1291 param_types
.add
(mparameter
.mtype
)
1293 vararg_rank
= msignature
.vararg_rank
1295 if msignature
!= null and ret_type
== null then
1296 ret_type
= msignature
.return_mtype
1299 if param_names
.length
!= param_types
.length
then
1300 # Some parameters are typed, other parameters are not typed.
1301 modelbuilder
.error
(nsig
.n_params
[param_types
.length
], "Error: Untyped parameter `{param_names[param_types.length]}'.")
1305 var mparameters
= new Array[MParameter]
1306 for i
in [0..param_names
.length
[ do
1307 var mparameter
= new MParameter(param_names
[i
], param_types
[i
], i
== vararg_rank
)
1308 mparameters
.add
(mparameter
)
1311 msignature
= new MSignature(mparameters
, ret_type
)
1312 mpropdef
.msignature
= msignature
1314 if nsig
!= null then
1315 for nclosure
in nsig
.n_closure_decls
do
1316 var clos_signature
= nclosure
.n_signature
.build_signature
(modelbuilder
, nclassdef
)
1317 if clos_signature
== null then return
1318 var mparameter
= new MParameter(nclosure
.n_id
.text
, clos_signature
, false)
1319 msignature
.mclosures
.add
(mparameter
)
1325 redef fun check_signature
(modelbuilder
, nclassdef
)
1327 var mpropdef
= self.mpropdef
1328 if mpropdef
== null then return # Error thus skiped
1329 var mmodule
= mpropdef
.mclassdef
.mmodule
1330 var nsig
= self.n_signature
1331 var mysignature
= self.mpropdef
.msignature
1332 if mysignature
== null then return # Error thus skiped
1334 # Lookup for signature in the precursor
1335 # FIXME all precursors should be considered
1336 if not mpropdef
.is_intro
then
1337 var msignature
= mpropdef
.mproperty
.intro
.msignature
1338 if msignature
== null then return
1340 var precursor_ret_type
= msignature
.return_mtype
1341 var ret_type
= mysignature
.return_mtype
1342 if ret_type
!= null and precursor_ret_type
== null then
1343 modelbuilder
.error
(nsig
.n_type
.as(not null), "Redef Error: {mpropdef.mproperty} is a procedure, not a function.")
1347 if mysignature
.arity
> 0 then
1348 # Check parameters types
1349 for i
in [0..mysignature
.arity
[ do
1350 var myt
= mysignature
.mparameters
[i
].mtype
1351 var prt
= msignature
.mparameters
[i
].mtype
1352 if not myt
.is_subtype
(mmodule
, nclassdef
.mclassdef
.bound_mtype
, prt
) and
1353 not prt
.is_subtype
(mmodule
, nclassdef
.mclassdef
.bound_mtype
, myt
) then
1354 modelbuilder
.error
(nsig
.n_params
[i
], "Redef Error: Wrong type for parameter `{mysignature.mparameters[i].name}'. found {myt}, expected {prt}.")
1358 if precursor_ret_type
!= null then
1359 if ret_type
== null then
1360 # Inherit the return type
1361 ret_type
= precursor_ret_type
1362 else if not ret_type
.is_subtype
(mmodule
, nclassdef
.mclassdef
.bound_mtype
, precursor_ret_type
) then
1363 modelbuilder
.error
(nsig
.n_type
.as(not null), "Redef Error: Wrong return type. found {ret_type}, expected {precursor_ret_type}.")
1370 redef class AAttrPropdef
1371 # The associated MAttributeDef once build by a `ModelBuilder'
1372 var mpropdef
: nullable MAttributeDef
1373 # The associated getter (read accessor) if any
1374 var mreadpropdef
: nullable MMethodDef
1375 # The associated setter (write accessor) if any
1376 var mwritepropdef
: nullable MMethodDef
1377 redef fun build_property
(modelbuilder
, nclassdef
)
1379 var mclassdef
= nclassdef
.mclassdef
.as(not null)
1380 var mclass
= mclassdef
.mclass
1383 if self.n_id
!= null then
1384 name
= self.n_id
.text
1386 name
= self.n_id2
.text
1389 if mclass
.kind
== interface_kind
or mclassdef
.mclass
.kind
== enum_kind
then
1390 modelbuilder
.error
(self, "Error: Attempt to define attribute {name} in the interface {mclass}.")
1391 else if mclass
.kind
== enum_kind
then
1392 modelbuilder
.error
(self, "Error: Attempt to define attribute {name} in the enum class {mclass}.")
1393 else if mclass
.kind
== extern_kind
then
1394 modelbuilder
.error
(self, "Error: Attempt to define attribute {name} in the extern class {mclass}.")
1399 # Old attribute style
1400 var mprop
= modelbuilder
.try_get_mproperty_by_name
(nid
, mclassdef
, name
)
1401 if mprop
== null then
1402 var mvisibility
= new_property_visibility
(modelbuilder
, nclassdef
, self.n_visibility
)
1403 mprop
= new MAttribute(mclassdef
, name
, mvisibility
)
1404 if not self.check_redef_keyword
(modelbuilder
, nclassdef
, self.n_kwredef
, false, mprop
) then return
1406 assert mprop
isa MAttribute
1407 check_redef_property_visibility
(modelbuilder
, nclassdef
, self.n_visibility
, mprop
)
1408 if not self.check_redef_keyword
(modelbuilder
, nclassdef
, self.n_kwredef
, true, mprop
) then return
1410 nclassdef
.mprop2npropdef
[mprop
] = self
1412 var mpropdef
= new MAttributeDef(mclassdef
, mprop
, self.location
)
1413 self.mpropdef
= mpropdef
1414 modelbuilder
.mpropdef2npropdef
[mpropdef
] = self
1416 var nreadable
= self.n_readable
1417 if nreadable
!= null then
1418 var readname
= name
.substring_from
(1)
1419 var mreadprop
= modelbuilder
.try_get_mproperty_by_name
(nid
, mclassdef
, readname
).as(nullable MMethod)
1420 if mreadprop
== null then
1421 var mvisibility
= new_property_visibility
(modelbuilder
, nclassdef
, nreadable
.n_visibility
)
1422 mreadprop
= new MMethod(mclassdef
, readname
, mvisibility
)
1423 if not self.check_redef_keyword
(modelbuilder
, nclassdef
, nreadable
.n_kwredef
, false, mreadprop
) then return
1425 if not self.check_redef_keyword
(modelbuilder
, nclassdef
, nreadable
.n_kwredef
, true, mreadprop
) then return
1426 check_redef_property_visibility
(modelbuilder
, nclassdef
, nreadable
.n_visibility
, mreadprop
)
1428 nclassdef
.mprop2npropdef
[mreadprop
] = self
1430 var mreadpropdef
= new MMethodDef(mclassdef
, mreadprop
, self.location
)
1431 self.mreadpropdef
= mreadpropdef
1432 modelbuilder
.mpropdef2npropdef
[mreadpropdef
] = self
1435 var nwritable
= self.n_writable
1436 if nwritable
!= null then
1437 var writename
= name
.substring_from
(1) + "="
1438 var mwriteprop
= modelbuilder
.try_get_mproperty_by_name
(nid
, mclassdef
, writename
).as(nullable MMethod)
1439 if mwriteprop
== null then
1440 var mvisibility
= new_property_visibility
(modelbuilder
, nclassdef
, nwritable
.n_visibility
)
1441 mwriteprop
= new MMethod(mclassdef
, writename
, mvisibility
)
1442 if not self.check_redef_keyword
(modelbuilder
, nclassdef
, nwritable
.n_kwredef
, false, mwriteprop
) then return
1444 if not self.check_redef_keyword
(modelbuilder
, nclassdef
, nwritable
.n_kwredef
, true, mwriteprop
) then return
1445 check_redef_property_visibility
(modelbuilder
, nclassdef
, nwritable
.n_visibility
, mwriteprop
)
1447 nclassdef
.mprop2npropdef
[mwriteprop
] = self
1449 var mwritepropdef
= new MMethodDef(mclassdef
, mwriteprop
, self.location
)
1450 self.mwritepropdef
= mwritepropdef
1451 modelbuilder
.mpropdef2npropdef
[mwritepropdef
] = self
1454 # New attribute style
1455 var nid2
= self.n_id2
.as(not null)
1456 var mprop
= new MAttribute(mclassdef
, "@" + name
, none_visibility
)
1457 var mpropdef
= new MAttributeDef(mclassdef
, mprop
, self.location
)
1458 self.mpropdef
= mpropdef
1459 modelbuilder
.mpropdef2npropdef
[mpropdef
] = self
1462 var mreadprop
= modelbuilder
.try_get_mproperty_by_name
(nid2
, mclassdef
, readname
).as(nullable MMethod)
1463 if mreadprop
== null then
1464 var mvisibility
= new_property_visibility
(modelbuilder
, nclassdef
, self.n_visibility
)
1465 mreadprop
= new MMethod(mclassdef
, readname
, mvisibility
)
1466 if not self.check_redef_keyword
(modelbuilder
, nclassdef
, n_kwredef
, false, mreadprop
) then return
1468 if not self.check_redef_keyword
(modelbuilder
, nclassdef
, n_kwredef
, true, mreadprop
) then return
1469 check_redef_property_visibility
(modelbuilder
, nclassdef
, self.n_visibility
, mreadprop
)
1471 nclassdef
.mprop2npropdef
[mreadprop
] = self
1473 var mreadpropdef
= new MMethodDef(mclassdef
, mreadprop
, self.location
)
1474 self.mreadpropdef
= mreadpropdef
1475 modelbuilder
.mpropdef2npropdef
[mreadpropdef
] = self
1477 var writename
= name
+ "="
1478 var nwritable
= self.n_writable
1479 var mwriteprop
= modelbuilder
.try_get_mproperty_by_name
(nid2
, mclassdef
, writename
).as(nullable MMethod)
1480 var nwkwredef
: nullable Token = null
1481 if nwritable
!= null then nwkwredef
= nwritable
.n_kwredef
1482 if mwriteprop
== null then
1484 if nwritable
!= null then
1485 mvisibility
= new_property_visibility
(modelbuilder
, nclassdef
, nwritable
.n_visibility
)
1487 mvisibility
= private_visibility
1489 mwriteprop
= new MMethod(mclassdef
, writename
, mvisibility
)
1490 if not self.check_redef_keyword
(modelbuilder
, nclassdef
, nwkwredef
, false, mwriteprop
) then return
1492 if not self.check_redef_keyword
(modelbuilder
, nclassdef
, nwkwredef
, true, mwriteprop
) then return
1493 if nwritable
!= null then
1494 check_redef_property_visibility
(modelbuilder
, nclassdef
, nwritable
.n_visibility
, mwriteprop
)
1497 nclassdef
.mprop2npropdef
[mwriteprop
] = self
1499 var mwritepropdef
= new MMethodDef(mclassdef
, mwriteprop
, self.location
)
1500 self.mwritepropdef
= mwritepropdef
1501 modelbuilder
.mpropdef2npropdef
[mwritepropdef
] = self
1505 redef fun build_signature
(modelbuilder
, nclassdef
)
1507 var mpropdef
= self.mpropdef
1508 if mpropdef
== null then return # Error thus skiped
1509 var mmodule
= mpropdef
.mclassdef
.mmodule
1510 var mtype
: nullable MType = null
1512 var ntype
= self.n_type
1513 if ntype
!= null then
1514 mtype
= modelbuilder
.resolve_mtype
(nclassdef
, ntype
)
1515 if mtype
== null then return
1518 if mtype
== null then
1519 var nexpr
= self.n_expr
1520 if nexpr
!= null then
1521 if nexpr
isa ANewExpr then
1522 mtype
= modelbuilder
.resolve_mtype
(nclassdef
, nexpr
.n_type
)
1523 else if nexpr
isa AIntExpr then
1524 var cla
= modelbuilder
.try_get_mclass_by_name
(nexpr
, mmodule
, "Int")
1525 if cla
!= null then mtype
= cla
.mclass_type
1526 else if nexpr
isa AFloatExpr then
1527 var cla
= modelbuilder
.try_get_mclass_by_name
(nexpr
, mmodule
, "Float")
1528 if cla
!= null then mtype
= cla
.mclass_type
1529 else if nexpr
isa ACharExpr then
1530 var cla
= modelbuilder
.try_get_mclass_by_name
(nexpr
, mmodule
, "Char")
1531 if cla
!= null then mtype
= cla
.mclass_type
1532 else if nexpr
isa ABoolExpr then
1533 var cla
= modelbuilder
.try_get_mclass_by_name
(nexpr
, mmodule
, "Bool")
1534 if cla
!= null then mtype
= cla
.mclass_type
1535 else if nexpr
isa ASuperstringExpr then
1536 var cla
= modelbuilder
.try_get_mclass_by_name
(nexpr
, mmodule
, "String")
1537 if cla
!= null then mtype
= cla
.mclass_type
1538 else if nexpr
isa AStringFormExpr then
1539 var cla
= modelbuilder
.try_get_mclass_by_name
(nexpr
, mmodule
, "String")
1540 if cla
!= null then mtype
= cla
.mclass_type
1542 modelbuilder
.error
(self, "Error: Untyped attribute {mpropdef}. Implicit typing allowed only for literals and new.")
1546 modelbuilder
.error
(self, "Error: Untyped attribute {mpropdef}")
1550 if mtype
== null then return
1552 mpropdef
.static_mtype
= mtype
1554 var mreadpropdef
= self.mreadpropdef
1555 if mreadpropdef
!= null then
1556 var msignature
= new MSignature(new Array[MParameter], mtype
)
1557 mreadpropdef
.msignature
= msignature
1560 var msritepropdef
= self.mwritepropdef
1561 if mwritepropdef
!= null then
1563 if n_id
!= null then
1564 name
= n_id
.text
.substring_from
(1)
1568 var mparameter
= new MParameter(name
, mtype
, false)
1569 var msignature
= new MSignature([mparameter
], null)
1570 mwritepropdef
.msignature
= msignature
1574 redef fun check_signature
(modelbuilder
, nclassdef
)
1576 var mpropdef
= self.mpropdef
1577 if mpropdef
== null then return # Error thus skiped
1578 var mmodule
= mpropdef
.mclassdef
.mmodule
1579 var ntype
= self.n_type
1580 var mtype
= self.mpropdef
.static_mtype
1581 if mtype
== null then return # Error thus skiped
1583 # Lookup for signature in the precursor
1584 # FIXME all precursors should be considered
1585 if not mpropdef
.is_intro
then
1586 var precursor_type
= mpropdef
.mproperty
.intro
.static_mtype
1587 if precursor_type
== null then return
1589 if mtype
!= precursor_type
then
1590 modelbuilder
.error
(ntype
.as(not null), "Redef Error: Wrong static type. found {mtype}, expected {precursor_type}.")
1595 # Check getter and setter
1596 var meth
= self.mreadpropdef
1597 if meth
!= null then self.check_method_signature
(modelbuilder
, nclassdef
, meth
)
1598 meth
= self.mwritepropdef
1599 if meth
!= null then self.check_method_signature
(modelbuilder
, nclassdef
, meth
)
1602 private fun check_method_signature
(modelbuilder
: ModelBuilder, nclassdef
: AClassdef, mpropdef
: MMethodDef)
1604 var mmodule
= mpropdef
.mclassdef
.mmodule
1605 var nsig
= self.n_type
1606 var mysignature
= mpropdef
.msignature
1607 if mysignature
== null then return # Error thus skiped
1609 # Lookup for signature in the precursor
1610 # FIXME all precursors should be considered
1611 if not mpropdef
.is_intro
then
1612 var msignature
= mpropdef
.mproperty
.intro
.msignature
1613 if msignature
== null then return
1615 if mysignature
.arity
!= msignature
.arity
then
1617 if nsig
!= null then node
= nsig
else node
= self
1618 modelbuilder
.error
(node
, "Redef Error: {mysignature.arity} parameters found, {msignature.arity} expected. Signature is {mpropdef}{msignature}")
1621 var precursor_ret_type
= msignature
.return_mtype
1622 var ret_type
= mysignature
.return_mtype
1623 if ret_type
!= null and precursor_ret_type
== null then
1625 if nsig
!= null then node
= nsig
else node
= self
1626 modelbuilder
.error
(node
, "Redef Error: {mpropdef.mproperty} is a procedure, not a function.")
1630 if mysignature
.arity
> 0 then
1631 # Check parameters types
1632 for i
in [0..mysignature
.arity
[ do
1633 var myt
= mysignature
.mparameters
[i
].mtype
1634 var prt
= msignature
.mparameters
[i
].mtype
1635 if not myt
.is_subtype
(mmodule
, nclassdef
.mclassdef
.bound_mtype
, prt
) and
1636 not prt
.is_subtype
(mmodule
, nclassdef
.mclassdef
.bound_mtype
, myt
) then
1638 if nsig
!= null then node
= nsig
else node
= self
1639 modelbuilder
.error
(node
, "Redef Error: Wrong type for parameter `{mysignature.mparameters[i].name}'. found {myt}, expected {prt}.")
1643 if precursor_ret_type
!= null then
1644 if ret_type
== null then
1645 # Inherit the return type
1646 ret_type
= precursor_ret_type
1647 else if not ret_type
.is_subtype
(mmodule
, nclassdef
.mclassdef
.bound_mtype
, precursor_ret_type
) then
1649 if nsig
!= null then node
= nsig
else node
= self
1650 modelbuilder
.error
(node
, "Redef Error: Wrong return type. found {ret_type}, expected {precursor_ret_type}.")
1657 redef class ATypePropdef
1658 # The associated MVirtualTypeDef once build by a `ModelBuilder'
1659 var mpropdef
: nullable MVirtualTypeDef
1660 redef fun build_property
(modelbuilder
, nclassdef
)
1662 var mclassdef
= nclassdef
.mclassdef
.as(not null)
1663 var name
= self.n_id
.text
1664 var mprop
= modelbuilder
.try_get_mproperty_by_name
(self.n_id
, mclassdef
, name
)
1665 if mprop
== null then
1666 var mvisibility
= new_property_visibility
(modelbuilder
, nclassdef
, self.n_visibility
)
1667 mprop
= new MVirtualTypeProp(mclassdef
, name
, mvisibility
)
1668 if not self.check_redef_keyword
(modelbuilder
, nclassdef
, self.n_kwredef
, false, mprop
) then return
1670 if not self.check_redef_keyword
(modelbuilder
, nclassdef
, self.n_kwredef
, true, mprop
) then return
1671 assert mprop
isa MVirtualTypeProp
1672 check_redef_property_visibility
(modelbuilder
, nclassdef
, self.n_visibility
, mprop
)
1674 nclassdef
.mprop2npropdef
[mprop
] = self
1676 var mpropdef
= new MVirtualTypeDef(mclassdef
, mprop
, self.location
)
1677 self.mpropdef
= mpropdef
1680 redef fun build_signature
(modelbuilder
, nclassdef
)
1682 var mpropdef
= self.mpropdef
1683 if mpropdef
== null then return # Error thus skiped
1684 var mmodule
= mpropdef
.mclassdef
.mmodule
1685 var mtype
: nullable MType = null
1687 var ntype
= self.n_type
1688 mtype
= modelbuilder
.resolve_mtype
(nclassdef
, ntype
)
1689 if mtype
== null then return
1691 mpropdef
.bound
= mtype
1692 # print "{mpropdef}: {mtype}"
1695 redef fun check_signature
(modelbuilder
, nclassdef
)
1697 var bound
= self.mpropdef
.bound
1699 # Fast case: the bound is not a formal type
1700 if not bound
isa MVirtualType then return
1702 var mmodule
= nclassdef
.mclassdef
.mmodule
1703 var anchor
= nclassdef
.mclassdef
.bound_mtype
1705 # Slow case: progress on each resolution until: (i) we loop, or (ii) we found a non formal type
1706 var seen
= [self.mpropdef
.mproperty
.mvirtualtype
]
1708 if seen
.has
(bound
) then
1710 modelbuilder
.error
(self, "Error: circularity of virtual type definition: {seen.join(" -> ")}")
1714 var next
= bound
.lookup_bound
(mmodule
, anchor
)
1715 if not next
isa MVirtualType then return