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 # Look for the init in Object, or create it
86 if mclassdef
.mclass
.name
== "Object" and the_root_init_mmethod
== null then
87 # Create the implicit root-init method
88 var mprop
= new MMethod(mclassdef
, "init", mclassdef
.mclass
.visibility
)
89 mprop
.is_root_init
= true
90 var mpropdef
= new MMethodDef(mclassdef
, mprop
, nclassdef
.location
)
91 var mparameters
= new Array[MParameter]
92 var msignature
= new MSignature(mparameters
, null)
93 mpropdef
.msignature
= msignature
94 mpropdef
.new_msignature
= msignature
96 nclassdef
.mfree_init
= mpropdef
97 self.toolcontext
.info
("{mclassdef} gets a free empty constructor {mpropdef}{msignature}", 3)
98 the_root_init_mmethod
= mprop
102 # Is the class forbid constructors?
103 if not mclassdef
.mclass
.kind
.need_init
then return
105 # Is there already a constructor defined?
106 var defined_init
: nullable MMethodDef = null
107 for mpropdef
in mclassdef
.mpropdefs
do
108 if not mpropdef
isa MMethodDef then continue
109 if not mpropdef
.mproperty
.is_init
then continue
110 if mpropdef
.mproperty
.is_root_init
then
111 assert defined_init
== null
112 defined_init
= mpropdef
113 else if mpropdef
.mproperty
.name
== "init" then
114 # An explicit old-style init named "init", so return
119 if not nclassdef
isa AStdClassdef then return
121 # Collect undefined attributes
122 var mparameters
= new Array[MParameter]
123 var initializers
= new Array[MProperty]
124 var anode
: nullable ANode = null
125 for npropdef
in nclassdef
.n_propdefs
do
126 if npropdef
isa AAttrPropdef then
127 if npropdef
.mpropdef
== null then return # Skip broken attribute
128 var at
= npropdef
.get_single_annotation
("noinit", self)
130 npropdef
.noinit
= true
131 if npropdef
.n_expr
!= null then
132 self.error
(at
, "Error: `noinit` attributes cannot have an initial value")
134 continue # Skip noinit attributes
136 if npropdef
.n_expr
!= null then continue
137 var paramname
= npropdef
.mpropdef
.mproperty
.name
.substring_from
(1)
138 var ret_type
= npropdef
.mpropdef
.static_mtype
139 if ret_type
== null then return
140 var mparameter
= new MParameter(paramname
, ret_type
, false)
141 mparameters
.add
(mparameter
)
142 var msetter
= npropdef
.mwritepropdef
143 if msetter
== null then
144 # No setter, it is a old-style attribute, so just add it
145 initializers
.add
(npropdef
.mpropdef
.mproperty
)
147 # Add the setter to the list
148 initializers
.add
(msetter
.mproperty
)
150 if anode
== null then anode
= npropdef
153 if anode
== null then anode
= nclassdef
155 if the_root_init_mmethod
== null then return
157 # Look for most-specific new-stype init definitions
158 var spropdefs
= the_root_init_mmethod
.lookup_super_definitions
(mclassdef
.mmodule
, mclassdef
.bound_mtype
)
159 if spropdefs
.is_empty
then
160 toolcontext
.fatal_error
(nclassdef
.location
, "Fatal error: {mclassdef} does not specialize {the_root_init_mmethod.intro_mclassdef}. Possible duplication of the root class `Object`?")
163 # Search the longest-one and checks for conflict
164 var longest
= spropdefs
.first
165 if spropdefs
.length
> 1 then
166 # Check for conflict in the order of initializers
167 # Each initializer list must me a prefix of the longest list
168 # part 1. find the longest list
169 for spd
in spropdefs
do
170 if spd
.initializers
.length
> longest
.initializers
.length
then longest
= spd
173 for spd
in spropdefs
do
175 for p
in spd
.initializers
do
176 if p
!= longest
.initializers
[i
] then
177 self.error
(nclassdef
, "Error: conflict for inherited inits {spd}({spd.initializers.join(", ")}) and {longest}({longest.initializers.join(", ")})")
185 # Can we just inherit?
186 if spropdefs
.length
== 1 and mparameters
.is_empty
and defined_init
== null then
187 self.toolcontext
.info
("{mclassdef} inherits the basic constructor {longest}", 3)
191 # Combine the inherited list to what is collected
192 if longest
.initializers
.length
> 0 then
193 mparameters
.prepend longest
.new_msignature
.mparameters
194 initializers
.prepend longest
.initializers
197 # If we already have a basic init definition, then setup its initializers
198 if defined_init
!= null then
199 defined_init
.initializers
.add_all
(initializers
)
200 var msignature
= new MSignature(mparameters
, null)
201 defined_init
.new_msignature
= msignature
202 self.toolcontext
.info
("{mclassdef} extends its basic constructor signature to {defined_init}{msignature}", 3)
206 # Else create the local implicit basic init definition
207 var mprop
= the_root_init_mmethod
.as(not null)
208 var mpropdef
= new MMethodDef(mclassdef
, mprop
, nclassdef
.location
)
209 mpropdef
.has_supercall
= true
210 mpropdef
.initializers
.add_all
(initializers
)
211 var msignature
= new MSignature(mparameters
, null)
212 mpropdef
.new_msignature
= msignature
213 mpropdef
.msignature
= new MSignature(new Array[MParameter], null) # always an empty real signature
214 nclassdef
.mfree_init
= mpropdef
215 self.toolcontext
.info
("{mclassdef} gets a free constructor for attributes {mpropdef}{msignature}", 3)
218 # Check the visibility of `mtype` as an element of the signature of `mpropdef`.
219 fun check_visibility
(node
: ANode, mtype
: MType, mpropdef
: MPropDef)
221 var mmodule
= mpropdef
.mclassdef
.mmodule
222 var mproperty
= mpropdef
.mproperty
224 # Extract visibility information of the main part of `mtype`
225 # It is a case-by case
226 var vis_type
: nullable MVisibility = null # The own visibility of the type
227 var mmodule_type
: nullable MModule = null # The origial module of the type
228 mtype
= mtype
.as_notnullable
229 if mtype
isa MClassType then
230 vis_type
= mtype
.mclass
.visibility
231 mmodule_type
= mtype
.mclass
.intro
.mmodule
232 else if mtype
isa MVirtualType then
233 vis_type
= mtype
.mproperty
.visibility
234 mmodule_type
= mtype
.mproperty
.intro_mclassdef
.mmodule
235 else if mtype
isa MParameterType then
236 # nothing, always visible
238 node
.debug
"Unexpected type {mtype}"
242 if vis_type
!= null then
243 assert mmodule_type
!= null
244 var vis_module_type
= mmodule
.visibility_for
(mmodule_type
) # the visibility of the original module
245 if mproperty
.visibility
> vis_type
then
246 error
(node
, "Error: The {mproperty.visibility} property `{mproperty}` cannot contain the {vis_type} type `{mtype}`")
248 else if mproperty
.visibility
> vis_module_type
then
249 error
(node
, "Error: The {mproperty.visibility} property `{mproperty}` cannot contain the type `{mtype}` from the {vis_module_type} module `{mmodule_type}`")
254 # No error, try to go deeper in generic types
255 if node
isa AType then
256 for a
in node
.n_types
do
258 if t
== null then continue # Error, thus skipped
259 check_visibility
(a
, t
, mpropdef
)
261 else if mtype
isa MGenericType then
262 for t
in mtype
.arguments
do check_visibility
(node
, t
, mpropdef
)
268 # Does the MPropDef contains a call to super or a call of a super-constructor?
269 # Subsequent phases of the frontend (esp. typing) set it if required
270 var has_supercall
: Bool = false is writable
273 redef class AClassdef
274 var build_properties_is_done
: Bool = false
275 # The list of super-constructor to call at the start of the free constructor
276 # 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
277 var super_inits
: nullable Collection[MMethod] = null
279 # The free init (implicitely constructed by the class if required)
280 var mfree_init
: nullable MMethodDef = null
283 redef class MClassDef
284 # What is the `APropdef` associated to a `MProperty`?
285 # Used to check multiple definition of a property.
286 var mprop2npropdef
: Map[MProperty, APropdef] = new HashMap[MProperty, APropdef]
290 # Join the text of all tokens
291 # Used to get the 'real name' of method definitions.
292 fun collect_text
: String
294 var v
= new TextCollectorVisitor
301 private class TextCollectorVisitor
303 var text
: String = ""
306 if n
isa Token then text
+= n
.text
312 # The associated main model entity
313 type MPROPDEF: MPropDef
315 # The associated propdef once build by a `ModelBuilder`
316 var mpropdef
: nullable MPROPDEF is writable
318 private fun build_property
(modelbuilder
: ModelBuilder, mclassdef
: MClassDef) is abstract
319 private fun build_signature
(modelbuilder
: ModelBuilder) is abstract
320 private fun check_signature
(modelbuilder
: ModelBuilder) is abstract
321 private fun new_property_visibility
(modelbuilder
: ModelBuilder, mclassdef
: MClassDef, nvisibility
: nullable AVisibility): MVisibility
323 var mvisibility
= public_visibility
324 if nvisibility
!= null then
325 mvisibility
= nvisibility
.mvisibility
326 if mvisibility
== intrude_visibility
then
327 modelbuilder
.error
(nvisibility
, "Error: intrude is not a legal visibility for properties.")
328 mvisibility
= public_visibility
331 if mclassdef
.mclass
.visibility
== private_visibility
then
332 if mvisibility
== protected_visibility
then
333 assert nvisibility
!= null
334 modelbuilder
.error
(nvisibility
, "Error: The only legal visibility for properties in a private class is private.")
335 else if mvisibility
== private_visibility
then
336 assert nvisibility
!= null
337 modelbuilder
.advice
(nvisibility
, "useless-visibility", "Warning: private is superfluous since the only legal visibility for properties in a private class is private.")
339 mvisibility
= private_visibility
344 private fun set_doc
(mpropdef
: MPropDef, modelbuilder
: ModelBuilder)
346 var ndoc
= self.n_doc
348 var mdoc
= ndoc
.to_mdoc
350 mdoc
.original_mentity
= mpropdef
351 else if mpropdef
.is_intro
and mpropdef
.mproperty
.visibility
>= protected_visibility
then
352 modelbuilder
.advice
(self, "missing-doc", "Documentation warning: Undocumented property `{mpropdef.mproperty}`")
355 var at_deprecated
= get_single_annotation
("deprecated", modelbuilder
)
356 if at_deprecated
!= null then
357 if not mpropdef
.is_intro
then
358 modelbuilder
.error
(self, "Error: method redefinition cannot be deprecated.")
360 var info
= new MDeprecationInfo
361 ndoc
= at_deprecated
.n_doc
362 if ndoc
!= null then info
.mdoc
= ndoc
.to_mdoc
363 mpropdef
.mproperty
.deprecation
= info
368 private fun check_redef_property_visibility
(modelbuilder
: ModelBuilder, nvisibility
: nullable AVisibility, mprop
: MProperty)
370 if nvisibility
== null then return
371 var mvisibility
= nvisibility
.mvisibility
372 if mvisibility
!= mprop
.visibility
and mvisibility
!= public_visibility
then
373 modelbuilder
.error
(nvisibility
, "Error: redefinition changed the visibility from a {mprop.visibility} to a {mvisibility}")
377 private fun check_redef_keyword
(modelbuilder
: ModelBuilder, mclassdef
: MClassDef, kwredef
: nullable Token, need_redef
: Bool, mprop
: MProperty): Bool
379 if mclassdef
.mprop2npropdef
.has_key
(mprop
) then
380 modelbuilder
.error
(self, "Error: A property {mprop} is already defined in class {mclassdef.mclass} at line {mclassdef.mprop2npropdef[mprop].location.line_start}.")
383 if mprop
isa MMethod and mprop
.is_toplevel
!= (parent
isa ATopClassdef) then
384 if mprop
.is_toplevel
then
385 modelbuilder
.error
(self, "Error: {mprop} is a top level method.")
387 modelbuilder
.error
(self, "Error: {mprop} is not a top level method.")
392 if kwredef
== null then
394 modelbuilder
.error
(self, "Redef error: {mclassdef.mclass}::{mprop.name} is an inherited property. To redefine it, add the redef keyword.")
398 if not need_redef
then
399 modelbuilder
.error
(self, "Error: No property {mclassdef.mclass}::{mprop.name} is inherited. Remove the redef keyword to define a new property.")
408 redef class ASignature
409 # Is the model builder has correctly visited the signature
410 var is_visited
= false
411 # Names of parameters from the AST
412 # REQUIRE: is_visited
413 var param_names
= new Array[String]
414 # Types of parameters from the AST
415 # REQUIRE: is_visited
416 var param_types
= new Array[MType]
417 # Rank of the vararg (of -1 if none)
418 # REQUIRE: is_visited
419 var vararg_rank
: Int = -1
421 var ret_type
: nullable MType = null
423 # Visit and fill information about a signature
424 private fun visit_signature
(modelbuilder
: ModelBuilder, mclassdef
: MClassDef): Bool
426 var mmodule
= mclassdef
.mmodule
427 var param_names
= self.param_names
428 var param_types
= self.param_types
429 for np
in self.n_params
do
430 param_names
.add
(np
.n_id
.text
)
431 var ntype
= np
.n_type
432 if ntype
!= null then
433 var mtype
= modelbuilder
.resolve_mtype
(mmodule
, mclassdef
, ntype
)
434 if mtype
== null then return false # Skip error
435 for i
in [0..param_names
.length-param_types
.length
[ do
436 param_types
.add
(mtype
)
438 if np
.n_dotdotdot
!= null then
439 if self.vararg_rank
!= -1 then
440 modelbuilder
.error
(np
, "Error: {param_names[self.vararg_rank]} is already a vararg")
443 self.vararg_rank
= param_names
.length
- 1
448 var ntype
= self.n_type
449 if ntype
!= null then
450 self.ret_type
= modelbuilder
.resolve_mtype
(mmodule
, mclassdef
, ntype
)
451 if self.ret_type
== null then return false # Skip errir
454 self.is_visited
= true
458 # Build a visited signature
459 fun build_signature
(modelbuilder
: ModelBuilder): nullable MSignature
461 if param_names
.length
!= param_types
.length
then
462 # Some parameters are typed, other parameters are not typed.
463 modelbuilder
.error
(self.n_params
[param_types
.length
], "Error: Untyped parameter `{param_names[param_types.length]}'.")
467 var mparameters
= new Array[MParameter]
468 for i
in [0..param_names
.length
[ do
469 var mparameter
= new MParameter(param_names
[i
], param_types
[i
], i
== vararg_rank
)
470 self.n_params
[i
].mparameter
= mparameter
471 mparameters
.add
(mparameter
)
474 var msignature
= new MSignature(mparameters
, ret_type
)
480 # The associated mparameter if any
481 var mparameter
: nullable MParameter = null
484 redef class AMethPropdef
485 redef type MPROPDEF: MMethodDef
488 # Can self be used as a root init?
489 private fun look_like_a_root_init
(modelbuilder
: ModelBuilder): Bool
491 # Need the `init` keyword
492 if n_kwinit
== null then return false
493 # Need to by anonymous
494 if self.n_methid
!= null then return false
496 if self.n_signature
.n_params
.length
> 0 then return false
497 # Cannot be private or something
498 if not self.n_visibility
isa APublicVisibility then return false
499 # No annotation on itself
500 if get_single_annotation
("old_style_init", modelbuilder
) != null then return false
502 var amod
= self.parent
.parent
.as(AModule)
503 var amoddecl
= amod
.n_moduledecl
504 if amoddecl
!= null then
505 var old
= amoddecl
.get_single_annotation
("old_style_init", modelbuilder
)
506 if old
!= null then return false
512 redef fun build_property
(modelbuilder
, mclassdef
)
514 var n_kwinit
= n_kwinit
515 var n_kwnew
= n_kwnew
516 var is_init
= n_kwinit
!= null or n_kwnew
!= null
518 var amethodid
= self.n_methid
520 if amethodid
== null then
524 else if n_kwinit
!= null then
527 else if n_kwnew
!= null then
533 else if amethodid
isa AIdMethid then
534 name
= amethodid
.n_id
.text
535 name_node
= amethodid
537 # operator, bracket or assign
538 name
= amethodid
.collect_text
539 name_node
= amethodid
541 if name
== "-" and self.n_signature
.n_params
.length
== 0 then
546 var mprop
: nullable MMethod = null
547 if not is_init
or n_kwredef
!= null then mprop
= modelbuilder
.try_get_mproperty_by_name
(name_node
, mclassdef
, name
).as(nullable MMethod)
548 if mprop
== null and look_like_a_root_init
(modelbuilder
) then
549 mprop
= modelbuilder
.the_root_init_mmethod
551 if nb
isa ABlockExpr and nb
.n_expr
.is_empty
and n_doc
== null then
552 modelbuilder
.advice
(self, "useless-init", "Warning: useless empty init in {mclassdef}")
555 if mprop
== null then
556 var mvisibility
= new_property_visibility
(modelbuilder
, mclassdef
, self.n_visibility
)
557 mprop
= new MMethod(mclassdef
, name
, mvisibility
)
558 if look_like_a_root_init
(modelbuilder
) and modelbuilder
.the_root_init_mmethod
== null then
559 modelbuilder
.the_root_init_mmethod
= mprop
560 mprop
.is_root_init
= true
562 mprop
.is_init
= is_init
563 mprop
.is_new
= n_kwnew
!= null
564 if parent
isa ATopClassdef then mprop
.is_toplevel
= true
565 if not self.check_redef_keyword
(modelbuilder
, mclassdef
, n_kwredef
, false, mprop
) then return
567 if not mprop
.is_root_init
and not self.check_redef_keyword
(modelbuilder
, mclassdef
, n_kwredef
, not self isa AMainMethPropdef, mprop
) then return
568 check_redef_property_visibility
(modelbuilder
, self.n_visibility
, mprop
)
570 mclassdef
.mprop2npropdef
[mprop
] = self
572 var mpropdef
= new MMethodDef(mclassdef
, mprop
, self.location
)
574 set_doc
(mpropdef
, modelbuilder
)
576 self.mpropdef
= mpropdef
577 modelbuilder
.mpropdef2npropdef
[mpropdef
] = self
578 if mpropdef
.is_intro
then
579 modelbuilder
.toolcontext
.info
("{mpropdef} introduces new method {mprop.full_name}", 3)
581 modelbuilder
.toolcontext
.info
("{mpropdef} redefines method {mprop.full_name}", 3)
585 redef fun build_signature
(modelbuilder
)
587 var mpropdef
= self.mpropdef
588 if mpropdef
== null then return # Error thus skiped
589 var mclassdef
= mpropdef
.mclassdef
590 var mmodule
= mclassdef
.mmodule
591 var nsig
= self.n_signature
593 # Retrieve info from the signature AST
594 var param_names
= new Array[String] # Names of parameters from the AST
595 var param_types
= new Array[MType] # Types of parameters from the AST
597 var ret_type
: nullable MType = null # Return type from the AST
599 if not nsig
.visit_signature
(modelbuilder
, mclassdef
) then return
600 param_names
= nsig
.param_names
601 param_types
= nsig
.param_types
602 vararg_rank
= nsig
.vararg_rank
603 ret_type
= nsig
.ret_type
606 # Look for some signature to inherit
607 # FIXME: do not inherit from the intro, but from the most specific
608 var msignature
: nullable MSignature = null
609 if not mpropdef
.is_intro
then
610 msignature
= mpropdef
.mproperty
.intro
.msignature
611 if msignature
== null then return # Skip error
613 # Check inherited signature arity
614 if param_names
.length
!= msignature
.arity
then
616 if nsig
!= null then node
= nsig
else node
= self
617 modelbuilder
.error
(node
, "Redef error: {mpropdef} redefines {mpropdef.mproperty.intro} with {param_names.length} parameter(s), {msignature.arity} expected. Signature is {mpropdef}{msignature}")
620 else if mpropdef
.mproperty
.is_init
then
621 # FIXME UGLY: inherit signature from a super-constructor
622 for msupertype
in mclassdef
.supertypes
do
623 msupertype
= msupertype
.anchor_to
(mmodule
, mclassdef
.bound_mtype
)
624 var candidate
= modelbuilder
.try_get_mproperty_by_name2
(self, mmodule
, msupertype
, mpropdef
.mproperty
.name
)
625 if candidate
!= null then
626 if msignature
== null then
627 msignature
= candidate
.intro
.as(MMethodDef).msignature
634 # Inherit the signature
635 if msignature
!= null and param_names
.length
!= param_types
.length
and param_names
.length
== msignature
.arity
and param_types
.length
== 0 then
636 # Parameters are untyped, thus inherit them
637 param_types
= new Array[MType]
638 for mparameter
in msignature
.mparameters
do
639 param_types
.add
(mparameter
.mtype
)
641 vararg_rank
= msignature
.vararg_rank
643 if msignature
!= null and ret_type
== null then
644 ret_type
= msignature
.return_mtype
647 if param_names
.length
!= param_types
.length
then
648 # Some parameters are typed, other parameters are not typed.
649 modelbuilder
.error
(nsig
.n_params
[param_types
.length
], "Error: Untyped parameter `{param_names[param_types.length]}'.")
653 var mparameters
= new Array[MParameter]
654 for i
in [0..param_names
.length
[ do
655 var mparameter
= new MParameter(param_names
[i
], param_types
[i
], i
== vararg_rank
)
656 if nsig
!= null then nsig
.n_params
[i
].mparameter
= mparameter
657 mparameters
.add
(mparameter
)
660 msignature
= new MSignature(mparameters
, ret_type
)
661 mpropdef
.msignature
= msignature
662 mpropdef
.is_abstract
= self.get_single_annotation
("abstract", modelbuilder
) != null
663 mpropdef
.is_intern
= self.get_single_annotation
("intern", modelbuilder
) != null
664 mpropdef
.is_extern
= self.n_extern_code_block
!= null or self.get_single_annotation
("extern", modelbuilder
) != null
667 redef fun check_signature
(modelbuilder
)
669 var mpropdef
= self.mpropdef
670 if mpropdef
== null then return # Error thus skiped
671 var mclassdef
= mpropdef
.mclassdef
672 var mmodule
= mclassdef
.mmodule
673 var nsig
= self.n_signature
674 var mysignature
= self.mpropdef
.msignature
675 if mysignature
== null then return # Error thus skiped
677 # Lookup for signature in the precursor
678 # FIXME all precursors should be considered
679 if not mpropdef
.is_intro
then
680 var msignature
= mpropdef
.mproperty
.intro
.msignature
681 if msignature
== null then return
683 var precursor_ret_type
= msignature
.return_mtype
684 var ret_type
= mysignature
.return_mtype
685 if ret_type
!= null and precursor_ret_type
== null then
686 modelbuilder
.error
(nsig
.n_type
.as(not null), "Redef Error: {mpropdef.mproperty} is a procedure, not a function.")
690 if mysignature
.arity
> 0 then
691 # Check parameters types
692 for i
in [0..mysignature
.arity
[ do
693 var myt
= mysignature
.mparameters
[i
].mtype
694 var prt
= msignature
.mparameters
[i
].mtype
695 if not myt
.is_subtype
(mmodule
, mclassdef
.bound_mtype
, prt
) or
696 not prt
.is_subtype
(mmodule
, mclassdef
.bound_mtype
, myt
) then
697 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}.")
701 if precursor_ret_type
!= null then
702 if ret_type
== null then
703 # Inherit the return type
704 ret_type
= precursor_ret_type
705 else if not ret_type
.is_subtype
(mmodule
, mclassdef
.bound_mtype
, precursor_ret_type
) then
706 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}.")
711 if mysignature
.arity
> 0 then
712 # Check parameters visibility
713 for i
in [0..mysignature
.arity
[ do
714 var nt
= nsig
.n_params
[i
].n_type
715 if nt
!= null then modelbuilder
.check_visibility
(nt
, nt
.mtype
.as(not null), mpropdef
)
718 if nt
!= null then modelbuilder
.check_visibility
(nt
, nt
.mtype
.as(not null), mpropdef
)
723 redef class AAttrPropdef
724 redef type MPROPDEF: MAttributeDef
726 # Is the node tagged `noinit`?
729 # Is the node taggeg lazy?
732 # The guard associated to a lasy attribute.
733 # Because some engines does not have a working `isset`,
734 # this additionnal attribute is used to guard the lazy initialization.
735 # TODO: to remove once isset is correctly implemented
736 var mlazypropdef
: nullable MAttributeDef
738 # The associated getter (read accessor) if any
739 var mreadpropdef
: nullable MMethodDef is writable
740 # The associated setter (write accessor) if any
741 var mwritepropdef
: nullable MMethodDef is writable
743 redef fun build_property
(modelbuilder
, mclassdef
)
745 var mclass
= mclassdef
.mclass
748 name
= self.n_id2
.text
750 if mclass
.kind
== interface_kind
or mclassdef
.mclass
.kind
== enum_kind
then
751 modelbuilder
.error
(self, "Error: Attempt to define attribute {name} in the interface {mclass}.")
752 else if mclass
.kind
== enum_kind
then
753 modelbuilder
.error
(self, "Error: Attempt to define attribute {name} in the enum class {mclass}.")
754 else if mclass
.kind
== extern_kind
then
755 modelbuilder
.error
(self, "Error: Attempt to define attribute {name} in the extern class {mclass}.")
758 # New attribute style
759 var nid2
= self.n_id2
760 var mprop
= new MAttribute(mclassdef
, "_" + name
, private_visibility
)
761 var mpropdef
= new MAttributeDef(mclassdef
, mprop
, self.location
)
762 self.mpropdef
= mpropdef
763 modelbuilder
.mpropdef2npropdef
[mpropdef
] = self
764 set_doc
(mpropdef
, modelbuilder
)
767 var mreadprop
= modelbuilder
.try_get_mproperty_by_name
(nid2
, mclassdef
, readname
).as(nullable MMethod)
768 if mreadprop
== null then
769 var mvisibility
= new_property_visibility
(modelbuilder
, mclassdef
, self.n_visibility
)
770 mreadprop
= new MMethod(mclassdef
, readname
, mvisibility
)
771 if not self.check_redef_keyword
(modelbuilder
, mclassdef
, n_kwredef
, false, mreadprop
) then return
772 mreadprop
.deprecation
= mprop
.deprecation
774 if not self.check_redef_keyword
(modelbuilder
, mclassdef
, n_kwredef
, true, mreadprop
) then return
775 check_redef_property_visibility
(modelbuilder
, self.n_visibility
, mreadprop
)
777 mclassdef
.mprop2npropdef
[mreadprop
] = self
779 var mreadpropdef
= new MMethodDef(mclassdef
, mreadprop
, self.location
)
780 self.mreadpropdef
= mreadpropdef
781 modelbuilder
.mpropdef2npropdef
[mreadpropdef
] = self
782 mreadpropdef
.mdoc
= mpropdef
.mdoc
784 var atlazy
= self.get_single_annotation
("lazy", modelbuilder
)
785 if atlazy
!= null then
786 if n_expr
== null then
787 modelbuilder
.error
(atlazy
, "Error: a lazy attribute needs a value")
790 var mlazyprop
= new MAttribute(mclassdef
, "lazy _" + name
, none_visibility
)
791 var mlazypropdef
= new MAttributeDef(mclassdef
, mlazyprop
, self.location
)
792 self.mlazypropdef
= mlazypropdef
795 var atreadonly
= self.get_single_annotation
("readonly", modelbuilder
)
796 if atreadonly
!= null then
797 if n_expr
== null then
798 modelbuilder
.error
(atreadonly
, "Error: a readonly attribute needs a value")
800 # No setter, so just leave
804 var writename
= name
+ "="
805 var atwritable
= self.get_single_annotation
("writable", modelbuilder
)
806 if atwritable
!= null then
807 if not atwritable
.n_args
.is_empty
then
808 writename
= atwritable
.arg_as_id
(modelbuilder
) or else writename
811 var mwriteprop
= modelbuilder
.try_get_mproperty_by_name
(nid2
, mclassdef
, writename
).as(nullable MMethod)
812 var nwkwredef
: nullable Token = null
813 if atwritable
!= null then nwkwredef
= atwritable
.n_kwredef
814 if mwriteprop
== null then
816 if atwritable
!= null then
817 mvisibility
= new_property_visibility
(modelbuilder
, mclassdef
, atwritable
.n_visibility
)
819 mvisibility
= private_visibility
821 mwriteprop
= new MMethod(mclassdef
, writename
, mvisibility
)
822 if not self.check_redef_keyword
(modelbuilder
, mclassdef
, nwkwredef
, false, mwriteprop
) then return
823 mwriteprop
.deprecation
= mprop
.deprecation
825 if not self.check_redef_keyword
(modelbuilder
, mclassdef
, nwkwredef
or else n_kwredef
, true, mwriteprop
) then return
826 if atwritable
!= null then
827 check_redef_property_visibility
(modelbuilder
, atwritable
.n_visibility
, mwriteprop
)
830 mclassdef
.mprop2npropdef
[mwriteprop
] = self
832 var mwritepropdef
= new MMethodDef(mclassdef
, mwriteprop
, self.location
)
833 self.mwritepropdef
= mwritepropdef
834 modelbuilder
.mpropdef2npropdef
[mwritepropdef
] = self
835 mwritepropdef
.mdoc
= mpropdef
.mdoc
838 redef fun build_signature
(modelbuilder
)
840 var mpropdef
= self.mpropdef
841 if mpropdef
== null then return # Error thus skiped
842 var mclassdef
= mpropdef
.mclassdef
843 var mmodule
= mclassdef
.mmodule
844 var mtype
: nullable MType = null
846 var mreadpropdef
= self.mreadpropdef
848 var ntype
= self.n_type
849 if ntype
!= null then
850 mtype
= modelbuilder
.resolve_mtype
(mmodule
, mclassdef
, ntype
)
851 if mtype
== null then return
854 # Inherit the type from the getter (usually an abstact getter)
855 if mtype
== null and mreadpropdef
!= null and not mreadpropdef
.is_intro
then
856 var msignature
= mreadpropdef
.mproperty
.intro
.msignature
857 if msignature
== null then return # Error, thus skiped
858 mtype
= msignature
.return_mtype
861 var nexpr
= self.n_expr
862 if mtype
== null then
863 if nexpr
!= null then
864 if nexpr
isa ANewExpr then
865 mtype
= modelbuilder
.resolve_mtype
(mmodule
, mclassdef
, nexpr
.n_type
)
866 else if nexpr
isa AIntExpr then
867 var cla
= modelbuilder
.try_get_mclass_by_name
(nexpr
, mmodule
, "Int")
868 if cla
!= null then mtype
= cla
.mclass_type
869 else if nexpr
isa AFloatExpr then
870 var cla
= modelbuilder
.try_get_mclass_by_name
(nexpr
, mmodule
, "Float")
871 if cla
!= null then mtype
= cla
.mclass_type
872 else if nexpr
isa ACharExpr then
873 var cla
= modelbuilder
.try_get_mclass_by_name
(nexpr
, mmodule
, "Char")
874 if cla
!= null then mtype
= cla
.mclass_type
875 else if nexpr
isa ABoolExpr then
876 var cla
= modelbuilder
.try_get_mclass_by_name
(nexpr
, mmodule
, "Bool")
877 if cla
!= null then mtype
= cla
.mclass_type
878 else if nexpr
isa ASuperstringExpr then
879 var cla
= modelbuilder
.try_get_mclass_by_name
(nexpr
, mmodule
, "String")
880 if cla
!= null then mtype
= cla
.mclass_type
881 else if nexpr
isa AStringFormExpr then
882 var cla
= modelbuilder
.try_get_mclass_by_name
(nexpr
, mmodule
, "String")
883 if cla
!= null then mtype
= cla
.mclass_type
885 modelbuilder
.error
(self, "Error: Untyped attribute {mpropdef}. Implicit typing allowed only for literals and new.")
888 if mtype
== null then return
890 else if ntype
!= null then
891 if nexpr
isa ANewExpr then
892 var xmtype
= modelbuilder
.resolve_mtype
(mmodule
, mclassdef
, nexpr
.n_type
)
893 if xmtype
== mtype
then
894 modelbuilder
.advice
(ntype
, "useless-type", "Warning: useless type definition")
899 if mtype
== null then
900 modelbuilder
.error
(self, "Error: Untyped attribute {mpropdef}")
904 mpropdef
.static_mtype
= mtype
906 if mreadpropdef
!= null then
907 var msignature
= new MSignature(new Array[MParameter], mtype
)
908 mreadpropdef
.msignature
= msignature
911 var mwritepropdef
= self.mwritepropdef
912 if mwritepropdef
!= null then
915 var mparameter
= new MParameter(name
, mtype
, false)
916 var msignature
= new MSignature([mparameter
], null)
917 mwritepropdef
.msignature
= msignature
920 var mlazypropdef
= self.mlazypropdef
921 if mlazypropdef
!= null then
922 mlazypropdef
.static_mtype
= modelbuilder
.model
.get_mclasses_by_name
("Bool").first
.mclass_type
926 redef fun check_signature
(modelbuilder
)
928 var mpropdef
= self.mpropdef
929 if mpropdef
== null then return # Error thus skiped
930 var mclassdef
= mpropdef
.mclassdef
931 var mmodule
= mclassdef
.mmodule
932 var ntype
= self.n_type
933 var mtype
= self.mpropdef
.static_mtype
934 if mtype
== null then return # Error thus skiped
936 # Lookup for signature in the precursor
937 # FIXME all precursors should be considered
938 if not mpropdef
.is_intro
then
939 var precursor_type
= mpropdef
.mproperty
.intro
.static_mtype
940 if precursor_type
== null then return
942 if mtype
!= precursor_type
then
943 modelbuilder
.error
(ntype
.as(not null), "Redef Error: Wrong static type. found {mtype}, expected {precursor_type}.")
948 # Check getter and setter
949 var meth
= self.mreadpropdef
951 self.check_method_signature
(modelbuilder
, meth
)
952 var node
: nullable ANode = ntype
953 if node
== null then node
= self
954 modelbuilder
.check_visibility
(node
, mtype
, meth
)
956 meth
= self.mwritepropdef
958 self.check_method_signature
(modelbuilder
, meth
)
959 var node
: nullable ANode = ntype
960 if node
== null then node
= self
961 modelbuilder
.check_visibility
(node
, mtype
, meth
)
965 private fun check_method_signature
(modelbuilder
: ModelBuilder, mpropdef
: MMethodDef)
967 var mclassdef
= mpropdef
.mclassdef
968 var mmodule
= mclassdef
.mmodule
969 var nsig
= self.n_type
970 var mysignature
= mpropdef
.msignature
971 if mysignature
== null then return # Error thus skiped
973 # Lookup for signature in the precursor
974 # FIXME all precursors should be considered
975 if not mpropdef
.is_intro
then
976 var msignature
= mpropdef
.mproperty
.intro
.msignature
977 if msignature
== null then return
979 if mysignature
.arity
!= msignature
.arity
then
981 if nsig
!= null then node
= nsig
else node
= self
982 modelbuilder
.error
(node
, "Redef Error: {mysignature.arity} parameters found, {msignature.arity} expected. Signature is {mpropdef}{msignature}")
985 var precursor_ret_type
= msignature
.return_mtype
986 var ret_type
= mysignature
.return_mtype
987 if ret_type
!= null and precursor_ret_type
== null then
989 if nsig
!= null then node
= nsig
else node
= self
990 modelbuilder
.error
(node
, "Redef Error: {mpropdef.mproperty} is a procedure, not a function.")
994 if mysignature
.arity
> 0 then
995 # Check parameters types
996 for i
in [0..mysignature
.arity
[ do
997 var myt
= mysignature
.mparameters
[i
].mtype
998 var prt
= msignature
.mparameters
[i
].mtype
999 if not myt
.is_subtype
(mmodule
, mclassdef
.bound_mtype
, prt
) or
1000 not prt
.is_subtype
(mmodule
, mclassdef
.bound_mtype
, myt
) then
1002 if nsig
!= null then node
= nsig
else node
= self
1003 modelbuilder
.error
(node
, "Redef Error: Wrong type for parameter `{mysignature.mparameters[i].name}'. found {myt}, expected {prt}.")
1007 if precursor_ret_type
!= null then
1008 if ret_type
== null then
1009 # Inherit the return type
1010 ret_type
= precursor_ret_type
1011 else if not ret_type
.is_subtype
(mmodule
, mclassdef
.bound_mtype
, precursor_ret_type
) then
1013 if nsig
!= null then node
= nsig
else node
= self
1014 modelbuilder
.error
(node
, "Redef Error: Wrong return type. found {ret_type}, expected {precursor_ret_type}.")
1021 redef class ATypePropdef
1022 redef type MPROPDEF: MVirtualTypeDef
1024 redef fun build_property
(modelbuilder
, mclassdef
)
1026 var name
= self.n_id
.text
1027 var mprop
= modelbuilder
.try_get_mproperty_by_name
(self.n_id
, mclassdef
, name
)
1028 if mprop
== null then
1029 var mvisibility
= new_property_visibility
(modelbuilder
, mclassdef
, self.n_visibility
)
1030 mprop
= new MVirtualTypeProp(mclassdef
, name
, mvisibility
)
1031 for c
in name
.chars
do if c
>= 'a' and c
<= 'z' then
1032 modelbuilder
.warning
(n_id
, "bad-type-name", "Warning: lowercase in the virtual type {name}")
1035 if not self.check_redef_keyword
(modelbuilder
, mclassdef
, self.n_kwredef
, false, mprop
) then return
1037 if not self.check_redef_keyword
(modelbuilder
, mclassdef
, self.n_kwredef
, true, mprop
) then return
1038 assert mprop
isa MVirtualTypeProp
1039 check_redef_property_visibility
(modelbuilder
, self.n_visibility
, mprop
)
1041 mclassdef
.mprop2npropdef
[mprop
] = self
1043 var mpropdef
= new MVirtualTypeDef(mclassdef
, mprop
, self.location
)
1044 self.mpropdef
= mpropdef
1045 modelbuilder
.mpropdef2npropdef
[mpropdef
] = self
1046 set_doc
(mpropdef
, modelbuilder
)
1048 var atfixed
= get_single_annotation
("fixed", modelbuilder
)
1049 if atfixed
!= null then
1050 mpropdef
.is_fixed
= true
1054 redef fun build_signature
(modelbuilder
)
1056 var mpropdef
= self.mpropdef
1057 if mpropdef
== null then return # Error thus skiped
1058 var mclassdef
= mpropdef
.mclassdef
1059 var mmodule
= mclassdef
.mmodule
1060 var mtype
: nullable MType = null
1062 var ntype
= self.n_type
1063 mtype
= modelbuilder
.resolve_mtype
(mmodule
, mclassdef
, ntype
)
1064 if mtype
== null then return
1066 mpropdef
.bound
= mtype
1067 # print "{mpropdef}: {mtype}"
1070 redef fun check_signature
(modelbuilder
)
1072 var mpropdef
= self.mpropdef
1073 if mpropdef
== null then return # Error thus skiped
1075 var bound
= self.mpropdef
.bound
1076 if bound
== null then return # Error thus skiped
1078 modelbuilder
.check_visibility
(n_type
, bound
, mpropdef
)
1080 var mclassdef
= mpropdef
.mclassdef
1081 var mmodule
= mclassdef
.mmodule
1082 var anchor
= mclassdef
.bound_mtype
1085 if bound
isa MVirtualType then
1086 # Slow case: progress on each resolution until: (i) we loop, or (ii) we found a non formal type
1087 var seen
= [self.mpropdef
.mproperty
.mvirtualtype
]
1089 if seen
.has
(bound
) then
1091 modelbuilder
.error
(self, "Error: circularity of virtual type definition: {seen.join(" -> ")}")
1095 var next
= bound
.lookup_bound
(mmodule
, anchor
)
1096 if not next
isa MVirtualType then break
1101 # Check redefinitions
1102 bound
= mpropdef
.bound
.as(not null)
1103 for p
in mpropdef
.mproperty
.lookup_super_definitions
(mmodule
, anchor
) do
1104 var supbound
= p
.bound
.as(not null)
1106 modelbuilder
.error
(self, "Redef Error: Virtual type {mpropdef.mproperty} is fixed in super-class {p.mclassdef.mclass}")
1109 if p
.mclassdef
.mclass
== mclassdef
.mclass
then
1110 # Still a warning to pass existing bad code
1111 modelbuilder
.warning
(n_type
, "refine-type", "Redef Error: a virtual type cannot be refined.")
1114 if not bound
.is_subtype
(mmodule
, anchor
, supbound
) then
1115 modelbuilder
.error
(n_type
, "Redef Error: Wrong bound type. Found {bound}, expected a subtype of {supbound}, as in {p}.")