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
21 private import annotation
23 redef class ToolContext
24 var modelize_property_phase
: Phase = new ModelizePropertyPhase(self, [modelize_class_phase
])
27 private class ModelizePropertyPhase
29 redef fun process_nmodule
(nmodule
)
31 for nclassdef
in nmodule
.n_classdefs
do
32 if nclassdef
.all_defs
== null then continue # skip non principal classdef
33 toolcontext
.modelbuilder
.build_properties
(nclassdef
)
38 redef class ModelBuilder
39 # Register the npropdef associated to each mpropdef
40 # FIXME: why not refine the `MPropDef` class with a nullable attribute?
41 var mpropdef2npropdef
: HashMap[MPropDef, APropdef] = new HashMap[MPropDef, APropdef]
43 # Build the properties of `nclassdef`.
44 # REQUIRE: all superclasses are built.
45 private fun build_properties
(nclassdef
: AClassdef)
47 # Force building recursively
48 if nclassdef
.build_properties_is_done
then return
49 nclassdef
.build_properties_is_done
= true
50 var mclassdef
= nclassdef
.mclassdef
.as(not null)
51 if mclassdef
.in_hierarchy
== null then return # Skip error
52 for superclassdef
in mclassdef
.in_hierarchy
.direct_greaters
do
53 if not mclassdef2nclassdef
.has_key
(superclassdef
) then continue
54 build_properties
(mclassdef2nclassdef
[superclassdef
])
57 for nclassdef2
in nclassdef
.all_defs
do
58 for npropdef
in nclassdef2
.n_propdefs
do
59 npropdef
.build_property
(self, mclassdef
)
61 for npropdef
in nclassdef2
.n_propdefs
do
62 npropdef
.build_signature
(self)
64 for npropdef
in nclassdef2
.n_propdefs
do
65 npropdef
.check_signature
(self)
68 process_default_constructors
(nclassdef
)
71 # the root init of the Object class
72 # Is usually implicitly defined
73 # Then explicit or implicit definitions of root-init are attached to it
74 var the_root_init_mmethod
: nullable MMethod
76 # Introduce or inherit default constructor
77 # This is the last part of `build_properties`.
78 private fun process_default_constructors
(nclassdef
: AClassdef)
80 var mclassdef
= nclassdef
.mclassdef
.as(not null)
83 if not mclassdef
.is_intro
then return
85 # Look for the init in Object, or create it
86 if mclassdef
.mclass
.name
== "Object" and the_root_init_mmethod
== null then
87 # Create the implicit root-init method
88 var mprop
= new MMethod(mclassdef
, "init", mclassdef
.mclass
.visibility
)
89 mprop
.is_root_init
= true
90 var mpropdef
= new MMethodDef(mclassdef
, mprop
, nclassdef
.location
)
91 var mparameters
= new Array[MParameter]
92 var msignature
= new MSignature(mparameters
, null)
93 mpropdef
.msignature
= msignature
94 mpropdef
.new_msignature
= msignature
96 nclassdef
.mfree_init
= mpropdef
97 self.toolcontext
.info
("{mclassdef} gets a free empty constructor {mpropdef}{msignature}", 3)
98 the_root_init_mmethod
= mprop
102 # Is the class forbid constructors?
103 if not mclassdef
.mclass
.kind
.need_init
then return
105 # Is there already a constructor defined?
106 var defined_init
: nullable MMethodDef = null
107 for mpropdef
in mclassdef
.mpropdefs
do
108 if not mpropdef
isa MMethodDef then continue
109 if not mpropdef
.mproperty
.is_init
then continue
110 if mpropdef
.mproperty
.is_root_init
then
111 assert defined_init
== null
112 defined_init
= mpropdef
113 else if mpropdef
.mproperty
.name
== "init" then
114 # An explicit old-style init named "init", so return
119 if not nclassdef
isa AStdClassdef then return
121 # Collect undefined attributes
122 var mparameters
= new Array[MParameter]
123 var initializers
= new Array[MProperty]
124 for npropdef
in nclassdef
.n_propdefs
do
125 if npropdef
isa AMethPropdef then
126 if npropdef
.mpropdef
== null then return # Skip broken attribute
127 var at
= npropdef
.get_single_annotation
("autoinit", self)
128 if at
== null then continue # Skip non tagged init
130 var sig
= npropdef
.mpropdef
.msignature
131 if sig
== null then continue # Skip broken method
133 if not npropdef
.mpropdef
.is_intro
then
134 self.error
(at
, "Error: `autoinit` cannot be set on redefinitions")
138 for param
in sig
.mparameters
do
139 var ret_type
= param
.mtype
140 var mparameter
= new MParameter(param
.name
, ret_type
, false)
141 mparameters
.add
(mparameter
)
143 initializers
.add
(npropdef
.mpropdef
.mproperty
)
145 if npropdef
isa AAttrPropdef then
146 if npropdef
.mpropdef
== null then return # Skip broken attribute
147 var at
= npropdef
.get_single_annotation
("noinit", self)
149 npropdef
.noinit
= true
150 if npropdef
.n_expr
!= null then
151 self.error
(at
, "Error: `noinit` attributes cannot have an initial value")
153 continue # Skip noinit attributes
155 if npropdef
.n_expr
!= null then continue
156 var paramname
= npropdef
.mpropdef
.mproperty
.name
.substring_from
(1)
157 var ret_type
= npropdef
.mpropdef
.static_mtype
158 if ret_type
== null then return
159 var mparameter
= new MParameter(paramname
, ret_type
, false)
160 mparameters
.add
(mparameter
)
161 var msetter
= npropdef
.mwritepropdef
162 if msetter
== null then
163 # No setter, it is a old-style attribute, so just add it
164 initializers
.add
(npropdef
.mpropdef
.mproperty
)
166 # Add the setter to the list
167 initializers
.add
(msetter
.mproperty
)
172 if the_root_init_mmethod
== null then return
174 # Look for most-specific new-stype init definitions
175 var spropdefs
= the_root_init_mmethod
.lookup_super_definitions
(mclassdef
.mmodule
, mclassdef
.bound_mtype
)
176 if spropdefs
.is_empty
then
177 toolcontext
.fatal_error
(nclassdef
.location
, "Fatal error: {mclassdef} does not specialize {the_root_init_mmethod.intro_mclassdef}. Possible duplication of the root class `Object`?")
180 # Search the longest-one and checks for conflict
181 var longest
= spropdefs
.first
182 if spropdefs
.length
> 1 then
183 # Check for conflict in the order of initializers
184 # Each initializer list must me a prefix of the longest list
185 # part 1. find the longest list
186 for spd
in spropdefs
do
187 if spd
.initializers
.length
> longest
.initializers
.length
then longest
= spd
190 for spd
in spropdefs
do
192 for p
in spd
.initializers
do
193 if p
!= longest
.initializers
[i
] then
194 self.error
(nclassdef
, "Error: conflict for inherited inits {spd}({spd.initializers.join(", ")}) and {longest}({longest.initializers.join(", ")})")
202 # Can we just inherit?
203 if spropdefs
.length
== 1 and mparameters
.is_empty
and defined_init
== null then
204 self.toolcontext
.info
("{mclassdef} inherits the basic constructor {longest}", 3)
208 # Combine the inherited list to what is collected
209 if longest
.initializers
.length
> 0 then
210 mparameters
.prepend longest
.new_msignature
.mparameters
211 initializers
.prepend longest
.initializers
214 # If we already have a basic init definition, then setup its initializers
215 if defined_init
!= null then
216 defined_init
.initializers
.add_all
(initializers
)
217 var msignature
= new MSignature(mparameters
, null)
218 defined_init
.new_msignature
= msignature
219 self.toolcontext
.info
("{mclassdef} extends its basic constructor signature to {defined_init}{msignature}", 3)
223 # Else create the local implicit basic init definition
224 var mprop
= the_root_init_mmethod
.as(not null)
225 var mpropdef
= new MMethodDef(mclassdef
, mprop
, nclassdef
.location
)
226 mpropdef
.has_supercall
= true
227 mpropdef
.initializers
.add_all
(initializers
)
228 var msignature
= new MSignature(mparameters
, null)
229 mpropdef
.new_msignature
= msignature
230 mpropdef
.msignature
= new MSignature(new Array[MParameter], null) # always an empty real signature
231 nclassdef
.mfree_init
= mpropdef
232 self.toolcontext
.info
("{mclassdef} gets a free constructor for attributes {mpropdef}{msignature}", 3)
235 # Check the visibility of `mtype` as an element of the signature of `mpropdef`.
236 fun check_visibility
(node
: ANode, mtype
: MType, mpropdef
: MPropDef)
238 var mmodule
= mpropdef
.mclassdef
.mmodule
239 var mproperty
= mpropdef
.mproperty
241 # Extract visibility information of the main part of `mtype`
242 # It is a case-by case
243 var vis_type
: nullable MVisibility = null # The own visibility of the type
244 var mmodule_type
: nullable MModule = null # The origial module of the type
245 mtype
= mtype
.as_notnullable
246 if mtype
isa MClassType then
247 vis_type
= mtype
.mclass
.visibility
248 mmodule_type
= mtype
.mclass
.intro
.mmodule
249 else if mtype
isa MVirtualType then
250 vis_type
= mtype
.mproperty
.visibility
251 mmodule_type
= mtype
.mproperty
.intro_mclassdef
.mmodule
252 else if mtype
isa MParameterType then
253 # nothing, always visible
255 node
.debug
"Unexpected type {mtype}"
259 if vis_type
!= null then
260 assert mmodule_type
!= null
261 var vis_module_type
= mmodule
.visibility_for
(mmodule_type
) # the visibility of the original module
262 if mproperty
.visibility
> vis_type
then
263 error
(node
, "Error: The {mproperty.visibility} property `{mproperty}` cannot contain the {vis_type} type `{mtype}`")
265 else if mproperty
.visibility
> vis_module_type
then
266 error
(node
, "Error: The {mproperty.visibility} property `{mproperty}` cannot contain the type `{mtype}` from the {vis_module_type} module `{mmodule_type}`")
271 # No error, try to go deeper in generic types
272 if node
isa AType then
273 for a
in node
.n_types
do
275 if t
== null then continue # Error, thus skipped
276 check_visibility
(a
, t
, mpropdef
)
278 else if mtype
isa MGenericType then
279 for t
in mtype
.arguments
do check_visibility
(node
, t
, mpropdef
)
285 # Does the MPropDef contains a call to super or a call of a super-constructor?
286 # Subsequent phases of the frontend (esp. typing) set it if required
287 var has_supercall
: Bool = false is writable
290 redef class AClassdef
291 var build_properties_is_done
: Bool = false
292 # The list of super-constructor to call at the start of the free constructor
293 # 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
294 var super_inits
: nullable Collection[MMethod] = null
296 # The free init (implicitely constructed by the class if required)
297 var mfree_init
: nullable MMethodDef = null
300 redef class MClassDef
301 # What is the `APropdef` associated to a `MProperty`?
302 # Used to check multiple definition of a property.
303 var mprop2npropdef
: Map[MProperty, APropdef] = new HashMap[MProperty, APropdef]
307 # Join the text of all tokens
308 # Used to get the 'real name' of method definitions.
309 fun collect_text
: String
311 var v
= new TextCollectorVisitor
318 private class TextCollectorVisitor
320 var text
: String = ""
323 if n
isa Token then text
+= n
.text
329 # The associated main model entity
330 type MPROPDEF: MPropDef
332 # The associated propdef once build by a `ModelBuilder`
333 var mpropdef
: nullable MPROPDEF is writable
335 private fun build_property
(modelbuilder
: ModelBuilder, mclassdef
: MClassDef) is abstract
336 private fun build_signature
(modelbuilder
: ModelBuilder) is abstract
337 private fun check_signature
(modelbuilder
: ModelBuilder) is abstract
338 private fun new_property_visibility
(modelbuilder
: ModelBuilder, mclassdef
: MClassDef, nvisibility
: nullable AVisibility): MVisibility
340 var mvisibility
= public_visibility
341 if nvisibility
!= null then
342 mvisibility
= nvisibility
.mvisibility
343 if mvisibility
== intrude_visibility
then
344 modelbuilder
.error
(nvisibility
, "Error: intrude is not a legal visibility for properties.")
345 mvisibility
= public_visibility
348 if mclassdef
.mclass
.visibility
== private_visibility
then
349 if mvisibility
== protected_visibility
then
350 assert nvisibility
!= null
351 modelbuilder
.error
(nvisibility
, "Error: The only legal visibility for properties in a private class is private.")
352 else if mvisibility
== private_visibility
then
353 assert nvisibility
!= null
354 modelbuilder
.advice
(nvisibility
, "useless-visibility", "Warning: private is superfluous since the only legal visibility for properties in a private class is private.")
356 mvisibility
= private_visibility
361 private fun set_doc
(mpropdef
: MPropDef, modelbuilder
: ModelBuilder)
363 var ndoc
= self.n_doc
365 var mdoc
= ndoc
.to_mdoc
367 mdoc
.original_mentity
= mpropdef
368 else if mpropdef
.is_intro
and mpropdef
.mproperty
.visibility
>= protected_visibility
then
369 modelbuilder
.advice
(self, "missing-doc", "Documentation warning: Undocumented property `{mpropdef.mproperty}`")
372 var at_deprecated
= get_single_annotation
("deprecated", modelbuilder
)
373 if at_deprecated
!= null then
374 if not mpropdef
.is_intro
then
375 modelbuilder
.error
(self, "Error: method redefinition cannot be deprecated.")
377 var info
= new MDeprecationInfo
378 ndoc
= at_deprecated
.n_doc
379 if ndoc
!= null then info
.mdoc
= ndoc
.to_mdoc
380 mpropdef
.mproperty
.deprecation
= info
385 private fun check_redef_property_visibility
(modelbuilder
: ModelBuilder, nvisibility
: nullable AVisibility, mprop
: MProperty)
387 if nvisibility
== null then return
388 var mvisibility
= nvisibility
.mvisibility
389 if mvisibility
!= mprop
.visibility
and mvisibility
!= public_visibility
then
390 modelbuilder
.error
(nvisibility
, "Error: redefinition changed the visibility from a {mprop.visibility} to a {mvisibility}")
394 private fun check_redef_keyword
(modelbuilder
: ModelBuilder, mclassdef
: MClassDef, kwredef
: nullable Token, need_redef
: Bool, mprop
: MProperty): Bool
396 if mclassdef
.mprop2npropdef
.has_key
(mprop
) then
397 modelbuilder
.error
(self, "Error: A property {mprop} is already defined in class {mclassdef.mclass} at line {mclassdef.mprop2npropdef[mprop].location.line_start}.")
400 if mprop
isa MMethod and mprop
.is_toplevel
!= (parent
isa ATopClassdef) then
401 if mprop
.is_toplevel
then
402 modelbuilder
.error
(self, "Error: {mprop} is a top level method.")
404 modelbuilder
.error
(self, "Error: {mprop} is not a top level method.")
409 if kwredef
== null then
411 modelbuilder
.error
(self, "Redef error: {mclassdef.mclass}::{mprop.name} is an inherited property. To redefine it, add the redef keyword.")
415 if not need_redef
then
416 modelbuilder
.error
(self, "Error: No property {mclassdef.mclass}::{mprop.name} is inherited. Remove the redef keyword to define a new property.")
425 redef class ASignature
426 # Is the model builder has correctly visited the signature
427 var is_visited
= false
428 # Names of parameters from the AST
429 # REQUIRE: is_visited
430 var param_names
= new Array[String]
431 # Types of parameters from the AST
432 # REQUIRE: is_visited
433 var param_types
= new Array[MType]
434 # Rank of the vararg (of -1 if none)
435 # REQUIRE: is_visited
436 var vararg_rank
: Int = -1
438 var ret_type
: nullable MType = null
440 # Visit and fill information about a signature
441 private fun visit_signature
(modelbuilder
: ModelBuilder, mclassdef
: MClassDef): Bool
443 var mmodule
= mclassdef
.mmodule
444 var param_names
= self.param_names
445 var param_types
= self.param_types
446 for np
in self.n_params
do
447 param_names
.add
(np
.n_id
.text
)
448 var ntype
= np
.n_type
449 if ntype
!= null then
450 var mtype
= modelbuilder
.resolve_mtype
(mmodule
, mclassdef
, ntype
)
451 if mtype
== null then return false # Skip error
452 for i
in [0..param_names
.length-param_types
.length
[ do
453 param_types
.add
(mtype
)
455 if np
.n_dotdotdot
!= null then
456 if self.vararg_rank
!= -1 then
457 modelbuilder
.error
(np
, "Error: {param_names[self.vararg_rank]} is already a vararg")
460 self.vararg_rank
= param_names
.length
- 1
465 var ntype
= self.n_type
466 if ntype
!= null then
467 self.ret_type
= modelbuilder
.resolve_mtype
(mmodule
, mclassdef
, ntype
)
468 if self.ret_type
== null then return false # Skip errir
471 self.is_visited
= true
475 # Build a visited signature
476 fun build_signature
(modelbuilder
: ModelBuilder): nullable MSignature
478 if param_names
.length
!= param_types
.length
then
479 # Some parameters are typed, other parameters are not typed.
480 modelbuilder
.error
(self.n_params
[param_types
.length
], "Error: Untyped parameter `{param_names[param_types.length]}'.")
484 var mparameters
= new Array[MParameter]
485 for i
in [0..param_names
.length
[ do
486 var mparameter
= new MParameter(param_names
[i
], param_types
[i
], i
== vararg_rank
)
487 self.n_params
[i
].mparameter
= mparameter
488 mparameters
.add
(mparameter
)
491 var msignature
= new MSignature(mparameters
, ret_type
)
497 # The associated mparameter if any
498 var mparameter
: nullable MParameter = null
501 redef class AMethPropdef
502 redef type MPROPDEF: MMethodDef
505 # Can self be used as a root init?
506 private fun look_like_a_root_init
(modelbuilder
: ModelBuilder): Bool
508 # Need the `init` keyword
509 if n_kwinit
== null then return false
510 # Need to by anonymous
511 if self.n_methid
!= null then return false
513 if self.n_signature
.n_params
.length
> 0 then return false
514 # Cannot be private or something
515 if not self.n_visibility
isa APublicVisibility then return false
516 # No annotation on itself
517 if get_single_annotation
("old_style_init", modelbuilder
) != null then return false
519 var amod
= self.parent
.parent
.as(AModule)
520 var amoddecl
= amod
.n_moduledecl
521 if amoddecl
!= null then
522 var old
= amoddecl
.get_single_annotation
("old_style_init", modelbuilder
)
523 if old
!= null then return false
529 redef fun build_property
(modelbuilder
, mclassdef
)
531 var n_kwinit
= n_kwinit
532 var n_kwnew
= n_kwnew
533 var is_init
= n_kwinit
!= null or n_kwnew
!= null
535 var amethodid
= self.n_methid
537 if amethodid
== null then
541 else if n_kwinit
!= null then
544 else if n_kwnew
!= null then
550 else if amethodid
isa AIdMethid then
551 name
= amethodid
.n_id
.text
552 name_node
= amethodid
554 # operator, bracket or assign
555 name
= amethodid
.collect_text
556 name_node
= amethodid
558 if name
== "-" and self.n_signature
.n_params
.length
== 0 then
563 var mprop
: nullable MMethod = null
564 if not is_init
or n_kwredef
!= null then mprop
= modelbuilder
.try_get_mproperty_by_name
(name_node
, mclassdef
, name
).as(nullable MMethod)
565 if mprop
== null and look_like_a_root_init
(modelbuilder
) then
566 mprop
= modelbuilder
.the_root_init_mmethod
568 if nb
isa ABlockExpr and nb
.n_expr
.is_empty
and n_doc
== null then
569 modelbuilder
.advice
(self, "useless-init", "Warning: useless empty init in {mclassdef}")
572 if mprop
== null then
573 var mvisibility
= new_property_visibility
(modelbuilder
, mclassdef
, self.n_visibility
)
574 mprop
= new MMethod(mclassdef
, name
, mvisibility
)
575 if look_like_a_root_init
(modelbuilder
) and modelbuilder
.the_root_init_mmethod
== null then
576 modelbuilder
.the_root_init_mmethod
= mprop
577 mprop
.is_root_init
= true
579 mprop
.is_init
= is_init
580 mprop
.is_new
= n_kwnew
!= null
581 if parent
isa ATopClassdef then mprop
.is_toplevel
= true
582 if not self.check_redef_keyword
(modelbuilder
, mclassdef
, n_kwredef
, false, mprop
) then return
584 if not mprop
.is_root_init
and not self.check_redef_keyword
(modelbuilder
, mclassdef
, n_kwredef
, not self isa AMainMethPropdef, mprop
) then return
585 check_redef_property_visibility
(modelbuilder
, self.n_visibility
, mprop
)
587 mclassdef
.mprop2npropdef
[mprop
] = self
589 var mpropdef
= new MMethodDef(mclassdef
, mprop
, self.location
)
591 set_doc
(mpropdef
, modelbuilder
)
593 self.mpropdef
= mpropdef
594 modelbuilder
.mpropdef2npropdef
[mpropdef
] = self
595 if mpropdef
.is_intro
then
596 modelbuilder
.toolcontext
.info
("{mpropdef} introduces new method {mprop.full_name}", 3)
598 modelbuilder
.toolcontext
.info
("{mpropdef} redefines method {mprop.full_name}", 3)
602 redef fun build_signature
(modelbuilder
)
604 var mpropdef
= self.mpropdef
605 if mpropdef
== null then return # Error thus skiped
606 var mclassdef
= mpropdef
.mclassdef
607 var mmodule
= mclassdef
.mmodule
608 var nsig
= self.n_signature
610 # Retrieve info from the signature AST
611 var param_names
= new Array[String] # Names of parameters from the AST
612 var param_types
= new Array[MType] # Types of parameters from the AST
614 var ret_type
: nullable MType = null # Return type from the AST
616 if not nsig
.visit_signature
(modelbuilder
, mclassdef
) then return
617 param_names
= nsig
.param_names
618 param_types
= nsig
.param_types
619 vararg_rank
= nsig
.vararg_rank
620 ret_type
= nsig
.ret_type
623 # Look for some signature to inherit
624 # FIXME: do not inherit from the intro, but from the most specific
625 var msignature
: nullable MSignature = null
626 if not mpropdef
.is_intro
then
627 msignature
= mpropdef
.mproperty
.intro
.msignature
628 if msignature
== null then return # Skip error
630 # Check inherited signature arity
631 if param_names
.length
!= msignature
.arity
then
633 if nsig
!= null then node
= nsig
else node
= self
634 modelbuilder
.error
(node
, "Redef error: {mpropdef} redefines {mpropdef.mproperty.intro} with {param_names.length} parameter(s), {msignature.arity} expected. Signature is {mpropdef}{msignature}")
637 else if mpropdef
.mproperty
.is_init
then
638 # FIXME UGLY: inherit signature from a super-constructor
639 for msupertype
in mclassdef
.supertypes
do
640 msupertype
= msupertype
.anchor_to
(mmodule
, mclassdef
.bound_mtype
)
641 var candidate
= modelbuilder
.try_get_mproperty_by_name2
(self, mmodule
, msupertype
, mpropdef
.mproperty
.name
)
642 if candidate
!= null then
643 if msignature
== null then
644 msignature
= candidate
.intro
.as(MMethodDef).msignature
651 # Inherit the signature
652 if msignature
!= null and param_names
.length
!= param_types
.length
and param_names
.length
== msignature
.arity
and param_types
.length
== 0 then
653 # Parameters are untyped, thus inherit them
654 param_types
= new Array[MType]
655 for mparameter
in msignature
.mparameters
do
656 param_types
.add
(mparameter
.mtype
)
658 vararg_rank
= msignature
.vararg_rank
660 if msignature
!= null and ret_type
== null then
661 ret_type
= msignature
.return_mtype
664 if param_names
.length
!= param_types
.length
then
665 # Some parameters are typed, other parameters are not typed.
666 modelbuilder
.error
(nsig
.n_params
[param_types
.length
], "Error: Untyped parameter `{param_names[param_types.length]}'.")
670 var mparameters
= new Array[MParameter]
671 for i
in [0..param_names
.length
[ do
672 var mparameter
= new MParameter(param_names
[i
], param_types
[i
], i
== vararg_rank
)
673 if nsig
!= null then nsig
.n_params
[i
].mparameter
= mparameter
674 mparameters
.add
(mparameter
)
677 msignature
= new MSignature(mparameters
, ret_type
)
678 mpropdef
.msignature
= msignature
679 mpropdef
.is_abstract
= self.get_single_annotation
("abstract", modelbuilder
) != null
680 mpropdef
.is_intern
= self.get_single_annotation
("intern", modelbuilder
) != null
681 mpropdef
.is_extern
= self.n_extern_code_block
!= null or self.get_single_annotation
("extern", modelbuilder
) != null
684 redef fun check_signature
(modelbuilder
)
686 var mpropdef
= self.mpropdef
687 if mpropdef
== null then return # Error thus skiped
688 var mclassdef
= mpropdef
.mclassdef
689 var mmodule
= mclassdef
.mmodule
690 var nsig
= self.n_signature
691 var mysignature
= self.mpropdef
.msignature
692 if mysignature
== null then return # Error thus skiped
694 # Lookup for signature in the precursor
695 # FIXME all precursors should be considered
696 if not mpropdef
.is_intro
then
697 var msignature
= mpropdef
.mproperty
.intro
.msignature
698 if msignature
== null then return
700 var precursor_ret_type
= msignature
.return_mtype
701 var ret_type
= mysignature
.return_mtype
702 if ret_type
!= null and precursor_ret_type
== null then
703 modelbuilder
.error
(nsig
.n_type
.as(not null), "Redef Error: {mpropdef.mproperty} is a procedure, not a function.")
707 if mysignature
.arity
> 0 then
708 # Check parameters types
709 for i
in [0..mysignature
.arity
[ do
710 var myt
= mysignature
.mparameters
[i
].mtype
711 var prt
= msignature
.mparameters
[i
].mtype
712 if not myt
.is_subtype
(mmodule
, mclassdef
.bound_mtype
, prt
) or
713 not prt
.is_subtype
(mmodule
, mclassdef
.bound_mtype
, myt
) then
714 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}.")
718 if precursor_ret_type
!= null then
719 if ret_type
== null then
720 # Inherit the return type
721 ret_type
= precursor_ret_type
722 else if not ret_type
.is_subtype
(mmodule
, mclassdef
.bound_mtype
, precursor_ret_type
) then
723 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}.")
728 if mysignature
.arity
> 0 then
729 # Check parameters visibility
730 for i
in [0..mysignature
.arity
[ do
731 var nt
= nsig
.n_params
[i
].n_type
732 if nt
!= null then modelbuilder
.check_visibility
(nt
, nt
.mtype
.as(not null), mpropdef
)
735 if nt
!= null then modelbuilder
.check_visibility
(nt
, nt
.mtype
.as(not null), mpropdef
)
740 redef class AAttrPropdef
741 redef type MPROPDEF: MAttributeDef
743 # Is the node tagged `noinit`?
746 # Is the node taggeg lazy?
749 # The guard associated to a lasy attribute.
750 # Because some engines does not have a working `isset`,
751 # this additionnal attribute is used to guard the lazy initialization.
752 # TODO: to remove once isset is correctly implemented
753 var mlazypropdef
: nullable MAttributeDef
755 # The associated getter (read accessor) if any
756 var mreadpropdef
: nullable MMethodDef is writable
757 # The associated setter (write accessor) if any
758 var mwritepropdef
: nullable MMethodDef is writable
760 redef fun build_property
(modelbuilder
, mclassdef
)
762 var mclass
= mclassdef
.mclass
765 name
= self.n_id2
.text
767 if mclass
.kind
== interface_kind
or mclassdef
.mclass
.kind
== enum_kind
then
768 modelbuilder
.error
(self, "Error: Attempt to define attribute {name} in the interface {mclass}.")
769 else if mclass
.kind
== enum_kind
then
770 modelbuilder
.error
(self, "Error: Attempt to define attribute {name} in the enum class {mclass}.")
771 else if mclass
.kind
== extern_kind
then
772 modelbuilder
.error
(self, "Error: Attempt to define attribute {name} in the extern class {mclass}.")
775 # New attribute style
776 var nid2
= self.n_id2
777 var mprop
= new MAttribute(mclassdef
, "_" + name
, private_visibility
)
778 var mpropdef
= new MAttributeDef(mclassdef
, mprop
, self.location
)
779 self.mpropdef
= mpropdef
780 modelbuilder
.mpropdef2npropdef
[mpropdef
] = self
781 set_doc
(mpropdef
, modelbuilder
)
784 var mreadprop
= modelbuilder
.try_get_mproperty_by_name
(nid2
, mclassdef
, readname
).as(nullable MMethod)
785 if mreadprop
== null then
786 var mvisibility
= new_property_visibility
(modelbuilder
, mclassdef
, self.n_visibility
)
787 mreadprop
= new MMethod(mclassdef
, readname
, mvisibility
)
788 if not self.check_redef_keyword
(modelbuilder
, mclassdef
, n_kwredef
, false, mreadprop
) then return
789 mreadprop
.deprecation
= mprop
.deprecation
791 if not self.check_redef_keyword
(modelbuilder
, mclassdef
, n_kwredef
, true, mreadprop
) then return
792 check_redef_property_visibility
(modelbuilder
, self.n_visibility
, mreadprop
)
794 mclassdef
.mprop2npropdef
[mreadprop
] = self
796 var mreadpropdef
= new MMethodDef(mclassdef
, mreadprop
, self.location
)
797 self.mreadpropdef
= mreadpropdef
798 modelbuilder
.mpropdef2npropdef
[mreadpropdef
] = self
799 mreadpropdef
.mdoc
= mpropdef
.mdoc
801 var atlazy
= self.get_single_annotation
("lazy", modelbuilder
)
802 if atlazy
!= null then
803 if n_expr
== null then
804 modelbuilder
.error
(atlazy
, "Error: a lazy attribute needs a value")
807 var mlazyprop
= new MAttribute(mclassdef
, "lazy _" + name
, none_visibility
)
808 var mlazypropdef
= new MAttributeDef(mclassdef
, mlazyprop
, self.location
)
809 self.mlazypropdef
= mlazypropdef
812 var atreadonly
= self.get_single_annotation
("readonly", modelbuilder
)
813 if atreadonly
!= null then
814 if n_expr
== null then
815 modelbuilder
.error
(atreadonly
, "Error: a readonly attribute needs a value")
817 # No setter, so just leave
821 var writename
= name
+ "="
822 var atwritable
= self.get_single_annotation
("writable", modelbuilder
)
823 if atwritable
!= null then
824 if not atwritable
.n_args
.is_empty
then
825 writename
= atwritable
.arg_as_id
(modelbuilder
) or else writename
828 var mwriteprop
= modelbuilder
.try_get_mproperty_by_name
(nid2
, mclassdef
, writename
).as(nullable MMethod)
829 var nwkwredef
: nullable Token = null
830 if atwritable
!= null then nwkwredef
= atwritable
.n_kwredef
831 if mwriteprop
== null then
833 if atwritable
!= null then
834 mvisibility
= new_property_visibility
(modelbuilder
, mclassdef
, atwritable
.n_visibility
)
836 mvisibility
= private_visibility
838 mwriteprop
= new MMethod(mclassdef
, writename
, mvisibility
)
839 if not self.check_redef_keyword
(modelbuilder
, mclassdef
, nwkwredef
, false, mwriteprop
) then return
840 mwriteprop
.deprecation
= mprop
.deprecation
842 if not self.check_redef_keyword
(modelbuilder
, mclassdef
, nwkwredef
or else n_kwredef
, true, mwriteprop
) then return
843 if atwritable
!= null then
844 check_redef_property_visibility
(modelbuilder
, atwritable
.n_visibility
, mwriteprop
)
847 mclassdef
.mprop2npropdef
[mwriteprop
] = self
849 var mwritepropdef
= new MMethodDef(mclassdef
, mwriteprop
, self.location
)
850 self.mwritepropdef
= mwritepropdef
851 modelbuilder
.mpropdef2npropdef
[mwritepropdef
] = self
852 mwritepropdef
.mdoc
= mpropdef
.mdoc
855 redef fun build_signature
(modelbuilder
)
857 var mpropdef
= self.mpropdef
858 if mpropdef
== null then return # Error thus skiped
859 var mclassdef
= mpropdef
.mclassdef
860 var mmodule
= mclassdef
.mmodule
861 var mtype
: nullable MType = null
863 var mreadpropdef
= self.mreadpropdef
865 var ntype
= self.n_type
866 if ntype
!= null then
867 mtype
= modelbuilder
.resolve_mtype
(mmodule
, mclassdef
, ntype
)
868 if mtype
== null then return
871 # Inherit the type from the getter (usually an abstact getter)
872 if mtype
== null and mreadpropdef
!= null and not mreadpropdef
.is_intro
then
873 var msignature
= mreadpropdef
.mproperty
.intro
.msignature
874 if msignature
== null then return # Error, thus skiped
875 mtype
= msignature
.return_mtype
878 var nexpr
= self.n_expr
879 if mtype
== null then
880 if nexpr
!= null then
881 if nexpr
isa ANewExpr then
882 mtype
= modelbuilder
.resolve_mtype
(mmodule
, mclassdef
, nexpr
.n_type
)
883 else if nexpr
isa AIntExpr then
884 var cla
= modelbuilder
.try_get_mclass_by_name
(nexpr
, mmodule
, "Int")
885 if cla
!= null then mtype
= cla
.mclass_type
886 else if nexpr
isa AFloatExpr then
887 var cla
= modelbuilder
.try_get_mclass_by_name
(nexpr
, mmodule
, "Float")
888 if cla
!= null then mtype
= cla
.mclass_type
889 else if nexpr
isa ACharExpr then
890 var cla
= modelbuilder
.try_get_mclass_by_name
(nexpr
, mmodule
, "Char")
891 if cla
!= null then mtype
= cla
.mclass_type
892 else if nexpr
isa ABoolExpr then
893 var cla
= modelbuilder
.try_get_mclass_by_name
(nexpr
, mmodule
, "Bool")
894 if cla
!= null then mtype
= cla
.mclass_type
895 else if nexpr
isa ASuperstringExpr then
896 var cla
= modelbuilder
.try_get_mclass_by_name
(nexpr
, mmodule
, "String")
897 if cla
!= null then mtype
= cla
.mclass_type
898 else if nexpr
isa AStringFormExpr then
899 var cla
= modelbuilder
.try_get_mclass_by_name
(nexpr
, mmodule
, "String")
900 if cla
!= null then mtype
= cla
.mclass_type
902 modelbuilder
.error
(self, "Error: Untyped attribute {mpropdef}. Implicit typing allowed only for literals and new.")
905 if mtype
== null then return
907 else if ntype
!= null then
908 if nexpr
isa ANewExpr then
909 var xmtype
= modelbuilder
.resolve_mtype
(mmodule
, mclassdef
, nexpr
.n_type
)
910 if xmtype
== mtype
then
911 modelbuilder
.advice
(ntype
, "useless-type", "Warning: useless type definition")
916 if mtype
== null then
917 modelbuilder
.error
(self, "Error: Untyped attribute {mpropdef}")
921 mpropdef
.static_mtype
= mtype
923 if mreadpropdef
!= null then
924 var msignature
= new MSignature(new Array[MParameter], mtype
)
925 mreadpropdef
.msignature
= msignature
928 var mwritepropdef
= self.mwritepropdef
929 if mwritepropdef
!= null then
932 var mparameter
= new MParameter(name
, mtype
, false)
933 var msignature
= new MSignature([mparameter
], null)
934 mwritepropdef
.msignature
= msignature
937 var mlazypropdef
= self.mlazypropdef
938 if mlazypropdef
!= null then
939 mlazypropdef
.static_mtype
= modelbuilder
.model
.get_mclasses_by_name
("Bool").first
.mclass_type
943 redef fun check_signature
(modelbuilder
)
945 var mpropdef
= self.mpropdef
946 if mpropdef
== null then return # Error thus skiped
947 var mclassdef
= mpropdef
.mclassdef
948 var mmodule
= mclassdef
.mmodule
949 var ntype
= self.n_type
950 var mtype
= self.mpropdef
.static_mtype
951 if mtype
== null then return # Error thus skiped
953 # Lookup for signature in the precursor
954 # FIXME all precursors should be considered
955 if not mpropdef
.is_intro
then
956 var precursor_type
= mpropdef
.mproperty
.intro
.static_mtype
957 if precursor_type
== null then return
959 if mtype
!= precursor_type
then
960 modelbuilder
.error
(ntype
.as(not null), "Redef Error: Wrong static type. found {mtype}, expected {precursor_type}.")
965 # Check getter and setter
966 var meth
= self.mreadpropdef
968 self.check_method_signature
(modelbuilder
, meth
)
969 var node
: nullable ANode = ntype
970 if node
== null then node
= self
971 modelbuilder
.check_visibility
(node
, mtype
, meth
)
973 meth
= self.mwritepropdef
975 self.check_method_signature
(modelbuilder
, meth
)
976 var node
: nullable ANode = ntype
977 if node
== null then node
= self
978 modelbuilder
.check_visibility
(node
, mtype
, meth
)
982 private fun check_method_signature
(modelbuilder
: ModelBuilder, mpropdef
: MMethodDef)
984 var mclassdef
= mpropdef
.mclassdef
985 var mmodule
= mclassdef
.mmodule
986 var nsig
= self.n_type
987 var mysignature
= mpropdef
.msignature
988 if mysignature
== null then return # Error thus skiped
990 # Lookup for signature in the precursor
991 # FIXME all precursors should be considered
992 if not mpropdef
.is_intro
then
993 var msignature
= mpropdef
.mproperty
.intro
.msignature
994 if msignature
== null then return
996 if mysignature
.arity
!= msignature
.arity
then
998 if nsig
!= null then node
= nsig
else node
= self
999 modelbuilder
.error
(node
, "Redef Error: {mysignature.arity} parameters found, {msignature.arity} expected. Signature is {mpropdef}{msignature}")
1002 var precursor_ret_type
= msignature
.return_mtype
1003 var ret_type
= mysignature
.return_mtype
1004 if ret_type
!= null and precursor_ret_type
== null then
1006 if nsig
!= null then node
= nsig
else node
= self
1007 modelbuilder
.error
(node
, "Redef Error: {mpropdef.mproperty} is a procedure, not a function.")
1011 if mysignature
.arity
> 0 then
1012 # Check parameters types
1013 for i
in [0..mysignature
.arity
[ do
1014 var myt
= mysignature
.mparameters
[i
].mtype
1015 var prt
= msignature
.mparameters
[i
].mtype
1016 if not myt
.is_subtype
(mmodule
, mclassdef
.bound_mtype
, prt
) or
1017 not prt
.is_subtype
(mmodule
, mclassdef
.bound_mtype
, myt
) then
1019 if nsig
!= null then node
= nsig
else node
= self
1020 modelbuilder
.error
(node
, "Redef Error: Wrong type for parameter `{mysignature.mparameters[i].name}'. found {myt}, expected {prt}.")
1024 if precursor_ret_type
!= null then
1025 if ret_type
== null then
1026 # Inherit the return type
1027 ret_type
= precursor_ret_type
1028 else if not ret_type
.is_subtype
(mmodule
, mclassdef
.bound_mtype
, precursor_ret_type
) then
1030 if nsig
!= null then node
= nsig
else node
= self
1031 modelbuilder
.error
(node
, "Redef Error: Wrong return type. found {ret_type}, expected {precursor_ret_type}.")
1038 redef class ATypePropdef
1039 redef type MPROPDEF: MVirtualTypeDef
1041 redef fun build_property
(modelbuilder
, mclassdef
)
1043 var name
= self.n_id
.text
1044 var mprop
= modelbuilder
.try_get_mproperty_by_name
(self.n_id
, mclassdef
, name
)
1045 if mprop
== null then
1046 var mvisibility
= new_property_visibility
(modelbuilder
, mclassdef
, self.n_visibility
)
1047 mprop
= new MVirtualTypeProp(mclassdef
, name
, mvisibility
)
1048 for c
in name
.chars
do if c
>= 'a' and c
<= 'z' then
1049 modelbuilder
.warning
(n_id
, "bad-type-name", "Warning: lowercase in the virtual type {name}")
1052 if not self.check_redef_keyword
(modelbuilder
, mclassdef
, self.n_kwredef
, false, mprop
) then return
1054 if not self.check_redef_keyword
(modelbuilder
, mclassdef
, self.n_kwredef
, true, mprop
) then return
1055 assert mprop
isa MVirtualTypeProp
1056 check_redef_property_visibility
(modelbuilder
, self.n_visibility
, mprop
)
1058 mclassdef
.mprop2npropdef
[mprop
] = self
1060 var mpropdef
= new MVirtualTypeDef(mclassdef
, mprop
, self.location
)
1061 self.mpropdef
= mpropdef
1062 modelbuilder
.mpropdef2npropdef
[mpropdef
] = self
1063 set_doc
(mpropdef
, modelbuilder
)
1065 var atfixed
= get_single_annotation
("fixed", modelbuilder
)
1066 if atfixed
!= null then
1067 mpropdef
.is_fixed
= true
1071 redef fun build_signature
(modelbuilder
)
1073 var mpropdef
= self.mpropdef
1074 if mpropdef
== null then return # Error thus skiped
1075 var mclassdef
= mpropdef
.mclassdef
1076 var mmodule
= mclassdef
.mmodule
1077 var mtype
: nullable MType = null
1079 var ntype
= self.n_type
1080 mtype
= modelbuilder
.resolve_mtype
(mmodule
, mclassdef
, ntype
)
1081 if mtype
== null then return
1083 mpropdef
.bound
= mtype
1084 # print "{mpropdef}: {mtype}"
1087 redef fun check_signature
(modelbuilder
)
1089 var mpropdef
= self.mpropdef
1090 if mpropdef
== null then return # Error thus skiped
1092 var bound
= self.mpropdef
.bound
1093 if bound
== null then return # Error thus skiped
1095 modelbuilder
.check_visibility
(n_type
, bound
, mpropdef
)
1097 var mclassdef
= mpropdef
.mclassdef
1098 var mmodule
= mclassdef
.mmodule
1099 var anchor
= mclassdef
.bound_mtype
1102 if bound
isa MVirtualType then
1103 # Slow case: progress on each resolution until: (i) we loop, or (ii) we found a non formal type
1104 var seen
= [self.mpropdef
.mproperty
.mvirtualtype
]
1106 if seen
.has
(bound
) then
1108 modelbuilder
.error
(self, "Error: circularity of virtual type definition: {seen.join(" -> ")}")
1112 var next
= bound
.lookup_bound
(mmodule
, anchor
)
1113 if not next
isa MVirtualType then break
1118 # Check redefinitions
1119 bound
= mpropdef
.bound
.as(not null)
1120 for p
in mpropdef
.mproperty
.lookup_super_definitions
(mmodule
, anchor
) do
1121 var supbound
= p
.bound
.as(not null)
1123 modelbuilder
.error
(self, "Redef Error: Virtual type {mpropdef.mproperty} is fixed in super-class {p.mclassdef.mclass}")
1126 if p
.mclassdef
.mclass
== mclassdef
.mclass
then
1127 # Still a warning to pass existing bad code
1128 modelbuilder
.warning
(n_type
, "refine-type", "Redef Error: a virtual type cannot be refined.")
1131 if not bound
.is_subtype
(mmodule
, anchor
, supbound
) then
1132 modelbuilder
.error
(n_type
, "Redef Error: Wrong bound type. Found {bound}, expected a subtype of {supbound}, as in {p}.")