Java FFI: enable inserting additionnal Java files to a project
[nit.git] / src / modelize_property.nit
1 # This file is part of NIT ( http://www.nitlanguage.org ).
2 #
3 # Copyright 2012 Jean Privat <jean@pryen.org>
4 #
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
8 #
9 # http://www.apache.org/licenses/LICENSE-2.0
10 #
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.
16
17 # Analysis and verification of property definitions to instantiate model element
18 module modelize_property
19
20 import modelize_class
21
22 redef class ToolContext
23 var modelize_property_phase: Phase = new ModelizePropertyPhase(self, [modelize_class_phase])
24 end
25
26 private class ModelizePropertyPhase
27 super Phase
28 redef fun process_nmodule(nmodule)
29 do
30 for nclassdef in nmodule.n_classdefs do
31 toolcontext.modelbuilder.build_properties(nclassdef)
32 end
33 end
34 end
35
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]
40
41 # Build the properties of `nclassdef`.
42 # REQUIRE: all superclasses are built.
43 private fun build_properties(nclassdef: AClassdef)
44 do
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])
53 end
54
55 for npropdef in nclassdef.n_propdefs do
56 npropdef.build_property(self, nclassdef)
57 end
58 for npropdef in nclassdef.n_propdefs do
59 npropdef.build_signature(self)
60 end
61 for npropdef in nclassdef.n_propdefs do
62 npropdef.check_signature(self)
63 end
64 process_default_constructors(nclassdef)
65 end
66
67 # Introduce or inherit default constructor
68 # This is the last part of `build_properties`.
69 private fun process_default_constructors(nclassdef: AClassdef)
70 do
71 var mclassdef = nclassdef.mclassdef.as(not null)
72
73 # Are we a refinement
74 if not mclassdef.is_intro then return
75
76 # Is the class forbid constructors?
77 if not mclassdef.mclass.kind.need_init then return
78
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
83 end
84
85 if not nclassdef isa AStdClassdef then return
86
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
92 var c = st.mclass
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)
98 continue
99 end
100 var inhc2 = c.inherit_init_from
101 if inhc2 == null then inhc2 = c
102 if inhc2 == inhc then continue
103 if inhc != null then
104 self.error(nclassdef, "Error: Cannot provide a defaut constructor: conflict for {inhc} and {c}")
105 else
106 inhc = inhc2
107 end
108 end
109
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
122 end
123 end
124 if anode == null then anode = nclassdef
125
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(", ")}")
129 return
130 end
131
132 # TODO: actively inherit the consturctor
133 self.toolcontext.info("{mclassdef} inherits all constructors from {inhc}", 3)
134 mclassdef.mclass.inherit_init_from = inhc
135 return
136 end
137
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}")
140 return
141 end
142
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)
149 return
150 end
151 nclassdef.super_inits = combine
152 end
153
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
158 mprop.is_init = true
159 nclassdef.mfree_init = mpropdef
160 self.toolcontext.info("{mclassdef} gets a free constructor for attributes {mpropdef}{msignature}", 3)
161 end
162
163 # Check the visibility of `mtype` as an element of the signature of `mpropdef`.
164 fun check_visibility(node: ANode, mtype: MType, mpropdef: MPropDef)
165 do
166 var mmodule = mpropdef.mclassdef.mmodule
167 var mproperty = mpropdef.mproperty
168
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
182 else
183 node.debug "Unexpected type {mtype}"
184 abort
185 end
186
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}`")
192 return
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}`")
195 return
196 end
197 end
198
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)
204 end
205 end
206 end
207
208 redef class MClass
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
212 end
213
214 redef class MClassDef
215 private var propdef_names = new HashSet[String]
216 end
217
218 redef class MPropDef
219 # Does the MPropDef contains a call to super or a call of a super-constructor?
220 # Subsequent phases of the frontend (esp. typing) set it if required
221 var has_supercall: Bool writable = false
222 end
223
224 redef class AClassdef
225 var build_properties_is_done: Bool = false
226 # The list of super-constructor to call at the start of the free constructor
227 # 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
228 var super_inits: nullable Collection[MMethod] = null
229
230 # The free init (implicitely constructed by the class if required)
231 var mfree_init: nullable MMethodDef = null
232
233 # What is the `APropdef` associated to a `MProperty`?
234 # Used to check multiple definition of a property.
235 var mprop2npropdef: Map[MProperty, APropdef] = new HashMap[MProperty, APropdef]
236 end
237
238 redef class Prod
239 # Join the text of all tokens
240 # Used to get the 'real name' of method definitions.
241 fun collect_text: String
242 do
243 var v = new TextCollectorVisitor
244 v.enter_visit(self)
245 assert v.text != ""
246 return v.text
247 end
248 end
249
250 private class TextCollectorVisitor
251 super Visitor
252 var text: String = ""
253 redef fun visit(n)
254 do
255 if n isa Token then text += n.text
256 n.visit_all(self)
257 end
258 end
259
260 redef class APropdef
261 # The associated main model entity
262 type MPROPDEF: MPropDef
263
264 # The associated propdef once build by a `ModelBuilder`
265 var mpropdef: nullable MPROPDEF writable
266
267 private fun build_property(modelbuilder: ModelBuilder, nclassdef: AClassdef) is abstract
268 private fun build_signature(modelbuilder: ModelBuilder) is abstract
269 private fun check_signature(modelbuilder: ModelBuilder) is abstract
270 private fun new_property_visibility(modelbuilder: ModelBuilder, mclassdef: MClassDef, nvisibility: nullable AVisibility): MVisibility
271 do
272 var mvisibility = public_visibility
273 if nvisibility != null then
274 mvisibility = nvisibility.mvisibility
275 if mvisibility == intrude_visibility then
276 modelbuilder.error(nvisibility, "Error: intrude is not a legal visibility for properties.")
277 mvisibility = public_visibility
278 end
279 end
280 if mclassdef.mclass.visibility == private_visibility then
281 if mvisibility == protected_visibility then
282 assert nvisibility != null
283 modelbuilder.error(nvisibility, "Error: The only legal visibility for properties in a private class is private.")
284 else if mvisibility == private_visibility then
285 assert nvisibility != null
286 # Not yet
287 # modelbuilder.warning(nvisibility, "Warning: private is unrequired since the only legal visibility for properties in a private class is private.")
288 end
289 mvisibility = private_visibility
290 end
291 return mvisibility
292 end
293
294 private fun set_doc(mpropdef: MPropDef)
295 do
296 var ndoc = self.n_doc
297 if ndoc != null then
298 var mdoc = ndoc.to_mdoc
299 mpropdef.mdoc = mdoc
300 mdoc.original_mentity = mpropdef
301 end
302 end
303
304 private fun check_redef_property_visibility(modelbuilder: ModelBuilder, nvisibility: nullable AVisibility, mprop: MProperty)
305 do
306 if nvisibility == null then return
307 var mvisibility = nvisibility.mvisibility
308 if mvisibility != mprop.visibility and mvisibility != public_visibility then
309 modelbuilder.error(nvisibility, "Error: redefinition changed the visibility from a {mprop.visibility} to a {mvisibility}")
310 end
311 end
312
313 private fun check_redef_keyword(modelbuilder: ModelBuilder, nclassdef: AClassdef, kwredef: nullable Token, need_redef: Bool, mprop: MProperty): Bool
314 do
315 if nclassdef.mprop2npropdef.has_key(mprop) then
316 modelbuilder.error(self, "Error: A property {mprop} is already defined in class {nclassdef.mclassdef.mclass}.")
317 return false
318 end
319 if kwredef == null then
320 if need_redef then
321 modelbuilder.error(self, "Redef error: {nclassdef.mclassdef.mclass}::{mprop.name} is an inherited property. To redefine it, add the redef keyword.")
322 return false
323 end
324 else
325 if not need_redef then
326 modelbuilder.error(self, "Error: No property {nclassdef.mclassdef.mclass}::{mprop.name} is inherited. Remove the redef keyword to define a new property.")
327 return false
328 end
329 end
330 return true
331 end
332
333 end
334
335 redef class ASignature
336 # Is the model builder has correctly visited the signature
337 var is_visited = false
338 # Names of parameters from the AST
339 # REQUIRE: is_visited
340 var param_names = new Array[String]
341 # Types of parameters from the AST
342 # REQUIRE: is_visited
343 var param_types = new Array[MType]
344 # Rank of the vararg (of -1 if none)
345 # REQUIRE: is_visited
346 var vararg_rank: Int = -1
347 # Return type
348 var ret_type: nullable MType = null
349
350 # Visit and fill information about a signature
351 private fun visit_signature(modelbuilder: ModelBuilder, mclassdef: MClassDef): Bool
352 do
353 var mmodule = mclassdef.mmodule
354 var param_names = self.param_names
355 var param_types = self.param_types
356 for np in self.n_params do
357 param_names.add(np.n_id.text)
358 var ntype = np.n_type
359 if ntype != null then
360 var mtype = modelbuilder.resolve_mtype(mmodule, mclassdef, ntype)
361 if mtype == null then return false # Skip error
362 for i in [0..param_names.length-param_types.length[ do
363 param_types.add(mtype)
364 end
365 if np.n_dotdotdot != null then
366 if self.vararg_rank != -1 then
367 modelbuilder.error(np, "Error: {param_names[self.vararg_rank]} is already a vararg")
368 return false
369 else
370 self.vararg_rank = param_names.length - 1
371 end
372 end
373 end
374 end
375 var ntype = self.n_type
376 if ntype != null then
377 self.ret_type = modelbuilder.resolve_mtype(mmodule, mclassdef, ntype)
378 if self.ret_type == null then return false # Skip errir
379 end
380
381 self.is_visited = true
382 return true
383 end
384
385 # Build a visited signature
386 fun build_signature(modelbuilder: ModelBuilder): nullable MSignature
387 do
388 if param_names.length != param_types.length then
389 # Some parameters are typed, other parameters are not typed.
390 modelbuilder.error(self.n_params[param_types.length], "Error: Untyped parameter `{param_names[param_types.length]}'.")
391 return null
392 end
393
394 var mparameters = new Array[MParameter]
395 for i in [0..param_names.length[ do
396 var mparameter = new MParameter(param_names[i], param_types[i], i == vararg_rank)
397 self.n_params[i].mparameter = mparameter
398 mparameters.add(mparameter)
399 end
400
401 var msignature = new MSignature(mparameters, ret_type)
402 return msignature
403 end
404 end
405
406 redef class AParam
407 # The associated mparameter if any
408 var mparameter: nullable MParameter = null
409 end
410
411 redef class AMethPropdef
412 redef type MPROPDEF: MMethodDef
413
414 redef fun build_property(modelbuilder, nclassdef)
415 do
416 var n_kwinit = n_kwinit
417 var n_kwnew = n_kwnew
418 var is_init = n_kwinit != null or n_kwnew != null
419 var mclassdef = nclassdef.mclassdef.as(not null)
420 var name: String
421 var amethodid = self.n_methid
422 var name_node: ANode
423 if amethodid == null then
424 if not is_init then
425 name = "main"
426 name_node = self
427 else if n_kwinit != null then
428 name = "init"
429 name_node = n_kwinit
430 else if n_kwnew != null then
431 name = "init"
432 name_node = n_kwnew
433 else
434 abort
435 end
436 else if amethodid isa AIdMethid then
437 name = amethodid.n_id.text
438 name_node = amethodid
439 else
440 # operator, bracket or assign
441 name = amethodid.collect_text
442 name_node = amethodid
443
444 if name == "-" and self.n_signature.n_params.length == 0 then
445 name = "unary -"
446 end
447 end
448
449 var mprop: nullable MMethod = null
450 if not is_init or n_kwredef != null then mprop = modelbuilder.try_get_mproperty_by_name(name_node, mclassdef, name).as(nullable MMethod)
451 if mprop == null then
452 var mvisibility = new_property_visibility(modelbuilder, mclassdef, self.n_visibility)
453 mprop = new MMethod(mclassdef, name, mvisibility)
454 mprop.is_init = is_init
455 mprop.is_new = n_kwnew != null
456 if not self.check_redef_keyword(modelbuilder, nclassdef, n_kwredef, false, mprop) then return
457 else
458 if n_kwredef == null then
459 if self isa AMainMethPropdef then
460 # no warning
461 else
462 if not self.check_redef_keyword(modelbuilder, nclassdef, n_kwredef, true, mprop) then return
463 end
464 end
465 check_redef_property_visibility(modelbuilder, self.n_visibility, mprop)
466 end
467 nclassdef.mprop2npropdef[mprop] = self
468
469 var mpropdef = new MMethodDef(mclassdef, mprop, self.location)
470
471 if mclassdef.propdef_names.has(mprop.name) then
472 var loc: nullable Location = null
473 for i in mclassdef.mpropdefs do
474 if i.mproperty.name == mprop.name then
475 loc = i.location
476 break
477 end
478 end
479 if loc == null then abort
480 modelbuilder.error(self, "Error: a property {mprop} is already defined in class {mclassdef.mclass} at {loc}")
481 end
482
483 mclassdef.propdef_names.add(mpropdef.mproperty.name)
484
485 set_doc(mpropdef)
486
487 self.mpropdef = mpropdef
488 modelbuilder.mpropdef2npropdef[mpropdef] = self
489 if mpropdef.is_intro then
490 modelbuilder.toolcontext.info("{mpropdef} introduces new method {mprop.full_name}", 3)
491 else
492 modelbuilder.toolcontext.info("{mpropdef} redefines method {mprop.full_name}", 3)
493 end
494 end
495
496 redef fun build_signature(modelbuilder)
497 do
498 var mpropdef = self.mpropdef
499 if mpropdef == null then return # Error thus skiped
500 var mclassdef = mpropdef.mclassdef
501 var mmodule = mclassdef.mmodule
502 var nsig = self.n_signature
503
504 # Retrieve info from the signature AST
505 var param_names = new Array[String] # Names of parameters from the AST
506 var param_types = new Array[MType] # Types of parameters from the AST
507 var vararg_rank = -1
508 var ret_type: nullable MType = null # Return type from the AST
509 if nsig != null then
510 if not nsig.visit_signature(modelbuilder, mclassdef) then return
511 param_names = nsig.param_names
512 param_types = nsig.param_types
513 vararg_rank = nsig.vararg_rank
514 ret_type = nsig.ret_type
515 end
516
517 # Look for some signature to inherit
518 # FIXME: do not inherit from the intro, but from the most specific
519 var msignature: nullable MSignature = null
520 if not mpropdef.is_intro then
521 msignature = mpropdef.mproperty.intro.msignature
522 if msignature == null then return # Skip error
523
524 # Check inherited signature arity
525 if param_names.length != msignature.arity then
526 var node: ANode
527 if nsig != null then node = nsig else node = self
528 modelbuilder.error(node, "Redef error: {mpropdef} redefines {mpropdef.mproperty.intro} with {param_names.length} parameter(s), {msignature.arity} expected. Signature is {mpropdef}{msignature}")
529 return
530 end
531 else if mpropdef.mproperty.is_init then
532 # FIXME UGLY: inherit signature from a super-constructor
533 for msupertype in mclassdef.supertypes do
534 msupertype = msupertype.anchor_to(mmodule, mclassdef.bound_mtype)
535 var candidate = modelbuilder.try_get_mproperty_by_name2(self, mmodule, msupertype, mpropdef.mproperty.name)
536 if candidate != null then
537 if msignature == null then
538 msignature = candidate.intro.as(MMethodDef).msignature
539 end
540 end
541 end
542 end
543
544
545 # Inherit the signature
546 if msignature != null and param_names.length != param_types.length and param_names.length == msignature.arity and param_types.length == 0 then
547 # Parameters are untyped, thus inherit them
548 param_types = new Array[MType]
549 for mparameter in msignature.mparameters do
550 param_types.add(mparameter.mtype)
551 end
552 vararg_rank = msignature.vararg_rank
553 end
554 if msignature != null and ret_type == null then
555 ret_type = msignature.return_mtype
556 end
557
558 if param_names.length != param_types.length then
559 # Some parameters are typed, other parameters are not typed.
560 modelbuilder.error(nsig.n_params[param_types.length], "Error: Untyped parameter `{param_names[param_types.length]}'.")
561 return
562 end
563
564 var mparameters = new Array[MParameter]
565 for i in [0..param_names.length[ do
566 var mparameter = new MParameter(param_names[i], param_types[i], i == vararg_rank)
567 if nsig != null then nsig.n_params[i].mparameter = mparameter
568 mparameters.add(mparameter)
569 end
570
571 msignature = new MSignature(mparameters, ret_type)
572 mpropdef.msignature = msignature
573 mpropdef.is_abstract = self isa ADeferredMethPropdef
574 mpropdef.is_intern = self isa AInternMethPropdef
575 mpropdef.is_extern = self isa AExternPropdef
576 end
577
578 redef fun check_signature(modelbuilder)
579 do
580 var mpropdef = self.mpropdef
581 if mpropdef == null then return # Error thus skiped
582 var mclassdef = mpropdef.mclassdef
583 var mmodule = mclassdef.mmodule
584 var nsig = self.n_signature
585 var mysignature = self.mpropdef.msignature
586 if mysignature == null then return # Error thus skiped
587
588 # Lookup for signature in the precursor
589 # FIXME all precursors should be considered
590 if not mpropdef.is_intro then
591 var msignature = mpropdef.mproperty.intro.msignature
592 if msignature == null then return
593
594 var precursor_ret_type = msignature.return_mtype
595 var ret_type = mysignature.return_mtype
596 if ret_type != null and precursor_ret_type == null then
597 modelbuilder.error(nsig.n_type.as(not null), "Redef Error: {mpropdef.mproperty} is a procedure, not a function.")
598 return
599 end
600
601 if mysignature.arity > 0 then
602 # Check parameters types
603 for i in [0..mysignature.arity[ do
604 var myt = mysignature.mparameters[i].mtype
605 var prt = msignature.mparameters[i].mtype
606 if not myt.is_subtype(mmodule, mclassdef.bound_mtype, prt) or
607 not prt.is_subtype(mmodule, mclassdef.bound_mtype, myt) then
608 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}.")
609 end
610 end
611 end
612 if precursor_ret_type != null then
613 if ret_type == null then
614 # Inherit the return type
615 ret_type = precursor_ret_type
616 else if not ret_type.is_subtype(mmodule, mclassdef.bound_mtype, precursor_ret_type) then
617 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}.")
618 end
619 end
620 end
621
622 if mysignature.arity > 0 then
623 # Check parameters visibility
624 for i in [0..mysignature.arity[ do
625 var nt = nsig.n_params[i].n_type
626 if nt != null then modelbuilder.check_visibility(nt, nt.mtype.as(not null), mpropdef)
627 end
628 var nt = nsig.n_type
629 if nt != null then modelbuilder.check_visibility(nt, nt.mtype.as(not null), mpropdef)
630 end
631 end
632 end
633
634 redef class AAttrPropdef
635 redef type MPROPDEF: MAttributeDef
636
637 # The associated getter (read accessor) if any
638 var mreadpropdef: nullable MMethodDef writable
639 # The associated setter (write accessor) if any
640 var mwritepropdef: nullable MMethodDef writable
641 redef fun build_property(modelbuilder, nclassdef)
642 do
643 var mclassdef = nclassdef.mclassdef.as(not null)
644 var mclass = mclassdef.mclass
645
646 var name: String
647 if self.n_id != null then
648 name = self.n_id.text
649 else
650 name = self.n_id2.text
651 end
652
653 if mclass.kind == interface_kind or mclassdef.mclass.kind == enum_kind then
654 modelbuilder.error(self, "Error: Attempt to define attribute {name} in the interface {mclass}.")
655 else if mclass.kind == enum_kind then
656 modelbuilder.error(self, "Error: Attempt to define attribute {name} in the enum class {mclass}.")
657 else if mclass.kind == extern_kind then
658 modelbuilder.error(self, "Error: Attempt to define attribute {name} in the extern class {mclass}.")
659 end
660
661 var nid = self.n_id
662 if nid != null then
663 # Old attribute style
664 var mprop = modelbuilder.try_get_mproperty_by_name(nid, mclassdef, name)
665 if mprop == null then
666 var mvisibility = new_property_visibility(modelbuilder, mclassdef, self.n_visibility)
667 mprop = new MAttribute(mclassdef, name, mvisibility)
668 if not self.check_redef_keyword(modelbuilder, nclassdef, self.n_kwredef, false, mprop) then return
669 else
670 assert mprop isa MAttribute
671 check_redef_property_visibility(modelbuilder, self.n_visibility, mprop)
672 if not self.check_redef_keyword(modelbuilder, nclassdef, self.n_kwredef, true, mprop) then return
673 end
674 nclassdef.mprop2npropdef[mprop] = self
675
676 var mpropdef = new MAttributeDef(mclassdef, mprop, self.location)
677 self.mpropdef = mpropdef
678 modelbuilder.mpropdef2npropdef[mpropdef] = self
679 set_doc(mpropdef)
680
681 var nreadable = self.n_readable
682 if nreadable != null then
683 var readname = name.substring_from(1)
684 var mreadprop = modelbuilder.try_get_mproperty_by_name(nid, mclassdef, readname).as(nullable MMethod)
685 if mreadprop == null then
686 var mvisibility = new_property_visibility(modelbuilder, mclassdef, nreadable.n_visibility)
687 mreadprop = new MMethod(mclassdef, readname, mvisibility)
688 if not self.check_redef_keyword(modelbuilder, nclassdef, nreadable.n_kwredef, false, mreadprop) then return
689 else
690 if not self.check_redef_keyword(modelbuilder, nclassdef, nreadable.n_kwredef, true, mreadprop) then return
691 check_redef_property_visibility(modelbuilder, nreadable.n_visibility, mreadprop)
692 end
693 nclassdef.mprop2npropdef[mreadprop] = self
694
695 var mreadpropdef = new MMethodDef(mclassdef, mreadprop, self.location)
696 self.mreadpropdef = mreadpropdef
697 modelbuilder.mpropdef2npropdef[mreadpropdef] = self
698 mreadpropdef.mdoc = mpropdef.mdoc
699 end
700
701 var nwritable = self.n_writable
702 if nwritable != null then
703 var writename = name.substring_from(1) + "="
704 var mwriteprop = modelbuilder.try_get_mproperty_by_name(nid, mclassdef, writename).as(nullable MMethod)
705 if mwriteprop == null then
706 var mvisibility = new_property_visibility(modelbuilder, mclassdef, nwritable.n_visibility)
707 mwriteprop = new MMethod(mclassdef, writename, mvisibility)
708 if not self.check_redef_keyword(modelbuilder, nclassdef, nwritable.n_kwredef, false, mwriteprop) then return
709 else
710 if not self.check_redef_keyword(modelbuilder, nclassdef, nwritable.n_kwredef, true, mwriteprop) then return
711 check_redef_property_visibility(modelbuilder, nwritable.n_visibility, mwriteprop)
712 end
713 nclassdef.mprop2npropdef[mwriteprop] = self
714
715 var mwritepropdef = new MMethodDef(mclassdef, mwriteprop, self.location)
716 self.mwritepropdef = mwritepropdef
717 modelbuilder.mpropdef2npropdef[mwritepropdef] = self
718 mwritepropdef.mdoc = mpropdef.mdoc
719 end
720 else
721 # New attribute style
722 var nid2 = self.n_id2.as(not null)
723 var mprop = new MAttribute(mclassdef, "@" + name, none_visibility)
724 var mpropdef = new MAttributeDef(mclassdef, mprop, self.location)
725 self.mpropdef = mpropdef
726 modelbuilder.mpropdef2npropdef[mpropdef] = self
727 set_doc(mpropdef)
728
729 var readname = name
730 var mreadprop = modelbuilder.try_get_mproperty_by_name(nid2, mclassdef, readname).as(nullable MMethod)
731 if mreadprop == null then
732 var mvisibility = new_property_visibility(modelbuilder, mclassdef, self.n_visibility)
733 mreadprop = new MMethod(mclassdef, readname, mvisibility)
734 if not self.check_redef_keyword(modelbuilder, nclassdef, n_kwredef, false, mreadprop) then return
735 else
736 if not self.check_redef_keyword(modelbuilder, nclassdef, n_kwredef, true, mreadprop) then return
737 check_redef_property_visibility(modelbuilder, self.n_visibility, mreadprop)
738 end
739 nclassdef.mprop2npropdef[mreadprop] = self
740
741 var mreadpropdef = new MMethodDef(mclassdef, mreadprop, self.location)
742 self.mreadpropdef = mreadpropdef
743 modelbuilder.mpropdef2npropdef[mreadpropdef] = self
744 mreadpropdef.mdoc = mpropdef.mdoc
745
746 var writename = name + "="
747 var nwritable = self.n_writable
748 var mwriteprop = modelbuilder.try_get_mproperty_by_name(nid2, mclassdef, writename).as(nullable MMethod)
749 var nwkwredef: nullable Token = null
750 if nwritable != null then nwkwredef = nwritable.n_kwredef
751 if mwriteprop == null then
752 var mvisibility
753 if nwritable != null then
754 mvisibility = new_property_visibility(modelbuilder, mclassdef, nwritable.n_visibility)
755 else
756 mvisibility = private_visibility
757 end
758 mwriteprop = new MMethod(mclassdef, writename, mvisibility)
759 if not self.check_redef_keyword(modelbuilder, nclassdef, nwkwredef, false, mwriteprop) then return
760 else
761 if not self.check_redef_keyword(modelbuilder, nclassdef, nwkwredef, true, mwriteprop) then return
762 if nwritable != null then
763 check_redef_property_visibility(modelbuilder, nwritable.n_visibility, mwriteprop)
764 end
765 end
766 nclassdef.mprop2npropdef[mwriteprop] = self
767
768 var mwritepropdef = new MMethodDef(mclassdef, mwriteprop, self.location)
769 self.mwritepropdef = mwritepropdef
770 modelbuilder.mpropdef2npropdef[mwritepropdef] = self
771 mwritepropdef.mdoc = mpropdef.mdoc
772 end
773 end
774
775 redef fun build_signature(modelbuilder)
776 do
777 var mpropdef = self.mpropdef
778 if mpropdef == null then return # Error thus skiped
779 var mclassdef = mpropdef.mclassdef
780 var mmodule = mclassdef.mmodule
781 var mtype: nullable MType = null
782
783 var ntype = self.n_type
784 if ntype != null then
785 mtype = modelbuilder.resolve_mtype(mmodule, mclassdef, ntype)
786 if mtype == null then return
787 end
788
789 var nexpr = self.n_expr
790 if mtype == null then
791 if nexpr != null then
792 if nexpr isa ANewExpr then
793 mtype = modelbuilder.resolve_mtype(mmodule, mclassdef, nexpr.n_type)
794 else if nexpr isa AIntExpr then
795 var cla = modelbuilder.try_get_mclass_by_name(nexpr, mmodule, "Int")
796 if cla != null then mtype = cla.mclass_type
797 else if nexpr isa AFloatExpr then
798 var cla = modelbuilder.try_get_mclass_by_name(nexpr, mmodule, "Float")
799 if cla != null then mtype = cla.mclass_type
800 else if nexpr isa ACharExpr then
801 var cla = modelbuilder.try_get_mclass_by_name(nexpr, mmodule, "Char")
802 if cla != null then mtype = cla.mclass_type
803 else if nexpr isa ABoolExpr then
804 var cla = modelbuilder.try_get_mclass_by_name(nexpr, mmodule, "Bool")
805 if cla != null then mtype = cla.mclass_type
806 else if nexpr isa ASuperstringExpr then
807 var cla = modelbuilder.try_get_mclass_by_name(nexpr, mmodule, "String")
808 if cla != null then mtype = cla.mclass_type
809 else if nexpr isa AStringFormExpr then
810 var cla = modelbuilder.try_get_mclass_by_name(nexpr, mmodule, "String")
811 if cla != null then mtype = cla.mclass_type
812 else
813 modelbuilder.error(self, "Error: Untyped attribute {mpropdef}. Implicit typing allowed only for literals and new.")
814 end
815
816 else
817 modelbuilder.error(self, "Error: Untyped attribute {mpropdef}")
818 end
819 else
820 assert ntype != null
821 if nexpr isa ANewExpr then
822 var xmtype = modelbuilder.resolve_mtype(mmodule, mclassdef, nexpr.n_type)
823 if xmtype == mtype and modelbuilder.toolcontext.opt_warn.value >= 2 then
824 modelbuilder.warning(ntype, "Warning: useless type definition")
825 end
826 end
827 end
828
829 if mtype == null then return
830
831 mpropdef.static_mtype = mtype
832
833 var mreadpropdef = self.mreadpropdef
834 if mreadpropdef != null then
835 var msignature = new MSignature(new Array[MParameter], mtype)
836 mreadpropdef.msignature = msignature
837 end
838
839 var msritepropdef = self.mwritepropdef
840 if mwritepropdef != null then
841 var name: String
842 if n_id != null then
843 name = n_id.text.substring_from(1)
844 else
845 name = n_id2.text
846 end
847 var mparameter = new MParameter(name, mtype, false)
848 var msignature = new MSignature([mparameter], null)
849 mwritepropdef.msignature = msignature
850 end
851 end
852
853 redef fun check_signature(modelbuilder)
854 do
855 var mpropdef = self.mpropdef
856 if mpropdef == null then return # Error thus skiped
857 var mclassdef = mpropdef.mclassdef
858 var mmodule = mclassdef.mmodule
859 var ntype = self.n_type
860 var mtype = self.mpropdef.static_mtype
861 if mtype == null then return # Error thus skiped
862
863 # Lookup for signature in the precursor
864 # FIXME all precursors should be considered
865 if not mpropdef.is_intro then
866 var precursor_type = mpropdef.mproperty.intro.static_mtype
867 if precursor_type == null then return
868
869 if mtype != precursor_type then
870 modelbuilder.error(ntype.as(not null), "Redef Error: Wrong static type. found {mtype}, expected {precursor_type}.")
871 return
872 end
873 end
874
875 # Check getter and setter
876 var meth = self.mreadpropdef
877 if meth != null then
878 self.check_method_signature(modelbuilder, meth)
879 var node: nullable ANode = ntype
880 if node == null then node = self
881 modelbuilder.check_visibility(node, mtype, meth)
882 end
883 meth = self.mwritepropdef
884 if meth != null then
885 self.check_method_signature(modelbuilder, meth)
886 var node: nullable ANode = ntype
887 if node == null then node = self
888 modelbuilder.check_visibility(node, mtype, meth)
889 end
890 end
891
892 private fun check_method_signature(modelbuilder: ModelBuilder, mpropdef: MMethodDef)
893 do
894 var mclassdef = mpropdef.mclassdef
895 var mmodule = mclassdef.mmodule
896 var nsig = self.n_type
897 var mysignature = mpropdef.msignature
898 if mysignature == null then return # Error thus skiped
899
900 # Lookup for signature in the precursor
901 # FIXME all precursors should be considered
902 if not mpropdef.is_intro then
903 var msignature = mpropdef.mproperty.intro.msignature
904 if msignature == null then return
905
906 if mysignature.arity != msignature.arity then
907 var node: ANode
908 if nsig != null then node = nsig else node = self
909 modelbuilder.error(node, "Redef Error: {mysignature.arity} parameters found, {msignature.arity} expected. Signature is {mpropdef}{msignature}")
910 return
911 end
912 var precursor_ret_type = msignature.return_mtype
913 var ret_type = mysignature.return_mtype
914 if ret_type != null and precursor_ret_type == null then
915 var node: ANode
916 if nsig != null then node = nsig else node = self
917 modelbuilder.error(node, "Redef Error: {mpropdef.mproperty} is a procedure, not a function.")
918 return
919 end
920
921 if mysignature.arity > 0 then
922 # Check parameters types
923 for i in [0..mysignature.arity[ do
924 var myt = mysignature.mparameters[i].mtype
925 var prt = msignature.mparameters[i].mtype
926 if not myt.is_subtype(mmodule, mclassdef.bound_mtype, prt) and
927 not prt.is_subtype(mmodule, mclassdef.bound_mtype, myt) then
928 var node: ANode
929 if nsig != null then node = nsig else node = self
930 modelbuilder.error(node, "Redef Error: Wrong type for parameter `{mysignature.mparameters[i].name}'. found {myt}, expected {prt}.")
931 end
932 end
933 end
934 if precursor_ret_type != null then
935 if ret_type == null then
936 # Inherit the return type
937 ret_type = precursor_ret_type
938 else if not ret_type.is_subtype(mmodule, mclassdef.bound_mtype, precursor_ret_type) then
939 var node: ANode
940 if nsig != null then node = nsig else node = self
941 modelbuilder.error(node, "Redef Error: Wrong return type. found {ret_type}, expected {precursor_ret_type}.")
942 end
943 end
944 end
945 end
946 end
947
948 redef class ATypePropdef
949 redef type MPROPDEF: MVirtualTypeDef
950
951 redef fun build_property(modelbuilder, nclassdef)
952 do
953 var mclassdef = nclassdef.mclassdef.as(not null)
954 var name = self.n_id.text
955 var mprop = modelbuilder.try_get_mproperty_by_name(self.n_id, mclassdef, name)
956 if mprop == null then
957 var mvisibility = new_property_visibility(modelbuilder, mclassdef, self.n_visibility)
958 mprop = new MVirtualTypeProp(mclassdef, name, mvisibility)
959 for c in name.chars do if c >= 'a' and c<= 'z' then
960 modelbuilder.warning(n_id, "Warning: lowercase in the virtual type {name}")
961 break
962 end
963 if not self.check_redef_keyword(modelbuilder, nclassdef, self.n_kwredef, false, mprop) then return
964 else
965 if not self.check_redef_keyword(modelbuilder, nclassdef, self.n_kwredef, true, mprop) then return
966 assert mprop isa MVirtualTypeProp
967 check_redef_property_visibility(modelbuilder, self.n_visibility, mprop)
968 end
969 nclassdef.mprop2npropdef[mprop] = self
970
971 var mpropdef = new MVirtualTypeDef(mclassdef, mprop, self.location)
972 self.mpropdef = mpropdef
973 modelbuilder.mpropdef2npropdef[mpropdef] = self
974 set_doc(mpropdef)
975 end
976
977 redef fun build_signature(modelbuilder)
978 do
979 var mpropdef = self.mpropdef
980 if mpropdef == null then return # Error thus skiped
981 var mclassdef = mpropdef.mclassdef
982 var mmodule = mclassdef.mmodule
983 var mtype: nullable MType = null
984
985 var ntype = self.n_type
986 mtype = modelbuilder.resolve_mtype(mmodule, mclassdef, ntype)
987 if mtype == null then return
988
989 mpropdef.bound = mtype
990 # print "{mpropdef}: {mtype}"
991 end
992
993 redef fun check_signature(modelbuilder)
994 do
995 var mpropdef = self.mpropdef
996 if mpropdef == null then return # Error thus skiped
997
998 var bound = self.mpropdef.bound
999 if bound == null then return # Error thus skiped
1000
1001 modelbuilder.check_visibility(n_type.as(not null), bound, mpropdef)
1002
1003 # Fast case: the bound is not a formal type
1004 if not bound isa MVirtualType then return
1005
1006 var mclassdef = mpropdef.mclassdef
1007 var mmodule = mclassdef.mmodule
1008 var anchor = mclassdef.bound_mtype
1009
1010 # Slow case: progress on each resolution until: (i) we loop, or (ii) we found a non formal type
1011 var seen = [self.mpropdef.mproperty.mvirtualtype]
1012 loop
1013 if seen.has(bound) then
1014 seen.add(bound)
1015 modelbuilder.error(self, "Error: circularity of virtual type definition: {seen.join(" -> ")}")
1016 return
1017 end
1018 seen.add(bound)
1019 var next = bound.lookup_bound(mmodule, anchor)
1020 if not next isa MVirtualType then break
1021 bound = next
1022 end
1023 end
1024 end