vala r1740 - in trunk: . gobject vala



Author: juergbi
Date: Sun Aug 10 09:12:00 2008
New Revision: 1740
URL: http://svn.gnome.org/viewvc/vala?rev=1740&view=rev

Log:
2008-08-10  JÃrg Billeter  <j bitron ch>

	* vala/valasemanticanalyzer.vala:
	* gobject/valaccodeclassbinding.vala:
	* gobject/valaccodegenerator.vala:

	Use accessor vfuncs to implement virtual and abstract properties,
	fixes bug 508472 and bug 505966


Modified:
   trunk/ChangeLog
   trunk/gobject/valaccodeclassbinding.vala
   trunk/gobject/valaccodegenerator.vala
   trunk/vala/valasemanticanalyzer.vala

Modified: trunk/gobject/valaccodeclassbinding.vala
==============================================================================
--- trunk/gobject/valaccodeclassbinding.vala	(original)
+++ trunk/gobject/valaccodeclassbinding.vala	Sun Aug 10 09:12:00 2008
@@ -364,6 +364,26 @@
 			init_block.add_statement (new CCodeExpressionStatement (new CCodeAssignment (new CCodeMemberAccess.pointer (ccast, m.base_method.vfunc_name), new CCodeIdentifier (m.get_real_cname ()))));
 		}
 
+		/* connect overridden properties */
+		foreach (Property prop in cl.get_properties ()) {
+			if (prop.base_property == null) {
+				continue;
+			}
+			var base_type = prop.base_property.parent_symbol;
+			
+			var ccast = new CCodeFunctionCall (new CCodeIdentifier ("%s_CLASS".printf (((Class) base_type).get_upper_case_cname (null))));
+			ccast.add_argument (new CCodeIdentifier ("klass"));
+
+			if (prop.get_accessor != null) {
+				string cname = "%s_real_get_%s".printf (cl.get_lower_case_cname (null), prop.name);
+				init_block.add_statement (new CCodeExpressionStatement (new CCodeAssignment (new CCodeMemberAccess.pointer (ccast, "get_%s".printf (prop.name)), new CCodeIdentifier (cname))));
+			}
+			if (prop.set_accessor != null) {
+				string cname = "%s_real_set_%s".printf (cl.get_lower_case_cname (null), prop.name);
+				init_block.add_statement (new CCodeExpressionStatement (new CCodeAssignment (new CCodeMemberAccess.pointer (ccast, "set_%s".printf (prop.name)), new CCodeIdentifier (cname))));
+			}
+		}
+
 		if (cl.is_subtype_of (codegen.gobject_type)) {
 			/* create type, dup_func, and destroy_func properties for generic types */
 			foreach (TypeParameter type_param in cl.get_type_parameters ()) {
@@ -528,7 +548,7 @@
 			}
 			
 			var ciface = new CCodeIdentifier ("iface");
-			var cname = m.get_real_cname ();
+			string cname = m.get_real_cname ();
 			if (m.is_abstract || m.is_virtual) {
 				// FIXME results in C compiler warning
 				cname = m.get_cname ();
@@ -554,6 +574,61 @@
 			}
 		}
 
