From: Juerg Billeter Date: Sun, 18 May 2008 16:57:27 +0000 (+0000) Subject: Add support for dynamic properties X-Git-Tag: VALA_0_3_3~160 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=414ff72391eee8ca23b00883b71350e0e83b31ca;p=platform%2Fupstream%2Fvala.git Add support for dynamic properties 2008-05-18 Juerg Billeter * vala/Makefile.am: * vala/valacodegenerator.vala: * vala/valadynamicproperty.vala: * vala/valasemanticanalyzer.vala: * gobject/Makefile.am: * gobject/valaccodedynamicmethodbinding.vala: * gobject/valaccodedynamicpropertybinding.vala: * gobject/valaccodegenerator.vala: * gobject/valaccodememberaccessbinding.vala: Add support for dynamic properties svn path=/trunk/; revision=1398 --- diff --git a/ChangeLog b/ChangeLog index d4e6190..bb95386 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,17 @@ +2008-05-18 Jürg Billeter + + * vala/Makefile.am: + * vala/valacodegenerator.vala: + * vala/valadynamicproperty.vala: + * vala/valasemanticanalyzer.vala: + * gobject/Makefile.am: + * gobject/valaccodedynamicmethodbinding.vala: + * gobject/valaccodedynamicpropertybinding.vala: + * gobject/valaccodegenerator.vala: + * gobject/valaccodememberaccessbinding.vala: + + Add support for dynamic properties + 2008-05-17 Jürg Billeter * vapi/glib-2.0.vapi: fix typo in GSpawnFlags binding, diff --git a/gobject/Makefile.am b/gobject/Makefile.am index 6a0d9d1..8d5c11a 100644 --- a/gobject/Makefile.am +++ b/gobject/Makefile.am @@ -19,6 +19,7 @@ libvala_la_VALASOURCES = \ valaccodecompiler.vala \ valaccodecreationmethodbinding.vala \ valaccodedynamicmethodbinding.vala \ + valaccodedynamicpropertybinding.vala \ valaccodedynamicsignalbinding.vala \ valaccodeelementaccessbinding.vala \ valaccodeexpressionbinding.vala \ diff --git a/gobject/valaccodedynamicmethodbinding.vala b/gobject/valaccodedynamicmethodbinding.vala index aff92b1..17a2f24 100644 --- a/gobject/valaccodedynamicmethodbinding.vala +++ b/gobject/valaccodedynamicmethodbinding.vala @@ -39,7 +39,7 @@ public class Vala.CCodeDynamicMethodBinding : CCodeMethodBinding { var cparam_map = new HashMap (direct_hash, direct_equal); - var instance_param = new CCodeFormalParameter ("obj", "gpointer"); + var instance_param = new CCodeFormalParameter ("obj", dynamic_method.dynamic_type.get_cname ()); cparam_map.set (codegen.get_param_pos (method.cinstance_parameter_position), instance_param); generate_cparameters (method, method.return_type, cparam_map, func); diff --git a/gobject/valaccodedynamicpropertybinding.vala b/gobject/valaccodedynamicpropertybinding.vala new file mode 100644 index 0000000..d0c37a4 --- /dev/null +++ b/gobject/valaccodedynamicpropertybinding.vala @@ -0,0 +1,92 @@ +/* valaccodedynamicpropertybinding.vala + * + * Copyright (C) 2008 Jürg Billeter + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Author: + * Jürg Billeter + */ + +using GLib; +using Gee; + +/** + * The link between a dynamic property and generated code. + */ +public class Vala.CCodeDynamicPropertyBinding : CCodeBinding { + public Property node { get; set; } + + string? getter_cname; + string? setter_cname; + + static int dynamic_property_id; + + public CCodeDynamicPropertyBinding (CCodeGenerator codegen, DynamicProperty property) { + this.node = property; + this.codegen = codegen; + } + + public string get_getter_cname () { + if (getter_cname != null) { + return getter_cname; + } + + getter_cname = "_dynamic_get_%s%d".printf (node.name, dynamic_property_id++); + + var dynamic_property = (DynamicProperty) node; + + var func = new CCodeFunction (getter_cname, node.property_type.get_cname ()); + + func.add_parameter (new CCodeFormalParameter ("obj", dynamic_property.dynamic_type.get_cname ())); + + var block = new CCodeBlock (); + Report.error (node.source_reference, "dynamic properties are not supported for `%s'".printf (dynamic_property.dynamic_type.to_string ())); + + // append to C source file + codegen.source_type_member_declaration.append (func.copy ()); + + func.block = block; + codegen.source_type_member_definition.append (func); + + return getter_cname; + } + + public string get_setter_cname () { + if (setter_cname != null) { + return setter_cname; + } + + getter_cname = "_dynamic_set_%s%d".printf (node.name, dynamic_property_id++); + + var dynamic_property = (DynamicProperty) node; + + var func = new CCodeFunction (getter_cname, "void"); + + func.add_parameter (new CCodeFormalParameter ("obj", dynamic_property.dynamic_type.get_cname ())); + func.add_parameter (new CCodeFormalParameter ("value", node.property_type.get_cname ())); + + var block = new CCodeBlock (); + Report.error (node.source_reference, "dynamic properties are not supported for `%s'".printf (dynamic_property.dynamic_type.to_string ())); + + // append to C source file + codegen.source_type_member_declaration.append (func.copy ()); + + func.block = block; + codegen.source_type_member_definition.append (func); + + return getter_cname; + } +} diff --git a/gobject/valaccodegenerator.vala b/gobject/valaccodegenerator.vala index 5882af3..2eb4988 100644 --- a/gobject/valaccodegenerator.vala +++ b/gobject/valaccodegenerator.vala @@ -3629,6 +3629,9 @@ public class Vala.CCodeGenerator : CodeGenerator { } var base_property_type = (Typesymbol) base_property.parent_symbol; set_func = "%s_set_%s".printf (base_property_type.get_lower_case_cname (null), base_property.name); + if (prop is DynamicProperty) { + set_func = dynamic_property_binding ((DynamicProperty) prop).get_setter_cname (); + } } var ccall = new CCodeFunctionCall (new CCodeIdentifier (set_func)); @@ -3875,6 +3878,10 @@ public class Vala.CCodeGenerator : CodeGenerator { return null; } + public override CodeBinding? create_dynamic_property_binding (DynamicProperty node) { + return new CCodeDynamicPropertyBinding (this, node); + } + public override CodeBinding? create_property_accessor_binding (PropertyAccessor node) { return null; } @@ -4103,6 +4110,10 @@ public class Vala.CCodeGenerator : CodeGenerator { return (CCodeDynamicMethodBinding) node.get_code_binding (this); } + public CCodeDynamicPropertyBinding dynamic_property_binding (DynamicProperty node) { + return (CCodeDynamicPropertyBinding) node.get_code_binding (this); + } + public CCodeDynamicSignalBinding dynamic_signal_binding (DynamicSignal node) { return (CCodeDynamicSignalBinding) node.get_code_binding (this); } diff --git a/gobject/valaccodememberaccessbinding.vala b/gobject/valaccodememberaccessbinding.vala index ef1408c..83126df 100644 --- a/gobject/valaccodememberaccessbinding.vala +++ b/gobject/valaccodememberaccessbinding.vala @@ -131,7 +131,13 @@ public class Vala.CCodeMemberAccessBinding : CCodeExpressionBinding { base_property = prop.base_interface_property; } var base_property_type = (Typesymbol) base_property.parent_symbol; - var ccall = new CCodeFunctionCall (new CCodeIdentifier ("%s_get_%s".printf (base_property_type.get_lower_case_cname (null), base_property.name))); + string getter_cname; + if (prop is DynamicProperty) { + getter_cname = codegen.dynamic_property_binding ((DynamicProperty) prop).get_getter_cname (); + } else { + getter_cname = "%s_get_%s".printf (base_property_type.get_lower_case_cname (null), base_property.name); + } + var ccall = new CCodeFunctionCall (new CCodeIdentifier (getter_cname)); var instance_expression_type = base_type; var instance_target_type = codegen.get_data_type_for_symbol (base_property_type); diff --git a/vala/Makefile.am b/vala/Makefile.am index 9d4bf4b..89aa6e8 100644 --- a/vala/Makefile.am +++ b/vala/Makefile.am @@ -54,6 +54,7 @@ libvalacore_la_VALASOURCES = \ valadestructor.vala \ valadostatement.vala \ valadynamicmethod.vala \ + valadynamicproperty.vala \ valadynamicsignal.vala \ valaelementaccess.vala \ valaemptystatement.vala \ diff --git a/vala/valacodegenerator.vala b/vala/valacodegenerator.vala index 3367e83..2a35272 100644 --- a/vala/valacodegenerator.vala +++ b/vala/valacodegenerator.vala @@ -98,6 +98,10 @@ public class Vala.CodeGenerator : CodeVisitor { return null; } + public virtual CodeBinding? create_dynamic_property_binding (DynamicProperty node) { + return null; + } + public virtual CodeBinding? create_property_accessor_binding (PropertyAccessor node) { return null; } diff --git a/vala/valadynamicproperty.vala b/vala/valadynamicproperty.vala new file mode 100644 index 0000000..ea76ca5 --- /dev/null +++ b/vala/valadynamicproperty.vala @@ -0,0 +1,47 @@ +/* valadynamicproperty.vala + * + * Copyright (C) 2008 Jürg Billeter + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Author: + * Jürg Billeter + */ + +using GLib; +using Gee; + +/** + * Represents a late bound property. + */ +public class Vala.DynamicProperty : Property { + public DataType dynamic_type { get; set; } + + private string cname; + + public DynamicProperty (DataType dynamic_type, string name, SourceReference? source_reference = null) { + this.dynamic_type = dynamic_type; + this.name = name; + this.source_reference = source_reference; + } + + public override Collection get_cheader_filenames () { + return new ReadOnlyCollection (); + } + + public override CodeBinding? create_code_binding (CodeGenerator codegen) { + return codegen.create_dynamic_property_binding (this); + } +} diff --git a/vala/valasemanticanalyzer.vala b/vala/valasemanticanalyzer.vala index d3a8e64..02c3989 100644 --- a/vala/valasemanticanalyzer.vala +++ b/vala/valasemanticanalyzer.vala @@ -1380,9 +1380,11 @@ public class Vala.SemanticAnalyzer : CodeVisitor { return c.type_reference; } else if (sym is Property) { var prop = (Property) sym; - var type = prop.property_type.copy (); - type.value_owned = false; - return type; + if (prop.property_type != null) { + var type = prop.property_type.copy (); + type.value_owned = false; + return type; + } } else if (sym is FormalParameter) { var p = (FormalParameter) sym; var type = p.parameter_type.copy (); @@ -1587,32 +1589,65 @@ public class Vala.SemanticAnalyzer : CodeVisitor { // allow late bound members for dynamic types if (expr.parent_node is InvocationExpression) { var invoc = (InvocationExpression) expr.parent_node; - DataType ret_type; - if (invoc.expected_type != null) { - ret_type = invoc.expected_type.copy (); - ret_type.value_owned = true; - } else { - ret_type = new VoidType (); + if (invoc.call == expr) { + // dynamic method + DataType ret_type; + if (invoc.expected_type != null) { + ret_type = invoc.expected_type.copy (); + ret_type.value_owned = true; + } else if (invoc.parent_node is ExpressionStatement) { + ret_type = new VoidType (); + } else { + // expect dynamic object of the same type + ret_type = expr.inner.value_type.copy (); + } + var m = new DynamicMethod (expr.inner.value_type, expr.member_name, ret_type, expr.source_reference); + m.invocation = invoc; + m.add_error_domain (new ErrorType (null)); + m.access = SymbolAccessibility.PUBLIC; + m.add_parameter (new FormalParameter.with_ellipsis ()); + context.add_dynamic_member (m); + expr.symbol_reference = m; } - var m = new DynamicMethod (expr.inner.value_type, expr.member_name, ret_type, expr.source_reference); - m.invocation = invoc; - m.add_error_domain (new ErrorType (null)); - m.access = SymbolAccessibility.PUBLIC; - m.add_parameter (new FormalParameter.with_ellipsis ()); - context.add_dynamic_member (m); - expr.symbol_reference = m; } else if (expr.parent_node is Assignment) { var a = (Assignment) expr.parent_node; if (a.left == expr && (a.operator == AssignmentOperator.ADD || a.operator == AssignmentOperator.SUB)) { + // dynamic signal var s = new DynamicSignal (expr.inner.value_type, expr.member_name, new VoidType (), expr.source_reference); s.handler = a.right; s.access = SymbolAccessibility.PUBLIC; context.add_dynamic_member (s); expr.symbol_reference = s; + } else if (a.left == expr) { + // dynamic property assignment + var prop = new DynamicProperty (expr.inner.value_type, expr.member_name, expr.source_reference); + prop.access = SymbolAccessibility.PUBLIC; + prop.set_accessor = new PropertyAccessor (false, true, false, null, null); + prop.set_accessor.access = SymbolAccessibility.PUBLIC; + prop.owner = expr.inner.value_type.data_type.scope; + context.add_dynamic_member (prop); + expr.symbol_reference = prop; } } + if (expr.symbol_reference == null) { + // dynamic property read access + var prop = new DynamicProperty (expr.inner.value_type, expr.member_name, expr.source_reference); + if (expr.expected_type != null) { + prop.property_type = expr.expected_type; + } else { + // expect dynamic object of the same type + prop.property_type = expr.inner.value_type.copy (); + } + prop.access = SymbolAccessibility.PUBLIC; + prop.get_accessor = new PropertyAccessor (true, false, false, null, null); + prop.get_accessor.access = SymbolAccessibility.PUBLIC; + prop.owner = expr.inner.value_type.data_type.scope; + // maybe better move add_dynamic_member to Symbol class + context.add_dynamic_member (prop); + expr.symbol_reference = prop; + } if (expr.symbol_reference != null) { may_access_instance_members = true; } @@ -2970,7 +3005,7 @@ public class Vala.SemanticAnalyzer : CodeVisitor { if (a.left is MemberAccess) { var ma = (MemberAccess) a.left; - if (!(ma.symbol_reference is Signal) && ma.value_type == null) { + if (!(ma.symbol_reference is Signal || ma.symbol_reference is DynamicProperty) && ma.value_type == null) { a.error = true; Report.error (a.source_reference, "unsupported lvalue in assignment"); return; @@ -3069,6 +3104,12 @@ public class Vala.SemanticAnalyzer : CodeVisitor { } else if (ma.symbol_reference is Property) { var prop = (Property) ma.symbol_reference; + var dynamic_prop = prop as DynamicProperty; + if (dynamic_prop != null) { + dynamic_prop.property_type = a.right.value_type.copy (); + a.left.value_type = dynamic_prop.property_type.copy (); + } + if (prop.set_accessor == null || (!prop.set_accessor.writable && !(find_current_method () is CreationMethod || is_in_constructor ()))) { ma.error = true;