diff options
author | Juerg Billeter <j@bitron.ch> | 2007-09-15 21:43:43 +0000 |
---|---|---|
committer | Jürg Billeter <juergbi@src.gnome.org> | 2007-09-15 21:43:43 +0000 |
commit | 420527fb1ddd2d9ea40f169479f535e7f3d5e1de (patch) | |
tree | 8c635016181075ee7b155849a96cd3f5461f08d6 | |
parent | 087945bcf71247fbba63bd92cc232c8e0d009b8a (diff) | |
download | vala-420527fb1ddd2d9ea40f169479f535e7f3d5e1de.tar.gz |
add support for object initializers
2007-09-15 Juerg Billeter <j@bitron.ch>
* vala/Makefile.am, vala/parser.y, vala/valamemberinitializer.vala,
vala/valaobjectcreationexpression.vala,
vala/valasemanticanalyzer.vala, gobject/valacodegenerator.vala: add
support for object initializers
* tests/classes.exp, tests/classes.vala, tests/structs.exp,
tests/structs.vala: test object initializers with classes and structs
svn path=/trunk/; revision=609
-rw-r--r-- | ChangeLog | 10 | ||||
-rw-r--r-- | gobject/valacodegenerator.vala | 48 | ||||
-rw-r--r-- | tests/classes.exp | 2 | ||||
-rw-r--r-- | tests/classes.vala | 11 | ||||
-rw-r--r-- | tests/structs.exp | 2 | ||||
-rw-r--r-- | tests/structs.vala | 10 | ||||
-rw-r--r-- | vala/Makefile.am | 4 | ||||
-rw-r--r-- | vala/parser.y | 62 | ||||
-rw-r--r-- | vala/valamemberinitializer.vala | 60 | ||||
-rw-r--r-- | vala/valaobjectcreationexpression.vala | 31 | ||||
-rw-r--r-- | vala/valasemanticanalyzer.vala | 32 |
11 files changed, 256 insertions, 16 deletions
@@ -1,5 +1,15 @@ 2007-09-15 Jürg Billeter <j@bitron.ch> + * vala/Makefile.am, vala/parser.y, vala/valamemberinitializer.vala, + vala/valaobjectcreationexpression.vala, + vala/valasemanticanalyzer.vala, gobject/valacodegenerator.vala: add + support for object initializers + + * tests/classes.exp, tests/classes.vala, tests/structs.exp, + tests/structs.vala: test object initializers with classes and structs + +2007-09-15 Jürg Billeter <j@bitron.ch> + * vala/valainterfacewriter.vala, vala/valamethod.vala, vala/valasemanticanalyzer.vala, vala/valastruct.vala, gobject/valacodegenerator.vala, diff --git a/gobject/valacodegenerator.vala b/gobject/valacodegenerator.vala index 3c8b0befe..82b3f823a 100644 --- a/gobject/valacodegenerator.vala +++ b/gobject/valacodegenerator.vala @@ -2408,15 +2408,15 @@ public class Vala.CodeGenerator : CodeVisitor { } public override void visit_end_object_creation_expression (ObjectCreationExpression! expr) { - CCodeExpression struct_instance = null; + CCodeExpression instance = null; CCodeFunctionCall creation_call = null; - if (expr.type_reference.data_type is Struct) { - // value-type initialization + if (expr.type_reference.data_type is Struct || expr.get_object_initializer ().size > 0) { + // value-type initialization or object creation expression with object initializer var temp_decl = get_temp_variable_declarator (expr.type_reference, false, expr); temp_vars.add (temp_decl); - struct_instance = new CCodeIdentifier (get_variable_cname (temp_decl.name)); + instance = new CCodeIdentifier (get_variable_cname (temp_decl.name)); } if (expr.symbol_reference == null) { @@ -2437,7 +2437,7 @@ public class Vala.CodeGenerator : CodeVisitor { // memset needs string.h string_h_needed = true; creation_call = new CCodeFunctionCall (new CCodeIdentifier ("memset")); - creation_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, struct_instance)); + creation_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, instance)); creation_call.add_argument (new CCodeConstant ("0")); creation_call.add_argument (new CCodeIdentifier ("sizeof (%s)".printf (expr.type_reference.get_cname ()))); } @@ -2448,8 +2448,8 @@ public class Vala.CodeGenerator : CodeVisitor { creation_call = new CCodeFunctionCall (new CCodeIdentifier (m.get_cname ())); - if (struct_instance != null) { - creation_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, struct_instance)); + if (expr.type_reference.data_type is Struct) { + creation_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, instance)); } if (expr.type_reference.data_type is Class && expr.type_reference.data_type.is_subtype_of (gobject_type)) { @@ -2530,10 +2530,38 @@ public class Vala.CodeGenerator : CodeVisitor { assert (false); } - if (expr.type_reference.data_type is Struct) { + if (instance != null) { var ccomma = new CCodeCommaExpression (); - ccomma.append_expression (creation_call); - ccomma.append_expression (struct_instance); + + if (expr.type_reference.data_type is Struct) { + ccomma.append_expression (creation_call); + } else { + ccomma.append_expression (new CCodeAssignment (instance, creation_call)); + } + + foreach (MemberInitializer init in expr.get_object_initializer ()) { + if (init.symbol_reference is Field) { + var f = (Field) init.symbol_reference; + var instance_target_type = new TypeReference (); + instance_target_type.data_type = (DataType) f.parent_symbol; + var typed_inst = get_implicit_cast_expression (instance, expr.type_reference, instance_target_type); + CCodeExpression lhs; + if (expr.type_reference.data_type is Struct) { + lhs = new CCodeMemberAccess (typed_inst, f.get_cname ()); + } else { + lhs = new CCodeMemberAccess.pointer (typed_inst, f.get_cname ()); + } + ccomma.append_expression (new CCodeAssignment (lhs, (CCodeExpression) init.initializer.ccodenode)); + } else if (init.symbol_reference is Property) { + var inst_ma = new MemberAccess.simple ("new"); + inst_ma.static_type = expr.type_reference; + inst_ma.ccodenode = instance; + var ma = new MemberAccess (inst_ma, init.name); + ccomma.append_expression (get_property_set_call ((Property) init.symbol_reference, ma, (CCodeExpression) init.initializer.ccodenode)); + } + } + + ccomma.append_expression (instance); expr.ccodenode = ccomma; } else if (creation_call != null) { diff --git a/tests/classes.exp b/tests/classes.exp index aacc7636b..645de25b0 100644 --- a/tests/classes.exp +++ b/tests/classes.exp @@ -11,4 +11,6 @@ new DerivedGObjectClass () new PublicGObjectClass () new GObjectClassWithCreationMethod () new GObjectClassWithNamedCreationMethod () +new SimpleClass () { field = 1 } +simple_class.field = 1 . diff --git a/tests/classes.vala b/tests/classes.vala index 77c4a4c1b..ccf561047 100644 --- a/tests/classes.vala +++ b/tests/classes.vala @@ -1,15 +1,18 @@ using GLib; class SimpleClass { + public int field; } class DerivedClass : SimpleClass { } public class PublicClass { + public int field; } abstract class AbstractClass { + public int field; } static class StaticClass { @@ -19,12 +22,16 @@ class ClassWithCreationMethod { public ClassWithCreationMethod () { stdout.printf ("ClassWithCreationMethod\n"); } + + public int field; } class ClassWithNamedCreationMethod { public ClassWithNamedCreationMethod.named () { stdout.printf ("ClassWithNamedCreationMethod\n"); } + + public int field; } class SimpleGObjectClass : Object { @@ -75,6 +82,10 @@ static class ClassesTest { stdout.printf ("new GObjectClassWithNamedCreationMethod ()\n"); var gobject_class_with_named_creation_method = new GObjectClassWithNamedCreationMethod.named (); + stdout.printf ("new SimpleClass () { field = 1 }\n"); + simple_class = new SimpleClass () { field = 1 }; + stdout.printf ("simple_class.field = %d\n", simple_class.field); + stdout.printf (".\n"); return 0; diff --git a/tests/structs.exp b/tests/structs.exp index bbcf3cd5d..f59c798ac 100644 --- a/tests/structs.exp +++ b/tests/structs.exp @@ -5,4 +5,6 @@ new StructWithCreationMethod () StructWithCreationMethod new StructWithNamedCreationMethod () StructWithNamedCreationMethod +new SimpleStruct () { field = 1 } +simple_struct.field = 1 . diff --git a/tests/structs.vala b/tests/structs.vala index a5873a10b..2f5d1efd9 100644 --- a/tests/structs.vala +++ b/tests/structs.vala @@ -1,21 +1,27 @@ using GLib; struct SimpleStruct { + public int field; } public struct PublicStruct { + public int field; } struct StructWithCreationMethod { public StructWithCreationMethod () { stdout.printf ("StructWithCreationMethod\n"); } + + public int field; } struct StructWithNamedCreationMethod { public StructWithNamedCreationMethod.named () { stdout.printf ("StructWithNamedCreationMethod\n"); } + + public int field; } static class StructsTest { @@ -31,6 +37,10 @@ static class StructsTest { stdout.printf ("new StructWithNamedCreationMethod ()\n"); var struct_with_named_creation_method = new StructWithNamedCreationMethod.named (); + stdout.printf ("new SimpleStruct () { field = 1 }\n"); + simple_struct = new SimpleStruct () { field = 1 }; + stdout.printf ("simple_struct.field = %d\n", simple_struct.field); + stdout.printf (".\n"); return 0; diff --git a/vala/Makefile.am b/vala/Makefile.am index 5779913b2..09833b452 100644 --- a/vala/Makefile.am +++ b/vala/Makefile.am @@ -191,6 +191,9 @@ libvalacore_la_SOURCES = \ valamemberaccess.c \ valamemberaccess.h \ valamemberaccess.vala \ + valamemberinitializer.c \ + valamemberinitializer.h \ + valamemberinitializer.vala \ valamemorymanager.c \ valamemorymanager.h \ valamemorymanager.vala \ @@ -381,6 +384,7 @@ valainclude_HEADERS = \ valalockstatement.h \ valamember.h \ valamemberaccess.h \ + valamemberinitializer.h \ valamemorymanager.h \ valamethod.h \ valanamedargument.h \ diff --git a/vala/parser.y b/vala/parser.y index 8abaad574..4bc417dbe 100644 --- a/vala/parser.y +++ b/vala/parser.y @@ -87,6 +87,7 @@ static gboolean check_is_struct (ValaSymbol *symbol, ValaSourceReference *src); ValaLocalVariableDeclaration *local_variable_declaration; ValaVariableDeclarator *variable_declarator; ValaTypeParameter *type_parameter; + ValaMemberInitializer *member_initializer; ValaAttribute *attribute; ValaNamedArgument *named_argument; ValaSwitchSection *switch_section; @@ -239,6 +240,10 @@ static gboolean check_is_struct (ValaSymbol *symbol, ValaSourceReference *src); %type <expression> post_increment_expression %type <expression> post_decrement_expression %type <expression> object_creation_expression +%type <list> opt_object_initializer +%type <list> object_initializer +%type <list> member_initializer_list +%type <member_initializer> member_initializer %type <expression> sizeof_expression %type <expression> typeof_expression %type <expression> unary_expression @@ -845,13 +850,13 @@ post_decrement_expression ; object_creation_expression - : NEW member_name open_parens opt_argument_list CLOSE_PARENS + : NEW member_name open_parens opt_argument_list CLOSE_PARENS opt_object_initializer { ValaSourceReference *src = src(@2); ValaObjectCreationExpression *expr = vala_object_creation_expression_new (VALA_MEMBER_ACCESS ($2), src); g_object_unref ($2); g_object_unref (src); - + if ($4 != NULL) { GList *l; for (l = $4; l != NULL; l = l->next) { @@ -860,11 +865,62 @@ object_creation_expression } g_list_free ($4); } - + + if ($6 != NULL) { + GList *l; + for (l = $6; l != NULL; l = l->next) { + vala_object_creation_expression_add_member_initializer (expr, l->data); + g_object_unref (l->data); + } + g_list_free ($6); + } + $$ = VALA_EXPRESSION (expr); } ; +opt_object_initializer + : /* empty */ + { + $$ = NULL; + } + | object_initializer + ; + +object_initializer + : OPEN_BRACE member_initializer_list CLOSE_BRACE + { + $$ = $2; + } + ; + +member_initializer_list + : member_initializer + { + $$ = g_list_append (NULL, $1); + } + | member_initializer_list COMMA member_initializer + { + $$ = g_list_append ($1, $3); + } + ; + +member_initializer + : IDENTIFIER ASSIGN expression + { + if ($1 == NULL || $3 == NULL) { + // error in subexpression + $$ = NULL; + } else { + ValaSourceReference *src = src(@2); + $$ = vala_member_initializer_new ($1, $3, src); + g_object_unref (src); + g_free ($1); + g_object_unref ($3); + } + } + ; + sizeof_expression : SIZEOF open_parens type_name CLOSE_PARENS { diff --git a/vala/valamemberinitializer.vala b/vala/valamemberinitializer.vala new file mode 100644 index 000000000..597c8b351 --- /dev/null +++ b/vala/valamemberinitializer.vala @@ -0,0 +1,60 @@ +/* valamemberinitializer.vala + * + * Copyright (C) 2007 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; + +/** + * Represents a member initializer, i.e. an element of an object initializer, in + * the source code. + */ +public class Vala.MemberInitializer : CodeNode { + /** + * Member name. + */ + public string! name { get; set; } + + /** + * Initializer expression. + */ + public Expression! initializer { get; set; } + + /** + * The symbol this expression refers to. + */ + public weak Symbol symbol_reference { get; set; } + + /** + * Creates a new member initializer. + * + * @param name member name + * @param initializer initializer expression + * @param source_reference reference to source code + * @return newly created member initializer + */ + public MemberInitializer (construct string! name, construct Expression! initializer, construct SourceReference source_reference = null) { + } + + public override void accept (CodeVisitor! visitor) { + initializer.accept (visitor); + } +} + diff --git a/vala/valaobjectcreationexpression.vala b/vala/valaobjectcreationexpression.vala index fcb84fab0..1968d60e4 100644 --- a/vala/valaobjectcreationexpression.vala +++ b/vala/valaobjectcreationexpression.vala @@ -46,6 +46,8 @@ public class Vala.ObjectCreationExpression : Expression { private Gee.List<Expression> argument_list = new ArrayList<Expression> (); + private Gee.List<MemberInitializer> object_initializer = new ArrayList<MemberInitializer> (); + /** * Creates a new object creation expression. * @@ -65,7 +67,7 @@ public class Vala.ObjectCreationExpression : Expression { argument_list.add (arg); arg.parent_node = this; } - + /** * Returns a copy of the argument list. * @@ -74,7 +76,26 @@ public class Vala.ObjectCreationExpression : Expression { public Collection<Expression> get_argument_list () { return new ReadOnlyCollection<Expression> (argument_list); } - + + /** + * Appends the specified member initializer to the object initializer. + * + * @param init a member initializer + */ + public void add_member_initializer (MemberInitializer! init) { + object_initializer.add (init); + init.parent_node = this; + } + + /** + * Returns the object initializer. + * + * @return member initializer list + */ + public Collection<MemberInitializer> get_object_initializer () { + return new ReadOnlyCollection<MemberInitializer> (object_initializer); + } + public override void accept (CodeVisitor! visitor) { if (type_reference != null) { type_reference.accept (visitor); @@ -89,7 +110,11 @@ public class Vala.ObjectCreationExpression : Expression { foreach (Expression arg in argument_list) { arg.accept (visitor); } - + + foreach (MemberInitializer init in object_initializer) { + init.accept (visitor); + } + visitor.visit_end_object_creation_expression (this); } diff --git a/vala/valasemanticanalyzer.vala b/vala/valasemanticanalyzer.vala index 7ee813747..d2e8b6233 100644 --- a/vala/valasemanticanalyzer.vala +++ b/vala/valasemanticanalyzer.vala @@ -1941,6 +1941,38 @@ public class Vala.SemanticAnalyzer : CodeVisitor { } expr.static_type = new TypeReference (); } + + foreach (MemberInitializer init in expr.get_object_initializer ()) { + init.symbol_reference = symbol_lookup_inherited (expr.type_reference.data_type, init.name); + if (!(init.symbol_reference is Field || init.symbol_reference is Property)) { + expr.error = true; + Report.error (expr.source_reference, "Invalid member `%s' in `%s'".printf (init.name, expr.type_reference.data_type.get_full_name ())); + return; + } + if (init.symbol_reference.access != SymbolAccessibility.PUBLIC) { + expr.error = true; + Report.error (expr.source_reference, "Access to private member `%s' denied".printf (init.symbol_reference.get_full_name ())); + return; + } + TypeReference member_type; + if (init.symbol_reference is Field) { + var f = (Field) init.symbol_reference; + member_type = f.type_reference; + } else if (init.symbol_reference is Property) { + var prop = (Property) init.symbol_reference; + member_type = prop.type_reference; + if (prop.set_accessor == null || !prop.set_accessor.writable) { + expr.error = true; + Report.error (expr.source_reference, "Property `%s' is read-only".printf (prop.get_full_name ())); + return; + } + } + if (init.initializer.static_type == null || !is_type_compatible (init.initializer.static_type, member_type)) { + expr.error = true; + Report.error (init.source_reference, "Invalid type for member `%s'".printf (init.name)); + return; + } + } } public override void visit_sizeof_expression (SizeofExpression! expr) { |