summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJuerg Billeter <j@bitron.ch>2007-09-15 21:43:43 +0000
committerJürg Billeter <juergbi@src.gnome.org>2007-09-15 21:43:43 +0000
commit420527fb1ddd2d9ea40f169479f535e7f3d5e1de (patch)
tree8c635016181075ee7b155849a96cd3f5461f08d6
parent087945bcf71247fbba63bd92cc232c8e0d009b8a (diff)
downloadvala-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--ChangeLog10
-rw-r--r--gobject/valacodegenerator.vala48
-rw-r--r--tests/classes.exp2
-rw-r--r--tests/classes.vala11
-rw-r--r--tests/structs.exp2
-rw-r--r--tests/structs.vala10
-rw-r--r--vala/Makefile.am4
-rw-r--r--vala/parser.y62
-rw-r--r--vala/valamemberinitializer.vala60
-rw-r--r--vala/valaobjectcreationexpression.vala31
-rw-r--r--vala/valasemanticanalyzer.vala32
11 files changed, 256 insertions, 16 deletions
diff --git a/ChangeLog b/ChangeLog
index 049e4d06e..7869590c8 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -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) {