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 set_doc
(mpropdef
: MPropDef)
243 var ndoc
= self.n_doc
244 if ndoc
!= null then mpropdef
.mdoc
= ndoc
.to_mdoc
247 private fun check_redef_property_visibility
(modelbuilder
: ModelBuilder, nclassdef
: AClassdef, nvisibility
: nullable AVisibility, mprop
: MProperty)
249 if nvisibility
== null then return
250 var mvisibility
= nvisibility
.mvisibility
251 if mvisibility
!= mprop
.visibility
and mvisibility
!= public_visibility
then
252 modelbuilder
.error
(nvisibility
, "Error: redefinition changed the visibility from a {mprop.visibility} to a {mvisibility}")
256 private fun check_redef_keyword
(modelbuilder
: ModelBuilder, nclassdef
: AClassdef, kwredef
: nullable Token, need_redef
: Bool, mprop
: MProperty): Bool
258 if nclassdef
.mprop2npropdef
.has_key
(mprop
) then
259 modelbuilder
.error
(self, "Error: A property {mprop} is already defined in class {nclassdef.mclassdef.mclass}.")
262 if kwredef
== null then
264 modelbuilder
.error
(self, "Redef error: {nclassdef.mclassdef.mclass}::{mprop.name} is an inherited property. To redefine it, add the redef keyword.")
268 if not need_redef
then
269 modelbuilder
.error
(self, "Error: No property {nclassdef.mclassdef.mclass}::{mprop.name} is inherited. Remove the redef keyword to define a new property.")
278 redef class ASignature
279 # Is the model builder has correctly visited the signature
280 var is_visited
= false
281 # Names of parameters from the AST
282 # REQUIRE: is_visited
283 var param_names
= new Array[String]
284 # Types of parameters from the AST
285 # REQUIRE: is_visited
286 var param_types
= new Array[MType]
287 # Rank of the vararg (of -1 if none)
288 # REQUIRE: is_visited
289 var vararg_rank
: Int = -1
291 var ret_type
: nullable MType = null
293 # Visit and fill information about a signature
294 private fun visit_signature
(modelbuilder
: ModelBuilder, nclassdef
: AClassdef): Bool
296 var param_names
= self.param_names
297 var param_types
= self.param_types
298 for np
in self.n_params
do
299 param_names
.add
(np
.n_id
.text
)
300 var ntype
= np
.n_type
301 if ntype
!= null then
302 var mtype
= modelbuilder
.resolve_mtype
(nclassdef
, ntype
)
303 if mtype
== null then return false # Skip error
304 for i
in [0..param_names
.length-param_types
.length
[ do
305 param_types
.add
(mtype
)
307 if np
.n_dotdotdot
!= null then
308 if self.vararg_rank
!= -1 then
309 modelbuilder
.error
(np
, "Error: {param_names[self.vararg_rank]} is already a vararg")
312 self.vararg_rank
= param_names
.length
- 1
317 var ntype
= self.n_type
318 if ntype
!= null then
319 self.ret_type
= modelbuilder
.resolve_mtype
(nclassdef
, ntype
)
320 if self.ret_type
== null then return false # Skip errir
323 self.is_visited
= true
327 # Build a visited signature
328 fun build_signature
(modelbuilder
: ModelBuilder, nclassdef
: AClassdef): nullable MSignature
330 if param_names
.length
!= param_types
.length
then
331 # Some parameters are typed, other parameters are not typed.
332 modelbuilder
.error
(self.n_params
[param_types
.length
], "Error: Untyped parameter `{param_names[param_types.length]}'.")
336 var mparameters
= new Array[MParameter]
337 for i
in [0..param_names
.length
[ do
338 var mparameter
= new MParameter(param_names
[i
], param_types
[i
], i
== vararg_rank
)
339 self.n_params
[i
].mparameter
= mparameter
340 mparameters
.add
(mparameter
)
343 var msignature
= new MSignature(mparameters
, ret_type
)
349 # The associated mparameter if any
350 var mparameter
: nullable MParameter = null
353 redef class AMethPropdef
354 redef type MPROPDEF: MMethodDef
356 redef fun build_property
(modelbuilder
, nclassdef
)
358 var is_init
= self isa AInitPropdef
359 var mclassdef
= nclassdef
.mclassdef
.as(not null)
361 var amethodid
= self.n_methid
363 if amethodid
== null then
364 if self isa AMainMethPropdef then
367 else if self isa AConcreteInitPropdef then
369 name_node
= self.n_kwinit
370 else if self isa AExternInitPropdef then
372 name_node
= self.n_kwnew
376 else if amethodid
isa AIdMethid then
377 name
= amethodid
.n_id
.text
378 name_node
= amethodid
380 # operator, bracket or assign
381 name
= amethodid
.collect_text
382 name_node
= amethodid
384 if name
== "-" and self.n_signature
.n_params
.length
== 0 then
389 var mprop
: nullable MMethod = null
390 if not is_init
or n_kwredef
!= null then mprop
= modelbuilder
.try_get_mproperty_by_name
(name_node
, mclassdef
, name
).as(nullable MMethod)
391 if mprop
== null then
392 var mvisibility
= new_property_visibility
(modelbuilder
, nclassdef
, self.n_visibility
)
393 mprop
= new MMethod(mclassdef
, name
, mvisibility
)
394 mprop
.is_init
= is_init
395 mprop
.is_new
= self isa AExternInitPropdef
396 if not self.check_redef_keyword
(modelbuilder
, nclassdef
, n_kwredef
, false, mprop
) then return
398 if n_kwredef
== null then
399 if self isa AMainMethPropdef then
402 if not self.check_redef_keyword
(modelbuilder
, nclassdef
, n_kwredef
, true, mprop
) then return
405 check_redef_property_visibility
(modelbuilder
, nclassdef
, self.n_visibility
, mprop
)
407 nclassdef
.mprop2npropdef
[mprop
] = self
409 var mpropdef
= new MMethodDef(mclassdef
, mprop
, self.location
)
411 if mclassdef
.propdef_names
.has
(mprop
.name
) then
412 var loc
: nullable Location = null
413 for i
in mclassdef
.mpropdefs
do
414 if i
.mproperty
.name
== mprop
.name
then
419 if loc
== null then abort
420 modelbuilder
.error
(self, "Error: a property {mprop} is already defined in class {mclassdef.mclass} at {loc}")
423 mclassdef
.propdef_names
.add
(mpropdef
.mproperty
.name
)
427 self.mpropdef
= mpropdef
428 modelbuilder
.mpropdef2npropdef
[mpropdef
] = self
429 if mpropdef
.is_intro
then
430 modelbuilder
.toolcontext
.info
("{mpropdef} introduces new method {mprop.full_name}", 3)
432 modelbuilder
.toolcontext
.info
("{mpropdef} redefines method {mprop.full_name}", 3)
436 redef fun build_signature
(modelbuilder
, nclassdef
)
438 var mpropdef
= self.mpropdef
439 if mpropdef
== null then return # Error thus skiped
440 var mmodule
= mpropdef
.mclassdef
.mmodule
441 var nsig
= self.n_signature
443 # Retrieve info from the signature AST
444 var param_names
= new Array[String] # Names of parameters from the AST
445 var param_types
= new Array[MType] # Types of parameters from the AST
447 var ret_type
: nullable MType = null # Return type from the AST
449 if not nsig
.visit_signature
(modelbuilder
, nclassdef
) then return
450 param_names
= nsig
.param_names
451 param_types
= nsig
.param_types
452 vararg_rank
= nsig
.vararg_rank
453 ret_type
= nsig
.ret_type
456 # Look for some signature to inherit
457 # FIXME: do not inherit from the intro, but from the most specific
458 var msignature
: nullable MSignature = null
459 if not mpropdef
.is_intro
then
460 msignature
= mpropdef
.mproperty
.intro
.msignature
461 if msignature
== null then return # Skip error
463 # Check inherited signature arity
464 if param_names
.length
!= msignature
.arity
then
466 if nsig
!= null then node
= nsig
else node
= self
467 modelbuilder
.error
(node
, "Redef error: {mpropdef} redefines {mpropdef.mproperty.intro} with {param_names.length} parameter(s), {msignature.arity} expected. Signature is {mpropdef}{msignature}")
470 else if mpropdef
.mproperty
.is_init
then
471 # FIXME UGLY: inherit signature from a super-constructor
472 for msupertype
in nclassdef
.mclassdef
.supertypes
do
473 msupertype
= msupertype
.anchor_to
(mmodule
, nclassdef
.mclassdef
.bound_mtype
)
474 var candidate
= modelbuilder
.try_get_mproperty_by_name2
(self, mmodule
, msupertype
, mpropdef
.mproperty
.name
)
475 if candidate
!= null then
476 if msignature
== null then
477 msignature
= candidate
.intro
.as(MMethodDef).msignature
484 # Inherit the signature
485 if msignature
!= null and param_names
.length
!= param_types
.length
and param_names
.length
== msignature
.arity
and param_types
.length
== 0 then
486 # Parameters are untyped, thus inherit them
487 param_types
= new Array[MType]
488 for mparameter
in msignature
.mparameters
do
489 param_types
.add
(mparameter
.mtype
)
491 vararg_rank
= msignature
.vararg_rank
493 if msignature
!= null and ret_type
== null then
494 ret_type
= msignature
.return_mtype
497 if param_names
.length
!= param_types
.length
then
498 # Some parameters are typed, other parameters are not typed.
499 modelbuilder
.error
(nsig
.n_params
[param_types
.length
], "Error: Untyped parameter `{param_names[param_types.length]}'.")
503 var mparameters
= new Array[MParameter]
504 for i
in [0..param_names
.length
[ do
505 var mparameter
= new MParameter(param_names
[i
], param_types
[i
], i
== vararg_rank
)
506 if nsig
!= null then nsig
.n_params
[i
].mparameter
= mparameter
507 mparameters
.add
(mparameter
)
510 msignature
= new MSignature(mparameters
, ret_type
)
511 mpropdef
.msignature
= msignature
512 mpropdef
.is_abstract
= self isa ADeferredMethPropdef
515 redef fun check_signature
(modelbuilder
, nclassdef
)
517 var mpropdef
= self.mpropdef
518 if mpropdef
== null then return # Error thus skiped
519 var mmodule
= mpropdef
.mclassdef
.mmodule
520 var nsig
= self.n_signature
521 var mysignature
= self.mpropdef
.msignature
522 if mysignature
== null then return # Error thus skiped
524 # Lookup for signature in the precursor
525 # FIXME all precursors should be considered
526 if not mpropdef
.is_intro
then
527 var msignature
= mpropdef
.mproperty
.intro
.msignature
528 if msignature
== null then return
530 var precursor_ret_type
= msignature
.return_mtype
531 var ret_type
= mysignature
.return_mtype
532 if ret_type
!= null and precursor_ret_type
== null then
533 modelbuilder
.error
(nsig
.n_type
.as(not null), "Redef Error: {mpropdef.mproperty} is a procedure, not a function.")
537 if mysignature
.arity
> 0 then
538 # Check parameters types
539 for i
in [0..mysignature
.arity
[ do
540 var myt
= mysignature
.mparameters
[i
].mtype
541 var prt
= msignature
.mparameters
[i
].mtype
542 if not myt
.is_subtype
(mmodule
, nclassdef
.mclassdef
.bound_mtype
, prt
) or
543 not prt
.is_subtype
(mmodule
, nclassdef
.mclassdef
.bound_mtype
, myt
) then
544 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}.")
548 if precursor_ret_type
!= null then
549 if ret_type
== null then
550 # Inherit the return type
551 ret_type
= precursor_ret_type
552 else if not ret_type
.is_subtype
(mmodule
, nclassdef
.mclassdef
.bound_mtype
, precursor_ret_type
) then
553 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}.")
560 redef class AAttrPropdef
561 redef type MPROPDEF: MAttributeDef
563 # The associated getter (read accessor) if any
564 var mreadpropdef
: nullable MMethodDef writable
565 # The associated setter (write accessor) if any
566 var mwritepropdef
: nullable MMethodDef writable
567 redef fun build_property
(modelbuilder
, nclassdef
)
569 var mclassdef
= nclassdef
.mclassdef
.as(not null)
570 var mclass
= mclassdef
.mclass
573 if self.n_id
!= null then
574 name
= self.n_id
.text
576 name
= self.n_id2
.text
579 if mclass
.kind
== interface_kind
or mclassdef
.mclass
.kind
== enum_kind
then
580 modelbuilder
.error
(self, "Error: Attempt to define attribute {name} in the interface {mclass}.")
581 else if mclass
.kind
== enum_kind
then
582 modelbuilder
.error
(self, "Error: Attempt to define attribute {name} in the enum class {mclass}.")
583 else if mclass
.kind
== extern_kind
then
584 modelbuilder
.error
(self, "Error: Attempt to define attribute {name} in the extern class {mclass}.")
589 # Old attribute style
590 var mprop
= modelbuilder
.try_get_mproperty_by_name
(nid
, mclassdef
, name
)
591 if mprop
== null then
592 var mvisibility
= new_property_visibility
(modelbuilder
, nclassdef
, self.n_visibility
)
593 mprop
= new MAttribute(mclassdef
, name
, mvisibility
)
594 if not self.check_redef_keyword
(modelbuilder
, nclassdef
, self.n_kwredef
, false, mprop
) then return
596 assert mprop
isa MAttribute
597 check_redef_property_visibility
(modelbuilder
, nclassdef
, self.n_visibility
, mprop
)
598 if not self.check_redef_keyword
(modelbuilder
, nclassdef
, self.n_kwredef
, true, mprop
) then return
600 nclassdef
.mprop2npropdef
[mprop
] = self
602 var mpropdef
= new MAttributeDef(mclassdef
, mprop
, self.location
)
603 self.mpropdef
= mpropdef
604 modelbuilder
.mpropdef2npropdef
[mpropdef
] = self
607 var nreadable
= self.n_readable
608 if nreadable
!= null then
609 var readname
= name
.substring_from
(1)
610 var mreadprop
= modelbuilder
.try_get_mproperty_by_name
(nid
, mclassdef
, readname
).as(nullable MMethod)
611 if mreadprop
== null then
612 var mvisibility
= new_property_visibility
(modelbuilder
, nclassdef
, nreadable
.n_visibility
)
613 mreadprop
= new MMethod(mclassdef
, readname
, mvisibility
)
614 if not self.check_redef_keyword
(modelbuilder
, nclassdef
, nreadable
.n_kwredef
, false, mreadprop
) then return
616 if not self.check_redef_keyword
(modelbuilder
, nclassdef
, nreadable
.n_kwredef
, true, mreadprop
) then return
617 check_redef_property_visibility
(modelbuilder
, nclassdef
, nreadable
.n_visibility
, mreadprop
)
619 nclassdef
.mprop2npropdef
[mreadprop
] = self
621 var mreadpropdef
= new MMethodDef(mclassdef
, mreadprop
, self.location
)
622 self.mreadpropdef
= mreadpropdef
623 modelbuilder
.mpropdef2npropdef
[mreadpropdef
] = self
624 mreadpropdef
.mdoc
= mpropdef
.mdoc
627 var nwritable
= self.n_writable
628 if nwritable
!= null then
629 var writename
= name
.substring_from
(1) + "="
630 var mwriteprop
= modelbuilder
.try_get_mproperty_by_name
(nid
, mclassdef
, writename
).as(nullable MMethod)
631 if mwriteprop
== null then
632 var mvisibility
= new_property_visibility
(modelbuilder
, nclassdef
, nwritable
.n_visibility
)
633 mwriteprop
= new MMethod(mclassdef
, writename
, mvisibility
)
634 if not self.check_redef_keyword
(modelbuilder
, nclassdef
, nwritable
.n_kwredef
, false, mwriteprop
) then return
636 if not self.check_redef_keyword
(modelbuilder
, nclassdef
, nwritable
.n_kwredef
, true, mwriteprop
) then return
637 check_redef_property_visibility
(modelbuilder
, nclassdef
, nwritable
.n_visibility
, mwriteprop
)
639 nclassdef
.mprop2npropdef
[mwriteprop
] = self
641 var mwritepropdef
= new MMethodDef(mclassdef
, mwriteprop
, self.location
)
642 self.mwritepropdef
= mwritepropdef
643 modelbuilder
.mpropdef2npropdef
[mwritepropdef
] = self
644 mwritepropdef
.mdoc
= mpropdef
.mdoc
647 # New attribute style
648 var nid2
= self.n_id2
.as(not null)
649 var mprop
= new MAttribute(mclassdef
, "@" + name
, none_visibility
)
650 var mpropdef
= new MAttributeDef(mclassdef
, mprop
, self.location
)
651 self.mpropdef
= mpropdef
652 modelbuilder
.mpropdef2npropdef
[mpropdef
] = self
656 var mreadprop
= modelbuilder
.try_get_mproperty_by_name
(nid2
, mclassdef
, readname
).as(nullable MMethod)
657 if mreadprop
== null then
658 var mvisibility
= new_property_visibility
(modelbuilder
, nclassdef
, self.n_visibility
)
659 mreadprop
= new MMethod(mclassdef
, readname
, mvisibility
)
660 if not self.check_redef_keyword
(modelbuilder
, nclassdef
, n_kwredef
, false, mreadprop
) then return
662 if not self.check_redef_keyword
(modelbuilder
, nclassdef
, n_kwredef
, true, mreadprop
) then return
663 check_redef_property_visibility
(modelbuilder
, nclassdef
, self.n_visibility
, mreadprop
)
665 nclassdef
.mprop2npropdef
[mreadprop
] = self
667 var mreadpropdef
= new MMethodDef(mclassdef
, mreadprop
, self.location
)
668 self.mreadpropdef
= mreadpropdef
669 modelbuilder
.mpropdef2npropdef
[mreadpropdef
] = self
670 mreadpropdef
.mdoc
= mpropdef
.mdoc
672 var writename
= name
+ "="
673 var nwritable
= self.n_writable
674 var mwriteprop
= modelbuilder
.try_get_mproperty_by_name
(nid2
, mclassdef
, writename
).as(nullable MMethod)
675 var nwkwredef
: nullable Token = null
676 if nwritable
!= null then nwkwredef
= nwritable
.n_kwredef
677 if mwriteprop
== null then
679 if nwritable
!= null then
680 mvisibility
= new_property_visibility
(modelbuilder
, nclassdef
, nwritable
.n_visibility
)
682 mvisibility
= private_visibility
684 mwriteprop
= new MMethod(mclassdef
, writename
, mvisibility
)
685 if not self.check_redef_keyword
(modelbuilder
, nclassdef
, nwkwredef
, false, mwriteprop
) then return
687 if not self.check_redef_keyword
(modelbuilder
, nclassdef
, nwkwredef
, true, mwriteprop
) then return
688 if nwritable
!= null then
689 check_redef_property_visibility
(modelbuilder
, nclassdef
, nwritable
.n_visibility
, mwriteprop
)
692 nclassdef
.mprop2npropdef
[mwriteprop
] = self
694 var mwritepropdef
= new MMethodDef(mclassdef
, mwriteprop
, self.location
)
695 self.mwritepropdef
= mwritepropdef
696 modelbuilder
.mpropdef2npropdef
[mwritepropdef
] = self
697 mwritepropdef
.mdoc
= mpropdef
.mdoc
701 redef fun build_signature
(modelbuilder
, nclassdef
)
703 var mpropdef
= self.mpropdef
704 if mpropdef
== null then return # Error thus skiped
705 var mmodule
= mpropdef
.mclassdef
.mmodule
706 var mtype
: nullable MType = null
708 var ntype
= self.n_type
709 if ntype
!= null then
710 mtype
= modelbuilder
.resolve_mtype
(nclassdef
, ntype
)
711 if mtype
== null then return
714 var nexpr
= self.n_expr
715 if mtype
== null then
716 if nexpr
!= null then
717 if nexpr
isa ANewExpr then
718 mtype
= modelbuilder
.resolve_mtype
(nclassdef
, nexpr
.n_type
)
719 else if nexpr
isa AIntExpr then
720 var cla
= modelbuilder
.try_get_mclass_by_name
(nexpr
, mmodule
, "Int")
721 if cla
!= null then mtype
= cla
.mclass_type
722 else if nexpr
isa AFloatExpr then
723 var cla
= modelbuilder
.try_get_mclass_by_name
(nexpr
, mmodule
, "Float")
724 if cla
!= null then mtype
= cla
.mclass_type
725 else if nexpr
isa ACharExpr then
726 var cla
= modelbuilder
.try_get_mclass_by_name
(nexpr
, mmodule
, "Char")
727 if cla
!= null then mtype
= cla
.mclass_type
728 else if nexpr
isa ABoolExpr then
729 var cla
= modelbuilder
.try_get_mclass_by_name
(nexpr
, mmodule
, "Bool")
730 if cla
!= null then mtype
= cla
.mclass_type
731 else if nexpr
isa ASuperstringExpr then
732 var cla
= modelbuilder
.try_get_mclass_by_name
(nexpr
, mmodule
, "String")
733 if cla
!= null then mtype
= cla
.mclass_type
734 else if nexpr
isa AStringFormExpr then
735 var cla
= modelbuilder
.try_get_mclass_by_name
(nexpr
, mmodule
, "String")
736 if cla
!= null then mtype
= cla
.mclass_type
738 modelbuilder
.error
(self, "Error: Untyped attribute {mpropdef}. Implicit typing allowed only for literals and new.")
742 modelbuilder
.error
(self, "Error: Untyped attribute {mpropdef}")
746 if nexpr
isa ANewExpr then
747 var xmtype
= modelbuilder
.resolve_mtype
(nclassdef
, nexpr
.n_type
)
748 if xmtype
== mtype
and modelbuilder
.toolcontext
.opt_warn
.value
>= 2 then
749 modelbuilder
.warning
(ntype
, "Warning: useless type definition")
754 if mtype
== null then return
756 mpropdef
.static_mtype
= mtype
758 var mreadpropdef
= self.mreadpropdef
759 if mreadpropdef
!= null then
760 var msignature
= new MSignature(new Array[MParameter], mtype
)
761 mreadpropdef
.msignature
= msignature
764 var msritepropdef
= self.mwritepropdef
765 if mwritepropdef
!= null then
768 name
= n_id
.text
.substring_from
(1)
772 var mparameter
= new MParameter(name
, mtype
, false)
773 var msignature
= new MSignature([mparameter
], null)
774 mwritepropdef
.msignature
= msignature
778 redef fun check_signature
(modelbuilder
, nclassdef
)
780 var mpropdef
= self.mpropdef
781 if mpropdef
== null then return # Error thus skiped
782 var mmodule
= mpropdef
.mclassdef
.mmodule
783 var ntype
= self.n_type
784 var mtype
= self.mpropdef
.static_mtype
785 if mtype
== null then return # Error thus skiped
787 # Lookup for signature in the precursor
788 # FIXME all precursors should be considered
789 if not mpropdef
.is_intro
then
790 var precursor_type
= mpropdef
.mproperty
.intro
.static_mtype
791 if precursor_type
== null then return
793 if mtype
!= precursor_type
then
794 modelbuilder
.error
(ntype
.as(not null), "Redef Error: Wrong static type. found {mtype}, expected {precursor_type}.")
799 # Check getter and setter
800 var meth
= self.mreadpropdef
801 if meth
!= null then self.check_method_signature
(modelbuilder
, nclassdef
, meth
)
802 meth
= self.mwritepropdef
803 if meth
!= null then self.check_method_signature
(modelbuilder
, nclassdef
, meth
)
806 private fun check_method_signature
(modelbuilder
: ModelBuilder, nclassdef
: AClassdef, mpropdef
: MMethodDef)
808 var mmodule
= mpropdef
.mclassdef
.mmodule
809 var nsig
= self.n_type
810 var mysignature
= mpropdef
.msignature
811 if mysignature
== null then return # Error thus skiped
813 # Lookup for signature in the precursor
814 # FIXME all precursors should be considered
815 if not mpropdef
.is_intro
then
816 var msignature
= mpropdef
.mproperty
.intro
.msignature
817 if msignature
== null then return
819 if mysignature
.arity
!= msignature
.arity
then
821 if nsig
!= null then node
= nsig
else node
= self
822 modelbuilder
.error
(node
, "Redef Error: {mysignature.arity} parameters found, {msignature.arity} expected. Signature is {mpropdef}{msignature}")
825 var precursor_ret_type
= msignature
.return_mtype
826 var ret_type
= mysignature
.return_mtype
827 if ret_type
!= null and precursor_ret_type
== null then
829 if nsig
!= null then node
= nsig
else node
= self
830 modelbuilder
.error
(node
, "Redef Error: {mpropdef.mproperty} is a procedure, not a function.")
834 if mysignature
.arity
> 0 then
835 # Check parameters types
836 for i
in [0..mysignature
.arity
[ do
837 var myt
= mysignature
.mparameters
[i
].mtype
838 var prt
= msignature
.mparameters
[i
].mtype
839 if not myt
.is_subtype
(mmodule
, nclassdef
.mclassdef
.bound_mtype
, prt
) and
840 not prt
.is_subtype
(mmodule
, nclassdef
.mclassdef
.bound_mtype
, myt
) then
842 if nsig
!= null then node
= nsig
else node
= self
843 modelbuilder
.error
(node
, "Redef Error: Wrong type for parameter `{mysignature.mparameters[i].name}'. found {myt}, expected {prt}.")
847 if precursor_ret_type
!= null then
848 if ret_type
== null then
849 # Inherit the return type
850 ret_type
= precursor_ret_type
851 else if not ret_type
.is_subtype
(mmodule
, nclassdef
.mclassdef
.bound_mtype
, precursor_ret_type
) then
853 if nsig
!= null then node
= nsig
else node
= self
854 modelbuilder
.error
(node
, "Redef Error: Wrong return type. found {ret_type}, expected {precursor_ret_type}.")
861 redef class ATypePropdef
862 redef type MPROPDEF: MVirtualTypeDef
864 redef fun build_property
(modelbuilder
, nclassdef
)
866 var mclassdef
= nclassdef
.mclassdef
.as(not null)
867 var name
= self.n_id
.text
868 var mprop
= modelbuilder
.try_get_mproperty_by_name
(self.n_id
, mclassdef
, name
)
869 if mprop
== null then
870 var mvisibility
= new_property_visibility
(modelbuilder
, nclassdef
, self.n_visibility
)
871 mprop
= new MVirtualTypeProp(mclassdef
, name
, mvisibility
)
872 for c
in name
do if c
>= 'a' and c
<= 'z' then
873 modelbuilder
.warning
(n_id
, "Warning: lowercase in the virtual type {name}")
876 if not self.check_redef_keyword
(modelbuilder
, nclassdef
, self.n_kwredef
, false, mprop
) then return
878 if not self.check_redef_keyword
(modelbuilder
, nclassdef
, self.n_kwredef
, true, mprop
) then return
879 assert mprop
isa MVirtualTypeProp
880 check_redef_property_visibility
(modelbuilder
, nclassdef
, self.n_visibility
, mprop
)
882 nclassdef
.mprop2npropdef
[mprop
] = self
884 var mpropdef
= new MVirtualTypeDef(mclassdef
, mprop
, self.location
)
885 self.mpropdef
= mpropdef
889 redef fun build_signature
(modelbuilder
, nclassdef
)
891 var mpropdef
= self.mpropdef
892 if mpropdef
== null then return # Error thus skiped
893 var mmodule
= mpropdef
.mclassdef
.mmodule
894 var mtype
: nullable MType = null
896 var ntype
= self.n_type
897 mtype
= modelbuilder
.resolve_mtype
(nclassdef
, ntype
)
898 if mtype
== null then return
900 mpropdef
.bound
= mtype
901 # print "{mpropdef}: {mtype}"
904 redef fun check_signature
(modelbuilder
, nclassdef
)
906 var mpropdef
= self.mpropdef
907 if mpropdef
== null then return # Error thus skiped
909 var bound
= self.mpropdef
.bound
911 # Fast case: the bound is not a formal type
912 if not bound
isa MVirtualType then return
914 var mmodule
= nclassdef
.mclassdef
.mmodule
915 var anchor
= nclassdef
.mclassdef
.bound_mtype
917 # Slow case: progress on each resolution until: (i) we loop, or (ii) we found a non formal type
918 var seen
= [self.mpropdef
.mproperty
.mvirtualtype
]
920 if seen
.has
(bound
) then
922 modelbuilder
.error
(self, "Error: circularity of virtual type definition: {seen.join(" -> ")}")
926 var next
= bound
.lookup_bound
(mmodule
, anchor
)
927 if not next
isa MVirtualType then return