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
28 redef class ToolContext
29 var modelize_property_phase
: Phase = new ModelizePropertyPhase(self, [modelize_class_phase
])
32 private class ModelizePropertyPhase
34 redef fun process_nmodule
(nmodule
)
36 for nclassdef
in nmodule
.n_classdefs
do
37 toolcontext
.modelbuilder
.build_properties
(nclassdef
)
42 redef class ModelBuilder
43 # Register the npropdef associated to each mpropdef
44 # FIXME: why not refine the MPropDef class with a nullable attribute?
45 var mpropdef2npropdef
: HashMap[MPropDef, APropdef] = new HashMap[MPropDef, APropdef]
47 # Build the properties of `nclassdef'.
48 # REQUIRE: all superclasses are built.
49 private fun build_properties
(nclassdef
: AClassdef)
51 # Force building recursively
52 if nclassdef
.build_properties_is_done
then return
53 nclassdef
.build_properties_is_done
= true
54 var mclassdef
= nclassdef
.mclassdef
.as(not null)
55 if mclassdef
.in_hierarchy
== null then return # Skip error
56 for superclassdef
in mclassdef
.in_hierarchy
.direct_greaters
do
57 build_properties
(mclassdef2nclassdef
[superclassdef
])
60 for npropdef
in nclassdef
.n_propdefs
do
61 npropdef
.build_property
(self, nclassdef
)
63 for npropdef
in nclassdef
.n_propdefs
do
64 npropdef
.build_signature
(self, nclassdef
)
66 for npropdef
in nclassdef
.n_propdefs
do
67 npropdef
.check_signature
(self, nclassdef
)
69 process_default_constructors
(nclassdef
)
72 # Introduce or inherit default constructor
73 # This is the last part of `build_properties'.
74 private fun process_default_constructors
(nclassdef
: AClassdef)
76 var mclassdef
= nclassdef
.mclassdef
.as(not null)
79 if not mclassdef
.is_intro
then return
81 # Is the class forbid constructors?
82 if not mclassdef
.mclass
.kind
.need_init
then return
84 # Is there already a constructor defined?
85 for mpropdef
in mclassdef
.mpropdefs
do
86 if not mpropdef
isa MMethodDef then continue
87 if mpropdef
.mproperty
.is_init
then return
90 if not nclassdef
isa AStdClassdef then return
92 var mmodule
= nclassdef
.mclassdef
.mmodule
93 # Do we inherit for a constructor?
94 var combine
= new Array[MMethod]
95 var inhc
: nullable MClass = null
96 for st
in mclassdef
.supertypes
do
98 if not c
.kind
.need_init
then continue
99 st
= st
.anchor_to
(mmodule
, nclassdef
.mclassdef
.bound_mtype
)
100 var candidate
= self.try_get_mproperty_by_name2
(nclassdef
, mmodule
, st
, "init").as(nullable MMethod)
101 if candidate
!= null and candidate
.intro
.msignature
.arity
== 0 then
102 combine
.add
(candidate
)
105 var inhc2
= c
.inherit_init_from
106 if inhc2
== null then inhc2
= c
107 if inhc2
== inhc
then continue
109 self.error
(nclassdef
, "Error: Cannot provide a defaut constructor: conflict for {inhc} and {c}")
114 if combine
.is_empty
and inhc
!= null then
115 # TODO: actively inherit the consturctor
116 self.toolcontext
.info
("{mclassdef} inherits all constructors from {inhc}", 3)
117 mclassdef
.mclass
.inherit_init_from
= inhc
120 if not combine
.is_empty
and inhc
!= null then
121 self.error
(nclassdef
, "Error: Cannot provide a defaut constructor: conflict for {combine.join(", ")} and {inhc}")
125 if not combine
.is_empty
then
126 nclassdef
.super_inits
= combine
127 var mprop
= new MMethod(mclassdef
, "init", mclassdef
.mclass
.visibility
)
128 var mpropdef
= new MMethodDef(mclassdef
, mprop
, nclassdef
.location
)
129 var mparameters
= new Array[MParameter]
130 var msignature
= new MSignature(mparameters
, null)
131 mpropdef
.msignature
= msignature
133 nclassdef
.mfree_init
= mpropdef
134 self.toolcontext
.info
("{mclassdef} gets a free empty constructor {mpropdef}{msignature}", 3)
138 # Collect undefined attributes
139 var mparameters
= new Array[MParameter]
140 for npropdef
in nclassdef
.n_propdefs
do
141 if npropdef
isa AAttrPropdef and npropdef
.n_expr
== null then
142 if npropdef
.mpropdef
== null then return # Skip broken attribute
143 var paramname
= npropdef
.mpropdef
.mproperty
.name
.substring_from
(1)
144 var ret_type
= npropdef
.mpropdef
.static_mtype
145 if ret_type
== null then return
146 var mparameter
= new MParameter(paramname
, ret_type
, false)
147 mparameters
.add
(mparameter
)
151 var mprop
= new MMethod(mclassdef
, "init", mclassdef
.mclass
.visibility
)
152 var mpropdef
= new MMethodDef(mclassdef
, mprop
, nclassdef
.location
)
153 var msignature
= new MSignature(mparameters
, null)
154 mpropdef
.msignature
= msignature
156 nclassdef
.mfree_init
= mpropdef
157 self.toolcontext
.info
("{mclassdef} gets a free constructor for attributes {mpropdef}{msignature}", 3)
162 # The class whose self inherit all the constructors.
163 # 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
164 var inherit_init_from
: nullable MClass = null
167 redef class AClassdef
168 var build_properties_is_done
: Bool = false
169 # The list of super-constructor to call at the start of the free constructor
170 # 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
171 var super_inits
: nullable Collection[MMethod] = null
173 # The free init (implicitely constructed by the class if required)
174 var mfree_init
: nullable MMethodDef = null
176 # What is the APropdef associated to a MProperty?
177 # Used to check multiple definition of a property.
178 var mprop2npropdef
: Map[MProperty, APropdef] = new HashMap[MProperty, APropdef]
182 # Join the text of all tokens
183 # Used to get the 'real name' of method definitions.
184 fun collect_text
: String
186 var v
= new TextCollectorVisitor
193 private class TextCollectorVisitor
195 var text
: String = ""
198 if n
isa Token then text
+= n
.text
204 private fun build_property
(modelbuilder
: ModelBuilder, nclassdef
: AClassdef)
207 private fun build_signature
(modelbuilder
: ModelBuilder, nclassdef
: AClassdef)
210 private fun check_signature
(modelbuilder
: ModelBuilder, nclassdef
: AClassdef)
213 private fun new_property_visibility
(modelbuilder
: ModelBuilder, nclassdef
: AClassdef, nvisibility
: nullable AVisibility): MVisibility
215 var mvisibility
= public_visibility
216 if nvisibility
!= null then mvisibility
= nvisibility
.mvisibility
217 if nclassdef
.mclassdef
.mclass
.visibility
== private_visibility
then
218 if mvisibility
== protected_visibility
then
219 assert nvisibility
!= null
220 modelbuilder
.error
(nvisibility
, "Error: The only legal visibility for properties in a private class is private.")
221 else if mvisibility
== private_visibility
then
222 assert nvisibility
!= null
224 # modelbuilder.warning(nvisibility, "Warning: private is unrequired since the only legal visibility for properties in a private class is private.")
226 mvisibility
= private_visibility
231 private fun check_redef_property_visibility
(modelbuilder
: ModelBuilder, nclassdef
: AClassdef, nvisibility
: nullable AVisibility, mprop
: MProperty)
233 if nvisibility
== null then return
234 var mvisibility
= nvisibility
.mvisibility
235 if mvisibility
!= mprop
.visibility
and mvisibility
!= public_visibility
then
236 modelbuilder
.error
(nvisibility
, "Error: redefinition changed the visibility from a {mprop.visibility} to a {mvisibility}")
240 private fun check_redef_keyword
(modelbuilder
: ModelBuilder, nclassdef
: AClassdef, kwredef
: nullable Token, need_redef
: Bool, mprop
: MProperty): Bool
242 if nclassdef
.mprop2npropdef
.has_key
(mprop
) then
243 modelbuilder
.error
(self, "Error: A property {mprop} is already defined in class {nclassdef.mclassdef.mclass}.")
246 if kwredef
== null then
248 modelbuilder
.error
(self, "Redef error: {nclassdef.mclassdef.mclass}::{mprop.name} is an inherited property. To redefine it, add the redef keyword.")
252 if not need_redef
then
253 modelbuilder
.error
(self, "Error: No property {nclassdef.mclassdef.mclass}::{mprop.name} is inherited. Remove the redef keyword to define a new property.")
262 redef class ASignature
263 # Is the model builder has correctly visited the signature
264 var is_visited
= false
265 # Names of parameters from the AST
266 # REQUIRE: is_visited
267 var param_names
= new Array[String]
268 # Types of parameters from the AST
269 # REQUIRE: is_visited
270 var param_types
= new Array[MType]
271 # Rank of the vararg (of -1 if none)
272 # REQUIRE: is_visited
273 var vararg_rank
: Int = -1
275 var ret_type
: nullable MType = null
277 # Visit and fill information about a signature
278 private fun visit_signature
(modelbuilder
: ModelBuilder, nclassdef
: AClassdef): Bool
280 var param_names
= self.param_names
281 var param_types
= self.param_types
282 for np
in self.n_params
do
283 param_names
.add
(np
.n_id
.text
)
284 var ntype
= np
.n_type
285 if ntype
!= null then
286 var mtype
= modelbuilder
.resolve_mtype
(nclassdef
, ntype
)
287 if mtype
== null then return false # Skip error
288 for i
in [0..param_names
.length-param_types
.length
[ do
289 param_types
.add
(mtype
)
291 if np
.n_dotdotdot
!= null then
292 if self.vararg_rank
!= -1 then
293 modelbuilder
.error
(np
, "Error: {param_names[self.vararg_rank]} is already a vararg")
296 self.vararg_rank
= param_names
.length
- 1
301 var ntype
= self.n_type
302 if ntype
!= null then
303 self.ret_type
= modelbuilder
.resolve_mtype
(nclassdef
, ntype
)
304 if self.ret_type
== null then return false # Skip errir
307 for nclosure
in self.n_closure_decls
do
308 if not nclosure
.n_signature
.visit_signature
(modelbuilder
, nclassdef
) then return false
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 mparameters
.add
(mparameter
)
330 var msignature
= new MSignature(mparameters
, ret_type
)
335 redef class AMethPropdef
336 # The associated MMethodDef once build by a `ModelBuilder'
337 var mpropdef
: nullable MMethodDef
339 # The associated super init if any
340 var super_init
: nullable MMethod
341 redef fun build_property
(modelbuilder
, nclassdef
)
343 var is_init
= self isa AInitPropdef
344 var mclassdef
= nclassdef
.mclassdef
.as(not null)
346 var amethodid
= self.n_methid
348 if amethodid
== null then
349 if self isa AMainMethPropdef then
352 else if self isa AConcreteInitPropdef then
354 name_node
= self.n_kwinit
355 else if self isa AExternInitPropdef then
357 name_node
= self.n_kwnew
361 else if amethodid
isa AIdMethid then
362 name
= amethodid
.n_id
.text
363 name_node
= amethodid
365 # operator, bracket or assign
366 name
= amethodid
.collect_text
367 name_node
= amethodid
369 if name
== "-" and self.n_signature
.n_params
.length
== 0 then
374 var mprop
: nullable MMethod = null
375 if not is_init
or n_kwredef
!= null then mprop
= modelbuilder
.try_get_mproperty_by_name
(name_node
, mclassdef
, name
).as(nullable MMethod)
376 if mprop
== null then
377 var mvisibility
= new_property_visibility
(modelbuilder
, nclassdef
, self.n_visibility
)
378 mprop
= new MMethod(mclassdef
, name
, mvisibility
)
379 mprop
.is_init
= is_init
380 mprop
.is_new
= self isa AExternInitPropdef
381 if not self.check_redef_keyword
(modelbuilder
, nclassdef
, n_kwredef
, false, mprop
) then return
383 if n_kwredef
== null then
384 if self isa AMainMethPropdef then
387 if not self.check_redef_keyword
(modelbuilder
, nclassdef
, n_kwredef
, true, mprop
) then return
390 check_redef_property_visibility
(modelbuilder
, nclassdef
, self.n_visibility
, mprop
)
392 nclassdef
.mprop2npropdef
[mprop
] = self
394 var mpropdef
= new MMethodDef(mclassdef
, mprop
, self.location
)
396 self.mpropdef
= mpropdef
397 modelbuilder
.mpropdef2npropdef
[mpropdef
] = self
398 if mpropdef
.is_intro
then
399 modelbuilder
.toolcontext
.info
("{mpropdef} introduces new method {mprop.full_name}", 3)
401 modelbuilder
.toolcontext
.info
("{mpropdef} redefines method {mprop.full_name}", 3)
405 redef fun build_signature
(modelbuilder
, nclassdef
)
407 var mpropdef
= self.mpropdef
408 if mpropdef
== null then return # Error thus skiped
409 var mmodule
= mpropdef
.mclassdef
.mmodule
410 var nsig
= self.n_signature
412 # Retrieve info from the signature AST
413 var param_names
= new Array[String] # Names of parameters from the AST
414 var param_types
= new Array[MType] # Types of parameters from the AST
416 var ret_type
: nullable MType = null # Return type from the AST
418 if not nsig
.visit_signature
(modelbuilder
, nclassdef
) then return
419 param_names
= nsig
.param_names
420 param_types
= nsig
.param_types
421 vararg_rank
= nsig
.vararg_rank
422 ret_type
= nsig
.ret_type
425 # Look for some signature to inherit
426 # FIXME: do not inherit from the intro, but from the most specific
427 var msignature
: nullable MSignature = null
428 if not mpropdef
.is_intro
then
429 msignature
= mpropdef
.mproperty
.intro
.msignature
430 if msignature
== null then return # Skip error
432 # Check inherited signature arity
433 if param_names
.length
!= msignature
.arity
then
435 if nsig
!= null then node
= nsig
else node
= self
436 modelbuilder
.error
(node
, "Redef error: {mpropdef} redefines {mpropdef.mproperty.intro} with {param_names.length} parameter(s), {msignature.arity} expected. Signature is {mpropdef}{msignature}")
439 else if mpropdef
.mproperty
.is_init
then
440 # FIXME UGLY: inherit signature from a super-constructor
441 for msupertype
in nclassdef
.mclassdef
.supertypes
do
442 msupertype
= msupertype
.anchor_to
(mmodule
, nclassdef
.mclassdef
.bound_mtype
)
443 var candidate
= modelbuilder
.try_get_mproperty_by_name2
(self, mmodule
, msupertype
, mpropdef
.mproperty
.name
)
444 if candidate
!= null then
445 if msignature
== null then
446 msignature
= candidate
.intro
.as(MMethodDef).msignature
453 # Inherit the signature
454 if msignature
!= null and param_names
.length
!= param_types
.length
and param_names
.length
== msignature
.arity
and param_types
.length
== 0 then
455 # Parameters are untyped, thus inherit them
456 param_types
= new Array[MType]
457 for mparameter
in msignature
.mparameters
do
458 param_types
.add
(mparameter
.mtype
)
460 vararg_rank
= msignature
.vararg_rank
462 if msignature
!= null and ret_type
== null then
463 ret_type
= msignature
.return_mtype
466 if param_names
.length
!= param_types
.length
then
467 # Some parameters are typed, other parameters are not typed.
468 modelbuilder
.error
(nsig
.n_params
[param_types
.length
], "Error: Untyped parameter `{param_names[param_types.length]}'.")
472 var mparameters
= new Array[MParameter]
473 for i
in [0..param_names
.length
[ do
474 var mparameter
= new MParameter(param_names
[i
], param_types
[i
], i
== vararg_rank
)
475 mparameters
.add
(mparameter
)
478 msignature
= new MSignature(mparameters
, ret_type
)
479 mpropdef
.msignature
= msignature
482 for nclosure
in nsig
.n_closure_decls
do
483 var clos_signature
= nclosure
.n_signature
.build_signature
(modelbuilder
, nclassdef
)
484 if clos_signature
== null then return
485 var mparameter
= new MParameter(nclosure
.n_id
.text
, clos_signature
, false)
486 msignature
.mclosures
.add
(mparameter
)
492 redef fun check_signature
(modelbuilder
, nclassdef
)
494 var mpropdef
= self.mpropdef
495 if mpropdef
== null then return # Error thus skiped
496 var mmodule
= mpropdef
.mclassdef
.mmodule
497 var nsig
= self.n_signature
498 var mysignature
= self.mpropdef
.msignature
499 if mysignature
== null then return # Error thus skiped
501 # Lookup for signature in the precursor
502 # FIXME all precursors should be considered
503 if not mpropdef
.is_intro
then
504 var msignature
= mpropdef
.mproperty
.intro
.msignature
505 if msignature
== null then return
507 var precursor_ret_type
= msignature
.return_mtype
508 var ret_type
= mysignature
.return_mtype
509 if ret_type
!= null and precursor_ret_type
== null then
510 modelbuilder
.error
(nsig
.n_type
.as(not null), "Redef Error: {mpropdef.mproperty} is a procedure, not a function.")
514 if mysignature
.arity
> 0 then
515 # Check parameters types
516 for i
in [0..mysignature
.arity
[ do
517 var myt
= mysignature
.mparameters
[i
].mtype
518 var prt
= msignature
.mparameters
[i
].mtype
519 if not myt
.is_subtype
(mmodule
, nclassdef
.mclassdef
.bound_mtype
, prt
) and
520 not prt
.is_subtype
(mmodule
, nclassdef
.mclassdef
.bound_mtype
, myt
) then
521 modelbuilder
.error
(nsig
.n_params
[i
], "Redef Error: Wrong type for parameter `{mysignature.mparameters[i].name}'. found {myt}, expected {prt}.")
525 if precursor_ret_type
!= null then
526 if ret_type
== null then
527 # Inherit the return type
528 ret_type
= precursor_ret_type
529 else if not ret_type
.is_subtype
(mmodule
, nclassdef
.mclassdef
.bound_mtype
, precursor_ret_type
) then
530 modelbuilder
.error
(nsig
.n_type
.as(not null), "Redef Error: Wrong return type. found {ret_type}, expected {precursor_ret_type}.")
537 redef class AAttrPropdef
538 # The associated MAttributeDef once build by a `ModelBuilder'
539 var mpropdef
: nullable MAttributeDef
540 # The associated getter (read accessor) if any
541 var mreadpropdef
: nullable MMethodDef
542 # The associated setter (write accessor) if any
543 var mwritepropdef
: nullable MMethodDef
544 redef fun build_property
(modelbuilder
, nclassdef
)
546 var mclassdef
= nclassdef
.mclassdef
.as(not null)
547 var mclass
= mclassdef
.mclass
550 if self.n_id
!= null then
551 name
= self.n_id
.text
553 name
= self.n_id2
.text
556 if mclass
.kind
== interface_kind
or mclassdef
.mclass
.kind
== enum_kind
then
557 modelbuilder
.error
(self, "Error: Attempt to define attribute {name} in the interface {mclass}.")
558 else if mclass
.kind
== enum_kind
then
559 modelbuilder
.error
(self, "Error: Attempt to define attribute {name} in the enum class {mclass}.")
560 else if mclass
.kind
== extern_kind
then
561 modelbuilder
.error
(self, "Error: Attempt to define attribute {name} in the extern class {mclass}.")
566 # Old attribute style
567 var mprop
= modelbuilder
.try_get_mproperty_by_name
(nid
, mclassdef
, name
)
568 if mprop
== null then
569 var mvisibility
= new_property_visibility
(modelbuilder
, nclassdef
, self.n_visibility
)
570 mprop
= new MAttribute(mclassdef
, name
, mvisibility
)
571 if not self.check_redef_keyword
(modelbuilder
, nclassdef
, self.n_kwredef
, false, mprop
) then return
573 assert mprop
isa MAttribute
574 check_redef_property_visibility
(modelbuilder
, nclassdef
, self.n_visibility
, mprop
)
575 if not self.check_redef_keyword
(modelbuilder
, nclassdef
, self.n_kwredef
, true, mprop
) then return
577 nclassdef
.mprop2npropdef
[mprop
] = self
579 var mpropdef
= new MAttributeDef(mclassdef
, mprop
, self.location
)
580 self.mpropdef
= mpropdef
581 modelbuilder
.mpropdef2npropdef
[mpropdef
] = self
583 var nreadable
= self.n_readable
584 if nreadable
!= null then
585 var readname
= name
.substring_from
(1)
586 var mreadprop
= modelbuilder
.try_get_mproperty_by_name
(nid
, mclassdef
, readname
).as(nullable MMethod)
587 if mreadprop
== null then
588 var mvisibility
= new_property_visibility
(modelbuilder
, nclassdef
, nreadable
.n_visibility
)
589 mreadprop
= new MMethod(mclassdef
, readname
, mvisibility
)
590 if not self.check_redef_keyword
(modelbuilder
, nclassdef
, nreadable
.n_kwredef
, false, mreadprop
) then return
592 if not self.check_redef_keyword
(modelbuilder
, nclassdef
, nreadable
.n_kwredef
, true, mreadprop
) then return
593 check_redef_property_visibility
(modelbuilder
, nclassdef
, nreadable
.n_visibility
, mreadprop
)
595 nclassdef
.mprop2npropdef
[mreadprop
] = self
597 var mreadpropdef
= new MMethodDef(mclassdef
, mreadprop
, self.location
)
598 self.mreadpropdef
= mreadpropdef
599 modelbuilder
.mpropdef2npropdef
[mreadpropdef
] = self
602 var nwritable
= self.n_writable
603 if nwritable
!= null then
604 var writename
= name
.substring_from
(1) + "="
605 var mwriteprop
= modelbuilder
.try_get_mproperty_by_name
(nid
, mclassdef
, writename
).as(nullable MMethod)
606 if mwriteprop
== null then
607 var mvisibility
= new_property_visibility
(modelbuilder
, nclassdef
, nwritable
.n_visibility
)
608 mwriteprop
= new MMethod(mclassdef
, writename
, mvisibility
)
609 if not self.check_redef_keyword
(modelbuilder
, nclassdef
, nwritable
.n_kwredef
, false, mwriteprop
) then return
611 if not self.check_redef_keyword
(modelbuilder
, nclassdef
, nwritable
.n_kwredef
, true, mwriteprop
) then return
612 check_redef_property_visibility
(modelbuilder
, nclassdef
, nwritable
.n_visibility
, mwriteprop
)
614 nclassdef
.mprop2npropdef
[mwriteprop
] = self
616 var mwritepropdef
= new MMethodDef(mclassdef
, mwriteprop
, self.location
)
617 self.mwritepropdef
= mwritepropdef
618 modelbuilder
.mpropdef2npropdef
[mwritepropdef
] = self
621 # New attribute style
622 var nid2
= self.n_id2
.as(not null)
623 var mprop
= new MAttribute(mclassdef
, "@" + name
, none_visibility
)
624 var mpropdef
= new MAttributeDef(mclassdef
, mprop
, self.location
)
625 self.mpropdef
= mpropdef
626 modelbuilder
.mpropdef2npropdef
[mpropdef
] = self
629 var mreadprop
= modelbuilder
.try_get_mproperty_by_name
(nid2
, mclassdef
, readname
).as(nullable MMethod)
630 if mreadprop
== null then
631 var mvisibility
= new_property_visibility
(modelbuilder
, nclassdef
, self.n_visibility
)
632 mreadprop
= new MMethod(mclassdef
, readname
, mvisibility
)
633 if not self.check_redef_keyword
(modelbuilder
, nclassdef
, n_kwredef
, false, mreadprop
) then return
635 if not self.check_redef_keyword
(modelbuilder
, nclassdef
, n_kwredef
, true, mreadprop
) then return
636 check_redef_property_visibility
(modelbuilder
, nclassdef
, self.n_visibility
, mreadprop
)
638 nclassdef
.mprop2npropdef
[mreadprop
] = self
640 var mreadpropdef
= new MMethodDef(mclassdef
, mreadprop
, self.location
)
641 self.mreadpropdef
= mreadpropdef
642 modelbuilder
.mpropdef2npropdef
[mreadpropdef
] = self
644 var writename
= name
+ "="
645 var nwritable
= self.n_writable
646 var mwriteprop
= modelbuilder
.try_get_mproperty_by_name
(nid2
, mclassdef
, writename
).as(nullable MMethod)
647 var nwkwredef
: nullable Token = null
648 if nwritable
!= null then nwkwredef
= nwritable
.n_kwredef
649 if mwriteprop
== null then
651 if nwritable
!= null then
652 mvisibility
= new_property_visibility
(modelbuilder
, nclassdef
, nwritable
.n_visibility
)
654 mvisibility
= private_visibility
656 mwriteprop
= new MMethod(mclassdef
, writename
, mvisibility
)
657 if not self.check_redef_keyword
(modelbuilder
, nclassdef
, nwkwredef
, false, mwriteprop
) then return
659 if not self.check_redef_keyword
(modelbuilder
, nclassdef
, nwkwredef
, true, mwriteprop
) then return
660 if nwritable
!= null then
661 check_redef_property_visibility
(modelbuilder
, nclassdef
, nwritable
.n_visibility
, mwriteprop
)
664 nclassdef
.mprop2npropdef
[mwriteprop
] = self
666 var mwritepropdef
= new MMethodDef(mclassdef
, mwriteprop
, self.location
)
667 self.mwritepropdef
= mwritepropdef
668 modelbuilder
.mpropdef2npropdef
[mwritepropdef
] = self
672 redef fun build_signature
(modelbuilder
, nclassdef
)
674 var mpropdef
= self.mpropdef
675 if mpropdef
== null then return # Error thus skiped
676 var mmodule
= mpropdef
.mclassdef
.mmodule
677 var mtype
: nullable MType = null
679 var ntype
= self.n_type
680 if ntype
!= null then
681 mtype
= modelbuilder
.resolve_mtype
(nclassdef
, ntype
)
682 if mtype
== null then return
685 if mtype
== null then
686 var nexpr
= self.n_expr
687 if nexpr
!= null then
688 if nexpr
isa ANewExpr then
689 mtype
= modelbuilder
.resolve_mtype
(nclassdef
, nexpr
.n_type
)
690 else if nexpr
isa AIntExpr then
691 var cla
= modelbuilder
.try_get_mclass_by_name
(nexpr
, mmodule
, "Int")
692 if cla
!= null then mtype
= cla
.mclass_type
693 else if nexpr
isa AFloatExpr then
694 var cla
= modelbuilder
.try_get_mclass_by_name
(nexpr
, mmodule
, "Float")
695 if cla
!= null then mtype
= cla
.mclass_type
696 else if nexpr
isa ACharExpr then
697 var cla
= modelbuilder
.try_get_mclass_by_name
(nexpr
, mmodule
, "Char")
698 if cla
!= null then mtype
= cla
.mclass_type
699 else if nexpr
isa ABoolExpr then
700 var cla
= modelbuilder
.try_get_mclass_by_name
(nexpr
, mmodule
, "Bool")
701 if cla
!= null then mtype
= cla
.mclass_type
702 else if nexpr
isa ASuperstringExpr then
703 var cla
= modelbuilder
.try_get_mclass_by_name
(nexpr
, mmodule
, "String")
704 if cla
!= null then mtype
= cla
.mclass_type
705 else if nexpr
isa AStringFormExpr then
706 var cla
= modelbuilder
.try_get_mclass_by_name
(nexpr
, mmodule
, "String")
707 if cla
!= null then mtype
= cla
.mclass_type
709 modelbuilder
.error
(self, "Error: Untyped attribute {mpropdef}. Implicit typing allowed only for literals and new.")
713 modelbuilder
.error
(self, "Error: Untyped attribute {mpropdef}")
717 if mtype
== null then return
719 mpropdef
.static_mtype
= mtype
721 var mreadpropdef
= self.mreadpropdef
722 if mreadpropdef
!= null then
723 var msignature
= new MSignature(new Array[MParameter], mtype
)
724 mreadpropdef
.msignature
= msignature
727 var msritepropdef
= self.mwritepropdef
728 if mwritepropdef
!= null then
731 name
= n_id
.text
.substring_from
(1)
735 var mparameter
= new MParameter(name
, mtype
, false)
736 var msignature
= new MSignature([mparameter
], null)
737 mwritepropdef
.msignature
= msignature
741 redef fun check_signature
(modelbuilder
, nclassdef
)
743 var mpropdef
= self.mpropdef
744 if mpropdef
== null then return # Error thus skiped
745 var mmodule
= mpropdef
.mclassdef
.mmodule
746 var ntype
= self.n_type
747 var mtype
= self.mpropdef
.static_mtype
748 if mtype
== null then return # Error thus skiped
750 # Lookup for signature in the precursor
751 # FIXME all precursors should be considered
752 if not mpropdef
.is_intro
then
753 var precursor_type
= mpropdef
.mproperty
.intro
.static_mtype
754 if precursor_type
== null then return
756 if mtype
!= precursor_type
then
757 modelbuilder
.error
(ntype
.as(not null), "Redef Error: Wrong static type. found {mtype}, expected {precursor_type}.")
762 # Check getter and setter
763 var meth
= self.mreadpropdef
764 if meth
!= null then self.check_method_signature
(modelbuilder
, nclassdef
, meth
)
765 meth
= self.mwritepropdef
766 if meth
!= null then self.check_method_signature
(modelbuilder
, nclassdef
, meth
)
769 private fun check_method_signature
(modelbuilder
: ModelBuilder, nclassdef
: AClassdef, mpropdef
: MMethodDef)
771 var mmodule
= mpropdef
.mclassdef
.mmodule
772 var nsig
= self.n_type
773 var mysignature
= mpropdef
.msignature
774 if mysignature
== null then return # Error thus skiped
776 # Lookup for signature in the precursor
777 # FIXME all precursors should be considered
778 if not mpropdef
.is_intro
then
779 var msignature
= mpropdef
.mproperty
.intro
.msignature
780 if msignature
== null then return
782 if mysignature
.arity
!= msignature
.arity
then
784 if nsig
!= null then node
= nsig
else node
= self
785 modelbuilder
.error
(node
, "Redef Error: {mysignature.arity} parameters found, {msignature.arity} expected. Signature is {mpropdef}{msignature}")
788 var precursor_ret_type
= msignature
.return_mtype
789 var ret_type
= mysignature
.return_mtype
790 if ret_type
!= null and precursor_ret_type
== null then
792 if nsig
!= null then node
= nsig
else node
= self
793 modelbuilder
.error
(node
, "Redef Error: {mpropdef.mproperty} is a procedure, not a function.")
797 if mysignature
.arity
> 0 then
798 # Check parameters types
799 for i
in [0..mysignature
.arity
[ do
800 var myt
= mysignature
.mparameters
[i
].mtype
801 var prt
= msignature
.mparameters
[i
].mtype
802 if not myt
.is_subtype
(mmodule
, nclassdef
.mclassdef
.bound_mtype
, prt
) and
803 not prt
.is_subtype
(mmodule
, nclassdef
.mclassdef
.bound_mtype
, myt
) then
805 if nsig
!= null then node
= nsig
else node
= self
806 modelbuilder
.error
(node
, "Redef Error: Wrong type for parameter `{mysignature.mparameters[i].name}'. found {myt}, expected {prt}.")
810 if precursor_ret_type
!= null then
811 if ret_type
== null then
812 # Inherit the return type
813 ret_type
= precursor_ret_type
814 else if not ret_type
.is_subtype
(mmodule
, nclassdef
.mclassdef
.bound_mtype
, precursor_ret_type
) then
816 if nsig
!= null then node
= nsig
else node
= self
817 modelbuilder
.error
(node
, "Redef Error: Wrong return type. found {ret_type}, expected {precursor_ret_type}.")
824 redef class ATypePropdef
825 # The associated MVirtualTypeDef once build by a `ModelBuilder'
826 var mpropdef
: nullable MVirtualTypeDef
827 redef fun build_property
(modelbuilder
, nclassdef
)
829 var mclassdef
= nclassdef
.mclassdef
.as(not null)
830 var name
= self.n_id
.text
831 var mprop
= modelbuilder
.try_get_mproperty_by_name
(self.n_id
, mclassdef
, name
)
832 if mprop
== null then
833 var mvisibility
= new_property_visibility
(modelbuilder
, nclassdef
, self.n_visibility
)
834 mprop
= new MVirtualTypeProp(mclassdef
, name
, mvisibility
)
835 if not self.check_redef_keyword
(modelbuilder
, nclassdef
, self.n_kwredef
, false, mprop
) then return
837 if not self.check_redef_keyword
(modelbuilder
, nclassdef
, self.n_kwredef
, true, mprop
) then return
838 assert mprop
isa MVirtualTypeProp
839 check_redef_property_visibility
(modelbuilder
, nclassdef
, self.n_visibility
, mprop
)
841 nclassdef
.mprop2npropdef
[mprop
] = self
843 var mpropdef
= new MVirtualTypeDef(mclassdef
, mprop
, self.location
)
844 self.mpropdef
= mpropdef
847 redef fun build_signature
(modelbuilder
, nclassdef
)
849 var mpropdef
= self.mpropdef
850 if mpropdef
== null then return # Error thus skiped
851 var mmodule
= mpropdef
.mclassdef
.mmodule
852 var mtype
: nullable MType = null
854 var ntype
= self.n_type
855 mtype
= modelbuilder
.resolve_mtype
(nclassdef
, ntype
)
856 if mtype
== null then return
858 mpropdef
.bound
= mtype
859 # print "{mpropdef}: {mtype}"
862 redef fun check_signature
(modelbuilder
, nclassdef
)
864 var bound
= self.mpropdef
.bound
866 # Fast case: the bound is not a formal type
867 if not bound
isa MVirtualType then return
869 var mmodule
= nclassdef
.mclassdef
.mmodule
870 var anchor
= nclassdef
.mclassdef
.bound_mtype
872 # Slow case: progress on each resolution until: (i) we loop, or (ii) we found a non formal type
873 var seen
= [self.mpropdef
.mproperty
.mvirtualtype
]
875 if seen
.has
(bound
) then
877 modelbuilder
.error
(self, "Error: circularity of virtual type definition: {seen.join(" -> ")}")
881 var next
= bound
.lookup_bound
(mmodule
, anchor
)
882 if not next
isa MVirtualType then return