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 check_visibility
(a
, a
.mtype
.as(not null), mpropdef
)
209 else if mtype
isa MGenericType then
210 for t
in mtype
.arguments
do check_visibility
(node
, t
, mpropdef
)
216 # The class whose self inherit all the constructors.
217 # 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
218 var inherit_init_from
: nullable MClass = null
222 # Does the MPropDef contains a call to super or a call of a super-constructor?
223 # Subsequent phases of the frontend (esp. typing) set it if required
224 var has_supercall
: Bool writable = false
227 redef class AClassdef
228 var build_properties_is_done
: Bool = false
229 # The list of super-constructor to call at the start of the free constructor
230 # 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
231 var super_inits
: nullable Collection[MMethod] = null
233 # The free init (implicitely constructed by the class if required)
234 var mfree_init
: nullable MMethodDef = null
237 redef class MClassDef
238 # What is the `APropdef` associated to a `MProperty`?
239 # Used to check multiple definition of a property.
240 var mprop2npropdef
: Map[MProperty, APropdef] = new HashMap[MProperty, APropdef]
244 # Join the text of all tokens
245 # Used to get the 'real name' of method definitions.
246 fun collect_text
: String
248 var v
= new TextCollectorVisitor
255 private class TextCollectorVisitor
257 var text
: String = ""
260 if n
isa Token then text
+= n
.text
266 # The associated main model entity
267 type MPROPDEF: MPropDef
269 # The associated propdef once build by a `ModelBuilder`
270 var mpropdef
: nullable MPROPDEF writable
272 private fun build_property
(modelbuilder
: ModelBuilder, mclassdef
: MClassDef) is abstract
273 private fun build_signature
(modelbuilder
: ModelBuilder) is abstract
274 private fun check_signature
(modelbuilder
: ModelBuilder) is abstract
275 private fun new_property_visibility
(modelbuilder
: ModelBuilder, mclassdef
: MClassDef, nvisibility
: nullable AVisibility): MVisibility
277 var mvisibility
= public_visibility
278 if nvisibility
!= null then
279 mvisibility
= nvisibility
.mvisibility
280 if mvisibility
== intrude_visibility
then
281 modelbuilder
.error
(nvisibility
, "Error: intrude is not a legal visibility for properties.")
282 mvisibility
= public_visibility
285 if mclassdef
.mclass
.visibility
== private_visibility
then
286 if mvisibility
== protected_visibility
then
287 assert nvisibility
!= null
288 modelbuilder
.error
(nvisibility
, "Error: The only legal visibility for properties in a private class is private.")
289 else if mvisibility
== private_visibility
then
290 assert nvisibility
!= null
292 # modelbuilder.warning(nvisibility, "Warning: private is unrequired since the only legal visibility for properties in a private class is private.")
294 mvisibility
= private_visibility
299 private fun set_doc
(mpropdef
: MPropDef)
301 var ndoc
= self.n_doc
303 var mdoc
= ndoc
.to_mdoc
305 mdoc
.original_mentity
= mpropdef
309 private fun check_redef_property_visibility
(modelbuilder
: ModelBuilder, nvisibility
: nullable AVisibility, mprop
: MProperty)
311 if nvisibility
== null then return
312 var mvisibility
= nvisibility
.mvisibility
313 if mvisibility
!= mprop
.visibility
and mvisibility
!= public_visibility
then
314 modelbuilder
.error
(nvisibility
, "Error: redefinition changed the visibility from a {mprop.visibility} to a {mvisibility}")
318 private fun check_redef_keyword
(modelbuilder
: ModelBuilder, mclassdef
: MClassDef, kwredef
: nullable Token, need_redef
: Bool, mprop
: MProperty): Bool
320 if mclassdef
.mprop2npropdef
.has_key
(mprop
) then
321 modelbuilder
.error
(self, "Error: A property {mprop} is already defined in class {mclassdef.mclass} at line {mclassdef.mprop2npropdef[mprop].location.line_start}.")
324 if mprop
isa MMethod and mprop
.is_toplevel
!= (parent
isa ATopClassdef) then
325 if mprop
.is_toplevel
then
326 modelbuilder
.error
(self, "Error: {mprop} is a top level method.")
328 modelbuilder
.error
(self, "Error: {mprop} is not a top level method.")
333 if kwredef
== null then
335 modelbuilder
.error
(self, "Redef error: {mclassdef.mclass}::{mprop.name} is an inherited property. To redefine it, add the redef keyword.")
339 if not need_redef
then
340 modelbuilder
.error
(self, "Error: No property {mclassdef.mclass}::{mprop.name} is inherited. Remove the redef keyword to define a new property.")
349 redef class ASignature
350 # Is the model builder has correctly visited the signature
351 var is_visited
= false
352 # Names of parameters from the AST
353 # REQUIRE: is_visited
354 var param_names
= new Array[String]
355 # Types of parameters from the AST
356 # REQUIRE: is_visited
357 var param_types
= new Array[MType]
358 # Rank of the vararg (of -1 if none)
359 # REQUIRE: is_visited
360 var vararg_rank
: Int = -1
362 var ret_type
: nullable MType = null
364 # Visit and fill information about a signature
365 private fun visit_signature
(modelbuilder
: ModelBuilder, mclassdef
: MClassDef): Bool
367 var mmodule
= mclassdef
.mmodule
368 var param_names
= self.param_names
369 var param_types
= self.param_types
370 for np
in self.n_params
do
371 param_names
.add
(np
.n_id
.text
)
372 var ntype
= np
.n_type
373 if ntype
!= null then
374 var mtype
= modelbuilder
.resolve_mtype
(mmodule
, mclassdef
, ntype
)
375 if mtype
== null then return false # Skip error
376 for i
in [0..param_names
.length-param_types
.length
[ do
377 param_types
.add
(mtype
)
379 if np
.n_dotdotdot
!= null then
380 if self.vararg_rank
!= -1 then
381 modelbuilder
.error
(np
, "Error: {param_names[self.vararg_rank]} is already a vararg")
384 self.vararg_rank
= param_names
.length
- 1
389 var ntype
= self.n_type
390 if ntype
!= null then
391 self.ret_type
= modelbuilder
.resolve_mtype
(mmodule
, mclassdef
, ntype
)
392 if self.ret_type
== null then return false # Skip errir
395 self.is_visited
= true
399 # Build a visited signature
400 fun build_signature
(modelbuilder
: ModelBuilder): nullable MSignature
402 if param_names
.length
!= param_types
.length
then
403 # Some parameters are typed, other parameters are not typed.
404 modelbuilder
.error
(self.n_params
[param_types
.length
], "Error: Untyped parameter `{param_names[param_types.length]}'.")
408 var mparameters
= new Array[MParameter]
409 for i
in [0..param_names
.length
[ do
410 var mparameter
= new MParameter(param_names
[i
], param_types
[i
], i
== vararg_rank
)
411 self.n_params
[i
].mparameter
= mparameter
412 mparameters
.add
(mparameter
)
415 var msignature
= new MSignature(mparameters
, ret_type
)
421 # The associated mparameter if any
422 var mparameter
: nullable MParameter = null
425 redef class AMethPropdef
426 redef type MPROPDEF: MMethodDef
428 redef fun build_property
(modelbuilder
, mclassdef
)
430 var n_kwinit
= n_kwinit
431 var n_kwnew
= n_kwnew
432 var is_init
= n_kwinit
!= null or n_kwnew
!= null
434 var amethodid
= self.n_methid
436 if amethodid
== null then
440 else if n_kwinit
!= null then
443 else if n_kwnew
!= null then
449 else if amethodid
isa AIdMethid then
450 name
= amethodid
.n_id
.text
451 name_node
= amethodid
453 # operator, bracket or assign
454 name
= amethodid
.collect_text
455 name_node
= amethodid
457 if name
== "-" and self.n_signature
.n_params
.length
== 0 then
462 var mprop
: nullable MMethod = null
463 if not is_init
or n_kwredef
!= null then mprop
= modelbuilder
.try_get_mproperty_by_name
(name_node
, mclassdef
, name
).as(nullable MMethod)
464 if mprop
== null then
465 var mvisibility
= new_property_visibility
(modelbuilder
, mclassdef
, self.n_visibility
)
466 mprop
= new MMethod(mclassdef
, name
, mvisibility
)
467 mprop
.is_init
= is_init
468 mprop
.is_new
= n_kwnew
!= null
469 if parent
isa ATopClassdef then mprop
.is_toplevel
= true
470 if not self.check_redef_keyword
(modelbuilder
, mclassdef
, n_kwredef
, false, mprop
) then return
472 if not self.check_redef_keyword
(modelbuilder
, mclassdef
, n_kwredef
, not self isa AMainMethPropdef, mprop
) then return
473 check_redef_property_visibility
(modelbuilder
, self.n_visibility
, mprop
)
475 mclassdef
.mprop2npropdef
[mprop
] = self
477 var mpropdef
= new MMethodDef(mclassdef
, mprop
, self.location
)
481 self.mpropdef
= mpropdef
482 modelbuilder
.mpropdef2npropdef
[mpropdef
] = self
483 if mpropdef
.is_intro
then
484 modelbuilder
.toolcontext
.info
("{mpropdef} introduces new method {mprop.full_name}", 3)
486 modelbuilder
.toolcontext
.info
("{mpropdef} redefines method {mprop.full_name}", 3)
490 redef fun build_signature
(modelbuilder
)
492 var mpropdef
= self.mpropdef
493 if mpropdef
== null then return # Error thus skiped
494 var mclassdef
= mpropdef
.mclassdef
495 var mmodule
= mclassdef
.mmodule
496 var nsig
= self.n_signature
498 # Retrieve info from the signature AST
499 var param_names
= new Array[String] # Names of parameters from the AST
500 var param_types
= new Array[MType] # Types of parameters from the AST
502 var ret_type
: nullable MType = null # Return type from the AST
504 if not nsig
.visit_signature
(modelbuilder
, mclassdef
) then return
505 param_names
= nsig
.param_names
506 param_types
= nsig
.param_types
507 vararg_rank
= nsig
.vararg_rank
508 ret_type
= nsig
.ret_type
511 # Look for some signature to inherit
512 # FIXME: do not inherit from the intro, but from the most specific
513 var msignature
: nullable MSignature = null
514 if not mpropdef
.is_intro
then
515 msignature
= mpropdef
.mproperty
.intro
.msignature
516 if msignature
== null then return # Skip error
518 # Check inherited signature arity
519 if param_names
.length
!= msignature
.arity
then
521 if nsig
!= null then node
= nsig
else node
= self
522 modelbuilder
.error
(node
, "Redef error: {mpropdef} redefines {mpropdef.mproperty.intro} with {param_names.length} parameter(s), {msignature.arity} expected. Signature is {mpropdef}{msignature}")
525 else if mpropdef
.mproperty
.is_init
then
526 # FIXME UGLY: inherit signature from a super-constructor
527 for msupertype
in mclassdef
.supertypes
do
528 msupertype
= msupertype
.anchor_to
(mmodule
, mclassdef
.bound_mtype
)
529 var candidate
= modelbuilder
.try_get_mproperty_by_name2
(self, mmodule
, msupertype
, mpropdef
.mproperty
.name
)
530 if candidate
!= null then
531 if msignature
== null then
532 msignature
= candidate
.intro
.as(MMethodDef).msignature
539 # Inherit the signature
540 if msignature
!= null and param_names
.length
!= param_types
.length
and param_names
.length
== msignature
.arity
and param_types
.length
== 0 then
541 # Parameters are untyped, thus inherit them
542 param_types
= new Array[MType]
543 for mparameter
in msignature
.mparameters
do
544 param_types
.add
(mparameter
.mtype
)
546 vararg_rank
= msignature
.vararg_rank
548 if msignature
!= null and ret_type
== null then
549 ret_type
= msignature
.return_mtype
552 if param_names
.length
!= param_types
.length
then
553 # Some parameters are typed, other parameters are not typed.
554 modelbuilder
.error
(nsig
.n_params
[param_types
.length
], "Error: Untyped parameter `{param_names[param_types.length]}'.")
558 var mparameters
= new Array[MParameter]
559 for i
in [0..param_names
.length
[ do
560 var mparameter
= new MParameter(param_names
[i
], param_types
[i
], i
== vararg_rank
)
561 if nsig
!= null then nsig
.n_params
[i
].mparameter
= mparameter
562 mparameters
.add
(mparameter
)
565 msignature
= new MSignature(mparameters
, ret_type
)
566 mpropdef
.msignature
= msignature
567 mpropdef
.is_abstract
= self isa ADeferredMethPropdef
568 mpropdef
.is_intern
= self isa AInternMethPropdef
569 mpropdef
.is_extern
= self isa AExternPropdef
572 redef fun check_signature
(modelbuilder
)
574 var mpropdef
= self.mpropdef
575 if mpropdef
== null then return # Error thus skiped
576 var mclassdef
= mpropdef
.mclassdef
577 var mmodule
= mclassdef
.mmodule
578 var nsig
= self.n_signature
579 var mysignature
= self.mpropdef
.msignature
580 if mysignature
== null then return # Error thus skiped
582 # Lookup for signature in the precursor
583 # FIXME all precursors should be considered
584 if not mpropdef
.is_intro
then
585 var msignature
= mpropdef
.mproperty
.intro
.msignature
586 if msignature
== null then return
588 var precursor_ret_type
= msignature
.return_mtype
589 var ret_type
= mysignature
.return_mtype
590 if ret_type
!= null and precursor_ret_type
== null then
591 modelbuilder
.error
(nsig
.n_type
.as(not null), "Redef Error: {mpropdef.mproperty} is a procedure, not a function.")
595 if mysignature
.arity
> 0 then
596 # Check parameters types
597 for i
in [0..mysignature
.arity
[ do
598 var myt
= mysignature
.mparameters
[i
].mtype
599 var prt
= msignature
.mparameters
[i
].mtype
600 if not myt
.is_subtype
(mmodule
, mclassdef
.bound_mtype
, prt
) or
601 not prt
.is_subtype
(mmodule
, mclassdef
.bound_mtype
, myt
) then
602 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}.")
606 if precursor_ret_type
!= null then
607 if ret_type
== null then
608 # Inherit the return type
609 ret_type
= precursor_ret_type
610 else if not ret_type
.is_subtype
(mmodule
, mclassdef
.bound_mtype
, precursor_ret_type
) then
611 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}.")
616 if mysignature
.arity
> 0 then
617 # Check parameters visibility
618 for i
in [0..mysignature
.arity
[ do
619 var nt
= nsig
.n_params
[i
].n_type
620 if nt
!= null then modelbuilder
.check_visibility
(nt
, nt
.mtype
.as(not null), mpropdef
)
623 if nt
!= null then modelbuilder
.check_visibility
(nt
, nt
.mtype
.as(not null), mpropdef
)
628 redef class AAttrPropdef
629 redef type MPROPDEF: MAttributeDef
631 # The associated getter (read accessor) if any
632 var mreadpropdef
: nullable MMethodDef writable
633 # The associated setter (write accessor) if any
634 var mwritepropdef
: nullable MMethodDef writable
635 redef fun build_property
(modelbuilder
, mclassdef
)
637 var mclass
= mclassdef
.mclass
640 if self.n_id
!= null then
641 name
= self.n_id
.text
643 name
= self.n_id2
.text
646 if mclass
.kind
== interface_kind
or mclassdef
.mclass
.kind
== enum_kind
then
647 modelbuilder
.error
(self, "Error: Attempt to define attribute {name} in the interface {mclass}.")
648 else if mclass
.kind
== enum_kind
then
649 modelbuilder
.error
(self, "Error: Attempt to define attribute {name} in the enum class {mclass}.")
650 else if mclass
.kind
== extern_kind
then
651 modelbuilder
.error
(self, "Error: Attempt to define attribute {name} in the extern class {mclass}.")
656 # Old attribute style
657 var mprop
= modelbuilder
.try_get_mproperty_by_name
(nid
, mclassdef
, name
)
658 if mprop
== null then
659 var mvisibility
= new_property_visibility
(modelbuilder
, mclassdef
, self.n_visibility
)
660 mprop
= new MAttribute(mclassdef
, name
, mvisibility
)
661 if not self.check_redef_keyword
(modelbuilder
, mclassdef
, self.n_kwredef
, false, mprop
) then return
663 assert mprop
isa MAttribute
664 check_redef_property_visibility
(modelbuilder
, self.n_visibility
, mprop
)
665 if not self.check_redef_keyword
(modelbuilder
, mclassdef
, self.n_kwredef
, true, mprop
) then return
667 mclassdef
.mprop2npropdef
[mprop
] = self
669 var mpropdef
= new MAttributeDef(mclassdef
, mprop
, self.location
)
670 self.mpropdef
= mpropdef
671 modelbuilder
.mpropdef2npropdef
[mpropdef
] = self
674 var nreadable
= self.n_readable
675 if nreadable
!= null then modelbuilder
.error
(nreadable
, "Error: old-style getter no more supported")
676 var nwritable
= self.n_writable
677 if nwritable
!= null then modelbuilder
.error
(nwritable
, "Error: old-style setter no more supported")
679 # New attribute style
680 var nid2
= self.n_id2
.as(not null)
681 var mprop
= new MAttribute(mclassdef
, "@" + name
, none_visibility
)
682 var mpropdef
= new MAttributeDef(mclassdef
, mprop
, self.location
)
683 self.mpropdef
= mpropdef
684 modelbuilder
.mpropdef2npropdef
[mpropdef
] = self
688 var mreadprop
= modelbuilder
.try_get_mproperty_by_name
(nid2
, mclassdef
, readname
).as(nullable MMethod)
689 if mreadprop
== null then
690 var mvisibility
= new_property_visibility
(modelbuilder
, mclassdef
, self.n_visibility
)
691 mreadprop
= new MMethod(mclassdef
, readname
, mvisibility
)
692 if not self.check_redef_keyword
(modelbuilder
, mclassdef
, n_kwredef
, false, mreadprop
) then return
694 if not self.check_redef_keyword
(modelbuilder
, mclassdef
, n_kwredef
, true, mreadprop
) then return
695 check_redef_property_visibility
(modelbuilder
, self.n_visibility
, mreadprop
)
697 mclassdef
.mprop2npropdef
[mreadprop
] = self
699 var mreadpropdef
= new MMethodDef(mclassdef
, mreadprop
, self.location
)
700 self.mreadpropdef
= mreadpropdef
701 modelbuilder
.mpropdef2npropdef
[mreadpropdef
] = self
702 mreadpropdef
.mdoc
= mpropdef
.mdoc
704 var writename
= name
+ "="
705 var nwritable
= self.n_writable
706 var mwriteprop
= modelbuilder
.try_get_mproperty_by_name
(nid2
, mclassdef
, writename
).as(nullable MMethod)
707 var nwkwredef
: nullable Token = null
708 if nwritable
!= null then nwkwredef
= nwritable
.n_kwredef
709 if mwriteprop
== null then
711 if nwritable
!= null then
712 mvisibility
= new_property_visibility
(modelbuilder
, mclassdef
, nwritable
.n_visibility
)
714 mvisibility
= private_visibility
716 mwriteprop
= new MMethod(mclassdef
, writename
, mvisibility
)
717 if not self.check_redef_keyword
(modelbuilder
, mclassdef
, nwkwredef
, false, mwriteprop
) then return
719 if not self.check_redef_keyword
(modelbuilder
, mclassdef
, nwkwredef
or else n_kwredef
, true, mwriteprop
) then return
720 if nwritable
!= null then
721 check_redef_property_visibility
(modelbuilder
, nwritable
.n_visibility
, mwriteprop
)
724 mclassdef
.mprop2npropdef
[mwriteprop
] = self
726 var mwritepropdef
= new MMethodDef(mclassdef
, mwriteprop
, self.location
)
727 self.mwritepropdef
= mwritepropdef
728 modelbuilder
.mpropdef2npropdef
[mwritepropdef
] = self
729 mwritepropdef
.mdoc
= mpropdef
.mdoc
733 redef fun build_signature
(modelbuilder
)
735 var mpropdef
= self.mpropdef
736 if mpropdef
== null then return # Error thus skiped
737 var mclassdef
= mpropdef
.mclassdef
738 var mmodule
= mclassdef
.mmodule
739 var mtype
: nullable MType = null
741 var ntype
= self.n_type
742 if ntype
!= null then
743 mtype
= modelbuilder
.resolve_mtype
(mmodule
, mclassdef
, ntype
)
744 if mtype
== null then return
747 var nexpr
= self.n_expr
748 if mtype
== null then
749 if nexpr
!= null then
750 if nexpr
isa ANewExpr then
751 mtype
= modelbuilder
.resolve_mtype
(mmodule
, mclassdef
, nexpr
.n_type
)
752 else if nexpr
isa AIntExpr then
753 var cla
= modelbuilder
.try_get_mclass_by_name
(nexpr
, mmodule
, "Int")
754 if cla
!= null then mtype
= cla
.mclass_type
755 else if nexpr
isa AFloatExpr then
756 var cla
= modelbuilder
.try_get_mclass_by_name
(nexpr
, mmodule
, "Float")
757 if cla
!= null then mtype
= cla
.mclass_type
758 else if nexpr
isa ACharExpr then
759 var cla
= modelbuilder
.try_get_mclass_by_name
(nexpr
, mmodule
, "Char")
760 if cla
!= null then mtype
= cla
.mclass_type
761 else if nexpr
isa ABoolExpr then
762 var cla
= modelbuilder
.try_get_mclass_by_name
(nexpr
, mmodule
, "Bool")
763 if cla
!= null then mtype
= cla
.mclass_type
764 else if nexpr
isa ASuperstringExpr then
765 var cla
= modelbuilder
.try_get_mclass_by_name
(nexpr
, mmodule
, "String")
766 if cla
!= null then mtype
= cla
.mclass_type
767 else if nexpr
isa AStringFormExpr then
768 var cla
= modelbuilder
.try_get_mclass_by_name
(nexpr
, mmodule
, "String")
769 if cla
!= null then mtype
= cla
.mclass_type
771 modelbuilder
.error
(self, "Error: Untyped attribute {mpropdef}. Implicit typing allowed only for literals and new.")
775 modelbuilder
.error
(self, "Error: Untyped attribute {mpropdef}")
779 if nexpr
isa ANewExpr then
780 var xmtype
= modelbuilder
.resolve_mtype
(mmodule
, mclassdef
, nexpr
.n_type
)
781 if xmtype
== mtype
and modelbuilder
.toolcontext
.opt_warn
.value
>= 2 then
782 modelbuilder
.warning
(ntype
, "Warning: useless type definition")
787 if mtype
== null then return
789 mpropdef
.static_mtype
= mtype
791 var mreadpropdef
= self.mreadpropdef
792 if mreadpropdef
!= null then
793 var msignature
= new MSignature(new Array[MParameter], mtype
)
794 mreadpropdef
.msignature
= msignature
797 var msritepropdef
= self.mwritepropdef
798 if mwritepropdef
!= null then
801 name
= n_id
.text
.substring_from
(1)
805 var mparameter
= new MParameter(name
, mtype
, false)
806 var msignature
= new MSignature([mparameter
], null)
807 mwritepropdef
.msignature
= msignature
811 redef fun check_signature
(modelbuilder
)
813 var mpropdef
= self.mpropdef
814 if mpropdef
== null then return # Error thus skiped
815 var mclassdef
= mpropdef
.mclassdef
816 var mmodule
= mclassdef
.mmodule
817 var ntype
= self.n_type
818 var mtype
= self.mpropdef
.static_mtype
819 if mtype
== null then return # Error thus skiped
821 # Lookup for signature in the precursor
822 # FIXME all precursors should be considered
823 if not mpropdef
.is_intro
then
824 var precursor_type
= mpropdef
.mproperty
.intro
.static_mtype
825 if precursor_type
== null then return
827 if mtype
!= precursor_type
then
828 modelbuilder
.error
(ntype
.as(not null), "Redef Error: Wrong static type. found {mtype}, expected {precursor_type}.")
833 # Check getter and setter
834 var meth
= self.mreadpropdef
836 self.check_method_signature
(modelbuilder
, meth
)
837 var node
: nullable ANode = ntype
838 if node
== null then node
= self
839 modelbuilder
.check_visibility
(node
, mtype
, meth
)
841 meth
= self.mwritepropdef
843 self.check_method_signature
(modelbuilder
, meth
)
844 var node
: nullable ANode = ntype
845 if node
== null then node
= self
846 modelbuilder
.check_visibility
(node
, mtype
, meth
)
850 private fun check_method_signature
(modelbuilder
: ModelBuilder, mpropdef
: MMethodDef)
852 var mclassdef
= mpropdef
.mclassdef
853 var mmodule
= mclassdef
.mmodule
854 var nsig
= self.n_type
855 var mysignature
= mpropdef
.msignature
856 if mysignature
== null then return # Error thus skiped
858 # Lookup for signature in the precursor
859 # FIXME all precursors should be considered
860 if not mpropdef
.is_intro
then
861 var msignature
= mpropdef
.mproperty
.intro
.msignature
862 if msignature
== null then return
864 if mysignature
.arity
!= msignature
.arity
then
866 if nsig
!= null then node
= nsig
else node
= self
867 modelbuilder
.error
(node
, "Redef Error: {mysignature.arity} parameters found, {msignature.arity} expected. Signature is {mpropdef}{msignature}")
870 var precursor_ret_type
= msignature
.return_mtype
871 var ret_type
= mysignature
.return_mtype
872 if ret_type
!= null and precursor_ret_type
== null then
874 if nsig
!= null then node
= nsig
else node
= self
875 modelbuilder
.error
(node
, "Redef Error: {mpropdef.mproperty} is a procedure, not a function.")
879 if mysignature
.arity
> 0 then
880 # Check parameters types
881 for i
in [0..mysignature
.arity
[ do
882 var myt
= mysignature
.mparameters
[i
].mtype
883 var prt
= msignature
.mparameters
[i
].mtype
884 if not myt
.is_subtype
(mmodule
, mclassdef
.bound_mtype
, prt
) and
885 not prt
.is_subtype
(mmodule
, mclassdef
.bound_mtype
, myt
) then
887 if nsig
!= null then node
= nsig
else node
= self
888 modelbuilder
.error
(node
, "Redef Error: Wrong type for parameter `{mysignature.mparameters[i].name}'. found {myt}, expected {prt}.")
892 if precursor_ret_type
!= null then
893 if ret_type
== null then
894 # Inherit the return type
895 ret_type
= precursor_ret_type
896 else if not ret_type
.is_subtype
(mmodule
, mclassdef
.bound_mtype
, precursor_ret_type
) then
898 if nsig
!= null then node
= nsig
else node
= self
899 modelbuilder
.error
(node
, "Redef Error: Wrong return type. found {ret_type}, expected {precursor_ret_type}.")
906 redef class ATypePropdef
907 redef type MPROPDEF: MVirtualTypeDef
909 redef fun build_property
(modelbuilder
, mclassdef
)
911 var name
= self.n_id
.text
912 var mprop
= modelbuilder
.try_get_mproperty_by_name
(self.n_id
, mclassdef
, name
)
913 if mprop
== null then
914 var mvisibility
= new_property_visibility
(modelbuilder
, mclassdef
, self.n_visibility
)
915 mprop
= new MVirtualTypeProp(mclassdef
, name
, mvisibility
)
916 for c
in name
.chars
do if c
>= 'a' and c
<= 'z' then
917 modelbuilder
.warning
(n_id
, "Warning: lowercase in the virtual type {name}")
920 if not self.check_redef_keyword
(modelbuilder
, mclassdef
, self.n_kwredef
, false, mprop
) then return
922 if not self.check_redef_keyword
(modelbuilder
, mclassdef
, self.n_kwredef
, true, mprop
) then return
923 assert mprop
isa MVirtualTypeProp
924 check_redef_property_visibility
(modelbuilder
, self.n_visibility
, mprop
)
926 mclassdef
.mprop2npropdef
[mprop
] = self
928 var mpropdef
= new MVirtualTypeDef(mclassdef
, mprop
, self.location
)
929 self.mpropdef
= mpropdef
930 modelbuilder
.mpropdef2npropdef
[mpropdef
] = self
934 redef fun build_signature
(modelbuilder
)
936 var mpropdef
= self.mpropdef
937 if mpropdef
== null then return # Error thus skiped
938 var mclassdef
= mpropdef
.mclassdef
939 var mmodule
= mclassdef
.mmodule
940 var mtype
: nullable MType = null
942 var ntype
= self.n_type
943 mtype
= modelbuilder
.resolve_mtype
(mmodule
, mclassdef
, ntype
)
944 if mtype
== null then return
946 mpropdef
.bound
= mtype
947 # print "{mpropdef}: {mtype}"
950 redef fun check_signature
(modelbuilder
)
952 var mpropdef
= self.mpropdef
953 if mpropdef
== null then return # Error thus skiped
955 var bound
= self.mpropdef
.bound
956 if bound
== null then return # Error thus skiped
958 modelbuilder
.check_visibility
(n_type
.as(not null), bound
, mpropdef
)
960 # Fast case: the bound is not a formal type
961 if not bound
isa MVirtualType then return
963 var mclassdef
= mpropdef
.mclassdef
964 var mmodule
= mclassdef
.mmodule
965 var anchor
= mclassdef
.bound_mtype
967 # Slow case: progress on each resolution until: (i) we loop, or (ii) we found a non formal type
968 var seen
= [self.mpropdef
.mproperty
.mvirtualtype
]
970 if seen
.has
(bound
) then
972 modelbuilder
.error
(self, "Error: circularity of virtual type definition: {seen.join(" -> ")}")
976 var next
= bound
.lookup_bound
(mmodule
, anchor
)
977 if not next
isa MVirtualType then break