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 = false is writable
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 is 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
, "useless-visibility", "Warning: private is superfluous since the only legal visibility for properties in a private class is private.")
410 mvisibility
= private_visibility
415 private fun set_doc
(mpropdef
: MPropDef, modelbuilder
: ModelBuilder)
417 var ndoc
= self.n_doc
419 var mdoc
= ndoc
.to_mdoc
421 mdoc
.original_mentity
= mpropdef
424 var at_deprecated
= get_single_annotation
("deprecated", modelbuilder
)
425 if at_deprecated
!= null then
426 if not mpropdef
.is_intro
then
427 modelbuilder
.error
(self, "Error: method redefinition cannot be deprecated.")
429 var info
= new MDeprecationInfo
430 ndoc
= at_deprecated
.n_doc
431 if ndoc
!= null then info
.mdoc
= ndoc
.to_mdoc
432 mpropdef
.mproperty
.deprecation
= info
437 private fun check_redef_property_visibility
(modelbuilder
: ModelBuilder, nvisibility
: nullable AVisibility, mprop
: MProperty)
439 if nvisibility
== null then return
440 var mvisibility
= nvisibility
.mvisibility
441 if mvisibility
!= mprop
.visibility
and mvisibility
!= public_visibility
then
442 modelbuilder
.error
(nvisibility
, "Error: redefinition changed the visibility from a {mprop.visibility} to a {mvisibility}")
446 private fun check_redef_keyword
(modelbuilder
: ModelBuilder, mclassdef
: MClassDef, kwredef
: nullable Token, need_redef
: Bool, mprop
: MProperty): Bool
448 if mclassdef
.mprop2npropdef
.has_key
(mprop
) then
449 modelbuilder
.error
(self, "Error: A property {mprop} is already defined in class {mclassdef.mclass} at line {mclassdef.mprop2npropdef[mprop].location.line_start}.")
452 if mprop
isa MMethod and mprop
.is_toplevel
!= (parent
isa ATopClassdef) then
453 if mprop
.is_toplevel
then
454 modelbuilder
.error
(self, "Error: {mprop} is a top level method.")
456 modelbuilder
.error
(self, "Error: {mprop} is not a top level method.")
461 if kwredef
== null then
463 modelbuilder
.error
(self, "Redef error: {mclassdef.mclass}::{mprop.name} is an inherited property. To redefine it, add the redef keyword.")
467 if not need_redef
then
468 modelbuilder
.error
(self, "Error: No property {mclassdef.mclass}::{mprop.name} is inherited. Remove the redef keyword to define a new property.")
477 redef class ASignature
478 # Is the model builder has correctly visited the signature
479 var is_visited
= false
480 # Names of parameters from the AST
481 # REQUIRE: is_visited
482 var param_names
= new Array[String]
483 # Types of parameters from the AST
484 # REQUIRE: is_visited
485 var param_types
= new Array[MType]
486 # Rank of the vararg (of -1 if none)
487 # REQUIRE: is_visited
488 var vararg_rank
: Int = -1
490 var ret_type
: nullable MType = null
492 # Visit and fill information about a signature
493 private fun visit_signature
(modelbuilder
: ModelBuilder, mclassdef
: MClassDef): Bool
495 var mmodule
= mclassdef
.mmodule
496 var param_names
= self.param_names
497 var param_types
= self.param_types
498 for np
in self.n_params
do
499 param_names
.add
(np
.n_id
.text
)
500 var ntype
= np
.n_type
501 if ntype
!= null then
502 var mtype
= modelbuilder
.resolve_mtype
(mmodule
, mclassdef
, ntype
)
503 if mtype
== null then return false # Skip error
504 for i
in [0..param_names
.length-param_types
.length
[ do
505 param_types
.add
(mtype
)
507 if np
.n_dotdotdot
!= null then
508 if self.vararg_rank
!= -1 then
509 modelbuilder
.error
(np
, "Error: {param_names[self.vararg_rank]} is already a vararg")
512 self.vararg_rank
= param_names
.length
- 1
517 var ntype
= self.n_type
518 if ntype
!= null then
519 self.ret_type
= modelbuilder
.resolve_mtype
(mmodule
, mclassdef
, ntype
)
520 if self.ret_type
== null then return false # Skip errir
523 self.is_visited
= true
527 # Build a visited signature
528 fun build_signature
(modelbuilder
: ModelBuilder): nullable MSignature
530 if param_names
.length
!= param_types
.length
then
531 # Some parameters are typed, other parameters are not typed.
532 modelbuilder
.error
(self.n_params
[param_types
.length
], "Error: Untyped parameter `{param_names[param_types.length]}'.")
536 var mparameters
= new Array[MParameter]
537 for i
in [0..param_names
.length
[ do
538 var mparameter
= new MParameter(param_names
[i
], param_types
[i
], i
== vararg_rank
)
539 self.n_params
[i
].mparameter
= mparameter
540 mparameters
.add
(mparameter
)
543 var msignature
= new MSignature(mparameters
, ret_type
)
549 # The associated mparameter if any
550 var mparameter
: nullable MParameter = null
553 redef class AMethPropdef
554 redef type MPROPDEF: MMethodDef
557 # Can self be used as a root init?
558 private fun look_like_a_root_init
(modelbuilder
: ModelBuilder): Bool
560 # Need the `init` keyword
561 if n_kwinit
== null then return false
562 # Need to by anonymous
563 if self.n_methid
!= null then return false
565 if self.n_signature
.n_params
.length
> 0 then return false
566 # Cannot be private or something
567 if not self.n_visibility
isa APublicVisibility then return false
568 # No annotation on itself
569 if get_single_annotation
("old_style_init", modelbuilder
) != null then return false
571 var amod
= self.parent
.parent
.as(AModule)
572 var amoddecl
= amod
.n_moduledecl
573 if amoddecl
!= null then
574 var old
= amoddecl
.get_single_annotation
("old_style_init", modelbuilder
)
575 if old
!= null then return false
581 redef fun build_property
(modelbuilder
, mclassdef
)
583 var n_kwinit
= n_kwinit
584 var n_kwnew
= n_kwnew
585 var is_init
= n_kwinit
!= null or n_kwnew
!= null
587 var amethodid
= self.n_methid
589 if amethodid
== null then
593 else if n_kwinit
!= null then
596 else if n_kwnew
!= null then
602 else if amethodid
isa AIdMethid then
603 name
= amethodid
.n_id
.text
604 name_node
= amethodid
606 # operator, bracket or assign
607 name
= amethodid
.collect_text
608 name_node
= amethodid
610 if name
== "-" and self.n_signature
.n_params
.length
== 0 then
615 var mprop
: nullable MMethod = null
616 if not is_init
or n_kwredef
!= null then mprop
= modelbuilder
.try_get_mproperty_by_name
(name_node
, mclassdef
, name
).as(nullable MMethod)
617 if mprop
== null and look_like_a_root_init
(modelbuilder
) then
618 mprop
= modelbuilder
.the_root_init_mmethod
620 if mprop
== null then
621 var mvisibility
= new_property_visibility
(modelbuilder
, mclassdef
, self.n_visibility
)
622 mprop
= new MMethod(mclassdef
, name
, mvisibility
)
623 if look_like_a_root_init
(modelbuilder
) and modelbuilder
.the_root_init_mmethod
== null then
624 modelbuilder
.the_root_init_mmethod
= mprop
625 mprop
.is_root_init
= true
627 mprop
.is_init
= is_init
628 mprop
.is_new
= n_kwnew
!= null
629 if parent
isa ATopClassdef then mprop
.is_toplevel
= true
630 if not self.check_redef_keyword
(modelbuilder
, mclassdef
, n_kwredef
, false, mprop
) then return
632 if not mprop
.is_root_init
and not self.check_redef_keyword
(modelbuilder
, mclassdef
, n_kwredef
, not self isa AMainMethPropdef, mprop
) then return
633 check_redef_property_visibility
(modelbuilder
, self.n_visibility
, mprop
)
635 mclassdef
.mprop2npropdef
[mprop
] = self
637 var mpropdef
= new MMethodDef(mclassdef
, mprop
, self.location
)
639 set_doc
(mpropdef
, modelbuilder
)
641 self.mpropdef
= mpropdef
642 modelbuilder
.mpropdef2npropdef
[mpropdef
] = self
643 if mpropdef
.is_intro
then
644 modelbuilder
.toolcontext
.info
("{mpropdef} introduces new method {mprop.full_name}", 3)
646 modelbuilder
.toolcontext
.info
("{mpropdef} redefines method {mprop.full_name}", 3)
650 redef fun build_signature
(modelbuilder
)
652 var mpropdef
= self.mpropdef
653 if mpropdef
== null then return # Error thus skiped
654 var mclassdef
= mpropdef
.mclassdef
655 var mmodule
= mclassdef
.mmodule
656 var nsig
= self.n_signature
658 # Retrieve info from the signature AST
659 var param_names
= new Array[String] # Names of parameters from the AST
660 var param_types
= new Array[MType] # Types of parameters from the AST
662 var ret_type
: nullable MType = null # Return type from the AST
664 if not nsig
.visit_signature
(modelbuilder
, mclassdef
) then return
665 param_names
= nsig
.param_names
666 param_types
= nsig
.param_types
667 vararg_rank
= nsig
.vararg_rank
668 ret_type
= nsig
.ret_type
671 # Look for some signature to inherit
672 # FIXME: do not inherit from the intro, but from the most specific
673 var msignature
: nullable MSignature = null
674 if not mpropdef
.is_intro
then
675 msignature
= mpropdef
.mproperty
.intro
.msignature
676 if msignature
== null then return # Skip error
678 # Check inherited signature arity
679 if param_names
.length
!= msignature
.arity
then
681 if nsig
!= null then node
= nsig
else node
= self
682 modelbuilder
.error
(node
, "Redef error: {mpropdef} redefines {mpropdef.mproperty.intro} with {param_names.length} parameter(s), {msignature.arity} expected. Signature is {mpropdef}{msignature}")
685 else if mpropdef
.mproperty
.is_init
then
686 # FIXME UGLY: inherit signature from a super-constructor
687 for msupertype
in mclassdef
.supertypes
do
688 msupertype
= msupertype
.anchor_to
(mmodule
, mclassdef
.bound_mtype
)
689 var candidate
= modelbuilder
.try_get_mproperty_by_name2
(self, mmodule
, msupertype
, mpropdef
.mproperty
.name
)
690 if candidate
!= null then
691 if msignature
== null then
692 msignature
= candidate
.intro
.as(MMethodDef).msignature
699 # Inherit the signature
700 if msignature
!= null and param_names
.length
!= param_types
.length
and param_names
.length
== msignature
.arity
and param_types
.length
== 0 then
701 # Parameters are untyped, thus inherit them
702 param_types
= new Array[MType]
703 for mparameter
in msignature
.mparameters
do
704 param_types
.add
(mparameter
.mtype
)
706 vararg_rank
= msignature
.vararg_rank
708 if msignature
!= null and ret_type
== null then
709 ret_type
= msignature
.return_mtype
712 if param_names
.length
!= param_types
.length
then
713 # Some parameters are typed, other parameters are not typed.
714 modelbuilder
.error
(nsig
.n_params
[param_types
.length
], "Error: Untyped parameter `{param_names[param_types.length]}'.")
718 var mparameters
= new Array[MParameter]
719 for i
in [0..param_names
.length
[ do
720 var mparameter
= new MParameter(param_names
[i
], param_types
[i
], i
== vararg_rank
)
721 if nsig
!= null then nsig
.n_params
[i
].mparameter
= mparameter
722 mparameters
.add
(mparameter
)
725 msignature
= new MSignature(mparameters
, ret_type
)
726 mpropdef
.msignature
= msignature
727 mpropdef
.is_abstract
= self isa ADeferredMethPropdef or self.get_single_annotation
("abstract", modelbuilder
) != null
728 mpropdef
.is_intern
= self isa AInternMethPropdef or self.get_single_annotation
("intern", modelbuilder
) != null
729 mpropdef
.is_extern
= self isa AExternPropdef or self.n_extern_code_block
!= null or self.get_single_annotation
("extern", modelbuilder
) != null
732 redef fun check_signature
(modelbuilder
)
734 var mpropdef
= self.mpropdef
735 if mpropdef
== null then return # Error thus skiped
736 var mclassdef
= mpropdef
.mclassdef
737 var mmodule
= mclassdef
.mmodule
738 var nsig
= self.n_signature
739 var mysignature
= self.mpropdef
.msignature
740 if mysignature
== null then return # Error thus skiped
742 # Lookup for signature in the precursor
743 # FIXME all precursors should be considered
744 if not mpropdef
.is_intro
then
745 var msignature
= mpropdef
.mproperty
.intro
.msignature
746 if msignature
== null then return
748 var precursor_ret_type
= msignature
.return_mtype
749 var ret_type
= mysignature
.return_mtype
750 if ret_type
!= null and precursor_ret_type
== null then
751 modelbuilder
.error
(nsig
.n_type
.as(not null), "Redef Error: {mpropdef.mproperty} is a procedure, not a function.")
755 if mysignature
.arity
> 0 then
756 # Check parameters types
757 for i
in [0..mysignature
.arity
[ do
758 var myt
= mysignature
.mparameters
[i
].mtype
759 var prt
= msignature
.mparameters
[i
].mtype
760 if not myt
.is_subtype
(mmodule
, mclassdef
.bound_mtype
, prt
) or
761 not prt
.is_subtype
(mmodule
, mclassdef
.bound_mtype
, myt
) then
762 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}.")
766 if precursor_ret_type
!= null then
767 if ret_type
== null then
768 # Inherit the return type
769 ret_type
= precursor_ret_type
770 else if not ret_type
.is_subtype
(mmodule
, mclassdef
.bound_mtype
, precursor_ret_type
) then
771 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}.")
776 if mysignature
.arity
> 0 then
777 # Check parameters visibility
778 for i
in [0..mysignature
.arity
[ do
779 var nt
= nsig
.n_params
[i
].n_type
780 if nt
!= null then modelbuilder
.check_visibility
(nt
, nt
.mtype
.as(not null), mpropdef
)
783 if nt
!= null then modelbuilder
.check_visibility
(nt
, nt
.mtype
.as(not null), mpropdef
)
788 redef class AAttrPropdef
789 redef type MPROPDEF: MAttributeDef
791 # Is the node tagged `noinit`?
794 # Is the node taggeg lazy?
797 # The guard associated to a lasy attribute.
798 # Because some engines does not have a working `isset`,
799 # this additionnal attribute is used to guard the lazy initialization.
800 # TODO: to remove once isset is correctly implemented
801 var mlazypropdef
: nullable MAttributeDef
803 # The associated getter (read accessor) if any
804 var mreadpropdef
: nullable MMethodDef is writable
805 # The associated setter (write accessor) if any
806 var mwritepropdef
: nullable MMethodDef is writable
808 redef fun build_property
(modelbuilder
, mclassdef
)
810 var mclass
= mclassdef
.mclass
813 if self.n_id
!= null then
814 name
= self.n_id
.text
816 name
= self.n_id2
.text
819 if mclass
.kind
== interface_kind
or mclassdef
.mclass
.kind
== enum_kind
then
820 modelbuilder
.error
(self, "Error: Attempt to define attribute {name} in the interface {mclass}.")
821 else if mclass
.kind
== enum_kind
then
822 modelbuilder
.error
(self, "Error: Attempt to define attribute {name} in the enum class {mclass}.")
823 else if mclass
.kind
== extern_kind
then
824 modelbuilder
.error
(self, "Error: Attempt to define attribute {name} in the extern class {mclass}.")
829 # Old attribute style
830 modelbuilder
.error
(nid
, "Error: old-style attribute no more supported")
832 # New attribute style
833 var nid2
= self.n_id2
.as(not null)
834 var mprop
= new MAttribute(mclassdef
, "_" + name
, private_visibility
)
835 var mpropdef
= new MAttributeDef(mclassdef
, mprop
, self.location
)
836 self.mpropdef
= mpropdef
837 modelbuilder
.mpropdef2npropdef
[mpropdef
] = self
838 set_doc
(mpropdef
, modelbuilder
)
841 var mreadprop
= modelbuilder
.try_get_mproperty_by_name
(nid2
, mclassdef
, readname
).as(nullable MMethod)
842 if mreadprop
== null then
843 var mvisibility
= new_property_visibility
(modelbuilder
, mclassdef
, self.n_visibility
)
844 mreadprop
= new MMethod(mclassdef
, readname
, mvisibility
)
845 if not self.check_redef_keyword
(modelbuilder
, mclassdef
, n_kwredef
, false, mreadprop
) then return
846 mreadprop
.deprecation
= mprop
.deprecation
848 if not self.check_redef_keyword
(modelbuilder
, mclassdef
, n_kwredef
, true, mreadprop
) then return
849 check_redef_property_visibility
(modelbuilder
, self.n_visibility
, mreadprop
)
851 mclassdef
.mprop2npropdef
[mreadprop
] = self
853 var mreadpropdef
= new MMethodDef(mclassdef
, mreadprop
, self.location
)
854 self.mreadpropdef
= mreadpropdef
855 modelbuilder
.mpropdef2npropdef
[mreadpropdef
] = self
856 mreadpropdef
.mdoc
= mpropdef
.mdoc
858 var atlazy
= self.get_single_annotation
("lazy", modelbuilder
)
859 if atlazy
!= null then
860 if n_expr
== null then
861 modelbuilder
.error
(atlazy
, "Error: a lazy attribute needs a value")
864 var mlazyprop
= new MAttribute(mclassdef
, "lazy _" + name
, none_visibility
)
865 var mlazypropdef
= new MAttributeDef(mclassdef
, mlazyprop
, self.location
)
866 self.mlazypropdef
= mlazypropdef
869 var atreadonly
= self.get_single_annotation
("readonly", modelbuilder
)
870 if atreadonly
!= null then
871 if n_expr
== null then
872 modelbuilder
.error
(atreadonly
, "Error: a readonly attribute needs a value")
874 # No setter, so just leave
878 var writename
= name
+ "="
879 var nwritable
= self.n_writable
880 if nwritable
!= null then modelbuilder
.error
(nwritable
, "Error: old-style setter no more supported")
881 var atwritable
= self.get_single_annotation
("writable", modelbuilder
)
882 if atwritable
!= null then
883 if not atwritable
.n_args
.is_empty
then
884 writename
= atwritable
.arg_as_id
(modelbuilder
) or else writename
887 var mwriteprop
= modelbuilder
.try_get_mproperty_by_name
(nid2
, mclassdef
, writename
).as(nullable MMethod)
888 var nwkwredef
: nullable Token = null
889 if atwritable
!= null then nwkwredef
= atwritable
.n_kwredef
890 if mwriteprop
== null then
892 if atwritable
!= null then
893 mvisibility
= new_property_visibility
(modelbuilder
, mclassdef
, atwritable
.n_visibility
)
895 mvisibility
= private_visibility
897 mwriteprop
= new MMethod(mclassdef
, writename
, mvisibility
)
898 if not self.check_redef_keyword
(modelbuilder
, mclassdef
, nwkwredef
, false, mwriteprop
) then return
899 mwriteprop
.deprecation
= mprop
.deprecation
901 if not self.check_redef_keyword
(modelbuilder
, mclassdef
, nwkwredef
or else n_kwredef
, true, mwriteprop
) then return
902 if atwritable
!= null then
903 check_redef_property_visibility
(modelbuilder
, atwritable
.n_visibility
, mwriteprop
)
906 mclassdef
.mprop2npropdef
[mwriteprop
] = self
908 var mwritepropdef
= new MMethodDef(mclassdef
, mwriteprop
, self.location
)
909 self.mwritepropdef
= mwritepropdef
910 modelbuilder
.mpropdef2npropdef
[mwritepropdef
] = self
911 mwritepropdef
.mdoc
= mpropdef
.mdoc
915 redef fun build_signature
(modelbuilder
)
917 var mpropdef
= self.mpropdef
918 if mpropdef
== null then return # Error thus skiped
919 var mclassdef
= mpropdef
.mclassdef
920 var mmodule
= mclassdef
.mmodule
921 var mtype
: nullable MType = null
923 var mreadpropdef
= self.mreadpropdef
925 var ntype
= self.n_type
926 if ntype
!= null then
927 mtype
= modelbuilder
.resolve_mtype
(mmodule
, mclassdef
, ntype
)
928 if mtype
== null then return
931 # Inherit the type from the getter (usually an abstact getter)
932 if mtype
== null and mreadpropdef
!= null and not mreadpropdef
.is_intro
then
933 var msignature
= mreadpropdef
.mproperty
.intro
.msignature
934 if msignature
== null then return # Error, thus skiped
935 mtype
= msignature
.return_mtype
938 var nexpr
= self.n_expr
939 if mtype
== null then
940 if nexpr
!= null then
941 if nexpr
isa ANewExpr then
942 mtype
= modelbuilder
.resolve_mtype
(mmodule
, mclassdef
, nexpr
.n_type
)
943 else if nexpr
isa AIntExpr then
944 var cla
= modelbuilder
.try_get_mclass_by_name
(nexpr
, mmodule
, "Int")
945 if cla
!= null then mtype
= cla
.mclass_type
946 else if nexpr
isa AFloatExpr then
947 var cla
= modelbuilder
.try_get_mclass_by_name
(nexpr
, mmodule
, "Float")
948 if cla
!= null then mtype
= cla
.mclass_type
949 else if nexpr
isa ACharExpr then
950 var cla
= modelbuilder
.try_get_mclass_by_name
(nexpr
, mmodule
, "Char")
951 if cla
!= null then mtype
= cla
.mclass_type
952 else if nexpr
isa ABoolExpr then
953 var cla
= modelbuilder
.try_get_mclass_by_name
(nexpr
, mmodule
, "Bool")
954 if cla
!= null then mtype
= cla
.mclass_type
955 else if nexpr
isa ASuperstringExpr then
956 var cla
= modelbuilder
.try_get_mclass_by_name
(nexpr
, mmodule
, "String")
957 if cla
!= null then mtype
= cla
.mclass_type
958 else if nexpr
isa AStringFormExpr then
959 var cla
= modelbuilder
.try_get_mclass_by_name
(nexpr
, mmodule
, "String")
960 if cla
!= null then mtype
= cla
.mclass_type
962 modelbuilder
.error
(self, "Error: Untyped attribute {mpropdef}. Implicit typing allowed only for literals and new.")
965 if mtype
== null then return
967 else if ntype
!= null then
968 if nexpr
isa ANewExpr then
969 var xmtype
= modelbuilder
.resolve_mtype
(mmodule
, mclassdef
, nexpr
.n_type
)
970 if xmtype
== mtype
and modelbuilder
.toolcontext
.opt_warn
.value
>= 2 then
971 modelbuilder
.warning
(ntype
, "useless-type", "Warning: useless type definition")
976 if mtype
== null then
977 modelbuilder
.error
(self, "Error: Untyped attribute {mpropdef}")
981 mpropdef
.static_mtype
= mtype
983 if mreadpropdef
!= null then
984 var msignature
= new MSignature(new Array[MParameter], mtype
)
985 mreadpropdef
.msignature
= msignature
988 var mwritepropdef
= self.mwritepropdef
989 if mwritepropdef
!= null then
992 name
= n_id
.text
.substring_from
(1)
996 var mparameter
= new MParameter(name
, mtype
, false)
997 var msignature
= new MSignature([mparameter
], null)
998 mwritepropdef
.msignature
= msignature
1001 var mlazypropdef
= self.mlazypropdef
1002 if mlazypropdef
!= null then
1003 mlazypropdef
.static_mtype
= modelbuilder
.model
.get_mclasses_by_name
("Bool").first
.mclass_type
1007 redef fun check_signature
(modelbuilder
)
1009 var mpropdef
= self.mpropdef
1010 if mpropdef
== null then return # Error thus skiped
1011 var mclassdef
= mpropdef
.mclassdef
1012 var mmodule
= mclassdef
.mmodule
1013 var ntype
= self.n_type
1014 var mtype
= self.mpropdef
.static_mtype
1015 if mtype
== null then return # Error thus skiped
1017 # Lookup for signature in the precursor
1018 # FIXME all precursors should be considered
1019 if not mpropdef
.is_intro
then
1020 var precursor_type
= mpropdef
.mproperty
.intro
.static_mtype
1021 if precursor_type
== null then return
1023 if mtype
!= precursor_type
then
1024 modelbuilder
.error
(ntype
.as(not null), "Redef Error: Wrong static type. found {mtype}, expected {precursor_type}.")
1029 # Check getter and setter
1030 var meth
= self.mreadpropdef
1031 if meth
!= null then
1032 self.check_method_signature
(modelbuilder
, meth
)
1033 var node
: nullable ANode = ntype
1034 if node
== null then node
= self
1035 modelbuilder
.check_visibility
(node
, mtype
, meth
)
1037 meth
= self.mwritepropdef
1038 if meth
!= null then
1039 self.check_method_signature
(modelbuilder
, meth
)
1040 var node
: nullable ANode = ntype
1041 if node
== null then node
= self
1042 modelbuilder
.check_visibility
(node
, mtype
, meth
)
1046 private fun check_method_signature
(modelbuilder
: ModelBuilder, mpropdef
: MMethodDef)
1048 var mclassdef
= mpropdef
.mclassdef
1049 var mmodule
= mclassdef
.mmodule
1050 var nsig
= self.n_type
1051 var mysignature
= mpropdef
.msignature
1052 if mysignature
== null then return # Error thus skiped
1054 # Lookup for signature in the precursor
1055 # FIXME all precursors should be considered
1056 if not mpropdef
.is_intro
then
1057 var msignature
= mpropdef
.mproperty
.intro
.msignature
1058 if msignature
== null then return
1060 if mysignature
.arity
!= msignature
.arity
then
1062 if nsig
!= null then node
= nsig
else node
= self
1063 modelbuilder
.error
(node
, "Redef Error: {mysignature.arity} parameters found, {msignature.arity} expected. Signature is {mpropdef}{msignature}")
1066 var precursor_ret_type
= msignature
.return_mtype
1067 var ret_type
= mysignature
.return_mtype
1068 if ret_type
!= null and precursor_ret_type
== null then
1070 if nsig
!= null then node
= nsig
else node
= self
1071 modelbuilder
.error
(node
, "Redef Error: {mpropdef.mproperty} is a procedure, not a function.")
1075 if mysignature
.arity
> 0 then
1076 # Check parameters types
1077 for i
in [0..mysignature
.arity
[ do
1078 var myt
= mysignature
.mparameters
[i
].mtype
1079 var prt
= msignature
.mparameters
[i
].mtype
1080 if not myt
.is_subtype
(mmodule
, mclassdef
.bound_mtype
, prt
) or
1081 not prt
.is_subtype
(mmodule
, mclassdef
.bound_mtype
, myt
) then
1083 if nsig
!= null then node
= nsig
else node
= self
1084 modelbuilder
.error
(node
, "Redef Error: Wrong type for parameter `{mysignature.mparameters[i].name}'. found {myt}, expected {prt}.")
1088 if precursor_ret_type
!= null then
1089 if ret_type
== null then
1090 # Inherit the return type
1091 ret_type
= precursor_ret_type
1092 else if not ret_type
.is_subtype
(mmodule
, mclassdef
.bound_mtype
, precursor_ret_type
) then
1094 if nsig
!= null then node
= nsig
else node
= self
1095 modelbuilder
.error
(node
, "Redef Error: Wrong return type. found {ret_type}, expected {precursor_ret_type}.")
1102 redef class ATypePropdef
1103 redef type MPROPDEF: MVirtualTypeDef
1105 redef fun build_property
(modelbuilder
, mclassdef
)
1107 var name
= self.n_id
.text
1108 var mprop
= modelbuilder
.try_get_mproperty_by_name
(self.n_id
, mclassdef
, name
)
1109 if mprop
== null then
1110 var mvisibility
= new_property_visibility
(modelbuilder
, mclassdef
, self.n_visibility
)
1111 mprop
= new MVirtualTypeProp(mclassdef
, name
, mvisibility
)
1112 for c
in name
.chars
do if c
>= 'a' and c
<= 'z' then
1113 modelbuilder
.warning
(n_id
, "bad-type-name", "Warning: lowercase in the virtual type {name}")
1116 if not self.check_redef_keyword
(modelbuilder
, mclassdef
, self.n_kwredef
, false, mprop
) then return
1118 if not self.check_redef_keyword
(modelbuilder
, mclassdef
, self.n_kwredef
, true, mprop
) then return
1119 assert mprop
isa MVirtualTypeProp
1120 check_redef_property_visibility
(modelbuilder
, self.n_visibility
, mprop
)
1122 mclassdef
.mprop2npropdef
[mprop
] = self
1124 var mpropdef
= new MVirtualTypeDef(mclassdef
, mprop
, self.location
)
1125 self.mpropdef
= mpropdef
1126 modelbuilder
.mpropdef2npropdef
[mpropdef
] = self
1127 set_doc
(mpropdef
, modelbuilder
)
1129 var atfixed
= get_single_annotation
("fixed", modelbuilder
)
1130 if atfixed
!= null then
1131 mpropdef
.is_fixed
= true
1135 redef fun build_signature
(modelbuilder
)
1137 var mpropdef
= self.mpropdef
1138 if mpropdef
== null then return # Error thus skiped
1139 var mclassdef
= mpropdef
.mclassdef
1140 var mmodule
= mclassdef
.mmodule
1141 var mtype
: nullable MType = null
1143 var ntype
= self.n_type
1144 mtype
= modelbuilder
.resolve_mtype
(mmodule
, mclassdef
, ntype
)
1145 if mtype
== null then return
1147 mpropdef
.bound
= mtype
1148 # print "{mpropdef}: {mtype}"
1151 redef fun check_signature
(modelbuilder
)
1153 var mpropdef
= self.mpropdef
1154 if mpropdef
== null then return # Error thus skiped
1156 var bound
= self.mpropdef
.bound
1157 if bound
== null then return # Error thus skiped
1159 modelbuilder
.check_visibility
(n_type
, bound
, mpropdef
)
1161 var mclassdef
= mpropdef
.mclassdef
1162 var mmodule
= mclassdef
.mmodule
1163 var anchor
= mclassdef
.bound_mtype
1166 if bound
isa MVirtualType then
1167 # Slow case: progress on each resolution until: (i) we loop, or (ii) we found a non formal type
1168 var seen
= [self.mpropdef
.mproperty
.mvirtualtype
]
1170 if seen
.has
(bound
) then
1172 modelbuilder
.error
(self, "Error: circularity of virtual type definition: {seen.join(" -> ")}")
1176 var next
= bound
.lookup_bound
(mmodule
, anchor
)
1177 if not next
isa MVirtualType then break
1182 # Check redefinitions
1183 bound
= mpropdef
.bound
.as(not null)
1184 for p
in mpropdef
.mproperty
.lookup_super_definitions
(mmodule
, anchor
) do
1185 var supbound
= p
.bound
.as(not null)
1187 modelbuilder
.error
(self, "Redef Error: Virtual type {mpropdef.mproperty} is fixed in super-class {p.mclassdef.mclass}")
1190 if p
.mclassdef
.mclass
== mclassdef
.mclass
then
1191 # Still a warning to pass existing bad code
1192 modelbuilder
.warning
(n_type
, "refine-type", "Redef Error: a virtual type cannot be refined.")
1195 if not bound
.is_subtype
(mmodule
, anchor
, supbound
) then
1196 modelbuilder
.error
(n_type
, "Redef Error: Wrong bound type. Found {bound}, expected a subtype of {supbound}, as in {p}.")