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 for npropdef
in nclassdef
.n_propdefs
do
125 if npropdef
isa AAttrPropdef then
126 if npropdef
.mpropdef
== null then return # Skip broken attribute
127 var at
= npropdef
.get_single_annotation
("noinit", self)
129 npropdef
.noinit
= true
130 if npropdef
.n_expr
!= null then
131 self.error
(at
, "Error: `noinit` attributes cannot have an initial value")
133 continue # Skip noinit attributes
135 if npropdef
.n_expr
!= null then continue
136 var paramname
= npropdef
.mpropdef
.mproperty
.name
.substring_from
(1)
137 var ret_type
= npropdef
.mpropdef
.static_mtype
138 if ret_type
== null then return
139 var mparameter
= new MParameter(paramname
, ret_type
, false)
140 mparameters
.add
(mparameter
)
141 var msetter
= npropdef
.mwritepropdef
142 if msetter
== null then
143 # No setter, it is a old-style attribute, so just add it
144 initializers
.add
(npropdef
.mpropdef
.mproperty
)
146 # Add the setter to the list
147 initializers
.add
(msetter
.mproperty
)
152 if the_root_init_mmethod
== null then return
154 # Look for most-specific new-stype init definitions
155 var spropdefs
= the_root_init_mmethod
.lookup_super_definitions
(mclassdef
.mmodule
, mclassdef
.bound_mtype
)
156 if spropdefs
.is_empty
then
157 toolcontext
.fatal_error
(nclassdef
.location
, "Fatal error: {mclassdef} does not specialize {the_root_init_mmethod.intro_mclassdef}. Possible duplication of the root class `Object`?")
160 # Search the longest-one and checks for conflict
161 var longest
= spropdefs
.first
162 if spropdefs
.length
> 1 then
163 # Check for conflict in the order of initializers
164 # Each initializer list must me a prefix of the longest list
165 # part 1. find the longest list
166 for spd
in spropdefs
do
167 if spd
.initializers
.length
> longest
.initializers
.length
then longest
= spd
170 for spd
in spropdefs
do
172 for p
in spd
.initializers
do
173 if p
!= longest
.initializers
[i
] then
174 self.error
(nclassdef
, "Error: conflict for inherited inits {spd}({spd.initializers.join(", ")}) and {longest}({longest.initializers.join(", ")})")
182 # Can we just inherit?
183 if spropdefs
.length
== 1 and mparameters
.is_empty
and defined_init
== null then
184 self.toolcontext
.info
("{mclassdef} inherits the basic constructor {longest}", 3)
188 # Combine the inherited list to what is collected
189 if longest
.initializers
.length
> 0 then
190 mparameters
.prepend longest
.new_msignature
.mparameters
191 initializers
.prepend longest
.initializers
194 # If we already have a basic init definition, then setup its initializers
195 if defined_init
!= null then
196 defined_init
.initializers
.add_all
(initializers
)
197 var msignature
= new MSignature(mparameters
, null)
198 defined_init
.new_msignature
= msignature
199 self.toolcontext
.info
("{mclassdef} extends its basic constructor signature to {defined_init}{msignature}", 3)
203 # Else create the local implicit basic init definition
204 var mprop
= the_root_init_mmethod
.as(not null)
205 var mpropdef
= new MMethodDef(mclassdef
, mprop
, nclassdef
.location
)
206 mpropdef
.has_supercall
= true
207 mpropdef
.initializers
.add_all
(initializers
)
208 var msignature
= new MSignature(mparameters
, null)
209 mpropdef
.new_msignature
= msignature
210 mpropdef
.msignature
= new MSignature(new Array[MParameter], null) # always an empty real signature
211 nclassdef
.mfree_init
= mpropdef
212 self.toolcontext
.info
("{mclassdef} gets a free constructor for attributes {mpropdef}{msignature}", 3)
215 # Check the visibility of `mtype` as an element of the signature of `mpropdef`.
216 fun check_visibility
(node
: ANode, mtype
: MType, mpropdef
: MPropDef)
218 var mmodule
= mpropdef
.mclassdef
.mmodule
219 var mproperty
= mpropdef
.mproperty
221 # Extract visibility information of the main part of `mtype`
222 # It is a case-by case
223 var vis_type
: nullable MVisibility = null # The own visibility of the type
224 var mmodule_type
: nullable MModule = null # The origial module of the type
225 mtype
= mtype
.as_notnullable
226 if mtype
isa MClassType then
227 vis_type
= mtype
.mclass
.visibility
228 mmodule_type
= mtype
.mclass
.intro
.mmodule
229 else if mtype
isa MVirtualType then
230 vis_type
= mtype
.mproperty
.visibility
231 mmodule_type
= mtype
.mproperty
.intro_mclassdef
.mmodule
232 else if mtype
isa MParameterType then
233 # nothing, always visible
235 node
.debug
"Unexpected type {mtype}"
239 if vis_type
!= null then
240 assert mmodule_type
!= null
241 var vis_module_type
= mmodule
.visibility_for
(mmodule_type
) # the visibility of the original module
242 if mproperty
.visibility
> vis_type
then
243 error
(node
, "Error: The {mproperty.visibility} property `{mproperty}` cannot contain the {vis_type} type `{mtype}`")
245 else if mproperty
.visibility
> vis_module_type
then
246 error
(node
, "Error: The {mproperty.visibility} property `{mproperty}` cannot contain the type `{mtype}` from the {vis_module_type} module `{mmodule_type}`")
251 # No error, try to go deeper in generic types
252 if node
isa AType then
253 for a
in node
.n_types
do
255 if t
== null then continue # Error, thus skipped
256 check_visibility
(a
, t
, mpropdef
)
258 else if mtype
isa MGenericType then
259 for t
in mtype
.arguments
do check_visibility
(node
, t
, mpropdef
)
265 # Does the MPropDef contains a call to super or a call of a super-constructor?
266 # Subsequent phases of the frontend (esp. typing) set it if required
267 var has_supercall
: Bool = false is writable
270 redef class AClassdef
271 var build_properties_is_done
: Bool = false
272 # The list of super-constructor to call at the start of the free constructor
273 # 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
274 var super_inits
: nullable Collection[MMethod] = null
276 # The free init (implicitely constructed by the class if required)
277 var mfree_init
: nullable MMethodDef = null
280 redef class MClassDef
281 # What is the `APropdef` associated to a `MProperty`?
282 # Used to check multiple definition of a property.
283 var mprop2npropdef
: Map[MProperty, APropdef] = new HashMap[MProperty, APropdef]
287 # Join the text of all tokens
288 # Used to get the 'real name' of method definitions.
289 fun collect_text
: String
291 var v
= new TextCollectorVisitor
298 private class TextCollectorVisitor
300 var text
: String = ""
303 if n
isa Token then text
+= n
.text
309 # The associated main model entity
310 type MPROPDEF: MPropDef
312 # The associated propdef once build by a `ModelBuilder`
313 var mpropdef
: nullable MPROPDEF is writable
315 private fun build_property
(modelbuilder
: ModelBuilder, mclassdef
: MClassDef) is abstract
316 private fun build_signature
(modelbuilder
: ModelBuilder) is abstract
317 private fun check_signature
(modelbuilder
: ModelBuilder) is abstract
318 private fun new_property_visibility
(modelbuilder
: ModelBuilder, mclassdef
: MClassDef, nvisibility
: nullable AVisibility): MVisibility
320 var mvisibility
= public_visibility
321 if nvisibility
!= null then
322 mvisibility
= nvisibility
.mvisibility
323 if mvisibility
== intrude_visibility
then
324 modelbuilder
.error
(nvisibility
, "Error: intrude is not a legal visibility for properties.")
325 mvisibility
= public_visibility
328 if mclassdef
.mclass
.visibility
== private_visibility
then
329 if mvisibility
== protected_visibility
then
330 assert nvisibility
!= null
331 modelbuilder
.error
(nvisibility
, "Error: The only legal visibility for properties in a private class is private.")
332 else if mvisibility
== private_visibility
then
333 assert nvisibility
!= null
334 modelbuilder
.advice
(nvisibility
, "useless-visibility", "Warning: private is superfluous since the only legal visibility for properties in a private class is private.")
336 mvisibility
= private_visibility
341 private fun set_doc
(mpropdef
: MPropDef, modelbuilder
: ModelBuilder)
343 var ndoc
= self.n_doc
345 var mdoc
= ndoc
.to_mdoc
347 mdoc
.original_mentity
= mpropdef
348 else if mpropdef
.is_intro
and mpropdef
.mproperty
.visibility
>= protected_visibility
then
349 modelbuilder
.advice
(self, "missing-doc", "Documentation warning: Undocumented property `{mpropdef.mproperty}`")
352 var at_deprecated
= get_single_annotation
("deprecated", modelbuilder
)
353 if at_deprecated
!= null then
354 if not mpropdef
.is_intro
then
355 modelbuilder
.error
(self, "Error: method redefinition cannot be deprecated.")
357 var info
= new MDeprecationInfo
358 ndoc
= at_deprecated
.n_doc
359 if ndoc
!= null then info
.mdoc
= ndoc
.to_mdoc
360 mpropdef
.mproperty
.deprecation
= info
365 private fun check_redef_property_visibility
(modelbuilder
: ModelBuilder, nvisibility
: nullable AVisibility, mprop
: MProperty)
367 if nvisibility
== null then return
368 var mvisibility
= nvisibility
.mvisibility
369 if mvisibility
!= mprop
.visibility
and mvisibility
!= public_visibility
then
370 modelbuilder
.error
(nvisibility
, "Error: redefinition changed the visibility from a {mprop.visibility} to a {mvisibility}")
374 private fun check_redef_keyword
(modelbuilder
: ModelBuilder, mclassdef
: MClassDef, kwredef
: nullable Token, need_redef
: Bool, mprop
: MProperty): Bool
376 if mclassdef
.mprop2npropdef
.has_key
(mprop
) then
377 modelbuilder
.error
(self, "Error: A property {mprop} is already defined in class {mclassdef.mclass} at line {mclassdef.mprop2npropdef[mprop].location.line_start}.")
380 if mprop
isa MMethod and mprop
.is_toplevel
!= (parent
isa ATopClassdef) then
381 if mprop
.is_toplevel
then
382 modelbuilder
.error
(self, "Error: {mprop} is a top level method.")
384 modelbuilder
.error
(self, "Error: {mprop} is not a top level method.")
389 if kwredef
== null then
391 modelbuilder
.error
(self, "Redef error: {mclassdef.mclass}::{mprop.name} is an inherited property. To redefine it, add the redef keyword.")
395 if not need_redef
then
396 modelbuilder
.error
(self, "Error: No property {mclassdef.mclass}::{mprop.name} is inherited. Remove the redef keyword to define a new property.")
405 redef class ASignature
406 # Is the model builder has correctly visited the signature
407 var is_visited
= false
408 # Names of parameters from the AST
409 # REQUIRE: is_visited
410 var param_names
= new Array[String]
411 # Types of parameters from the AST
412 # REQUIRE: is_visited
413 var param_types
= new Array[MType]
414 # Rank of the vararg (of -1 if none)
415 # REQUIRE: is_visited
416 var vararg_rank
: Int = -1
418 var ret_type
: nullable MType = null
420 # Visit and fill information about a signature
421 private fun visit_signature
(modelbuilder
: ModelBuilder, mclassdef
: MClassDef): Bool
423 var mmodule
= mclassdef
.mmodule
424 var param_names
= self.param_names
425 var param_types
= self.param_types
426 for np
in self.n_params
do
427 param_names
.add
(np
.n_id
.text
)
428 var ntype
= np
.n_type
429 if ntype
!= null then
430 var mtype
= modelbuilder
.resolve_mtype
(mmodule
, mclassdef
, ntype
)
431 if mtype
== null then return false # Skip error
432 for i
in [0..param_names
.length-param_types
.length
[ do
433 param_types
.add
(mtype
)
435 if np
.n_dotdotdot
!= null then
436 if self.vararg_rank
!= -1 then
437 modelbuilder
.error
(np
, "Error: {param_names[self.vararg_rank]} is already a vararg")
440 self.vararg_rank
= param_names
.length
- 1
445 var ntype
= self.n_type
446 if ntype
!= null then
447 self.ret_type
= modelbuilder
.resolve_mtype
(mmodule
, mclassdef
, ntype
)
448 if self.ret_type
== null then return false # Skip errir
451 self.is_visited
= true
455 # Build a visited signature
456 fun build_signature
(modelbuilder
: ModelBuilder): nullable MSignature
458 if param_names
.length
!= param_types
.length
then
459 # Some parameters are typed, other parameters are not typed.
460 modelbuilder
.error
(self.n_params
[param_types
.length
], "Error: Untyped parameter `{param_names[param_types.length]}'.")
464 var mparameters
= new Array[MParameter]
465 for i
in [0..param_names
.length
[ do
466 var mparameter
= new MParameter(param_names
[i
], param_types
[i
], i
== vararg_rank
)
467 self.n_params
[i
].mparameter
= mparameter
468 mparameters
.add
(mparameter
)
471 var msignature
= new MSignature(mparameters
, ret_type
)
477 # The associated mparameter if any
478 var mparameter
: nullable MParameter = null
481 redef class AMethPropdef
482 redef type MPROPDEF: MMethodDef
485 # Can self be used as a root init?
486 private fun look_like_a_root_init
(modelbuilder
: ModelBuilder): Bool
488 # Need the `init` keyword
489 if n_kwinit
== null then return false
490 # Need to by anonymous
491 if self.n_methid
!= null then return false
493 if self.n_signature
.n_params
.length
> 0 then return false
494 # Cannot be private or something
495 if not self.n_visibility
isa APublicVisibility then return false
496 # No annotation on itself
497 if get_single_annotation
("old_style_init", modelbuilder
) != null then return false
499 var amod
= self.parent
.parent
.as(AModule)
500 var amoddecl
= amod
.n_moduledecl
501 if amoddecl
!= null then
502 var old
= amoddecl
.get_single_annotation
("old_style_init", modelbuilder
)
503 if old
!= null then return false
509 redef fun build_property
(modelbuilder
, mclassdef
)
511 var n_kwinit
= n_kwinit
512 var n_kwnew
= n_kwnew
513 var is_init
= n_kwinit
!= null or n_kwnew
!= null
515 var amethodid
= self.n_methid
517 if amethodid
== null then
521 else if n_kwinit
!= null then
524 else if n_kwnew
!= null then
530 else if amethodid
isa AIdMethid then
531 name
= amethodid
.n_id
.text
532 name_node
= amethodid
534 # operator, bracket or assign
535 name
= amethodid
.collect_text
536 name_node
= amethodid
538 if name
== "-" and self.n_signature
.n_params
.length
== 0 then
543 var mprop
: nullable MMethod = null
544 if not is_init
or n_kwredef
!= null then mprop
= modelbuilder
.try_get_mproperty_by_name
(name_node
, mclassdef
, name
).as(nullable MMethod)
545 if mprop
== null and look_like_a_root_init
(modelbuilder
) then
546 mprop
= modelbuilder
.the_root_init_mmethod
548 if nb
isa ABlockExpr and nb
.n_expr
.is_empty
and n_doc
== null then
549 modelbuilder
.advice
(self, "useless-init", "Warning: useless empty init in {mclassdef}")
552 if mprop
== null then
553 var mvisibility
= new_property_visibility
(modelbuilder
, mclassdef
, self.n_visibility
)
554 mprop
= new MMethod(mclassdef
, name
, mvisibility
)
555 if look_like_a_root_init
(modelbuilder
) and modelbuilder
.the_root_init_mmethod
== null then
556 modelbuilder
.the_root_init_mmethod
= mprop
557 mprop
.is_root_init
= true
559 mprop
.is_init
= is_init
560 mprop
.is_new
= n_kwnew
!= null
561 if parent
isa ATopClassdef then mprop
.is_toplevel
= true
562 if not self.check_redef_keyword
(modelbuilder
, mclassdef
, n_kwredef
, false, mprop
) then return
564 if not mprop
.is_root_init
and not self.check_redef_keyword
(modelbuilder
, mclassdef
, n_kwredef
, not self isa AMainMethPropdef, mprop
) then return
565 check_redef_property_visibility
(modelbuilder
, self.n_visibility
, mprop
)
567 mclassdef
.mprop2npropdef
[mprop
] = self
569 var mpropdef
= new MMethodDef(mclassdef
, mprop
, self.location
)
571 set_doc
(mpropdef
, modelbuilder
)
573 self.mpropdef
= mpropdef
574 modelbuilder
.mpropdef2npropdef
[mpropdef
] = self
575 if mpropdef
.is_intro
then
576 modelbuilder
.toolcontext
.info
("{mpropdef} introduces new method {mprop.full_name}", 3)
578 modelbuilder
.toolcontext
.info
("{mpropdef} redefines method {mprop.full_name}", 3)
582 redef fun build_signature
(modelbuilder
)
584 var mpropdef
= self.mpropdef
585 if mpropdef
== null then return # Error thus skiped
586 var mclassdef
= mpropdef
.mclassdef
587 var mmodule
= mclassdef
.mmodule
588 var nsig
= self.n_signature
590 # Retrieve info from the signature AST
591 var param_names
= new Array[String] # Names of parameters from the AST
592 var param_types
= new Array[MType] # Types of parameters from the AST
594 var ret_type
: nullable MType = null # Return type from the AST
596 if not nsig
.visit_signature
(modelbuilder
, mclassdef
) then return
597 param_names
= nsig
.param_names
598 param_types
= nsig
.param_types
599 vararg_rank
= nsig
.vararg_rank
600 ret_type
= nsig
.ret_type
603 # Look for some signature to inherit
604 # FIXME: do not inherit from the intro, but from the most specific
605 var msignature
: nullable MSignature = null
606 if not mpropdef
.is_intro
then
607 msignature
= mpropdef
.mproperty
.intro
.msignature
608 if msignature
== null then return # Skip error
610 # Check inherited signature arity
611 if param_names
.length
!= msignature
.arity
then
613 if nsig
!= null then node
= nsig
else node
= self
614 modelbuilder
.error
(node
, "Redef error: {mpropdef} redefines {mpropdef.mproperty.intro} with {param_names.length} parameter(s), {msignature.arity} expected. Signature is {mpropdef}{msignature}")
617 else if mpropdef
.mproperty
.is_init
then
618 # FIXME UGLY: inherit signature from a super-constructor
619 for msupertype
in mclassdef
.supertypes
do
620 msupertype
= msupertype
.anchor_to
(mmodule
, mclassdef
.bound_mtype
)
621 var candidate
= modelbuilder
.try_get_mproperty_by_name2
(self, mmodule
, msupertype
, mpropdef
.mproperty
.name
)
622 if candidate
!= null then
623 if msignature
== null then
624 msignature
= candidate
.intro
.as(MMethodDef).msignature
631 # Inherit the signature
632 if msignature
!= null and param_names
.length
!= param_types
.length
and param_names
.length
== msignature
.arity
and param_types
.length
== 0 then
633 # Parameters are untyped, thus inherit them
634 param_types
= new Array[MType]
635 for mparameter
in msignature
.mparameters
do
636 param_types
.add
(mparameter
.mtype
)
638 vararg_rank
= msignature
.vararg_rank
640 if msignature
!= null and ret_type
== null then
641 ret_type
= msignature
.return_mtype
644 if param_names
.length
!= param_types
.length
then
645 # Some parameters are typed, other parameters are not typed.
646 modelbuilder
.error
(nsig
.n_params
[param_types
.length
], "Error: Untyped parameter `{param_names[param_types.length]}'.")
650 var mparameters
= new Array[MParameter]
651 for i
in [0..param_names
.length
[ do
652 var mparameter
= new MParameter(param_names
[i
], param_types
[i
], i
== vararg_rank
)
653 if nsig
!= null then nsig
.n_params
[i
].mparameter
= mparameter
654 mparameters
.add
(mparameter
)
657 msignature
= new MSignature(mparameters
, ret_type
)
658 mpropdef
.msignature
= msignature
659 mpropdef
.is_abstract
= self.get_single_annotation
("abstract", modelbuilder
) != null
660 mpropdef
.is_intern
= self.get_single_annotation
("intern", modelbuilder
) != null
661 mpropdef
.is_extern
= self.n_extern_code_block
!= null or self.get_single_annotation
("extern", modelbuilder
) != null
664 redef fun check_signature
(modelbuilder
)
666 var mpropdef
= self.mpropdef
667 if mpropdef
== null then return # Error thus skiped
668 var mclassdef
= mpropdef
.mclassdef
669 var mmodule
= mclassdef
.mmodule
670 var nsig
= self.n_signature
671 var mysignature
= self.mpropdef
.msignature
672 if mysignature
== null then return # Error thus skiped
674 # Lookup for signature in the precursor
675 # FIXME all precursors should be considered
676 if not mpropdef
.is_intro
then
677 var msignature
= mpropdef
.mproperty
.intro
.msignature
678 if msignature
== null then return
680 var precursor_ret_type
= msignature
.return_mtype
681 var ret_type
= mysignature
.return_mtype
682 if ret_type
!= null and precursor_ret_type
== null then
683 modelbuilder
.error
(nsig
.n_type
.as(not null), "Redef Error: {mpropdef.mproperty} is a procedure, not a function.")
687 if mysignature
.arity
> 0 then
688 # Check parameters types
689 for i
in [0..mysignature
.arity
[ do
690 var myt
= mysignature
.mparameters
[i
].mtype
691 var prt
= msignature
.mparameters
[i
].mtype
692 if not myt
.is_subtype
(mmodule
, mclassdef
.bound_mtype
, prt
) or
693 not prt
.is_subtype
(mmodule
, mclassdef
.bound_mtype
, myt
) then
694 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}.")
698 if precursor_ret_type
!= null then
699 if ret_type
== null then
700 # Inherit the return type
701 ret_type
= precursor_ret_type
702 else if not ret_type
.is_subtype
(mmodule
, mclassdef
.bound_mtype
, precursor_ret_type
) then
703 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}.")
708 if mysignature
.arity
> 0 then
709 # Check parameters visibility
710 for i
in [0..mysignature
.arity
[ do
711 var nt
= nsig
.n_params
[i
].n_type
712 if nt
!= null then modelbuilder
.check_visibility
(nt
, nt
.mtype
.as(not null), mpropdef
)
715 if nt
!= null then modelbuilder
.check_visibility
(nt
, nt
.mtype
.as(not null), mpropdef
)
720 redef class AAttrPropdef
721 redef type MPROPDEF: MAttributeDef
723 # Is the node tagged `noinit`?
726 # Is the node taggeg lazy?
729 # The guard associated to a lasy attribute.
730 # Because some engines does not have a working `isset`,
731 # this additionnal attribute is used to guard the lazy initialization.
732 # TODO: to remove once isset is correctly implemented
733 var mlazypropdef
: nullable MAttributeDef
735 # The associated getter (read accessor) if any
736 var mreadpropdef
: nullable MMethodDef is writable
737 # The associated setter (write accessor) if any
738 var mwritepropdef
: nullable MMethodDef is writable
740 redef fun build_property
(modelbuilder
, mclassdef
)
742 var mclass
= mclassdef
.mclass
745 name
= self.n_id2
.text
747 if mclass
.kind
== interface_kind
or mclassdef
.mclass
.kind
== enum_kind
then
748 modelbuilder
.error
(self, "Error: Attempt to define attribute {name} in the interface {mclass}.")
749 else if mclass
.kind
== enum_kind
then
750 modelbuilder
.error
(self, "Error: Attempt to define attribute {name} in the enum class {mclass}.")
751 else if mclass
.kind
== extern_kind
then
752 modelbuilder
.error
(self, "Error: Attempt to define attribute {name} in the extern class {mclass}.")
755 # New attribute style
756 var nid2
= self.n_id2
757 var mprop
= new MAttribute(mclassdef
, "_" + name
, private_visibility
)
758 var mpropdef
= new MAttributeDef(mclassdef
, mprop
, self.location
)
759 self.mpropdef
= mpropdef
760 modelbuilder
.mpropdef2npropdef
[mpropdef
] = self
761 set_doc
(mpropdef
, modelbuilder
)
764 var mreadprop
= modelbuilder
.try_get_mproperty_by_name
(nid2
, mclassdef
, readname
).as(nullable MMethod)
765 if mreadprop
== null then
766 var mvisibility
= new_property_visibility
(modelbuilder
, mclassdef
, self.n_visibility
)
767 mreadprop
= new MMethod(mclassdef
, readname
, mvisibility
)
768 if not self.check_redef_keyword
(modelbuilder
, mclassdef
, n_kwredef
, false, mreadprop
) then return
769 mreadprop
.deprecation
= mprop
.deprecation
771 if not self.check_redef_keyword
(modelbuilder
, mclassdef
, n_kwredef
, true, mreadprop
) then return
772 check_redef_property_visibility
(modelbuilder
, self.n_visibility
, mreadprop
)
774 mclassdef
.mprop2npropdef
[mreadprop
] = self
776 var mreadpropdef
= new MMethodDef(mclassdef
, mreadprop
, self.location
)
777 self.mreadpropdef
= mreadpropdef
778 modelbuilder
.mpropdef2npropdef
[mreadpropdef
] = self
779 mreadpropdef
.mdoc
= mpropdef
.mdoc
781 var atlazy
= self.get_single_annotation
("lazy", modelbuilder
)
782 if atlazy
!= null then
783 if n_expr
== null then
784 modelbuilder
.error
(atlazy
, "Error: a lazy attribute needs a value")
787 var mlazyprop
= new MAttribute(mclassdef
, "lazy _" + name
, none_visibility
)
788 var mlazypropdef
= new MAttributeDef(mclassdef
, mlazyprop
, self.location
)
789 self.mlazypropdef
= mlazypropdef
792 var atreadonly
= self.get_single_annotation
("readonly", modelbuilder
)
793 if atreadonly
!= null then
794 if n_expr
== null then
795 modelbuilder
.error
(atreadonly
, "Error: a readonly attribute needs a value")
797 # No setter, so just leave
801 var writename
= name
+ "="
802 var atwritable
= self.get_single_annotation
("writable", modelbuilder
)
803 if atwritable
!= null then
804 if not atwritable
.n_args
.is_empty
then
805 writename
= atwritable
.arg_as_id
(modelbuilder
) or else writename
808 var mwriteprop
= modelbuilder
.try_get_mproperty_by_name
(nid2
, mclassdef
, writename
).as(nullable MMethod)
809 var nwkwredef
: nullable Token = null
810 if atwritable
!= null then nwkwredef
= atwritable
.n_kwredef
811 if mwriteprop
== null then
813 if atwritable
!= null then
814 mvisibility
= new_property_visibility
(modelbuilder
, mclassdef
, atwritable
.n_visibility
)
816 mvisibility
= private_visibility
818 mwriteprop
= new MMethod(mclassdef
, writename
, mvisibility
)
819 if not self.check_redef_keyword
(modelbuilder
, mclassdef
, nwkwredef
, false, mwriteprop
) then return
820 mwriteprop
.deprecation
= mprop
.deprecation
822 if not self.check_redef_keyword
(modelbuilder
, mclassdef
, nwkwredef
or else n_kwredef
, true, mwriteprop
) then return
823 if atwritable
!= null then
824 check_redef_property_visibility
(modelbuilder
, atwritable
.n_visibility
, mwriteprop
)
827 mclassdef
.mprop2npropdef
[mwriteprop
] = self
829 var mwritepropdef
= new MMethodDef(mclassdef
, mwriteprop
, self.location
)
830 self.mwritepropdef
= mwritepropdef
831 modelbuilder
.mpropdef2npropdef
[mwritepropdef
] = self
832 mwritepropdef
.mdoc
= mpropdef
.mdoc
835 redef fun build_signature
(modelbuilder
)
837 var mpropdef
= self.mpropdef
838 if mpropdef
== null then return # Error thus skiped
839 var mclassdef
= mpropdef
.mclassdef
840 var mmodule
= mclassdef
.mmodule
841 var mtype
: nullable MType = null
843 var mreadpropdef
= self.mreadpropdef
845 var ntype
= self.n_type
846 if ntype
!= null then
847 mtype
= modelbuilder
.resolve_mtype
(mmodule
, mclassdef
, ntype
)
848 if mtype
== null then return
851 # Inherit the type from the getter (usually an abstact getter)
852 if mtype
== null and mreadpropdef
!= null and not mreadpropdef
.is_intro
then
853 var msignature
= mreadpropdef
.mproperty
.intro
.msignature
854 if msignature
== null then return # Error, thus skiped
855 mtype
= msignature
.return_mtype
858 var nexpr
= self.n_expr
859 if mtype
== null then
860 if nexpr
!= null then
861 if nexpr
isa ANewExpr then
862 mtype
= modelbuilder
.resolve_mtype
(mmodule
, mclassdef
, nexpr
.n_type
)
863 else if nexpr
isa AIntExpr then
864 var cla
= modelbuilder
.try_get_mclass_by_name
(nexpr
, mmodule
, "Int")
865 if cla
!= null then mtype
= cla
.mclass_type
866 else if nexpr
isa AFloatExpr then
867 var cla
= modelbuilder
.try_get_mclass_by_name
(nexpr
, mmodule
, "Float")
868 if cla
!= null then mtype
= cla
.mclass_type
869 else if nexpr
isa ACharExpr then
870 var cla
= modelbuilder
.try_get_mclass_by_name
(nexpr
, mmodule
, "Char")
871 if cla
!= null then mtype
= cla
.mclass_type
872 else if nexpr
isa ABoolExpr then
873 var cla
= modelbuilder
.try_get_mclass_by_name
(nexpr
, mmodule
, "Bool")
874 if cla
!= null then mtype
= cla
.mclass_type
875 else if nexpr
isa ASuperstringExpr then
876 var cla
= modelbuilder
.try_get_mclass_by_name
(nexpr
, mmodule
, "String")
877 if cla
!= null then mtype
= cla
.mclass_type
878 else if nexpr
isa AStringFormExpr then
879 var cla
= modelbuilder
.try_get_mclass_by_name
(nexpr
, mmodule
, "String")
880 if cla
!= null then mtype
= cla
.mclass_type
882 modelbuilder
.error
(self, "Error: Untyped attribute {mpropdef}. Implicit typing allowed only for literals and new.")
885 if mtype
== null then return
887 else if ntype
!= null then
888 if nexpr
isa ANewExpr then
889 var xmtype
= modelbuilder
.resolve_mtype
(mmodule
, mclassdef
, nexpr
.n_type
)
890 if xmtype
== mtype
then
891 modelbuilder
.advice
(ntype
, "useless-type", "Warning: useless type definition")
896 if mtype
== null then
897 modelbuilder
.error
(self, "Error: Untyped attribute {mpropdef}")
901 mpropdef
.static_mtype
= mtype
903 if mreadpropdef
!= null then
904 var msignature
= new MSignature(new Array[MParameter], mtype
)
905 mreadpropdef
.msignature
= msignature
908 var mwritepropdef
= self.mwritepropdef
909 if mwritepropdef
!= null then
912 var mparameter
= new MParameter(name
, mtype
, false)
913 var msignature
= new MSignature([mparameter
], null)
914 mwritepropdef
.msignature
= msignature
917 var mlazypropdef
= self.mlazypropdef
918 if mlazypropdef
!= null then
919 mlazypropdef
.static_mtype
= modelbuilder
.model
.get_mclasses_by_name
("Bool").first
.mclass_type
923 redef fun check_signature
(modelbuilder
)
925 var mpropdef
= self.mpropdef
926 if mpropdef
== null then return # Error thus skiped
927 var mclassdef
= mpropdef
.mclassdef
928 var mmodule
= mclassdef
.mmodule
929 var ntype
= self.n_type
930 var mtype
= self.mpropdef
.static_mtype
931 if mtype
== null then return # Error thus skiped
933 # Lookup for signature in the precursor
934 # FIXME all precursors should be considered
935 if not mpropdef
.is_intro
then
936 var precursor_type
= mpropdef
.mproperty
.intro
.static_mtype
937 if precursor_type
== null then return
939 if mtype
!= precursor_type
then
940 modelbuilder
.error
(ntype
.as(not null), "Redef Error: Wrong static type. found {mtype}, expected {precursor_type}.")
945 # Check getter and setter
946 var meth
= self.mreadpropdef
948 self.check_method_signature
(modelbuilder
, meth
)
949 var node
: nullable ANode = ntype
950 if node
== null then node
= self
951 modelbuilder
.check_visibility
(node
, mtype
, meth
)
953 meth
= self.mwritepropdef
955 self.check_method_signature
(modelbuilder
, meth
)
956 var node
: nullable ANode = ntype
957 if node
== null then node
= self
958 modelbuilder
.check_visibility
(node
, mtype
, meth
)
962 private fun check_method_signature
(modelbuilder
: ModelBuilder, mpropdef
: MMethodDef)
964 var mclassdef
= mpropdef
.mclassdef
965 var mmodule
= mclassdef
.mmodule
966 var nsig
= self.n_type
967 var mysignature
= mpropdef
.msignature
968 if mysignature
== null then return # Error thus skiped
970 # Lookup for signature in the precursor
971 # FIXME all precursors should be considered
972 if not mpropdef
.is_intro
then
973 var msignature
= mpropdef
.mproperty
.intro
.msignature
974 if msignature
== null then return
976 if mysignature
.arity
!= msignature
.arity
then
978 if nsig
!= null then node
= nsig
else node
= self
979 modelbuilder
.error
(node
, "Redef Error: {mysignature.arity} parameters found, {msignature.arity} expected. Signature is {mpropdef}{msignature}")
982 var precursor_ret_type
= msignature
.return_mtype
983 var ret_type
= mysignature
.return_mtype
984 if ret_type
!= null and precursor_ret_type
== null then
986 if nsig
!= null then node
= nsig
else node
= self
987 modelbuilder
.error
(node
, "Redef Error: {mpropdef.mproperty} is a procedure, not a function.")
991 if mysignature
.arity
> 0 then
992 # Check parameters types
993 for i
in [0..mysignature
.arity
[ do
994 var myt
= mysignature
.mparameters
[i
].mtype
995 var prt
= msignature
.mparameters
[i
].mtype
996 if not myt
.is_subtype
(mmodule
, mclassdef
.bound_mtype
, prt
) or
997 not prt
.is_subtype
(mmodule
, mclassdef
.bound_mtype
, myt
) then
999 if nsig
!= null then node
= nsig
else node
= self
1000 modelbuilder
.error
(node
, "Redef Error: Wrong type for parameter `{mysignature.mparameters[i].name}'. found {myt}, expected {prt}.")
1004 if precursor_ret_type
!= null then
1005 if ret_type
== null then
1006 # Inherit the return type
1007 ret_type
= precursor_ret_type
1008 else if not ret_type
.is_subtype
(mmodule
, mclassdef
.bound_mtype
, precursor_ret_type
) then
1010 if nsig
!= null then node
= nsig
else node
= self
1011 modelbuilder
.error
(node
, "Redef Error: Wrong return type. found {ret_type}, expected {precursor_ret_type}.")
1018 redef class ATypePropdef
1019 redef type MPROPDEF: MVirtualTypeDef
1021 redef fun build_property
(modelbuilder
, mclassdef
)
1023 var name
= self.n_id
.text
1024 var mprop
= modelbuilder
.try_get_mproperty_by_name
(self.n_id
, mclassdef
, name
)
1025 if mprop
== null then
1026 var mvisibility
= new_property_visibility
(modelbuilder
, mclassdef
, self.n_visibility
)
1027 mprop
= new MVirtualTypeProp(mclassdef
, name
, mvisibility
)
1028 for c
in name
.chars
do if c
>= 'a' and c
<= 'z' then
1029 modelbuilder
.warning
(n_id
, "bad-type-name", "Warning: lowercase in the virtual type {name}")
1032 if not self.check_redef_keyword
(modelbuilder
, mclassdef
, self.n_kwredef
, false, mprop
) then return
1034 if not self.check_redef_keyword
(modelbuilder
, mclassdef
, self.n_kwredef
, true, mprop
) then return
1035 assert mprop
isa MVirtualTypeProp
1036 check_redef_property_visibility
(modelbuilder
, self.n_visibility
, mprop
)
1038 mclassdef
.mprop2npropdef
[mprop
] = self
1040 var mpropdef
= new MVirtualTypeDef(mclassdef
, mprop
, self.location
)
1041 self.mpropdef
= mpropdef
1042 modelbuilder
.mpropdef2npropdef
[mpropdef
] = self
1043 set_doc
(mpropdef
, modelbuilder
)
1045 var atfixed
= get_single_annotation
("fixed", modelbuilder
)
1046 if atfixed
!= null then
1047 mpropdef
.is_fixed
= true
1051 redef fun build_signature
(modelbuilder
)
1053 var mpropdef
= self.mpropdef
1054 if mpropdef
== null then return # Error thus skiped
1055 var mclassdef
= mpropdef
.mclassdef
1056 var mmodule
= mclassdef
.mmodule
1057 var mtype
: nullable MType = null
1059 var ntype
= self.n_type
1060 mtype
= modelbuilder
.resolve_mtype
(mmodule
, mclassdef
, ntype
)
1061 if mtype
== null then return
1063 mpropdef
.bound
= mtype
1064 # print "{mpropdef}: {mtype}"
1067 redef fun check_signature
(modelbuilder
)
1069 var mpropdef
= self.mpropdef
1070 if mpropdef
== null then return # Error thus skiped
1072 var bound
= self.mpropdef
.bound
1073 if bound
== null then return # Error thus skiped
1075 modelbuilder
.check_visibility
(n_type
, bound
, mpropdef
)
1077 var mclassdef
= mpropdef
.mclassdef
1078 var mmodule
= mclassdef
.mmodule
1079 var anchor
= mclassdef
.bound_mtype
1082 if bound
isa MVirtualType then
1083 # Slow case: progress on each resolution until: (i) we loop, or (ii) we found a non formal type
1084 var seen
= [self.mpropdef
.mproperty
.mvirtualtype
]
1086 if seen
.has
(bound
) then
1088 modelbuilder
.error
(self, "Error: circularity of virtual type definition: {seen.join(" -> ")}")
1092 var next
= bound
.lookup_bound
(mmodule
, anchor
)
1093 if not next
isa MVirtualType then break
1098 # Check redefinitions
1099 bound
= mpropdef
.bound
.as(not null)
1100 for p
in mpropdef
.mproperty
.lookup_super_definitions
(mmodule
, anchor
) do
1101 var supbound
= p
.bound
.as(not null)
1103 modelbuilder
.error
(self, "Redef Error: Virtual type {mpropdef.mproperty} is fixed in super-class {p.mclassdef.mclass}")
1106 if p
.mclassdef
.mclass
== mclassdef
.mclass
then
1107 # Still a warning to pass existing bad code
1108 modelbuilder
.warning
(n_type
, "refine-type", "Redef Error: a virtual type cannot be refined.")
1111 if not bound
.is_subtype
(mmodule
, anchor
, supbound
) then
1112 modelbuilder
.error
(n_type
, "Redef Error: Wrong bound type. Found {bound}, expected a subtype of {supbound}, as in {p}.")