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 if nclassdef
.all_defs
== null then continue # skip non principal classdef
32 toolcontext
.modelbuilder
.build_properties
(nclassdef
)
37 redef class ModelBuilder
38 # Register the npropdef associated to each mpropdef
39 # FIXME: why not refine the `MPropDef` class with a nullable attribute?
40 var mpropdef2npropdef
: HashMap[MPropDef, APropdef] = new HashMap[MPropDef, APropdef]
42 # Build the properties of `nclassdef`.
43 # REQUIRE: all superclasses are built.
44 private fun build_properties
(nclassdef
: AClassdef)
46 # Force building recursively
47 if nclassdef
.build_properties_is_done
then return
48 nclassdef
.build_properties_is_done
= true
49 var mclassdef
= nclassdef
.mclassdef
.as(not null)
50 if mclassdef
.in_hierarchy
== null then return # Skip error
51 for superclassdef
in mclassdef
.in_hierarchy
.direct_greaters
do
52 if not mclassdef2nclassdef
.has_key
(superclassdef
) then continue
53 build_properties
(mclassdef2nclassdef
[superclassdef
])
56 for nclassdef2
in nclassdef
.all_defs
do
57 for npropdef
in nclassdef2
.n_propdefs
do
58 npropdef
.build_property
(self, mclassdef
)
60 for npropdef
in nclassdef2
.n_propdefs
do
61 npropdef
.build_signature
(self)
63 for npropdef
in nclassdef2
.n_propdefs
do
64 npropdef
.check_signature
(self)
67 process_default_constructors
(nclassdef
)
70 # Introduce or inherit default constructor
71 # This is the last part of `build_properties`.
72 private fun process_default_constructors
(nclassdef
: AClassdef)
74 var mclassdef
= nclassdef
.mclassdef
.as(not null)
77 if not mclassdef
.is_intro
then return
79 # Is the class forbid constructors?
80 if not mclassdef
.mclass
.kind
.need_init
then return
82 # Is there already a constructor defined?
83 for mpropdef
in mclassdef
.mpropdefs
do
84 if not mpropdef
isa MMethodDef then continue
85 if mpropdef
.mproperty
.is_init
then return
88 if not nclassdef
isa AStdClassdef then return
90 var mmodule
= mclassdef
.mmodule
91 # Do we inherit for a constructor?
92 var combine
= new Array[MMethod]
93 var inhc
: nullable MClass = null
94 for st
in mclassdef
.supertypes
do
96 if not c
.kind
.need_init
then continue
97 st
= st
.anchor_to
(mmodule
, mclassdef
.bound_mtype
)
98 var candidate
= self.try_get_mproperty_by_name2
(nclassdef
, mmodule
, st
, "init").as(nullable MMethod)
99 if candidate
!= null then
100 if candidate
.intro
.msignature
!= null then
101 if candidate
.intro
.msignature
.arity
== 0 then
102 combine
.add
(candidate
)
107 var inhc2
= c
.inherit_init_from
108 if inhc2
== null then inhc2
= c
109 if inhc2
== inhc
then continue
111 self.error
(nclassdef
, "Error: Cannot provide a defaut constructor: conflict for {inhc} and {c}")
117 # Collect undefined attributes
118 var mparameters
= new Array[MParameter]
119 var anode
: nullable ANode = null
120 for npropdef
in nclassdef
.n_propdefs
do
121 if npropdef
isa AAttrPropdef and npropdef
.n_expr
== null then
122 if npropdef
.mpropdef
== null then return # Skip broken attribute
123 var paramname
= npropdef
.mpropdef
.mproperty
.name
.substring_from
(1)
124 var ret_type
= npropdef
.mpropdef
.static_mtype
125 if ret_type
== null then return
126 var mparameter
= new MParameter(paramname
, ret_type
, false)
127 mparameters
.add
(mparameter
)
128 if anode
== null then anode
= npropdef
131 if anode
== null then anode
= nclassdef
133 if combine
.is_empty
and inhc
!= null then
134 if not mparameters
.is_empty
then
135 self.error
(anode
,"Error: {mclassdef} cannot inherit constructors from {inhc} because there is attributes without initial values: {mparameters.join(", ")}")
139 # TODO: actively inherit the consturctor
140 self.toolcontext
.info
("{mclassdef} inherits all constructors from {inhc}", 3)
141 mclassdef
.mclass
.inherit_init_from
= inhc
145 if not combine
.is_empty
and inhc
!= null then
146 self.error
(nclassdef
, "Error: Cannot provide a defaut constructor: conflict for {combine.join(", ")} and {inhc}")
150 if not combine
.is_empty
then
151 if mparameters
.is_empty
and combine
.length
== 1 then
152 # No need to create a local init, the inherited one is enough
153 inhc
= combine
.first
.intro_mclassdef
.mclass
154 mclassdef
.mclass
.inherit_init_from
= inhc
155 self.toolcontext
.info
("{mclassdef} inherits all constructors from {inhc}", 3)
158 nclassdef
.super_inits
= combine
161 var mprop
= new MMethod(mclassdef
, "init", mclassdef
.mclass
.visibility
)
162 var mpropdef
= new MMethodDef(mclassdef
, mprop
, nclassdef
.location
)
163 var msignature
= new MSignature(mparameters
, null)
164 mpropdef
.msignature
= msignature
166 nclassdef
.mfree_init
= mpropdef
167 self.toolcontext
.info
("{mclassdef} gets a free constructor for attributes {mpropdef}{msignature}", 3)
170 # Check the visibility of `mtype` as an element of the signature of `mpropdef`.
171 fun check_visibility
(node
: ANode, mtype
: MType, mpropdef
: MPropDef)
173 var mmodule
= mpropdef
.mclassdef
.mmodule
174 var mproperty
= mpropdef
.mproperty
176 # Extract visibility information of the main part of `mtype`
177 # It is a case-by case
178 var vis_type
: nullable MVisibility = null # The own visibility of the type
179 var mmodule_type
: nullable MModule = null # The origial module of the type
180 if mtype
isa MNullableType then mtype
= mtype
.mtype
181 if mtype
isa MClassType then
182 vis_type
= mtype
.mclass
.visibility
183 mmodule_type
= mtype
.mclass
.intro
.mmodule
184 else if mtype
isa MVirtualType then
185 vis_type
= mtype
.mproperty
.visibility
186 mmodule_type
= mtype
.mproperty
.intro_mclassdef
.mmodule
187 else if mtype
isa MParameterType then
188 # nothing, always visible
190 node
.debug
"Unexpected type {mtype}"
194 if vis_type
!= null then
195 assert mmodule_type
!= null
196 var vis_module_type
= mmodule
.visibility_for
(mmodule_type
) # the visibility of the original module
197 if mproperty
.visibility
> vis_type
then
198 error
(node
, "Error: The {mproperty.visibility} property `{mproperty}` cannot contain the {vis_type} type `{mtype}`")
200 else if mproperty
.visibility
> vis_module_type
then
201 error
(node
, "Error: The {mproperty.visibility} property `{mproperty}` cannot contain the type `{mtype}` from the {vis_module_type} module `{mmodule_type}`")
206 # No error, try to go deeper in generic types
207 if node
isa AType then
208 for a
in node
.n_types
do
210 if t
== null then continue # Error, thus skipped
211 check_visibility
(a
, t
, mpropdef
)
213 else if mtype
isa MGenericType then
214 for t
in mtype
.arguments
do check_visibility
(node
, t
, mpropdef
)
220 # The class whose self inherit all the constructors.
221 # 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
222 var inherit_init_from
: nullable MClass = null
226 # Does the MPropDef contains a call to super or a call of a super-constructor?
227 # Subsequent phases of the frontend (esp. typing) set it if required
228 var has_supercall
: Bool writable = false
231 redef class AClassdef
232 var build_properties_is_done
: Bool = false
233 # The list of super-constructor to call at the start of the free constructor
234 # 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
235 var super_inits
: nullable Collection[MMethod] = null
237 # The free init (implicitely constructed by the class if required)
238 var mfree_init
: nullable MMethodDef = null
241 redef class MClassDef
242 # What is the `APropdef` associated to a `MProperty`?
243 # Used to check multiple definition of a property.
244 var mprop2npropdef
: Map[MProperty, APropdef] = new HashMap[MProperty, APropdef]
248 # Join the text of all tokens
249 # Used to get the 'real name' of method definitions.
250 fun collect_text
: String
252 var v
= new TextCollectorVisitor
259 private class TextCollectorVisitor
261 var text
: String = ""
264 if n
isa Token then text
+= n
.text
270 # The associated main model entity
271 type MPROPDEF: MPropDef
273 # The associated propdef once build by a `ModelBuilder`
274 var mpropdef
: nullable MPROPDEF writable
276 private fun build_property
(modelbuilder
: ModelBuilder, mclassdef
: MClassDef) is abstract
277 private fun build_signature
(modelbuilder
: ModelBuilder) is abstract
278 private fun check_signature
(modelbuilder
: ModelBuilder) is abstract
279 private fun new_property_visibility
(modelbuilder
: ModelBuilder, mclassdef
: MClassDef, nvisibility
: nullable AVisibility): MVisibility
281 var mvisibility
= public_visibility
282 if nvisibility
!= null then
283 mvisibility
= nvisibility
.mvisibility
284 if mvisibility
== intrude_visibility
then
285 modelbuilder
.error
(nvisibility
, "Error: intrude is not a legal visibility for properties.")
286 mvisibility
= public_visibility
289 if mclassdef
.mclass
.visibility
== private_visibility
then
290 if mvisibility
== protected_visibility
then
291 assert nvisibility
!= null
292 modelbuilder
.error
(nvisibility
, "Error: The only legal visibility for properties in a private class is private.")
293 else if mvisibility
== private_visibility
then
294 assert nvisibility
!= null
296 # modelbuilder.warning(nvisibility, "Warning: private is unrequired since the only legal visibility for properties in a private class is private.")
298 mvisibility
= private_visibility
303 private fun set_doc
(mpropdef
: MPropDef)
305 var ndoc
= self.n_doc
307 var mdoc
= ndoc
.to_mdoc
309 mdoc
.original_mentity
= mpropdef
313 private fun check_redef_property_visibility
(modelbuilder
: ModelBuilder, nvisibility
: nullable AVisibility, mprop
: MProperty)
315 if nvisibility
== null then return
316 var mvisibility
= nvisibility
.mvisibility
317 if mvisibility
!= mprop
.visibility
and mvisibility
!= public_visibility
then
318 modelbuilder
.error
(nvisibility
, "Error: redefinition changed the visibility from a {mprop.visibility} to a {mvisibility}")
322 private fun check_redef_keyword
(modelbuilder
: ModelBuilder, mclassdef
: MClassDef, kwredef
: nullable Token, need_redef
: Bool, mprop
: MProperty): Bool
324 if mclassdef
.mprop2npropdef
.has_key
(mprop
) then
325 modelbuilder
.error
(self, "Error: A property {mprop} is already defined in class {mclassdef.mclass} at line {mclassdef.mprop2npropdef[mprop].location.line_start}.")
328 if mprop
isa MMethod and mprop
.is_toplevel
!= (parent
isa ATopClassdef) then
329 if mprop
.is_toplevel
then
330 modelbuilder
.error
(self, "Error: {mprop} is a top level method.")
332 modelbuilder
.error
(self, "Error: {mprop} is not a top level method.")
337 if kwredef
== null then
339 modelbuilder
.error
(self, "Redef error: {mclassdef.mclass}::{mprop.name} is an inherited property. To redefine it, add the redef keyword.")
343 if not need_redef
then
344 modelbuilder
.error
(self, "Error: No property {mclassdef.mclass}::{mprop.name} is inherited. Remove the redef keyword to define a new property.")
353 redef class ASignature
354 # Is the model builder has correctly visited the signature
355 var is_visited
= false
356 # Names of parameters from the AST
357 # REQUIRE: is_visited
358 var param_names
= new Array[String]
359 # Types of parameters from the AST
360 # REQUIRE: is_visited
361 var param_types
= new Array[MType]
362 # Rank of the vararg (of -1 if none)
363 # REQUIRE: is_visited
364 var vararg_rank
: Int = -1
366 var ret_type
: nullable MType = null
368 # Visit and fill information about a signature
369 private fun visit_signature
(modelbuilder
: ModelBuilder, mclassdef
: MClassDef): Bool
371 var mmodule
= mclassdef
.mmodule
372 var param_names
= self.param_names
373 var param_types
= self.param_types
374 for np
in self.n_params
do
375 param_names
.add
(np
.n_id
.text
)
376 var ntype
= np
.n_type
377 if ntype
!= null then
378 var mtype
= modelbuilder
.resolve_mtype
(mmodule
, mclassdef
, ntype
)
379 if mtype
== null then return false # Skip error
380 for i
in [0..param_names
.length-param_types
.length
[ do
381 param_types
.add
(mtype
)
383 if np
.n_dotdotdot
!= null then
384 if self.vararg_rank
!= -1 then
385 modelbuilder
.error
(np
, "Error: {param_names[self.vararg_rank]} is already a vararg")
388 self.vararg_rank
= param_names
.length
- 1
393 var ntype
= self.n_type
394 if ntype
!= null then
395 self.ret_type
= modelbuilder
.resolve_mtype
(mmodule
, mclassdef
, ntype
)
396 if self.ret_type
== null then return false # Skip errir
399 self.is_visited
= true
403 # Build a visited signature
404 fun build_signature
(modelbuilder
: ModelBuilder): nullable MSignature
406 if param_names
.length
!= param_types
.length
then
407 # Some parameters are typed, other parameters are not typed.
408 modelbuilder
.error
(self.n_params
[param_types
.length
], "Error: Untyped parameter `{param_names[param_types.length]}'.")
412 var mparameters
= new Array[MParameter]
413 for i
in [0..param_names
.length
[ do
414 var mparameter
= new MParameter(param_names
[i
], param_types
[i
], i
== vararg_rank
)
415 self.n_params
[i
].mparameter
= mparameter
416 mparameters
.add
(mparameter
)
419 var msignature
= new MSignature(mparameters
, ret_type
)
425 # The associated mparameter if any
426 var mparameter
: nullable MParameter = null
429 redef class AMethPropdef
430 redef type MPROPDEF: MMethodDef
432 redef fun build_property
(modelbuilder
, mclassdef
)
434 var n_kwinit
= n_kwinit
435 var n_kwnew
= n_kwnew
436 var is_init
= n_kwinit
!= null or n_kwnew
!= null
438 var amethodid
= self.n_methid
440 if amethodid
== null then
444 else if n_kwinit
!= null then
447 else if n_kwnew
!= null then
453 else if amethodid
isa AIdMethid then
454 name
= amethodid
.n_id
.text
455 name_node
= amethodid
457 # operator, bracket or assign
458 name
= amethodid
.collect_text
459 name_node
= amethodid
461 if name
== "-" and self.n_signature
.n_params
.length
== 0 then
466 var mprop
: nullable MMethod = null
467 if not is_init
or n_kwredef
!= null then mprop
= modelbuilder
.try_get_mproperty_by_name
(name_node
, mclassdef
, name
).as(nullable MMethod)
468 if mprop
== null then
469 var mvisibility
= new_property_visibility
(modelbuilder
, mclassdef
, self.n_visibility
)
470 mprop
= new MMethod(mclassdef
, name
, mvisibility
)
471 mprop
.is_init
= is_init
472 mprop
.is_new
= n_kwnew
!= null
473 if parent
isa ATopClassdef then mprop
.is_toplevel
= true
474 if not self.check_redef_keyword
(modelbuilder
, mclassdef
, n_kwredef
, false, mprop
) then return
476 if not self.check_redef_keyword
(modelbuilder
, mclassdef
, n_kwredef
, not self isa AMainMethPropdef, mprop
) then return
477 check_redef_property_visibility
(modelbuilder
, self.n_visibility
, mprop
)
479 mclassdef
.mprop2npropdef
[mprop
] = self
481 var mpropdef
= new MMethodDef(mclassdef
, mprop
, self.location
)
485 self.mpropdef
= mpropdef
486 modelbuilder
.mpropdef2npropdef
[mpropdef
] = self
487 if mpropdef
.is_intro
then
488 modelbuilder
.toolcontext
.info
("{mpropdef} introduces new method {mprop.full_name}", 3)
490 modelbuilder
.toolcontext
.info
("{mpropdef} redefines method {mprop.full_name}", 3)
494 redef fun build_signature
(modelbuilder
)
496 var mpropdef
= self.mpropdef
497 if mpropdef
== null then return # Error thus skiped
498 var mclassdef
= mpropdef
.mclassdef
499 var mmodule
= mclassdef
.mmodule
500 var nsig
= self.n_signature
502 # Retrieve info from the signature AST
503 var param_names
= new Array[String] # Names of parameters from the AST
504 var param_types
= new Array[MType] # Types of parameters from the AST
506 var ret_type
: nullable MType = null # Return type from the AST
508 if not nsig
.visit_signature
(modelbuilder
, mclassdef
) then return
509 param_names
= nsig
.param_names
510 param_types
= nsig
.param_types
511 vararg_rank
= nsig
.vararg_rank
512 ret_type
= nsig
.ret_type
515 # Look for some signature to inherit
516 # FIXME: do not inherit from the intro, but from the most specific
517 var msignature
: nullable MSignature = null
518 if not mpropdef
.is_intro
then
519 msignature
= mpropdef
.mproperty
.intro
.msignature
520 if msignature
== null then return # Skip error
522 # Check inherited signature arity
523 if param_names
.length
!= msignature
.arity
then
525 if nsig
!= null then node
= nsig
else node
= self
526 modelbuilder
.error
(node
, "Redef error: {mpropdef} redefines {mpropdef.mproperty.intro} with {param_names.length} parameter(s), {msignature.arity} expected. Signature is {mpropdef}{msignature}")
529 else if mpropdef
.mproperty
.is_init
then
530 # FIXME UGLY: inherit signature from a super-constructor
531 for msupertype
in mclassdef
.supertypes
do
532 msupertype
= msupertype
.anchor_to
(mmodule
, mclassdef
.bound_mtype
)
533 var candidate
= modelbuilder
.try_get_mproperty_by_name2
(self, mmodule
, msupertype
, mpropdef
.mproperty
.name
)
534 if candidate
!= null then
535 if msignature
== null then
536 msignature
= candidate
.intro
.as(MMethodDef).msignature
543 # Inherit the signature
544 if msignature
!= null and param_names
.length
!= param_types
.length
and param_names
.length
== msignature
.arity
and param_types
.length
== 0 then
545 # Parameters are untyped, thus inherit them
546 param_types
= new Array[MType]
547 for mparameter
in msignature
.mparameters
do
548 param_types
.add
(mparameter
.mtype
)
550 vararg_rank
= msignature
.vararg_rank
552 if msignature
!= null and ret_type
== null then
553 ret_type
= msignature
.return_mtype
556 if param_names
.length
!= param_types
.length
then
557 # Some parameters are typed, other parameters are not typed.
558 modelbuilder
.error
(nsig
.n_params
[param_types
.length
], "Error: Untyped parameter `{param_names[param_types.length]}'.")
562 var mparameters
= new Array[MParameter]
563 for i
in [0..param_names
.length
[ do
564 var mparameter
= new MParameter(param_names
[i
], param_types
[i
], i
== vararg_rank
)
565 if nsig
!= null then nsig
.n_params
[i
].mparameter
= mparameter
566 mparameters
.add
(mparameter
)
569 msignature
= new MSignature(mparameters
, ret_type
)
570 mpropdef
.msignature
= msignature
571 mpropdef
.is_abstract
= self isa ADeferredMethPropdef
572 mpropdef
.is_intern
= self isa AInternMethPropdef
573 mpropdef
.is_extern
= self isa AExternPropdef
576 redef fun check_signature
(modelbuilder
)
578 var mpropdef
= self.mpropdef
579 if mpropdef
== null then return # Error thus skiped
580 var mclassdef
= mpropdef
.mclassdef
581 var mmodule
= mclassdef
.mmodule
582 var nsig
= self.n_signature
583 var mysignature
= self.mpropdef
.msignature
584 if mysignature
== null then return # Error thus skiped
586 # Lookup for signature in the precursor
587 # FIXME all precursors should be considered
588 if not mpropdef
.is_intro
then
589 var msignature
= mpropdef
.mproperty
.intro
.msignature
590 if msignature
== null then return
592 var precursor_ret_type
= msignature
.return_mtype
593 var ret_type
= mysignature
.return_mtype
594 if ret_type
!= null and precursor_ret_type
== null then
595 modelbuilder
.error
(nsig
.n_type
.as(not null), "Redef Error: {mpropdef.mproperty} is a procedure, not a function.")
599 if mysignature
.arity
> 0 then
600 # Check parameters types
601 for i
in [0..mysignature
.arity
[ do
602 var myt
= mysignature
.mparameters
[i
].mtype
603 var prt
= msignature
.mparameters
[i
].mtype
604 if not myt
.is_subtype
(mmodule
, mclassdef
.bound_mtype
, prt
) or
605 not prt
.is_subtype
(mmodule
, mclassdef
.bound_mtype
, myt
) then
606 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}.")
610 if precursor_ret_type
!= null then
611 if ret_type
== null then
612 # Inherit the return type
613 ret_type
= precursor_ret_type
614 else if not ret_type
.is_subtype
(mmodule
, mclassdef
.bound_mtype
, precursor_ret_type
) then
615 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}.")
620 if mysignature
.arity
> 0 then
621 # Check parameters visibility
622 for i
in [0..mysignature
.arity
[ do
623 var nt
= nsig
.n_params
[i
].n_type
624 if nt
!= null then modelbuilder
.check_visibility
(nt
, nt
.mtype
.as(not null), mpropdef
)
627 if nt
!= null then modelbuilder
.check_visibility
(nt
, nt
.mtype
.as(not null), mpropdef
)
632 redef class AAttrPropdef
633 redef type MPROPDEF: MAttributeDef
635 # The associated getter (read accessor) if any
636 var mreadpropdef
: nullable MMethodDef writable
637 # The associated setter (write accessor) if any
638 var mwritepropdef
: nullable MMethodDef writable
639 redef fun build_property
(modelbuilder
, mclassdef
)
641 var mclass
= mclassdef
.mclass
644 if self.n_id
!= null then
645 name
= self.n_id
.text
647 name
= self.n_id2
.text
650 if mclass
.kind
== interface_kind
or mclassdef
.mclass
.kind
== enum_kind
then
651 modelbuilder
.error
(self, "Error: Attempt to define attribute {name} in the interface {mclass}.")
652 else if mclass
.kind
== enum_kind
then
653 modelbuilder
.error
(self, "Error: Attempt to define attribute {name} in the enum class {mclass}.")
654 else if mclass
.kind
== extern_kind
then
655 modelbuilder
.error
(self, "Error: Attempt to define attribute {name} in the extern class {mclass}.")
660 # Old attribute style
661 var mprop
= modelbuilder
.try_get_mproperty_by_name
(nid
, mclassdef
, name
)
662 if mprop
== null then
663 var mvisibility
= new_property_visibility
(modelbuilder
, mclassdef
, self.n_visibility
)
664 mprop
= new MAttribute(mclassdef
, name
, mvisibility
)
665 if not self.check_redef_keyword
(modelbuilder
, mclassdef
, self.n_kwredef
, false, mprop
) then return
667 assert mprop
isa MAttribute
668 check_redef_property_visibility
(modelbuilder
, self.n_visibility
, mprop
)
669 if not self.check_redef_keyword
(modelbuilder
, mclassdef
, self.n_kwredef
, true, mprop
) then return
671 mclassdef
.mprop2npropdef
[mprop
] = self
673 var mpropdef
= new MAttributeDef(mclassdef
, mprop
, self.location
)
674 self.mpropdef
= mpropdef
675 modelbuilder
.mpropdef2npropdef
[mpropdef
] = self
678 var nreadable
= self.n_readable
679 if nreadable
!= null then modelbuilder
.error
(nreadable
, "Error: old-style getter no more supported")
680 var nwritable
= self.n_writable
681 if nwritable
!= null then modelbuilder
.error
(nwritable
, "Error: old-style setter no more supported")
683 # New attribute style
684 var nid2
= self.n_id2
.as(not null)
685 var mprop
= new MAttribute(mclassdef
, "_" + name
, private_visibility
)
686 var mpropdef
= new MAttributeDef(mclassdef
, mprop
, self.location
)
687 self.mpropdef
= mpropdef
688 modelbuilder
.mpropdef2npropdef
[mpropdef
] = self
692 var mreadprop
= modelbuilder
.try_get_mproperty_by_name
(nid2
, mclassdef
, readname
).as(nullable MMethod)
693 if mreadprop
== null then
694 var mvisibility
= new_property_visibility
(modelbuilder
, mclassdef
, self.n_visibility
)
695 mreadprop
= new MMethod(mclassdef
, readname
, mvisibility
)
696 if not self.check_redef_keyword
(modelbuilder
, mclassdef
, n_kwredef
, false, mreadprop
) then return
698 if not self.check_redef_keyword
(modelbuilder
, mclassdef
, n_kwredef
, true, mreadprop
) then return
699 check_redef_property_visibility
(modelbuilder
, self.n_visibility
, mreadprop
)
701 mclassdef
.mprop2npropdef
[mreadprop
] = self
703 var mreadpropdef
= new MMethodDef(mclassdef
, mreadprop
, self.location
)
704 self.mreadpropdef
= mreadpropdef
705 modelbuilder
.mpropdef2npropdef
[mreadpropdef
] = self
706 mreadpropdef
.mdoc
= mpropdef
.mdoc
708 var writename
= name
+ "="
709 var nwritable
= self.n_writable
710 var mwriteprop
= modelbuilder
.try_get_mproperty_by_name
(nid2
, mclassdef
, writename
).as(nullable MMethod)
711 var nwkwredef
: nullable Token = null
712 if nwritable
!= null then nwkwredef
= nwritable
.n_kwredef
713 if mwriteprop
== null then
715 if nwritable
!= null then
716 mvisibility
= new_property_visibility
(modelbuilder
, mclassdef
, nwritable
.n_visibility
)
718 mvisibility
= private_visibility
720 mwriteprop
= new MMethod(mclassdef
, writename
, mvisibility
)
721 if not self.check_redef_keyword
(modelbuilder
, mclassdef
, nwkwredef
, false, mwriteprop
) then return
723 if not self.check_redef_keyword
(modelbuilder
, mclassdef
, nwkwredef
or else n_kwredef
, true, mwriteprop
) then return
724 if nwritable
!= null then
725 check_redef_property_visibility
(modelbuilder
, nwritable
.n_visibility
, mwriteprop
)
728 mclassdef
.mprop2npropdef
[mwriteprop
] = self
730 var mwritepropdef
= new MMethodDef(mclassdef
, mwriteprop
, self.location
)
731 self.mwritepropdef
= mwritepropdef
732 modelbuilder
.mpropdef2npropdef
[mwritepropdef
] = self
733 mwritepropdef
.mdoc
= mpropdef
.mdoc
737 redef fun build_signature
(modelbuilder
)
739 var mpropdef
= self.mpropdef
740 if mpropdef
== null then return # Error thus skiped
741 var mclassdef
= mpropdef
.mclassdef
742 var mmodule
= mclassdef
.mmodule
743 var mtype
: nullable MType = null
745 var mreadpropdef
= self.mreadpropdef
747 var ntype
= self.n_type
748 if ntype
!= null then
749 mtype
= modelbuilder
.resolve_mtype
(mmodule
, mclassdef
, ntype
)
750 if mtype
== null then return
753 # Inherit the type from the getter (usually an abstact getter)
754 if mtype
== null and mreadpropdef
!= null and not mreadpropdef
.is_intro
then
755 var msignature
= mreadpropdef
.mproperty
.intro
.msignature
756 if msignature
== null then return # Error, thus skiped
757 mtype
= msignature
.return_mtype
760 var nexpr
= self.n_expr
761 if mtype
== null then
762 if nexpr
!= null then
763 if nexpr
isa ANewExpr then
764 mtype
= modelbuilder
.resolve_mtype
(mmodule
, mclassdef
, nexpr
.n_type
)
765 else if nexpr
isa AIntExpr then
766 var cla
= modelbuilder
.try_get_mclass_by_name
(nexpr
, mmodule
, "Int")
767 if cla
!= null then mtype
= cla
.mclass_type
768 else if nexpr
isa AFloatExpr then
769 var cla
= modelbuilder
.try_get_mclass_by_name
(nexpr
, mmodule
, "Float")
770 if cla
!= null then mtype
= cla
.mclass_type
771 else if nexpr
isa ACharExpr then
772 var cla
= modelbuilder
.try_get_mclass_by_name
(nexpr
, mmodule
, "Char")
773 if cla
!= null then mtype
= cla
.mclass_type
774 else if nexpr
isa ABoolExpr then
775 var cla
= modelbuilder
.try_get_mclass_by_name
(nexpr
, mmodule
, "Bool")
776 if cla
!= null then mtype
= cla
.mclass_type
777 else if nexpr
isa ASuperstringExpr then
778 var cla
= modelbuilder
.try_get_mclass_by_name
(nexpr
, mmodule
, "String")
779 if cla
!= null then mtype
= cla
.mclass_type
780 else if nexpr
isa AStringFormExpr then
781 var cla
= modelbuilder
.try_get_mclass_by_name
(nexpr
, mmodule
, "String")
782 if cla
!= null then mtype
= cla
.mclass_type
784 modelbuilder
.error
(self, "Error: Untyped attribute {mpropdef}. Implicit typing allowed only for literals and new.")
787 if mtype
== null then return
789 else if ntype
!= null then
790 if nexpr
isa ANewExpr then
791 var xmtype
= modelbuilder
.resolve_mtype
(mmodule
, mclassdef
, nexpr
.n_type
)
792 if xmtype
== mtype
and modelbuilder
.toolcontext
.opt_warn
.value
>= 2 then
793 modelbuilder
.warning
(ntype
, "Warning: useless type definition")
798 if mtype
== null then
799 modelbuilder
.error
(self, "Error: Untyped attribute {mpropdef}")
803 mpropdef
.static_mtype
= mtype
805 if mreadpropdef
!= null then
806 var msignature
= new MSignature(new Array[MParameter], mtype
)
807 mreadpropdef
.msignature
= msignature
810 var msritepropdef
= self.mwritepropdef
811 if mwritepropdef
!= null then
814 name
= n_id
.text
.substring_from
(1)
818 var mparameter
= new MParameter(name
, mtype
, false)
819 var msignature
= new MSignature([mparameter
], null)
820 mwritepropdef
.msignature
= msignature
824 redef fun check_signature
(modelbuilder
)
826 var mpropdef
= self.mpropdef
827 if mpropdef
== null then return # Error thus skiped
828 var mclassdef
= mpropdef
.mclassdef
829 var mmodule
= mclassdef
.mmodule
830 var ntype
= self.n_type
831 var mtype
= self.mpropdef
.static_mtype
832 if mtype
== null then return # Error thus skiped
834 # Lookup for signature in the precursor
835 # FIXME all precursors should be considered
836 if not mpropdef
.is_intro
then
837 var precursor_type
= mpropdef
.mproperty
.intro
.static_mtype
838 if precursor_type
== null then return
840 if mtype
!= precursor_type
then
841 modelbuilder
.error
(ntype
.as(not null), "Redef Error: Wrong static type. found {mtype}, expected {precursor_type}.")
846 # Check getter and setter
847 var meth
= self.mreadpropdef
849 self.check_method_signature
(modelbuilder
, meth
)
850 var node
: nullable ANode = ntype
851 if node
== null then node
= self
852 modelbuilder
.check_visibility
(node
, mtype
, meth
)
854 meth
= self.mwritepropdef
856 self.check_method_signature
(modelbuilder
, meth
)
857 var node
: nullable ANode = ntype
858 if node
== null then node
= self
859 modelbuilder
.check_visibility
(node
, mtype
, meth
)
863 private fun check_method_signature
(modelbuilder
: ModelBuilder, mpropdef
: MMethodDef)
865 var mclassdef
= mpropdef
.mclassdef
866 var mmodule
= mclassdef
.mmodule
867 var nsig
= self.n_type
868 var mysignature
= mpropdef
.msignature
869 if mysignature
== null then return # Error thus skiped
871 # Lookup for signature in the precursor
872 # FIXME all precursors should be considered
873 if not mpropdef
.is_intro
then
874 var msignature
= mpropdef
.mproperty
.intro
.msignature
875 if msignature
== null then return
877 if mysignature
.arity
!= msignature
.arity
then
879 if nsig
!= null then node
= nsig
else node
= self
880 modelbuilder
.error
(node
, "Redef Error: {mysignature.arity} parameters found, {msignature.arity} expected. Signature is {mpropdef}{msignature}")
883 var precursor_ret_type
= msignature
.return_mtype
884 var ret_type
= mysignature
.return_mtype
885 if ret_type
!= null and precursor_ret_type
== null then
887 if nsig
!= null then node
= nsig
else node
= self
888 modelbuilder
.error
(node
, "Redef Error: {mpropdef.mproperty} is a procedure, not a function.")
892 if mysignature
.arity
> 0 then
893 # Check parameters types
894 for i
in [0..mysignature
.arity
[ do
895 var myt
= mysignature
.mparameters
[i
].mtype
896 var prt
= msignature
.mparameters
[i
].mtype
897 if not myt
.is_subtype
(mmodule
, mclassdef
.bound_mtype
, prt
) or
898 not prt
.is_subtype
(mmodule
, mclassdef
.bound_mtype
, myt
) then
900 if nsig
!= null then node
= nsig
else node
= self
901 modelbuilder
.error
(node
, "Redef Error: Wrong type for parameter `{mysignature.mparameters[i].name}'. found {myt}, expected {prt}.")
905 if precursor_ret_type
!= null then
906 if ret_type
== null then
907 # Inherit the return type
908 ret_type
= precursor_ret_type
909 else if not ret_type
.is_subtype
(mmodule
, mclassdef
.bound_mtype
, precursor_ret_type
) then
911 if nsig
!= null then node
= nsig
else node
= self
912 modelbuilder
.error
(node
, "Redef Error: Wrong return type. found {ret_type}, expected {precursor_ret_type}.")
919 redef class ATypePropdef
920 redef type MPROPDEF: MVirtualTypeDef
922 redef fun build_property
(modelbuilder
, mclassdef
)
924 var name
= self.n_id
.text
925 var mprop
= modelbuilder
.try_get_mproperty_by_name
(self.n_id
, mclassdef
, name
)
926 if mprop
== null then
927 var mvisibility
= new_property_visibility
(modelbuilder
, mclassdef
, self.n_visibility
)
928 mprop
= new MVirtualTypeProp(mclassdef
, name
, mvisibility
)
929 for c
in name
.chars
do if c
>= 'a' and c
<= 'z' then
930 modelbuilder
.warning
(n_id
, "Warning: lowercase in the virtual type {name}")
933 if not self.check_redef_keyword
(modelbuilder
, mclassdef
, self.n_kwredef
, false, mprop
) then return
935 if not self.check_redef_keyword
(modelbuilder
, mclassdef
, self.n_kwredef
, true, mprop
) then return
936 assert mprop
isa MVirtualTypeProp
937 check_redef_property_visibility
(modelbuilder
, self.n_visibility
, mprop
)
939 mclassdef
.mprop2npropdef
[mprop
] = self
941 var mpropdef
= new MVirtualTypeDef(mclassdef
, mprop
, self.location
)
942 self.mpropdef
= mpropdef
943 modelbuilder
.mpropdef2npropdef
[mpropdef
] = self
947 redef fun build_signature
(modelbuilder
)
949 var mpropdef
= self.mpropdef
950 if mpropdef
== null then return # Error thus skiped
951 var mclassdef
= mpropdef
.mclassdef
952 var mmodule
= mclassdef
.mmodule
953 var mtype
: nullable MType = null
955 var ntype
= self.n_type
956 mtype
= modelbuilder
.resolve_mtype
(mmodule
, mclassdef
, ntype
)
957 if mtype
== null then return
959 mpropdef
.bound
= mtype
960 # print "{mpropdef}: {mtype}"
963 redef fun check_signature
(modelbuilder
)
965 var mpropdef
= self.mpropdef
966 if mpropdef
== null then return # Error thus skiped
968 var bound
= self.mpropdef
.bound
969 if bound
== null then return # Error thus skiped
971 modelbuilder
.check_visibility
(n_type
.as(not null), bound
, mpropdef
)
973 # Fast case: the bound is not a formal type
974 if not bound
isa MVirtualType then return
976 var mclassdef
= mpropdef
.mclassdef
977 var mmodule
= mclassdef
.mmodule
978 var anchor
= mclassdef
.bound_mtype
980 # Slow case: progress on each resolution until: (i) we loop, or (ii) we found a non formal type
981 var seen
= [self.mpropdef
.mproperty
.mvirtualtype
]
983 if seen
.has
(bound
) then
985 modelbuilder
.error
(self, "Error: circularity of virtual type definition: {seen.join(" -> ")}")
989 var next
= bound
.lookup_bound
(mmodule
, anchor
)
990 if not next
isa MVirtualType then break