From: Jürg Billeter Date: Sat, 11 Oct 2008 11:03:30 +0000 (+0000) Subject: Support chaining constructors using `base' and `this' X-Git-Tag: VALA_0_4_0~32 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=bdbb1c75d3db6897c257785f3dc710985f4b7f92;p=thirdparty%2Fvala.git Support chaining constructors using `base' and `this' 2008-10-11 Jürg Billeter * vala/valaclass.vala: * vala/valacreationmethod.vala: * vala/valainterfacewriter.vala: * vala/valaobjecttype.vala: * vala/valasemanticanalyzer.vala: * vala/valastruct.vala: * gobject/valaccodeinvocationexpressionbinding.vala: * gobject/valaccodemethodbinding.vala: * gobject/valagidlwriter.vala: Support chaining constructors using `base' and `this' svn path=/trunk/; revision=1829 --- diff --git a/ChangeLog b/ChangeLog index d1d150dc7..00ffbb35c 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,17 @@ +2008-10-11 Jürg Billeter + + * vala/valaclass.vala: + * vala/valacreationmethod.vala: + * vala/valainterfacewriter.vala: + * vala/valaobjecttype.vala: + * vala/valasemanticanalyzer.vala: + * vala/valastruct.vala: + * gobject/valaccodeinvocationexpressionbinding.vala: + * gobject/valaccodemethodbinding.vala: + * gobject/valagidlwriter.vala: + + Support chaining constructors using `base' and `this' + 2008-10-11 Jürg Billeter * vala/valacfgbuilder.vala: diff --git a/gobject/valaccodeinvocationexpressionbinding.vala b/gobject/valaccodeinvocationexpressionbinding.vala index 79d9ab2e9..342263dd2 100644 --- a/gobject/valaccodeinvocationexpressionbinding.vala +++ b/gobject/valaccodeinvocationexpressionbinding.vala @@ -53,6 +53,12 @@ public class Vala.CCodeInvocationExpressionBinding : CCodeExpressionBinding { m = ((MethodType) itype).method_symbol; } else if (itype is SignalType) { ccall = (CCodeFunctionCall) expr.call.ccodenode; + } else if (itype is ObjectType) { + // constructor + var cl = (Class) ((ObjectType) itype).type_symbol; + m = cl.default_construction_method; + ccall = new CCodeFunctionCall (new CCodeIdentifier (m.get_real_cname ())); + ccall.add_argument (new CCodeIdentifier ("object_type")); } // the complete call expression, might include casts, comma expressions, and/or assignments @@ -152,6 +158,8 @@ public class Vala.CCodeInvocationExpressionBinding : CCodeExpressionBinding { param.accept (codegen); } codegen.dynamic_method_binding ((DynamicMethod) m).generate_wrapper (); + } else if (m is CreationMethod) { + ccall_expr = new CCodeAssignment (new CCodeIdentifier ("self"), new CCodeCastExpression (ccall, codegen.current_class.get_cname () + "*")); } bool ellipsis = false; diff --git a/gobject/valaccodemethodbinding.vala b/gobject/valaccodemethodbinding.vala index ae3bfd8ad..e0b2316fe 100644 --- a/gobject/valaccodemethodbinding.vala +++ b/gobject/valaccodemethodbinding.vala @@ -100,24 +100,31 @@ public class Vala.CCodeMethodBinding : CCodeBinding { if (in_gobject_creation_method && m.body != null) { var cblock = new CCodeBlock (); - // set construct properties - foreach (CodeNode stmt in m.body.get_statements ()) { - var expr_stmt = stmt as ExpressionStatement; - if (expr_stmt != null) { - var prop = expr_stmt.assigned_property (); - if (prop != null && prop.set_accessor.construction) { - if (stmt.ccodenode is CCodeFragment) { - foreach (CCodeNode cstmt in ((CCodeFragment) stmt.ccodenode).get_children ()) { - cblock.add_statement (cstmt); + if (!((CreationMethod) m).chain_up) { + // set construct properties + foreach (CodeNode stmt in m.body.get_statements ()) { + var expr_stmt = stmt as ExpressionStatement; + if (expr_stmt != null) { + var prop = expr_stmt.assigned_property (); + if (prop != null && prop.set_accessor.construction) { + if (stmt.ccodenode is CCodeFragment) { + foreach (CCodeNode cstmt in ((CCodeFragment) stmt.ccodenode).get_children ()) { + cblock.add_statement (cstmt); + } + } else { + cblock.add_statement (stmt.ccodenode); } - } else { - cblock.add_statement (stmt.ccodenode); } } } - } - add_object_creation (cblock, ((CreationMethod) m).n_construction_params > 0 || codegen.current_class.get_type_parameters ().size > 0); + add_object_creation (cblock, ((CreationMethod) m).n_construction_params > 0 || codegen.current_class.get_type_parameters ().size > 0); + } else { + var cdeclaration = new CCodeDeclaration ("%s *".printf (((Class) codegen.current_type_symbol).get_cname ())); + cdeclaration.add_declarator (new CCodeVariableDeclarator ("self")); + + cblock.add_statement (cdeclaration); + } // other initialization code foreach (CodeNode stmt in m.body.get_statements ()) { diff --git a/gobject/valagidlwriter.vala b/gobject/valagidlwriter.vala index c0c9592d0..4944ccc1a 100644 --- a/gobject/valagidlwriter.vala +++ b/gobject/valagidlwriter.vala @@ -406,13 +406,8 @@ public class Vala.GIdlWriter : CodeVisitor { return; } - string name = "new"; - if (m.name.has_prefix (".new.")) { - name = m.name.substring (5, m.name.len () - 5); - } - write_indent (); - stream.printf ("\n"); indent++; diff --git a/vala/valaclass.vala b/vala/valaclass.vala index f259ec167..6a2b712b7 100644 --- a/vala/valaclass.vala +++ b/vala/valaclass.vala @@ -318,9 +318,7 @@ public class Vala.Class : ObjectTypeSymbol { if (m is CreationMethod) { if (m.name == null) { default_construction_method = m; - m.name = ".new"; - } else { - m.name = ".new." + m.name; + m.name = "new"; } var cm = (CreationMethod) m; diff --git a/vala/valacreationmethod.vala b/vala/valacreationmethod.vala index 5cb194b7b..8336e96c9 100644 --- a/vala/valacreationmethod.vala +++ b/vala/valacreationmethod.vala @@ -45,6 +45,12 @@ public class Vala.CreationMethod : Method { */ public string? custom_return_type_cname { get; set; } + /** + * Specifies whether this constructor chains up to a base + * constructor or a different constructor of the same class. + */ + public bool chain_up { get; set; } + /** * Creates a new method. * @@ -89,10 +95,10 @@ public class Vala.CreationMethod : Method { infix = "init"; } - if (name.len () == ".new".len ()) { + if (name == "new") { return "%s%s".printf (parent.get_lower_case_cprefix (), infix); } else { - return "%s%s_%s".printf (parent.get_lower_case_cprefix (), infix, name.offset (".new.".len ())); + return "%s%s_%s".printf (parent.get_lower_case_cprefix (), infix, name); } } @@ -109,10 +115,10 @@ public class Vala.CreationMethod : Method { string infix = "construct"; - if (name.len () == ".new".len ()) { + if (name == "new") { return "%s%s".printf (parent.get_lower_case_cprefix (), infix); } else { - return "%s%s_%s".printf (parent.get_lower_case_cprefix (), infix, name.offset (".new.".len ())); + return "%s%s_%s".printf (parent.get_lower_case_cprefix (), infix, name); } } } diff --git a/vala/valainterfacewriter.vala b/vala/valainterfacewriter.vala index 85ec0dd6d..3a83a255c 100644 --- a/vala/valainterfacewriter.vala +++ b/vala/valainterfacewriter.vala @@ -815,7 +815,10 @@ public class Vala.InterfaceWriter : CodeVisitor { if (m is CreationMethod) { var datatype = (TypeSymbol) m.parent_symbol; write_identifier (datatype.name); - write_identifier (m.name.offset (".new".len ())); + if (m.name != "new") { + write_string ("."); + write_identifier (m.name); + } write_string (" "); } else if (m.binding == MemberBinding.STATIC) { write_string ("static "); diff --git a/vala/valaobjecttype.vala b/vala/valaobjecttype.vala index 953b4883b..a8aa9dd04 100644 --- a/vala/valaobjecttype.vala +++ b/vala/valaobjecttype.vala @@ -71,4 +71,31 @@ public class Vala.ObjectType : ReferenceType { return type_symbol.is_subtype_of (obj_target_type.type_symbol); } + + public override bool is_invokable () { + var cl = type_symbol as Class; + if (cl != null && cl.default_construction_method != null) { + return true; + } else { + return false; + } + } + + public override DataType? get_return_type () { + var cl = type_symbol as Class; + if (cl != null && cl.default_construction_method != null) { + return cl.default_construction_method.return_type; + } else { + return null; + } + } + + public override Gee.List? get_parameters () { + var cl = type_symbol as Class; + if (cl != null && cl.default_construction_method != null) { + return cl.default_construction_method.get_parameters (); + } else { + return null; + } + } } diff --git a/vala/valasemanticanalyzer.vala b/vala/valasemanticanalyzer.vala index 020815c85..f45c6e406 100644 --- a/vala/valasemanticanalyzer.vala +++ b/vala/valasemanticanalyzer.vala @@ -1641,11 +1641,6 @@ public class Vala.SemanticAnalyzer : CodeVisitor { if (expr.inner is MemberAccess || expr.inner is BaseAccess) { base_symbol = expr.inner.symbol_reference; - if (expr.creation_member && base_symbol is TypeSymbol) { - // check for named creation method - expr.symbol_reference = base_symbol.scope.lookup (".new." + expr.member_name); - } - if (expr.symbol_reference == null && (base_symbol is Namespace || base_symbol is TypeSymbol)) { expr.symbol_reference = base_symbol.scope.lookup (expr.member_name); if (expr.inner is BaseAccess) { @@ -1672,11 +1667,6 @@ public class Vala.SemanticAnalyzer : CodeVisitor { } } - if (expr.symbol_reference == null && expr.inner is MemberAccess && base_symbol is Struct) { - // check for named struct creation method - expr.symbol_reference = base_symbol.scope.lookup (".new." + expr.member_name); - } - if (expr.symbol_reference == null && expr.inner.value_type != null && expr.inner.value_type.is_dynamic) { // allow late bound members for dynamic types var dynamic_object_type = (ObjectType) expr.inner.value_type; @@ -1934,9 +1924,22 @@ public class Vala.SemanticAnalyzer : CodeVisitor { var mtype = expr.call.value_type; + if (mtype is ObjectType) { + // constructor chain-up + var cm = find_current_method () as CreationMethod; + assert (cm != null); + if (cm.chain_up) { + expr.error = true; + Report.error (expr.source_reference, "Multiple constructor calls in the same constructor are not permitted"); + return; + } + cm.chain_up = true; + } + // check for struct construction if (expr.call is MemberAccess && - (expr.call.symbol_reference is CreationMethod + ((expr.call.symbol_reference is CreationMethod + && expr.call.symbol_reference.parent_symbol is Struct) || expr.call.symbol_reference is Struct)) { var struct_creation_expression = new ObjectCreationExpression ((MemberAccess) expr.call, expr.source_reference); struct_creation_expression.struct_creation = true; @@ -1948,6 +1951,17 @@ public class Vala.SemanticAnalyzer : CodeVisitor { expr.parent_node.replace_expression (expr, struct_creation_expression); struct_creation_expression.accept (this); return; + } else if (expr.call is MemberAccess + && expr.call.symbol_reference is CreationMethod) { + // constructor chain-up + var cm = find_current_method () as CreationMethod; + assert (cm != null); + if (cm.chain_up) { + expr.error = true; + Report.error (expr.source_reference, "Multiple constructor calls in the same constructor are not permitted"); + return; + } + cm.chain_up = true; } Gee.List params; @@ -2673,7 +2687,11 @@ public class Vala.SemanticAnalyzer : CodeVisitor { expr.symbol_reference = constructor; - type_args = ((MemberAccess) expr.member_name.inner).get_type_arguments (); + // inner expression can also be base access when chaining constructors + var ma = expr.member_name.inner as MemberAccess; + if (ma != null) { + type_args = ma.get_type_arguments (); + } } else if (constructor_sym is ErrorCode) { type_sym = constructor_sym.parent_symbol; diff --git a/vala/valastruct.vala b/vala/valastruct.vala index 74d8297da..9e3850591 100644 --- a/vala/valastruct.vala +++ b/vala/valastruct.vala @@ -148,9 +148,7 @@ public class Vala.Struct : TypeSymbol { if (m is CreationMethod) { if (m.name == null) { default_construction_method = m; - m.name = ".new"; - } else { - m.name = ".new." + m.name; + m.name = "new"; } var cm = (CreationMethod) m;