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
215 # Does the MPropDef contains a call to super or a call of a super-constructor?
216 # Subsequent phases of the frontend (esp. typing) set it if required
217 var has_supercall
: Bool writable = false
220 redef class AClassdef
221 var build_properties_is_done
: Bool = false
222 # The list of super-constructor to call at the start of the free constructor
223 # 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
224 var super_inits
: nullable Collection[MMethod] = null
226 # The free init (implicitely constructed by the class if required)
227 var mfree_init
: nullable MMethodDef = null
229 # What is the `APropdef` associated to a `MProperty`?
230 # Used to check multiple definition of a property.
231 var mprop2npropdef
: Map[MProperty, APropdef] = new HashMap[MProperty, APropdef]
235 # Join the text of all tokens
236 # Used to get the 'real name' of method definitions.
237 fun collect_text
: String
239 var v
= new TextCollectorVisitor
246 private class TextCollectorVisitor
248 var text
: String = ""
251 if n
isa Token then text
+= n
.text
257 # The associated main model entity
258 type MPROPDEF: MPropDef
260 # The associated propdef once build by a `ModelBuilder`
261 var mpropdef
: nullable MPROPDEF writable
263 private fun build_property
(modelbuilder
: ModelBuilder, nclassdef
: AClassdef) is abstract
264 private fun build_signature
(modelbuilder
: ModelBuilder) is abstract
265 private fun check_signature
(modelbuilder
: ModelBuilder) is abstract
266 private fun new_property_visibility
(modelbuilder
: ModelBuilder, mclassdef
: MClassDef, nvisibility
: nullable AVisibility): MVisibility
268 var mvisibility
= public_visibility
269 if nvisibility
!= null then
270 mvisibility
= nvisibility
.mvisibility
271 if mvisibility
== intrude_visibility
then
272 modelbuilder
.error
(nvisibility
, "Error: intrude is not a legal visibility for properties.")
273 mvisibility
= public_visibility
276 if mclassdef
.mclass
.visibility
== private_visibility
then
277 if mvisibility
== protected_visibility
then
278 assert nvisibility
!= null
279 modelbuilder
.error
(nvisibility
, "Error: The only legal visibility for properties in a private class is private.")
280 else if mvisibility
== private_visibility
then
281 assert nvisibility
!= null
283 # modelbuilder.warning(nvisibility, "Warning: private is unrequired since the only legal visibility for properties in a private class is private.")
285 mvisibility
= private_visibility
290 private fun set_doc
(mpropdef
: MPropDef)
292 var ndoc
= self.n_doc
294 var mdoc
= ndoc
.to_mdoc
296 mdoc
.original_mentity
= mpropdef
300 private fun check_redef_property_visibility
(modelbuilder
: ModelBuilder, nvisibility
: nullable AVisibility, mprop
: MProperty)
302 if nvisibility
== null then return
303 var mvisibility
= nvisibility
.mvisibility
304 if mvisibility
!= mprop
.visibility
and mvisibility
!= public_visibility
then
305 modelbuilder
.error
(nvisibility
, "Error: redefinition changed the visibility from a {mprop.visibility} to a {mvisibility}")
309 private fun check_redef_keyword
(modelbuilder
: ModelBuilder, nclassdef
: AClassdef, kwredef
: nullable Token, need_redef
: Bool, mprop
: MProperty): Bool
311 if nclassdef
.mprop2npropdef
.has_key
(mprop
) then
312 modelbuilder
.error
(self, "Error: A property {mprop} is already defined in class {nclassdef.mclassdef.mclass} at line {nclassdef.mprop2npropdef[mprop].location.line_start}.")
315 if kwredef
== null then
317 modelbuilder
.error
(self, "Redef error: {nclassdef.mclassdef.mclass}::{mprop.name} is an inherited property. To redefine it, add the redef keyword.")
321 if not need_redef
then
322 modelbuilder
.error
(self, "Error: No property {nclassdef.mclassdef.mclass}::{mprop.name} is inherited. Remove the redef keyword to define a new property.")
331 redef class ASignature
332 # Is the model builder has correctly visited the signature
333 var is_visited
= false
334 # Names of parameters from the AST
335 # REQUIRE: is_visited
336 var param_names
= new Array[String]
337 # Types of parameters from the AST
338 # REQUIRE: is_visited
339 var param_types
= new Array[MType]
340 # Rank of the vararg (of -1 if none)
341 # REQUIRE: is_visited
342 var vararg_rank
: Int = -1
344 var ret_type
: nullable MType = null
346 # Visit and fill information about a signature
347 private fun visit_signature
(modelbuilder
: ModelBuilder, mclassdef
: MClassDef): Bool
349 var mmodule
= mclassdef
.mmodule
350 var param_names
= self.param_names
351 var param_types
= self.param_types
352 for np
in self.n_params
do
353 param_names
.add
(np
.n_id
.text
)
354 var ntype
= np
.n_type
355 if ntype
!= null then
356 var mtype
= modelbuilder
.resolve_mtype
(mmodule
, mclassdef
, ntype
)
357 if mtype
== null then return false # Skip error
358 for i
in [0..param_names
.length-param_types
.length
[ do
359 param_types
.add
(mtype
)
361 if np
.n_dotdotdot
!= null then
362 if self.vararg_rank
!= -1 then
363 modelbuilder
.error
(np
, "Error: {param_names[self.vararg_rank]} is already a vararg")
366 self.vararg_rank
= param_names
.length
- 1
371 var ntype
= self.n_type
372 if ntype
!= null then
373 self.ret_type
= modelbuilder
.resolve_mtype
(mmodule
, mclassdef
, ntype
)
374 if self.ret_type
== null then return false # Skip errir
377 self.is_visited
= true
381 # Build a visited signature
382 fun build_signature
(modelbuilder
: ModelBuilder): nullable MSignature
384 if param_names
.length
!= param_types
.length
then
385 # Some parameters are typed, other parameters are not typed.
386 modelbuilder
.error
(self.n_params
[param_types
.length
], "Error: Untyped parameter `{param_names[param_types.length]}'.")
390 var mparameters
= new Array[MParameter]
391 for i
in [0..param_names
.length
[ do
392 var mparameter
= new MParameter(param_names
[i
], param_types
[i
], i
== vararg_rank
)
393 self.n_params
[i
].mparameter
= mparameter
394 mparameters
.add
(mparameter
)
397 var msignature
= new MSignature(mparameters
, ret_type
)
403 # The associated mparameter if any
404 var mparameter
: nullable MParameter = null
407 redef class AMethPropdef
408 redef type MPROPDEF: MMethodDef
410 redef fun build_property
(modelbuilder
, nclassdef
)
412 var n_kwinit
= n_kwinit
413 var n_kwnew
= n_kwnew
414 var is_init
= n_kwinit
!= null or n_kwnew
!= null
415 var mclassdef
= nclassdef
.mclassdef
.as(not null)
417 var amethodid
= self.n_methid
419 if amethodid
== null then
423 else if n_kwinit
!= null then
426 else if n_kwnew
!= null then
432 else if amethodid
isa AIdMethid then
433 name
= amethodid
.n_id
.text
434 name_node
= amethodid
436 # operator, bracket or assign
437 name
= amethodid
.collect_text
438 name_node
= amethodid
440 if name
== "-" and self.n_signature
.n_params
.length
== 0 then
445 var mprop
: nullable MMethod = null
446 if not is_init
or n_kwredef
!= null then mprop
= modelbuilder
.try_get_mproperty_by_name
(name_node
, mclassdef
, name
).as(nullable MMethod)
447 if mprop
== null then
448 var mvisibility
= new_property_visibility
(modelbuilder
, mclassdef
, self.n_visibility
)
449 mprop
= new MMethod(mclassdef
, name
, mvisibility
)
450 mprop
.is_init
= is_init
451 mprop
.is_new
= n_kwnew
!= null
452 if nclassdef
isa ATopClassdef then mprop
.is_toplevel
= true
453 if not self.check_redef_keyword
(modelbuilder
, nclassdef
, n_kwredef
, false, mprop
) then return
455 if not self.check_redef_keyword
(modelbuilder
, nclassdef
, n_kwredef
, not self isa AMainMethPropdef, mprop
) then return
456 check_redef_property_visibility
(modelbuilder
, self.n_visibility
, mprop
)
458 nclassdef
.mprop2npropdef
[mprop
] = self
460 var mpropdef
= new MMethodDef(mclassdef
, mprop
, self.location
)
464 self.mpropdef
= mpropdef
465 modelbuilder
.mpropdef2npropdef
[mpropdef
] = self
466 if mpropdef
.is_intro
then
467 modelbuilder
.toolcontext
.info
("{mpropdef} introduces new method {mprop.full_name}", 3)
469 modelbuilder
.toolcontext
.info
("{mpropdef} redefines method {mprop.full_name}", 3)
473 redef fun build_signature
(modelbuilder
)
475 var mpropdef
= self.mpropdef
476 if mpropdef
== null then return # Error thus skiped
477 var mclassdef
= mpropdef
.mclassdef
478 var mmodule
= mclassdef
.mmodule
479 var nsig
= self.n_signature
481 # Retrieve info from the signature AST
482 var param_names
= new Array[String] # Names of parameters from the AST
483 var param_types
= new Array[MType] # Types of parameters from the AST
485 var ret_type
: nullable MType = null # Return type from the AST
487 if not nsig
.visit_signature
(modelbuilder
, mclassdef
) then return
488 param_names
= nsig
.param_names
489 param_types
= nsig
.param_types
490 vararg_rank
= nsig
.vararg_rank
491 ret_type
= nsig
.ret_type
494 # Look for some signature to inherit
495 # FIXME: do not inherit from the intro, but from the most specific
496 var msignature
: nullable MSignature = null
497 if not mpropdef
.is_intro
then
498 msignature
= mpropdef
.mproperty
.intro
.msignature
499 if msignature
== null then return # Skip error
501 # Check inherited signature arity
502 if param_names
.length
!= msignature
.arity
then
504 if nsig
!= null then node
= nsig
else node
= self
505 modelbuilder
.error
(node
, "Redef error: {mpropdef} redefines {mpropdef.mproperty.intro} with {param_names.length} parameter(s), {msignature.arity} expected. Signature is {mpropdef}{msignature}")
508 else if mpropdef
.mproperty
.is_init
then
509 # FIXME UGLY: inherit signature from a super-constructor
510 for msupertype
in mclassdef
.supertypes
do
511 msupertype
= msupertype
.anchor_to
(mmodule
, mclassdef
.bound_mtype
)
512 var candidate
= modelbuilder
.try_get_mproperty_by_name2
(self, mmodule
, msupertype
, mpropdef
.mproperty
.name
)
513 if candidate
!= null then
514 if msignature
== null then
515 msignature
= candidate
.intro
.as(MMethodDef).msignature
522 # Inherit the signature
523 if msignature
!= null and param_names
.length
!= param_types
.length
and param_names
.length
== msignature
.arity
and param_types
.length
== 0 then
524 # Parameters are untyped, thus inherit them
525 param_types
= new Array[MType]
526 for mparameter
in msignature
.mparameters
do
527 param_types
.add
(mparameter
.mtype
)
529 vararg_rank
= msignature
.vararg_rank
531 if msignature
!= null and ret_type
== null then
532 ret_type
= msignature
.return_mtype
535 if param_names
.length
!= param_types
.length
then
536 # Some parameters are typed, other parameters are not typed.
537 modelbuilder
.error
(nsig
.n_params
[param_types
.length
], "Error: Untyped parameter `{param_names[param_types.length]}'.")
541 var mparameters
= new Array[MParameter]
542 for i
in [0..param_names
.length
[ do
543 var mparameter
= new MParameter(param_names
[i
], param_types
[i
], i
== vararg_rank
)
544 if nsig
!= null then nsig
.n_params
[i
].mparameter
= mparameter
545 mparameters
.add
(mparameter
)
548 msignature
= new MSignature(mparameters
, ret_type
)
549 mpropdef
.msignature
= msignature
550 mpropdef
.is_abstract
= self isa ADeferredMethPropdef
551 mpropdef
.is_intern
= self isa AInternMethPropdef
552 mpropdef
.is_extern
= self isa AExternPropdef
555 redef fun check_signature
(modelbuilder
)
557 var mpropdef
= self.mpropdef
558 if mpropdef
== null then return # Error thus skiped
559 var mclassdef
= mpropdef
.mclassdef
560 var mmodule
= mclassdef
.mmodule
561 var nsig
= self.n_signature
562 var mysignature
= self.mpropdef
.msignature
563 if mysignature
== null then return # Error thus skiped
565 # Lookup for signature in the precursor
566 # FIXME all precursors should be considered
567 if not mpropdef
.is_intro
then
568 var msignature
= mpropdef
.mproperty
.intro
.msignature
569 if msignature
== null then return
571 var precursor_ret_type
= msignature
.return_mtype
572 var ret_type
= mysignature
.return_mtype
573 if ret_type
!= null and precursor_ret_type
== null then
574 modelbuilder
.error
(nsig
.n_type
.as(not null), "Redef Error: {mpropdef.mproperty} is a procedure, not a function.")
578 if mysignature
.arity
> 0 then
579 # Check parameters types
580 for i
in [0..mysignature
.arity
[ do
581 var myt
= mysignature
.mparameters
[i
].mtype
582 var prt
= msignature
.mparameters
[i
].mtype
583 if not myt
.is_subtype
(mmodule
, mclassdef
.bound_mtype
, prt
) or
584 not prt
.is_subtype
(mmodule
, mclassdef
.bound_mtype
, myt
) then
585 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}.")
589 if precursor_ret_type
!= null then
590 if ret_type
== null then
591 # Inherit the return type
592 ret_type
= precursor_ret_type
593 else if not ret_type
.is_subtype
(mmodule
, mclassdef
.bound_mtype
, precursor_ret_type
) then
594 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}.")
599 if mysignature
.arity
> 0 then
600 # Check parameters visibility
601 for i
in [0..mysignature
.arity
[ do
602 var nt
= nsig
.n_params
[i
].n_type
603 if nt
!= null then modelbuilder
.check_visibility
(nt
, nt
.mtype
.as(not null), mpropdef
)
606 if nt
!= null then modelbuilder
.check_visibility
(nt
, nt
.mtype
.as(not null), mpropdef
)
611 redef class AAttrPropdef
612 redef type MPROPDEF: MAttributeDef
614 # The associated getter (read accessor) if any
615 var mreadpropdef
: nullable MMethodDef writable
616 # The associated setter (write accessor) if any
617 var mwritepropdef
: nullable MMethodDef writable
618 redef fun build_property
(modelbuilder
, nclassdef
)
620 var mclassdef
= nclassdef
.mclassdef
.as(not null)
621 var mclass
= mclassdef
.mclass
624 if self.n_id
!= null then
625 name
= self.n_id
.text
627 name
= self.n_id2
.text
630 if mclass
.kind
== interface_kind
or mclassdef
.mclass
.kind
== enum_kind
then
631 modelbuilder
.error
(self, "Error: Attempt to define attribute {name} in the interface {mclass}.")
632 else if mclass
.kind
== enum_kind
then
633 modelbuilder
.error
(self, "Error: Attempt to define attribute {name} in the enum class {mclass}.")
634 else if mclass
.kind
== extern_kind
then
635 modelbuilder
.error
(self, "Error: Attempt to define attribute {name} in the extern class {mclass}.")
640 # Old attribute style
641 var mprop
= modelbuilder
.try_get_mproperty_by_name
(nid
, mclassdef
, name
)
642 if mprop
== null then
643 var mvisibility
= new_property_visibility
(modelbuilder
, mclassdef
, self.n_visibility
)
644 mprop
= new MAttribute(mclassdef
, name
, mvisibility
)
645 if not self.check_redef_keyword
(modelbuilder
, nclassdef
, self.n_kwredef
, false, mprop
) then return
647 assert mprop
isa MAttribute
648 check_redef_property_visibility
(modelbuilder
, self.n_visibility
, mprop
)
649 if not self.check_redef_keyword
(modelbuilder
, nclassdef
, self.n_kwredef
, true, mprop
) then return
651 nclassdef
.mprop2npropdef
[mprop
] = self
653 var mpropdef
= new MAttributeDef(mclassdef
, mprop
, self.location
)
654 self.mpropdef
= mpropdef
655 modelbuilder
.mpropdef2npropdef
[mpropdef
] = self
658 var nreadable
= self.n_readable
659 if nreadable
!= null then
660 var readname
= name
.substring_from
(1)
661 var mreadprop
= modelbuilder
.try_get_mproperty_by_name
(nid
, mclassdef
, readname
).as(nullable MMethod)
662 if mreadprop
== null then
663 var mvisibility
= new_property_visibility
(modelbuilder
, mclassdef
, nreadable
.n_visibility
)
664 mreadprop
= new MMethod(mclassdef
, readname
, mvisibility
)
665 if not self.check_redef_keyword
(modelbuilder
, nclassdef
, nreadable
.n_kwredef
, false, mreadprop
) then return
667 if not self.check_redef_keyword
(modelbuilder
, nclassdef
, nreadable
.n_kwredef
, true, mreadprop
) then return
668 check_redef_property_visibility
(modelbuilder
, nreadable
.n_visibility
, mreadprop
)
670 nclassdef
.mprop2npropdef
[mreadprop
] = self
672 var mreadpropdef
= new MMethodDef(mclassdef
, mreadprop
, self.location
)
673 self.mreadpropdef
= mreadpropdef
674 modelbuilder
.mpropdef2npropdef
[mreadpropdef
] = self
675 mreadpropdef
.mdoc
= mpropdef
.mdoc
678 var nwritable
= self.n_writable
679 if nwritable
!= null then
680 var writename
= name
.substring_from
(1) + "="
681 var mwriteprop
= modelbuilder
.try_get_mproperty_by_name
(nid
, mclassdef
, writename
).as(nullable MMethod)
682 if mwriteprop
== null then
683 var mvisibility
= new_property_visibility
(modelbuilder
, mclassdef
, nwritable
.n_visibility
)
684 mwriteprop
= new MMethod(mclassdef
, writename
, mvisibility
)
685 if not self.check_redef_keyword
(modelbuilder
, nclassdef
, nwritable
.n_kwredef
, false, mwriteprop
) then return
687 if not self.check_redef_keyword
(modelbuilder
, nclassdef
, nwritable
.n_kwredef
, true, mwriteprop
) then return
688 check_redef_property_visibility
(modelbuilder
, nwritable
.n_visibility
, mwriteprop
)
690 nclassdef
.mprop2npropdef
[mwriteprop
] = self
692 var mwritepropdef
= new MMethodDef(mclassdef
, mwriteprop
, self.location
)
693 self.mwritepropdef
= mwritepropdef
694 modelbuilder
.mpropdef2npropdef
[mwritepropdef
] = self
695 mwritepropdef
.mdoc
= mpropdef
.mdoc
698 # New attribute style
699 var nid2
= self.n_id2
.as(not null)
700 var mprop
= new MAttribute(mclassdef
, "@" + name
, none_visibility
)
701 var mpropdef
= new MAttributeDef(mclassdef
, mprop
, self.location
)
702 self.mpropdef
= mpropdef
703 modelbuilder
.mpropdef2npropdef
[mpropdef
] = self
707 var mreadprop
= modelbuilder
.try_get_mproperty_by_name
(nid2
, mclassdef
, readname
).as(nullable MMethod)
708 if mreadprop
== null then
709 var mvisibility
= new_property_visibility
(modelbuilder
, mclassdef
, self.n_visibility
)
710 mreadprop
= new MMethod(mclassdef
, readname
, mvisibility
)
711 if not self.check_redef_keyword
(modelbuilder
, nclassdef
, n_kwredef
, false, mreadprop
) then return
713 if not self.check_redef_keyword
(modelbuilder
, nclassdef
, n_kwredef
, true, mreadprop
) then return
714 check_redef_property_visibility
(modelbuilder
, self.n_visibility
, mreadprop
)
716 nclassdef
.mprop2npropdef
[mreadprop
] = self
718 var mreadpropdef
= new MMethodDef(mclassdef
, mreadprop
, self.location
)
719 self.mreadpropdef
= mreadpropdef
720 modelbuilder
.mpropdef2npropdef
[mreadpropdef
] = self
721 mreadpropdef
.mdoc
= mpropdef
.mdoc
723 var writename
= name
+ "="
724 var nwritable
= self.n_writable
725 var mwriteprop
= modelbuilder
.try_get_mproperty_by_name
(nid2
, mclassdef
, writename
).as(nullable MMethod)
726 var nwkwredef
: nullable Token = null
727 if nwritable
!= null then nwkwredef
= nwritable
.n_kwredef
728 if mwriteprop
== null then
730 if nwritable
!= null then
731 mvisibility
= new_property_visibility
(modelbuilder
, mclassdef
, nwritable
.n_visibility
)
733 mvisibility
= private_visibility
735 mwriteprop
= new MMethod(mclassdef
, writename
, mvisibility
)
736 if not self.check_redef_keyword
(modelbuilder
, nclassdef
, nwkwredef
, false, mwriteprop
) then return
738 if not self.check_redef_keyword
(modelbuilder
, nclassdef
, nwkwredef
, true, mwriteprop
) then return
739 if nwritable
!= null then
740 check_redef_property_visibility
(modelbuilder
, nwritable
.n_visibility
, mwriteprop
)
743 nclassdef
.mprop2npropdef
[mwriteprop
] = self
745 var mwritepropdef
= new MMethodDef(mclassdef
, mwriteprop
, self.location
)
746 self.mwritepropdef
= mwritepropdef
747 modelbuilder
.mpropdef2npropdef
[mwritepropdef
] = self
748 mwritepropdef
.mdoc
= mpropdef
.mdoc
752 redef fun build_signature
(modelbuilder
)
754 var mpropdef
= self.mpropdef
755 if mpropdef
== null then return # Error thus skiped
756 var mclassdef
= mpropdef
.mclassdef
757 var mmodule
= mclassdef
.mmodule
758 var mtype
: nullable MType = null
760 var ntype
= self.n_type
761 if ntype
!= null then
762 mtype
= modelbuilder
.resolve_mtype
(mmodule
, mclassdef
, ntype
)
763 if mtype
== null then return
766 var nexpr
= self.n_expr
767 if mtype
== null then
768 if nexpr
!= null then
769 if nexpr
isa ANewExpr then
770 mtype
= modelbuilder
.resolve_mtype
(mmodule
, mclassdef
, nexpr
.n_type
)
771 else if nexpr
isa AIntExpr then
772 var cla
= modelbuilder
.try_get_mclass_by_name
(nexpr
, mmodule
, "Int")
773 if cla
!= null then mtype
= cla
.mclass_type
774 else if nexpr
isa AFloatExpr then
775 var cla
= modelbuilder
.try_get_mclass_by_name
(nexpr
, mmodule
, "Float")
776 if cla
!= null then mtype
= cla
.mclass_type
777 else if nexpr
isa ACharExpr then
778 var cla
= modelbuilder
.try_get_mclass_by_name
(nexpr
, mmodule
, "Char")
779 if cla
!= null then mtype
= cla
.mclass_type
780 else if nexpr
isa ABoolExpr then
781 var cla
= modelbuilder
.try_get_mclass_by_name
(nexpr
, mmodule
, "Bool")
782 if cla
!= null then mtype
= cla
.mclass_type
783 else if nexpr
isa ASuperstringExpr then
784 var cla
= modelbuilder
.try_get_mclass_by_name
(nexpr
, mmodule
, "String")
785 if cla
!= null then mtype
= cla
.mclass_type
786 else if nexpr
isa AStringFormExpr then
787 var cla
= modelbuilder
.try_get_mclass_by_name
(nexpr
, mmodule
, "String")
788 if cla
!= null then mtype
= cla
.mclass_type
790 modelbuilder
.error
(self, "Error: Untyped attribute {mpropdef}. Implicit typing allowed only for literals and new.")
794 modelbuilder
.error
(self, "Error: Untyped attribute {mpropdef}")
798 if nexpr
isa ANewExpr then
799 var xmtype
= modelbuilder
.resolve_mtype
(mmodule
, mclassdef
, nexpr
.n_type
)
800 if xmtype
== mtype
and modelbuilder
.toolcontext
.opt_warn
.value
>= 2 then
801 modelbuilder
.warning
(ntype
, "Warning: useless type definition")
806 if mtype
== null then return
808 mpropdef
.static_mtype
= mtype
810 var mreadpropdef
= self.mreadpropdef
811 if mreadpropdef
!= null then
812 var msignature
= new MSignature(new Array[MParameter], mtype
)
813 mreadpropdef
.msignature
= msignature
816 var msritepropdef
= self.mwritepropdef
817 if mwritepropdef
!= null then
820 name
= n_id
.text
.substring_from
(1)
824 var mparameter
= new MParameter(name
, mtype
, false)
825 var msignature
= new MSignature([mparameter
], null)
826 mwritepropdef
.msignature
= msignature
830 redef fun check_signature
(modelbuilder
)
832 var mpropdef
= self.mpropdef
833 if mpropdef
== null then return # Error thus skiped
834 var mclassdef
= mpropdef
.mclassdef
835 var mmodule
= mclassdef
.mmodule
836 var ntype
= self.n_type
837 var mtype
= self.mpropdef
.static_mtype
838 if mtype
== null then return # Error thus skiped
840 # Lookup for signature in the precursor
841 # FIXME all precursors should be considered
842 if not mpropdef
.is_intro
then
843 var precursor_type
= mpropdef
.mproperty
.intro
.static_mtype
844 if precursor_type
== null then return
846 if mtype
!= precursor_type
then
847 modelbuilder
.error
(ntype
.as(not null), "Redef Error: Wrong static type. found {mtype}, expected {precursor_type}.")
852 # Check getter and setter
853 var meth
= self.mreadpropdef
855 self.check_method_signature
(modelbuilder
, meth
)
856 var node
: nullable ANode = ntype
857 if node
== null then node
= self
858 modelbuilder
.check_visibility
(node
, mtype
, meth
)
860 meth
= self.mwritepropdef
862 self.check_method_signature
(modelbuilder
, meth
)
863 var node
: nullable ANode = ntype
864 if node
== null then node
= self
865 modelbuilder
.check_visibility
(node
, mtype
, meth
)
869 private fun check_method_signature
(modelbuilder
: ModelBuilder, mpropdef
: MMethodDef)
871 var mclassdef
= mpropdef
.mclassdef
872 var mmodule
= mclassdef
.mmodule
873 var nsig
= self.n_type
874 var mysignature
= mpropdef
.msignature
875 if mysignature
== null then return # Error thus skiped
877 # Lookup for signature in the precursor
878 # FIXME all precursors should be considered
879 if not mpropdef
.is_intro
then
880 var msignature
= mpropdef
.mproperty
.intro
.msignature
881 if msignature
== null then return
883 if mysignature
.arity
!= msignature
.arity
then
885 if nsig
!= null then node
= nsig
else node
= self
886 modelbuilder
.error
(node
, "Redef Error: {mysignature.arity} parameters found, {msignature.arity} expected. Signature is {mpropdef}{msignature}")
889 var precursor_ret_type
= msignature
.return_mtype
890 var ret_type
= mysignature
.return_mtype
891 if ret_type
!= null and precursor_ret_type
== null then
893 if nsig
!= null then node
= nsig
else node
= self
894 modelbuilder
.error
(node
, "Redef Error: {mpropdef.mproperty} is a procedure, not a function.")
898 if mysignature
.arity
> 0 then
899 # Check parameters types
900 for i
in [0..mysignature
.arity
[ do
901 var myt
= mysignature
.mparameters
[i
].mtype
902 var prt
= msignature
.mparameters
[i
].mtype
903 if not myt
.is_subtype
(mmodule
, mclassdef
.bound_mtype
, prt
) and
904 not prt
.is_subtype
(mmodule
, mclassdef
.bound_mtype
, myt
) then
906 if nsig
!= null then node
= nsig
else node
= self
907 modelbuilder
.error
(node
, "Redef Error: Wrong type for parameter `{mysignature.mparameters[i].name}'. found {myt}, expected {prt}.")
911 if precursor_ret_type
!= null then
912 if ret_type
== null then
913 # Inherit the return type
914 ret_type
= precursor_ret_type
915 else if not ret_type
.is_subtype
(mmodule
, mclassdef
.bound_mtype
, precursor_ret_type
) then
917 if nsig
!= null then node
= nsig
else node
= self
918 modelbuilder
.error
(node
, "Redef Error: Wrong return type. found {ret_type}, expected {precursor_ret_type}.")
925 redef class ATypePropdef
926 redef type MPROPDEF: MVirtualTypeDef
928 redef fun build_property
(modelbuilder
, nclassdef
)
930 var mclassdef
= nclassdef
.mclassdef
.as(not null)
931 var name
= self.n_id
.text
932 var mprop
= modelbuilder
.try_get_mproperty_by_name
(self.n_id
, mclassdef
, name
)
933 if mprop
== null then
934 var mvisibility
= new_property_visibility
(modelbuilder
, mclassdef
, self.n_visibility
)
935 mprop
= new MVirtualTypeProp(mclassdef
, name
, mvisibility
)
936 for c
in name
.chars
do if c
>= 'a' and c
<= 'z' then
937 modelbuilder
.warning
(n_id
, "Warning: lowercase in the virtual type {name}")
940 if not self.check_redef_keyword
(modelbuilder
, nclassdef
, self.n_kwredef
, false, mprop
) then return
942 if not self.check_redef_keyword
(modelbuilder
, nclassdef
, self.n_kwredef
, true, mprop
) then return
943 assert mprop
isa MVirtualTypeProp
944 check_redef_property_visibility
(modelbuilder
, self.n_visibility
, mprop
)
946 nclassdef
.mprop2npropdef
[mprop
] = self
948 var mpropdef
= new MVirtualTypeDef(mclassdef
, mprop
, self.location
)
949 self.mpropdef
= mpropdef
950 modelbuilder
.mpropdef2npropdef
[mpropdef
] = self
954 redef fun build_signature
(modelbuilder
)
956 var mpropdef
= self.mpropdef
957 if mpropdef
== null then return # Error thus skiped
958 var mclassdef
= mpropdef
.mclassdef
959 var mmodule
= mclassdef
.mmodule
960 var mtype
: nullable MType = null
962 var ntype
= self.n_type
963 mtype
= modelbuilder
.resolve_mtype
(mmodule
, mclassdef
, ntype
)
964 if mtype
== null then return
966 mpropdef
.bound
= mtype
967 # print "{mpropdef}: {mtype}"
970 redef fun check_signature
(modelbuilder
)
972 var mpropdef
= self.mpropdef
973 if mpropdef
== null then return # Error thus skiped
975 var bound
= self.mpropdef
.bound
976 if bound
== null then return # Error thus skiped
978 modelbuilder
.check_visibility
(n_type
.as(not null), bound
, mpropdef
)
980 # Fast case: the bound is not a formal type
981 if not bound
isa MVirtualType then return
983 var mclassdef
= mpropdef
.mclassdef
984 var mmodule
= mclassdef
.mmodule
985 var anchor
= mclassdef
.bound_mtype
987 # Slow case: progress on each resolution until: (i) we loop, or (ii) we found a non formal type
988 var seen
= [self.mpropdef
.mproperty
.mvirtualtype
]
990 if seen
.has
(bound
) then
992 modelbuilder
.error
(self, "Error: circularity of virtual type definition: {seen.join(" -> ")}")
996 var next
= bound
.lookup_bound
(mmodule
, anchor
)
997 if not next
isa MVirtualType then break