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
)
427 for nclassdef
in nmodule
.n_classdefs
do
428 build_properties
(nclassdef
)
433 # Visit the AST and create the MClass objects
434 private fun build_a_mclass
(nmodule
: AModule, nclassdef
: AClassdef)
436 var mmodule
= nmodule
.mmodule
.as(not null)
439 var nkind
: nullable AClasskind
440 var mkind
: MClassKind
441 var nvisibility
: nullable AVisibility
442 var mvisibility
: nullable MVisibility
444 if nclassdef
isa AStdClassdef then
445 name
= nclassdef
.n_id
.text
446 nkind
= nclassdef
.n_classkind
448 nvisibility
= nclassdef
.n_visibility
449 mvisibility
= nvisibility
.mvisibility
450 arity
= nclassdef
.n_formaldefs
.length
451 else if nclassdef
isa ATopClassdef then
454 mkind
= interface_kind
456 mvisibility
= public_visibility
457 else if nclassdef
isa AMainClassdef then
460 mkind
= concrete_kind
462 mvisibility
= public_visibility
467 var mclass
= try_get_mclass_by_name
(nclassdef
, mmodule
, name
)
468 if mclass
== null then
469 mclass
= new MClass(mmodule
, name
, arity
, mkind
, mvisibility
)
470 #print "new class {mclass}"
471 else if nclassdef
isa AStdClassdef and nmodule
.mclass2nclassdef
.has_key
(mclass
) then
472 error
(nclassdef
, "Error: A class {name} is already defined at line {nmodule.mclass2nclassdef[mclass].location.line_start}.")
474 else if nclassdef
isa AStdClassdef and nclassdef
.n_kwredef
== null then
475 error
(nclassdef
, "Redef error: {name} is an imported class. Add the redef keyword to refine it.")
477 else if mclass
.arity
!= arity
then
478 error
(nclassdef
, "Redef error: Formal parameter arity missmatch; got {arity}, expected {mclass.arity}.")
480 else if nkind
!= null and mkind
!= concrete_kind
and mclass
.kind
!= mkind
then
481 error
(nkind
, "Error: refinement changed the kind from a {mclass.kind} to a {mkind}")
482 else if nvisibility
!= null and mvisibility
!= public_visibility
and mclass
.visibility
!= mvisibility
then
483 error
(nvisibility
, "Error: refinement changed the visibility from a {mclass.visibility} to a {mvisibility}")
485 nclassdef
.mclass
= mclass
486 nmodule
.mclass2nclassdef
[mclass
] = nclassdef
489 # Visit the AST and create the MClassDef objects
490 private fun build_a_mclassdef
(nmodule
: AModule, nclassdef
: AClassdef)
492 var mmodule
= nmodule
.mmodule
.as(not null)
493 var objectclass
= try_get_mclass_by_name
(nmodule
, mmodule
, "Object")
494 var mclass
= nclassdef
.mclass
495 if mclass
== null then return # Skip error
496 #var mclassdef = nclassdef.mclassdef.as(not null)
498 var names
= new Array[String]
499 var bounds
= new Array[MType]
500 if nclassdef
isa AStdClassdef and mclass
.arity
> 0 then
501 # Collect formal parameter names
502 for i
in [0..mclass
.arity
[ do
503 var nfd
= nclassdef
.n_formaldefs
[i
]
504 var ptname
= nfd
.n_id
.text
505 if names
.has
(ptname
) then
506 error
(nfd
, "Error: A formal parameter type `{ptname}' already exists")
512 # Revolve bound for formal parameter names
513 for i
in [0..mclass
.arity
[ do
514 var nfd
= nclassdef
.n_formaldefs
[i
]
515 var nfdt
= nfd
.n_type
517 var bound
= resolve_mtype_unchecked
(nclassdef
, nfdt
, false)
518 if bound
== null then return # Forward error
519 if bound
.need_anchor
then
521 error
(nfd
, "Error: Formal parameter type `{names[i]}' bounded with a formal parameter type")
525 else if mclass
.mclassdefs
.is_empty
then
526 # No bound, then implicitely bound by nullable Object
527 bounds
.add
(objectclass
.mclass_type
.as_nullable
)
530 bounds
.add
(mclass
.intro
.bound_mtype
.arguments
[i
])
535 var bound_mtype
= mclass
.get_mtype
(bounds
)
536 var mclassdef
= new MClassDef(mmodule
, bound_mtype
, nclassdef
.location
, names
)
537 nclassdef
.mclassdef
= mclassdef
538 self.mclassdef2nclassdef
[mclassdef
] = nclassdef
540 if mclassdef
.is_intro
then
541 self.toolcontext
.info
("{mclassdef} introduces new {mclass.kind} {mclass.full_name}", 3)
543 self.toolcontext
.info
("{mclassdef} refine {mclass.kind} {mclass.full_name}", 3)
547 # Visit the AST and set the super-types of the MClassdef objects
548 private fun collect_a_mclassdef_inheritance
(nmodule
: AModule, nclassdef
: AClassdef)
550 var mmodule
= nmodule
.mmodule
.as(not null)
551 var objectclass
= try_get_mclass_by_name
(nmodule
, mmodule
, "Object")
552 var mclass
= nclassdef
.mclass
.as(not null)
553 var mclassdef
= nclassdef
.mclassdef
.as(not null)
555 var specobject
= true
556 var supertypes
= new Array[MClassType]
557 if nclassdef
isa AStdClassdef then
558 for nsc
in nclassdef
.n_superclasses
do
560 var ntype
= nsc
.n_type
561 var mtype
= resolve_mtype_unchecked
(nclassdef
, ntype
, false)
562 if mtype
== null then continue # Skip because of error
563 if not mtype
isa MClassType then
564 error
(ntype
, "Error: supertypes cannot be a formal type")
568 #print "new super : {mclass} < {mtype}"
571 if specobject
and mclass
.name
!= "Object" and objectclass
!= null and mclassdef
.is_intro
then
572 supertypes
.add objectclass
.mclass_type
575 mclassdef
.set_supertypes
(supertypes
)
576 if not supertypes
.is_empty
then self.toolcontext
.info
("{mclassdef} new super-types: {supertypes.join(", ")}", 3)
579 # Check the validity of the specialization heirarchy
580 private fun check_supertypes
(nmodule
: AModule, nclassdef
: AClassdef)
582 var mmodule
= nmodule
.mmodule
.as(not null)
583 var objectclass
= try_get_mclass_by_name
(nmodule
, mmodule
, "Object")
584 var mclass
= nclassdef
.mclass
.as(not null)
585 var mclassdef
= nclassdef
.mclassdef
.as(not null)
587 for s
in mclassdef
.supertypes
do
588 if s
.is_subtype
(mmodule
, mclassdef
.bound_mtype
, mclassdef
.bound_mtype
) then
589 error
(nclassdef
, "Error: Inheritance loop for class {mclass} with type {s}")
594 # Build the classes of the module `nmodule'.
595 # REQUIRE: classes of imported modules are already build. (let `build_all_classes' do the job)
596 private fun build_classes
(nmodule
: AModule)
598 # Force building recursively
599 if nmodule
.build_classes_is_done
then return
600 nmodule
.build_classes_is_done
= true
601 var mmodule
= nmodule
.mmodule
.as(not null)
602 for imp
in mmodule
.in_importation
.direct_greaters
do
604 build_classes
(mmodule2nmodule
[imp
])
608 for nclassdef
in nmodule
.n_classdefs
do
609 self.build_a_mclass
(nmodule
, nclassdef
)
612 # Create all classdefs
613 for nclassdef
in nmodule
.n_classdefs
do
614 self.build_a_mclassdef
(nmodule
, nclassdef
)
617 for nclassdef
in nmodule
.n_classdefs
do
618 if nclassdef
.mclassdef
== null then return # forward error
621 # Create inheritance on all classdefs
622 for nclassdef
in nmodule
.n_classdefs
do
623 self.collect_a_mclassdef_inheritance
(nmodule
, nclassdef
)
626 # Create the mclassdef hierarchy
627 for nclassdef
in nmodule
.n_classdefs
do
628 var mclassdef
= nclassdef
.mclassdef
.as(not null)
629 mclassdef
.add_in_hierarchy
633 for nclassdef
in nmodule
.n_classdefs
do
634 self.check_supertypes
(nmodule
, nclassdef
)
637 # Check unchecked ntypes
638 for nclassdef
in nmodule
.n_classdefs
do
639 if nclassdef
isa AStdClassdef then
640 # check bound of formal parameter
641 for nfd
in nclassdef
.n_formaldefs
do
642 var nfdt
= nfd
.n_type
643 if nfdt
!= null and nfdt
.mtype
!= null then
644 var bound
= resolve_mtype
(nclassdef
, nfdt
)
645 if bound
== null then return # Forward error
648 # check declared super types
649 for nsc
in nclassdef
.n_superclasses
do
650 var ntype
= nsc
.n_type
651 if ntype
.mtype
!= null then
652 var mtype
= resolve_mtype
(nclassdef
, ntype
)
653 if mtype
== null then return # Forward error
660 # TODO: Check that the super-class is not intrusive
662 # TODO: Check that the super-class is not already known (by transitivity)
665 # Register the nmodule associated to each mmodule
666 # FIXME: why not refine the MModule class with a nullable attribute?
667 var mmodule2nmodule
: HashMap[MModule, AModule] = new HashMap[MModule, AModule]
668 # Register the nclassdef associated to each mclassdef
669 # FIXME: why not refine the MClassDef class with a nullable attribute?
670 var mclassdef2nclassdef
: HashMap[MClassDef, AClassdef] = new HashMap[MClassDef, AClassdef]
671 # Register the npropdef associated to each mpropdef
672 # FIXME: why not refine the MPropDef class with a nullable attribute?
673 var mpropdef2npropdef
: HashMap[MPropDef, APropdef] = new HashMap[MPropDef, APropdef]
675 # Build the properties of `nclassdef'.
676 # REQUIRE: all superclasses are built.
677 private fun build_properties
(nclassdef
: AClassdef)
679 # Force building recursively
680 if nclassdef
.build_properties_is_done
then return
681 nclassdef
.build_properties_is_done
= true
682 var mclassdef
= nclassdef
.mclassdef
.as(not null)
683 if mclassdef
.in_hierarchy
== null then return # Skip error
684 for superclassdef
in mclassdef
.in_hierarchy
.direct_greaters
do
685 build_properties
(mclassdef2nclassdef
[superclassdef
])
688 for npropdef
in nclassdef
.n_propdefs
do
689 npropdef
.build_property
(self, nclassdef
)
691 for npropdef
in nclassdef
.n_propdefs
do
692 npropdef
.build_signature
(self, nclassdef
)
694 for npropdef
in nclassdef
.n_propdefs
do
695 npropdef
.check_signature
(self, nclassdef
)
697 process_default_constructors
(nclassdef
)
700 # Introduce or inherit default constructor
701 # This is the last part of `build_properties'.
702 private fun process_default_constructors
(nclassdef
: AClassdef)
704 var mclassdef
= nclassdef
.mclassdef
.as(not null)
706 # Are we a refinement
707 if not mclassdef
.is_intro
then return
709 # Is the class forbid constructors?
710 if not mclassdef
.mclass
.kind
.need_init
then return
712 # Is there already a constructor defined?
713 for mpropdef
in mclassdef
.mpropdefs
do
714 if not mpropdef
isa MMethodDef then continue
715 if mpropdef
.mproperty
.is_init
then return
718 if not nclassdef
isa AStdClassdef then return
720 var mmodule
= nclassdef
.mclassdef
.mmodule
721 # Do we inherit for a constructor?
722 var combine
= new Array[MMethod]
723 var inhc
: nullable MClass = null
724 for st
in mclassdef
.supertypes
do
726 if not c
.kind
.need_init
then continue
727 st
= st
.anchor_to
(mmodule
, nclassdef
.mclassdef
.bound_mtype
)
728 var candidate
= self.try_get_mproperty_by_name2
(nclassdef
, mmodule
, st
, "init").as(nullable MMethod)
729 if candidate
!= null and candidate
.intro
.msignature
.arity
== 0 then
730 combine
.add
(candidate
)
733 var inhc2
= c
.inherit_init_from
734 if inhc2
== null then inhc2
= c
735 if inhc2
== inhc
then continue
737 self.error
(nclassdef
, "Error: Cannot provide a defaut constructor: conflict for {inhc} and {c}")
742 if combine
.is_empty
and inhc
!= null then
743 # TODO: actively inherit the consturctor
744 self.toolcontext
.info
("{mclassdef} inherits all constructors from {inhc}", 3)
745 mclassdef
.mclass
.inherit_init_from
= inhc
748 if not combine
.is_empty
and inhc
!= null then
749 self.error
(nclassdef
, "Error: Cannot provide a defaut constructor: conflict for {combine.join(", ")} and {inhc}")
753 if not combine
.is_empty
then
754 nclassdef
.super_inits
= combine
755 var mprop
= new MMethod(mclassdef
, "init", mclassdef
.mclass
.visibility
)
756 var mpropdef
= new MMethodDef(mclassdef
, mprop
, nclassdef
.location
)
757 var mparameters
= new Array[MParameter]
758 var msignature
= new MSignature(mparameters
, null)
759 mpropdef
.msignature
= msignature
761 nclassdef
.mfree_init
= mpropdef
762 self.toolcontext
.info
("{mclassdef} gets a free empty constructor {mpropdef}{msignature}", 3)
766 # Collect undefined attributes
767 var mparameters
= new Array[MParameter]
768 for npropdef
in nclassdef
.n_propdefs
do
769 if npropdef
isa AAttrPropdef and npropdef
.n_expr
== null then
770 if npropdef
.mpropdef
== null then return # Skip broken attribute
771 var paramname
= npropdef
.mpropdef
.mproperty
.name
.substring_from
(1)
772 var ret_type
= npropdef
.mpropdef
.static_mtype
773 if ret_type
== null then return
774 var mparameter
= new MParameter(paramname
, ret_type
, false)
775 mparameters
.add
(mparameter
)
779 var mprop
= new MMethod(mclassdef
, "init", mclassdef
.mclass
.visibility
)
780 var mpropdef
= new MMethodDef(mclassdef
, mprop
, nclassdef
.location
)
781 var msignature
= new MSignature(mparameters
, null)
782 mpropdef
.msignature
= msignature
784 nclassdef
.mfree_init
= mpropdef
785 self.toolcontext
.info
("{mclassdef} gets a free constructor for attributes {mpropdef}{msignature}", 3)
788 # Return the static type associated to the node `ntype'.
789 # `classdef' is the context where the call is made (used to understand formal types)
790 # The mmodule used as context is `nclassdef.mmodule'
791 # In case of problem, an error is displayed on `ntype' and null is returned.
792 # FIXME: the name "resolve_mtype" is awful
793 fun resolve_mtype_unchecked
(nclassdef
: AClassdef, ntype
: AType, with_virtual
: Bool): nullable MType
795 var name
= ntype
.n_id
.text
796 var mclassdef
= nclassdef
.mclassdef
797 var mmodule
= nclassdef
.parent
.as(AModule).mmodule
.as(not null)
801 if mclassdef
!= null and with_virtual
then
802 var prop
= try_get_mproperty_by_name
(ntype
, mclassdef
, name
).as(nullable MVirtualTypeProp)
804 if not ntype
.n_types
.is_empty
then
805 error
(ntype
, "Type error: formal type {name} cannot have formal parameters.")
807 res
= prop
.mvirtualtype
808 if ntype
.n_kwnullable
!= null then res
= res
.as_nullable
814 # Check parameter type
815 if mclassdef
!= null and mclassdef
.parameter_names
.has
(name
) then
816 if not ntype
.n_types
.is_empty
then
817 error
(ntype
, "Type error: formal type {name} cannot have formal parameters.")
819 for i
in [0..mclassdef
.parameter_names
.length
[ do
820 if mclassdef
.parameter_names
[i
] == name
then
821 res
= mclassdef
.mclass
.mclass_type
.arguments
[i
]
822 if ntype
.n_kwnullable
!= null then res
= res
.as_nullable
831 var mclass
= try_get_mclass_by_name
(ntype
, mmodule
, name
)
832 if mclass
!= null then
833 var arity
= ntype
.n_types
.length
834 if arity
!= mclass
.arity
then
836 error
(ntype
, "Type error: '{name}' is a generic class.")
837 else if mclass
.arity
== 0 then
838 error
(ntype
, "Type error: '{name}' is not a generic class.")
840 error
(ntype
, "Type error: '{name}' has {mclass.arity} parameters ({arity} are provided).")
845 res
= mclass
.mclass_type
846 if ntype
.n_kwnullable
!= null then res
= res
.as_nullable
850 var mtypes
= new Array[MType]
851 for nt
in ntype
.n_types
do
852 var mt
= resolve_mtype_unchecked
(nclassdef
, nt
, with_virtual
)
853 if mt
== null then return null # Forward error
856 res
= mclass
.get_mtype
(mtypes
)
857 if ntype
.n_kwnullable
!= null then res
= res
.as_nullable
863 # If everything fail, then give up :(
864 error
(ntype
, "Type error: class {name} not found in module {mmodule}.")
868 # Return the static type associated to the node `ntype'.
869 # `classdef' is the context where the call is made (used to understand formal types)
870 # The mmodule used as context is `nclassdef.mmodule'
871 # In case of problem, an error is displayed on `ntype' and null is returned.
872 # FIXME: the name "resolve_mtype" is awful
873 fun resolve_mtype
(nclassdef
: AClassdef, ntype
: AType): nullable MType
875 var mtype
= ntype
.mtype
876 if mtype
== null then mtype
= resolve_mtype_unchecked
(nclassdef
, ntype
, true)
877 if mtype
== null then return null # Forward error
879 if ntype
.checked_mtype
then return mtype
880 if mtype
isa MGenericType then
881 var mmodule
= nclassdef
.parent
.as(AModule).mmodule
.as(not null)
882 var mclassdef
= nclassdef
.mclassdef
883 var mclass
= mtype
.mclass
884 for i
in [0..mclass
.arity
[ do
885 var bound
= mclass
.intro
.bound_mtype
.arguments
[i
]
886 var nt
= ntype
.n_types
[i
]
887 var mt
= resolve_mtype
(nclassdef
, nt
)
888 if mt
== null then return null # forward error
889 if not mt
.is_subtype
(mmodule
, mclassdef
.bound_mtype
, bound
) then
890 error
(nt
, "Type error: expected {bound}, got {mt}")
895 ntype
.checked_mtype
= true
899 # Helper function to display an error on a node.
900 # Alias for `self.toolcontext.error(n.hot_location, text)'
901 fun error
(n
: ANode, text
: String)
903 self.toolcontext
.error
(n
.hot_location
, text
)
906 # Helper function to display a warning on a node.
907 # Alias for: `self.toolcontext.warning(n.hot_location, text)'
908 fun warning
(n
: ANode, text
: String)
910 self.toolcontext
.warning
(n
.hot_location
, text
)
913 # Force to get the primitive method named `name' on the type `recv' or do a fatal error on `n'
914 fun force_get_primitive_method
(n
: ANode, name
: String, recv
: MType, mmodule
: MModule): MMethod
916 var res
= mmodule
.try_get_primitive_method
(name
, recv
)
918 self.toolcontext
.fatal_error
(n
.hot_location
, "Fatal Error: {recv} must have a property named {name}.")
926 # The associated MModule once build by a `ModelBuilder'
927 var mmodule
: nullable MModule
928 # Flag that indicate if the importation is already completed
929 var is_importation_done
: Bool = false
930 # Flag that indicate if the class and prop building is already completed
931 var build_classes_is_done
: Bool = false
932 # What is the AClassdef associated to a MClass?
933 # Used to check multiple definition of a class.
934 var mclass2nclassdef
: Map[MClass, AClassdef] = new HashMap[MClass, AClassdef]
939 # The class whose self inherit all the constructors.
940 # 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
941 var inherit_init_from
: nullable MClass = null
944 redef class AClassdef
945 # The associated MClass once build by a `ModelBuilder'
946 var mclass
: nullable MClass
947 # The associated MClassDef once build by a `ModelBuilder'
948 var mclassdef
: nullable MClassDef
949 var build_properties_is_done
: Bool = false
950 # The list of super-constructor to call at the start of the free constructor
951 # 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
952 var super_inits
: nullable Collection[MMethod] = null
954 # The free init (implicitely constructed by the class if required)
955 var mfree_init
: nullable MMethodDef = null
957 # What is the APropdef associated to a MProperty?
958 # Used to check multiple definition of a property.
959 var mprop2npropdef
: Map[MProperty, APropdef] = new HashMap[MProperty, APropdef]
962 redef class AClasskind
963 # The class kind associated with the AST node class
964 private fun mkind
: MClassKind is abstract
966 redef class AConcreteClasskind
967 redef fun mkind
do return concrete_kind
969 redef class AAbstractClasskind
970 redef fun mkind
do return abstract_kind
972 redef class AInterfaceClasskind
973 redef fun mkind
do return interface_kind
975 redef class AEnumClasskind
976 redef fun mkind
do return enum_kind
978 redef class AExternClasskind
979 redef fun mkind
do return extern_kind
982 redef class AVisibility
983 # The visibility level associated with the AST node class
984 private fun mvisibility
: MVisibility is abstract
986 redef class AIntrudeVisibility
987 redef fun mvisibility
do return intrude_visibility
989 redef class APublicVisibility
990 redef fun mvisibility
do return public_visibility
992 redef class AProtectedVisibility
993 redef fun mvisibility
do return protected_visibility
995 redef class APrivateVisibility
996 redef fun mvisibility
do return private_visibility
1000 # The mtype associated to the node
1001 var mtype
: nullable MType = null
1003 # Is the mtype a valid one?
1004 var checked_mtype
: Bool = false
1010 # Join the text of all tokens
1011 # Used to get the 'real name' of method definitions.
1012 fun collect_text
: String
1014 var v
= new TextCollectorVisitor
1021 private class TextCollectorVisitor
1023 var text
: String = ""
1026 if n
isa Token then text
+= n
.text
1031 redef class APropdef
1032 private fun build_property
(modelbuilder
: ModelBuilder, nclassdef
: AClassdef)
1035 private fun build_signature
(modelbuilder
: ModelBuilder, nclassdef
: AClassdef)
1038 private fun check_signature
(modelbuilder
: ModelBuilder, nclassdef
: AClassdef)
1041 private fun new_property_visibility
(modelbuilder
: ModelBuilder, nclassdef
: AClassdef, nvisibility
: nullable AVisibility): MVisibility
1043 var mvisibility
= public_visibility
1044 if nvisibility
!= null then mvisibility
= nvisibility
.mvisibility
1045 if nclassdef
.mclassdef
.mclass
.visibility
== private_visibility
then
1046 if mvisibility
== protected_visibility
then
1047 assert nvisibility
!= null
1048 modelbuilder
.error
(nvisibility
, "Error: The only legal visibility for properties in a private class is private.")
1049 else if mvisibility
== private_visibility
then
1050 assert nvisibility
!= null
1052 # modelbuilder.warning(nvisibility, "Warning: private is unrequired since the only legal visibility for properties in a private class is private.")
1054 mvisibility
= private_visibility
1059 private fun check_redef_property_visibility
(modelbuilder
: ModelBuilder, nclassdef
: AClassdef, nvisibility
: nullable AVisibility, mprop
: MProperty)
1061 if nvisibility
== null then return
1062 var mvisibility
= nvisibility
.mvisibility
1063 if mvisibility
!= mprop
.visibility
and mvisibility
!= public_visibility
then
1064 modelbuilder
.error
(nvisibility
, "Error: redefinition changed the visibility from a {mprop.visibility} to a {mvisibility}")
1068 private fun check_redef_keyword
(modelbuilder
: ModelBuilder, nclassdef
: AClassdef, kwredef
: nullable Token, need_redef
: Bool, mprop
: MProperty): Bool
1070 if nclassdef
.mprop2npropdef
.has_key
(mprop
) then
1071 modelbuilder
.error
(self, "Error: A property {mprop} is already defined in class {nclassdef.mclassdef.mclass}.")
1074 if kwredef
== null then
1076 modelbuilder
.error
(self, "Redef error: {nclassdef.mclassdef.mclass}::{mprop.name} is an inherited property. To redefine it, add the redef keyword.")
1080 if not need_redef
then
1081 modelbuilder
.error
(self, "Error: No property {nclassdef.mclassdef.mclass}::{mprop.name} is inherited. Remove the redef keyword to define a new property.")
1090 redef class ASignature
1091 # Is the model builder has correctly visited the signature
1092 var is_visited
= false
1093 # Names of parameters from the AST
1094 # REQUIRE: is_visited
1095 var param_names
= new Array[String]
1096 # Types of parameters from the AST
1097 # REQUIRE: is_visited
1098 var param_types
= new Array[MType]
1099 # Rank of the vararg (of -1 if none)
1100 # REQUIRE: is_visited
1101 var vararg_rank
: Int = -1
1103 var ret_type
: nullable MType = null
1105 # Visit and fill information about a signature
1106 private fun visit_signature
(modelbuilder
: ModelBuilder, nclassdef
: AClassdef): Bool
1108 var param_names
= self.param_names
1109 var param_types
= self.param_types
1110 for np
in self.n_params
do
1111 param_names
.add
(np
.n_id
.text
)
1112 var ntype
= np
.n_type
1113 if ntype
!= null then
1114 var mtype
= modelbuilder
.resolve_mtype
(nclassdef
, ntype
)
1115 if mtype
== null then return false # Skip error
1116 for i
in [0..param_names
.length-param_types
.length
[ do
1117 param_types
.add
(mtype
)
1119 if np
.n_dotdotdot
!= null then
1120 if self.vararg_rank
!= -1 then
1121 modelbuilder
.error
(np
, "Error: {param_names[self.vararg_rank]} is already a vararg")
1124 self.vararg_rank
= param_names
.length
- 1
1129 var ntype
= self.n_type
1130 if ntype
!= null then
1131 self.ret_type
= modelbuilder
.resolve_mtype
(nclassdef
, ntype
)
1132 if self.ret_type
== null then return false # Skip errir
1135 for nclosure
in self.n_closure_decls
do
1136 if not nclosure
.n_signature
.visit_signature
(modelbuilder
, nclassdef
) then return false
1139 self.is_visited
= true
1143 # Build a visited signature
1144 fun build_signature
(modelbuilder
: ModelBuilder, nclassdef
: AClassdef): nullable MSignature
1146 if param_names
.length
!= param_types
.length
then
1147 # Some parameters are typed, other parameters are not typed.
1148 modelbuilder
.error
(self.n_params
[param_types
.length
], "Error: Untyped parameter `{param_names[param_types.length]}'.")
1152 var mparameters
= new Array[MParameter]
1153 for i
in [0..param_names
.length
[ do
1154 var mparameter
= new MParameter(param_names
[i
], param_types
[i
], i
== vararg_rank
)
1155 mparameters
.add
(mparameter
)
1158 var msignature
= new MSignature(mparameters
, ret_type
)
1163 redef class AMethPropdef
1164 # The associated MMethodDef once build by a `ModelBuilder'
1165 var mpropdef
: nullable MMethodDef
1167 # The associated super init if any
1168 var super_init
: nullable MMethod
1169 redef fun build_property
(modelbuilder
, nclassdef
)
1171 var is_init
= self isa AInitPropdef
1172 var mclassdef
= nclassdef
.mclassdef
.as(not null)
1174 var amethodid
= self.n_methid
1175 var name_node
: ANode
1176 if amethodid
== null then
1177 if self isa AMainMethPropdef then
1180 else if self isa AConcreteInitPropdef then
1182 name_node
= self.n_kwinit
1183 else if self isa AExternInitPropdef then
1185 name_node
= self.n_kwnew
1189 else if amethodid
isa AIdMethid then
1190 name
= amethodid
.n_id
.text
1191 name_node
= amethodid
1193 # operator, bracket or assign
1194 name
= amethodid
.collect_text
1195 name_node
= amethodid
1197 if name
== "-" and self.n_signature
.n_params
.length
== 0 then
1202 var mprop
: nullable MMethod = null
1203 if not is_init
or n_kwredef
!= null then mprop
= modelbuilder
.try_get_mproperty_by_name
(name_node
, mclassdef
, name
).as(nullable MMethod)
1204 if mprop
== null then
1205 var mvisibility
= new_property_visibility
(modelbuilder
, nclassdef
, self.n_visibility
)
1206 mprop
= new MMethod(mclassdef
, name
, mvisibility
)
1207 mprop
.is_init
= is_init
1208 mprop
.is_new
= self isa AExternInitPropdef
1209 if not self.check_redef_keyword
(modelbuilder
, nclassdef
, n_kwredef
, false, mprop
) then return
1211 if n_kwredef
== null then
1212 if self isa AMainMethPropdef then
1215 if not self.check_redef_keyword
(modelbuilder
, nclassdef
, n_kwredef
, true, mprop
) then return
1218 check_redef_property_visibility
(modelbuilder
, nclassdef
, self.n_visibility
, mprop
)
1220 nclassdef
.mprop2npropdef
[mprop
] = self
1222 var mpropdef
= new MMethodDef(mclassdef
, mprop
, self.location
)
1224 self.mpropdef
= mpropdef
1225 modelbuilder
.mpropdef2npropdef
[mpropdef
] = self
1226 if mpropdef
.is_intro
then
1227 modelbuilder
.toolcontext
.info
("{mpropdef} introduces new method {mprop.full_name}", 3)
1229 modelbuilder
.toolcontext
.info
("{mpropdef} redefines method {mprop.full_name}", 3)
1233 redef fun build_signature
(modelbuilder
, nclassdef
)
1235 var mpropdef
= self.mpropdef
1236 if mpropdef
== null then return # Error thus skiped
1237 var mmodule
= mpropdef
.mclassdef
.mmodule
1238 var nsig
= self.n_signature
1240 # Retrieve info from the signature AST
1241 var param_names
= new Array[String] # Names of parameters from the AST
1242 var param_types
= new Array[MType] # Types of parameters from the AST
1243 var vararg_rank
= -1
1244 var ret_type
: nullable MType = null # Return type from the AST
1245 if nsig
!= null then
1246 if not nsig
.visit_signature
(modelbuilder
, nclassdef
) then return
1247 param_names
= nsig
.param_names
1248 param_types
= nsig
.param_types
1249 vararg_rank
= nsig
.vararg_rank
1250 ret_type
= nsig
.ret_type
1253 # Look for some signature to inherit
1254 # FIXME: do not inherit from the intro, but from the most specific
1255 var msignature
: nullable MSignature = null
1256 if not mpropdef
.is_intro
then
1257 msignature
= mpropdef
.mproperty
.intro
.msignature
1258 if msignature
== null then return # Skip error
1260 # Check inherited signature arity
1261 if param_names
.length
!= msignature
.arity
then
1263 if nsig
!= null then node
= nsig
else node
= self
1264 modelbuilder
.error
(node
, "Redef error: {mpropdef} redefines {mpropdef.mproperty.intro} with {param_names.length} parameter(s), {msignature.arity} expected. Signature is {mpropdef}{msignature}")
1267 else if mpropdef
.mproperty
.is_init
then
1268 # FIXME UGLY: inherit signature from a super-constructor
1269 for msupertype
in nclassdef
.mclassdef
.supertypes
do
1270 msupertype
= msupertype
.anchor_to
(mmodule
, nclassdef
.mclassdef
.bound_mtype
)
1271 var candidate
= modelbuilder
.try_get_mproperty_by_name2
(self, mmodule
, msupertype
, mpropdef
.mproperty
.name
)
1272 if candidate
!= null then
1273 if msignature
== null then
1274 msignature
= candidate
.intro
.as(MMethodDef).msignature
1281 # Inherit the signature
1282 if msignature
!= null and param_names
.length
!= param_types
.length
and param_names
.length
== msignature
.arity
and param_types
.length
== 0 then
1283 # Parameters are untyped, thus inherit them
1284 param_types
= new Array[MType]
1285 for mparameter
in msignature
.mparameters
do
1286 param_types
.add
(mparameter
.mtype
)
1288 vararg_rank
= msignature
.vararg_rank
1290 if msignature
!= null and ret_type
== null then
1291 ret_type
= msignature
.return_mtype
1294 if param_names
.length
!= param_types
.length
then
1295 # Some parameters are typed, other parameters are not typed.
1296 modelbuilder
.error
(nsig
.n_params
[param_types
.length
], "Error: Untyped parameter `{param_names[param_types.length]}'.")
1300 var mparameters
= new Array[MParameter]
1301 for i
in [0..param_names
.length
[ do
1302 var mparameter
= new MParameter(param_names
[i
], param_types
[i
], i
== vararg_rank
)
1303 mparameters
.add
(mparameter
)
1306 msignature
= new MSignature(mparameters
, ret_type
)
1307 mpropdef
.msignature
= msignature
1309 if nsig
!= null then
1310 for nclosure
in nsig
.n_closure_decls
do
1311 var clos_signature
= nclosure
.n_signature
.build_signature
(modelbuilder
, nclassdef
)
1312 if clos_signature
== null then return
1313 var mparameter
= new MParameter(nclosure
.n_id
.text
, clos_signature
, false)
1314 msignature
.mclosures
.add
(mparameter
)
1320 redef fun check_signature
(modelbuilder
, nclassdef
)
1322 var mpropdef
= self.mpropdef
1323 if mpropdef
== null then return # Error thus skiped
1324 var mmodule
= mpropdef
.mclassdef
.mmodule
1325 var nsig
= self.n_signature
1326 var mysignature
= self.mpropdef
.msignature
1327 if mysignature
== null then return # Error thus skiped
1329 # Lookup for signature in the precursor
1330 # FIXME all precursors should be considered
1331 if not mpropdef
.is_intro
then
1332 var msignature
= mpropdef
.mproperty
.intro
.msignature
1333 if msignature
== null then return
1335 var precursor_ret_type
= msignature
.return_mtype
1336 var ret_type
= mysignature
.return_mtype
1337 if ret_type
!= null and precursor_ret_type
== null then
1338 modelbuilder
.error
(nsig
.n_type
.as(not null), "Redef Error: {mpropdef.mproperty} is a procedure, not a function.")
1342 if mysignature
.arity
> 0 then
1343 # Check parameters types
1344 for i
in [0..mysignature
.arity
[ do
1345 var myt
= mysignature
.mparameters
[i
].mtype
1346 var prt
= msignature
.mparameters
[i
].mtype
1347 if not myt
.is_subtype
(mmodule
, nclassdef
.mclassdef
.bound_mtype
, prt
) and
1348 not prt
.is_subtype
(mmodule
, nclassdef
.mclassdef
.bound_mtype
, myt
) then
1349 modelbuilder
.error
(nsig
.n_params
[i
], "Redef Error: Wrong type for parameter `{mysignature.mparameters[i].name}'. found {myt}, expected {prt}.")
1353 if precursor_ret_type
!= null then
1354 if ret_type
== null then
1355 # Inherit the return type
1356 ret_type
= precursor_ret_type
1357 else if not ret_type
.is_subtype
(mmodule
, nclassdef
.mclassdef
.bound_mtype
, precursor_ret_type
) then
1358 modelbuilder
.error
(nsig
.n_type
.as(not null), "Redef Error: Wrong return type. found {ret_type}, expected {precursor_ret_type}.")
1365 redef class AAttrPropdef
1366 # The associated MAttributeDef once build by a `ModelBuilder'
1367 var mpropdef
: nullable MAttributeDef
1368 # The associated getter (read accessor) if any
1369 var mreadpropdef
: nullable MMethodDef
1370 # The associated setter (write accessor) if any
1371 var mwritepropdef
: nullable MMethodDef
1372 redef fun build_property
(modelbuilder
, nclassdef
)
1374 var mclassdef
= nclassdef
.mclassdef
.as(not null)
1375 var mclass
= mclassdef
.mclass
1378 if self.n_id
!= null then
1379 name
= self.n_id
.text
1381 name
= self.n_id2
.text
1384 if mclass
.kind
== interface_kind
or mclassdef
.mclass
.kind
== enum_kind
then
1385 modelbuilder
.error
(self, "Error: Attempt to define attribute {name} in the interface {mclass}.")
1386 else if mclass
.kind
== enum_kind
then
1387 modelbuilder
.error
(self, "Error: Attempt to define attribute {name} in the enum class {mclass}.")
1388 else if mclass
.kind
== extern_kind
then
1389 modelbuilder
.error
(self, "Error: Attempt to define attribute {name} in the extern class {mclass}.")
1394 # Old attribute style
1395 var mprop
= modelbuilder
.try_get_mproperty_by_name
(nid
, mclassdef
, name
)
1396 if mprop
== null then
1397 var mvisibility
= new_property_visibility
(modelbuilder
, nclassdef
, self.n_visibility
)
1398 mprop
= new MAttribute(mclassdef
, name
, mvisibility
)
1399 if not self.check_redef_keyword
(modelbuilder
, nclassdef
, self.n_kwredef
, false, mprop
) then return
1401 assert mprop
isa MAttribute
1402 check_redef_property_visibility
(modelbuilder
, nclassdef
, self.n_visibility
, mprop
)
1403 if not self.check_redef_keyword
(modelbuilder
, nclassdef
, self.n_kwredef
, true, mprop
) then return
1405 nclassdef
.mprop2npropdef
[mprop
] = self
1407 var mpropdef
= new MAttributeDef(mclassdef
, mprop
, self.location
)
1408 self.mpropdef
= mpropdef
1409 modelbuilder
.mpropdef2npropdef
[mpropdef
] = self
1411 var nreadable
= self.n_readable
1412 if nreadable
!= null then
1413 var readname
= name
.substring_from
(1)
1414 var mreadprop
= modelbuilder
.try_get_mproperty_by_name
(nid
, mclassdef
, readname
).as(nullable MMethod)
1415 if mreadprop
== null then
1416 var mvisibility
= new_property_visibility
(modelbuilder
, nclassdef
, nreadable
.n_visibility
)
1417 mreadprop
= new MMethod(mclassdef
, readname
, mvisibility
)
1418 if not self.check_redef_keyword
(modelbuilder
, nclassdef
, nreadable
.n_kwredef
, false, mreadprop
) then return
1420 if not self.check_redef_keyword
(modelbuilder
, nclassdef
, nreadable
.n_kwredef
, true, mreadprop
) then return
1421 check_redef_property_visibility
(modelbuilder
, nclassdef
, nreadable
.n_visibility
, mreadprop
)
1423 nclassdef
.mprop2npropdef
[mreadprop
] = self
1425 var mreadpropdef
= new MMethodDef(mclassdef
, mreadprop
, self.location
)
1426 self.mreadpropdef
= mreadpropdef
1427 modelbuilder
.mpropdef2npropdef
[mreadpropdef
] = self
1430 var nwritable
= self.n_writable
1431 if nwritable
!= null then
1432 var writename
= name
.substring_from
(1) + "="
1433 var mwriteprop
= modelbuilder
.try_get_mproperty_by_name
(nid
, mclassdef
, writename
).as(nullable MMethod)
1434 if mwriteprop
== null then
1435 var mvisibility
= new_property_visibility
(modelbuilder
, nclassdef
, nwritable
.n_visibility
)
1436 mwriteprop
= new MMethod(mclassdef
, writename
, mvisibility
)
1437 if not self.check_redef_keyword
(modelbuilder
, nclassdef
, nwritable
.n_kwredef
, false, mwriteprop
) then return
1439 if not self.check_redef_keyword
(modelbuilder
, nclassdef
, nwritable
.n_kwredef
, true, mwriteprop
) then return
1440 check_redef_property_visibility
(modelbuilder
, nclassdef
, nwritable
.n_visibility
, mwriteprop
)
1442 nclassdef
.mprop2npropdef
[mwriteprop
] = self
1444 var mwritepropdef
= new MMethodDef(mclassdef
, mwriteprop
, self.location
)
1445 self.mwritepropdef
= mwritepropdef
1446 modelbuilder
.mpropdef2npropdef
[mwritepropdef
] = self
1449 # New attribute style
1450 var nid2
= self.n_id2
.as(not null)
1451 var mprop
= new MAttribute(mclassdef
, "@" + name
, none_visibility
)
1452 var mpropdef
= new MAttributeDef(mclassdef
, mprop
, self.location
)
1453 self.mpropdef
= mpropdef
1454 modelbuilder
.mpropdef2npropdef
[mpropdef
] = self
1457 var mreadprop
= modelbuilder
.try_get_mproperty_by_name
(nid2
, mclassdef
, readname
).as(nullable MMethod)
1458 if mreadprop
== null then
1459 var mvisibility
= new_property_visibility
(modelbuilder
, nclassdef
, self.n_visibility
)
1460 mreadprop
= new MMethod(mclassdef
, readname
, mvisibility
)
1461 if not self.check_redef_keyword
(modelbuilder
, nclassdef
, n_kwredef
, false, mreadprop
) then return
1463 if not self.check_redef_keyword
(modelbuilder
, nclassdef
, n_kwredef
, true, mreadprop
) then return
1464 check_redef_property_visibility
(modelbuilder
, nclassdef
, self.n_visibility
, mreadprop
)
1466 nclassdef
.mprop2npropdef
[mreadprop
] = self
1468 var mreadpropdef
= new MMethodDef(mclassdef
, mreadprop
, self.location
)
1469 self.mreadpropdef
= mreadpropdef
1470 modelbuilder
.mpropdef2npropdef
[mreadpropdef
] = self
1472 var writename
= name
+ "="
1473 var nwritable
= self.n_writable
1474 var mwriteprop
= modelbuilder
.try_get_mproperty_by_name
(nid2
, mclassdef
, writename
).as(nullable MMethod)
1475 var nwkwredef
: nullable Token = null
1476 if nwritable
!= null then nwkwredef
= nwritable
.n_kwredef
1477 if mwriteprop
== null then
1479 if nwritable
!= null then
1480 mvisibility
= new_property_visibility
(modelbuilder
, nclassdef
, nwritable
.n_visibility
)
1482 mvisibility
= private_visibility
1484 mwriteprop
= new MMethod(mclassdef
, writename
, mvisibility
)
1485 if not self.check_redef_keyword
(modelbuilder
, nclassdef
, nwkwredef
, false, mwriteprop
) then return
1487 if not self.check_redef_keyword
(modelbuilder
, nclassdef
, nwkwredef
, true, mwriteprop
) then return
1488 if nwritable
!= null then
1489 check_redef_property_visibility
(modelbuilder
, nclassdef
, nwritable
.n_visibility
, mwriteprop
)
1492 nclassdef
.mprop2npropdef
[mwriteprop
] = self
1494 var mwritepropdef
= new MMethodDef(mclassdef
, mwriteprop
, self.location
)
1495 self.mwritepropdef
= mwritepropdef
1496 modelbuilder
.mpropdef2npropdef
[mwritepropdef
] = self
1500 redef fun build_signature
(modelbuilder
, nclassdef
)
1502 var mpropdef
= self.mpropdef
1503 if mpropdef
== null then return # Error thus skiped
1504 var mmodule
= mpropdef
.mclassdef
.mmodule
1505 var mtype
: nullable MType = null
1507 var ntype
= self.n_type
1508 if ntype
!= null then
1509 mtype
= modelbuilder
.resolve_mtype
(nclassdef
, ntype
)
1510 if mtype
== null then return
1513 if mtype
== null then
1514 var nexpr
= self.n_expr
1515 if nexpr
!= null then
1516 if nexpr
isa ANewExpr then
1517 mtype
= modelbuilder
.resolve_mtype
(nclassdef
, nexpr
.n_type
)
1518 else if nexpr
isa AIntExpr then
1519 var cla
= modelbuilder
.try_get_mclass_by_name
(nexpr
, mmodule
, "Int")
1520 if cla
!= null then mtype
= cla
.mclass_type
1521 else if nexpr
isa AFloatExpr then
1522 var cla
= modelbuilder
.try_get_mclass_by_name
(nexpr
, mmodule
, "Float")
1523 if cla
!= null then mtype
= cla
.mclass_type
1524 else if nexpr
isa ACharExpr then
1525 var cla
= modelbuilder
.try_get_mclass_by_name
(nexpr
, mmodule
, "Char")
1526 if cla
!= null then mtype
= cla
.mclass_type
1527 else if nexpr
isa ABoolExpr then
1528 var cla
= modelbuilder
.try_get_mclass_by_name
(nexpr
, mmodule
, "Bool")
1529 if cla
!= null then mtype
= cla
.mclass_type
1530 else if nexpr
isa ASuperstringExpr then
1531 var cla
= modelbuilder
.try_get_mclass_by_name
(nexpr
, mmodule
, "String")
1532 if cla
!= null then mtype
= cla
.mclass_type
1533 else if nexpr
isa AStringFormExpr then
1534 var cla
= modelbuilder
.try_get_mclass_by_name
(nexpr
, mmodule
, "String")
1535 if cla
!= null then mtype
= cla
.mclass_type
1537 modelbuilder
.error
(self, "Error: Untyped attribute {mpropdef}. Implicit typing allowed only for literals and new.")
1541 modelbuilder
.error
(self, "Error: Untyped attribute {mpropdef}")
1545 if mtype
== null then return
1547 mpropdef
.static_mtype
= mtype
1549 var mreadpropdef
= self.mreadpropdef
1550 if mreadpropdef
!= null then
1551 var msignature
= new MSignature(new Array[MParameter], mtype
)
1552 mreadpropdef
.msignature
= msignature
1555 var msritepropdef
= self.mwritepropdef
1556 if mwritepropdef
!= null then
1558 if n_id
!= null then
1559 name
= n_id
.text
.substring_from
(1)
1563 var mparameter
= new MParameter(name
, mtype
, false)
1564 var msignature
= new MSignature([mparameter
], null)
1565 mwritepropdef
.msignature
= msignature
1569 redef fun check_signature
(modelbuilder
, nclassdef
)
1571 var mpropdef
= self.mpropdef
1572 if mpropdef
== null then return # Error thus skiped
1573 var mmodule
= mpropdef
.mclassdef
.mmodule
1574 var ntype
= self.n_type
1575 var mtype
= self.mpropdef
.static_mtype
1576 if mtype
== null then return # Error thus skiped
1578 # Lookup for signature in the precursor
1579 # FIXME all precursors should be considered
1580 if not mpropdef
.is_intro
then
1581 var precursor_type
= mpropdef
.mproperty
.intro
.static_mtype
1582 if precursor_type
== null then return
1584 if mtype
!= precursor_type
then
1585 modelbuilder
.error
(ntype
.as(not null), "Redef Error: Wrong static type. found {mtype}, expected {precursor_type}.")
1590 # Check getter and setter
1591 var meth
= self.mreadpropdef
1592 if meth
!= null then self.check_method_signature
(modelbuilder
, nclassdef
, meth
)
1593 meth
= self.mwritepropdef
1594 if meth
!= null then self.check_method_signature
(modelbuilder
, nclassdef
, meth
)
1597 private fun check_method_signature
(modelbuilder
: ModelBuilder, nclassdef
: AClassdef, mpropdef
: MMethodDef)
1599 var mmodule
= mpropdef
.mclassdef
.mmodule
1600 var nsig
= self.n_type
1601 var mysignature
= mpropdef
.msignature
1602 if mysignature
== null then return # Error thus skiped
1604 # Lookup for signature in the precursor
1605 # FIXME all precursors should be considered
1606 if not mpropdef
.is_intro
then
1607 var msignature
= mpropdef
.mproperty
.intro
.msignature
1608 if msignature
== null then return
1610 if mysignature
.arity
!= msignature
.arity
then
1612 if nsig
!= null then node
= nsig
else node
= self
1613 modelbuilder
.error
(node
, "Redef Error: {mysignature.arity} parameters found, {msignature.arity} expected. Signature is {mpropdef}{msignature}")
1616 var precursor_ret_type
= msignature
.return_mtype
1617 var ret_type
= mysignature
.return_mtype
1618 if ret_type
!= null and precursor_ret_type
== null then
1620 if nsig
!= null then node
= nsig
else node
= self
1621 modelbuilder
.error
(node
, "Redef Error: {mpropdef.mproperty} is a procedure, not a function.")
1625 if mysignature
.arity
> 0 then
1626 # Check parameters types
1627 for i
in [0..mysignature
.arity
[ do
1628 var myt
= mysignature
.mparameters
[i
].mtype
1629 var prt
= msignature
.mparameters
[i
].mtype
1630 if not myt
.is_subtype
(mmodule
, nclassdef
.mclassdef
.bound_mtype
, prt
) and
1631 not prt
.is_subtype
(mmodule
, nclassdef
.mclassdef
.bound_mtype
, myt
) then
1633 if nsig
!= null then node
= nsig
else node
= self
1634 modelbuilder
.error
(node
, "Redef Error: Wrong type for parameter `{mysignature.mparameters[i].name}'. found {myt}, expected {prt}.")
1638 if precursor_ret_type
!= null then
1639 if ret_type
== null then
1640 # Inherit the return type
1641 ret_type
= precursor_ret_type
1642 else if not ret_type
.is_subtype
(mmodule
, nclassdef
.mclassdef
.bound_mtype
, precursor_ret_type
) then
1644 if nsig
!= null then node
= nsig
else node
= self
1645 modelbuilder
.error
(node
, "Redef Error: Wrong return type. found {ret_type}, expected {precursor_ret_type}.")
1652 redef class ATypePropdef
1653 # The associated MVirtualTypeDef once build by a `ModelBuilder'
1654 var mpropdef
: nullable MVirtualTypeDef
1655 redef fun build_property
(modelbuilder
, nclassdef
)
1657 var mclassdef
= nclassdef
.mclassdef
.as(not null)
1658 var name
= self.n_id
.text
1659 var mprop
= modelbuilder
.try_get_mproperty_by_name
(self.n_id
, mclassdef
, name
)
1660 if mprop
== null then
1661 var mvisibility
= new_property_visibility
(modelbuilder
, nclassdef
, self.n_visibility
)
1662 mprop
= new MVirtualTypeProp(mclassdef
, name
, mvisibility
)
1663 if not self.check_redef_keyword
(modelbuilder
, nclassdef
, self.n_kwredef
, false, mprop
) then return
1665 if not self.check_redef_keyword
(modelbuilder
, nclassdef
, self.n_kwredef
, true, mprop
) then return
1666 assert mprop
isa MVirtualTypeProp
1667 check_redef_property_visibility
(modelbuilder
, nclassdef
, self.n_visibility
, mprop
)
1669 nclassdef
.mprop2npropdef
[mprop
] = self
1671 var mpropdef
= new MVirtualTypeDef(mclassdef
, mprop
, self.location
)
1672 self.mpropdef
= mpropdef
1675 redef fun build_signature
(modelbuilder
, nclassdef
)
1677 var mpropdef
= self.mpropdef
1678 if mpropdef
== null then return # Error thus skiped
1679 var mmodule
= mpropdef
.mclassdef
.mmodule
1680 var mtype
: nullable MType = null
1682 var ntype
= self.n_type
1683 mtype
= modelbuilder
.resolve_mtype
(nclassdef
, ntype
)
1684 if mtype
== null then return
1686 mpropdef
.bound
= mtype
1687 # print "{mpropdef}: {mtype}"
1690 redef fun check_signature
(modelbuilder
, nclassdef
)
1692 var bound
= self.mpropdef
.bound
1694 # Fast case: the bound is not a formal type
1695 if not bound
isa MVirtualType then return
1697 var mmodule
= nclassdef
.mclassdef
.mmodule
1698 var anchor
= nclassdef
.mclassdef
.bound_mtype
1700 # Slow case: progress on each resolution until: (i) we loop, or (ii) we found a non formal type
1701 var seen
= [self.mpropdef
.mproperty
.mvirtualtype
]
1703 if seen
.has
(bound
) then
1705 modelbuilder
.error
(self, "Error: circularity of virtual type definition: {seen.join(" -> ")}")
1709 var next
= bound
.lookup_bound
(mmodule
, anchor
)
1710 if not next
isa MVirtualType then return