Commit bdbb1c75 authored by Jürg Billeter's avatar Jürg Billeter Committed by Jürg Billeter

Support chaining constructors using `base' and `this'

2008-10-11  Jürg Billeter  <j@bitron.ch>

	* vala/valaclass.vala:
	* vala/valacreationmethod.vala:
	* vala/valainterfacewriter.vala:
	* vala/valaobjecttype.vala:
	* vala/valasemanticanalyzer.vala:
	* vala/valastruct.vala:
	* gobject/valaccodeinvocationexpressionbinding.vala:
	* gobject/valaccodemethodbinding.vala:
	* gobject/valagidlwriter.vala:

	Support chaining constructors using `base' and `this'

svn path=/trunk/; revision=1829
parent e46d2467
2008-10-11 Jürg Billeter <j@bitron.ch>
* vala/valaclass.vala:
* vala/valacreationmethod.vala:
* vala/valainterfacewriter.vala:
* vala/valaobjecttype.vala:
* vala/valasemanticanalyzer.vala:
* vala/valastruct.vala:
* gobject/valaccodeinvocationexpressionbinding.vala:
* gobject/valaccodemethodbinding.vala:
* gobject/valagidlwriter.vala:
Support chaining constructors using `base' and `this'
2008-10-11 Jürg Billeter <j@bitron.ch>
* vala/valacfgbuilder.vala:
......
......@@ -53,6 +53,12 @@ public class Vala.CCodeInvocationExpressionBinding : CCodeExpressionBinding {
m = ((MethodType) itype).method_symbol;
} else if (itype is SignalType) {
ccall = (CCodeFunctionCall) expr.call.ccodenode;
} else if (itype is ObjectType) {
// constructor
var cl = (Class) ((ObjectType) itype).type_symbol;
m = cl.default_construction_method;
ccall = new CCodeFunctionCall (new CCodeIdentifier (m.get_real_cname ()));
ccall.add_argument (new CCodeIdentifier ("object_type"));
}
// the complete call expression, might include casts, comma expressions, and/or assignments
......@@ -152,6 +158,8 @@ public class Vala.CCodeInvocationExpressionBinding : CCodeExpressionBinding {
param.accept (codegen);
}
codegen.dynamic_method_binding ((DynamicMethod) m).generate_wrapper ();
} else if (m is CreationMethod) {
ccall_expr = new CCodeAssignment (new CCodeIdentifier ("self"), new CCodeCastExpression (ccall, codegen.current_class.get_cname () + "*"));
}
bool ellipsis = false;
......
......@@ -100,24 +100,31 @@ public class Vala.CCodeMethodBinding : CCodeBinding {
if (in_gobject_creation_method && m.body != null) {
var cblock = new CCodeBlock ();
// set construct properties
foreach (CodeNode stmt in m.body.get_statements ()) {
var expr_stmt = stmt as ExpressionStatement;
if (expr_stmt != null) {
var prop = expr_stmt.assigned_property ();
if (prop != null && prop.set_accessor.construction) {
if (stmt.ccodenode is CCodeFragment) {
foreach (CCodeNode cstmt in ((CCodeFragment) stmt.ccodenode).get_children ()) {
cblock.add_statement (cstmt);
if (!((CreationMethod) m).chain_up) {
// set construct properties
foreach (CodeNode stmt in m.body.get_statements ()) {
var expr_stmt = stmt as ExpressionStatement;
if (expr_stmt != null) {
var prop = expr_stmt.assigned_property ();
if (prop != null && prop.set_accessor.construction) {
if (stmt.ccodenode is CCodeFragment) {
foreach (CCodeNode cstmt in ((CCodeFragment) stmt.ccodenode).get_children ()) {
cblock.add_statement (cstmt);
}
} else {
cblock.add_statement (stmt.ccodenode);
}
} else {
cblock.add_statement (stmt.ccodenode);
}
}
}
}
add_object_creation (cblock, ((CreationMethod) m).n_construction_params > 0 || codegen.current_class.get_type_parameters ().size > 0);
add_object_creation (cblock, ((CreationMethod) m).n_construction_params > 0 || codegen.current_class.get_type_parameters ().size > 0);
} else {
var cdeclaration = new CCodeDeclaration ("%s *".printf (((Class) codegen.current_type_symbol).get_cname ()));
cdeclaration.add_declarator (new CCodeVariableDeclarator ("self"));
cblock.add_statement (cdeclaration);
}
// other initialization code
foreach (CodeNode stmt in m.body.get_statements ()) {
......
......@@ -406,13 +406,8 @@ public class Vala.GIdlWriter : CodeVisitor {
return;
}
string name = "new";
if (m.name.has_prefix (".new.")) {
name = m.name.substring (5, m.name.len () - 5);
}
write_indent ();
stream.printf ("<constructor name=\"%s\" symbol=\"%s\"", name, m.get_cname ());
stream.printf ("<constructor name=\"%s\" symbol=\"%s\"", m.name, m.get_cname ());
stream.printf (">\n");
indent++;
......
......@@ -318,9 +318,7 @@ public class Vala.Class : ObjectTypeSymbol {
if (m is CreationMethod) {
if (m.name == null) {
default_construction_method = m;
m.name = ".new";
} else {
m.name = ".new." + m.name;
m.name = "new";
}
var cm = (CreationMethod) m;
......
......@@ -45,6 +45,12 @@ public class Vala.CreationMethod : Method {
*/
public string? custom_return_type_cname { get; set; }
/**
* Specifies whether this constructor chains up to a base
* constructor or a different constructor of the same class.
*/
public bool chain_up { get; set; }
/**
* Creates a new method.
*
......@@ -89,10 +95,10 @@ public class Vala.CreationMethod : Method {
infix = "init";
}
if (name.len () == ".new".len ()) {
if (name == "new") {
return "%s%s".printf (parent.get_lower_case_cprefix (), infix);
} else {
return "%s%s_%s".printf (parent.get_lower_case_cprefix (), infix, name.offset (".new.".len ()));
return "%s%s_%s".printf (parent.get_lower_case_cprefix (), infix, name);
}
}
......@@ -109,10 +115,10 @@ public class Vala.CreationMethod : Method {
string infix = "construct";
if (name.len () == ".new".len ()) {
if (name == "new") {
return "%s%s".printf (parent.get_lower_case_cprefix (), infix);
} else {
return "%s%s_%s".printf (parent.get_lower_case_cprefix (), infix, name.offset (".new.".len ()));
return "%s%s_%s".printf (parent.get_lower_case_cprefix (), infix, name);
}
}
}
......@@ -815,7 +815,10 @@ public class Vala.InterfaceWriter : CodeVisitor {
if (m is CreationMethod) {
var datatype = (TypeSymbol) m.parent_symbol;
write_identifier (datatype.name);
write_identifier (m.name.offset (".new".len ()));
if (m.name != "new") {
write_string (".");
write_identifier (m.name);
}
write_string (" ");
} else if (m.binding == MemberBinding.STATIC) {
write_string ("static ");
......
......@@ -71,4 +71,31 @@ public class Vala.ObjectType : ReferenceType {
return type_symbol.is_subtype_of (obj_target_type.type_symbol);
}
public override bool is_invokable () {
var cl = type_symbol as Class;
if (cl != null && cl.default_construction_method != null) {
return true;
} else {
return false;
}
}
public override DataType? get_return_type () {
var cl = type_symbol as Class;
if (cl != null && cl.default_construction_method != null) {
return cl.default_construction_method.return_type;
} else {
return null;
}
}
public override Gee.List<FormalParameter>? get_parameters () {
var cl = type_symbol as Class;
if (cl != null && cl.default_construction_method != null) {
return cl.default_construction_method.get_parameters ();
} else {
return null;
}
}
}
......@@ -1641,11 +1641,6 @@ public class Vala.SemanticAnalyzer : CodeVisitor {
if (expr.inner is MemberAccess || expr.inner is BaseAccess) {
base_symbol = expr.inner.symbol_reference;
if (expr.creation_member && base_symbol is TypeSymbol) {
// check for named creation method
expr.symbol_reference = base_symbol.scope.lookup (".new." + expr.member_name);
}
if (expr.symbol_reference == null && (base_symbol is Namespace || base_symbol is TypeSymbol)) {
expr.symbol_reference = base_symbol.scope.lookup (expr.member_name);
if (expr.inner is BaseAccess) {
......@@ -1672,11 +1667,6 @@ public class Vala.SemanticAnalyzer : CodeVisitor {
}
}
if (expr.symbol_reference == null && expr.inner is MemberAccess && base_symbol is Struct) {
// check for named struct creation method
expr.symbol_reference = base_symbol.scope.lookup (".new." + expr.member_name);
}
if (expr.symbol_reference == null && expr.inner.value_type != null && expr.inner.value_type.is_dynamic) {
// allow late bound members for dynamic types
var dynamic_object_type = (ObjectType) expr.inner.value_type;
......@@ -1934,9 +1924,22 @@ public class Vala.SemanticAnalyzer : CodeVisitor {
var mtype = expr.call.value_type;
if (mtype is ObjectType) {
// constructor chain-up
var cm = find_current_method () as CreationMethod;
assert (cm != null);
if (cm.chain_up) {
expr.error = true;
Report.error (expr.source_reference, "Multiple constructor calls in the same constructor are not permitted");
return;
}
cm.chain_up = true;
}
// check for struct construction
if (expr.call is MemberAccess &&
(expr.call.symbol_reference is CreationMethod
((expr.call.symbol_reference is CreationMethod
&& expr.call.symbol_reference.parent_symbol is Struct)
|| expr.call.symbol_reference is Struct)) {
var struct_creation_expression = new ObjectCreationExpression ((MemberAccess) expr.call, expr.source_reference);
struct_creation_expression.struct_creation = true;
......@@ -1948,6 +1951,17 @@ public class Vala.SemanticAnalyzer : CodeVisitor {
expr.parent_node.replace_expression (expr, struct_creation_expression);
struct_creation_expression.accept (this);
return;
} else if (expr.call is MemberAccess
&& expr.call.symbol_reference is CreationMethod) {
// constructor chain-up
var cm = find_current_method () as CreationMethod;
assert (cm != null);
if (cm.chain_up) {
expr.error = true;
Report.error (expr.source_reference, "Multiple constructor calls in the same constructor are not permitted");
return;
}
cm.chain_up = true;
}
Gee.List<FormalParameter> params;
......@@ -2673,7 +2687,11 @@ public class Vala.SemanticAnalyzer : CodeVisitor {
expr.symbol_reference = constructor;
type_args = ((MemberAccess) expr.member_name.inner).get_type_arguments ();
// inner expression can also be base access when chaining constructors
var ma = expr.member_name.inner as MemberAccess;
if (ma != null) {
type_args = ma.get_type_arguments ();
}
} else if (constructor_sym is ErrorCode) {
type_sym = constructor_sym.parent_symbol;
......
......@@ -148,9 +148,7 @@ public class Vala.Struct : TypeSymbol {
if (m is CreationMethod) {
if (m.name == null) {
default_construction_method = m;
m.name = ".new";
} else {
m.name = ".new." + m.name;
m.name = "new";
}
var cm = (CreationMethod) m;
......
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