1 # This file is part of NIT ( http://www.nitlanguage.org ).
3 # Copyright 2012 Jean Privat <jean@pryen.org>
5 # Licensed under the Apache License, Version 2.0 (the "License");
6 # you may not use this file except in compliance with the License.
7 # You may obtain a copy of the License at
9 # http://www.apache.org/licenses/LICENSE-2.0
11 # Unless required by applicable law or agreed to in writing, software
12 # distributed under the License is distributed on an "AS IS" BASIS,
13 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 # See the License for the specific language governing permissions and
15 # limitations under the License.
17 # Analysis and verification of property definitions to instantiate model element
18 module modelize_property
22 redef class ToolContext
23 var modelize_property_phase
: Phase = new ModelizePropertyPhase(self, [modelize_class_phase
])
26 private class ModelizePropertyPhase
28 redef fun process_nmodule
(nmodule
)
30 for nclassdef
in nmodule
.n_classdefs
do
31 toolcontext
.modelbuilder
.build_properties
(nclassdef
)
36 redef class ModelBuilder
37 # Register the npropdef associated to each mpropdef
38 # FIXME: why not refine the `MPropDef` class with a nullable attribute?
39 var mpropdef2npropdef
: HashMap[MPropDef, APropdef] = new HashMap[MPropDef, APropdef]
41 # Build the properties of `nclassdef`.
42 # REQUIRE: all superclasses are built.
43 private fun build_properties
(nclassdef
: AClassdef)
45 # Force building recursively
46 if nclassdef
.build_properties_is_done
then return
47 nclassdef
.build_properties_is_done
= true
48 var mclassdef
= nclassdef
.mclassdef
.as(not null)
49 if mclassdef
.in_hierarchy
== null then return # Skip error
50 for superclassdef
in mclassdef
.in_hierarchy
.direct_greaters
do
51 build_properties
(mclassdef2nclassdef
[superclassdef
])
54 for npropdef
in nclassdef
.n_propdefs
do
55 npropdef
.build_property
(self, nclassdef
)
57 for npropdef
in nclassdef
.n_propdefs
do
58 npropdef
.build_signature
(self, nclassdef
)
60 for npropdef
in nclassdef
.n_propdefs
do
61 npropdef
.check_signature
(self, nclassdef
)
63 process_default_constructors
(nclassdef
)
66 # Introduce or inherit default constructor
67 # This is the last part of `build_properties`.
68 private fun process_default_constructors
(nclassdef
: AClassdef)
70 var mclassdef
= nclassdef
.mclassdef
.as(not null)
73 if not mclassdef
.is_intro
then return
75 # Is the class forbid constructors?
76 if not mclassdef
.mclass
.kind
.need_init
then return
78 # Is there already a constructor defined?
79 for mpropdef
in mclassdef
.mpropdefs
do
80 if not mpropdef
isa MMethodDef then continue
81 if mpropdef
.mproperty
.is_init
then return
84 if not nclassdef
isa AStdClassdef then return
86 var mmodule
= nclassdef
.mclassdef
.mmodule
87 # Do we inherit for a constructor?
88 var combine
= new Array[MMethod]
89 var inhc
: nullable MClass = null
90 for st
in mclassdef
.supertypes
do
92 if not c
.kind
.need_init
then continue
93 st
= st
.anchor_to
(mmodule
, nclassdef
.mclassdef
.bound_mtype
)
94 var candidate
= self.try_get_mproperty_by_name2
(nclassdef
, mmodule
, st
, "init").as(nullable MMethod)
95 if candidate
!= null and candidate
.intro
.msignature
.arity
== 0 then
96 combine
.add
(candidate
)
99 var inhc2
= c
.inherit_init_from
100 if inhc2
== null then inhc2
= c
101 if inhc2
== inhc
then continue
103 self.error
(nclassdef
, "Error: Cannot provide a defaut constructor: conflict for {inhc} and {c}")
108 if combine
.is_empty
and inhc
!= null then
109 # TODO: actively inherit the consturctor
110 self.toolcontext
.info
("{mclassdef} inherits all constructors from {inhc}", 3)
111 mclassdef
.mclass
.inherit_init_from
= inhc
114 if not combine
.is_empty
and inhc
!= null then
115 self.error
(nclassdef
, "Error: Cannot provide a defaut constructor: conflict for {combine.join(", ")} and {inhc}")
119 if not combine
.is_empty
then
120 nclassdef
.super_inits
= combine
121 var mprop
= new MMethod(mclassdef
, "init", mclassdef
.mclass
.visibility
)
122 var mpropdef
= new MMethodDef(mclassdef
, mprop
, nclassdef
.location
)
123 var mparameters
= new Array[MParameter]
124 var msignature
= new MSignature(mparameters
, null)
125 mpropdef
.msignature
= msignature
127 nclassdef
.mfree_init
= mpropdef
128 self.toolcontext
.info
("{mclassdef} gets a free empty constructor {mpropdef}{msignature}", 3)
132 # Collect undefined attributes
133 var mparameters
= new Array[MParameter]
134 for npropdef
in nclassdef
.n_propdefs
do
135 if npropdef
isa AAttrPropdef and npropdef
.n_expr
== null then
136 if npropdef
.mpropdef
== null then return # Skip broken attribute
137 var paramname
= npropdef
.mpropdef
.mproperty
.name
.substring_from
(1)
138 var ret_type
= npropdef
.mpropdef
.static_mtype
139 if ret_type
== null then return
140 var mparameter
= new MParameter(paramname
, ret_type
, false)
141 mparameters
.add
(mparameter
)
145 var mprop
= new MMethod(mclassdef
, "init", mclassdef
.mclass
.visibility
)
146 var mpropdef
= new MMethodDef(mclassdef
, mprop
, nclassdef
.location
)
147 var msignature
= new MSignature(mparameters
, null)
148 mpropdef
.msignature
= msignature
150 nclassdef
.mfree_init
= mpropdef
151 self.toolcontext
.info
("{mclassdef} gets a free constructor for attributes {mpropdef}{msignature}", 3)
154 # Check the visibility of `mtype` as an element of the signature of `mpropdef`.
155 fun check_visibility
(node
: ANode, mtype
: MType, mpropdef
: MPropDef)
157 var mmodule
= mpropdef
.mclassdef
.mmodule
158 var mproperty
= mpropdef
.mproperty
160 # Extract visibility information of the main part of `mtype`
161 # It is a case-by case
162 var vis_type
: nullable MVisibility = null # The own visibility of the type
163 var mmodule_type
: nullable MModule = null # The origial module of the type
164 if mtype
isa MNullableType then mtype
= mtype
.mtype
165 if mtype
isa MClassType then
166 vis_type
= mtype
.mclass
.visibility
167 mmodule_type
= mtype
.mclass
.intro
.mmodule
168 else if mtype
isa MVirtualType then
169 vis_type
= mtype
.mproperty
.visibility
170 mmodule_type
= mtype
.mproperty
.intro_mclassdef
.mmodule
171 else if mtype
isa MParameterType then
172 # nothing, always visible
174 node
.debug
"Unexpected type {mtype}"
178 if vis_type
!= null then
179 assert mmodule_type
!= null
180 var vis_module_type
= mmodule
.visibility_for
(mmodule_type
) # the visibility of the original module
181 if mproperty
.visibility
> vis_type
then
182 error
(node
, "Error: The {mproperty.visibility} property `{mproperty}` cannot contain the {vis_type} type `{mtype}`")
184 else if mproperty
.visibility
> vis_module_type
then
185 error
(node
, "Error: The {mproperty.visibility} property `{mproperty}` cannot contain the type `{mtype}` from the {vis_module_type} module `{mmodule_type}`")
190 # No error, try to go deeper in generic types
191 if node
isa AType then
192 for a
in node
.n_types
do check_visibility
(a
, a
.mtype
.as(not null), mpropdef
)
193 else if mtype
isa MGenericType then
194 for t
in mtype
.arguments
do check_visibility
(node
, t
, mpropdef
)
200 # The class whose self inherit all the constructors.
201 # 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
202 var inherit_init_from
: nullable MClass = null
205 redef class MClassDef
206 private var propdef_names
= new HashSet[String]
210 # Does the MPropDef contains a call to super or a call of a super-constructor?
211 # Subsequent phases of the frontend (esp. typing) set it if required
212 var has_supercall
: Bool writable = false
215 redef class AClassdef
216 var build_properties_is_done
: Bool = false
217 # The list of super-constructor to call at the start of the free constructor
218 # 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
219 var super_inits
: nullable Collection[MMethod] = null
221 # The free init (implicitely constructed by the class if required)
222 var mfree_init
: nullable MMethodDef = null
224 # What is the `APropdef` associated to a `MProperty`?
225 # Used to check multiple definition of a property.
226 var mprop2npropdef
: Map[MProperty, APropdef] = new HashMap[MProperty, APropdef]
230 # Join the text of all tokens
231 # Used to get the 'real name' of method definitions.
232 fun collect_text
: String
234 var v
= new TextCollectorVisitor
241 private class TextCollectorVisitor
243 var text
: String = ""
246 if n
isa Token then text
+= n
.text
252 # The associated main model entity
253 type MPROPDEF: MPropDef
255 # The associated propdef once build by a `ModelBuilder`
256 var mpropdef
: nullable MPROPDEF writable
258 private fun build_property
(modelbuilder
: ModelBuilder, nclassdef
: AClassdef) is abstract
259 private fun build_signature
(modelbuilder
: ModelBuilder, nclassdef
: AClassdef) is abstract
260 private fun check_signature
(modelbuilder
: ModelBuilder, nclassdef
: AClassdef) is abstract
261 private fun new_property_visibility
(modelbuilder
: ModelBuilder, nclassdef
: AClassdef, nvisibility
: nullable AVisibility): MVisibility
263 var mvisibility
= public_visibility
264 if nvisibility
!= null then
265 mvisibility
= nvisibility
.mvisibility
266 if mvisibility
== intrude_visibility
then
267 modelbuilder
.error
(nvisibility
, "Error: intrude is not a legal visibility for properties.")
268 mvisibility
= public_visibility
271 if nclassdef
.mclassdef
.mclass
.visibility
== private_visibility
then
272 if mvisibility
== protected_visibility
then
273 assert nvisibility
!= null
274 modelbuilder
.error
(nvisibility
, "Error: The only legal visibility for properties in a private class is private.")
275 else if mvisibility
== private_visibility
then
276 assert nvisibility
!= null
278 # modelbuilder.warning(nvisibility, "Warning: private is unrequired since the only legal visibility for properties in a private class is private.")
280 mvisibility
= private_visibility
285 private fun set_doc
(mpropdef
: MPropDef)
287 var ndoc
= self.n_doc
288 if ndoc
!= null then mpropdef
.mdoc
= ndoc
.to_mdoc
291 private fun check_redef_property_visibility
(modelbuilder
: ModelBuilder, nclassdef
: AClassdef, nvisibility
: nullable AVisibility, mprop
: MProperty)
293 if nvisibility
== null then return
294 var mvisibility
= nvisibility
.mvisibility
295 if mvisibility
!= mprop
.visibility
and mvisibility
!= public_visibility
then
296 modelbuilder
.error
(nvisibility
, "Error: redefinition changed the visibility from a {mprop.visibility} to a {mvisibility}")
300 private fun check_redef_keyword
(modelbuilder
: ModelBuilder, nclassdef
: AClassdef, kwredef
: nullable Token, need_redef
: Bool, mprop
: MProperty): Bool
302 if nclassdef
.mprop2npropdef
.has_key
(mprop
) then
303 modelbuilder
.error
(self, "Error: A property {mprop} is already defined in class {nclassdef.mclassdef.mclass}.")
306 if kwredef
== null then
308 modelbuilder
.error
(self, "Redef error: {nclassdef.mclassdef.mclass}::{mprop.name} is an inherited property. To redefine it, add the redef keyword.")
312 if not need_redef
then
313 modelbuilder
.error
(self, "Error: No property {nclassdef.mclassdef.mclass}::{mprop.name} is inherited. Remove the redef keyword to define a new property.")
322 redef class ASignature
323 # Is the model builder has correctly visited the signature
324 var is_visited
= false
325 # Names of parameters from the AST
326 # REQUIRE: is_visited
327 var param_names
= new Array[String]
328 # Types of parameters from the AST
329 # REQUIRE: is_visited
330 var param_types
= new Array[MType]
331 # Rank of the vararg (of -1 if none)
332 # REQUIRE: is_visited
333 var vararg_rank
: Int = -1
335 var ret_type
: nullable MType = null
337 # Visit and fill information about a signature
338 private fun visit_signature
(modelbuilder
: ModelBuilder, nclassdef
: AClassdef): Bool
340 var param_names
= self.param_names
341 var param_types
= self.param_types
342 for np
in self.n_params
do
343 param_names
.add
(np
.n_id
.text
)
344 var ntype
= np
.n_type
345 if ntype
!= null then
346 var mtype
= modelbuilder
.resolve_mtype
(nclassdef
, ntype
)
347 if mtype
== null then return false # Skip error
348 for i
in [0..param_names
.length-param_types
.length
[ do
349 param_types
.add
(mtype
)
351 if np
.n_dotdotdot
!= null then
352 if self.vararg_rank
!= -1 then
353 modelbuilder
.error
(np
, "Error: {param_names[self.vararg_rank]} is already a vararg")
356 self.vararg_rank
= param_names
.length
- 1
361 var ntype
= self.n_type
362 if ntype
!= null then
363 self.ret_type
= modelbuilder
.resolve_mtype
(nclassdef
, ntype
)
364 if self.ret_type
== null then return false # Skip errir
367 self.is_visited
= true
371 # Build a visited signature
372 fun build_signature
(modelbuilder
: ModelBuilder, nclassdef
: AClassdef): nullable MSignature
374 if param_names
.length
!= param_types
.length
then
375 # Some parameters are typed, other parameters are not typed.
376 modelbuilder
.error
(self.n_params
[param_types
.length
], "Error: Untyped parameter `{param_names[param_types.length]}'.")
380 var mparameters
= new Array[MParameter]
381 for i
in [0..param_names
.length
[ do
382 var mparameter
= new MParameter(param_names
[i
], param_types
[i
], i
== vararg_rank
)
383 self.n_params
[i
].mparameter
= mparameter
384 mparameters
.add
(mparameter
)
387 var msignature
= new MSignature(mparameters
, ret_type
)
393 # The associated mparameter if any
394 var mparameter
: nullable MParameter = null
397 redef class AMethPropdef
398 redef type MPROPDEF: MMethodDef
400 redef fun build_property
(modelbuilder
, nclassdef
)
402 var is_init
= self isa AInitPropdef
403 var mclassdef
= nclassdef
.mclassdef
.as(not null)
405 var amethodid
= self.n_methid
407 if amethodid
== null then
408 if self isa AMainMethPropdef then
411 else if self isa AConcreteInitPropdef then
413 name_node
= self.n_kwinit
414 else if self isa AExternInitPropdef then
416 name_node
= self.n_kwnew
420 else if amethodid
isa AIdMethid then
421 name
= amethodid
.n_id
.text
422 name_node
= amethodid
424 # operator, bracket or assign
425 name
= amethodid
.collect_text
426 name_node
= amethodid
428 if name
== "-" and self.n_signature
.n_params
.length
== 0 then
433 var mprop
: nullable MMethod = null
434 if not is_init
or n_kwredef
!= null then mprop
= modelbuilder
.try_get_mproperty_by_name
(name_node
, mclassdef
, name
).as(nullable MMethod)
435 if mprop
== null then
436 var mvisibility
= new_property_visibility
(modelbuilder
, nclassdef
, self.n_visibility
)
437 mprop
= new MMethod(mclassdef
, name
, mvisibility
)
438 mprop
.is_init
= is_init
439 mprop
.is_new
= self isa AExternInitPropdef
440 if not self.check_redef_keyword
(modelbuilder
, nclassdef
, n_kwredef
, false, mprop
) then return
442 if n_kwredef
== null then
443 if self isa AMainMethPropdef then
446 if not self.check_redef_keyword
(modelbuilder
, nclassdef
, n_kwredef
, true, mprop
) then return
449 check_redef_property_visibility
(modelbuilder
, nclassdef
, self.n_visibility
, mprop
)
451 nclassdef
.mprop2npropdef
[mprop
] = self
453 var mpropdef
= new MMethodDef(mclassdef
, mprop
, self.location
)
455 if mclassdef
.propdef_names
.has
(mprop
.name
) then
456 var loc
: nullable Location = null
457 for i
in mclassdef
.mpropdefs
do
458 if i
.mproperty
.name
== mprop
.name
then
463 if loc
== null then abort
464 modelbuilder
.error
(self, "Error: a property {mprop} is already defined in class {mclassdef.mclass} at {loc}")
467 mclassdef
.propdef_names
.add
(mpropdef
.mproperty
.name
)
471 self.mpropdef
= mpropdef
472 modelbuilder
.mpropdef2npropdef
[mpropdef
] = self
473 if mpropdef
.is_intro
then
474 modelbuilder
.toolcontext
.info
("{mpropdef} introduces new method {mprop.full_name}", 3)
476 modelbuilder
.toolcontext
.info
("{mpropdef} redefines method {mprop.full_name}", 3)
480 redef fun build_signature
(modelbuilder
, nclassdef
)
482 var mpropdef
= self.mpropdef
483 if mpropdef
== null then return # Error thus skiped
484 var mmodule
= mpropdef
.mclassdef
.mmodule
485 var nsig
= self.n_signature
487 # Retrieve info from the signature AST
488 var param_names
= new Array[String] # Names of parameters from the AST
489 var param_types
= new Array[MType] # Types of parameters from the AST
491 var ret_type
: nullable MType = null # Return type from the AST
493 if not nsig
.visit_signature
(modelbuilder
, nclassdef
) then return
494 param_names
= nsig
.param_names
495 param_types
= nsig
.param_types
496 vararg_rank
= nsig
.vararg_rank
497 ret_type
= nsig
.ret_type
500 # Look for some signature to inherit
501 # FIXME: do not inherit from the intro, but from the most specific
502 var msignature
: nullable MSignature = null
503 if not mpropdef
.is_intro
then
504 msignature
= mpropdef
.mproperty
.intro
.msignature
505 if msignature
== null then return # Skip error
507 # Check inherited signature arity
508 if param_names
.length
!= msignature
.arity
then
510 if nsig
!= null then node
= nsig
else node
= self
511 modelbuilder
.error
(node
, "Redef error: {mpropdef} redefines {mpropdef.mproperty.intro} with {param_names.length} parameter(s), {msignature.arity} expected. Signature is {mpropdef}{msignature}")
514 else if mpropdef
.mproperty
.is_init
then
515 # FIXME UGLY: inherit signature from a super-constructor
516 for msupertype
in nclassdef
.mclassdef
.supertypes
do
517 msupertype
= msupertype
.anchor_to
(mmodule
, nclassdef
.mclassdef
.bound_mtype
)
518 var candidate
= modelbuilder
.try_get_mproperty_by_name2
(self, mmodule
, msupertype
, mpropdef
.mproperty
.name
)
519 if candidate
!= null then
520 if msignature
== null then
521 msignature
= candidate
.intro
.as(MMethodDef).msignature
528 # Inherit the signature
529 if msignature
!= null and param_names
.length
!= param_types
.length
and param_names
.length
== msignature
.arity
and param_types
.length
== 0 then
530 # Parameters are untyped, thus inherit them
531 param_types
= new Array[MType]
532 for mparameter
in msignature
.mparameters
do
533 param_types
.add
(mparameter
.mtype
)
535 vararg_rank
= msignature
.vararg_rank
537 if msignature
!= null and ret_type
== null then
538 ret_type
= msignature
.return_mtype
541 if param_names
.length
!= param_types
.length
then
542 # Some parameters are typed, other parameters are not typed.
543 modelbuilder
.error
(nsig
.n_params
[param_types
.length
], "Error: Untyped parameter `{param_names[param_types.length]}'.")
547 var mparameters
= new Array[MParameter]
548 for i
in [0..param_names
.length
[ do
549 var mparameter
= new MParameter(param_names
[i
], param_types
[i
], i
== vararg_rank
)
550 if nsig
!= null then nsig
.n_params
[i
].mparameter
= mparameter
551 mparameters
.add
(mparameter
)
554 msignature
= new MSignature(mparameters
, ret_type
)
555 mpropdef
.msignature
= msignature
556 mpropdef
.is_abstract
= self isa ADeferredMethPropdef
559 redef fun check_signature
(modelbuilder
, nclassdef
)
561 var mpropdef
= self.mpropdef
562 if mpropdef
== null then return # Error thus skiped
563 var mmodule
= mpropdef
.mclassdef
.mmodule
564 var nsig
= self.n_signature
565 var mysignature
= self.mpropdef
.msignature
566 if mysignature
== null then return # Error thus skiped
568 # Lookup for signature in the precursor
569 # FIXME all precursors should be considered
570 if not mpropdef
.is_intro
then
571 var msignature
= mpropdef
.mproperty
.intro
.msignature
572 if msignature
== null then return
574 var precursor_ret_type
= msignature
.return_mtype
575 var ret_type
= mysignature
.return_mtype
576 if ret_type
!= null and precursor_ret_type
== null then
577 modelbuilder
.error
(nsig
.n_type
.as(not null), "Redef Error: {mpropdef.mproperty} is a procedure, not a function.")
581 if mysignature
.arity
> 0 then
582 # Check parameters types
583 for i
in [0..mysignature
.arity
[ do
584 var myt
= mysignature
.mparameters
[i
].mtype
585 var prt
= msignature
.mparameters
[i
].mtype
586 if not myt
.is_subtype
(mmodule
, nclassdef
.mclassdef
.bound_mtype
, prt
) or
587 not prt
.is_subtype
(mmodule
, nclassdef
.mclassdef
.bound_mtype
, myt
) then
588 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}.")
592 if precursor_ret_type
!= null then
593 if ret_type
== null then
594 # Inherit the return type
595 ret_type
= precursor_ret_type
596 else if not ret_type
.is_subtype
(mmodule
, nclassdef
.mclassdef
.bound_mtype
, precursor_ret_type
) then
597 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}.")
602 if mysignature
.arity
> 0 then
603 # Check parameters visibility
604 for i
in [0..mysignature
.arity
[ do
605 var nt
= nsig
.n_params
[i
].n_type
606 if nt
!= null then modelbuilder
.check_visibility
(nt
, nt
.mtype
.as(not null), mpropdef
)
609 if nt
!= null then modelbuilder
.check_visibility
(nt
, nt
.mtype
.as(not null), mpropdef
)
614 redef class AAttrPropdef
615 redef type MPROPDEF: MAttributeDef
617 # The associated getter (read accessor) if any
618 var mreadpropdef
: nullable MMethodDef writable
619 # The associated setter (write accessor) if any
620 var mwritepropdef
: nullable MMethodDef writable
621 redef fun build_property
(modelbuilder
, nclassdef
)
623 var mclassdef
= nclassdef
.mclassdef
.as(not null)
624 var mclass
= mclassdef
.mclass
627 if self.n_id
!= null then
628 name
= self.n_id
.text
630 name
= self.n_id2
.text
633 if mclass
.kind
== interface_kind
or mclassdef
.mclass
.kind
== enum_kind
then
634 modelbuilder
.error
(self, "Error: Attempt to define attribute {name} in the interface {mclass}.")
635 else if mclass
.kind
== enum_kind
then
636 modelbuilder
.error
(self, "Error: Attempt to define attribute {name} in the enum class {mclass}.")
637 else if mclass
.kind
== extern_kind
then
638 modelbuilder
.error
(self, "Error: Attempt to define attribute {name} in the extern class {mclass}.")
643 # Old attribute style
644 var mprop
= modelbuilder
.try_get_mproperty_by_name
(nid
, mclassdef
, name
)
645 if mprop
== null then
646 var mvisibility
= new_property_visibility
(modelbuilder
, nclassdef
, self.n_visibility
)
647 mprop
= new MAttribute(mclassdef
, name
, mvisibility
)
648 if not self.check_redef_keyword
(modelbuilder
, nclassdef
, self.n_kwredef
, false, mprop
) then return
650 assert mprop
isa MAttribute
651 check_redef_property_visibility
(modelbuilder
, nclassdef
, self.n_visibility
, mprop
)
652 if not self.check_redef_keyword
(modelbuilder
, nclassdef
, self.n_kwredef
, true, mprop
) then return
654 nclassdef
.mprop2npropdef
[mprop
] = self
656 var mpropdef
= new MAttributeDef(mclassdef
, mprop
, self.location
)
657 self.mpropdef
= mpropdef
658 modelbuilder
.mpropdef2npropdef
[mpropdef
] = self
661 var nreadable
= self.n_readable
662 if nreadable
!= null then
663 var readname
= name
.substring_from
(1)
664 var mreadprop
= modelbuilder
.try_get_mproperty_by_name
(nid
, mclassdef
, readname
).as(nullable MMethod)
665 if mreadprop
== null then
666 var mvisibility
= new_property_visibility
(modelbuilder
, nclassdef
, nreadable
.n_visibility
)
667 mreadprop
= new MMethod(mclassdef
, readname
, mvisibility
)
668 if not self.check_redef_keyword
(modelbuilder
, nclassdef
, nreadable
.n_kwredef
, false, mreadprop
) then return
670 if not self.check_redef_keyword
(modelbuilder
, nclassdef
, nreadable
.n_kwredef
, true, mreadprop
) then return
671 check_redef_property_visibility
(modelbuilder
, nclassdef
, nreadable
.n_visibility
, mreadprop
)
673 nclassdef
.mprop2npropdef
[mreadprop
] = self
675 var mreadpropdef
= new MMethodDef(mclassdef
, mreadprop
, self.location
)
676 self.mreadpropdef
= mreadpropdef
677 modelbuilder
.mpropdef2npropdef
[mreadpropdef
] = self
678 mreadpropdef
.mdoc
= mpropdef
.mdoc
681 var nwritable
= self.n_writable
682 if nwritable
!= null then
683 var writename
= name
.substring_from
(1) + "="
684 var mwriteprop
= modelbuilder
.try_get_mproperty_by_name
(nid
, mclassdef
, writename
).as(nullable MMethod)
685 if mwriteprop
== null then
686 var mvisibility
= new_property_visibility
(modelbuilder
, nclassdef
, nwritable
.n_visibility
)
687 mwriteprop
= new MMethod(mclassdef
, writename
, mvisibility
)
688 if not self.check_redef_keyword
(modelbuilder
, nclassdef
, nwritable
.n_kwredef
, false, mwriteprop
) then return
690 if not self.check_redef_keyword
(modelbuilder
, nclassdef
, nwritable
.n_kwredef
, true, mwriteprop
) then return
691 check_redef_property_visibility
(modelbuilder
, nclassdef
, nwritable
.n_visibility
, mwriteprop
)
693 nclassdef
.mprop2npropdef
[mwriteprop
] = self
695 var mwritepropdef
= new MMethodDef(mclassdef
, mwriteprop
, self.location
)
696 self.mwritepropdef
= mwritepropdef
697 modelbuilder
.mpropdef2npropdef
[mwritepropdef
] = self
698 mwritepropdef
.mdoc
= mpropdef
.mdoc
701 # New attribute style
702 var nid2
= self.n_id2
.as(not null)
703 var mprop
= new MAttribute(mclassdef
, "@" + name
, none_visibility
)
704 var mpropdef
= new MAttributeDef(mclassdef
, mprop
, self.location
)
705 self.mpropdef
= mpropdef
706 modelbuilder
.mpropdef2npropdef
[mpropdef
] = self
710 var mreadprop
= modelbuilder
.try_get_mproperty_by_name
(nid2
, mclassdef
, readname
).as(nullable MMethod)
711 if mreadprop
== null then
712 var mvisibility
= new_property_visibility
(modelbuilder
, nclassdef
, self.n_visibility
)
713 mreadprop
= new MMethod(mclassdef
, readname
, mvisibility
)
714 if not self.check_redef_keyword
(modelbuilder
, nclassdef
, n_kwredef
, false, mreadprop
) then return
716 if not self.check_redef_keyword
(modelbuilder
, nclassdef
, n_kwredef
, true, mreadprop
) then return
717 check_redef_property_visibility
(modelbuilder
, nclassdef
, self.n_visibility
, mreadprop
)
719 nclassdef
.mprop2npropdef
[mreadprop
] = self
721 var mreadpropdef
= new MMethodDef(mclassdef
, mreadprop
, self.location
)
722 self.mreadpropdef
= mreadpropdef
723 modelbuilder
.mpropdef2npropdef
[mreadpropdef
] = self
724 mreadpropdef
.mdoc
= mpropdef
.mdoc
726 var writename
= name
+ "="
727 var nwritable
= self.n_writable
728 var mwriteprop
= modelbuilder
.try_get_mproperty_by_name
(nid2
, mclassdef
, writename
).as(nullable MMethod)
729 var nwkwredef
: nullable Token = null
730 if nwritable
!= null then nwkwredef
= nwritable
.n_kwredef
731 if mwriteprop
== null then
733 if nwritable
!= null then
734 mvisibility
= new_property_visibility
(modelbuilder
, nclassdef
, nwritable
.n_visibility
)
736 mvisibility
= private_visibility
738 mwriteprop
= new MMethod(mclassdef
, writename
, mvisibility
)
739 if not self.check_redef_keyword
(modelbuilder
, nclassdef
, nwkwredef
, false, mwriteprop
) then return
741 if not self.check_redef_keyword
(modelbuilder
, nclassdef
, nwkwredef
, true, mwriteprop
) then return
742 if nwritable
!= null then
743 check_redef_property_visibility
(modelbuilder
, nclassdef
, nwritable
.n_visibility
, mwriteprop
)
746 nclassdef
.mprop2npropdef
[mwriteprop
] = self
748 var mwritepropdef
= new MMethodDef(mclassdef
, mwriteprop
, self.location
)
749 self.mwritepropdef
= mwritepropdef
750 modelbuilder
.mpropdef2npropdef
[mwritepropdef
] = self
751 mwritepropdef
.mdoc
= mpropdef
.mdoc
755 redef fun build_signature
(modelbuilder
, nclassdef
)
757 var mpropdef
= self.mpropdef
758 if mpropdef
== null then return # Error thus skiped
759 var mmodule
= mpropdef
.mclassdef
.mmodule
760 var mtype
: nullable MType = null
762 var ntype
= self.n_type
763 if ntype
!= null then
764 mtype
= modelbuilder
.resolve_mtype
(nclassdef
, ntype
)
765 if mtype
== null then return
768 var nexpr
= self.n_expr
769 if mtype
== null then
770 if nexpr
!= null then
771 if nexpr
isa ANewExpr then
772 mtype
= modelbuilder
.resolve_mtype
(nclassdef
, nexpr
.n_type
)
773 else if nexpr
isa AIntExpr then
774 var cla
= modelbuilder
.try_get_mclass_by_name
(nexpr
, mmodule
, "Int")
775 if cla
!= null then mtype
= cla
.mclass_type
776 else if nexpr
isa AFloatExpr then
777 var cla
= modelbuilder
.try_get_mclass_by_name
(nexpr
, mmodule
, "Float")
778 if cla
!= null then mtype
= cla
.mclass_type
779 else if nexpr
isa ACharExpr then
780 var cla
= modelbuilder
.try_get_mclass_by_name
(nexpr
, mmodule
, "Char")
781 if cla
!= null then mtype
= cla
.mclass_type
782 else if nexpr
isa ABoolExpr then
783 var cla
= modelbuilder
.try_get_mclass_by_name
(nexpr
, mmodule
, "Bool")
784 if cla
!= null then mtype
= cla
.mclass_type
785 else if nexpr
isa ASuperstringExpr then
786 var cla
= modelbuilder
.try_get_mclass_by_name
(nexpr
, mmodule
, "String")
787 if cla
!= null then mtype
= cla
.mclass_type
788 else if nexpr
isa AStringFormExpr then
789 var cla
= modelbuilder
.try_get_mclass_by_name
(nexpr
, mmodule
, "String")
790 if cla
!= null then mtype
= cla
.mclass_type
792 modelbuilder
.error
(self, "Error: Untyped attribute {mpropdef}. Implicit typing allowed only for literals and new.")
796 modelbuilder
.error
(self, "Error: Untyped attribute {mpropdef}")
800 if nexpr
isa ANewExpr then
801 var xmtype
= modelbuilder
.resolve_mtype
(nclassdef
, nexpr
.n_type
)
802 if xmtype
== mtype
and modelbuilder
.toolcontext
.opt_warn
.value
>= 2 then
803 modelbuilder
.warning
(ntype
, "Warning: useless type definition")
808 if mtype
== null then return
810 mpropdef
.static_mtype
= mtype
812 var mreadpropdef
= self.mreadpropdef
813 if mreadpropdef
!= null then
814 var msignature
= new MSignature(new Array[MParameter], mtype
)
815 mreadpropdef
.msignature
= msignature
818 var msritepropdef
= self.mwritepropdef
819 if mwritepropdef
!= null then
822 name
= n_id
.text
.substring_from
(1)
826 var mparameter
= new MParameter(name
, mtype
, false)
827 var msignature
= new MSignature([mparameter
], null)
828 mwritepropdef
.msignature
= msignature
832 redef fun check_signature
(modelbuilder
, nclassdef
)
834 var mpropdef
= self.mpropdef
835 if mpropdef
== null then return # Error thus skiped
836 var mmodule
= mpropdef
.mclassdef
.mmodule
837 var ntype
= self.n_type
838 var mtype
= self.mpropdef
.static_mtype
839 if mtype
== null then return # Error thus skiped
841 # Lookup for signature in the precursor
842 # FIXME all precursors should be considered
843 if not mpropdef
.is_intro
then
844 var precursor_type
= mpropdef
.mproperty
.intro
.static_mtype
845 if precursor_type
== null then return
847 if mtype
!= precursor_type
then
848 modelbuilder
.error
(ntype
.as(not null), "Redef Error: Wrong static type. found {mtype}, expected {precursor_type}.")
853 # Check getter and setter
854 var meth
= self.mreadpropdef
856 self.check_method_signature
(modelbuilder
, nclassdef
, meth
)
857 var node
: nullable ANode = ntype
858 if node
== null then node
= self
859 modelbuilder
.check_visibility
(node
, mtype
, meth
)
861 meth
= self.mwritepropdef
863 self.check_method_signature
(modelbuilder
, nclassdef
, meth
)
864 var node
: nullable ANode = ntype
865 if node
== null then node
= self
866 modelbuilder
.check_visibility
(node
, mtype
, meth
)
870 private fun check_method_signature
(modelbuilder
: ModelBuilder, nclassdef
: AClassdef, mpropdef
: MMethodDef)
872 var mmodule
= mpropdef
.mclassdef
.mmodule
873 var nsig
= self.n_type
874 var mysignature
= mpropdef
.msignature
875 if mysignature
== null then return # Error thus skiped
877 # Lookup for signature in the precursor
878 # FIXME all precursors should be considered
879 if not mpropdef
.is_intro
then
880 var msignature
= mpropdef
.mproperty
.intro
.msignature
881 if msignature
== null then return
883 if mysignature
.arity
!= msignature
.arity
then
885 if nsig
!= null then node
= nsig
else node
= self
886 modelbuilder
.error
(node
, "Redef Error: {mysignature.arity} parameters found, {msignature.arity} expected. Signature is {mpropdef}{msignature}")
889 var precursor_ret_type
= msignature
.return_mtype
890 var ret_type
= mysignature
.return_mtype
891 if ret_type
!= null and precursor_ret_type
== null then
893 if nsig
!= null then node
= nsig
else node
= self
894 modelbuilder
.error
(node
, "Redef Error: {mpropdef.mproperty} is a procedure, not a function.")
898 if mysignature
.arity
> 0 then
899 # Check parameters types
900 for i
in [0..mysignature
.arity
[ do
901 var myt
= mysignature
.mparameters
[i
].mtype
902 var prt
= msignature
.mparameters
[i
].mtype
903 if not myt
.is_subtype
(mmodule
, nclassdef
.mclassdef
.bound_mtype
, prt
) and
904 not prt
.is_subtype
(mmodule
, nclassdef
.mclassdef
.bound_mtype
, myt
) then
906 if nsig
!= null then node
= nsig
else node
= self
907 modelbuilder
.error
(node
, "Redef Error: Wrong type for parameter `{mysignature.mparameters[i].name}'. found {myt}, expected {prt}.")
911 if precursor_ret_type
!= null then
912 if ret_type
== null then
913 # Inherit the return type
914 ret_type
= precursor_ret_type
915 else if not ret_type
.is_subtype
(mmodule
, nclassdef
.mclassdef
.bound_mtype
, precursor_ret_type
) then
917 if nsig
!= null then node
= nsig
else node
= self
918 modelbuilder
.error
(node
, "Redef Error: Wrong return type. found {ret_type}, expected {precursor_ret_type}.")
925 redef class ATypePropdef
926 redef type MPROPDEF: MVirtualTypeDef
928 redef fun build_property
(modelbuilder
, nclassdef
)
930 var mclassdef
= nclassdef
.mclassdef
.as(not null)
931 var name
= self.n_id
.text
932 var mprop
= modelbuilder
.try_get_mproperty_by_name
(self.n_id
, mclassdef
, name
)
933 if mprop
== null then
934 var mvisibility
= new_property_visibility
(modelbuilder
, nclassdef
, self.n_visibility
)
935 mprop
= new MVirtualTypeProp(mclassdef
, name
, mvisibility
)
936 for c
in name
do if c
>= 'a' and c
<= 'z' then
937 modelbuilder
.warning
(n_id
, "Warning: lowercase in the virtual type {name}")
940 if not self.check_redef_keyword
(modelbuilder
, nclassdef
, self.n_kwredef
, false, mprop
) then return
942 if not self.check_redef_keyword
(modelbuilder
, nclassdef
, self.n_kwredef
, true, mprop
) then return
943 assert mprop
isa MVirtualTypeProp
944 check_redef_property_visibility
(modelbuilder
, nclassdef
, self.n_visibility
, mprop
)
946 nclassdef
.mprop2npropdef
[mprop
] = self
948 var mpropdef
= new MVirtualTypeDef(mclassdef
, mprop
, self.location
)
949 self.mpropdef
= mpropdef
953 redef fun build_signature
(modelbuilder
, nclassdef
)
955 var mpropdef
= self.mpropdef
956 if mpropdef
== null then return # Error thus skiped
957 var mmodule
= mpropdef
.mclassdef
.mmodule
958 var mtype
: nullable MType = null
960 var ntype
= self.n_type
961 mtype
= modelbuilder
.resolve_mtype
(nclassdef
, ntype
)
962 if mtype
== null then return
964 mpropdef
.bound
= mtype
965 # print "{mpropdef}: {mtype}"
968 redef fun check_signature
(modelbuilder
, nclassdef
)
970 var mpropdef
= self.mpropdef
971 if mpropdef
== null then return # Error thus skiped
973 var bound
= self.mpropdef
.bound
974 if bound
== null then return # Error thus skiped
976 modelbuilder
.check_visibility
(n_type
.as(not null), bound
, mpropdef
)
978 # Fast case: the bound is not a formal type
979 if not bound
isa MVirtualType then return
981 var mmodule
= nclassdef
.mclassdef
.mmodule
982 var anchor
= nclassdef
.mclassdef
.bound_mtype
984 # Slow case: progress on each resolution until: (i) we loop, or (ii) we found a non formal type
985 var seen
= [self.mpropdef
.mproperty
.mvirtualtype
]
987 if seen
.has
(bound
) then
989 modelbuilder
.error
(self, "Error: circularity of virtual type definition: {seen.join(" -> ")}")
993 var next
= bound
.lookup_bound
(mmodule
, anchor
)
994 if not next
isa MVirtualType then break