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
54 # A model builder knows how to load nit source files and build the associated model
55 # The important function is `parse_and_build' that does all the job.
56 # The others function can be used for specific tasks
58 # The model where new modules, classes and properties are added
61 # The toolcontext used to control the interaction with the user (getting options and displaying messages)
62 var toolcontext
: ToolContext
66 var mmodules
= model
.mmodules
.to_a
67 model
.mmodule_importation_hierarchy
.sort
(mmodules
)
68 var nmodules
= new Array[AModule]
70 nmodules
.add
(mmodule2nmodule
[mm
])
72 toolcontext
.run_phases
(nmodules
)
75 # Instantiate a modelbuilder for a model and a toolcontext
76 # Important, the options of the toolcontext must be correctly set (parse_option already called)
77 init(model
: Model, toolcontext
: ToolContext)
80 self.toolcontext
= toolcontext
81 assert toolcontext
.modelbuilder_real
== null
82 toolcontext
.modelbuilder_real
= self
84 # Setup the paths value
85 paths
.append
(toolcontext
.opt_path
.value
)
87 var path_env
= "NIT_PATH".environ
88 if not path_env
.is_empty
then
89 paths
.append
(path_env
.split_with
(':'))
92 path_env
= "NIT_DIR".environ
93 if not path_env
.is_empty
then
94 var libname
= "{path_env}/lib"
95 if libname
.file_exists
then paths
.add
(libname
)
98 var libname
= "{sys.program_name.dirname}/../lib"
99 if libname
.file_exists
then paths
.add
(libname
.simplify_path
)
102 # Load and analyze a bunch of modules.
103 # `modules' can contains filenames or module names.
104 # Imported modules are automatically loaded, builds and analysed.
105 # The result is the corresponding built modules.
106 # Errors and warnings are printed with the toolcontext.
108 # FIXME: Maybe just let the client do the loop (instead of playing with Sequences)
109 fun parse_and_build
(modules
: Sequence[String]): Array[MModule]
111 var mmodules
= parse
(modules
)
113 if self.toolcontext
.opt_only_parse
.value
then
114 self.toolcontext
.info
("--only-parse: stop processing", 2)
115 return new Array[MModule]
120 self.toolcontext
.info
("*** BUILD MODEL ***", 1)
121 self.build_all_classes
123 self.toolcontext
.info
("*** END BUILD MODEL: {time2-time1} ***", 2)
125 self.toolcontext
.check_errors
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 # Build the classes of all modules `nmodules'.
440 private fun build_all_classes
442 for nmodule
in self.nmodules
do
443 build_classes
(nmodule
)
444 for nclassdef
in nmodule
.n_classdefs
do
445 build_properties
(nclassdef
)
450 # Visit the AST and create the MClass objects
451 private fun build_a_mclass
(nmodule
: AModule, nclassdef
: AClassdef)
453 var mmodule
= nmodule
.mmodule
.as(not null)
456 var nkind
: nullable AClasskind
457 var mkind
: MClassKind
458 var nvisibility
: nullable AVisibility
459 var mvisibility
: nullable MVisibility
461 if nclassdef
isa AStdClassdef then
462 name
= nclassdef
.n_id
.text
463 nkind
= nclassdef
.n_classkind
465 nvisibility
= nclassdef
.n_visibility
466 mvisibility
= nvisibility
.mvisibility
467 arity
= nclassdef
.n_formaldefs
.length
468 else if nclassdef
isa ATopClassdef then
471 mkind
= interface_kind
473 mvisibility
= public_visibility
474 else if nclassdef
isa AMainClassdef then
477 mkind
= concrete_kind
479 mvisibility
= public_visibility
484 var mclass
= try_get_mclass_by_name
(nclassdef
, mmodule
, name
)
485 if mclass
== null then
486 mclass
= new MClass(mmodule
, name
, arity
, mkind
, mvisibility
)
487 #print "new class {mclass}"
488 else if nclassdef
isa AStdClassdef and nmodule
.mclass2nclassdef
.has_key
(mclass
) then
489 error
(nclassdef
, "Error: A class {name} is already defined at line {nmodule.mclass2nclassdef[mclass].location.line_start}.")
491 else if nclassdef
isa AStdClassdef and nclassdef
.n_kwredef
== null then
492 error
(nclassdef
, "Redef error: {name} is an imported class. Add the redef keyword to refine it.")
494 else if mclass
.arity
!= arity
then
495 error
(nclassdef
, "Redef error: Formal parameter arity missmatch; got {arity}, expected {mclass.arity}.")
497 else if nkind
!= null and mkind
!= concrete_kind
and mclass
.kind
!= mkind
then
498 error
(nkind
, "Error: refinement changed the kind from a {mclass.kind} to a {mkind}")
499 else if nvisibility
!= null and mvisibility
!= public_visibility
and mclass
.visibility
!= mvisibility
then
500 error
(nvisibility
, "Error: refinement changed the visibility from a {mclass.visibility} to a {mvisibility}")
502 nclassdef
.mclass
= mclass
503 nmodule
.mclass2nclassdef
[mclass
] = nclassdef
506 # Visit the AST and create the MClassDef objects
507 private fun build_a_mclassdef
(nmodule
: AModule, nclassdef
: AClassdef)
509 var mmodule
= nmodule
.mmodule
.as(not null)
510 var objectclass
= try_get_mclass_by_name
(nmodule
, mmodule
, "Object")
511 var mclass
= nclassdef
.mclass
512 if mclass
== null then return # Skip error
513 #var mclassdef = nclassdef.mclassdef.as(not null)
515 var names
= new Array[String]
516 var bounds
= new Array[MType]
517 if nclassdef
isa AStdClassdef and mclass
.arity
> 0 then
518 # Collect formal parameter names
519 for i
in [0..mclass
.arity
[ do
520 var nfd
= nclassdef
.n_formaldefs
[i
]
521 var ptname
= nfd
.n_id
.text
522 if names
.has
(ptname
) then
523 error
(nfd
, "Error: A formal parameter type `{ptname}' already exists")
529 # Revolve bound for formal parameter names
530 for i
in [0..mclass
.arity
[ do
531 var nfd
= nclassdef
.n_formaldefs
[i
]
532 var nfdt
= nfd
.n_type
534 var bound
= resolve_mtype_unchecked
(nclassdef
, nfdt
, false)
535 if bound
== null then return # Forward error
536 if bound
.need_anchor
then
538 error
(nfd
, "Error: Formal parameter type `{names[i]}' bounded with a formal parameter type")
542 else if mclass
.mclassdefs
.is_empty
then
543 # No bound, then implicitely bound by nullable Object
544 bounds
.add
(objectclass
.mclass_type
.as_nullable
)
547 bounds
.add
(mclass
.intro
.bound_mtype
.arguments
[i
])
552 var bound_mtype
= mclass
.get_mtype
(bounds
)
553 var mclassdef
= new MClassDef(mmodule
, bound_mtype
, nclassdef
.location
, names
)
554 nclassdef
.mclassdef
= mclassdef
555 self.mclassdef2nclassdef
[mclassdef
] = nclassdef
557 if mclassdef
.is_intro
then
558 self.toolcontext
.info
("{mclassdef} introduces new {mclass.kind} {mclass.full_name}", 3)
560 self.toolcontext
.info
("{mclassdef} refine {mclass.kind} {mclass.full_name}", 3)
564 # Visit the AST and set the super-types of the MClassdef objects
565 private fun collect_a_mclassdef_inheritance
(nmodule
: AModule, nclassdef
: AClassdef)
567 var mmodule
= nmodule
.mmodule
.as(not null)
568 var objectclass
= try_get_mclass_by_name
(nmodule
, mmodule
, "Object")
569 var mclass
= nclassdef
.mclass
.as(not null)
570 var mclassdef
= nclassdef
.mclassdef
.as(not null)
572 var specobject
= true
573 var supertypes
= new Array[MClassType]
574 if nclassdef
isa AStdClassdef then
575 for nsc
in nclassdef
.n_superclasses
do
577 var ntype
= nsc
.n_type
578 var mtype
= resolve_mtype_unchecked
(nclassdef
, ntype
, false)
579 if mtype
== null then continue # Skip because of error
580 if not mtype
isa MClassType then
581 error
(ntype
, "Error: supertypes cannot be a formal type")
585 #print "new super : {mclass} < {mtype}"
588 if specobject
and mclass
.name
!= "Object" and objectclass
!= null and mclassdef
.is_intro
then
589 supertypes
.add objectclass
.mclass_type
592 mclassdef
.set_supertypes
(supertypes
)
593 if not supertypes
.is_empty
then self.toolcontext
.info
("{mclassdef} new super-types: {supertypes.join(", ")}", 3)
596 # Check the validity of the specialization heirarchy
597 private fun check_supertypes
(nmodule
: AModule, nclassdef
: AClassdef)
599 var mmodule
= nmodule
.mmodule
.as(not null)
600 var objectclass
= try_get_mclass_by_name
(nmodule
, mmodule
, "Object")
601 var mclass
= nclassdef
.mclass
.as(not null)
602 var mclassdef
= nclassdef
.mclassdef
.as(not null)
604 for s
in mclassdef
.supertypes
do
605 if s
.is_subtype
(mmodule
, mclassdef
.bound_mtype
, mclassdef
.bound_mtype
) then
606 error
(nclassdef
, "Error: Inheritance loop for class {mclass} with type {s}")
611 # Build the classes of the module `nmodule'.
612 # REQUIRE: classes of imported modules are already build. (let `build_all_classes' do the job)
613 private fun build_classes
(nmodule
: AModule)
615 # Force building recursively
616 if nmodule
.build_classes_is_done
then return
617 nmodule
.build_classes_is_done
= true
618 var mmodule
= nmodule
.mmodule
.as(not null)
619 for imp
in mmodule
.in_importation
.direct_greaters
do
621 build_classes
(mmodule2nmodule
[imp
])
625 for nclassdef
in nmodule
.n_classdefs
do
626 self.build_a_mclass
(nmodule
, nclassdef
)
629 # Create all classdefs
630 for nclassdef
in nmodule
.n_classdefs
do
631 self.build_a_mclassdef
(nmodule
, nclassdef
)
634 for nclassdef
in nmodule
.n_classdefs
do
635 if nclassdef
.mclassdef
== null then return # forward error
638 # Create inheritance on all classdefs
639 for nclassdef
in nmodule
.n_classdefs
do
640 self.collect_a_mclassdef_inheritance
(nmodule
, nclassdef
)
643 # Create the mclassdef hierarchy
644 for nclassdef
in nmodule
.n_classdefs
do
645 var mclassdef
= nclassdef
.mclassdef
.as(not null)
646 mclassdef
.add_in_hierarchy
650 for nclassdef
in nmodule
.n_classdefs
do
651 self.check_supertypes
(nmodule
, nclassdef
)
654 # Check unchecked ntypes
655 for nclassdef
in nmodule
.n_classdefs
do
656 if nclassdef
isa AStdClassdef then
657 # check bound of formal parameter
658 for nfd
in nclassdef
.n_formaldefs
do
659 var nfdt
= nfd
.n_type
660 if nfdt
!= null and nfdt
.mtype
!= null then
661 var bound
= resolve_mtype
(nclassdef
, nfdt
)
662 if bound
== null then return # Forward error
665 # check declared super types
666 for nsc
in nclassdef
.n_superclasses
do
667 var ntype
= nsc
.n_type
668 if ntype
.mtype
!= null then
669 var mtype
= resolve_mtype
(nclassdef
, ntype
)
670 if mtype
== null then return # Forward error
677 # TODO: Check that the super-class is not intrusive
679 # TODO: Check that the super-class is not already known (by transitivity)
682 # Register the nmodule associated to each mmodule
683 # FIXME: why not refine the MModule class with a nullable attribute?
684 var mmodule2nmodule
: HashMap[MModule, AModule] = new HashMap[MModule, AModule]
685 # Register the nclassdef associated to each mclassdef
686 # FIXME: why not refine the MClassDef class with a nullable attribute?
687 var mclassdef2nclassdef
: HashMap[MClassDef, AClassdef] = new HashMap[MClassDef, AClassdef]
688 # Register the npropdef associated to each mpropdef
689 # FIXME: why not refine the MPropDef class with a nullable attribute?
690 var mpropdef2npropdef
: HashMap[MPropDef, APropdef] = new HashMap[MPropDef, APropdef]
692 # Build the properties of `nclassdef'.
693 # REQUIRE: all superclasses are built.
694 private fun build_properties
(nclassdef
: AClassdef)
696 # Force building recursively
697 if nclassdef
.build_properties_is_done
then return
698 nclassdef
.build_properties_is_done
= true
699 var mclassdef
= nclassdef
.mclassdef
.as(not null)
700 if mclassdef
.in_hierarchy
== null then return # Skip error
701 for superclassdef
in mclassdef
.in_hierarchy
.direct_greaters
do
702 build_properties
(mclassdef2nclassdef
[superclassdef
])
705 for npropdef
in nclassdef
.n_propdefs
do
706 npropdef
.build_property
(self, nclassdef
)
708 for npropdef
in nclassdef
.n_propdefs
do
709 npropdef
.build_signature
(self, nclassdef
)
711 for npropdef
in nclassdef
.n_propdefs
do
712 npropdef
.check_signature
(self, nclassdef
)
714 process_default_constructors
(nclassdef
)
717 # Introduce or inherit default constructor
718 # This is the last part of `build_properties'.
719 private fun process_default_constructors
(nclassdef
: AClassdef)
721 var mclassdef
= nclassdef
.mclassdef
.as(not null)
723 # Are we a refinement
724 if not mclassdef
.is_intro
then return
726 # Is the class forbid constructors?
727 if not mclassdef
.mclass
.kind
.need_init
then return
729 # Is there already a constructor defined?
730 for mpropdef
in mclassdef
.mpropdefs
do
731 if not mpropdef
isa MMethodDef then continue
732 if mpropdef
.mproperty
.is_init
then return
735 if not nclassdef
isa AStdClassdef then return
737 var mmodule
= nclassdef
.mclassdef
.mmodule
738 # Do we inherit for a constructor?
739 var combine
= new Array[MMethod]
740 var inhc
: nullable MClass = null
741 for st
in mclassdef
.supertypes
do
743 if not c
.kind
.need_init
then continue
744 st
= st
.anchor_to
(mmodule
, nclassdef
.mclassdef
.bound_mtype
)
745 var candidate
= self.try_get_mproperty_by_name2
(nclassdef
, mmodule
, st
, "init").as(nullable MMethod)
746 if candidate
!= null and candidate
.intro
.msignature
.arity
== 0 then
747 combine
.add
(candidate
)
750 var inhc2
= c
.inherit_init_from
751 if inhc2
== null then inhc2
= c
752 if inhc2
== inhc
then continue
754 self.error
(nclassdef
, "Error: Cannot provide a defaut constructor: conflict for {inhc} and {c}")
759 if combine
.is_empty
and inhc
!= null then
760 # TODO: actively inherit the consturctor
761 self.toolcontext
.info
("{mclassdef} inherits all constructors from {inhc}", 3)
762 mclassdef
.mclass
.inherit_init_from
= inhc
765 if not combine
.is_empty
and inhc
!= null then
766 self.error
(nclassdef
, "Error: Cannot provide a defaut constructor: conflict for {combine.join(", ")} and {inhc}")
770 if not combine
.is_empty
then
771 nclassdef
.super_inits
= combine
772 var mprop
= new MMethod(mclassdef
, "init", mclassdef
.mclass
.visibility
)
773 var mpropdef
= new MMethodDef(mclassdef
, mprop
, nclassdef
.location
)
774 var mparameters
= new Array[MParameter]
775 var msignature
= new MSignature(mparameters
, null)
776 mpropdef
.msignature
= msignature
778 nclassdef
.mfree_init
= mpropdef
779 self.toolcontext
.info
("{mclassdef} gets a free empty constructor {mpropdef}{msignature}", 3)
783 # Collect undefined attributes
784 var mparameters
= new Array[MParameter]
785 for npropdef
in nclassdef
.n_propdefs
do
786 if npropdef
isa AAttrPropdef and npropdef
.n_expr
== null then
787 if npropdef
.mpropdef
== null then return # Skip broken attribute
788 var paramname
= npropdef
.mpropdef
.mproperty
.name
.substring_from
(1)
789 var ret_type
= npropdef
.mpropdef
.static_mtype
790 if ret_type
== null then return
791 var mparameter
= new MParameter(paramname
, ret_type
, false)
792 mparameters
.add
(mparameter
)
796 var mprop
= new MMethod(mclassdef
, "init", mclassdef
.mclass
.visibility
)
797 var mpropdef
= new MMethodDef(mclassdef
, mprop
, nclassdef
.location
)
798 var msignature
= new MSignature(mparameters
, null)
799 mpropdef
.msignature
= msignature
801 nclassdef
.mfree_init
= mpropdef
802 self.toolcontext
.info
("{mclassdef} gets a free constructor for attributes {mpropdef}{msignature}", 3)
805 # Return the static type associated to the node `ntype'.
806 # `classdef' is the context where the call is made (used to understand formal types)
807 # The mmodule used as context is `nclassdef.mmodule'
808 # In case of problem, an error is displayed on `ntype' and null is returned.
809 # FIXME: the name "resolve_mtype" is awful
810 fun resolve_mtype_unchecked
(nclassdef
: AClassdef, ntype
: AType, with_virtual
: Bool): nullable MType
812 var name
= ntype
.n_id
.text
813 var mclassdef
= nclassdef
.mclassdef
814 var mmodule
= nclassdef
.parent
.as(AModule).mmodule
.as(not null)
818 if mclassdef
!= null and with_virtual
then
819 var prop
= try_get_mproperty_by_name
(ntype
, mclassdef
, name
).as(nullable MVirtualTypeProp)
821 if not ntype
.n_types
.is_empty
then
822 error
(ntype
, "Type error: formal type {name} cannot have formal parameters.")
824 res
= prop
.mvirtualtype
825 if ntype
.n_kwnullable
!= null then res
= res
.as_nullable
831 # Check parameter type
832 if mclassdef
!= null and mclassdef
.parameter_names
.has
(name
) then
833 if not ntype
.n_types
.is_empty
then
834 error
(ntype
, "Type error: formal type {name} cannot have formal parameters.")
836 for i
in [0..mclassdef
.parameter_names
.length
[ do
837 if mclassdef
.parameter_names
[i
] == name
then
838 res
= mclassdef
.mclass
.mclass_type
.arguments
[i
]
839 if ntype
.n_kwnullable
!= null then res
= res
.as_nullable
848 var mclass
= try_get_mclass_by_name
(ntype
, mmodule
, name
)
849 if mclass
!= null then
850 var arity
= ntype
.n_types
.length
851 if arity
!= mclass
.arity
then
853 error
(ntype
, "Type error: '{name}' is a generic class.")
854 else if mclass
.arity
== 0 then
855 error
(ntype
, "Type error: '{name}' is not a generic class.")
857 error
(ntype
, "Type error: '{name}' has {mclass.arity} parameters ({arity} are provided).")
862 res
= mclass
.mclass_type
863 if ntype
.n_kwnullable
!= null then res
= res
.as_nullable
867 var mtypes
= new Array[MType]
868 for nt
in ntype
.n_types
do
869 var mt
= resolve_mtype_unchecked
(nclassdef
, nt
, with_virtual
)
870 if mt
== null then return null # Forward error
873 res
= mclass
.get_mtype
(mtypes
)
874 if ntype
.n_kwnullable
!= null then res
= res
.as_nullable
880 # If everything fail, then give up :(
881 error
(ntype
, "Type error: class {name} not found in module {mmodule}.")
885 # Return the static type associated to the node `ntype'.
886 # `classdef' is the context where the call is made (used to understand formal types)
887 # The mmodule used as context is `nclassdef.mmodule'
888 # In case of problem, an error is displayed on `ntype' and null is returned.
889 # FIXME: the name "resolve_mtype" is awful
890 fun resolve_mtype
(nclassdef
: AClassdef, ntype
: AType): nullable MType
892 var mtype
= ntype
.mtype
893 if mtype
== null then mtype
= resolve_mtype_unchecked
(nclassdef
, ntype
, true)
894 if mtype
== null then return null # Forward error
896 if ntype
.checked_mtype
then return mtype
897 if mtype
isa MGenericType then
898 var mmodule
= nclassdef
.parent
.as(AModule).mmodule
.as(not null)
899 var mclassdef
= nclassdef
.mclassdef
900 var mclass
= mtype
.mclass
901 for i
in [0..mclass
.arity
[ do
902 var bound
= mclass
.intro
.bound_mtype
.arguments
[i
]
903 var nt
= ntype
.n_types
[i
]
904 var mt
= resolve_mtype
(nclassdef
, nt
)
905 if mt
== null then return null # forward error
906 if not mt
.is_subtype
(mmodule
, mclassdef
.bound_mtype
, bound
) then
907 error
(nt
, "Type error: expected {bound}, got {mt}")
912 ntype
.checked_mtype
= true
916 # Helper function to display an error on a node.
917 # Alias for `self.toolcontext.error(n.hot_location, text)'
918 fun error
(n
: ANode, text
: String)
920 self.toolcontext
.error
(n
.hot_location
, text
)
923 # Helper function to display a warning on a node.
924 # Alias for: `self.toolcontext.warning(n.hot_location, text)'
925 fun warning
(n
: ANode, text
: String)
927 self.toolcontext
.warning
(n
.hot_location
, text
)
930 # Force to get the primitive method named `name' on the type `recv' or do a fatal error on `n'
931 fun force_get_primitive_method
(n
: ANode, name
: String, recv
: MType, mmodule
: MModule): MMethod
933 var res
= mmodule
.try_get_primitive_method
(name
, recv
)
935 self.toolcontext
.fatal_error
(n
.hot_location
, "Fatal Error: {recv} must have a property named {name}.")
943 # The associated MModule once build by a `ModelBuilder'
944 var mmodule
: nullable MModule
945 # Flag that indicate if the importation is already completed
946 var is_importation_done
: Bool = false
947 # Flag that indicate if the class and prop building is already completed
948 var build_classes_is_done
: Bool = false
949 # What is the AClassdef associated to a MClass?
950 # Used to check multiple definition of a class.
951 var mclass2nclassdef
: Map[MClass, AClassdef] = new HashMap[MClass, AClassdef]
956 # The class whose self inherit all the constructors.
957 # 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
958 var inherit_init_from
: nullable MClass = null
961 redef class AClassdef
962 # The associated MClass once build by a `ModelBuilder'
963 var mclass
: nullable MClass
964 # The associated MClassDef once build by a `ModelBuilder'
965 var mclassdef
: nullable MClassDef
966 var build_properties_is_done
: Bool = false
967 # The list of super-constructor to call at the start of the free constructor
968 # 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
969 var super_inits
: nullable Collection[MMethod] = null
971 # The free init (implicitely constructed by the class if required)
972 var mfree_init
: nullable MMethodDef = null
974 # What is the APropdef associated to a MProperty?
975 # Used to check multiple definition of a property.
976 var mprop2npropdef
: Map[MProperty, APropdef] = new HashMap[MProperty, APropdef]
979 redef class AClasskind
980 # The class kind associated with the AST node class
981 private fun mkind
: MClassKind is abstract
983 redef class AConcreteClasskind
984 redef fun mkind
do return concrete_kind
986 redef class AAbstractClasskind
987 redef fun mkind
do return abstract_kind
989 redef class AInterfaceClasskind
990 redef fun mkind
do return interface_kind
992 redef class AEnumClasskind
993 redef fun mkind
do return enum_kind
995 redef class AExternClasskind
996 redef fun mkind
do return extern_kind
999 redef class AVisibility
1000 # The visibility level associated with the AST node class
1001 private fun mvisibility
: MVisibility is abstract
1003 redef class AIntrudeVisibility
1004 redef fun mvisibility
do return intrude_visibility
1006 redef class APublicVisibility
1007 redef fun mvisibility
do return public_visibility
1009 redef class AProtectedVisibility
1010 redef fun mvisibility
do return protected_visibility
1012 redef class APrivateVisibility
1013 redef fun mvisibility
do return private_visibility
1017 # The mtype associated to the node
1018 var mtype
: nullable MType = null
1020 # Is the mtype a valid one?
1021 var checked_mtype
: Bool = false
1027 # Join the text of all tokens
1028 # Used to get the 'real name' of method definitions.
1029 fun collect_text
: String
1031 var v
= new TextCollectorVisitor
1038 private class TextCollectorVisitor
1040 var text
: String = ""
1043 if n
isa Token then text
+= n
.text
1048 redef class APropdef
1049 private fun build_property
(modelbuilder
: ModelBuilder, nclassdef
: AClassdef)
1052 private fun build_signature
(modelbuilder
: ModelBuilder, nclassdef
: AClassdef)
1055 private fun check_signature
(modelbuilder
: ModelBuilder, nclassdef
: AClassdef)
1058 private fun new_property_visibility
(modelbuilder
: ModelBuilder, nclassdef
: AClassdef, nvisibility
: nullable AVisibility): MVisibility
1060 var mvisibility
= public_visibility
1061 if nvisibility
!= null then mvisibility
= nvisibility
.mvisibility
1062 if nclassdef
.mclassdef
.mclass
.visibility
== private_visibility
then
1063 if mvisibility
== protected_visibility
then
1064 assert nvisibility
!= null
1065 modelbuilder
.error
(nvisibility
, "Error: The only legal visibility for properties in a private class is private.")
1066 else if mvisibility
== private_visibility
then
1067 assert nvisibility
!= null
1069 # modelbuilder.warning(nvisibility, "Warning: private is unrequired since the only legal visibility for properties in a private class is private.")
1071 mvisibility
= private_visibility
1076 private fun check_redef_property_visibility
(modelbuilder
: ModelBuilder, nclassdef
: AClassdef, nvisibility
: nullable AVisibility, mprop
: MProperty)
1078 if nvisibility
== null then return
1079 var mvisibility
= nvisibility
.mvisibility
1080 if mvisibility
!= mprop
.visibility
and mvisibility
!= public_visibility
then
1081 modelbuilder
.error
(nvisibility
, "Error: redefinition changed the visibility from a {mprop.visibility} to a {mvisibility}")
1085 private fun check_redef_keyword
(modelbuilder
: ModelBuilder, nclassdef
: AClassdef, kwredef
: nullable Token, need_redef
: Bool, mprop
: MProperty): Bool
1087 if nclassdef
.mprop2npropdef
.has_key
(mprop
) then
1088 modelbuilder
.error
(self, "Error: A property {mprop} is already defined in class {nclassdef.mclassdef.mclass}.")
1091 if kwredef
== null then
1093 modelbuilder
.error
(self, "Redef error: {nclassdef.mclassdef.mclass}::{mprop.name} is an inherited property. To redefine it, add the redef keyword.")
1097 if not need_redef
then
1098 modelbuilder
.error
(self, "Error: No property {nclassdef.mclassdef.mclass}::{mprop.name} is inherited. Remove the redef keyword to define a new property.")
1107 redef class ASignature
1108 # Is the model builder has correctly visited the signature
1109 var is_visited
= false
1110 # Names of parameters from the AST
1111 # REQUIRE: is_visited
1112 var param_names
= new Array[String]
1113 # Types of parameters from the AST
1114 # REQUIRE: is_visited
1115 var param_types
= new Array[MType]
1116 # Rank of the vararg (of -1 if none)
1117 # REQUIRE: is_visited
1118 var vararg_rank
: Int = -1
1120 var ret_type
: nullable MType = null
1122 # Visit and fill information about a signature
1123 private fun visit_signature
(modelbuilder
: ModelBuilder, nclassdef
: AClassdef): Bool
1125 var param_names
= self.param_names
1126 var param_types
= self.param_types
1127 for np
in self.n_params
do
1128 param_names
.add
(np
.n_id
.text
)
1129 var ntype
= np
.n_type
1130 if ntype
!= null then
1131 var mtype
= modelbuilder
.resolve_mtype
(nclassdef
, ntype
)
1132 if mtype
== null then return false # Skip error
1133 for i
in [0..param_names
.length-param_types
.length
[ do
1134 param_types
.add
(mtype
)
1136 if np
.n_dotdotdot
!= null then
1137 if self.vararg_rank
!= -1 then
1138 modelbuilder
.error
(np
, "Error: {param_names[self.vararg_rank]} is already a vararg")
1141 self.vararg_rank
= param_names
.length
- 1
1146 var ntype
= self.n_type
1147 if ntype
!= null then
1148 self.ret_type
= modelbuilder
.resolve_mtype
(nclassdef
, ntype
)
1149 if self.ret_type
== null then return false # Skip errir
1152 for nclosure
in self.n_closure_decls
do
1153 if not nclosure
.n_signature
.visit_signature
(modelbuilder
, nclassdef
) then return false
1156 self.is_visited
= true
1160 # Build a visited signature
1161 fun build_signature
(modelbuilder
: ModelBuilder, nclassdef
: AClassdef): nullable MSignature
1163 if param_names
.length
!= param_types
.length
then
1164 # Some parameters are typed, other parameters are not typed.
1165 modelbuilder
.error
(self.n_params
[param_types
.length
], "Error: Untyped parameter `{param_names[param_types.length]}'.")
1169 var mparameters
= new Array[MParameter]
1170 for i
in [0..param_names
.length
[ do
1171 var mparameter
= new MParameter(param_names
[i
], param_types
[i
], i
== vararg_rank
)
1172 mparameters
.add
(mparameter
)
1175 var msignature
= new MSignature(mparameters
, ret_type
)
1180 redef class AMethPropdef
1181 # The associated MMethodDef once build by a `ModelBuilder'
1182 var mpropdef
: nullable MMethodDef
1184 # The associated super init if any
1185 var super_init
: nullable MMethod
1186 redef fun build_property
(modelbuilder
, nclassdef
)
1188 var is_init
= self isa AInitPropdef
1189 var mclassdef
= nclassdef
.mclassdef
.as(not null)
1191 var amethodid
= self.n_methid
1192 var name_node
: ANode
1193 if amethodid
== null then
1194 if self isa AMainMethPropdef then
1197 else if self isa AConcreteInitPropdef then
1199 name_node
= self.n_kwinit
1200 else if self isa AExternInitPropdef then
1202 name_node
= self.n_kwnew
1206 else if amethodid
isa AIdMethid then
1207 name
= amethodid
.n_id
.text
1208 name_node
= amethodid
1210 # operator, bracket or assign
1211 name
= amethodid
.collect_text
1212 name_node
= amethodid
1214 if name
== "-" and self.n_signature
.n_params
.length
== 0 then
1219 var mprop
: nullable MMethod = null
1220 if not is_init
or n_kwredef
!= null then mprop
= modelbuilder
.try_get_mproperty_by_name
(name_node
, mclassdef
, name
).as(nullable MMethod)
1221 if mprop
== null then
1222 var mvisibility
= new_property_visibility
(modelbuilder
, nclassdef
, self.n_visibility
)
1223 mprop
= new MMethod(mclassdef
, name
, mvisibility
)
1224 mprop
.is_init
= is_init
1225 mprop
.is_new
= self isa AExternInitPropdef
1226 if not self.check_redef_keyword
(modelbuilder
, nclassdef
, n_kwredef
, false, mprop
) then return
1228 if n_kwredef
== null then
1229 if self isa AMainMethPropdef then
1232 if not self.check_redef_keyword
(modelbuilder
, nclassdef
, n_kwredef
, true, mprop
) then return
1235 check_redef_property_visibility
(modelbuilder
, nclassdef
, self.n_visibility
, mprop
)
1237 nclassdef
.mprop2npropdef
[mprop
] = self
1239 var mpropdef
= new MMethodDef(mclassdef
, mprop
, self.location
)
1241 self.mpropdef
= mpropdef
1242 modelbuilder
.mpropdef2npropdef
[mpropdef
] = self
1243 if mpropdef
.is_intro
then
1244 modelbuilder
.toolcontext
.info
("{mpropdef} introduces new method {mprop.full_name}", 3)
1246 modelbuilder
.toolcontext
.info
("{mpropdef} redefines method {mprop.full_name}", 3)
1250 redef fun build_signature
(modelbuilder
, nclassdef
)
1252 var mpropdef
= self.mpropdef
1253 if mpropdef
== null then return # Error thus skiped
1254 var mmodule
= mpropdef
.mclassdef
.mmodule
1255 var nsig
= self.n_signature
1257 # Retrieve info from the signature AST
1258 var param_names
= new Array[String] # Names of parameters from the AST
1259 var param_types
= new Array[MType] # Types of parameters from the AST
1260 var vararg_rank
= -1
1261 var ret_type
: nullable MType = null # Return type from the AST
1262 if nsig
!= null then
1263 if not nsig
.visit_signature
(modelbuilder
, nclassdef
) then return
1264 param_names
= nsig
.param_names
1265 param_types
= nsig
.param_types
1266 vararg_rank
= nsig
.vararg_rank
1267 ret_type
= nsig
.ret_type
1270 # Look for some signature to inherit
1271 # FIXME: do not inherit from the intro, but from the most specific
1272 var msignature
: nullable MSignature = null
1273 if not mpropdef
.is_intro
then
1274 msignature
= mpropdef
.mproperty
.intro
.msignature
1275 if msignature
== null then return # Skip error
1277 # Check inherited signature arity
1278 if param_names
.length
!= msignature
.arity
then
1280 if nsig
!= null then node
= nsig
else node
= self
1281 modelbuilder
.error
(node
, "Redef error: {mpropdef} redefines {mpropdef.mproperty.intro} with {param_names.length} parameter(s), {msignature.arity} expected. Signature is {mpropdef}{msignature}")
1284 else if mpropdef
.mproperty
.is_init
then
1285 # FIXME UGLY: inherit signature from a super-constructor
1286 for msupertype
in nclassdef
.mclassdef
.supertypes
do
1287 msupertype
= msupertype
.anchor_to
(mmodule
, nclassdef
.mclassdef
.bound_mtype
)
1288 var candidate
= modelbuilder
.try_get_mproperty_by_name2
(self, mmodule
, msupertype
, mpropdef
.mproperty
.name
)
1289 if candidate
!= null then
1290 if msignature
== null then
1291 msignature
= candidate
.intro
.as(MMethodDef).msignature
1298 # Inherit the signature
1299 if msignature
!= null and param_names
.length
!= param_types
.length
and param_names
.length
== msignature
.arity
and param_types
.length
== 0 then
1300 # Parameters are untyped, thus inherit them
1301 param_types
= new Array[MType]
1302 for mparameter
in msignature
.mparameters
do
1303 param_types
.add
(mparameter
.mtype
)
1305 vararg_rank
= msignature
.vararg_rank
1307 if msignature
!= null and ret_type
== null then
1308 ret_type
= msignature
.return_mtype
1311 if param_names
.length
!= param_types
.length
then
1312 # Some parameters are typed, other parameters are not typed.
1313 modelbuilder
.error
(nsig
.n_params
[param_types
.length
], "Error: Untyped parameter `{param_names[param_types.length]}'.")
1317 var mparameters
= new Array[MParameter]
1318 for i
in [0..param_names
.length
[ do
1319 var mparameter
= new MParameter(param_names
[i
], param_types
[i
], i
== vararg_rank
)
1320 mparameters
.add
(mparameter
)
1323 msignature
= new MSignature(mparameters
, ret_type
)
1324 mpropdef
.msignature
= msignature
1326 if nsig
!= null then
1327 for nclosure
in nsig
.n_closure_decls
do
1328 var clos_signature
= nclosure
.n_signature
.build_signature
(modelbuilder
, nclassdef
)
1329 if clos_signature
== null then return
1330 var mparameter
= new MParameter(nclosure
.n_id
.text
, clos_signature
, false)
1331 msignature
.mclosures
.add
(mparameter
)
1337 redef fun check_signature
(modelbuilder
, nclassdef
)
1339 var mpropdef
= self.mpropdef
1340 if mpropdef
== null then return # Error thus skiped
1341 var mmodule
= mpropdef
.mclassdef
.mmodule
1342 var nsig
= self.n_signature
1343 var mysignature
= self.mpropdef
.msignature
1344 if mysignature
== null then return # Error thus skiped
1346 # Lookup for signature in the precursor
1347 # FIXME all precursors should be considered
1348 if not mpropdef
.is_intro
then
1349 var msignature
= mpropdef
.mproperty
.intro
.msignature
1350 if msignature
== null then return
1352 var precursor_ret_type
= msignature
.return_mtype
1353 var ret_type
= mysignature
.return_mtype
1354 if ret_type
!= null and precursor_ret_type
== null then
1355 modelbuilder
.error
(nsig
.n_type
.as(not null), "Redef Error: {mpropdef.mproperty} is a procedure, not a function.")
1359 if mysignature
.arity
> 0 then
1360 # Check parameters types
1361 for i
in [0..mysignature
.arity
[ do
1362 var myt
= mysignature
.mparameters
[i
].mtype
1363 var prt
= msignature
.mparameters
[i
].mtype
1364 if not myt
.is_subtype
(mmodule
, nclassdef
.mclassdef
.bound_mtype
, prt
) and
1365 not prt
.is_subtype
(mmodule
, nclassdef
.mclassdef
.bound_mtype
, myt
) then
1366 modelbuilder
.error
(nsig
.n_params
[i
], "Redef Error: Wrong type for parameter `{mysignature.mparameters[i].name}'. found {myt}, expected {prt}.")
1370 if precursor_ret_type
!= null then
1371 if ret_type
== null then
1372 # Inherit the return type
1373 ret_type
= precursor_ret_type
1374 else if not ret_type
.is_subtype
(mmodule
, nclassdef
.mclassdef
.bound_mtype
, precursor_ret_type
) then
1375 modelbuilder
.error
(nsig
.n_type
.as(not null), "Redef Error: Wrong return type. found {ret_type}, expected {precursor_ret_type}.")
1382 redef class AAttrPropdef
1383 # The associated MAttributeDef once build by a `ModelBuilder'
1384 var mpropdef
: nullable MAttributeDef
1385 # The associated getter (read accessor) if any
1386 var mreadpropdef
: nullable MMethodDef
1387 # The associated setter (write accessor) if any
1388 var mwritepropdef
: nullable MMethodDef
1389 redef fun build_property
(modelbuilder
, nclassdef
)
1391 var mclassdef
= nclassdef
.mclassdef
.as(not null)
1392 var mclass
= mclassdef
.mclass
1395 if self.n_id
!= null then
1396 name
= self.n_id
.text
1398 name
= self.n_id2
.text
1401 if mclass
.kind
== interface_kind
or mclassdef
.mclass
.kind
== enum_kind
then
1402 modelbuilder
.error
(self, "Error: Attempt to define attribute {name} in the interface {mclass}.")
1403 else if mclass
.kind
== enum_kind
then
1404 modelbuilder
.error
(self, "Error: Attempt to define attribute {name} in the enum class {mclass}.")
1405 else if mclass
.kind
== extern_kind
then
1406 modelbuilder
.error
(self, "Error: Attempt to define attribute {name} in the extern class {mclass}.")
1411 # Old attribute style
1412 var mprop
= modelbuilder
.try_get_mproperty_by_name
(nid
, mclassdef
, name
)
1413 if mprop
== null then
1414 var mvisibility
= new_property_visibility
(modelbuilder
, nclassdef
, self.n_visibility
)
1415 mprop
= new MAttribute(mclassdef
, name
, mvisibility
)
1416 if not self.check_redef_keyword
(modelbuilder
, nclassdef
, self.n_kwredef
, false, mprop
) then return
1418 assert mprop
isa MAttribute
1419 check_redef_property_visibility
(modelbuilder
, nclassdef
, self.n_visibility
, mprop
)
1420 if not self.check_redef_keyword
(modelbuilder
, nclassdef
, self.n_kwredef
, true, mprop
) then return
1422 nclassdef
.mprop2npropdef
[mprop
] = self
1424 var mpropdef
= new MAttributeDef(mclassdef
, mprop
, self.location
)
1425 self.mpropdef
= mpropdef
1426 modelbuilder
.mpropdef2npropdef
[mpropdef
] = self
1428 var nreadable
= self.n_readable
1429 if nreadable
!= null then
1430 var readname
= name
.substring_from
(1)
1431 var mreadprop
= modelbuilder
.try_get_mproperty_by_name
(nid
, mclassdef
, readname
).as(nullable MMethod)
1432 if mreadprop
== null then
1433 var mvisibility
= new_property_visibility
(modelbuilder
, nclassdef
, nreadable
.n_visibility
)
1434 mreadprop
= new MMethod(mclassdef
, readname
, mvisibility
)
1435 if not self.check_redef_keyword
(modelbuilder
, nclassdef
, nreadable
.n_kwredef
, false, mreadprop
) then return
1437 if not self.check_redef_keyword
(modelbuilder
, nclassdef
, nreadable
.n_kwredef
, true, mreadprop
) then return
1438 check_redef_property_visibility
(modelbuilder
, nclassdef
, nreadable
.n_visibility
, mreadprop
)
1440 nclassdef
.mprop2npropdef
[mreadprop
] = self
1442 var mreadpropdef
= new MMethodDef(mclassdef
, mreadprop
, self.location
)
1443 self.mreadpropdef
= mreadpropdef
1444 modelbuilder
.mpropdef2npropdef
[mreadpropdef
] = self
1447 var nwritable
= self.n_writable
1448 if nwritable
!= null then
1449 var writename
= name
.substring_from
(1) + "="
1450 var mwriteprop
= modelbuilder
.try_get_mproperty_by_name
(nid
, mclassdef
, writename
).as(nullable MMethod)
1451 if mwriteprop
== null then
1452 var mvisibility
= new_property_visibility
(modelbuilder
, nclassdef
, nwritable
.n_visibility
)
1453 mwriteprop
= new MMethod(mclassdef
, writename
, mvisibility
)
1454 if not self.check_redef_keyword
(modelbuilder
, nclassdef
, nwritable
.n_kwredef
, false, mwriteprop
) then return
1456 if not self.check_redef_keyword
(modelbuilder
, nclassdef
, nwritable
.n_kwredef
, true, mwriteprop
) then return
1457 check_redef_property_visibility
(modelbuilder
, nclassdef
, nwritable
.n_visibility
, mwriteprop
)
1459 nclassdef
.mprop2npropdef
[mwriteprop
] = self
1461 var mwritepropdef
= new MMethodDef(mclassdef
, mwriteprop
, self.location
)
1462 self.mwritepropdef
= mwritepropdef
1463 modelbuilder
.mpropdef2npropdef
[mwritepropdef
] = self
1466 # New attribute style
1467 var nid2
= self.n_id2
.as(not null)
1468 var mprop
= new MAttribute(mclassdef
, "@" + name
, none_visibility
)
1469 var mpropdef
= new MAttributeDef(mclassdef
, mprop
, self.location
)
1470 self.mpropdef
= mpropdef
1471 modelbuilder
.mpropdef2npropdef
[mpropdef
] = self
1474 var mreadprop
= modelbuilder
.try_get_mproperty_by_name
(nid2
, mclassdef
, readname
).as(nullable MMethod)
1475 if mreadprop
== null then
1476 var mvisibility
= new_property_visibility
(modelbuilder
, nclassdef
, self.n_visibility
)
1477 mreadprop
= new MMethod(mclassdef
, readname
, mvisibility
)
1478 if not self.check_redef_keyword
(modelbuilder
, nclassdef
, n_kwredef
, false, mreadprop
) then return
1480 if not self.check_redef_keyword
(modelbuilder
, nclassdef
, n_kwredef
, true, mreadprop
) then return
1481 check_redef_property_visibility
(modelbuilder
, nclassdef
, self.n_visibility
, mreadprop
)
1483 nclassdef
.mprop2npropdef
[mreadprop
] = self
1485 var mreadpropdef
= new MMethodDef(mclassdef
, mreadprop
, self.location
)
1486 self.mreadpropdef
= mreadpropdef
1487 modelbuilder
.mpropdef2npropdef
[mreadpropdef
] = self
1489 var writename
= name
+ "="
1490 var nwritable
= self.n_writable
1491 var mwriteprop
= modelbuilder
.try_get_mproperty_by_name
(nid2
, mclassdef
, writename
).as(nullable MMethod)
1492 var nwkwredef
: nullable Token = null
1493 if nwritable
!= null then nwkwredef
= nwritable
.n_kwredef
1494 if mwriteprop
== null then
1496 if nwritable
!= null then
1497 mvisibility
= new_property_visibility
(modelbuilder
, nclassdef
, nwritable
.n_visibility
)
1499 mvisibility
= private_visibility
1501 mwriteprop
= new MMethod(mclassdef
, writename
, mvisibility
)
1502 if not self.check_redef_keyword
(modelbuilder
, nclassdef
, nwkwredef
, false, mwriteprop
) then return
1504 if not self.check_redef_keyword
(modelbuilder
, nclassdef
, nwkwredef
, true, mwriteprop
) then return
1505 if nwritable
!= null then
1506 check_redef_property_visibility
(modelbuilder
, nclassdef
, nwritable
.n_visibility
, mwriteprop
)
1509 nclassdef
.mprop2npropdef
[mwriteprop
] = self
1511 var mwritepropdef
= new MMethodDef(mclassdef
, mwriteprop
, self.location
)
1512 self.mwritepropdef
= mwritepropdef
1513 modelbuilder
.mpropdef2npropdef
[mwritepropdef
] = self
1517 redef fun build_signature
(modelbuilder
, nclassdef
)
1519 var mpropdef
= self.mpropdef
1520 if mpropdef
== null then return # Error thus skiped
1521 var mmodule
= mpropdef
.mclassdef
.mmodule
1522 var mtype
: nullable MType = null
1524 var ntype
= self.n_type
1525 if ntype
!= null then
1526 mtype
= modelbuilder
.resolve_mtype
(nclassdef
, ntype
)
1527 if mtype
== null then return
1530 if mtype
== null then
1531 var nexpr
= self.n_expr
1532 if nexpr
!= null then
1533 if nexpr
isa ANewExpr then
1534 mtype
= modelbuilder
.resolve_mtype
(nclassdef
, nexpr
.n_type
)
1535 else if nexpr
isa AIntExpr then
1536 var cla
= modelbuilder
.try_get_mclass_by_name
(nexpr
, mmodule
, "Int")
1537 if cla
!= null then mtype
= cla
.mclass_type
1538 else if nexpr
isa AFloatExpr then
1539 var cla
= modelbuilder
.try_get_mclass_by_name
(nexpr
, mmodule
, "Float")
1540 if cla
!= null then mtype
= cla
.mclass_type
1541 else if nexpr
isa ACharExpr then
1542 var cla
= modelbuilder
.try_get_mclass_by_name
(nexpr
, mmodule
, "Char")
1543 if cla
!= null then mtype
= cla
.mclass_type
1544 else if nexpr
isa ABoolExpr then
1545 var cla
= modelbuilder
.try_get_mclass_by_name
(nexpr
, mmodule
, "Bool")
1546 if cla
!= null then mtype
= cla
.mclass_type
1547 else if nexpr
isa ASuperstringExpr then
1548 var cla
= modelbuilder
.try_get_mclass_by_name
(nexpr
, mmodule
, "String")
1549 if cla
!= null then mtype
= cla
.mclass_type
1550 else if nexpr
isa AStringFormExpr then
1551 var cla
= modelbuilder
.try_get_mclass_by_name
(nexpr
, mmodule
, "String")
1552 if cla
!= null then mtype
= cla
.mclass_type
1554 modelbuilder
.error
(self, "Error: Untyped attribute {mpropdef}. Implicit typing allowed only for literals and new.")
1558 modelbuilder
.error
(self, "Error: Untyped attribute {mpropdef}")
1562 if mtype
== null then return
1564 mpropdef
.static_mtype
= mtype
1566 var mreadpropdef
= self.mreadpropdef
1567 if mreadpropdef
!= null then
1568 var msignature
= new MSignature(new Array[MParameter], mtype
)
1569 mreadpropdef
.msignature
= msignature
1572 var msritepropdef
= self.mwritepropdef
1573 if mwritepropdef
!= null then
1575 if n_id
!= null then
1576 name
= n_id
.text
.substring_from
(1)
1580 var mparameter
= new MParameter(name
, mtype
, false)
1581 var msignature
= new MSignature([mparameter
], null)
1582 mwritepropdef
.msignature
= msignature
1586 redef fun check_signature
(modelbuilder
, nclassdef
)
1588 var mpropdef
= self.mpropdef
1589 if mpropdef
== null then return # Error thus skiped
1590 var mmodule
= mpropdef
.mclassdef
.mmodule
1591 var ntype
= self.n_type
1592 var mtype
= self.mpropdef
.static_mtype
1593 if mtype
== null then return # Error thus skiped
1595 # Lookup for signature in the precursor
1596 # FIXME all precursors should be considered
1597 if not mpropdef
.is_intro
then
1598 var precursor_type
= mpropdef
.mproperty
.intro
.static_mtype
1599 if precursor_type
== null then return
1601 if mtype
!= precursor_type
then
1602 modelbuilder
.error
(ntype
.as(not null), "Redef Error: Wrong static type. found {mtype}, expected {precursor_type}.")
1607 # Check getter and setter
1608 var meth
= self.mreadpropdef
1609 if meth
!= null then self.check_method_signature
(modelbuilder
, nclassdef
, meth
)
1610 meth
= self.mwritepropdef
1611 if meth
!= null then self.check_method_signature
(modelbuilder
, nclassdef
, meth
)
1614 private fun check_method_signature
(modelbuilder
: ModelBuilder, nclassdef
: AClassdef, mpropdef
: MMethodDef)
1616 var mmodule
= mpropdef
.mclassdef
.mmodule
1617 var nsig
= self.n_type
1618 var mysignature
= mpropdef
.msignature
1619 if mysignature
== null then return # Error thus skiped
1621 # Lookup for signature in the precursor
1622 # FIXME all precursors should be considered
1623 if not mpropdef
.is_intro
then
1624 var msignature
= mpropdef
.mproperty
.intro
.msignature
1625 if msignature
== null then return
1627 if mysignature
.arity
!= msignature
.arity
then
1629 if nsig
!= null then node
= nsig
else node
= self
1630 modelbuilder
.error
(node
, "Redef Error: {mysignature.arity} parameters found, {msignature.arity} expected. Signature is {mpropdef}{msignature}")
1633 var precursor_ret_type
= msignature
.return_mtype
1634 var ret_type
= mysignature
.return_mtype
1635 if ret_type
!= null and precursor_ret_type
== null then
1637 if nsig
!= null then node
= nsig
else node
= self
1638 modelbuilder
.error
(node
, "Redef Error: {mpropdef.mproperty} is a procedure, not a function.")
1642 if mysignature
.arity
> 0 then
1643 # Check parameters types
1644 for i
in [0..mysignature
.arity
[ do
1645 var myt
= mysignature
.mparameters
[i
].mtype
1646 var prt
= msignature
.mparameters
[i
].mtype
1647 if not myt
.is_subtype
(mmodule
, nclassdef
.mclassdef
.bound_mtype
, prt
) and
1648 not prt
.is_subtype
(mmodule
, nclassdef
.mclassdef
.bound_mtype
, myt
) then
1650 if nsig
!= null then node
= nsig
else node
= self
1651 modelbuilder
.error
(node
, "Redef Error: Wrong type for parameter `{mysignature.mparameters[i].name}'. found {myt}, expected {prt}.")
1655 if precursor_ret_type
!= null then
1656 if ret_type
== null then
1657 # Inherit the return type
1658 ret_type
= precursor_ret_type
1659 else if not ret_type
.is_subtype
(mmodule
, nclassdef
.mclassdef
.bound_mtype
, precursor_ret_type
) then
1661 if nsig
!= null then node
= nsig
else node
= self
1662 modelbuilder
.error
(node
, "Redef Error: Wrong return type. found {ret_type}, expected {precursor_ret_type}.")
1669 redef class ATypePropdef
1670 # The associated MVirtualTypeDef once build by a `ModelBuilder'
1671 var mpropdef
: nullable MVirtualTypeDef
1672 redef fun build_property
(modelbuilder
, nclassdef
)
1674 var mclassdef
= nclassdef
.mclassdef
.as(not null)
1675 var name
= self.n_id
.text
1676 var mprop
= modelbuilder
.try_get_mproperty_by_name
(self.n_id
, mclassdef
, name
)
1677 if mprop
== null then
1678 var mvisibility
= new_property_visibility
(modelbuilder
, nclassdef
, self.n_visibility
)
1679 mprop
= new MVirtualTypeProp(mclassdef
, name
, mvisibility
)
1680 if not self.check_redef_keyword
(modelbuilder
, nclassdef
, self.n_kwredef
, false, mprop
) then return
1682 if not self.check_redef_keyword
(modelbuilder
, nclassdef
, self.n_kwredef
, true, mprop
) then return
1683 assert mprop
isa MVirtualTypeProp
1684 check_redef_property_visibility
(modelbuilder
, nclassdef
, self.n_visibility
, mprop
)
1686 nclassdef
.mprop2npropdef
[mprop
] = self
1688 var mpropdef
= new MVirtualTypeDef(mclassdef
, mprop
, self.location
)
1689 self.mpropdef
= mpropdef
1692 redef fun build_signature
(modelbuilder
, nclassdef
)
1694 var mpropdef
= self.mpropdef
1695 if mpropdef
== null then return # Error thus skiped
1696 var mmodule
= mpropdef
.mclassdef
.mmodule
1697 var mtype
: nullable MType = null
1699 var ntype
= self.n_type
1700 mtype
= modelbuilder
.resolve_mtype
(nclassdef
, ntype
)
1701 if mtype
== null then return
1703 mpropdef
.bound
= mtype
1704 # print "{mpropdef}: {mtype}"
1707 redef fun check_signature
(modelbuilder
, nclassdef
)
1709 var bound
= self.mpropdef
.bound
1711 # Fast case: the bound is not a formal type
1712 if not bound
isa MVirtualType then return
1714 var mmodule
= nclassdef
.mclassdef
.mmodule
1715 var anchor
= nclassdef
.mclassdef
.bound_mtype
1717 # Slow case: progress on each resolution until: (i) we loop, or (ii) we found a non formal type
1718 var seen
= [self.mpropdef
.mproperty
.mvirtualtype
]
1720 if seen
.has
(bound
) then
1722 modelbuilder
.error
(self, "Error: circularity of virtual type definition: {seen.join(" -> ")}")
1726 var next
= bound
.lookup_bound
(mmodule
, anchor
)
1727 if not next
isa MVirtualType then return