+		foreach (Property prop in cl.get_properties ()) {
+			if (prop.base_interface_property == null) {
+				continue;
+			}
+
+			var base_type = prop.base_interface_property.parent_symbol;
+			if (base_type != iface) {
+				continue;
+			}
+			
+			var ciface = new CCodeIdentifier ("iface");
+
+			if (prop.get_accessor != null) {
+				string cname = "%s_real_get_%s".printf (cl.get_lower_case_cname (null), prop.name);
+				if (prop.is_abstract || prop.is_virtual) {
+					cname = "%s_get_%s".printf (cl.get_lower_case_cname (null), prop.name);
+				}
+				init_block.add_statement (new CCodeExpressionStatement (new CCodeAssignment (new CCodeMemberAccess.pointer (ciface, "get_%s".printf (prop.name)), new CCodeIdentifier (cname))));
+			}
+			if (prop.set_accessor != null) {
+				string cname = "%s_real_set_%s".printf (cl.get_lower_case_cname (null), prop.name);
+				if (prop.is_abstract || prop.is_virtual) {
+					cname = "%s_set_%s".printf (cl.get_lower_case_cname (null), prop.name);
+				}
+				init_block.add_statement (new CCodeExpressionStatement (new CCodeAssignment (new CCodeMemberAccess.pointer (ciface, "set_%s".printf (prop.name)), new CCodeIdentifier (cname))));
+			}
+		}
+
+		foreach (Property prop in iface.get_properties ()) {
+			if (!prop.is_abstract) {
+				continue;
+			}
+
+			Property cl_prop = null;
+			var base_class = cl;
+			while (base_class != null && cl_prop == null) {
+				cl_prop = base_class.scope.lookup (prop.name) as Property;
+				base_class = base_class.base_class;
+			}
+			if (base_class != null && cl_prop.parent_symbol != cl) {
+				// property inherited from base class
+				
+				var ciface = new CCodeIdentifier ("iface");
+
+				if (prop.get_accessor != null) {
+					string cname = "%s_real_get_%s".printf (cl.get_lower_case_cname (null), prop.name);
+					init_block.add_statement (new CCodeExpressionStatement (new CCodeAssignment (new CCodeMemberAccess.pointer (ciface, "get_%s".printf (prop.name)), new CCodeIdentifier (cname))));
+				}
+				if (prop.set_accessor != null) {
+					string cname = "%s_real_set_%s".printf (cl.get_lower_case_cname (null), prop.name);
+					init_block.add_statement (new CCodeExpressionStatement (new CCodeAssignment (new CCodeMemberAccess.pointer (ciface, "set_%s".printf (prop.name)), new CCodeIdentifier (cname))));
+				}
+			}
+		}
+
 		codegen.source_type_member_definition.append (iface_init);
 	}
 	
@@ -664,16 +739,21 @@
 				continue;
 			}
 
-			bool is_virtual = prop.base_property != null || prop.base_interface_property != null;
-
 			string prefix = cl.get_lower_case_cname (null);
-			if (is_virtual) {
-				prefix += "_real";
+			CCodeExpression cself = new CCodeIdentifier ("self");
+			if (prop.base_property != null) {
+				var base_type = (Class) prop.base_property.parent_symbol;
+				prefix = base_type.get_lower_case_cname (null);
+				cself = codegen.transform_expression (cself, new ObjectType (cl), new ObjectType (base_type));
+			} else if (prop.base_interface_property != null) {
+				var base_type = (Interface) prop.base_interface_property.parent_symbol;
+				prefix = base_type.get_lower_case_cname (null);
+				cself = codegen.transform_expression (cself, new ObjectType (cl), new ObjectType (base_type));
 			}
 
 			var ccase = new CCodeCaseStatement (new CCodeIdentifier (prop.get_upper_case_cname ()));
 			var ccall = new CCodeFunctionCall (new CCodeIdentifier ("%s_get_%s".printf (prefix, prop.name)));
-			ccall.add_argument (new CCodeIdentifier ("self"));
+			ccall.add_argument (cself);
 			var csetcall = new CCodeFunctionCall ();
 			csetcall.call = get_value_setter_function (prop.property_type);
 			csetcall.add_argument (new CCodeIdentifier ("value"));
@@ -719,16 +799,21 @@
 				continue;
 			}
 
-			bool is_virtual = prop.base_property != null || prop.base_interface_property != null;
-
 			string prefix = cl.get_lower_case_cname (null);
