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 if not mclassdef2nclassdef
.has_key
(superclassdef
) then continue
52 build_properties
(mclassdef2nclassdef
[superclassdef
])
55 for npropdef
in nclassdef
.n_propdefs
do
56 npropdef
.build_property
(self, nclassdef
)
58 for npropdef
in nclassdef
.n_propdefs
do
59 npropdef
.build_signature
(self)
61 for npropdef
in nclassdef
.n_propdefs
do
62 npropdef
.check_signature
(self)
64 process_default_constructors
(nclassdef
)
67 # Introduce or inherit default constructor
68 # This is the last part of `build_properties`.
69 private fun process_default_constructors
(nclassdef
: AClassdef)
71 var mclassdef
= nclassdef
.mclassdef
.as(not null)
74 if not mclassdef
.is_intro
then return
76 # Is the class forbid constructors?
77 if not mclassdef
.mclass
.kind
.need_init
then return
79 # Is there already a constructor defined?
80 for mpropdef
in mclassdef
.mpropdefs
do
81 if not mpropdef
isa MMethodDef then continue
82 if mpropdef
.mproperty
.is_init
then return
85 if not nclassdef
isa AStdClassdef then return
87 var mmodule
= mclassdef
.mmodule
88 # Do we inherit for a constructor?
89 var combine
= new Array[MMethod]
90 var inhc
: nullable MClass = null
91 for st
in mclassdef
.supertypes
do
93 if not c
.kind
.need_init
then continue
94 st
= st
.anchor_to
(mmodule
, mclassdef
.bound_mtype
)
95 var candidate
= self.try_get_mproperty_by_name2
(nclassdef
, mmodule
, st
, "init").as(nullable MMethod)
96 if candidate
!= null and candidate
.intro
.msignature
.arity
== 0 then
97 combine
.add
(candidate
)
100 var inhc2
= c
.inherit_init_from
101 if inhc2
== null then inhc2
= c
102 if inhc2
== inhc
then continue
104 self.error
(nclassdef
, "Error: Cannot provide a defaut constructor: conflict for {inhc} and {c}")
110 # Collect undefined attributes
111 var mparameters
= new Array[MParameter]
112 var anode
: nullable ANode = null
113 for npropdef
in nclassdef
.n_propdefs
do
114 if npropdef
isa AAttrPropdef and npropdef
.n_expr
== null then
115 if npropdef
.mpropdef
== null then return # Skip broken attribute
116 var paramname
= npropdef
.mpropdef
.mproperty
.name
.substring_from
(1)
117 var ret_type
= npropdef
.mpropdef
.static_mtype
118 if ret_type
== null then return
119 var mparameter
= new MParameter(paramname
, ret_type
, false)
120 mparameters
.add
(mparameter
)
121 if anode
== null then anode
= npropdef
124 if anode
== null then anode
= nclassdef
126 if combine
.is_empty
and inhc
!= null then
127 if not mparameters
.is_empty
then
128 self.error
(anode
,"Error: {mclassdef} cannot inherit constructors from {inhc} because there is attributes without initial values: {mparameters.join(", ")}")
132 # TODO: actively inherit the consturctor
133 self.toolcontext
.info
("{mclassdef} inherits all constructors from {inhc}", 3)
134 mclassdef
.mclass
.inherit_init_from
= inhc
138 if not combine
.is_empty
and inhc
!= null then
139 self.error
(nclassdef
, "Error: Cannot provide a defaut constructor: conflict for {combine.join(", ")} and {inhc}")
143 if not combine
.is_empty
then
144 if mparameters
.is_empty
and combine
.length
== 1 then
145 # No need to create a local init, the inherited one is enough
146 inhc
= combine
.first
.intro_mclassdef
.mclass
147 mclassdef
.mclass
.inherit_init_from
= inhc
148 self.toolcontext
.info
("{mclassdef} inherits all constructors from {inhc}", 3)
151 nclassdef
.super_inits
= combine
154 var mprop
= new MMethod(mclassdef
, "init", mclassdef
.mclass
.visibility
)
155 var mpropdef
= new MMethodDef(mclassdef
, mprop
, nclassdef
.location
)
156 var msignature
= new MSignature(mparameters
, null)
157 mpropdef
.msignature
= msignature
159 nclassdef
.mfree_init
= mpropdef
160 self.toolcontext
.info
("{mclassdef} gets a free constructor for attributes {mpropdef}{msignature}", 3)
163 # Check the visibility of `mtype` as an element of the signature of `mpropdef`.
164 fun check_visibility
(node
: ANode, mtype
: MType, mpropdef
: MPropDef)
166 var mmodule
= mpropdef
.mclassdef
.mmodule
167 var mproperty
= mpropdef
.mproperty
169 # Extract visibility information of the main part of `mtype`
170 # It is a case-by case
171 var vis_type
: nullable MVisibility = null # The own visibility of the type
172 var mmodule_type
: nullable MModule = null # The origial module of the type
173 if mtype
isa MNullableType then mtype
= mtype
.mtype
174 if mtype
isa MClassType then
175 vis_type
= mtype
.mclass
.visibility
176 mmodule_type
= mtype
.mclass
.intro
.mmodule
177 else if mtype
isa MVirtualType then
178 vis_type
= mtype
.mproperty
.visibility
179 mmodule_type
= mtype
.mproperty
.intro_mclassdef
.mmodule
180 else if mtype
isa MParameterType then
181 # nothing, always visible
183 node
.debug
"Unexpected type {mtype}"
187 if vis_type
!= null then
188 assert mmodule_type
!= null
189 var vis_module_type
= mmodule
.visibility_for
(mmodule_type
) # the visibility of the original module
190 if mproperty
.visibility
> vis_type
then
191 error
(node
, "Error: The {mproperty.visibility} property `{mproperty}` cannot contain the {vis_type} type `{mtype}`")
193 else if mproperty
.visibility
> vis_module_type
then
194 error
(node
, "Error: The {mproperty.visibility} property `{mproperty}` cannot contain the type `{mtype}` from the {vis_module_type} module `{mmodule_type}`")
199 # No error, try to go deeper in generic types
200 if node
isa AType then
201 for a
in node
.n_types
do check_visibility
(a
, a
.mtype
.as(not null), mpropdef
)
202 else if mtype
isa MGenericType then
203 for t
in mtype
.arguments
do check_visibility
(node
, t
, mpropdef
)
209 # The class whose self inherit all the constructors.
210 # 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
211 var inherit_init_from
: nullable MClass = null
214 redef class MClassDef
215 private var propdef_names
= new HashSet[String]
219 # Does the MPropDef contains a call to super or a call of a super-constructor?
220 # Subsequent phases of the frontend (esp. typing) set it if required
221 var has_supercall
: Bool writable = false
224 redef class AClassdef
225 var build_properties_is_done
: Bool = false
226 # The list of super-constructor to call at the start of the free constructor
227 # 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
228 var super_inits
: nullable Collection[MMethod] = null
230 # The free init (implicitely constructed by the class if required)
231 var mfree_init
: nullable MMethodDef = null
233 # What is the `APropdef` associated to a `MProperty`?
234 # Used to check multiple definition of a property.
235 var mprop2npropdef
: Map[MProperty, APropdef] = new HashMap[MProperty, APropdef]
239 # Join the text of all tokens
240 # Used to get the 'real name' of method definitions.
241 fun collect_text
: String
243 var v
= new TextCollectorVisitor
250 private class TextCollectorVisitor
252 var text
: String = ""
255 if n
isa Token then text
+= n
.text
261 # The associated main model entity
262 type MPROPDEF: MPropDef
264 # The associated propdef once build by a `ModelBuilder`
265 var mpropdef
: nullable MPROPDEF writable
267 private fun build_property
(modelbuilder
: ModelBuilder, nclassdef
: AClassdef) is abstract
268 private fun build_signature
(modelbuilder
: ModelBuilder) is abstract
269 private fun check_signature
(modelbuilder
: ModelBuilder) is abstract
270 private fun new_property_visibility
(modelbuilder
: ModelBuilder, mclassdef
: MClassDef, nvisibility
: nullable AVisibility): MVisibility
272 var mvisibility
= public_visibility
273 if nvisibility
!= null then
274 mvisibility
= nvisibility
.mvisibility
275 if mvisibility
== intrude_visibility
then
276 modelbuilder
.error
(nvisibility
, "Error: intrude is not a legal visibility for properties.")
277 mvisibility
= public_visibility
280 if mclassdef
.mclass
.visibility
== private_visibility
then
281 if mvisibility
== protected_visibility
then
282 assert nvisibility
!= null
283 modelbuilder
.error
(nvisibility
, "Error: The only legal visibility for properties in a private class is private.")
284 else if mvisibility
== private_visibility
then
285 assert nvisibility
!= null
287 # modelbuilder.warning(nvisibility, "Warning: private is unrequired since the only legal visibility for properties in a private class is private.")
289 mvisibility
= private_visibility
294 private fun set_doc
(mpropdef
: MPropDef)
296 var ndoc
= self.n_doc
298 var mdoc
= ndoc
.to_mdoc
300 mdoc
.original_mentity
= mpropdef
304 private fun check_redef_property_visibility
(modelbuilder
: ModelBuilder, nvisibility
: nullable AVisibility, mprop
: MProperty)
306 if nvisibility
== null then return
307 var mvisibility
= nvisibility
.mvisibility
308 if mvisibility
!= mprop
.visibility
and mvisibility
!= public_visibility
then
309 modelbuilder
.error
(nvisibility
, "Error: redefinition changed the visibility from a {mprop.visibility} to a {mvisibility}")
313 private fun check_redef_keyword
(modelbuilder
: ModelBuilder, nclassdef
: AClassdef, kwredef
: nullable Token, need_redef
: Bool, mprop
: MProperty): Bool
315 if nclassdef
.mprop2npropdef
.has_key
(mprop
) then
316 modelbuilder
.error
(self, "Error: A property {mprop} is already defined in class {nclassdef.mclassdef.mclass}.")
319 if kwredef
== null then
321 modelbuilder
.error
(self, "Redef error: {nclassdef.mclassdef.mclass}::{mprop.name} is an inherited property. To redefine it, add the redef keyword.")
325 if not need_redef
then
326 modelbuilder
.error
(self, "Error: No property {nclassdef.mclassdef.mclass}::{mprop.name} is inherited. Remove the redef keyword to define a new property.")
335 redef class ASignature
336 # Is the model builder has correctly visited the signature
337 var is_visited
= false
338 # Names of parameters from the AST
339 # REQUIRE: is_visited
340 var param_names
= new Array[String]
341 # Types of parameters from the AST
342 # REQUIRE: is_visited
343 var param_types
= new Array[MType]
344 # Rank of the vararg (of -1 if none)
345 # REQUIRE: is_visited
346 var vararg_rank
: Int = -1
348 var ret_type
: nullable MType = null
350 # Visit and fill information about a signature
351 private fun visit_signature
(modelbuilder
: ModelBuilder, mclassdef
: MClassDef): Bool
353 var mmodule
= mclassdef
.mmodule
354 var param_names
= self.param_names
355 var param_types
= self.param_types
356 for np
in self.n_params
do
357 param_names
.add
(np
.n_id
.text
)
358 var ntype
= np
.n_type
359 if ntype
!= null then
360 var mtype
= modelbuilder
.resolve_mtype
(mmodule
, mclassdef
, ntype
)
361 if mtype
== null then return false # Skip error
362 for i
in [0..param_names
.length-param_types
.length
[ do
363 param_types
.add
(mtype
)
365 if np
.n_dotdotdot
!= null then
366 if self.vararg_rank
!= -1 then
367 modelbuilder
.error
(np
, "Error: {param_names[self.vararg_rank]} is already a vararg")
370 self.vararg_rank
= param_names
.length
- 1
375 var ntype
= self.n_type
376 if ntype
!= null then
377 self.ret_type
= modelbuilder
.resolve_mtype
(mmodule
, mclassdef
, ntype
)
378 if self.ret_type
== null then return false # Skip errir
381 self.is_visited
= true
385 # Build a visited signature
386 fun build_signature
(modelbuilder
: ModelBuilder): nullable MSignature
388 if param_names
.length
!= param_types
.length
then
389 # Some parameters are typed, other parameters are not typed.
390 modelbuilder
.error
(self.n_params
[param_types
.length
], "Error: Untyped parameter `{param_names[param_types.length]}'.")
394 var mparameters
= new Array[MParameter]
395 for i
in [0..param_names
.length
[ do
396 var mparameter
= new MParameter(param_names
[i
], param_types
[i
], i
== vararg_rank
)
397 self.n_params
[i
].mparameter
= mparameter
398 mparameters
.add
(mparameter
)
401 var msignature
= new MSignature(mparameters
, ret_type
)
407 # The associated mparameter if any
408 var mparameter
: nullable MParameter = null
411 redef class AMethPropdef
412 redef type MPROPDEF: MMethodDef
414 redef fun build_property
(modelbuilder
, nclassdef
)
416 var n_kwinit
= n_kwinit
417 var n_kwnew
= n_kwnew
418 var is_init
= n_kwinit
!= null or n_kwnew
!= null
419 var mclassdef
= nclassdef
.mclassdef
.as(not null)
421 var amethodid
= self.n_methid
423 if amethodid
== null then
427 else if n_kwinit
!= null then
430 else if n_kwnew
!= null then
436 else if amethodid
isa AIdMethid then
437 name
= amethodid
.n_id
.text
438 name_node
= amethodid
440 # operator, bracket or assign
441 name
= amethodid
.collect_text
442 name_node
= amethodid
444 if name
== "-" and self.n_signature
.n_params
.length
== 0 then
449 var mprop
: nullable MMethod = null
450 if not is_init
or n_kwredef
!= null then mprop
= modelbuilder
.try_get_mproperty_by_name
(name_node
, mclassdef
, name
).as(nullable MMethod)
451 if mprop
== null then
452 var mvisibility
= new_property_visibility
(modelbuilder
, mclassdef
, self.n_visibility
)
453 mprop
= new MMethod(mclassdef
, name
, mvisibility
)
454 mprop
.is_init
= is_init
455 mprop
.is_new
= n_kwnew
!= null
456 if not self.check_redef_keyword
(modelbuilder
, nclassdef
, n_kwredef
, false, mprop
) then return
458 if n_kwredef
== null then
459 if self isa AMainMethPropdef then
462 if not self.check_redef_keyword
(modelbuilder
, nclassdef
, n_kwredef
, true, mprop
) then return
465 check_redef_property_visibility
(modelbuilder
, self.n_visibility
, mprop
)
467 nclassdef
.mprop2npropdef
[mprop
] = self
469 var mpropdef
= new MMethodDef(mclassdef
, mprop
, self.location
)
471 if mclassdef
.propdef_names
.has
(mprop
.name
) then
472 var loc
: nullable Location = null
473 for i
in mclassdef
.mpropdefs
do
474 if i
.mproperty
.name
== mprop
.name
then
479 if loc
== null then abort
480 modelbuilder
.error
(self, "Error: a property {mprop} is already defined in class {mclassdef.mclass} at {loc}")
483 mclassdef
.propdef_names
.add
(mpropdef
.mproperty
.name
)
487 self.mpropdef
= mpropdef
488 modelbuilder
.mpropdef2npropdef
[mpropdef
] = self
489 if mpropdef
.is_intro
then
490 modelbuilder
.toolcontext
.info
("{mpropdef} introduces new method {mprop.full_name}", 3)
492 modelbuilder
.toolcontext
.info
("{mpropdef} redefines method {mprop.full_name}", 3)
496 redef fun build_signature
(modelbuilder
)
498 var mpropdef
= self.mpropdef
499 if mpropdef
== null then return # Error thus skiped
500 var mclassdef
= mpropdef
.mclassdef
501 var mmodule
= mclassdef
.mmodule
502 var nsig
= self.n_signature
504 # Retrieve info from the signature AST
505 var param_names
= new Array[String] # Names of parameters from the AST
506 var param_types
= new Array[MType] # Types of parameters from the AST
508 var ret_type
: nullable MType = null # Return type from the AST
510 if not nsig
.visit_signature
(modelbuilder
, mclassdef
) then return
511 param_names
= nsig
.param_names
512 param_types
= nsig
.param_types
513 vararg_rank
= nsig
.vararg_rank
514 ret_type
= nsig
.ret_type
517 # Look for some signature to inherit
518 # FIXME: do not inherit from the intro, but from the most specific
519 var msignature
: nullable MSignature = null
520 if not mpropdef
.is_intro
then
521 msignature
= mpropdef
.mproperty
.intro
.msignature
522 if msignature
== null then return # Skip error
524 # Check inherited signature arity
525 if param_names
.length
!= msignature
.arity
then
527 if nsig
!= null then node
= nsig
else node
= self
528 modelbuilder
.error
(node
, "Redef error: {mpropdef} redefines {mpropdef.mproperty.intro} with {param_names.length} parameter(s), {msignature.arity} expected. Signature is {mpropdef}{msignature}")
531 else if mpropdef
.mproperty
.is_init
then
532 # FIXME UGLY: inherit signature from a super-constructor
533 for msupertype
in mclassdef
.supertypes
do
534 msupertype
= msupertype
.anchor_to
(mmodule
, mclassdef
.bound_mtype
)
535 var candidate
= modelbuilder
.try_get_mproperty_by_name2
(self, mmodule
, msupertype
, mpropdef
.mproperty
.name
)
536 if candidate
!= null then
537 if msignature
== null then
538 msignature
= candidate
.intro
.as(MMethodDef).msignature
545 # Inherit the signature
546 if msignature
!= null and param_names
.length
!= param_types
.length
and param_names
.length
== msignature
.arity
and param_types
.length
== 0 then
547 # Parameters are untyped, thus inherit them
548 param_types
= new Array[MType]
549 for mparameter
in msignature
.mparameters
do
550 param_types
.add
(mparameter
.mtype
)
552 vararg_rank
= msignature
.vararg_rank
554 if msignature
!= null and ret_type
== null then
555 ret_type
= msignature
.return_mtype
558 if param_names
.length
!= param_types
.length
then
559 # Some parameters are typed, other parameters are not typed.
560 modelbuilder
.error
(nsig
.n_params
[param_types
.length
], "Error: Untyped parameter `{param_names[param_types.length]}'.")
564 var mparameters
= new Array[MParameter]
565 for i
in [0..param_names
.length
[ do
566 var mparameter
= new MParameter(param_names
[i
], param_types
[i
], i
== vararg_rank
)
567 if nsig
!= null then nsig
.n_params
[i
].mparameter
= mparameter
568 mparameters
.add
(mparameter
)
571 msignature
= new MSignature(mparameters
, ret_type
)
572 mpropdef
.msignature
= msignature
573 mpropdef
.is_abstract
= self isa ADeferredMethPropdef
574 mpropdef
.is_intern
= self isa AInternMethPropdef
575 mpropdef
.is_extern
= self isa AExternPropdef
578 redef fun check_signature
(modelbuilder
)
580 var mpropdef
= self.mpropdef
581 if mpropdef
== null then return # Error thus skiped
582 var mclassdef
= mpropdef
.mclassdef
583 var mmodule
= mclassdef
.mmodule
584 var nsig
= self.n_signature
585 var mysignature
= self.mpropdef
.msignature
586 if mysignature
== null then return # Error thus skiped
588 # Lookup for signature in the precursor
589 # FIXME all precursors should be considered
590 if not mpropdef
.is_intro
then
591 var msignature
= mpropdef
.mproperty
.intro
.msignature
592 if msignature
== null then return
594 var precursor_ret_type
= msignature
.return_mtype
595 var ret_type
= mysignature
.return_mtype
596 if ret_type
!= null and precursor_ret_type
== null then
597 modelbuilder
.error
(nsig
.n_type
.as(not null), "Redef Error: {mpropdef.mproperty} is a procedure, not a function.")
601 if mysignature
.arity
> 0 then
602 # Check parameters types
603 for i
in [0..mysignature
.arity
[ do
604 var myt
= mysignature
.mparameters
[i
].mtype
605 var prt
= msignature
.mparameters
[i
].mtype
606 if not myt
.is_subtype
(mmodule
, mclassdef
.bound_mtype
, prt
) or
607 not prt
.is_subtype
(mmodule
, mclassdef
.bound_mtype
, myt
) then
608 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}.")
612 if precursor_ret_type
!= null then
613 if ret_type
== null then
614 # Inherit the return type
615 ret_type
= precursor_ret_type
616 else if not ret_type
.is_subtype
(mmodule
, mclassdef
.bound_mtype
, precursor_ret_type
) then
617 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}.")
622 if mysignature
.arity
> 0 then
623 # Check parameters visibility
624 for i
in [0..mysignature
.arity
[ do
625 var nt
= nsig
.n_params
[i
].n_type
626 if nt
!= null then modelbuilder
.check_visibility
(nt
, nt
.mtype
.as(not null), mpropdef
)
629 if nt
!= null then modelbuilder
.check_visibility
(nt
, nt
.mtype
.as(not null), mpropdef
)
634 redef class AAttrPropdef
635 redef type MPROPDEF: MAttributeDef
637 # The associated getter (read accessor) if any
638 var mreadpropdef
: nullable MMethodDef writable
639 # The associated setter (write accessor) if any
640 var mwritepropdef
: nullable MMethodDef writable
641 redef fun build_property
(modelbuilder
, nclassdef
)
643 var mclassdef
= nclassdef
.mclassdef
.as(not null)
644 var mclass
= mclassdef
.mclass
647 if self.n_id
!= null then
648 name
= self.n_id
.text
650 name
= self.n_id2
.text
653 if mclass
.kind
== interface_kind
or mclassdef
.mclass
.kind
== enum_kind
then
654 modelbuilder
.error
(self, "Error: Attempt to define attribute {name} in the interface {mclass}.")
655 else if mclass
.kind
== enum_kind
then
656 modelbuilder
.error
(self, "Error: Attempt to define attribute {name} in the enum class {mclass}.")
657 else if mclass
.kind
== extern_kind
then
658 modelbuilder
.error
(self, "Error: Attempt to define attribute {name} in the extern class {mclass}.")
663 # Old attribute style
664 var mprop
= modelbuilder
.try_get_mproperty_by_name
(nid
, mclassdef
, name
)
665 if mprop
== null then
666 var mvisibility
= new_property_visibility
(modelbuilder
, mclassdef
, self.n_visibility
)
667 mprop
= new MAttribute(mclassdef
, name
, mvisibility
)
668 if not self.check_redef_keyword
(modelbuilder
, nclassdef
, self.n_kwredef
, false, mprop
) then return
670 assert mprop
isa MAttribute
671 check_redef_property_visibility
(modelbuilder
, self.n_visibility
, mprop
)
672 if not self.check_redef_keyword
(modelbuilder
, nclassdef
, self.n_kwredef
, true, mprop
) then return
674 nclassdef
.mprop2npropdef
[mprop
] = self
676 var mpropdef
= new MAttributeDef(mclassdef
, mprop
, self.location
)
677 self.mpropdef
= mpropdef
678 modelbuilder
.mpropdef2npropdef
[mpropdef
] = self
681 var nreadable
= self.n_readable
682 if nreadable
!= null then
683 var readname
= name
.substring_from
(1)
684 var mreadprop
= modelbuilder
.try_get_mproperty_by_name
(nid
, mclassdef
, readname
).as(nullable MMethod)
685 if mreadprop
== null then
686 var mvisibility
= new_property_visibility
(modelbuilder
, mclassdef
, nreadable
.n_visibility
)
687 mreadprop
= new MMethod(mclassdef
, readname
, mvisibility
)
688 if not self.check_redef_keyword
(modelbuilder
, nclassdef
, nreadable
.n_kwredef
, false, mreadprop
) then return
690 if not self.check_redef_keyword
(modelbuilder
, nclassdef
, nreadable
.n_kwredef
, true, mreadprop
) then return
691 check_redef_property_visibility
(modelbuilder
, nreadable
.n_visibility
, mreadprop
)
693 nclassdef
.mprop2npropdef
[mreadprop
] = self
695 var mreadpropdef
= new MMethodDef(mclassdef
, mreadprop
, self.location
)
696 self.mreadpropdef
= mreadpropdef
697 modelbuilder
.mpropdef2npropdef
[mreadpropdef
] = self
698 mreadpropdef
.mdoc
= mpropdef
.mdoc
701 var nwritable
= self.n_writable
702 if nwritable
!= null then
703 var writename
= name
.substring_from
(1) + "="
704 var mwriteprop
= modelbuilder
.try_get_mproperty_by_name
(nid
, mclassdef
, writename
).as(nullable MMethod)
705 if mwriteprop
== null then
706 var mvisibility
= new_property_visibility
(modelbuilder
, mclassdef
, nwritable
.n_visibility
)
707 mwriteprop
= new MMethod(mclassdef
, writename
, mvisibility
)
708 if not self.check_redef_keyword
(modelbuilder
, nclassdef
, nwritable
.n_kwredef
, false, mwriteprop
) then return
710 if not self.check_redef_keyword
(modelbuilder
, nclassdef
, nwritable
.n_kwredef
, true, mwriteprop
) then return
711 check_redef_property_visibility
(modelbuilder
, nwritable
.n_visibility
, mwriteprop
)
713 nclassdef
.mprop2npropdef
[mwriteprop
] = self
715 var mwritepropdef
= new MMethodDef(mclassdef
, mwriteprop
, self.location
)
716 self.mwritepropdef
= mwritepropdef
717 modelbuilder
.mpropdef2npropdef
[mwritepropdef
] = self
718 mwritepropdef
.mdoc
= mpropdef
.mdoc
721 # New attribute style
722 var nid2
= self.n_id2
.as(not null)
723 var mprop
= new MAttribute(mclassdef
, "@" + name
, none_visibility
)
724 var mpropdef
= new MAttributeDef(mclassdef
, mprop
, self.location
)
725 self.mpropdef
= mpropdef
726 modelbuilder
.mpropdef2npropdef
[mpropdef
] = self
730 var mreadprop
= modelbuilder
.try_get_mproperty_by_name
(nid2
, mclassdef
, readname
).as(nullable MMethod)
731 if mreadprop
== null then
732 var mvisibility
= new_property_visibility
(modelbuilder
, mclassdef
, self.n_visibility
)
733 mreadprop
= new MMethod(mclassdef
, readname
, mvisibility
)
734 if not self.check_redef_keyword
(modelbuilder
, nclassdef
, n_kwredef
, false, mreadprop
) then return
736 if not self.check_redef_keyword
(modelbuilder
, nclassdef
, n_kwredef
, true, mreadprop
) then return
737 check_redef_property_visibility
(modelbuilder
, self.n_visibility
, mreadprop
)
739 nclassdef
.mprop2npropdef
[mreadprop
] = self
741 var mreadpropdef
= new MMethodDef(mclassdef
, mreadprop
, self.location
)
742 self.mreadpropdef
= mreadpropdef
743 modelbuilder
.mpropdef2npropdef
[mreadpropdef
] = self
744 mreadpropdef
.mdoc
= mpropdef
.mdoc
746 var writename
= name
+ "="
747 var nwritable
= self.n_writable
748 var mwriteprop
= modelbuilder
.try_get_mproperty_by_name
(nid2
, mclassdef
, writename
).as(nullable MMethod)
749 var nwkwredef
: nullable Token = null
750 if nwritable
!= null then nwkwredef
= nwritable
.n_kwredef
751 if mwriteprop
== null then
753 if nwritable
!= null then
754 mvisibility
= new_property_visibility
(modelbuilder
, mclassdef
, nwritable
.n_visibility
)
756 mvisibility
= private_visibility
758 mwriteprop
= new MMethod(mclassdef
, writename
, mvisibility
)
759 if not self.check_redef_keyword
(modelbuilder
, nclassdef
, nwkwredef
, false, mwriteprop
) then return
761 if not self.check_redef_keyword
(modelbuilder
, nclassdef
, nwkwredef
, true, mwriteprop
) then return
762 if nwritable
!= null then
763 check_redef_property_visibility
(modelbuilder
, nwritable
.n_visibility
, mwriteprop
)
766 nclassdef
.mprop2npropdef
[mwriteprop
] = self
768 var mwritepropdef
= new MMethodDef(mclassdef
, mwriteprop
, self.location
)
769 self.mwritepropdef
= mwritepropdef
770 modelbuilder
.mpropdef2npropdef
[mwritepropdef
] = self
771 mwritepropdef
.mdoc
= mpropdef
.mdoc
775 redef fun build_signature
(modelbuilder
)
777 var mpropdef
= self.mpropdef
778 if mpropdef
== null then return # Error thus skiped
779 var mclassdef
= mpropdef
.mclassdef
780 var mmodule
= mclassdef
.mmodule
781 var mtype
: nullable MType = null
783 var ntype
= self.n_type
784 if ntype
!= null then
785 mtype
= modelbuilder
.resolve_mtype
(mmodule
, mclassdef
, ntype
)
786 if mtype
== null then return
789 var nexpr
= self.n_expr
790 if mtype
== null then
791 if nexpr
!= null then
792 if nexpr
isa ANewExpr then
793 mtype
= modelbuilder
.resolve_mtype
(mmodule
, mclassdef
, nexpr
.n_type
)
794 else if nexpr
isa AIntExpr then
795 var cla
= modelbuilder
.try_get_mclass_by_name
(nexpr
, mmodule
, "Int")
796 if cla
!= null then mtype
= cla
.mclass_type
797 else if nexpr
isa AFloatExpr then
798 var cla
= modelbuilder
.try_get_mclass_by_name
(nexpr
, mmodule
, "Float")
799 if cla
!= null then mtype
= cla
.mclass_type
800 else if nexpr
isa ACharExpr then
801 var cla
= modelbuilder
.try_get_mclass_by_name
(nexpr
, mmodule
, "Char")
802 if cla
!= null then mtype
= cla
.mclass_type
803 else if nexpr
isa ABoolExpr then
804 var cla
= modelbuilder
.try_get_mclass_by_name
(nexpr
, mmodule
, "Bool")
805 if cla
!= null then mtype
= cla
.mclass_type
806 else if nexpr
isa ASuperstringExpr then
807 var cla
= modelbuilder
.try_get_mclass_by_name
(nexpr
, mmodule
, "String")
808 if cla
!= null then mtype
= cla
.mclass_type
809 else if nexpr
isa AStringFormExpr then
810 var cla
= modelbuilder
.try_get_mclass_by_name
(nexpr
, mmodule
, "String")
811 if cla
!= null then mtype
= cla
.mclass_type
813 modelbuilder
.error
(self, "Error: Untyped attribute {mpropdef}. Implicit typing allowed only for literals and new.")
817 modelbuilder
.error
(self, "Error: Untyped attribute {mpropdef}")
821 if nexpr
isa ANewExpr then
822 var xmtype
= modelbuilder
.resolve_mtype
(mmodule
, mclassdef
, nexpr
.n_type
)
823 if xmtype
== mtype
and modelbuilder
.toolcontext
.opt_warn
.value
>= 2 then
824 modelbuilder
.warning
(ntype
, "Warning: useless type definition")
829 if mtype
== null then return
831 mpropdef
.static_mtype
= mtype
833 var mreadpropdef
= self.mreadpropdef
834 if mreadpropdef
!= null then
835 var msignature
= new MSignature(new Array[MParameter], mtype
)
836 mreadpropdef
.msignature
= msignature
839 var msritepropdef
= self.mwritepropdef
840 if mwritepropdef
!= null then
843 name
= n_id
.text
.substring_from
(1)
847 var mparameter
= new MParameter(name
, mtype
, false)
848 var msignature
= new MSignature([mparameter
], null)
849 mwritepropdef
.msignature
= msignature
853 redef fun check_signature
(modelbuilder
)
855 var mpropdef
= self.mpropdef
856 if mpropdef
== null then return # Error thus skiped
857 var mclassdef
= mpropdef
.mclassdef
858 var mmodule
= mclassdef
.mmodule
859 var ntype
= self.n_type
860 var mtype
= self.mpropdef
.static_mtype
861 if mtype
== null then return # Error thus skiped
863 # Lookup for signature in the precursor
864 # FIXME all precursors should be considered
865 if not mpropdef
.is_intro
then
866 var precursor_type
= mpropdef
.mproperty
.intro
.static_mtype
867 if precursor_type
== null then return
869 if mtype
!= precursor_type
then
870 modelbuilder
.error
(ntype
.as(not null), "Redef Error: Wrong static type. found {mtype}, expected {precursor_type}.")
875 # Check getter and setter
876 var meth
= self.mreadpropdef
878 self.check_method_signature
(modelbuilder
, meth
)
879 var node
: nullable ANode = ntype
880 if node
== null then node
= self
881 modelbuilder
.check_visibility
(node
, mtype
, meth
)
883 meth
= self.mwritepropdef
885 self.check_method_signature
(modelbuilder
, meth
)
886 var node
: nullable ANode = ntype
887 if node
== null then node
= self
888 modelbuilder
.check_visibility
(node
, mtype
, meth
)
892 private fun check_method_signature
(modelbuilder
: ModelBuilder, mpropdef
: MMethodDef)
894 var mclassdef
= mpropdef
.mclassdef
895 var mmodule
= mclassdef
.mmodule
896 var nsig
= self.n_type
897 var mysignature
= mpropdef
.msignature
898 if mysignature
== null then return # Error thus skiped
900 # Lookup for signature in the precursor
901 # FIXME all precursors should be considered
902 if not mpropdef
.is_intro
then
903 var msignature
= mpropdef
.mproperty
.intro
.msignature
904 if msignature
== null then return
906 if mysignature
.arity
!= msignature
.arity
then
908 if nsig
!= null then node
= nsig
else node
= self
909 modelbuilder
.error
(node
, "Redef Error: {mysignature.arity} parameters found, {msignature.arity} expected. Signature is {mpropdef}{msignature}")
912 var precursor_ret_type
= msignature
.return_mtype
913 var ret_type
= mysignature
.return_mtype
914 if ret_type
!= null and precursor_ret_type
== null then
916 if nsig
!= null then node
= nsig
else node
= self
917 modelbuilder
.error
(node
, "Redef Error: {mpropdef.mproperty} is a procedure, not a function.")
921 if mysignature
.arity
> 0 then
922 # Check parameters types
923 for i
in [0..mysignature
.arity
[ do
924 var myt
= mysignature
.mparameters
[i
].mtype
925 var prt
= msignature
.mparameters
[i
].mtype
926 if not myt
.is_subtype
(mmodule
, mclassdef
.bound_mtype
, prt
) and
927 not prt
.is_subtype
(mmodule
, mclassdef
.bound_mtype
, myt
) then
929 if nsig
!= null then node
= nsig
else node
= self
930 modelbuilder
.error
(node
, "Redef Error: Wrong type for parameter `{mysignature.mparameters[i].name}'. found {myt}, expected {prt}.")
934 if precursor_ret_type
!= null then
935 if ret_type
== null then
936 # Inherit the return type
937 ret_type
= precursor_ret_type
938 else if not ret_type
.is_subtype
(mmodule
, mclassdef
.bound_mtype
, precursor_ret_type
) then
940 if nsig
!= null then node
= nsig
else node
= self
941 modelbuilder
.error
(node
, "Redef Error: Wrong return type. found {ret_type}, expected {precursor_ret_type}.")
948 redef class ATypePropdef
949 redef type MPROPDEF: MVirtualTypeDef
951 redef fun build_property
(modelbuilder
, nclassdef
)
953 var mclassdef
= nclassdef
.mclassdef
.as(not null)
954 var name
= self.n_id
.text
955 var mprop
= modelbuilder
.try_get_mproperty_by_name
(self.n_id
, mclassdef
, name
)
956 if mprop
== null then
957 var mvisibility
= new_property_visibility
(modelbuilder
, mclassdef
, self.n_visibility
)
958 mprop
= new MVirtualTypeProp(mclassdef
, name
, mvisibility
)
959 for c
in name
.chars
do if c
>= 'a' and c
<= 'z' then
960 modelbuilder
.warning
(n_id
, "Warning: lowercase in the virtual type {name}")
963 if not self.check_redef_keyword
(modelbuilder
, nclassdef
, self.n_kwredef
, false, mprop
) then return
965 if not self.check_redef_keyword
(modelbuilder
, nclassdef
, self.n_kwredef
, true, mprop
) then return
966 assert mprop
isa MVirtualTypeProp
967 check_redef_property_visibility
(modelbuilder
, self.n_visibility
, mprop
)
969 nclassdef
.mprop2npropdef
[mprop
] = self
971 var mpropdef
= new MVirtualTypeDef(mclassdef
, mprop
, self.location
)
972 self.mpropdef
= mpropdef
973 modelbuilder
.mpropdef2npropdef
[mpropdef
] = self
977 redef fun build_signature
(modelbuilder
)
979 var mpropdef
= self.mpropdef
980 if mpropdef
== null then return # Error thus skiped
981 var mclassdef
= mpropdef
.mclassdef
982 var mmodule
= mclassdef
.mmodule
983 var mtype
: nullable MType = null
985 var ntype
= self.n_type
986 mtype
= modelbuilder
.resolve_mtype
(mmodule
, mclassdef
, ntype
)
987 if mtype
== null then return
989 mpropdef
.bound
= mtype
990 # print "{mpropdef}: {mtype}"
993 redef fun check_signature
(modelbuilder
)
995 var mpropdef
= self.mpropdef
996 if mpropdef
== null then return # Error thus skiped
998 var bound
= self.mpropdef
.bound
999 if bound
== null then return # Error thus skiped
1001 modelbuilder
.check_visibility
(n_type
.as(not null), bound
, mpropdef
)
1003 # Fast case: the bound is not a formal type
1004 if not bound
isa MVirtualType then return
1006 var mclassdef
= mpropdef
.mclassdef
1007 var mmodule
= mclassdef
.mmodule
1008 var anchor
= mclassdef
.bound_mtype
1010 # Slow case: progress on each resolution until: (i) we loop, or (ii) we found a non formal type
1011 var seen
= [self.mpropdef
.mproperty
.mvirtualtype
]
1013 if seen
.has
(bound
) then
1015 modelbuilder
.error
(self, "Error: circularity of virtual type definition: {seen.join(" -> ")}")
1019 var next
= bound
.lookup_bound
(mmodule
, anchor
)
1020 if not next
isa MVirtualType then break