From: Luca Bruno Date: Tue, 3 Jan 2012 14:34:48 +0000 (+0100) Subject: Complete the gvariant transformer X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=1f6c751cc47bce3f7eb57cadfe4c037ff1797690;p=thirdparty%2Fvala.git Complete the gvariant transformer --- diff --git a/codegen/valagvariantmodule.vala b/codegen/valagvariantmodule.vala index 061b8f5ab..5757e3525 100644 --- a/codegen/valagvariantmodule.vala +++ b/codegen/valagvariantmodule.vala @@ -144,32 +144,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"); - - // for G_DBUS_ERROR - cfile.add_include ("gio/gio.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; @@ -200,58 +174,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); @@ -569,41 +491,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 a46ec210f..3d1fad917 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) { if (signature != null) { foreach (BasicTypeInfo info in basic_types) { @@ -58,10 +65,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); @@ -72,13 +75,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); @@ -402,10 +398,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 (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; } @@ -416,7 +472,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); @@ -438,10 +500,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; } @@ -452,7 +513,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 cf2058e70..ed52b08c3 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 79b42a86e..ff4947f3a 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)) {