From e331118336dc32e5392503d090f9514b6002b731 Mon Sep 17 00:00:00 2001 From: =?utf8?q?J=C3=BCrg=20Billeter?= Date: Wed, 2 Aug 2006 15:59:07 +0000 Subject: [PATCH] add support for construction methods add to_string method support storing MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit 2006-08-02 Jürg Billeter * vala/parser.y, vala/valacodevisitor.vala, vala/valasymbolbuilder.vala, vala/valasemanticanalyzer.vala, vala/valacodegenerator.vala, vala/valainterfacewriter.vala, vala/valaclass.vala, vala/valaexpressionstatement.vala, vala/valamethod.vala, vala/valaobjectcreationexpression.vala, vala/valastatement.vala, vala/valastruct.vala: add support for construction methods * vala/valabooleanliteral.vala, vala/valaexpression.vala, vala/valaintegerliteral.vala, vala/valaliteral.vala, vala/valaliteralexpression.vala, vala/valamemberaccess.vala: add to_string method * vala/valamemberaccess.vala, vala/valatypereference.vala: support storing type arguments in MemberAccess * vala/valacodenode.vala: add parent_node property * vala/parser.y, vala/valaifstatement.vala: only allow blocks as embedded statements * vala/valaenum.vala: implement get_type_id method * vala/valainterfacewriter.vala: output default expressions of formal parameters * vala/valaformalparameter.vala: visit default expression * vala/valaobjectcreationexpression.vala, vala/valanullliteral.vala, vala/valaproperty.vala, vala/valapropertyaccessor.vala: add interface documentation, use implicit namespace specification * vala/vala.h: add valaelementaccess.h and valarealliteral.h * ccode/valaccodememberaccess.vala: don't mark is_pointer as construct * vapi/glib-2.0.vala: add GValue * vapi/gtk+-2.0.vala: small updates svn path=/trunk/; revision=88 --- vala/ChangeLog | 29 +++ vala/ccode/valaccodememberaccess.vala | 2 +- vala/vala/parser.y | 180 ++++++++++++---- vala/vala/vala.h | 2 + vala/vala/valabooleanliteral.vala | 8 + vala/vala/valaclass.vala | 5 + vala/vala/valacodegenerator.vala | 308 ++++++++++++++++++++-------- vala/vala/valacodenode.vala | 5 + vala/vala/valacodevisitor.vala | 13 +- vala/vala/valaenum.vala | 5 + vala/vala/valaexpression.vala | 2 + vala/vala/valaexpressionstatement.vala | 17 ++ vala/vala/valaformalparameter.vala | 4 + vala/vala/valaifstatement.vala | 6 +- vala/vala/valaintegerliteral.vala | 4 + vala/vala/valainterfacewriter.vala | 34 ++- vala/vala/valaliteral.vala | 2 + vala/vala/valaliteralexpression.vala | 4 + vala/vala/valamemberaccess.vala | 28 +++ vala/vala/valamethod.vala | 32 ++- vala/vala/valanullliteral.vala | 29 ++- vala/vala/valaobjectcreationexpression.vala | 78 +++++-- vala/vala/valaproperty.vala | 157 +++++++++----- vala/vala/valapropertyaccessor.vala | 69 +++++-- vala/vala/valasemanticanalyzer.vala | 189 ++++++++++++----- vala/vala/valastatement.vala | 16 ++ vala/vala/valastruct.vala | 5 + vala/vala/valasymbolbuilder.vala | 38 +++- vala/vala/valatypereference.vala | 15 +- vala/vapi/glib-2.0.vala | 5 + vala/vapi/gtk+-2.0.vala | 28 +++ 31 files changed, 1020 insertions(+), 299 deletions(-) diff --git a/vala/ChangeLog b/vala/ChangeLog index 473cc00..7476dc1 100644 --- a/vala/ChangeLog +++ b/vala/ChangeLog @@ -1,3 +1,32 @@ +2006-08-02 Jürg Billeter + + * vala/parser.y, vala/valacodevisitor.vala, vala/valasymbolbuilder.vala, + vala/valasemanticanalyzer.vala, vala/valacodegenerator.vala, + vala/valainterfacewriter.vala, vala/valaclass.vala, + vala/valaexpressionstatement.vala, vala/valamethod.vala, + vala/valaobjectcreationexpression.vala, vala/valastatement.vala, + vala/valastruct.vala: add support for construction methods + * vala/valabooleanliteral.vala, vala/valaexpression.vala, + vala/valaintegerliteral.vala, vala/valaliteral.vala, + vala/valaliteralexpression.vala, vala/valamemberaccess.vala: add + to_string method + * vala/valamemberaccess.vala, vala/valatypereference.vala: support + storing type arguments in MemberAccess + * vala/valacodenode.vala: add parent_node property + * vala/parser.y, vala/valaifstatement.vala: only allow blocks as + embedded statements + * vala/valaenum.vala: implement get_type_id method + * vala/valainterfacewriter.vala: output default expressions of formal + parameters + * vala/valaformalparameter.vala: visit default expression + * vala/valaobjectcreationexpression.vala, vala/valanullliteral.vala, + vala/valaproperty.vala, vala/valapropertyaccessor.vala: add interface + documentation, use implicit namespace specification + * vala/vala.h: add valaelementaccess.h and valarealliteral.h + * ccode/valaccodememberaccess.vala: don't mark is_pointer as construct + * vapi/glib-2.0.vala: add GValue + * vapi/gtk+-2.0.vala: small updates + 2006-07-31 Jürg Billeter * vala/parser.y: support prefix increment and decrement, fix parsing diff --git a/vala/ccode/valaccodememberaccess.vala b/vala/ccode/valaccodememberaccess.vala index e317751..bad06e4 100644 --- a/vala/ccode/valaccodememberaccess.vala +++ b/vala/ccode/valaccodememberaccess.vala @@ -39,7 +39,7 @@ public class Vala.CCodeMemberAccess : CCodeExpression { /** * Specifies whether the member access happens by pointer dereferencing. */ - public bool is_pointer { get; set construct; } + public bool is_pointer { get; set; } public override void write (CCodeWriter! writer) { inner.write (writer); diff --git a/vala/vala/parser.y b/vala/vala/parser.y index aa30ea4..7ac0d7b 100644 --- a/vala/vala/parser.y +++ b/vala/vala/parser.y @@ -199,6 +199,7 @@ static void yyerror (YYLTYPE *locp, ValaParser *parser, const char *msg); %token STRING_LITERAL "string" %type comment +%type opt_identifier %type literal %type boolean_literal %type type_name @@ -210,7 +211,6 @@ static void yyerror (YYLTYPE *locp, ValaParser *parser, const char *msg); %type simple_name %type parenthesized_expression %type member_access -%type identifier_or_new %type invocation_expression %type element_access %type post_increment_expression @@ -330,6 +330,7 @@ static void yyerror (YYLTYPE *locp, ValaParser *parser, const char *msg); %type type_argument_list %type type_arguments %type type_argument +%type member_name /* expect shift/reduce conflict on if/else */ %expect 1 @@ -343,6 +344,14 @@ opt_comma | COMMA ; +opt_identifier + : /* empty */ + { + $$ = NULL; + } + | IDENTIFIER + ; + literal : boolean_literal | INTEGER_LITERAL @@ -525,12 +534,21 @@ primary_expression ; simple_name - : IDENTIFIER + : IDENTIFIER opt_type_argument_list { ValaSourceReference *src = src(@1); $$ = VALA_EXPRESSION (vala_member_access_new (NULL, $1, src)); g_free ($1); g_object_unref (src); + + if ($2 != NULL) { + GList *l; + for (l = $2; l != NULL; l = l->next) { + vala_member_access_add_type_argument (VALA_MEMBER_ACCESS ($$), l->data); + g_object_unref (l->data); + } + g_list_free ($2); + } } ; @@ -545,21 +563,22 @@ parenthesized_expression ; member_access - : primary_expression DOT identifier_or_new + : primary_expression DOT IDENTIFIER opt_type_argument_list { ValaSourceReference *src = src(@3); $$ = VALA_EXPRESSION (vala_member_access_new ($1, $3, src)); - g_object_unref (src); g_object_unref ($1); g_free ($3); - } - ; + g_object_unref (src); -identifier_or_new - : IDENTIFIER - | NEW - { - $$ = g_strdup ("new"); + if ($4 != NULL) { + GList *l; + for (l = $4; l != NULL; l = l->next) { + vala_member_access_add_type_argument (VALA_MEMBER_ACCESS ($$), l->data); + g_object_unref (l->data); + } + g_list_free ($4); + } } ; @@ -616,15 +635,23 @@ post_decrement_expression ; object_creation_expression - : NEW type open_parens opt_named_argument_list CLOSE_PARENS + : NEW member_name open_parens opt_argument_list CLOSE_PARENS { ValaSourceReference *src = src(@2); - $$ = VALA_EXPRESSION (vala_object_creation_expression_new ($2, $4, src)); + ValaObjectCreationExpression *expr = vala_object_creation_expression_new ($2, src); g_object_unref ($2); + g_object_unref (src); + if ($4 != NULL) { + GList *l; + for (l = $4; l != NULL; l = l->next) { + vala_object_creation_expression_add_argument (expr, l->data); + g_object_unref (l->data); + } g_list_free ($4); } - g_object_unref (src); + + $$ = VALA_EXPRESSION (expr); } ; @@ -1157,38 +1184,26 @@ local_variable_declaration /* don't use type to prevent reduce/reduce conflict */ local_variable_type - : primary_expression opt_type_argument_list opt_op_neg + : primary_expression opt_op_neg { ValaSourceReference *src = src(@1); $$ = vala_type_reference_new_from_expression ($1, src); + g_object_unref ($1); g_object_unref (src); - if ($3) { + if ($2) { vala_type_reference_set_non_null ($$, TRUE); } - GList *l; - for (l = $2; l != NULL; l = l->next) { - vala_type_reference_add_type_argument ($$, l->data); - g_object_unref (l->data); - } - g_list_free ($2); - g_object_unref ($1); } - | REF primary_expression opt_type_argument_list opt_op_neg + | REF primary_expression opt_op_neg { ValaSourceReference *src = src(@2); $$ = vala_type_reference_new_from_expression ($2, src); + g_object_unref ($2); g_object_unref (src); vala_type_reference_set_takes_ownership ($$, TRUE); - if ($4) { + if ($3) { vala_type_reference_set_non_null ($$, TRUE); } - GList *l; - for (l = $3; l != NULL; l = l->next) { - vala_type_reference_add_type_argument ($$, l->data); - g_object_unref (l->data); - } - g_list_free ($3); - g_object_unref ($2); } | local_variable_type array_qualifier { @@ -1214,6 +1229,7 @@ expression_statement ValaSourceReference *src = src_com(@2, $1); $$ = VALA_STATEMENT (vala_expression_statement_new ($2, src)); g_object_unref (src); + vala_code_node_set_parent_node (VALA_CODE_NODE ($2), VALA_CODE_NODE ($$)); g_object_unref ($2); } ; @@ -1234,20 +1250,47 @@ selection_statement if_statement : comment IF open_parens expression CLOSE_PARENS embedded_statement { + ValaBlock *true_block; + if (VALA_IS_BLOCK ($6)) { + true_block = VALA_BLOCK ($6); + } else { + true_block = vala_block_new (vala_code_node_get_source_reference (VALA_CODE_NODE ($6))); + vala_block_add_statement (true_block, $6); + g_object_unref ($6); + } + ValaSourceReference *src = src_com(@4, $1); - $$ = VALA_STATEMENT (vala_if_statement_new ($4, $6, NULL, src)); + $$ = VALA_STATEMENT (vala_if_statement_new ($4, true_block, NULL, src)); g_object_unref (src); g_object_unref ($4); - g_object_unref ($6); + g_object_unref (true_block); } | comment IF open_parens expression CLOSE_PARENS embedded_statement ELSE embedded_statement { + ValaBlock *true_block; + if (VALA_IS_BLOCK ($6)) { + true_block = VALA_BLOCK ($6); + } else { + true_block = vala_block_new (vala_code_node_get_source_reference (VALA_CODE_NODE ($6))); + vala_block_add_statement (true_block, $6); + g_object_unref ($6); + } + + ValaBlock *false_block; + if (VALA_IS_BLOCK ($8)) { + false_block = VALA_BLOCK ($8); + } else { + false_block = vala_block_new (vala_code_node_get_source_reference (VALA_CODE_NODE ($8))); + vala_block_add_statement (false_block, $8); + g_object_unref ($8); + } + ValaSourceReference *src = src_com(@4, $1); - $$ = VALA_STATEMENT (vala_if_statement_new ($4, $6, $8, src)); + $$ = VALA_STATEMENT (vala_if_statement_new ($4, true_block, false_block, src)); g_object_unref (src); g_object_unref ($4); - g_object_unref ($6); - g_object_unref ($8); + g_object_unref (true_block); + g_object_unref (false_block); } ; @@ -2061,7 +2104,7 @@ method_declaration ; method_header - : comment opt_attributes opt_access_modifier opt_modifiers type identifier_or_new OPEN_PARENS opt_formal_parameter_list CLOSE_PARENS + : comment opt_attributes opt_access_modifier opt_modifiers type IDENTIFIER OPEN_PARENS opt_formal_parameter_list CLOSE_PARENS { GList *l; @@ -2100,6 +2143,29 @@ method_header g_object_unref ($5); g_free ($6); } + | comment opt_attributes opt_access_modifier CONSTRUCT opt_identifier OPEN_PARENS opt_formal_parameter_list CLOSE_PARENS + { + GList *l; + + ValaSourceReference *src = src_com(@4, $1); + $$ = vala_method_new ($5, NULL, src); + g_free ($5); + g_object_unref (src); + vala_method_set_construction ($$, TRUE); + vala_method_set_instance ($$, FALSE); + if ($3 != 0) { + $$->access = $3; + } + VALA_CODE_NODE($$)->attributes = $2; + + if ($7 != NULL) { + for (l = $7; l != NULL; l = l->next) { + vala_method_add_parameter ($$, l->data); + g_object_unref (l->data); + } + g_list_free ($7); + } + } ; method_body @@ -2272,7 +2338,7 @@ set_accessor_declaration ; signal_declaration - : comment opt_attributes opt_access_modifier SIGNAL type identifier_or_new OPEN_PARENS opt_formal_parameter_list CLOSE_PARENS SEMICOLON + : comment opt_attributes opt_access_modifier SIGNAL type IDENTIFIER OPEN_PARENS opt_formal_parameter_list CLOSE_PARENS SEMICOLON { GList *l; @@ -2808,6 +2874,42 @@ open_parens | OPEN_CAST_PARENS ; +member_name + : IDENTIFIER opt_type_argument_list + { + ValaSourceReference *src = src(@1); + $$ = VALA_EXPRESSION (vala_member_access_new (NULL, $1, src)); + g_free ($1); + g_object_unref (src); + + if ($2 != NULL) { + GList *l; + for (l = $2; l != NULL; l = l->next) { + vala_member_access_add_type_argument (VALA_MEMBER_ACCESS ($$), l->data); + g_object_unref (l->data); + } + g_list_free ($2); + } + } + | member_name DOT IDENTIFIER opt_type_argument_list + { + ValaSourceReference *src = src(@1); + $$ = VALA_EXPRESSION (vala_member_access_new ($1, $3, src)); + g_object_unref ($1); + g_free ($3); + g_object_unref (src); + + if ($4 != NULL) { + GList *l; + for (l = $4; l != NULL; l = l->next) { + vala_member_access_add_type_argument (VALA_MEMBER_ACCESS ($$), l->data); + g_object_unref (l->data); + } + g_list_free ($4); + } + } + ; + %% extern FILE *yyin; diff --git a/vala/vala/vala.h b/vala/vala/vala.h index 68ee28e..6dc8914 100644 --- a/vala/vala/vala.h +++ b/vala/vala/vala.h @@ -16,6 +16,7 @@ #include #include #include +#include #include #include #include @@ -47,6 +48,7 @@ #include #include #include +#include #include #include #include diff --git a/vala/vala/valabooleanliteral.vala b/vala/vala/valabooleanliteral.vala index a0fac5f..e58fa52 100644 --- a/vala/vala/valabooleanliteral.vala +++ b/vala/vala/valabooleanliteral.vala @@ -45,4 +45,12 @@ public class Vala.BooleanLiteral : Literal { public override void accept (CodeVisitor! visitor) { visitor.visit_boolean_literal (this); } + + public override ref string! to_string () { + if (value) { + return "true"; + } else { + return "false"; + } + } } diff --git a/vala/vala/valaclass.vala b/vala/vala/valaclass.vala index 7461143..ef0e30e 100644 --- a/vala/vala/valaclass.vala +++ b/vala/vala/valaclass.vala @@ -63,6 +63,11 @@ public class Vala.Class : DataType { private List signals; /** + * Specifies the default construction method. + */ + public Method default_construction_method { get; set; } + + /** * Specifies the instance constructor. */ public Constructor constructor { get; set; } diff --git a/vala/vala/valacodegenerator.vala b/vala/vala/valacodegenerator.vala index 30b48e2..8eb53c6 100644 --- a/vala/vala/valacodegenerator.vala +++ b/vala/vala/valacodegenerator.vala @@ -61,6 +61,7 @@ public class Vala.CodeGenerator : CodeVisitor { private int next_temp_var_id = 0; TypeReference bool_type; + TypeReference int_type; TypeReference string_type; /** @@ -76,6 +77,9 @@ public class Vala.CodeGenerator : CodeVisitor { bool_type = new TypeReference (); bool_type.data_type = (DataType) root_symbol.lookup ("bool").node; + int_type = new TypeReference (); + int_type.data_type = (DataType) root_symbol.lookup ("int").node; + string_type = new TypeReference (); string_type.data_type = (DataType) root_symbol.lookup ("string").node; @@ -359,16 +363,16 @@ public class Vala.CodeGenerator : CodeVisitor { if (prop.type_reference.data_type is Class) { cspec.call = new CCodeIdentifier (name = "g_param_spec_object"); cspec.add_argument (new CCodeIdentifier (name = prop.type_reference.data_type.get_upper_case_cname ("TYPE_"))); - } else if (prop.type_reference.type_name == "string") { + } else if (prop.type_reference.data_type == string_type.data_type) { cspec.call = new CCodeIdentifier (name = "g_param_spec_string"); cspec.add_argument (new CCodeConstant (name = "NULL")); - } else if (prop.type_reference.type_name == "int" + } else if (prop.type_reference.data_type == int_type.data_type || prop.type_reference.data_type is Enum) { cspec.call = new CCodeIdentifier (name = "g_param_spec_int"); cspec.add_argument (new CCodeConstant (name = "G_MININT")); cspec.add_argument (new CCodeConstant (name = "G_MAXINT")); cspec.add_argument (new CCodeConstant (name = "0")); - } else if (prop.type_reference.type_name == "bool") { + } else if (prop.type_reference.data_type == bool_type.data_type) { cspec.call = new CCodeIdentifier (name = "g_param_spec_boolean"); cspec.add_argument (new CCodeConstant (name = "FALSE")); } else { @@ -381,7 +385,7 @@ public class Vala.CodeGenerator : CodeVisitor { } if (prop.set_accessor != null) { pflags = "%s%s".printf (pflags, " | G_PARAM_WRITABLE"); - if (prop.set_accessor.construct_) { + if (prop.set_accessor.construction) { if (prop.set_accessor.writable) { pflags = "%s%s".printf (pflags, " | G_PARAM_CONSTRUCT"); } else { @@ -574,6 +578,21 @@ public class Vala.CodeGenerator : CodeVisitor { source_type_member_definition.append (function); } + private ref CCodeIdentifier! get_value_setter_function (TypeReference! type_reference) { + if (type_reference.data_type is Class) { + return new CCodeIdentifier (name = "g_value_set_object"); + } else if (type_reference.data_type == string_type.data_type) { + return new CCodeIdentifier (name = "g_value_set_string"); + } else if (type_reference.type_name == "int" + || type_reference.data_type is Enum) { + return new CCodeIdentifier (name = "g_value_set_int"); + } else if (type_reference.data_type == bool_type.data_type) { + return new CCodeIdentifier (name = "g_value_set_boolean"); + } else { + return new CCodeIdentifier (name = "g_value_set_pointer"); + } + } + private void add_get_property_function (Class! cl) { var get_prop = new CCodeFunction (name = "%s_get_property".printf (cl.get_lower_case_cname (null)), return_type = "void"); get_prop.add_parameter (new CCodeFormalParameter (type_name = "GObject *", name = "object")); @@ -600,18 +619,7 @@ public class Vala.CodeGenerator : CodeVisitor { var ccall = new CCodeFunctionCall (call = new CCodeIdentifier (name = "%s_get_%s".printf (cl.get_lower_case_cname (null), prop.name))); ccall.add_argument (new CCodeIdentifier (name = "self")); var csetcall = new CCodeFunctionCall (); - if (prop.type_reference.data_type is Class) { - csetcall.call = new CCodeIdentifier (name = "g_value_set_object"); - } else if (prop.type_reference.type_name == "string") { - csetcall.call = new CCodeIdentifier (name = "g_value_set_string"); - } else if (prop.type_reference.type_name == "int" - || prop.type_reference.data_type is Enum) { - csetcall.call = new CCodeIdentifier (name = "g_value_set_int"); - } else if (prop.type_reference.type_name == "bool") { - csetcall.call = new CCodeIdentifier (name = "g_value_set_boolean"); - } else { - csetcall.call = new CCodeIdentifier (name = "g_value_set_pointer"); - } + csetcall.call = get_value_setter_function (prop.type_reference); csetcall.add_argument (new CCodeIdentifier (name = "value")); csetcall.add_argument (ccall); ccase.add_statement (new CCodeExpressionStatement (expression = csetcall)); @@ -867,10 +875,6 @@ public class Vala.CodeGenerator : CodeVisitor { public override void visit_end_method (Method! m) { current_symbol = current_symbol.parent_symbol; - if (m.name == "init") { - return; - } - function = new CCodeFunction (name = m.get_real_cname (), return_type = m.return_type.get_cname ()); CCodeFunctionDeclarator vdeclarator = null; @@ -962,6 +966,21 @@ public class Vala.CodeGenerator : CodeVisitor { source_type_member_definition.append (new CCodeComment (text = m.source_reference.comment)); } source_type_member_definition.append (function); + + if (m.construction) { + // declare construction parameter array + var cparamsinit = new CCodeFunctionCall (call = new CCodeIdentifier (name = "g_new0")); + cparamsinit.add_argument (new CCodeIdentifier (name = "GParameter")); + cparamsinit.add_argument (new CCodeConstant (name = m.n_construction_params.to_string ())); + + var cdecl = new CCodeDeclaration (type_name = "GParameter *"); + cdecl.add_declarator (new CCodeVariableDeclarator (name = "__params", initializer = cparamsinit)); + cinit.append (cdecl); + + cdecl = new CCodeDeclaration (type_name = "GParameter *"); + cdecl.add_declarator (new CCodeVariableDeclarator (name = "__params_it", initializer = new CCodeIdentifier (name = "__params"))); + cinit.append (cdecl); + } } } @@ -1006,7 +1025,13 @@ public class Vala.CodeGenerator : CodeVisitor { source_type_member_definition.append (vfunc); } - if (m.name == "main") { + if (m.construction) { + var creturn = new CCodeReturnStatement (); + creturn.return_expression = new CCodeIdentifier (name = "self"); + function.block.add_statement (creturn); + } + + if (m.name != null && m.name == "main") { var cmain = new CCodeFunction (name = "main", return_type = "int"); cmain.add_parameter (new CCodeFormalParameter (type_name = "int", name = "argc")); cmain.add_parameter (new CCodeFormalParameter (type_name = "char **", name = "argv")); @@ -1044,7 +1069,7 @@ public class Vala.CodeGenerator : CodeVisitor { this_type.data_type = cl; var cparam = new CCodeFormalParameter (type_name = this_type.get_cname (), name = "self"); function.add_parameter (cparam); - if (acc.writable || acc.construct_) { + if (acc.writable || acc.construction) { function.add_parameter (new CCodeFormalParameter (type_name = prop.type_reference.get_cname (), name = "value")); } @@ -1130,16 +1155,41 @@ public class Vala.CodeGenerator : CodeVisitor { public override void visit_begin_block (Block! b) { current_symbol = b.symbol; } + + private void add_object_creation (CCodeBlock! b) { + var cl = (Class) current_type_symbol.node; + + var ccall = new CCodeFunctionCall (call = new CCodeIdentifier (name = "g_object_newv")); + ccall.add_argument (new CCodeConstant (name = cl.get_type_id ())); + ccall.add_argument (new CCodeConstant (name = "__params_it - __params")); + ccall.add_argument (new CCodeConstant (name = "__params")); + + var cdecl = new CCodeVariableDeclarator (name = "self"); + cdecl.initializer = ccall; + + var cdeclaration = new CCodeDeclaration (type_name = "%s *".printf (cl.get_cname ())); + cdeclaration.add_declarator (cdecl); + + b.add_statement (cdeclaration); + } public override void visit_end_block (Block! b) { var local_vars = b.get_local_variables (); foreach (VariableDeclarator decl in local_vars) { decl.symbol.active = false; } + + bool in_construction = b.construction; var cblock = new CCodeBlock (); foreach (Statement stmt in b.get_statements ()) { + if (in_construction && !stmt.construction) { + // construction part of construction method ends here + add_object_creation (cblock); + in_construction = false; + } + var src = stmt.source_reference; if (src != null && src.comment != null) { cblock.add_statement (new CCodeComment (text = src.comment)); @@ -1154,6 +1204,11 @@ public class Vala.CodeGenerator : CodeVisitor { } } + if (in_construction) { + // construction method doesn't contain non-construction parts + add_object_creation (cblock); + } + if (memory_management) { foreach (VariableDeclarator decl in local_vars) { if (decl.type_reference.data_type.is_reference_type () && decl.type_reference.takes_ownership) { @@ -1969,25 +2024,81 @@ public class Vala.CodeGenerator : CodeVisitor { } } - public override void visit_object_creation_expression (ObjectCreationExpression! expr) { - if (expr.type_reference.data_type is Class) { - var ccall = new CCodeFunctionCall (call = new CCodeIdentifier (name = "g_object_new")); - - ccall.add_argument (new CCodeConstant (name = expr.type_reference.data_type.get_upper_case_cname ("TYPE_"))); + public override void visit_end_object_creation_expression (ObjectCreationExpression! expr) { + if (expr.symbol_reference == null) { + // no construction method + if (expr.type_reference.data_type is Class) { + var ccall = new CCodeFunctionCall (call = new CCodeIdentifier (name = "g_object_new")); + + ccall.add_argument (new CCodeConstant (name = expr.type_reference.data_type.get_type_id ())); - foreach (NamedArgument arg in expr.named_argument_list) { - ccall.add_argument (new CCodeConstant (name = "\"%s\"".printf (arg.name))); - ccall.add_argument ((CCodeExpression) arg.argument.ccodenode); + ccall.add_argument (new CCodeConstant (name = "NULL")); + + expr.ccodenode = ccall; + } else { + var ccall = new CCodeFunctionCall (call = new CCodeIdentifier (name = "g_new0")); + + ccall.add_argument (new CCodeConstant (name = expr.type_reference.data_type.get_cname ())); + + ccall.add_argument (new CCodeConstant (name = "1")); + + expr.ccodenode = ccall; } - ccall.add_argument (new CCodeConstant (name = "NULL")); - - expr.ccodenode = ccall; } else { - var ccall = new CCodeFunctionCall (call = new CCodeIdentifier (name = "g_new0")); + // use construction method + var m = (Method) expr.symbol_reference.node; + var params = m.get_parameters (); + + var ccall = new CCodeFunctionCall (call = new CCodeIdentifier (name = m.get_cname ())); + + var i = 1; + foreach (Expression arg in expr.get_argument_list ()) { + /* explicitly use strong reference as ccall gets + * unrefed at end of inner block + */ + ref CCodeExpression cexpr = (CCodeExpression) arg.ccodenode; + if (params != null) { + var param = (FormalParameter) params.data; + if (!param.ellipsis + && param.type_reference.data_type != null + && param.type_reference.data_type.is_reference_type () + && arg.static_type.data_type != null + && param.type_reference.data_type != arg.static_type.data_type) { + var ccall = new CCodeFunctionCall (call = new CCodeIdentifier (name = param.type_reference.data_type.get_upper_case_cname (null))); + ccall.add_argument (cexpr); + cexpr = ccall; + } + } + + ccall.add_argument (cexpr); + i++; + + if (params != null) { + params = params.next; + } + } + while (params != null) { + var param = (FormalParameter) params.data; + + if (param.ellipsis) { + break; + } + + if (param.default_expression == null) { + Report.error (expr.source_reference, "no default expression for argument %d".printf (i)); + return; + } + + /* evaluate default expression here as the code + * generator might not have visited the formal + * parameter yet */ + param.default_expression.accept (this); - ccall.add_argument (new CCodeConstant (name = expr.type_reference.data_type.get_cname ())); + ccall.add_argument ((CCodeExpression) param.default_expression.ccodenode); + i++; - ccall.add_argument (new CCodeConstant (name = "1")); + params = params.next; + } expr.ccodenode = ccall; } @@ -2059,60 +2170,91 @@ public class Vala.CodeGenerator : CodeVisitor { if (a.left.symbol_reference.node is Property) { var prop = (Property) a.left.symbol_reference.node; var cl = (Class) prop.symbol.parent_symbol.node; - - var set_func = "g_object_set"; - if (!prop.no_accessor_method) { - set_func = "%s_set_%s".printf (cl.get_lower_case_cname (null), prop.name); - } - - var ccall = new CCodeFunctionCall (call = new CCodeIdentifier (name = set_func)); + if (ma.inner == null && a.parent_node is Statement && + ((Statement) a.parent_node).construction) { + // this property is used as a construction parameter + var cpointer = new CCodeIdentifier (name = "__params_it"); + + var ccomma = new CCodeCommaExpression (); + // set name in array for current parameter + var cnamemember = new CCodeMemberAccess (inner = cpointer, member_name = "name", is_pointer = true); + var cnameassign = new CCodeAssignment (left = cnamemember, right = prop.get_canonical_cconstant ()); + ccomma.append_expression (cnameassign); + + var gvaluearg = new CCodeUnaryExpression (operator = CCodeUnaryOperator.ADDRESS_OF, inner = new CCodeMemberAccess (inner = cpointer, member_name = "value", is_pointer = true)); + + // initialize GValue in array for current parameter + var cvalueinit = new CCodeFunctionCall (call = new CCodeIdentifier (name = "g_value_init")); + cvalueinit.add_argument (gvaluearg); + cvalueinit.add_argument (new CCodeIdentifier (name = prop.type_reference.data_type.get_type_id ())); + ccomma.append_expression (cvalueinit); + + // set GValue for current parameter + var cvalueset = new CCodeFunctionCall (call = get_value_setter_function (prop.type_reference)); + cvalueset.add_argument (gvaluearg); + cvalueset.add_argument ((CCodeExpression) a.right.ccodenode); + ccomma.append_expression (cvalueset); + + // move pointer to next parameter in array + ccomma.append_expression (new CCodeUnaryExpression (operator = CCodeUnaryOperator.POSTFIX_INCREMENT, inner = cpointer)); + + a.ccodenode = ccomma; + } else { + var set_func = "g_object_set"; + + if (!prop.no_accessor_method) { + set_func = "%s_set_%s".printf (cl.get_lower_case_cname (null), prop.name); + } + + var ccall = new CCodeFunctionCall (call = new CCodeIdentifier (name = set_func)); - /* target instance is first argument */ - ref CCodeExpression instance; - var req_cast = false; + /* target instance is first argument */ + ref CCodeExpression instance; + var req_cast = false; - if (ma.inner == null) { - instance = new CCodeIdentifier (name = "self"); - /* require casts for inherited properties */ - req_cast = (prop.symbol.parent_symbol != current_type_symbol); - } else { - instance = (CCodeExpression) ma.inner.ccodenode; - /* require casts if the type of the used instance is - * different than the type which declared the property */ - req_cast = prop.symbol.parent_symbol.node != ma.inner.static_type.data_type; - } - - if (req_cast && ((DataType) prop.symbol.parent_symbol.node).is_reference_type ()) { - var ccast = new CCodeFunctionCall (call = new CCodeIdentifier (name = ((DataType) prop.symbol.parent_symbol.node).get_upper_case_cname (null))); - ccast.add_argument (instance); - instance = ccast; - } + if (ma.inner == null) { + instance = new CCodeIdentifier (name = "self"); + /* require casts for inherited properties */ + req_cast = (prop.symbol.parent_symbol != current_type_symbol); + } else { + instance = (CCodeExpression) ma.inner.ccodenode; + /* require casts if the type of the used instance is + * different than the type which declared the property */ + req_cast = prop.symbol.parent_symbol.node != ma.inner.static_type.data_type; + } + + if (req_cast && ((DataType) prop.symbol.parent_symbol.node).is_reference_type ()) { + var ccast = new CCodeFunctionCall (call = new CCodeIdentifier (name = ((DataType) prop.symbol.parent_symbol.node).get_upper_case_cname (null))); + ccast.add_argument (instance); + instance = ccast; + } - ccall.add_argument (instance); + ccall.add_argument (instance); + + ref CCodeExpression cexpr = (CCodeExpression) a.right.ccodenode; - ref CCodeExpression cexpr = (CCodeExpression) a.right.ccodenode; - - if (prop.no_accessor_method) { - /* property name is second argument of g_object_set */ - ccall.add_argument (prop.get_canonical_cconstant ()); - } else if (prop.type_reference.data_type != null - && prop.type_reference.data_type.is_reference_type () - && a.right.static_type.data_type != null - && prop.type_reference.data_type != a.right.static_type.data_type) { - /* cast is necessary */ - var ccast = new CCodeFunctionCall (call = new CCodeIdentifier (name = prop.type_reference.data_type.get_upper_case_cname (null))); - ccast.add_argument (cexpr); - cexpr = ccast; - } + if (prop.no_accessor_method) { + /* property name is second argument of g_object_set */ + ccall.add_argument (prop.get_canonical_cconstant ()); + } else if (prop.type_reference.data_type != null + && prop.type_reference.data_type.is_reference_type () + && a.right.static_type.data_type != null + && prop.type_reference.data_type != a.right.static_type.data_type) { + /* cast is necessary */ + var ccast = new CCodeFunctionCall (call = new CCodeIdentifier (name = prop.type_reference.data_type.get_upper_case_cname (null))); + ccast.add_argument (cexpr); + cexpr = ccast; + } + + ccall.add_argument (cexpr); - ccall.add_argument (cexpr); - - if (prop.no_accessor_method) { - ccall.add_argument (new CCodeConstant (name = "NULL")); + if (prop.no_accessor_method) { + ccall.add_argument (new CCodeConstant (name = "NULL")); + } + + a.ccodenode = ccall; } - - a.ccodenode = ccall; } else if (a.left.symbol_reference.node is Signal) { var sig = (Signal) a.left.symbol_reference.node; diff --git a/vala/vala/valacodenode.vala b/vala/vala/valacodenode.vala index f0042f4..fec5c82 100644 --- a/vala/vala/valacodenode.vala +++ b/vala/vala/valacodenode.vala @@ -30,6 +30,11 @@ using GLib; */ public abstract class Vala.CodeNode { /** + * Parent of this code node. + */ + public CodeNode parent_node { get; set; } + + /** * Symbol that corresponds to this code node. */ public Symbol symbol { get; set; } diff --git a/vala/vala/valacodevisitor.vala b/vala/vala/valacodevisitor.vala index 7f1e982..74d2883 100644 --- a/vala/vala/valacodevisitor.vala +++ b/vala/vala/valacodevisitor.vala @@ -588,11 +588,20 @@ public abstract class Vala.CodeVisitor { } /** - * Visit operation called for object creation expressions. + * Visit operation called at beginning of object creation + * expressions. * * @param expr an object creation expression */ - public virtual void visit_object_creation_expression (ObjectCreationExpression! expr) { + public virtual void visit_begin_object_creation_expression (ObjectCreationExpression! expr) { + } + + /** + * Visit operation called at end of object creation expressions. + * + * @param expr an object creation expression + */ + public virtual void visit_end_object_creation_expression (ObjectCreationExpression! expr) { } /** diff --git a/vala/vala/valaenum.vala b/vala/vala/valaenum.vala index 4a9e38c..1e1dcef 100644 --- a/vala/vala/valaenum.vala +++ b/vala/vala/valaenum.vala @@ -139,4 +139,9 @@ public class Vala.Enum : DataType { } } } + + public override string get_type_id () { + // FIXME: use GType-registered enums + return "G_TYPE_INT"; + } } diff --git a/vala/vala/valaexpression.vala b/vala/vala/valaexpression.vala index 6fe357b..38ee3a1 100644 --- a/vala/vala/valaexpression.vala +++ b/vala/vala/valaexpression.vala @@ -68,4 +68,6 @@ public abstract class Vala.Expression : CodeNode { * The code generator sets and uses them for memory management. */ public List temp_vars; + + public abstract ref string! to_string (); } diff --git a/vala/vala/valaexpressionstatement.vala b/vala/vala/valaexpressionstatement.vala index 8234970..ff35a13 100644 --- a/vala/vala/valaexpressionstatement.vala +++ b/vala/vala/valaexpressionstatement.vala @@ -48,4 +48,21 @@ public class Vala.ExpressionStatement : Statement { visitor.visit_expression_statement (this); } + + public override int get_number_of_set_construction_parameters () { + if (expression is Assignment) { + var assign = (Assignment) expression; + if (assign.left is MemberAccess) { + var ma = (MemberAccess) assign.left; + if (ma.symbol_reference != null) { + if (ma.symbol_reference.node is Property) { + var prop = (Property) ma.symbol_reference.node; + return 1; + } + } + } + } + + return -1; + } } diff --git a/vala/vala/valaformalparameter.vala b/vala/vala/valaformalparameter.vala index ebaea26..a252e34 100644 --- a/vala/vala/valaformalparameter.vala +++ b/vala/vala/valaformalparameter.vala @@ -71,6 +71,10 @@ public class Vala.FormalParameter : CodeNode { public override void accept (CodeVisitor! visitor) { if (!ellipsis) { type_reference.accept (visitor); + + if (default_expression != null) { + default_expression.accept (visitor); + } } visitor.visit_formal_parameter (this); diff --git a/vala/vala/valaifstatement.vala b/vala/vala/valaifstatement.vala index d0cf494..2e09666 100644 --- a/vala/vala/valaifstatement.vala +++ b/vala/vala/valaifstatement.vala @@ -34,12 +34,12 @@ public class Vala.IfStatement : Statement { /** * The statement to be evaluated if the condition holds. */ - public Statement! true_statement { get; set construct; } + public Block! true_statement { get; set construct; } /** * The optional statement to be evaluated if the condition doesn't hold. */ - public Statement false_statement { get; set construct; } + public Block false_statement { get; set construct; } /** * Creates a new if statement. @@ -49,7 +49,7 @@ public class Vala.IfStatement : Statement { * @param false_stmt statement to be evaluated if condition is false * @return newly created if statement */ - public static ref IfStatement! new (Expression! cond, Statement! true_stmt, Statement false_stmt, SourceReference source) { + public static ref IfStatement! new (Expression! cond, Block! true_stmt, Block false_stmt, SourceReference source) { return (new IfStatement (condition = cond, true_statement = true_stmt, false_statement = false_stmt, source_reference = source)); } diff --git a/vala/vala/valaintegerliteral.vala b/vala/vala/valaintegerliteral.vala index 5f95c38..f96e666 100644 --- a/vala/vala/valaintegerliteral.vala +++ b/vala/vala/valaintegerliteral.vala @@ -45,4 +45,8 @@ public class Vala.IntegerLiteral : Literal { public override void accept (CodeVisitor! visitor) { visitor.visit_integer_literal (this); } + + public override ref string! to_string () { + return value; + } } diff --git a/vala/vala/valainterfacewriter.vala b/vala/vala/valainterfacewriter.vala index 91eb89a..46ca460 100644 --- a/vala/vala/valainterfacewriter.vala +++ b/vala/vala/valainterfacewriter.vala @@ -221,7 +221,9 @@ public class Vala.InterfaceWriter : CodeVisitor { write_indent (); write_string ("public "); - if (!m.instance) { + if (m.construction) { + write_string ("construct "); + } else if (!m.instance) { write_string ("static "); } else if (m.is_abstract) { write_string ("abstract "); @@ -229,18 +231,23 @@ public class Vala.InterfaceWriter : CodeVisitor { write_string ("virtual "); } - var type = m.return_type.data_type; - if (type == null) { - write_string ("void"); - } else { - if (m.return_type.transfers_ownership) { - write_string ("ref "); + if (!m.construction) { + var type = m.return_type.data_type; + if (type == null) { + write_string ("void"); + } else { + if (m.return_type.transfers_ownership) { + write_string ("ref "); + } + write_string (m.return_type.data_type.symbol.get_full_name ()); } - write_string (m.return_type.data_type.symbol.get_full_name ()); } - write_string (" "); - write_identifier (m.name); + if (m.name != null) { + write_string (" "); + write_identifier (m.name); + } + write_string (" ("); bool first = true; @@ -273,6 +280,11 @@ public class Vala.InterfaceWriter : CodeVisitor { write_string (" "); write_identifier (param.name); + + if (param.default_expression != null) { + write_string (" = "); + write_string (param.default_expression.to_string ()); + } } write_string (");"); @@ -313,7 +325,7 @@ public class Vala.InterfaceWriter : CodeVisitor { if (prop.set_accessor.writable) { write_string (" set"); } - if (prop.set_accessor.construct_) { + if (prop.set_accessor.construction) { write_string (" construct"); } write_string (";"); diff --git a/vala/vala/valaliteral.vala b/vala/vala/valaliteral.vala index 6f06088..aab9f21 100644 --- a/vala/vala/valaliteral.vala +++ b/vala/vala/valaliteral.vala @@ -30,4 +30,6 @@ public abstract class Vala.Literal : CodeNode { * Specifies the type of this literal. */ public TypeReference static_type { get; set; } + + public abstract ref string! to_string (); } diff --git a/vala/vala/valaliteralexpression.vala b/vala/vala/valaliteralexpression.vala index 5c740f2..6a29a03 100644 --- a/vala/vala/valaliteralexpression.vala +++ b/vala/vala/valaliteralexpression.vala @@ -47,4 +47,8 @@ public class Vala.LiteralExpression : Expression { visitor.visit_literal_expression (this); } + + public override ref string! to_string () { + return literal.to_string (); + } } diff --git a/vala/vala/valamemberaccess.vala b/vala/vala/valamemberaccess.vala index bc77ad1..c0bdde6 100644 --- a/vala/vala/valamemberaccess.vala +++ b/vala/vala/valamemberaccess.vala @@ -35,6 +35,8 @@ public class Vala.MemberAccess : Expression { * The name of the member. */ public string! member_name { get; set construct; } + + private List type_argument_list; /** * Creates a new member access expression. @@ -48,6 +50,24 @@ public class Vala.MemberAccess : Expression { return new MemberAccess (inner = inner, member_name = member, source_reference = source); } + /** + * Appends the specified type as generic type argument. + * + * @param arg a type reference + */ + public void add_type_argument (TypeReference! arg) { + type_argument_list.append (arg); + } + + /** + * Returns a copy of the list of generic type arguments. + * + * @return type argument list + */ + public ref List get_type_arguments () { + return type_argument_list.copy (); + } + public override void accept (CodeVisitor! visitor) { if (inner != null) { inner.accept (visitor); @@ -55,4 +75,12 @@ public class Vala.MemberAccess : Expression { visitor.visit_member_access (this); } + + public override ref string! to_string () { + if (inner == null) { + return member_name; + } else { + return "%s.%s".printf (inner.to_string (), member_name); + } + } } diff --git a/vala/vala/valamethod.vala b/vala/vala/valamethod.vala index 2da57d5..2234ece 100644 --- a/vala/vala/valamethod.vala +++ b/vala/vala/valamethod.vala @@ -29,14 +29,14 @@ public class Vala.Method : CodeNode { /** * The symbol name of this method. */ - public string! name { get; set construct; } + public string name { get; set; } /** * The return type of this method. */ - public TypeReference! return_type { get; set construct; } + public TypeReference return_type { get; set; } - public Statement body { get; set; } + public Block body { get; set; } /** * Specifies the accessibility of this method. Public accessibility @@ -77,6 +77,16 @@ public class Vala.Method : CodeNode { * of a base type. */ public bool overrides { get; set; } + + /** + * Specifies whether this is a construction method. + */ + public bool construction { get; set; } + + /** + * Specifies the number of parameters this construction method sets. + */ + public int n_construction_params { get; set; } /** * Specifies whether the C method returns a new instance pointer which @@ -115,7 +125,7 @@ public class Vala.Method : CodeNode { * @param source reference to source code * @return newly created method */ - public static ref Method! new (string! name, TypeReference! return_type, SourceReference source) { + public static ref Method! new (string name, TypeReference return_type, SourceReference source) { return (new Method (name = name, return_type = return_type, source_reference = source)); } @@ -140,7 +150,9 @@ public class Vala.Method : CodeNode { public override void accept (CodeVisitor! visitor) { visitor.visit_begin_method (this); - return_type.accept (visitor); + if (return_type != null) { + return_type.accept (visitor); + } foreach (FormalParameter param in parameters) { param.accept (visitor); @@ -162,7 +174,15 @@ public class Vala.Method : CodeNode { if (cname == null) { var parent = symbol.parent_symbol.node; if (parent is DataType) { - cname = "%s_%s".printf (((DataType) parent).get_lower_case_cname (null), name); + if (construction) { + if (name == null) { + cname = "%s_new".printf (((DataType) parent).get_lower_case_cname (null)); + } else { + cname = "%s_new_%s".printf (((DataType) parent).get_lower_case_cname (null), name); + } + } else { + cname = "%s_%s".printf (((DataType) parent).get_lower_case_cname (null), name); + } } else if (parent is Namespace) { cname = "%s%s".printf (((Namespace) parent).get_lower_case_cprefix (), name); } else { diff --git a/vala/vala/valanullliteral.vala b/vala/vala/valanullliteral.vala index b506947..f835b81 100644 --- a/vala/vala/valanullliteral.vala +++ b/vala/vala/valanullliteral.vala @@ -22,14 +22,25 @@ using GLib; -namespace Vala { - public class NullLiteral : Literal { - public static ref NullLiteral! new (SourceReference source) { - return (new NullLiteral (source_reference = source)); - } - - public override void accept (CodeVisitor! visitor) { - visitor.visit_null_literal (this); - } +/** + * Represents a literal `null' in the source code. + */ +public class Vala.NullLiteral : Literal { + /** + * Creates a new null literal. + * + * @param source reference to source code + * @return newly created null literal + */ + public static ref NullLiteral! new (SourceReference source) { + return (new NullLiteral (source_reference = source)); + } + + public override void accept (CodeVisitor! visitor) { + visitor.visit_null_literal (this); + } + + public override ref string! to_string () { + return "null"; } } diff --git a/vala/vala/valaobjectcreationexpression.vala b/vala/vala/valaobjectcreationexpression.vala index e5f4917..a12a949 100644 --- a/vala/vala/valaobjectcreationexpression.vala +++ b/vala/vala/valaobjectcreationexpression.vala @@ -22,23 +22,73 @@ using GLib; -namespace Vala { - public class ObjectCreationExpression : Expression { - public TypeReference type_reference { get; construct; } - public List named_argument_list { get; construct; } +/** + * Represents an object creation expression in the source code. + */ +public class Vala.ObjectCreationExpression : Expression { + /** + * The object type to create. + */ + public TypeReference type_reference { get; set; } - public static ref ObjectCreationExpression new (TypeReference type, List named_argument_list, SourceReference source) { - return (new ObjectCreationExpression (type_reference = type, named_argument_list = named_argument_list, source_reference = source)); - } - - public override void accept (CodeVisitor! visitor) { + /** + * The construction method to use. May be null to indicate that + * the default construction method should be used. + */ + public Method constructor { get; set; } + + /** + * The construction method to use or the data type to be created + * with the default construction method. + */ + public MemberAccess member_name { get; set; } + + private List argument_list; + + /** + * Creates a new object creation expression. + * + * @param type object type to create + * @param source reference to source code + * @return newly created object creation expression + */ + public static ref ObjectCreationExpression! new (MemberAccess! name, SourceReference source) { + return (new ObjectCreationExpression (member_name = name, source_reference = source)); + } + + /** + * Appends the specified expression to the list of arguments. + * + * @param arg an argument + */ + public void add_argument (Expression! arg) { + argument_list.append (arg); + } + + /** + * Returns a copy of the argument list. + * + * @return argument list + */ + public ref List get_argument_list () { + return argument_list.copy (); + } + + public override void accept (CodeVisitor! visitor) { + if (type_reference != null) { type_reference.accept (visitor); - - foreach (NamedArgument arg in named_argument_list) { - arg.accept (visitor); - } + } + + if (member_name != null) { + member_name.accept (visitor); + } - visitor.visit_object_creation_expression (this); + visitor.visit_begin_object_creation_expression (this); + + foreach (Expression arg in argument_list) { + arg.accept (visitor); } + + visitor.visit_end_object_creation_expression (this); } } diff --git a/vala/vala/valaproperty.vala b/vala/vala/valaproperty.vala index a0b6ee4..b33ff70 100644 --- a/vala/vala/valaproperty.vala +++ b/vala/vala/valaproperty.vala @@ -22,65 +22,122 @@ using GLib; -namespace Vala { - public class Property : CodeNode { - public string name { get; construct; } - public TypeReference type_reference { get; construct; } - public PropertyAccessor get_accessor { get; construct; } - public PropertyAccessor set_accessor { get; construct; } - public MemberAccessibility access; - public FormalParameter this_parameter; - public bool no_accessor_method; - - public static ref Property new (string name, TypeReference type, PropertyAccessor get_accessor, PropertyAccessor set_accessor, SourceReference source) { - return (new Property (name = name, type_reference = type, get_accessor = get_accessor, set_accessor = set_accessor, source_reference = source)); - } - - public override void accept (CodeVisitor! visitor) { - visitor.visit_begin_property (this); +/** + * Represents a property declaration in the source code. + */ +public class Vala.Property : CodeNode { + /** + * The property name. + */ + public string! name { get; set construct; } + + /** + * The property type. + */ + public TypeReference! type_reference { get; set construct; } + + /** + * The get accessor of this property if available. + */ + public PropertyAccessor get_accessor { get; set; } + + /** + * The set/construct accessor of this property if available. + */ + public PropertyAccessor set_accessor { get; set; } + + /** + * Specifies the accessibility of this property. Public accessibility + * doesn't limit access. Default accessibility limits access to this + * program or library. Private accessibility limits access to the parent + * class. + */ + public MemberAccessibility access { get; set; } + + /** + * Represents the generated ´this' parameter in this property. + */ + public FormalParameter this_parameter { get; set; } + + /** + * Specifies whether the implementation of this property does not + * provide getter/setter methods. + */ + public bool no_accessor_method { get; set; } + + /** + * Creates a new property. + * + * @param name property name + * @param type property type + * @param get_accessor get accessor + * @param set_accessor set/construct accessor + * @param source reference to source code + * @return newly created property + */ + public static ref Property! new (string! name, TypeReference! type, PropertyAccessor get_accessor, PropertyAccessor set_accessor, SourceReference source) { + return (new Property (name = name, type_reference = type, get_accessor = get_accessor, set_accessor = set_accessor, source_reference = source)); + } + + public override void accept (CodeVisitor! visitor) { + visitor.visit_begin_property (this); - type_reference.accept (visitor); - - if (get_accessor != null) { - get_accessor.accept (visitor); - } - if (set_accessor != null) { - set_accessor.accept (visitor); - } + type_reference.accept (visitor); - visitor.visit_end_property (this); + if (get_accessor != null) { + get_accessor.accept (visitor); } - - public ref string get_upper_case_cname () { - return "%s_%s".printf (((Class) symbol.parent_symbol.node).get_lower_case_cname (null), Namespace.camel_case_to_lower_case (name)).up (); + if (set_accessor != null) { + set_accessor.accept (visitor); } + + visitor.visit_end_property (this); + } + + /** + * Returns the C name of this property in upper case. Words are + * separated by underscores. The upper case C name of the class is + * prefix of the result. + * + * @return the upper case name to be used in C code + */ + public ref string! get_upper_case_cname () { + return "%s_%s".printf (((Class) symbol.parent_symbol.node).get_lower_case_cname (null), Namespace.camel_case_to_lower_case (name)).up (); + } + + /** + * Returns the string literal of this property to be used in C code. + * + * @return string literal to be used in C code + */ + public ref CCodeConstant! get_canonical_cconstant () { + var str = String.new ("\""); - public ref CCodeConstant get_canonical_cconstant () { - var str = String.new ("\""); - - string i = name; - - while (i.len () > 0) { - unichar c = i.get_char (); - if (c == '_') { - str.append_c ('-'); - } else { - str.append_unichar (c); - } - - i = i.next_char (); + string i = name; + + while (i.len () > 0) { + unichar c = i.get_char (); + if (c == '_') { + str.append_c ('-'); + } else { + str.append_unichar (c); } - str.append_c ('"'); - - return new CCodeConstant (name = str.str); + i = i.next_char (); } - public void process_attributes () { - foreach (Attribute a in attributes) { - if (a.name == "NoAccessorMethod") { - no_accessor_method = true; - } + str.append_c ('"'); + + return new CCodeConstant (name = str.str); + } + + /** + * Process all associated attributes. + */ + public void process_attributes () { + foreach (Attribute a in attributes) { + if (a.name == "NoAccessorMethod") { + no_accessor_method = true; } } } diff --git a/vala/vala/valapropertyaccessor.vala b/vala/vala/valapropertyaccessor.vala index fecbd3d..5d33c7b 100644 --- a/vala/vala/valapropertyaccessor.vala +++ b/vala/vala/valapropertyaccessor.vala @@ -22,26 +22,57 @@ using GLib; -namespace Vala { - public class PropertyAccessor : CodeNode { - public bool readable { get; construct; } - public bool writable { get; construct; } - public bool construct_ { get; construct; } - public Statement body { get; construct; } - public FormalParameter value_parameter; - - public static ref PropertyAccessor new (bool readable, bool writable, bool construct_, Statement body, SourceReference source) { - return (new PropertyAccessor (readable = readable, writable = writable, construct_ = construct_, body = body, source_reference = source)); - } - - public override void accept (CodeVisitor! visitor) { - visitor.visit_begin_property_accessor (this); +/** + * Represents a get or set accessor of a property in the source code. + */ +public class Vala.PropertyAccessor : CodeNode { + /** + * Specifies whether this accessor may be used to get the property. + */ + public bool readable { get; set; } + + /** + * Specifies whether this accessor may be used to set the property. + */ + public bool writable { get; set; } + + /** + * Specifies whether this accessor may be used to construct the + * property. + */ + public bool construction { get; set; } + + /** + * The accessor body. + */ + public Statement body { get; set; } + + /** + * Represents the generated value parameter in a set accessor. + */ + public FormalParameter value_parameter { get; set; } + + /** + * Creates a new property accessor. + * + * @param readable true if get accessor, false otherwise + * @param writable true if set accessor, false otherwise + * @param construction true if construct accessor, false otherwise + * @param body accessor body + * @param source reference to source code + * @return newly created property accessor + */ + public static ref PropertyAccessor! new (bool readable, bool writable, bool construction, Statement body, SourceReference source) { + return (new PropertyAccessor (readable = readable, writable = writable, construction = construction, body = body, source_reference = source)); + } + + public override void accept (CodeVisitor! visitor) { + visitor.visit_begin_property_accessor (this); - if (body != null) { - body.accept (visitor); - } - - visitor.visit_end_property_accessor (this); + if (body != null) { + body.accept (visitor); } + + visitor.visit_end_property_accessor (this); } } diff --git a/vala/vala/valasemanticanalyzer.vala b/vala/vala/valasemanticanalyzer.vala index 53cbf01..fd12b6d 100644 --- a/vala/vala/valasemanticanalyzer.vala +++ b/vala/vala/valasemanticanalyzer.vala @@ -128,6 +128,16 @@ public class Vala.SemanticAnalyzer : CodeVisitor { } public override void visit_begin_method (Method! m) { + if (m.construction) { + m.return_type = new TypeReference (); + m.return_type.data_type = (DataType) current_symbol.node; + m.return_type.transfers_ownership = true; + + if (m.body != null) { + m.body.construction = true; + } + } + current_symbol = m.symbol; current_return_type = m.return_type; @@ -193,6 +203,19 @@ public class Vala.SemanticAnalyzer : CodeVisitor { return; } } + + if (m.construction && m.body != null) { + int n_params = 0; + foreach (Statement stmt in m.body.get_statements ()) { + int params = stmt.get_number_of_set_construction_parameters (); + if (params == -1) { + break; + } + n_params += params; + stmt.construction = true; + } + m.n_construction_params = n_params; + } } public override void visit_formal_parameter (FormalParameter! p) { @@ -744,45 +767,8 @@ public class Vala.SemanticAnalyzer : CodeVisitor { } } } - - public override void visit_end_invocation_expression (InvocationExpression! expr) { - if (expr.error) { - return; - } - - var msym = expr.call.symbol_reference; - - TypeReference ret_type; - List params; - - if (msym.node is VariableDeclarator) { - var decl = (VariableDeclarator) msym.node; - var cb = (Callback) decl.type_reference.data_type; - ret_type = cb.return_type; - params = cb.get_parameters (); - } else if (msym.node is FormalParameter) { - var param = (FormalParameter) msym.node; - var cb = (Callback) param.type_reference.data_type; - ret_type = cb.return_type; - params = cb.get_parameters (); - } else if (msym.node is Field) { - var f = (Field) msym.node; - var cb = (Callback) f.type_reference.data_type; - ret_type = cb.return_type; - params = cb.get_parameters (); - } else if (msym.node is Method) { - var m = (Method) msym.node; - ret_type = m.return_type; - params = m.get_parameters (); - } else if (msym.node is Signal) { - var sig = (Signal) msym.node; - ret_type = sig.return_type; - params = sig.get_parameters (); - } - expr.static_type = ret_type; - - var args = expr.get_argument_list (); + private bool check_arguments (Expression! expr, Symbol! msym, List params, List args) { List arg_it = args; bool ellipsis = false; @@ -800,16 +786,18 @@ public class Vala.SemanticAnalyzer : CodeVisitor { if (arg_it == null) { if (param.default_expression == null) { + expr.error = true; Report.error (expr.source_reference, "Too few arguments, method `%s' does not take %d arguments".printf (msym.get_full_name (), args.length ())); - return; + return false; } } else { var arg = (Expression) arg_it.data; if (arg.static_type != null && !is_type_compatible (arg.static_type, param.type_reference)) { /* if there was an error in the argument, * i.e. arg.static_type == null, skip type check */ + expr.error = true; Report.error (expr.source_reference, "Argument %d: Cannot convert from `%s' to `%s'".printf (i + 1, arg.static_type.to_string (), param.type_reference.to_string ())); - return; + return false; } arg_it = arg_it.next; @@ -819,9 +807,52 @@ public class Vala.SemanticAnalyzer : CodeVisitor { } if (!ellipsis && arg_it != null) { + expr.error = true; Report.error (expr.source_reference, "Too many arguments, method `%s' does not take %d arguments".printf (msym.get_full_name (), args.length ())); + return false; + } + + return true; + } + + public override void visit_end_invocation_expression (InvocationExpression! expr) { + if (expr.error) { return; } + + var msym = expr.call.symbol_reference; + + TypeReference ret_type; + List params; + + if (msym.node is VariableDeclarator) { + var decl = (VariableDeclarator) msym.node; + var cb = (Callback) decl.type_reference.data_type; + ret_type = cb.return_type; + params = cb.get_parameters (); + } else if (msym.node is FormalParameter) { + var param = (FormalParameter) msym.node; + var cb = (Callback) param.type_reference.data_type; + ret_type = cb.return_type; + params = cb.get_parameters (); + } else if (msym.node is Field) { + var f = (Field) msym.node; + var cb = (Callback) f.type_reference.data_type; + ret_type = cb.return_type; + params = cb.get_parameters (); + } else if (msym.node is Method) { + var m = (Method) msym.node; + ret_type = m.return_type; + params = m.get_parameters (); + } else if (msym.node is Signal) { + var sig = (Signal) msym.node; + ret_type = sig.return_type; + params = sig.get_parameters (); + } + + expr.static_type = ret_type; + + check_arguments (expr, msym, params, expr.get_argument_list ()); } public override void visit_element_access (ElementAccess! expr) { @@ -851,33 +882,74 @@ public class Vala.SemanticAnalyzer : CodeVisitor { expr.static_type = expr.inner.static_type; } - public override void visit_object_creation_expression (ObjectCreationExpression! expr) { - if (expr.type_reference.data_type == null) { - /* if type resolving didn't succeed, skip this check */ - return; - } + public override void visit_end_object_creation_expression (ObjectCreationExpression! expr) { + DataType type = null; - if (!expr.type_reference.data_type.is_reference_type ()) { + if (expr.type_reference == null) { + if (expr.member_name == null) { + expr.error = true; + Report.error (expr.source_reference, "Incomplete object creation expression"); + return; + } + + if (expr.member_name.symbol_reference == null) { + expr.error = true; + return; + } + + var constructor_node = expr.member_name.symbol_reference.node; + var type_node = expr.member_name.symbol_reference.node; + + if (constructor_node is Method) { + type_node = constructor_node.symbol.parent_symbol.node; + + var constructor = (Method) constructor_node; + if (!constructor.construction) { + expr.error = true; + Report.error (expr.source_reference, "`%s' is not a construction method".printf (constructor.symbol.get_full_name ())); + return; + } + + expr.symbol_reference = constructor.symbol; + } + + if (type_node is Class || type_node is Struct) { + type = (DataType) type_node; + } else { + expr.error = true; + Report.error (expr.source_reference, "`%s' is not a class or struct".printf (type.symbol.get_full_name ())); + return; + } + } + + if (!type.is_reference_type ()) { expr.error = true; Report.error (expr.source_reference, "Can't create instance of value type `%s'".printf (expr.type_reference.to_string ())); return; } - current_source_file.add_symbol_dependency (expr.type_reference.data_type.symbol, SourceFileDependencyType.SOURCE); + current_source_file.add_symbol_dependency (type.symbol, SourceFileDependencyType.SOURCE); + + expr.type_reference = new TypeReference (); + expr.type_reference.data_type = type; expr.static_type = expr.type_reference.copy (); expr.static_type.transfers_ownership = true; - if (expr.type_reference.data_type is Class) { - var cl = (Class) expr.type_reference.data_type; + if (type is Class) { + var cl = (Class) type; if (cl.is_abstract) { expr.static_type = null; expr.error = true; - Report.error (expr.source_reference, "Can't create instance of abstract class `%s'".printf (expr.type_reference.to_string ())); + Report.error (expr.source_reference, "Can't create instance of abstract class `%s'".printf (cl.symbol.get_full_name ())); return; } + if (expr.symbol_reference == null && cl.default_construction_method != null) { + expr.symbol_reference = cl.default_construction_method.symbol; + } + while (cl != null) { if (cl == initially_unowned_type) { expr.static_type.floating_reference = true; @@ -886,12 +958,25 @@ public class Vala.SemanticAnalyzer : CodeVisitor { cl = cl.base_class; } - } else if (expr.named_argument_list.length () != 0) { + } else if (type is Struct) { + var st = (Struct) type; + + if (expr.symbol_reference == null && st.default_construction_method != null) { + expr.symbol_reference = st.default_construction_method.symbol; + } + } + + if (expr.symbol_reference == null && expr.get_argument_list ().length () != 0) { expr.static_type = null; expr.error = true; - Report.error (expr.source_reference, "No arguments allowed when constructing struct `%s'".printf (expr.type_reference.to_string ())); + Report.error (expr.source_reference, "No arguments allowed when constructing type `%s'".printf (type.symbol.get_full_name ())); return; } + + if (expr.symbol_reference != null) { + var m = (Method) expr.symbol_reference.node; + check_arguments (expr, m.symbol, m.get_parameters (), expr.get_argument_list ()); + } } public override void visit_unary_expression (UnaryExpression! expr) { diff --git a/vala/vala/valastatement.vala b/vala/vala/valastatement.vala index f38ea1a..33793fd 100644 --- a/vala/vala/valastatement.vala +++ b/vala/vala/valastatement.vala @@ -26,4 +26,20 @@ using GLib; * Base class for all statement types. */ public abstract class Vala.Statement : CodeNode { + /** + * Specifies whether this statement is in the construction part + * of a construction method. + */ + public bool construction { get; set; } + + /** + * Returns the number of construction parameters this statement sets in + * maximum or -1 if this statement may not be used in the construction + * part of a construction method. + * + * @return number of construction parameters set or -1 + */ + public virtual int get_number_of_set_construction_parameters () { + return -1; + } } diff --git a/vala/vala/valastruct.vala b/vala/vala/valastruct.vala index 4397e6d..bd8282a 100644 --- a/vala/vala/valastruct.vala +++ b/vala/vala/valastruct.vala @@ -40,6 +40,11 @@ public class Vala.Struct : DataType { string marshaller_type_name; /** + * Specifies the default construction method. + */ + public Method default_construction_method { get; set; } + + /** * Creates a new struct. * * @param name type name diff --git a/vala/vala/valasymbolbuilder.vala b/vala/vala/valasymbolbuilder.vala index 764d1d4..3288891 100644 --- a/vala/vala/valasymbolbuilder.vala +++ b/vala/vala/valasymbolbuilder.vala @@ -65,14 +65,20 @@ public class Vala.SymbolBuilder : CodeVisitor { current_symbol = current_symbol.parent_symbol; } - private Symbol add_symbol (string! name, CodeNode! node) { - if (current_symbol.lookup (name) != null) { - node.error = true; - Report.error (node.source_reference, "`%s' already contains a definition for `%s'".printf (current_symbol.get_full_name (), name)); - return null; + private Symbol add_symbol (string name, CodeNode! node) { + if (name != null) { + if (current_symbol.lookup (name) != null) { + node.error = true; + Report.error (node.source_reference, "`%s' already contains a definition for `%s'".printf (current_symbol.get_full_name (), name)); + return null; + } } node.symbol = new Symbol (node = node); - current_symbol.add (name, node.symbol); + if (name != null) { + current_symbol.add (name, node.symbol); + } else { + node.symbol.parent_symbol = current_symbol; + } return node.symbol; } @@ -180,7 +186,23 @@ public class Vala.SymbolBuilder : CodeVisitor { return; } - if (m.instance) { + if (m.construction) { + var type_node = m.symbol.parent_symbol.node; + if (!(type_node is Class || type_node is Struct)) { + Report.error (m.source_reference, "construction methods may only be declared within classes and structs"); + + m.error = true; + return; + } + + if (m.name == null) { + if (type_node is Class) { + ((Class) type_node).default_construction_method = m; + } else if (type_node is Struct) { + ((Struct) type_node).default_construction_method = m; + } + } + } else if (m.instance) { if (!(m.symbol.parent_symbol.node is DataType)) { Report.error (m.source_reference, "instance methods not allowed outside of data types"); @@ -243,7 +265,7 @@ public class Vala.SymbolBuilder : CodeVisitor { return; } - if (acc.writable || acc.construct_) { + if (acc.writable || acc.construction) { acc.value_parameter = new FormalParameter (name = "value", type_reference = ((Property) current_symbol.parent_symbol.node).type_reference); acc.value_parameter.symbol = new Symbol (node = acc.value_parameter); diff --git a/vala/vala/valatypereference.vala b/vala/vala/valatypereference.vala index ef6ad80..708ef1f 100644 --- a/vala/vala/valatypereference.vala +++ b/vala/vala/valatypereference.vala @@ -126,14 +126,25 @@ public class Vala.TypeReference : CodeNode { string ns = null; string type_name = null; if (expr is MemberAccess) { + TypeReference type_ref = null; + MemberAccess ma = (MemberAccess) expr; if (ma.inner != null) { if (ma.inner is MemberAccess) { var simple = (MemberAccess) ma.inner; - return (new TypeReference (namespace_name = simple.member_name, type_name = ma.member_name, source_reference = source)); + type_ref = new TypeReference (namespace_name = simple.member_name, type_name = ma.member_name, source_reference = source); } } else { - return (new TypeReference (type_name = ma.member_name, source_reference = source)); + type_ref = new TypeReference (type_name = ma.member_name, source_reference = source); + } + + if (type_ref != null) { + var type_args = ma.get_type_arguments (); + foreach (TypeReference arg in type_args) { + type_ref.add_type_argument (arg); + } + + return type_ref; } } diff --git a/vala/vapi/glib-2.0.vala b/vala/vapi/glib-2.0.vala index a1a086b..81a974e 100644 --- a/vala/vapi/glib-2.0.vala +++ b/vala/vapi/glib-2.0.vala @@ -214,6 +214,11 @@ namespace GLib { public abstract class InitiallyUnowned : Object { } + [ReferenceType (free_function = "g_free")] + public struct Value { + public Object get_object (); + } + [ReferenceType (dup_function = "g_main_loop_ref", free_function = "g_main_loop_unref")] public struct MainLoop { public static ref MainLoop new (MainContext context, bool is_running); diff --git a/vala/vapi/gtk+-2.0.vala b/vala/vapi/gtk+-2.0.vala index 5b6b2ef..3cf68a5 100644 --- a/vala/vapi/gtk+-2.0.vala +++ b/vala/vapi/gtk+-2.0.vala @@ -87,6 +87,10 @@ namespace Gtk { public bool use_markup { get; set; } } + public class ProgressBar : Widget { + public void pulse (); + } + public class StatusIcon { public static ref StatusIcon! new_from_stock (string! stock_id); @@ -121,6 +125,13 @@ namespace Gtk { } public interface TreeModel { + public abstract void get_value (ref TreeIter iter, int column, GLib.Value value); + } + + public class TreeSelection { + public bool get_selected (out TreeModel model, ref TreeIter iter); + + public signal void changed (); } public struct TreeIter { @@ -130,14 +141,23 @@ namespace Gtk { public pointer user_data3; } + [CCode (cprefix = "GTK_TREE_VIEW_COLUMN_")] + public enum TreeViewColumnSizing { + FIXED + } + public class TreeViewColumn : Object { [FloatingReference ()] public static ref TreeViewColumn new_with_attributes (string title, CellRenderer cell, ...); + + public int fixed_width { get; set; } + public TreeViewColumnSizing sizing { get; set; } } public class TreeView : Container { public TreeModel model { get; set; } + public TreeSelection get_selection (); public int append_column (TreeViewColumn column); } @@ -190,6 +210,9 @@ namespace Gtk { public static ref VBox new (bool homogeneous, int spacing); } + public class VPaned : Paned { + } + public class Notebook : Container { public int append_page (Widget child, Widget tab_label); } @@ -222,9 +245,14 @@ namespace Gtk { public signal void destroy (); } + public abstract class Paned : Container { + public void pack2 (Widget! child, bool resize, bool shrink); + } + public abstract class Widget : Object { public void show (); public void show_all (); + public void hide (); [NoAccessorMethod ()] public bool visible { get; set; } -- 2.7.4