+2008-05-18 Jürg Billeter <j@bitron.ch>
+
+ * 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 <j@bitron.ch>
* vapi/glib-2.0.vapi: fix typo in GSpawnFlags binding,
valaccodecompiler.vala \
valaccodecreationmethodbinding.vala \
valaccodedynamicmethodbinding.vala \
+ valaccodedynamicpropertybinding.vala \
valaccodedynamicsignalbinding.vala \
valaccodeelementaccessbinding.vala \
valaccodeexpressionbinding.vala \
var cparam_map = new HashMap<int,CCodeFormalParameter> (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);
--- /dev/null
+/* 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 <j@bitron.ch>
+ */
+
+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;
+ }
+}
}
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));
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;
}
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);
}
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);
valadestructor.vala \
valadostatement.vala \
valadynamicmethod.vala \
+ valadynamicproperty.vala \
valadynamicsignal.vala \
valaelementaccess.vala \
valaemptystatement.vala \
return null;
}
+ public virtual CodeBinding? create_dynamic_property_binding (DynamicProperty node) {
+ return null;
+ }
+
public virtual CodeBinding? create_property_accessor_binding (PropertyAccessor node) {
return null;
}
--- /dev/null
+/* 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 <j@bitron.ch>
+ */
+
+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<string> get_cheader_filenames () {
+ return new ReadOnlyCollection<string> ();
+ }
+
+ public override CodeBinding? create_code_binding (CodeGenerator codegen) {
+ return codegen.create_dynamic_property_binding (this);
+ }
+}
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 ();
// 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;
}
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;
} 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;