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]
95 # Parse and recursively load
96 self.toolcontext
.info
("*** PARSE ***", 1)
97 var mmodules
= new Array[MModule]
99 var nmodule
= self.load_module
(null, a
)
100 if nmodule
== null then continue # Skip error
101 mmodules
.add
(nmodule
.mmodule
.as(not null))
104 self.toolcontext
.info
("*** END PARSE: {time1-time0} ***", 2)
106 self.toolcontext
.check_errors
108 if self.toolcontext
.opt_only_parse
.value
then
109 self.toolcontext
.info
("--only-parse: stop processing", 2)
110 return new Array[MModule]
114 self.toolcontext
.info
("*** BUILD MODEL ***", 1)
115 self.build_all_classes
117 self.toolcontext
.info
("*** END BUILD MODEL: {time2-time1} ***", 2)
119 self.toolcontext
.check_errors
124 # Return a class named `name' visible by the module `mmodule'.
125 # Visibility in modules is correctly handled.
126 # If no such a class exists, then null is returned.
127 # If more than one class exists, then an error on `anode' is displayed and null is returned.
128 # FIXME: add a way to handle class name conflict
129 fun try_get_mclass_by_name
(anode
: ANode, mmodule
: MModule, name
: String): nullable MClass
131 var classes
= model
.get_mclasses_by_name
(name
)
132 if classes
== null then
136 var res
: nullable MClass = null
137 for mclass
in classes
do
138 if not mmodule
.in_importation
<= mclass
.intro_mmodule
then continue
139 if not mmodule
.is_visible
(mclass
.intro_mmodule
, mclass
.visibility
) then continue
143 error
(anode
, "Ambigous class name '{name}'; conflict between {mclass.full_name} and {res.full_name}")
150 # Return a property named `name' on the type `mtype' visible in the module `mmodule'.
151 # Visibility in modules is correctly handled.
152 # Protected properties are returned (it is up to the caller to check and reject protected properties).
153 # If no such a property exists, then null is returned.
154 # If more than one property exists, then an error on `anode' is displayed and null is returned.
155 # FIXME: add a way to handle property name conflict
156 fun try_get_mproperty_by_name2
(anode
: ANode, mmodule
: MModule, mtype
: MType, name
: String): nullable MProperty
158 var props
= self.model
.get_mproperties_by_name
(name
)
159 if props
== null then
163 var cache
= self.try_get_mproperty_by_name2_cache
[mmodule
, mtype
, name
]
164 if cache
!= null then return cache
166 var res
: nullable MProperty = null
167 var ress
: nullable Array[MProperty] = null
168 for mprop
in props
do
169 if not mtype
.has_mproperty
(mmodule
, mprop
) then continue
170 if not mmodule
.is_visible
(mprop
.intro_mclassdef
.mmodule
, mprop
.visibility
) then continue
174 var restype
= res
.intro_mclassdef
.bound_mtype
175 var mproptype
= mprop
.intro_mclassdef
.bound_mtype
176 if restype
.is_subtype
(mmodule
, null, mproptype
) then
178 else if mproptype
.is_subtype
(mmodule
, null, restype
) then
181 if ress
== null then ress
= new Array[MProperty]
187 var restype
= res
.intro_mclassdef
.bound_mtype
189 var mproptype
= mprop
.intro_mclassdef
.bound_mtype
190 if not restype
.is_subtype
(mmodule
, null, mproptype
) then
191 self.error
(anode
, "Ambigous property name '{name}' for {mtype}; conflict between {mprop.full_name} and {res.full_name}")
197 self.try_get_mproperty_by_name2_cache
[mmodule
, mtype
, name
] = res
201 private var try_get_mproperty_by_name2_cache
: HashMap3[MModule, MType, String, nullable MProperty] = new HashMap3[MModule, MType, String, nullable MProperty]
204 # Alias for try_get_mproperty_by_name2(anode, mclassdef.mmodule, mclassdef.mtype, name)
205 fun try_get_mproperty_by_name
(anode
: ANode, mclassdef
: MClassDef, name
: String): nullable MProperty
207 return try_get_mproperty_by_name2
(anode
, mclassdef
.mmodule
, mclassdef
.bound_mtype
, name
)
210 # The list of directories to search for top level modules
211 # The list is initially set with :
212 # * the toolcontext --path option
213 # * the NIT_PATH environment variable
214 # * some heuristics including the NIT_DIR environment variable and the progname of the process
215 # Path can be added (or removed) by the client
216 var paths
: Array[String] = new Array[String]
218 # Get a module by its short name; if required, the module is loaded, parsed and its hierarchies computed.
219 # If `mmodule' is set, then the module search starts from it up to the top level (see `paths');
220 # if `mmodule' is null then the module is searched in the top level only.
221 # If no module exists or there is a name conflict, then an error on `anode' is displayed and null is returned.
222 # FIXME: add a way to handle module name conflict
223 fun get_mmodule_by_name
(anode
: ANode, mmodule
: nullable MModule, name
: String): nullable MModule
225 var origmmodule
= mmodule
226 var modules
= model
.get_mmodules_by_name
(name
)
228 var tries
= new Array[String]
230 var lastmodule
= mmodule
231 while mmodule
!= null do
232 var dirname
= mmodule
.location
.file
.filename
.dirname
234 # Determine the owner
235 var owner
: nullable MModule
236 if dirname
.basename
("") != mmodule
.name
then
237 owner
= mmodule
.direct_owner
242 # First, try the already known nested modules
243 if modules
!= null then
244 for candidate
in modules
do
245 if candidate
.direct_owner
== owner
then
251 # Second, try the directory to find a file
252 var try_file
= dirname
+ "/" + name
+ ".nit"
254 if try_file
.file_exists
then
255 var res
= self.load_module
(owner
, try_file
.simplify_path
)
256 if res
== null then return null # Forward error
257 return res
.mmodule
.as(not null)
260 # Third, try if the requested module is itself an owner
261 try_file
= dirname
+ "/" + name
+ "/" + name
+ ".nit"
262 if try_file
.file_exists
then
263 var res
= self.load_module
(owner
, try_file
.simplify_path
)
264 if res
== null then return null # Forward error
265 return res
.mmodule
.as(not null)
269 mmodule
= mmodule
.direct_owner
272 if modules
!= null then
273 for candidate
in modules
do
274 if candidate
.direct_owner
== null then
280 # Look at some known directories
281 var lookpaths
= self.paths
283 # Look in the directory of the last module also (event if not in the path)
284 if lastmodule
!= null then
285 var dirname
= lastmodule
.location
.file
.filename
.dirname
286 if dirname
.basename
("") == lastmodule
.name
then
287 dirname
= dirname
.dirname
289 if not lookpaths
.has
(dirname
) then
290 lookpaths
= lookpaths
.to_a
291 lookpaths
.add
(dirname
)
295 var candidate
: nullable String = null
296 for dirname
in lookpaths
do
297 var try_file
= (dirname
+ "/" + name
+ ".nit").simplify_path
299 if try_file
.file_exists
then
300 if candidate
== null then
302 else if candidate
!= try_file
then
303 error
(anode
, "Error: conflicting module file for {name}: {candidate} {try_file}")
306 try_file
= (dirname
+ "/" + name
+ "/" + name
+ ".nit").simplify_path
307 if try_file
.file_exists
then
308 if candidate
== null then
310 else if candidate
!= try_file
then
311 error
(anode
, "Error: conflicting module file for {name}: {candidate} {try_file}")
315 if candidate
== null then
316 if origmmodule
!= null then
317 error
(anode
, "Error: cannot find module {name} from {origmmodule}. tried {tries.join(", ")}")
319 error
(anode
, "Error: cannot find module {name}. tried {tries.join(", ")}")
323 var res
= self.load_module
(mmodule
, candidate
)
324 if res
== null then return null # Forward error
325 return res
.mmodule
.as(not null)
328 # Try to load a module using a path.
329 # Display an error if there is a problem (IO / lexer / parser) and return null
330 # Note: usually, you do not need this method, use `get_mmodule_by_name` instead.
331 fun load_module
(owner
: nullable MModule, filename
: String): nullable AModule
333 if not filename
.file_exists
then
334 self.toolcontext
.error
(null, "Error: file {filename} not found.")
338 var x
= if owner
!= null then owner
.to_s
else "."
339 self.toolcontext
.info
("load module {filename} in {x}", 2)
342 var file
= new IFStream.open
(filename
)
343 var lexer
= new Lexer(new SourceFile(filename
, file
))
344 var parser
= new Parser(lexer
)
345 var tree
= parser
.parse
348 # Handle lexer and parser error
349 var nmodule
= tree
.n_base
350 if nmodule
== null then
351 var neof
= tree
.n_eof
352 assert neof
isa AError
353 error
(neof
, neof
.message
)
357 # Check the module name
358 var mod_name
= filename
.basename
(".nit")
359 var decl
= nmodule
.n_moduledecl
361 #warning(nmodule, "Warning: Missing 'module' keyword") #FIXME: NOT YET FOR COMPATIBILITY
363 var decl_name
= decl
.n_name
.n_id
.text
364 if decl_name
!= mod_name
then
365 error
(decl
.n_name
, "Error: module name missmatch; declared {decl_name} file named {mod_name}")
370 var mmodule
= new MModule(model
, owner
, mod_name
, nmodule
.location
)
371 nmodule
.mmodule
= mmodule
372 nmodules
.add
(nmodule
)
373 self.mmodule2nmodule
[mmodule
] = nmodule
375 build_module_importation
(nmodule
)
380 # Analysis the module importation and fill the module_importation_hierarchy
381 private fun build_module_importation
(nmodule
: AModule)
383 if nmodule
.is_importation_done
then return
384 nmodule
.is_importation_done
= true
385 var mmodule
= nmodule
.mmodule
.as(not null)
387 var imported_modules
= new Array[MModule]
388 for aimport
in nmodule
.n_imports
do
390 if not aimport
isa AStdImport then
393 var mod_name
= aimport
.n_name
.n_id
.text
394 var sup
= self.get_mmodule_by_name
(aimport
.n_name
, mmodule
, mod_name
)
395 if sup
== null then continue # Skip error
396 imported_modules
.add
(sup
)
397 var mvisibility
= aimport
.n_visibility
.mvisibility
398 mmodule
.set_visibility_for
(sup
, mvisibility
)
401 var mod_name
= "standard"
402 var sup
= self.get_mmodule_by_name
(nmodule
, null, mod_name
)
403 if sup
!= null then # Skip error
404 imported_modules
.add
(sup
)
405 mmodule
.set_visibility_for
(sup
, public_visibility
)
408 self.toolcontext
.info
("{mmodule} imports {imported_modules.join(", ")}", 3)
409 mmodule
.set_imported_mmodules
(imported_modules
)
412 # All the loaded modules
413 var nmodules
: Array[AModule] = new Array[AModule]
415 # Build the classes of all modules `nmodules'.
416 private fun build_all_classes
418 for nmodule
in self.nmodules
do
419 build_classes
(nmodule
)
423 # Visit the AST and create the MClass objects
424 private fun build_a_mclass
(nmodule
: AModule, nclassdef
: AClassdef)
426 var mmodule
= nmodule
.mmodule
.as(not null)
429 var nkind
: nullable AClasskind
430 var mkind
: MClassKind
431 var nvisibility
: nullable AVisibility
432 var mvisibility
: nullable MVisibility
434 if nclassdef
isa AStdClassdef then
435 name
= nclassdef
.n_id
.text
436 nkind
= nclassdef
.n_classkind
438 nvisibility
= nclassdef
.n_visibility
439 mvisibility
= nvisibility
.mvisibility
440 arity
= nclassdef
.n_formaldefs
.length
441 else if nclassdef
isa ATopClassdef then
444 mkind
= interface_kind
446 mvisibility
= public_visibility
447 else if nclassdef
isa AMainClassdef then
450 mkind
= concrete_kind
452 mvisibility
= public_visibility
457 var mclass
= try_get_mclass_by_name
(nclassdef
, mmodule
, name
)
458 if mclass
== null then
459 mclass
= new MClass(mmodule
, name
, arity
, mkind
, mvisibility
)
460 #print "new class {mclass}"
461 else if nclassdef
isa AStdClassdef and nmodule
.mclass2nclassdef
.has_key
(mclass
) then
462 error
(nclassdef
, "Error: A class {name} is already defined at line {nmodule.mclass2nclassdef[mclass].location.line_start}.")
464 else if nclassdef
isa AStdClassdef and nclassdef
.n_kwredef
== null then
465 error
(nclassdef
, "Redef error: {name} is an imported class. Add the redef keyword to refine it.")
467 else if mclass
.arity
!= arity
then
468 error
(nclassdef
, "Redef error: Formal parameter arity missmatch; got {arity}, expected {mclass.arity}.")
470 else if nkind
!= null and mkind
!= concrete_kind
and mclass
.kind
!= mkind
then
471 error
(nkind
, "Error: refinement changed the kind from a {mclass.kind} to a {mkind}")
472 else if nvisibility
!= null and mvisibility
!= public_visibility
and mclass
.visibility
!= mvisibility
then
473 error
(nvisibility
, "Error: refinement changed the visibility from a {mclass.visibility} to a {mvisibility}")
475 nclassdef
.mclass
= mclass
476 nmodule
.mclass2nclassdef
[mclass
] = nclassdef
479 # Visit the AST and create the MClassDef objects
480 private fun build_a_mclassdef
(nmodule
: AModule, nclassdef
: AClassdef)
482 var mmodule
= nmodule
.mmodule
.as(not null)
483 var objectclass
= try_get_mclass_by_name
(nmodule
, mmodule
, "Object")
484 var mclass
= nclassdef
.mclass
485 if mclass
== null then return # Skip error
486 #var mclassdef = nclassdef.mclassdef.as(not null)
488 var names
= new Array[String]
489 var bounds
= new Array[MType]
490 if nclassdef
isa AStdClassdef and mclass
.arity
> 0 then
491 # Collect formal parameter names
492 for i
in [0..mclass
.arity
[ do
493 var nfd
= nclassdef
.n_formaldefs
[i
]
494 var ptname
= nfd
.n_id
.text
495 if names
.has
(ptname
) then
496 error
(nfd
, "Error: A formal parameter type `{ptname}' already exists")
502 # Revolve bound for formal parameter names
503 for i
in [0..mclass
.arity
[ do
504 var nfd
= nclassdef
.n_formaldefs
[i
]
505 var nfdt
= nfd
.n_type
507 var bound
= resolve_mtype
(nclassdef
, nfdt
)
508 if bound
== null then return # Forward error
509 if bound
.need_anchor
then
511 error
(nfd
, "Error: Formal parameter type `{names[i]}' bounded with a formal parameter type")
515 else if mclass
.mclassdefs
.is_empty
then
516 # No bound, then implicitely bound by nullable Object
517 bounds
.add
(objectclass
.mclass_type
.as_nullable
)
520 bounds
.add
(mclass
.mclassdefs
.first
.bound_mtype
.arguments
[i
])
525 var bound_mtype
= mclass
.get_mtype
(bounds
)
526 var mclassdef
= new MClassDef(mmodule
, bound_mtype
, nclassdef
.location
, names
)
527 nclassdef
.mclassdef
= mclassdef
528 self.mclassdef2nclassdef
[mclassdef
] = nclassdef
530 if mclassdef
.is_intro
then
531 self.toolcontext
.info
("{mclassdef} introduces new {mclass.kind} {mclass.full_name}", 3)
533 self.toolcontext
.info
("{mclassdef} refine {mclass.kind} {mclass.full_name}", 3)
537 # Visit the AST and set the super-types of the MClassdef objects
538 private fun collect_a_mclassdef_inheritance
(nmodule
: AModule, nclassdef
: AClassdef)
540 var mmodule
= nmodule
.mmodule
.as(not null)
541 var objectclass
= try_get_mclass_by_name
(nmodule
, mmodule
, "Object")
542 var mclass
= nclassdef
.mclass
.as(not null)
543 var mclassdef
= nclassdef
.mclassdef
.as(not null)
545 var specobject
= true
546 var supertypes
= new Array[MClassType]
547 if nclassdef
isa AStdClassdef then
548 for nsc
in nclassdef
.n_superclasses
do
550 var ntype
= nsc
.n_type
551 var mtype
= resolve_mtype
(nclassdef
, ntype
)
552 if mtype
== null then continue # Skip because of error
553 if not mtype
isa MClassType then
554 error
(ntype
, "Error: supertypes cannot be a formal type")
558 #print "new super : {mclass} < {mtype}"
561 if specobject
and mclass
.name
!= "Object" and objectclass
!= null and mclassdef
.is_intro
then
562 supertypes
.add objectclass
.mclass_type
565 mclassdef
.set_supertypes
(supertypes
)
566 if not supertypes
.is_empty
then self.toolcontext
.info
("{mclassdef} new super-types: {supertypes.join(", ")}", 3)
569 # Check the validity of the specialization heirarchy
570 # FIXME Stub implementation
571 private fun check_supertypes
(nmodule
: AModule, nclassdef
: AClassdef)
573 var mmodule
= nmodule
.mmodule
.as(not null)
574 var objectclass
= try_get_mclass_by_name
(nmodule
, mmodule
, "Object")
575 var mclass
= nclassdef
.mclass
.as(not null)
576 var mclassdef
= nclassdef
.mclassdef
.as(not null)
579 # Build the classes of the module `nmodule'.
580 # REQUIRE: classes of imported modules are already build. (let `build_all_classes' do the job)
581 private fun build_classes
(nmodule
: AModule)
583 # Force building recursively
584 if nmodule
.build_classes_is_done
then return
585 nmodule
.build_classes_is_done
= true
586 var mmodule
= nmodule
.mmodule
.as(not null)
587 for imp
in mmodule
.in_importation
.direct_greaters
do
589 build_classes
(mmodule2nmodule
[imp
])
593 for nclassdef
in nmodule
.n_classdefs
do
594 self.build_a_mclass
(nmodule
, nclassdef
)
597 # Create all classdefs
598 for nclassdef
in nmodule
.n_classdefs
do
599 self.build_a_mclassdef
(nmodule
, nclassdef
)
602 for nclassdef
in nmodule
.n_classdefs
do
603 if nclassdef
.mclassdef
== null then return # forward error
606 # Create inheritance on all classdefs
607 for nclassdef
in nmodule
.n_classdefs
do
608 self.collect_a_mclassdef_inheritance
(nmodule
, nclassdef
)
611 # Create the mclassdef hierarchy
612 for nclassdef
in nmodule
.n_classdefs
do
613 var mclassdef
= nclassdef
.mclassdef
.as(not null)
614 mclassdef
.add_in_hierarchy
617 # TODO: Check that the super-class is not intrusive
619 # TODO: Check that the super-class is not already known (by transitivity)
621 for nclassdef
in nmodule
.n_classdefs
do
622 self.build_properties
(nclassdef
)
626 # Register the nmodule associated to each mmodule
627 # FIXME: why not refine the MModule class with a nullable attribute?
628 var mmodule2nmodule
: HashMap[MModule, AModule] = new HashMap[MModule, AModule]
629 # Register the nclassdef associated to each mclassdef
630 # FIXME: why not refine the MClassDef class with a nullable attribute?
631 var mclassdef2nclassdef
: HashMap[MClassDef, AClassdef] = new HashMap[MClassDef, AClassdef]
632 # Register the npropdef associated to each mpropdef
633 # FIXME: why not refine the MPropDef class with a nullable attribute?
634 var mpropdef2npropdef
: HashMap[MPropDef, APropdef] = new HashMap[MPropDef, APropdef]
636 # Build the properties of `nclassdef'.
637 # REQUIRE: all superclasses are built.
638 private fun build_properties
(nclassdef
: AClassdef)
640 # Force building recursively
641 if nclassdef
.build_properties_is_done
then return
642 nclassdef
.build_properties_is_done
= true
643 var mclassdef
= nclassdef
.mclassdef
.as(not null)
644 if mclassdef
.in_hierarchy
== null then return # Skip error
645 for superclassdef
in mclassdef
.in_hierarchy
.direct_greaters
do
646 build_properties
(mclassdef2nclassdef
[superclassdef
])
649 for npropdef
in nclassdef
.n_propdefs
do
650 npropdef
.build_property
(self, nclassdef
)
652 for npropdef
in nclassdef
.n_propdefs
do
653 npropdef
.build_signature
(self, nclassdef
)
655 for npropdef
in nclassdef
.n_propdefs
do
656 npropdef
.check_signature
(self, nclassdef
)
658 process_default_constructors
(nclassdef
)
661 # Introduce or inherit default constructor
662 # This is the last part of `build_properties'.
663 private fun process_default_constructors
(nclassdef
: AClassdef)
665 var mclassdef
= nclassdef
.mclassdef
.as(not null)
667 # Are we a refinement
668 if not mclassdef
.is_intro
then return
670 # Is the class forbid constructors?
671 if not mclassdef
.mclass
.kind
.need_init
then return
673 # Is there already a constructor defined?
674 for mpropdef
in mclassdef
.mpropdefs
do
675 if not mpropdef
isa MMethodDef then continue
676 if mpropdef
.mproperty
.is_init
then return
679 if not nclassdef
isa AStdClassdef then return
681 var mmodule
= nclassdef
.mclassdef
.mmodule
682 # Do we inherit for a constructor?
683 var combine
= new Array[MMethod]
684 var inhc
: nullable MClass = null
685 for st
in mclassdef
.supertypes
do
687 if not c
.kind
.need_init
then continue
688 st
= st
.anchor_to
(mmodule
, nclassdef
.mclassdef
.bound_mtype
)
689 var candidate
= self.try_get_mproperty_by_name2
(nclassdef
, mmodule
, st
, "init").as(nullable MMethod)
690 if candidate
!= null and candidate
.intro
.msignature
.arity
== 0 then
691 combine
.add
(candidate
)
694 var inhc2
= c
.inherit_init_from
695 if inhc2
== null then inhc2
= c
696 if inhc2
== inhc
then continue
698 self.error
(nclassdef
, "Error: Cannot provide a defaut constructor: conflict for {inhc} and {c}")
703 if combine
.is_empty
and inhc
!= null then
704 # TODO: actively inherit the consturctor
705 self.toolcontext
.info
("{mclassdef} inherits all constructors from {inhc}", 3)
706 mclassdef
.mclass
.inherit_init_from
= inhc
709 if not combine
.is_empty
and inhc
!= null then
710 self.error
(nclassdef
, "Error: Cannot provide a defaut constructor: conflict for {combine.join(", ")} and {inhc}")
714 if not combine
.is_empty
then
715 nclassdef
.super_inits
= combine
716 var mprop
= new MMethod(mclassdef
, "init", mclassdef
.mclass
.visibility
)
717 var mpropdef
= new MMethodDef(mclassdef
, mprop
, nclassdef
.location
)
718 var mparameters
= new Array[MParameter]
719 var msignature
= new MSignature(mparameters
, null)
720 mpropdef
.msignature
= msignature
722 nclassdef
.mfree_init
= mpropdef
723 self.toolcontext
.info
("{mclassdef} gets a free empty constructor {mpropdef}{msignature}", 3)
727 # Collect undefined attributes
728 var mparameters
= new Array[MParameter]
729 for npropdef
in nclassdef
.n_propdefs
do
730 if npropdef
isa AAttrPropdef and npropdef
.n_expr
== null then
731 var paramname
= npropdef
.mpropdef
.mproperty
.name
.substring_from
(1)
732 var ret_type
= npropdef
.mpropdef
.static_mtype
733 if ret_type
== null then return
734 var mparameter
= new MParameter(paramname
, ret_type
, false)
735 mparameters
.add
(mparameter
)
739 var mprop
= new MMethod(mclassdef
, "init", mclassdef
.mclass
.visibility
)
740 var mpropdef
= new MMethodDef(mclassdef
, mprop
, nclassdef
.location
)
741 var msignature
= new MSignature(mparameters
, null)
742 mpropdef
.msignature
= msignature
744 nclassdef
.mfree_init
= mpropdef
745 self.toolcontext
.info
("{mclassdef} gets a free constructor for attributes {mpropdef}{msignature}", 3)
748 # Return the static type associated to the node `ntype'.
749 # `classdef' is the context where the call is made (used to understand formal types)
750 # The mmodule used as context is `nclassdef.mmodule'
751 # In case of problem, an error is displayed on `ntype' and null is returned.
752 # FIXME: the name "resolve_mtype" is awful
753 fun resolve_mtype
(nclassdef
: AClassdef, ntype
: AType): nullable MType
755 var name
= ntype
.n_id
.text
756 var mclassdef
= nclassdef
.mclassdef
757 var mmodule
= nclassdef
.parent
.as(AModule).mmodule
.as(not null)
761 if mclassdef
!= null then
762 var prop
= try_get_mproperty_by_name
(ntype
, mclassdef
, name
).as(nullable MVirtualTypeProp)
764 if not ntype
.n_types
.is_empty
then
765 error
(ntype
, "Type error: formal type {name} cannot have formal parameters.")
767 res
= prop
.mvirtualtype
768 if ntype
.n_kwnullable
!= null then res
= res
.as_nullable
773 # Check parameter type
774 if mclassdef
!= null and mclassdef
.parameter_names
.has
(name
) then
775 if not ntype
.n_types
.is_empty
then
776 error
(ntype
, "Type error: formal type {name} cannot have formal parameters.")
778 for i
in [0..mclassdef
.parameter_names
.length
[ do
779 if mclassdef
.parameter_names
[i
] == name
then
780 res
= mclassdef
.mclass
.mclass_type
.arguments
[i
]
781 if ntype
.n_kwnullable
!= null then res
= res
.as_nullable
789 var mclass
= try_get_mclass_by_name
(ntype
, mmodule
, name
)
790 if mclass
!= null then
791 var arity
= ntype
.n_types
.length
792 if arity
!= mclass
.arity
then
794 error
(ntype
, "Type error: '{name}' is a generic class.")
795 else if mclass
.arity
== 0 then
796 error
(ntype
, "Type error: '{name}' is not a generic class.")
798 error
(ntype
, "Type error: '{name}' has {mclass.arity} parameters ({arity} are provided).")
803 res
= mclass
.mclass_type
804 if ntype
.n_kwnullable
!= null then res
= res
.as_nullable
807 var mtypes
= new Array[MType]
808 for nt
in ntype
.n_types
do
809 var mt
= resolve_mtype
(nclassdef
, nt
)
810 if mt
== null then return null # Forward error
813 res
= mclass
.get_mtype
(mtypes
)
814 if ntype
.n_kwnullable
!= null then res
= res
.as_nullable
819 # If everything fail, then give up :(
820 error
(ntype
, "Type error: class {name} not found in module {mmodule}.")
824 # Helper function to display an error on a node.
825 # Alias for `self.toolcontext.error(n.hot_location, text)'
826 fun error
(n
: ANode, text
: String)
828 self.toolcontext
.error
(n
.hot_location
, text
)
831 # Helper function to display a warning on a node.
832 # Alias for: `self.toolcontext.warning(n.hot_location, text)'
833 fun warning
(n
: ANode, text
: String)
835 self.toolcontext
.warning
(n
.hot_location
, text
)
838 # Force to get the primitive method named `name' on the type `recv' or do a fatal error on `n'
839 fun force_get_primitive_method
(n
: ANode, name
: String, recv
: MType, mmodule
: MModule): MMethod
841 var res
= mmodule
.try_get_primitive_method
(name
, recv
)
843 self.toolcontext
.fatal_error
(n
.hot_location
, "Fatal Error: {recv} must have a property named {name}.")
851 # The associated MModule once build by a `ModelBuilder'
852 var mmodule
: nullable MModule
853 # Flag that indicate if the importation is already completed
854 var is_importation_done
: Bool = false
855 # Flag that indicate if the class and prop building is already completed
856 var build_classes_is_done
: Bool = false
857 # What is the AClassdef associated to a MClass?
858 # Used to check multiple definition of a class.
859 var mclass2nclassdef
: Map[MClass, AClassdef] = new HashMap[MClass, AClassdef]
864 # The class whose self inherit all the constructors.
865 # 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
866 var inherit_init_from
: nullable MClass = null
869 redef class AClassdef
870 # The associated MClass once build by a `ModelBuilder'
871 var mclass
: nullable MClass
872 # The associated MClassDef once build by a `ModelBuilder'
873 var mclassdef
: nullable MClassDef
874 var build_properties_is_done
: Bool = false
875 # The list of super-constructor to call at the start of the free constructor
876 # 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
877 var super_inits
: nullable Collection[MMethod] = null
879 # The free init (implicitely constructed by the class if required)
880 var mfree_init
: nullable MMethodDef = null
883 redef class AClasskind
884 # The class kind associated with the AST node class
885 private fun mkind
: MClassKind is abstract
887 redef class AConcreteClasskind
888 redef fun mkind
do return concrete_kind
890 redef class AAbstractClasskind
891 redef fun mkind
do return abstract_kind
893 redef class AInterfaceClasskind
894 redef fun mkind
do return interface_kind
896 redef class AEnumClasskind
897 redef fun mkind
do return enum_kind
899 redef class AExternClasskind
900 redef fun mkind
do return extern_kind
903 redef class AVisibility
904 # The visibility level associated with the AST node class
905 private fun mvisibility
: MVisibility is abstract
907 redef class AIntrudeVisibility
908 redef fun mvisibility
do return intrude_visibility
910 redef class APublicVisibility
911 redef fun mvisibility
do return public_visibility
913 redef class AProtectedVisibility
914 redef fun mvisibility
do return protected_visibility
916 redef class APrivateVisibility
917 redef fun mvisibility
do return private_visibility
924 # Join the text of all tokens
925 # Used to get the 'real name' of method definitions.
926 fun collect_text
: String
928 var v
= new TextCollectorVisitor
935 private class TextCollectorVisitor
937 var text
: String = ""
940 if n
isa Token then text
+= n
.text
946 private fun build_property
(modelbuilder
: ModelBuilder, nclassdef
: AClassdef)
949 private fun build_signature
(modelbuilder
: ModelBuilder, nclassdef
: AClassdef)
952 private fun check_signature
(modelbuilder
: ModelBuilder, nclassdef
: AClassdef)
955 private fun new_property_visibility
(modelbuilder
: ModelBuilder, nclassdef
: AClassdef, nvisibility
: nullable AVisibility): MVisibility
957 var mvisibility
= public_visibility
958 if nvisibility
!= null then mvisibility
= nvisibility
.mvisibility
959 if nclassdef
.mclassdef
.mclass
.visibility
== private_visibility
then
960 if mvisibility
== protected_visibility
then
961 assert nvisibility
!= null
962 modelbuilder
.error
(nvisibility
, "Error: The only legal visibility for properties in a private class is private.")
963 else if mvisibility
== private_visibility
then
964 assert nvisibility
!= null
966 # modelbuilder.warning(nvisibility, "Warning: private is unrequired since the only legal visibility for properties in a private class is private.")
968 mvisibility
= private_visibility
973 private fun check_redef_property_visibility
(modelbuilder
: ModelBuilder, nclassdef
: AClassdef, nvisibility
: nullable AVisibility, mprop
: MProperty)
975 if nvisibility
== null then return
976 var mvisibility
= nvisibility
.mvisibility
977 if mvisibility
!= mprop
.visibility
and mvisibility
!= public_visibility
then
978 modelbuilder
.error
(nvisibility
, "Error: redefinition changed the visibility from a {mprop.visibility} to a {mvisibility}")
982 private fun check_redef_keyword
(modelbuilder
: ModelBuilder, nclassdef
: AClassdef, kwredef
: nullable Token, need_redef
: Bool, mprop
: MProperty)
984 if kwredef
== null then
986 modelbuilder
.error
(self, "Redef error: {nclassdef.mclassdef.mclass}::{mprop.name} is an inherited property. To redefine it, add the redef keyword.")
989 if not need_redef
then
990 modelbuilder
.error
(self, "Error: No property {nclassdef.mclassdef.mclass}::{mprop.name} is inherited. Remove the redef keyword to define a new property.")
997 redef class ASignature
998 # Is the model builder has correctly visited the signature
999 var is_visited
= false
1000 # Names of parameters from the AST
1001 # REQUIRE: is_visited
1002 var param_names
= new Array[String]
1003 # Types of parameters from the AST
1004 # REQUIRE: is_visited
1005 var param_types
= new Array[MType]
1006 # Rank of the vararg (of -1 if none)
1007 # REQUIRE: is_visited
1008 var vararg_rank
: Int = -1
1010 var ret_type
: nullable MType = null
1012 # Visit and fill information about a signature
1013 private fun visit_signature
(modelbuilder
: ModelBuilder, nclassdef
: AClassdef): Bool
1015 var param_names
= self.param_names
1016 var param_types
= self.param_types
1017 for np
in self.n_params
do
1018 param_names
.add
(np
.n_id
.text
)
1019 var ntype
= np
.n_type
1020 if ntype
!= null then
1021 var mtype
= modelbuilder
.resolve_mtype
(nclassdef
, ntype
)
1022 if mtype
== null then return false # Skip error
1023 for i
in [0..param_names
.length-param_types
.length
[ do
1024 param_types
.add
(mtype
)
1026 if np
.n_dotdotdot
!= null then
1027 if self.vararg_rank
!= -1 then
1028 modelbuilder
.error
(np
, "Error: {param_names[self.vararg_rank]} is already a vararg")
1031 self.vararg_rank
= param_names
.length
- 1
1036 var ntype
= self.n_type
1037 if ntype
!= null then
1038 self.ret_type
= modelbuilder
.resolve_mtype
(nclassdef
, ntype
)
1039 if self.ret_type
== null then return false # Skip errir
1042 for nclosure
in self.n_closure_decls
do
1043 if not nclosure
.n_signature
.visit_signature
(modelbuilder
, nclassdef
) then return false
1046 self.is_visited
= true
1050 # Build a visited signature
1051 fun build_signature
(modelbuilder
: ModelBuilder, nclassdef
: AClassdef): nullable MSignature
1053 if param_names
.length
!= param_types
.length
then
1054 # Some parameters are typed, other parameters are not typed.
1055 modelbuilder
.error
(self.n_params
[param_types
.length
], "Error: Untyped parameter `{param_names[param_types.length]}'.")
1059 var mparameters
= new Array[MParameter]
1060 for i
in [0..param_names
.length
[ do
1061 var mparameter
= new MParameter(param_names
[i
], param_types
[i
], i
== vararg_rank
)
1062 mparameters
.add
(mparameter
)
1065 var msignature
= new MSignature(mparameters
, ret_type
)
1070 redef class AMethPropdef
1071 # The associated MMethodDef once build by a `ModelBuilder'
1072 var mpropdef
: nullable MMethodDef
1074 # The associated super init if any
1075 var super_init
: nullable MMethod
1076 redef fun build_property
(modelbuilder
, nclassdef
)
1078 var is_init
= self isa AInitPropdef
1079 var mclassdef
= nclassdef
.mclassdef
.as(not null)
1081 var amethodid
= self.n_methid
1082 var name_node
: ANode
1083 if amethodid
== null then
1084 if self isa AMainMethPropdef then
1087 else if self isa AConcreteInitPropdef then
1089 name_node
= self.n_kwinit
1090 else if self isa AExternInitPropdef then
1092 name_node
= self.n_kwnew
1096 else if amethodid
isa AIdMethid then
1097 name
= amethodid
.n_id
.text
1098 name_node
= amethodid
1100 # operator, bracket or assign
1101 name
= amethodid
.collect_text
1102 name_node
= amethodid
1104 if name
== "-" and self.n_signature
.n_params
.length
== 0 then
1109 var mprop
: nullable MMethod = null
1110 if not is_init
or n_kwredef
!= null then mprop
= modelbuilder
.try_get_mproperty_by_name
(name_node
, mclassdef
, name
).as(nullable MMethod)
1111 if mprop
== null then
1112 var mvisibility
= new_property_visibility
(modelbuilder
, nclassdef
, self.n_visibility
)
1113 mprop
= new MMethod(mclassdef
, name
, mvisibility
)
1114 mprop
.is_init
= is_init
1115 mprop
.is_new
= self isa AExternInitPropdef
1116 self.check_redef_keyword
(modelbuilder
, nclassdef
, n_kwredef
, false, mprop
)
1118 if n_kwredef
== null then
1119 if self isa AMainMethPropdef then
1122 self.check_redef_keyword
(modelbuilder
, nclassdef
, n_kwredef
, true, mprop
)
1125 check_redef_property_visibility
(modelbuilder
, nclassdef
, self.n_visibility
, mprop
)
1128 var mpropdef
= new MMethodDef(mclassdef
, mprop
, self.location
)
1130 self.mpropdef
= mpropdef
1131 modelbuilder
.mpropdef2npropdef
[mpropdef
] = self
1132 if mpropdef
.is_intro
then
1133 modelbuilder
.toolcontext
.info
("{mpropdef} introduces new method {mprop.full_name}", 3)
1135 modelbuilder
.toolcontext
.info
("{mpropdef} redefines method {mprop.full_name}", 3)
1139 redef fun build_signature
(modelbuilder
, nclassdef
)
1141 var mpropdef
= self.mpropdef
1142 if mpropdef
== null then return # Error thus skiped
1143 var mmodule
= mpropdef
.mclassdef
.mmodule
1144 var nsig
= self.n_signature
1146 # Retrieve info from the signature AST
1147 var param_names
= new Array[String] # Names of parameters from the AST
1148 var param_types
= new Array[MType] # Types of parameters from the AST
1149 var vararg_rank
= -1
1150 var ret_type
: nullable MType = null # Return type from the AST
1151 if nsig
!= null then
1152 if not nsig
.visit_signature
(modelbuilder
, nclassdef
) then return
1153 param_names
= nsig
.param_names
1154 param_types
= nsig
.param_types
1155 vararg_rank
= nsig
.vararg_rank
1156 ret_type
= nsig
.ret_type
1159 # Look for some signature to inherit
1160 # FIXME: do not inherit from the intro, but from the most specific
1161 var msignature
: nullable MSignature = null
1162 if not mpropdef
.is_intro
then
1163 msignature
= mpropdef
.mproperty
.intro
.msignature
1164 if msignature
== null then return # Skip error
1166 # Check inherited signature arity
1167 if param_names
.length
!= msignature
.arity
then
1169 if nsig
!= null then node
= nsig
else node
= self
1170 modelbuilder
.error
(node
, "Redef error: {mpropdef} redefines {mpropdef.mproperty.intro} with {param_names.length} parameter(s), {msignature.arity} expected. Signature is {mpropdef}{msignature}")
1173 else if mpropdef
.mproperty
.is_init
then
1174 # FIXME UGLY: inherit signature from a super-constructor
1175 for msupertype
in nclassdef
.mclassdef
.supertypes
do
1176 msupertype
= msupertype
.anchor_to
(mmodule
, nclassdef
.mclassdef
.bound_mtype
)
1177 var candidate
= modelbuilder
.try_get_mproperty_by_name2
(self, mmodule
, msupertype
, mpropdef
.mproperty
.name
)
1178 if candidate
!= null then
1179 if msignature
== null then
1180 msignature
= candidate
.intro
.as(MMethodDef).msignature
1187 # Inherit the signature
1188 if msignature
!= null and param_names
.length
!= param_types
.length
and param_names
.length
== msignature
.arity
and param_types
.length
== 0 then
1189 # Parameters are untyped, thus inherit them
1190 param_types
= new Array[MType]
1191 for mparameter
in msignature
.mparameters
do
1192 param_types
.add
(mparameter
.mtype
)
1194 vararg_rank
= msignature
.vararg_rank
1196 if msignature
!= null and ret_type
== null then
1197 ret_type
= msignature
.return_mtype
1200 if param_names
.length
!= param_types
.length
then
1201 # Some parameters are typed, other parameters are not typed.
1202 modelbuilder
.error
(nsig
.n_params
[param_types
.length
], "Error: Untyped parameter `{param_names[param_types.length]}'.")
1206 var mparameters
= new Array[MParameter]
1207 for i
in [0..param_names
.length
[ do
1208 var mparameter
= new MParameter(param_names
[i
], param_types
[i
], i
== vararg_rank
)
1209 mparameters
.add
(mparameter
)
1212 msignature
= new MSignature(mparameters
, ret_type
)
1213 mpropdef
.msignature
= msignature
1215 if nsig
!= null then
1216 for nclosure
in nsig
.n_closure_decls
do
1217 var clos_signature
= nclosure
.n_signature
.build_signature
(modelbuilder
, nclassdef
)
1218 if clos_signature
== null then return
1219 var mparameter
= new MParameter(nclosure
.n_id
.text
, clos_signature
, false)
1220 msignature
.mclosures
.add
(mparameter
)
1226 redef fun check_signature
(modelbuilder
, nclassdef
)
1228 var mpropdef
= self.mpropdef
1229 if mpropdef
== null then return # Error thus skiped
1230 var mmodule
= mpropdef
.mclassdef
.mmodule
1231 var nsig
= self.n_signature
1232 var mysignature
= self.mpropdef
.msignature
1233 if mysignature
== null then return # Error thus skiped
1235 # Lookup for signature in the precursor
1236 # FIXME all precursors should be considered
1237 if not mpropdef
.is_intro
then
1238 var msignature
= mpropdef
.mproperty
.intro
.msignature
1239 if msignature
== null then return
1241 var precursor_ret_type
= msignature
.return_mtype
1242 var ret_type
= mysignature
.return_mtype
1243 if ret_type
!= null and precursor_ret_type
== null then
1244 modelbuilder
.error
(nsig
.n_type
.as(not null), "Redef Error: {mpropdef.mproperty} is a procedure, not a function.")
1248 if mysignature
.arity
> 0 then
1249 # Check parameters types
1250 for i
in [0..mysignature
.arity
[ do
1251 var myt
= mysignature
.mparameters
[i
].mtype
1252 var prt
= msignature
.mparameters
[i
].mtype
1253 if not myt
.is_subtype
(mmodule
, nclassdef
.mclassdef
.bound_mtype
, prt
) and
1254 not prt
.is_subtype
(mmodule
, nclassdef
.mclassdef
.bound_mtype
, myt
) then
1255 modelbuilder
.error
(nsig
.n_params
[i
], "Redef Error: Wrong type for parameter `{mysignature.mparameters[i].name}'. found {myt}, expected {prt}.")
1259 if precursor_ret_type
!= null then
1260 if ret_type
== null then
1261 # Inherit the return type
1262 ret_type
= precursor_ret_type
1263 else if not ret_type
.is_subtype
(mmodule
, nclassdef
.mclassdef
.bound_mtype
, precursor_ret_type
) then
1264 modelbuilder
.error
(nsig
.n_type
.as(not null), "Redef Error: Wrong return type. found {ret_type}, expected {precursor_ret_type}.")
1271 redef class AAttrPropdef
1272 # The associated MAttributeDef once build by a `ModelBuilder'
1273 var mpropdef
: nullable MAttributeDef
1274 # The associated getter (read accessor) if any
1275 var mreadpropdef
: nullable MMethodDef
1276 # The associated setter (write accessor) if any
1277 var mwritepropdef
: nullable MMethodDef
1278 redef fun build_property
(modelbuilder
, nclassdef
)
1280 var mclassdef
= nclassdef
.mclassdef
.as(not null)
1281 var mclass
= mclassdef
.mclass
1284 if self.n_id
!= null then
1285 name
= self.n_id
.text
1287 name
= self.n_id2
.text
1290 if mclass
.kind
== interface_kind
or mclassdef
.mclass
.kind
== enum_kind
then
1291 modelbuilder
.error
(self, "Error: Attempt to define attribute {name} in the interface {mclass}.")
1292 else if mclass
.kind
== enum_kind
then
1293 modelbuilder
.error
(self, "Error: Attempt to define attribute {name} in the enum class {mclass}.")
1298 # Old attribute style
1299 var mprop
= modelbuilder
.try_get_mproperty_by_name
(nid
, mclassdef
, name
)
1300 if mprop
== null then
1301 var mvisibility
= new_property_visibility
(modelbuilder
, nclassdef
, self.n_visibility
)
1302 mprop
= new MAttribute(mclassdef
, name
, mvisibility
)
1303 self.check_redef_keyword
(modelbuilder
, nclassdef
, self.n_kwredef
, false, mprop
)
1305 assert mprop
isa MAttribute
1306 check_redef_property_visibility
(modelbuilder
, nclassdef
, self.n_visibility
, mprop
)
1307 self.check_redef_keyword
(modelbuilder
, nclassdef
, self.n_kwredef
, true, mprop
)
1309 var mpropdef
= new MAttributeDef(mclassdef
, mprop
, self.location
)
1310 self.mpropdef
= mpropdef
1311 modelbuilder
.mpropdef2npropdef
[mpropdef
] = self
1313 var nreadable
= self.n_readable
1314 if nreadable
!= null then
1315 var readname
= name
.substring_from
(1)
1316 var mreadprop
= modelbuilder
.try_get_mproperty_by_name
(nid
, mclassdef
, readname
).as(nullable MMethod)
1317 if mreadprop
== null then
1318 var mvisibility
= new_property_visibility
(modelbuilder
, nclassdef
, nreadable
.n_visibility
)
1319 mreadprop
= new MMethod(mclassdef
, readname
, mvisibility
)
1320 self.check_redef_keyword
(modelbuilder
, nclassdef
, nreadable
.n_kwredef
, false, mreadprop
)
1322 self.check_redef_keyword
(modelbuilder
, nclassdef
, nreadable
.n_kwredef
, true, mreadprop
)
1323 check_redef_property_visibility
(modelbuilder
, nclassdef
, nreadable
.n_visibility
, mreadprop
)
1325 var mreadpropdef
= new MMethodDef(mclassdef
, mreadprop
, self.location
)
1326 self.mreadpropdef
= mreadpropdef
1327 modelbuilder
.mpropdef2npropdef
[mreadpropdef
] = self
1330 var nwritable
= self.n_writable
1331 if nwritable
!= null then
1332 var writename
= name
.substring_from
(1) + "="
1333 var mwriteprop
= modelbuilder
.try_get_mproperty_by_name
(nid
, mclassdef
, writename
).as(nullable MMethod)
1334 if mwriteprop
== null then
1335 var mvisibility
= new_property_visibility
(modelbuilder
, nclassdef
, nwritable
.n_visibility
)
1336 mwriteprop
= new MMethod(mclassdef
, writename
, mvisibility
)
1337 self.check_redef_keyword
(modelbuilder
, nclassdef
, nwritable
.n_kwredef
, false, mwriteprop
)
1339 self.check_redef_keyword
(modelbuilder
, nclassdef
, nwritable
.n_kwredef
, true, mwriteprop
)
1340 check_redef_property_visibility
(modelbuilder
, nclassdef
, nwritable
.n_visibility
, mwriteprop
)
1342 var mwritepropdef
= new MMethodDef(mclassdef
, mwriteprop
, self.location
)
1343 self.mwritepropdef
= mwritepropdef
1344 modelbuilder
.mpropdef2npropdef
[mwritepropdef
] = self
1347 # New attribute style
1348 var nid2
= self.n_id2
.as(not null)
1349 var mprop
= new MAttribute(mclassdef
, "@" + name
, none_visibility
)
1350 var mpropdef
= new MAttributeDef(mclassdef
, mprop
, self.location
)
1351 self.mpropdef
= mpropdef
1352 modelbuilder
.mpropdef2npropdef
[mpropdef
] = self
1355 var mreadprop
= modelbuilder
.try_get_mproperty_by_name
(nid2
, mclassdef
, readname
).as(nullable MMethod)
1356 if mreadprop
== null then
1357 var mvisibility
= new_property_visibility
(modelbuilder
, nclassdef
, self.n_visibility
)
1358 mreadprop
= new MMethod(mclassdef
, readname
, mvisibility
)
1359 self.check_redef_keyword
(modelbuilder
, nclassdef
, n_kwredef
, false, mreadprop
)
1361 self.check_redef_keyword
(modelbuilder
, nclassdef
, n_kwredef
, true, mreadprop
)
1362 check_redef_property_visibility
(modelbuilder
, nclassdef
, self.n_visibility
, mreadprop
)
1364 var mreadpropdef
= new MMethodDef(mclassdef
, mreadprop
, self.location
)
1365 self.mreadpropdef
= mreadpropdef
1366 modelbuilder
.mpropdef2npropdef
[mreadpropdef
] = self
1368 var writename
= name
+ "="
1369 var nwritable
= self.n_writable
1370 var mwriteprop
= modelbuilder
.try_get_mproperty_by_name
(nid2
, mclassdef
, writename
).as(nullable MMethod)
1371 var nwkwredef
: nullable Token = null
1372 if nwritable
!= null then nwkwredef
= nwritable
.n_kwredef
1373 if mwriteprop
== null then
1375 if nwritable
!= null then
1376 mvisibility
= new_property_visibility
(modelbuilder
, nclassdef
, nwritable
.n_visibility
)
1378 mvisibility
= private_visibility
1380 mwriteprop
= new MMethod(mclassdef
, writename
, mvisibility
)
1381 self.check_redef_keyword
(modelbuilder
, nclassdef
, nwkwredef
, false, mwriteprop
)
1383 self.check_redef_keyword
(modelbuilder
, nclassdef
, nwkwredef
, true, mwriteprop
)
1384 if nwritable
!= null then
1385 check_redef_property_visibility
(modelbuilder
, nclassdef
, nwritable
.n_visibility
, mwriteprop
)
1388 var mwritepropdef
= new MMethodDef(mclassdef
, mwriteprop
, self.location
)
1389 self.mwritepropdef
= mwritepropdef
1390 modelbuilder
.mpropdef2npropdef
[mwritepropdef
] = self
1394 redef fun build_signature
(modelbuilder
, nclassdef
)
1396 var mpropdef
= self.mpropdef
1397 if mpropdef
== null then return # Error thus skiped
1398 var mmodule
= mpropdef
.mclassdef
.mmodule
1399 var mtype
: nullable MType = null
1401 var ntype
= self.n_type
1402 if ntype
!= null then
1403 mtype
= modelbuilder
.resolve_mtype
(nclassdef
, ntype
)
1404 if mtype
== null then return
1407 if mtype
== null then
1408 var nexpr
= self.n_expr
1409 if nexpr
!= null then
1410 if nexpr
isa ANewExpr then
1411 mtype
= modelbuilder
.resolve_mtype
(nclassdef
, nexpr
.n_type
)
1412 else if nexpr
isa AIntExpr then
1413 var cla
= modelbuilder
.try_get_mclass_by_name
(nexpr
, mmodule
, "Int")
1414 if cla
!= null then mtype
= cla
.mclass_type
1415 else if nexpr
isa AFloatExpr then
1416 var cla
= modelbuilder
.try_get_mclass_by_name
(nexpr
, mmodule
, "Float")
1417 if cla
!= null then mtype
= cla
.mclass_type
1418 else if nexpr
isa ACharExpr then
1419 var cla
= modelbuilder
.try_get_mclass_by_name
(nexpr
, mmodule
, "Char")
1420 if cla
!= null then mtype
= cla
.mclass_type
1421 else if nexpr
isa ABoolExpr then
1422 var cla
= modelbuilder
.try_get_mclass_by_name
(nexpr
, mmodule
, "Bool")
1423 if cla
!= null then mtype
= cla
.mclass_type
1424 else if nexpr
isa ASuperstringExpr then
1425 var cla
= modelbuilder
.try_get_mclass_by_name
(nexpr
, mmodule
, "String")
1426 if cla
!= null then mtype
= cla
.mclass_type
1427 else if nexpr
isa AStringFormExpr then
1428 var cla
= modelbuilder
.try_get_mclass_by_name
(nexpr
, mmodule
, "String")
1429 if cla
!= null then mtype
= cla
.mclass_type
1431 modelbuilder
.error
(self, "Error: Untyped attribute {mpropdef}. Implicit typing allowed only for literals and new.")
1435 modelbuilder
.error
(self, "Error: Untyped attribute {mpropdef}")
1439 if mtype
== null then return
1441 mpropdef
.static_mtype
= mtype
1443 var mreadpropdef
= self.mreadpropdef
1444 if mreadpropdef
!= null then
1445 var msignature
= new MSignature(new Array[MParameter], mtype
)
1446 mreadpropdef
.msignature
= msignature
1449 var msritepropdef
= self.mwritepropdef
1450 if mwritepropdef
!= null then
1452 if n_id
!= null then
1453 name
= n_id
.text
.substring_from
(1)
1457 var mparameter
= new MParameter(name
, mtype
, false)
1458 var msignature
= new MSignature([mparameter
], null)
1459 mwritepropdef
.msignature
= msignature
1463 redef fun check_signature
(modelbuilder
, nclassdef
)
1465 var mpropdef
= self.mpropdef
1466 if mpropdef
== null then return # Error thus skiped
1467 var mmodule
= mpropdef
.mclassdef
.mmodule
1468 var ntype
= self.n_type
1469 var mtype
= self.mpropdef
.static_mtype
1470 if mtype
== null then return # Error thus skiped
1472 # Lookup for signature in the precursor
1473 # FIXME all precursors should be considered
1474 if not mpropdef
.is_intro
then
1475 var precursor_type
= mpropdef
.mproperty
.intro
.static_mtype
1476 if precursor_type
== null then return
1478 if mtype
!= precursor_type
then
1479 modelbuilder
.error
(ntype
.as(not null), "Redef Error: Wrong static type. found {mtype}, expected {precursor_type}.")
1484 # Check getter and setter
1485 var meth
= self.mreadpropdef
1486 if meth
!= null then self.check_method_signature
(modelbuilder
, nclassdef
, meth
)
1487 meth
= self.mwritepropdef
1488 if meth
!= null then self.check_method_signature
(modelbuilder
, nclassdef
, meth
)
1491 private fun check_method_signature
(modelbuilder
: ModelBuilder, nclassdef
: AClassdef, mpropdef
: MMethodDef)
1493 var mmodule
= mpropdef
.mclassdef
.mmodule
1494 var nsig
= self.n_type
1495 var mysignature
= mpropdef
.msignature
1496 if mysignature
== null then return # Error thus skiped
1498 # Lookup for signature in the precursor
1499 # FIXME all precursors should be considered
1500 if not mpropdef
.is_intro
then
1501 var msignature
= mpropdef
.mproperty
.intro
.msignature
1502 if msignature
== null then return
1504 if mysignature
.arity
!= msignature
.arity
then
1506 if nsig
!= null then node
= nsig
else node
= self
1507 modelbuilder
.error
(node
, "Redef Error: {mysignature.arity} parameters found, {msignature.arity} expected. Signature is {mpropdef}{msignature}")
1510 var precursor_ret_type
= msignature
.return_mtype
1511 var ret_type
= mysignature
.return_mtype
1512 if ret_type
!= null and precursor_ret_type
== null then
1514 if nsig
!= null then node
= nsig
else node
= self
1515 modelbuilder
.error
(node
, "Redef Error: {mpropdef.mproperty} is a procedure, not a function.")
1519 if mysignature
.arity
> 0 then
1520 # Check parameters types
1521 for i
in [0..mysignature
.arity
[ do
1522 var myt
= mysignature
.mparameters
[i
].mtype
1523 var prt
= msignature
.mparameters
[i
].mtype
1524 if not myt
.is_subtype
(mmodule
, nclassdef
.mclassdef
.bound_mtype
, prt
) and
1525 not prt
.is_subtype
(mmodule
, nclassdef
.mclassdef
.bound_mtype
, myt
) then
1527 if nsig
!= null then node
= nsig
else node
= self
1528 modelbuilder
.error
(node
, "Redef Error: Wrong type for parameter `{mysignature.mparameters[i].name}'. found {myt}, expected {prt}.")
1532 if precursor_ret_type
!= null then
1533 if ret_type
== null then
1534 # Inherit the return type
1535 ret_type
= precursor_ret_type
1536 else if not ret_type
.is_subtype
(mmodule
, nclassdef
.mclassdef
.bound_mtype
, precursor_ret_type
) then
1538 if nsig
!= null then node
= nsig
else node
= self
1539 modelbuilder
.error
(node
, "Redef Error: Wrong return type. found {ret_type}, expected {precursor_ret_type}.")
1546 redef class ATypePropdef
1547 # The associated MVirtualTypeDef once build by a `ModelBuilder'
1548 var mpropdef
: nullable MVirtualTypeDef
1549 redef fun build_property
(modelbuilder
, nclassdef
)
1551 var mclassdef
= nclassdef
.mclassdef
.as(not null)
1552 var name
= self.n_id
.text
1553 var mprop
= modelbuilder
.try_get_mproperty_by_name
(self.n_id
, mclassdef
, name
)
1554 if mprop
== null then
1555 var mvisibility
= new_property_visibility
(modelbuilder
, nclassdef
, self.n_visibility
)
1556 mprop
= new MVirtualTypeProp(mclassdef
, name
, mvisibility
)
1557 self.check_redef_keyword
(modelbuilder
, nclassdef
, self.n_kwredef
, false, mprop
)
1559 self.check_redef_keyword
(modelbuilder
, nclassdef
, self.n_kwredef
, true, mprop
)
1560 assert mprop
isa MVirtualTypeProp
1561 check_redef_property_visibility
(modelbuilder
, nclassdef
, self.n_visibility
, mprop
)
1563 var mpropdef
= new MVirtualTypeDef(mclassdef
, mprop
, self.location
)
1564 self.mpropdef
= mpropdef
1567 redef fun build_signature
(modelbuilder
, nclassdef
)
1569 var mpropdef
= self.mpropdef
1570 if mpropdef
== null then return # Error thus skiped
1571 var mmodule
= mpropdef
.mclassdef
.mmodule
1572 var mtype
: nullable MType = null
1574 var ntype
= self.n_type
1575 mtype
= modelbuilder
.resolve_mtype
(nclassdef
, ntype
)
1576 if mtype
== null then return
1578 mpropdef
.bound
= mtype
1579 # print "{mpropdef}: {mtype}"
1582 redef fun check_signature
(modelbuilder
, nclassdef
)
1584 var bound
= self.mpropdef
.bound
1586 # Fast case: the bound is not a formal type
1587 if not bound
isa MVirtualType then return
1589 var mmodule
= nclassdef
.mclassdef
.mmodule
1590 var anchor
= nclassdef
.mclassdef
.bound_mtype
1592 # Slow case: progress on each resolution until: (i) we loop, or (ii) we found a non formal type
1593 var seen
= [self.mpropdef
.mproperty
.mvirtualtype
]
1595 if seen
.has
(bound
) then
1597 modelbuilder
.error
(self, "Error: circularity of virtual type definition: {seen.join(" -> ")}")
1601 var next
= bound
.lookup_bound
(mmodule
, anchor
)
1602 if not next
isa MVirtualType then return