Inheritance of constructors.
[nit.git] / src / syntax / mmbuilder.nit
1 # This file is part of NIT ( http://www.nitlanguage.org ).
2 #
3 # Copyright 2008 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 # Build MM entity from NIT AST and check conformance of these entities.
18 # This module introduce specific MM class (MMSrcXXX) that specialize the abstract one from metamodel
19 #
20 package mmbuilder
21
22 import syntax_base
23
24 # Class specialization hierarchy sorter
25 private class CSHSorter
26 special AbstractSorter[MMLocalClass]
27 redef meth compare(a, b)
28 do
29 return a.cshe.rank <=> b.cshe.rank
30 end
31
32 init do end
33 end
34
35 redef class MMSrcModule
36 # Syntax analysis and MM construction for the module
37 # Require that supermodules are processed
38 meth do_mmbuilder(tc: ToolContext)
39 do
40 # Import global classes
41 import_global_classes
42
43 # Create local classes and attach them to global classes
44 var mmbv = new ClassBuilderVisitor(tc, self)
45 mmbv.visit(node)
46 if tc.error_count > 0 then exit(1)
47
48 # Import unrefined local classes and attach them to global classes
49 import_local_classes
50
51 # Resolve classes in super clauses
52 var mmbv1 = new ClassSpecializationBuilderVisitor(tc, self)
53 mmbv1.visit(node)
54 if tc.error_count > 0 then exit(1)
55
56 # Compute specialization relation
57 for c in local_classes do
58 if visibility_for(c.global.intro.module) < c.global.visibility_level then
59 continue
60 end
61 c.compute_super_classes
62 end
63
64 # Class that we will process now are those in the hierarchy
65 # Its mean all the visible classes and their super-classes
66 # Note that leaves invisible classes are not in the 'classes' set
67 var classes = class_specialization_hierarchy.to_a
68
69 # Prepare class list to process the following in a right order
70 var sorter = once new CSHSorter
71 sorter.sort(classes)
72
73 # Compute class ancestors types
74 var mmbv1b = new ClassAncestorBuilder(tc, self)
75 for c in classes do
76 c.accept_class_visitor(mmbv1b)
77 c.compute_ancestors
78 end
79 if tc.error_count > 0 then exit(1)
80
81 # Check class conformity
82 var mmbv1b = new ClassVerifierVisitor(tc, self)
83 for c in classes do
84 c.accept_class_visitor(mmbv1b)
85 end
86 if tc.error_count > 0 then exit(1)
87
88 # Property inhritance and introduction
89 var mmbv2 = new PropertyBuilderVisitor(tc, self)
90 for c in classes do
91 # Inherit global properties
92 c.inherit_global_properties
93
94 # Global property introduction and redefinition
95 c.accept_class_visitor(mmbv2)
96
97 # Default and inherited constructor if needed
98 if c isa MMSrcLocalClass and c.global.intro == c and not c.global.is_universal and not c.global.is_interface then
99 c.process_default_constructors(mmbv2)
100 end
101
102 # Note that inherited unredefined property are processed on demand latter
103 end
104 if tc.error_count > 0 then exit(1)
105
106 # Property signature analysis and inheritance conformance
107 var mmbv3 = new PropertyVerifierVisitor(tc, self)
108 for c in classes do
109 c.accept_properties_visitor(mmbv3)
110 end
111
112 # Check inherited local properties
113 for c in classes do
114 for g in c.global_properties do
115 if visibility_for(g.intro.module) < g.visibility_level then continue
116 var p = c[g]
117 end
118 end
119
120 if tc.error_count > 0 then exit(1)
121 end
122 end
123
124 redef class MMLocalClass
125 # Accept a class visitor (on class nodes)
126 private meth accept_class_visitor(v: AbsSyntaxVisitor)
127 do
128 end
129
130 # Accept a class visitor (on class properties)
131 private meth accept_properties_visitor(v: AbsSyntaxVisitor)
132 do
133 end
134 end
135
136 redef class MMSrcLocalClass
137 redef meth accept_class_visitor(v)
138 do
139 for n in nodes do
140 v.visit(n)
141 end
142 end
143
144 # Accept a class visitor (on class properties)
145 redef meth accept_properties_visitor(v)
146 do
147 for n in nodes do
148 v.visit(n)
149 end
150
151 for p in src_local_properties do
152 p.accept_property_visitor(v)
153 end
154 end
155
156 # A mixin class can be build the same way that one of its superclasses
157 readable attr _is_mixin: Bool = false
158
159 # Introduce or inherit default constructors
160 private meth process_default_constructors(v: PropertyBuilderVisitor)
161 do
162 # Is there already a constructor ?
163 for gp in global_properties do
164 if gp.is_init then
165 # Return if explicit constructor in the class
166 if gp.intro.local_class == self then return
167 end
168 end
169
170 # Collect visible constructors in super stateful classes
171 var super_constructors = new ArraySet[MMGlobalProperty]
172 for sc in che.direct_greaters do
173 if sc.global.is_universal or sc.global.is_interface then continue
174 for gp in sc.global_properties do
175 if not gp.is_init then continue
176 super_constructors.add(gp)
177 end
178 end
179
180 if not super_constructors.is_empty then
181 # Select most specific classes introducing inheritable constructors
182 # Mixin classes are skipped
183 var supers = new Array[MMLocalClass]
184 for gp in super_constructors do
185 var sc = gp.local_class
186 if supers.has(sc) then continue
187 assert sc isa MMSrcLocalClass
188 if not sc.is_mixin then
189 supers.add(sc)
190 end
191 end
192 supers = che.order.select_smallests(supers)
193
194 # A mixin class can only have 0 or 1 most specific non-mixin superclass
195 var superclass: MMLocalClass = null # This most specific non-mixin superclass (if any)
196
197 if supers.length > 1 then
198 v.error(nodes.first, "Error: Explicit constructor required in {self} since multiple inheritance of constructor is forbiden. Conflicting classes are {supers.join(", ")}. Costructors are {super_constructors.join(", ")}.")
199 return
200 else if supers.length == 1 then
201 superclass = supers.first
202 end
203
204 for gp in super_constructors do
205 # Inherit constructors : the one of the non-mixin super class or all from the all mixin super-classes
206 if superclass == null or gp.local_class == superclass then
207 make_visible_an_inherited_global_property(gp)
208 end
209 end
210 _is_mixin = true
211 end
212 end
213
214 # Add a source property
215 # Register it to the class and attach it to global property
216 private meth add_src_local_property(v: PropertyBuilderVisitor, prop: MMLocalProperty)
217 do
218 var pname = prop.name
219 # Check double definition in the same class
220 if src_local_properties.has_key(pname) then
221 v.error(prop.node, "Error: A property {pname} is already defined in class {name}.")
222 return
223 end
224 src_local_properties[pname] = prop
225
226 # Intro or redefinition ?
227 if has_global_property_by_name(pname) then
228 var globs = properties_by_name[pname]
229 if globs.length > 1 then
230 v.error(prop.node, "Name error: {self} inherits {globs.length} global properties named {pname}.")
231 end
232 var g = globs.first
233 prop.inherit_global(g)
234 end
235
236 if prop.global == null then
237 #print "{prop.full_name} is an introduction"
238 prop.new_global
239 prop.global.is_init = prop.node isa AConcreteInitPropdef
240 end
241 end
242 end
243
244 redef class MMLocalProperty
245 private meth accept_property_visitor(v: AbsSyntaxVisitor)
246 do
247 end
248 end
249 # Concrete NIT class specialization relation
250 class MMSrcAncestor
251 special MMAncestor
252 # The related AST node
253 readable attr _node: ASuperclass
254 redef readable attr _local_class: MMLocalClass
255
256 init(n: ASuperclass, c: MMLocalClass)
257 do
258 _node = n
259 _local_class = c
260 end
261 end
262
263 ###############################################################################
264
265 # A pass visitor for syntax analysis.
266 # * Build the classes and attach them to global classes
267 # * Collect generic formal parameters.
268 private class ClassBuilderVisitor
269 special AbsSyntaxVisitor
270 # Current class arity
271 readable writable attr _local_class_arity: Int
272
273 # Current class formal parameters
274 readable writable attr _formals: Map[Symbol, MMTypeFormalParameter]
275
276 redef meth visit(n) do n.accept_class_builder(self)
277 init(tc, m) do super
278 end
279
280 # Another pass visitor for syntax analysis.
281 # * Build ancertors (with only class informations not the type one)
282 private class ClassSpecializationBuilderVisitor
283 special AbsSyntaxVisitor
284 redef meth visit(n) do n.accept_class_specialization_builder(self)
285 init(tc, m) do super
286 end
287
288 # Another pass visitor for syntax analysis.
289 # * Compute types in ancestors
290 private class ClassAncestorBuilder
291 special AbsSyntaxVisitor
292 redef meth visit(n) do n.accept_class_ancestor_builder(self)
293 init(tc, m) do super
294 end
295
296 # Another pass visitor for syntax analysis.
297 # * Checks classes in regard to superclasses
298 private class ClassVerifierVisitor
299 special AbsSyntaxVisitor
300 redef meth visit(n) do n.accept_class_verifier(self)
301 init(tc, m) do super
302 end
303
304
305 # Another pass visitor for syntax analysis.
306 # * Build propertie names
307 # * Build local properties and attache them to global properties
308 # * Attach bound to formal types
309 private class PropertyBuilderVisitor
310 special AbsSyntaxVisitor
311 redef meth visit(n) do n.accept_property_builder(self)
312 init(tc, m) do super
313 end
314
315 # Another pass pass visitor for syntax analysis.
316 # * Check property conformance
317 private class PropertyVerifierVisitor
318 special AbsSyntaxVisitor
319 # Current visited parameter types
320 readable writable attr _params: Array[PParam]
321
322 # Visited parameters without type information added
323 readable writable attr _untyped_params: Array[PParam]
324
325 # Position of the current star parameter
326 readable writable attr _vararg_rank: Int
327
328 # Current signature
329 readable writable attr _signature: MMSignature
330
331 redef meth visit(n) do n.accept_property_verifier(self)
332
333 init(tc, m) do super
334 end
335
336 ###############################################################################
337
338 redef class PNode
339 private meth accept_class_builder(v: ClassBuilderVisitor) do accept_abs_syntax_visitor(v)
340 private meth accept_class_specialization_builder(v: ClassSpecializationBuilderVisitor) do accept_abs_syntax_visitor(v)
341 private meth accept_class_ancestor_builder(v: ClassAncestorBuilder) do accept_abs_syntax_visitor(v)
342 private meth accept_class_verifier(v: ClassVerifierVisitor) do accept_abs_syntax_visitor(v)
343 private meth accept_property_builder(v: PropertyBuilderVisitor) do accept_abs_syntax_visitor(v)
344 private meth accept_property_verifier(v: PropertyVerifierVisitor) do accept_abs_syntax_visitor(v)
345 end
346
347 redef class AModule
348 # Import supermodules and compute visibility
349 meth import_super_modules(tc: ToolContext, mod: MMSrcModule)
350 do
351 # Import super-modules
352 var module_names_to_import = new Array[Symbol]
353 var module_visibility = new HashMap[Symbol, Int]
354 var no_import: PImport = null
355 for i in n_imports do
356 var n = i.module_name
357 if n != null then
358 module_names_to_import.add(n)
359 module_visibility[n] = i.visibility_level
360 else
361 no_import = i
362 end
363 end
364 if no_import != null then
365 if not module_names_to_import.is_empty then
366 tc.error("{no_import.locate}: Error: Top modules cannot import other modules.")
367 end
368 else if module_names_to_import.is_empty then
369 var stdname = once "standard".to_symbol
370 module_names_to_import.add(stdname)
371 module_visibility[stdname] = 1
372 end
373
374 mod.import_supers_modules(module_names_to_import)
375
376 for mname in module_names_to_import do
377 var level = module_visibility[mname]
378 var m = tc.get_module(mname, mod)
379 mod.add_super_module(m, level)
380 end
381 end
382 end
383
384 redef class APackagedecl
385 redef meth accept_class_builder(v)
386 do
387 if n_id.to_symbol != v.module.name then
388 v.error(n_id, "Error: Package name missmatch between {v.module.name} and {n_id.to_symbol}")
389 end
390 end
391 end
392
393 redef class PImport
394 # Imported module name (or null)
395 meth module_name: Symbol is abstract
396
397 # Visibility level (intrude/public/private)
398 meth visibility_level: Int is abstract
399 end
400 redef class AImport
401 redef meth module_name
402 do
403 return n_id.to_symbol
404 end
405 redef meth visibility_level
406 do
407 return n_visibility.level
408 end
409 end
410 redef class ANoImport
411 redef meth module_name
412 do
413 return null
414 end
415 end
416
417 redef class PVisibility
418 # Visibility level
419 meth level: Int is abstract
420 end
421 redef class APublicVisibility
422 redef meth level do return 1
423 end
424 redef class AProtectedVisibility
425 redef meth level do return 2
426 end
427 redef class APrivateVisibility
428 redef meth level do return 3
429 end
430 redef class AIntrudeVisibility
431 redef meth level do return 0
432 end
433
434
435 redef class PClassdef
436 redef readable attr _local_class: MMSrcLocalClass
437
438 # Name of the class
439 meth name: Symbol is abstract
440
441 # Number of formal parameters
442 meth arity: Int do return 0
443
444 # Visibility of the class
445 meth visibility_level: Int do return 1
446
447 redef meth accept_class_builder(v)
448 do
449 var local_class: MMSrcLocalClass
450 var mod = v.module
451 var local_classes = mod.src_local_classes
452 if (local_classes.has_key(name)) then
453 local_class = local_classes[name]
454 if self isa AClassdef then
455 # If we are not a special implicit class then rant
456 v.error(self, "Error: A class {name} is already defined at line {local_class.nodes.first.first_token.line}.")
457 return
458 end
459 local_class.nodes.add(self)
460 else
461 local_class = new MMSrcLocalClass(name, self, arity)
462 mod.add_local_class(local_class)
463 local_classes[name] = local_class
464 var g = mod.global_class_named(name)
465 if g == null then
466 # Intro
467 local_class.new_global
468 g = local_class.global
469 else
470 local_class.set_global(g)
471 end
472
473 end
474 _local_class = local_class
475 v.local_class_arity = 0
476 v.formals = new HashMap[Symbol, MMTypeFormalParameter]
477
478 #####
479 super
480 #####
481
482 _local_class.formal_dict = v.formals
483 v.formals = null
484 end
485
486 redef meth accept_abs_syntax_visitor(v)
487 do
488 v.local_class = _local_class
489 super
490 v.local_class = null
491 end
492 end
493
494 redef class PClasskind
495 meth is_interface: Bool do return false
496 meth is_universal: Bool do return false
497 meth is_abstract: Bool do return false
498 end
499
500 redef class AInterfaceClasskind
501 redef meth is_interface do return true
502 end
503 redef class AUniversalClasskind
504 redef meth is_universal do return true
505 end
506 redef class AAbstractClasskind
507 redef meth is_abstract do return true
508 end
509
510 redef class AClassdef
511 redef meth name
512 do
513 return n_id.to_symbol
514 end
515 redef meth arity
516 do
517 return n_formaldefs.length
518 end
519 redef meth accept_class_verifier(v)
520 do
521 super
522 var glob = _local_class.global
523 if glob.intro == _local_class then
524 # Intro
525 glob.visibility_level = visibility_level
526 glob.is_interface = n_classkind.is_interface
527 glob.is_abstract = n_classkind.is_abstract
528 glob.is_universal = n_classkind.is_universal
529 if n_kwredef != null then
530 v.error(self, "Redef error: No class {name} is imported. Remove the redef keyword to define a new class.")
531 end
532
533 for c in _local_class.cshe.direct_greaters do
534 var cg = c.global
535 if glob.is_interface then
536 if cg.is_universal then
537 v.error(self, "Special error: Interface {name} try to specialise universal class {c.name}.")
538 else if not cg.is_interface then
539 v.error(self, "Special error: Interface {name} try to specialise class {c.name}.")
540 end
541 else if glob.is_universal then
542 if not cg.is_interface and not cg.is_universal then
543 v.error(self, "Special error: Universal class {name} try to specialise class {c.name}.")
544 end
545 else
546 if cg.is_universal then
547 v.error(self, "Special error: Class {name} try to specialise universal class {c.name}.")
548 end
549 end
550
551 end
552 return
553 end
554
555 # Redef
556
557 glob.check_visibility(v, self, v.module)
558 if n_kwredef == null then
559 v.error(self, "Redef error: {name} is an imported class. Add the redef keyword to refine it.")
560 return
561 end
562
563 if glob.intro.arity != _local_class.arity then
564 v.error(self, "Redef error: Formal parameter arity missmatch; got {_local_class.arity}, expected {glob.intro.arity}.")
565 end
566
567 if
568 not glob.is_interface and n_classkind.is_interface or
569 not glob.is_abstract and n_classkind.is_abstract or
570 not glob.is_universal and n_classkind.is_universal
571 then
572 v.error(self, "Redef error: cannot change kind of class {name}.")
573 end
574 end
575
576 redef meth visibility_level
577 do
578 return n_visibility.level
579 end
580 end
581
582 redef class AMainClassdef
583 redef meth name
584 do
585 return once "Sys".to_symbol
586 end
587 end
588
589 redef class ATopClassdef
590 redef meth name
591 do
592 return once "Object".to_symbol
593 end
594 end
595
596 class MMSrcTypeFormalParameter
597 special MMTypeFormalParameter
598 # The associated node
599 readable attr _node: AFormaldef
600
601 init(name: Symbol, pos: Int, local_class: MMLocalClass, n: AFormaldef)
602 do
603 super(name, pos, local_class)
604 _node = n
605 end
606 end
607
608 redef class AFormaldef
609 # The associated formal generic parameter (MM entity)
610 attr _formal: MMSrcTypeFormalParameter
611
612 redef meth accept_class_builder(v)
613 do
614 var name = n_id.to_symbol
615 var formal_type = new MMSrcTypeFormalParameter(name, v.local_class_arity, v.local_class, self)
616 _formal = formal_type
617 v.local_class_arity = v.local_class_arity + 1
618 v.local_class.register_formal(formal_type)
619 v.formals[name] = formal_type
620 super
621 end
622
623 redef meth accept_class_verifier(v)
624 do
625 super
626 var c = v.local_class
627 var o = c.global.intro
628 if c == o then
629 if n_type == null then
630 _formal.bound = v.module.type_any
631 else
632 _formal.bound = n_type.get_stype(v)
633 end
634 else
635 var ob = o.get_formal(_formal.position).bound.for_module(v.module)
636 if n_type == null then
637 _formal.bound = ob
638 else
639 _formal.bound = n_type.get_stype(v)
640 if _formal.bound != ob then
641 v.error(self, "Redef error: Cannot change formal parameter type of class {c}; got {_formal.bound}, expected {ob}.")
642 end
643 end
644 end
645 end
646 end
647
648 redef class ASuperclass
649 readable attr _ancestor: MMSrcAncestor
650
651 redef meth accept_class_specialization_builder(v)
652 do
653 super
654 var c = n_type.get_local_class(v)
655 var ancestor = new MMSrcAncestor(self, c)
656 _ancestor = ancestor
657 v.local_class.add_direct_parent(ancestor)
658 end
659
660 redef meth accept_class_ancestor_builder(v)
661 do
662 super
663 _ancestor.stype = n_type.get_unchecked_stype(v)
664 _ancestor.inheriter = v.local_class.get_type
665 end
666
667 redef meth accept_class_verifier(v)
668 do
669 super
670 n_type.check_conform(v)
671 end
672 end
673
674 redef class PPropdef
675 # Process and check properties of the property.
676 # * Distinguish inits and methods
677 # * Inherit or check visibility.
678 # * Check redef errors.
679 # * Check forbiden attribute definitions.
680 # * Check signature conformance.
681 private meth process_and_check(v: PropertyVerifierVisitor, prop: MMLocalProperty, has_redef: Bool, visibility_level: Int)
682 do
683 if prop.global.intro == prop then
684 do_and_check_intro(v, prop, has_redef, visibility_level)
685 else
686 do_and_check_redef(v, prop, has_redef, visibility_level)
687 end
688 end
689
690 # The part of process_and_check when prop is an introduction
691 private meth do_and_check_intro(v: PropertyVerifierVisitor, prop: MMLocalProperty, has_redef: Bool, visibility_level: Int)
692 do
693 var glob = prop.global
694 var gbc = prop.local_class.global
695 if v.local_class.global.visibility_level >= 3 then
696 # Method of private classes are private
697 visibility_level = 3
698 end
699 glob.visibility_level = visibility_level
700 if has_redef then
701 v.error(self, "Error: No property {prop.local_class}::{prop} is inherited. Remove the redef keyword to define a new property.")
702 end
703 if glob.is_attribute then
704 if gbc.is_interface then
705 v.error(self, "Error: Attempt to define attribute {prop} in the interface {prop.local_class}.")
706 else if gbc.is_universal then
707 v.error(self, "Error: Attempt to define attribute {prop} in the universal class {prop.local_class}.")
708 end
709 else if glob.is_init then
710 if gbc.is_interface then
711 v.error(self, "Error: Attempt to define a constructor {prop} in the class {prop.local_class}.")
712 else if gbc.is_universal then
713 v.error(self, "Error: Attempt to define a constructor {prop} in the universal {prop.local_class}.")
714 end
715 end
716 if prop.signature == null then
717 if glob.is_init then
718 var supers = prop.local_class.super_methods_named(prop.name)
719 inherit_signature(v, prop, supers)
720 end
721 if prop.signature != null then
722 # ok
723 else if not v.untyped_params.is_empty then
724 v.error(v.untyped_params.first, "Error: Untyped parameter.")
725 else
726 prop.signature = new MMSignature(new Array[MMType], null, v.local_class.get_type)
727 end
728 end
729 end
730
731 private meth inherit_signature(v: PropertyVerifierVisitor, prop: MMLocalProperty, supers: Array[MMLocalProperty])
732 do
733 var s = prop.signature
734 for ip in supers do
735 var isig = ip.signature.adaptation_to(v.local_class.get_type)
736
737 if s == null then
738 if v.params.length != isig.arity then
739 #prop.node.printl("v.params.length {v.params.length} != isig.arity {isig.arity} ; {prop.full_name} vs {ip.full_name}")
740 return
741 end
742 for p in v.params do
743 var t = isig[p.position]
744 p.stype = t
745 if p.position == isig.vararg_rank then
746 t = v.type_array(t)
747 end
748 p.variable.stype = t
749 end
750
751 s = isig
752 prop.signature = s
753 end
754 end
755 end
756
757 # The part of process_and_check when prop is a redefinition
758 private meth do_and_check_redef(v: PropertyVerifierVisitor, prop: MMLocalProperty, has_redef: Bool, visibility_level: Int)
759 do
760 var is_init = self isa AConcreteInitPropdef
761 var glob = prop.global
762
763 if not has_redef then
764 v.error(self, "Redef error: {prop.local_class}::{prop} is an inherited property. To redefine it, add the redef keyword.")
765 return
766 end
767 if glob.is_init and not is_init then
768 v.error(self, "Redef error: A method {prop.local_class}::{prop} cannot redefine a constructor.")
769 else if not glob.is_init and is_init then
770 v.error(self, "Redef error: A constructor {prop.local_class}::{prop} cannot redefine a method.")
771 end
772
773 var s = prop.signature
774 #print "process {prop.local_class.module}::{prop.local_class}::{prop} from global {prop.global.local_property.local_class.module}::{prop.global.local_property.local_class}::{prop.global.local_property}"
775 for i in prop.prhe.direct_greaters do
776 var ip = i.local_class[prop.global]
777 var isig = i.signature.adaptation_to(v.local_class.get_type)
778
779 if s == null then
780 #print "{prop.full_name} inherits signature from {ip.full_name}"
781 if v.params.length != isig.arity then
782 v.error(self, "Redef error: {prop.local_class}::{prop} redefines {ip.local_class}::{ip} with {isig.arity} parameter(s).")
783 return
784 end
785 for p in v.params do
786 var t = isig[p.position]
787 p.stype = t
788 if p.position == isig.vararg_rank then
789 t = v.type_array(t)
790 end
791 p.variable.stype = t
792 end
793 s = isig
794 prop.signature = s
795 end
796
797 #print "orig signature: {i.signature.recv} . {i.signature}"
798 #print "inh signature: {isig.recv} . {isig}"
799 #print "redef signature: {s.recv} . {s}"
800
801 if glob.is_init and i.local_class.global != prop.local_class.global then
802 # Do not check signature
803 else if s.arity != isig.arity then
804 v.error(self, "Redef error: {prop.local_class}::{prop} redefines {ip.local_class}::{ip} with {isig.arity} parameter(s).")
805 else
806 for i in [0..s.arity[ do
807 if s[i] != isig[i] then
808 v.error(self, "Redef error: Expected {isig[i]} (as in {ip.local_class}::{ip}), got {s[i]} in {prop.local_class}::{prop}.")
809 end
810 end
811 end
812
813 var srt = s.return_type
814 var isrt = isig.return_type
815 if srt == null and isrt != null then
816 v.error(self, "Redef error: The procedure {prop.local_class}::{prop} redefines the function {ip.local_class}::{ip}.")
817 else if srt != null and isrt == null then
818 v.error(self, "Redef error: The function {prop.local_class}::{prop} redefines the procedure {ip.local_class}::{ip}.")
819 else if srt != null and isrt != null and not srt < isrt then
820 v.error(self, "Redef error: Expected {isrt} (as in {ip.local_class}::{ip}), got {srt} in {prop.local_class}::{prop}.")
821 else if srt != null and isrt != null and srt != isrt and prop isa MMAttribute then
822 # FIXME: To remove
823 v.warning(self, "Redef warning: Expected {isrt} (as in {ip.local_class}::{ip}), got {srt} in {prop.local_class}::{prop}.")
824 end
825 end
826
827 if visibility_level != 1 and glob.visibility_level != visibility_level then
828 v.error(self, "Redef error: {prop.local_class}::{prop} redefinition cannot change visibility.")
829 end
830 glob.check_visibility(v, self, v.module, true)
831 end
832 end
833
834 redef class AAttrPropdef
835 redef readable attr _readmethod: MMSrcMethod
836 redef readable attr _writemethod: MMSrcMethod
837 redef readable attr _prop: MMSrcAttribute
838
839 redef meth accept_property_builder(v)
840 do
841 super
842 var name = n_id.to_symbol
843 var prop = new MMSrcAttribute(name, v.local_class, self)
844 _prop = prop
845 v.local_class.add_src_local_property(v, prop)
846
847 if n_readable != null then
848 name = n_id.text.substring_from(1).to_symbol
849 _readmethod = new MMReadImplementationMethod(name, v.local_class, self)
850 v.local_class.add_src_local_property(v, _readmethod)
851 end
852 if n_writable != null then
853 name = (n_id.text.substring_from(1) + "=").to_symbol
854 _writemethod = new MMWriteImplementationMethod(name, v.local_class, self)
855 v.local_class.add_src_local_property(v, _writemethod)
856 end
857 end
858
859 redef meth accept_property_verifier(v)
860 do
861 super
862 var t: MMType
863 if n_type != null then
864 t = n_type.get_stype(v)
865 else
866 v.error(self, "Not yet implemented: Attribute definition {_prop.local_class}::{_prop} requires an explicit type.")
867 return
868 end
869
870 var signature = new MMSignature(new Array[MMType], t, v.local_class.get_type)
871 _prop.signature = signature
872 var visibility_level = n_visibility.level
873 process_and_check(v, _prop, n_kwredef != null, visibility_level)
874 if n_readable != null then
875 _readmethod.signature = signature
876 process_and_check(v, _readmethod, n_readable.n_kwredef != null, visibility_level)
877 n_type.check_visibility(v, _readmethod)
878 end
879 if n_writable != null then
880 _writemethod.signature = new MMSignature(new Array[MMType].with(t), null, v.local_class.get_type)
881 process_and_check(v, _writemethod, n_writable.n_kwredef != null, visibility_level)
882 n_type.check_visibility(v, _writemethod)
883 end
884 end
885
886 redef meth accept_abs_syntax_visitor(v)
887 do
888 v.local_property = prop
889 super
890 v.local_property = null
891 end
892 end
893
894 redef class AMethPropdef
895 # Name of the method
896 readable attr _name: Symbol
897
898 redef readable attr _method: MMMethSrcMethod
899
900 redef meth accept_property_builder(v)
901 do
902 super
903 if n_methid == null then
904 if self isa AConcreteInitPropdef then
905 _name = once "init".to_symbol
906 else
907 _name = once "main".to_symbol
908 end
909 else
910 _name = n_methid.name
911 # FIXME: Add the 'unary' keyword
912 if n_methid.name == (once "-".to_symbol) then
913 var ns = n_signature
914 if ns isa ASignature and ns.n_params.length == 0 then
915 _name = once "unary -".to_symbol
916 end
917 end
918 end
919 var prop = new MMMethSrcMethod(_name, v.local_class, self)
920 _method = prop
921 v.local_class.add_src_local_property(v, prop)
922 end
923
924 redef meth accept_property_verifier(v)
925 do
926 v.params = new Array[PParam]
927 v.untyped_params = new Array[PParam]
928 v.signature = null
929 v.vararg_rank = -1
930
931 super
932
933 if v.signature == null then
934 #_method.signature = new MMSignature(new Array[MMType], null, v.local_class.get_type)
935 else
936 _method.signature = v.signature
937 end
938 var visibility_level = 1
939 if n_visibility != null and n_visibility.level > 1 then
940 visibility_level = n_visibility.level
941 end
942 process_and_check(v, _method, n_kwredef != null, visibility_level)
943 if n_signature != null then n_signature.check_visibility(v, _method)
944 end
945
946 redef meth accept_abs_syntax_visitor(v)
947 do
948 v.local_property = method
949 super
950 v.local_property = null
951 end
952 end
953
954 redef class AMainMethPropdef
955 redef meth process_and_check(v, prop, has_redef, visibility_level)
956 do
957 prop.global.visibility_level = visibility_level
958 prop.signature = new MMSignature(new Array[MMType], null, v.local_class.get_type)
959 # Disable all checks for main
960 end
961 end
962
963 redef class ATypePropdef
964 redef readable attr _prop: MMSrcTypeProperty
965
966 redef meth accept_property_builder(v)
967 do
968 super
969 var name = n_id.to_symbol
970 var prop = new MMSrcTypeProperty(name, v.local_class, self)
971 _prop = prop
972 v.local_class.add_src_local_property(v, prop)
973 end
974
975 redef meth accept_property_verifier(v)
976 do
977 super
978 var signature = new MMSignature(new Array[MMType], n_type.get_stype(v), v.local_class.get_type)
979 _prop.signature = signature
980 var visibility_level = n_visibility.level
981 process_and_check(v, _prop, n_kwredef != null, visibility_level)
982 end
983
984 redef meth accept_abs_syntax_visitor(v)
985 do
986 v.local_property = prop
987 super
988 v.local_property = null
989 end
990 end
991
992 # Visitor used to build a full method name from multiple tokens
993 private class MethidAccumulator
994 special Visitor
995 readable attr _name: String
996 redef meth visit(n)
997 do
998 if n isa Token then
999 _name.append(n.text)
1000 else
1001 n.visit_all(self)
1002 end
1003 end
1004
1005 init
1006 do
1007 _name = new String
1008 end
1009 end
1010
1011 redef class PMethid
1012 # Method name
1013 readable attr _name: Symbol
1014
1015 redef meth accept_property_builder(v)
1016 do
1017 var accumulator = new MethidAccumulator
1018 accumulator.visit(self)
1019 _name = accumulator.name.to_symbol
1020 super
1021 end
1022 end
1023
1024 redef class PSignature
1025 # Check that visibilities of types in the signature are compatible with the visibility of the property.
1026 meth check_visibility(v: AbsSyntaxVisitor, p: MMLocalProperty) is abstract
1027 end
1028
1029 redef class ASignature
1030 redef meth accept_property_verifier(v)
1031 do
1032 super
1033 if not v.untyped_params.is_empty then
1034 if v.untyped_params.first != v.params.first or n_type != null then
1035 v.error(v.untyped_params.first, "Syntax error: untyped parameter.")
1036 return
1037 end
1038 else if not v.params.is_empty or n_type != null then
1039 var pars = new Array[MMType]
1040 for p in v.params do
1041 pars.add(p.stype)
1042 end
1043 var ret: MMType = null
1044 if n_type != null then
1045 ret = n_type.get_stype(v)
1046 end
1047 v.signature = new MMSignature(pars, ret, v.local_class.get_type)
1048 if v.vararg_rank >= 0 then
1049 v.signature.vararg_rank = v.vararg_rank
1050 end
1051 end
1052 end
1053
1054 redef meth check_visibility(v, p)
1055 do
1056 if p.global.visibility_level >= 3 then return
1057 for n in n_params do
1058 if n.n_type != null then n.n_type.check_visibility(v, p)
1059 end
1060 if n_type != null then n_type.check_visibility(v, p)
1061 end
1062 end
1063
1064 redef class PParam
1065 redef readable attr _position: Int
1066
1067 redef readable attr _variable: Variable
1068
1069 # The type of the parameter in signature
1070 readable writable attr _stype: MMType
1071
1072 redef meth accept_property_verifier(v)
1073 do
1074 super
1075 _position = v.params.length
1076 _variable = new Variable(n_id.to_symbol, self)
1077 v.params.add(self)
1078 v.untyped_params.add(self)
1079 if n_type != null then
1080 var stype = n_type.get_stype(v)
1081 for p in v.untyped_params do
1082 p.stype = stype
1083 if is_vararg then
1084 if v.vararg_rank == -1 then
1085 v.vararg_rank = p.position
1086 else
1087 v.error(self, "Error: A vararg parameter is already defined.")
1088 end
1089 stype = v.type_array(stype)
1090 end
1091 p.variable.stype = stype
1092 end
1093 v.untyped_params.clear
1094 end
1095 end
1096
1097 meth is_vararg: Bool is abstract
1098 end
1099
1100 redef class AParam
1101 redef meth is_vararg do return n_dotdotdot != null
1102 end
1103
1104 redef class PType
1105 # Check that visibilities of types in the signature are compatible with the visibility of the property.
1106 private meth check_visibility(v: AbsSyntaxVisitor, p: MMLocalProperty) is abstract
1107 end
1108
1109 redef class AType
1110 redef meth check_visibility(v, p)
1111 do
1112 if p.global.visibility_level >= 3 then return
1113 var t = get_stype(v)
1114 if t == null then return
1115 var bc = t.local_class
1116 if bc == null then return
1117 if bc.global.visibility_level >= 3 then
1118 v.error(self, "Access error: Class {bc} is private and cannot be used in the signature of the non-private property {p}.")
1119 end
1120 for n in n_types do
1121 n.check_visibility(v, p)
1122 end
1123 end
1124 end
1125
1126 redef class PExpr
1127 redef meth accept_class_builder(v) do end
1128 redef meth accept_property_builder(v) do end
1129 redef meth accept_property_verifier(v) do end
1130 end