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 # Analysis and verification of property definitions to instantiate model element
18 module modelize_property
21 private import annotation
23 redef class ToolContext
24 var modelize_property_phase
: Phase = new ModelizePropertyPhase(self, [modelize_class_phase
])
27 private class ModelizePropertyPhase
29 redef fun process_nmodule
(nmodule
)
31 for nclassdef
in nmodule
.n_classdefs
do
32 if nclassdef
.all_defs
== null then continue # skip non principal classdef
33 toolcontext
.modelbuilder
.build_properties
(nclassdef
)
38 redef class ModelBuilder
39 # Register the npropdef associated to each mpropdef
40 # FIXME: why not refine the `MPropDef` class with a nullable attribute?
41 var mpropdef2npropdef
: HashMap[MPropDef, APropdef] = new HashMap[MPropDef, APropdef]
43 # Build the properties of `nclassdef`.
44 # REQUIRE: all superclasses are built.
45 private fun build_properties
(nclassdef
: AClassdef)
47 # Force building recursively
48 if nclassdef
.build_properties_is_done
then return
49 nclassdef
.build_properties_is_done
= true
50 var mclassdef
= nclassdef
.mclassdef
.as(not null)
51 if mclassdef
.in_hierarchy
== null then return # Skip error
52 for superclassdef
in mclassdef
.in_hierarchy
.direct_greaters
do
53 if not mclassdef2nclassdef
.has_key
(superclassdef
) then continue
54 build_properties
(mclassdef2nclassdef
[superclassdef
])
57 for nclassdef2
in nclassdef
.all_defs
do
58 for npropdef
in nclassdef2
.n_propdefs
do
59 npropdef
.build_property
(self, mclassdef
)
61 for npropdef
in nclassdef2
.n_propdefs
do
62 npropdef
.build_signature
(self)
64 for npropdef
in nclassdef2
.n_propdefs
do
65 npropdef
.check_signature
(self)
68 process_default_constructors
(nclassdef
)
71 # the root init of the Object class
72 # Is usually implicitly defined
73 # Then explicit or implicit definitions of root-init are attached to it
74 var the_root_init_mmethod
: nullable MMethod
76 # Introduce or inherit default constructor
77 # This is the last part of `build_properties`.
78 private fun process_default_constructors
(nclassdef
: AClassdef)
80 var mclassdef
= nclassdef
.mclassdef
.as(not null)
83 if not mclassdef
.is_intro
then return
85 var mmodule
= nclassdef
.mclassdef
.mmodule
87 # Look for the init in Object, or create it
88 if mclassdef
.mclass
.name
== "Object" and the_root_init_mmethod
== null then
89 # Create the implicit root-init method
90 var mprop
= new MMethod(mclassdef
, "init", mclassdef
.mclass
.visibility
)
91 mprop
.is_root_init
= true
92 var mpropdef
= new MMethodDef(mclassdef
, mprop
, nclassdef
.location
)
93 var mparameters
= new Array[MParameter]
94 var msignature
= new MSignature(mparameters
, null)
95 mpropdef
.msignature
= msignature
96 mpropdef
.new_msignature
= msignature
98 nclassdef
.mfree_init
= mpropdef
99 self.toolcontext
.info
("{mclassdef} gets a free empty constructor {mpropdef}{msignature}", 3)
100 the_root_init_mmethod
= mprop
104 # Is the class forbid constructors?
105 if not mclassdef
.mclass
.kind
.need_init
then return
107 # Is there already a constructor defined?
108 var defined_init
: nullable MMethodDef = null
109 for mpropdef
in mclassdef
.mpropdefs
do
110 if not mpropdef
isa MMethodDef then continue
111 if not mpropdef
.mproperty
.is_init
then continue
112 if mpropdef
.mproperty
.is_root_init
then
113 assert defined_init
== null
114 defined_init
= mpropdef
116 # An explicit old-style init, so return
121 if not nclassdef
isa AStdClassdef then return
123 # Do we inherit a old-style constructor?
124 var combine
= new Array[MMethod] # old-style constructors without arguments
125 var inhc
: nullable MClass = null # single super-class with a constructor with arguments
126 if defined_init
== null then for st
in mclassdef
.supertypes
do
128 if not c
.kind
.need_init
then continue
129 st
= st
.anchor_to
(mmodule
, mclassdef
.bound_mtype
)
130 var candidate
= self.try_get_mproperty_by_name2
(nclassdef
, mmodule
, st
, "init").as(nullable MMethod)
131 if candidate
!= null then
132 if candidate
.is_root_init
then continue
133 if candidate
.intro
.msignature
!= null then
134 if candidate
.intro
.msignature
.arity
== 0 then
135 combine
.add
(candidate
)
140 var inhc2
= c
.inherit_init_from
141 if inhc2
== null then inhc2
= c
142 if inhc2
== inhc
then continue
144 self.error
(nclassdef
, "Error: Cannot provide a defaut constructor: conflict for {inhc} and {c}")
150 # Collect undefined attributes
151 var mparameters
= new Array[MParameter]
152 var initializers
= new Array[MProperty]
153 var anode
: nullable ANode = null
154 for npropdef
in nclassdef
.n_propdefs
do
155 if npropdef
isa AAttrPropdef then
156 if npropdef
.mpropdef
== null then return # Skip broken attribute
157 var at
= npropdef
.get_single_annotation
("noinit", self)
159 npropdef
.noinit
= true
160 if npropdef
.n_expr
!= null then
161 self.error
(at
, "Error: `noinit` attributes cannot have an initial value")
163 continue # Skip noinit attributes
165 if npropdef
.n_expr
!= null then continue
166 var paramname
= npropdef
.mpropdef
.mproperty
.name
.substring_from
(1)
167 var ret_type
= npropdef
.mpropdef
.static_mtype
168 if ret_type
== null then return
169 var mparameter
= new MParameter(paramname
, ret_type
, false)
170 mparameters
.add
(mparameter
)
171 var msetter
= npropdef
.mwritepropdef
172 if msetter
== null then
173 # No setter, it is a old-style attribute, so just add it
174 initializers
.add
(npropdef
.mpropdef
.mproperty
)
176 # Add the setter to the list
177 initializers
.add
(msetter
.mproperty
)
179 if anode
== null then anode
= npropdef
182 if anode
== null then anode
= nclassdef
184 if combine
.is_empty
and inhc
!= null then
185 if not mparameters
.is_empty
then
186 self.error
(anode
,"Error: {mclassdef} cannot inherit constructors from {inhc} because there is attributes without initial values: {mparameters.join(", ")}")
190 # TODO: actively inherit the consturctor
191 self.toolcontext
.info
("{mclassdef} inherits all constructors from {inhc}", 3)
192 #mclassdef.mclass.inherit_init_from = inhc
196 if not combine
.is_empty
and inhc
!= null then
197 self.error
(nclassdef
, "Error: Cannot provide a defaut constructor: conflict for {combine.join(", ")} and {inhc}")
200 if not combine
.is_empty
then
201 if mparameters
.is_empty
and combine
.length
== 1 then
202 # No need to create a local init, the inherited one is enough
203 inhc
= combine
.first
.intro_mclassdef
.mclass
204 mclassdef
.mclass
.inherit_init_from
= inhc
205 self.toolcontext
.info
("{mclassdef} inherits all constructors from {inhc}", 3)
208 nclassdef
.super_inits
= combine
209 var mprop
= new MMethod(mclassdef
, "init", mclassdef
.mclass
.visibility
)
210 var mpropdef
= new MMethodDef(mclassdef
, mprop
, nclassdef
.location
)
211 var msignature
= new MSignature(mparameters
, null)
212 mpropdef
.msignature
= msignature
214 nclassdef
.mfree_init
= mpropdef
215 self.toolcontext
.info
("{mclassdef} gets a free empty constructor {mpropdef}{msignature}", 3)
219 if the_root_init_mmethod
== null then return
221 # Look for nost-specific new-stype init definitions
222 var spropdefs
= the_root_init_mmethod
.lookup_super_definitions
(mclassdef
.mmodule
, mclassdef
.bound_mtype
)
223 if spropdefs
.is_empty
then
224 toolcontext
.fatal_error
(nclassdef
.location
, "Fatal error: {mclassdef} does not specialize {the_root_init_mmethod.intro_mclassdef}. Possible duplication of the root class `Object`?")
227 # Search the longest-one and checks for conflict
228 var longest
= spropdefs
.first
229 if spropdefs
.length
> 1 then
230 # Check for conflict in the order of initializers
231 # Each initializer list must me a prefix of the longest list
232 # part 1. find the longest list
233 for spd
in spropdefs
do
234 if spd
.initializers
.length
> longest
.initializers
.length
then longest
= spd
237 for spd
in spropdefs
do
239 for p
in spd
.initializers
do
240 if p
!= longest
.initializers
[i
] then
241 self.error
(nclassdef
, "Error: conflict for inherited inits {spd}({spd.initializers.join(", ")}) and {longest}({longest.initializers.join(", ")})")
249 # Can we just inherit?
250 if spropdefs
.length
== 1 and mparameters
.is_empty
and defined_init
== null then
251 self.toolcontext
.info
("{mclassdef} inherits the basic constructor {longest}", 3)
255 # Combine the inherited list to what is collected
256 if longest
.initializers
.length
> 0 then
257 mparameters
.prepend longest
.new_msignature
.mparameters
258 initializers
.prepend longest
.initializers
261 # If we already have a basic init definition, then setup its initializers
262 if defined_init
!= null then
263 defined_init
.initializers
.add_all
(initializers
)
264 var msignature
= new MSignature(mparameters
, null)
265 defined_init
.new_msignature
= msignature
266 self.toolcontext
.info
("{mclassdef} extends its basic constructor signature to {defined_init}{msignature}", 3)
270 # Else create the local implicit basic init definition
271 var mprop
= the_root_init_mmethod
.as(not null)
272 var mpropdef
= new MMethodDef(mclassdef
, mprop
, nclassdef
.location
)
273 mpropdef
.has_supercall
= true
274 mpropdef
.initializers
.add_all
(initializers
)
275 var msignature
= new MSignature(mparameters
, null)
276 mpropdef
.new_msignature
= msignature
277 mpropdef
.msignature
= new MSignature(new Array[MParameter], null) # always an empty real signature
278 nclassdef
.mfree_init
= mpropdef
279 self.toolcontext
.info
("{mclassdef} gets a free constructor for attributes {mpropdef}{msignature}", 3)
282 # Check the visibility of `mtype` as an element of the signature of `mpropdef`.
283 fun check_visibility
(node
: ANode, mtype
: MType, mpropdef
: MPropDef)
285 var mmodule
= mpropdef
.mclassdef
.mmodule
286 var mproperty
= mpropdef
.mproperty
288 # Extract visibility information of the main part of `mtype`
289 # It is a case-by case
290 var vis_type
: nullable MVisibility = null # The own visibility of the type
291 var mmodule_type
: nullable MModule = null # The origial module of the type
292 mtype
= mtype
.as_notnullable
293 if mtype
isa MClassType then
294 vis_type
= mtype
.mclass
.visibility
295 mmodule_type
= mtype
.mclass
.intro
.mmodule
296 else if mtype
isa MVirtualType then
297 vis_type
= mtype
.mproperty
.visibility
298 mmodule_type
= mtype
.mproperty
.intro_mclassdef
.mmodule
299 else if mtype
isa MParameterType then
300 # nothing, always visible
302 node
.debug
"Unexpected type {mtype}"
306 if vis_type
!= null then
307 assert mmodule_type
!= null
308 var vis_module_type
= mmodule
.visibility_for
(mmodule_type
) # the visibility of the original module
309 if mproperty
.visibility
> vis_type
then
310 error
(node
, "Error: The {mproperty.visibility} property `{mproperty}` cannot contain the {vis_type} type `{mtype}`")
312 else if mproperty
.visibility
> vis_module_type
then
313 error
(node
, "Error: The {mproperty.visibility} property `{mproperty}` cannot contain the type `{mtype}` from the {vis_module_type} module `{mmodule_type}`")
318 # No error, try to go deeper in generic types
319 if node
isa AType then
320 for a
in node
.n_types
do
322 if t
== null then continue # Error, thus skipped
323 check_visibility
(a
, t
, mpropdef
)
325 else if mtype
isa MGenericType then
326 for t
in mtype
.arguments
do check_visibility
(node
, t
, mpropdef
)
332 # The class whose self inherit all the constructors.
333 # 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
334 var inherit_init_from
: nullable MClass = null
338 # Does the MPropDef contains a call to super or a call of a super-constructor?
339 # Subsequent phases of the frontend (esp. typing) set it if required
340 var has_supercall
: Bool writable = false
343 redef class AClassdef
344 var build_properties_is_done
: Bool = false
345 # The list of super-constructor to call at the start of the free constructor
346 # 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
347 var super_inits
: nullable Collection[MMethod] = null
349 # The free init (implicitely constructed by the class if required)
350 var mfree_init
: nullable MMethodDef = null
353 redef class MClassDef
354 # What is the `APropdef` associated to a `MProperty`?
355 # Used to check multiple definition of a property.
356 var mprop2npropdef
: Map[MProperty, APropdef] = new HashMap[MProperty, APropdef]
360 # Join the text of all tokens
361 # Used to get the 'real name' of method definitions.
362 fun collect_text
: String
364 var v
= new TextCollectorVisitor
371 private class TextCollectorVisitor
373 var text
: String = ""
376 if n
isa Token then text
+= n
.text
382 # The associated main model entity
383 type MPROPDEF: MPropDef
385 # The associated propdef once build by a `ModelBuilder`
386 var mpropdef
: nullable MPROPDEF writable
388 private fun build_property
(modelbuilder
: ModelBuilder, mclassdef
: MClassDef) is abstract
389 private fun build_signature
(modelbuilder
: ModelBuilder) is abstract
390 private fun check_signature
(modelbuilder
: ModelBuilder) is abstract
391 private fun new_property_visibility
(modelbuilder
: ModelBuilder, mclassdef
: MClassDef, nvisibility
: nullable AVisibility): MVisibility
393 var mvisibility
= public_visibility
394 if nvisibility
!= null then
395 mvisibility
= nvisibility
.mvisibility
396 if mvisibility
== intrude_visibility
then
397 modelbuilder
.error
(nvisibility
, "Error: intrude is not a legal visibility for properties.")
398 mvisibility
= public_visibility
401 if mclassdef
.mclass
.visibility
== private_visibility
then
402 if mvisibility
== protected_visibility
then
403 assert nvisibility
!= null
404 modelbuilder
.error
(nvisibility
, "Error: The only legal visibility for properties in a private class is private.")
405 else if mvisibility
== private_visibility
then
406 assert nvisibility
!= null
408 # modelbuilder.warning(nvisibility, "Warning: private is unrequired since the only legal visibility for properties in a private class is private.")
410 mvisibility
= private_visibility
415 private fun set_doc
(mpropdef
: MPropDef)
417 var ndoc
= self.n_doc
419 var mdoc
= ndoc
.to_mdoc
421 mdoc
.original_mentity
= mpropdef
425 private fun check_redef_property_visibility
(modelbuilder
: ModelBuilder, nvisibility
: nullable AVisibility, mprop
: MProperty)
427 if nvisibility
== null then return
428 var mvisibility
= nvisibility
.mvisibility
429 if mvisibility
!= mprop
.visibility
and mvisibility
!= public_visibility
then
430 modelbuilder
.error
(nvisibility
, "Error: redefinition changed the visibility from a {mprop.visibility} to a {mvisibility}")
434 private fun check_redef_keyword
(modelbuilder
: ModelBuilder, mclassdef
: MClassDef, kwredef
: nullable Token, need_redef
: Bool, mprop
: MProperty): Bool
436 if mclassdef
.mprop2npropdef
.has_key
(mprop
) then
437 modelbuilder
.error
(self, "Error: A property {mprop} is already defined in class {mclassdef.mclass} at line {mclassdef.mprop2npropdef[mprop].location.line_start}.")
440 if mprop
isa MMethod and mprop
.is_toplevel
!= (parent
isa ATopClassdef) then
441 if mprop
.is_toplevel
then
442 modelbuilder
.error
(self, "Error: {mprop} is a top level method.")
444 modelbuilder
.error
(self, "Error: {mprop} is not a top level method.")
449 if kwredef
== null then
451 modelbuilder
.error
(self, "Redef error: {mclassdef.mclass}::{mprop.name} is an inherited property. To redefine it, add the redef keyword.")
455 if not need_redef
then
456 modelbuilder
.error
(self, "Error: No property {mclassdef.mclass}::{mprop.name} is inherited. Remove the redef keyword to define a new property.")
465 redef class ASignature
466 # Is the model builder has correctly visited the signature
467 var is_visited
= false
468 # Names of parameters from the AST
469 # REQUIRE: is_visited
470 var param_names
= new Array[String]
471 # Types of parameters from the AST
472 # REQUIRE: is_visited
473 var param_types
= new Array[MType]
474 # Rank of the vararg (of -1 if none)
475 # REQUIRE: is_visited
476 var vararg_rank
: Int = -1
478 var ret_type
: nullable MType = null
480 # Visit and fill information about a signature
481 private fun visit_signature
(modelbuilder
: ModelBuilder, mclassdef
: MClassDef): Bool
483 var mmodule
= mclassdef
.mmodule
484 var param_names
= self.param_names
485 var param_types
= self.param_types
486 for np
in self.n_params
do
487 param_names
.add
(np
.n_id
.text
)
488 var ntype
= np
.n_type
489 if ntype
!= null then
490 var mtype
= modelbuilder
.resolve_mtype
(mmodule
, mclassdef
, ntype
)
491 if mtype
== null then return false # Skip error
492 for i
in [0..param_names
.length-param_types
.length
[ do
493 param_types
.add
(mtype
)
495 if np
.n_dotdotdot
!= null then
496 if self.vararg_rank
!= -1 then
497 modelbuilder
.error
(np
, "Error: {param_names[self.vararg_rank]} is already a vararg")
500 self.vararg_rank
= param_names
.length
- 1
505 var ntype
= self.n_type
506 if ntype
!= null then
507 self.ret_type
= modelbuilder
.resolve_mtype
(mmodule
, mclassdef
, ntype
)
508 if self.ret_type
== null then return false # Skip errir
511 self.is_visited
= true
515 # Build a visited signature
516 fun build_signature
(modelbuilder
: ModelBuilder): nullable MSignature
518 if param_names
.length
!= param_types
.length
then
519 # Some parameters are typed, other parameters are not typed.
520 modelbuilder
.error
(self.n_params
[param_types
.length
], "Error: Untyped parameter `{param_names[param_types.length]}'.")
524 var mparameters
= new Array[MParameter]
525 for i
in [0..param_names
.length
[ do
526 var mparameter
= new MParameter(param_names
[i
], param_types
[i
], i
== vararg_rank
)
527 self.n_params
[i
].mparameter
= mparameter
528 mparameters
.add
(mparameter
)
531 var msignature
= new MSignature(mparameters
, ret_type
)
537 # The associated mparameter if any
538 var mparameter
: nullable MParameter = null
541 redef class AMethPropdef
542 redef type MPROPDEF: MMethodDef
545 # Can self be used as a root init?
546 private fun look_like_a_root_init
(modelbuilder
: ModelBuilder): Bool
548 # Need the `init` keyword
549 if n_kwinit
== null then return false
550 # Need to by anonymous
551 if self.n_methid
!= null then return false
553 if self.n_signature
.n_params
.length
> 0 then return false
554 # Cannot be private or something
555 if not self.n_visibility
isa APublicVisibility then return false
556 # No annotation on itself
557 if get_single_annotation
("old_style_init", modelbuilder
) != null then return false
559 var amod
= self.parent
.parent
.as(AModule)
560 var amoddecl
= amod
.n_moduledecl
561 if amoddecl
!= null then
562 var old
= amoddecl
.get_single_annotation
("old_style_init", modelbuilder
)
563 if old
!= null then return false
569 redef fun build_property
(modelbuilder
, mclassdef
)
571 var n_kwinit
= n_kwinit
572 var n_kwnew
= n_kwnew
573 var is_init
= n_kwinit
!= null or n_kwnew
!= null
575 var amethodid
= self.n_methid
577 if amethodid
== null then
581 else if n_kwinit
!= null then
584 else if n_kwnew
!= null then
590 else if amethodid
isa AIdMethid then
591 name
= amethodid
.n_id
.text
592 name_node
= amethodid
594 # operator, bracket or assign
595 name
= amethodid
.collect_text
596 name_node
= amethodid
598 if name
== "-" and self.n_signature
.n_params
.length
== 0 then
603 var mprop
: nullable MMethod = null
604 if not is_init
or n_kwredef
!= null then mprop
= modelbuilder
.try_get_mproperty_by_name
(name_node
, mclassdef
, name
).as(nullable MMethod)
605 if mprop
== null and look_like_a_root_init
(modelbuilder
) then
606 mprop
= modelbuilder
.the_root_init_mmethod
608 if mprop
== null then
609 var mvisibility
= new_property_visibility
(modelbuilder
, mclassdef
, self.n_visibility
)
610 mprop
= new MMethod(mclassdef
, name
, mvisibility
)
611 if look_like_a_root_init
(modelbuilder
) and modelbuilder
.the_root_init_mmethod
== null then
612 modelbuilder
.the_root_init_mmethod
= mprop
613 mprop
.is_root_init
= true
615 mprop
.is_init
= is_init
616 mprop
.is_new
= n_kwnew
!= null
617 if parent
isa ATopClassdef then mprop
.is_toplevel
= true
618 if not self.check_redef_keyword
(modelbuilder
, mclassdef
, n_kwredef
, false, mprop
) then return
620 if not mprop
.is_root_init
and not self.check_redef_keyword
(modelbuilder
, mclassdef
, n_kwredef
, not self isa AMainMethPropdef, mprop
) then return
621 check_redef_property_visibility
(modelbuilder
, self.n_visibility
, mprop
)
623 mclassdef
.mprop2npropdef
[mprop
] = self
625 var mpropdef
= new MMethodDef(mclassdef
, mprop
, self.location
)
629 self.mpropdef
= mpropdef
630 modelbuilder
.mpropdef2npropdef
[mpropdef
] = self
631 if mpropdef
.is_intro
then
632 modelbuilder
.toolcontext
.info
("{mpropdef} introduces new method {mprop.full_name}", 3)
634 modelbuilder
.toolcontext
.info
("{mpropdef} redefines method {mprop.full_name}", 3)
638 redef fun build_signature
(modelbuilder
)
640 var mpropdef
= self.mpropdef
641 if mpropdef
== null then return # Error thus skiped
642 var mclassdef
= mpropdef
.mclassdef
643 var mmodule
= mclassdef
.mmodule
644 var nsig
= self.n_signature
646 # Retrieve info from the signature AST
647 var param_names
= new Array[String] # Names of parameters from the AST
648 var param_types
= new Array[MType] # Types of parameters from the AST
650 var ret_type
: nullable MType = null # Return type from the AST
652 if not nsig
.visit_signature
(modelbuilder
, mclassdef
) then return
653 param_names
= nsig
.param_names
654 param_types
= nsig
.param_types
655 vararg_rank
= nsig
.vararg_rank
656 ret_type
= nsig
.ret_type
659 # Look for some signature to inherit
660 # FIXME: do not inherit from the intro, but from the most specific
661 var msignature
: nullable MSignature = null
662 if not mpropdef
.is_intro
then
663 msignature
= mpropdef
.mproperty
.intro
.msignature
664 if msignature
== null then return # Skip error
666 # Check inherited signature arity
667 if param_names
.length
!= msignature
.arity
then
669 if nsig
!= null then node
= nsig
else node
= self
670 modelbuilder
.error
(node
, "Redef error: {mpropdef} redefines {mpropdef.mproperty.intro} with {param_names.length} parameter(s), {msignature.arity} expected. Signature is {mpropdef}{msignature}")
673 else if mpropdef
.mproperty
.is_init
then
674 # FIXME UGLY: inherit signature from a super-constructor
675 for msupertype
in mclassdef
.supertypes
do
676 msupertype
= msupertype
.anchor_to
(mmodule
, mclassdef
.bound_mtype
)
677 var candidate
= modelbuilder
.try_get_mproperty_by_name2
(self, mmodule
, msupertype
, mpropdef
.mproperty
.name
)
678 if candidate
!= null then
679 if msignature
== null then
680 msignature
= candidate
.intro
.as(MMethodDef).msignature
687 # Inherit the signature
688 if msignature
!= null and param_names
.length
!= param_types
.length
and param_names
.length
== msignature
.arity
and param_types
.length
== 0 then
689 # Parameters are untyped, thus inherit them
690 param_types
= new Array[MType]
691 for mparameter
in msignature
.mparameters
do
692 param_types
.add
(mparameter
.mtype
)
694 vararg_rank
= msignature
.vararg_rank
696 if msignature
!= null and ret_type
== null then
697 ret_type
= msignature
.return_mtype
700 if param_names
.length
!= param_types
.length
then
701 # Some parameters are typed, other parameters are not typed.
702 modelbuilder
.error
(nsig
.n_params
[param_types
.length
], "Error: Untyped parameter `{param_names[param_types.length]}'.")
706 var mparameters
= new Array[MParameter]
707 for i
in [0..param_names
.length
[ do
708 var mparameter
= new MParameter(param_names
[i
], param_types
[i
], i
== vararg_rank
)
709 if nsig
!= null then nsig
.n_params
[i
].mparameter
= mparameter
710 mparameters
.add
(mparameter
)
713 msignature
= new MSignature(mparameters
, ret_type
)
714 mpropdef
.msignature
= msignature
715 mpropdef
.is_abstract
= self isa ADeferredMethPropdef
716 mpropdef
.is_intern
= self isa AInternMethPropdef
717 mpropdef
.is_extern
= self isa AExternPropdef
720 redef fun check_signature
(modelbuilder
)
722 var mpropdef
= self.mpropdef
723 if mpropdef
== null then return # Error thus skiped
724 var mclassdef
= mpropdef
.mclassdef
725 var mmodule
= mclassdef
.mmodule
726 var nsig
= self.n_signature
727 var mysignature
= self.mpropdef
.msignature
728 if mysignature
== null then return # Error thus skiped
730 # Lookup for signature in the precursor
731 # FIXME all precursors should be considered
732 if not mpropdef
.is_intro
then
733 var msignature
= mpropdef
.mproperty
.intro
.msignature
734 if msignature
== null then return
736 var precursor_ret_type
= msignature
.return_mtype
737 var ret_type
= mysignature
.return_mtype
738 if ret_type
!= null and precursor_ret_type
== null then
739 modelbuilder
.error
(nsig
.n_type
.as(not null), "Redef Error: {mpropdef.mproperty} is a procedure, not a function.")
743 if mysignature
.arity
> 0 then
744 # Check parameters types
745 for i
in [0..mysignature
.arity
[ do
746 var myt
= mysignature
.mparameters
[i
].mtype
747 var prt
= msignature
.mparameters
[i
].mtype
748 if not myt
.is_subtype
(mmodule
, mclassdef
.bound_mtype
, prt
) or
749 not prt
.is_subtype
(mmodule
, mclassdef
.bound_mtype
, myt
) then
750 modelbuilder
.error
(nsig
.n_params
[i
], "Redef Error: Wrong type for parameter `{mysignature.mparameters[i].name}'. found {myt}, expected {prt} as in {mpropdef.mproperty.intro}.")
754 if precursor_ret_type
!= null then
755 if ret_type
== null then
756 # Inherit the return type
757 ret_type
= precursor_ret_type
758 else if not ret_type
.is_subtype
(mmodule
, mclassdef
.bound_mtype
, precursor_ret_type
) then
759 modelbuilder
.error
(nsig
.n_type
.as(not null), "Redef Error: Wrong return type. found {ret_type}, expected {precursor_ret_type} as in {mpropdef.mproperty.intro}.")
764 if mysignature
.arity
> 0 then
765 # Check parameters visibility
766 for i
in [0..mysignature
.arity
[ do
767 var nt
= nsig
.n_params
[i
].n_type
768 if nt
!= null then modelbuilder
.check_visibility
(nt
, nt
.mtype
.as(not null), mpropdef
)
771 if nt
!= null then modelbuilder
.check_visibility
(nt
, nt
.mtype
.as(not null), mpropdef
)
776 redef class AAttrPropdef
777 redef type MPROPDEF: MAttributeDef
779 # Is the node tagged `noinit`?
782 # Is the node taggeg lazy?
785 # The guard associated to a lasy attribute.
786 # Because some engines does not have a working `isset`,
787 # this additionnal attribute is used to guard the lazy initialization.
788 # TODO: to remove once isset is correctly implemented
789 var mlazypropdef
: nullable MAttributeDef
791 # The associated getter (read accessor) if any
792 var mreadpropdef
: nullable MMethodDef writable
793 # The associated setter (write accessor) if any
794 var mwritepropdef
: nullable MMethodDef writable
796 redef fun build_property
(modelbuilder
, mclassdef
)
798 var mclass
= mclassdef
.mclass
801 if self.n_id
!= null then
802 name
= self.n_id
.text
804 name
= self.n_id2
.text
807 if mclass
.kind
== interface_kind
or mclassdef
.mclass
.kind
== enum_kind
then
808 modelbuilder
.error
(self, "Error: Attempt to define attribute {name} in the interface {mclass}.")
809 else if mclass
.kind
== enum_kind
then
810 modelbuilder
.error
(self, "Error: Attempt to define attribute {name} in the enum class {mclass}.")
811 else if mclass
.kind
== extern_kind
then
812 modelbuilder
.error
(self, "Error: Attempt to define attribute {name} in the extern class {mclass}.")
817 # Old attribute style
818 var mprop
= modelbuilder
.try_get_mproperty_by_name
(nid
, mclassdef
, name
)
819 if mprop
== null then
820 var mvisibility
= new_property_visibility
(modelbuilder
, mclassdef
, self.n_visibility
)
821 mprop
= new MAttribute(mclassdef
, name
, mvisibility
)
822 if not self.check_redef_keyword
(modelbuilder
, mclassdef
, self.n_kwredef
, false, mprop
) then return
824 assert mprop
isa MAttribute
825 check_redef_property_visibility
(modelbuilder
, self.n_visibility
, mprop
)
826 if not self.check_redef_keyword
(modelbuilder
, mclassdef
, self.n_kwredef
, true, mprop
) then return
828 mclassdef
.mprop2npropdef
[mprop
] = self
830 var mpropdef
= new MAttributeDef(mclassdef
, mprop
, self.location
)
831 self.mpropdef
= mpropdef
832 modelbuilder
.mpropdef2npropdef
[mpropdef
] = self
835 var nreadable
= self.n_readable
836 if nreadable
!= null then modelbuilder
.error
(nreadable
, "Error: old-style getter no more supported")
837 var nwritable
= self.n_writable
838 if nwritable
!= null then modelbuilder
.error
(nwritable
, "Error: old-style setter no more supported")
840 # New attribute style
841 var nid2
= self.n_id2
.as(not null)
842 var mprop
= new MAttribute(mclassdef
, "_" + name
, private_visibility
)
843 var mpropdef
= new MAttributeDef(mclassdef
, mprop
, self.location
)
844 self.mpropdef
= mpropdef
845 modelbuilder
.mpropdef2npropdef
[mpropdef
] = self
849 var mreadprop
= modelbuilder
.try_get_mproperty_by_name
(nid2
, mclassdef
, readname
).as(nullable MMethod)
850 if mreadprop
== null then
851 var mvisibility
= new_property_visibility
(modelbuilder
, mclassdef
, self.n_visibility
)
852 mreadprop
= new MMethod(mclassdef
, readname
, mvisibility
)
853 if not self.check_redef_keyword
(modelbuilder
, mclassdef
, n_kwredef
, false, mreadprop
) then return
855 if not self.check_redef_keyword
(modelbuilder
, mclassdef
, n_kwredef
, true, mreadprop
) then return
856 check_redef_property_visibility
(modelbuilder
, self.n_visibility
, mreadprop
)
858 mclassdef
.mprop2npropdef
[mreadprop
] = self
860 var mreadpropdef
= new MMethodDef(mclassdef
, mreadprop
, self.location
)
861 self.mreadpropdef
= mreadpropdef
862 modelbuilder
.mpropdef2npropdef
[mreadpropdef
] = self
863 mreadpropdef
.mdoc
= mpropdef
.mdoc
865 var atlazy
= self.get_single_annotation
("lazy", modelbuilder
)
866 if atlazy
!= null then
867 if n_expr
== null then
868 modelbuilder
.error
(atlazy
, "Error: a lazy attribute needs a value")
871 var mlazyprop
= new MAttribute(mclassdef
, "lazy _" + name
, none_visibility
)
872 var mlazypropdef
= new MAttributeDef(mclassdef
, mlazyprop
, self.location
)
873 self.mlazypropdef
= mlazypropdef
876 var atreadonly
= self.get_single_annotation
("readonly", modelbuilder
)
877 if atreadonly
!= null then
878 if n_expr
== null then
879 modelbuilder
.error
(atreadonly
, "Error: a readonly attribute needs a value")
881 # No setter, so just leave
885 var writename
= name
+ "="
886 var nwritable
= self.n_writable
887 var atwritable
= self.get_single_annotation
("writable", modelbuilder
)
888 if atwritable
!= null then
889 if not atwritable
.n_args
.is_empty
then
890 writename
= atwritable
.arg_as_id
(modelbuilder
) or else writename
893 var mwriteprop
= modelbuilder
.try_get_mproperty_by_name
(nid2
, mclassdef
, writename
).as(nullable MMethod)
894 var nwkwredef
: nullable Token = null
895 if nwritable
!= null then nwkwredef
= nwritable
.n_kwredef
896 if atwritable
!= null then nwkwredef
= atwritable
.n_kwredef
897 if mwriteprop
== null then
899 if nwritable
!= null then
900 mvisibility
= new_property_visibility
(modelbuilder
, mclassdef
, nwritable
.n_visibility
)
901 else if atwritable
!= null then
902 mvisibility
= new_property_visibility
(modelbuilder
, mclassdef
, atwritable
.n_visibility
)
904 mvisibility
= private_visibility
906 mwriteprop
= new MMethod(mclassdef
, writename
, mvisibility
)
907 if not self.check_redef_keyword
(modelbuilder
, mclassdef
, nwkwredef
, false, mwriteprop
) then return
909 if not self.check_redef_keyword
(modelbuilder
, mclassdef
, nwkwredef
or else n_kwredef
, true, mwriteprop
) then return
910 if nwritable
!= null then
911 check_redef_property_visibility
(modelbuilder
, nwritable
.n_visibility
, mwriteprop
)
912 else if atwritable
!= null then
913 check_redef_property_visibility
(modelbuilder
, atwritable
.n_visibility
, mwriteprop
)
916 mclassdef
.mprop2npropdef
[mwriteprop
] = self
918 var mwritepropdef
= new MMethodDef(mclassdef
, mwriteprop
, self.location
)
919 self.mwritepropdef
= mwritepropdef
920 modelbuilder
.mpropdef2npropdef
[mwritepropdef
] = self
921 mwritepropdef
.mdoc
= mpropdef
.mdoc
925 redef fun build_signature
(modelbuilder
)
927 var mpropdef
= self.mpropdef
928 if mpropdef
== null then return # Error thus skiped
929 var mclassdef
= mpropdef
.mclassdef
930 var mmodule
= mclassdef
.mmodule
931 var mtype
: nullable MType = null
933 var mreadpropdef
= self.mreadpropdef
935 var ntype
= self.n_type
936 if ntype
!= null then
937 mtype
= modelbuilder
.resolve_mtype
(mmodule
, mclassdef
, ntype
)
938 if mtype
== null then return
941 # Inherit the type from the getter (usually an abstact getter)
942 if mtype
== null and mreadpropdef
!= null and not mreadpropdef
.is_intro
then
943 var msignature
= mreadpropdef
.mproperty
.intro
.msignature
944 if msignature
== null then return # Error, thus skiped
945 mtype
= msignature
.return_mtype
948 var nexpr
= self.n_expr
949 if mtype
== null then
950 if nexpr
!= null then
951 if nexpr
isa ANewExpr then
952 mtype
= modelbuilder
.resolve_mtype
(mmodule
, mclassdef
, nexpr
.n_type
)
953 else if nexpr
isa AIntExpr then
954 var cla
= modelbuilder
.try_get_mclass_by_name
(nexpr
, mmodule
, "Int")
955 if cla
!= null then mtype
= cla
.mclass_type
956 else if nexpr
isa AFloatExpr then
957 var cla
= modelbuilder
.try_get_mclass_by_name
(nexpr
, mmodule
, "Float")
958 if cla
!= null then mtype
= cla
.mclass_type
959 else if nexpr
isa ACharExpr then
960 var cla
= modelbuilder
.try_get_mclass_by_name
(nexpr
, mmodule
, "Char")
961 if cla
!= null then mtype
= cla
.mclass_type
962 else if nexpr
isa ABoolExpr then
963 var cla
= modelbuilder
.try_get_mclass_by_name
(nexpr
, mmodule
, "Bool")
964 if cla
!= null then mtype
= cla
.mclass_type
965 else if nexpr
isa ASuperstringExpr then
966 var cla
= modelbuilder
.try_get_mclass_by_name
(nexpr
, mmodule
, "String")
967 if cla
!= null then mtype
= cla
.mclass_type
968 else if nexpr
isa AStringFormExpr then
969 var cla
= modelbuilder
.try_get_mclass_by_name
(nexpr
, mmodule
, "String")
970 if cla
!= null then mtype
= cla
.mclass_type
972 modelbuilder
.error
(self, "Error: Untyped attribute {mpropdef}. Implicit typing allowed only for literals and new.")
975 if mtype
== null then return
977 else if ntype
!= null then
978 if nexpr
isa ANewExpr then
979 var xmtype
= modelbuilder
.resolve_mtype
(mmodule
, mclassdef
, nexpr
.n_type
)
980 if xmtype
== mtype
and modelbuilder
.toolcontext
.opt_warn
.value
>= 2 then
981 modelbuilder
.warning
(ntype
, "Warning: useless type definition")
986 if mtype
== null then
987 modelbuilder
.error
(self, "Error: Untyped attribute {mpropdef}")
991 mpropdef
.static_mtype
= mtype
993 if mreadpropdef
!= null then
994 var msignature
= new MSignature(new Array[MParameter], mtype
)
995 mreadpropdef
.msignature
= msignature
998 var mwritepropdef
= self.mwritepropdef
999 if mwritepropdef
!= null then
1001 if n_id
!= null then
1002 name
= n_id
.text
.substring_from
(1)
1006 var mparameter
= new MParameter(name
, mtype
, false)
1007 var msignature
= new MSignature([mparameter
], null)
1008 mwritepropdef
.msignature
= msignature
1011 var mlazypropdef
= self.mlazypropdef
1012 if mlazypropdef
!= null then
1013 mlazypropdef
.static_mtype
= modelbuilder
.model
.get_mclasses_by_name
("Bool").first
.mclass_type
1017 redef fun check_signature
(modelbuilder
)
1019 var mpropdef
= self.mpropdef
1020 if mpropdef
== null then return # Error thus skiped
1021 var mclassdef
= mpropdef
.mclassdef
1022 var mmodule
= mclassdef
.mmodule
1023 var ntype
= self.n_type
1024 var mtype
= self.mpropdef
.static_mtype
1025 if mtype
== null then return # Error thus skiped
1027 # Lookup for signature in the precursor
1028 # FIXME all precursors should be considered
1029 if not mpropdef
.is_intro
then
1030 var precursor_type
= mpropdef
.mproperty
.intro
.static_mtype
1031 if precursor_type
== null then return
1033 if mtype
!= precursor_type
then
1034 modelbuilder
.error
(ntype
.as(not null), "Redef Error: Wrong static type. found {mtype}, expected {precursor_type}.")
1039 # Check getter and setter
1040 var meth
= self.mreadpropdef
1041 if meth
!= null then
1042 self.check_method_signature
(modelbuilder
, meth
)
1043 var node
: nullable ANode = ntype
1044 if node
== null then node
= self
1045 modelbuilder
.check_visibility
(node
, mtype
, meth
)
1047 meth
= self.mwritepropdef
1048 if meth
!= null then
1049 self.check_method_signature
(modelbuilder
, meth
)
1050 var node
: nullable ANode = ntype
1051 if node
== null then node
= self
1052 modelbuilder
.check_visibility
(node
, mtype
, meth
)
1056 private fun check_method_signature
(modelbuilder
: ModelBuilder, mpropdef
: MMethodDef)
1058 var mclassdef
= mpropdef
.mclassdef
1059 var mmodule
= mclassdef
.mmodule
1060 var nsig
= self.n_type
1061 var mysignature
= mpropdef
.msignature
1062 if mysignature
== null then return # Error thus skiped
1064 # Lookup for signature in the precursor
1065 # FIXME all precursors should be considered
1066 if not mpropdef
.is_intro
then
1067 var msignature
= mpropdef
.mproperty
.intro
.msignature
1068 if msignature
== null then return
1070 if mysignature
.arity
!= msignature
.arity
then
1072 if nsig
!= null then node
= nsig
else node
= self
1073 modelbuilder
.error
(node
, "Redef Error: {mysignature.arity} parameters found, {msignature.arity} expected. Signature is {mpropdef}{msignature}")
1076 var precursor_ret_type
= msignature
.return_mtype
1077 var ret_type
= mysignature
.return_mtype
1078 if ret_type
!= null and precursor_ret_type
== null then
1080 if nsig
!= null then node
= nsig
else node
= self
1081 modelbuilder
.error
(node
, "Redef Error: {mpropdef.mproperty} is a procedure, not a function.")
1085 if mysignature
.arity
> 0 then
1086 # Check parameters types
1087 for i
in [0..mysignature
.arity
[ do
1088 var myt
= mysignature
.mparameters
[i
].mtype
1089 var prt
= msignature
.mparameters
[i
].mtype
1090 if not myt
.is_subtype
(mmodule
, mclassdef
.bound_mtype
, prt
) or
1091 not prt
.is_subtype
(mmodule
, mclassdef
.bound_mtype
, myt
) then
1093 if nsig
!= null then node
= nsig
else node
= self
1094 modelbuilder
.error
(node
, "Redef Error: Wrong type for parameter `{mysignature.mparameters[i].name}'. found {myt}, expected {prt}.")
1098 if precursor_ret_type
!= null then
1099 if ret_type
== null then
1100 # Inherit the return type
1101 ret_type
= precursor_ret_type
1102 else if not ret_type
.is_subtype
(mmodule
, mclassdef
.bound_mtype
, precursor_ret_type
) then
1104 if nsig
!= null then node
= nsig
else node
= self
1105 modelbuilder
.error
(node
, "Redef Error: Wrong return type. found {ret_type}, expected {precursor_ret_type}.")
1112 redef class ATypePropdef
1113 redef type MPROPDEF: MVirtualTypeDef
1115 redef fun build_property
(modelbuilder
, mclassdef
)
1117 var name
= self.n_id
.text
1118 var mprop
= modelbuilder
.try_get_mproperty_by_name
(self.n_id
, mclassdef
, name
)
1119 if mprop
== null then
1120 var mvisibility
= new_property_visibility
(modelbuilder
, mclassdef
, self.n_visibility
)
1121 mprop
= new MVirtualTypeProp(mclassdef
, name
, mvisibility
)
1122 for c
in name
.chars
do if c
>= 'a' and c
<= 'z' then
1123 modelbuilder
.warning
(n_id
, "Warning: lowercase in the virtual type {name}")
1126 if not self.check_redef_keyword
(modelbuilder
, mclassdef
, self.n_kwredef
, false, mprop
) then return
1128 if not self.check_redef_keyword
(modelbuilder
, mclassdef
, self.n_kwredef
, true, mprop
) then return
1129 assert mprop
isa MVirtualTypeProp
1130 check_redef_property_visibility
(modelbuilder
, self.n_visibility
, mprop
)
1132 mclassdef
.mprop2npropdef
[mprop
] = self
1134 var mpropdef
= new MVirtualTypeDef(mclassdef
, mprop
, self.location
)
1135 self.mpropdef
= mpropdef
1136 modelbuilder
.mpropdef2npropdef
[mpropdef
] = self
1139 var atfixed
= get_single_annotation
("fixed", modelbuilder
)
1140 if atfixed
!= null then
1141 mpropdef
.is_fixed
= true
1145 redef fun build_signature
(modelbuilder
)
1147 var mpropdef
= self.mpropdef
1148 if mpropdef
== null then return # Error thus skiped
1149 var mclassdef
= mpropdef
.mclassdef
1150 var mmodule
= mclassdef
.mmodule
1151 var mtype
: nullable MType = null
1153 var ntype
= self.n_type
1154 mtype
= modelbuilder
.resolve_mtype
(mmodule
, mclassdef
, ntype
)
1155 if mtype
== null then return
1157 mpropdef
.bound
= mtype
1158 # print "{mpropdef}: {mtype}"
1161 redef fun check_signature
(modelbuilder
)
1163 var mpropdef
= self.mpropdef
1164 if mpropdef
== null then return # Error thus skiped
1166 var bound
= self.mpropdef
.bound
1167 if bound
== null then return # Error thus skiped
1169 modelbuilder
.check_visibility
(n_type
, bound
, mpropdef
)
1171 var mclassdef
= mpropdef
.mclassdef
1172 var mmodule
= mclassdef
.mmodule
1173 var anchor
= mclassdef
.bound_mtype
1176 if bound
isa MVirtualType then
1177 # Slow case: progress on each resolution until: (i) we loop, or (ii) we found a non formal type
1178 var seen
= [self.mpropdef
.mproperty
.mvirtualtype
]
1180 if seen
.has
(bound
) then
1182 modelbuilder
.error
(self, "Error: circularity of virtual type definition: {seen.join(" -> ")}")
1186 var next
= bound
.lookup_bound
(mmodule
, anchor
)
1187 if not next
isa MVirtualType then break
1192 # Check redefinitions
1193 bound
= mpropdef
.bound
.as(not null)
1194 for p
in mpropdef
.mproperty
.lookup_super_definitions
(mmodule
, anchor
) do
1195 var supbound
= p
.bound
.as(not null)
1197 modelbuilder
.error
(self, "Redef Error: Virtual type {mpropdef.mproperty} is fixed in super-class {p.mclassdef.mclass}")
1200 if p
.mclassdef
.mclass
== mclassdef
.mclass
then
1201 # Still a warning to pass existing bad code
1202 modelbuilder
.warning
(n_type
, "Redef Error: a virtual type cannot be refined.")
1205 if not bound
.is_subtype
(mmodule
, anchor
, supbound
) then
1206 modelbuilder
.error
(n_type
, "Redef Error: Wrong bound type. Found {bound}, expected a subtype of {supbound}, as in {p}.")