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}")
108 if combine
.is_empty
and inhc
!= null then
109 # TODO: actively inherit the consturctor
110 self.toolcontext
.info
("{mclassdef} inherits all constructors from {inhc}", 3)
111 mclassdef
.mclass
.inherit_init_from
= inhc
114 if not combine
.is_empty
and inhc
!= null then
115 self.error
(nclassdef
, "Error: Cannot provide a defaut constructor: conflict for {combine.join(", ")} and {inhc}")
119 if not combine
.is_empty
then
120 nclassdef
.super_inits
= combine
121 var mprop
= new MMethod(mclassdef
, "init", mclassdef
.mclass
.visibility
)
122 var mpropdef
= new MMethodDef(mclassdef
, mprop
, nclassdef
.location
)
123 var mparameters
= new Array[MParameter]
124 var msignature
= new MSignature(mparameters
, null)
125 mpropdef
.msignature
= msignature
127 nclassdef
.mfree_init
= mpropdef
128 self.toolcontext
.info
("{mclassdef} gets a free empty constructor {mpropdef}{msignature}", 3)
132 # Collect undefined attributes
133 var mparameters
= new Array[MParameter]
134 for npropdef
in nclassdef
.n_propdefs
do
135 if npropdef
isa AAttrPropdef and npropdef
.n_expr
== null then
136 if npropdef
.mpropdef
== null then return # Skip broken attribute
137 var paramname
= npropdef
.mpropdef
.mproperty
.name
.substring_from
(1)
138 var ret_type
= npropdef
.mpropdef
.static_mtype
139 if ret_type
== null then return
140 var mparameter
= new MParameter(paramname
, ret_type
, false)
141 mparameters
.add
(mparameter
)
145 var mprop
= new MMethod(mclassdef
, "init", mclassdef
.mclass
.visibility
)
146 var mpropdef
= new MMethodDef(mclassdef
, mprop
, nclassdef
.location
)
147 var msignature
= new MSignature(mparameters
, null)
148 mpropdef
.msignature
= msignature
150 nclassdef
.mfree_init
= mpropdef
151 self.toolcontext
.info
("{mclassdef} gets a free constructor for attributes {mpropdef}{msignature}", 3)
156 # The class whose self inherit all the constructors.
157 # 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
158 var inherit_init_from
: nullable MClass = null
161 redef class MClassDef
162 private var propdef_names
= new HashSet[String]
166 # Does the MPropDef contains a call to super or a call of a super-constructor?
167 # Subsequent phases of the frontend (esp. typing) set it if required
168 var has_supercall
: Bool writable = false
171 redef class AClassdef
172 var build_properties_is_done
: Bool = false
173 # The list of super-constructor to call at the start of the free constructor
174 # 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
175 var super_inits
: nullable Collection[MMethod] = null
177 # The free init (implicitely constructed by the class if required)
178 var mfree_init
: nullable MMethodDef = null
180 # What is the `APropdef` associated to a `MProperty`?
181 # Used to check multiple definition of a property.
182 var mprop2npropdef
: Map[MProperty, APropdef] = new HashMap[MProperty, APropdef]
186 # Join the text of all tokens
187 # Used to get the 'real name' of method definitions.
188 fun collect_text
: String
190 var v
= new TextCollectorVisitor
197 private class TextCollectorVisitor
199 var text
: String = ""
202 if n
isa Token then text
+= n
.text
208 # The associated main model entity
209 type MPROPDEF: MPropDef
211 # The associated propdef once build by a `ModelBuilder`
212 var mpropdef
: nullable MPROPDEF writable
214 private fun build_property
(modelbuilder
: ModelBuilder, nclassdef
: AClassdef) is abstract
215 private fun build_signature
(modelbuilder
: ModelBuilder, nclassdef
: AClassdef) is abstract
216 private fun check_signature
(modelbuilder
: ModelBuilder, nclassdef
: AClassdef) is abstract
217 private fun new_property_visibility
(modelbuilder
: ModelBuilder, nclassdef
: AClassdef, nvisibility
: nullable AVisibility): MVisibility
219 var mvisibility
= public_visibility
220 if nvisibility
!= null then
221 mvisibility
= nvisibility
.mvisibility
222 if mvisibility
== intrude_visibility
then
223 modelbuilder
.error
(nvisibility
, "Error: intrude is not a legal visibility for properties.")
224 mvisibility
= public_visibility
227 if nclassdef
.mclassdef
.mclass
.visibility
== private_visibility
then
228 if mvisibility
== protected_visibility
then
229 assert nvisibility
!= null
230 modelbuilder
.error
(nvisibility
, "Error: The only legal visibility for properties in a private class is private.")
231 else if mvisibility
== private_visibility
then
232 assert nvisibility
!= null
234 # modelbuilder.warning(nvisibility, "Warning: private is unrequired since the only legal visibility for properties in a private class is private.")
236 mvisibility
= private_visibility
241 private fun check_redef_property_visibility
(modelbuilder
: ModelBuilder, nclassdef
: AClassdef, nvisibility
: nullable AVisibility, mprop
: MProperty)
243 if nvisibility
== null then return
244 var mvisibility
= nvisibility
.mvisibility
245 if mvisibility
!= mprop
.visibility
and mvisibility
!= public_visibility
then
246 modelbuilder
.error
(nvisibility
, "Error: redefinition changed the visibility from a {mprop.visibility} to a {mvisibility}")
250 private fun check_redef_keyword
(modelbuilder
: ModelBuilder, nclassdef
: AClassdef, kwredef
: nullable Token, need_redef
: Bool, mprop
: MProperty): Bool
252 if nclassdef
.mprop2npropdef
.has_key
(mprop
) then
253 modelbuilder
.error
(self, "Error: A property {mprop} is already defined in class {nclassdef.mclassdef.mclass}.")
256 if kwredef
== null then
258 modelbuilder
.error
(self, "Redef error: {nclassdef.mclassdef.mclass}::{mprop.name} is an inherited property. To redefine it, add the redef keyword.")
262 if not need_redef
then
263 modelbuilder
.error
(self, "Error: No property {nclassdef.mclassdef.mclass}::{mprop.name} is inherited. Remove the redef keyword to define a new property.")
272 redef class ASignature
273 # Is the model builder has correctly visited the signature
274 var is_visited
= false
275 # Names of parameters from the AST
276 # REQUIRE: is_visited
277 var param_names
= new Array[String]
278 # Types of parameters from the AST
279 # REQUIRE: is_visited
280 var param_types
= new Array[MType]
281 # Rank of the vararg (of -1 if none)
282 # REQUIRE: is_visited
283 var vararg_rank
: Int = -1
285 var ret_type
: nullable MType = null
287 # Visit and fill information about a signature
288 private fun visit_signature
(modelbuilder
: ModelBuilder, nclassdef
: AClassdef): Bool
290 var param_names
= self.param_names
291 var param_types
= self.param_types
292 for np
in self.n_params
do
293 param_names
.add
(np
.n_id
.text
)
294 var ntype
= np
.n_type
295 if ntype
!= null then
296 var mtype
= modelbuilder
.resolve_mtype
(nclassdef
, ntype
)
297 if mtype
== null then return false # Skip error
298 for i
in [0..param_names
.length-param_types
.length
[ do
299 param_types
.add
(mtype
)
301 if np
.n_dotdotdot
!= null then
302 if self.vararg_rank
!= -1 then
303 modelbuilder
.error
(np
, "Error: {param_names[self.vararg_rank]} is already a vararg")
306 self.vararg_rank
= param_names
.length
- 1
311 var ntype
= self.n_type
312 if ntype
!= null then
313 self.ret_type
= modelbuilder
.resolve_mtype
(nclassdef
, ntype
)
314 if self.ret_type
== null then return false # Skip errir
317 self.is_visited
= true
321 # Build a visited signature
322 fun build_signature
(modelbuilder
: ModelBuilder, nclassdef
: AClassdef): nullable MSignature
324 if param_names
.length
!= param_types
.length
then
325 # Some parameters are typed, other parameters are not typed.
326 modelbuilder
.error
(self.n_params
[param_types
.length
], "Error: Untyped parameter `{param_names[param_types.length]}'.")
330 var mparameters
= new Array[MParameter]
331 for i
in [0..param_names
.length
[ do
332 var mparameter
= new MParameter(param_names
[i
], param_types
[i
], i
== vararg_rank
)
333 self.n_params
[i
].mparameter
= mparameter
334 mparameters
.add
(mparameter
)
337 var msignature
= new MSignature(mparameters
, ret_type
)
343 # The associated mparameter if any
344 var mparameter
: nullable MParameter = null
347 redef class AMethPropdef
348 redef type MPROPDEF: MMethodDef
350 redef fun build_property
(modelbuilder
, nclassdef
)
352 var is_init
= self isa AInitPropdef
353 var mclassdef
= nclassdef
.mclassdef
.as(not null)
355 var amethodid
= self.n_methid
357 if amethodid
== null then
358 if self isa AMainMethPropdef then
361 else if self isa AConcreteInitPropdef then
363 name_node
= self.n_kwinit
364 else if self isa AExternInitPropdef then
366 name_node
= self.n_kwnew
370 else if amethodid
isa AIdMethid then
371 name
= amethodid
.n_id
.text
372 name_node
= amethodid
374 # operator, bracket or assign
375 name
= amethodid
.collect_text
376 name_node
= amethodid
378 if name
== "-" and self.n_signature
.n_params
.length
== 0 then
383 var mprop
: nullable MMethod = null
384 if not is_init
or n_kwredef
!= null then mprop
= modelbuilder
.try_get_mproperty_by_name
(name_node
, mclassdef
, name
).as(nullable MMethod)
385 if mprop
== null then
386 var mvisibility
= new_property_visibility
(modelbuilder
, nclassdef
, self.n_visibility
)
387 mprop
= new MMethod(mclassdef
, name
, mvisibility
)
388 mprop
.is_init
= is_init
389 mprop
.is_new
= self isa AExternInitPropdef
390 if not self.check_redef_keyword
(modelbuilder
, nclassdef
, n_kwredef
, false, mprop
) then return
392 if n_kwredef
== null then
393 if self isa AMainMethPropdef then
396 if not self.check_redef_keyword
(modelbuilder
, nclassdef
, n_kwredef
, true, mprop
) then return
399 check_redef_property_visibility
(modelbuilder
, nclassdef
, self.n_visibility
, mprop
)
401 nclassdef
.mprop2npropdef
[mprop
] = self
403 var mpropdef
= new MMethodDef(mclassdef
, mprop
, self.location
)
405 if mclassdef
.propdef_names
.has
(mprop
.name
) then
406 var loc
: nullable Location = null
407 for i
in mclassdef
.mpropdefs
do
408 if i
.mproperty
.name
== mprop
.name
then
413 if loc
== null then abort
414 modelbuilder
.error
(self, "Error: a property {mprop} is already defined in class {mclassdef.mclass} at {loc}")
417 mclassdef
.propdef_names
.add
(mpropdef
.mproperty
.name
)
419 self.mpropdef
= mpropdef
420 modelbuilder
.mpropdef2npropdef
[mpropdef
] = self
421 if mpropdef
.is_intro
then
422 modelbuilder
.toolcontext
.info
("{mpropdef} introduces new method {mprop.full_name}", 3)
424 modelbuilder
.toolcontext
.info
("{mpropdef} redefines method {mprop.full_name}", 3)
428 redef fun build_signature
(modelbuilder
, nclassdef
)
430 var mpropdef
= self.mpropdef
431 if mpropdef
== null then return # Error thus skiped
432 var mmodule
= mpropdef
.mclassdef
.mmodule
433 var nsig
= self.n_signature
435 # Retrieve info from the signature AST
436 var param_names
= new Array[String] # Names of parameters from the AST
437 var param_types
= new Array[MType] # Types of parameters from the AST
439 var ret_type
: nullable MType = null # Return type from the AST
441 if not nsig
.visit_signature
(modelbuilder
, nclassdef
) then return
442 param_names
= nsig
.param_names
443 param_types
= nsig
.param_types
444 vararg_rank
= nsig
.vararg_rank
445 ret_type
= nsig
.ret_type
448 # Look for some signature to inherit
449 # FIXME: do not inherit from the intro, but from the most specific
450 var msignature
: nullable MSignature = null
451 if not mpropdef
.is_intro
then
452 msignature
= mpropdef
.mproperty
.intro
.msignature
453 if msignature
== null then return # Skip error
455 # Check inherited signature arity
456 if param_names
.length
!= msignature
.arity
then
458 if nsig
!= null then node
= nsig
else node
= self
459 modelbuilder
.error
(node
, "Redef error: {mpropdef} redefines {mpropdef.mproperty.intro} with {param_names.length} parameter(s), {msignature.arity} expected. Signature is {mpropdef}{msignature}")
462 else if mpropdef
.mproperty
.is_init
then
463 # FIXME UGLY: inherit signature from a super-constructor
464 for msupertype
in nclassdef
.mclassdef
.supertypes
do
465 msupertype
= msupertype
.anchor_to
(mmodule
, nclassdef
.mclassdef
.bound_mtype
)
466 var candidate
= modelbuilder
.try_get_mproperty_by_name2
(self, mmodule
, msupertype
, mpropdef
.mproperty
.name
)
467 if candidate
!= null then
468 if msignature
== null then
469 msignature
= candidate
.intro
.as(MMethodDef).msignature
476 # Inherit the signature
477 if msignature
!= null and param_names
.length
!= param_types
.length
and param_names
.length
== msignature
.arity
and param_types
.length
== 0 then
478 # Parameters are untyped, thus inherit them
479 param_types
= new Array[MType]
480 for mparameter
in msignature
.mparameters
do
481 param_types
.add
(mparameter
.mtype
)
483 vararg_rank
= msignature
.vararg_rank
485 if msignature
!= null and ret_type
== null then
486 ret_type
= msignature
.return_mtype
489 if param_names
.length
!= param_types
.length
then
490 # Some parameters are typed, other parameters are not typed.
491 modelbuilder
.error
(nsig
.n_params
[param_types
.length
], "Error: Untyped parameter `{param_names[param_types.length]}'.")
495 var mparameters
= new Array[MParameter]
496 for i
in [0..param_names
.length
[ do
497 var mparameter
= new MParameter(param_names
[i
], param_types
[i
], i
== vararg_rank
)
498 if nsig
!= null then nsig
.n_params
[i
].mparameter
= mparameter
499 mparameters
.add
(mparameter
)
502 msignature
= new MSignature(mparameters
, ret_type
)
503 mpropdef
.msignature
= msignature
504 mpropdef
.is_abstract
= self isa ADeferredMethPropdef
507 redef fun check_signature
(modelbuilder
, nclassdef
)
509 var mpropdef
= self.mpropdef
510 if mpropdef
== null then return # Error thus skiped
511 var mmodule
= mpropdef
.mclassdef
.mmodule
512 var nsig
= self.n_signature
513 var mysignature
= self.mpropdef
.msignature
514 if mysignature
== null then return # Error thus skiped
516 # Lookup for signature in the precursor
517 # FIXME all precursors should be considered
518 if not mpropdef
.is_intro
then
519 var msignature
= mpropdef
.mproperty
.intro
.msignature
520 if msignature
== null then return
522 var precursor_ret_type
= msignature
.return_mtype
523 var ret_type
= mysignature
.return_mtype
524 if ret_type
!= null and precursor_ret_type
== null then
525 modelbuilder
.error
(nsig
.n_type
.as(not null), "Redef Error: {mpropdef.mproperty} is a procedure, not a function.")
529 if mysignature
.arity
> 0 then
530 # Check parameters types
531 for i
in [0..mysignature
.arity
[ do
532 var myt
= mysignature
.mparameters
[i
].mtype
533 var prt
= msignature
.mparameters
[i
].mtype
534 if not myt
.is_subtype
(mmodule
, nclassdef
.mclassdef
.bound_mtype
, prt
) or
535 not prt
.is_subtype
(mmodule
, nclassdef
.mclassdef
.bound_mtype
, myt
) then
536 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}.")
540 if precursor_ret_type
!= null then
541 if ret_type
== null then
542 # Inherit the return type
543 ret_type
= precursor_ret_type
544 else if not ret_type
.is_subtype
(mmodule
, nclassdef
.mclassdef
.bound_mtype
, precursor_ret_type
) then
545 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}.")
552 redef class AAttrPropdef
553 redef type MPROPDEF: MAttributeDef
555 # The associated getter (read accessor) if any
556 var mreadpropdef
: nullable MMethodDef writable
557 # The associated setter (write accessor) if any
558 var mwritepropdef
: nullable MMethodDef writable
559 redef fun build_property
(modelbuilder
, nclassdef
)
561 var mclassdef
= nclassdef
.mclassdef
.as(not null)
562 var mclass
= mclassdef
.mclass
565 if self.n_id
!= null then
566 name
= self.n_id
.text
568 name
= self.n_id2
.text
571 if mclass
.kind
== interface_kind
or mclassdef
.mclass
.kind
== enum_kind
then
572 modelbuilder
.error
(self, "Error: Attempt to define attribute {name} in the interface {mclass}.")
573 else if mclass
.kind
== enum_kind
then
574 modelbuilder
.error
(self, "Error: Attempt to define attribute {name} in the enum class {mclass}.")
575 else if mclass
.kind
== extern_kind
then
576 modelbuilder
.error
(self, "Error: Attempt to define attribute {name} in the extern class {mclass}.")
581 # Old attribute style
582 var mprop
= modelbuilder
.try_get_mproperty_by_name
(nid
, mclassdef
, name
)
583 if mprop
== null then
584 var mvisibility
= new_property_visibility
(modelbuilder
, nclassdef
, self.n_visibility
)
585 mprop
= new MAttribute(mclassdef
, name
, mvisibility
)
586 if not self.check_redef_keyword
(modelbuilder
, nclassdef
, self.n_kwredef
, false, mprop
) then return
588 assert mprop
isa MAttribute
589 check_redef_property_visibility
(modelbuilder
, nclassdef
, self.n_visibility
, mprop
)
590 if not self.check_redef_keyword
(modelbuilder
, nclassdef
, self.n_kwredef
, true, mprop
) then return
592 nclassdef
.mprop2npropdef
[mprop
] = self
594 var mpropdef
= new MAttributeDef(mclassdef
, mprop
, self.location
)
595 self.mpropdef
= mpropdef
596 modelbuilder
.mpropdef2npropdef
[mpropdef
] = self
598 var nreadable
= self.n_readable
599 if nreadable
!= null then
600 var readname
= name
.substring_from
(1)
601 var mreadprop
= modelbuilder
.try_get_mproperty_by_name
(nid
, mclassdef
, readname
).as(nullable MMethod)
602 if mreadprop
== null then
603 var mvisibility
= new_property_visibility
(modelbuilder
, nclassdef
, nreadable
.n_visibility
)
604 mreadprop
= new MMethod(mclassdef
, readname
, mvisibility
)
605 if not self.check_redef_keyword
(modelbuilder
, nclassdef
, nreadable
.n_kwredef
, false, mreadprop
) then return
607 if not self.check_redef_keyword
(modelbuilder
, nclassdef
, nreadable
.n_kwredef
, true, mreadprop
) then return
608 check_redef_property_visibility
(modelbuilder
, nclassdef
, nreadable
.n_visibility
, mreadprop
)
610 nclassdef
.mprop2npropdef
[mreadprop
] = self
612 var mreadpropdef
= new MMethodDef(mclassdef
, mreadprop
, self.location
)
613 self.mreadpropdef
= mreadpropdef
614 modelbuilder
.mpropdef2npropdef
[mreadpropdef
] = self
617 var nwritable
= self.n_writable
618 if nwritable
!= null then
619 var writename
= name
.substring_from
(1) + "="
620 var mwriteprop
= modelbuilder
.try_get_mproperty_by_name
(nid
, mclassdef
, writename
).as(nullable MMethod)
621 if mwriteprop
== null then
622 var mvisibility
= new_property_visibility
(modelbuilder
, nclassdef
, nwritable
.n_visibility
)
623 mwriteprop
= new MMethod(mclassdef
, writename
, mvisibility
)
624 if not self.check_redef_keyword
(modelbuilder
, nclassdef
, nwritable
.n_kwredef
, false, mwriteprop
) then return
626 if not self.check_redef_keyword
(modelbuilder
, nclassdef
, nwritable
.n_kwredef
, true, mwriteprop
) then return
627 check_redef_property_visibility
(modelbuilder
, nclassdef
, nwritable
.n_visibility
, mwriteprop
)
629 nclassdef
.mprop2npropdef
[mwriteprop
] = self
631 var mwritepropdef
= new MMethodDef(mclassdef
, mwriteprop
, self.location
)
632 self.mwritepropdef
= mwritepropdef
633 modelbuilder
.mpropdef2npropdef
[mwritepropdef
] = self
636 # New attribute style
637 var nid2
= self.n_id2
.as(not null)
638 var mprop
= new MAttribute(mclassdef
, "@" + name
, none_visibility
)
639 var mpropdef
= new MAttributeDef(mclassdef
, mprop
, self.location
)
640 self.mpropdef
= mpropdef
641 modelbuilder
.mpropdef2npropdef
[mpropdef
] = self
644 var mreadprop
= modelbuilder
.try_get_mproperty_by_name
(nid2
, mclassdef
, readname
).as(nullable MMethod)
645 if mreadprop
== null then
646 var mvisibility
= new_property_visibility
(modelbuilder
, nclassdef
, self.n_visibility
)
647 mreadprop
= new MMethod(mclassdef
, readname
, mvisibility
)
648 if not self.check_redef_keyword
(modelbuilder
, nclassdef
, n_kwredef
, false, mreadprop
) then return
650 if not self.check_redef_keyword
(modelbuilder
, nclassdef
, n_kwredef
, true, mreadprop
) then return
651 check_redef_property_visibility
(modelbuilder
, nclassdef
, self.n_visibility
, mreadprop
)
653 nclassdef
.mprop2npropdef
[mreadprop
] = self
655 var mreadpropdef
= new MMethodDef(mclassdef
, mreadprop
, self.location
)
656 self.mreadpropdef
= mreadpropdef
657 modelbuilder
.mpropdef2npropdef
[mreadpropdef
] = self
659 var writename
= name
+ "="
660 var nwritable
= self.n_writable
661 var mwriteprop
= modelbuilder
.try_get_mproperty_by_name
(nid2
, mclassdef
, writename
).as(nullable MMethod)
662 var nwkwredef
: nullable Token = null
663 if nwritable
!= null then nwkwredef
= nwritable
.n_kwredef
664 if mwriteprop
== null then
666 if nwritable
!= null then
667 mvisibility
= new_property_visibility
(modelbuilder
, nclassdef
, nwritable
.n_visibility
)
669 mvisibility
= private_visibility
671 mwriteprop
= new MMethod(mclassdef
, writename
, mvisibility
)
672 if not self.check_redef_keyword
(modelbuilder
, nclassdef
, nwkwredef
, false, mwriteprop
) then return
674 if not self.check_redef_keyword
(modelbuilder
, nclassdef
, nwkwredef
, true, mwriteprop
) then return
675 if nwritable
!= null then
676 check_redef_property_visibility
(modelbuilder
, nclassdef
, nwritable
.n_visibility
, mwriteprop
)
679 nclassdef
.mprop2npropdef
[mwriteprop
] = self
681 var mwritepropdef
= new MMethodDef(mclassdef
, mwriteprop
, self.location
)
682 self.mwritepropdef
= mwritepropdef
683 modelbuilder
.mpropdef2npropdef
[mwritepropdef
] = self
687 redef fun build_signature
(modelbuilder
, nclassdef
)
689 var mpropdef
= self.mpropdef
690 if mpropdef
== null then return # Error thus skiped
691 var mmodule
= mpropdef
.mclassdef
.mmodule
692 var mtype
: nullable MType = null
694 var ntype
= self.n_type
695 if ntype
!= null then
696 mtype
= modelbuilder
.resolve_mtype
(nclassdef
, ntype
)
697 if mtype
== null then return
700 var nexpr
= self.n_expr
701 if mtype
== null then
702 if nexpr
!= null then
703 if nexpr
isa ANewExpr then
704 mtype
= modelbuilder
.resolve_mtype
(nclassdef
, nexpr
.n_type
)
705 else if nexpr
isa AIntExpr then
706 var cla
= modelbuilder
.try_get_mclass_by_name
(nexpr
, mmodule
, "Int")
707 if cla
!= null then mtype
= cla
.mclass_type
708 else if nexpr
isa AFloatExpr then
709 var cla
= modelbuilder
.try_get_mclass_by_name
(nexpr
, mmodule
, "Float")
710 if cla
!= null then mtype
= cla
.mclass_type
711 else if nexpr
isa ACharExpr then
712 var cla
= modelbuilder
.try_get_mclass_by_name
(nexpr
, mmodule
, "Char")
713 if cla
!= null then mtype
= cla
.mclass_type
714 else if nexpr
isa ABoolExpr then
715 var cla
= modelbuilder
.try_get_mclass_by_name
(nexpr
, mmodule
, "Bool")
716 if cla
!= null then mtype
= cla
.mclass_type
717 else if nexpr
isa ASuperstringExpr then
718 var cla
= modelbuilder
.try_get_mclass_by_name
(nexpr
, mmodule
, "String")
719 if cla
!= null then mtype
= cla
.mclass_type
720 else if nexpr
isa AStringFormExpr then
721 var cla
= modelbuilder
.try_get_mclass_by_name
(nexpr
, mmodule
, "String")
722 if cla
!= null then mtype
= cla
.mclass_type
724 modelbuilder
.error
(self, "Error: Untyped attribute {mpropdef}. Implicit typing allowed only for literals and new.")
728 modelbuilder
.error
(self, "Error: Untyped attribute {mpropdef}")
732 if nexpr
isa ANewExpr then
733 var xmtype
= modelbuilder
.resolve_mtype
(nclassdef
, nexpr
.n_type
)
734 if xmtype
== mtype
and modelbuilder
.toolcontext
.opt_warn
.value
>= 2 then
735 modelbuilder
.warning
(ntype
, "Warning: useless type definition")
740 if mtype
== null then return
742 mpropdef
.static_mtype
= mtype
744 var mreadpropdef
= self.mreadpropdef
745 if mreadpropdef
!= null then
746 var msignature
= new MSignature(new Array[MParameter], mtype
)
747 mreadpropdef
.msignature
= msignature
750 var msritepropdef
= self.mwritepropdef
751 if mwritepropdef
!= null then
754 name
= n_id
.text
.substring_from
(1)
758 var mparameter
= new MParameter(name
, mtype
, false)
759 var msignature
= new MSignature([mparameter
], null)
760 mwritepropdef
.msignature
= msignature
764 redef fun check_signature
(modelbuilder
, nclassdef
)
766 var mpropdef
= self.mpropdef
767 if mpropdef
== null then return # Error thus skiped
768 var mmodule
= mpropdef
.mclassdef
.mmodule
769 var ntype
= self.n_type
770 var mtype
= self.mpropdef
.static_mtype
771 if mtype
== null then return # Error thus skiped
773 # Lookup for signature in the precursor
774 # FIXME all precursors should be considered
775 if not mpropdef
.is_intro
then
776 var precursor_type
= mpropdef
.mproperty
.intro
.static_mtype
777 if precursor_type
== null then return
779 if mtype
!= precursor_type
then
780 modelbuilder
.error
(ntype
.as(not null), "Redef Error: Wrong static type. found {mtype}, expected {precursor_type}.")
785 # Check getter and setter
786 var meth
= self.mreadpropdef
787 if meth
!= null then self.check_method_signature
(modelbuilder
, nclassdef
, meth
)
788 meth
= self.mwritepropdef
789 if meth
!= null then self.check_method_signature
(modelbuilder
, nclassdef
, meth
)
792 private fun check_method_signature
(modelbuilder
: ModelBuilder, nclassdef
: AClassdef, mpropdef
: MMethodDef)
794 var mmodule
= mpropdef
.mclassdef
.mmodule
795 var nsig
= self.n_type
796 var mysignature
= mpropdef
.msignature
797 if mysignature
== null then return # Error thus skiped
799 # Lookup for signature in the precursor
800 # FIXME all precursors should be considered
801 if not mpropdef
.is_intro
then
802 var msignature
= mpropdef
.mproperty
.intro
.msignature
803 if msignature
== null then return
805 if mysignature
.arity
!= msignature
.arity
then
807 if nsig
!= null then node
= nsig
else node
= self
808 modelbuilder
.error
(node
, "Redef Error: {mysignature.arity} parameters found, {msignature.arity} expected. Signature is {mpropdef}{msignature}")
811 var precursor_ret_type
= msignature
.return_mtype
812 var ret_type
= mysignature
.return_mtype
813 if ret_type
!= null and precursor_ret_type
== null then
815 if nsig
!= null then node
= nsig
else node
= self
816 modelbuilder
.error
(node
, "Redef Error: {mpropdef.mproperty} is a procedure, not a function.")
820 if mysignature
.arity
> 0 then
821 # Check parameters types
822 for i
in [0..mysignature
.arity
[ do
823 var myt
= mysignature
.mparameters
[i
].mtype
824 var prt
= msignature
.mparameters
[i
].mtype
825 if not myt
.is_subtype
(mmodule
, nclassdef
.mclassdef
.bound_mtype
, prt
) and
826 not prt
.is_subtype
(mmodule
, nclassdef
.mclassdef
.bound_mtype
, myt
) then
828 if nsig
!= null then node
= nsig
else node
= self
829 modelbuilder
.error
(node
, "Redef Error: Wrong type for parameter `{mysignature.mparameters[i].name}'. found {myt}, expected {prt}.")
833 if precursor_ret_type
!= null then
834 if ret_type
== null then
835 # Inherit the return type
836 ret_type
= precursor_ret_type
837 else if not ret_type
.is_subtype
(mmodule
, nclassdef
.mclassdef
.bound_mtype
, precursor_ret_type
) then
839 if nsig
!= null then node
= nsig
else node
= self
840 modelbuilder
.error
(node
, "Redef Error: Wrong return type. found {ret_type}, expected {precursor_ret_type}.")
847 redef class ATypePropdef
848 redef type MPROPDEF: MVirtualTypeDef
850 redef fun build_property
(modelbuilder
, nclassdef
)
852 var mclassdef
= nclassdef
.mclassdef
.as(not null)
853 var name
= self.n_id
.text
854 var mprop
= modelbuilder
.try_get_mproperty_by_name
(self.n_id
, mclassdef
, name
)
855 if mprop
== null then
856 var mvisibility
= new_property_visibility
(modelbuilder
, nclassdef
, self.n_visibility
)
857 mprop
= new MVirtualTypeProp(mclassdef
, name
, mvisibility
)
858 for c
in name
do if c
>= 'a' and c
<= 'z' then
859 modelbuilder
.warning
(n_id
, "Warning: lowercase in the virtual type {name}")
862 if not self.check_redef_keyword
(modelbuilder
, nclassdef
, self.n_kwredef
, false, mprop
) then return
864 if not self.check_redef_keyword
(modelbuilder
, nclassdef
, self.n_kwredef
, true, mprop
) then return
865 assert mprop
isa MVirtualTypeProp
866 check_redef_property_visibility
(modelbuilder
, nclassdef
, self.n_visibility
, mprop
)
868 nclassdef
.mprop2npropdef
[mprop
] = self
870 var mpropdef
= new MVirtualTypeDef(mclassdef
, mprop
, self.location
)
871 self.mpropdef
= mpropdef
874 redef fun build_signature
(modelbuilder
, nclassdef
)
876 var mpropdef
= self.mpropdef
877 if mpropdef
== null then return # Error thus skiped
878 var mmodule
= mpropdef
.mclassdef
.mmodule
879 var mtype
: nullable MType = null
881 var ntype
= self.n_type
882 mtype
= modelbuilder
.resolve_mtype
(nclassdef
, ntype
)
883 if mtype
== null then return
885 mpropdef
.bound
= mtype
886 # print "{mpropdef}: {mtype}"
889 redef fun check_signature
(modelbuilder
, nclassdef
)
891 var mpropdef
= self.mpropdef
892 if mpropdef
== null then return # Error thus skiped
894 var bound
= self.mpropdef
.bound
896 # Fast case: the bound is not a formal type
897 if not bound
isa MVirtualType then return
899 var mmodule
= nclassdef
.mclassdef
.mmodule
900 var anchor
= nclassdef
.mclassdef
.bound_mtype
902 # Slow case: progress on each resolution until: (i) we loop, or (ii) we found a non formal type
903 var seen
= [self.mpropdef
.mproperty
.mvirtualtype
]
905 if seen
.has
(bound
) then
907 modelbuilder
.error
(self, "Error: circularity of virtual type definition: {seen.join(" -> ")}")
911 var next
= bound
.lookup_bound
(mmodule
, anchor
)
912 if not next
isa MVirtualType then return