Commit 420527fb authored by Jürg Billeter's avatar Jürg Billeter Committed by Jürg Billeter

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
parent 087945bc
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,
......
......@@ -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) {
......
......@@ -11,4 +11,6 @@ new DerivedGObjectClass ()
new PublicGObjectClass ()
new GObjectClassWithCreationMethod ()
new GObjectClassWithNamedCreationMethod ()
new SimpleClass () { field = 1 }
simple_class.field = 1
.
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;
......
......@@ -5,4 +5,6 @@ new StructWithCreationMethod ()
StructWithCreationMethod
new StructWithNamedCreationMethod ()
StructWithNamedCreationMethod
new SimpleStruct () { field = 1 }
simple_struct.field = 1
.
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;
......
......@@ -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 \
......
......@@ -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
{
......
/* 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);
}
}
......@@ -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);
}
......
......@@ -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) {
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment