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