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
34 redef class ToolContext
36 readable var _opt_path
: OptionArray = new OptionArray("Set include path for loaders (may be used more than once)", "-I", "--path")
38 # Option --only-metamodel
39 readable var _opt_only_metamodel
: OptionBool = new OptionBool("Stop after meta-model processing", "--only-metamodel")
42 readable var _opt_only_parse
: OptionBool = new OptionBool("Only proceed to parse step of loaders", "--only-parse")
47 option_context
.add_option
(opt_path
, opt_only_parse
, opt_only_metamodel
)
50 fun modelbuilder
: ModelBuilder do return modelbuilder_real
.as(not null)
51 private var modelbuilder_real
: nullable ModelBuilder = null
53 var modelize_class_phase
: Phase = new ModelizeClassPhase(self, null)
54 var modelize_property_phase
: Phase = new ModelizePropertyPhase(self, [modelize_class_phase
])
57 private class ModelizeClassPhase
60 redef fun process_nmodule
(nmodule
)
62 toolcontext
.modelbuilder
.build_classes
(nmodule
)
66 private class ModelizePropertyPhase
68 redef fun process_nmodule
(nmodule
)
70 for nclassdef
in nmodule
.n_classdefs
do
71 toolcontext
.modelbuilder
.build_properties
(nclassdef
)
76 # A model builder knows how to load nit source files and build the associated model
78 # The model where new modules, classes and properties are added
81 # The toolcontext used to control the interaction with the user (getting options and displaying messages)
82 var toolcontext
: ToolContext
84 # Run phases on all loaded modules
87 var mmodules
= model
.mmodules
.to_a
88 model
.mmodule_importation_hierarchy
.sort
(mmodules
)
89 var nmodules
= new Array[AModule]
91 nmodules
.add
(mmodule2nmodule
[mm
])
93 toolcontext
.run_phases
(nmodules
)
96 # Instantiate a modelbuilder for a model and a toolcontext
97 # Important, the options of the toolcontext must be correctly set (parse_option already called)
98 init(model
: Model, toolcontext
: ToolContext)
101 self.toolcontext
= toolcontext
102 assert toolcontext
.modelbuilder_real
== null
103 toolcontext
.modelbuilder_real
= self
105 # Setup the paths value
106 paths
.append
(toolcontext
.opt_path
.value
)
108 var path_env
= "NIT_PATH".environ
109 if not path_env
.is_empty
then
110 paths
.append
(path_env
.split_with
(':'))
113 path_env
= "NIT_DIR".environ
114 if not path_env
.is_empty
then
115 var libname
= "{path_env}/lib"
116 if libname
.file_exists
then paths
.add
(libname
)
119 var libname
= "{sys.program_name.dirname}/../lib"
120 if libname
.file_exists
then paths
.add
(libname
.simplify_path
)
123 # Load a bunch of modules.
124 # `modules' can contains filenames or module names.
125 # Imported modules are automatically loaded and modelized.
126 # The result is the corresponding model elements.
127 # Errors and warnings are printed with the toolcontext.
129 # Note: class and property model element are not analysed.
130 fun parse
(modules
: Sequence[String]): Array[MModule]
133 # Parse and recursively load
134 self.toolcontext
.info
("*** PARSE ***", 1)
135 var mmodules
= new Array[MModule]
137 var nmodule
= self.load_module
(null, a
)
138 if nmodule
== null then continue # Skip error
139 mmodules
.add
(nmodule
.mmodule
.as(not null))
142 self.toolcontext
.info
("*** END PARSE: {time1-time0} ***", 2)
144 self.toolcontext
.check_errors
148 # Return a class named `name' visible by the module `mmodule'.
149 # Visibility in modules is correctly handled.
150 # If no such a class exists, then null is returned.
151 # If more than one class exists, then an error on `anode' is displayed and null is returned.
152 # FIXME: add a way to handle class name conflict
153 fun try_get_mclass_by_name
(anode
: ANode, mmodule
: MModule, name
: String): nullable MClass
155 var classes
= model
.get_mclasses_by_name
(name
)
156 if classes
== null then
160 var res
: nullable MClass = null
161 for mclass
in classes
do
162 if not mmodule
.in_importation
<= mclass
.intro_mmodule
then continue
163 if not mmodule
.is_visible
(mclass
.intro_mmodule
, mclass
.visibility
) then continue
167 error
(anode
, "Ambigous class name '{name}'; conflict between {mclass.full_name} and {res.full_name}")
174 # Return a property named `name' on the type `mtype' visible in the module `mmodule'.
175 # Visibility in modules is correctly handled.
176 # Protected properties are returned (it is up to the caller to check and reject protected properties).
177 # If no such a property exists, then null is returned.
178 # If more than one property exists, then an error on `anode' is displayed and null is returned.
179 # FIXME: add a way to handle property name conflict
180 fun try_get_mproperty_by_name2
(anode
: ANode, mmodule
: MModule, mtype
: MType, name
: String): nullable MProperty
182 var props
= self.model
.get_mproperties_by_name
(name
)
183 if props
== null then
187 var cache
= self.try_get_mproperty_by_name2_cache
[mmodule
, mtype
, name
]
188 if cache
!= null then return cache
190 var res
: nullable MProperty = null
191 var ress
: nullable Array[MProperty] = null
192 for mprop
in props
do
193 if not mtype
.has_mproperty
(mmodule
, mprop
) then continue
194 if not mmodule
.is_visible
(mprop
.intro_mclassdef
.mmodule
, mprop
.visibility
) then continue
198 var restype
= res
.intro_mclassdef
.bound_mtype
199 var mproptype
= mprop
.intro_mclassdef
.bound_mtype
200 if restype
.is_subtype
(mmodule
, null, mproptype
) then
202 else if mproptype
.is_subtype
(mmodule
, null, restype
) then
205 if ress
== null then ress
= new Array[MProperty]
211 var restype
= res
.intro_mclassdef
.bound_mtype
213 var mproptype
= mprop
.intro_mclassdef
.bound_mtype
214 if not restype
.is_subtype
(mmodule
, null, mproptype
) then
215 self.error
(anode
, "Ambigous property name '{name}' for {mtype}; conflict between {mprop.full_name} and {res.full_name}")
221 self.try_get_mproperty_by_name2_cache
[mmodule
, mtype
, name
] = res
225 private var try_get_mproperty_by_name2_cache
: HashMap3[MModule, MType, String, nullable MProperty] = new HashMap3[MModule, MType, String, nullable MProperty]
228 # Alias for try_get_mproperty_by_name2(anode, mclassdef.mmodule, mclassdef.mtype, name)
229 fun try_get_mproperty_by_name
(anode
: ANode, mclassdef
: MClassDef, name
: String): nullable MProperty
231 return try_get_mproperty_by_name2
(anode
, mclassdef
.mmodule
, mclassdef
.bound_mtype
, name
)
234 # The list of directories to search for top level modules
235 # The list is initially set with :
236 # * the toolcontext --path option
237 # * the NIT_PATH environment variable
238 # * some heuristics including the NIT_DIR environment variable and the progname of the process
239 # Path can be added (or removed) by the client
240 var paths
: Array[String] = new Array[String]
242 # Get a module by its short name; if required, the module is loaded, parsed and its hierarchies computed.
243 # If `mmodule' is set, then the module search starts from it up to the top level (see `paths');
244 # if `mmodule' is null then the module is searched in the top level only.
245 # If no module exists or there is a name conflict, then an error on `anode' is displayed and null is returned.
246 # FIXME: add a way to handle module name conflict
247 fun get_mmodule_by_name
(anode
: ANode, mmodule
: nullable MModule, name
: String): nullable MModule
249 var origmmodule
= mmodule
250 var modules
= model
.get_mmodules_by_name
(name
)
252 var tries
= new Array[String]
254 var lastmodule
= mmodule
255 while mmodule
!= null do
256 var dirname
= mmodule
.location
.file
.filename
.dirname
258 # Determine the owner
259 var owner
: nullable MModule
260 if dirname
.basename
("") != mmodule
.name
then
261 owner
= mmodule
.direct_owner
266 # First, try the already known nested modules
267 if modules
!= null then
268 for candidate
in modules
do
269 if candidate
.direct_owner
== owner
then
275 # Second, try the directory to find a file
276 var try_file
= dirname
+ "/" + name
+ ".nit"
278 if try_file
.file_exists
then
279 var res
= self.load_module
(owner
, try_file
.simplify_path
)
280 if res
== null then return null # Forward error
281 return res
.mmodule
.as(not null)
284 # Third, try if the requested module is itself an owner
285 try_file
= dirname
+ "/" + name
+ "/" + name
+ ".nit"
286 if try_file
.file_exists
then
287 var res
= self.load_module
(owner
, try_file
.simplify_path
)
288 if res
== null then return null # Forward error
289 return res
.mmodule
.as(not null)
293 mmodule
= mmodule
.direct_owner
296 if modules
!= null then
297 for candidate
in modules
do
298 if candidate
.direct_owner
== null then
304 # Look at some known directories
305 var lookpaths
= self.paths
307 # Look in the directory of the last module also (event if not in the path)
308 if lastmodule
!= null then
309 var dirname
= lastmodule
.location
.file
.filename
.dirname
310 if dirname
.basename
("") == lastmodule
.name
then
311 dirname
= dirname
.dirname
313 if not lookpaths
.has
(dirname
) then
314 lookpaths
= lookpaths
.to_a
315 lookpaths
.add
(dirname
)
319 var candidate
: nullable String = null
320 for dirname
in lookpaths
do
321 var try_file
= (dirname
+ "/" + name
+ ".nit").simplify_path
323 if try_file
.file_exists
then
324 if candidate
== null then
326 else if candidate
!= try_file
then
327 error
(anode
, "Error: conflicting module file for {name}: {candidate} {try_file}")
330 try_file
= (dirname
+ "/" + name
+ "/" + name
+ ".nit").simplify_path
331 if try_file
.file_exists
then
332 if candidate
== null then
334 else if candidate
!= try_file
then
335 error
(anode
, "Error: conflicting module file for {name}: {candidate} {try_file}")
339 if candidate
== null then
340 if origmmodule
!= null then
341 error
(anode
, "Error: cannot find module {name} from {origmmodule}. tried {tries.join(", ")}")
343 error
(anode
, "Error: cannot find module {name}. tried {tries.join(", ")}")
347 var res
= self.load_module
(mmodule
, candidate
)
348 if res
== null then return null # Forward error
349 return res
.mmodule
.as(not null)
352 # Try to load a module using a path.
353 # Display an error if there is a problem (IO / lexer / parser) and return null
354 # Note: usually, you do not need this method, use `get_mmodule_by_name` instead.
355 fun load_module
(owner
: nullable MModule, filename
: String): nullable AModule
357 if not filename
.file_exists
then
358 self.toolcontext
.error
(null, "Error: file {filename} not found.")
362 var x
= if owner
!= null then owner
.to_s
else "."
363 self.toolcontext
.info
("load module {filename} in {x}", 2)
366 var file
= new IFStream.open
(filename
)
367 var lexer
= new Lexer(new SourceFile(filename
, file
))
368 var parser
= new Parser(lexer
)
369 var tree
= parser
.parse
372 # Handle lexer and parser error
373 var nmodule
= tree
.n_base
374 if nmodule
== null then
375 var neof
= tree
.n_eof
376 assert neof
isa AError
377 error
(neof
, neof
.message
)
381 # Check the module name
382 var mod_name
= filename
.basename
(".nit")
383 var decl
= nmodule
.n_moduledecl
385 #warning(nmodule, "Warning: Missing 'module' keyword") #FIXME: NOT YET FOR COMPATIBILITY
387 var decl_name
= decl
.n_name
.n_id
.text
388 if decl_name
!= mod_name
then
389 error
(decl
.n_name
, "Error: module name missmatch; declared {decl_name} file named {mod_name}")
394 var mmodule
= new MModule(model
, owner
, mod_name
, nmodule
.location
)
395 nmodule
.mmodule
= mmodule
396 nmodules
.add
(nmodule
)
397 self.mmodule2nmodule
[mmodule
] = nmodule
399 build_module_importation
(nmodule
)
404 # Analysis the module importation and fill the module_importation_hierarchy
405 private fun build_module_importation
(nmodule
: AModule)
407 if nmodule
.is_importation_done
then return
408 nmodule
.is_importation_done
= true
409 var mmodule
= nmodule
.mmodule
.as(not null)
411 var imported_modules
= new Array[MModule]
412 for aimport
in nmodule
.n_imports
do
414 if not aimport
isa AStdImport then
417 var mod_name
= aimport
.n_name
.n_id
.text
418 var sup
= self.get_mmodule_by_name
(aimport
.n_name
, mmodule
, mod_name
)
419 if sup
== null then continue # Skip error
420 imported_modules
.add
(sup
)
421 var mvisibility
= aimport
.n_visibility
.mvisibility
422 mmodule
.set_visibility_for
(sup
, mvisibility
)
425 var mod_name
= "standard"
426 var sup
= self.get_mmodule_by_name
(nmodule
, null, mod_name
)
427 if sup
!= null then # Skip error
428 imported_modules
.add
(sup
)
429 mmodule
.set_visibility_for
(sup
, public_visibility
)
432 self.toolcontext
.info
("{mmodule} imports {imported_modules.join(", ")}", 3)
433 mmodule
.set_imported_mmodules
(imported_modules
)
436 # All the loaded modules
437 var nmodules
: Array[AModule] = new Array[AModule]
439 # Visit the AST and create the MClass objects
440 private fun build_a_mclass
(nmodule
: AModule, nclassdef
: AClassdef)
442 var mmodule
= nmodule
.mmodule
.as(not null)
445 var nkind
: nullable AClasskind
446 var mkind
: MClassKind
447 var nvisibility
: nullable AVisibility
448 var mvisibility
: nullable MVisibility
450 if nclassdef
isa AStdClassdef then
451 name
= nclassdef
.n_id
.text
452 nkind
= nclassdef
.n_classkind
454 nvisibility
= nclassdef
.n_visibility
455 mvisibility
= nvisibility
.mvisibility
456 arity
= nclassdef
.n_formaldefs
.length
457 else if nclassdef
isa ATopClassdef then
460 mkind
= interface_kind
462 mvisibility
= public_visibility
463 else if nclassdef
isa AMainClassdef then
466 mkind
= concrete_kind
468 mvisibility
= public_visibility
473 var mclass
= try_get_mclass_by_name
(nclassdef
, mmodule
, name
)
474 if mclass
== null then
475 mclass
= new MClass(mmodule
, name
, arity
, mkind
, mvisibility
)
476 #print "new class {mclass}"
477 else if nclassdef
isa AStdClassdef and nmodule
.mclass2nclassdef
.has_key
(mclass
) then
478 error
(nclassdef
, "Error: A class {name} is already defined at line {nmodule.mclass2nclassdef[mclass].location.line_start}.")
480 else if nclassdef
isa AStdClassdef and nclassdef
.n_kwredef
== null then
481 error
(nclassdef
, "Redef error: {name} is an imported class. Add the redef keyword to refine it.")
483 else if mclass
.arity
!= arity
then
484 error
(nclassdef
, "Redef error: Formal parameter arity missmatch; got {arity}, expected {mclass.arity}.")
486 else if nkind
!= null and mkind
!= concrete_kind
and mclass
.kind
!= mkind
then
487 error
(nkind
, "Error: refinement changed the kind from a {mclass.kind} to a {mkind}")
488 else if nvisibility
!= null and mvisibility
!= public_visibility
and mclass
.visibility
!= mvisibility
then
489 error
(nvisibility
, "Error: refinement changed the visibility from a {mclass.visibility} to a {mvisibility}")
491 nclassdef
.mclass
= mclass
492 nmodule
.mclass2nclassdef
[mclass
] = nclassdef
495 # Visit the AST and create the MClassDef objects
496 private fun build_a_mclassdef
(nmodule
: AModule, nclassdef
: AClassdef)
498 var mmodule
= nmodule
.mmodule
.as(not null)
499 var objectclass
= try_get_mclass_by_name
(nmodule
, mmodule
, "Object")
500 var mclass
= nclassdef
.mclass
501 if mclass
== null then return # Skip error
502 #var mclassdef = nclassdef.mclassdef.as(not null)
504 var names
= new Array[String]
505 var bounds
= new Array[MType]
506 if nclassdef
isa AStdClassdef and mclass
.arity
> 0 then
507 # Collect formal parameter names
508 for i
in [0..mclass
.arity
[ do
509 var nfd
= nclassdef
.n_formaldefs
[i
]
510 var ptname
= nfd
.n_id
.text
511 if names
.has
(ptname
) then
512 error
(nfd
, "Error: A formal parameter type `{ptname}' already exists")
518 # Revolve bound for formal parameter names
519 for i
in [0..mclass
.arity
[ do
520 var nfd
= nclassdef
.n_formaldefs
[i
]
521 var nfdt
= nfd
.n_type
523 var bound
= resolve_mtype_unchecked
(nclassdef
, nfdt
, false)
524 if bound
== null then return # Forward error
525 if bound
.need_anchor
then
527 error
(nfd
, "Error: Formal parameter type `{names[i]}' bounded with a formal parameter type")
531 else if mclass
.mclassdefs
.is_empty
then
532 # No bound, then implicitely bound by nullable Object
533 bounds
.add
(objectclass
.mclass_type
.as_nullable
)
536 bounds
.add
(mclass
.intro
.bound_mtype
.arguments
[i
])
541 var bound_mtype
= mclass
.get_mtype
(bounds
)
542 var mclassdef
= new MClassDef(mmodule
, bound_mtype
, nclassdef
.location
, names
)
543 nclassdef
.mclassdef
= mclassdef
544 self.mclassdef2nclassdef
[mclassdef
] = nclassdef
546 if mclassdef
.is_intro
then
547 self.toolcontext
.info
("{mclassdef} introduces new {mclass.kind} {mclass.full_name}", 3)
549 self.toolcontext
.info
("{mclassdef} refine {mclass.kind} {mclass.full_name}", 3)
553 # Visit the AST and set the super-types of the MClassdef objects
554 private fun collect_a_mclassdef_inheritance
(nmodule
: AModule, nclassdef
: AClassdef)
556 var mmodule
= nmodule
.mmodule
.as(not null)
557 var objectclass
= try_get_mclass_by_name
(nmodule
, mmodule
, "Object")
558 var mclass
= nclassdef
.mclass
.as(not null)
559 var mclassdef
= nclassdef
.mclassdef
.as(not null)
561 var specobject
= true
562 var supertypes
= new Array[MClassType]
563 if nclassdef
isa AStdClassdef then
564 for nsc
in nclassdef
.n_superclasses
do
566 var ntype
= nsc
.n_type
567 var mtype
= resolve_mtype_unchecked
(nclassdef
, ntype
, false)
568 if mtype
== null then continue # Skip because of error
569 if not mtype
isa MClassType then
570 error
(ntype
, "Error: supertypes cannot be a formal type")
574 #print "new super : {mclass} < {mtype}"
577 if specobject
and mclass
.name
!= "Object" and objectclass
!= null and mclassdef
.is_intro
then
578 supertypes
.add objectclass
.mclass_type
581 mclassdef
.set_supertypes
(supertypes
)
582 if not supertypes
.is_empty
then self.toolcontext
.info
("{mclassdef} new super-types: {supertypes.join(", ")}", 3)
585 # Check the validity of the specialization heirarchy
586 private fun check_supertypes
(nmodule
: AModule, nclassdef
: AClassdef)
588 var mmodule
= nmodule
.mmodule
.as(not null)
589 var objectclass
= try_get_mclass_by_name
(nmodule
, mmodule
, "Object")
590 var mclass
= nclassdef
.mclass
.as(not null)
591 var mclassdef
= nclassdef
.mclassdef
.as(not null)
593 for s
in mclassdef
.supertypes
do
594 if s
.is_subtype
(mmodule
, mclassdef
.bound_mtype
, mclassdef
.bound_mtype
) then
595 error
(nclassdef
, "Error: Inheritance loop for class {mclass} with type {s}")
600 # Build the classes of the module `nmodule'.
601 # REQUIRE: classes of imported modules are already build. (let `phase' do the job)
602 private fun build_classes
(nmodule
: AModule)
604 # Force building recursively
605 if nmodule
.build_classes_is_done
then return
606 nmodule
.build_classes_is_done
= true
607 var mmodule
= nmodule
.mmodule
.as(not null)
608 for imp
in mmodule
.in_importation
.direct_greaters
do
610 build_classes
(mmodule2nmodule
[imp
])
614 for nclassdef
in nmodule
.n_classdefs
do
615 self.build_a_mclass
(nmodule
, nclassdef
)
618 # Create all classdefs
619 for nclassdef
in nmodule
.n_classdefs
do
620 self.build_a_mclassdef
(nmodule
, nclassdef
)
623 for nclassdef
in nmodule
.n_classdefs
do
624 if nclassdef
.mclassdef
== null then return # forward error
627 # Create inheritance on all classdefs
628 for nclassdef
in nmodule
.n_classdefs
do
629 self.collect_a_mclassdef_inheritance
(nmodule
, nclassdef
)
632 # Create the mclassdef hierarchy
633 for nclassdef
in nmodule
.n_classdefs
do
634 var mclassdef
= nclassdef
.mclassdef
.as(not null)
635 mclassdef
.add_in_hierarchy
639 for nclassdef
in nmodule
.n_classdefs
do
640 self.check_supertypes
(nmodule
, nclassdef
)
643 # Check unchecked ntypes
644 for nclassdef
in nmodule
.n_classdefs
do
645 if nclassdef
isa AStdClassdef then
646 # check bound of formal parameter
647 for nfd
in nclassdef
.n_formaldefs
do
648 var nfdt
= nfd
.n_type
649 if nfdt
!= null and nfdt
.mtype
!= null then
650 var bound
= resolve_mtype
(nclassdef
, nfdt
)
651 if bound
== null then return # Forward error
654 # check declared super types
655 for nsc
in nclassdef
.n_superclasses
do
656 var ntype
= nsc
.n_type
657 if ntype
.mtype
!= null then
658 var mtype
= resolve_mtype
(nclassdef
, ntype
)
659 if mtype
== null then return # Forward error
666 # TODO: Check that the super-class is not intrusive
668 # TODO: Check that the super-class is not already known (by transitivity)
671 # Register the nmodule associated to each mmodule
672 # FIXME: why not refine the MModule class with a nullable attribute?
673 var mmodule2nmodule
: HashMap[MModule, AModule] = new HashMap[MModule, AModule]
674 # Register the nclassdef associated to each mclassdef
675 # FIXME: why not refine the MClassDef class with a nullable attribute?
676 var mclassdef2nclassdef
: HashMap[MClassDef, AClassdef] = new HashMap[MClassDef, AClassdef]
677 # Register the npropdef associated to each mpropdef
678 # FIXME: why not refine the MPropDef class with a nullable attribute?
679 var mpropdef2npropdef
: HashMap[MPropDef, APropdef] = new HashMap[MPropDef, APropdef]
681 # Build the properties of `nclassdef'.
682 # REQUIRE: all superclasses are built.
683 private fun build_properties
(nclassdef
: AClassdef)
685 # Force building recursively
686 if nclassdef
.build_properties_is_done
then return
687 nclassdef
.build_properties_is_done
= true
688 var mclassdef
= nclassdef
.mclassdef
.as(not null)
689 if mclassdef
.in_hierarchy
== null then return # Skip error
690 for superclassdef
in mclassdef
.in_hierarchy
.direct_greaters
do
691 build_properties
(mclassdef2nclassdef
[superclassdef
])
694 for npropdef
in nclassdef
.n_propdefs
do
695 npropdef
.build_property
(self, nclassdef
)
697 for npropdef
in nclassdef
.n_propdefs
do
698 npropdef
.build_signature
(self, nclassdef
)
700 for npropdef
in nclassdef
.n_propdefs
do
701 npropdef
.check_signature
(self, nclassdef
)
703 process_default_constructors
(nclassdef
)
706 # Introduce or inherit default constructor
707 # This is the last part of `build_properties'.
708 private fun process_default_constructors
(nclassdef
: AClassdef)
710 var mclassdef
= nclassdef
.mclassdef
.as(not null)
712 # Are we a refinement
713 if not mclassdef
.is_intro
then return
715 # Is the class forbid constructors?
716 if not mclassdef
.mclass
.kind
.need_init
then return
718 # Is there already a constructor defined?
719 for mpropdef
in mclassdef
.mpropdefs
do
720 if not mpropdef
isa MMethodDef then continue
721 if mpropdef
.mproperty
.is_init
then return
724 if not nclassdef
isa AStdClassdef then return
726 var mmodule
= nclassdef
.mclassdef
.mmodule
727 # Do we inherit for a constructor?
728 var combine
= new Array[MMethod]
729 var inhc
: nullable MClass = null
730 for st
in mclassdef
.supertypes
do
732 if not c
.kind
.need_init
then continue
733 st
= st
.anchor_to
(mmodule
, nclassdef
.mclassdef
.bound_mtype
)
734 var candidate
= self.try_get_mproperty_by_name2
(nclassdef
, mmodule
, st
, "init").as(nullable MMethod)
735 if candidate
!= null and candidate
.intro
.msignature
.arity
== 0 then
736 combine
.add
(candidate
)
739 var inhc2
= c
.inherit_init_from
740 if inhc2
== null then inhc2
= c
741 if inhc2
== inhc
then continue
743 self.error
(nclassdef
, "Error: Cannot provide a defaut constructor: conflict for {inhc} and {c}")
748 if combine
.is_empty
and inhc
!= null then
749 # TODO: actively inherit the consturctor
750 self.toolcontext
.info
("{mclassdef} inherits all constructors from {inhc}", 3)
751 mclassdef
.mclass
.inherit_init_from
= inhc
754 if not combine
.is_empty
and inhc
!= null then
755 self.error
(nclassdef
, "Error: Cannot provide a defaut constructor: conflict for {combine.join(", ")} and {inhc}")
759 if not combine
.is_empty
then
760 nclassdef
.super_inits
= combine
761 var mprop
= new MMethod(mclassdef
, "init", mclassdef
.mclass
.visibility
)
762 var mpropdef
= new MMethodDef(mclassdef
, mprop
, nclassdef
.location
)
763 var mparameters
= new Array[MParameter]
764 var msignature
= new MSignature(mparameters
, null)
765 mpropdef
.msignature
= msignature
767 nclassdef
.mfree_init
= mpropdef
768 self.toolcontext
.info
("{mclassdef} gets a free empty constructor {mpropdef}{msignature}", 3)
772 # Collect undefined attributes
773 var mparameters
= new Array[MParameter]
774 for npropdef
in nclassdef
.n_propdefs
do
775 if npropdef
isa AAttrPropdef and npropdef
.n_expr
== null then
776 if npropdef
.mpropdef
== null then return # Skip broken attribute
777 var paramname
= npropdef
.mpropdef
.mproperty
.name
.substring_from
(1)
778 var ret_type
= npropdef
.mpropdef
.static_mtype
779 if ret_type
== null then return
780 var mparameter
= new MParameter(paramname
, ret_type
, false)
781 mparameters
.add
(mparameter
)
785 var mprop
= new MMethod(mclassdef
, "init", mclassdef
.mclass
.visibility
)
786 var mpropdef
= new MMethodDef(mclassdef
, mprop
, nclassdef
.location
)
787 var msignature
= new MSignature(mparameters
, null)
788 mpropdef
.msignature
= msignature
790 nclassdef
.mfree_init
= mpropdef
791 self.toolcontext
.info
("{mclassdef} gets a free constructor for attributes {mpropdef}{msignature}", 3)
794 # Return the static type associated to the node `ntype'.
795 # `classdef' is the context where the call is made (used to understand formal types)
796 # The mmodule used as context is `nclassdef.mmodule'
797 # In case of problem, an error is displayed on `ntype' and null is returned.
798 # FIXME: the name "resolve_mtype" is awful
799 fun resolve_mtype_unchecked
(nclassdef
: AClassdef, ntype
: AType, with_virtual
: Bool): nullable MType
801 var name
= ntype
.n_id
.text
802 var mclassdef
= nclassdef
.mclassdef
803 var mmodule
= nclassdef
.parent
.as(AModule).mmodule
.as(not null)
807 if mclassdef
!= null and with_virtual
then
808 var prop
= try_get_mproperty_by_name
(ntype
, mclassdef
, name
).as(nullable MVirtualTypeProp)
810 if not ntype
.n_types
.is_empty
then
811 error
(ntype
, "Type error: formal type {name} cannot have formal parameters.")
813 res
= prop
.mvirtualtype
814 if ntype
.n_kwnullable
!= null then res
= res
.as_nullable
820 # Check parameter type
821 if mclassdef
!= null and mclassdef
.parameter_names
.has
(name
) then
822 if not ntype
.n_types
.is_empty
then
823 error
(ntype
, "Type error: formal type {name} cannot have formal parameters.")
825 for i
in [0..mclassdef
.parameter_names
.length
[ do
826 if mclassdef
.parameter_names
[i
] == name
then
827 res
= mclassdef
.mclass
.mclass_type
.arguments
[i
]
828 if ntype
.n_kwnullable
!= null then res
= res
.as_nullable
837 var mclass
= try_get_mclass_by_name
(ntype
, mmodule
, name
)
838 if mclass
!= null then
839 var arity
= ntype
.n_types
.length
840 if arity
!= mclass
.arity
then
842 error
(ntype
, "Type error: '{name}' is a generic class.")
843 else if mclass
.arity
== 0 then
844 error
(ntype
, "Type error: '{name}' is not a generic class.")
846 error
(ntype
, "Type error: '{name}' has {mclass.arity} parameters ({arity} are provided).")
851 res
= mclass
.mclass_type
852 if ntype
.n_kwnullable
!= null then res
= res
.as_nullable
856 var mtypes
= new Array[MType]
857 for nt
in ntype
.n_types
do
858 var mt
= resolve_mtype_unchecked
(nclassdef
, nt
, with_virtual
)
859 if mt
== null then return null # Forward error
862 res
= mclass
.get_mtype
(mtypes
)
863 if ntype
.n_kwnullable
!= null then res
= res
.as_nullable
869 # If everything fail, then give up :(
870 error
(ntype
, "Type error: class {name} not found in module {mmodule}.")
874 # Return the static type associated to the node `ntype'.
875 # `classdef' is the context where the call is made (used to understand formal types)
876 # The mmodule used as context is `nclassdef.mmodule'
877 # In case of problem, an error is displayed on `ntype' and null is returned.
878 # FIXME: the name "resolve_mtype" is awful
879 fun resolve_mtype
(nclassdef
: AClassdef, ntype
: AType): nullable MType
881 var mtype
= ntype
.mtype
882 if mtype
== null then mtype
= resolve_mtype_unchecked
(nclassdef
, ntype
, true)
883 if mtype
== null then return null # Forward error
885 if ntype
.checked_mtype
then return mtype
886 if mtype
isa MGenericType then
887 var mmodule
= nclassdef
.parent
.as(AModule).mmodule
.as(not null)
888 var mclassdef
= nclassdef
.mclassdef
889 var mclass
= mtype
.mclass
890 for i
in [0..mclass
.arity
[ do
891 var bound
= mclass
.intro
.bound_mtype
.arguments
[i
]
892 var nt
= ntype
.n_types
[i
]
893 var mt
= resolve_mtype
(nclassdef
, nt
)
894 if mt
== null then return null # forward error
895 if not mt
.is_subtype
(mmodule
, mclassdef
.bound_mtype
, bound
) then
896 error
(nt
, "Type error: expected {bound}, got {mt}")
901 ntype
.checked_mtype
= true
905 # Helper function to display an error on a node.
906 # Alias for `self.toolcontext.error(n.hot_location, text)'
907 fun error
(n
: ANode, text
: String)
909 self.toolcontext
.error
(n
.hot_location
, text
)
912 # Helper function to display a warning on a node.
913 # Alias for: `self.toolcontext.warning(n.hot_location, text)'
914 fun warning
(n
: ANode, text
: String)
916 self.toolcontext
.warning
(n
.hot_location
, text
)
919 # Force to get the primitive method named `name' on the type `recv' or do a fatal error on `n'
920 fun force_get_primitive_method
(n
: ANode, name
: String, recv
: MType, mmodule
: MModule): MMethod
922 var res
= mmodule
.try_get_primitive_method
(name
, recv
)
924 self.toolcontext
.fatal_error
(n
.hot_location
, "Fatal Error: {recv} must have a property named {name}.")
932 # The associated MModule once build by a `ModelBuilder'
933 var mmodule
: nullable MModule
934 # Flag that indicate if the importation is already completed
935 var is_importation_done
: Bool = false
936 # Flag that indicate if the class and prop building is already completed
937 var build_classes_is_done
: Bool = false
938 # What is the AClassdef associated to a MClass?
939 # Used to check multiple definition of a class.
940 var mclass2nclassdef
: Map[MClass, AClassdef] = new HashMap[MClass, AClassdef]
945 # The class whose self inherit all the constructors.
946 # 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
947 var inherit_init_from
: nullable MClass = null
950 redef class AClassdef
951 # The associated MClass once build by a `ModelBuilder'
952 var mclass
: nullable MClass
953 # The associated MClassDef once build by a `ModelBuilder'
954 var mclassdef
: nullable MClassDef
955 var build_properties_is_done
: Bool = false
956 # The list of super-constructor to call at the start of the free constructor
957 # 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
958 var super_inits
: nullable Collection[MMethod] = null
960 # The free init (implicitely constructed by the class if required)
961 var mfree_init
: nullable MMethodDef = null
963 # What is the APropdef associated to a MProperty?
964 # Used to check multiple definition of a property.
965 var mprop2npropdef
: Map[MProperty, APropdef] = new HashMap[MProperty, APropdef]
968 redef class AClasskind
969 # The class kind associated with the AST node class
970 private fun mkind
: MClassKind is abstract
972 redef class AConcreteClasskind
973 redef fun mkind
do return concrete_kind
975 redef class AAbstractClasskind
976 redef fun mkind
do return abstract_kind
978 redef class AInterfaceClasskind
979 redef fun mkind
do return interface_kind
981 redef class AEnumClasskind
982 redef fun mkind
do return enum_kind
984 redef class AExternClasskind
985 redef fun mkind
do return extern_kind
988 redef class AVisibility
989 # The visibility level associated with the AST node class
990 private fun mvisibility
: MVisibility is abstract
992 redef class AIntrudeVisibility
993 redef fun mvisibility
do return intrude_visibility
995 redef class APublicVisibility
996 redef fun mvisibility
do return public_visibility
998 redef class AProtectedVisibility
999 redef fun mvisibility
do return protected_visibility
1001 redef class APrivateVisibility
1002 redef fun mvisibility
do return private_visibility
1006 # The mtype associated to the node
1007 var mtype
: nullable MType = null
1009 # Is the mtype a valid one?
1010 var checked_mtype
: Bool = false
1016 # Join the text of all tokens
1017 # Used to get the 'real name' of method definitions.
1018 fun collect_text
: String
1020 var v
= new TextCollectorVisitor
1027 private class TextCollectorVisitor
1029 var text
: String = ""
1032 if n
isa Token then text
+= n
.text
1037 redef class APropdef
1038 private fun build_property
(modelbuilder
: ModelBuilder, nclassdef
: AClassdef)
1041 private fun build_signature
(modelbuilder
: ModelBuilder, nclassdef
: AClassdef)
1044 private fun check_signature
(modelbuilder
: ModelBuilder, nclassdef
: AClassdef)
1047 private fun new_property_visibility
(modelbuilder
: ModelBuilder, nclassdef
: AClassdef, nvisibility
: nullable AVisibility): MVisibility
1049 var mvisibility
= public_visibility
1050 if nvisibility
!= null then mvisibility
= nvisibility
.mvisibility
1051 if nclassdef
.mclassdef
.mclass
.visibility
== private_visibility
then
1052 if mvisibility
== protected_visibility
then
1053 assert nvisibility
!= null
1054 modelbuilder
.error
(nvisibility
, "Error: The only legal visibility for properties in a private class is private.")
1055 else if mvisibility
== private_visibility
then
1056 assert nvisibility
!= null
1058 # modelbuilder.warning(nvisibility, "Warning: private is unrequired since the only legal visibility for properties in a private class is private.")
1060 mvisibility
= private_visibility
1065 private fun check_redef_property_visibility
(modelbuilder
: ModelBuilder, nclassdef
: AClassdef, nvisibility
: nullable AVisibility, mprop
: MProperty)
1067 if nvisibility
== null then return
1068 var mvisibility
= nvisibility
.mvisibility
1069 if mvisibility
!= mprop
.visibility
and mvisibility
!= public_visibility
then
1070 modelbuilder
.error
(nvisibility
, "Error: redefinition changed the visibility from a {mprop.visibility} to a {mvisibility}")
1074 private fun check_redef_keyword
(modelbuilder
: ModelBuilder, nclassdef
: AClassdef, kwredef
: nullable Token, need_redef
: Bool, mprop
: MProperty): Bool
1076 if nclassdef
.mprop2npropdef
.has_key
(mprop
) then
1077 modelbuilder
.error
(self, "Error: A property {mprop} is already defined in class {nclassdef.mclassdef.mclass}.")
1080 if kwredef
== null then
1082 modelbuilder
.error
(self, "Redef error: {nclassdef.mclassdef.mclass}::{mprop.name} is an inherited property. To redefine it, add the redef keyword.")
1086 if not need_redef
then
1087 modelbuilder
.error
(self, "Error: No property {nclassdef.mclassdef.mclass}::{mprop.name} is inherited. Remove the redef keyword to define a new property.")
1096 redef class ASignature
1097 # Is the model builder has correctly visited the signature
1098 var is_visited
= false
1099 # Names of parameters from the AST
1100 # REQUIRE: is_visited
1101 var param_names
= new Array[String]
1102 # Types of parameters from the AST
1103 # REQUIRE: is_visited
1104 var param_types
= new Array[MType]
1105 # Rank of the vararg (of -1 if none)
1106 # REQUIRE: is_visited
1107 var vararg_rank
: Int = -1
1109 var ret_type
: nullable MType = null
1111 # Visit and fill information about a signature
1112 private fun visit_signature
(modelbuilder
: ModelBuilder, nclassdef
: AClassdef): Bool
1114 var param_names
= self.param_names
1115 var param_types
= self.param_types
1116 for np
in self.n_params
do
1117 param_names
.add
(np
.n_id
.text
)
1118 var ntype
= np
.n_type
1119 if ntype
!= null then
1120 var mtype
= modelbuilder
.resolve_mtype
(nclassdef
, ntype
)
1121 if mtype
== null then return false # Skip error
1122 for i
in [0..param_names
.length-param_types
.length
[ do
1123 param_types
.add
(mtype
)
1125 if np
.n_dotdotdot
!= null then
1126 if self.vararg_rank
!= -1 then
1127 modelbuilder
.error
(np
, "Error: {param_names[self.vararg_rank]} is already a vararg")
1130 self.vararg_rank
= param_names
.length
- 1
1135 var ntype
= self.n_type
1136 if ntype
!= null then
1137 self.ret_type
= modelbuilder
.resolve_mtype
(nclassdef
, ntype
)
1138 if self.ret_type
== null then return false # Skip errir
1141 for nclosure
in self.n_closure_decls
do
1142 if not nclosure
.n_signature
.visit_signature
(modelbuilder
, nclassdef
) then return false
1145 self.is_visited
= true
1149 # Build a visited signature
1150 fun build_signature
(modelbuilder
: ModelBuilder, nclassdef
: AClassdef): nullable MSignature
1152 if param_names
.length
!= param_types
.length
then
1153 # Some parameters are typed, other parameters are not typed.
1154 modelbuilder
.error
(self.n_params
[param_types
.length
], "Error: Untyped parameter `{param_names[param_types.length]}'.")
1158 var mparameters
= new Array[MParameter]
1159 for i
in [0..param_names
.length
[ do
1160 var mparameter
= new MParameter(param_names
[i
], param_types
[i
], i
== vararg_rank
)
1161 mparameters
.add
(mparameter
)
1164 var msignature
= new MSignature(mparameters
, ret_type
)
1169 redef class AMethPropdef
1170 # The associated MMethodDef once build by a `ModelBuilder'
1171 var mpropdef
: nullable MMethodDef
1173 # The associated super init if any
1174 var super_init
: nullable MMethod
1175 redef fun build_property
(modelbuilder
, nclassdef
)
1177 var is_init
= self isa AInitPropdef
1178 var mclassdef
= nclassdef
.mclassdef
.as(not null)
1180 var amethodid
= self.n_methid
1181 var name_node
: ANode
1182 if amethodid
== null then
1183 if self isa AMainMethPropdef then
1186 else if self isa AConcreteInitPropdef then
1188 name_node
= self.n_kwinit
1189 else if self isa AExternInitPropdef then
1191 name_node
= self.n_kwnew
1195 else if amethodid
isa AIdMethid then
1196 name
= amethodid
.n_id
.text
1197 name_node
= amethodid
1199 # operator, bracket or assign
1200 name
= amethodid
.collect_text
1201 name_node
= amethodid
1203 if name
== "-" and self.n_signature
.n_params
.length
== 0 then
1208 var mprop
: nullable MMethod = null
1209 if not is_init
or n_kwredef
!= null then mprop
= modelbuilder
.try_get_mproperty_by_name
(name_node
, mclassdef
, name
).as(nullable MMethod)
1210 if mprop
== null then
1211 var mvisibility
= new_property_visibility
(modelbuilder
, nclassdef
, self.n_visibility
)
1212 mprop
= new MMethod(mclassdef
, name
, mvisibility
)
1213 mprop
.is_init
= is_init
1214 mprop
.is_new
= self isa AExternInitPropdef
1215 if not self.check_redef_keyword
(modelbuilder
, nclassdef
, n_kwredef
, false, mprop
) then return
1217 if n_kwredef
== null then
1218 if self isa AMainMethPropdef then
1221 if not self.check_redef_keyword
(modelbuilder
, nclassdef
, n_kwredef
, true, mprop
) then return
1224 check_redef_property_visibility
(modelbuilder
, nclassdef
, self.n_visibility
, mprop
)
1226 nclassdef
.mprop2npropdef
[mprop
] = self
1228 var mpropdef
= new MMethodDef(mclassdef
, mprop
, self.location
)
1230 self.mpropdef
= mpropdef
1231 modelbuilder
.mpropdef2npropdef
[mpropdef
] = self
1232 if mpropdef
.is_intro
then
1233 modelbuilder
.toolcontext
.info
("{mpropdef} introduces new method {mprop.full_name}", 3)
1235 modelbuilder
.toolcontext
.info
("{mpropdef} redefines method {mprop.full_name}", 3)
1239 redef fun build_signature
(modelbuilder
, nclassdef
)
1241 var mpropdef
= self.mpropdef
1242 if mpropdef
== null then return # Error thus skiped
1243 var mmodule
= mpropdef
.mclassdef
.mmodule
1244 var nsig
= self.n_signature
1246 # Retrieve info from the signature AST
1247 var param_names
= new Array[String] # Names of parameters from the AST
1248 var param_types
= new Array[MType] # Types of parameters from the AST
1249 var vararg_rank
= -1
1250 var ret_type
: nullable MType = null # Return type from the AST
1251 if nsig
!= null then
1252 if not nsig
.visit_signature
(modelbuilder
, nclassdef
) then return
1253 param_names
= nsig
.param_names
1254 param_types
= nsig
.param_types
1255 vararg_rank
= nsig
.vararg_rank
1256 ret_type
= nsig
.ret_type
1259 # Look for some signature to inherit
1260 # FIXME: do not inherit from the intro, but from the most specific
1261 var msignature
: nullable MSignature = null
1262 if not mpropdef
.is_intro
then
1263 msignature
= mpropdef
.mproperty
.intro
.msignature
1264 if msignature
== null then return # Skip error
1266 # Check inherited signature arity
1267 if param_names
.length
!= msignature
.arity
then
1269 if nsig
!= null then node
= nsig
else node
= self
1270 modelbuilder
.error
(node
, "Redef error: {mpropdef} redefines {mpropdef.mproperty.intro} with {param_names.length} parameter(s), {msignature.arity} expected. Signature is {mpropdef}{msignature}")
1273 else if mpropdef
.mproperty
.is_init
then
1274 # FIXME UGLY: inherit signature from a super-constructor
1275 for msupertype
in nclassdef
.mclassdef
.supertypes
do
1276 msupertype
= msupertype
.anchor_to
(mmodule
, nclassdef
.mclassdef
.bound_mtype
)
1277 var candidate
= modelbuilder
.try_get_mproperty_by_name2
(self, mmodule
, msupertype
, mpropdef
.mproperty
.name
)
1278 if candidate
!= null then
1279 if msignature
== null then
1280 msignature
= candidate
.intro
.as(MMethodDef).msignature
1287 # Inherit the signature
1288 if msignature
!= null and param_names
.length
!= param_types
.length
and param_names
.length
== msignature
.arity
and param_types
.length
== 0 then
1289 # Parameters are untyped, thus inherit them
1290 param_types
= new Array[MType]
1291 for mparameter
in msignature
.mparameters
do
1292 param_types
.add
(mparameter
.mtype
)
1294 vararg_rank
= msignature
.vararg_rank
1296 if msignature
!= null and ret_type
== null then
1297 ret_type
= msignature
.return_mtype
1300 if param_names
.length
!= param_types
.length
then
1301 # Some parameters are typed, other parameters are not typed.
1302 modelbuilder
.error
(nsig
.n_params
[param_types
.length
], "Error: Untyped parameter `{param_names[param_types.length]}'.")
1306 var mparameters
= new Array[MParameter]
1307 for i
in [0..param_names
.length
[ do
1308 var mparameter
= new MParameter(param_names
[i
], param_types
[i
], i
== vararg_rank
)
1309 mparameters
.add
(mparameter
)
1312 msignature
= new MSignature(mparameters
, ret_type
)
1313 mpropdef
.msignature
= msignature
1315 if nsig
!= null then
1316 for nclosure
in nsig
.n_closure_decls
do
1317 var clos_signature
= nclosure
.n_signature
.build_signature
(modelbuilder
, nclassdef
)
1318 if clos_signature
== null then return
1319 var mparameter
= new MParameter(nclosure
.n_id
.text
, clos_signature
, false)
1320 msignature
.mclosures
.add
(mparameter
)
1326 redef fun check_signature
(modelbuilder
, nclassdef
)
1328 var mpropdef
= self.mpropdef
1329 if mpropdef
== null then return # Error thus skiped
1330 var mmodule
= mpropdef
.mclassdef
.mmodule
1331 var nsig
= self.n_signature
1332 var mysignature
= self.mpropdef
.msignature
1333 if mysignature
== null then return # Error thus skiped
1335 # Lookup for signature in the precursor
1336 # FIXME all precursors should be considered
1337 if not mpropdef
.is_intro
then
1338 var msignature
= mpropdef
.mproperty
.intro
.msignature
1339 if msignature
== null then return
1341 var precursor_ret_type
= msignature
.return_mtype
1342 var ret_type
= mysignature
.return_mtype
1343 if ret_type
!= null and precursor_ret_type
== null then
1344 modelbuilder
.error
(nsig
.n_type
.as(not null), "Redef Error: {mpropdef.mproperty} is a procedure, not a function.")
1348 if mysignature
.arity
> 0 then
1349 # Check parameters types
1350 for i
in [0..mysignature
.arity
[ do
1351 var myt
= mysignature
.mparameters
[i
].mtype
1352 var prt
= msignature
.mparameters
[i
].mtype
1353 if not myt
.is_subtype
(mmodule
, nclassdef
.mclassdef
.bound_mtype
, prt
) and
1354 not prt
.is_subtype
(mmodule
, nclassdef
.mclassdef
.bound_mtype
, myt
) then
1355 modelbuilder
.error
(nsig
.n_params
[i
], "Redef Error: Wrong type for parameter `{mysignature.mparameters[i].name}'. found {myt}, expected {prt}.")
1359 if precursor_ret_type
!= null then
1360 if ret_type
== null then
1361 # Inherit the return type
1362 ret_type
= precursor_ret_type
1363 else if not ret_type
.is_subtype
(mmodule
, nclassdef
.mclassdef
.bound_mtype
, precursor_ret_type
) then
1364 modelbuilder
.error
(nsig
.n_type
.as(not null), "Redef Error: Wrong return type. found {ret_type}, expected {precursor_ret_type}.")
1371 redef class AAttrPropdef
1372 # The associated MAttributeDef once build by a `ModelBuilder'
1373 var mpropdef
: nullable MAttributeDef
1374 # The associated getter (read accessor) if any
1375 var mreadpropdef
: nullable MMethodDef
1376 # The associated setter (write accessor) if any
1377 var mwritepropdef
: nullable MMethodDef
1378 redef fun build_property
(modelbuilder
, nclassdef
)
1380 var mclassdef
= nclassdef
.mclassdef
.as(not null)
1381 var mclass
= mclassdef
.mclass
1384 if self.n_id
!= null then
1385 name
= self.n_id
.text
1387 name
= self.n_id2
.text
1390 if mclass
.kind
== interface_kind
or mclassdef
.mclass
.kind
== enum_kind
then
1391 modelbuilder
.error
(self, "Error: Attempt to define attribute {name} in the interface {mclass}.")
1392 else if mclass
.kind
== enum_kind
then
1393 modelbuilder
.error
(self, "Error: Attempt to define attribute {name} in the enum class {mclass}.")
1394 else if mclass
.kind
== extern_kind
then
1395 modelbuilder
.error
(self, "Error: Attempt to define attribute {name} in the extern class {mclass}.")
1400 # Old attribute style
1401 var mprop
= modelbuilder
.try_get_mproperty_by_name
(nid
, mclassdef
, name
)
1402 if mprop
== null then
1403 var mvisibility
= new_property_visibility
(modelbuilder
, nclassdef
, self.n_visibility
)
1404 mprop
= new MAttribute(mclassdef
, name
, mvisibility
)
1405 if not self.check_redef_keyword
(modelbuilder
, nclassdef
, self.n_kwredef
, false, mprop
) then return
1407 assert mprop
isa MAttribute
1408 check_redef_property_visibility
(modelbuilder
, nclassdef
, self.n_visibility
, mprop
)
1409 if not self.check_redef_keyword
(modelbuilder
, nclassdef
, self.n_kwredef
, true, mprop
) then return
1411 nclassdef
.mprop2npropdef
[mprop
] = self
1413 var mpropdef
= new MAttributeDef(mclassdef
, mprop
, self.location
)
1414 self.mpropdef
= mpropdef
1415 modelbuilder
.mpropdef2npropdef
[mpropdef
] = self
1417 var nreadable
= self.n_readable
1418 if nreadable
!= null then
1419 var readname
= name
.substring_from
(1)
1420 var mreadprop
= modelbuilder
.try_get_mproperty_by_name
(nid
, mclassdef
, readname
).as(nullable MMethod)
1421 if mreadprop
== null then
1422 var mvisibility
= new_property_visibility
(modelbuilder
, nclassdef
, nreadable
.n_visibility
)
1423 mreadprop
= new MMethod(mclassdef
, readname
, mvisibility
)
1424 if not self.check_redef_keyword
(modelbuilder
, nclassdef
, nreadable
.n_kwredef
, false, mreadprop
) then return
1426 if not self.check_redef_keyword
(modelbuilder
, nclassdef
, nreadable
.n_kwredef
, true, mreadprop
) then return
1427 check_redef_property_visibility
(modelbuilder
, nclassdef
, nreadable
.n_visibility
, mreadprop
)
1429 nclassdef
.mprop2npropdef
[mreadprop
] = self
1431 var mreadpropdef
= new MMethodDef(mclassdef
, mreadprop
, self.location
)
1432 self.mreadpropdef
= mreadpropdef
1433 modelbuilder
.mpropdef2npropdef
[mreadpropdef
] = self
1436 var nwritable
= self.n_writable
1437 if nwritable
!= null then
1438 var writename
= name
.substring_from
(1) + "="
1439 var mwriteprop
= modelbuilder
.try_get_mproperty_by_name
(nid
, mclassdef
, writename
).as(nullable MMethod)
1440 if mwriteprop
== null then
1441 var mvisibility
= new_property_visibility
(modelbuilder
, nclassdef
, nwritable
.n_visibility
)
1442 mwriteprop
= new MMethod(mclassdef
, writename
, mvisibility
)
1443 if not self.check_redef_keyword
(modelbuilder
, nclassdef
, nwritable
.n_kwredef
, false, mwriteprop
) then return
1445 if not self.check_redef_keyword
(modelbuilder
, nclassdef
, nwritable
.n_kwredef
, true, mwriteprop
) then return
1446 check_redef_property_visibility
(modelbuilder
, nclassdef
, nwritable
.n_visibility
, mwriteprop
)
1448 nclassdef
.mprop2npropdef
[mwriteprop
] = self
1450 var mwritepropdef
= new MMethodDef(mclassdef
, mwriteprop
, self.location
)
1451 self.mwritepropdef
= mwritepropdef
1452 modelbuilder
.mpropdef2npropdef
[mwritepropdef
] = self
1455 # New attribute style
1456 var nid2
= self.n_id2
.as(not null)
1457 var mprop
= new MAttribute(mclassdef
, "@" + name
, none_visibility
)
1458 var mpropdef
= new MAttributeDef(mclassdef
, mprop
, self.location
)
1459 self.mpropdef
= mpropdef
1460 modelbuilder
.mpropdef2npropdef
[mpropdef
] = self
1463 var mreadprop
= modelbuilder
.try_get_mproperty_by_name
(nid2
, mclassdef
, readname
).as(nullable MMethod)
1464 if mreadprop
== null then
1465 var mvisibility
= new_property_visibility
(modelbuilder
, nclassdef
, self.n_visibility
)
1466 mreadprop
= new MMethod(mclassdef
, readname
, mvisibility
)
1467 if not self.check_redef_keyword
(modelbuilder
, nclassdef
, n_kwredef
, false, mreadprop
) then return
1469 if not self.check_redef_keyword
(modelbuilder
, nclassdef
, n_kwredef
, true, mreadprop
) then return
1470 check_redef_property_visibility
(modelbuilder
, nclassdef
, self.n_visibility
, mreadprop
)
1472 nclassdef
.mprop2npropdef
[mreadprop
] = self
1474 var mreadpropdef
= new MMethodDef(mclassdef
, mreadprop
, self.location
)
1475 self.mreadpropdef
= mreadpropdef
1476 modelbuilder
.mpropdef2npropdef
[mreadpropdef
] = self
1478 var writename
= name
+ "="
1479 var nwritable
= self.n_writable
1480 var mwriteprop
= modelbuilder
.try_get_mproperty_by_name
(nid2
, mclassdef
, writename
).as(nullable MMethod)
1481 var nwkwredef
: nullable Token = null
1482 if nwritable
!= null then nwkwredef
= nwritable
.n_kwredef
1483 if mwriteprop
== null then
1485 if nwritable
!= null then
1486 mvisibility
= new_property_visibility
(modelbuilder
, nclassdef
, nwritable
.n_visibility
)
1488 mvisibility
= private_visibility
1490 mwriteprop
= new MMethod(mclassdef
, writename
, mvisibility
)
1491 if not self.check_redef_keyword
(modelbuilder
, nclassdef
, nwkwredef
, false, mwriteprop
) then return
1493 if not self.check_redef_keyword
(modelbuilder
, nclassdef
, nwkwredef
, true, mwriteprop
) then return
1494 if nwritable
!= null then
1495 check_redef_property_visibility
(modelbuilder
, nclassdef
, nwritable
.n_visibility
, mwriteprop
)
1498 nclassdef
.mprop2npropdef
[mwriteprop
] = self
1500 var mwritepropdef
= new MMethodDef(mclassdef
, mwriteprop
, self.location
)
1501 self.mwritepropdef
= mwritepropdef
1502 modelbuilder
.mpropdef2npropdef
[mwritepropdef
] = self
1506 redef fun build_signature
(modelbuilder
, nclassdef
)
1508 var mpropdef
= self.mpropdef
1509 if mpropdef
== null then return # Error thus skiped
1510 var mmodule
= mpropdef
.mclassdef
.mmodule
1511 var mtype
: nullable MType = null
1513 var ntype
= self.n_type
1514 if ntype
!= null then
1515 mtype
= modelbuilder
.resolve_mtype
(nclassdef
, ntype
)
1516 if mtype
== null then return
1519 if mtype
== null then
1520 var nexpr
= self.n_expr
1521 if nexpr
!= null then
1522 if nexpr
isa ANewExpr then
1523 mtype
= modelbuilder
.resolve_mtype
(nclassdef
, nexpr
.n_type
)
1524 else if nexpr
isa AIntExpr then
1525 var cla
= modelbuilder
.try_get_mclass_by_name
(nexpr
, mmodule
, "Int")
1526 if cla
!= null then mtype
= cla
.mclass_type
1527 else if nexpr
isa AFloatExpr then
1528 var cla
= modelbuilder
.try_get_mclass_by_name
(nexpr
, mmodule
, "Float")
1529 if cla
!= null then mtype
= cla
.mclass_type
1530 else if nexpr
isa ACharExpr then
1531 var cla
= modelbuilder
.try_get_mclass_by_name
(nexpr
, mmodule
, "Char")
1532 if cla
!= null then mtype
= cla
.mclass_type
1533 else if nexpr
isa ABoolExpr then
1534 var cla
= modelbuilder
.try_get_mclass_by_name
(nexpr
, mmodule
, "Bool")
1535 if cla
!= null then mtype
= cla
.mclass_type
1536 else if nexpr
isa ASuperstringExpr then
1537 var cla
= modelbuilder
.try_get_mclass_by_name
(nexpr
, mmodule
, "String")
1538 if cla
!= null then mtype
= cla
.mclass_type
1539 else if nexpr
isa AStringFormExpr then
1540 var cla
= modelbuilder
.try_get_mclass_by_name
(nexpr
, mmodule
, "String")
1541 if cla
!= null then mtype
= cla
.mclass_type
1543 modelbuilder
.error
(self, "Error: Untyped attribute {mpropdef}. Implicit typing allowed only for literals and new.")
1547 modelbuilder
.error
(self, "Error: Untyped attribute {mpropdef}")
1551 if mtype
== null then return
1553 mpropdef
.static_mtype
= mtype
1555 var mreadpropdef
= self.mreadpropdef
1556 if mreadpropdef
!= null then
1557 var msignature
= new MSignature(new Array[MParameter], mtype
)
1558 mreadpropdef
.msignature
= msignature
1561 var msritepropdef
= self.mwritepropdef
1562 if mwritepropdef
!= null then
1564 if n_id
!= null then
1565 name
= n_id
.text
.substring_from
(1)
1569 var mparameter
= new MParameter(name
, mtype
, false)
1570 var msignature
= new MSignature([mparameter
], null)
1571 mwritepropdef
.msignature
= msignature
1575 redef fun check_signature
(modelbuilder
, nclassdef
)
1577 var mpropdef
= self.mpropdef
1578 if mpropdef
== null then return # Error thus skiped
1579 var mmodule
= mpropdef
.mclassdef
.mmodule
1580 var ntype
= self.n_type
1581 var mtype
= self.mpropdef
.static_mtype
1582 if mtype
== null then return # Error thus skiped
1584 # Lookup for signature in the precursor
1585 # FIXME all precursors should be considered
1586 if not mpropdef
.is_intro
then
1587 var precursor_type
= mpropdef
.mproperty
.intro
.static_mtype
1588 if precursor_type
== null then return
1590 if mtype
!= precursor_type
then
1591 modelbuilder
.error
(ntype
.as(not null), "Redef Error: Wrong static type. found {mtype}, expected {precursor_type}.")
1596 # Check getter and setter
1597 var meth
= self.mreadpropdef
1598 if meth
!= null then self.check_method_signature
(modelbuilder
, nclassdef
, meth
)
1599 meth
= self.mwritepropdef
1600 if meth
!= null then self.check_method_signature
(modelbuilder
, nclassdef
, meth
)
1603 private fun check_method_signature
(modelbuilder
: ModelBuilder, nclassdef
: AClassdef, mpropdef
: MMethodDef)
1605 var mmodule
= mpropdef
.mclassdef
.mmodule
1606 var nsig
= self.n_type
1607 var mysignature
= mpropdef
.msignature
1608 if mysignature
== null then return # Error thus skiped
1610 # Lookup for signature in the precursor
1611 # FIXME all precursors should be considered
1612 if not mpropdef
.is_intro
then
1613 var msignature
= mpropdef
.mproperty
.intro
.msignature
1614 if msignature
== null then return
1616 if mysignature
.arity
!= msignature
.arity
then
1618 if nsig
!= null then node
= nsig
else node
= self
1619 modelbuilder
.error
(node
, "Redef Error: {mysignature.arity} parameters found, {msignature.arity} expected. Signature is {mpropdef}{msignature}")
1622 var precursor_ret_type
= msignature
.return_mtype
1623 var ret_type
= mysignature
.return_mtype
1624 if ret_type
!= null and precursor_ret_type
== null then
1626 if nsig
!= null then node
= nsig
else node
= self
1627 modelbuilder
.error
(node
, "Redef Error: {mpropdef.mproperty} is a procedure, not a function.")
1631 if mysignature
.arity
> 0 then
1632 # Check parameters types
1633 for i
in [0..mysignature
.arity
[ do
1634 var myt
= mysignature
.mparameters
[i
].mtype
1635 var prt
= msignature
.mparameters
[i
].mtype
1636 if not myt
.is_subtype
(mmodule
, nclassdef
.mclassdef
.bound_mtype
, prt
) and
1637 not prt
.is_subtype
(mmodule
, nclassdef
.mclassdef
.bound_mtype
, myt
) then
1639 if nsig
!= null then node
= nsig
else node
= self
1640 modelbuilder
.error
(node
, "Redef Error: Wrong type for parameter `{mysignature.mparameters[i].name}'. found {myt}, expected {prt}.")
1644 if precursor_ret_type
!= null then
1645 if ret_type
== null then
1646 # Inherit the return type
1647 ret_type
= precursor_ret_type
1648 else if not ret_type
.is_subtype
(mmodule
, nclassdef
.mclassdef
.bound_mtype
, precursor_ret_type
) then
1650 if nsig
!= null then node
= nsig
else node
= self
1651 modelbuilder
.error
(node
, "Redef Error: Wrong return type. found {ret_type}, expected {precursor_ret_type}.")
1658 redef class ATypePropdef
1659 # The associated MVirtualTypeDef once build by a `ModelBuilder'
1660 var mpropdef
: nullable MVirtualTypeDef
1661 redef fun build_property
(modelbuilder
, nclassdef
)
1663 var mclassdef
= nclassdef
.mclassdef
.as(not null)
1664 var name
= self.n_id
.text
1665 var mprop
= modelbuilder
.try_get_mproperty_by_name
(self.n_id
, mclassdef
, name
)
1666 if mprop
== null then
1667 var mvisibility
= new_property_visibility
(modelbuilder
, nclassdef
, self.n_visibility
)
1668 mprop
= new MVirtualTypeProp(mclassdef
, name
, mvisibility
)
1669 if not self.check_redef_keyword
(modelbuilder
, nclassdef
, self.n_kwredef
, false, mprop
) then return
1671 if not self.check_redef_keyword
(modelbuilder
, nclassdef
, self.n_kwredef
, true, mprop
) then return
1672 assert mprop
isa MVirtualTypeProp
1673 check_redef_property_visibility
(modelbuilder
, nclassdef
, self.n_visibility
, mprop
)
1675 nclassdef
.mprop2npropdef
[mprop
] = self
1677 var mpropdef
= new MVirtualTypeDef(mclassdef
, mprop
, self.location
)
1678 self.mpropdef
= mpropdef
1681 redef fun build_signature
(modelbuilder
, nclassdef
)
1683 var mpropdef
= self.mpropdef
1684 if mpropdef
== null then return # Error thus skiped
1685 var mmodule
= mpropdef
.mclassdef
.mmodule
1686 var mtype
: nullable MType = null
1688 var ntype
= self.n_type
1689 mtype
= modelbuilder
.resolve_mtype
(nclassdef
, ntype
)
1690 if mtype
== null then return
1692 mpropdef
.bound
= mtype
1693 # print "{mpropdef}: {mtype}"
1696 redef fun check_signature
(modelbuilder
, nclassdef
)
1698 var bound
= self.mpropdef
.bound
1700 # Fast case: the bound is not a formal type
1701 if not bound
isa MVirtualType then return
1703 var mmodule
= nclassdef
.mclassdef
.mmodule
1704 var anchor
= nclassdef
.mclassdef
.bound_mtype
1706 # Slow case: progress on each resolution until: (i) we loop, or (ii) we found a non formal type
1707 var seen
= [self.mpropdef
.mproperty
.mvirtualtype
]
1709 if seen
.has
(bound
) then
1711 modelbuilder
.error
(self, "Error: circularity of virtual type definition: {seen.join(" -> ")}")
1715 var next
= bound
.lookup_bound
(mmodule
, anchor
)
1716 if not next
isa MVirtualType then return