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
22 redef class ToolContext
23 var modelize_property_phase
: Phase = new ModelizePropertyPhase(self, [modelize_class_phase
])
26 private class ModelizePropertyPhase
28 redef fun process_nmodule
(nmodule
)
30 for nclassdef
in nmodule
.n_classdefs
do
31 toolcontext
.modelbuilder
.build_properties
(nclassdef
)
36 redef class ModelBuilder
37 # Register the npropdef associated to each mpropdef
38 # FIXME: why not refine the `MPropDef` class with a nullable attribute?
39 var mpropdef2npropdef
: HashMap[MPropDef, APropdef] = new HashMap[MPropDef, APropdef]
41 # Build the properties of `nclassdef`.
42 # REQUIRE: all superclasses are built.
43 private fun build_properties
(nclassdef
: AClassdef)
45 # Force building recursively
46 if nclassdef
.build_properties_is_done
then return
47 nclassdef
.build_properties_is_done
= true
48 var mclassdef
= nclassdef
.mclassdef
.as(not null)
49 if mclassdef
.in_hierarchy
== null then return # Skip error
50 for superclassdef
in mclassdef
.in_hierarchy
.direct_greaters
do
51 build_properties
(mclassdef2nclassdef
[superclassdef
])
54 for npropdef
in nclassdef
.n_propdefs
do
55 npropdef
.build_property
(self, nclassdef
)
57 for npropdef
in nclassdef
.n_propdefs
do
58 npropdef
.build_signature
(self, nclassdef
)
60 for npropdef
in nclassdef
.n_propdefs
do
61 npropdef
.check_signature
(self, nclassdef
)
63 process_default_constructors
(nclassdef
)
66 # Introduce or inherit default constructor
67 # This is the last part of `build_properties`.
68 private fun process_default_constructors
(nclassdef
: AClassdef)
70 var mclassdef
= nclassdef
.mclassdef
.as(not null)
73 if not mclassdef
.is_intro
then return
75 # Is the class forbid constructors?
76 if not mclassdef
.mclass
.kind
.need_init
then return
78 # Is there already a constructor defined?
79 for mpropdef
in mclassdef
.mpropdefs
do
80 if not mpropdef
isa MMethodDef then continue
81 if mpropdef
.mproperty
.is_init
then return
84 if not nclassdef
isa AStdClassdef then return
86 var mmodule
= nclassdef
.mclassdef
.mmodule
87 # Do we inherit for a constructor?
88 var combine
= new Array[MMethod]
89 var inhc
: nullable MClass = null
90 for st
in mclassdef
.supertypes
do
92 if not c
.kind
.need_init
then continue
93 st
= st
.anchor_to
(mmodule
, nclassdef
.mclassdef
.bound_mtype
)
94 var candidate
= self.try_get_mproperty_by_name2
(nclassdef
, mmodule
, st
, "init").as(nullable MMethod)
95 if candidate
!= null and candidate
.intro
.msignature
.arity
== 0 then
96 combine
.add
(candidate
)
99 var inhc2
= c
.inherit_init_from
100 if inhc2
== null then inhc2
= c
101 if inhc2
== inhc
then continue
103 self.error
(nclassdef
, "Error: Cannot provide a defaut constructor: conflict for {inhc} and {c}")
109 # Collect undefined attributes
110 var mparameters
= new Array[MParameter]
111 var anode
: nullable ANode = null
112 for npropdef
in nclassdef
.n_propdefs
do
113 if npropdef
isa AAttrPropdef and npropdef
.n_expr
== null then
114 if npropdef
.mpropdef
== null then return # Skip broken attribute
115 var paramname
= npropdef
.mpropdef
.mproperty
.name
.substring_from
(1)
116 var ret_type
= npropdef
.mpropdef
.static_mtype
117 if ret_type
== null then return
118 var mparameter
= new MParameter(paramname
, ret_type
, false)
119 mparameters
.add
(mparameter
)
120 if anode
== null then anode
= npropdef
123 if anode
== null then anode
= nclassdef
125 if combine
.is_empty
and inhc
!= null then
126 if not mparameters
.is_empty
then
127 self.error
(anode
,"Error: {mclassdef} cannot inherit constructors from {inhc} because there is attributes without initial values: {mparameters.join(", ")}")
131 # TODO: actively inherit the consturctor
132 self.toolcontext
.info
("{mclassdef} inherits all constructors from {inhc}", 3)
133 mclassdef
.mclass
.inherit_init_from
= inhc
137 if not combine
.is_empty
and inhc
!= null then
138 self.error
(nclassdef
, "Error: Cannot provide a defaut constructor: conflict for {combine.join(", ")} and {inhc}")
142 if not combine
.is_empty
then
143 if mparameters
.is_empty
and combine
.length
== 1 then
144 # No need to create a local init, the inherited one is enough
145 inhc
= combine
.first
.intro_mclassdef
.mclass
146 mclassdef
.mclass
.inherit_init_from
= inhc
147 self.toolcontext
.info
("{mclassdef} inherits all constructors from {inhc}", 3)
150 nclassdef
.super_inits
= combine
153 var mprop
= new MMethod(mclassdef
, "init", mclassdef
.mclass
.visibility
)
154 var mpropdef
= new MMethodDef(mclassdef
, mprop
, nclassdef
.location
)
155 var msignature
= new MSignature(mparameters
, null)
156 mpropdef
.msignature
= msignature
158 nclassdef
.mfree_init
= mpropdef
159 self.toolcontext
.info
("{mclassdef} gets a free constructor for attributes {mpropdef}{msignature}", 3)
162 # Check the visibility of `mtype` as an element of the signature of `mpropdef`.
163 fun check_visibility
(node
: ANode, mtype
: MType, mpropdef
: MPropDef)
165 var mmodule
= mpropdef
.mclassdef
.mmodule
166 var mproperty
= mpropdef
.mproperty
168 # Extract visibility information of the main part of `mtype`
169 # It is a case-by case
170 var vis_type
: nullable MVisibility = null # The own visibility of the type
171 var mmodule_type
: nullable MModule = null # The origial module of the type
172 if mtype
isa MNullableType then mtype
= mtype
.mtype
173 if mtype
isa MClassType then
174 vis_type
= mtype
.mclass
.visibility
175 mmodule_type
= mtype
.mclass
.intro
.mmodule
176 else if mtype
isa MVirtualType then
177 vis_type
= mtype
.mproperty
.visibility
178 mmodule_type
= mtype
.mproperty
.intro_mclassdef
.mmodule
179 else if mtype
isa MParameterType then
180 # nothing, always visible
182 node
.debug
"Unexpected type {mtype}"
186 if vis_type
!= null then
187 assert mmodule_type
!= null
188 var vis_module_type
= mmodule
.visibility_for
(mmodule_type
) # the visibility of the original module
189 if mproperty
.visibility
> vis_type
then
190 error
(node
, "Error: The {mproperty.visibility} property `{mproperty}` cannot contain the {vis_type} type `{mtype}`")
192 else if mproperty
.visibility
> vis_module_type
then
193 error
(node
, "Error: The {mproperty.visibility} property `{mproperty}` cannot contain the type `{mtype}` from the {vis_module_type} module `{mmodule_type}`")
198 # No error, try to go deeper in generic types
199 if node
isa AType then
200 for a
in node
.n_types
do check_visibility
(a
, a
.mtype
.as(not null), mpropdef
)
201 else if mtype
isa MGenericType then
202 for t
in mtype
.arguments
do check_visibility
(node
, t
, mpropdef
)
208 # The class whose self inherit all the constructors.
209 # 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
210 var inherit_init_from
: nullable MClass = null
213 redef class MClassDef
214 private var propdef_names
= new HashSet[String]
218 # Does the MPropDef contains a call to super or a call of a super-constructor?
219 # Subsequent phases of the frontend (esp. typing) set it if required
220 var has_supercall
: Bool writable = false
223 redef class AClassdef
224 var build_properties_is_done
: Bool = false
225 # The list of super-constructor to call at the start of the free constructor
226 # 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
227 var super_inits
: nullable Collection[MMethod] = null
229 # The free init (implicitely constructed by the class if required)
230 var mfree_init
: nullable MMethodDef = null
232 # What is the `APropdef` associated to a `MProperty`?
233 # Used to check multiple definition of a property.
234 var mprop2npropdef
: Map[MProperty, APropdef] = new HashMap[MProperty, APropdef]
238 # Join the text of all tokens
239 # Used to get the 'real name' of method definitions.
240 fun collect_text
: String
242 var v
= new TextCollectorVisitor
249 private class TextCollectorVisitor
251 var text
: String = ""
254 if n
isa Token then text
+= n
.text
260 # The associated main model entity
261 type MPROPDEF: MPropDef
263 # The associated propdef once build by a `ModelBuilder`
264 var mpropdef
: nullable MPROPDEF writable
266 private fun build_property
(modelbuilder
: ModelBuilder, nclassdef
: AClassdef) is abstract
267 private fun build_signature
(modelbuilder
: ModelBuilder, nclassdef
: AClassdef) is abstract
268 private fun check_signature
(modelbuilder
: ModelBuilder, nclassdef
: AClassdef) is abstract
269 private fun new_property_visibility
(modelbuilder
: ModelBuilder, nclassdef
: AClassdef, nvisibility
: nullable AVisibility): MVisibility
271 var mvisibility
= public_visibility
272 if nvisibility
!= null then
273 mvisibility
= nvisibility
.mvisibility
274 if mvisibility
== intrude_visibility
then
275 modelbuilder
.error
(nvisibility
, "Error: intrude is not a legal visibility for properties.")
276 mvisibility
= public_visibility
279 if nclassdef
.mclassdef
.mclass
.visibility
== private_visibility
then
280 if mvisibility
== protected_visibility
then
281 assert nvisibility
!= null
282 modelbuilder
.error
(nvisibility
, "Error: The only legal visibility for properties in a private class is private.")
283 else if mvisibility
== private_visibility
then
284 assert nvisibility
!= null
286 # modelbuilder.warning(nvisibility, "Warning: private is unrequired since the only legal visibility for properties in a private class is private.")
288 mvisibility
= private_visibility
293 private fun set_doc
(mpropdef
: MPropDef)
295 var ndoc
= self.n_doc
297 var mdoc
= ndoc
.to_mdoc
299 mdoc
.original_mentity
= mpropdef
303 private fun check_redef_property_visibility
(modelbuilder
: ModelBuilder, nclassdef
: AClassdef, nvisibility
: nullable AVisibility, mprop
: MProperty)
305 if nvisibility
== null then return
306 var mvisibility
= nvisibility
.mvisibility
307 if mvisibility
!= mprop
.visibility
and mvisibility
!= public_visibility
then
308 modelbuilder
.error
(nvisibility
, "Error: redefinition changed the visibility from a {mprop.visibility} to a {mvisibility}")
312 private fun check_redef_keyword
(modelbuilder
: ModelBuilder, nclassdef
: AClassdef, kwredef
: nullable Token, need_redef
: Bool, mprop
: MProperty): Bool
314 if nclassdef
.mprop2npropdef
.has_key
(mprop
) then
315 modelbuilder
.error
(self, "Error: A property {mprop} is already defined in class {nclassdef.mclassdef.mclass}.")
318 if kwredef
== null then
320 modelbuilder
.error
(self, "Redef error: {nclassdef.mclassdef.mclass}::{mprop.name} is an inherited property. To redefine it, add the redef keyword.")
324 if not need_redef
then
325 modelbuilder
.error
(self, "Error: No property {nclassdef.mclassdef.mclass}::{mprop.name} is inherited. Remove the redef keyword to define a new property.")
334 redef class ASignature
335 # Is the model builder has correctly visited the signature
336 var is_visited
= false
337 # Names of parameters from the AST
338 # REQUIRE: is_visited
339 var param_names
= new Array[String]
340 # Types of parameters from the AST
341 # REQUIRE: is_visited
342 var param_types
= new Array[MType]
343 # Rank of the vararg (of -1 if none)
344 # REQUIRE: is_visited
345 var vararg_rank
: Int = -1
347 var ret_type
: nullable MType = null
349 # Visit and fill information about a signature
350 private fun visit_signature
(modelbuilder
: ModelBuilder, nclassdef
: AClassdef): Bool
352 var param_names
= self.param_names
353 var param_types
= self.param_types
354 for np
in self.n_params
do
355 param_names
.add
(np
.n_id
.text
)
356 var ntype
= np
.n_type
357 if ntype
!= null then
358 var mtype
= modelbuilder
.resolve_mtype
(nclassdef
, ntype
)
359 if mtype
== null then return false # Skip error
360 for i
in [0..param_names
.length-param_types
.length
[ do
361 param_types
.add
(mtype
)
363 if np
.n_dotdotdot
!= null then
364 if self.vararg_rank
!= -1 then
365 modelbuilder
.error
(np
, "Error: {param_names[self.vararg_rank]} is already a vararg")
368 self.vararg_rank
= param_names
.length
- 1
373 var ntype
= self.n_type
374 if ntype
!= null then
375 self.ret_type
= modelbuilder
.resolve_mtype
(nclassdef
, ntype
)
376 if self.ret_type
== null then return false # Skip errir
379 self.is_visited
= true
383 # Build a visited signature
384 fun build_signature
(modelbuilder
: ModelBuilder, nclassdef
: AClassdef): nullable MSignature
386 if param_names
.length
!= param_types
.length
then
387 # Some parameters are typed, other parameters are not typed.
388 modelbuilder
.error
(self.n_params
[param_types
.length
], "Error: Untyped parameter `{param_names[param_types.length]}'.")
392 var mparameters
= new Array[MParameter]
393 for i
in [0..param_names
.length
[ do
394 var mparameter
= new MParameter(param_names
[i
], param_types
[i
], i
== vararg_rank
)
395 self.n_params
[i
].mparameter
= mparameter
396 mparameters
.add
(mparameter
)
399 var msignature
= new MSignature(mparameters
, ret_type
)
405 # The associated mparameter if any
406 var mparameter
: nullable MParameter = null
409 redef class AMethPropdef
410 redef type MPROPDEF: MMethodDef
412 redef fun build_property
(modelbuilder
, nclassdef
)
414 var n_kwinit
= n_kwinit
415 var n_kwnew
= n_kwnew
416 var is_init
= n_kwinit
!= null or n_kwnew
!= null
417 var mclassdef
= nclassdef
.mclassdef
.as(not null)
419 var amethodid
= self.n_methid
421 if amethodid
== null then
425 else if n_kwinit
!= null then
428 else if n_kwnew
!= null then
434 else if amethodid
isa AIdMethid then
435 name
= amethodid
.n_id
.text
436 name_node
= amethodid
438 # operator, bracket or assign
439 name
= amethodid
.collect_text
440 name_node
= amethodid
442 if name
== "-" and self.n_signature
.n_params
.length
== 0 then
447 var mprop
: nullable MMethod = null
448 if not is_init
or n_kwredef
!= null then mprop
= modelbuilder
.try_get_mproperty_by_name
(name_node
, mclassdef
, name
).as(nullable MMethod)
449 if mprop
== null then
450 var mvisibility
= new_property_visibility
(modelbuilder
, nclassdef
, self.n_visibility
)
451 mprop
= new MMethod(mclassdef
, name
, mvisibility
)
452 mprop
.is_init
= is_init
453 mprop
.is_new
= n_kwnew
!= null
454 if not self.check_redef_keyword
(modelbuilder
, nclassdef
, n_kwredef
, false, mprop
) then return
456 if n_kwredef
== null then
457 if self isa AMainMethPropdef then
460 if not self.check_redef_keyword
(modelbuilder
, nclassdef
, n_kwredef
, true, mprop
) then return
463 check_redef_property_visibility
(modelbuilder
, nclassdef
, self.n_visibility
, mprop
)
465 nclassdef
.mprop2npropdef
[mprop
] = self
467 var mpropdef
= new MMethodDef(mclassdef
, mprop
, self.location
)
469 if mclassdef
.propdef_names
.has
(mprop
.name
) then
470 var loc
: nullable Location = null
471 for i
in mclassdef
.mpropdefs
do
472 if i
.mproperty
.name
== mprop
.name
then
477 if loc
== null then abort
478 modelbuilder
.error
(self, "Error: a property {mprop} is already defined in class {mclassdef.mclass} at {loc}")
481 mclassdef
.propdef_names
.add
(mpropdef
.mproperty
.name
)
485 self.mpropdef
= mpropdef
486 modelbuilder
.mpropdef2npropdef
[mpropdef
] = self
487 if mpropdef
.is_intro
then
488 modelbuilder
.toolcontext
.info
("{mpropdef} introduces new method {mprop.full_name}", 3)
490 modelbuilder
.toolcontext
.info
("{mpropdef} redefines method {mprop.full_name}", 3)
494 redef fun build_signature
(modelbuilder
, nclassdef
)
496 var mpropdef
= self.mpropdef
497 if mpropdef
== null then return # Error thus skiped
498 var mmodule
= mpropdef
.mclassdef
.mmodule
499 var nsig
= self.n_signature
501 # Retrieve info from the signature AST
502 var param_names
= new Array[String] # Names of parameters from the AST
503 var param_types
= new Array[MType] # Types of parameters from the AST
505 var ret_type
: nullable MType = null # Return type from the AST
507 if not nsig
.visit_signature
(modelbuilder
, nclassdef
) then return
508 param_names
= nsig
.param_names
509 param_types
= nsig
.param_types
510 vararg_rank
= nsig
.vararg_rank
511 ret_type
= nsig
.ret_type
514 # Look for some signature to inherit
515 # FIXME: do not inherit from the intro, but from the most specific
516 var msignature
: nullable MSignature = null
517 if not mpropdef
.is_intro
then
518 msignature
= mpropdef
.mproperty
.intro
.msignature
519 if msignature
== null then return # Skip error
521 # Check inherited signature arity
522 if param_names
.length
!= msignature
.arity
then
524 if nsig
!= null then node
= nsig
else node
= self
525 modelbuilder
.error
(node
, "Redef error: {mpropdef} redefines {mpropdef.mproperty.intro} with {param_names.length} parameter(s), {msignature.arity} expected. Signature is {mpropdef}{msignature}")
528 else if mpropdef
.mproperty
.is_init
then
529 # FIXME UGLY: inherit signature from a super-constructor
530 for msupertype
in nclassdef
.mclassdef
.supertypes
do
531 msupertype
= msupertype
.anchor_to
(mmodule
, nclassdef
.mclassdef
.bound_mtype
)
532 var candidate
= modelbuilder
.try_get_mproperty_by_name2
(self, mmodule
, msupertype
, mpropdef
.mproperty
.name
)
533 if candidate
!= null then
534 if msignature
== null then
535 msignature
= candidate
.intro
.as(MMethodDef).msignature
542 # Inherit the signature
543 if msignature
!= null and param_names
.length
!= param_types
.length
and param_names
.length
== msignature
.arity
and param_types
.length
== 0 then
544 # Parameters are untyped, thus inherit them
545 param_types
= new Array[MType]
546 for mparameter
in msignature
.mparameters
do
547 param_types
.add
(mparameter
.mtype
)
549 vararg_rank
= msignature
.vararg_rank
551 if msignature
!= null and ret_type
== null then
552 ret_type
= msignature
.return_mtype
555 if param_names
.length
!= param_types
.length
then
556 # Some parameters are typed, other parameters are not typed.
557 modelbuilder
.error
(nsig
.n_params
[param_types
.length
], "Error: Untyped parameter `{param_names[param_types.length]}'.")
561 var mparameters
= new Array[MParameter]
562 for i
in [0..param_names
.length
[ do
563 var mparameter
= new MParameter(param_names
[i
], param_types
[i
], i
== vararg_rank
)
564 if nsig
!= null then nsig
.n_params
[i
].mparameter
= mparameter
565 mparameters
.add
(mparameter
)
568 msignature
= new MSignature(mparameters
, ret_type
)
569 mpropdef
.msignature
= msignature
570 mpropdef
.is_abstract
= self isa ADeferredMethPropdef
571 mpropdef
.is_intern
= self isa AInternMethPropdef
572 mpropdef
.is_extern
= self isa AExternPropdef
575 redef fun check_signature
(modelbuilder
, nclassdef
)
577 var mpropdef
= self.mpropdef
578 if mpropdef
== null then return # Error thus skiped
579 var mmodule
= mpropdef
.mclassdef
.mmodule
580 var nsig
= self.n_signature
581 var mysignature
= self.mpropdef
.msignature
582 if mysignature
== null then return # Error thus skiped
584 # Lookup for signature in the precursor
585 # FIXME all precursors should be considered
586 if not mpropdef
.is_intro
then
587 var msignature
= mpropdef
.mproperty
.intro
.msignature
588 if msignature
== null then return
590 var precursor_ret_type
= msignature
.return_mtype
591 var ret_type
= mysignature
.return_mtype
592 if ret_type
!= null and precursor_ret_type
== null then
593 modelbuilder
.error
(nsig
.n_type
.as(not null), "Redef Error: {mpropdef.mproperty} is a procedure, not a function.")
597 if mysignature
.arity
> 0 then
598 # Check parameters types
599 for i
in [0..mysignature
.arity
[ do
600 var myt
= mysignature
.mparameters
[i
].mtype
601 var prt
= msignature
.mparameters
[i
].mtype
602 if not myt
.is_subtype
(mmodule
, nclassdef
.mclassdef
.bound_mtype
, prt
) or
603 not prt
.is_subtype
(mmodule
, nclassdef
.mclassdef
.bound_mtype
, myt
) then
604 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}.")
608 if precursor_ret_type
!= null then
609 if ret_type
== null then
610 # Inherit the return type
611 ret_type
= precursor_ret_type
612 else if not ret_type
.is_subtype
(mmodule
, nclassdef
.mclassdef
.bound_mtype
, precursor_ret_type
) then
613 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}.")
618 if mysignature
.arity
> 0 then
619 # Check parameters visibility
620 for i
in [0..mysignature
.arity
[ do
621 var nt
= nsig
.n_params
[i
].n_type
622 if nt
!= null then modelbuilder
.check_visibility
(nt
, nt
.mtype
.as(not null), mpropdef
)
625 if nt
!= null then modelbuilder
.check_visibility
(nt
, nt
.mtype
.as(not null), mpropdef
)
630 redef class AAttrPropdef
631 redef type MPROPDEF: MAttributeDef
633 # The associated getter (read accessor) if any
634 var mreadpropdef
: nullable MMethodDef writable
635 # The associated setter (write accessor) if any
636 var mwritepropdef
: nullable MMethodDef writable
637 redef fun build_property
(modelbuilder
, nclassdef
)
639 var mclassdef
= nclassdef
.mclassdef
.as(not null)
640 var mclass
= mclassdef
.mclass
643 if self.n_id
!= null then
644 name
= self.n_id
.text
646 name
= self.n_id2
.text
649 if mclass
.kind
== interface_kind
or mclassdef
.mclass
.kind
== enum_kind
then
650 modelbuilder
.error
(self, "Error: Attempt to define attribute {name} in the interface {mclass}.")
651 else if mclass
.kind
== enum_kind
then
652 modelbuilder
.error
(self, "Error: Attempt to define attribute {name} in the enum class {mclass}.")
653 else if mclass
.kind
== extern_kind
then
654 modelbuilder
.error
(self, "Error: Attempt to define attribute {name} in the extern class {mclass}.")
659 # Old attribute style
660 var mprop
= modelbuilder
.try_get_mproperty_by_name
(nid
, mclassdef
, name
)
661 if mprop
== null then
662 var mvisibility
= new_property_visibility
(modelbuilder
, nclassdef
, self.n_visibility
)
663 mprop
= new MAttribute(mclassdef
, name
, mvisibility
)
664 if not self.check_redef_keyword
(modelbuilder
, nclassdef
, self.n_kwredef
, false, mprop
) then return
666 assert mprop
isa MAttribute
667 check_redef_property_visibility
(modelbuilder
, nclassdef
, self.n_visibility
, mprop
)
668 if not self.check_redef_keyword
(modelbuilder
, nclassdef
, self.n_kwredef
, true, mprop
) then return
670 nclassdef
.mprop2npropdef
[mprop
] = self
672 var mpropdef
= new MAttributeDef(mclassdef
, mprop
, self.location
)
673 self.mpropdef
= mpropdef
674 modelbuilder
.mpropdef2npropdef
[mpropdef
] = self
677 var nreadable
= self.n_readable
678 if nreadable
!= null then
679 var readname
= name
.substring_from
(1)
680 var mreadprop
= modelbuilder
.try_get_mproperty_by_name
(nid
, mclassdef
, readname
).as(nullable MMethod)
681 if mreadprop
== null then
682 var mvisibility
= new_property_visibility
(modelbuilder
, nclassdef
, nreadable
.n_visibility
)
683 mreadprop
= new MMethod(mclassdef
, readname
, mvisibility
)
684 if not self.check_redef_keyword
(modelbuilder
, nclassdef
, nreadable
.n_kwredef
, false, mreadprop
) then return
686 if not self.check_redef_keyword
(modelbuilder
, nclassdef
, nreadable
.n_kwredef
, true, mreadprop
) then return
687 check_redef_property_visibility
(modelbuilder
, nclassdef
, nreadable
.n_visibility
, mreadprop
)
689 nclassdef
.mprop2npropdef
[mreadprop
] = self
691 var mreadpropdef
= new MMethodDef(mclassdef
, mreadprop
, self.location
)
692 self.mreadpropdef
= mreadpropdef
693 modelbuilder
.mpropdef2npropdef
[mreadpropdef
] = self
694 mreadpropdef
.mdoc
= mpropdef
.mdoc
697 var nwritable
= self.n_writable
698 if nwritable
!= null then
699 var writename
= name
.substring_from
(1) + "="
700 var mwriteprop
= modelbuilder
.try_get_mproperty_by_name
(nid
, mclassdef
, writename
).as(nullable MMethod)
701 if mwriteprop
== null then
702 var mvisibility
= new_property_visibility
(modelbuilder
, nclassdef
, nwritable
.n_visibility
)
703 mwriteprop
= new MMethod(mclassdef
, writename
, mvisibility
)
704 if not self.check_redef_keyword
(modelbuilder
, nclassdef
, nwritable
.n_kwredef
, false, mwriteprop
) then return
706 if not self.check_redef_keyword
(modelbuilder
, nclassdef
, nwritable
.n_kwredef
, true, mwriteprop
) then return
707 check_redef_property_visibility
(modelbuilder
, nclassdef
, nwritable
.n_visibility
, mwriteprop
)
709 nclassdef
.mprop2npropdef
[mwriteprop
] = self
711 var mwritepropdef
= new MMethodDef(mclassdef
, mwriteprop
, self.location
)
712 self.mwritepropdef
= mwritepropdef
713 modelbuilder
.mpropdef2npropdef
[mwritepropdef
] = self
714 mwritepropdef
.mdoc
= mpropdef
.mdoc
717 # New attribute style
718 var nid2
= self.n_id2
.as(not null)
719 var mprop
= new MAttribute(mclassdef
, "@" + name
, none_visibility
)
720 var mpropdef
= new MAttributeDef(mclassdef
, mprop
, self.location
)
721 self.mpropdef
= mpropdef
722 modelbuilder
.mpropdef2npropdef
[mpropdef
] = self
726 var mreadprop
= modelbuilder
.try_get_mproperty_by_name
(nid2
, mclassdef
, readname
).as(nullable MMethod)
727 if mreadprop
== null then
728 var mvisibility
= new_property_visibility
(modelbuilder
, nclassdef
, self.n_visibility
)
729 mreadprop
= new MMethod(mclassdef
, readname
, mvisibility
)
730 if not self.check_redef_keyword
(modelbuilder
, nclassdef
, n_kwredef
, false, mreadprop
) then return
732 if not self.check_redef_keyword
(modelbuilder
, nclassdef
, n_kwredef
, true, mreadprop
) then return
733 check_redef_property_visibility
(modelbuilder
, nclassdef
, self.n_visibility
, mreadprop
)
735 nclassdef
.mprop2npropdef
[mreadprop
] = self
737 var mreadpropdef
= new MMethodDef(mclassdef
, mreadprop
, self.location
)
738 self.mreadpropdef
= mreadpropdef
739 modelbuilder
.mpropdef2npropdef
[mreadpropdef
] = self
740 mreadpropdef
.mdoc
= mpropdef
.mdoc
742 var writename
= name
+ "="
743 var nwritable
= self.n_writable
744 var mwriteprop
= modelbuilder
.try_get_mproperty_by_name
(nid2
, mclassdef
, writename
).as(nullable MMethod)
745 var nwkwredef
: nullable Token = null
746 if nwritable
!= null then nwkwredef
= nwritable
.n_kwredef
747 if mwriteprop
== null then
749 if nwritable
!= null then
750 mvisibility
= new_property_visibility
(modelbuilder
, nclassdef
, nwritable
.n_visibility
)
752 mvisibility
= private_visibility
754 mwriteprop
= new MMethod(mclassdef
, writename
, mvisibility
)
755 if not self.check_redef_keyword
(modelbuilder
, nclassdef
, nwkwredef
, false, mwriteprop
) then return
757 if not self.check_redef_keyword
(modelbuilder
, nclassdef
, nwkwredef
, true, mwriteprop
) then return
758 if nwritable
!= null then
759 check_redef_property_visibility
(modelbuilder
, nclassdef
, nwritable
.n_visibility
, mwriteprop
)
762 nclassdef
.mprop2npropdef
[mwriteprop
] = self
764 var mwritepropdef
= new MMethodDef(mclassdef
, mwriteprop
, self.location
)
765 self.mwritepropdef
= mwritepropdef
766 modelbuilder
.mpropdef2npropdef
[mwritepropdef
] = self
767 mwritepropdef
.mdoc
= mpropdef
.mdoc
771 redef fun build_signature
(modelbuilder
, nclassdef
)
773 var mpropdef
= self.mpropdef
774 if mpropdef
== null then return # Error thus skiped
775 var mmodule
= mpropdef
.mclassdef
.mmodule
776 var mtype
: nullable MType = null
778 var ntype
= self.n_type
779 if ntype
!= null then
780 mtype
= modelbuilder
.resolve_mtype
(nclassdef
, ntype
)
781 if mtype
== null then return
784 var nexpr
= self.n_expr
785 if mtype
== null then
786 if nexpr
!= null then
787 if nexpr
isa ANewExpr then
788 mtype
= modelbuilder
.resolve_mtype
(nclassdef
, nexpr
.n_type
)
789 else if nexpr
isa AIntExpr then
790 var cla
= modelbuilder
.try_get_mclass_by_name
(nexpr
, mmodule
, "Int")
791 if cla
!= null then mtype
= cla
.mclass_type
792 else if nexpr
isa AFloatExpr then
793 var cla
= modelbuilder
.try_get_mclass_by_name
(nexpr
, mmodule
, "Float")
794 if cla
!= null then mtype
= cla
.mclass_type
795 else if nexpr
isa ACharExpr then
796 var cla
= modelbuilder
.try_get_mclass_by_name
(nexpr
, mmodule
, "Char")
797 if cla
!= null then mtype
= cla
.mclass_type
798 else if nexpr
isa ABoolExpr then
799 var cla
= modelbuilder
.try_get_mclass_by_name
(nexpr
, mmodule
, "Bool")
800 if cla
!= null then mtype
= cla
.mclass_type
801 else if nexpr
isa ASuperstringExpr then
802 var cla
= modelbuilder
.try_get_mclass_by_name
(nexpr
, mmodule
, "String")
803 if cla
!= null then mtype
= cla
.mclass_type
804 else if nexpr
isa AStringFormExpr then
805 var cla
= modelbuilder
.try_get_mclass_by_name
(nexpr
, mmodule
, "String")
806 if cla
!= null then mtype
= cla
.mclass_type
808 modelbuilder
.error
(self, "Error: Untyped attribute {mpropdef}. Implicit typing allowed only for literals and new.")
812 modelbuilder
.error
(self, "Error: Untyped attribute {mpropdef}")
816 if nexpr
isa ANewExpr then
817 var xmtype
= modelbuilder
.resolve_mtype
(nclassdef
, nexpr
.n_type
)
818 if xmtype
== mtype
and modelbuilder
.toolcontext
.opt_warn
.value
>= 2 then
819 modelbuilder
.warning
(ntype
, "Warning: useless type definition")
824 if mtype
== null then return
826 mpropdef
.static_mtype
= mtype
828 var mreadpropdef
= self.mreadpropdef
829 if mreadpropdef
!= null then
830 var msignature
= new MSignature(new Array[MParameter], mtype
)
831 mreadpropdef
.msignature
= msignature
834 var msritepropdef
= self.mwritepropdef
835 if mwritepropdef
!= null then
838 name
= n_id
.text
.substring_from
(1)
842 var mparameter
= new MParameter(name
, mtype
, false)
843 var msignature
= new MSignature([mparameter
], null)
844 mwritepropdef
.msignature
= msignature
848 redef fun check_signature
(modelbuilder
, nclassdef
)
850 var mpropdef
= self.mpropdef
851 if mpropdef
== null then return # Error thus skiped
852 var mmodule
= mpropdef
.mclassdef
.mmodule
853 var ntype
= self.n_type
854 var mtype
= self.mpropdef
.static_mtype
855 if mtype
== null then return # Error thus skiped
857 # Lookup for signature in the precursor
858 # FIXME all precursors should be considered
859 if not mpropdef
.is_intro
then
860 var precursor_type
= mpropdef
.mproperty
.intro
.static_mtype
861 if precursor_type
== null then return
863 if mtype
!= precursor_type
then
864 modelbuilder
.error
(ntype
.as(not null), "Redef Error: Wrong static type. found {mtype}, expected {precursor_type}.")
869 # Check getter and setter
870 var meth
= self.mreadpropdef
872 self.check_method_signature
(modelbuilder
, nclassdef
, meth
)
873 var node
: nullable ANode = ntype
874 if node
== null then node
= self
875 modelbuilder
.check_visibility
(node
, mtype
, meth
)
877 meth
= self.mwritepropdef
879 self.check_method_signature
(modelbuilder
, nclassdef
, meth
)
880 var node
: nullable ANode = ntype
881 if node
== null then node
= self
882 modelbuilder
.check_visibility
(node
, mtype
, meth
)
886 private fun check_method_signature
(modelbuilder
: ModelBuilder, nclassdef
: AClassdef, mpropdef
: MMethodDef)
888 var mmodule
= mpropdef
.mclassdef
.mmodule
889 var nsig
= self.n_type
890 var mysignature
= mpropdef
.msignature
891 if mysignature
== 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 msignature
= mpropdef
.mproperty
.intro
.msignature
897 if msignature
== null then return
899 if mysignature
.arity
!= msignature
.arity
then
901 if nsig
!= null then node
= nsig
else node
= self
902 modelbuilder
.error
(node
, "Redef Error: {mysignature.arity} parameters found, {msignature.arity} expected. Signature is {mpropdef}{msignature}")
905 var precursor_ret_type
= msignature
.return_mtype
906 var ret_type
= mysignature
.return_mtype
907 if ret_type
!= null and precursor_ret_type
== null then
909 if nsig
!= null then node
= nsig
else node
= self
910 modelbuilder
.error
(node
, "Redef Error: {mpropdef.mproperty} is a procedure, not a function.")
914 if mysignature
.arity
> 0 then
915 # Check parameters types
916 for i
in [0..mysignature
.arity
[ do
917 var myt
= mysignature
.mparameters
[i
].mtype
918 var prt
= msignature
.mparameters
[i
].mtype
919 if not myt
.is_subtype
(mmodule
, nclassdef
.mclassdef
.bound_mtype
, prt
) and
920 not prt
.is_subtype
(mmodule
, nclassdef
.mclassdef
.bound_mtype
, myt
) then
922 if nsig
!= null then node
= nsig
else node
= self
923 modelbuilder
.error
(node
, "Redef Error: Wrong type for parameter `{mysignature.mparameters[i].name}'. found {myt}, expected {prt}.")
927 if precursor_ret_type
!= null then
928 if ret_type
== null then
929 # Inherit the return type
930 ret_type
= precursor_ret_type
931 else if not ret_type
.is_subtype
(mmodule
, nclassdef
.mclassdef
.bound_mtype
, precursor_ret_type
) then
933 if nsig
!= null then node
= nsig
else node
= self
934 modelbuilder
.error
(node
, "Redef Error: Wrong return type. found {ret_type}, expected {precursor_ret_type}.")
941 redef class ATypePropdef
942 redef type MPROPDEF: MVirtualTypeDef
944 redef fun build_property
(modelbuilder
, nclassdef
)
946 var mclassdef
= nclassdef
.mclassdef
.as(not null)
947 var name
= self.n_id
.text
948 var mprop
= modelbuilder
.try_get_mproperty_by_name
(self.n_id
, mclassdef
, name
)
949 if mprop
== null then
950 var mvisibility
= new_property_visibility
(modelbuilder
, nclassdef
, self.n_visibility
)
951 mprop
= new MVirtualTypeProp(mclassdef
, name
, mvisibility
)
952 for c
in name
.chars
do if c
>= 'a' and c
<= 'z' then
953 modelbuilder
.warning
(n_id
, "Warning: lowercase in the virtual type {name}")
956 if not self.check_redef_keyword
(modelbuilder
, nclassdef
, self.n_kwredef
, false, mprop
) then return
958 if not self.check_redef_keyword
(modelbuilder
, nclassdef
, self.n_kwredef
, true, mprop
) then return
959 assert mprop
isa MVirtualTypeProp
960 check_redef_property_visibility
(modelbuilder
, nclassdef
, self.n_visibility
, mprop
)
962 nclassdef
.mprop2npropdef
[mprop
] = self
964 var mpropdef
= new MVirtualTypeDef(mclassdef
, mprop
, self.location
)
965 self.mpropdef
= mpropdef
966 modelbuilder
.mpropdef2npropdef
[mpropdef
] = self
970 redef fun build_signature
(modelbuilder
, nclassdef
)
972 var mpropdef
= self.mpropdef
973 if mpropdef
== null then return # Error thus skiped
974 var mmodule
= mpropdef
.mclassdef
.mmodule
975 var mtype
: nullable MType = null
977 var ntype
= self.n_type
978 mtype
= modelbuilder
.resolve_mtype
(nclassdef
, ntype
)
979 if mtype
== null then return
981 mpropdef
.bound
= mtype
982 # print "{mpropdef}: {mtype}"
985 redef fun check_signature
(modelbuilder
, nclassdef
)
987 var mpropdef
= self.mpropdef
988 if mpropdef
== null then return # Error thus skiped
990 var bound
= self.mpropdef
.bound
991 if bound
== null then return # Error thus skiped
993 modelbuilder
.check_visibility
(n_type
.as(not null), bound
, mpropdef
)
995 # Fast case: the bound is not a formal type
996 if not bound
isa MVirtualType then return
998 var mmodule
= nclassdef
.mclassdef
.mmodule
999 var anchor
= nclassdef
.mclassdef
.bound_mtype
1001 # Slow case: progress on each resolution until: (i) we loop, or (ii) we found a non formal type
1002 var seen
= [self.mpropdef
.mproperty
.mvirtualtype
]
1004 if seen
.has
(bound
) then
1006 modelbuilder
.error
(self, "Error: circularity of virtual type definition: {seen.join(" -> ")}")
1010 var next
= bound
.lookup_bound
(mmodule
, anchor
)
1011 if not next
isa MVirtualType then break