-			if (is_virtual) {
-				prefix += "_real";
+			CCodeExpression cself = new CCodeIdentifier ("self");
+			if (prop.base_property != null) {
+				var base_type = (Class) prop.base_property.parent_symbol;
+				prefix = base_type.get_lower_case_cname (null);
+				cself = codegen.transform_expression (cself, new ObjectType (cl), new ObjectType (base_type));
+			} else if (prop.base_interface_property != null) {
+				var base_type = (Interface) prop.base_interface_property.parent_symbol;
+				prefix = base_type.get_lower_case_cname (null);
+				cself = codegen.transform_expression (cself, new ObjectType (cl), new ObjectType (base_type));
 			}
 
 			var ccase = new CCodeCaseStatement (new CCodeIdentifier (prop.get_upper_case_cname ()));
 			var ccall = new CCodeFunctionCall (new CCodeIdentifier ("%s_set_%s".printf (prefix, prop.name)));
-			ccall.add_argument (new CCodeIdentifier ("self"));
+			ccall.add_argument (cself);
 			var cgetcall = new CCodeFunctionCall ();
 			if (prop.property_type.data_type != null) {
 				cgetcall.call = new CCodeIdentifier (prop.property_type.data_type.get_get_value_function ());

Modified: trunk/gobject/valaccodegenerator.vala
==============================================================================
--- trunk/gobject/valaccodegenerator.vala	(original)
+++ trunk/gobject/valaccodegenerator.vala	Sun Aug 10 09:12:00 2008
@@ -815,14 +815,28 @@
 		var cvalueparam = new CCodeFormalParameter ("value", value_type.get_cname ());
 
 		if (prop.is_abstract || prop.is_virtual) {
+			CCodeFunctionDeclarator vdeclarator;
+
 			if (acc.readable) {
 				function = new CCodeFunction (acc.get_cname (), prop.property_type.get_cname ());
+
+				var vdecl = new CCodeDeclaration (prop.property_type.get_cname ());
+				vdeclarator = new CCodeFunctionDeclarator ("get_%s".printf (prop.name));
+				vdecl.add_declarator (vdeclarator);
+				type_struct.add_declaration (vdecl);
 			} else {
 				function = new CCodeFunction (acc.get_cname (), "void");
+
+				var vdecl = new CCodeDeclaration ("void");
+				vdeclarator = new CCodeFunctionDeclarator ("set_%s".printf (prop.name));
+				vdecl.add_declarator (vdeclarator);
+				type_struct.add_declaration (vdecl);
 			}
 			function.add_parameter (cselfparam);
+			vdeclarator.add_parameter (cselfparam);
 			if (acc.writable || acc.construction) {
 				function.add_parameter (cvalueparam);
+				vdeclarator.add_parameter (cvalueparam);
 			}
 			
 			if (!prop.is_internal_symbol () && (acc.readable || acc.writable) && acc.access != SymbolAccessibility.PRIVATE) {
@@ -836,53 +850,26 @@
 			var block = new CCodeBlock ();
 			function.block = block;
 
-			if (acc.readable) {
-				// declare temporary variable to save the property value
-				var decl = new CCodeDeclaration (prop.property_type.get_cname ());
-				decl.add_declarator (new CCodeVariableDeclarator ("value"));
-				block.add_statement (decl);
-			
-				var ccall = new CCodeFunctionCall (new CCodeIdentifier ("g_object_get"));
-			
-				var ccast = new CCodeFunctionCall (new CCodeIdentifier ("G_OBJECT"));
-				ccast.add_argument (new CCodeIdentifier ("self"));
-				ccall.add_argument (ccast);
-				
-				// property name is second argument of g_object_get
-				ccall.add_argument (prop.get_canonical_cconstant ());
-
-				ccall.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier ("value")));
-
-				ccall.add_argument (new CCodeConstant ("NULL"));
-				
-				block.add_statement (new CCodeExpressionStatement (ccall));
-
-				// HACK: decrement the refcount before returning the value to simulate a weak reference getter function
-				if (prop.property_type.data_type != null && prop.property_type.data_type.is_reference_counting ()) {
-					var unref_cond = new CCodeBinaryExpression (CCodeBinaryOperator.INEQUALITY, new CCodeIdentifier ("value"), new CCodeConstant ("NULL"));
-					var unref_function = new CCodeFunctionCall (get_destroy_func_expression (prop.property_type));
-					unref_function.add_argument (new CCodeIdentifier ("value"));
-					var unref_block = new CCodeBlock ();
-					unref_block.add_statement (new CCodeExpressionStatement (unref_function));
-					block.add_statement (new CCodeIfStatement (unref_cond, unref_block));
-				}
+			CCodeFunctionCall vcast = null;
+			if (prop.parent_symbol is Interface) {
+				var iface = (Interface) prop.parent_symbol;
 
-				block.add_statement (new CCodeReturnStatement (new CCodeIdentifier ("value")));
+				vcast = new CCodeFunctionCall (new CCodeIdentifier ("%s_GET_INTERFACE".printf (iface.get_upper_case_cname (null))));
 			} else {
-				var ccall = new CCodeFunctionCall (new CCodeIdentifier ("g_object_set"));
-			
-				var ccast = new CCodeFunctionCall (new CCodeIdentifier ("G_OBJECT"));
-				ccast.add_argument (new CCodeIdentifier ("self"));
-				ccall.add_argument (ccast);
-				
-				// property name is second argument of g_object_set
-				ccall.add_argument (prop.get_canonical_cconstant ());
+				var cl = (Class) prop.parent_symbol;
 
-				ccall.add_argument (new CCodeIdentifier ("value"));
+				vcast = new CCodeFunctionCall (new CCodeIdentifier ("%s_GET_CLASS".printf (cl.get_upper_case_cname (null))));
+			}
+			vcast.add_argument (new CCodeIdentifier ("self"));
 
-				ccall.add_argument (new CCodeConstant ("NULL"));
-				
-				block.add_statement (new CCodeExpressionStatement (ccall));
+			if (acc.readable) {
+				var vcall = new CCodeFunctionCall (new CCodeMemberAccess.pointer (vcast, "get_%s".printf (prop.name)));
+				vcall.add_argument (new CCodeIdentifier ("self"));
+				block.add_statement (new CCodeReturnStatement (vcall));
+			} else {
+				var vcall = new CCodeFunctionCall (new CCodeMemberAccess.pointer (vcast, "set_%s".printf (prop.name)));
+				vcall.add_argument (new CCodeIdentifier ("self"));
+				vcall.add_argument (new CCodeIdentifier ("value"));
 			}
 
 			source_type_member_definition.append (function);
@@ -913,10 +900,18 @@
 				function = new CCodeFunction (cname, "void");
 			}
 
+			ObjectType base_type = null;
 			if (is_virtual) {
+				if (prop.base_property != null) {
+					base_type = new ObjectType ((ObjectTypeSymbol) prop.base_property.parent_symbol);
+				} else if (prop.base_interface_property != null) {
+					base_type = new ObjectType ((ObjectTypeSymbol) prop.base_interface_property.parent_symbol);
+				}
 				function.modifiers |= CCodeModifiers.STATIC;
+				function.add_parameter (new CCodeFormalParameter ("base", base_type.get_cname ()));
+			} else {
+				function.add_parameter (cselfparam);
 			}
-			function.add_parameter (cselfparam);
 			if (returns_real_struct) {
 				// return non simple structs as out parameter
 				var coutparamname = "%s*".printf (prop.property_type.get_cname ());
@@ -940,16 +935,24 @@
 
 			function.block = (CCodeBlock) acc.body.ccodenode;
 
+			if (is_virtual) {
+				var cdecl = new CCodeDeclaration (this_type.get_cname ());
+				cdecl.add_declarator (new CCodeVariableDeclarator.with_initializer ("self", transform_expression (new CCodeIdentifier ("base"), base_type, this_type)));
+				function.block.prepend_statement (cdecl);
+			}
+
 			if (current_method_inner_error) {
 				var cdecl = new CCodeDeclaration ("GError *");
 				cdecl.add_declarator (new CCodeVariableDeclarator.with_initializer ("inner_error", new CCodeConstant ("NULL")));
 				function.block.prepend_statement (cdecl);
 			}
 
-			if (returns_real_struct) {
-				function.block.prepend_statement (create_property_type_check_statement (prop, false, t, true, "self"));
-			} else {
-				function.block.prepend_statement (create_property_type_check_statement (prop, acc.readable, t, true, "self"));
+			if (!is_virtual) {
+				if (returns_real_struct) {
+					function.block.prepend_statement (create_property_type_check_statement (prop, false, t, true, "self"));
+				} else {
+					function.block.prepend_statement (create_property_type_check_statement (prop, acc.readable, t, true, "self"));
+				}
 			}
 
 			// notify on property changes

Modified: trunk/vala/valasemanticanalyzer.vala
==============================================================================
--- trunk/vala/valasemanticanalyzer.vala	(original)
+++ trunk/vala/valasemanticanalyzer.vala	Sun Aug 10 09:12:00 2008
@@ -654,22 +654,6 @@
 			return;
 		}
 
-		/* abstract/virtual properties using reference types without
-		 * reference counting need to transfer ownership of their
-		 * return values because of limitations in the GObject property
-		 * system (g_object_get always returns strong references).
-		 * Reference counting types can simulate to return a weak
-		 * reference */
-		if ((prop.is_abstract || prop.is_virtual) &&
-		    prop.property_type.data_type != null &&
-		    prop.property_type.data_type.is_reference_type () &&
-		    !prop.property_type.data_type.is_reference_counting () &&
-		    !prop.property_type.value_owned)
-		{
-			Report.error (prop.source_reference, "%s: abstract or virtual properties using reference types not supporting reference counting, like `%s', have to mark their return value to transfer ownership.".printf (prop.get_full_name (), prop.property_type.data_type.get_full_name ()));
-			prop.error = true;
-		}
-
 		current_symbol = current_symbol.parent_symbol;
 
 		if (!prop.is_internal_symbol ()) {



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]