1 # This file is part of NIT ( http://www.nitlanguage.org ).
3 # Copyright 2012 Jean Privat <jean@pryen.org>
5 # Licensed under the Apache License, Version 2.0 (the "License");
6 # you may not use this file except in compliance with the License.
7 # You may obtain a copy of the License at
9 # http://www.apache.org/licenses/LICENSE-2.0
11 # Unless required by applicable law or agreed to in writing, software
12 # distributed under the License is distributed on an "AS IS" BASIS,
13 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 # See the License for the specific language governing permissions and
15 # limitations under the License.
17 # Load nit source files and build the associated model
21 # FIXME split this module into submodules
22 # FIXME add missing error checks
33 redef class ToolContext
35 readable var _opt_path
: OptionArray = new OptionArray("Set include path for loaders (may be used more than once)", "-I", "--path")
37 # Option --only-metamodel
38 readable var _opt_only_metamodel
: OptionBool = new OptionBool("Stop after meta-model processing", "--only-metamodel")
41 readable var _opt_only_parse
: OptionBool = new OptionBool("Only proceed to parse step of loaders", "--only-parse")
46 option_context
.add_option
(opt_path
, opt_only_parse
, opt_only_metamodel
)
50 # A model builder knows how to load nit source files and build the associated model
51 # The important function is `parse_and_build' that does all the job.
52 # The others function can be used for specific tasks
54 # The model where new modules, classes and properties are added
57 # The toolcontext used to control the interaction with the user (getting options and displaying messages)
58 var toolcontext
: ToolContext
60 # Instantiate a modelbuilder for a model and a toolcontext
61 # Important, the options of the toolcontext must be correctly set (parse_option already called)
62 init(model
: Model, toolcontext
: ToolContext)
65 self.toolcontext
= toolcontext
67 # Setup the paths value
68 paths
.append
(toolcontext
.opt_path
.value
)
70 var path_env
= "NIT_PATH".environ
71 if not path_env
.is_empty
then
72 paths
.append
(path_env
.split_with
(':'))
75 path_env
= "NIT_DIR".environ
76 if not path_env
.is_empty
then
77 var libname
= "{path_env}/lib"
78 if libname
.file_exists
then paths
.add
(libname
)
81 var libname
= "{sys.program_name.dirname}/../lib"
82 if libname
.file_exists
then paths
.add
(libname
.simplify_path
)
85 # Load and analyze a bunch of modules.
86 # `modules' can contains filenames or module names.
87 # Imported modules are automatically loaded, builds and analysed.
88 # The result is the corresponding built modules.
89 # Errors and warnings are printed with the toolcontext.
91 # FIXME: Maybe just let the client do the loop (instead of playing with Sequences)
92 fun parse_and_build
(modules
: Sequence[String]): Array[MModule]
94 var mmodules
= parse
(modules
)
96 if self.toolcontext
.opt_only_parse
.value
then
97 self.toolcontext
.info
("--only-parse: stop processing", 2)
98 return new Array[MModule]
103 self.toolcontext
.info
("*** BUILD MODEL ***", 1)
104 self.build_all_classes
106 self.toolcontext
.info
("*** END BUILD MODEL: {time2-time1} ***", 2)
108 self.toolcontext
.check_errors
113 fun parse
(modules
: Sequence[String]): Array[MModule]
116 # Parse and recursively load
117 self.toolcontext
.info
("*** PARSE ***", 1)
118 var mmodules
= new Array[MModule]
120 var nmodule
= self.load_module
(null, a
)
121 if nmodule
== null then continue # Skip error
122 mmodules
.add
(nmodule
.mmodule
.as(not null))
125 self.toolcontext
.info
("*** END PARSE: {time1-time0} ***", 2)
127 self.toolcontext
.check_errors
131 # Return a class named `name' visible by the module `mmodule'.
132 # Visibility in modules is correctly handled.
133 # If no such a class exists, then null is returned.
134 # If more than one class exists, then an error on `anode' is displayed and null is returned.
135 # FIXME: add a way to handle class name conflict
136 fun try_get_mclass_by_name
(anode
: ANode, mmodule
: MModule, name
: String): nullable MClass
138 var classes
= model
.get_mclasses_by_name
(name
)
139 if classes
== null then
143 var res
: nullable MClass = null
144 for mclass
in classes
do
145 if not mmodule
.in_importation
<= mclass
.intro_mmodule
then continue
146 if not mmodule
.is_visible
(mclass
.intro_mmodule
, mclass
.visibility
) then continue
150 error
(anode
, "Ambigous class name '{name}'; conflict between {mclass.full_name} and {res.full_name}")
157 # Return a property named `name' on the type `mtype' visible in the module `mmodule'.
158 # Visibility in modules is correctly handled.
159 # Protected properties are returned (it is up to the caller to check and reject protected properties).
160 # If no such a property exists, then null is returned.
161 # If more than one property exists, then an error on `anode' is displayed and null is returned.
162 # FIXME: add a way to handle property name conflict
163 fun try_get_mproperty_by_name2
(anode
: ANode, mmodule
: MModule, mtype
: MType, name
: String): nullable MProperty
165 var props
= self.model
.get_mproperties_by_name
(name
)
166 if props
== null then
170 var cache
= self.try_get_mproperty_by_name2_cache
[mmodule
, mtype
, name
]
171 if cache
!= null then return cache
173 var res
: nullable MProperty = null
174 var ress
: nullable Array[MProperty] = null
175 for mprop
in props
do
176 if not mtype
.has_mproperty
(mmodule
, mprop
) then continue
177 if not mmodule
.is_visible
(mprop
.intro_mclassdef
.mmodule
, mprop
.visibility
) then continue
181 var restype
= res
.intro_mclassdef
.bound_mtype
182 var mproptype
= mprop
.intro_mclassdef
.bound_mtype
183 if restype
.is_subtype
(mmodule
, null, mproptype
) then
185 else if mproptype
.is_subtype
(mmodule
, null, restype
) then
188 if ress
== null then ress
= new Array[MProperty]
194 var restype
= res
.intro_mclassdef
.bound_mtype
196 var mproptype
= mprop
.intro_mclassdef
.bound_mtype
197 if not restype
.is_subtype
(mmodule
, null, mproptype
) then
198 self.error
(anode
, "Ambigous property name '{name}' for {mtype}; conflict between {mprop.full_name} and {res.full_name}")
204 self.try_get_mproperty_by_name2_cache
[mmodule
, mtype
, name
] = res
208 private var try_get_mproperty_by_name2_cache
: HashMap3[MModule, MType, String, nullable MProperty] = new HashMap3[MModule, MType, String, nullable MProperty]
211 # Alias for try_get_mproperty_by_name2(anode, mclassdef.mmodule, mclassdef.mtype, name)
212 fun try_get_mproperty_by_name
(anode
: ANode, mclassdef
: MClassDef, name
: String): nullable MProperty
214 return try_get_mproperty_by_name2
(anode
, mclassdef
.mmodule
, mclassdef
.bound_mtype
, name
)
217 # The list of directories to search for top level modules
218 # The list is initially set with :
219 # * the toolcontext --path option
220 # * the NIT_PATH environment variable
221 # * some heuristics including the NIT_DIR environment variable and the progname of the process
222 # Path can be added (or removed) by the client
223 var paths
: Array[String] = new Array[String]
225 # Get a module by its short name; if required, the module is loaded, parsed and its hierarchies computed.
226 # If `mmodule' is set, then the module search starts from it up to the top level (see `paths');
227 # if `mmodule' is null then the module is searched in the top level only.
228 # If no module exists or there is a name conflict, then an error on `anode' is displayed and null is returned.
229 # FIXME: add a way to handle module name conflict
230 fun get_mmodule_by_name
(anode
: ANode, mmodule
: nullable MModule, name
: String): nullable MModule
232 var origmmodule
= mmodule
233 var modules
= model
.get_mmodules_by_name
(name
)
235 var tries
= new Array[String]
237 var lastmodule
= mmodule
238 while mmodule
!= null do
239 var dirname
= mmodule
.location
.file
.filename
.dirname
241 # Determine the owner
242 var owner
: nullable MModule
243 if dirname
.basename
("") != mmodule
.name
then
244 owner
= mmodule
.direct_owner
249 # First, try the already known nested modules
250 if modules
!= null then
251 for candidate
in modules
do
252 if candidate
.direct_owner
== owner
then
258 # Second, try the directory to find a file
259 var try_file
= dirname
+ "/" + name
+ ".nit"
261 if try_file
.file_exists
then
262 var res
= self.load_module
(owner
, try_file
.simplify_path
)
263 if res
== null then return null # Forward error
264 return res
.mmodule
.as(not null)
267 # Third, try if the requested module is itself an owner
268 try_file
= dirname
+ "/" + name
+ "/" + name
+ ".nit"
269 if try_file
.file_exists
then
270 var res
= self.load_module
(owner
, try_file
.simplify_path
)
271 if res
== null then return null # Forward error
272 return res
.mmodule
.as(not null)
276 mmodule
= mmodule
.direct_owner
279 if modules
!= null then
280 for candidate
in modules
do
281 if candidate
.direct_owner
== null then
287 # Look at some known directories
288 var lookpaths
= self.paths
290 # Look in the directory of the last module also (event if not in the path)
291 if lastmodule
!= null then
292 var dirname
= lastmodule
.location
.file
.filename
.dirname
293 if dirname
.basename
("") == lastmodule
.name
then
294 dirname
= dirname
.dirname
296 if not lookpaths
.has
(dirname
) then
297 lookpaths
= lookpaths
.to_a
298 lookpaths
.add
(dirname
)
302 var candidate
: nullable String = null
303 for dirname
in lookpaths
do
304 var try_file
= (dirname
+ "/" + name
+ ".nit").simplify_path
306 if try_file
.file_exists
then
307 if candidate
== null then
309 else if candidate
!= try_file
then
310 error
(anode
, "Error: conflicting module file for {name}: {candidate} {try_file}")
313 try_file
= (dirname
+ "/" + name
+ "/" + name
+ ".nit").simplify_path
314 if try_file
.file_exists
then
315 if candidate
== null then
317 else if candidate
!= try_file
then
318 error
(anode
, "Error: conflicting module file for {name}: {candidate} {try_file}")
322 if candidate
== null then
323 if origmmodule
!= null then
324 error
(anode
, "Error: cannot find module {name} from {origmmodule}. tried {tries.join(", ")}")
326 error
(anode
, "Error: cannot find module {name}. tried {tries.join(", ")}")
330 var res
= self.load_module
(mmodule
, candidate
)
331 if res
== null then return null # Forward error
332 return res
.mmodule
.as(not null)
335 # Try to load a module using a path.
336 # Display an error if there is a problem (IO / lexer / parser) and return null
337 # Note: usually, you do not need this method, use `get_mmodule_by_name` instead.
338 fun load_module
(owner
: nullable MModule, filename
: String): nullable AModule
340 if not filename
.file_exists
then
341 self.toolcontext
.error
(null, "Error: file {filename} not found.")
345 var x
= if owner
!= null then owner
.to_s
else "."
346 self.toolcontext
.info
("load module {filename} in {x}", 2)
349 var file
= new IFStream.open
(filename
)
350 var lexer
= new Lexer(new SourceFile(filename
, file
))
351 var parser
= new Parser(lexer
)
352 var tree
= parser
.parse
355 # Handle lexer and parser error
356 var nmodule
= tree
.n_base
357 if nmodule
== null then
358 var neof
= tree
.n_eof
359 assert neof
isa AError
360 error
(neof
, neof
.message
)
364 # Check the module name
365 var mod_name
= filename
.basename
(".nit")
366 var decl
= nmodule
.n_moduledecl
368 #warning(nmodule, "Warning: Missing 'module' keyword") #FIXME: NOT YET FOR COMPATIBILITY
370 var decl_name
= decl
.n_name
.n_id
.text
371 if decl_name
!= mod_name
then
372 error
(decl
.n_name
, "Error: module name missmatch; declared {decl_name} file named {mod_name}")
377 var mmodule
= new MModule(model
, owner
, mod_name
, nmodule
.location
)
378 nmodule
.mmodule
= mmodule
379 nmodules
.add
(nmodule
)
380 self.mmodule2nmodule
[mmodule
] = nmodule
382 build_module_importation
(nmodule
)
387 # Analysis the module importation and fill the module_importation_hierarchy
388 private fun build_module_importation
(nmodule
: AModule)
390 if nmodule
.is_importation_done
then return
391 nmodule
.is_importation_done
= true
392 var mmodule
= nmodule
.mmodule
.as(not null)
394 var imported_modules
= new Array[MModule]
395 for aimport
in nmodule
.n_imports
do
397 if not aimport
isa AStdImport then
400 var mod_name
= aimport
.n_name
.n_id
.text
401 var sup
= self.get_mmodule_by_name
(aimport
.n_name
, mmodule
, mod_name
)
402 if sup
== null then continue # Skip error
403 imported_modules
.add
(sup
)
404 var mvisibility
= aimport
.n_visibility
.mvisibility
405 mmodule
.set_visibility_for
(sup
, mvisibility
)
408 var mod_name
= "standard"
409 var sup
= self.get_mmodule_by_name
(nmodule
, null, mod_name
)
410 if sup
!= null then # Skip error
411 imported_modules
.add
(sup
)
412 mmodule
.set_visibility_for
(sup
, public_visibility
)
415 self.toolcontext
.info
("{mmodule} imports {imported_modules.join(", ")}", 3)
416 mmodule
.set_imported_mmodules
(imported_modules
)
419 # All the loaded modules
420 var nmodules
: Array[AModule] = new Array[AModule]
422 # Build the classes of all modules `nmodules'.
423 private fun build_all_classes
425 for nmodule
in self.nmodules
do
426 build_classes
(nmodule
)
430 # Visit the AST and create the MClass objects
431 private fun build_a_mclass
(nmodule
: AModule, nclassdef
: AClassdef)
433 var mmodule
= nmodule
.mmodule
.as(not null)
436 var nkind
: nullable AClasskind
437 var mkind
: MClassKind
438 var nvisibility
: nullable AVisibility
439 var mvisibility
: nullable MVisibility
441 if nclassdef
isa AStdClassdef then
442 name
= nclassdef
.n_id
.text
443 nkind
= nclassdef
.n_classkind
445 nvisibility
= nclassdef
.n_visibility
446 mvisibility
= nvisibility
.mvisibility
447 arity
= nclassdef
.n_formaldefs
.length
448 else if nclassdef
isa ATopClassdef then
451 mkind
= interface_kind
453 mvisibility
= public_visibility
454 else if nclassdef
isa AMainClassdef then
457 mkind
= concrete_kind
459 mvisibility
= public_visibility
464 var mclass
= try_get_mclass_by_name
(nclassdef
, mmodule
, name
)
465 if mclass
== null then
466 mclass
= new MClass(mmodule
, name
, arity
, mkind
, mvisibility
)
467 #print "new class {mclass}"
468 else if nclassdef
isa AStdClassdef and nmodule
.mclass2nclassdef
.has_key
(mclass
) then
469 error
(nclassdef
, "Error: A class {name} is already defined at line {nmodule.mclass2nclassdef[mclass].location.line_start}.")
471 else if nclassdef
isa AStdClassdef and nclassdef
.n_kwredef
== null then
472 error
(nclassdef
, "Redef error: {name} is an imported class. Add the redef keyword to refine it.")
474 else if mclass
.arity
!= arity
then
475 error
(nclassdef
, "Redef error: Formal parameter arity missmatch; got {arity}, expected {mclass.arity}.")
477 else if nkind
!= null and mkind
!= concrete_kind
and mclass
.kind
!= mkind
then
478 error
(nkind
, "Error: refinement changed the kind from a {mclass.kind} to a {mkind}")
479 else if nvisibility
!= null and mvisibility
!= public_visibility
and mclass
.visibility
!= mvisibility
then
480 error
(nvisibility
, "Error: refinement changed the visibility from a {mclass.visibility} to a {mvisibility}")
482 nclassdef
.mclass
= mclass
483 nmodule
.mclass2nclassdef
[mclass
] = nclassdef
486 # Visit the AST and create the MClassDef objects
487 private fun build_a_mclassdef
(nmodule
: AModule, nclassdef
: AClassdef)
489 var mmodule
= nmodule
.mmodule
.as(not null)
490 var objectclass
= try_get_mclass_by_name
(nmodule
, mmodule
, "Object")
491 var mclass
= nclassdef
.mclass
492 if mclass
== null then return # Skip error
493 #var mclassdef = nclassdef.mclassdef.as(not null)
495 var names
= new Array[String]
496 var bounds
= new Array[MType]
497 if nclassdef
isa AStdClassdef and mclass
.arity
> 0 then
498 # Collect formal parameter names
499 for i
in [0..mclass
.arity
[ do
500 var nfd
= nclassdef
.n_formaldefs
[i
]
501 var ptname
= nfd
.n_id
.text
502 if names
.has
(ptname
) then
503 error
(nfd
, "Error: A formal parameter type `{ptname}' already exists")
509 # Revolve bound for formal parameter names
510 for i
in [0..mclass
.arity
[ do
511 var nfd
= nclassdef
.n_formaldefs
[i
]
512 var nfdt
= nfd
.n_type
514 var bound
= resolve_mtype_unchecked
(nclassdef
, nfdt
, false)
515 if bound
== null then return # Forward error
516 if bound
.need_anchor
then
518 error
(nfd
, "Error: Formal parameter type `{names[i]}' bounded with a formal parameter type")
522 else if mclass
.mclassdefs
.is_empty
then
523 # No bound, then implicitely bound by nullable Object
524 bounds
.add
(objectclass
.mclass_type
.as_nullable
)
527 bounds
.add
(mclass
.intro
.bound_mtype
.arguments
[i
])
532 var bound_mtype
= mclass
.get_mtype
(bounds
)
533 var mclassdef
= new MClassDef(mmodule
, bound_mtype
, nclassdef
.location
, names
)
534 nclassdef
.mclassdef
= mclassdef
535 self.mclassdef2nclassdef
[mclassdef
] = nclassdef
537 if mclassdef
.is_intro
then
538 self.toolcontext
.info
("{mclassdef} introduces new {mclass.kind} {mclass.full_name}", 3)
540 self.toolcontext
.info
("{mclassdef} refine {mclass.kind} {mclass.full_name}", 3)
544 # Visit the AST and set the super-types of the MClassdef objects
545 private fun collect_a_mclassdef_inheritance
(nmodule
: AModule, nclassdef
: AClassdef)
547 var mmodule
= nmodule
.mmodule
.as(not null)
548 var objectclass
= try_get_mclass_by_name
(nmodule
, mmodule
, "Object")
549 var mclass
= nclassdef
.mclass
.as(not null)
550 var mclassdef
= nclassdef
.mclassdef
.as(not null)
552 var specobject
= true
553 var supertypes
= new Array[MClassType]
554 if nclassdef
isa AStdClassdef then
555 for nsc
in nclassdef
.n_superclasses
do
557 var ntype
= nsc
.n_type
558 var mtype
= resolve_mtype_unchecked
(nclassdef
, ntype
, false)
559 if mtype
== null then continue # Skip because of error
560 if not mtype
isa MClassType then
561 error
(ntype
, "Error: supertypes cannot be a formal type")
565 #print "new super : {mclass} < {mtype}"
568 if specobject
and mclass
.name
!= "Object" and objectclass
!= null and mclassdef
.is_intro
then
569 supertypes
.add objectclass
.mclass_type
572 mclassdef
.set_supertypes
(supertypes
)
573 if not supertypes
.is_empty
then self.toolcontext
.info
("{mclassdef} new super-types: {supertypes.join(", ")}", 3)
576 # Check the validity of the specialization heirarchy
577 private fun check_supertypes
(nmodule
: AModule, nclassdef
: AClassdef)
579 var mmodule
= nmodule
.mmodule
.as(not null)
580 var objectclass
= try_get_mclass_by_name
(nmodule
, mmodule
, "Object")
581 var mclass
= nclassdef
.mclass
.as(not null)
582 var mclassdef
= nclassdef
.mclassdef
.as(not null)
584 for s
in mclassdef
.supertypes
do
585 if s
.is_subtype
(mmodule
, mclassdef
.bound_mtype
, mclassdef
.bound_mtype
) then
586 error
(nclassdef
, "Error: Inheritance loop for class {mclass} with type {s}")
591 # Build the classes of the module `nmodule'.
592 # REQUIRE: classes of imported modules are already build. (let `build_all_classes' do the job)
593 private fun build_classes
(nmodule
: AModule)
595 # Force building recursively
596 if nmodule
.build_classes_is_done
then return
597 nmodule
.build_classes_is_done
= true
598 var mmodule
= nmodule
.mmodule
.as(not null)
599 for imp
in mmodule
.in_importation
.direct_greaters
do
601 build_classes
(mmodule2nmodule
[imp
])
605 for nclassdef
in nmodule
.n_classdefs
do
606 self.build_a_mclass
(nmodule
, nclassdef
)
609 # Create all classdefs
610 for nclassdef
in nmodule
.n_classdefs
do
611 self.build_a_mclassdef
(nmodule
, nclassdef
)
614 for nclassdef
in nmodule
.n_classdefs
do
615 if nclassdef
.mclassdef
== null then return # forward error
618 # Create inheritance on all classdefs
619 for nclassdef
in nmodule
.n_classdefs
do
620 self.collect_a_mclassdef_inheritance
(nmodule
, nclassdef
)
623 # Create the mclassdef hierarchy
624 for nclassdef
in nmodule
.n_classdefs
do
625 var mclassdef
= nclassdef
.mclassdef
.as(not null)
626 mclassdef
.add_in_hierarchy
630 for nclassdef
in nmodule
.n_classdefs
do
631 self.check_supertypes
(nmodule
, nclassdef
)
634 # Check unchecked ntypes
635 for nclassdef
in nmodule
.n_classdefs
do
636 if nclassdef
isa AStdClassdef then
637 # check bound of formal parameter
638 for nfd
in nclassdef
.n_formaldefs
do
639 var nfdt
= nfd
.n_type
640 if nfdt
!= null and nfdt
.mtype
!= null then
641 var bound
= resolve_mtype
(nclassdef
, nfdt
)
642 if bound
== null then return # Forward error
645 # check declared super types
646 for nsc
in nclassdef
.n_superclasses
do
647 var ntype
= nsc
.n_type
648 if ntype
.mtype
!= null then
649 var mtype
= resolve_mtype
(nclassdef
, ntype
)
650 if mtype
== null then return # Forward error
657 # TODO: Check that the super-class is not intrusive
659 # TODO: Check that the super-class is not already known (by transitivity)
661 for nclassdef
in nmodule
.n_classdefs
do
662 self.build_properties
(nclassdef
)
666 # Register the nmodule associated to each mmodule
667 # FIXME: why not refine the MModule class with a nullable attribute?
668 var mmodule2nmodule
: HashMap[MModule, AModule] = new HashMap[MModule, AModule]
669 # Register the nclassdef associated to each mclassdef
670 # FIXME: why not refine the MClassDef class with a nullable attribute?
671 var mclassdef2nclassdef
: HashMap[MClassDef, AClassdef] = new HashMap[MClassDef, AClassdef]
672 # Register the npropdef associated to each mpropdef
673 # FIXME: why not refine the MPropDef class with a nullable attribute?
674 var mpropdef2npropdef
: HashMap[MPropDef, APropdef] = new HashMap[MPropDef, APropdef]
676 # Build the properties of `nclassdef'.
677 # REQUIRE: all superclasses are built.
678 private fun build_properties
(nclassdef
: AClassdef)
680 # Force building recursively
681 if nclassdef
.build_properties_is_done
then return
682 nclassdef
.build_properties_is_done
= true
683 var mclassdef
= nclassdef
.mclassdef
.as(not null)
684 if mclassdef
.in_hierarchy
== null then return # Skip error
685 for superclassdef
in mclassdef
.in_hierarchy
.direct_greaters
do
686 build_properties
(mclassdef2nclassdef
[superclassdef
])
689 for npropdef
in nclassdef
.n_propdefs
do
690 npropdef
.build_property
(self, nclassdef
)
692 for npropdef
in nclassdef
.n_propdefs
do
693 npropdef
.build_signature
(self, nclassdef
)
695 for npropdef
in nclassdef
.n_propdefs
do
696 npropdef
.check_signature
(self, nclassdef
)
698 process_default_constructors
(nclassdef
)
701 # Introduce or inherit default constructor
702 # This is the last part of `build_properties'.
703 private fun process_default_constructors
(nclassdef
: AClassdef)
705 var mclassdef
= nclassdef
.mclassdef
.as(not null)
707 # Are we a refinement
708 if not mclassdef
.is_intro
then return
710 # Is the class forbid constructors?
711 if not mclassdef
.mclass
.kind
.need_init
then return
713 # Is there already a constructor defined?
714 for mpropdef
in mclassdef
.mpropdefs
do
715 if not mpropdef
isa MMethodDef then continue
716 if mpropdef
.mproperty
.is_init
then return
719 if not nclassdef
isa AStdClassdef then return
721 var mmodule
= nclassdef
.mclassdef
.mmodule
722 # Do we inherit for a constructor?
723 var combine
= new Array[MMethod]
724 var inhc
: nullable MClass = null
725 for st
in mclassdef
.supertypes
do
727 if not c
.kind
.need_init
then continue
728 st
= st
.anchor_to
(mmodule
, nclassdef
.mclassdef
.bound_mtype
)
729 var candidate
= self.try_get_mproperty_by_name2
(nclassdef
, mmodule
, st
, "init").as(nullable MMethod)
730 if candidate
!= null and candidate
.intro
.msignature
.arity
== 0 then
731 combine
.add
(candidate
)
734 var inhc2
= c
.inherit_init_from
735 if inhc2
== null then inhc2
= c
736 if inhc2
== inhc
then continue
738 self.error
(nclassdef
, "Error: Cannot provide a defaut constructor: conflict for {inhc} and {c}")
743 if combine
.is_empty
and inhc
!= null then
744 # TODO: actively inherit the consturctor
745 self.toolcontext
.info
("{mclassdef} inherits all constructors from {inhc}", 3)
746 mclassdef
.mclass
.inherit_init_from
= inhc
749 if not combine
.is_empty
and inhc
!= null then
750 self.error
(nclassdef
, "Error: Cannot provide a defaut constructor: conflict for {combine.join(", ")} and {inhc}")
754 if not combine
.is_empty
then
755 nclassdef
.super_inits
= combine
756 var mprop
= new MMethod(mclassdef
, "init", mclassdef
.mclass
.visibility
)
757 var mpropdef
= new MMethodDef(mclassdef
, mprop
, nclassdef
.location
)
758 var mparameters
= new Array[MParameter]
759 var msignature
= new MSignature(mparameters
, null)
760 mpropdef
.msignature
= msignature
762 nclassdef
.mfree_init
= mpropdef
763 self.toolcontext
.info
("{mclassdef} gets a free empty constructor {mpropdef}{msignature}", 3)
767 # Collect undefined attributes
768 var mparameters
= new Array[MParameter]
769 for npropdef
in nclassdef
.n_propdefs
do
770 if npropdef
isa AAttrPropdef and npropdef
.n_expr
== null then
771 if npropdef
.mpropdef
== null then return # Skip broken attribute
772 var paramname
= npropdef
.mpropdef
.mproperty
.name
.substring_from
(1)
773 var ret_type
= npropdef
.mpropdef
.static_mtype
774 if ret_type
== null then return
775 var mparameter
= new MParameter(paramname
, ret_type
, false)
776 mparameters
.add
(mparameter
)
780 var mprop
= new MMethod(mclassdef
, "init", mclassdef
.mclass
.visibility
)
781 var mpropdef
= new MMethodDef(mclassdef
, mprop
, nclassdef
.location
)
782 var msignature
= new MSignature(mparameters
, null)
783 mpropdef
.msignature
= msignature
785 nclassdef
.mfree_init
= mpropdef
786 self.toolcontext
.info
("{mclassdef} gets a free constructor for attributes {mpropdef}{msignature}", 3)
789 # Return the static type associated to the node `ntype'.
790 # `classdef' is the context where the call is made (used to understand formal types)
791 # The mmodule used as context is `nclassdef.mmodule'
792 # In case of problem, an error is displayed on `ntype' and null is returned.
793 # FIXME: the name "resolve_mtype" is awful
794 fun resolve_mtype_unchecked
(nclassdef
: AClassdef, ntype
: AType, with_virtual
: Bool): nullable MType
796 var name
= ntype
.n_id
.text
797 var mclassdef
= nclassdef
.mclassdef
798 var mmodule
= nclassdef
.parent
.as(AModule).mmodule
.as(not null)
802 if mclassdef
!= null and with_virtual
then
803 var prop
= try_get_mproperty_by_name
(ntype
, mclassdef
, name
).as(nullable MVirtualTypeProp)
805 if not ntype
.n_types
.is_empty
then
806 error
(ntype
, "Type error: formal type {name} cannot have formal parameters.")
808 res
= prop
.mvirtualtype
809 if ntype
.n_kwnullable
!= null then res
= res
.as_nullable
815 # Check parameter type
816 if mclassdef
!= null and mclassdef
.parameter_names
.has
(name
) then
817 if not ntype
.n_types
.is_empty
then
818 error
(ntype
, "Type error: formal type {name} cannot have formal parameters.")
820 for i
in [0..mclassdef
.parameter_names
.length
[ do
821 if mclassdef
.parameter_names
[i
] == name
then
822 res
= mclassdef
.mclass
.mclass_type
.arguments
[i
]
823 if ntype
.n_kwnullable
!= null then res
= res
.as_nullable
832 var mclass
= try_get_mclass_by_name
(ntype
, mmodule
, name
)
833 if mclass
!= null then
834 var arity
= ntype
.n_types
.length
835 if arity
!= mclass
.arity
then
837 error
(ntype
, "Type error: '{name}' is a generic class.")
838 else if mclass
.arity
== 0 then
839 error
(ntype
, "Type error: '{name}' is not a generic class.")
841 error
(ntype
, "Type error: '{name}' has {mclass.arity} parameters ({arity} are provided).")
846 res
= mclass
.mclass_type
847 if ntype
.n_kwnullable
!= null then res
= res
.as_nullable
851 var mtypes
= new Array[MType]
852 for nt
in ntype
.n_types
do
853 var mt
= resolve_mtype_unchecked
(nclassdef
, nt
, with_virtual
)
854 if mt
== null then return null # Forward error
857 res
= mclass
.get_mtype
(mtypes
)
858 if ntype
.n_kwnullable
!= null then res
= res
.as_nullable
864 # If everything fail, then give up :(
865 error
(ntype
, "Type error: class {name} not found in module {mmodule}.")
869 # Return the static type associated to the node `ntype'.
870 # `classdef' is the context where the call is made (used to understand formal types)
871 # The mmodule used as context is `nclassdef.mmodule'
872 # In case of problem, an error is displayed on `ntype' and null is returned.
873 # FIXME: the name "resolve_mtype" is awful
874 fun resolve_mtype
(nclassdef
: AClassdef, ntype
: AType): nullable MType
876 var mtype
= ntype
.mtype
877 if mtype
== null then mtype
= resolve_mtype_unchecked
(nclassdef
, ntype
, true)
878 if mtype
== null then return null # Forward error
880 if ntype
.checked_mtype
then return mtype
881 if mtype
isa MGenericType then
882 var mmodule
= nclassdef
.parent
.as(AModule).mmodule
.as(not null)
883 var mclassdef
= nclassdef
.mclassdef
884 var mclass
= mtype
.mclass
885 for i
in [0..mclass
.arity
[ do
886 var bound
= mclass
.intro
.bound_mtype
.arguments
[i
]
887 var nt
= ntype
.n_types
[i
]
888 var mt
= resolve_mtype
(nclassdef
, nt
)
889 if mt
== null then return null # forward error
890 if not mt
.is_subtype
(mmodule
, mclassdef
.bound_mtype
, bound
) then
891 error
(nt
, "Type error: expected {bound}, got {mt}")
896 ntype
.checked_mtype
= true
900 # Helper function to display an error on a node.
901 # Alias for `self.toolcontext.error(n.hot_location, text)'
902 fun error
(n
: ANode, text
: String)
904 self.toolcontext
.error
(n
.hot_location
, text
)
907 # Helper function to display a warning on a node.
908 # Alias for: `self.toolcontext.warning(n.hot_location, text)'
909 fun warning
(n
: ANode, text
: String)
911 self.toolcontext
.warning
(n
.hot_location
, text
)
914 # Force to get the primitive method named `name' on the type `recv' or do a fatal error on `n'
915 fun force_get_primitive_method
(n
: ANode, name
: String, recv
: MType, mmodule
: MModule): MMethod
917 var res
= mmodule
.try_get_primitive_method
(name
, recv
)
919 self.toolcontext
.fatal_error
(n
.hot_location
, "Fatal Error: {recv} must have a property named {name}.")
927 # The associated MModule once build by a `ModelBuilder'
928 var mmodule
: nullable MModule
929 # Flag that indicate if the importation is already completed
930 var is_importation_done
: Bool = false
931 # Flag that indicate if the class and prop building is already completed
932 var build_classes_is_done
: Bool = false
933 # What is the AClassdef associated to a MClass?
934 # Used to check multiple definition of a class.
935 var mclass2nclassdef
: Map[MClass, AClassdef] = new HashMap[MClass, AClassdef]
940 # The class whose self inherit all the constructors.
941 # 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
942 var inherit_init_from
: nullable MClass = null
945 redef class AClassdef
946 # The associated MClass once build by a `ModelBuilder'
947 var mclass
: nullable MClass
948 # The associated MClassDef once build by a `ModelBuilder'
949 var mclassdef
: nullable MClassDef
950 var build_properties_is_done
: Bool = false
951 # The list of super-constructor to call at the start of the free constructor
952 # 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
953 var super_inits
: nullable Collection[MMethod] = null
955 # The free init (implicitely constructed by the class if required)
956 var mfree_init
: nullable MMethodDef = null
958 # What is the APropdef associated to a MProperty?
959 # Used to check multiple definition of a property.
960 var mprop2npropdef
: Map[MProperty, APropdef] = new HashMap[MProperty, APropdef]
963 redef class AClasskind
964 # The class kind associated with the AST node class
965 private fun mkind
: MClassKind is abstract
967 redef class AConcreteClasskind
968 redef fun mkind
do return concrete_kind
970 redef class AAbstractClasskind
971 redef fun mkind
do return abstract_kind
973 redef class AInterfaceClasskind
974 redef fun mkind
do return interface_kind
976 redef class AEnumClasskind
977 redef fun mkind
do return enum_kind
979 redef class AExternClasskind
980 redef fun mkind
do return extern_kind
983 redef class AVisibility
984 # The visibility level associated with the AST node class
985 private fun mvisibility
: MVisibility is abstract
987 redef class AIntrudeVisibility
988 redef fun mvisibility
do return intrude_visibility
990 redef class APublicVisibility
991 redef fun mvisibility
do return public_visibility
993 redef class AProtectedVisibility
994 redef fun mvisibility
do return protected_visibility
996 redef class APrivateVisibility
997 redef fun mvisibility
do return private_visibility
1001 # The mtype associated to the node
1002 var mtype
: nullable MType = null
1004 # Is the mtype a valid one?
1005 var checked_mtype
: Bool = false
1011 # Join the text of all tokens
1012 # Used to get the 'real name' of method definitions.
1013 fun collect_text
: String
1015 var v
= new TextCollectorVisitor
1022 private class TextCollectorVisitor
1024 var text
: String = ""
1027 if n
isa Token then text
+= n
.text
1032 redef class APropdef
1033 private fun build_property
(modelbuilder
: ModelBuilder, nclassdef
: AClassdef)
1036 private fun build_signature
(modelbuilder
: ModelBuilder, nclassdef
: AClassdef)
1039 private fun check_signature
(modelbuilder
: ModelBuilder, nclassdef
: AClassdef)
1042 private fun new_property_visibility
(modelbuilder
: ModelBuilder, nclassdef
: AClassdef, nvisibility
: nullable AVisibility): MVisibility
1044 var mvisibility
= public_visibility
1045 if nvisibility
!= null then mvisibility
= nvisibility
.mvisibility
1046 if nclassdef
.mclassdef
.mclass
.visibility
== private_visibility
then
1047 if mvisibility
== protected_visibility
then
1048 assert nvisibility
!= null
1049 modelbuilder
.error
(nvisibility
, "Error: The only legal visibility for properties in a private class is private.")
1050 else if mvisibility
== private_visibility
then
1051 assert nvisibility
!= null
1053 # modelbuilder.warning(nvisibility, "Warning: private is unrequired since the only legal visibility for properties in a private class is private.")
1055 mvisibility
= private_visibility
1060 private fun check_redef_property_visibility
(modelbuilder
: ModelBuilder, nclassdef
: AClassdef, nvisibility
: nullable AVisibility, mprop
: MProperty)
1062 if nvisibility
== null then return
1063 var mvisibility
= nvisibility
.mvisibility
1064 if mvisibility
!= mprop
.visibility
and mvisibility
!= public_visibility
then
1065 modelbuilder
.error
(nvisibility
, "Error: redefinition changed the visibility from a {mprop.visibility} to a {mvisibility}")
1069 private fun check_redef_keyword
(modelbuilder
: ModelBuilder, nclassdef
: AClassdef, kwredef
: nullable Token, need_redef
: Bool, mprop
: MProperty): Bool
1071 if nclassdef
.mprop2npropdef
.has_key
(mprop
) then
1072 modelbuilder
.error
(self, "Error: A property {mprop} is already defined in class {nclassdef.mclassdef.mclass}.")
1075 if kwredef
== null then
1077 modelbuilder
.error
(self, "Redef error: {nclassdef.mclassdef.mclass}::{mprop.name} is an inherited property. To redefine it, add the redef keyword.")
1081 if not need_redef
then
1082 modelbuilder
.error
(self, "Error: No property {nclassdef.mclassdef.mclass}::{mprop.name} is inherited. Remove the redef keyword to define a new property.")
1091 redef class ASignature
1092 # Is the model builder has correctly visited the signature
1093 var is_visited
= false
1094 # Names of parameters from the AST
1095 # REQUIRE: is_visited
1096 var param_names
= new Array[String]
1097 # Types of parameters from the AST
1098 # REQUIRE: is_visited
1099 var param_types
= new Array[MType]
1100 # Rank of the vararg (of -1 if none)
1101 # REQUIRE: is_visited
1102 var vararg_rank
: Int = -1
1104 var ret_type
: nullable MType = null
1106 # Visit and fill information about a signature
1107 private fun visit_signature
(modelbuilder
: ModelBuilder, nclassdef
: AClassdef): Bool
1109 var param_names
= self.param_names
1110 var param_types
= self.param_types
1111 for np
in self.n_params
do
1112 param_names
.add
(np
.n_id
.text
)
1113 var ntype
= np
.n_type
1114 if ntype
!= null then
1115 var mtype
= modelbuilder
.resolve_mtype
(nclassdef
, ntype
)
1116 if mtype
== null then return false # Skip error
1117 for i
in [0..param_names
.length-param_types
.length
[ do
1118 param_types
.add
(mtype
)
1120 if np
.n_dotdotdot
!= null then
1121 if self.vararg_rank
!= -1 then
1122 modelbuilder
.error
(np
, "Error: {param_names[self.vararg_rank]} is already a vararg")
1125 self.vararg_rank
= param_names
.length
- 1
1130 var ntype
= self.n_type
1131 if ntype
!= null then
1132 self.ret_type
= modelbuilder
.resolve_mtype
(nclassdef
, ntype
)
1133 if self.ret_type
== null then return false # Skip errir
1136 for nclosure
in self.n_closure_decls
do
1137 if not nclosure
.n_signature
.visit_signature
(modelbuilder
, nclassdef
) then return false
1140 self.is_visited
= true
1144 # Build a visited signature
1145 fun build_signature
(modelbuilder
: ModelBuilder, nclassdef
: AClassdef): nullable MSignature
1147 if param_names
.length
!= param_types
.length
then
1148 # Some parameters are typed, other parameters are not typed.
1149 modelbuilder
.error
(self.n_params
[param_types
.length
], "Error: Untyped parameter `{param_names[param_types.length]}'.")
1153 var mparameters
= new Array[MParameter]
1154 for i
in [0..param_names
.length
[ do
1155 var mparameter
= new MParameter(param_names
[i
], param_types
[i
], i
== vararg_rank
)
1156 mparameters
.add
(mparameter
)
1159 var msignature
= new MSignature(mparameters
, ret_type
)
1164 redef class AMethPropdef
1165 # The associated MMethodDef once build by a `ModelBuilder'
1166 var mpropdef
: nullable MMethodDef
1168 # The associated super init if any
1169 var super_init
: nullable MMethod
1170 redef fun build_property
(modelbuilder
, nclassdef
)
1172 var is_init
= self isa AInitPropdef
1173 var mclassdef
= nclassdef
.mclassdef
.as(not null)
1175 var amethodid
= self.n_methid
1176 var name_node
: ANode
1177 if amethodid
== null then
1178 if self isa AMainMethPropdef then
1181 else if self isa AConcreteInitPropdef then
1183 name_node
= self.n_kwinit
1184 else if self isa AExternInitPropdef then
1186 name_node
= self.n_kwnew
1190 else if amethodid
isa AIdMethid then
1191 name
= amethodid
.n_id
.text
1192 name_node
= amethodid
1194 # operator, bracket or assign
1195 name
= amethodid
.collect_text
1196 name_node
= amethodid
1198 if name
== "-" and self.n_signature
.n_params
.length
== 0 then
1203 var mprop
: nullable MMethod = null
1204 if not is_init
or n_kwredef
!= null then mprop
= modelbuilder
.try_get_mproperty_by_name
(name_node
, mclassdef
, name
).as(nullable MMethod)
1205 if mprop
== null then
1206 var mvisibility
= new_property_visibility
(modelbuilder
, nclassdef
, self.n_visibility
)
1207 mprop
= new MMethod(mclassdef
, name
, mvisibility
)
1208 mprop
.is_init
= is_init
1209 mprop
.is_new
= self isa AExternInitPropdef
1210 if not self.check_redef_keyword
(modelbuilder
, nclassdef
, n_kwredef
, false, mprop
) then return
1212 if n_kwredef
== null then
1213 if self isa AMainMethPropdef then
1216 if not self.check_redef_keyword
(modelbuilder
, nclassdef
, n_kwredef
, true, mprop
) then return
1219 check_redef_property_visibility
(modelbuilder
, nclassdef
, self.n_visibility
, mprop
)
1221 nclassdef
.mprop2npropdef
[mprop
] = self
1223 var mpropdef
= new MMethodDef(mclassdef
, mprop
, self.location
)
1225 self.mpropdef
= mpropdef
1226 modelbuilder
.mpropdef2npropdef
[mpropdef
] = self
1227 if mpropdef
.is_intro
then
1228 modelbuilder
.toolcontext
.info
("{mpropdef} introduces new method {mprop.full_name}", 3)
1230 modelbuilder
.toolcontext
.info
("{mpropdef} redefines method {mprop.full_name}", 3)
1234 redef fun build_signature
(modelbuilder
, nclassdef
)
1236 var mpropdef
= self.mpropdef
1237 if mpropdef
== null then return # Error thus skiped
1238 var mmodule
= mpropdef
.mclassdef
.mmodule
1239 var nsig
= self.n_signature
1241 # Retrieve info from the signature AST
1242 var param_names
= new Array[String] # Names of parameters from the AST
1243 var param_types
= new Array[MType] # Types of parameters from the AST
1244 var vararg_rank
= -1
1245 var ret_type
: nullable MType = null # Return type from the AST
1246 if nsig
!= null then
1247 if not nsig
.visit_signature
(modelbuilder
, nclassdef
) then return
1248 param_names
= nsig
.param_names
1249 param_types
= nsig
.param_types
1250 vararg_rank
= nsig
.vararg_rank
1251 ret_type
= nsig
.ret_type
1254 # Look for some signature to inherit
1255 # FIXME: do not inherit from the intro, but from the most specific
1256 var msignature
: nullable MSignature = null
1257 if not mpropdef
.is_intro
then
1258 msignature
= mpropdef
.mproperty
.intro
.msignature
1259 if msignature
== null then return # Skip error
1261 # Check inherited signature arity
1262 if param_names
.length
!= msignature
.arity
then
1264 if nsig
!= null then node
= nsig
else node
= self
1265 modelbuilder
.error
(node
, "Redef error: {mpropdef} redefines {mpropdef.mproperty.intro} with {param_names.length} parameter(s), {msignature.arity} expected. Signature is {mpropdef}{msignature}")
1268 else if mpropdef
.mproperty
.is_init
then
1269 # FIXME UGLY: inherit signature from a super-constructor
1270 for msupertype
in nclassdef
.mclassdef
.supertypes
do
1271 msupertype
= msupertype
.anchor_to
(mmodule
, nclassdef
.mclassdef
.bound_mtype
)
1272 var candidate
= modelbuilder
.try_get_mproperty_by_name2
(self, mmodule
, msupertype
, mpropdef
.mproperty
.name
)
1273 if candidate
!= null then
1274 if msignature
== null then
1275 msignature
= candidate
.intro
.as(MMethodDef).msignature
1282 # Inherit the signature
1283 if msignature
!= null and param_names
.length
!= param_types
.length
and param_names
.length
== msignature
.arity
and param_types
.length
== 0 then
1284 # Parameters are untyped, thus inherit them
1285 param_types
= new Array[MType]
1286 for mparameter
in msignature
.mparameters
do
1287 param_types
.add
(mparameter
.mtype
)
1289 vararg_rank
= msignature
.vararg_rank
1291 if msignature
!= null and ret_type
== null then
1292 ret_type
= msignature
.return_mtype
1295 if param_names
.length
!= param_types
.length
then
1296 # Some parameters are typed, other parameters are not typed.
1297 modelbuilder
.error
(nsig
.n_params
[param_types
.length
], "Error: Untyped parameter `{param_names[param_types.length]}'.")
1301 var mparameters
= new Array[MParameter]
1302 for i
in [0..param_names
.length
[ do
1303 var mparameter
= new MParameter(param_names
[i
], param_types
[i
], i
== vararg_rank
)
1304 mparameters
.add
(mparameter
)
1307 msignature
= new MSignature(mparameters
, ret_type
)
1308 mpropdef
.msignature
= msignature
1310 if nsig
!= null then
1311 for nclosure
in nsig
.n_closure_decls
do
1312 var clos_signature
= nclosure
.n_signature
.build_signature
(modelbuilder
, nclassdef
)
1313 if clos_signature
== null then return
1314 var mparameter
= new MParameter(nclosure
.n_id
.text
, clos_signature
, false)
1315 msignature
.mclosures
.add
(mparameter
)
1321 redef fun check_signature
(modelbuilder
, nclassdef
)
1323 var mpropdef
= self.mpropdef
1324 if mpropdef
== null then return # Error thus skiped
1325 var mmodule
= mpropdef
.mclassdef
.mmodule
1326 var nsig
= self.n_signature
1327 var mysignature
= self.mpropdef
.msignature
1328 if mysignature
== null then return # Error thus skiped
1330 # Lookup for signature in the precursor
1331 # FIXME all precursors should be considered
1332 if not mpropdef
.is_intro
then
1333 var msignature
= mpropdef
.mproperty
.intro
.msignature
1334 if msignature
== null then return
1336 var precursor_ret_type
= msignature
.return_mtype
1337 var ret_type
= mysignature
.return_mtype
1338 if ret_type
!= null and precursor_ret_type
== null then
1339 modelbuilder
.error
(nsig
.n_type
.as(not null), "Redef Error: {mpropdef.mproperty} is a procedure, not a function.")
1343 if mysignature
.arity
> 0 then
1344 # Check parameters types
1345 for i
in [0..mysignature
.arity
[ do
1346 var myt
= mysignature
.mparameters
[i
].mtype
1347 var prt
= msignature
.mparameters
[i
].mtype
1348 if not myt
.is_subtype
(mmodule
, nclassdef
.mclassdef
.bound_mtype
, prt
) and
1349 not prt
.is_subtype
(mmodule
, nclassdef
.mclassdef
.bound_mtype
, myt
) then
1350 modelbuilder
.error
(nsig
.n_params
[i
], "Redef Error: Wrong type for parameter `{mysignature.mparameters[i].name}'. found {myt}, expected {prt}.")
1354 if precursor_ret_type
!= null then
1355 if ret_type
== null then
1356 # Inherit the return type
1357 ret_type
= precursor_ret_type
1358 else if not ret_type
.is_subtype
(mmodule
, nclassdef
.mclassdef
.bound_mtype
, precursor_ret_type
) then
1359 modelbuilder
.error
(nsig
.n_type
.as(not null), "Redef Error: Wrong return type. found {ret_type}, expected {precursor_ret_type}.")
1366 redef class AAttrPropdef
1367 # The associated MAttributeDef once build by a `ModelBuilder'
1368 var mpropdef
: nullable MAttributeDef
1369 # The associated getter (read accessor) if any
1370 var mreadpropdef
: nullable MMethodDef
1371 # The associated setter (write accessor) if any
1372 var mwritepropdef
: nullable MMethodDef
1373 redef fun build_property
(modelbuilder
, nclassdef
)
1375 var mclassdef
= nclassdef
.mclassdef
.as(not null)
1376 var mclass
= mclassdef
.mclass
1379 if self.n_id
!= null then
1380 name
= self.n_id
.text
1382 name
= self.n_id2
.text
1385 if mclass
.kind
== interface_kind
or mclassdef
.mclass
.kind
== enum_kind
then
1386 modelbuilder
.error
(self, "Error: Attempt to define attribute {name} in the interface {mclass}.")
1387 else if mclass
.kind
== enum_kind
then
1388 modelbuilder
.error
(self, "Error: Attempt to define attribute {name} in the enum class {mclass}.")
1389 else if mclass
.kind
== extern_kind
then
1390 modelbuilder
.error
(self, "Error: Attempt to define attribute {name} in the extern class {mclass}.")
1395 # Old attribute style
1396 var mprop
= modelbuilder
.try_get_mproperty_by_name
(nid
, mclassdef
, name
)
1397 if mprop
== null then
1398 var mvisibility
= new_property_visibility
(modelbuilder
, nclassdef
, self.n_visibility
)
1399 mprop
= new MAttribute(mclassdef
, name
, mvisibility
)
1400 if not self.check_redef_keyword
(modelbuilder
, nclassdef
, self.n_kwredef
, false, mprop
) then return
1402 assert mprop
isa MAttribute
1403 check_redef_property_visibility
(modelbuilder
, nclassdef
, self.n_visibility
, mprop
)
1404 if not self.check_redef_keyword
(modelbuilder
, nclassdef
, self.n_kwredef
, true, mprop
) then return
1406 nclassdef
.mprop2npropdef
[mprop
] = self
1408 var mpropdef
= new MAttributeDef(mclassdef
, mprop
, self.location
)
1409 self.mpropdef
= mpropdef
1410 modelbuilder
.mpropdef2npropdef
[mpropdef
] = self
1412 var nreadable
= self.n_readable
1413 if nreadable
!= null then
1414 var readname
= name
.substring_from
(1)
1415 var mreadprop
= modelbuilder
.try_get_mproperty_by_name
(nid
, mclassdef
, readname
).as(nullable MMethod)
1416 if mreadprop
== null then
1417 var mvisibility
= new_property_visibility
(modelbuilder
, nclassdef
, nreadable
.n_visibility
)
1418 mreadprop
= new MMethod(mclassdef
, readname
, mvisibility
)
1419 if not self.check_redef_keyword
(modelbuilder
, nclassdef
, nreadable
.n_kwredef
, false, mreadprop
) then return
1421 if not self.check_redef_keyword
(modelbuilder
, nclassdef
, nreadable
.n_kwredef
, true, mreadprop
) then return
1422 check_redef_property_visibility
(modelbuilder
, nclassdef
, nreadable
.n_visibility
, mreadprop
)
1424 nclassdef
.mprop2npropdef
[mreadprop
] = self
1426 var mreadpropdef
= new MMethodDef(mclassdef
, mreadprop
, self.location
)
1427 self.mreadpropdef
= mreadpropdef
1428 modelbuilder
.mpropdef2npropdef
[mreadpropdef
] = self
1431 var nwritable
= self.n_writable
1432 if nwritable
!= null then
1433 var writename
= name
.substring_from
(1) + "="
1434 var mwriteprop
= modelbuilder
.try_get_mproperty_by_name
(nid
, mclassdef
, writename
).as(nullable MMethod)
1435 if mwriteprop
== null then
1436 var mvisibility
= new_property_visibility
(modelbuilder
, nclassdef
, nwritable
.n_visibility
)
1437 mwriteprop
= new MMethod(mclassdef
, writename
, mvisibility
)
1438 if not self.check_redef_keyword
(modelbuilder
, nclassdef
, nwritable
.n_kwredef
, false, mwriteprop
) then return
1440 if not self.check_redef_keyword
(modelbuilder
, nclassdef
, nwritable
.n_kwredef
, true, mwriteprop
) then return
1441 check_redef_property_visibility
(modelbuilder
, nclassdef
, nwritable
.n_visibility
, mwriteprop
)
1443 nclassdef
.mprop2npropdef
[mwriteprop
] = self
1445 var mwritepropdef
= new MMethodDef(mclassdef
, mwriteprop
, self.location
)
1446 self.mwritepropdef
= mwritepropdef
1447 modelbuilder
.mpropdef2npropdef
[mwritepropdef
] = self
1450 # New attribute style
1451 var nid2
= self.n_id2
.as(not null)
1452 var mprop
= new MAttribute(mclassdef
, "@" + name
, none_visibility
)
1453 var mpropdef
= new MAttributeDef(mclassdef
, mprop
, self.location
)
1454 self.mpropdef
= mpropdef
1455 modelbuilder
.mpropdef2npropdef
[mpropdef
] = self
1458 var mreadprop
= modelbuilder
.try_get_mproperty_by_name
(nid2
, mclassdef
, readname
).as(nullable MMethod)
1459 if mreadprop
== null then
1460 var mvisibility
= new_property_visibility
(modelbuilder
, nclassdef
, self.n_visibility
)
1461 mreadprop
= new MMethod(mclassdef
, readname
, mvisibility
)
1462 if not self.check_redef_keyword
(modelbuilder
, nclassdef
, n_kwredef
, false, mreadprop
) then return
1464 if not self.check_redef_keyword
(modelbuilder
, nclassdef
, n_kwredef
, true, mreadprop
) then return
1465 check_redef_property_visibility
(modelbuilder
, nclassdef
, self.n_visibility
, mreadprop
)
1467 nclassdef
.mprop2npropdef
[mreadprop
] = self
1469 var mreadpropdef
= new MMethodDef(mclassdef
, mreadprop
, self.location
)
1470 self.mreadpropdef
= mreadpropdef
1471 modelbuilder
.mpropdef2npropdef
[mreadpropdef
] = self
1473 var writename
= name
+ "="
1474 var nwritable
= self.n_writable
1475 var mwriteprop
= modelbuilder
.try_get_mproperty_by_name
(nid2
, mclassdef
, writename
).as(nullable MMethod)
1476 var nwkwredef
: nullable Token = null
1477 if nwritable
!= null then nwkwredef
= nwritable
.n_kwredef
1478 if mwriteprop
== null then
1480 if nwritable
!= null then
1481 mvisibility
= new_property_visibility
(modelbuilder
, nclassdef
, nwritable
.n_visibility
)
1483 mvisibility
= private_visibility
1485 mwriteprop
= new MMethod(mclassdef
, writename
, mvisibility
)
1486 if not self.check_redef_keyword
(modelbuilder
, nclassdef
, nwkwredef
, false, mwriteprop
) then return
1488 if not self.check_redef_keyword
(modelbuilder
, nclassdef
, nwkwredef
, true, mwriteprop
) then return
1489 if nwritable
!= null then
1490 check_redef_property_visibility
(modelbuilder
, nclassdef
, nwritable
.n_visibility
, mwriteprop
)
1493 nclassdef
.mprop2npropdef
[mwriteprop
] = self
1495 var mwritepropdef
= new MMethodDef(mclassdef
, mwriteprop
, self.location
)
1496 self.mwritepropdef
= mwritepropdef
1497 modelbuilder
.mpropdef2npropdef
[mwritepropdef
] = self
1501 redef fun build_signature
(modelbuilder
, nclassdef
)
1503 var mpropdef
= self.mpropdef
1504 if mpropdef
== null then return # Error thus skiped
1505 var mmodule
= mpropdef
.mclassdef
.mmodule
1506 var mtype
: nullable MType = null
1508 var ntype
= self.n_type
1509 if ntype
!= null then
1510 mtype
= modelbuilder
.resolve_mtype
(nclassdef
, ntype
)
1511 if mtype
== null then return
1514 if mtype
== null then
1515 var nexpr
= self.n_expr
1516 if nexpr
!= null then
1517 if nexpr
isa ANewExpr then
1518 mtype
= modelbuilder
.resolve_mtype
(nclassdef
, nexpr
.n_type
)
1519 else if nexpr
isa AIntExpr then
1520 var cla
= modelbuilder
.try_get_mclass_by_name
(nexpr
, mmodule
, "Int")
1521 if cla
!= null then mtype
= cla
.mclass_type
1522 else if nexpr
isa AFloatExpr then
1523 var cla
= modelbuilder
.try_get_mclass_by_name
(nexpr
, mmodule
, "Float")
1524 if cla
!= null then mtype
= cla
.mclass_type
1525 else if nexpr
isa ACharExpr then
1526 var cla
= modelbuilder
.try_get_mclass_by_name
(nexpr
, mmodule
, "Char")
1527 if cla
!= null then mtype
= cla
.mclass_type
1528 else if nexpr
isa ABoolExpr then
1529 var cla
= modelbuilder
.try_get_mclass_by_name
(nexpr
, mmodule
, "Bool")
1530 if cla
!= null then mtype
= cla
.mclass_type
1531 else if nexpr
isa ASuperstringExpr then
1532 var cla
= modelbuilder
.try_get_mclass_by_name
(nexpr
, mmodule
, "String")
1533 if cla
!= null then mtype
= cla
.mclass_type
1534 else if nexpr
isa AStringFormExpr then
1535 var cla
= modelbuilder
.try_get_mclass_by_name
(nexpr
, mmodule
, "String")
1536 if cla
!= null then mtype
= cla
.mclass_type
1538 modelbuilder
.error
(self, "Error: Untyped attribute {mpropdef}. Implicit typing allowed only for literals and new.")
1542 modelbuilder
.error
(self, "Error: Untyped attribute {mpropdef}")
1546 if mtype
== null then return
1548 mpropdef
.static_mtype
= mtype
1550 var mreadpropdef
= self.mreadpropdef
1551 if mreadpropdef
!= null then
1552 var msignature
= new MSignature(new Array[MParameter], mtype
)
1553 mreadpropdef
.msignature
= msignature
1556 var msritepropdef
= self.mwritepropdef
1557 if mwritepropdef
!= null then
1559 if n_id
!= null then
1560 name
= n_id
.text
.substring_from
(1)
1564 var mparameter
= new MParameter(name
, mtype
, false)
1565 var msignature
= new MSignature([mparameter
], null)
1566 mwritepropdef
.msignature
= msignature
1570 redef fun check_signature
(modelbuilder
, nclassdef
)
1572 var mpropdef
= self.mpropdef
1573 if mpropdef
== null then return # Error thus skiped
1574 var mmodule
= mpropdef
.mclassdef
.mmodule
1575 var ntype
= self.n_type
1576 var mtype
= self.mpropdef
.static_mtype
1577 if mtype
== null then return # Error thus skiped
1579 # Lookup for signature in the precursor
1580 # FIXME all precursors should be considered
1581 if not mpropdef
.is_intro
then
1582 var precursor_type
= mpropdef
.mproperty
.intro
.static_mtype
1583 if precursor_type
== null then return
1585 if mtype
!= precursor_type
then
1586 modelbuilder
.error
(ntype
.as(not null), "Redef Error: Wrong static type. found {mtype}, expected {precursor_type}.")
1591 # Check getter and setter
1592 var meth
= self.mreadpropdef
1593 if meth
!= null then self.check_method_signature
(modelbuilder
, nclassdef
, meth
)
1594 meth
= self.mwritepropdef
1595 if meth
!= null then self.check_method_signature
(modelbuilder
, nclassdef
, meth
)
1598 private fun check_method_signature
(modelbuilder
: ModelBuilder, nclassdef
: AClassdef, mpropdef
: MMethodDef)
1600 var mmodule
= mpropdef
.mclassdef
.mmodule
1601 var nsig
= self.n_type
1602 var mysignature
= mpropdef
.msignature
1603 if mysignature
== null then return # Error thus skiped
1605 # Lookup for signature in the precursor
1606 # FIXME all precursors should be considered
1607 if not mpropdef
.is_intro
then
1608 var msignature
= mpropdef
.mproperty
.intro
.msignature
1609 if msignature
== null then return
1611 if mysignature
.arity
!= msignature
.arity
then
1613 if nsig
!= null then node
= nsig
else node
= self
1614 modelbuilder
.error
(node
, "Redef Error: {mysignature.arity} parameters found, {msignature.arity} expected. Signature is {mpropdef}{msignature}")
1617 var precursor_ret_type
= msignature
.return_mtype
1618 var ret_type
= mysignature
.return_mtype
1619 if ret_type
!= null and precursor_ret_type
== null then
1621 if nsig
!= null then node
= nsig
else node
= self
1622 modelbuilder
.error
(node
, "Redef Error: {mpropdef.mproperty} is a procedure, not a function.")
1626 if mysignature
.arity
> 0 then
1627 # Check parameters types
1628 for i
in [0..mysignature
.arity
[ do
1629 var myt
= mysignature
.mparameters
[i
].mtype
1630 var prt
= msignature
.mparameters
[i
].mtype
1631 if not myt
.is_subtype
(mmodule
, nclassdef
.mclassdef
.bound_mtype
, prt
) and
1632 not prt
.is_subtype
(mmodule
, nclassdef
.mclassdef
.bound_mtype
, myt
) then
1634 if nsig
!= null then node
= nsig
else node
= self
1635 modelbuilder
.error
(node
, "Redef Error: Wrong type for parameter `{mysignature.mparameters[i].name}'. found {myt}, expected {prt}.")
1639 if precursor_ret_type
!= null then
1640 if ret_type
== null then
1641 # Inherit the return type
1642 ret_type
= precursor_ret_type
1643 else if not ret_type
.is_subtype
(mmodule
, nclassdef
.mclassdef
.bound_mtype
, precursor_ret_type
) then
1645 if nsig
!= null then node
= nsig
else node
= self
1646 modelbuilder
.error
(node
, "Redef Error: Wrong return type. found {ret_type}, expected {precursor_ret_type}.")
1653 redef class ATypePropdef
1654 # The associated MVirtualTypeDef once build by a `ModelBuilder'
1655 var mpropdef
: nullable MVirtualTypeDef
1656 redef fun build_property
(modelbuilder
, nclassdef
)
1658 var mclassdef
= nclassdef
.mclassdef
.as(not null)
1659 var name
= self.n_id
.text
1660 var mprop
= modelbuilder
.try_get_mproperty_by_name
(self.n_id
, mclassdef
, name
)
1661 if mprop
== null then
1662 var mvisibility
= new_property_visibility
(modelbuilder
, nclassdef
, self.n_visibility
)
1663 mprop
= new MVirtualTypeProp(mclassdef
, name
, mvisibility
)
1664 if not self.check_redef_keyword
(modelbuilder
, nclassdef
, self.n_kwredef
, false, mprop
) then return
1666 if not self.check_redef_keyword
(modelbuilder
, nclassdef
, self.n_kwredef
, true, mprop
) then return
1667 assert mprop
isa MVirtualTypeProp
1668 check_redef_property_visibility
(modelbuilder
, nclassdef
, self.n_visibility
, mprop
)
1670 nclassdef
.mprop2npropdef
[mprop
] = self
1672 var mpropdef
= new MVirtualTypeDef(mclassdef
, mprop
, self.location
)
1673 self.mpropdef
= mpropdef
1676 redef fun build_signature
(modelbuilder
, nclassdef
)
1678 var mpropdef
= self.mpropdef
1679 if mpropdef
== null then return # Error thus skiped
1680 var mmodule
= mpropdef
.mclassdef
.mmodule
1681 var mtype
: nullable MType = null
1683 var ntype
= self.n_type
1684 mtype
= modelbuilder
.resolve_mtype
(nclassdef
, ntype
)
1685 if mtype
== null then return
1687 mpropdef
.bound
= mtype
1688 # print "{mpropdef}: {mtype}"
1691 redef fun check_signature
(modelbuilder
, nclassdef
)
1693 var bound
= self.mpropdef
.bound
1695 # Fast case: the bound is not a formal type
1696 if not bound
isa MVirtualType then return
1698 var mmodule
= nclassdef
.mclassdef
.mmodule
1699 var anchor
= nclassdef
.mclassdef
.bound_mtype
1701 # Slow case: progress on each resolution until: (i) we loop, or (ii) we found a non formal type
1702 var seen
= [self.mpropdef
.mproperty
.mvirtualtype
]
1704 if seen
.has
(bound
) then
1706 modelbuilder
.error
(self, "Error: circularity of virtual type definition: {seen.join(" -> ")}")
1710 var next
= bound
.lookup_bound
(mmodule
, anchor
)
1711 if not next
isa MVirtualType then return