X-Git-Url: http://nitlanguage.org diff --git a/src/syntax/mmbuilder.nit b/src/syntax/mmbuilder.nit index ab85b7c..db15e8b 100644 --- a/src/syntax/mmbuilder.nit +++ b/src/syntax/mmbuilder.nit @@ -73,11 +73,7 @@ redef class MMSrcModule # Compute class ancestors types var mmbv1b = new ClassAncestorBuilder(tc, self) for c in classes do - if c isa MMSrcLocalClass then - for n in c.nodes do - mmbv1b.visit(n) - end - end + c.accept_class_visitor(mmbv1b) c.compute_ancestors end if tc.error_count > 0 then exit(1) @@ -85,11 +81,7 @@ redef class MMSrcModule # Check class conformity var mmbv1b = new ClassVerifierVisitor(tc, self) for c in classes do - if c isa MMSrcLocalClass then - for n in c.nodes do - mmbv1b.visit(n) - end - end + c.accept_class_visitor(mmbv1b) end if tc.error_count > 0 then exit(1) @@ -100,10 +92,11 @@ redef class MMSrcModule c.inherit_global_properties # Global property introduction and redefinition - if c isa MMSrcLocalClass then - for n in c.nodes do - mmbv2.visit(n) - end + c.accept_class_visitor(mmbv2) + + # Default and inherited constructor if needed + if c isa MMSrcLocalClass and c.global.intro == c and not c.global.is_universal and not c.global.is_interface then + c.process_default_constructors(mmbv2) end # Note that inherited unredefined property are processed on demand latter @@ -113,11 +106,7 @@ redef class MMSrcModule # Property signature analysis and inheritance conformance var mmbv3 = new PropertyVerifierVisitor(tc, self) for c in classes do - if c isa MMSrcLocalClass then - for n in c.nodes do - mmbv3.visit(n) - end - end + c.accept_properties_visitor(mmbv3) end # Check inherited local properties @@ -132,10 +121,118 @@ redef class MMSrcModule end end +redef class MMLocalClass + # Accept a class visitor (on class nodes) + private meth accept_class_visitor(v: AbsSyntaxVisitor) + do + end + + # Accept a class visitor (on class properties) + private meth accept_properties_visitor(v: AbsSyntaxVisitor) + do + end +end + redef class MMSrcLocalClass + redef meth accept_class_visitor(v) + do + for n in nodes do + v.visit(n) + end + end + + # Accept a class visitor (on class properties) + redef meth accept_properties_visitor(v) + do + for n in nodes do + v.visit(n) + end + + for p in src_local_properties do + p.accept_property_visitor(v) + end + end + + # Introduce or inherit default constructors + private meth process_default_constructors(v: PropertyBuilderVisitor) + do + # Is there already a constructor ? + for gp in global_properties do + if gp.is_init then + # Return if explicit constructor in the class + if gp.intro.local_class == self then return + end + end + + # Collect visible constructors in super stateful classes + var super_inits = new ArraySet[MMLocalProperty] + var super_constructors = new ArraySet[MMGlobalProperty] + for sc in che.direct_greaters do + if sc.global.is_universal or sc.global.is_interface then continue + for gp in sc.global_properties do + if not gp.is_init then continue + super_constructors.add(gp) + end + var initname = once ("init".to_symbol) + if sc.has_global_property_by_name(initname) then + var gp = sc.get_property_by_name(initname) + super_inits.add(self[gp]) + end + end + + # Collect unassigned attributes + var unassigned_attributes = new Array[MMSrcAttribute] + for a in src_local_properties do + if a isa MMSrcAttribute then + var n = a.node + assert n isa AAttrPropdef + if n.n_expr == null then unassigned_attributes.add(a) + end + end + + if not super_constructors.is_empty then + # Select most specific classes introducing inheritable constructors + # Mixin classes are skipped + var supers = new Array[MMLocalClass] + for gp in super_constructors do + var sc = gp.local_class + if supers.has(sc) then continue + if not sc.global.is_mixin then + supers.add(sc) + end + end + supers = che.order.select_smallests(supers) + + # A mixin class can only have 0 or 1 most specific non-mixin superclass + var superclass: MMLocalClass = null # This most specific non-mixin superclass (if any) + + if supers.length > 1 then + 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(", ")}.") + return + else if supers.length == 1 then + superclass = supers.first + end + + for gp in super_constructors do + # Inherit constructors : the one of the non-mixin super class or all from the all mixin super-classes + if superclass == null or gp.local_class == superclass then + make_visible_an_inherited_global_property(gp) + end + end + global.mixin_of = superclass.global + else + # v.error(nodes.first, "Error, constructor required in {self} since no anonimous init found in {sc}.") + + # unassigned attributes, then implicit consructors are generated + var p = new MMImplicitInit(self, unassigned_attributes, super_inits.to_a) + add_src_local_property(v, p) + #print("Create implicit init {p} in {self} from {super_inits.join(", ")} + {unassigned_attributes.length} args") + end + end + # Add a source property # Register it to the class and attach it to global property - private meth add_src_local_property(v: PropertyBuilderVisitor, prop: MMConcreteProperty) + private meth add_src_local_property(v: PropertyBuilderVisitor, prop: MMLocalProperty) do var pname = prop.name # Check double definition in the same class @@ -156,13 +253,50 @@ redef class MMSrcLocalClass end if prop.global == null then - #print "{prop.full_name} is an introduction" prop.new_global - prop.global.is_init = prop.node isa AConcreteInitPropdef + prop.global.is_init = prop.is_init end end end +redef class MMLocalProperty + private meth accept_property_visitor(v: AbsSyntaxVisitor) + do + end +end + +redef class MMImplicitInit + readable attr _super_init: MMLocalProperty = null + redef meth accept_property_visitor(v) + do + var base: MMLocalProperty = null + for p in super_inits do + if p.signature.arity > 0 then + if base == null then + base = p + else + v.error(null, "Error: explicit constructor needed in {local_class} since both super-constructor {base.full_name} and {p.full_name} have paramters") + return + end + end + end + _super_init = base + + var params = new Array[MMType] + if base != null then + var sig = base.signature + for i in [0..sig.arity[ do + params.add(sig[i]) + end + end + for a in unassigned_attributes do + params.add(a.signature.return_type) + end + signature = new MMSignature(params, null, local_class.get_type) + end +end + + # Concrete NIT class specialization relation class MMSrcAncestor special MMAncestor @@ -233,21 +367,35 @@ end # * Check property conformance private class PropertyVerifierVisitor special AbsSyntaxVisitor + + # The signature currently build + readable writable attr _signature_builder: SignatureBuilder + + redef meth visit(n) do n.accept_property_verifier(self) + + init(tc, m) + do + super + _signature_builder = new SignatureBuilder + end +end + +# Information about a signature currently build +private class SignatureBuilder # Current visited parameter types - readable writable attr _params: Array[PParam] + readable writable attr _params: Array[PParam] = new Array[PParam] # Visited parameters without type information added - readable writable attr _untyped_params: Array[PParam] + readable writable attr _untyped_params: Array[PParam] = new Array[PParam] # Position of the current star parameter - readable writable attr _vararg_rank: Int + readable writable attr _vararg_rank: Int = -1 - # Current signature - readable writable attr _signature: MMSignature + # Current closure declarations + readable writable attr _closure_decls: Array[AClosureDecl] = new Array[AClosureDecl] - redef meth visit(n) do n.accept_property_verifier(self) - - init(tc, m) do super + # Current signature + readable writable attr _signature: MMSignature = null end ############################################################################### @@ -268,7 +416,7 @@ redef class AModule # Import super-modules var module_names_to_import = new Array[Symbol] var module_visibility = new HashMap[Symbol, Int] - var no_import: PImport + var no_import: PImport = null for i in n_imports do var n = i.module_name if n != null then @@ -595,7 +743,7 @@ redef class PPropdef # * Check redef errors. # * Check forbiden attribute definitions. # * Check signature conformance. - private meth process_and_check(v: PropertyVerifierVisitor, prop: MMConcreteProperty, has_redef: Bool, visibility_level: Int) + private meth process_and_check(v: PropertyVerifierVisitor, prop: MMLocalProperty, has_redef: Bool, visibility_level: Int) do if prop.global.intro == prop then do_and_check_intro(v, prop, has_redef, visibility_level) @@ -605,7 +753,7 @@ redef class PPropdef end # The part of process_and_check when prop is an introduction - private meth do_and_check_intro(v: PropertyVerifierVisitor, prop: MMConcreteProperty, has_redef: Bool, visibility_level: Int) + private meth do_and_check_intro(v: PropertyVerifierVisitor, prop: MMLocalProperty, has_redef: Bool, visibility_level: Int) do var glob = prop.global var gbc = prop.local_class.global @@ -614,7 +762,7 @@ redef class PPropdef visibility_level = 3 end glob.visibility_level = visibility_level - if has_redef and not glob.is_init then + if has_redef then v.error(self, "Error: No property {prop.local_class}::{prop} is inherited. Remove the redef keyword to define a new property.") end if glob.is_attribute then @@ -637,26 +785,31 @@ redef class PPropdef end if prop.signature != null then # ok - else if not v.untyped_params.is_empty then - v.error(v.untyped_params.first, "Error: Untyped parameter.") + else if not v.signature_builder.untyped_params.is_empty then + v.error(v.signature_builder.untyped_params.first, "Error: Untyped parameter.") else prop.signature = new MMSignature(new Array[MMType], null, v.local_class.get_type) + if v.signature_builder.closure_decls != null then + for clos in v.signature_builder.closure_decls do + prop.signature.closures.add(clos.variable.closure) + end + end end end end - private meth inherit_signature(v: PropertyVerifierVisitor, prop: MMConcreteProperty, supers: Array[MMLocalProperty]) + private meth inherit_signature(v: PropertyVerifierVisitor, prop: MMLocalProperty, supers: Array[MMLocalProperty]) do var s = prop.signature for ip in supers do var isig = ip.signature.adaptation_to(v.local_class.get_type) if s == null then - if v.params.length != isig.arity then - prop.node.printl("v.params.length {v.params.length} != isig.arity {isig.arity} ; {prop.full_name} vs {ip.full_name}") + if v.signature_builder.params.length != isig.arity then + #prop.node.printl("v.params.length {v.params.length} != isig.arity {isig.arity} ; {prop.full_name} vs {ip.full_name}") return end - for p in v.params do + for p in v.signature_builder.params do var t = isig[p.position] p.stype = t if p.position == isig.vararg_rank then @@ -672,12 +825,12 @@ redef class PPropdef end # The part of process_and_check when prop is a redefinition - private meth do_and_check_redef(v: PropertyVerifierVisitor, prop: MMConcreteProperty, has_redef: Bool, visibility_level: Int) + private meth do_and_check_redef(v: PropertyVerifierVisitor, prop: MMLocalProperty, has_redef: Bool, visibility_level: Int) do var is_init = self isa AConcreteInitPropdef var glob = prop.global - if not has_redef and prop.name != once "init".to_symbol then + if not has_redef then v.error(self, "Redef error: {prop.local_class}::{prop} is an inherited property. To redefine it, add the redef keyword.") return end @@ -689,17 +842,21 @@ redef class PPropdef var s = prop.signature #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}" - for i in prop.cprhe.direct_greaters do + for i in prop.prhe.direct_greaters do var ip = i.local_class[prop.global] var isig = i.signature.adaptation_to(v.local_class.get_type) if s == null then #print "{prop.full_name} inherits signature from {ip.full_name}" - if v.params.length != isig.arity then + if v.signature_builder.params.length != isig.arity then v.error(self, "Redef error: {prop.local_class}::{prop} redefines {ip.local_class}::{ip} with {isig.arity} parameter(s).") return end - for p in v.params do + if v.signature_builder.closure_decls.length != isig.closures.length then + v.error(self, "Redef error: {prop.local_class}::{prop} redefines {ip.local_class}::{ip} with {isig.arity} closure(s).") + return + end + for p in v.signature_builder.params do var t = isig[p.position] p.stype = t if p.position == isig.vararg_rank then @@ -709,15 +866,18 @@ redef class PPropdef end s = isig prop.signature = s + #print "s is null" end + var nberr = v.tc.error_count + #print "Check {prop.local_class}::{prop}{s} vs {ip.local_class}::{ip}{isig}" + #print "s={s.object_id} isig={isig.object_id} isigorig={i.signature.object_id}" + #print "orig signature: {i.signature.recv} . {i.signature}" #print "inh signature: {isig.recv} . {isig}" #print "redef signature: {s.recv} . {s}" - if glob.is_init and i.local_class.global != prop.local_class.global then - # Do not check signature - else if s.arity != isig.arity then + if s.arity != isig.arity then v.error(self, "Redef error: {prop.local_class}::{prop} redefines {ip.local_class}::{ip} with {isig.arity} parameter(s).") else for i in [0..s.arity[ do @@ -735,6 +895,9 @@ redef class PPropdef v.error(self, "Redef error: The function {prop.local_class}::{prop} redefines the procedure {ip.local_class}::{ip}.") else if srt != null and isrt != null and not srt < isrt then v.error(self, "Redef error: Expected {isrt} (as in {ip.local_class}::{ip}), got {srt} in {prop.local_class}::{prop}.") + else if not s < isig and nberr == v.tc.error_count then + # Systematic fallback for conformance check + v.error(self, "Redef error: Incompatible redefinition of {ip.local_class}::{ip} with {prop.local_class}::{prop}") else if srt != null and isrt != null and srt != isrt and prop isa MMAttribute then # FIXME: To remove v.warning(self, "Redef warning: Expected {isrt} (as in {ip.local_class}::{ip}), got {srt} in {prop.local_class}::{prop}.") @@ -794,7 +957,7 @@ redef class AAttrPropdef n_type.check_visibility(v, _readmethod) end if n_writable != null then - _writemethod.signature = new MMSignature(new Array[MMType].with(t), null, v.local_class.get_type) + _writemethod.signature = new MMSignature(new Array[MMType].with_items(t), null, v.local_class.get_type) process_and_check(v, _writemethod, n_writable.n_kwredef != null, visibility_level) n_type.check_visibility(v, _writemethod) end @@ -840,17 +1003,13 @@ redef class AMethPropdef redef meth accept_property_verifier(v) do - v.params = new Array[PParam] - v.untyped_params = new Array[PParam] - v.signature = null - v.vararg_rank = -1 - + v.signature_builder = new SignatureBuilder super - if v.signature == null then + if v.signature_builder.signature == null then #_method.signature = new MMSignature(new Array[MMType], null, v.local_class.get_type) else - _method.signature = v.signature + _method.signature = v.signature_builder.signature end var visibility_level = 1 if n_visibility != null and n_visibility.level > 1 then @@ -909,7 +1068,7 @@ end # Visitor used to build a full method name from multiple tokens private class MethidAccumulator special Visitor - readable attr _name: String + readable attr _name: Buffer = new Buffer redef meth visit(n) do if n isa Token then @@ -918,11 +1077,6 @@ special Visitor n.visit_all(self) end end - - init - do - _name = new String - end end redef class PMethid @@ -933,37 +1087,40 @@ redef class PMethid do var accumulator = new MethidAccumulator accumulator.visit(self) - _name = accumulator.name.to_symbol + _name = accumulator.name.to_s.to_symbol super end end redef class PSignature # Check that visibilities of types in the signature are compatible with the visibility of the property. - meth check_visibility(v: AbsSyntaxVisitor, p: MMConcreteProperty) is abstract + meth check_visibility(v: AbsSyntaxVisitor, p: MMLocalProperty) is abstract end redef class ASignature redef meth accept_property_verifier(v) do super - if not v.untyped_params.is_empty then - if v.untyped_params.first != v.params.first or n_type != null then - v.error(v.untyped_params.first, "Syntax error: untyped parameter.") + if not v.signature_builder.untyped_params.is_empty then + if v.signature_builder.untyped_params.first != v.signature_builder.params.first or n_type != null then + v.error(v.signature_builder.untyped_params.first, "Syntax error: untyped parameter.") return end - else if not v.params.is_empty or n_type != null then + else if not v.signature_builder.params.is_empty or n_type != null then var pars = new Array[MMType] - for p in v.params do + for p in v.signature_builder.params do pars.add(p.stype) end var ret: MMType = null if n_type != null then ret = n_type.get_stype(v) end - v.signature = new MMSignature(pars, ret, v.local_class.get_type) - if v.vararg_rank >= 0 then - v.signature.vararg_rank = v.vararg_rank + v.signature_builder.signature = new MMSignature(pars, ret, v.local_class.get_type) + if v.signature_builder.vararg_rank >= 0 then + v.signature_builder.signature.vararg_rank = v.signature_builder.vararg_rank + end + for clos in v.signature_builder.closure_decls do + v.signature_builder.signature.closures.add(clos.variable.closure) end end end @@ -981,7 +1138,7 @@ end redef class PParam redef readable attr _position: Int - redef readable attr _variable: Variable + redef readable attr _variable: ParamVariable # The type of the parameter in signature readable writable attr _stype: MMType @@ -989,17 +1146,17 @@ redef class PParam redef meth accept_property_verifier(v) do super - _position = v.params.length - _variable = new Variable(n_id.to_symbol, self) - v.params.add(self) - v.untyped_params.add(self) + _position = v.signature_builder.params.length + _variable = new ParamVariable(n_id.to_symbol, self) + v.signature_builder.params.add(self) + v.signature_builder.untyped_params.add(self) if n_type != null then var stype = n_type.get_stype(v) - for p in v.untyped_params do + for p in v.signature_builder.untyped_params do p.stype = stype if is_vararg then - if v.vararg_rank == -1 then - v.vararg_rank = p.position + if v.signature_builder.vararg_rank == -1 then + v.signature_builder.vararg_rank = p.position else v.error(self, "Error: A vararg parameter is already defined.") end @@ -1007,7 +1164,7 @@ redef class PParam end p.variable.stype = stype end - v.untyped_params.clear + v.signature_builder.untyped_params.clear end end @@ -1018,9 +1175,37 @@ redef class AParam redef meth is_vararg do return n_dotdotdot != null end +redef class AClosureDecl + redef readable attr _variable: ClosureVariable + + redef meth accept_property_verifier(v) + do + var old_signature_builder = v.signature_builder + v.signature_builder = new SignatureBuilder + super + var sig = v.signature_builder.signature + if sig == null then + sig = new MMSignature(new Array[MMType], null, v.local_class.get_type) + end + if sig.return_type != null and n_kwbreak != null then + v.error(self, "Syntax Error: A break block cannot have a return value.") + end + + # Add the finalizer to the closure signature + var finalize_sig = new MMSignature(new Array[MMType], null, null) + var finalizer_clos = new MMClosure(finalize_sig, false, true) + sig.closures.add(finalizer_clos) + + var clos = new MMClosure(sig, n_kwbreak != null, n_expr != null) + v.signature_builder = old_signature_builder + old_signature_builder.closure_decls.add(self) + _variable = new ClosureVariable(n_id.to_symbol, self, clos) + end +end + redef class PType # Check that visibilities of types in the signature are compatible with the visibility of the property. - private meth check_visibility(v: AbsSyntaxVisitor, p: MMConcreteProperty) is abstract + private meth check_visibility(v: AbsSyntaxVisitor, p: MMLocalProperty) is abstract end redef class AType