[vala/wip/transform: 30/50] Complete the gvariant transformer



commit bfc83af234e91216fce10cad3305b4a84fb776ed
Author: Luca Bruno <lucabru src gnome org>
Date:   Tue Jan 3 15:34:48 2012 +0100

    Complete the gvariant transformer

 codegen/valagvariantmodule.vala      |  110 ----------------------------------
 codegen/valagvarianttransformer.vala |   98 +++++++++++++++++++++++++-----
 vala/valacodebuilder.vala            |   62 +++++++++++++++++++
 vala/valacodetransformer.vala        |    7 ++-
 4 files changed, 149 insertions(+), 128 deletions(-)
---
diff --git a/codegen/valagvariantmodule.vala b/codegen/valagvariantmodule.vala
index 8b08731..3684fa9 100644
--- a/codegen/valagvariantmodule.vala
+++ b/codegen/valagvariantmodule.vala
@@ -142,29 +142,6 @@ public class Vala.GVariantModule : GAsyncModule {
 		}
 	}
 
-	public override void visit_enum (Enum en) {
-		base.visit_enum (en);
-
-		if (is_string_marshalled_enum (en)) {
-			// strcmp
-			cfile.add_include ("string.h");
-
-			cfile.add_function (generate_enum_from_string_function (en));
-			cfile.add_function (generate_enum_to_string_function (en));
-		}
-	}
-
-	public override bool generate_enum_declaration (Enum en, CCodeFile decl_space) {
-		if (base.generate_enum_declaration (en, decl_space)) {
-			if (is_string_marshalled_enum (en)) {
-				decl_space.add_function_declaration (generate_enum_from_string_function_declaration (en));
-				decl_space.add_function_declaration (generate_enum_to_string_function_declaration (en));
-			}
-			return true;
-		}
-		return false;
-	}
-
 	CCodeExpression? get_array_length (CCodeExpression expr, int dim) {
 		var id = expr as CCodeIdentifier;
 		var ma = expr as CCodeMemberAccess;
@@ -195,58 +172,6 @@ public class Vala.GVariantModule : GAsyncModule {
 		return from_string_call;
 	}
 
-	public CCodeFunction generate_enum_from_string_function_declaration (Enum en) {
-		var from_string_name = "%s_from_string".printf (get_ccode_lower_case_name (en, null));
-
-		var from_string_func = new CCodeFunction (from_string_name, get_ccode_name (en));
-		from_string_func.add_parameter (new CCodeParameter ("str", "const char*"));
-		from_string_func.add_parameter (new CCodeParameter ("error", "GError**"));
-
-		return from_string_func;
-	}
-
-	public CCodeFunction generate_enum_from_string_function (Enum en) {
-		var from_string_name = "%s_from_string".printf (get_ccode_lower_case_name (en, null));
-
-		var from_string_func = new CCodeFunction (from_string_name, get_ccode_name (en));
-		from_string_func.add_parameter (new CCodeParameter ("str", "const char*"));
-		from_string_func.add_parameter (new CCodeParameter ("error", "GError**"));
-
-		push_function (from_string_func);
-
-		ccode.add_declaration (get_ccode_name (en), new CCodeVariableDeclarator.zero ("value", new CCodeConstant ("0")));
-
-		bool firstif = true;
-		foreach (EnumValue enum_value in en.get_values ()) {
-			string dbus_value = get_dbus_value (enum_value, enum_value.name);
-			var string_comparison = new CCodeFunctionCall (new CCodeIdentifier ("strcmp"));
-			string_comparison.add_argument (new CCodeIdentifier ("str"));
-			string_comparison.add_argument (new CCodeConstant ("\"%s\"".printf (dbus_value)));
-			var cond = new CCodeBinaryExpression (CCodeBinaryOperator.EQUALITY, string_comparison, new CCodeConstant ("0"));
-			if (firstif) {
-				ccode.open_if (cond);
-				firstif = false;
-			} else {
-				ccode.else_if (cond);
-			}
-			ccode.add_assignment (new CCodeIdentifier ("value"), new CCodeIdentifier (get_ccode_name (enum_value)));
-		}
-
-		ccode.add_else ();
-		var set_error = new CCodeFunctionCall (new CCodeIdentifier ("g_set_error"));
-		set_error.add_argument (new CCodeIdentifier ("error"));
-		set_error.add_argument (new CCodeIdentifier ("G_DBUS_ERROR"));
-		set_error.add_argument (new CCodeIdentifier ("G_DBUS_ERROR_INVALID_ARGS"));
-		set_error.add_argument (new CCodeConstant ("\"Invalid value for enum `%s'\"".printf (get_ccode_name (en))));
-		ccode.add_expression (set_error);
-		ccode.close ();
-
-		ccode.add_return (new CCodeIdentifier ("value"));
-
-		pop_function ();
-		return from_string_func;
-	}
-
 	CCodeExpression deserialize_basic (BasicTypeInfo basic_type, CCodeExpression variant_expr, bool transfer = false) {
 		var get_call = new CCodeFunctionCall (new CCodeIdentifier ("g_variant_get_" + basic_type.type_name));
 		get_call.add_argument (variant_expr);
@@ -523,41 +448,6 @@ public class Vala.GVariantModule : GAsyncModule {
 		return to_string_call;
 	}
 
-	public CCodeFunction generate_enum_to_string_function_declaration (Enum en) {
-		var to_string_name = "%s_to_string".printf (get_ccode_lower_case_name (en, null));
-
-		var to_string_func = new CCodeFunction (to_string_name, "const char*");
-		to_string_func.add_parameter (new CCodeParameter ("value", get_ccode_name (en)));
-
-		return to_string_func;
-	}
-
-	public CCodeFunction generate_enum_to_string_function (Enum en) {
-		var to_string_name = "%s_to_string".printf (get_ccode_lower_case_name (en, null));
-
-		var to_string_func = new CCodeFunction (to_string_name, "const char*");
-		to_string_func.add_parameter (new CCodeParameter ("value", get_ccode_name (en)));
-
-		push_function (to_string_func);
-
-		ccode.add_declaration ("const char *", new CCodeVariableDeclarator ("str"));
-
-		ccode.open_switch (new CCodeIdentifier ("value"));
-		foreach (EnumValue enum_value in en.get_values ()) {
-			string dbus_value = get_dbus_value (enum_value, enum_value.name);
-			ccode.add_case (new CCodeIdentifier (get_ccode_name (enum_value)));
-			ccode.add_assignment (new CCodeIdentifier ("str"), new CCodeConstant ("\"%s\"".printf (dbus_value)));
-			ccode.add_break ();
-		}
-
-		ccode.close();
-
-		ccode.add_return (new CCodeIdentifier ("str"));
-
-		pop_function ();
-		return to_string_func;
-	}
-
 	CCodeExpression? serialize_basic (BasicTypeInfo basic_type, CCodeExpression expr) {
 		var new_call = new CCodeFunctionCall (new CCodeIdentifier ("g_variant_new_" + basic_type.type_name));
 		new_call.add_argument (expr);
diff --git a/codegen/valagvarianttransformer.vala b/codegen/valagvarianttransformer.vala
index 170595f..686c8f8 100644
--- a/codegen/valagvarianttransformer.vala
+++ b/codegen/valagvarianttransformer.vala
@@ -45,6 +45,13 @@ public class Vala.GVariantTransformer : CodeTransformer {
 		{ "g", "signature", true }
 	};
 
+	static bool is_string_marshalled_enum (TypeSymbol? symbol) {
+		if (symbol != null && symbol is Enum) {
+			return symbol.get_attribute_bool ("DBus", "use_string_marshalling");
+		}
+		return false;
+	}
+
 	bool get_basic_type_info (string signature, out BasicTypeInfo basic_type) {
 		foreach (BasicTypeInfo info in basic_types) {
 			if (info.signature == signature) {
@@ -56,10 +63,6 @@ public class Vala.GVariantTransformer : CodeTransformer {
 		return false;
 	}
 
-	Expression expression (string str) {
-		return new Parser().parse_expression_string (str, b.source_reference);
-	}
-
 	Expression serialize_basic (BasicTypeInfo basic_type, Expression expr) {
 		var new_call = (ObjectCreationExpression) expression (@"new GLib.Variant.$(basic_type.type_name)()");
 		new_call.add_argument (expr);
@@ -70,13 +73,6 @@ public class Vala.GVariantTransformer : CodeTransformer {
 		return symbol.get_attribute_string ("DBus", "signature");
 	}
 
-	static bool is_string_marshalled_enum (TypeSymbol? symbol) {
-		if (symbol != null && symbol is Enum) {
-			return symbol.get_attribute_bool ("DBus", "use_string_marshalling");
-		}
-		return false;
-	}
-
 	public static string? get_type_signature (DataType datatype, Symbol? symbol = null) {
 		if (symbol != null) {
 			string sig = get_dbus_signature (symbol);
@@ -400,10 +396,70 @@ public class Vala.GVariantTransformer : CodeTransformer {
 		return call;
 	}
 
-	public override void visit_cast_expression (CastExpression expr) {
-		base.visit_cast_expression (expr);
+	string get_dbus_value (EnumValue value, string default_value) {
+		var dbus_value = value.get_attribute_string ("DBus", "value");
+		if (dbus_value != null) {
+			return dbus_value;;
+		}
+		return default_value;
+	}
 
+	void add_enum_from_string_method (Enum en) {
+		if (en.scope.lookup ("from_string") != null) {
+			return;
+		}
+		var m = new Method ("from_string", context.analyzer.get_data_type_for_symbol (en), en.source_reference);
+		m.add_error_type (data_type ("GLib.DBusError.INVALID_ARGS"));
+		m.add_parameter (new Parameter ("str", data_type ("string", false), en.source_reference));
+		en.add_method (m);
+		m.binding = MemberBinding.STATIC;
+		m.access = SymbolAccessibility.PUBLIC;
+		b = new CodeBuilder.for_method (m);
+
+		b.open_switch (expression ("str"), null);
+		b.add_throw (expression ("new GLib.DBusError.INVALID_ARGS (\"Invalid value for enum `%s'\")".printf (CCodeBaseModule.get_ccode_name (en))));
+		foreach (var enum_value in en.get_values ()) {
+			string dbus_value = get_dbus_value (enum_value, enum_value.name);
+			b.add_section (expression (@"\"$dbus_value\""));
+			b.add_return (expression (@"$(en.get_full_name()).$(enum_value.name)"));
+		}
+		b.close ();
+
+		check (m);
+	}
+
+	void add_enum_to_string_method (Enum en) {
+		if (en.scope.lookup ("to_string") != null) {
+			return;
+		}
+		var m = new Method ("to_string", data_type ("string", false, true), en.source_reference);
+		en.add_method (m);
+		m.access = SymbolAccessibility.PUBLIC;
+		b = new CodeBuilder.for_method (m);
+
+		b.open_switch (expression ("this"), null);
+		b.add_return (expression ("null"));
+		foreach (var enum_value in en.get_values ()) {
+			string dbus_value = get_dbus_value (enum_value, enum_value.name);
+			b.add_section (expression (@"$(en.get_full_name()).$(enum_value.name)"));
+			b.add_return (expression (@"\"$dbus_value\""));
+		}
+		b.close ();
+
+		check (m);
+	}
+
+	public override void visit_enum (Enum en) {
+		if (!en.external && is_string_marshalled_enum (en) && context.has_package ("gio-2.0")) {
+			add_enum_from_string_method (en);
+			add_enum_to_string_method (en);
+		}
+		base.visit_enum (en);
+	}
+
+	public override void visit_cast_expression (CastExpression expr) {
 		if (!(expr.inner.value_type.data_type == context.analyzer.gvariant_type.data_type && expr.type_reference.data_type != context.analyzer.gvariant_type.data_type)) {
+			base.visit_cast_expression (expr);
 			return;
 		}
 
@@ -414,7 +470,13 @@ public class Vala.GVariantTransformer : CodeTransformer {
 
 		BasicTypeInfo basic_type;
 		Expression result = null;
-		if (get_basic_type_info (get_type_signature (type), out basic_type)) {
+		if (is_string_marshalled_enum (type.data_type)) {
+			get_basic_type_info ("s", out basic_type);
+			result = deserialize_basic (basic_type, expr.inner);
+			var call = (MethodCall) expression (@"$(type.data_type.get_full_name()).from_string ()");
+			call.add_argument (result);
+			result = call;
+		} else if (get_basic_type_info (get_type_signature (type), out basic_type)) {
 			result = deserialize_basic (basic_type, expr.inner);
 		} else if (type is ArrayType) {
 			result = deserialize_array ((ArrayType) type, expr.inner);
@@ -436,10 +498,9 @@ public class Vala.GVariantTransformer : CodeTransformer {
 	}
 
 	public override void visit_expression (Expression expr) {
-		base.visit_expression (expr);
-
 		if (!(context.profile == Profile.GOBJECT && expr.target_type != null && expr.target_type.data_type == context.analyzer.gvariant_type.data_type && !(expr.value_type is NullType) && expr.value_type.data_type != context.analyzer.gvariant_type.data_type)) {
 			// no implicit gvariant boxing
+			base.visit_expression (expr);
 			return;
 		}
 
@@ -450,7 +511,10 @@ public class Vala.GVariantTransformer : CodeTransformer {
 
 		BasicTypeInfo basic_type;
 		Expression result = null;
-		if (get_basic_type_info (get_type_signature (type), out basic_type)) {
+		if (is_string_marshalled_enum (type.data_type)) {
+			get_basic_type_info ("s", out basic_type);
+			result = new MethodCall (new MemberAccess (expr, "to_string"), b.source_reference);
+		} else if (get_basic_type_info (get_type_signature (type), out basic_type)) {
 			result = serialize_basic (basic_type, expr);
 		} else if (type is ArrayType) {
 			result = serialize_array ((ArrayType) type, expr);
diff --git a/vala/valacodebuilder.vala b/vala/valacodebuilder.vala
index b981bf2..ec7d370 100644
--- a/vala/valacodebuilder.vala
+++ b/vala/valacodebuilder.vala
@@ -48,6 +48,14 @@ public class Vala.CodeBuilder {
 		build_context.check_nodes.add (build_context.current_block);
 	}
 
+	public CodeBuilder.for_method (Method m) {
+		source_reference = m.source_reference;
+		build_context = new BuildContext ();
+		build_context.insert_block = m.body = new Block (source_reference);
+		build_context.insert_statement = build_context.current_block = new Block (source_reference);
+		m.body.add_statement (build_context.current_block);
+	}
+
 	public void check (CodeTransformer transformer) {
 		foreach (var node in build_context.check_nodes) {
 			transformer.check (node);
@@ -138,6 +146,56 @@ public class Vala.CodeBuilder {
 		parent_block.add_statement (stmt);
 	}
 
+	public void open_switch (Expression expression, Expression? first_label) {
+		var parent_block = build_context.current_block;
+
+		var stmt = new SwitchStatement (expression, source_reference);
+		build_context.statement_stack.add (stmt);
+
+		var section = new SwitchSection (source_reference);
+		SwitchLabel label;
+		if (first_label == null) {
+			label = new SwitchLabel.with_default (source_reference);
+		} else {
+			label = new SwitchLabel (first_label);
+		}
+		section.add_label (label);
+		build_context.current_block = section;
+		build_context.statement_stack.add (section);
+
+		parent_block.add_statement (stmt);
+		stmt.add_section (section);
+	}
+
+	public void add_section (Expression? expression) {
+		build_context.statement_stack.remove_at (build_context.statement_stack.size - 1);
+
+		var stmt = (SwitchStatement) build_context.statement_stack[build_context.statement_stack.size - 1];
+		var section = new SwitchSection (source_reference);
+		SwitchLabel label;
+		if (expression == null) {
+			label = new SwitchLabel.with_default (source_reference);
+		} else {
+			label = new SwitchLabel (expression);
+		}
+		section.add_label (label);
+		build_context.current_block = section;
+		build_context.statement_stack.add (section);
+
+		stmt.add_section (section);	
+	}
+
+	public void add_label (Expression? expression) {
+		var section = (SwitchSection) build_context.statement_stack[build_context.statement_stack.size - 1];
+		SwitchLabel label;
+		if (expression == null) {
+			label = new SwitchLabel.with_default (source_reference);
+		} else {
+			label = new SwitchLabel (expression);
+		}
+		section.add_label (label);
+	}
+
 	public void add_statement (Statement statement) {
 		build_context.current_block.add_statement (statement);
 	}
@@ -150,6 +208,10 @@ public class Vala.CodeBuilder {
 		add_expression (new Assignment (left, right, AssignmentOperator.SIMPLE, source_reference));
 	}
 
+	public void add_throw (Expression expression) {
+		add_statement (new ThrowStatement (expression, source_reference));
+	}
+
 	public void add_return (Expression? expression = null) {
 		add_statement (new ReturnStatement (expression, source_reference));
 	}
diff --git a/vala/valacodetransformer.vala b/vala/valacodetransformer.vala
index fcca37b..f79edca 100644
--- a/vala/valacodetransformer.vala
+++ b/vala/valacodetransformer.vala
@@ -86,12 +86,17 @@ public class Vala.CodeTransformer : CodeVisitor {
 	}
 
 	// only qualified types, will slightly simplify the work of SymbolResolver
-	public DataType data_type (string s, bool value_owned = true) {
+	public DataType data_type (string s, bool value_owned = true, bool nullable = false) {
 		DataType type = context.analyzer.get_data_type_for_symbol ((TypeSymbol) symbol_from_string (s));
 		type.value_owned = value_owned;
+		type.nullable = nullable;
 		return type;
 	}
 
+	public Expression expression (string str) {
+		return new Parser().parse_expression_string (str, b.source_reference);
+	}
+
 	public void check (CodeNode node) {
 		node.accept (context.resolver);
 		if (!node.check (context)) {



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