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
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 # Introduce or inherit default constructor
72 # This is the last part of `build_properties`.
73 private fun process_default_constructors
(nclassdef
: AClassdef)
75 var mclassdef
= nclassdef
.mclassdef
.as(not null)
78 if not mclassdef
.is_intro
then return
80 # Is the class forbid constructors?
81 if not mclassdef
.mclass
.kind
.need_init
then return
83 # Is there already a constructor defined?
84 for mpropdef
in mclassdef
.mpropdefs
do
85 if not mpropdef
isa MMethodDef then continue
86 if mpropdef
.mproperty
.is_init
then return
89 if not nclassdef
isa AStdClassdef then return
91 var mmodule
= mclassdef
.mmodule
92 # Do we inherit for a constructor?
93 var combine
= new Array[MMethod]
94 var inhc
: nullable MClass = null
95 for st
in mclassdef
.supertypes
do
97 if not c
.kind
.need_init
then continue
98 st
= st
.anchor_to
(mmodule
, mclassdef
.bound_mtype
)
99 var candidate
= self.try_get_mproperty_by_name2
(nclassdef
, mmodule
, st
, "init").as(nullable MMethod)
100 if candidate
!= null then
101 if candidate
.intro
.msignature
!= null then
102 if candidate
.intro
.msignature
.arity
== 0 then
103 combine
.add
(candidate
)
108 var inhc2
= c
.inherit_init_from
109 if inhc2
== null then inhc2
= c
110 if inhc2
== inhc
then continue
112 self.error
(nclassdef
, "Error: Cannot provide a defaut constructor: conflict for {inhc} and {c}")
118 # Collect undefined attributes
119 var mparameters
= new Array[MParameter]
120 var anode
: nullable ANode = null
121 for npropdef
in nclassdef
.n_propdefs
do
122 if npropdef
isa AAttrPropdef then
123 if npropdef
.mpropdef
== null then return # Skip broken attribute
124 var at
= npropdef
.get_single_annotation
("noinit", self)
126 npropdef
.noinit
= true
127 if npropdef
.n_expr
!= null then
128 self.error
(at
, "Error: `noinit` attributes cannot have an initial value")
130 continue # Skip noinit attributes
132 if npropdef
.n_expr
!= null then continue
133 var paramname
= npropdef
.mpropdef
.mproperty
.name
.substring_from
(1)
134 var ret_type
= npropdef
.mpropdef
.static_mtype
135 if ret_type
== null then return
136 var mparameter
= new MParameter(paramname
, ret_type
, false)
137 mparameters
.add
(mparameter
)
138 if anode
== null then anode
= npropdef
141 if anode
== null then anode
= nclassdef
143 if combine
.is_empty
and inhc
!= null then
144 if not mparameters
.is_empty
then
145 self.error
(anode
,"Error: {mclassdef} cannot inherit constructors from {inhc} because there is attributes without initial values: {mparameters.join(", ")}")
149 # TODO: actively inherit the consturctor
150 self.toolcontext
.info
("{mclassdef} inherits all constructors from {inhc}", 3)
151 mclassdef
.mclass
.inherit_init_from
= inhc
155 if not combine
.is_empty
and inhc
!= null then
156 self.error
(nclassdef
, "Error: Cannot provide a defaut constructor: conflict for {combine.join(", ")} and {inhc}")
160 if not combine
.is_empty
then
161 if mparameters
.is_empty
and combine
.length
== 1 then
162 # No need to create a local init, the inherited one is enough
163 inhc
= combine
.first
.intro_mclassdef
.mclass
164 mclassdef
.mclass
.inherit_init_from
= inhc
165 self.toolcontext
.info
("{mclassdef} inherits all constructors from {inhc}", 3)
168 nclassdef
.super_inits
= combine
171 var mprop
= new MMethod(mclassdef
, "init", mclassdef
.mclass
.visibility
)
172 var mpropdef
= new MMethodDef(mclassdef
, mprop
, nclassdef
.location
)
173 var msignature
= new MSignature(mparameters
, null)
174 mpropdef
.msignature
= msignature
176 nclassdef
.mfree_init
= mpropdef
177 self.toolcontext
.info
("{mclassdef} gets a free constructor for attributes {mpropdef}{msignature}", 3)
180 # Check the visibility of `mtype` as an element of the signature of `mpropdef`.
181 fun check_visibility
(node
: ANode, mtype
: MType, mpropdef
: MPropDef)
183 var mmodule
= mpropdef
.mclassdef
.mmodule
184 var mproperty
= mpropdef
.mproperty
186 # Extract visibility information of the main part of `mtype`
187 # It is a case-by case
188 var vis_type
: nullable MVisibility = null # The own visibility of the type
189 var mmodule_type
: nullable MModule = null # The origial module of the type
190 mtype
= mtype
.as_notnullable
191 if mtype
isa MClassType then
192 vis_type
= mtype
.mclass
.visibility
193 mmodule_type
= mtype
.mclass
.intro
.mmodule
194 else if mtype
isa MVirtualType then
195 vis_type
= mtype
.mproperty
.visibility
196 mmodule_type
= mtype
.mproperty
.intro_mclassdef
.mmodule
197 else if mtype
isa MParameterType then
198 # nothing, always visible
200 node
.debug
"Unexpected type {mtype}"
204 if vis_type
!= null then
205 assert mmodule_type
!= null
206 var vis_module_type
= mmodule
.visibility_for
(mmodule_type
) # the visibility of the original module
207 if mproperty
.visibility
> vis_type
then
208 error
(node
, "Error: The {mproperty.visibility} property `{mproperty}` cannot contain the {vis_type} type `{mtype}`")
210 else if mproperty
.visibility
> vis_module_type
then
211 error
(node
, "Error: The {mproperty.visibility} property `{mproperty}` cannot contain the type `{mtype}` from the {vis_module_type} module `{mmodule_type}`")
216 # No error, try to go deeper in generic types
217 if node
isa AType then
218 for a
in node
.n_types
do
220 if t
== null then continue # Error, thus skipped
221 check_visibility
(a
, t
, mpropdef
)
223 else if mtype
isa MGenericType then
224 for t
in mtype
.arguments
do check_visibility
(node
, t
, mpropdef
)
230 # The class whose self inherit all the constructors.
231 # 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
232 var inherit_init_from
: nullable MClass = null
236 # Does the MPropDef contains a call to super or a call of a super-constructor?
237 # Subsequent phases of the frontend (esp. typing) set it if required
238 var has_supercall
: Bool writable = false
241 redef class AClassdef
242 var build_properties_is_done
: Bool = false
243 # The list of super-constructor to call at the start of the free constructor
244 # 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
245 var super_inits
: nullable Collection[MMethod] = null
247 # The free init (implicitely constructed by the class if required)
248 var mfree_init
: nullable MMethodDef = null
251 redef class MClassDef
252 # What is the `APropdef` associated to a `MProperty`?
253 # Used to check multiple definition of a property.
254 var mprop2npropdef
: Map[MProperty, APropdef] = new HashMap[MProperty, APropdef]
258 # Join the text of all tokens
259 # Used to get the 'real name' of method definitions.
260 fun collect_text
: String
262 var v
= new TextCollectorVisitor
269 private class TextCollectorVisitor
271 var text
: String = ""
274 if n
isa Token then text
+= n
.text
280 # The associated main model entity
281 type MPROPDEF: MPropDef
283 # The associated propdef once build by a `ModelBuilder`
284 var mpropdef
: nullable MPROPDEF writable
286 private fun build_property
(modelbuilder
: ModelBuilder, mclassdef
: MClassDef) is abstract
287 private fun build_signature
(modelbuilder
: ModelBuilder) is abstract
288 private fun check_signature
(modelbuilder
: ModelBuilder) is abstract
289 private fun new_property_visibility
(modelbuilder
: ModelBuilder, mclassdef
: MClassDef, nvisibility
: nullable AVisibility): MVisibility
291 var mvisibility
= public_visibility
292 if nvisibility
!= null then
293 mvisibility
= nvisibility
.mvisibility
294 if mvisibility
== intrude_visibility
then
295 modelbuilder
.error
(nvisibility
, "Error: intrude is not a legal visibility for properties.")
296 mvisibility
= public_visibility
299 if mclassdef
.mclass
.visibility
== private_visibility
then
300 if mvisibility
== protected_visibility
then
301 assert nvisibility
!= null
302 modelbuilder
.error
(nvisibility
, "Error: The only legal visibility for properties in a private class is private.")
303 else if mvisibility
== private_visibility
then
304 assert nvisibility
!= null
306 # modelbuilder.warning(nvisibility, "Warning: private is unrequired since the only legal visibility for properties in a private class is private.")
308 mvisibility
= private_visibility
313 private fun set_doc
(mpropdef
: MPropDef)
315 var ndoc
= self.n_doc
317 var mdoc
= ndoc
.to_mdoc
319 mdoc
.original_mentity
= mpropdef
323 private fun check_redef_property_visibility
(modelbuilder
: ModelBuilder, nvisibility
: nullable AVisibility, mprop
: MProperty)
325 if nvisibility
== null then return
326 var mvisibility
= nvisibility
.mvisibility
327 if mvisibility
!= mprop
.visibility
and mvisibility
!= public_visibility
then
328 modelbuilder
.error
(nvisibility
, "Error: redefinition changed the visibility from a {mprop.visibility} to a {mvisibility}")
332 private fun check_redef_keyword
(modelbuilder
: ModelBuilder, mclassdef
: MClassDef, kwredef
: nullable Token, need_redef
: Bool, mprop
: MProperty): Bool
334 if mclassdef
.mprop2npropdef
.has_key
(mprop
) then
335 modelbuilder
.error
(self, "Error: A property {mprop} is already defined in class {mclassdef.mclass} at line {mclassdef.mprop2npropdef[mprop].location.line_start}.")
338 if mprop
isa MMethod and mprop
.is_toplevel
!= (parent
isa ATopClassdef) then
339 if mprop
.is_toplevel
then
340 modelbuilder
.error
(self, "Error: {mprop} is a top level method.")
342 modelbuilder
.error
(self, "Error: {mprop} is not a top level method.")
347 if kwredef
== null then
349 modelbuilder
.error
(self, "Redef error: {mclassdef.mclass}::{mprop.name} is an inherited property. To redefine it, add the redef keyword.")
353 if not need_redef
then
354 modelbuilder
.error
(self, "Error: No property {mclassdef.mclass}::{mprop.name} is inherited. Remove the redef keyword to define a new property.")
363 redef class ASignature
364 # Is the model builder has correctly visited the signature
365 var is_visited
= false
366 # Names of parameters from the AST
367 # REQUIRE: is_visited
368 var param_names
= new Array[String]
369 # Types of parameters from the AST
370 # REQUIRE: is_visited
371 var param_types
= new Array[MType]
372 # Rank of the vararg (of -1 if none)
373 # REQUIRE: is_visited
374 var vararg_rank
: Int = -1
376 var ret_type
: nullable MType = null
378 # Visit and fill information about a signature
379 private fun visit_signature
(modelbuilder
: ModelBuilder, mclassdef
: MClassDef): Bool
381 var mmodule
= mclassdef
.mmodule
382 var param_names
= self.param_names
383 var param_types
= self.param_types
384 for np
in self.n_params
do
385 param_names
.add
(np
.n_id
.text
)
386 var ntype
= np
.n_type
387 if ntype
!= null then
388 var mtype
= modelbuilder
.resolve_mtype
(mmodule
, mclassdef
, ntype
)
389 if mtype
== null then return false # Skip error
390 for i
in [0..param_names
.length-param_types
.length
[ do
391 param_types
.add
(mtype
)
393 if np
.n_dotdotdot
!= null then
394 if self.vararg_rank
!= -1 then
395 modelbuilder
.error
(np
, "Error: {param_names[self.vararg_rank]} is already a vararg")
398 self.vararg_rank
= param_names
.length
- 1
403 var ntype
= self.n_type
404 if ntype
!= null then
405 self.ret_type
= modelbuilder
.resolve_mtype
(mmodule
, mclassdef
, ntype
)
406 if self.ret_type
== null then return false # Skip errir
409 self.is_visited
= true
413 # Build a visited signature
414 fun build_signature
(modelbuilder
: ModelBuilder): nullable MSignature
416 if param_names
.length
!= param_types
.length
then
417 # Some parameters are typed, other parameters are not typed.
418 modelbuilder
.error
(self.n_params
[param_types
.length
], "Error: Untyped parameter `{param_names[param_types.length]}'.")
422 var mparameters
= new Array[MParameter]
423 for i
in [0..param_names
.length
[ do
424 var mparameter
= new MParameter(param_names
[i
], param_types
[i
], i
== vararg_rank
)
425 self.n_params
[i
].mparameter
= mparameter
426 mparameters
.add
(mparameter
)
429 var msignature
= new MSignature(mparameters
, ret_type
)
435 # The associated mparameter if any
436 var mparameter
: nullable MParameter = null
439 redef class AMethPropdef
440 redef type MPROPDEF: MMethodDef
442 redef fun build_property
(modelbuilder
, mclassdef
)
444 var n_kwinit
= n_kwinit
445 var n_kwnew
= n_kwnew
446 var is_init
= n_kwinit
!= null or n_kwnew
!= null
448 var amethodid
= self.n_methid
450 if amethodid
== null then
454 else if n_kwinit
!= null then
457 else if n_kwnew
!= null then
463 else if amethodid
isa AIdMethid then
464 name
= amethodid
.n_id
.text
465 name_node
= amethodid
467 # operator, bracket or assign
468 name
= amethodid
.collect_text
469 name_node
= amethodid
471 if name
== "-" and self.n_signature
.n_params
.length
== 0 then
476 var mprop
: nullable MMethod = null
477 if not is_init
or n_kwredef
!= null then mprop
= modelbuilder
.try_get_mproperty_by_name
(name_node
, mclassdef
, name
).as(nullable MMethod)
478 if mprop
== null then
479 var mvisibility
= new_property_visibility
(modelbuilder
, mclassdef
, self.n_visibility
)
480 mprop
= new MMethod(mclassdef
, name
, mvisibility
)
481 mprop
.is_init
= is_init
482 mprop
.is_new
= n_kwnew
!= null
483 if parent
isa ATopClassdef then mprop
.is_toplevel
= true
484 if not self.check_redef_keyword
(modelbuilder
, mclassdef
, n_kwredef
, false, mprop
) then return
486 if not self.check_redef_keyword
(modelbuilder
, mclassdef
, n_kwredef
, not self isa AMainMethPropdef, mprop
) then return
487 check_redef_property_visibility
(modelbuilder
, self.n_visibility
, mprop
)
489 mclassdef
.mprop2npropdef
[mprop
] = self
491 var mpropdef
= new MMethodDef(mclassdef
, mprop
, self.location
)
495 self.mpropdef
= mpropdef
496 modelbuilder
.mpropdef2npropdef
[mpropdef
] = self
497 if mpropdef
.is_intro
then
498 modelbuilder
.toolcontext
.info
("{mpropdef} introduces new method {mprop.full_name}", 3)
500 modelbuilder
.toolcontext
.info
("{mpropdef} redefines method {mprop.full_name}", 3)
504 redef fun build_signature
(modelbuilder
)
506 var mpropdef
= self.mpropdef
507 if mpropdef
== null then return # Error thus skiped
508 var mclassdef
= mpropdef
.mclassdef
509 var mmodule
= mclassdef
.mmodule
510 var nsig
= self.n_signature
512 # Retrieve info from the signature AST
513 var param_names
= new Array[String] # Names of parameters from the AST
514 var param_types
= new Array[MType] # Types of parameters from the AST
516 var ret_type
: nullable MType = null # Return type from the AST
518 if not nsig
.visit_signature
(modelbuilder
, mclassdef
) then return
519 param_names
= nsig
.param_names
520 param_types
= nsig
.param_types
521 vararg_rank
= nsig
.vararg_rank
522 ret_type
= nsig
.ret_type
525 # Look for some signature to inherit
526 # FIXME: do not inherit from the intro, but from the most specific
527 var msignature
: nullable MSignature = null
528 if not mpropdef
.is_intro
then
529 msignature
= mpropdef
.mproperty
.intro
.msignature
530 if msignature
== null then return # Skip error
532 # Check inherited signature arity
533 if param_names
.length
!= msignature
.arity
then
535 if nsig
!= null then node
= nsig
else node
= self
536 modelbuilder
.error
(node
, "Redef error: {mpropdef} redefines {mpropdef.mproperty.intro} with {param_names.length} parameter(s), {msignature.arity} expected. Signature is {mpropdef}{msignature}")
539 else if mpropdef
.mproperty
.is_init
then
540 # FIXME UGLY: inherit signature from a super-constructor
541 for msupertype
in mclassdef
.supertypes
do
542 msupertype
= msupertype
.anchor_to
(mmodule
, mclassdef
.bound_mtype
)
543 var candidate
= modelbuilder
.try_get_mproperty_by_name2
(self, mmodule
, msupertype
, mpropdef
.mproperty
.name
)
544 if candidate
!= null then
545 if msignature
== null then
546 msignature
= candidate
.intro
.as(MMethodDef).msignature
553 # Inherit the signature
554 if msignature
!= null and param_names
.length
!= param_types
.length
and param_names
.length
== msignature
.arity
and param_types
.length
== 0 then
555 # Parameters are untyped, thus inherit them
556 param_types
= new Array[MType]
557 for mparameter
in msignature
.mparameters
do
558 param_types
.add
(mparameter
.mtype
)
560 vararg_rank
= msignature
.vararg_rank
562 if msignature
!= null and ret_type
== null then
563 ret_type
= msignature
.return_mtype
566 if param_names
.length
!= param_types
.length
then
567 # Some parameters are typed, other parameters are not typed.
568 modelbuilder
.error
(nsig
.n_params
[param_types
.length
], "Error: Untyped parameter `{param_names[param_types.length]}'.")
572 var mparameters
= new Array[MParameter]
573 for i
in [0..param_names
.length
[ do
574 var mparameter
= new MParameter(param_names
[i
], param_types
[i
], i
== vararg_rank
)
575 if nsig
!= null then nsig
.n_params
[i
].mparameter
= mparameter
576 mparameters
.add
(mparameter
)
579 msignature
= new MSignature(mparameters
, ret_type
)
580 mpropdef
.msignature
= msignature
581 mpropdef
.is_abstract
= self isa ADeferredMethPropdef
582 mpropdef
.is_intern
= self isa AInternMethPropdef
583 mpropdef
.is_extern
= self isa AExternPropdef
586 redef fun check_signature
(modelbuilder
)
588 var mpropdef
= self.mpropdef
589 if mpropdef
== null then return # Error thus skiped
590 var mclassdef
= mpropdef
.mclassdef
591 var mmodule
= mclassdef
.mmodule
592 var nsig
= self.n_signature
593 var mysignature
= self.mpropdef
.msignature
594 if mysignature
== null then return # Error thus skiped
596 # Lookup for signature in the precursor
597 # FIXME all precursors should be considered
598 if not mpropdef
.is_intro
then
599 var msignature
= mpropdef
.mproperty
.intro
.msignature
600 if msignature
== null then return
602 var precursor_ret_type
= msignature
.return_mtype
603 var ret_type
= mysignature
.return_mtype
604 if ret_type
!= null and precursor_ret_type
== null then
605 modelbuilder
.error
(nsig
.n_type
.as(not null), "Redef Error: {mpropdef.mproperty} is a procedure, not a function.")
609 if mysignature
.arity
> 0 then
610 # Check parameters types
611 for i
in [0..mysignature
.arity
[ do
612 var myt
= mysignature
.mparameters
[i
].mtype
613 var prt
= msignature
.mparameters
[i
].mtype
614 if not myt
.is_subtype
(mmodule
, mclassdef
.bound_mtype
, prt
) or
615 not prt
.is_subtype
(mmodule
, mclassdef
.bound_mtype
, myt
) then
616 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}.")
620 if precursor_ret_type
!= null then
621 if ret_type
== null then
622 # Inherit the return type
623 ret_type
= precursor_ret_type
624 else if not ret_type
.is_subtype
(mmodule
, mclassdef
.bound_mtype
, precursor_ret_type
) then
625 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}.")
630 if mysignature
.arity
> 0 then
631 # Check parameters visibility
632 for i
in [0..mysignature
.arity
[ do
633 var nt
= nsig
.n_params
[i
].n_type
634 if nt
!= null then modelbuilder
.check_visibility
(nt
, nt
.mtype
.as(not null), mpropdef
)
637 if nt
!= null then modelbuilder
.check_visibility
(nt
, nt
.mtype
.as(not null), mpropdef
)
642 redef class AAttrPropdef
643 redef type MPROPDEF: MAttributeDef
645 # Is the node tagged `noinit`?
648 # Is the node taggeg lazy?
651 # The guard associated to a lasy attribute.
652 # Because some engines does not have a working `isset`,
653 # this additionnal attribute is used to guard the lazy initialization.
654 # TODO: to remove once isset is correctly implemented
655 var mlazypropdef
: nullable MAttributeDef
657 # The associated getter (read accessor) if any
658 var mreadpropdef
: nullable MMethodDef writable
659 # The associated setter (write accessor) if any
660 var mwritepropdef
: nullable MMethodDef writable
662 redef fun build_property
(modelbuilder
, mclassdef
)
664 var mclass
= mclassdef
.mclass
667 if self.n_id
!= null then
668 name
= self.n_id
.text
670 name
= self.n_id2
.text
673 if mclass
.kind
== interface_kind
or mclassdef
.mclass
.kind
== enum_kind
then
674 modelbuilder
.error
(self, "Error: Attempt to define attribute {name} in the interface {mclass}.")
675 else if mclass
.kind
== enum_kind
then
676 modelbuilder
.error
(self, "Error: Attempt to define attribute {name} in the enum class {mclass}.")
677 else if mclass
.kind
== extern_kind
then
678 modelbuilder
.error
(self, "Error: Attempt to define attribute {name} in the extern class {mclass}.")
683 # Old attribute style
684 var mprop
= modelbuilder
.try_get_mproperty_by_name
(nid
, mclassdef
, name
)
685 if mprop
== null then
686 var mvisibility
= new_property_visibility
(modelbuilder
, mclassdef
, self.n_visibility
)
687 mprop
= new MAttribute(mclassdef
, name
, mvisibility
)
688 if not self.check_redef_keyword
(modelbuilder
, mclassdef
, self.n_kwredef
, false, mprop
) then return
690 assert mprop
isa MAttribute
691 check_redef_property_visibility
(modelbuilder
, self.n_visibility
, mprop
)
692 if not self.check_redef_keyword
(modelbuilder
, mclassdef
, self.n_kwredef
, true, mprop
) then return
694 mclassdef
.mprop2npropdef
[mprop
] = self
696 var mpropdef
= new MAttributeDef(mclassdef
, mprop
, self.location
)
697 self.mpropdef
= mpropdef
698 modelbuilder
.mpropdef2npropdef
[mpropdef
] = self
701 var nreadable
= self.n_readable
702 if nreadable
!= null then modelbuilder
.error
(nreadable
, "Error: old-style getter no more supported")
703 var nwritable
= self.n_writable
704 if nwritable
!= null then modelbuilder
.error
(nwritable
, "Error: old-style setter no more supported")
706 # New attribute style
707 var nid2
= self.n_id2
.as(not null)
708 var mprop
= new MAttribute(mclassdef
, "_" + name
, private_visibility
)
709 var mpropdef
= new MAttributeDef(mclassdef
, mprop
, self.location
)
710 self.mpropdef
= mpropdef
711 modelbuilder
.mpropdef2npropdef
[mpropdef
] = self
715 var mreadprop
= modelbuilder
.try_get_mproperty_by_name
(nid2
, mclassdef
, readname
).as(nullable MMethod)
716 if mreadprop
== null then
717 var mvisibility
= new_property_visibility
(modelbuilder
, mclassdef
, self.n_visibility
)
718 mreadprop
= new MMethod(mclassdef
, readname
, mvisibility
)
719 if not self.check_redef_keyword
(modelbuilder
, mclassdef
, n_kwredef
, false, mreadprop
) then return
721 if not self.check_redef_keyword
(modelbuilder
, mclassdef
, n_kwredef
, true, mreadprop
) then return
722 check_redef_property_visibility
(modelbuilder
, self.n_visibility
, mreadprop
)
724 mclassdef
.mprop2npropdef
[mreadprop
] = self
726 var mreadpropdef
= new MMethodDef(mclassdef
, mreadprop
, self.location
)
727 self.mreadpropdef
= mreadpropdef
728 modelbuilder
.mpropdef2npropdef
[mreadpropdef
] = self
729 mreadpropdef
.mdoc
= mpropdef
.mdoc
731 var atlazy
= self.get_single_annotation
("lazy", modelbuilder
)
732 if atlazy
!= null then
733 if n_expr
== null then
734 modelbuilder
.error
(atlazy
, "Error: a lazy attribute needs a value")
737 var mlazyprop
= new MAttribute(mclassdef
, "lazy _" + name
, none_visibility
)
738 var mlazypropdef
= new MAttributeDef(mclassdef
, mlazyprop
, self.location
)
739 self.mlazypropdef
= mlazypropdef
742 var atreadonly
= self.get_single_annotation
("readonly", modelbuilder
)
743 if atreadonly
!= null then
744 if n_expr
== null then
745 modelbuilder
.error
(atreadonly
, "Error: a readonly attribute needs a value")
747 # No setter, so just leave
751 var writename
= name
+ "="
752 var nwritable
= self.n_writable
753 var atwritable
= self.get_single_annotation
("writable", modelbuilder
)
754 if atwritable
!= null then
755 if not atwritable
.n_args
.is_empty
then
756 writename
= atwritable
.arg_as_id
(modelbuilder
) or else writename
759 var mwriteprop
= modelbuilder
.try_get_mproperty_by_name
(nid2
, mclassdef
, writename
).as(nullable MMethod)
760 var nwkwredef
: nullable Token = null
761 if nwritable
!= null then nwkwredef
= nwritable
.n_kwredef
762 if atwritable
!= null then nwkwredef
= atwritable
.n_kwredef
763 if mwriteprop
== null then
765 if nwritable
!= null then
766 mvisibility
= new_property_visibility
(modelbuilder
, mclassdef
, nwritable
.n_visibility
)
767 else if atwritable
!= null then
768 mvisibility
= new_property_visibility
(modelbuilder
, mclassdef
, atwritable
.n_visibility
)
770 mvisibility
= private_visibility
772 mwriteprop
= new MMethod(mclassdef
, writename
, mvisibility
)
773 if not self.check_redef_keyword
(modelbuilder
, mclassdef
, nwkwredef
, false, mwriteprop
) then return
775 if not self.check_redef_keyword
(modelbuilder
, mclassdef
, nwkwredef
or else n_kwredef
, true, mwriteprop
) then return
776 if nwritable
!= null then
777 check_redef_property_visibility
(modelbuilder
, nwritable
.n_visibility
, mwriteprop
)
778 else if atwritable
!= null then
779 check_redef_property_visibility
(modelbuilder
, atwritable
.n_visibility
, mwriteprop
)
782 mclassdef
.mprop2npropdef
[mwriteprop
] = self
784 var mwritepropdef
= new MMethodDef(mclassdef
, mwriteprop
, self.location
)
785 self.mwritepropdef
= mwritepropdef
786 modelbuilder
.mpropdef2npropdef
[mwritepropdef
] = self
787 mwritepropdef
.mdoc
= mpropdef
.mdoc
791 redef fun build_signature
(modelbuilder
)
793 var mpropdef
= self.mpropdef
794 if mpropdef
== null then return # Error thus skiped
795 var mclassdef
= mpropdef
.mclassdef
796 var mmodule
= mclassdef
.mmodule
797 var mtype
: nullable MType = null
799 var mreadpropdef
= self.mreadpropdef
801 var ntype
= self.n_type
802 if ntype
!= null then
803 mtype
= modelbuilder
.resolve_mtype
(mmodule
, mclassdef
, ntype
)
804 if mtype
== null then return
807 # Inherit the type from the getter (usually an abstact getter)
808 if mtype
== null and mreadpropdef
!= null and not mreadpropdef
.is_intro
then
809 var msignature
= mreadpropdef
.mproperty
.intro
.msignature
810 if msignature
== null then return # Error, thus skiped
811 mtype
= msignature
.return_mtype
814 var nexpr
= self.n_expr
815 if mtype
== null then
816 if nexpr
!= null then
817 if nexpr
isa ANewExpr then
818 mtype
= modelbuilder
.resolve_mtype
(mmodule
, mclassdef
, nexpr
.n_type
)
819 else if nexpr
isa AIntExpr then
820 var cla
= modelbuilder
.try_get_mclass_by_name
(nexpr
, mmodule
, "Int")
821 if cla
!= null then mtype
= cla
.mclass_type
822 else if nexpr
isa AFloatExpr then
823 var cla
= modelbuilder
.try_get_mclass_by_name
(nexpr
, mmodule
, "Float")
824 if cla
!= null then mtype
= cla
.mclass_type
825 else if nexpr
isa ACharExpr then
826 var cla
= modelbuilder
.try_get_mclass_by_name
(nexpr
, mmodule
, "Char")
827 if cla
!= null then mtype
= cla
.mclass_type
828 else if nexpr
isa ABoolExpr then
829 var cla
= modelbuilder
.try_get_mclass_by_name
(nexpr
, mmodule
, "Bool")
830 if cla
!= null then mtype
= cla
.mclass_type
831 else if nexpr
isa ASuperstringExpr then
832 var cla
= modelbuilder
.try_get_mclass_by_name
(nexpr
, mmodule
, "String")
833 if cla
!= null then mtype
= cla
.mclass_type
834 else if nexpr
isa AStringFormExpr then
835 var cla
= modelbuilder
.try_get_mclass_by_name
(nexpr
, mmodule
, "String")
836 if cla
!= null then mtype
= cla
.mclass_type
838 modelbuilder
.error
(self, "Error: Untyped attribute {mpropdef}. Implicit typing allowed only for literals and new.")
841 if mtype
== null then return
843 else if ntype
!= null then
844 if nexpr
isa ANewExpr then
845 var xmtype
= modelbuilder
.resolve_mtype
(mmodule
, mclassdef
, nexpr
.n_type
)
846 if xmtype
== mtype
and modelbuilder
.toolcontext
.opt_warn
.value
>= 2 then
847 modelbuilder
.warning
(ntype
, "Warning: useless type definition")
852 if mtype
== null then
853 modelbuilder
.error
(self, "Error: Untyped attribute {mpropdef}")
857 mpropdef
.static_mtype
= mtype
859 if mreadpropdef
!= null then
860 var msignature
= new MSignature(new Array[MParameter], mtype
)
861 mreadpropdef
.msignature
= msignature
864 var mwritepropdef
= self.mwritepropdef
865 if mwritepropdef
!= null then
868 name
= n_id
.text
.substring_from
(1)
872 var mparameter
= new MParameter(name
, mtype
, false)
873 var msignature
= new MSignature([mparameter
], null)
874 mwritepropdef
.msignature
= msignature
877 var mlazypropdef
= self.mlazypropdef
878 if mlazypropdef
!= null then
879 mlazypropdef
.static_mtype
= modelbuilder
.model
.get_mclasses_by_name
("Bool").first
.mclass_type
883 redef fun check_signature
(modelbuilder
)
885 var mpropdef
= self.mpropdef
886 if mpropdef
== null then return # Error thus skiped
887 var mclassdef
= mpropdef
.mclassdef
888 var mmodule
= mclassdef
.mmodule
889 var ntype
= self.n_type
890 var mtype
= self.mpropdef
.static_mtype
891 if mtype
== null then return # Error thus skiped
893 # Lookup for signature in the precursor
894 # FIXME all precursors should be considered
895 if not mpropdef
.is_intro
then
896 var precursor_type
= mpropdef
.mproperty
.intro
.static_mtype
897 if precursor_type
== null then return
899 if mtype
!= precursor_type
then
900 modelbuilder
.error
(ntype
.as(not null), "Redef Error: Wrong static type. found {mtype}, expected {precursor_type}.")
905 # Check getter and setter
906 var meth
= self.mreadpropdef
908 self.check_method_signature
(modelbuilder
, meth
)
909 var node
: nullable ANode = ntype
910 if node
== null then node
= self
911 modelbuilder
.check_visibility
(node
, mtype
, meth
)
913 meth
= self.mwritepropdef
915 self.check_method_signature
(modelbuilder
, meth
)
916 var node
: nullable ANode = ntype
917 if node
== null then node
= self
918 modelbuilder
.check_visibility
(node
, mtype
, meth
)
922 private fun check_method_signature
(modelbuilder
: ModelBuilder, mpropdef
: MMethodDef)
924 var mclassdef
= mpropdef
.mclassdef
925 var mmodule
= mclassdef
.mmodule
926 var nsig
= self.n_type
927 var mysignature
= mpropdef
.msignature
928 if mysignature
== null then return # Error thus skiped
930 # Lookup for signature in the precursor
931 # FIXME all precursors should be considered
932 if not mpropdef
.is_intro
then
933 var msignature
= mpropdef
.mproperty
.intro
.msignature
934 if msignature
== null then return
936 if mysignature
.arity
!= msignature
.arity
then
938 if nsig
!= null then node
= nsig
else node
= self
939 modelbuilder
.error
(node
, "Redef Error: {mysignature.arity} parameters found, {msignature.arity} expected. Signature is {mpropdef}{msignature}")
942 var precursor_ret_type
= msignature
.return_mtype
943 var ret_type
= mysignature
.return_mtype
944 if ret_type
!= null and precursor_ret_type
== null then
946 if nsig
!= null then node
= nsig
else node
= self
947 modelbuilder
.error
(node
, "Redef Error: {mpropdef.mproperty} is a procedure, not a function.")
951 if mysignature
.arity
> 0 then
952 # Check parameters types
953 for i
in [0..mysignature
.arity
[ do
954 var myt
= mysignature
.mparameters
[i
].mtype
955 var prt
= msignature
.mparameters
[i
].mtype
956 if not myt
.is_subtype
(mmodule
, mclassdef
.bound_mtype
, prt
) or
957 not prt
.is_subtype
(mmodule
, mclassdef
.bound_mtype
, myt
) then
959 if nsig
!= null then node
= nsig
else node
= self
960 modelbuilder
.error
(node
, "Redef Error: Wrong type for parameter `{mysignature.mparameters[i].name}'. found {myt}, expected {prt}.")
964 if precursor_ret_type
!= null then
965 if ret_type
== null then
966 # Inherit the return type
967 ret_type
= precursor_ret_type
968 else if not ret_type
.is_subtype
(mmodule
, mclassdef
.bound_mtype
, precursor_ret_type
) then
970 if nsig
!= null then node
= nsig
else node
= self
971 modelbuilder
.error
(node
, "Redef Error: Wrong return type. found {ret_type}, expected {precursor_ret_type}.")
978 redef class ATypePropdef
979 redef type MPROPDEF: MVirtualTypeDef
981 redef fun build_property
(modelbuilder
, mclassdef
)
983 var name
= self.n_id
.text
984 var mprop
= modelbuilder
.try_get_mproperty_by_name
(self.n_id
, mclassdef
, name
)
985 if mprop
== null then
986 var mvisibility
= new_property_visibility
(modelbuilder
, mclassdef
, self.n_visibility
)
987 mprop
= new MVirtualTypeProp(mclassdef
, name
, mvisibility
)
988 for c
in name
.chars
do if c
>= 'a' and c
<= 'z' then
989 modelbuilder
.warning
(n_id
, "Warning: lowercase in the virtual type {name}")
992 if not self.check_redef_keyword
(modelbuilder
, mclassdef
, self.n_kwredef
, false, mprop
) then return
994 if not self.check_redef_keyword
(modelbuilder
, mclassdef
, self.n_kwredef
, true, mprop
) then return
995 assert mprop
isa MVirtualTypeProp
996 check_redef_property_visibility
(modelbuilder
, self.n_visibility
, mprop
)
998 mclassdef
.mprop2npropdef
[mprop
] = self
1000 var mpropdef
= new MVirtualTypeDef(mclassdef
, mprop
, self.location
)
1001 self.mpropdef
= mpropdef
1002 modelbuilder
.mpropdef2npropdef
[mpropdef
] = self
1005 var atfixed
= get_single_annotation
("fixed", modelbuilder
)
1006 if atfixed
!= null then
1007 mpropdef
.is_fixed
= true
1011 redef fun build_signature
(modelbuilder
)
1013 var mpropdef
= self.mpropdef
1014 if mpropdef
== null then return # Error thus skiped
1015 var mclassdef
= mpropdef
.mclassdef
1016 var mmodule
= mclassdef
.mmodule
1017 var mtype
: nullable MType = null
1019 var ntype
= self.n_type
1020 mtype
= modelbuilder
.resolve_mtype
(mmodule
, mclassdef
, ntype
)
1021 if mtype
== null then return
1023 mpropdef
.bound
= mtype
1024 # print "{mpropdef}: {mtype}"
1027 redef fun check_signature
(modelbuilder
)
1029 var mpropdef
= self.mpropdef
1030 if mpropdef
== null then return # Error thus skiped
1032 var bound
= self.mpropdef
.bound
1033 if bound
== null then return # Error thus skiped
1035 modelbuilder
.check_visibility
(n_type
, bound
, mpropdef
)
1037 var mclassdef
= mpropdef
.mclassdef
1038 var mmodule
= mclassdef
.mmodule
1039 var anchor
= mclassdef
.bound_mtype
1042 if bound
isa MVirtualType then
1043 # Slow case: progress on each resolution until: (i) we loop, or (ii) we found a non formal type
1044 var seen
= [self.mpropdef
.mproperty
.mvirtualtype
]
1046 if seen
.has
(bound
) then
1048 modelbuilder
.error
(self, "Error: circularity of virtual type definition: {seen.join(" -> ")}")
1052 var next
= bound
.lookup_bound
(mmodule
, anchor
)
1053 if not next
isa MVirtualType then break
1058 # Check redefinitions
1059 bound
= mpropdef
.bound
.as(not null)
1060 for p
in mpropdef
.mproperty
.lookup_super_definitions
(mmodule
, anchor
) do
1061 var supbound
= p
.bound
.as(not null)
1063 modelbuilder
.error
(self, "Redef Error: Virtual type {mpropdef.mproperty} is fixed in super-class {p.mclassdef.mclass}")
1066 if p
.mclassdef
.mclass
== mclassdef
.mclass
then
1067 # Still a warning to pass existing bad code
1068 modelbuilder
.warning
(n_type
, "Redef Error: a virtual type cannot be refined.")
1071 if not bound
.is_subtype
(mmodule
, anchor
, supbound
) then
1072 modelbuilder
.error
(n_type
, "Redef Error: Wrong bound type. Found {bound}, expected a subtype of {supbound}, as in {p}.")