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]
165 redef class AClassdef
166 var build_properties_is_done
: Bool = false
167 # The list of super-constructor to call at the start of the free constructor
168 # 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
169 var super_inits
: nullable Collection[MMethod] = null
171 # The free init (implicitely constructed by the class if required)
172 var mfree_init
: nullable MMethodDef = null
174 # What is the `APropdef` associated to a `MProperty`?
175 # Used to check multiple definition of a property.
176 var mprop2npropdef
: Map[MProperty, APropdef] = new HashMap[MProperty, APropdef]
180 # Join the text of all tokens
181 # Used to get the 'real name' of method definitions.
182 fun collect_text
: String
184 var v
= new TextCollectorVisitor
191 private class TextCollectorVisitor
193 var text
: String = ""
196 if n
isa Token then text
+= n
.text
202 # The associated main model entity
203 type MPROPDEF: MPropDef
205 # The associated propdef once build by a `ModelBuilder`
206 var mpropdef
: nullable MPROPDEF writable
208 private fun build_property
(modelbuilder
: ModelBuilder, nclassdef
: AClassdef) is abstract
209 private fun build_signature
(modelbuilder
: ModelBuilder, nclassdef
: AClassdef) is abstract
210 private fun check_signature
(modelbuilder
: ModelBuilder, nclassdef
: AClassdef) is abstract
211 private fun new_property_visibility
(modelbuilder
: ModelBuilder, nclassdef
: AClassdef, nvisibility
: nullable AVisibility): MVisibility
213 var mvisibility
= public_visibility
214 if nvisibility
!= null then
215 mvisibility
= nvisibility
.mvisibility
216 if mvisibility
== intrude_visibility
then
217 modelbuilder
.error
(nvisibility
, "Error: intrude is not a legal visibility for properties.")
218 mvisibility
= public_visibility
221 if nclassdef
.mclassdef
.mclass
.visibility
== private_visibility
then
222 if mvisibility
== protected_visibility
then
223 assert nvisibility
!= null
224 modelbuilder
.error
(nvisibility
, "Error: The only legal visibility for properties in a private class is private.")
225 else if mvisibility
== private_visibility
then
226 assert nvisibility
!= null
228 # modelbuilder.warning(nvisibility, "Warning: private is unrequired since the only legal visibility for properties in a private class is private.")
230 mvisibility
= private_visibility
235 private fun check_redef_property_visibility
(modelbuilder
: ModelBuilder, nclassdef
: AClassdef, nvisibility
: nullable AVisibility, mprop
: MProperty)
237 if nvisibility
== null then return
238 var mvisibility
= nvisibility
.mvisibility
239 if mvisibility
!= mprop
.visibility
and mvisibility
!= public_visibility
then
240 modelbuilder
.error
(nvisibility
, "Error: redefinition changed the visibility from a {mprop.visibility} to a {mvisibility}")
244 private fun check_redef_keyword
(modelbuilder
: ModelBuilder, nclassdef
: AClassdef, kwredef
: nullable Token, need_redef
: Bool, mprop
: MProperty): Bool
246 if nclassdef
.mprop2npropdef
.has_key
(mprop
) then
247 modelbuilder
.error
(self, "Error: A property {mprop} is already defined in class {nclassdef.mclassdef.mclass}.")
250 if kwredef
== null then
252 modelbuilder
.error
(self, "Redef error: {nclassdef.mclassdef.mclass}::{mprop.name} is an inherited property. To redefine it, add the redef keyword.")
256 if not need_redef
then
257 modelbuilder
.error
(self, "Error: No property {nclassdef.mclassdef.mclass}::{mprop.name} is inherited. Remove the redef keyword to define a new property.")
266 redef class ASignature
267 # Is the model builder has correctly visited the signature
268 var is_visited
= false
269 # Names of parameters from the AST
270 # REQUIRE: is_visited
271 var param_names
= new Array[String]
272 # Types of parameters from the AST
273 # REQUIRE: is_visited
274 var param_types
= new Array[MType]
275 # Rank of the vararg (of -1 if none)
276 # REQUIRE: is_visited
277 var vararg_rank
: Int = -1
279 var ret_type
: nullable MType = null
281 # Visit and fill information about a signature
282 private fun visit_signature
(modelbuilder
: ModelBuilder, nclassdef
: AClassdef): Bool
284 var param_names
= self.param_names
285 var param_types
= self.param_types
286 for np
in self.n_params
do
287 param_names
.add
(np
.n_id
.text
)
288 var ntype
= np
.n_type
289 if ntype
!= null then
290 var mtype
= modelbuilder
.resolve_mtype
(nclassdef
, ntype
)
291 if mtype
== null then return false # Skip error
292 for i
in [0..param_names
.length-param_types
.length
[ do
293 param_types
.add
(mtype
)
295 if np
.n_dotdotdot
!= null then
296 if self.vararg_rank
!= -1 then
297 modelbuilder
.error
(np
, "Error: {param_names[self.vararg_rank]} is already a vararg")
300 self.vararg_rank
= param_names
.length
- 1
305 var ntype
= self.n_type
306 if ntype
!= null then
307 self.ret_type
= modelbuilder
.resolve_mtype
(nclassdef
, ntype
)
308 if self.ret_type
== null then return false # Skip errir
311 self.is_visited
= true
315 # Build a visited signature
316 fun build_signature
(modelbuilder
: ModelBuilder, nclassdef
: AClassdef): nullable MSignature
318 if param_names
.length
!= param_types
.length
then
319 # Some parameters are typed, other parameters are not typed.
320 modelbuilder
.error
(self.n_params
[param_types
.length
], "Error: Untyped parameter `{param_names[param_types.length]}'.")
324 var mparameters
= new Array[MParameter]
325 for i
in [0..param_names
.length
[ do
326 var mparameter
= new MParameter(param_names
[i
], param_types
[i
], i
== vararg_rank
)
327 self.n_params
[i
].mparameter
= mparameter
328 mparameters
.add
(mparameter
)
331 var msignature
= new MSignature(mparameters
, ret_type
)
337 # The associated mparameter if any
338 var mparameter
: nullable MParameter = null
341 redef class AMethPropdef
342 redef type MPROPDEF: MMethodDef
344 redef fun build_property
(modelbuilder
, nclassdef
)
346 var is_init
= self isa AInitPropdef
347 var mclassdef
= nclassdef
.mclassdef
.as(not null)
349 var amethodid
= self.n_methid
351 if amethodid
== null then
352 if self isa AMainMethPropdef then
355 else if self isa AConcreteInitPropdef then
357 name_node
= self.n_kwinit
358 else if self isa AExternInitPropdef then
360 name_node
= self.n_kwnew
364 else if amethodid
isa AIdMethid then
365 name
= amethodid
.n_id
.text
366 name_node
= amethodid
368 # operator, bracket or assign
369 name
= amethodid
.collect_text
370 name_node
= amethodid
372 if name
== "-" and self.n_signature
.n_params
.length
== 0 then
377 var mprop
: nullable MMethod = null
378 if not is_init
or n_kwredef
!= null then mprop
= modelbuilder
.try_get_mproperty_by_name
(name_node
, mclassdef
, name
).as(nullable MMethod)
379 if mprop
== null then
380 var mvisibility
= new_property_visibility
(modelbuilder
, nclassdef
, self.n_visibility
)
381 mprop
= new MMethod(mclassdef
, name
, mvisibility
)
382 mprop
.is_init
= is_init
383 mprop
.is_new
= self isa AExternInitPropdef
384 if not self.check_redef_keyword
(modelbuilder
, nclassdef
, n_kwredef
, false, mprop
) then return
386 if n_kwredef
== null then
387 if self isa AMainMethPropdef then
390 if not self.check_redef_keyword
(modelbuilder
, nclassdef
, n_kwredef
, true, mprop
) then return
393 check_redef_property_visibility
(modelbuilder
, nclassdef
, self.n_visibility
, mprop
)
395 nclassdef
.mprop2npropdef
[mprop
] = self
397 var mpropdef
= new MMethodDef(mclassdef
, mprop
, self.location
)
399 if mclassdef
.propdef_names
.has
(mprop
.name
) then
400 var loc
: nullable Location = null
401 for i
in mclassdef
.mpropdefs
do
402 if i
.mproperty
.name
== mprop
.name
then
407 if loc
== null then abort
408 modelbuilder
.error
(self, "Error: a property {mprop} is already defined in class {mclassdef.mclass} at {loc}")
411 mclassdef
.propdef_names
.add
(mpropdef
.mproperty
.name
)
413 self.mpropdef
= mpropdef
414 modelbuilder
.mpropdef2npropdef
[mpropdef
] = self
415 if mpropdef
.is_intro
then
416 modelbuilder
.toolcontext
.info
("{mpropdef} introduces new method {mprop.full_name}", 3)
418 modelbuilder
.toolcontext
.info
("{mpropdef} redefines method {mprop.full_name}", 3)
422 redef fun build_signature
(modelbuilder
, nclassdef
)
424 var mpropdef
= self.mpropdef
425 if mpropdef
== null then return # Error thus skiped
426 var mmodule
= mpropdef
.mclassdef
.mmodule
427 var nsig
= self.n_signature
429 # Retrieve info from the signature AST
430 var param_names
= new Array[String] # Names of parameters from the AST
431 var param_types
= new Array[MType] # Types of parameters from the AST
433 var ret_type
: nullable MType = null # Return type from the AST
435 if not nsig
.visit_signature
(modelbuilder
, nclassdef
) then return
436 param_names
= nsig
.param_names
437 param_types
= nsig
.param_types
438 vararg_rank
= nsig
.vararg_rank
439 ret_type
= nsig
.ret_type
442 # Look for some signature to inherit
443 # FIXME: do not inherit from the intro, but from the most specific
444 var msignature
: nullable MSignature = null
445 if not mpropdef
.is_intro
then
446 msignature
= mpropdef
.mproperty
.intro
.msignature
447 if msignature
== null then return # Skip error
449 # Check inherited signature arity
450 if param_names
.length
!= msignature
.arity
then
452 if nsig
!= null then node
= nsig
else node
= self
453 modelbuilder
.error
(node
, "Redef error: {mpropdef} redefines {mpropdef.mproperty.intro} with {param_names.length} parameter(s), {msignature.arity} expected. Signature is {mpropdef}{msignature}")
456 else if mpropdef
.mproperty
.is_init
then
457 # FIXME UGLY: inherit signature from a super-constructor
458 for msupertype
in nclassdef
.mclassdef
.supertypes
do
459 msupertype
= msupertype
.anchor_to
(mmodule
, nclassdef
.mclassdef
.bound_mtype
)
460 var candidate
= modelbuilder
.try_get_mproperty_by_name2
(self, mmodule
, msupertype
, mpropdef
.mproperty
.name
)
461 if candidate
!= null then
462 if msignature
== null then
463 msignature
= candidate
.intro
.as(MMethodDef).msignature
470 # Inherit the signature
471 if msignature
!= null and param_names
.length
!= param_types
.length
and param_names
.length
== msignature
.arity
and param_types
.length
== 0 then
472 # Parameters are untyped, thus inherit them
473 param_types
= new Array[MType]
474 for mparameter
in msignature
.mparameters
do
475 param_types
.add
(mparameter
.mtype
)
477 vararg_rank
= msignature
.vararg_rank
479 if msignature
!= null and ret_type
== null then
480 ret_type
= msignature
.return_mtype
483 if param_names
.length
!= param_types
.length
then
484 # Some parameters are typed, other parameters are not typed.
485 modelbuilder
.error
(nsig
.n_params
[param_types
.length
], "Error: Untyped parameter `{param_names[param_types.length]}'.")
489 var mparameters
= new Array[MParameter]
490 for i
in [0..param_names
.length
[ do
491 var mparameter
= new MParameter(param_names
[i
], param_types
[i
], i
== vararg_rank
)
492 if nsig
!= null then nsig
.n_params
[i
].mparameter
= mparameter
493 mparameters
.add
(mparameter
)
496 msignature
= new MSignature(mparameters
, ret_type
)
497 mpropdef
.msignature
= msignature
498 mpropdef
.is_abstract
= self isa ADeferredMethPropdef
501 redef fun check_signature
(modelbuilder
, nclassdef
)
503 var mpropdef
= self.mpropdef
504 if mpropdef
== null then return # Error thus skiped
505 var mmodule
= mpropdef
.mclassdef
.mmodule
506 var nsig
= self.n_signature
507 var mysignature
= self.mpropdef
.msignature
508 if mysignature
== null then return # Error thus skiped
510 # Lookup for signature in the precursor
511 # FIXME all precursors should be considered
512 if not mpropdef
.is_intro
then
513 var msignature
= mpropdef
.mproperty
.intro
.msignature
514 if msignature
== null then return
516 var precursor_ret_type
= msignature
.return_mtype
517 var ret_type
= mysignature
.return_mtype
518 if ret_type
!= null and precursor_ret_type
== null then
519 modelbuilder
.error
(nsig
.n_type
.as(not null), "Redef Error: {mpropdef.mproperty} is a procedure, not a function.")
523 if mysignature
.arity
> 0 then
524 # Check parameters types
525 for i
in [0..mysignature
.arity
[ do
526 var myt
= mysignature
.mparameters
[i
].mtype
527 var prt
= msignature
.mparameters
[i
].mtype
528 if not myt
.is_subtype
(mmodule
, nclassdef
.mclassdef
.bound_mtype
, prt
) or
529 not prt
.is_subtype
(mmodule
, nclassdef
.mclassdef
.bound_mtype
, myt
) then
530 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}.")
534 if precursor_ret_type
!= null then
535 if ret_type
== null then
536 # Inherit the return type
537 ret_type
= precursor_ret_type
538 else if not ret_type
.is_subtype
(mmodule
, nclassdef
.mclassdef
.bound_mtype
, precursor_ret_type
) then
539 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}.")
546 redef class AAttrPropdef
547 redef type MPROPDEF: MAttributeDef
549 # The associated getter (read accessor) if any
550 var mreadpropdef
: nullable MMethodDef writable
551 # The associated setter (write accessor) if any
552 var mwritepropdef
: nullable MMethodDef writable
553 redef fun build_property
(modelbuilder
, nclassdef
)
555 var mclassdef
= nclassdef
.mclassdef
.as(not null)
556 var mclass
= mclassdef
.mclass
559 if self.n_id
!= null then
560 name
= self.n_id
.text
562 name
= self.n_id2
.text
565 if mclass
.kind
== interface_kind
or mclassdef
.mclass
.kind
== enum_kind
then
566 modelbuilder
.error
(self, "Error: Attempt to define attribute {name} in the interface {mclass}.")
567 else if mclass
.kind
== enum_kind
then
568 modelbuilder
.error
(self, "Error: Attempt to define attribute {name} in the enum class {mclass}.")
569 else if mclass
.kind
== extern_kind
then
570 modelbuilder
.error
(self, "Error: Attempt to define attribute {name} in the extern class {mclass}.")
575 # Old attribute style
576 var mprop
= modelbuilder
.try_get_mproperty_by_name
(nid
, mclassdef
, name
)
577 if mprop
== null then
578 var mvisibility
= new_property_visibility
(modelbuilder
, nclassdef
, self.n_visibility
)
579 mprop
= new MAttribute(mclassdef
, name
, mvisibility
)
580 if not self.check_redef_keyword
(modelbuilder
, nclassdef
, self.n_kwredef
, false, mprop
) then return
582 assert mprop
isa MAttribute
583 check_redef_property_visibility
(modelbuilder
, nclassdef
, self.n_visibility
, mprop
)
584 if not self.check_redef_keyword
(modelbuilder
, nclassdef
, self.n_kwredef
, true, mprop
) then return
586 nclassdef
.mprop2npropdef
[mprop
] = self
588 var mpropdef
= new MAttributeDef(mclassdef
, mprop
, self.location
)
589 self.mpropdef
= mpropdef
590 modelbuilder
.mpropdef2npropdef
[mpropdef
] = self
592 var nreadable
= self.n_readable
593 if nreadable
!= null then
594 var readname
= name
.substring_from
(1)
595 var mreadprop
= modelbuilder
.try_get_mproperty_by_name
(nid
, mclassdef
, readname
).as(nullable MMethod)
596 if mreadprop
== null then
597 var mvisibility
= new_property_visibility
(modelbuilder
, nclassdef
, nreadable
.n_visibility
)
598 mreadprop
= new MMethod(mclassdef
, readname
, mvisibility
)
599 if not self.check_redef_keyword
(modelbuilder
, nclassdef
, nreadable
.n_kwredef
, false, mreadprop
) then return
601 if not self.check_redef_keyword
(modelbuilder
, nclassdef
, nreadable
.n_kwredef
, true, mreadprop
) then return
602 check_redef_property_visibility
(modelbuilder
, nclassdef
, nreadable
.n_visibility
, mreadprop
)
604 nclassdef
.mprop2npropdef
[mreadprop
] = self
606 var mreadpropdef
= new MMethodDef(mclassdef
, mreadprop
, self.location
)
607 self.mreadpropdef
= mreadpropdef
608 modelbuilder
.mpropdef2npropdef
[mreadpropdef
] = self
611 var nwritable
= self.n_writable
612 if nwritable
!= null then
613 var writename
= name
.substring_from
(1) + "="
614 var mwriteprop
= modelbuilder
.try_get_mproperty_by_name
(nid
, mclassdef
, writename
).as(nullable MMethod)
615 if mwriteprop
== null then
616 var mvisibility
= new_property_visibility
(modelbuilder
, nclassdef
, nwritable
.n_visibility
)
617 mwriteprop
= new MMethod(mclassdef
, writename
, mvisibility
)
618 if not self.check_redef_keyword
(modelbuilder
, nclassdef
, nwritable
.n_kwredef
, false, mwriteprop
) then return
620 if not self.check_redef_keyword
(modelbuilder
, nclassdef
, nwritable
.n_kwredef
, true, mwriteprop
) then return
621 check_redef_property_visibility
(modelbuilder
, nclassdef
, nwritable
.n_visibility
, mwriteprop
)
623 nclassdef
.mprop2npropdef
[mwriteprop
] = self
625 var mwritepropdef
= new MMethodDef(mclassdef
, mwriteprop
, self.location
)
626 self.mwritepropdef
= mwritepropdef
627 modelbuilder
.mpropdef2npropdef
[mwritepropdef
] = self
630 # New attribute style
631 var nid2
= self.n_id2
.as(not null)
632 var mprop
= new MAttribute(mclassdef
, "@" + name
, none_visibility
)
633 var mpropdef
= new MAttributeDef(mclassdef
, mprop
, self.location
)
634 self.mpropdef
= mpropdef
635 modelbuilder
.mpropdef2npropdef
[mpropdef
] = self
638 var mreadprop
= modelbuilder
.try_get_mproperty_by_name
(nid2
, mclassdef
, readname
).as(nullable MMethod)
639 if mreadprop
== null then
640 var mvisibility
= new_property_visibility
(modelbuilder
, nclassdef
, self.n_visibility
)
641 mreadprop
= new MMethod(mclassdef
, readname
, mvisibility
)
642 if not self.check_redef_keyword
(modelbuilder
, nclassdef
, n_kwredef
, false, mreadprop
) then return
644 if not self.check_redef_keyword
(modelbuilder
, nclassdef
, n_kwredef
, true, mreadprop
) then return
645 check_redef_property_visibility
(modelbuilder
, nclassdef
, self.n_visibility
, mreadprop
)
647 nclassdef
.mprop2npropdef
[mreadprop
] = self
649 var mreadpropdef
= new MMethodDef(mclassdef
, mreadprop
, self.location
)
650 self.mreadpropdef
= mreadpropdef
651 modelbuilder
.mpropdef2npropdef
[mreadpropdef
] = self
653 var writename
= name
+ "="
654 var nwritable
= self.n_writable
655 var mwriteprop
= modelbuilder
.try_get_mproperty_by_name
(nid2
, mclassdef
, writename
).as(nullable MMethod)
656 var nwkwredef
: nullable Token = null
657 if nwritable
!= null then nwkwredef
= nwritable
.n_kwredef
658 if mwriteprop
== null then
660 if nwritable
!= null then
661 mvisibility
= new_property_visibility
(modelbuilder
, nclassdef
, nwritable
.n_visibility
)
663 mvisibility
= private_visibility
665 mwriteprop
= new MMethod(mclassdef
, writename
, mvisibility
)
666 if not self.check_redef_keyword
(modelbuilder
, nclassdef
, nwkwredef
, false, mwriteprop
) then return
668 if not self.check_redef_keyword
(modelbuilder
, nclassdef
, nwkwredef
, true, mwriteprop
) then return
669 if nwritable
!= null then
670 check_redef_property_visibility
(modelbuilder
, nclassdef
, nwritable
.n_visibility
, mwriteprop
)
673 nclassdef
.mprop2npropdef
[mwriteprop
] = self
675 var mwritepropdef
= new MMethodDef(mclassdef
, mwriteprop
, self.location
)
676 self.mwritepropdef
= mwritepropdef
677 modelbuilder
.mpropdef2npropdef
[mwritepropdef
] = self
681 redef fun build_signature
(modelbuilder
, nclassdef
)
683 var mpropdef
= self.mpropdef
684 if mpropdef
== null then return # Error thus skiped
685 var mmodule
= mpropdef
.mclassdef
.mmodule
686 var mtype
: nullable MType = null
688 var ntype
= self.n_type
689 if ntype
!= null then
690 mtype
= modelbuilder
.resolve_mtype
(nclassdef
, ntype
)
691 if mtype
== null then return
694 var nexpr
= self.n_expr
695 if mtype
== null then
696 if nexpr
!= null then
697 if nexpr
isa ANewExpr then
698 mtype
= modelbuilder
.resolve_mtype
(nclassdef
, nexpr
.n_type
)
699 else if nexpr
isa AIntExpr then
700 var cla
= modelbuilder
.try_get_mclass_by_name
(nexpr
, mmodule
, "Int")
701 if cla
!= null then mtype
= cla
.mclass_type
702 else if nexpr
isa AFloatExpr then
703 var cla
= modelbuilder
.try_get_mclass_by_name
(nexpr
, mmodule
, "Float")
704 if cla
!= null then mtype
= cla
.mclass_type
705 else if nexpr
isa ACharExpr then
706 var cla
= modelbuilder
.try_get_mclass_by_name
(nexpr
, mmodule
, "Char")
707 if cla
!= null then mtype
= cla
.mclass_type
708 else if nexpr
isa ABoolExpr then
709 var cla
= modelbuilder
.try_get_mclass_by_name
(nexpr
, mmodule
, "Bool")
710 if cla
!= null then mtype
= cla
.mclass_type
711 else if nexpr
isa ASuperstringExpr then
712 var cla
= modelbuilder
.try_get_mclass_by_name
(nexpr
, mmodule
, "String")
713 if cla
!= null then mtype
= cla
.mclass_type
714 else if nexpr
isa AStringFormExpr then
715 var cla
= modelbuilder
.try_get_mclass_by_name
(nexpr
, mmodule
, "String")
716 if cla
!= null then mtype
= cla
.mclass_type
718 modelbuilder
.error
(self, "Error: Untyped attribute {mpropdef}. Implicit typing allowed only for literals and new.")
722 modelbuilder
.error
(self, "Error: Untyped attribute {mpropdef}")
726 if nexpr
isa ANewExpr then
727 var xmtype
= modelbuilder
.resolve_mtype
(nclassdef
, nexpr
.n_type
)
728 if xmtype
== mtype
and modelbuilder
.toolcontext
.opt_warn
.value
>= 2 then
729 modelbuilder
.warning
(ntype
, "Warning: useless type definition")
734 if mtype
== null then return
736 mpropdef
.static_mtype
= mtype
738 var mreadpropdef
= self.mreadpropdef
739 if mreadpropdef
!= null then
740 var msignature
= new MSignature(new Array[MParameter], mtype
)
741 mreadpropdef
.msignature
= msignature
744 var msritepropdef
= self.mwritepropdef
745 if mwritepropdef
!= null then
748 name
= n_id
.text
.substring_from
(1)
752 var mparameter
= new MParameter(name
, mtype
, false)
753 var msignature
= new MSignature([mparameter
], null)
754 mwritepropdef
.msignature
= msignature
758 redef fun check_signature
(modelbuilder
, nclassdef
)
760 var mpropdef
= self.mpropdef
761 if mpropdef
== null then return # Error thus skiped
762 var mmodule
= mpropdef
.mclassdef
.mmodule
763 var ntype
= self.n_type
764 var mtype
= self.mpropdef
.static_mtype
765 if mtype
== null then return # Error thus skiped
767 # Lookup for signature in the precursor
768 # FIXME all precursors should be considered
769 if not mpropdef
.is_intro
then
770 var precursor_type
= mpropdef
.mproperty
.intro
.static_mtype
771 if precursor_type
== null then return
773 if mtype
!= precursor_type
then
774 modelbuilder
.error
(ntype
.as(not null), "Redef Error: Wrong static type. found {mtype}, expected {precursor_type}.")
779 # Check getter and setter
780 var meth
= self.mreadpropdef
781 if meth
!= null then self.check_method_signature
(modelbuilder
, nclassdef
, meth
)
782 meth
= self.mwritepropdef
783 if meth
!= null then self.check_method_signature
(modelbuilder
, nclassdef
, meth
)
786 private fun check_method_signature
(modelbuilder
: ModelBuilder, nclassdef
: AClassdef, mpropdef
: MMethodDef)
788 var mmodule
= mpropdef
.mclassdef
.mmodule
789 var nsig
= self.n_type
790 var mysignature
= mpropdef
.msignature
791 if mysignature
== null then return # Error thus skiped
793 # Lookup for signature in the precursor
794 # FIXME all precursors should be considered
795 if not mpropdef
.is_intro
then
796 var msignature
= mpropdef
.mproperty
.intro
.msignature
797 if msignature
== null then return
799 if mysignature
.arity
!= msignature
.arity
then
801 if nsig
!= null then node
= nsig
else node
= self
802 modelbuilder
.error
(node
, "Redef Error: {mysignature.arity} parameters found, {msignature.arity} expected. Signature is {mpropdef}{msignature}")
805 var precursor_ret_type
= msignature
.return_mtype
806 var ret_type
= mysignature
.return_mtype
807 if ret_type
!= null and precursor_ret_type
== null then
809 if nsig
!= null then node
= nsig
else node
= self
810 modelbuilder
.error
(node
, "Redef Error: {mpropdef.mproperty} is a procedure, not a function.")
814 if mysignature
.arity
> 0 then
815 # Check parameters types
816 for i
in [0..mysignature
.arity
[ do
817 var myt
= mysignature
.mparameters
[i
].mtype
818 var prt
= msignature
.mparameters
[i
].mtype
819 if not myt
.is_subtype
(mmodule
, nclassdef
.mclassdef
.bound_mtype
, prt
) and
820 not prt
.is_subtype
(mmodule
, nclassdef
.mclassdef
.bound_mtype
, myt
) then
822 if nsig
!= null then node
= nsig
else node
= self
823 modelbuilder
.error
(node
, "Redef Error: Wrong type for parameter `{mysignature.mparameters[i].name}'. found {myt}, expected {prt}.")
827 if precursor_ret_type
!= null then
828 if ret_type
== null then
829 # Inherit the return type
830 ret_type
= precursor_ret_type
831 else if not ret_type
.is_subtype
(mmodule
, nclassdef
.mclassdef
.bound_mtype
, precursor_ret_type
) then
833 if nsig
!= null then node
= nsig
else node
= self
834 modelbuilder
.error
(node
, "Redef Error: Wrong return type. found {ret_type}, expected {precursor_ret_type}.")
841 redef class ATypePropdef
842 redef type MPROPDEF: MVirtualTypeDef
844 redef fun build_property
(modelbuilder
, nclassdef
)
846 var mclassdef
= nclassdef
.mclassdef
.as(not null)
847 var name
= self.n_id
.text
848 var mprop
= modelbuilder
.try_get_mproperty_by_name
(self.n_id
, mclassdef
, name
)
849 if mprop
== null then
850 var mvisibility
= new_property_visibility
(modelbuilder
, nclassdef
, self.n_visibility
)
851 mprop
= new MVirtualTypeProp(mclassdef
, name
, mvisibility
)
852 for c
in name
do if c
>= 'a' and c
<= 'z' then
853 modelbuilder
.warning
(n_id
, "Warning: lowercase in the virtual type {name}")
856 if not self.check_redef_keyword
(modelbuilder
, nclassdef
, self.n_kwredef
, false, mprop
) then return
858 if not self.check_redef_keyword
(modelbuilder
, nclassdef
, self.n_kwredef
, true, mprop
) then return
859 assert mprop
isa MVirtualTypeProp
860 check_redef_property_visibility
(modelbuilder
, nclassdef
, self.n_visibility
, mprop
)
862 nclassdef
.mprop2npropdef
[mprop
] = self
864 var mpropdef
= new MVirtualTypeDef(mclassdef
, mprop
, self.location
)
865 self.mpropdef
= mpropdef
868 redef fun build_signature
(modelbuilder
, nclassdef
)
870 var mpropdef
= self.mpropdef
871 if mpropdef
== null then return # Error thus skiped
872 var mmodule
= mpropdef
.mclassdef
.mmodule
873 var mtype
: nullable MType = null
875 var ntype
= self.n_type
876 mtype
= modelbuilder
.resolve_mtype
(nclassdef
, ntype
)
877 if mtype
== null then return
879 mpropdef
.bound
= mtype
880 # print "{mpropdef}: {mtype}"
883 redef fun check_signature
(modelbuilder
, nclassdef
)
885 var bound
= self.mpropdef
.bound
887 # Fast case: the bound is not a formal type
888 if not bound
isa MVirtualType then return
890 var mmodule
= nclassdef
.mclassdef
.mmodule
891 var anchor
= nclassdef
.mclassdef
.bound_mtype
893 # Slow case: progress on each resolution until: (i) we loop, or (ii) we found a non formal type
894 var seen
= [self.mpropdef
.mproperty
.mvirtualtype
]
896 if seen
.has
(bound
) then
898 modelbuilder
.error
(self, "Error: circularity of virtual type definition: {seen.join(" -> ")}")
902 var next
= bound
.lookup_bound
(mmodule
, anchor
)
903 if not next
isa MVirtualType then return