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 var mmodule
= nmodule
.mmodule
.as(not null)
386 var imported_modules
= new Array[MModule]
387 for aimport
in nmodule
.n_imports
do
389 if not aimport
isa AStdImport then
392 var mod_name
= aimport
.n_name
.n_id
.text
393 var sup
= self.get_mmodule_by_name
(aimport
.n_name
, mmodule
, mod_name
)
394 if sup
== null then continue # Skip error
395 imported_modules
.add
(sup
)
396 var mvisibility
= aimport
.n_visibility
.mvisibility
397 mmodule
.set_visibility_for
(sup
, mvisibility
)
400 var mod_name
= "standard"
401 var sup
= self.get_mmodule_by_name
(nmodule
, null, mod_name
)
402 if sup
!= null then # Skip error
403 imported_modules
.add
(sup
)
404 mmodule
.set_visibility_for
(sup
, public_visibility
)
407 self.toolcontext
.info
("{mmodule} imports {imported_modules.join(", ")}", 3)
408 mmodule
.set_imported_mmodules
(imported_modules
)
409 nmodule
.is_importation_done
= true
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 nclassdef
.n_kwredef
== null then
462 error
(nclassdef
, "Redef error: {name} is an imported class. Add the redef keyword to refine it.")
464 else if mclass
.arity
!= arity
then
465 error
(nclassdef
, "Redef error: Formal parameter arity missmatch; got {arity}, expected {mclass.arity}.")
467 else if nkind
!= null and mkind
!= concrete_kind
and mclass
.kind
!= mkind
then
468 error
(nkind
, "Error: refinement changed the kind from a {mclass.kind} to a {mkind}")
469 else if nvisibility
!= null and mvisibility
!= public_visibility
and mclass
.visibility
!= mvisibility
then
470 error
(nvisibility
, "Error: refinement changed the visibility from a {mclass.visibility} to a {mvisibility}")
472 nclassdef
.mclass
= mclass
475 # Visit the AST and create the MClassDef objects
476 private fun build_a_mclassdef
(nmodule
: AModule, nclassdef
: AClassdef)
478 var mmodule
= nmodule
.mmodule
.as(not null)
479 var objectclass
= try_get_mclass_by_name
(nmodule
, mmodule
, "Object")
480 var mclass
= nclassdef
.mclass
481 if mclass
== null then return # Skip error
482 #var mclassdef = nclassdef.mclassdef.as(not null)
484 var names
= new Array[String]
485 var bounds
= new Array[MType]
486 if nclassdef
isa AStdClassdef and mclass
.arity
> 0 then
487 # Collect formal parameter names
488 for i
in [0..mclass
.arity
[ do
489 var nfd
= nclassdef
.n_formaldefs
[i
]
490 var ptname
= nfd
.n_id
.text
491 if names
.has
(ptname
) then
492 error
(nfd
, "Error: A formal parameter type `{ptname}' already exists")
498 # Revolve bound for formal parameter names
499 for i
in [0..mclass
.arity
[ do
500 var nfd
= nclassdef
.n_formaldefs
[i
]
501 var nfdt
= nfd
.n_type
503 var bound
= resolve_mtype
(nclassdef
, nfdt
)
504 if bound
== null then return # Forward error
505 if bound
.need_anchor
then
507 error
(nfd
, "Error: Formal parameter type `{names[i]}' bounded with a formal parameter type")
511 else if mclass
.mclassdefs
.is_empty
then
512 # No bound, then implicitely bound by nullable Object
513 bounds
.add
(objectclass
.mclass_type
.as_nullable
)
516 bounds
.add
(mclass
.mclassdefs
.first
.bound_mtype
.as(MGenericType).arguments
[i
])
521 var bound_mtype
= mclass
.get_mtype
(bounds
)
522 var mclassdef
= new MClassDef(mmodule
, bound_mtype
, nclassdef
.location
, names
)
523 nclassdef
.mclassdef
= mclassdef
524 self.mclassdef2nclassdef
[mclassdef
] = nclassdef
526 if mclassdef
.is_intro
then
527 self.toolcontext
.info
("{mclassdef} introduces new {mclass.kind} {mclass.full_name}", 3)
529 self.toolcontext
.info
("{mclassdef} refine {mclass.kind} {mclass.full_name}", 3)
533 # Visit the AST and set the super-types of the MClass objects (ie compute the inheritance)
534 private fun build_a_mclassdef_inheritance
(nmodule
: AModule, nclassdef
: AClassdef)
536 var mmodule
= nmodule
.mmodule
.as(not null)
537 var objectclass
= try_get_mclass_by_name
(nmodule
, mmodule
, "Object")
538 var mclass
= nclassdef
.mclass
.as(not null)
539 var mclassdef
= nclassdef
.mclassdef
.as(not null)
541 var specobject
= true
542 var supertypes
= new Array[MClassType]
543 if nclassdef
isa AStdClassdef then
544 for nsc
in nclassdef
.n_superclasses
do
546 var ntype
= nsc
.n_type
547 var mtype
= resolve_mtype
(nclassdef
, ntype
)
548 if mtype
== null then continue # Skip because of error
549 if not mtype
isa MClassType then
550 error
(ntype
, "Error: supertypes cannot be a formal type")
554 #print "new super : {mclass} < {mtype}"
557 if specobject
and mclass
.name
!= "Object" and objectclass
!= null and mclassdef
.is_intro
then
558 supertypes
.add objectclass
.mclass_type
561 mclassdef
.set_supertypes
(supertypes
)
562 if not supertypes
.is_empty
then self.toolcontext
.info
("{mclassdef} new super-types: {supertypes.join(", ")}", 3)
565 # Check the validity of the specialization heirarchy
566 # FIXME Stub implementation
567 private fun check_supertypes
(nmodule
: AModule, nclassdef
: AClassdef)
569 var mmodule
= nmodule
.mmodule
.as(not null)
570 var objectclass
= try_get_mclass_by_name
(nmodule
, mmodule
, "Object")
571 var mclass
= nclassdef
.mclass
.as(not null)
572 var mclassdef
= nclassdef
.mclassdef
.as(not null)
575 # Build the classes of the module `nmodule'.
576 # REQUIRE: classes of imported modules are already build. (let `build_all_classes' do the job)
577 private fun build_classes
(nmodule
: AModule)
579 # Force building recursively
580 if nmodule
.build_classes_is_done
then return
581 var mmodule
= nmodule
.mmodule
.as(not null)
582 for imp
in mmodule
.in_importation
.direct_greaters
do
583 build_classes
(mmodule2nmodule
[imp
])
587 for nclassdef
in nmodule
.n_classdefs
do
588 self.build_a_mclass
(nmodule
, nclassdef
)
591 # Create all classdefs
592 for nclassdef
in nmodule
.n_classdefs
do
593 self.build_a_mclassdef
(nmodule
, nclassdef
)
596 for nclassdef
in nmodule
.n_classdefs
do
597 if nclassdef
.mclassdef
== null then return # forward error
600 # Create inheritance on all classdefs
601 for nclassdef
in nmodule
.n_classdefs
do
602 self.build_a_mclassdef_inheritance
(nmodule
, nclassdef
)
605 # TODO: Check that the super-class is not intrusive
607 # TODO: Check that the super-class is not already known (by transitivity)
609 for nclassdef
in nmodule
.n_classdefs
do
610 self.build_properties
(nclassdef
)
613 nmodule
.build_classes_is_done
= true
616 # Register the nmodule associated to each mmodule
617 # FIXME: why not refine the MModule class with a nullable attribute?
618 var mmodule2nmodule
: HashMap[MModule, AModule] = new HashMap[MModule, AModule]
619 # Register the nclassdef associated to each mclassdef
620 # FIXME: why not refine the MClassDef class with a nullable attribute?
621 var mclassdef2nclassdef
: HashMap[MClassDef, AClassdef] = new HashMap[MClassDef, AClassdef]
622 # Register the npropdef associated to each mpropdef
623 # FIXME: why not refine the MPropDef class with a nullable attribute?
624 var mpropdef2npropdef
: HashMap[MPropDef, APropdef] = new HashMap[MPropDef, APropdef]
626 # Build the properties of `nclassdef'.
627 # REQUIRE: all superclasses are built.
628 private fun build_properties
(nclassdef
: AClassdef)
630 # Force building recursively
631 if nclassdef
.build_properties_is_done
then return
632 var mclassdef
= nclassdef
.mclassdef
.as(not null)
633 if mclassdef
.in_hierarchy
== null then return # Skip error
634 for superclassdef
in mclassdef
.in_hierarchy
.direct_greaters
do
635 build_properties
(mclassdef2nclassdef
[superclassdef
])
638 for npropdef
in nclassdef
.n_propdefs
do
639 npropdef
.build_property
(self, nclassdef
)
641 for npropdef
in nclassdef
.n_propdefs
do
642 npropdef
.build_signature
(self, nclassdef
)
644 for npropdef
in nclassdef
.n_propdefs
do
645 npropdef
.check_signature
(self, nclassdef
)
647 process_default_constructors
(nclassdef
)
648 nclassdef
.build_properties_is_done
= true
651 # Introduce or inherit default constructor
652 # This is the last part of `build_properties'.
653 private fun process_default_constructors
(nclassdef
: AClassdef)
655 var mclassdef
= nclassdef
.mclassdef
.as(not null)
657 # Are we a refinement
658 if not mclassdef
.is_intro
then return
660 # Is the class forbid constructors?
661 if not mclassdef
.mclass
.kind
.need_init
then return
663 # Is there already a constructor defined?
664 for mpropdef
in mclassdef
.mpropdefs
do
665 if not mpropdef
isa MMethodDef then continue
666 if mpropdef
.mproperty
.is_init
then return
669 if not nclassdef
isa AStdClassdef then return
671 var mmodule
= nclassdef
.mclassdef
.mmodule
672 # Do we inherit for a constructor?
673 var combine
= new Array[MMethod]
674 var inhc
: nullable MClass = null
675 for st
in mclassdef
.supertypes
do
677 if not c
.kind
.need_init
then continue
678 st
= st
.anchor_to
(mmodule
, nclassdef
.mclassdef
.bound_mtype
)
679 var candidate
= self.try_get_mproperty_by_name2
(nclassdef
, mmodule
, st
, "init").as(nullable MMethod)
680 if candidate
!= null and candidate
.intro
.msignature
.arity
== 0 then
681 combine
.add
(candidate
)
684 var inhc2
= c
.inherit_init_from
685 if inhc2
== null then inhc2
= c
686 if inhc2
== inhc
then continue
688 self.error
(nclassdef
, "Error: Cannot provide a defaut constructor: conflict for {inhc} and {c}")
693 if combine
.is_empty
and inhc
!= null then
694 # TODO: actively inherit the consturctor
695 self.toolcontext
.info
("{mclassdef} inherits all constructors from {inhc}", 3)
696 mclassdef
.mclass
.inherit_init_from
= inhc
699 if not combine
.is_empty
and inhc
!= null then
700 self.error
(nclassdef
, "Error: Cannot provide a defaut constructor: conflict for {combine.join(", ")} and {inhc}")
704 if not combine
.is_empty
then
705 nclassdef
.super_inits
= combine
706 var mprop
= new MMethod(mclassdef
, "init", mclassdef
.mclass
.visibility
)
707 var mpropdef
= new MMethodDef(mclassdef
, mprop
, nclassdef
.location
)
708 var mparameters
= new Array[MParameter]
709 var msignature
= new MSignature(mparameters
, null)
710 mpropdef
.msignature
= msignature
712 nclassdef
.mfree_init
= mpropdef
713 self.toolcontext
.info
("{mclassdef} gets a free empty constructor {mpropdef}{msignature}", 3)
717 # Collect undefined attributes
718 var mparameters
= new Array[MParameter]
719 for npropdef
in nclassdef
.n_propdefs
do
720 if npropdef
isa AAttrPropdef and npropdef
.n_expr
== null then
721 var paramname
= npropdef
.mpropdef
.mproperty
.name
.substring_from
(1)
722 var ret_type
= npropdef
.mpropdef
.static_mtype
723 if ret_type
== null then return
724 var mparameter
= new MParameter(paramname
, ret_type
, false)
725 mparameters
.add
(mparameter
)
729 var mprop
= new MMethod(mclassdef
, "init", mclassdef
.mclass
.visibility
)
730 var mpropdef
= new MMethodDef(mclassdef
, mprop
, nclassdef
.location
)
731 var msignature
= new MSignature(mparameters
, null)
732 mpropdef
.msignature
= msignature
734 nclassdef
.mfree_init
= mpropdef
735 self.toolcontext
.info
("{mclassdef} gets a free constructor for attributes {mpropdef}{msignature}", 3)
738 # Return the static type associated to the node `ntype'.
739 # `classdef' is the context where the call is made (used to understand formal types)
740 # The mmodule used as context is `nclassdef.mmodule'
741 # In case of problem, an error is displayed on `ntype' and null is returned.
742 # FIXME: the name "resolve_mtype" is awful
743 fun resolve_mtype
(nclassdef
: AClassdef, ntype
: AType): nullable MType
745 var name
= ntype
.n_id
.text
746 var mclassdef
= nclassdef
.mclassdef
747 var mmodule
= nclassdef
.parent
.as(AModule).mmodule
.as(not null)
751 if mclassdef
!= null then
752 var prop
= try_get_mproperty_by_name
(ntype
, mclassdef
, name
).as(nullable MVirtualTypeProp)
754 if not ntype
.n_types
.is_empty
then
755 error
(ntype
, "Type error: formal type {name} cannot have formal parameters.")
757 res
= prop
.mvirtualtype
758 if ntype
.n_kwnullable
!= null then res
= res
.as_nullable
763 # Check parameter type
764 if mclassdef
!= null and mclassdef
.parameter_names
.has
(name
) then
765 if not ntype
.n_types
.is_empty
then
766 error
(ntype
, "Type error: formal type {name} cannot have formal parameters.")
768 for i
in [0..mclassdef
.parameter_names
.length
[ do
769 if mclassdef
.parameter_names
[i
] == name
then
770 res
= mclassdef
.mclass
.mclass_type
.as(MGenericType).arguments
[i
]
771 if ntype
.n_kwnullable
!= null then res
= res
.as_nullable
779 var mclass
= try_get_mclass_by_name
(ntype
, mmodule
, name
)
780 if mclass
!= null then
781 var arity
= ntype
.n_types
.length
782 if arity
!= mclass
.arity
then
784 error
(ntype
, "Type error: '{name}' is a generic class.")
785 else if mclass
.arity
== 0 then
786 error
(ntype
, "Type error: '{name}' is not a generic class.")
788 error
(ntype
, "Type error: '{name}' has {mclass.arity} parameters ({arity} are provided).")
793 res
= mclass
.mclass_type
794 if ntype
.n_kwnullable
!= null then res
= res
.as_nullable
797 var mtypes
= new Array[MType]
798 for nt
in ntype
.n_types
do
799 var mt
= resolve_mtype
(nclassdef
, nt
)
800 if mt
== null then return null # Forward error
803 res
= mclass
.get_mtype
(mtypes
)
804 if ntype
.n_kwnullable
!= null then res
= res
.as_nullable
809 # If everything fail, then give up :(
810 error
(ntype
, "Type error: class {name} not found in module {mmodule}.")
814 # Helper function to display an error on a node.
815 # Alias for `self.toolcontext.error(n.hot_location, text)'
816 fun error
(n
: ANode, text
: String)
818 self.toolcontext
.error
(n
.hot_location
, text
)
821 # Helper function to display a warning on a node.
822 # Alias for: `self.toolcontext.warning(n.hot_location, text)'
823 fun warning
(n
: ANode, text
: String)
825 self.toolcontext
.warning
(n
.hot_location
, text
)
830 # The associated MModule once build by a `ModelBuilder'
831 var mmodule
: nullable MModule
832 # Flag that indicate if the importation is already completed
833 var is_importation_done
: Bool = false
834 # Flag that indicate if the class and prop building is already completed
835 var build_classes_is_done
: Bool = false
839 # The class whose self inherit all the constructors.
840 # 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
841 var inherit_init_from
: nullable MClass = null
844 redef class AClassdef
845 # The associated MClass once build by a `ModelBuilder'
846 var mclass
: nullable MClass
847 # The associated MClassDef once build by a `ModelBuilder'
848 var mclassdef
: nullable MClassDef
849 var build_properties_is_done
: Bool = false
850 # The list of super-constructor to call at the start of the free constructor
851 # 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
852 var super_inits
: nullable Collection[MMethod] = null
854 # The free init (implicitely constructed by the class if required)
855 var mfree_init
: nullable MMethodDef = null
858 redef class AClasskind
859 # The class kind associated with the AST node class
860 private fun mkind
: MClassKind is abstract
862 redef class AConcreteClasskind
863 redef fun mkind
do return concrete_kind
865 redef class AAbstractClasskind
866 redef fun mkind
do return abstract_kind
868 redef class AInterfaceClasskind
869 redef fun mkind
do return interface_kind
871 redef class AEnumClasskind
872 redef fun mkind
do return enum_kind
874 redef class AExternClasskind
875 redef fun mkind
do return extern_kind
878 redef class AVisibility
879 # The visibility level associated with the AST node class
880 private fun mvisibility
: MVisibility is abstract
882 redef class AIntrudeVisibility
883 redef fun mvisibility
do return intrude_visibility
885 redef class APublicVisibility
886 redef fun mvisibility
do return public_visibility
888 redef class AProtectedVisibility
889 redef fun mvisibility
do return protected_visibility
891 redef class APrivateVisibility
892 redef fun mvisibility
do return private_visibility
899 # Join the text of all tokens
900 # Used to get the 'real name' of method definitions.
901 fun collect_text
: String
903 var v
= new TextCollectorVisitor
910 private class TextCollectorVisitor
912 var text
: String = ""
915 if n
isa Token then text
+= n
.text
921 private fun build_property
(modelbuilder
: ModelBuilder, nclassdef
: AClassdef)
924 private fun build_signature
(modelbuilder
: ModelBuilder, nclassdef
: AClassdef)
927 private fun check_signature
(modelbuilder
: ModelBuilder, nclassdef
: AClassdef)
930 private fun new_property_visibility
(modelbuilder
: ModelBuilder, nclassdef
: AClassdef, nvisibility
: nullable AVisibility): MVisibility
932 var mvisibility
= public_visibility
933 if nvisibility
!= null then mvisibility
= nvisibility
.mvisibility
934 if nclassdef
.mclassdef
.mclass
.visibility
== private_visibility
then
935 if mvisibility
== protected_visibility
then
936 assert nvisibility
!= null
937 modelbuilder
.error
(nvisibility
, "Error: The only legal visibility for properties in a private class is private.")
938 else if mvisibility
== private_visibility
then
939 assert nvisibility
!= null
941 # modelbuilder.warning(nvisibility, "Warning: private is unrequired since the only legal visibility for properties in a private class is private.")
943 mvisibility
= private_visibility
948 private fun check_redef_property_visibility
(modelbuilder
: ModelBuilder, nclassdef
: AClassdef, nvisibility
: nullable AVisibility, mprop
: MProperty)
950 if nvisibility
== null then return
951 var mvisibility
= nvisibility
.mvisibility
952 if mvisibility
!= mprop
.visibility
and mvisibility
!= public_visibility
then
953 modelbuilder
.error
(nvisibility
, "Error: redefinition changed the visibility from a {mprop.visibility} to a {mvisibility}")
957 private fun check_redef_keyword
(modelbuilder
: ModelBuilder, nclassdef
: AClassdef, kwredef
: nullable Token, need_redef
: Bool, mprop
: MProperty)
959 if kwredef
== null then
961 modelbuilder
.error
(self, "Redef error: {nclassdef.mclassdef.mclass}::{mprop.name} is an inherited property. To redefine it, add the redef keyword.")
964 if not need_redef
then
965 modelbuilder
.error
(self, "Error: No property {nclassdef.mclassdef.mclass}::{mprop.name} is inherited. Remove the redef keyword to define a new property.")
972 redef class ASignature
973 # Is the model builder has correctly visited the signature
974 var is_visited
= false
975 # Names of parameters from the AST
976 # REQUIRE: is_visited
977 var param_names
= new Array[String]
978 # Types of parameters from the AST
979 # REQUIRE: is_visited
980 var param_types
= new Array[MType]
981 # Rank of the vararg (of -1 if none)
982 # REQUIRE: is_visited
983 var vararg_rank
: Int = -1
985 var ret_type
: nullable MType = null
987 # Visit and fill information about a signature
988 private fun visit_signature
(modelbuilder
: ModelBuilder, nclassdef
: AClassdef): Bool
990 var param_names
= self.param_names
991 var param_types
= self.param_types
992 for np
in self.n_params
do
993 param_names
.add
(np
.n_id
.text
)
994 var ntype
= np
.n_type
995 if ntype
!= null then
996 var mtype
= modelbuilder
.resolve_mtype
(nclassdef
, ntype
)
997 if mtype
== null then return false # Skip error
998 for i
in [0..param_names
.length-param_types
.length
[ do
999 param_types
.add
(mtype
)
1001 if np
.n_dotdotdot
!= null then
1002 if self.vararg_rank
!= -1 then
1003 modelbuilder
.error
(np
, "Error: {param_names[self.vararg_rank]} is already a vararg")
1006 self.vararg_rank
= param_names
.length
- 1
1011 var ntype
= self.n_type
1012 if ntype
!= null then
1013 self.ret_type
= modelbuilder
.resolve_mtype
(nclassdef
, ntype
)
1014 if self.ret_type
== null then return false # Skip errir
1017 for nclosure
in self.n_closure_decls
do
1018 if not nclosure
.n_signature
.visit_signature
(modelbuilder
, nclassdef
) then return false
1021 self.is_visited
= true
1025 # Build a visited signature
1026 fun build_signature
(modelbuilder
: ModelBuilder, nclassdef
: AClassdef): nullable MSignature
1028 if param_names
.length
!= param_types
.length
then
1029 # Some parameters are typed, other parameters are not typed.
1030 modelbuilder
.error
(self.n_params
[param_types
.length
], "Error: Untyped parameter `{param_names[param_types.length]}'.")
1034 var mparameters
= new Array[MParameter]
1035 for i
in [0..param_names
.length
[ do
1036 var mparameter
= new MParameter(param_names
[i
], param_types
[i
], i
== vararg_rank
)
1037 mparameters
.add
(mparameter
)
1040 var msignature
= new MSignature(mparameters
, ret_type
)
1045 redef class AMethPropdef
1046 # The associated MMethodDef once build by a `ModelBuilder'
1047 var mpropdef
: nullable MMethodDef
1049 # The associated super init if any
1050 var super_init
: nullable MMethod
1051 redef fun build_property
(modelbuilder
, nclassdef
)
1053 var is_init
= self isa AInitPropdef
1054 var mclassdef
= nclassdef
.mclassdef
.as(not null)
1056 var amethodid
= self.n_methid
1057 var name_node
: ANode
1058 if amethodid
== null then
1059 if self isa AMainMethPropdef then
1062 else if self isa AConcreteInitPropdef then
1064 name_node
= self.n_kwinit
1065 else if self isa AExternInitPropdef then
1067 name_node
= self.n_kwnew
1071 else if amethodid
isa AIdMethid then
1072 name
= amethodid
.n_id
.text
1073 name_node
= amethodid
1075 # operator, bracket or assign
1076 name
= amethodid
.collect_text
1077 name_node
= amethodid
1079 if name
== "-" and self.n_signature
.n_params
.length
== 0 then
1084 var mprop
: nullable MMethod = null
1085 if not is_init
or n_kwredef
!= null then mprop
= modelbuilder
.try_get_mproperty_by_name
(name_node
, mclassdef
, name
).as(nullable MMethod)
1086 if mprop
== null then
1087 var mvisibility
= new_property_visibility
(modelbuilder
, nclassdef
, self.n_visibility
)
1088 mprop
= new MMethod(mclassdef
, name
, mvisibility
)
1089 mprop
.is_init
= is_init
1090 mprop
.is_new
= self isa AExternInitPropdef
1091 self.check_redef_keyword
(modelbuilder
, nclassdef
, n_kwredef
, false, mprop
)
1093 if n_kwredef
== null then
1094 if self isa AMainMethPropdef then
1097 self.check_redef_keyword
(modelbuilder
, nclassdef
, n_kwredef
, true, mprop
)
1100 check_redef_property_visibility
(modelbuilder
, nclassdef
, self.n_visibility
, mprop
)
1103 var mpropdef
= new MMethodDef(mclassdef
, mprop
, self.location
)
1105 self.mpropdef
= mpropdef
1106 modelbuilder
.mpropdef2npropdef
[mpropdef
] = self
1107 if mpropdef
.is_intro
then
1108 modelbuilder
.toolcontext
.info
("{mpropdef} introduces new method {mprop.full_name}", 3)
1110 modelbuilder
.toolcontext
.info
("{mpropdef} redefines method {mprop.full_name}", 3)
1114 redef fun build_signature
(modelbuilder
, nclassdef
)
1116 var mpropdef
= self.mpropdef
1117 if mpropdef
== null then return # Error thus skiped
1118 var mmodule
= mpropdef
.mclassdef
.mmodule
1119 var nsig
= self.n_signature
1121 # Retrieve info from the signature AST
1122 var param_names
= new Array[String] # Names of parameters from the AST
1123 var param_types
= new Array[MType] # Types of parameters from the AST
1124 var vararg_rank
= -1
1125 var ret_type
: nullable MType = null # Return type from the AST
1126 if nsig
!= null then
1127 if not nsig
.visit_signature
(modelbuilder
, nclassdef
) then return
1128 param_names
= nsig
.param_names
1129 param_types
= nsig
.param_types
1130 vararg_rank
= nsig
.vararg_rank
1131 ret_type
= nsig
.ret_type
1134 # Look for some signature to inherit
1135 # FIXME: do not inherit from the intro, but from the most specific
1136 var msignature
: nullable MSignature = null
1137 if not mpropdef
.is_intro
then
1138 msignature
= mpropdef
.mproperty
.intro
.msignature
1139 if msignature
== null then return # Skip error
1141 # Check inherited signature arity
1142 if param_names
.length
!= msignature
.arity
then
1144 if nsig
!= null then node
= nsig
else node
= self
1145 modelbuilder
.error
(node
, "Redef error: {mpropdef} redefines {mpropdef.mproperty.intro} with {param_names.length} parameter(s), {msignature.arity} expected. Signature is {mpropdef}{msignature}")
1148 else if mpropdef
.mproperty
.is_init
then
1149 # FIXME UGLY: inherit signature from a super-constructor
1150 for msupertype
in nclassdef
.mclassdef
.supertypes
do
1151 msupertype
= msupertype
.anchor_to
(mmodule
, nclassdef
.mclassdef
.bound_mtype
)
1152 var candidate
= modelbuilder
.try_get_mproperty_by_name2
(self, mmodule
, msupertype
, mpropdef
.mproperty
.name
)
1153 if candidate
!= null then
1154 if msignature
== null then
1155 msignature
= candidate
.intro
.as(MMethodDef).msignature
1162 # Inherit the signature
1163 if msignature
!= null and param_names
.length
!= param_types
.length
and param_names
.length
== msignature
.arity
and param_types
.length
== 0 then
1164 # Parameters are untyped, thus inherit them
1165 param_types
= new Array[MType]
1166 for mparameter
in msignature
.mparameters
do
1167 param_types
.add
(mparameter
.mtype
)
1169 vararg_rank
= msignature
.vararg_rank
1171 if msignature
!= null and ret_type
== null then
1172 ret_type
= msignature
.return_mtype
1175 if param_names
.length
!= param_types
.length
then
1176 # Some parameters are typed, other parameters are not typed.
1177 modelbuilder
.error
(nsig
.n_params
[param_types
.length
], "Error: Untyped parameter `{param_names[param_types.length]}'.")
1181 var mparameters
= new Array[MParameter]
1182 for i
in [0..param_names
.length
[ do
1183 var mparameter
= new MParameter(param_names
[i
], param_types
[i
], i
== vararg_rank
)
1184 mparameters
.add
(mparameter
)
1187 msignature
= new MSignature(mparameters
, ret_type
)
1188 mpropdef
.msignature
= msignature
1190 if nsig
!= null then
1191 for nclosure
in nsig
.n_closure_decls
do
1192 var clos_signature
= nclosure
.n_signature
.build_signature
(modelbuilder
, nclassdef
)
1193 if clos_signature
== null then return
1194 var mparameter
= new MParameter(nclosure
.n_id
.text
, clos_signature
, false)
1195 msignature
.mclosures
.add
(mparameter
)
1201 redef fun check_signature
(modelbuilder
, nclassdef
)
1203 var mpropdef
= self.mpropdef
1204 if mpropdef
== null then return # Error thus skiped
1205 var mmodule
= mpropdef
.mclassdef
.mmodule
1206 var nsig
= self.n_signature
1207 var mysignature
= self.mpropdef
.msignature
1208 if mysignature
== null then return # Error thus skiped
1210 # Lookup for signature in the precursor
1211 # FIXME all precursors should be considered
1212 if not mpropdef
.is_intro
then
1213 var msignature
= mpropdef
.mproperty
.intro
.msignature
1214 if msignature
== null then return
1216 var precursor_ret_type
= msignature
.return_mtype
1217 var ret_type
= mysignature
.return_mtype
1218 if ret_type
!= null and precursor_ret_type
== null then
1219 modelbuilder
.error
(nsig
.n_type
.as(not null), "Redef Error: {mpropdef.mproperty} is a procedure, not a function.")
1223 if mysignature
.arity
> 0 then
1224 # Check parameters types
1225 for i
in [0..mysignature
.arity
[ do
1226 var myt
= mysignature
.mparameters
[i
].mtype
1227 var prt
= msignature
.mparameters
[i
].mtype
1228 if not myt
.is_subtype
(mmodule
, nclassdef
.mclassdef
.bound_mtype
, prt
) and
1229 not prt
.is_subtype
(mmodule
, nclassdef
.mclassdef
.bound_mtype
, myt
) then
1230 modelbuilder
.error
(nsig
.n_params
[i
], "Redef Error: Wrong type for parameter `{mysignature.mparameters[i].name}'. found {myt}, expected {prt}.")
1234 if precursor_ret_type
!= null then
1235 if ret_type
== null then
1236 # Inherit the return type
1237 ret_type
= precursor_ret_type
1238 else if not ret_type
.is_subtype
(mmodule
, nclassdef
.mclassdef
.bound_mtype
, precursor_ret_type
) then
1239 modelbuilder
.error
(nsig
.n_type
.as(not null), "Redef Error: Wrong return type. found {ret_type}, expected {precursor_ret_type}.")
1246 redef class AAttrPropdef
1247 # The associated MAttributeDef once build by a `ModelBuilder'
1248 var mpropdef
: nullable MAttributeDef
1249 # The associated getter (read accessor) if any
1250 var mreadpropdef
: nullable MMethodDef
1251 # The associated setter (write accessor) if any
1252 var mwritepropdef
: nullable MMethodDef
1253 redef fun build_property
(modelbuilder
, nclassdef
)
1255 var mclassdef
= nclassdef
.mclassdef
.as(not null)
1256 var mclass
= mclassdef
.mclass
1259 if self.n_id
!= null then
1260 name
= self.n_id
.text
1262 name
= self.n_id2
.text
1265 if mclass
.kind
== interface_kind
or mclassdef
.mclass
.kind
== enum_kind
then
1266 modelbuilder
.error
(self, "Error: Attempt to define attribute {name} in the interface {mclass}.")
1267 else if mclass
.kind
== enum_kind
then
1268 modelbuilder
.error
(self, "Error: Attempt to define attribute {name} in the enum class {mclass}.")
1273 # Old attribute style
1274 var mprop
= modelbuilder
.try_get_mproperty_by_name
(nid
, mclassdef
, name
)
1275 if mprop
== null then
1276 var mvisibility
= new_property_visibility
(modelbuilder
, nclassdef
, self.n_visibility
)
1277 mprop
= new MAttribute(mclassdef
, name
, mvisibility
)
1278 self.check_redef_keyword
(modelbuilder
, nclassdef
, self.n_kwredef
, false, mprop
)
1280 assert mprop
isa MAttribute
1281 check_redef_property_visibility
(modelbuilder
, nclassdef
, self.n_visibility
, mprop
)
1282 self.check_redef_keyword
(modelbuilder
, nclassdef
, self.n_kwredef
, true, mprop
)
1284 var mpropdef
= new MAttributeDef(mclassdef
, mprop
, self.location
)
1285 self.mpropdef
= mpropdef
1286 modelbuilder
.mpropdef2npropdef
[mpropdef
] = self
1288 var nreadable
= self.n_readable
1289 if nreadable
!= null then
1290 var readname
= name
.substring_from
(1)
1291 var mreadprop
= modelbuilder
.try_get_mproperty_by_name
(nid
, mclassdef
, readname
).as(nullable MMethod)
1292 if mreadprop
== null then
1293 var mvisibility
= new_property_visibility
(modelbuilder
, nclassdef
, nreadable
.n_visibility
)
1294 mreadprop
= new MMethod(mclassdef
, readname
, mvisibility
)
1295 self.check_redef_keyword
(modelbuilder
, nclassdef
, nreadable
.n_kwredef
, false, mreadprop
)
1297 self.check_redef_keyword
(modelbuilder
, nclassdef
, nreadable
.n_kwredef
, true, mreadprop
)
1298 check_redef_property_visibility
(modelbuilder
, nclassdef
, nreadable
.n_visibility
, mreadprop
)
1300 var mreadpropdef
= new MMethodDef(mclassdef
, mreadprop
, self.location
)
1301 self.mreadpropdef
= mreadpropdef
1302 modelbuilder
.mpropdef2npropdef
[mreadpropdef
] = self
1305 var nwritable
= self.n_writable
1306 if nwritable
!= null then
1307 var writename
= name
.substring_from
(1) + "="
1308 var mwriteprop
= modelbuilder
.try_get_mproperty_by_name
(nid
, mclassdef
, writename
).as(nullable MMethod)
1309 if mwriteprop
== null then
1310 var mvisibility
= new_property_visibility
(modelbuilder
, nclassdef
, nwritable
.n_visibility
)
1311 mwriteprop
= new MMethod(mclassdef
, writename
, mvisibility
)
1312 self.check_redef_keyword
(modelbuilder
, nclassdef
, nwritable
.n_kwredef
, false, mwriteprop
)
1314 self.check_redef_keyword
(modelbuilder
, nclassdef
, nwritable
.n_kwredef
, true, mwriteprop
)
1315 check_redef_property_visibility
(modelbuilder
, nclassdef
, nwritable
.n_visibility
, mwriteprop
)
1317 var mwritepropdef
= new MMethodDef(mclassdef
, mwriteprop
, self.location
)
1318 self.mwritepropdef
= mwritepropdef
1319 modelbuilder
.mpropdef2npropdef
[mwritepropdef
] = self
1322 # New attribute style
1323 var nid2
= self.n_id2
.as(not null)
1324 var mprop
= new MAttribute(mclassdef
, "@" + name
, none_visibility
)
1325 var mpropdef
= new MAttributeDef(mclassdef
, mprop
, self.location
)
1326 self.mpropdef
= mpropdef
1327 modelbuilder
.mpropdef2npropdef
[mpropdef
] = self
1330 var mreadprop
= modelbuilder
.try_get_mproperty_by_name
(nid2
, mclassdef
, readname
).as(nullable MMethod)
1331 if mreadprop
== null then
1332 var mvisibility
= new_property_visibility
(modelbuilder
, nclassdef
, self.n_visibility
)
1333 mreadprop
= new MMethod(mclassdef
, readname
, mvisibility
)
1334 self.check_redef_keyword
(modelbuilder
, nclassdef
, n_kwredef
, false, mreadprop
)
1336 self.check_redef_keyword
(modelbuilder
, nclassdef
, n_kwredef
, true, mreadprop
)
1337 check_redef_property_visibility
(modelbuilder
, nclassdef
, self.n_visibility
, mreadprop
)
1339 var mreadpropdef
= new MMethodDef(mclassdef
, mreadprop
, self.location
)
1340 self.mreadpropdef
= mreadpropdef
1341 modelbuilder
.mpropdef2npropdef
[mreadpropdef
] = self
1343 var writename
= name
+ "="
1344 var nwritable
= self.n_writable
1345 var mwriteprop
= modelbuilder
.try_get_mproperty_by_name
(nid2
, mclassdef
, writename
).as(nullable MMethod)
1346 var nwkwredef
: nullable Token = null
1347 if nwritable
!= null then nwkwredef
= nwritable
.n_kwredef
1348 if mwriteprop
== null then
1350 if nwritable
!= null then
1351 mvisibility
= new_property_visibility
(modelbuilder
, nclassdef
, nwritable
.n_visibility
)
1353 mvisibility
= private_visibility
1355 mwriteprop
= new MMethod(mclassdef
, writename
, mvisibility
)
1356 self.check_redef_keyword
(modelbuilder
, nclassdef
, nwkwredef
, false, mwriteprop
)
1358 self.check_redef_keyword
(modelbuilder
, nclassdef
, nwkwredef
, true, mwriteprop
)
1359 if nwritable
!= null then
1360 check_redef_property_visibility
(modelbuilder
, nclassdef
, nwritable
.n_visibility
, mwriteprop
)
1363 var mwritepropdef
= new MMethodDef(mclassdef
, mwriteprop
, self.location
)
1364 self.mwritepropdef
= mwritepropdef
1365 modelbuilder
.mpropdef2npropdef
[mwritepropdef
] = self
1369 redef fun build_signature
(modelbuilder
, nclassdef
)
1371 var mpropdef
= self.mpropdef
1372 if mpropdef
== null then return # Error thus skiped
1373 var mmodule
= mpropdef
.mclassdef
.mmodule
1374 var mtype
: nullable MType = null
1376 var ntype
= self.n_type
1377 if ntype
!= null then
1378 mtype
= modelbuilder
.resolve_mtype
(nclassdef
, ntype
)
1379 if mtype
== null then return
1382 if mtype
== null then
1383 var nexpr
= self.n_expr
1384 if nexpr
!= null then
1385 if nexpr
isa ANewExpr then
1386 mtype
= modelbuilder
.resolve_mtype
(nclassdef
, nexpr
.n_type
)
1387 else if nexpr
isa AIntExpr then
1388 var cla
= modelbuilder
.try_get_mclass_by_name
(nexpr
, mmodule
, "Int")
1389 if cla
!= null then mtype
= cla
.mclass_type
1390 else if nexpr
isa AFloatExpr then
1391 var cla
= modelbuilder
.try_get_mclass_by_name
(nexpr
, mmodule
, "Float")
1392 if cla
!= null then mtype
= cla
.mclass_type
1393 else if nexpr
isa ACharExpr then
1394 var cla
= modelbuilder
.try_get_mclass_by_name
(nexpr
, mmodule
, "Char")
1395 if cla
!= null then mtype
= cla
.mclass_type
1396 else if nexpr
isa ABoolExpr then
1397 var cla
= modelbuilder
.try_get_mclass_by_name
(nexpr
, mmodule
, "Bool")
1398 if cla
!= null then mtype
= cla
.mclass_type
1399 else if nexpr
isa ASuperstringExpr then
1400 var cla
= modelbuilder
.try_get_mclass_by_name
(nexpr
, mmodule
, "String")
1401 if cla
!= null then mtype
= cla
.mclass_type
1402 else if nexpr
isa AStringFormExpr then
1403 var cla
= modelbuilder
.try_get_mclass_by_name
(nexpr
, mmodule
, "String")
1404 if cla
!= null then mtype
= cla
.mclass_type
1406 modelbuilder
.error
(self, "Error: Untyped attribute {mpropdef}. Implicit typing allowed only for literals and new.")
1410 modelbuilder
.error
(self, "Error: Untyped attribute {mpropdef}")
1414 if mtype
== null then return
1416 mpropdef
.static_mtype
= mtype
1418 var mreadpropdef
= self.mreadpropdef
1419 if mreadpropdef
!= null then
1420 var msignature
= new MSignature(new Array[MParameter], mtype
)
1421 mreadpropdef
.msignature
= msignature
1424 var msritepropdef
= self.mwritepropdef
1425 if mwritepropdef
!= null then
1427 if n_id
!= null then
1428 name
= n_id
.text
.substring_from
(1)
1432 var mparameter
= new MParameter(name
, mtype
, false)
1433 var msignature
= new MSignature([mparameter
], null)
1434 mwritepropdef
.msignature
= msignature
1438 redef fun check_signature
(modelbuilder
, nclassdef
)
1440 var mpropdef
= self.mpropdef
1441 if mpropdef
== null then return # Error thus skiped
1442 var mmodule
= mpropdef
.mclassdef
.mmodule
1443 var ntype
= self.n_type
1444 var mtype
= self.mpropdef
.static_mtype
1445 if mtype
== null then return # Error thus skiped
1447 # Lookup for signature in the precursor
1448 # FIXME all precursors should be considered
1449 if not mpropdef
.is_intro
then
1450 var precursor_type
= mpropdef
.mproperty
.intro
.static_mtype
1451 if precursor_type
== null then return
1453 if mtype
!= precursor_type
then
1454 modelbuilder
.error
(ntype
.as(not null), "Redef Error: Wrong static type. found {mtype}, expected {precursor_type}.")
1459 # Check getter and setter
1460 var meth
= self.mreadpropdef
1461 if meth
!= null then self.check_method_signature
(modelbuilder
, nclassdef
, meth
)
1462 meth
= self.mwritepropdef
1463 if meth
!= null then self.check_method_signature
(modelbuilder
, nclassdef
, meth
)
1466 private fun check_method_signature
(modelbuilder
: ModelBuilder, nclassdef
: AClassdef, mpropdef
: MMethodDef)
1468 var mmodule
= mpropdef
.mclassdef
.mmodule
1469 var nsig
= self.n_type
1470 var mysignature
= mpropdef
.msignature
1471 if mysignature
== null then return # Error thus skiped
1473 # Lookup for signature in the precursor
1474 # FIXME all precursors should be considered
1475 if not mpropdef
.is_intro
then
1476 var msignature
= mpropdef
.mproperty
.intro
.msignature
1477 if msignature
== null then return
1479 if mysignature
.arity
!= msignature
.arity
then
1481 if nsig
!= null then node
= nsig
else node
= self
1482 modelbuilder
.error
(node
, "Redef Error: {mysignature.arity} parameters found, {msignature.arity} expected. Signature is {mpropdef}{msignature}")
1485 var precursor_ret_type
= msignature
.return_mtype
1486 var ret_type
= mysignature
.return_mtype
1487 if ret_type
!= null and precursor_ret_type
== null then
1489 if nsig
!= null then node
= nsig
else node
= self
1490 modelbuilder
.error
(node
, "Redef Error: {mpropdef.mproperty} is a procedure, not a function.")
1494 if mysignature
.arity
> 0 then
1495 # Check parameters types
1496 for i
in [0..mysignature
.arity
[ do
1497 var myt
= mysignature
.mparameters
[i
].mtype
1498 var prt
= msignature
.mparameters
[i
].mtype
1499 if not myt
.is_subtype
(mmodule
, nclassdef
.mclassdef
.bound_mtype
, prt
) and
1500 not prt
.is_subtype
(mmodule
, nclassdef
.mclassdef
.bound_mtype
, myt
) then
1502 if nsig
!= null then node
= nsig
else node
= self
1503 modelbuilder
.error
(node
, "Redef Error: Wrong type for parameter `{mysignature.mparameters[i].name}'. found {myt}, expected {prt}.")
1507 if precursor_ret_type
!= null then
1508 if ret_type
== null then
1509 # Inherit the return type
1510 ret_type
= precursor_ret_type
1511 else if not ret_type
.is_subtype
(mmodule
, nclassdef
.mclassdef
.bound_mtype
, precursor_ret_type
) then
1513 if nsig
!= null then node
= nsig
else node
= self
1514 modelbuilder
.error
(node
, "Redef Error: Wrong return type. found {ret_type}, expected {precursor_ret_type}.")
1521 redef class ATypePropdef
1522 # The associated MVirtualTypeDef once build by a `ModelBuilder'
1523 var mpropdef
: nullable MVirtualTypeDef
1524 redef fun build_property
(modelbuilder
, nclassdef
)
1526 var mclassdef
= nclassdef
.mclassdef
.as(not null)
1527 var name
= self.n_id
.text
1528 var mprop
= modelbuilder
.try_get_mproperty_by_name
(self.n_id
, mclassdef
, name
)
1529 if mprop
== null then
1530 var mvisibility
= new_property_visibility
(modelbuilder
, nclassdef
, self.n_visibility
)
1531 mprop
= new MVirtualTypeProp(mclassdef
, name
, mvisibility
)
1532 self.check_redef_keyword
(modelbuilder
, nclassdef
, self.n_kwredef
, false, mprop
)
1534 self.check_redef_keyword
(modelbuilder
, nclassdef
, self.n_kwredef
, true, mprop
)
1535 assert mprop
isa MVirtualTypeProp
1536 check_redef_property_visibility
(modelbuilder
, nclassdef
, self.n_visibility
, mprop
)
1538 var mpropdef
= new MVirtualTypeDef(mclassdef
, mprop
, self.location
)
1539 self.mpropdef
= mpropdef
1542 redef fun build_signature
(modelbuilder
, nclassdef
)
1544 var mpropdef
= self.mpropdef
1545 if mpropdef
== null then return # Error thus skiped
1546 var mmodule
= mpropdef
.mclassdef
.mmodule
1547 var mtype
: nullable MType = null
1549 var ntype
= self.n_type
1550 mtype
= modelbuilder
.resolve_mtype
(nclassdef
, ntype
)
1551 if mtype
== null then return
1553 mpropdef
.bound
= mtype
1554 # print "{mpropdef}: {mtype}"
1557 redef fun check_signature
(modelbuilder
, nclassdef
)
1559 var bound
= self.mpropdef
.bound
1561 # Fast case: the bound is not a formal type
1562 if not bound
isa MVirtualType then return
1564 var mmodule
= nclassdef
.mclassdef
.mmodule
1565 var anchor
= nclassdef
.mclassdef
.bound_mtype
1567 # Slow case: progress on each resolution until: (i) we loop, or (ii) we found a non formal type
1568 var seen
= [self.mpropdef
.mproperty
.mvirtualtype
]
1570 if seen
.has
(bound
) then
1572 modelbuilder
.error
(self, "Error: circularity of virtual type definition: {seen.join(" -> ")}")
1576 var next
= bound
.lookup_bound
(mmodule
, anchor
)
1577 if not next
isa MVirtualType then return