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
407 modelbuilder
.advice
(nvisibility
, "useless-visibility", "Warning: private is superfluous since the only legal visibility for properties in a private class is private.")
409 mvisibility
= private_visibility
414 private fun set_doc
(mpropdef
: MPropDef, modelbuilder
: ModelBuilder)
416 var ndoc
= self.n_doc
418 var mdoc
= ndoc
.to_mdoc
420 mdoc
.original_mentity
= mpropdef
423 var at_deprecated
= get_single_annotation
("deprecated", modelbuilder
)
424 if at_deprecated
!= null then
425 if not mpropdef
.is_intro
then
426 modelbuilder
.error
(self, "Error: method redefinition cannot be deprecated.")
428 var info
= new MDeprecationInfo
429 ndoc
= at_deprecated
.n_doc
430 if ndoc
!= null then info
.mdoc
= ndoc
.to_mdoc
431 mpropdef
.mproperty
.deprecation
= info
436 private fun check_redef_property_visibility
(modelbuilder
: ModelBuilder, nvisibility
: nullable AVisibility, mprop
: MProperty)
438 if nvisibility
== null then return
439 var mvisibility
= nvisibility
.mvisibility
440 if mvisibility
!= mprop
.visibility
and mvisibility
!= public_visibility
then
441 modelbuilder
.error
(nvisibility
, "Error: redefinition changed the visibility from a {mprop.visibility} to a {mvisibility}")
445 private fun check_redef_keyword
(modelbuilder
: ModelBuilder, mclassdef
: MClassDef, kwredef
: nullable Token, need_redef
: Bool, mprop
: MProperty): Bool
447 if mclassdef
.mprop2npropdef
.has_key
(mprop
) then
448 modelbuilder
.error
(self, "Error: A property {mprop} is already defined in class {mclassdef.mclass} at line {mclassdef.mprop2npropdef[mprop].location.line_start}.")
451 if mprop
isa MMethod and mprop
.is_toplevel
!= (parent
isa ATopClassdef) then
452 if mprop
.is_toplevel
then
453 modelbuilder
.error
(self, "Error: {mprop} is a top level method.")
455 modelbuilder
.error
(self, "Error: {mprop} is not a top level method.")
460 if kwredef
== null then
462 modelbuilder
.error
(self, "Redef error: {mclassdef.mclass}::{mprop.name} is an inherited property. To redefine it, add the redef keyword.")
466 if not need_redef
then
467 modelbuilder
.error
(self, "Error: No property {mclassdef.mclass}::{mprop.name} is inherited. Remove the redef keyword to define a new property.")
476 redef class ASignature
477 # Is the model builder has correctly visited the signature
478 var is_visited
= false
479 # Names of parameters from the AST
480 # REQUIRE: is_visited
481 var param_names
= new Array[String]
482 # Types of parameters from the AST
483 # REQUIRE: is_visited
484 var param_types
= new Array[MType]
485 # Rank of the vararg (of -1 if none)
486 # REQUIRE: is_visited
487 var vararg_rank
: Int = -1
489 var ret_type
: nullable MType = null
491 # Visit and fill information about a signature
492 private fun visit_signature
(modelbuilder
: ModelBuilder, mclassdef
: MClassDef): Bool
494 var mmodule
= mclassdef
.mmodule
495 var param_names
= self.param_names
496 var param_types
= self.param_types
497 for np
in self.n_params
do
498 param_names
.add
(np
.n_id
.text
)
499 var ntype
= np
.n_type
500 if ntype
!= null then
501 var mtype
= modelbuilder
.resolve_mtype
(mmodule
, mclassdef
, ntype
)
502 if mtype
== null then return false # Skip error
503 for i
in [0..param_names
.length-param_types
.length
[ do
504 param_types
.add
(mtype
)
506 if np
.n_dotdotdot
!= null then
507 if self.vararg_rank
!= -1 then
508 modelbuilder
.error
(np
, "Error: {param_names[self.vararg_rank]} is already a vararg")
511 self.vararg_rank
= param_names
.length
- 1
516 var ntype
= self.n_type
517 if ntype
!= null then
518 self.ret_type
= modelbuilder
.resolve_mtype
(mmodule
, mclassdef
, ntype
)
519 if self.ret_type
== null then return false # Skip errir
522 self.is_visited
= true
526 # Build a visited signature
527 fun build_signature
(modelbuilder
: ModelBuilder): nullable MSignature
529 if param_names
.length
!= param_types
.length
then
530 # Some parameters are typed, other parameters are not typed.
531 modelbuilder
.error
(self.n_params
[param_types
.length
], "Error: Untyped parameter `{param_names[param_types.length]}'.")
535 var mparameters
= new Array[MParameter]
536 for i
in [0..param_names
.length
[ do
537 var mparameter
= new MParameter(param_names
[i
], param_types
[i
], i
== vararg_rank
)
538 self.n_params
[i
].mparameter
= mparameter
539 mparameters
.add
(mparameter
)
542 var msignature
= new MSignature(mparameters
, ret_type
)
548 # The associated mparameter if any
549 var mparameter
: nullable MParameter = null
552 redef class AMethPropdef
553 redef type MPROPDEF: MMethodDef
556 # Can self be used as a root init?
557 private fun look_like_a_root_init
(modelbuilder
: ModelBuilder): Bool
559 # Need the `init` keyword
560 if n_kwinit
== null then return false
561 # Need to by anonymous
562 if self.n_methid
!= null then return false
564 if self.n_signature
.n_params
.length
> 0 then return false
565 # Cannot be private or something
566 if not self.n_visibility
isa APublicVisibility then return false
567 # No annotation on itself
568 if get_single_annotation
("old_style_init", modelbuilder
) != null then return false
570 var amod
= self.parent
.parent
.as(AModule)
571 var amoddecl
= amod
.n_moduledecl
572 if amoddecl
!= null then
573 var old
= amoddecl
.get_single_annotation
("old_style_init", modelbuilder
)
574 if old
!= null then return false
580 redef fun build_property
(modelbuilder
, mclassdef
)
582 var n_kwinit
= n_kwinit
583 var n_kwnew
= n_kwnew
584 var is_init
= n_kwinit
!= null or n_kwnew
!= null
586 var amethodid
= self.n_methid
588 if amethodid
== null then
592 else if n_kwinit
!= null then
595 else if n_kwnew
!= null then
601 else if amethodid
isa AIdMethid then
602 name
= amethodid
.n_id
.text
603 name_node
= amethodid
605 # operator, bracket or assign
606 name
= amethodid
.collect_text
607 name_node
= amethodid
609 if name
== "-" and self.n_signature
.n_params
.length
== 0 then
614 var mprop
: nullable MMethod = null
615 if not is_init
or n_kwredef
!= null then mprop
= modelbuilder
.try_get_mproperty_by_name
(name_node
, mclassdef
, name
).as(nullable MMethod)
616 if mprop
== null and look_like_a_root_init
(modelbuilder
) then
617 mprop
= modelbuilder
.the_root_init_mmethod
619 if mprop
== null then
620 var mvisibility
= new_property_visibility
(modelbuilder
, mclassdef
, self.n_visibility
)
621 mprop
= new MMethod(mclassdef
, name
, mvisibility
)
622 if look_like_a_root_init
(modelbuilder
) and modelbuilder
.the_root_init_mmethod
== null then
623 modelbuilder
.the_root_init_mmethod
= mprop
624 mprop
.is_root_init
= true
626 mprop
.is_init
= is_init
627 mprop
.is_new
= n_kwnew
!= null
628 if parent
isa ATopClassdef then mprop
.is_toplevel
= true
629 if not self.check_redef_keyword
(modelbuilder
, mclassdef
, n_kwredef
, false, mprop
) then return
631 if not mprop
.is_root_init
and not self.check_redef_keyword
(modelbuilder
, mclassdef
, n_kwredef
, not self isa AMainMethPropdef, mprop
) then return
632 check_redef_property_visibility
(modelbuilder
, self.n_visibility
, mprop
)
634 mclassdef
.mprop2npropdef
[mprop
] = self
636 var mpropdef
= new MMethodDef(mclassdef
, mprop
, self.location
)
638 set_doc
(mpropdef
, modelbuilder
)
640 self.mpropdef
= mpropdef
641 modelbuilder
.mpropdef2npropdef
[mpropdef
] = self
642 if mpropdef
.is_intro
then
643 modelbuilder
.toolcontext
.info
("{mpropdef} introduces new method {mprop.full_name}", 3)
645 modelbuilder
.toolcontext
.info
("{mpropdef} redefines method {mprop.full_name}", 3)
649 redef fun build_signature
(modelbuilder
)
651 var mpropdef
= self.mpropdef
652 if mpropdef
== null then return # Error thus skiped
653 var mclassdef
= mpropdef
.mclassdef
654 var mmodule
= mclassdef
.mmodule
655 var nsig
= self.n_signature
657 # Retrieve info from the signature AST
658 var param_names
= new Array[String] # Names of parameters from the AST
659 var param_types
= new Array[MType] # Types of parameters from the AST
661 var ret_type
: nullable MType = null # Return type from the AST
663 if not nsig
.visit_signature
(modelbuilder
, mclassdef
) then return
664 param_names
= nsig
.param_names
665 param_types
= nsig
.param_types
666 vararg_rank
= nsig
.vararg_rank
667 ret_type
= nsig
.ret_type
670 # Look for some signature to inherit
671 # FIXME: do not inherit from the intro, but from the most specific
672 var msignature
: nullable MSignature = null
673 if not mpropdef
.is_intro
then
674 msignature
= mpropdef
.mproperty
.intro
.msignature
675 if msignature
== null then return # Skip error
677 # Check inherited signature arity
678 if param_names
.length
!= msignature
.arity
then
680 if nsig
!= null then node
= nsig
else node
= self
681 modelbuilder
.error
(node
, "Redef error: {mpropdef} redefines {mpropdef.mproperty.intro} with {param_names.length} parameter(s), {msignature.arity} expected. Signature is {mpropdef}{msignature}")
684 else if mpropdef
.mproperty
.is_init
then
685 # FIXME UGLY: inherit signature from a super-constructor
686 for msupertype
in mclassdef
.supertypes
do
687 msupertype
= msupertype
.anchor_to
(mmodule
, mclassdef
.bound_mtype
)
688 var candidate
= modelbuilder
.try_get_mproperty_by_name2
(self, mmodule
, msupertype
, mpropdef
.mproperty
.name
)
689 if candidate
!= null then
690 if msignature
== null then
691 msignature
= candidate
.intro
.as(MMethodDef).msignature
698 # Inherit the signature
699 if msignature
!= null and param_names
.length
!= param_types
.length
and param_names
.length
== msignature
.arity
and param_types
.length
== 0 then
700 # Parameters are untyped, thus inherit them
701 param_types
= new Array[MType]
702 for mparameter
in msignature
.mparameters
do
703 param_types
.add
(mparameter
.mtype
)
705 vararg_rank
= msignature
.vararg_rank
707 if msignature
!= null and ret_type
== null then
708 ret_type
= msignature
.return_mtype
711 if param_names
.length
!= param_types
.length
then
712 # Some parameters are typed, other parameters are not typed.
713 modelbuilder
.error
(nsig
.n_params
[param_types
.length
], "Error: Untyped parameter `{param_names[param_types.length]}'.")
717 var mparameters
= new Array[MParameter]
718 for i
in [0..param_names
.length
[ do
719 var mparameter
= new MParameter(param_names
[i
], param_types
[i
], i
== vararg_rank
)
720 if nsig
!= null then nsig
.n_params
[i
].mparameter
= mparameter
721 mparameters
.add
(mparameter
)
724 msignature
= new MSignature(mparameters
, ret_type
)
725 mpropdef
.msignature
= msignature
726 mpropdef
.is_abstract
= self isa ADeferredMethPropdef or self.get_single_annotation
("abstract", modelbuilder
) != null
727 mpropdef
.is_intern
= self isa AInternMethPropdef or self.get_single_annotation
("intern", modelbuilder
) != null
728 mpropdef
.is_extern
= self isa AExternPropdef or self.n_extern_code_block
!= null or self.get_single_annotation
("extern", modelbuilder
) != null
731 redef fun check_signature
(modelbuilder
)
733 var mpropdef
= self.mpropdef
734 if mpropdef
== null then return # Error thus skiped
735 var mclassdef
= mpropdef
.mclassdef
736 var mmodule
= mclassdef
.mmodule
737 var nsig
= self.n_signature
738 var mysignature
= self.mpropdef
.msignature
739 if mysignature
== null then return # Error thus skiped
741 # Lookup for signature in the precursor
742 # FIXME all precursors should be considered
743 if not mpropdef
.is_intro
then
744 var msignature
= mpropdef
.mproperty
.intro
.msignature
745 if msignature
== null then return
747 var precursor_ret_type
= msignature
.return_mtype
748 var ret_type
= mysignature
.return_mtype
749 if ret_type
!= null and precursor_ret_type
== null then
750 modelbuilder
.error
(nsig
.n_type
.as(not null), "Redef Error: {mpropdef.mproperty} is a procedure, not a function.")
754 if mysignature
.arity
> 0 then
755 # Check parameters types
756 for i
in [0..mysignature
.arity
[ do
757 var myt
= mysignature
.mparameters
[i
].mtype
758 var prt
= msignature
.mparameters
[i
].mtype
759 if not myt
.is_subtype
(mmodule
, mclassdef
.bound_mtype
, prt
) or
760 not prt
.is_subtype
(mmodule
, mclassdef
.bound_mtype
, myt
) then
761 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}.")
765 if precursor_ret_type
!= null then
766 if ret_type
== null then
767 # Inherit the return type
768 ret_type
= precursor_ret_type
769 else if not ret_type
.is_subtype
(mmodule
, mclassdef
.bound_mtype
, precursor_ret_type
) then
770 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}.")
775 if mysignature
.arity
> 0 then
776 # Check parameters visibility
777 for i
in [0..mysignature
.arity
[ do
778 var nt
= nsig
.n_params
[i
].n_type
779 if nt
!= null then modelbuilder
.check_visibility
(nt
, nt
.mtype
.as(not null), mpropdef
)
782 if nt
!= null then modelbuilder
.check_visibility
(nt
, nt
.mtype
.as(not null), mpropdef
)
787 redef class AAttrPropdef
788 redef type MPROPDEF: MAttributeDef
790 # Is the node tagged `noinit`?
793 # Is the node taggeg lazy?
796 # The guard associated to a lasy attribute.
797 # Because some engines does not have a working `isset`,
798 # this additionnal attribute is used to guard the lazy initialization.
799 # TODO: to remove once isset is correctly implemented
800 var mlazypropdef
: nullable MAttributeDef
802 # The associated getter (read accessor) if any
803 var mreadpropdef
: nullable MMethodDef is writable
804 # The associated setter (write accessor) if any
805 var mwritepropdef
: nullable MMethodDef is writable
807 redef fun build_property
(modelbuilder
, mclassdef
)
809 var mclass
= mclassdef
.mclass
812 if self.n_id
!= null then
813 name
= self.n_id
.text
815 name
= self.n_id2
.text
818 if mclass
.kind
== interface_kind
or mclassdef
.mclass
.kind
== enum_kind
then
819 modelbuilder
.error
(self, "Error: Attempt to define attribute {name} in the interface {mclass}.")
820 else if mclass
.kind
== enum_kind
then
821 modelbuilder
.error
(self, "Error: Attempt to define attribute {name} in the enum class {mclass}.")
822 else if mclass
.kind
== extern_kind
then
823 modelbuilder
.error
(self, "Error: Attempt to define attribute {name} in the extern class {mclass}.")
828 # Old attribute style
829 modelbuilder
.error
(nid
, "Error: old-style attribute no more supported")
831 # New attribute style
832 var nid2
= self.n_id2
.as(not null)
833 var mprop
= new MAttribute(mclassdef
, "_" + name
, private_visibility
)
834 var mpropdef
= new MAttributeDef(mclassdef
, mprop
, self.location
)
835 self.mpropdef
= mpropdef
836 modelbuilder
.mpropdef2npropdef
[mpropdef
] = self
837 set_doc
(mpropdef
, modelbuilder
)
840 var mreadprop
= modelbuilder
.try_get_mproperty_by_name
(nid2
, mclassdef
, readname
).as(nullable MMethod)
841 if mreadprop
== null then
842 var mvisibility
= new_property_visibility
(modelbuilder
, mclassdef
, self.n_visibility
)
843 mreadprop
= new MMethod(mclassdef
, readname
, mvisibility
)
844 if not self.check_redef_keyword
(modelbuilder
, mclassdef
, n_kwredef
, false, mreadprop
) then return
845 mreadprop
.deprecation
= mprop
.deprecation
847 if not self.check_redef_keyword
(modelbuilder
, mclassdef
, n_kwredef
, true, mreadprop
) then return
848 check_redef_property_visibility
(modelbuilder
, self.n_visibility
, mreadprop
)
850 mclassdef
.mprop2npropdef
[mreadprop
] = self
852 var mreadpropdef
= new MMethodDef(mclassdef
, mreadprop
, self.location
)
853 self.mreadpropdef
= mreadpropdef
854 modelbuilder
.mpropdef2npropdef
[mreadpropdef
] = self
855 mreadpropdef
.mdoc
= mpropdef
.mdoc
857 var atlazy
= self.get_single_annotation
("lazy", modelbuilder
)
858 if atlazy
!= null then
859 if n_expr
== null then
860 modelbuilder
.error
(atlazy
, "Error: a lazy attribute needs a value")
863 var mlazyprop
= new MAttribute(mclassdef
, "lazy _" + name
, none_visibility
)
864 var mlazypropdef
= new MAttributeDef(mclassdef
, mlazyprop
, self.location
)
865 self.mlazypropdef
= mlazypropdef
868 var atreadonly
= self.get_single_annotation
("readonly", modelbuilder
)
869 if atreadonly
!= null then
870 if n_expr
== null then
871 modelbuilder
.error
(atreadonly
, "Error: a readonly attribute needs a value")
873 # No setter, so just leave
877 var writename
= name
+ "="
878 var nwritable
= self.n_writable
879 if nwritable
!= null then modelbuilder
.error
(nwritable
, "Error: old-style setter no more supported")
880 var atwritable
= self.get_single_annotation
("writable", modelbuilder
)
881 if atwritable
!= null then
882 if not atwritable
.n_args
.is_empty
then
883 writename
= atwritable
.arg_as_id
(modelbuilder
) or else writename
886 var mwriteprop
= modelbuilder
.try_get_mproperty_by_name
(nid2
, mclassdef
, writename
).as(nullable MMethod)
887 var nwkwredef
: nullable Token = null
888 if atwritable
!= null then nwkwredef
= atwritable
.n_kwredef
889 if mwriteprop
== null then
891 if atwritable
!= null then
892 mvisibility
= new_property_visibility
(modelbuilder
, mclassdef
, atwritable
.n_visibility
)
894 mvisibility
= private_visibility
896 mwriteprop
= new MMethod(mclassdef
, writename
, mvisibility
)
897 if not self.check_redef_keyword
(modelbuilder
, mclassdef
, nwkwredef
, false, mwriteprop
) then return
898 mwriteprop
.deprecation
= mprop
.deprecation
900 if not self.check_redef_keyword
(modelbuilder
, mclassdef
, nwkwredef
or else n_kwredef
, true, mwriteprop
) then return
901 if atwritable
!= null then
902 check_redef_property_visibility
(modelbuilder
, atwritable
.n_visibility
, mwriteprop
)
905 mclassdef
.mprop2npropdef
[mwriteprop
] = self
907 var mwritepropdef
= new MMethodDef(mclassdef
, mwriteprop
, self.location
)
908 self.mwritepropdef
= mwritepropdef
909 modelbuilder
.mpropdef2npropdef
[mwritepropdef
] = self
910 mwritepropdef
.mdoc
= mpropdef
.mdoc
914 redef fun build_signature
(modelbuilder
)
916 var mpropdef
= self.mpropdef
917 if mpropdef
== null then return # Error thus skiped
918 var mclassdef
= mpropdef
.mclassdef
919 var mmodule
= mclassdef
.mmodule
920 var mtype
: nullable MType = null
922 var mreadpropdef
= self.mreadpropdef
924 var ntype
= self.n_type
925 if ntype
!= null then
926 mtype
= modelbuilder
.resolve_mtype
(mmodule
, mclassdef
, ntype
)
927 if mtype
== null then return
930 # Inherit the type from the getter (usually an abstact getter)
931 if mtype
== null and mreadpropdef
!= null and not mreadpropdef
.is_intro
then
932 var msignature
= mreadpropdef
.mproperty
.intro
.msignature
933 if msignature
== null then return # Error, thus skiped
934 mtype
= msignature
.return_mtype
937 var nexpr
= self.n_expr
938 if mtype
== null then
939 if nexpr
!= null then
940 if nexpr
isa ANewExpr then
941 mtype
= modelbuilder
.resolve_mtype
(mmodule
, mclassdef
, nexpr
.n_type
)
942 else if nexpr
isa AIntExpr then
943 var cla
= modelbuilder
.try_get_mclass_by_name
(nexpr
, mmodule
, "Int")
944 if cla
!= null then mtype
= cla
.mclass_type
945 else if nexpr
isa AFloatExpr then
946 var cla
= modelbuilder
.try_get_mclass_by_name
(nexpr
, mmodule
, "Float")
947 if cla
!= null then mtype
= cla
.mclass_type
948 else if nexpr
isa ACharExpr then
949 var cla
= modelbuilder
.try_get_mclass_by_name
(nexpr
, mmodule
, "Char")
950 if cla
!= null then mtype
= cla
.mclass_type
951 else if nexpr
isa ABoolExpr then
952 var cla
= modelbuilder
.try_get_mclass_by_name
(nexpr
, mmodule
, "Bool")
953 if cla
!= null then mtype
= cla
.mclass_type
954 else if nexpr
isa ASuperstringExpr then
955 var cla
= modelbuilder
.try_get_mclass_by_name
(nexpr
, mmodule
, "String")
956 if cla
!= null then mtype
= cla
.mclass_type
957 else if nexpr
isa AStringFormExpr then
958 var cla
= modelbuilder
.try_get_mclass_by_name
(nexpr
, mmodule
, "String")
959 if cla
!= null then mtype
= cla
.mclass_type
961 modelbuilder
.error
(self, "Error: Untyped attribute {mpropdef}. Implicit typing allowed only for literals and new.")
964 if mtype
== null then return
966 else if ntype
!= null then
967 if nexpr
isa ANewExpr then
968 var xmtype
= modelbuilder
.resolve_mtype
(mmodule
, mclassdef
, nexpr
.n_type
)
969 if xmtype
== mtype
and modelbuilder
.toolcontext
.opt_warn
.value
>= 2 then
970 modelbuilder
.warning
(ntype
, "useless-type", "Warning: useless type definition")
975 if mtype
== null then
976 modelbuilder
.error
(self, "Error: Untyped attribute {mpropdef}")
980 mpropdef
.static_mtype
= mtype
982 if mreadpropdef
!= null then
983 var msignature
= new MSignature(new Array[MParameter], mtype
)
984 mreadpropdef
.msignature
= msignature
987 var mwritepropdef
= self.mwritepropdef
988 if mwritepropdef
!= null then
991 name
= n_id
.text
.substring_from
(1)
995 var mparameter
= new MParameter(name
, mtype
, false)
996 var msignature
= new MSignature([mparameter
], null)
997 mwritepropdef
.msignature
= msignature
1000 var mlazypropdef
= self.mlazypropdef
1001 if mlazypropdef
!= null then
1002 mlazypropdef
.static_mtype
= modelbuilder
.model
.get_mclasses_by_name
("Bool").first
.mclass_type
1006 redef fun check_signature
(modelbuilder
)
1008 var mpropdef
= self.mpropdef
1009 if mpropdef
== null then return # Error thus skiped
1010 var mclassdef
= mpropdef
.mclassdef
1011 var mmodule
= mclassdef
.mmodule
1012 var ntype
= self.n_type
1013 var mtype
= self.mpropdef
.static_mtype
1014 if mtype
== null then return # Error thus skiped
1016 # Lookup for signature in the precursor
1017 # FIXME all precursors should be considered
1018 if not mpropdef
.is_intro
then
1019 var precursor_type
= mpropdef
.mproperty
.intro
.static_mtype
1020 if precursor_type
== null then return
1022 if mtype
!= precursor_type
then
1023 modelbuilder
.error
(ntype
.as(not null), "Redef Error: Wrong static type. found {mtype}, expected {precursor_type}.")
1028 # Check getter and setter
1029 var meth
= self.mreadpropdef
1030 if meth
!= null then
1031 self.check_method_signature
(modelbuilder
, meth
)
1032 var node
: nullable ANode = ntype
1033 if node
== null then node
= self
1034 modelbuilder
.check_visibility
(node
, mtype
, meth
)
1036 meth
= self.mwritepropdef
1037 if meth
!= null then
1038 self.check_method_signature
(modelbuilder
, meth
)
1039 var node
: nullable ANode = ntype
1040 if node
== null then node
= self
1041 modelbuilder
.check_visibility
(node
, mtype
, meth
)
1045 private fun check_method_signature
(modelbuilder
: ModelBuilder, mpropdef
: MMethodDef)
1047 var mclassdef
= mpropdef
.mclassdef
1048 var mmodule
= mclassdef
.mmodule
1049 var nsig
= self.n_type
1050 var mysignature
= mpropdef
.msignature
1051 if mysignature
== null then return # Error thus skiped
1053 # Lookup for signature in the precursor
1054 # FIXME all precursors should be considered
1055 if not mpropdef
.is_intro
then
1056 var msignature
= mpropdef
.mproperty
.intro
.msignature
1057 if msignature
== null then return
1059 if mysignature
.arity
!= msignature
.arity
then
1061 if nsig
!= null then node
= nsig
else node
= self
1062 modelbuilder
.error
(node
, "Redef Error: {mysignature.arity} parameters found, {msignature.arity} expected. Signature is {mpropdef}{msignature}")
1065 var precursor_ret_type
= msignature
.return_mtype
1066 var ret_type
= mysignature
.return_mtype
1067 if ret_type
!= null and precursor_ret_type
== null then
1069 if nsig
!= null then node
= nsig
else node
= self
1070 modelbuilder
.error
(node
, "Redef Error: {mpropdef.mproperty} is a procedure, not a function.")
1074 if mysignature
.arity
> 0 then
1075 # Check parameters types
1076 for i
in [0..mysignature
.arity
[ do
1077 var myt
= mysignature
.mparameters
[i
].mtype
1078 var prt
= msignature
.mparameters
[i
].mtype
1079 if not myt
.is_subtype
(mmodule
, mclassdef
.bound_mtype
, prt
) or
1080 not prt
.is_subtype
(mmodule
, mclassdef
.bound_mtype
, myt
) then
1082 if nsig
!= null then node
= nsig
else node
= self
1083 modelbuilder
.error
(node
, "Redef Error: Wrong type for parameter `{mysignature.mparameters[i].name}'. found {myt}, expected {prt}.")
1087 if precursor_ret_type
!= null then
1088 if ret_type
== null then
1089 # Inherit the return type
1090 ret_type
= precursor_ret_type
1091 else if not ret_type
.is_subtype
(mmodule
, mclassdef
.bound_mtype
, precursor_ret_type
) then
1093 if nsig
!= null then node
= nsig
else node
= self
1094 modelbuilder
.error
(node
, "Redef Error: Wrong return type. found {ret_type}, expected {precursor_ret_type}.")
1101 redef class ATypePropdef
1102 redef type MPROPDEF: MVirtualTypeDef
1104 redef fun build_property
(modelbuilder
, mclassdef
)
1106 var name
= self.n_id
.text
1107 var mprop
= modelbuilder
.try_get_mproperty_by_name
(self.n_id
, mclassdef
, name
)
1108 if mprop
== null then
1109 var mvisibility
= new_property_visibility
(modelbuilder
, mclassdef
, self.n_visibility
)
1110 mprop
= new MVirtualTypeProp(mclassdef
, name
, mvisibility
)
1111 for c
in name
.chars
do if c
>= 'a' and c
<= 'z' then
1112 modelbuilder
.warning
(n_id
, "bad-type-name", "Warning: lowercase in the virtual type {name}")
1115 if not self.check_redef_keyword
(modelbuilder
, mclassdef
, self.n_kwredef
, false, mprop
) then return
1117 if not self.check_redef_keyword
(modelbuilder
, mclassdef
, self.n_kwredef
, true, mprop
) then return
1118 assert mprop
isa MVirtualTypeProp
1119 check_redef_property_visibility
(modelbuilder
, self.n_visibility
, mprop
)
1121 mclassdef
.mprop2npropdef
[mprop
] = self
1123 var mpropdef
= new MVirtualTypeDef(mclassdef
, mprop
, self.location
)
1124 self.mpropdef
= mpropdef
1125 modelbuilder
.mpropdef2npropdef
[mpropdef
] = self
1126 set_doc
(mpropdef
, modelbuilder
)
1128 var atfixed
= get_single_annotation
("fixed", modelbuilder
)
1129 if atfixed
!= null then
1130 mpropdef
.is_fixed
= true
1134 redef fun build_signature
(modelbuilder
)
1136 var mpropdef
= self.mpropdef
1137 if mpropdef
== null then return # Error thus skiped
1138 var mclassdef
= mpropdef
.mclassdef
1139 var mmodule
= mclassdef
.mmodule
1140 var mtype
: nullable MType = null
1142 var ntype
= self.n_type
1143 mtype
= modelbuilder
.resolve_mtype
(mmodule
, mclassdef
, ntype
)
1144 if mtype
== null then return
1146 mpropdef
.bound
= mtype
1147 # print "{mpropdef}: {mtype}"
1150 redef fun check_signature
(modelbuilder
)
1152 var mpropdef
= self.mpropdef
1153 if mpropdef
== null then return # Error thus skiped
1155 var bound
= self.mpropdef
.bound
1156 if bound
== null then return # Error thus skiped
1158 modelbuilder
.check_visibility
(n_type
, bound
, mpropdef
)
1160 var mclassdef
= mpropdef
.mclassdef
1161 var mmodule
= mclassdef
.mmodule
1162 var anchor
= mclassdef
.bound_mtype
1165 if bound
isa MVirtualType then
1166 # Slow case: progress on each resolution until: (i) we loop, or (ii) we found a non formal type
1167 var seen
= [self.mpropdef
.mproperty
.mvirtualtype
]
1169 if seen
.has
(bound
) then
1171 modelbuilder
.error
(self, "Error: circularity of virtual type definition: {seen.join(" -> ")}")
1175 var next
= bound
.lookup_bound
(mmodule
, anchor
)
1176 if not next
isa MVirtualType then break
1181 # Check redefinitions
1182 bound
= mpropdef
.bound
.as(not null)
1183 for p
in mpropdef
.mproperty
.lookup_super_definitions
(mmodule
, anchor
) do
1184 var supbound
= p
.bound
.as(not null)
1186 modelbuilder
.error
(self, "Redef Error: Virtual type {mpropdef.mproperty} is fixed in super-class {p.mclassdef.mclass}")
1189 if p
.mclassdef
.mclass
== mclassdef
.mclass
then
1190 # Still a warning to pass existing bad code
1191 modelbuilder
.warning
(n_type
, "refine-type", "Redef Error: a virtual type cannot be refined.")
1194 if not bound
.is_subtype
(mmodule
, anchor
, supbound
) then
1195 modelbuilder
.error
(n_type
, "Redef Error: Wrong bound type. Found {bound}, expected a subtype of {supbound}, as in {p}.")