1 # This file is part of NIT ( http://www.nitlanguage.org ).
3 # Copyright 2012 Jean Privat <jean@pryen.org>
5 # Licensed under the Apache License, Version 2.0 (the "License");
6 # you may not use this file except in compliance with the License.
7 # You may obtain a copy of the License at
9 # http://www.apache.org/licenses/LICENSE-2.0
11 # Unless required by applicable law or agreed to in writing, software
12 # distributed under the License is distributed on an "AS IS" BASIS,
13 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 # See the License for the specific language governing permissions and
15 # limitations under the License.
17 # Analysis and verification of property definitions to instantiate model element
18 module modelize_property
22 redef class ToolContext
23 var modelize_property_phase
: Phase = new ModelizePropertyPhase(self, [modelize_class_phase
])
26 private class ModelizePropertyPhase
28 redef fun process_nmodule
(nmodule
)
30 for nclassdef
in nmodule
.n_classdefs
do
31 toolcontext
.modelbuilder
.build_properties
(nclassdef
)
36 redef class ModelBuilder
37 # Register the npropdef associated to each mpropdef
38 # FIXME: why not refine the `MPropDef` class with a nullable attribute?
39 var mpropdef2npropdef
: HashMap[MPropDef, APropdef] = new HashMap[MPropDef, APropdef]
41 # Build the properties of `nclassdef`.
42 # REQUIRE: all superclasses are built.
43 private fun build_properties
(nclassdef
: AClassdef)
45 # Force building recursively
46 if nclassdef
.build_properties_is_done
then return
47 nclassdef
.build_properties_is_done
= true
48 var mclassdef
= nclassdef
.mclassdef
.as(not null)
49 if mclassdef
.in_hierarchy
== null then return # Skip error
50 for superclassdef
in mclassdef
.in_hierarchy
.direct_greaters
do
51 build_properties
(mclassdef2nclassdef
[superclassdef
])
54 for npropdef
in nclassdef
.n_propdefs
do
55 npropdef
.build_property
(self, nclassdef
)
57 for npropdef
in nclassdef
.n_propdefs
do
58 npropdef
.build_signature
(self, nclassdef
)
60 for npropdef
in nclassdef
.n_propdefs
do
61 npropdef
.check_signature
(self, nclassdef
)
63 process_default_constructors
(nclassdef
)
66 # Introduce or inherit default constructor
67 # This is the last part of `build_properties`.
68 private fun process_default_constructors
(nclassdef
: AClassdef)
70 var mclassdef
= nclassdef
.mclassdef
.as(not null)
73 if not mclassdef
.is_intro
then return
75 # Is the class forbid constructors?
76 if not mclassdef
.mclass
.kind
.need_init
then return
78 # Is there already a constructor defined?
79 for mpropdef
in mclassdef
.mpropdefs
do
80 if not mpropdef
isa MMethodDef then continue
81 if mpropdef
.mproperty
.is_init
then return
84 if not nclassdef
isa AStdClassdef then return
86 var mmodule
= nclassdef
.mclassdef
.mmodule
87 # Do we inherit for a constructor?
88 var combine
= new Array[MMethod]
89 var inhc
: nullable MClass = null
90 for st
in mclassdef
.supertypes
do
92 if not c
.kind
.need_init
then continue
93 st
= st
.anchor_to
(mmodule
, nclassdef
.mclassdef
.bound_mtype
)
94 var candidate
= self.try_get_mproperty_by_name2
(nclassdef
, mmodule
, st
, "init").as(nullable MMethod)
95 if candidate
!= null and candidate
.intro
.msignature
.arity
== 0 then
96 combine
.add
(candidate
)
99 var inhc2
= c
.inherit_init_from
100 if inhc2
== null then inhc2
= c
101 if inhc2
== inhc
then continue
103 self.error
(nclassdef
, "Error: Cannot provide a defaut constructor: conflict for {inhc} and {c}")
109 # Collect undefined attributes
110 var mparameters
= new Array[MParameter]
111 for npropdef
in nclassdef
.n_propdefs
do
112 if npropdef
isa AAttrPropdef and npropdef
.n_expr
== null then
113 if npropdef
.mpropdef
== null then return # Skip broken attribute
114 var paramname
= npropdef
.mpropdef
.mproperty
.name
.substring_from
(1)
115 var ret_type
= npropdef
.mpropdef
.static_mtype
116 if ret_type
== null then return
117 var mparameter
= new MParameter(paramname
, ret_type
, false)
118 mparameters
.add
(mparameter
)
122 if combine
.is_empty
and inhc
!= null then
123 # TODO: actively inherit the consturctor
124 self.toolcontext
.info
("{mclassdef} inherits all constructors from {inhc}", 3)
125 mclassdef
.mclass
.inherit_init_from
= inhc
129 if not combine
.is_empty
and inhc
!= null then
130 self.error
(nclassdef
, "Error: Cannot provide a defaut constructor: conflict for {combine.join(", ")} and {inhc}")
134 if not combine
.is_empty
then
135 nclassdef
.super_inits
= combine
138 var mprop
= new MMethod(mclassdef
, "init", mclassdef
.mclass
.visibility
)
139 var mpropdef
= new MMethodDef(mclassdef
, mprop
, nclassdef
.location
)
140 var msignature
= new MSignature(mparameters
, null)
141 mpropdef
.msignature
= msignature
143 nclassdef
.mfree_init
= mpropdef
144 self.toolcontext
.info
("{mclassdef} gets a free constructor for attributes {mpropdef}{msignature}", 3)
147 # Check the visibility of `mtype` as an element of the signature of `mpropdef`.
148 fun check_visibility
(node
: ANode, mtype
: MType, mpropdef
: MPropDef)
150 var mmodule
= mpropdef
.mclassdef
.mmodule
151 var mproperty
= mpropdef
.mproperty
153 # Extract visibility information of the main part of `mtype`
154 # It is a case-by case
155 var vis_type
: nullable MVisibility = null # The own visibility of the type
156 var mmodule_type
: nullable MModule = null # The origial module of the type
157 if mtype
isa MNullableType then mtype
= mtype
.mtype
158 if mtype
isa MClassType then
159 vis_type
= mtype
.mclass
.visibility
160 mmodule_type
= mtype
.mclass
.intro
.mmodule
161 else if mtype
isa MVirtualType then
162 vis_type
= mtype
.mproperty
.visibility
163 mmodule_type
= mtype
.mproperty
.intro_mclassdef
.mmodule
164 else if mtype
isa MParameterType then
165 # nothing, always visible
167 node
.debug
"Unexpected type {mtype}"
171 if vis_type
!= null then
172 assert mmodule_type
!= null
173 var vis_module_type
= mmodule
.visibility_for
(mmodule_type
) # the visibility of the original module
174 if mproperty
.visibility
> vis_type
then
175 error
(node
, "Error: The {mproperty.visibility} property `{mproperty}` cannot contain the {vis_type} type `{mtype}`")
177 else if mproperty
.visibility
> vis_module_type
then
178 error
(node
, "Error: The {mproperty.visibility} property `{mproperty}` cannot contain the type `{mtype}` from the {vis_module_type} module `{mmodule_type}`")
183 # No error, try to go deeper in generic types
184 if node
isa AType then
185 for a
in node
.n_types
do check_visibility
(a
, a
.mtype
.as(not null), mpropdef
)
186 else if mtype
isa MGenericType then
187 for t
in mtype
.arguments
do check_visibility
(node
, t
, mpropdef
)
193 # The class whose self inherit all the constructors.
194 # 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
195 var inherit_init_from
: nullable MClass = null
198 redef class MClassDef
199 private var propdef_names
= new HashSet[String]
203 # Does the MPropDef contains a call to super or a call of a super-constructor?
204 # Subsequent phases of the frontend (esp. typing) set it if required
205 var has_supercall
: Bool writable = false
208 redef class AClassdef
209 var build_properties_is_done
: Bool = false
210 # The list of super-constructor to call at the start of the free constructor
211 # 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
212 var super_inits
: nullable Collection[MMethod] = null
214 # The free init (implicitely constructed by the class if required)
215 var mfree_init
: nullable MMethodDef = null
217 # What is the `APropdef` associated to a `MProperty`?
218 # Used to check multiple definition of a property.
219 var mprop2npropdef
: Map[MProperty, APropdef] = new HashMap[MProperty, APropdef]
223 # Join the text of all tokens
224 # Used to get the 'real name' of method definitions.
225 fun collect_text
: String
227 var v
= new TextCollectorVisitor
234 private class TextCollectorVisitor
236 var text
: String = ""
239 if n
isa Token then text
+= n
.text
245 # The associated main model entity
246 type MPROPDEF: MPropDef
248 # The associated propdef once build by a `ModelBuilder`
249 var mpropdef
: nullable MPROPDEF writable
251 private fun build_property
(modelbuilder
: ModelBuilder, nclassdef
: AClassdef) is abstract
252 private fun build_signature
(modelbuilder
: ModelBuilder, nclassdef
: AClassdef) is abstract
253 private fun check_signature
(modelbuilder
: ModelBuilder, nclassdef
: AClassdef) is abstract
254 private fun new_property_visibility
(modelbuilder
: ModelBuilder, nclassdef
: AClassdef, nvisibility
: nullable AVisibility): MVisibility
256 var mvisibility
= public_visibility
257 if nvisibility
!= null then
258 mvisibility
= nvisibility
.mvisibility
259 if mvisibility
== intrude_visibility
then
260 modelbuilder
.error
(nvisibility
, "Error: intrude is not a legal visibility for properties.")
261 mvisibility
= public_visibility
264 if nclassdef
.mclassdef
.mclass
.visibility
== private_visibility
then
265 if mvisibility
== protected_visibility
then
266 assert nvisibility
!= null
267 modelbuilder
.error
(nvisibility
, "Error: The only legal visibility for properties in a private class is private.")
268 else if mvisibility
== private_visibility
then
269 assert nvisibility
!= null
271 # modelbuilder.warning(nvisibility, "Warning: private is unrequired since the only legal visibility for properties in a private class is private.")
273 mvisibility
= private_visibility
278 private fun set_doc
(mpropdef
: MPropDef)
280 var ndoc
= self.n_doc
281 if ndoc
!= null then mpropdef
.mdoc
= ndoc
.to_mdoc
284 private fun check_redef_property_visibility
(modelbuilder
: ModelBuilder, nclassdef
: AClassdef, nvisibility
: nullable AVisibility, mprop
: MProperty)
286 if nvisibility
== null then return
287 var mvisibility
= nvisibility
.mvisibility
288 if mvisibility
!= mprop
.visibility
and mvisibility
!= public_visibility
then
289 modelbuilder
.error
(nvisibility
, "Error: redefinition changed the visibility from a {mprop.visibility} to a {mvisibility}")
293 private fun check_redef_keyword
(modelbuilder
: ModelBuilder, nclassdef
: AClassdef, kwredef
: nullable Token, need_redef
: Bool, mprop
: MProperty): Bool
295 if nclassdef
.mprop2npropdef
.has_key
(mprop
) then
296 modelbuilder
.error
(self, "Error: A property {mprop} is already defined in class {nclassdef.mclassdef.mclass}.")
299 if kwredef
== null then
301 modelbuilder
.error
(self, "Redef error: {nclassdef.mclassdef.mclass}::{mprop.name} is an inherited property. To redefine it, add the redef keyword.")
305 if not need_redef
then
306 modelbuilder
.error
(self, "Error: No property {nclassdef.mclassdef.mclass}::{mprop.name} is inherited. Remove the redef keyword to define a new property.")
315 redef class ASignature
316 # Is the model builder has correctly visited the signature
317 var is_visited
= false
318 # Names of parameters from the AST
319 # REQUIRE: is_visited
320 var param_names
= new Array[String]
321 # Types of parameters from the AST
322 # REQUIRE: is_visited
323 var param_types
= new Array[MType]
324 # Rank of the vararg (of -1 if none)
325 # REQUIRE: is_visited
326 var vararg_rank
: Int = -1
328 var ret_type
: nullable MType = null
330 # Visit and fill information about a signature
331 private fun visit_signature
(modelbuilder
: ModelBuilder, nclassdef
: AClassdef): Bool
333 var param_names
= self.param_names
334 var param_types
= self.param_types
335 for np
in self.n_params
do
336 param_names
.add
(np
.n_id
.text
)
337 var ntype
= np
.n_type
338 if ntype
!= null then
339 var mtype
= modelbuilder
.resolve_mtype
(nclassdef
, ntype
)
340 if mtype
== null then return false # Skip error
341 for i
in [0..param_names
.length-param_types
.length
[ do
342 param_types
.add
(mtype
)
344 if np
.n_dotdotdot
!= null then
345 if self.vararg_rank
!= -1 then
346 modelbuilder
.error
(np
, "Error: {param_names[self.vararg_rank]} is already a vararg")
349 self.vararg_rank
= param_names
.length
- 1
354 var ntype
= self.n_type
355 if ntype
!= null then
356 self.ret_type
= modelbuilder
.resolve_mtype
(nclassdef
, ntype
)
357 if self.ret_type
== null then return false # Skip errir
360 self.is_visited
= true
364 # Build a visited signature
365 fun build_signature
(modelbuilder
: ModelBuilder, nclassdef
: AClassdef): nullable MSignature
367 if param_names
.length
!= param_types
.length
then
368 # Some parameters are typed, other parameters are not typed.
369 modelbuilder
.error
(self.n_params
[param_types
.length
], "Error: Untyped parameter `{param_names[param_types.length]}'.")
373 var mparameters
= new Array[MParameter]
374 for i
in [0..param_names
.length
[ do
375 var mparameter
= new MParameter(param_names
[i
], param_types
[i
], i
== vararg_rank
)
376 self.n_params
[i
].mparameter
= mparameter
377 mparameters
.add
(mparameter
)
380 var msignature
= new MSignature(mparameters
, ret_type
)
386 # The associated mparameter if any
387 var mparameter
: nullable MParameter = null
390 redef class AMethPropdef
391 redef type MPROPDEF: MMethodDef
393 redef fun build_property
(modelbuilder
, nclassdef
)
395 var n_kwinit
= n_kwinit
396 var n_kwnew
= n_kwnew
397 var is_init
= n_kwinit
!= null or n_kwnew
!= null
398 var mclassdef
= nclassdef
.mclassdef
.as(not null)
400 var amethodid
= self.n_methid
402 if amethodid
== null then
406 else if n_kwinit
!= null then
409 else if n_kwnew
!= null then
415 else if amethodid
isa AIdMethid then
416 name
= amethodid
.n_id
.text
417 name_node
= amethodid
419 # operator, bracket or assign
420 name
= amethodid
.collect_text
421 name_node
= amethodid
423 if name
== "-" and self.n_signature
.n_params
.length
== 0 then
428 var mprop
: nullable MMethod = null
429 if not is_init
or n_kwredef
!= null then mprop
= modelbuilder
.try_get_mproperty_by_name
(name_node
, mclassdef
, name
).as(nullable MMethod)
430 if mprop
== null then
431 var mvisibility
= new_property_visibility
(modelbuilder
, nclassdef
, self.n_visibility
)
432 mprop
= new MMethod(mclassdef
, name
, mvisibility
)
433 mprop
.is_init
= is_init
434 mprop
.is_new
= n_kwnew
!= null
435 if not self.check_redef_keyword
(modelbuilder
, nclassdef
, n_kwredef
, false, mprop
) then return
437 if n_kwredef
== null then
438 if self isa AMainMethPropdef then
441 if not self.check_redef_keyword
(modelbuilder
, nclassdef
, n_kwredef
, true, mprop
) then return
444 check_redef_property_visibility
(modelbuilder
, nclassdef
, self.n_visibility
, mprop
)
446 nclassdef
.mprop2npropdef
[mprop
] = self
448 var mpropdef
= new MMethodDef(mclassdef
, mprop
, self.location
)
450 if mclassdef
.propdef_names
.has
(mprop
.name
) then
451 var loc
: nullable Location = null
452 for i
in mclassdef
.mpropdefs
do
453 if i
.mproperty
.name
== mprop
.name
then
458 if loc
== null then abort
459 modelbuilder
.error
(self, "Error: a property {mprop} is already defined in class {mclassdef.mclass} at {loc}")
462 mclassdef
.propdef_names
.add
(mpropdef
.mproperty
.name
)
466 self.mpropdef
= mpropdef
467 modelbuilder
.mpropdef2npropdef
[mpropdef
] = self
468 if mpropdef
.is_intro
then
469 modelbuilder
.toolcontext
.info
("{mpropdef} introduces new method {mprop.full_name}", 3)
471 modelbuilder
.toolcontext
.info
("{mpropdef} redefines method {mprop.full_name}", 3)
475 redef fun build_signature
(modelbuilder
, nclassdef
)
477 var mpropdef
= self.mpropdef
478 if mpropdef
== null then return # Error thus skiped
479 var mmodule
= mpropdef
.mclassdef
.mmodule
480 var nsig
= self.n_signature
482 # Retrieve info from the signature AST
483 var param_names
= new Array[String] # Names of parameters from the AST
484 var param_types
= new Array[MType] # Types of parameters from the AST
486 var ret_type
: nullable MType = null # Return type from the AST
488 if not nsig
.visit_signature
(modelbuilder
, nclassdef
) then return
489 param_names
= nsig
.param_names
490 param_types
= nsig
.param_types
491 vararg_rank
= nsig
.vararg_rank
492 ret_type
= nsig
.ret_type
495 # Look for some signature to inherit
496 # FIXME: do not inherit from the intro, but from the most specific
497 var msignature
: nullable MSignature = null
498 if not mpropdef
.is_intro
then
499 msignature
= mpropdef
.mproperty
.intro
.msignature
500 if msignature
== null then return # Skip error
502 # Check inherited signature arity
503 if param_names
.length
!= msignature
.arity
then
505 if nsig
!= null then node
= nsig
else node
= self
506 modelbuilder
.error
(node
, "Redef error: {mpropdef} redefines {mpropdef.mproperty.intro} with {param_names.length} parameter(s), {msignature.arity} expected. Signature is {mpropdef}{msignature}")
509 else if mpropdef
.mproperty
.is_init
then
510 # FIXME UGLY: inherit signature from a super-constructor
511 for msupertype
in nclassdef
.mclassdef
.supertypes
do
512 msupertype
= msupertype
.anchor_to
(mmodule
, nclassdef
.mclassdef
.bound_mtype
)
513 var candidate
= modelbuilder
.try_get_mproperty_by_name2
(self, mmodule
, msupertype
, mpropdef
.mproperty
.name
)
514 if candidate
!= null then
515 if msignature
== null then
516 msignature
= candidate
.intro
.as(MMethodDef).msignature
523 # Inherit the signature
524 if msignature
!= null and param_names
.length
!= param_types
.length
and param_names
.length
== msignature
.arity
and param_types
.length
== 0 then
525 # Parameters are untyped, thus inherit them
526 param_types
= new Array[MType]
527 for mparameter
in msignature
.mparameters
do
528 param_types
.add
(mparameter
.mtype
)
530 vararg_rank
= msignature
.vararg_rank
532 if msignature
!= null and ret_type
== null then
533 ret_type
= msignature
.return_mtype
536 if param_names
.length
!= param_types
.length
then
537 # Some parameters are typed, other parameters are not typed.
538 modelbuilder
.error
(nsig
.n_params
[param_types
.length
], "Error: Untyped parameter `{param_names[param_types.length]}'.")
542 var mparameters
= new Array[MParameter]
543 for i
in [0..param_names
.length
[ do
544 var mparameter
= new MParameter(param_names
[i
], param_types
[i
], i
== vararg_rank
)
545 if nsig
!= null then nsig
.n_params
[i
].mparameter
= mparameter
546 mparameters
.add
(mparameter
)
549 msignature
= new MSignature(mparameters
, ret_type
)
550 mpropdef
.msignature
= msignature
551 mpropdef
.is_abstract
= self isa ADeferredMethPropdef
552 mpropdef
.is_intern
= self isa AInternMethPropdef
553 mpropdef
.is_extern
= self isa AExternPropdef
556 redef fun check_signature
(modelbuilder
, nclassdef
)
558 var mpropdef
= self.mpropdef
559 if mpropdef
== null then return # Error thus skiped
560 var mmodule
= mpropdef
.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
, nclassdef
.mclassdef
.bound_mtype
, prt
) or
584 not prt
.is_subtype
(mmodule
, nclassdef
.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
, nclassdef
.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
, nclassdef
, 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
, nclassdef
, 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
, nclassdef
, 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
, nclassdef
, 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
, nclassdef
, 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
, nclassdef
, 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
, nclassdef
, 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
, nclassdef
, 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
, nclassdef
, 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
, nclassdef
, 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
, nclassdef
)
754 var mpropdef
= self.mpropdef
755 if mpropdef
== null then return # Error thus skiped
756 var mmodule
= mpropdef
.mclassdef
.mmodule
757 var mtype
: nullable MType = null
759 var ntype
= self.n_type
760 if ntype
!= null then
761 mtype
= modelbuilder
.resolve_mtype
(nclassdef
, ntype
)
762 if mtype
== null then return
765 var nexpr
= self.n_expr
766 if mtype
== null then
767 if nexpr
!= null then
768 if nexpr
isa ANewExpr then
769 mtype
= modelbuilder
.resolve_mtype
(nclassdef
, nexpr
.n_type
)
770 else if nexpr
isa AIntExpr then
771 var cla
= modelbuilder
.try_get_mclass_by_name
(nexpr
, mmodule
, "Int")
772 if cla
!= null then mtype
= cla
.mclass_type
773 else if nexpr
isa AFloatExpr then
774 var cla
= modelbuilder
.try_get_mclass_by_name
(nexpr
, mmodule
, "Float")
775 if cla
!= null then mtype
= cla
.mclass_type
776 else if nexpr
isa ACharExpr then
777 var cla
= modelbuilder
.try_get_mclass_by_name
(nexpr
, mmodule
, "Char")
778 if cla
!= null then mtype
= cla
.mclass_type
779 else if nexpr
isa ABoolExpr then
780 var cla
= modelbuilder
.try_get_mclass_by_name
(nexpr
, mmodule
, "Bool")
781 if cla
!= null then mtype
= cla
.mclass_type
782 else if nexpr
isa ASuperstringExpr then
783 var cla
= modelbuilder
.try_get_mclass_by_name
(nexpr
, mmodule
, "String")
784 if cla
!= null then mtype
= cla
.mclass_type
785 else if nexpr
isa AStringFormExpr then
786 var cla
= modelbuilder
.try_get_mclass_by_name
(nexpr
, mmodule
, "String")
787 if cla
!= null then mtype
= cla
.mclass_type
789 modelbuilder
.error
(self, "Error: Untyped attribute {mpropdef}. Implicit typing allowed only for literals and new.")
793 modelbuilder
.error
(self, "Error: Untyped attribute {mpropdef}")
797 if nexpr
isa ANewExpr then
798 var xmtype
= modelbuilder
.resolve_mtype
(nclassdef
, nexpr
.n_type
)
799 if xmtype
== mtype
and modelbuilder
.toolcontext
.opt_warn
.value
>= 2 then
800 modelbuilder
.warning
(ntype
, "Warning: useless type definition")
805 if mtype
== null then return
807 mpropdef
.static_mtype
= mtype
809 var mreadpropdef
= self.mreadpropdef
810 if mreadpropdef
!= null then
811 var msignature
= new MSignature(new Array[MParameter], mtype
)
812 mreadpropdef
.msignature
= msignature
815 var msritepropdef
= self.mwritepropdef
816 if mwritepropdef
!= null then
819 name
= n_id
.text
.substring_from
(1)
823 var mparameter
= new MParameter(name
, mtype
, false)
824 var msignature
= new MSignature([mparameter
], null)
825 mwritepropdef
.msignature
= msignature
829 redef fun check_signature
(modelbuilder
, nclassdef
)
831 var mpropdef
= self.mpropdef
832 if mpropdef
== null then return # Error thus skiped
833 var mmodule
= mpropdef
.mclassdef
.mmodule
834 var ntype
= self.n_type
835 var mtype
= self.mpropdef
.static_mtype
836 if mtype
== null then return # Error thus skiped
838 # Lookup for signature in the precursor
839 # FIXME all precursors should be considered
840 if not mpropdef
.is_intro
then
841 var precursor_type
= mpropdef
.mproperty
.intro
.static_mtype
842 if precursor_type
== null then return
844 if mtype
!= precursor_type
then
845 modelbuilder
.error
(ntype
.as(not null), "Redef Error: Wrong static type. found {mtype}, expected {precursor_type}.")
850 # Check getter and setter
851 var meth
= self.mreadpropdef
853 self.check_method_signature
(modelbuilder
, nclassdef
, meth
)
854 var node
: nullable ANode = ntype
855 if node
== null then node
= self
856 modelbuilder
.check_visibility
(node
, mtype
, meth
)
858 meth
= self.mwritepropdef
860 self.check_method_signature
(modelbuilder
, nclassdef
, meth
)
861 var node
: nullable ANode = ntype
862 if node
== null then node
= self
863 modelbuilder
.check_visibility
(node
, mtype
, meth
)
867 private fun check_method_signature
(modelbuilder
: ModelBuilder, nclassdef
: AClassdef, mpropdef
: MMethodDef)
869 var mmodule
= mpropdef
.mclassdef
.mmodule
870 var nsig
= self.n_type
871 var mysignature
= mpropdef
.msignature
872 if mysignature
== null then return # Error thus skiped
874 # Lookup for signature in the precursor
875 # FIXME all precursors should be considered
876 if not mpropdef
.is_intro
then
877 var msignature
= mpropdef
.mproperty
.intro
.msignature
878 if msignature
== null then return
880 if mysignature
.arity
!= msignature
.arity
then
882 if nsig
!= null then node
= nsig
else node
= self
883 modelbuilder
.error
(node
, "Redef Error: {mysignature.arity} parameters found, {msignature.arity} expected. Signature is {mpropdef}{msignature}")
886 var precursor_ret_type
= msignature
.return_mtype
887 var ret_type
= mysignature
.return_mtype
888 if ret_type
!= null and precursor_ret_type
== null then
890 if nsig
!= null then node
= nsig
else node
= self
891 modelbuilder
.error
(node
, "Redef Error: {mpropdef.mproperty} is a procedure, not a function.")
895 if mysignature
.arity
> 0 then
896 # Check parameters types
897 for i
in [0..mysignature
.arity
[ do
898 var myt
= mysignature
.mparameters
[i
].mtype
899 var prt
= msignature
.mparameters
[i
].mtype
900 if not myt
.is_subtype
(mmodule
, nclassdef
.mclassdef
.bound_mtype
, prt
) and
901 not prt
.is_subtype
(mmodule
, nclassdef
.mclassdef
.bound_mtype
, myt
) then
903 if nsig
!= null then node
= nsig
else node
= self
904 modelbuilder
.error
(node
, "Redef Error: Wrong type for parameter `{mysignature.mparameters[i].name}'. found {myt}, expected {prt}.")
908 if precursor_ret_type
!= null then
909 if ret_type
== null then
910 # Inherit the return type
911 ret_type
= precursor_ret_type
912 else if not ret_type
.is_subtype
(mmodule
, nclassdef
.mclassdef
.bound_mtype
, precursor_ret_type
) then
914 if nsig
!= null then node
= nsig
else node
= self
915 modelbuilder
.error
(node
, "Redef Error: Wrong return type. found {ret_type}, expected {precursor_ret_type}.")
922 redef class ATypePropdef
923 redef type MPROPDEF: MVirtualTypeDef
925 redef fun build_property
(modelbuilder
, nclassdef
)
927 var mclassdef
= nclassdef
.mclassdef
.as(not null)
928 var name
= self.n_id
.text
929 var mprop
= modelbuilder
.try_get_mproperty_by_name
(self.n_id
, mclassdef
, name
)
930 if mprop
== null then
931 var mvisibility
= new_property_visibility
(modelbuilder
, nclassdef
, self.n_visibility
)
932 mprop
= new MVirtualTypeProp(mclassdef
, name
, mvisibility
)
933 for c
in name
.chars
do if c
>= 'a' and c
<= 'z' then
934 modelbuilder
.warning
(n_id
, "Warning: lowercase in the virtual type {name}")
937 if not self.check_redef_keyword
(modelbuilder
, nclassdef
, self.n_kwredef
, false, mprop
) then return
939 if not self.check_redef_keyword
(modelbuilder
, nclassdef
, self.n_kwredef
, true, mprop
) then return
940 assert mprop
isa MVirtualTypeProp
941 check_redef_property_visibility
(modelbuilder
, nclassdef
, self.n_visibility
, mprop
)
943 nclassdef
.mprop2npropdef
[mprop
] = self
945 var mpropdef
= new MVirtualTypeDef(mclassdef
, mprop
, self.location
)
946 self.mpropdef
= mpropdef
947 modelbuilder
.mpropdef2npropdef
[mpropdef
] = self
951 redef fun build_signature
(modelbuilder
, nclassdef
)
953 var mpropdef
= self.mpropdef
954 if mpropdef
== null then return # Error thus skiped
955 var mmodule
= mpropdef
.mclassdef
.mmodule
956 var mtype
: nullable MType = null
958 var ntype
= self.n_type
959 mtype
= modelbuilder
.resolve_mtype
(nclassdef
, ntype
)
960 if mtype
== null then return
962 mpropdef
.bound
= mtype
963 # print "{mpropdef}: {mtype}"
966 redef fun check_signature
(modelbuilder
, nclassdef
)
968 var mpropdef
= self.mpropdef
969 if mpropdef
== null then return # Error thus skiped
971 var bound
= self.mpropdef
.bound
972 if bound
== null then return # Error thus skiped
974 modelbuilder
.check_visibility
(n_type
.as(not null), bound
, mpropdef
)
976 # Fast case: the bound is not a formal type
977 if not bound
isa MVirtualType then return
979 var mmodule
= nclassdef
.mclassdef
.mmodule
980 var anchor
= nclassdef
.mclassdef
.bound_mtype
982 # Slow case: progress on each resolution until: (i) we loop, or (ii) we found a non formal type
983 var seen
= [self.mpropdef
.mproperty
.mvirtualtype
]
985 if seen
.has
(bound
) then
987 modelbuilder
.error
(self, "Error: circularity of virtual type definition: {seen.join(" -> ")}")
991 var next
= bound
.lookup_bound
(mmodule
, anchor
)
992 if not next
isa MVirtualType then break