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
, none_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 ntype
= self.n_type
746 if ntype
!= null then
747 mtype
= modelbuilder
.resolve_mtype
(mmodule
, mclassdef
, ntype
)
748 if mtype
== null then return
751 var nexpr
= self.n_expr
752 if mtype
== null then
753 if nexpr
!= null then
754 if nexpr
isa ANewExpr then
755 mtype
= modelbuilder
.resolve_mtype
(mmodule
, mclassdef
, nexpr
.n_type
)
756 else if nexpr
isa AIntExpr then
757 var cla
= modelbuilder
.try_get_mclass_by_name
(nexpr
, mmodule
, "Int")
758 if cla
!= null then mtype
= cla
.mclass_type
759 else if nexpr
isa AFloatExpr then
760 var cla
= modelbuilder
.try_get_mclass_by_name
(nexpr
, mmodule
, "Float")
761 if cla
!= null then mtype
= cla
.mclass_type
762 else if nexpr
isa ACharExpr then
763 var cla
= modelbuilder
.try_get_mclass_by_name
(nexpr
, mmodule
, "Char")
764 if cla
!= null then mtype
= cla
.mclass_type
765 else if nexpr
isa ABoolExpr then
766 var cla
= modelbuilder
.try_get_mclass_by_name
(nexpr
, mmodule
, "Bool")
767 if cla
!= null then mtype
= cla
.mclass_type
768 else if nexpr
isa ASuperstringExpr then
769 var cla
= modelbuilder
.try_get_mclass_by_name
(nexpr
, mmodule
, "String")
770 if cla
!= null then mtype
= cla
.mclass_type
771 else if nexpr
isa AStringFormExpr then
772 var cla
= modelbuilder
.try_get_mclass_by_name
(nexpr
, mmodule
, "String")
773 if cla
!= null then mtype
= cla
.mclass_type
775 modelbuilder
.error
(self, "Error: Untyped attribute {mpropdef}. Implicit typing allowed only for literals and new.")
779 modelbuilder
.error
(self, "Error: Untyped attribute {mpropdef}")
783 if nexpr
isa ANewExpr then
784 var xmtype
= modelbuilder
.resolve_mtype
(mmodule
, mclassdef
, nexpr
.n_type
)
785 if xmtype
== mtype
and modelbuilder
.toolcontext
.opt_warn
.value
>= 2 then
786 modelbuilder
.warning
(ntype
, "Warning: useless type definition")
791 if mtype
== null then return
793 mpropdef
.static_mtype
= mtype
795 var mreadpropdef
= self.mreadpropdef
796 if mreadpropdef
!= null then
797 var msignature
= new MSignature(new Array[MParameter], mtype
)
798 mreadpropdef
.msignature
= msignature
801 var msritepropdef
= self.mwritepropdef
802 if mwritepropdef
!= null then
805 name
= n_id
.text
.substring_from
(1)
809 var mparameter
= new MParameter(name
, mtype
, false)
810 var msignature
= new MSignature([mparameter
], null)
811 mwritepropdef
.msignature
= msignature
815 redef fun check_signature
(modelbuilder
)
817 var mpropdef
= self.mpropdef
818 if mpropdef
== null then return # Error thus skiped
819 var mclassdef
= mpropdef
.mclassdef
820 var mmodule
= mclassdef
.mmodule
821 var ntype
= self.n_type
822 var mtype
= self.mpropdef
.static_mtype
823 if mtype
== null then return # Error thus skiped
825 # Lookup for signature in the precursor
826 # FIXME all precursors should be considered
827 if not mpropdef
.is_intro
then
828 var precursor_type
= mpropdef
.mproperty
.intro
.static_mtype
829 if precursor_type
== null then return
831 if mtype
!= precursor_type
then
832 modelbuilder
.error
(ntype
.as(not null), "Redef Error: Wrong static type. found {mtype}, expected {precursor_type}.")
837 # Check getter and setter
838 var meth
= self.mreadpropdef
840 self.check_method_signature
(modelbuilder
, meth
)
841 var node
: nullable ANode = ntype
842 if node
== null then node
= self
843 modelbuilder
.check_visibility
(node
, mtype
, meth
)
845 meth
= self.mwritepropdef
847 self.check_method_signature
(modelbuilder
, meth
)
848 var node
: nullable ANode = ntype
849 if node
== null then node
= self
850 modelbuilder
.check_visibility
(node
, mtype
, meth
)
854 private fun check_method_signature
(modelbuilder
: ModelBuilder, mpropdef
: MMethodDef)
856 var mclassdef
= mpropdef
.mclassdef
857 var mmodule
= mclassdef
.mmodule
858 var nsig
= self.n_type
859 var mysignature
= mpropdef
.msignature
860 if mysignature
== null then return # Error thus skiped
862 # Lookup for signature in the precursor
863 # FIXME all precursors should be considered
864 if not mpropdef
.is_intro
then
865 var msignature
= mpropdef
.mproperty
.intro
.msignature
866 if msignature
== null then return
868 if mysignature
.arity
!= msignature
.arity
then
870 if nsig
!= null then node
= nsig
else node
= self
871 modelbuilder
.error
(node
, "Redef Error: {mysignature.arity} parameters found, {msignature.arity} expected. Signature is {mpropdef}{msignature}")
874 var precursor_ret_type
= msignature
.return_mtype
875 var ret_type
= mysignature
.return_mtype
876 if ret_type
!= null and precursor_ret_type
== null then
878 if nsig
!= null then node
= nsig
else node
= self
879 modelbuilder
.error
(node
, "Redef Error: {mpropdef.mproperty} is a procedure, not a function.")
883 if mysignature
.arity
> 0 then
884 # Check parameters types
885 for i
in [0..mysignature
.arity
[ do
886 var myt
= mysignature
.mparameters
[i
].mtype
887 var prt
= msignature
.mparameters
[i
].mtype
888 if not myt
.is_subtype
(mmodule
, mclassdef
.bound_mtype
, prt
) or
889 not prt
.is_subtype
(mmodule
, mclassdef
.bound_mtype
, myt
) then
891 if nsig
!= null then node
= nsig
else node
= self
892 modelbuilder
.error
(node
, "Redef Error: Wrong type for parameter `{mysignature.mparameters[i].name}'. found {myt}, expected {prt}.")
896 if precursor_ret_type
!= null then
897 if ret_type
== null then
898 # Inherit the return type
899 ret_type
= precursor_ret_type
900 else if not ret_type
.is_subtype
(mmodule
, mclassdef
.bound_mtype
, precursor_ret_type
) then
902 if nsig
!= null then node
= nsig
else node
= self
903 modelbuilder
.error
(node
, "Redef Error: Wrong return type. found {ret_type}, expected {precursor_ret_type}.")
910 redef class ATypePropdef
911 redef type MPROPDEF: MVirtualTypeDef
913 redef fun build_property
(modelbuilder
, mclassdef
)
915 var name
= self.n_id
.text
916 var mprop
= modelbuilder
.try_get_mproperty_by_name
(self.n_id
, mclassdef
, name
)
917 if mprop
== null then
918 var mvisibility
= new_property_visibility
(modelbuilder
, mclassdef
, self.n_visibility
)
919 mprop
= new MVirtualTypeProp(mclassdef
, name
, mvisibility
)
920 for c
in name
.chars
do if c
>= 'a' and c
<= 'z' then
921 modelbuilder
.warning
(n_id
, "Warning: lowercase in the virtual type {name}")
924 if not self.check_redef_keyword
(modelbuilder
, mclassdef
, self.n_kwredef
, false, mprop
) then return
926 if not self.check_redef_keyword
(modelbuilder
, mclassdef
, self.n_kwredef
, true, mprop
) then return
927 assert mprop
isa MVirtualTypeProp
928 check_redef_property_visibility
(modelbuilder
, self.n_visibility
, mprop
)
930 mclassdef
.mprop2npropdef
[mprop
] = self
932 var mpropdef
= new MVirtualTypeDef(mclassdef
, mprop
, self.location
)
933 self.mpropdef
= mpropdef
934 modelbuilder
.mpropdef2npropdef
[mpropdef
] = self
938 redef fun build_signature
(modelbuilder
)
940 var mpropdef
= self.mpropdef
941 if mpropdef
== null then return # Error thus skiped
942 var mclassdef
= mpropdef
.mclassdef
943 var mmodule
= mclassdef
.mmodule
944 var mtype
: nullable MType = null
946 var ntype
= self.n_type
947 mtype
= modelbuilder
.resolve_mtype
(mmodule
, mclassdef
, ntype
)
948 if mtype
== null then return
950 mpropdef
.bound
= mtype
951 # print "{mpropdef}: {mtype}"
954 redef fun check_signature
(modelbuilder
)
956 var mpropdef
= self.mpropdef
957 if mpropdef
== null then return # Error thus skiped
959 var bound
= self.mpropdef
.bound
960 if bound
== null then return # Error thus skiped
962 modelbuilder
.check_visibility
(n_type
.as(not null), bound
, mpropdef
)
964 # Fast case: the bound is not a formal type
965 if not bound
isa MVirtualType then return
967 var mclassdef
= mpropdef
.mclassdef
968 var mmodule
= mclassdef
.mmodule
969 var anchor
= mclassdef
.bound_mtype
971 # Slow case: progress on each resolution until: (i) we loop, or (ii) we found a non formal type
972 var seen
= [self.mpropdef
.mproperty
.mvirtualtype
]
974 if seen
.has
(bound
) then
976 modelbuilder
.error
(self, "Error: circularity of virtual type definition: {seen.join(" -> ")}")
980 var next
= bound
.lookup_bound
(mmodule
, anchor
)
981 if not next
isa MVirtualType then break