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 and candidate
.intro
.msignature
.arity
== 0 then
100 combine
.add
(candidate
)
103 var inhc2
= c
.inherit_init_from
104 if inhc2
== null then inhc2
= c
105 if inhc2
== inhc
then continue
107 self.error
(nclassdef
, "Error: Cannot provide a defaut constructor: conflict for {inhc} and {c}")
113 # Collect undefined attributes
114 var mparameters
= new Array[MParameter]
115 var anode
: nullable ANode = null
116 for npropdef
in nclassdef
.n_propdefs
do
117 if npropdef
isa AAttrPropdef and npropdef
.n_expr
== null then
118 if npropdef
.mpropdef
== null then return # Skip broken attribute
119 var paramname
= npropdef
.mpropdef
.mproperty
.name
.substring_from
(1)
120 var ret_type
= npropdef
.mpropdef
.static_mtype
121 if ret_type
== null then return
122 var mparameter
= new MParameter(paramname
, ret_type
, false)
123 mparameters
.add
(mparameter
)
124 if anode
== null then anode
= npropdef
127 if anode
== null then anode
= nclassdef
129 if combine
.is_empty
and inhc
!= null then
130 if not mparameters
.is_empty
then
131 self.error
(anode
,"Error: {mclassdef} cannot inherit constructors from {inhc} because there is attributes without initial values: {mparameters.join(", ")}")
135 # TODO: actively inherit the consturctor
136 self.toolcontext
.info
("{mclassdef} inherits all constructors from {inhc}", 3)
137 mclassdef
.mclass
.inherit_init_from
= inhc
141 if not combine
.is_empty
and inhc
!= null then
142 self.error
(nclassdef
, "Error: Cannot provide a defaut constructor: conflict for {combine.join(", ")} and {inhc}")
146 if not combine
.is_empty
then
147 if mparameters
.is_empty
and combine
.length
== 1 then
148 # No need to create a local init, the inherited one is enough
149 inhc
= combine
.first
.intro_mclassdef
.mclass
150 mclassdef
.mclass
.inherit_init_from
= inhc
151 self.toolcontext
.info
("{mclassdef} inherits all constructors from {inhc}", 3)
154 nclassdef
.super_inits
= combine
157 var mprop
= new MMethod(mclassdef
, "init", mclassdef
.mclass
.visibility
)
158 var mpropdef
= new MMethodDef(mclassdef
, mprop
, nclassdef
.location
)
159 var msignature
= new MSignature(mparameters
, null)
160 mpropdef
.msignature
= msignature
162 nclassdef
.mfree_init
= mpropdef
163 self.toolcontext
.info
("{mclassdef} gets a free constructor for attributes {mpropdef}{msignature}", 3)
166 # Check the visibility of `mtype` as an element of the signature of `mpropdef`.
167 fun check_visibility
(node
: ANode, mtype
: MType, mpropdef
: MPropDef)
169 var mmodule
= mpropdef
.mclassdef
.mmodule
170 var mproperty
= mpropdef
.mproperty
172 # Extract visibility information of the main part of `mtype`
173 # It is a case-by case
174 var vis_type
: nullable MVisibility = null # The own visibility of the type
175 var mmodule_type
: nullable MModule = null # The origial module of the type
176 if mtype
isa MNullableType then mtype
= mtype
.mtype
177 if mtype
isa MClassType then
178 vis_type
= mtype
.mclass
.visibility
179 mmodule_type
= mtype
.mclass
.intro
.mmodule
180 else if mtype
isa MVirtualType then
181 vis_type
= mtype
.mproperty
.visibility
182 mmodule_type
= mtype
.mproperty
.intro_mclassdef
.mmodule
183 else if mtype
isa MParameterType then
184 # nothing, always visible
186 node
.debug
"Unexpected type {mtype}"
190 if vis_type
!= null then
191 assert mmodule_type
!= null
192 var vis_module_type
= mmodule
.visibility_for
(mmodule_type
) # the visibility of the original module
193 if mproperty
.visibility
> vis_type
then
194 error
(node
, "Error: The {mproperty.visibility} property `{mproperty}` cannot contain the {vis_type} type `{mtype}`")
196 else if mproperty
.visibility
> vis_module_type
then
197 error
(node
, "Error: The {mproperty.visibility} property `{mproperty}` cannot contain the type `{mtype}` from the {vis_module_type} module `{mmodule_type}`")
202 # No error, try to go deeper in generic types
203 if node
isa AType then
204 for a
in node
.n_types
do check_visibility
(a
, a
.mtype
.as(not null), mpropdef
)
205 else if mtype
isa MGenericType then
206 for t
in mtype
.arguments
do check_visibility
(node
, t
, mpropdef
)
212 # The class whose self inherit all the constructors.
213 # 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
214 var inherit_init_from
: nullable MClass = null
218 # Does the MPropDef contains a call to super or a call of a super-constructor?
219 # Subsequent phases of the frontend (esp. typing) set it if required
220 var has_supercall
: Bool writable = false
223 redef class AClassdef
224 var build_properties_is_done
: Bool = false
225 # The list of super-constructor to call at the start of the free constructor
226 # 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
227 var super_inits
: nullable Collection[MMethod] = null
229 # The free init (implicitely constructed by the class if required)
230 var mfree_init
: nullable MMethodDef = null
233 redef class MClassDef
234 # What is the `APropdef` associated to a `MProperty`?
235 # Used to check multiple definition of a property.
236 var mprop2npropdef
: Map[MProperty, APropdef] = new HashMap[MProperty, APropdef]
240 # Join the text of all tokens
241 # Used to get the 'real name' of method definitions.
242 fun collect_text
: String
244 var v
= new TextCollectorVisitor
251 private class TextCollectorVisitor
253 var text
: String = ""
256 if n
isa Token then text
+= n
.text
262 # The associated main model entity
263 type MPROPDEF: MPropDef
265 # The associated propdef once build by a `ModelBuilder`
266 var mpropdef
: nullable MPROPDEF writable
268 private fun build_property
(modelbuilder
: ModelBuilder, mclassdef
: MClassDef) is abstract
269 private fun build_signature
(modelbuilder
: ModelBuilder) is abstract
270 private fun check_signature
(modelbuilder
: ModelBuilder) is abstract
271 private fun new_property_visibility
(modelbuilder
: ModelBuilder, mclassdef
: MClassDef, nvisibility
: nullable AVisibility): MVisibility
273 var mvisibility
= public_visibility
274 if nvisibility
!= null then
275 mvisibility
= nvisibility
.mvisibility
276 if mvisibility
== intrude_visibility
then
277 modelbuilder
.error
(nvisibility
, "Error: intrude is not a legal visibility for properties.")
278 mvisibility
= public_visibility
281 if mclassdef
.mclass
.visibility
== private_visibility
then
282 if mvisibility
== protected_visibility
then
283 assert nvisibility
!= null
284 modelbuilder
.error
(nvisibility
, "Error: The only legal visibility for properties in a private class is private.")
285 else if mvisibility
== private_visibility
then
286 assert nvisibility
!= null
288 # modelbuilder.warning(nvisibility, "Warning: private is unrequired since the only legal visibility for properties in a private class is private.")
290 mvisibility
= private_visibility
295 private fun set_doc
(mpropdef
: MPropDef)
297 var ndoc
= self.n_doc
299 var mdoc
= ndoc
.to_mdoc
301 mdoc
.original_mentity
= mpropdef
305 private fun check_redef_property_visibility
(modelbuilder
: ModelBuilder, nvisibility
: nullable AVisibility, mprop
: MProperty)
307 if nvisibility
== null then return
308 var mvisibility
= nvisibility
.mvisibility
309 if mvisibility
!= mprop
.visibility
and mvisibility
!= public_visibility
then
310 modelbuilder
.error
(nvisibility
, "Error: redefinition changed the visibility from a {mprop.visibility} to a {mvisibility}")
314 private fun check_redef_keyword
(modelbuilder
: ModelBuilder, mclassdef
: MClassDef, kwredef
: nullable Token, need_redef
: Bool, mprop
: MProperty): Bool
316 if mclassdef
.mprop2npropdef
.has_key
(mprop
) then
317 modelbuilder
.error
(self, "Error: A property {mprop} is already defined in class {mclassdef.mclass} at line {mclassdef.mprop2npropdef[mprop].location.line_start}.")
320 if mprop
isa MMethod and mprop
.is_toplevel
!= (parent
isa ATopClassdef) then
321 if mprop
.is_toplevel
then
322 modelbuilder
.error
(self, "Error: {mprop} is a top level method.")
324 modelbuilder
.error
(self, "Error: {mprop} is not a top level method.")
329 if kwredef
== null then
331 modelbuilder
.error
(self, "Redef error: {mclassdef.mclass}::{mprop.name} is an inherited property. To redefine it, add the redef keyword.")
335 if not need_redef
then
336 modelbuilder
.error
(self, "Error: No property {mclassdef.mclass}::{mprop.name} is inherited. Remove the redef keyword to define a new property.")
345 redef class ASignature
346 # Is the model builder has correctly visited the signature
347 var is_visited
= false
348 # Names of parameters from the AST
349 # REQUIRE: is_visited
350 var param_names
= new Array[String]
351 # Types of parameters from the AST
352 # REQUIRE: is_visited
353 var param_types
= new Array[MType]
354 # Rank of the vararg (of -1 if none)
355 # REQUIRE: is_visited
356 var vararg_rank
: Int = -1
358 var ret_type
: nullable MType = null
360 # Visit and fill information about a signature
361 private fun visit_signature
(modelbuilder
: ModelBuilder, mclassdef
: MClassDef): Bool
363 var mmodule
= mclassdef
.mmodule
364 var param_names
= self.param_names
365 var param_types
= self.param_types
366 for np
in self.n_params
do
367 param_names
.add
(np
.n_id
.text
)
368 var ntype
= np
.n_type
369 if ntype
!= null then
370 var mtype
= modelbuilder
.resolve_mtype
(mmodule
, mclassdef
, ntype
)
371 if mtype
== null then return false # Skip error
372 for i
in [0..param_names
.length-param_types
.length
[ do
373 param_types
.add
(mtype
)
375 if np
.n_dotdotdot
!= null then
376 if self.vararg_rank
!= -1 then
377 modelbuilder
.error
(np
, "Error: {param_names[self.vararg_rank]} is already a vararg")
380 self.vararg_rank
= param_names
.length
- 1
385 var ntype
= self.n_type
386 if ntype
!= null then
387 self.ret_type
= modelbuilder
.resolve_mtype
(mmodule
, mclassdef
, ntype
)
388 if self.ret_type
== null then return false # Skip errir
391 self.is_visited
= true
395 # Build a visited signature
396 fun build_signature
(modelbuilder
: ModelBuilder): nullable MSignature
398 if param_names
.length
!= param_types
.length
then
399 # Some parameters are typed, other parameters are not typed.
400 modelbuilder
.error
(self.n_params
[param_types
.length
], "Error: Untyped parameter `{param_names[param_types.length]}'.")
404 var mparameters
= new Array[MParameter]
405 for i
in [0..param_names
.length
[ do
406 var mparameter
= new MParameter(param_names
[i
], param_types
[i
], i
== vararg_rank
)
407 self.n_params
[i
].mparameter
= mparameter
408 mparameters
.add
(mparameter
)
411 var msignature
= new MSignature(mparameters
, ret_type
)
417 # The associated mparameter if any
418 var mparameter
: nullable MParameter = null
421 redef class AMethPropdef
422 redef type MPROPDEF: MMethodDef
424 redef fun build_property
(modelbuilder
, mclassdef
)
426 var n_kwinit
= n_kwinit
427 var n_kwnew
= n_kwnew
428 var is_init
= n_kwinit
!= null or n_kwnew
!= null
430 var amethodid
= self.n_methid
432 if amethodid
== null then
436 else if n_kwinit
!= null then
439 else if n_kwnew
!= null then
445 else if amethodid
isa AIdMethid then
446 name
= amethodid
.n_id
.text
447 name_node
= amethodid
449 # operator, bracket or assign
450 name
= amethodid
.collect_text
451 name_node
= amethodid
453 if name
== "-" and self.n_signature
.n_params
.length
== 0 then
458 var mprop
: nullable MMethod = null
459 if not is_init
or n_kwredef
!= null then mprop
= modelbuilder
.try_get_mproperty_by_name
(name_node
, mclassdef
, name
).as(nullable MMethod)
460 if mprop
== null then
461 var mvisibility
= new_property_visibility
(modelbuilder
, mclassdef
, self.n_visibility
)
462 mprop
= new MMethod(mclassdef
, name
, mvisibility
)
463 mprop
.is_init
= is_init
464 mprop
.is_new
= n_kwnew
!= null
465 if parent
isa ATopClassdef then mprop
.is_toplevel
= true
466 if not self.check_redef_keyword
(modelbuilder
, mclassdef
, n_kwredef
, false, mprop
) then return
468 if not self.check_redef_keyword
(modelbuilder
, mclassdef
, n_kwredef
, not self isa AMainMethPropdef, mprop
) then return
469 check_redef_property_visibility
(modelbuilder
, self.n_visibility
, mprop
)
471 mclassdef
.mprop2npropdef
[mprop
] = self
473 var mpropdef
= new MMethodDef(mclassdef
, mprop
, self.location
)
477 self.mpropdef
= mpropdef
478 modelbuilder
.mpropdef2npropdef
[mpropdef
] = self
479 if mpropdef
.is_intro
then
480 modelbuilder
.toolcontext
.info
("{mpropdef} introduces new method {mprop.full_name}", 3)
482 modelbuilder
.toolcontext
.info
("{mpropdef} redefines method {mprop.full_name}", 3)
486 redef fun build_signature
(modelbuilder
)
488 var mpropdef
= self.mpropdef
489 if mpropdef
== null then return # Error thus skiped
490 var mclassdef
= mpropdef
.mclassdef
491 var mmodule
= mclassdef
.mmodule
492 var nsig
= self.n_signature
494 # Retrieve info from the signature AST
495 var param_names
= new Array[String] # Names of parameters from the AST
496 var param_types
= new Array[MType] # Types of parameters from the AST
498 var ret_type
: nullable MType = null # Return type from the AST
500 if not nsig
.visit_signature
(modelbuilder
, mclassdef
) then return
501 param_names
= nsig
.param_names
502 param_types
= nsig
.param_types
503 vararg_rank
= nsig
.vararg_rank
504 ret_type
= nsig
.ret_type
507 # Look for some signature to inherit
508 # FIXME: do not inherit from the intro, but from the most specific
509 var msignature
: nullable MSignature = null
510 if not mpropdef
.is_intro
then
511 msignature
= mpropdef
.mproperty
.intro
.msignature
512 if msignature
== null then return # Skip error
514 # Check inherited signature arity
515 if param_names
.length
!= msignature
.arity
then
517 if nsig
!= null then node
= nsig
else node
= self
518 modelbuilder
.error
(node
, "Redef error: {mpropdef} redefines {mpropdef.mproperty.intro} with {param_names.length} parameter(s), {msignature.arity} expected. Signature is {mpropdef}{msignature}")
521 else if mpropdef
.mproperty
.is_init
then
522 # FIXME UGLY: inherit signature from a super-constructor
523 for msupertype
in mclassdef
.supertypes
do
524 msupertype
= msupertype
.anchor_to
(mmodule
, mclassdef
.bound_mtype
)
525 var candidate
= modelbuilder
.try_get_mproperty_by_name2
(self, mmodule
, msupertype
, mpropdef
.mproperty
.name
)
526 if candidate
!= null then
527 if msignature
== null then
528 msignature
= candidate
.intro
.as(MMethodDef).msignature
535 # Inherit the signature
536 if msignature
!= null and param_names
.length
!= param_types
.length
and param_names
.length
== msignature
.arity
and param_types
.length
== 0 then
537 # Parameters are untyped, thus inherit them
538 param_types
= new Array[MType]
539 for mparameter
in msignature
.mparameters
do
540 param_types
.add
(mparameter
.mtype
)
542 vararg_rank
= msignature
.vararg_rank
544 if msignature
!= null and ret_type
== null then
545 ret_type
= msignature
.return_mtype
548 if param_names
.length
!= param_types
.length
then
549 # Some parameters are typed, other parameters are not typed.
550 modelbuilder
.error
(nsig
.n_params
[param_types
.length
], "Error: Untyped parameter `{param_names[param_types.length]}'.")
554 var mparameters
= new Array[MParameter]
555 for i
in [0..param_names
.length
[ do
556 var mparameter
= new MParameter(param_names
[i
], param_types
[i
], i
== vararg_rank
)
557 if nsig
!= null then nsig
.n_params
[i
].mparameter
= mparameter
558 mparameters
.add
(mparameter
)
561 msignature
= new MSignature(mparameters
, ret_type
)
562 mpropdef
.msignature
= msignature
563 mpropdef
.is_abstract
= self isa ADeferredMethPropdef
564 mpropdef
.is_intern
= self isa AInternMethPropdef
565 mpropdef
.is_extern
= self isa AExternPropdef
568 redef fun check_signature
(modelbuilder
)
570 var mpropdef
= self.mpropdef
571 if mpropdef
== null then return # Error thus skiped
572 var mclassdef
= mpropdef
.mclassdef
573 var mmodule
= mclassdef
.mmodule
574 var nsig
= self.n_signature
575 var mysignature
= self.mpropdef
.msignature
576 if mysignature
== null then return # Error thus skiped
578 # Lookup for signature in the precursor
579 # FIXME all precursors should be considered
580 if not mpropdef
.is_intro
then
581 var msignature
= mpropdef
.mproperty
.intro
.msignature
582 if msignature
== null then return
584 var precursor_ret_type
= msignature
.return_mtype
585 var ret_type
= mysignature
.return_mtype
586 if ret_type
!= null and precursor_ret_type
== null then
587 modelbuilder
.error
(nsig
.n_type
.as(not null), "Redef Error: {mpropdef.mproperty} is a procedure, not a function.")
591 if mysignature
.arity
> 0 then
592 # Check parameters types
593 for i
in [0..mysignature
.arity
[ do
594 var myt
= mysignature
.mparameters
[i
].mtype
595 var prt
= msignature
.mparameters
[i
].mtype
596 if not myt
.is_subtype
(mmodule
, mclassdef
.bound_mtype
, prt
) or
597 not prt
.is_subtype
(mmodule
, mclassdef
.bound_mtype
, myt
) then
598 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}.")
602 if precursor_ret_type
!= null then
603 if ret_type
== null then
604 # Inherit the return type
605 ret_type
= precursor_ret_type
606 else if not ret_type
.is_subtype
(mmodule
, mclassdef
.bound_mtype
, precursor_ret_type
) then
607 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}.")
612 if mysignature
.arity
> 0 then
613 # Check parameters visibility
614 for i
in [0..mysignature
.arity
[ do
615 var nt
= nsig
.n_params
[i
].n_type
616 if nt
!= null then modelbuilder
.check_visibility
(nt
, nt
.mtype
.as(not null), mpropdef
)
619 if nt
!= null then modelbuilder
.check_visibility
(nt
, nt
.mtype
.as(not null), mpropdef
)
624 redef class AAttrPropdef
625 redef type MPROPDEF: MAttributeDef
627 # The associated getter (read accessor) if any
628 var mreadpropdef
: nullable MMethodDef writable
629 # The associated setter (write accessor) if any
630 var mwritepropdef
: nullable MMethodDef writable
631 redef fun build_property
(modelbuilder
, mclassdef
)
633 var mclass
= mclassdef
.mclass
636 if self.n_id
!= null then
637 name
= self.n_id
.text
639 name
= self.n_id2
.text
642 if mclass
.kind
== interface_kind
or mclassdef
.mclass
.kind
== enum_kind
then
643 modelbuilder
.error
(self, "Error: Attempt to define attribute {name} in the interface {mclass}.")
644 else if mclass
.kind
== enum_kind
then
645 modelbuilder
.error
(self, "Error: Attempt to define attribute {name} in the enum class {mclass}.")
646 else if mclass
.kind
== extern_kind
then
647 modelbuilder
.error
(self, "Error: Attempt to define attribute {name} in the extern class {mclass}.")
652 # Old attribute style
653 var mprop
= modelbuilder
.try_get_mproperty_by_name
(nid
, mclassdef
, name
)
654 if mprop
== null then
655 var mvisibility
= new_property_visibility
(modelbuilder
, mclassdef
, self.n_visibility
)
656 mprop
= new MAttribute(mclassdef
, name
, mvisibility
)
657 if not self.check_redef_keyword
(modelbuilder
, mclassdef
, self.n_kwredef
, false, mprop
) then return
659 assert mprop
isa MAttribute
660 check_redef_property_visibility
(modelbuilder
, self.n_visibility
, mprop
)
661 if not self.check_redef_keyword
(modelbuilder
, mclassdef
, self.n_kwredef
, true, mprop
) then return
663 mclassdef
.mprop2npropdef
[mprop
] = self
665 var mpropdef
= new MAttributeDef(mclassdef
, mprop
, self.location
)
666 self.mpropdef
= mpropdef
667 modelbuilder
.mpropdef2npropdef
[mpropdef
] = self
670 var nreadable
= self.n_readable
671 if nreadable
!= null then
672 var readname
= name
.substring_from
(1)
673 var mreadprop
= modelbuilder
.try_get_mproperty_by_name
(nid
, mclassdef
, readname
).as(nullable MMethod)
674 if mreadprop
== null then
675 var mvisibility
= new_property_visibility
(modelbuilder
, mclassdef
, nreadable
.n_visibility
)
676 mreadprop
= new MMethod(mclassdef
, readname
, mvisibility
)
677 if not self.check_redef_keyword
(modelbuilder
, mclassdef
, nreadable
.n_kwredef
, false, mreadprop
) then return
679 if not self.check_redef_keyword
(modelbuilder
, mclassdef
, nreadable
.n_kwredef
, true, mreadprop
) then return
680 check_redef_property_visibility
(modelbuilder
, nreadable
.n_visibility
, mreadprop
)
682 mclassdef
.mprop2npropdef
[mreadprop
] = self
684 var mreadpropdef
= new MMethodDef(mclassdef
, mreadprop
, self.location
)
685 self.mreadpropdef
= mreadpropdef
686 modelbuilder
.mpropdef2npropdef
[mreadpropdef
] = self
687 mreadpropdef
.mdoc
= mpropdef
.mdoc
690 var nwritable
= self.n_writable
691 if nwritable
!= null then
692 var writename
= name
.substring_from
(1) + "="
693 var mwriteprop
= modelbuilder
.try_get_mproperty_by_name
(nid
, mclassdef
, writename
).as(nullable MMethod)
694 if mwriteprop
== null then
695 var mvisibility
= new_property_visibility
(modelbuilder
, mclassdef
, nwritable
.n_visibility
)
696 mwriteprop
= new MMethod(mclassdef
, writename
, mvisibility
)
697 if not self.check_redef_keyword
(modelbuilder
, mclassdef
, nwritable
.n_kwredef
, false, mwriteprop
) then return
699 if not self.check_redef_keyword
(modelbuilder
, mclassdef
, nwritable
.n_kwredef
, true, mwriteprop
) then return
700 check_redef_property_visibility
(modelbuilder
, nwritable
.n_visibility
, mwriteprop
)
702 mclassdef
.mprop2npropdef
[mwriteprop
] = self
704 var mwritepropdef
= new MMethodDef(mclassdef
, mwriteprop
, self.location
)
705 self.mwritepropdef
= mwritepropdef
706 modelbuilder
.mpropdef2npropdef
[mwritepropdef
] = self
707 mwritepropdef
.mdoc
= mpropdef
.mdoc
710 # New attribute style
711 var nid2
= self.n_id2
.as(not null)
712 var mprop
= new MAttribute(mclassdef
, "@" + name
, none_visibility
)
713 var mpropdef
= new MAttributeDef(mclassdef
, mprop
, self.location
)
714 self.mpropdef
= mpropdef
715 modelbuilder
.mpropdef2npropdef
[mpropdef
] = self
719 var mreadprop
= modelbuilder
.try_get_mproperty_by_name
(nid2
, mclassdef
, readname
).as(nullable MMethod)
720 if mreadprop
== null then
721 var mvisibility
= new_property_visibility
(modelbuilder
, mclassdef
, self.n_visibility
)
722 mreadprop
= new MMethod(mclassdef
, readname
, mvisibility
)
723 if not self.check_redef_keyword
(modelbuilder
, mclassdef
, n_kwredef
, false, mreadprop
) then return
725 if not self.check_redef_keyword
(modelbuilder
, mclassdef
, n_kwredef
, true, mreadprop
) then return
726 check_redef_property_visibility
(modelbuilder
, self.n_visibility
, mreadprop
)
728 mclassdef
.mprop2npropdef
[mreadprop
] = self
730 var mreadpropdef
= new MMethodDef(mclassdef
, mreadprop
, self.location
)
731 self.mreadpropdef
= mreadpropdef
732 modelbuilder
.mpropdef2npropdef
[mreadpropdef
] = self
733 mreadpropdef
.mdoc
= mpropdef
.mdoc
735 var writename
= name
+ "="
736 var nwritable
= self.n_writable
737 var mwriteprop
= modelbuilder
.try_get_mproperty_by_name
(nid2
, mclassdef
, writename
).as(nullable MMethod)
738 var nwkwredef
: nullable Token = null
739 if nwritable
!= null then nwkwredef
= nwritable
.n_kwredef
740 if mwriteprop
== null then
742 if nwritable
!= null then
743 mvisibility
= new_property_visibility
(modelbuilder
, mclassdef
, nwritable
.n_visibility
)
745 mvisibility
= private_visibility
747 mwriteprop
= new MMethod(mclassdef
, writename
, mvisibility
)
748 if not self.check_redef_keyword
(modelbuilder
, mclassdef
, nwkwredef
, false, mwriteprop
) then return
750 if not self.check_redef_keyword
(modelbuilder
, mclassdef
, nwkwredef
, true, mwriteprop
) then return
751 if nwritable
!= null then
752 check_redef_property_visibility
(modelbuilder
, nwritable
.n_visibility
, mwriteprop
)
755 mclassdef
.mprop2npropdef
[mwriteprop
] = self
757 var mwritepropdef
= new MMethodDef(mclassdef
, mwriteprop
, self.location
)
758 self.mwritepropdef
= mwritepropdef
759 modelbuilder
.mpropdef2npropdef
[mwritepropdef
] = self
760 mwritepropdef
.mdoc
= mpropdef
.mdoc
764 redef fun build_signature
(modelbuilder
)
766 var mpropdef
= self.mpropdef
767 if mpropdef
== null then return # Error thus skiped
768 var mclassdef
= mpropdef
.mclassdef
769 var mmodule
= mclassdef
.mmodule
770 var mtype
: nullable MType = null
772 var ntype
= self.n_type
773 if ntype
!= null then
774 mtype
= modelbuilder
.resolve_mtype
(mmodule
, mclassdef
, ntype
)
775 if mtype
== null then return
778 var nexpr
= self.n_expr
779 if mtype
== null then
780 if nexpr
!= null then
781 if nexpr
isa ANewExpr then
782 mtype
= modelbuilder
.resolve_mtype
(mmodule
, mclassdef
, nexpr
.n_type
)
783 else if nexpr
isa AIntExpr then
784 var cla
= modelbuilder
.try_get_mclass_by_name
(nexpr
, mmodule
, "Int")
785 if cla
!= null then mtype
= cla
.mclass_type
786 else if nexpr
isa AFloatExpr then
787 var cla
= modelbuilder
.try_get_mclass_by_name
(nexpr
, mmodule
, "Float")
788 if cla
!= null then mtype
= cla
.mclass_type
789 else if nexpr
isa ACharExpr then
790 var cla
= modelbuilder
.try_get_mclass_by_name
(nexpr
, mmodule
, "Char")
791 if cla
!= null then mtype
= cla
.mclass_type
792 else if nexpr
isa ABoolExpr then
793 var cla
= modelbuilder
.try_get_mclass_by_name
(nexpr
, mmodule
, "Bool")
794 if cla
!= null then mtype
= cla
.mclass_type
795 else if nexpr
isa ASuperstringExpr then
796 var cla
= modelbuilder
.try_get_mclass_by_name
(nexpr
, mmodule
, "String")
797 if cla
!= null then mtype
= cla
.mclass_type
798 else if nexpr
isa AStringFormExpr then
799 var cla
= modelbuilder
.try_get_mclass_by_name
(nexpr
, mmodule
, "String")
800 if cla
!= null then mtype
= cla
.mclass_type
802 modelbuilder
.error
(self, "Error: Untyped attribute {mpropdef}. Implicit typing allowed only for literals and new.")
806 modelbuilder
.error
(self, "Error: Untyped attribute {mpropdef}")
810 if nexpr
isa ANewExpr then
811 var xmtype
= modelbuilder
.resolve_mtype
(mmodule
, mclassdef
, nexpr
.n_type
)
812 if xmtype
== mtype
and modelbuilder
.toolcontext
.opt_warn
.value
>= 2 then
813 modelbuilder
.warning
(ntype
, "Warning: useless type definition")
818 if mtype
== null then return
820 mpropdef
.static_mtype
= mtype
822 var mreadpropdef
= self.mreadpropdef
823 if mreadpropdef
!= null then
824 var msignature
= new MSignature(new Array[MParameter], mtype
)
825 mreadpropdef
.msignature
= msignature
828 var msritepropdef
= self.mwritepropdef
829 if mwritepropdef
!= null then
832 name
= n_id
.text
.substring_from
(1)
836 var mparameter
= new MParameter(name
, mtype
, false)
837 var msignature
= new MSignature([mparameter
], null)
838 mwritepropdef
.msignature
= msignature
842 redef fun check_signature
(modelbuilder
)
844 var mpropdef
= self.mpropdef
845 if mpropdef
== null then return # Error thus skiped
846 var mclassdef
= mpropdef
.mclassdef
847 var mmodule
= mclassdef
.mmodule
848 var ntype
= self.n_type
849 var mtype
= self.mpropdef
.static_mtype
850 if mtype
== null then return # Error thus skiped
852 # Lookup for signature in the precursor
853 # FIXME all precursors should be considered
854 if not mpropdef
.is_intro
then
855 var precursor_type
= mpropdef
.mproperty
.intro
.static_mtype
856 if precursor_type
== null then return
858 if mtype
!= precursor_type
then
859 modelbuilder
.error
(ntype
.as(not null), "Redef Error: Wrong static type. found {mtype}, expected {precursor_type}.")
864 # Check getter and setter
865 var meth
= self.mreadpropdef
867 self.check_method_signature
(modelbuilder
, meth
)
868 var node
: nullable ANode = ntype
869 if node
== null then node
= self
870 modelbuilder
.check_visibility
(node
, mtype
, meth
)
872 meth
= self.mwritepropdef
874 self.check_method_signature
(modelbuilder
, meth
)
875 var node
: nullable ANode = ntype
876 if node
== null then node
= self
877 modelbuilder
.check_visibility
(node
, mtype
, meth
)
881 private fun check_method_signature
(modelbuilder
: ModelBuilder, mpropdef
: MMethodDef)
883 var mclassdef
= mpropdef
.mclassdef
884 var mmodule
= mclassdef
.mmodule
885 var nsig
= self.n_type
886 var mysignature
= mpropdef
.msignature
887 if mysignature
== null then return # Error thus skiped
889 # Lookup for signature in the precursor
890 # FIXME all precursors should be considered
891 if not mpropdef
.is_intro
then
892 var msignature
= mpropdef
.mproperty
.intro
.msignature
893 if msignature
== null then return
895 if mysignature
.arity
!= msignature
.arity
then
897 if nsig
!= null then node
= nsig
else node
= self
898 modelbuilder
.error
(node
, "Redef Error: {mysignature.arity} parameters found, {msignature.arity} expected. Signature is {mpropdef}{msignature}")
901 var precursor_ret_type
= msignature
.return_mtype
902 var ret_type
= mysignature
.return_mtype
903 if ret_type
!= null and precursor_ret_type
== null then
905 if nsig
!= null then node
= nsig
else node
= self
906 modelbuilder
.error
(node
, "Redef Error: {mpropdef.mproperty} is a procedure, not a function.")
910 if mysignature
.arity
> 0 then
911 # Check parameters types
912 for i
in [0..mysignature
.arity
[ do
913 var myt
= mysignature
.mparameters
[i
].mtype
914 var prt
= msignature
.mparameters
[i
].mtype
915 if not myt
.is_subtype
(mmodule
, mclassdef
.bound_mtype
, prt
) and
916 not prt
.is_subtype
(mmodule
, mclassdef
.bound_mtype
, myt
) then
918 if nsig
!= null then node
= nsig
else node
= self
919 modelbuilder
.error
(node
, "Redef Error: Wrong type for parameter `{mysignature.mparameters[i].name}'. found {myt}, expected {prt}.")
923 if precursor_ret_type
!= null then
924 if ret_type
== null then
925 # Inherit the return type
926 ret_type
= precursor_ret_type
927 else if not ret_type
.is_subtype
(mmodule
, mclassdef
.bound_mtype
, precursor_ret_type
) then
929 if nsig
!= null then node
= nsig
else node
= self
930 modelbuilder
.error
(node
, "Redef Error: Wrong return type. found {ret_type}, expected {precursor_ret_type}.")
937 redef class ATypePropdef
938 redef type MPROPDEF: MVirtualTypeDef
940 redef fun build_property
(modelbuilder
, mclassdef
)
942 var name
= self.n_id
.text
943 var mprop
= modelbuilder
.try_get_mproperty_by_name
(self.n_id
, mclassdef
, name
)
944 if mprop
== null then
945 var mvisibility
= new_property_visibility
(modelbuilder
, mclassdef
, self.n_visibility
)
946 mprop
= new MVirtualTypeProp(mclassdef
, name
, mvisibility
)
947 for c
in name
.chars
do if c
>= 'a' and c
<= 'z' then
948 modelbuilder
.warning
(n_id
, "Warning: lowercase in the virtual type {name}")
951 if not self.check_redef_keyword
(modelbuilder
, mclassdef
, self.n_kwredef
, false, mprop
) then return
953 if not self.check_redef_keyword
(modelbuilder
, mclassdef
, self.n_kwredef
, true, mprop
) then return
954 assert mprop
isa MVirtualTypeProp
955 check_redef_property_visibility
(modelbuilder
, self.n_visibility
, mprop
)
957 mclassdef
.mprop2npropdef
[mprop
] = self
959 var mpropdef
= new MVirtualTypeDef(mclassdef
, mprop
, self.location
)
960 self.mpropdef
= mpropdef
961 modelbuilder
.mpropdef2npropdef
[mpropdef
] = self
965 redef fun build_signature
(modelbuilder
)
967 var mpropdef
= self.mpropdef
968 if mpropdef
== null then return # Error thus skiped
969 var mclassdef
= mpropdef
.mclassdef
970 var mmodule
= mclassdef
.mmodule
971 var mtype
: nullable MType = null
973 var ntype
= self.n_type
974 mtype
= modelbuilder
.resolve_mtype
(mmodule
, mclassdef
, ntype
)
975 if mtype
== null then return
977 mpropdef
.bound
= mtype
978 # print "{mpropdef}: {mtype}"
981 redef fun check_signature
(modelbuilder
)
983 var mpropdef
= self.mpropdef
984 if mpropdef
== null then return # Error thus skiped
986 var bound
= self.mpropdef
.bound
987 if bound
== null then return # Error thus skiped
989 modelbuilder
.check_visibility
(n_type
.as(not null), bound
, mpropdef
)
991 # Fast case: the bound is not a formal type
992 if not bound
isa MVirtualType then return
994 var mclassdef
= mpropdef
.mclassdef
995 var mmodule
= mclassdef
.mmodule
996 var anchor
= mclassdef
.bound_mtype
998 # Slow case: progress on each resolution until: (i) we loop, or (ii) we found a non formal type
999 var seen
= [self.mpropdef
.mproperty
.mvirtualtype
]
1001 if seen
.has
(bound
) then
1003 modelbuilder
.error
(self, "Error: circularity of virtual type definition: {seen.join(" -> ")}")
1007 var next
= bound
.lookup_bound
(mmodule
, anchor
)
1008 if not next
isa MVirtualType then break