diff options
author | Jürg Billeter <j@bitron.ch> | 2007-05-02 09:42:00 +0000 |
---|---|---|
committer | Jürg Billeter <juergbi@src.gnome.org> | 2007-05-02 09:42:00 +0000 |
commit | f8387ad143f1884f8f5f89bd5389605624f4c34f (patch) | |
tree | e75e563fc9535200ec146af72962e80778359ae4 /vala | |
parent | 9db973114ee1449c1764404163ecc8294f8e73d2 (diff) | |
download | vala-f8387ad143f1884f8f5f89bd5389605624f4c34f.tar.gz |
Move contents of vala-pkg to trunk
2007-05-02 Jürg Billeter <j@bitron.ch>
* Move contents of vala-pkg to trunk
svn path=/trunk/; revision=300
Diffstat (limited to 'vala')
108 files changed, 23843 insertions, 0 deletions
diff --git a/vala/Makefile.am b/vala/Makefile.am new file mode 100644 index 000000000..f9a1fb15c --- /dev/null +++ b/vala/Makefile.am @@ -0,0 +1,450 @@ +NULL = + +INCLUDES = \ + $(GLIB_CFLAGS) \ + $(NULL) + +BUILT_SOURCES = parser.h vala.vala.stamp +AM_YFLAGS = -d + +lib_LTLIBRARIES = \ + libvala.la + $(NULL) + +libvala_la_SOURCES = \ + parser.y \ + scanner.l \ + vala.h \ + vala.vala.stamp \ + valaaddressofexpression.c \ + valaaddressofexpression.h \ + valaaddressofexpression.vala \ + valaarray.c \ + valaarray.h \ + valaarray.vala \ + valaarraycreationexpression.c \ + valaarraycreationexpression.h \ + valaarraycreationexpression.vala \ + valaarraylengthfield.c \ + valaarraylengthfield.h \ + valaarraylengthfield.vala \ + valaarrayresizemethod.c \ + valaarrayresizemethod.h \ + valaarrayresizemethod.vala \ + valaassignment.c \ + valaassignment.h \ + valaassignment.vala \ + valaattribute.c \ + valaattribute.h \ + valaattribute.vala \ + valaattributeprocessor.c \ + valaattributeprocessor.h \ + valaattributeprocessor.vala \ + valabaseaccess.c \ + valabaseaccess.h \ + valabaseaccess.vala \ + valabinaryexpression.c \ + valabinaryexpression.h \ + valabinaryexpression.vala \ + valablock.c \ + valablock.h \ + valablock.vala \ + valabooleanliteral.c \ + valabooleanliteral.h \ + valabooleanliteral.vala \ + valabreakstatement.c \ + valabreakstatement.h \ + valabreakstatement.vala \ + valacallback.c \ + valacallback.h \ + valacallback.vala \ + valacastexpression.c \ + valacastexpression.h \ + valacastexpression.vala \ + valacatchclause.c \ + valacatchclause.h \ + valacatchclause.vala \ + valacharacterliteral.c \ + valacharacterliteral.h \ + valacharacterliteral.vala \ + valaclass.c \ + valaclass.h \ + valaclass.vala \ + valaclassregisterfunction.c \ + valaclassregisterfunction.h \ + valaclassregisterfunction.vala \ + valacodecontext.c \ + valacodecontext.h \ + valacodecontext.vala \ + valacodegenerator.c \ + valacodegenerator.h \ + valacodegenerator.vala \ + valacodenode.c \ + valacodenode.h \ + valacodenode.vala \ + valacodevisitor.c \ + valacodevisitor.h \ + valacodevisitor.vala \ + valaconditionalexpression.c \ + valaconditionalexpression.h \ + valaconditionalexpression.vala \ + valaconstant.c \ + valaconstant.h \ + valaconstant.vala \ + valaconstructor.c \ + valaconstructor.h \ + valaconstructor.vala \ + valacontinuestatement.c \ + valacontinuestatement.h \ + valacontinuestatement.vala \ + valacreationmethod.c \ + valacreationmethod.h \ + valacreationmethod.vala \ + valadatatype.c \ + valadatatype.h \ + valadatatype.vala \ + valadeclarationstatement.c \ + valadeclarationstatement.h \ + valadeclarationstatement.vala \ + valadestructor.c \ + valadestructor.h \ + valadestructor.vala \ + valadostatement.c \ + valadostatement.h \ + valadostatement.vala \ + valaelementaccess.c \ + valaelementaccess.h \ + valaelementaccess.vala \ + valaemptystatement.c \ + valaemptystatement.h \ + valaemptystatement.vala \ + valaenum.c \ + valaenum.h \ + valaenum.vala \ + valaenumvalue.c \ + valaenumvalue.h \ + valaenumvalue.vala \ + valaexpression.c \ + valaexpression.h \ + valaexpression.vala \ + valaexpressionstatement.c \ + valaexpressionstatement.h \ + valaexpressionstatement.vala \ + valafield.c \ + valafield.h \ + valafield.vala \ + valaflags.c \ + valaflags.h \ + valaflags.vala \ + valaflagsvalue.c \ + valaflagsvalue.h \ + valaflagsvalue.vala \ + valaforeachstatement.c \ + valaforeachstatement.h \ + valaforeachstatement.vala \ + valaformalparameter.c \ + valaformalparameter.h \ + valaformalparameter.vala \ + valaforstatement.c \ + valaforstatement.h \ + valaforstatement.vala \ + valaifstatement.c \ + valaifstatement.h \ + valaifstatement.vala \ + valainitializerlist.c \ + valainitializerlist.h \ + valainitializerlist.vala \ + valainstancecast.c \ + valainstancecast.h \ + valainstancecast.vala \ + valaintegerliteral.c \ + valaintegerliteral.h \ + valaintegerliteral.vala \ + valainterface.c \ + valainterface.h \ + valainterface.vala \ + valainterfaceregisterfunction.c \ + valainterfaceregisterfunction.h \ + valainterfaceregisterfunction.vala \ + valainterfacewriter.c \ + valainterfacewriter.h \ + valainterfacewriter.vala \ + valainvocationexpression.c \ + valainvocationexpression.h \ + valainvocationexpression.vala \ + valainvokable.c \ + valainvokable.h \ + valainvokable.vala \ + valalambdaexpression.c \ + valalambdaexpression.h \ + valalambdaexpression.vala \ + valaliteral.c \ + valaliteral.h \ + valaliteral.vala \ + valaliteralexpression.c \ + valaliteralexpression.h \ + valaliteralexpression.vala \ + valalocalvariabledeclaration.c \ + valalocalvariabledeclaration.h \ + valalocalvariabledeclaration.vala \ + valalockable.c \ + valalockable.h \ + valalockable.vala \ + valalockstatement.c \ + valalockstatement.h \ + valalockstatement.vala \ + valamember.c \ + valamember.h \ + valamember.vala \ + valamemberaccess.c \ + valamemberaccess.h \ + valamemberaccess.vala \ + valamemberaccessibility.c \ + valamemberaccessibility.h \ + valamemberaccessibility.vala \ + valamemorymanager.c \ + valamemorymanager.h \ + valamemorymanager.vala \ + valamethod.c \ + valamethod.h \ + valamethod.vala \ + valanamedargument.c \ + valanamedargument.h \ + valanamedargument.vala \ + valanamespace.c \ + valanamespace.h \ + valanamespace.vala \ + valanamespacereference.c \ + valanamespacereference.h \ + valanamespacereference.vala \ + valanullliteral.c \ + valanullliteral.h \ + valanullliteral.vala \ + valaobjectcreationexpression.c \ + valaobjectcreationexpression.h \ + valaobjectcreationexpression.vala \ + valaparenthesizedexpression.c \ + valaparenthesizedexpression.h \ + valaparenthesizedexpression.vala \ + valaparser.c \ + valaparser.h \ + valaparser.vala \ + valapointer.c \ + valapointer.h \ + valapointer.vala \ + valapointerindirection.c \ + valapointerindirection.h \ + valapointerindirection.vala \ + valapostfixexpression.c \ + valapostfixexpression.h \ + valapostfixexpression.vala \ + valapropertyaccessor.c \ + valapropertyaccessor.h \ + valapropertyaccessor.vala \ + valaproperty.c \ + valaproperty.h \ + valaproperty.vala \ + valarealliteral.c \ + valarealliteral.h \ + valarealliteral.vala \ + valareferencetransferexpression.c \ + valareferencetransferexpression.h \ + valareferencetransferexpression.vala \ + valareport.c \ + valareport.h \ + valareport.vala \ + valareturnstatement.c \ + valareturnstatement.h \ + valareturnstatement.vala \ + valasemanticanalyzer.c \ + valasemanticanalyzer.h \ + valasemanticanalyzer.vala \ + valasignal.c \ + valasignal.h \ + valasignal.vala \ + valasourcefile.c \ + valasourcefile.h \ + valasourcefile.vala \ + valasourcefilecycle.c \ + valasourcefilecycle.h \ + valasourcefilecycle.vala \ + valasourcereference.c \ + valasourcereference.h \ + valasourcereference.vala \ + valastatement.c \ + valastatement.h \ + valastatement.vala \ + valastringliteral.c \ + valastringliteral.h \ + valastringliteral.vala \ + valastruct.c \ + valastruct.h \ + valastruct.vala \ + valaswitchlabel.c \ + valaswitchlabel.h \ + valaswitchlabel.vala \ + valaswitchsection.c \ + valaswitchsection.h \ + valaswitchsection.vala \ + valaswitchstatement.c \ + valaswitchstatement.h \ + valaswitchstatement.vala \ + valasymbolbuilder.c \ + valasymbolbuilder.h \ + valasymbolbuilder.vala \ + valasymbol.c \ + valasymbol.h \ + valasymbol.vala \ + valasymbolresolver.c \ + valasymbolresolver.h \ + valasymbolresolver.vala \ + valathrowstatement.c \ + valathrowstatement.h \ + valathrowstatement.vala \ + valatrystatement.c \ + valatrystatement.h \ + valatrystatement.vala \ + valatypecheck.c \ + valatypecheck.h \ + valatypecheck.vala \ + valatypeofexpression.c \ + valatypeofexpression.h \ + valatypeofexpression.vala \ + valatypeparameter.c \ + valatypeparameter.h \ + valatypeparameter.vala \ + valatypereference.c \ + valatypereference.h \ + valatypereference.vala \ + valatyperegisterfunction.c \ + valatyperegisterfunction.h \ + valatyperegisterfunction.vala \ + valaunaryexpression.c \ + valaunaryexpression.h \ + valaunaryexpression.vala \ + valavariabledeclarator.c \ + valavariabledeclarator.h \ + valavariabledeclarator.vala \ + valawhilestatement.c \ + valawhilestatement.h \ + valawhilestatement.vala \ + $(NULL) + +valaincludedir = $(includedir)/vala-1.0/vala + +valainclude_HEADERS = \ + vala.h \ + valaaddressofexpression.h \ + valaarray.h \ + valaarraycreationexpression.h \ + valaassignment.h \ + valaattribute.h \ + valaattributeprocessor.h \ + valabaseaccess.h \ + valabinaryexpression.h \ + valablock.h \ + valabooleanliteral.h \ + valabreakstatement.h \ + valacallback.h \ + valacastexpression.h \ + valacatchclause.h \ + valacharacterliteral.h \ + valaclass.h \ + valaclassregisterfunction.h \ + valacodecontext.h \ + valacodegenerator.h \ + valacodenode.h \ + valacodevisitor.h \ + valaconditionalexpression.h \ + valaconstant.h \ + valaconstructor.h \ + valacontinuestatement.h \ + valacreationmethod.h \ + valadatatype.h \ + valadeclarationstatement.h \ + valadestructor.h \ + valadostatement.h \ + valaelementaccess.h \ + valaemptystatement.h \ + valaenum.h \ + valaenumvalue.h \ + valaexpression.h \ + valaexpressionstatement.h \ + valafield.h \ + valaflags.h \ + valaflagsvalue.h \ + valaforeachstatement.h \ + valaformalparameter.h \ + valaforstatement.h \ + valaifstatement.h \ + valainitializerlist.h \ + valainstancecast.h \ + valaintegerliteral.h \ + valainterface.h \ + valainterfaceregisterfunction.h \ + valainterfacewriter.h \ + valainvocationexpression.h \ + valainvokable.h \ + valalambdaexpression.h \ + valaliteral.h \ + valaliteralexpression.h \ + valalocalvariabledeclaration.h \ + valalockable.h \ + valalockstatement.h \ + valamember.h \ + valamemberaccess.h \ + valamemberaccessibility.h \ + valamemorymanager.h \ + valamethod.h \ + valanamedargument.h \ + valanamespace.h \ + valanamespacereference.h \ + valanullliteral.h \ + valaobjectcreationexpression.h \ + valaparenthesizedexpression.h \ + valaparser.h \ + valapointer.h \ + valapointerindirection.h \ + valapostfixexpression.h \ + valapropertyaccessor.h \ + valaproperty.h \ + valarealliteral.h \ + valareferencetransferexpression.h \ + valareport.h \ + valareturnstatement.h \ + valasemanticanalyzer.h \ + valasignal.h \ + valasourcefile.h \ + valasourcefilecycle.h \ + valasourcereference.h \ + valastatement.h \ + valastringliteral.h \ + valastruct.h \ + valaswitchlabel.h \ + valaswitchsection.h \ + valaswitchstatement.h \ + valasymbolbuilder.h \ + valasymbol.h \ + valasymbolresolver.h \ + valathrowstatement.h \ + valatrystatement.h \ + valatypecheck.h \ + valatypeofexpression.h \ + valatypeparameter.h \ + valatypereference.h \ + valatyperegisterfunction.h \ + valaunaryexpression.h \ + valavariabledeclarator.h \ + valawhilestatement.h \ + $(NULL) + +vala.vala vala.vala.stamp: $(filter %.vala,$(libvala_la_SOURCES)) + $(VALAC) --vapidir $(srcdir)/../vapi --vapidir ../ccode --pkg ccode --library vala $^ + touch $@ + +libvala_la_LIBADD = \ + $(GLIB_LIBS) \ + ../ccode/libvalaccode.la \ + $(NULL) + +EXTRA_DIST = vala.vala vala.vala.stamp diff --git a/vala/parser.y b/vala/parser.y new file mode 100644 index 000000000..b42975439 --- /dev/null +++ b/vala/parser.y @@ -0,0 +1,3513 @@ +/* parser.y + * + * Copyright (C) 2006-2007 Jürg Billeter, Raffaele Sandrini + * + * 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 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> + * Raffaele Sandrini <rasa@gmx.ch> + */ + +%{ +#include <stdlib.h> +#include <stdio.h> +#include <string.h> + +#include <glib.h> + +#include "vala.h" +#include "parser.h" + +#define src(l) (vala_source_reference_new (current_source_file, l.first_line, l.first_column, l.last_line, l.last_column)) + +#define src_com(l,c) (vala_source_reference_new_with_comment (current_source_file, l.first_line, l.first_column, l.last_line, l.last_column, c)) + +static ValaSourceFile *current_source_file; +static ValaNamespace *current_namespace; +static gboolean current_namespace_implicit; +static ValaClass *current_class; +static ValaStruct *current_struct; +static ValaInterface *current_interface; + +typedef enum { + VALA_MODIFIER_NONE, + VALA_MODIFIER_ABSTRACT = 1 << 0, + VALA_MODIFIER_OVERRIDE = 1 << 1, + VALA_MODIFIER_STATIC = 1 << 2, + VALA_MODIFIER_VIRTUAL = 1 << 3, +} ValaModifier; + +int yylex (YYSTYPE *yylval_param, YYLTYPE *yylloc_param, ValaParser *parser); +static void yyerror (YYLTYPE *locp, ValaParser *parser, const char *msg); +%} + +%defines +%locations +%pure-parser +%parse-param {ValaParser *parser} +%lex-param {ValaParser *parser} +%error-verbose +%union { + int num; + char *str; + GList *list; + ValaLiteral *literal; + ValaTypeReference *type_reference; + ValaExpression *expression; + ValaStatement *statement; + ValaNamespace *namespace; + ValaClass *class; + ValaStruct *struct_; + ValaInterface *interface; + ValaEnum *enum_; + ValaEnumValue *enum_value; + ValaFlags *flags; + ValaFlagsValue *flags_value; + ValaCallback *callback; + ValaConstant *constant; + ValaField *field; + ValaMethod *method; + ValaFormalParameter *formal_parameter; + ValaProperty *property; + ValaPropertyAccessor *property_accessor; + ValaSignal *signal; + ValaConstructor *constructor; + ValaDestructor *destructor; + ValaLocalVariableDeclaration *local_variable_declaration; + ValaVariableDeclarator *variable_declarator; + ValaTypeParameter *type_parameter; + ValaAttribute *attribute; + ValaNamedArgument *named_argument; + ValaSwitchSection *switch_section; + ValaSwitchLabel *switch_label; + ValaCatchClause *catch_clause; +} + +%token OPEN_BRACE "{" +%token CLOSE_BRACE "}" +%token OPEN_PARENS "(" +%token OPEN_CAST_PARENS "cast (" +%token CLOSE_PARENS ")" +%token BRACKET_PAIR "[]" +%token OPEN_BRACKET "[" +%token CLOSE_BRACKET "]" +%token ELLIPSIS "..." +%token DOT "." +%token COLON ":" +%token COMMA "," +%token SEMICOLON ";" +%token HASH "#" +%token INTERR "?" + +%token ASSIGN_BITWISE_OR "|=" +%token ASSIGN_BITWISE_AND "&=" +%token ASSIGN_BITWISE_XOR "^=" +%token ASSIGN_ADD "+=" +%token ASSIGN_SUB "-=" +%token ASSIGN_MUL "*=" +%token ASSIGN_DIV "/=" +%token ASSIGN_PERCENT "%=" +%token ASSIGN_SHIFT_LEFT "<<=" +%token ASSIGN_SHIFT_RIGHT ">>=" + +%token OP_INC "++" +%token OP_DEC "--" +%token OP_EQ "==" +%token OP_NE "!=" +%token OP_SHIFT_LEFT "<<" +%token OP_SHIFT_RIGHT ">>" +%token OP_LE "<=" +%token OP_GE ">=" +%token LAMBDA "=>" +%token GENERIC_LT "generic <" +%token OP_LT "<" +%token OP_GT ">" +%token OP_NEG "!" +%token CARRET "^" +%token BITWISE_OR "|" +%token BITWISE_AND "&" +%token OP_OR "||" +%token OP_AND "&&" +%token TILDE "~" + +%token ASSIGN "=" +%token PLUS "+" +%token MINUS "-" +%token STAR "*" +%token DIV "/" +%token PERCENT "%" + +%token ABSTRACT "abstract" +%token BASE "base" +%token BREAK "break" +%token CALLBACK "callback" +%token CASE "case" +%token CATCH "catch" +%token CLASS "class" +%token CONST "const" +%token CONSTRUCT "construct" +%token CONTINUE "continue" +%token DEFAULT "default" +%token DO "do" +%token ELSE "else" +%token ENUM "enum" +%token VALA_FALSE "false" +%token FINALLY "finally" +%token FLAGS "flags" +%token FOR "for" +%token FOREACH "foreach" +%token GET "get" +%token IF "if" +%token IN "in" +%token INTERFACE "interface" +%token IS "is" +%token LOCK "lock" +%token NAMESPACE "namespace" +%token NEW "new" +%token VALA_NULL "null" +%token OUT "out" +%token OVERRIDE "override" +%token PRIVATE "private" +%token PROTECTED "protected" +%token PUBLIC "public" +%token REF "ref" +%token RETURN "return" +%token SET "set" +%token SIGNAL "signal" +%token STATIC "static" +%token STRUCT "struct" +%token SWITCH "switch" +%token THIS "this" +%token THROW "throw" +%token THROWS "throws" +%token VALA_TRUE "true" +%token TRY "try" +%token TYPEOF "typeof" +%token USING "using" +%token VAR "var" +%token VIRTUAL "virtual" +%token WEAK "weak" +%token WHILE "while" + +%token <str> IDENTIFIER "identifier" +%token <str> INTEGER_LITERAL "integer" +%token <str> REAL_LITERAL "real" +%token <str> CHARACTER_LITERAL "character" +%token <str> STRING_LITERAL "string" + +%type <str> comment +%type <str> identifier +%type <literal> literal +%type <literal> boolean_literal +%type <num> stars +%type <type_reference> type_name +%type <type_reference> type +%type <list> opt_argument_list +%type <list> argument_list +%type <expression> argument +%type <expression> primary_expression +%type <expression> array_creation_expression +%type <list> size_specifier_list +%type <expression> opt_initializer +%type <num> opt_rank_specifier +%type <num> rank_specifier +%type <num> opt_bracket_pair +%type <num> bracket_pair +%type <num> opt_comma_list +%type <num> comma_list +%type <expression> primary_no_array_creation_expression +%type <expression> simple_name +%type <expression> parenthesized_expression +%type <expression> member_access +%type <expression> invocation_expression +%type <expression> element_access +%type <list> expression_list +%type <expression> this_access +%type <expression> base_access +%type <expression> post_increment_expression +%type <expression> post_decrement_expression +%type <expression> object_creation_expression +%type <expression> typeof_expression +%type <expression> unary_expression +%type <expression> pre_increment_expression +%type <expression> pre_decrement_expression +%type <expression> cast_expression +%type <expression> pointer_indirection_expression +%type <expression> addressof_expression +%type <expression> multiplicative_expression +%type <expression> additive_expression +%type <expression> shift_expression +%type <expression> relational_expression +%type <expression> equality_expression +%type <expression> and_expression +%type <expression> exclusive_or_expression +%type <expression> inclusive_or_expression +%type <expression> conditional_and_expression +%type <expression> conditional_or_expression +%type <expression> conditional_expression +%type <expression> lambda_expression +%type <list> opt_lambda_parameter_list +%type <list> lambda_parameter_list +%type <expression> assignment +%type <num> assignment_operator +%type <expression> opt_expression +%type <expression> expression +%type <statement> statement +%type <statement> embedded_statement +%type <statement> block +%type <list> opt_statement_list +%type <list> statement_list +%type <statement> empty_statement +%type <statement> declaration_statement +%type <local_variable_declaration> local_variable_declaration +%type <type_reference> local_variable_type +%type <num> opt_op_neg +%type <statement> expression_statement +%type <expression> statement_expression +%type <statement> selection_statement +%type <statement> if_statement +%type <statement> switch_statement +%type <list> switch_block +%type <list> opt_switch_sections +%type <list> switch_sections +%type <switch_section> switch_section +%type <list> switch_labels +%type <switch_label> switch_label +%type <statement> iteration_statement +%type <statement> while_statement +%type <statement> do_statement +%type <statement> for_statement +%type <list> opt_statement_expression_list +%type <list> statement_expression_list +%type <statement> foreach_statement +%type <statement> jump_statement +%type <statement> break_statement +%type <statement> continue_statement +%type <statement> return_statement +%type <statement> throw_statement +%type <statement> try_statement +%type <list> catch_clauses +%type <list> specific_catch_clauses +%type <catch_clause> specific_catch_clause +%type <catch_clause> opt_general_catch_clause +%type <catch_clause> general_catch_clause +%type <statement> opt_finally_clause +%type <statement> finally_clause +%type <statement> lock_statement +%type <namespace> namespace_declaration +%type <str> opt_name_specifier +%type <str> name_specifier +%type <class> class_declaration +%type <num> opt_access_modifier +%type <num> access_modifier +%type <num> opt_modifiers +%type <num> modifiers +%type <num> modifier +%type <list> opt_class_base +%type <list> class_base +%type <list> type_list +%type <property> property_declaration +%type <property_accessor> get_accessor_declaration +%type <property_accessor> opt_set_accessor_declaration +%type <property_accessor> set_accessor_declaration +%type <struct_> struct_declaration +%type <struct_> struct_header +%type <interface> interface_declaration +%type <enum_> enum_declaration +%type <list> enum_body +%type <list> opt_enum_member_declarations +%type <list> enum_member_declarations +%type <enum_value> enum_member_declaration +%type <flags> flags_declaration +%type <list> flags_body +%type <list> opt_flags_member_declarations +%type <list> flags_member_declarations +%type <flags_value> flags_member_declaration +%type <callback> callback_declaration +%type <constant> constant_declaration +%type <field> field_declaration +%type <list> variable_declarators +%type <variable_declarator> variable_declarator +%type <expression> initializer +%type <list> opt_variable_initializer_list +%type <list> variable_initializer_list +%type <expression> variable_initializer +%type <method> method_declaration +%type <method> method_header +%type <statement> method_body +%type <list> opt_formal_parameter_list +%type <list> formal_parameter_list +%type <num> opt_construct +%type <list> fixed_parameters +%type <formal_parameter> fixed_parameter +%type <list> opt_throws_declaration +%type <list> throws_declaration +%type <signal> signal_declaration +%type <constructor> constructor_declaration +%type <destructor> destructor_declaration +%type <list> opt_attributes +%type <list> attributes +%type <list> attribute_sections +%type <list> attribute_section +%type <list> attribute_list +%type <attribute> attribute +%type <str> attribute_name +%type <list> opt_named_argument_list +%type <list> named_argument_list +%type <named_argument> named_argument +%type <list> opt_type_parameter_list +%type <list> type_parameter_list +%type <list> type_parameters +%type <type_parameter> type_parameter +%type <list> opt_type_argument_list +%type <list> type_argument_list +%type <list> type_arguments +%type <type_reference> type_argument +%type <expression> member_name + +/* expect shift/reduce conflict on if/else */ +%expect 1 + +%start compilation_unit + +%% + +opt_comma + : /* empty */ + | COMMA + ; + +/* identifiers never conflict with context-specific keywords get or set */ +identifier + : IDENTIFIER + | GET + { + $$ = g_strdup ("get"); + } + | SET + { + $$ = g_strdup ("set"); + } + ; + +literal + : boolean_literal + | INTEGER_LITERAL + { + ValaSourceReference *src = src(@1); + $$ = VALA_LITERAL (vala_integer_literal_new ($1, src)); + g_object_unref (src); + g_free ($1); + } + | REAL_LITERAL + { + ValaSourceReference *src = src(@1); + $$ = VALA_LITERAL (vala_real_literal_new ($1, src)); + g_free ($1); + g_object_unref (src); + } + | CHARACTER_LITERAL + { + ValaSourceReference *src = src(@1); + $$ = VALA_LITERAL (vala_character_literal_new ($1, src)); + g_object_unref (src); + g_free ($1); + } + | STRING_LITERAL + { + ValaSourceReference *src = src(@1); + $$ = VALA_LITERAL (vala_string_literal_new ($1, src)); + g_object_unref (src); + g_free ($1); + } + | VALA_NULL + { + ValaSourceReference *src = src(@1); + $$ = VALA_LITERAL (vala_null_literal_new (src)); + g_object_unref (src); + } + ; + +boolean_literal + : VALA_TRUE + { + ValaSourceReference *src = src(@1); + $$ = VALA_LITERAL (vala_boolean_literal_new (TRUE, src)); + g_object_unref (src); + } + | VALA_FALSE + { + ValaSourceReference *src = src(@1); + $$ = VALA_LITERAL (vala_boolean_literal_new (FALSE, src)); + g_object_unref (src); + } + ; + +compilation_unit + : opt_using_directives opt_outer_declarations + ; + +type_name + : identifier opt_type_argument_list + { + GList *l; + ValaSourceReference *src = src(@1); + $$ = vala_type_reference_new_from_name (NULL, $1, src); + g_free ($1); + g_object_unref (src); + 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); + } + | identifier DOT identifier opt_type_argument_list + { + GList *l; + ValaSourceReference *src = src(@1); + $$ = vala_type_reference_new_from_name ($1, $3, src); + g_free ($1); + g_free ($3); + g_object_unref (src); + for (l = $4; l != NULL; l = l->next) { + vala_type_reference_add_type_argument ($$, l->data); + g_object_unref (l->data); + } + g_list_free ($4); + } + ; + +stars + : STAR + { + $$ = 1; + } + | stars STAR + { + $$ = $1 + 1; + } + ; + +type + : type_name opt_rank_specifier opt_op_neg + { + $$ = $1; + vala_type_reference_set_array_rank ($$, $2); + if ($3) { + vala_type_reference_set_non_null ($$, TRUE); + } + } + | REF type_name opt_rank_specifier opt_op_neg + { + $$ = $2; + vala_type_reference_set_is_ref ($$, TRUE); + vala_type_reference_set_array_rank ($$, $3); + if ($4) { + vala_type_reference_set_non_null ($$, TRUE); + } + } + | WEAK type_name opt_rank_specifier opt_op_neg + { + $$ = $2; + vala_type_reference_set_is_weak ($$, TRUE); + vala_type_reference_set_array_rank ($$, $3); + if ($4) { + vala_type_reference_set_non_null ($$, TRUE); + } + } + | OUT type_name opt_rank_specifier opt_op_neg + { + $$ = $2; + vala_type_reference_set_is_out ($$, TRUE); + vala_type_reference_set_array_rank ($$, $3); + if ($4) { + vala_type_reference_set_non_null ($$, TRUE); + } + } + | OUT REF type_name opt_rank_specifier opt_op_neg + { + $$ = $3; + vala_type_reference_set_is_ref ($$, TRUE); + vala_type_reference_set_is_out ($$, TRUE); + vala_type_reference_set_array_rank ($$, $4); + if ($5) { + vala_type_reference_set_non_null ($$, TRUE); + } + } + | type_name stars opt_rank_specifier opt_op_neg + { + $$ = $1; + vala_type_reference_set_pointer_level ($$, $2); + vala_type_reference_set_array_rank ($$, $3); + if ($4) { + vala_type_reference_set_non_null ($$, TRUE); + } + } + ; + +opt_argument_list + : /* empty */ + { + $$ = NULL; + } + | argument_list + ; + +argument_list + : argument + { + $$ = g_list_append (NULL, $1); + } + | argument_list COMMA argument + { + $$ = g_list_append ($1, $3); + } + ; + +argument + : expression + ; + +primary_expression + : primary_no_array_creation_expression + | array_creation_expression + ; + +array_creation_expression + : NEW member_name size_specifier_list opt_initializer + { + GList *l; + ValaSourceReference *src = src(@2); + ValaTypeReference *t = vala_type_reference_new_from_expression (VALA_EXPRESSION ($2)); + $$ = VALA_EXPRESSION (vala_array_creation_expression_new (t, g_list_length ($3), VALA_INITIALIZER_LIST ($4), src)); + g_object_unref (t); + for (l = $3; l != NULL; l = l->next) { + vala_array_creation_expression_append_size (VALA_ARRAY_CREATION_EXPRESSION ($$), VALA_EXPRESSION (l->data)); + g_object_unref (l->data); + } + g_list_free ($3); + g_object_unref (src); + g_object_unref ($2); + if ($4 != NULL) { + g_object_unref ($4); + } + } + | NEW member_name rank_specifier initializer + { + ValaSourceReference *src = src(@2); + ValaTypeReference *t = vala_type_reference_new_from_expression (VALA_EXPRESSION ($2)); + $$ = VALA_EXPRESSION (vala_array_creation_expression_new (t, $3, VALA_INITIALIZER_LIST ($4), src)); + g_object_unref (t); + g_object_unref (src); + g_object_unref ($2); + g_object_unref ($4); + } + ; + +size_specifier_list + : OPEN_BRACKET expression_list CLOSE_BRACKET + { + $$ = $2; + } + ; + +opt_initializer + : /* empty */ + { + $$ = NULL; + } + | initializer + ; + +opt_rank_specifier + : /* empty */ + { + $$ = 0; + } + | rank_specifier + ; + +rank_specifier + : OPEN_BRACKET opt_comma_list CLOSE_BRACKET + { + $$ = $2; + } + | bracket_pair + ; + +opt_bracket_pair + : /* empty */ + { + $$ = 0; + } + | bracket_pair + ; + +bracket_pair + : BRACKET_PAIR + { + $$ = 1; + } + ; + +opt_comma_list + : /* empty */ + { + $$ = 1; + } + | comma_list + ; + +comma_list + : COMMA + { + $$ = 1; + } + | comma_list COMMA + { + $$ = $1 + 1; + } + ; + +primary_no_array_creation_expression + : literal + { + ValaSourceReference *src = src(@1); + $$ = VALA_EXPRESSION (vala_literal_expression_new ($1, src)); + g_object_unref (src); + g_object_unref ($1); + } + | simple_name + | parenthesized_expression + | member_access + | invocation_expression + | element_access + | this_access + | base_access + | post_increment_expression + | post_decrement_expression + | object_creation_expression + | typeof_expression + ; + +simple_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); + } + } + ; + +parenthesized_expression + : OPEN_PARENS expression CLOSE_PARENS + { + ValaSourceReference *src = src(@2); + $$ = VALA_EXPRESSION (vala_parenthesized_expression_new ($2, src)); + g_object_unref (src); + g_object_unref ($2); + } + ; + +member_access + : primary_expression DOT identifier opt_type_argument_list + { + ValaSourceReference *src = src(@3); + $$ = 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); + } + } + ; + +invocation_expression + : primary_expression open_parens opt_argument_list CLOSE_PARENS + { + ValaSourceReference *src = src(@1); + $$ = VALA_EXPRESSION (vala_invocation_expression_new ($1, src)); + g_object_unref ($1); + g_object_unref (src); + + if ($3 != NULL) { + GList *l; + for (l = $3; l != NULL; l = l->next) { + vala_invocation_expression_add_argument (VALA_INVOCATION_EXPRESSION ($$), l->data); + g_object_unref (l->data); + } + g_list_free ($3); + } + } + ; + +element_access + : primary_no_array_creation_expression OPEN_BRACKET expression_list CLOSE_BRACKET + { + GList *l; + ValaSourceReference *src = src(@1); + $$ = VALA_EXPRESSION (vala_element_access_new ($1, src)); + for (l = $3; l != NULL; l = l->next) { + vala_element_access_append_index (VALA_ELEMENT_ACCESS ($$), VALA_EXPRESSION (l->data)); + g_object_unref (l->data); + } + g_list_free ($3); + g_object_unref ($1); + g_object_unref (src); + } + ; + +expression_list + : expression + { + $$ = g_list_append (NULL, $1); + } + | expression_list COMMA expression + { + $$ = g_list_append ($1, $3); + } + ; + +this_access + : THIS + { + ValaSourceReference *src = src(@1); + $$ = VALA_EXPRESSION (vala_member_access_new (NULL, "this", src)); + g_object_unref (src); + } + ; + +base_access + : BASE + { + ValaSourceReference *src = src(@1); + $$ = VALA_EXPRESSION (vala_base_access_new (src)); + g_object_unref (src); + } + ; + +post_increment_expression + : primary_expression OP_INC + { + ValaSourceReference *src = src(@1); + $$ = VALA_EXPRESSION (vala_postfix_expression_new ($1, TRUE, src)); + g_object_unref (src); + g_object_unref ($1); + } + ; + +post_decrement_expression + : primary_expression OP_DEC + { + ValaSourceReference *src = src(@1); + $$ = VALA_EXPRESSION (vala_postfix_expression_new ($1, FALSE, src)); + g_object_unref (src); + g_object_unref ($1); + } + ; + +object_creation_expression + : NEW member_name open_parens opt_argument_list CLOSE_PARENS + { + 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) { + vala_object_creation_expression_add_argument (expr, l->data); + g_object_unref (l->data); + } + g_list_free ($4); + } + + $$ = VALA_EXPRESSION (expr); + } + ; + +typeof_expression + : TYPEOF open_parens type_name CLOSE_PARENS + { + ValaSourceReference *src = src(@1); + $$ = VALA_EXPRESSION (vala_typeof_expression_new ($3, src)); + g_object_unref ($3); + g_object_unref (src); + } + +unary_expression + : primary_expression + | PLUS unary_expression + { + ValaSourceReference *src = src(@1); + $$ = VALA_EXPRESSION (vala_unary_expression_new (VALA_UNARY_OPERATOR_PLUS, $2, src)); + g_object_unref (src); + g_object_unref ($2); + } + | MINUS unary_expression + { + ValaSourceReference *src = src(@1); + $$ = VALA_EXPRESSION (vala_unary_expression_new (VALA_UNARY_OPERATOR_MINUS, $2, src)); + g_object_unref (src); + g_object_unref ($2); + } + | OP_NEG unary_expression + { + ValaSourceReference *src = src(@1); + $$ = VALA_EXPRESSION (vala_unary_expression_new (VALA_UNARY_OPERATOR_LOGICAL_NEGATION, $2, src)); + g_object_unref (src); + g_object_unref ($2); + } + | TILDE unary_expression + { + ValaSourceReference *src = src(@1); + $$ = VALA_EXPRESSION (vala_unary_expression_new (VALA_UNARY_OPERATOR_BITWISE_COMPLEMENT, $2, src)); + g_object_unref (src); + g_object_unref ($2); + } + | pre_increment_expression + | pre_decrement_expression + | REF unary_expression + { + ValaSourceReference *src = src(@1); + $$ = VALA_EXPRESSION (vala_unary_expression_new (VALA_UNARY_OPERATOR_REF, $2, src)); + g_object_unref (src); + g_object_unref ($2); + } + | OUT unary_expression + { + ValaSourceReference *src = src(@1); + $$ = VALA_EXPRESSION (vala_unary_expression_new (VALA_UNARY_OPERATOR_OUT, $2, src)); + g_object_unref (src); + g_object_unref ($2); + } + | HASH unary_expression + { + ValaSourceReference *src = src(@1); + $$ = VALA_EXPRESSION (vala_reference_transfer_expression_new ($2, src)); + g_object_unref (src); + g_object_unref ($2); + } + | cast_expression + | pointer_indirection_expression + | addressof_expression + ; + +pre_increment_expression + : OP_INC unary_expression + { + ValaSourceReference *src = src(@1); + $$ = VALA_EXPRESSION (vala_unary_expression_new (VALA_UNARY_OPERATOR_INCREMENT, $2, src)); + g_object_unref ($2); + g_object_unref (src); + } + ; + +pre_decrement_expression + : OP_DEC unary_expression + { + ValaSourceReference *src = src(@1); + $$ = VALA_EXPRESSION (vala_unary_expression_new (VALA_UNARY_OPERATOR_DECREMENT, $2, src)); + g_object_unref ($2); + g_object_unref (src); + } + ; + +cast_expression + : OPEN_CAST_PARENS type CLOSE_PARENS unary_expression + { + ValaSourceReference *src = src(@1); + $$ = VALA_EXPRESSION (vala_cast_expression_new ($4, $2, src)); + g_object_unref (src); + g_object_unref ($2); + g_object_unref ($4); + } + ; + +pointer_indirection_expression + : STAR unary_expression + { + ValaSourceReference *src = src(@1); + $$ = VALA_EXPRESSION (vala_pointer_indirection_new ($2, src)); + g_object_unref (src); + g_object_unref ($2); + } + ; + +addressof_expression + : BITWISE_AND unary_expression + { + ValaSourceReference *src = src(@1); + $$ = VALA_EXPRESSION (vala_addressof_expression_new ($2, src)); + g_object_unref (src); + g_object_unref ($2); + } + ; + +multiplicative_expression + : unary_expression + | multiplicative_expression STAR unary_expression + { + ValaSourceReference *src = src(@2); + $$ = VALA_EXPRESSION (vala_binary_expression_new (VALA_BINARY_OPERATOR_MUL, $1, $3, src)); + g_object_unref (src); + g_object_unref ($1); + g_object_unref ($3); + } + | multiplicative_expression DIV unary_expression + { + ValaSourceReference *src = src(@2); + $$ = VALA_EXPRESSION (vala_binary_expression_new (VALA_BINARY_OPERATOR_DIV, $1, $3, src)); + g_object_unref (src); + g_object_unref ($1); + g_object_unref ($3); + } + | multiplicative_expression PERCENT unary_expression + { + ValaSourceReference *src = src(@2); + $$ = VALA_EXPRESSION (vala_binary_expression_new (VALA_BINARY_OPERATOR_MOD, $1, $3, src)); + g_object_unref (src); + g_object_unref ($1); + g_object_unref ($3); + } + ; + +additive_expression + : multiplicative_expression + | additive_expression PLUS multiplicative_expression + { + ValaSourceReference *src = src(@2); + $$ = VALA_EXPRESSION (vala_binary_expression_new (VALA_BINARY_OPERATOR_PLUS, $1, $3, src)); + g_object_unref (src); + g_object_unref ($1); + g_object_unref ($3); + } + | additive_expression MINUS multiplicative_expression + { + ValaSourceReference *src = src(@2); + $$ = VALA_EXPRESSION (vala_binary_expression_new (VALA_BINARY_OPERATOR_MINUS, $1, $3, src)); + g_object_unref (src); + g_object_unref ($1); + g_object_unref ($3); + } + ; + +shift_expression + : additive_expression + | shift_expression OP_SHIFT_LEFT additive_expression + { + ValaSourceReference *src = src(@2); + $$ = VALA_EXPRESSION (vala_binary_expression_new (VALA_BINARY_OPERATOR_SHIFT_LEFT, $1, $3, src)); + g_object_unref (src); + g_object_unref ($1); + g_object_unref ($3); + } + /* don't use two OP_GT due to resolve parse conflicts + * stacked generics won't be that common in vala */ + | shift_expression OP_SHIFT_RIGHT additive_expression + { + ValaSourceReference *src = src(@2); + $$ = VALA_EXPRESSION (vala_binary_expression_new (VALA_BINARY_OPERATOR_SHIFT_RIGHT, $1, $3, src)); + g_object_unref (src); + g_object_unref ($1); + g_object_unref ($3); + } + ; + +relational_expression + : shift_expression + | relational_expression OP_LT shift_expression + { + ValaSourceReference *src = src(@2); + $$ = VALA_EXPRESSION (vala_binary_expression_new (VALA_BINARY_OPERATOR_LESS_THAN, $1, $3, src)); + g_object_unref (src); + g_object_unref ($1); + g_object_unref ($3); + } + | relational_expression OP_GT shift_expression + { + ValaSourceReference *src = src(@2); + $$ = VALA_EXPRESSION (vala_binary_expression_new (VALA_BINARY_OPERATOR_GREATER_THAN, $1, $3, src)); + g_object_unref (src); + g_object_unref ($1); + g_object_unref ($3); + } + | relational_expression OP_LE shift_expression + { + ValaSourceReference *src = src(@2); + $$ = VALA_EXPRESSION (vala_binary_expression_new (VALA_BINARY_OPERATOR_LESS_THAN_OR_EQUAL, $1, $3, src)); + g_object_unref (src); + g_object_unref ($1); + g_object_unref ($3); + } + | relational_expression OP_GE shift_expression + { + ValaSourceReference *src = src(@2); + $$ = VALA_EXPRESSION (vala_binary_expression_new (VALA_BINARY_OPERATOR_GREATER_THAN_OR_EQUAL, $1, $3, src)); + g_object_unref (src); + g_object_unref ($1); + g_object_unref ($3); + } + | relational_expression IS type + { + ValaSourceReference *src = src(@2); + $$ = VALA_EXPRESSION (vala_type_check_new ($1, $3, src)); + g_object_unref (src); + g_object_unref ($1); + g_object_unref ($3); + } + ; + +equality_expression + : relational_expression + | equality_expression OP_EQ relational_expression + { + ValaSourceReference *src = src(@2); + $$ = VALA_EXPRESSION (vala_binary_expression_new (VALA_BINARY_OPERATOR_EQUALITY, $1, $3, src)); + g_object_unref (src); + g_object_unref ($1); + g_object_unref ($3); + } + | equality_expression OP_NE relational_expression + { + ValaSourceReference *src = src(@2); + $$ = VALA_EXPRESSION (vala_binary_expression_new (VALA_BINARY_OPERATOR_INEQUALITY, $1, $3, src)); + g_object_unref (src); + g_object_unref ($1); + g_object_unref ($3); + } + ; + +and_expression + : equality_expression + | and_expression BITWISE_AND equality_expression + { + ValaSourceReference *src = src(@2); + $$ = VALA_EXPRESSION (vala_binary_expression_new (VALA_BINARY_OPERATOR_BITWISE_AND, $1, $3, src)); + g_object_unref (src); + g_object_unref ($1); + g_object_unref ($3); + } + ; + +exclusive_or_expression + : and_expression + | exclusive_or_expression CARRET and_expression + { + ValaSourceReference *src = src(@2); + $$ = VALA_EXPRESSION (vala_binary_expression_new (VALA_BINARY_OPERATOR_BITWISE_XOR, $1, $3, src)); + g_object_unref (src); + g_object_unref ($1); + g_object_unref ($3); + } + ; + +inclusive_or_expression + : exclusive_or_expression + | inclusive_or_expression BITWISE_OR exclusive_or_expression + { + ValaSourceReference *src = src(@2); + $$ = VALA_EXPRESSION (vala_binary_expression_new (VALA_BINARY_OPERATOR_BITWISE_OR, $1, $3, src)); + g_object_unref (src); + g_object_unref ($1); + g_object_unref ($3); + } + ; + +conditional_and_expression + : inclusive_or_expression + | conditional_and_expression OP_AND inclusive_or_expression + { + ValaSourceReference *src = src(@2); + $$ = VALA_EXPRESSION (vala_binary_expression_new (VALA_BINARY_OPERATOR_AND, $1, $3, src)); + g_object_unref (src); + g_object_unref ($1); + g_object_unref ($3); + } + ; + +conditional_or_expression + : conditional_and_expression + | conditional_or_expression OP_OR conditional_and_expression + { + ValaSourceReference *src = src(@2); + $$ = VALA_EXPRESSION (vala_binary_expression_new (VALA_BINARY_OPERATOR_OR, $1, $3, src)); + g_object_unref (src); + g_object_unref ($1); + g_object_unref ($3); + } + ; + +conditional_expression + : conditional_or_expression + | conditional_or_expression INTERR expression COLON expression + { + ValaSourceReference *src = src(@2); + $$ = VALA_EXPRESSION (vala_conditional_expression_new ($1, $3, $5, src)); + g_object_unref (src); + g_object_unref ($1); + g_object_unref ($3); + g_object_unref ($5); + } + ; + +lambda_expression + : OPEN_PARENS opt_lambda_parameter_list CLOSE_PARENS LAMBDA expression + { + ValaSourceReference *src = src(@4); + $$ = VALA_EXPRESSION (vala_lambda_expression_new ($5, src)); + if ($2 != NULL) { + GList *l; + for (l = $2; l != NULL; l = l->next) { + vala_lambda_expression_add_parameter (VALA_LAMBDA_EXPRESSION ($$), l->data); + g_free (l->data); + } + g_list_free ($2); + } + g_object_unref ($5); + g_object_unref (src); + } + | identifier LAMBDA expression + { + ValaSourceReference *src = src(@2); + $$ = VALA_EXPRESSION (vala_lambda_expression_new ($3, src)); + g_object_unref ($3); + g_object_unref (src); + vala_lambda_expression_add_parameter (VALA_LAMBDA_EXPRESSION ($$), $1); + g_free ($1); + } + | OPEN_PARENS opt_lambda_parameter_list CLOSE_PARENS LAMBDA block + { + ValaSourceReference *src = src(@4); + $$ = VALA_EXPRESSION (vala_lambda_expression_new_with_statement_body (VALA_BLOCK ($5), src)); + if ($2 != NULL) { + GList *l; + for (l = $2; l != NULL; l = l->next) { + vala_lambda_expression_add_parameter (VALA_LAMBDA_EXPRESSION ($$), l->data); + g_free (l->data); + } + g_list_free ($2); + } + g_object_unref ($5); + g_object_unref (src); + } + | identifier LAMBDA block + { + ValaSourceReference *src = src(@2); + $$ = VALA_EXPRESSION (vala_lambda_expression_new_with_statement_body (VALA_BLOCK ($3), src)); + g_object_unref ($3); + g_object_unref (src); + vala_lambda_expression_add_parameter (VALA_LAMBDA_EXPRESSION ($$), $1); + g_free ($1); + } + ; + +opt_lambda_parameter_list + : /* empty */ + { + $$ = NULL; + } + | lambda_parameter_list + ; + +lambda_parameter_list + : identifier COMMA identifier + { + $$ = g_list_append (NULL, $1); + $$ = g_list_append ($$, $3); + } + | lambda_parameter_list COMMA identifier + { + $$ = g_list_append ($1, $3); + } + ; + +assignment + : unary_expression assignment_operator expression + { + ValaSourceReference *src = src(@2); + $$ = VALA_EXPRESSION (vala_assignment_new ($1, $3, $2, src)); + g_object_unref (src); + g_object_unref ($1); + g_object_unref ($3); + } + ; + +assignment_operator + : ASSIGN + { + $$ = VALA_ASSIGNMENT_OPERATOR_SIMPLE; + } + | ASSIGN_BITWISE_OR + { + $$ = VALA_ASSIGNMENT_OPERATOR_BITWISE_OR; + } + | ASSIGN_BITWISE_AND + { + $$ = VALA_ASSIGNMENT_OPERATOR_BITWISE_AND; + } + | ASSIGN_BITWISE_XOR + { + $$ = VALA_ASSIGNMENT_OPERATOR_BITWISE_XOR; + } + | ASSIGN_ADD + { + $$ = VALA_ASSIGNMENT_OPERATOR_ADD; + } + | ASSIGN_SUB + { + $$ = VALA_ASSIGNMENT_OPERATOR_SUB; + } + | ASSIGN_MUL + { + $$ = VALA_ASSIGNMENT_OPERATOR_MUL; + } + | ASSIGN_DIV + { + $$ = VALA_ASSIGNMENT_OPERATOR_DIV; + } + | ASSIGN_PERCENT + { + $$ = VALA_ASSIGNMENT_OPERATOR_PERCENT; + } + | ASSIGN_SHIFT_LEFT + { + $$ = VALA_ASSIGNMENT_OPERATOR_SHIFT_LEFT; + } + | ASSIGN_SHIFT_RIGHT + { + $$ = VALA_ASSIGNMENT_OPERATOR_SHIFT_RIGHT; + } + ; + +opt_expression + : /* empty */ + { + $$ = NULL; + } + | expression + ; + +expression + : conditional_expression + | lambda_expression + | assignment + | error + { + $$ = NULL; + } + ; + +statement + : declaration_statement + | block + | empty_statement + | expression_statement + | selection_statement + | iteration_statement + | jump_statement + | try_statement + | lock_statement + ; + +embedded_statement + : block + | empty_statement + { + ValaSourceReference *src = src(@1); + $$ = VALA_STATEMENT (vala_block_new (src)); + vala_block_add_statement (VALA_BLOCK ($$), $1); + g_object_unref ($1); + g_object_unref (src); + } + | expression_statement + { + ValaSourceReference *src = src(@1); + $$ = VALA_STATEMENT (vala_block_new (src)); + vala_block_add_statement (VALA_BLOCK ($$), $1); + g_object_unref ($1); + g_object_unref (src); + } + | selection_statement + { + ValaSourceReference *src = src(@1); + $$ = VALA_STATEMENT (vala_block_new (src)); + vala_block_add_statement (VALA_BLOCK ($$), $1); + g_object_unref ($1); + g_object_unref (src); + } + | iteration_statement + { + ValaSourceReference *src = src(@1); + $$ = VALA_STATEMENT (vala_block_new (src)); + vala_block_add_statement (VALA_BLOCK ($$), $1); + g_object_unref ($1); + g_object_unref (src); + } + | jump_statement + { + ValaSourceReference *src = src(@1); + $$ = VALA_STATEMENT (vala_block_new (src)); + vala_block_add_statement (VALA_BLOCK ($$), $1); + g_object_unref ($1); + g_object_unref (src); + } + | try_statement + { + ValaSourceReference *src = src(@1); + $$ = VALA_STATEMENT (vala_block_new (src)); + vala_block_add_statement (VALA_BLOCK ($$), $1); + g_object_unref ($1); + g_object_unref (src); + } + | lock_statement + { + ValaSourceReference *src = src(@1); + $$ = VALA_STATEMENT (vala_block_new (src)); + vala_block_add_statement (VALA_BLOCK ($$), $1); + g_object_unref ($1); + g_object_unref (src); + } + ; + +block + : OPEN_BRACE opt_statement_list CLOSE_BRACE + { + ValaSourceReference *src = src(@1); + $$ = VALA_STATEMENT (vala_block_new (src)); + if ($2 != NULL) { + GList *l; + for (l = $2; l != NULL; l = l->next) { + vala_block_add_statement (VALA_BLOCK ($$), l->data); + g_object_unref (l->data); + } + g_list_free ($2); + } + g_object_unref (src); + } + ; + +opt_statement_list + : /* empty */ + { + $$ = NULL; + } + | statement_list + ; + +statement_list + : statement + { + $$ = g_list_append (NULL, $1); + } + | statement_list statement + { + $$ = g_list_append ($1, $2); + } + ; + +empty_statement + : SEMICOLON + { + ValaSourceReference *src = src(@1); + $$ = VALA_STATEMENT (vala_empty_statement_new (src)); + g_object_unref (src); + } + ; + +declaration_statement + : comment local_variable_declaration SEMICOLON + { + ValaSourceReference *src = src_com(@2, $1); + $$ = VALA_STATEMENT (vala_declaration_statement_new ($2, src)); + g_object_unref (src); + g_object_unref ($2); + } + ; + +local_variable_declaration + : local_variable_type variable_declarators + { + GList *l; + ValaSourceReference *src = src(@2); + $$ = vala_local_variable_declaration_new ($1, src); + g_object_unref (src); + for (l = $2; l != NULL; l = l->next) { + ValaVariableDeclarator *decl = l->data; + ValaTypeReference *type = vala_type_reference_copy ($1); + vala_variable_declarator_set_type_reference (decl, type); + g_object_unref (type); + vala_local_variable_declaration_add_declarator ($$, decl); + g_object_unref (decl); + } + g_list_free ($2); + g_object_unref ($1); + } + | VAR variable_declarators + { + GList *l; + ValaSourceReference *src = src(@2); + $$ = vala_local_variable_declaration_new_var_type (src); + g_object_unref (src); + for (l = $2; l != NULL; l = l->next) { + vala_local_variable_declaration_add_declarator ($$, l->data); + g_object_unref (l->data); + } + g_list_free ($2); + } + ; + +/* don't use type to prevent reduce/reduce conflict */ +local_variable_type + : primary_expression opt_bracket_pair opt_op_neg + { + ValaSourceReference *src = src(@1); + $$ = vala_type_reference_new_from_expression ($1); + g_object_unref ($1); + g_object_unref (src); + vala_type_reference_set_takes_ownership ($$, TRUE); + vala_type_reference_set_array_rank ($$, $2); + if ($3) { + vala_type_reference_set_non_null ($$, TRUE); + } + } + | primary_expression stars + { + ValaSourceReference *src = src(@1); + $$ = vala_type_reference_new_from_expression ($1); + g_object_unref ($1); + g_object_unref (src); + vala_type_reference_set_pointer_level ($$, $2); + } + | REF primary_expression opt_bracket_pair opt_op_neg + { + ValaSourceReference *src = src(@2); + $$ = vala_type_reference_new_from_expression ($2); + g_object_unref ($2); + g_object_unref (src); + vala_type_reference_set_takes_ownership ($$, TRUE); + vala_type_reference_set_array_rank ($$, $3); + if ($4) { + vala_type_reference_set_non_null ($$, TRUE); + } + } + | WEAK primary_expression opt_bracket_pair opt_op_neg + { + ValaSourceReference *src = src(@2); + $$ = vala_type_reference_new_from_expression ($2); + g_object_unref ($2); + g_object_unref (src); + vala_type_reference_set_array_rank ($$, $3); + if ($4) { + vala_type_reference_set_non_null ($$, TRUE); + } + } + ; + +opt_op_neg + : /* empty */ + { + $$ = FALSE; + } + | OP_NEG + { + $$ = TRUE; + } + ; + +expression_statement + : comment statement_expression SEMICOLON + { + ValaSourceReference *src = src_com(@2, $1); + $$ = VALA_STATEMENT (vala_expression_statement_new ($2, src)); + g_object_unref (src); + g_object_unref ($2); + } + ; + +statement_expression + : invocation_expression + | object_creation_expression + | assignment + | post_increment_expression + | post_decrement_expression + | pre_increment_expression + | pre_decrement_expression + ; + +selection_statement + : if_statement + | switch_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, true_block, NULL, src)); + g_object_unref (src); + g_object_unref ($4); + 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, true_block, false_block, src)); + g_object_unref (src); + g_object_unref ($4); + g_object_unref (true_block); + g_object_unref (false_block); + } + ; + +switch_statement + : comment SWITCH open_parens expression CLOSE_PARENS switch_block + { + ValaSourceReference *src = src_com(@4, $1); + $$ = VALA_STATEMENT (vala_switch_statement_new ($4, src)); + g_object_unref ($4); + g_object_unref (src); + + if ($6 != NULL) { + GList *l; + for (l = $6; l != NULL; l = l->next) { + vala_switch_statement_add_section (VALA_SWITCH_STATEMENT ($$), l->data); + g_object_unref (l->data); + } + g_list_free ($6); + } + } + ; + +switch_block + : OPEN_BRACE opt_switch_sections CLOSE_BRACE + { + $$ = $2; + } + ; + +opt_switch_sections + : /* empty */ + { + $$ = NULL; + } + | switch_sections + ; + +switch_sections + : switch_section + { + $$ = g_list_append (NULL, $1); + } + | switch_sections switch_section + { + $$ = g_list_append ($1, $2); + } + ; + +switch_section + : comment switch_labels statement_list + { + ValaSourceReference *src = src_com(@2, $1); + $$ = vala_switch_section_new (src); + g_object_unref (src); + + GList *l; + for (l = $2; l != NULL; l = l->next) { + vala_switch_section_add_label ($$, l->data); + g_object_unref (l->data); + } + g_list_free ($2); + for (l = $3; l != NULL; l = l->next) { + vala_switch_section_add_statement ($$, l->data); + g_object_unref (l->data); + } + g_list_free ($3); + } + ; + +switch_labels + : switch_label + { + $$ = g_list_append (NULL, $1); + } + | switch_labels switch_label + { + $$ = g_list_append ($1, $2); + } + ; + +switch_label + : CASE expression COLON + { + ValaSourceReference *src = src(@2); + $$ = vala_switch_label_new ($2, src); + g_object_unref ($2); + g_object_unref (src); + } + | DEFAULT COLON + { + ValaSourceReference *src = src(@1); + $$ = vala_switch_label_new_with_default (src); + g_object_unref (src); + } + ; + +iteration_statement + : while_statement + | do_statement + | for_statement + | foreach_statement + ; + +while_statement + : WHILE open_parens expression CLOSE_PARENS embedded_statement + { + ValaSourceReference *src = src(@1); + $$ = VALA_STATEMENT (vala_while_statement_new ($3, $5, src)); + g_object_unref (src); + g_object_unref ($3); + g_object_unref ($5); + } + ; + +do_statement + : DO embedded_statement WHILE open_parens expression CLOSE_PARENS SEMICOLON + { + ValaSourceReference *src = src(@1); + $$ = VALA_STATEMENT (vala_do_statement_new ($2, $5, src)); + g_object_unref ($2); + g_object_unref ($5); + g_object_unref (src); + } + ; + +for_statement + : FOR OPEN_PARENS opt_statement_expression_list SEMICOLON opt_expression SEMICOLON opt_statement_expression_list CLOSE_PARENS embedded_statement + { + ValaSourceReference *src = src(@1); + $$ = VALA_STATEMENT (vala_for_statement_new ($5, $9, src)); + if ($5 != NULL) { + g_object_unref ($5); + } + g_object_unref ($9); + g_object_unref (src); + + GList *l; + if ($3 != NULL) { + for (l = $3; l != NULL; l = l->next) { + vala_for_statement_add_initializer (VALA_FOR_STATEMENT ($$), l->data); + g_object_unref (l->data); + } + g_list_free ($3); + } + if ($7 != NULL) { + for (l = $7; l != NULL; l = l->next) { + vala_for_statement_add_iterator (VALA_FOR_STATEMENT ($$), l->data); + g_object_unref (l->data); + } + g_list_free ($7); + } + } + | FOR OPEN_PARENS local_variable_declaration SEMICOLON opt_expression SEMICOLON opt_statement_expression_list CLOSE_PARENS embedded_statement + { + ValaSourceReference *src = src(@1); + + ValaBlock *block = vala_block_new (src); + + ValaForStatement *for_statement = vala_for_statement_new ($5, $9, src); + if ($5 != NULL) { + g_object_unref ($5); + } + g_object_unref ($9); + + GList *l; + + GList* decls = vala_local_variable_declaration_get_variable_declarators ($3); + for (l = decls; l != NULL; l = l->next) { + ValaVariableDeclarator *decl = l->data; + ValaExpression *init = vala_variable_declarator_get_initializer (decl); + + if (init != NULL) { + ValaSourceReference *decl_src = vala_code_node_get_source_reference (VALA_CODE_NODE (decl)); + ValaMemberAccess *lhs = vala_member_access_new (NULL, vala_variable_declarator_get_name (decl), decl_src); + ValaAssignment *assign = vala_assignment_new (VALA_EXPRESSION (lhs), init, VALA_ASSIGNMENT_OPERATOR_SIMPLE, decl_src); + g_object_unref (lhs); + vala_for_statement_add_initializer (for_statement, VALA_EXPRESSION (assign)); + g_object_unref (assign); + + vala_variable_declarator_set_initializer (decl, NULL); + } + } + g_list_free (decls); + + ValaDeclarationStatement *decl_statement = vala_declaration_statement_new ($3, src); + g_object_unref ($3); + g_object_unref (src); + vala_block_add_statement (block, VALA_STATEMENT (decl_statement)); + g_object_unref (decl_statement); + + if ($7 != NULL) { + for (l = $7; l != NULL; l = l->next) { + vala_for_statement_add_iterator (for_statement, l->data); + g_object_unref (l->data); + } + g_list_free ($7); + } + + vala_block_add_statement (block, VALA_STATEMENT (for_statement)); + + $$ = VALA_STATEMENT (block); + } + ; + +opt_statement_expression_list + : /* empty */ + { + $$ = NULL; + } + | statement_expression_list + ; + +statement_expression_list + : statement_expression + { + $$ = g_list_append (NULL, $1); + } + | statement_expression_list COMMA statement_expression + { + $$ = g_list_append ($1, $3); + } + ; + +foreach_statement + : FOREACH OPEN_PARENS type identifier IN expression CLOSE_PARENS embedded_statement + { + ValaSourceReference *src = src(@3); + $$ = VALA_STATEMENT (vala_foreach_statement_new ($3, $4, $6, $8, src)); + g_object_unref ($3); + g_free ($4); + g_object_unref ($6); + g_object_unref ($8); + g_object_unref (src); + } + ; + +jump_statement + : break_statement + | continue_statement + | return_statement + | throw_statement + ; + +break_statement + : BREAK SEMICOLON + { + ValaSourceReference *src = src(@1); + $$ = VALA_STATEMENT (vala_break_statement_new (src)); + g_object_unref (src); + } + ; + +continue_statement + : CONTINUE SEMICOLON + { + ValaSourceReference *src = src(@1); + $$ = VALA_STATEMENT (vala_continue_statement_new (src)); + g_object_unref (src); + } + ; + +return_statement + : RETURN opt_expression SEMICOLON + { + ValaSourceReference *src = src(@1); + $$ = VALA_STATEMENT (vala_return_statement_new ($2, src)); + g_object_unref (src); + if ($2 != NULL) { + g_object_unref ($2); + } + } + ; + +throw_statement + : THROW expression SEMICOLON + { + ValaSourceReference *src = src(@1); + $$ = VALA_STATEMENT (vala_throw_statement_new ($2, src)); + g_object_unref (src); + if ($2 != NULL) { + g_object_unref ($2); + } + } + ; + +try_statement + : TRY block catch_clauses opt_finally_clause + { + ValaSourceReference *src = src(@1); + $$ = VALA_STATEMENT (vala_try_statement_new (VALA_BLOCK ($2), VALA_BLOCK ($4), src)); + g_object_unref ($2); + if ($4 != NULL) { + g_object_unref ($4); + } + g_object_unref (src); + + GList *l; + for (l = $3; l != NULL; l = l->next) { + vala_try_statement_add_catch_clause (VALA_TRY_STATEMENT ($$), l->data); + g_object_unref (l->data); + } + g_list_free ($3); + } + | TRY block finally_clause + { + ValaSourceReference *src = src(@1); + $$ = VALA_STATEMENT (vala_try_statement_new (VALA_BLOCK ($2), VALA_BLOCK ($3), src)); + g_object_unref ($2); + g_object_unref ($3); + g_object_unref (src); + } + ; + +catch_clauses + : specific_catch_clauses opt_general_catch_clause + { + if ($2 != NULL) { + $$ = g_list_append ($1, $2); + } else { + $$ = $1; + } + } + | general_catch_clause + { + $$ = g_list_append (NULL, $1); + } + ; + +specific_catch_clauses + : specific_catch_clause + { + $$ = g_list_append (NULL, $1); + } + | specific_catch_clauses specific_catch_clause + { + $$ = g_list_append ($1, $2); + } + ; + +specific_catch_clause + : CATCH OPEN_PARENS type identifier CLOSE_PARENS block + { + ValaSourceReference *src = src(@1); + $$ = vala_catch_clause_new ($3, $4, VALA_BLOCK ($6), src); + g_object_unref ($3); + g_free ($4); + g_object_unref ($6); + g_object_unref (src); + } + ; + +opt_general_catch_clause + : /* empty */ + { + $$ = NULL; + } + | general_catch_clause + ; + +general_catch_clause + : CATCH block + { + ValaSourceReference *src = src(@1); + $$ = vala_catch_clause_new (NULL, NULL, VALA_BLOCK ($2), src); + g_object_unref ($2); + g_object_unref (src); + } + ; +opt_finally_clause + : /* empty */ + { + $$ = NULL; + } + | finally_clause + ; + + +finally_clause + : FINALLY block + { + $$ = $2; + } + ; + +lock_statement + : comment LOCK OPEN_PARENS expression CLOSE_PARENS embedded_statement + { + ValaSourceReference *src = src_com(@4, $1); + $$ = VALA_STATEMENT (vala_lock_statement_new ($4, $6, src)); + g_object_unref (src); + g_object_unref ($4); + g_object_unref ($6); + } + +namespace_declaration + : comment opt_attributes NAMESPACE identifier + { + ValaSourceReference *src = src_com(@4, $1); + current_namespace = vala_namespace_new ($4, src); + g_object_unref (src); + VALA_CODE_NODE(current_namespace)->attributes = $2; + g_free ($4); + } + namespace_body + { + $$ = current_namespace; + current_namespace = vala_source_file_get_global_namespace (current_source_file); + } + ; + +namespace_body + : OPEN_BRACE opt_namespace_member_declarations CLOSE_BRACE + | OPEN_BRACE error CLOSE_BRACE + ; + +opt_name_specifier + : /* empty */ + { + $$ = NULL; + } + | name_specifier + ; + +name_specifier + : DOT identifier + { + $$ = $2; + } + ; + +opt_using_directives + : /* empty */ + | using_directives + ; + +using_directives + : using_directive + | using_directives using_directive + ; + +using_directive + : USING identifier SEMICOLON + { + ValaSourceReference *src = src(@2); + ValaNamespaceReference *ns_ref = vala_namespace_reference_new ($2, src); + g_object_unref (src); + g_free ($2); + vala_source_file_add_using_directive (current_source_file, ns_ref); + g_object_unref (ns_ref); + } + ; + +opt_outer_declarations + : /* empty */ + | outer_declarations + ; + +outer_declarations + : outer_declaration + | outer_declarations outer_declaration + ; + +outer_declaration + : namespace_declaration + { + vala_source_file_add_namespace (current_source_file, $1); + g_object_unref ($1); + } + | namespace_member_declaration + ; + +opt_namespace_member_declarations + : /* empty */ + | namespace_member_declarations + ; + +namespace_member_declarations + : namespace_member_declaration + | namespace_member_declarations namespace_member_declaration + ; + +namespace_member_declaration + : class_declaration + { + /* skip declarations with errors */ + if ($1 != NULL) { + vala_namespace_add_class (current_namespace, $1); + g_object_unref ($1); + } + + if (current_namespace_implicit) { + /* current namespace has been declared implicitly */ + current_namespace = vala_source_file_get_global_namespace (current_source_file); + current_namespace_implicit = FALSE; + } + } + | struct_declaration + { + /* skip declarations with errors */ + if ($1 != NULL) { + vala_namespace_add_struct (current_namespace, $1); + g_object_unref ($1); + } + + if (current_namespace_implicit) { + /* current namespace has been declared implicitly */ + current_namespace = vala_source_file_get_global_namespace (current_source_file); + current_namespace_implicit = FALSE; + } + } + | interface_declaration + { + /* skip declarations with errors */ + if ($1 != NULL) { + vala_namespace_add_interface (current_namespace, $1); + g_object_unref ($1); + } + + if (current_namespace_implicit) { + /* current namespace has been declared implicitly */ + current_namespace = vala_source_file_get_global_namespace (current_source_file); + current_namespace_implicit = FALSE; + } + } + | enum_declaration + { + /* skip declarations with errors */ + if ($1 != NULL) { + vala_namespace_add_enum (current_namespace, $1); + g_object_unref ($1); + } + + if (current_namespace_implicit) { + /* current namespace has been declared implicitly */ + current_namespace = vala_source_file_get_global_namespace (current_source_file); + current_namespace_implicit = FALSE; + } + } + | flags_declaration + { + /* skip declarations with errors */ + if ($1 != NULL) { + vala_namespace_add_flags (current_namespace, $1); + g_object_unref ($1); + } + + if (current_namespace_implicit) { + /* current namespace has been declared implicitly */ + current_namespace = vala_source_file_get_global_namespace (current_source_file); + current_namespace_implicit = FALSE; + } + } + | callback_declaration + { + /* skip declarations with errors */ + if ($1 != NULL) { + vala_namespace_add_callback (current_namespace, $1); + g_object_unref ($1); + } + + if (current_namespace_implicit) { + /* current namespace has been declared implicitly */ + current_namespace = vala_source_file_get_global_namespace (current_source_file); + current_namespace_implicit = FALSE; + } + } + | constant_declaration + { + /* skip declarations with errors */ + if ($1 != NULL) { + vala_namespace_add_constant (current_namespace, $1); + g_object_unref ($1); + } + } + | field_declaration + { + /* skip declarations with errors */ + if ($1 != NULL) { + /* field must be static, don't require developer + * to explicitly state it */ + vala_field_set_instance ($1, FALSE); + + vala_namespace_add_field (current_namespace, $1); + g_object_unref ($1); + } + } + | method_declaration + { + /* skip declarations with errors */ + if ($1 != NULL) { + /* method must be static, don't require developer + * to explicitly state it */ + vala_method_set_instance ($1, FALSE); + + vala_namespace_add_method (current_namespace, $1); + g_object_unref ($1); + } + } + ; + +class_declaration + : comment opt_attributes opt_access_modifier opt_modifiers CLASS identifier opt_name_specifier opt_type_parameter_list opt_class_base + { + char *name = $6; + + if ($7 != NULL) { + ValaSourceReference *ns_src = src(@6); + current_namespace = vala_namespace_new ($6, ns_src); + g_free ($6); + g_object_unref (ns_src); + current_namespace_implicit = TRUE; + + vala_source_file_add_namespace (current_source_file, current_namespace); + g_object_unref (current_namespace); + + name = $7; + } + + GList *l; + ValaSourceReference *src = src_com(@6, $1); + current_class = vala_class_new (name, src); + g_free (name); + g_object_unref (src); + + VALA_CODE_NODE(current_class)->attributes = $2; + if ($3 != 0) { + VALA_DATA_TYPE(current_class)->access = $3; + } + if (($4 & VALA_MODIFIER_ABSTRACT) == VALA_MODIFIER_ABSTRACT) { + vala_class_set_is_abstract (current_class, TRUE); + } + if (($4 & VALA_MODIFIER_STATIC) == VALA_MODIFIER_STATIC) { + vala_class_set_is_static (current_class, TRUE); + } + if ($8 != NULL) { + for (l = $8; l != NULL; l = l->next) { + vala_class_add_type_parameter (current_class, l->data); + g_object_unref (l->data); + } + g_list_free ($8); + } + if ($9 != NULL) { + for (l = $9; l != NULL; l = l->next) { + vala_class_add_base_type (current_class, l->data); + g_object_unref (l->data); + } + g_list_free ($9); + } + } + class_body + { + $$ = current_class; + current_class = NULL; + } + ; + +opt_access_modifier + : /* empty */ + { + $$ = 0; + } + | access_modifier + ; + +access_modifier + : PUBLIC + { + $$ = VALA_MEMBER_ACCESSIBILITY_PUBLIC; + } + | PROTECTED + { + $$ = VALA_MEMBER_ACCESSIBILITY_PROTECTED; + } + | PRIVATE + { + $$ = VALA_MEMBER_ACCESSIBILITY_PRIVATE; + } + ; + +opt_modifiers + : /* empty */ + { + $$ = VALA_MODIFIER_NONE; + } + | modifiers + ; + +modifiers + : modifier + | modifiers modifier + { + if (($1 & $2) == $2) { + /* modifier specified twice, signal error */ + } + $$ = $1 | $2; + } + ; + +modifier + : ABSTRACT + { + $$ = VALA_MODIFIER_ABSTRACT; + } + | OVERRIDE + { + $$ = VALA_MODIFIER_OVERRIDE; + } + | STATIC + { + $$ = VALA_MODIFIER_STATIC; + } + | VIRTUAL + { + $$ = VALA_MODIFIER_VIRTUAL; + } + ; + +opt_class_base + : /* empty */ + { + $$ = NULL; + } + | class_base + ; + +class_base + : COLON type_list + { + $$ = $2; + } + ; + +type_list + : type_name + { + $$ = g_list_append (NULL, $1); + } + | type_list COMMA type_name + { + $$ = g_list_append ($1, $3); + } + ; + +class_body + : OPEN_BRACE opt_class_member_declarations CLOSE_BRACE + ; + +opt_class_member_declarations + : /* empty */ + | class_member_declarations + ; + +class_member_declarations + : class_member_declaration + | class_member_declarations class_member_declaration + ; + +class_member_declaration + : constant_declaration + { + /* skip declarations with errors */ + if ($1 != NULL) { + vala_class_add_constant (current_class, $1); + g_object_unref ($1); + } + } + | field_declaration + { + /* skip declarations with errors */ + if ($1 != NULL) { + vala_class_add_field (current_class, $1); + g_object_unref ($1); + } + } + | method_declaration + { + /* skip declarations with errors */ + if ($1 != NULL) { + vala_class_add_method (current_class, $1); + g_object_unref ($1); + } + } + | property_declaration + { + /* skip declarations with errors */ + if ($1 != NULL) { + vala_class_add_property (current_class, $1, FALSE); + g_object_unref ($1); + } + } + | signal_declaration + { + /* skip declarations with errors */ + if ($1 != NULL) { + vala_class_add_signal (current_class, $1); + g_object_unref ($1); + } + } + | constructor_declaration + { + /* skip declarations with errors */ + if ($1 != NULL) { + vala_class_set_constructor (current_class, $1); + g_object_unref ($1); + } + } + | destructor_declaration + { + /* skip declarations with errors */ + if ($1 != NULL) { + vala_class_set_destructor (current_class, $1); + g_object_unref ($1); + } + } + ; + +constant_declaration + : comment opt_attributes opt_access_modifier CONST type variable_declarator SEMICOLON + { + ValaSourceReference *src = src_com(@5, $1); + $$ = vala_constant_new (vala_variable_declarator_get_name ($6), $5, vala_variable_declarator_get_initializer ($6), src); + g_object_unref (src); + g_object_unref ($5); + g_object_unref ($6); + if ($3 != 0) { + $$->access = $3; + } + } + ; + +field_declaration + : comment opt_attributes opt_access_modifier opt_modifiers type variable_declarator SEMICOLON + { + if (!vala_type_reference_get_is_weak ($5)) { + vala_type_reference_set_takes_ownership ($5, TRUE); + } + vala_type_reference_set_is_ref ($5, FALSE); + + ValaSourceReference *src = src_com(@5, $1); + $$ = vala_field_new (vala_variable_declarator_get_name ($6), $5, vala_variable_declarator_get_initializer ($6), src); + g_object_unref (src); + if ($3 != 0) { + $$->access = $3; + } + if (($4 & VALA_MODIFIER_STATIC) == VALA_MODIFIER_STATIC) { + vala_field_set_instance ($$, FALSE); + } + VALA_CODE_NODE($$)->attributes = $2; + g_object_unref ($5); + g_object_unref ($6); + } + ; + +comment + : + { + $$ = vala_parser_pop_comment (parser); + } + ; + +variable_declarators + : variable_declarator + { + $$ = g_list_append (NULL, $1); + } + | variable_declarators COMMA variable_declarator + { + $$ = g_list_append ($1, $3); + } + ; + +variable_declarator + : identifier + { + ValaSourceReference *src = src(@1); + $$ = vala_variable_declarator_new ($1, NULL, src); + g_object_unref (src); + g_free ($1); + } + | identifier ASSIGN variable_initializer + { + ValaSourceReference *src = src(@1); + $$ = vala_variable_declarator_new ($1, $3, src); + g_object_unref (src); + g_free ($1); + g_object_unref ($3); + } + ; + +initializer + : OPEN_BRACE opt_variable_initializer_list CLOSE_BRACE + { + ValaSourceReference *src = src(@1); + $$ = VALA_EXPRESSION (vala_initializer_list_new (src)); + g_object_unref (src); + + if ($2 != NULL) { + GList *l; + for (l = $2; l != NULL; l = l->next) { + vala_initializer_list_append (VALA_INITIALIZER_LIST ($$), l->data); + g_object_unref (l->data); + } + } + } + ; + +opt_variable_initializer_list + : /* empty */ + { + $$ = NULL; + } + | variable_initializer_list + ; + +variable_initializer_list + : variable_initializer + { + $$ = g_list_append (NULL, $1); + } + | variable_initializer_list COMMA variable_initializer + { + $$ = g_list_append ($1, $3); + } + ; + +variable_initializer + : expression + | initializer + ; + +method_declaration + : method_header method_body + { + $$ = $1; + vala_method_set_body ($$, VALA_BLOCK($2)); + if ($2 != NULL) { + g_object_unref ($2); + } + } + | error method_body + { + $$ = NULL; + } + ; + +method_header + : comment opt_attributes opt_access_modifier opt_modifiers type identifier OPEN_PARENS opt_formal_parameter_list CLOSE_PARENS opt_throws_declaration + { + GList *l; + + if (!vala_type_reference_get_is_weak ($5)) { + vala_type_reference_set_transfers_ownership ($5, TRUE); + } + + ValaSourceReference *src = src_com(@6, $1); + $$ = vala_method_new ($6, $5, src); + g_object_unref (src); + if ($3 != 0) { + $$->access = $3; + } + if (($4 & VALA_MODIFIER_STATIC) == VALA_MODIFIER_STATIC) { + vala_method_set_instance ($$, FALSE); + } + if (($4 & VALA_MODIFIER_ABSTRACT) == VALA_MODIFIER_ABSTRACT) { + vala_method_set_is_abstract ($$, TRUE); + } + if (($4 & VALA_MODIFIER_VIRTUAL) == VALA_MODIFIER_VIRTUAL) { + vala_method_set_is_virtual ($$, TRUE); + } + if (($4 & VALA_MODIFIER_OVERRIDE) == VALA_MODIFIER_OVERRIDE) { + vala_method_set_overrides ($$, TRUE); + } + VALA_CODE_NODE($$)->attributes = $2; + + for (l = $8; l != NULL; l = l->next) { + vala_method_add_parameter ($$, l->data); + g_object_unref (l->data); + } + if ($8 != NULL) { + g_list_free ($8); + } + + g_object_unref ($5); + g_free ($6); + } + | comment opt_attributes opt_access_modifier opt_modifiers identifier opt_name_specifier OPEN_PARENS opt_formal_parameter_list CLOSE_PARENS + { + GList *l; + + ValaSourceReference *src = src_com(@5, $1); + $$ = VALA_METHOD (vala_creation_method_new ($6, src)); + g_free ($5); + g_free ($6); + g_object_unref (src); + vala_method_set_instance ($$, FALSE); + if ($3 != 0) { + $$->access = $3; + } + VALA_CODE_NODE($$)->attributes = $2; + + if ($8 != NULL) { + for (l = $8; l != NULL; l = l->next) { + vala_method_add_parameter ($$, l->data); + g_object_unref (l->data); + } + g_list_free ($8); + } + } + ; + +method_body + : block + | SEMICOLON + { + $$ = NULL; + } + ; + +opt_formal_parameter_list + : /* empty */ + { + $$ = NULL; + } + | formal_parameter_list + ; + +formal_parameter_list + : fixed_parameters + | fixed_parameters COMMA ELLIPSIS + { + ValaSourceReference *src = src(@3); + $$ = g_list_append ($1, vala_formal_parameter_new_with_ellipsis (src)); + g_object_unref (src); + } + | ELLIPSIS + { + ValaSourceReference *src = src(@1); + $$ = g_list_append (NULL, vala_formal_parameter_new_with_ellipsis (src)); + g_object_unref (src); + } + ; + +fixed_parameters + : fixed_parameter + { + $$ = g_list_append (NULL, $1); + } + | fixed_parameters COMMA fixed_parameter + { + $$ = g_list_append ($1, $3); + } + ; + +opt_construct + : /* empty */ + { + $$ = FALSE; + } + | CONSTRUCT + { + $$ = TRUE; + } + ; + +fixed_parameter + : opt_attributes opt_construct type identifier + { + if (vala_type_reference_get_is_ref ($3) && vala_type_reference_get_is_out ($3)) { + vala_type_reference_set_takes_ownership ($3, TRUE); + vala_type_reference_set_is_ref ($3, FALSE); + } + + ValaSourceReference *src = src(@3); + $$ = vala_formal_parameter_new ($4, $3, src); + g_object_unref (src); + vala_formal_parameter_set_construct_parameter ($$, $2); + g_object_unref ($3); + g_free ($4); + } + | opt_attributes opt_construct type identifier ASSIGN expression + { + if (vala_type_reference_get_is_ref ($3) && vala_type_reference_get_is_out ($3)) { + vala_type_reference_set_takes_ownership ($3, TRUE); + vala_type_reference_set_is_ref ($3, FALSE); + } + + ValaSourceReference *src = src(@3); + $$ = vala_formal_parameter_new ($4, $3, src); + g_object_unref (src); + vala_formal_parameter_set_default_expression ($$, $6); + vala_formal_parameter_set_construct_parameter ($$, $2); + g_object_unref ($3); + g_free ($4); + g_object_unref ($6); + } + ; + +opt_throws_declaration + : /* empty */ + { + $$ = NULL; + } + | throws_declaration + ; + +throws_declaration + : THROWS type_list + { + $$ = $2; + } + ; + +property_declaration + : comment opt_attributes opt_access_modifier opt_modifiers type identifier OPEN_BRACE get_accessor_declaration opt_set_accessor_declaration CLOSE_BRACE + { + if (!vala_type_reference_get_is_weak ($5)) { + vala_type_reference_set_takes_ownership ($5, TRUE); + } + + ValaSourceReference *src = src_com(@5, $1); + $$ = vala_property_new ($6, $5, $8, $9, src); + g_object_unref (src); + + VALA_CODE_NODE($$)->attributes = $2; + + g_object_unref ($5); + g_free ($6); + g_object_unref ($8); + if ($9 != NULL) { + g_object_unref ($9); + } + + if (($4 & VALA_MODIFIER_ABSTRACT) == VALA_MODIFIER_ABSTRACT) { + vala_property_set_is_abstract ($$, TRUE); + } + if (($4 & VALA_MODIFIER_VIRTUAL) == VALA_MODIFIER_VIRTUAL) { + vala_property_set_is_virtual ($$, TRUE); + } + if (($4 & VALA_MODIFIER_OVERRIDE) == VALA_MODIFIER_OVERRIDE) { + vala_property_set_overrides ($$, TRUE); + } + } + | comment opt_attributes opt_access_modifier opt_modifiers type identifier OPEN_BRACE set_accessor_declaration CLOSE_BRACE + { + if (!vala_type_reference_get_is_weak ($5)) { + vala_type_reference_set_takes_ownership ($5, TRUE); + } + + ValaSourceReference *src = src_com(@5, $1); + $$ = vala_property_new ($6, $5, NULL, $8, src); + g_object_unref (src); + + VALA_CODE_NODE($$)->attributes = $2; + + g_object_unref ($5); + g_free ($6); + g_object_unref ($8); + + if (($4 & VALA_MODIFIER_ABSTRACT) == VALA_MODIFIER_ABSTRACT) { + vala_property_set_is_abstract ($$, TRUE); + } + if (($4 & VALA_MODIFIER_VIRTUAL) == VALA_MODIFIER_VIRTUAL) { + vala_property_set_is_virtual ($$, TRUE); + } + if (($4 & VALA_MODIFIER_OVERRIDE) == VALA_MODIFIER_OVERRIDE) { + vala_property_set_overrides ($$, TRUE); + } + } + ; + +get_accessor_declaration + : opt_attributes GET method_body + { + ValaSourceReference *src = src(@2); + $$ = vala_property_accessor_new (TRUE, FALSE, FALSE, $3, src); + g_object_unref (src); + + if ($3 != NULL) { + g_object_unref ($3); + } + } + ; + +opt_set_accessor_declaration + : /* empty */ + { + $$ = NULL; + } + | set_accessor_declaration + ; + +set_accessor_declaration + : opt_attributes SET method_body + { + ValaSourceReference *src = src(@2); + $$ = vala_property_accessor_new (FALSE, TRUE, FALSE, $3, src); + g_object_unref (src); + if ($3 != NULL) { + g_object_unref ($3); + } + } + | opt_attributes SET CONSTRUCT method_body + { + ValaSourceReference *src = src(@2); + $$ = vala_property_accessor_new (FALSE, TRUE, TRUE, $4, src); + g_object_unref (src); + if ($4 != NULL) { + g_object_unref ($4); + } + } + | opt_attributes CONSTRUCT method_body + { + ValaSourceReference *src = src(@2); + $$ = vala_property_accessor_new (FALSE, FALSE, TRUE, $3, src); + g_object_unref (src); + if ($3 != NULL) { + g_object_unref ($3); + } + } + ; + +signal_declaration + : comment opt_attributes opt_access_modifier SIGNAL type identifier OPEN_PARENS opt_formal_parameter_list CLOSE_PARENS SEMICOLON + { + GList *l; + + ValaSourceReference *src = src_com(@6, $1); + $$ = vala_signal_new ($6, $5, src); + g_object_unref (src); + if ($3 != 0) { + vala_signal_set_access ($$, $3); + } + VALA_CODE_NODE($$)->attributes = $2; + + for (l = $8; l != NULL; l = l->next) { + vala_signal_add_parameter ($$, l->data); + g_object_unref (l->data); + } + if ($8 != NULL) { + g_list_free ($8); + } + + g_object_unref ($5); + g_free ($6); + } + ; + +constructor_declaration + : comment opt_attributes CONSTRUCT block + { + ValaSourceReference *src = src_com(@3, $1); + $$ = vala_constructor_new (src); + g_object_unref (src); + vala_constructor_set_body ($$, $4); + g_object_unref ($4); + } + ; + +destructor_declaration + : comment opt_attributes opt_access_modifier opt_modifiers TILDE identifier OPEN_PARENS CLOSE_PARENS block + { + ValaSourceReference *src = src_com(@6, $1); + $$ = vala_destructor_new (src); + g_object_unref (src); + vala_destructor_set_body ($$, $9); + + g_free ($6); + g_object_unref ($9); + } + ; + +struct_declaration + : struct_header + { + current_struct = $1; + } + struct_body + { + $$ = current_struct; + current_struct = NULL; + } + ; + +struct_header + : comment opt_attributes opt_access_modifier STRUCT identifier opt_name_specifier opt_type_parameter_list opt_class_base + { + char *name = $5; + + if ($6 != NULL) { + ValaSourceReference *ns_src = src(@5); + current_namespace = vala_namespace_new ($5, ns_src); + g_free ($5); + g_object_unref (ns_src); + current_namespace_implicit = TRUE; + + vala_source_file_add_namespace (current_source_file, current_namespace); + g_object_unref (current_namespace); + + name = $6; + } + + GList *l; + ValaSourceReference *src = src_com(@5, $1); + $$ = vala_struct_new (name, src); + g_free (name); + g_object_unref (src); + for (l = $7; l != NULL; l = l->next) { + vala_struct_add_type_parameter ($$, l->data); + } + VALA_CODE_NODE($$)->attributes = $2; + if ($3 != 0) { + VALA_DATA_TYPE($$)->access = $3; + } + if ($8 != NULL) { + for (l = $8; l != NULL; l = l->next) { + vala_struct_add_base_type ($$, l->data); + g_object_unref (l->data); + } + g_list_free ($8); + } + } + ; + +struct_body + : OPEN_BRACE opt_struct_member_declarations CLOSE_BRACE + ; + +opt_struct_member_declarations + : /* empty */ + | struct_member_declarations + ; + +struct_member_declarations + : struct_member_declaration + | struct_member_declarations struct_member_declaration + ; + +struct_member_declaration + : field_declaration + { + /* skip declarations with errors */ + if ($1 != NULL) { + vala_struct_add_field (current_struct, $1); + g_object_unref ($1); + } + } + | method_declaration + { + /* skip declarations with errors */ + if ($1 != NULL) { + vala_struct_add_method (current_struct, $1); + g_object_unref ($1); + } + } + ; + +interface_declaration + : comment opt_attributes opt_access_modifier opt_modifiers INTERFACE identifier opt_name_specifier opt_type_parameter_list opt_class_base + { + char *name = $6; + + if ($7 != NULL) { + ValaSourceReference *ns_src = src(@6); + current_namespace = vala_namespace_new ($6, ns_src); + g_free ($6); + g_object_unref (ns_src); + current_namespace_implicit = TRUE; + + vala_source_file_add_namespace (current_source_file, current_namespace); + g_object_unref (current_namespace); + + name = $7; + } + + ValaSourceReference *src = src_com(@6, $1); + current_interface = vala_interface_new (name, src); + g_free (name); + g_object_unref (src); + + VALA_CODE_NODE(current_interface)->attributes = $2; + if ($3 != 0) { + VALA_DATA_TYPE(current_interface)->access = $3; + } + if (($4 & VALA_MODIFIER_STATIC) == VALA_MODIFIER_STATIC) { + vala_interface_set_is_static (current_interface, TRUE); + } + if ($8 != NULL) { + GList *l; + for (l = $8; l != NULL; l = l->next) { + vala_interface_add_type_parameter (current_interface, l->data); + g_object_unref (l->data); + } + g_list_free ($8); + } + if ($9 != NULL) { + GList *l; + for (l = $9; l != NULL; l = l->next) { + vala_interface_add_prerequisite (current_interface, l->data); + g_object_unref (l->data); + } + g_list_free ($9); + } + } + interface_body + { + $$ = current_interface; + } + ; + +interface_body + : OPEN_BRACE opt_interface_member_declarations CLOSE_BRACE + ; + +opt_interface_member_declarations + : /* empty */ + | interface_member_declarations + ; + +interface_member_declarations + : interface_member_declaration + | interface_member_declarations interface_member_declaration + ; + +interface_member_declaration + : method_declaration + { + /* skip declarations with errors */ + if ($1 != NULL) { + vala_interface_add_method (current_interface, $1); + g_object_unref ($1); + } + } + | property_declaration + { + /* skip declarations with errors */ + if ($1 != NULL) { + vala_interface_add_property (current_interface, $1); + g_object_unref ($1); + } + } + | signal_declaration + { + /* skip declarations with errors */ + if ($1 != NULL) { + vala_interface_add_signal (current_interface, $1); + g_object_unref ($1); + } + } + ; + +enum_declaration + : comment opt_attributes opt_access_modifier ENUM identifier opt_name_specifier enum_body + { + char *name = $5; + + if ($6 != NULL) { + ValaSourceReference *ns_src = src(@5); + current_namespace = vala_namespace_new ($5, ns_src); + g_free ($5); + g_object_unref (ns_src); + current_namespace_implicit = TRUE; + + vala_source_file_add_namespace (current_source_file, current_namespace); + g_object_unref (current_namespace); + + name = $6; + } + + GList *l; + ValaSourceReference *src = src_com(@5, $1); + $$ = vala_enum_new (name, src); + g_free (name); + g_object_unref (src); + + VALA_CODE_NODE($$)->attributes = $2; + + if ($3 != 0) { + VALA_DATA_TYPE($$)->access = $3; + } + for (l = $7; l != NULL; l = l->next) { + vala_enum_add_value ($$, l->data); + g_object_unref (l->data); + } + } + ; + +enum_body + : OPEN_BRACE opt_enum_member_declarations CLOSE_BRACE + { + $$ = $2; + } + ; + +opt_enum_member_declarations + : /* empty */ + { + $$ = NULL; + } + | enum_member_declarations opt_comma + ; + +enum_member_declarations + : enum_member_declaration + { + $$ = g_list_append (NULL, $1); + } + | enum_member_declarations COMMA enum_member_declaration + { + $$ = g_list_append ($1, $3); + } + ; + +enum_member_declaration + : opt_attributes identifier + { + $$ = vala_enum_value_new ($2); + g_free ($2); + } + | opt_attributes identifier ASSIGN expression + { + $$ = vala_enum_value_new_with_value ($2, $4); + g_free ($2); + g_object_unref ($4); + } + ; + +flags_declaration + : comment opt_attributes opt_access_modifier FLAGS identifier opt_name_specifier flags_body + { + char *name = $5; + + if ($6 != NULL) { + ValaSourceReference *ns_src = src(@5); + current_namespace = vala_namespace_new ($5, ns_src); + g_free ($5); + g_object_unref (ns_src); + current_namespace_implicit = TRUE; + + vala_source_file_add_namespace (current_source_file, current_namespace); + g_object_unref (current_namespace); + + name = $6; + } + + GList *l; + ValaSourceReference *src = src_com(@5, $1); + $$ = vala_flags_new (name, src); + g_free (name); + g_object_unref (src); + + VALA_CODE_NODE($$)->attributes = $2; + + if ($3 != 0) { + VALA_DATA_TYPE($$)->access = $3; + } + for (l = $7; l != NULL; l = l->next) { + vala_flags_add_value ($$, l->data); + g_object_unref (l->data); + } + } + ; + +flags_body + : OPEN_BRACE opt_flags_member_declarations CLOSE_BRACE + { + $$ = $2; + } + ; + +opt_flags_member_declarations + : /* empty */ + { + $$ = NULL; + } + | flags_member_declarations opt_comma + ; + +flags_member_declarations + : flags_member_declaration + { + $$ = g_list_append (NULL, $1); + } + | flags_member_declarations COMMA flags_member_declaration + { + $$ = g_list_append ($1, $3); + } + ; + +flags_member_declaration + : opt_attributes identifier + { + $$ = vala_flags_value_new ($2); + g_free ($2); + } + | opt_attributes identifier ASSIGN expression + { + $$ = vala_flags_value_new_with_value ($2, $4); + g_free ($2); + g_object_unref ($4); + } + ; + +callback_declaration + : comment opt_attributes opt_access_modifier CALLBACK type identifier opt_name_specifier opt_type_parameter_list OPEN_PARENS opt_formal_parameter_list CLOSE_PARENS SEMICOLON + { + GList *l; + char *name = $6; + + if ($7 != NULL) { + ValaSourceReference *ns_src = src(@6); + current_namespace = vala_namespace_new ($6, ns_src); + g_free ($6); + g_object_unref (ns_src); + current_namespace_implicit = TRUE; + + vala_source_file_add_namespace (current_source_file, current_namespace); + g_object_unref (current_namespace); + + name = $7; + } + + ValaSourceReference *src = src_com(@6, $1); + $$ = vala_callback_new (name, $5, src); + g_free (name); + g_object_unref ($5); + g_object_unref (src); + if ($3 != 0) { + VALA_DATA_TYPE($$)->access = $3; + } + VALA_CODE_NODE($$)->attributes = $2; + + if ($8 != NULL) { + for (l = $8; l != NULL; l = l->next) { + vala_callback_add_type_parameter ($$, l->data); + g_object_unref (l->data); + } + g_list_free ($8); + } + if ($10 != NULL) { + for (l = $10; l != NULL; l = l->next) { + vala_callback_add_parameter ($$, l->data); + g_object_unref (l->data); + } + g_list_free ($10); + } + } + ; + +opt_attributes + : /* empty */ + { + $$ = NULL; + } + | attributes + ; + +attributes + : attribute_sections + ; + +attribute_sections + : attribute_section + | attribute_sections attribute_section + { + $$ = g_list_concat ($1, $2); + } + ; + +attribute_section + : OPEN_BRACKET attribute_list CLOSE_BRACKET + { + $$ = $2; + } + | OPEN_BRACKET error CLOSE_BRACKET + { + $$ = NULL; + } + ; + +attribute_list + : attribute + { + $$ = g_list_append (NULL, $1); + } + | attribute_list COMMA attribute + { + $$ = g_list_append ($1, $3); + } + ; + +attribute + : attribute_name + { + ValaSourceReference *src = src(@1); + $$ = vala_attribute_new ($1, src); + g_free ($1); + g_object_unref (src); + } + | attribute_name OPEN_PARENS opt_named_argument_list CLOSE_PARENS + { + GList *l; + + ValaSourceReference *src = src(@1); + $$ = vala_attribute_new ($1, src); + g_object_unref (src); + + for (l = $3; l != NULL; l = l->next) { + vala_attribute_add_argument ($$, l->data); + g_object_unref (l->data); + } + if ($3 != NULL) { + g_list_free ($3); + } + + g_free ($1); + } + ; + +attribute_name + : identifier + ; + +opt_named_argument_list + : /* empty */ + { + $$ = NULL; + } + | named_argument_list + ; + +named_argument_list + : named_argument + { + $$ = g_list_append (NULL, $1); + } + | named_argument_list COMMA named_argument + { + $$ = g_list_append ($1, $3); + } + ; + +named_argument + : identifier ASSIGN expression + { + ValaSourceReference *src = src(@1); + $$ = vala_named_argument_new ($1, $3, src); + g_object_unref (src); + + g_free ($1); + g_object_unref ($3); + } + ; + +opt_type_parameter_list + : /* empty */ + { + $$ = NULL; + } + | type_parameter_list + ; + +type_parameter_list + : GENERIC_LT type_parameters OP_GT + { + $$ = $2; + } + ; + +type_parameters + : type_parameter + { + $$ = g_list_append (NULL, $1); + } + | type_parameters COMMA type_parameter + { + $$ = g_list_append ($1, $3); + } + ; + +type_parameter + : identifier + { + ValaSourceReference *src = src(@1); + $$ = vala_type_parameter_new ($1, src); + g_object_unref (src); + g_free ($1); + } + ; + +opt_type_argument_list + : /* empty */ + { + $$ = NULL; + } + | type_argument_list + ; + +type_argument_list + : GENERIC_LT type_arguments OP_GT + { + $$ = $2; + } + ; + +type_arguments + : type_argument + { + $$ = g_list_append (NULL, $1); + } + | type_arguments COMMA type_argument + { + $$ = g_list_append ($1, $3); + } + ; + +type_argument + : type + { + $$ = $1; + if (!vala_type_reference_get_is_weak ($$)) { + vala_type_reference_set_takes_ownership ($$, TRUE); + } + } + ; + +open_parens + : 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; +extern int yylineno; + +static void +yyerror (YYLTYPE *locp, ValaParser *parser, const char *msg) +{ + ValaSourceReference *source_reference = vala_source_reference_new (current_source_file, locp->first_line, locp->first_column, locp->last_line, locp->last_column); + vala_report_error (source_reference, (char *) msg); +} + +void +vala_parser_parse_file (ValaParser *parser, ValaSourceFile *source_file) +{ + current_source_file = source_file; + current_namespace = vala_source_file_get_global_namespace (source_file); + yyin = fopen (vala_source_file_get_filename (current_source_file), "r"); + if (yyin == NULL) { + printf ("Couldn't open source file: %s.\n", vala_source_file_get_filename (current_source_file)); + return; + } + + /* restart line counter on each file */ + yylineno = 1; + + yyparse (parser); + fclose (yyin); + yyin = NULL; +} diff --git a/vala/scanner.l b/vala/scanner.l new file mode 100644 index 000000000..c510973da --- /dev/null +++ b/vala/scanner.l @@ -0,0 +1,193 @@ +/* scanner.l + * + * Copyright (C) 2006-2007 Jürg Billeter, Raffaele Sandrini + * + * 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 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> + * Raffaele Sandrini <rasa@gmx.ch> + */ + +%{ +#include "vala.h" +#include "parser.h" + +#define YY_DECL int yylex (YYSTYPE *yylval_param, YYLTYPE *yylloc_param, ValaParser *parser) + +#define uploc { yylloc->first_column = yylloc->last_column + 1; yylloc->last_column += yyleng; } + +static gboolean file_comment = FALSE; +%} + +%option yylineno +%option bison-bridge +%option bison-locations +%option noyywrap +%option nounput + +%x IN_COMMENT + +space [ \t\n]* +ident [[:alnum:]_]+ +decimal_integer_literal (0|[1-9][[:digit:]]*) +real_literal [[:digit:]]+"."[[:digit:]]*{real_suffix}? +hex_digit [[:digit:]A-fa-f] +octal_digit [0-7] +octal_integer_literal 0{octal_digit}+ +hexadecimal_integer_literal 0x{hex_digit}+ +integer_suffix L|LL|U|UL|ULL +real_suffix F +single_character [^\'\\] +single_string_literal_character [^\"\\] +simple_escape_sequence \\[\'\"\?\\abfnrtv] +hexadecimal_escape_sequence \\x{hex_digit}{hex_digit}?{hex_digit}?{hex_digit}? +character ({single_character}|{simple_escape_sequence}) +string_literal_character ({single_string_literal_character}|{simple_escape_sequence}) +character_literal \'{character}+\' +string_literal \"{string_literal_character}*\" +integer_literal ({decimal_integer_literal}|{hexadecimal_integer_literal}|{octal_integer_literal}){integer_suffix}? +literal ({integer_literal}|{real_literal}|{character_literal}|{string_literal}) + +%% + +"/*" { uploc; file_comment = (yylineno == 1); BEGIN (IN_COMMENT); } +<IN_COMMENT>"*/" { uploc; BEGIN (INITIAL); yytext[yyleng - 2] = '\0'; vala_parser_push_comment (parser, yytext, file_comment); } +<IN_COMMENT>[^*\n]+ { uploc; yymore (); } +<IN_COMMENT>"*" { uploc; yymore (); } +<IN_COMMENT>\n { yylloc->first_line = yylloc->last_line = yylineno; yylloc->first_column = 1; yylloc->last_column = 0; yymore (); } + +"//".* { uploc; vala_parser_push_comment (parser, g_strdup (yytext + 2), FALSE); } + +"{" { uploc; return OPEN_BRACE; } +"}" { uploc; return CLOSE_BRACE; } +"("({space}"weak")?{space}{ident}("."{ident})?("<"({ident}".")?{ident}(","({ident}".")?{ident})*">")?("["{space}"]")*{space}")"{space}("("|{ident}|{literal}) { yyless (1); uploc; return OPEN_CAST_PARENS; } +"(" { uploc; return OPEN_PARENS; } +")" { uploc; return CLOSE_PARENS; } +"[]" { uploc; return BRACKET_PAIR; } +"[" { uploc; return OPEN_BRACKET; } +"]" { uploc; return CLOSE_BRACKET; } +"..." { uploc; return ELLIPSIS; } +"." { uploc; return DOT; } +":" { uploc; return COLON; } +"," { uploc; return COMMA; } +";" { uploc; return SEMICOLON; } +"#" { uploc; return HASH; } +"?" { uploc; return INTERR; } + +"|=" { uploc; return ASSIGN_BITWISE_OR; } +"&=" { uploc; return ASSIGN_BITWISE_AND; } +"^=" { uploc; return ASSIGN_BITWISE_XOR; } +"+=" { uploc; return ASSIGN_ADD; } +"-=" { uploc; return ASSIGN_SUB; } +"*=" { uploc; return ASSIGN_MUL; } +"/=" { uploc; return ASSIGN_DIV; } +"%=" { uploc; return ASSIGN_PERCENT; } +"<<=" { uploc; return ASSIGN_SHIFT_LEFT; } +">>=" { uploc; return ASSIGN_SHIFT_RIGHT; } + +"++" { uploc; return OP_INC; } +"--" { uploc; return OP_DEC; } +"==" { uploc; return OP_EQ; } +"!=" { uploc; return OP_NE; } +"<<" { uploc; return OP_SHIFT_LEFT; } +">>" { uploc; return OP_SHIFT_RIGHT; } +"<=" { uploc; return OP_LE; } +">=" { uploc; return OP_GE; } +"=>" { uploc; return LAMBDA; } +"<"(("ref"|"weak")" "+)?({ident}".")?{ident}"#"?("[]""#"?)?(","" "*({ident}".")?{ident}"#"?("[]""#"?)?)*">" { yyless (1); uploc; return GENERIC_LT; } +"<" { uploc; return OP_LT; } +">" { uploc; return OP_GT; } +"!" { uploc; return OP_NEG; } +"||" { uploc; return OP_OR; } +"|" { uploc; return BITWISE_OR; } +"&&" { uploc; return OP_AND; } +"&" { uploc; return BITWISE_AND; } +"^" { uploc; return CARRET; } +"~" { uploc; return TILDE; } + +"=" { uploc; return ASSIGN; } +"+" { uploc; return PLUS; } +"-" { uploc; return MINUS; } +"*" { uploc; return STAR; } +"/" { uploc; return DIV; } +"%" { uploc; return PERCENT; } + +"@"[[:alnum:]_]+ { uploc; yylval->str = g_strdup (yytext + 1); return IDENTIFIER; } + +"abstract" { uploc; return ABSTRACT; } +"base" { uploc; return BASE; } +"break" { uploc; return BREAK; } +"callback" { uploc; return CALLBACK; } +"case" { uploc; return CASE; } +"catch" { uploc; return CATCH; } +"class" { uploc; return CLASS; } +"const" { uploc; return CONST; } +"construct" { uploc; return CONSTRUCT; } +"continue" { uploc; return CONTINUE; } +"default" { uploc; return DEFAULT; } +"do" { uploc; return DO; } +"else" { uploc; return ELSE; } +"enum" { uploc; return ENUM; } +"false" { uploc; return VALA_FALSE; } +"finally" { uploc; return FINALLY; } +"flags" { uploc; return FLAGS; } +"for" { uploc; return FOR; } +"foreach" { uploc; return FOREACH; } +"get" { uploc; return GET; } +"if" { uploc; return IF; } +"in" { uploc; return IN; } +"interface" { uploc; return INTERFACE; } +"is" { uploc; return IS; } +"lock" { uploc; return LOCK; } +"namespace" { uploc; return NAMESPACE; } +"new" { uploc; return NEW; } +"null" { uploc; return VALA_NULL; } +"out" { uploc; return OUT; } +"override" { uploc; return OVERRIDE; } +"private" { uploc; return PRIVATE; } +"protected" { uploc; return PROTECTED; } +"public" { uploc; return PUBLIC; } +"ref" { uploc; return REF; } +"set" { uploc; return SET; } +"signal" { uploc; return SIGNAL; } +"static" { uploc; return STATIC; } +"struct" { uploc; return STRUCT; } +"switch" { uploc; return SWITCH; } +"return" { uploc; return RETURN; } +"this" { uploc; return THIS; } +"throw" { uploc; return THROW; } +"throws" { uploc; return THROWS; } +"true" { uploc; return VALA_TRUE; } +"try" { uploc; return TRY; } +"typeof" { uploc; return TYPEOF; } +"using" { uploc; return USING; } +"var" { uploc; return VAR; } +"virtual" { uploc; return VIRTUAL; } +"weak" { uploc; return WEAK; } +"while" { uploc; return WHILE; } + +{real_literal} { uploc; yylval->str = g_strdup (yytext); return REAL_LITERAL; } +{integer_literal} { uploc; yylval->str = g_strdup (yytext); return INTEGER_LITERAL; } + +{character_literal} { uploc; yylval->str = g_strdup (yytext); return CHARACTER_LITERAL; } +{string_literal} { uploc; yylval->str = g_strdup (yytext); return STRING_LITERAL; } + +{ident} { uploc; yylval->str = g_strdup (yytext); return IDENTIFIER; } + +[ \t]+ { uploc; /* eat up whitespace */ } +[\n]+ { yylloc->first_line = yylloc->last_line = yylineno; yylloc->first_column = 1; yylloc->last_column = 0; } + +. { uploc; fprintf (stderr, "%d: syntax error: unexpected character ´%s´\n", yylloc->first_line, yytext); } diff --git a/vala/vala.h b/vala/vala.h new file mode 100644 index 000000000..9b66faa92 --- /dev/null +++ b/vala/vala.h @@ -0,0 +1,78 @@ +#include <vala/valaaddressofexpression.h> +#include <vala/valaarraycreationexpression.h> +#include <vala/valaassignment.h> +#include <vala/valaattribute.h> +#include <vala/valabaseaccess.h> +#include <vala/valabinaryexpression.h> +#include <vala/valablock.h> +#include <vala/valabooleanliteral.h> +#include <vala/valabreakstatement.h> +#include <vala/valacallback.h> +#include <vala/valacastexpression.h> +#include <vala/valacatchclause.h> +#include <vala/valacharacterliteral.h> +#include <vala/valaclass.h> +#include <vala/valacodecontext.h> +#include <vala/valaconditionalexpression.h> +#include <vala/valaconstant.h> +#include <vala/valaconstructor.h> +#include <vala/valacontinuestatement.h> +#include <vala/valacreationmethod.h> +#include <vala/valadeclarationstatement.h> +#include <vala/valadestructor.h> +#include <vala/valadostatement.h> +#include <vala/valaelementaccess.h> +#include <vala/valaemptystatement.h> +#include <vala/valaenum.h> +#include <vala/valaenumvalue.h> +#include <vala/valaexpression.h> +#include <vala/valaexpressionstatement.h> +#include <vala/valafield.h> +#include <vala/valaflags.h> +#include <vala/valaforeachstatement.h> +#include <vala/valaformalparameter.h> +#include <vala/valaforstatement.h> +#include <vala/valaifstatement.h> +#include <vala/valainitializerlist.h> +#include <vala/valaintegerliteral.h> +#include <vala/valainterface.h> +#include <vala/valainvocationexpression.h> +#include <vala/valalambdaexpression.h> +#include <vala/valaliteral.h> +#include <vala/valaliteralexpression.h> +#include <vala/valalocalvariabledeclaration.h> +#include <vala/valalockstatement.h> +#include <vala/valamemberaccess.h> +#include <vala/valamethod.h> +#include <vala/valanamedargument.h> +#include <vala/valanamespace.h> +#include <vala/valanamespacereference.h> +#include <vala/valanullliteral.h> +#include <vala/valaobjectcreationexpression.h> +#include <vala/valaparenthesizedexpression.h> +#include <vala/valaparser.h> +#include <vala/valapointerindirection.h> +#include <vala/valapostfixexpression.h> +#include <vala/valaproperty.h> +#include <vala/valapropertyaccessor.h> +#include <vala/valarealliteral.h> +#include <vala/valareferencetransferexpression.h> +#include <vala/valareport.h> +#include <vala/valareturnstatement.h> +#include <vala/valasignal.h> +#include <vala/valasourcefile.h> +#include <vala/valasourcereference.h> +#include <vala/valastringliteral.h> +#include <vala/valastruct.h> +#include <vala/valaswitchlabel.h> +#include <vala/valaswitchsection.h> +#include <vala/valaswitchstatement.h> +#include <vala/valathrowstatement.h> +#include <vala/valatrystatement.h> +#include <vala/valatypecheck.h> +#include <vala/valatypeofexpression.h> +#include <vala/valatypeparameter.h> +#include <vala/valatypereference.h> +#include <vala/valaunaryexpression.h> +#include <vala/valavariabledeclarator.h> +#include <vala/valawhilestatement.h> diff --git a/vala/valaaddressofexpression.vala b/vala/valaaddressofexpression.vala new file mode 100644 index 000000000..8cfb82524 --- /dev/null +++ b/vala/valaaddressofexpression.vala @@ -0,0 +1,64 @@ +/* valaaddressofexpression.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 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 an address-of expression in the source code, e.g. `&foo'. + */ +public class Vala.AddressofExpression : Expression { + /** + * The variable whose address is to be computed. + */ + public Expression! inner { + get { + return _inner; + } + set construct { + _inner = value; + _inner.parent_node = this; + } + } + + private Expression! _inner; + + /** + * Creates a new address-of expression. + * + * @param inner variable whose address is to be computed + * @return newly created address-of expression + */ + public AddressofExpression (construct Expression! inner, construct SourceReference source_reference = null) { + } + + public override void accept (CodeVisitor! visitor) { + inner.accept (visitor); + + visitor.visit_addressof_expression (this); + } + + public override void replace (CodeNode! old_node, CodeNode! new_node) { + if (inner == old_node) { + inner = (Expression) new_node; + } + } +} diff --git a/vala/valaarray.vala b/vala/valaarray.vala new file mode 100644 index 000000000..d1e5fa131 --- /dev/null +++ b/vala/valaarray.vala @@ -0,0 +1,201 @@ +/* valaarray.vala + * + * Copyright (C) 2006-2007 Raffaele Sandrini, 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 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: + * Raffaele Sandrini <rasa@gmx.ch> + * Jürg Billeter <j@bitron.ch> + */ + +using GLib; + +/** + * Represents an array type i.e. everything with direct accessable elements. + */ +public class Vala.Array : DataType { + + /** + * DataType of which this is an array of. + */ + public DataType element_type { get; set construct; } + + /** + * TypeParameter of which this is an array of. + */ + public TypeParameter element_type_parameter { get; set construct; } + + /** + * The rank of this array. + */ + public int rank { get; set construct; } + + private string cname; + + private ArrayLengthField length_field; + + private ArrayResizeMethod resize_method; + + public Array (DataType! _element_type, int _rank, SourceReference! _source_reference) { + rank = _rank; + element_type = _element_type; + source_reference = _source_reference; + } + + public Array.with_type_parameter (TypeParameter! _element_type_parameter, int _rank, SourceReference! _source_reference) { + rank = _rank; + element_type_parameter = _element_type_parameter; + source_reference = _source_reference; + } + + construct { + /* FIXME: this implementation reveals compiler bugs + string commas = ""; + int i = rank - 1; + + while (i > 0) { + string += ","; + i--; + } + + name = "%s[%s]".printf (element_type.name, commas); */ + + if (rank < 1) { + Report.error (null, "internal: attempt to create an array with rank smaller than 1"); + } + + int i = rank - 1; + if (element_type != null) { + name = "%s[".printf (element_type.name); + } else { + name = "%s[".printf (element_type_parameter.name); + } + while (i > 0) { + name = "%s,".printf (name); + i--; + } + name = "%s]".printf (name); + + length_field = new ArrayLengthField (source_reference); + length_field.symbol = new Symbol (length_field); + + resize_method = new ArrayResizeMethod (source_reference); + resize_method.symbol = new Symbol (resize_method); + } + + /** + * Returns the name of this data type as it is used in C code. + * + * @return the name to be used in C code + */ + public override string get_cname (bool const_type = false) { + if (cname == null) { + if (element_type != null) { + if (element_type.is_reference_type ()) { + cname = "%s*".printf (element_type.get_cname ()); + } else { + cname = element_type.get_cname (); + } + } else { + cname = "gpointer"; + } + } + + return cname; + } + + /** + * Checks whether this data type has value or reference type semantics. + * + * @return true if this data type has reference type semantics + */ + public override bool is_reference_type () { + return true; + } + + /** + * Returns the C name of this data type in upper case. Words are + * separated by underscores. The upper case C name of the namespace is + * prefix of the result. + * + * @param infix a string to be placed between namespace and data type + * name or null + * @return the upper case name to be used in C code + */ + public override ref string get_upper_case_cname (string infix) { + return null; + } + + /** + * Returns the C name of this data type in lower case. Words are + * separated by underscores. The lower case C name of the namespace is + * prefix of the result. + * + * @param infix a string to be placed between namespace and data type + * name or null + * @return the lower case name to be used in C code + */ + public override ref string get_lower_case_cname (string infix) { + return null; + } + + /** + * Returns the C function name that frees instances of this data type. + * This is only valid for data types with reference type semantics that + * do not support reference counting. The specified C function must + * accept one argument pointing to the instance to be freed. + * + * @return the name of the C function or null if this data type is not a + * reference type or if it supports reference counting + */ + public override string get_free_function () { + return "g_free"; + } + + /** + * Returns a list of C header filenames users of this data type must + * include. + * + * @return list of C header filenames for this data type + */ + public override ref List<string> get_cheader_filenames () { + if (element_type != null) { + return element_type.get_cheader_filenames (); + } else { + return null; + } + } + + public override string get_marshaller_type_name () { + return "POINTER"; + } + + public override string get_get_value_function () { + return "g_value_get_pointer"; + } + + public override string get_set_value_function () { + return "g_value_set_pointer"; + } + + public ArrayLengthField get_length_field () { + return length_field; + } + + public ArrayResizeMethod get_resize_method () { + return resize_method; + } +} diff --git a/vala/valaarraycreationexpression.vala b/vala/valaarraycreationexpression.vala new file mode 100644 index 000000000..376e03f74 --- /dev/null +++ b/vala/valaarraycreationexpression.vala @@ -0,0 +1,89 @@ +/* valaarraycreationexpression.vala + * + * Copyright (C) 2006 Raffaele Sandrini + * + * 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 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: + * Raffaele Sandrini <rasa@gmx.ch> + */ + +using GLib; + +/** + * Represents an array creation expression e.g. "new int[] {1,2,3}". + */ +public class Vala.ArrayCreationExpression : Expression { + /** + * The type of the elements of the array. + */ + public TypeReference element_type { get; set construct; } + + /** + * The rank of the array. + */ + public int rank { get; set construct; } + + /** + * The size for each dimension ascending from left to right. + */ + private List<Expression> sizes; + + /** + * The root array initializer list. + */ + public InitializerList initializer_list { get; set construct; } + + /** + * Add a size expression. + */ + public void append_size (Expression! size) { + sizes.append (size); + } + + /** + * Get the sizes for all dimensions ascending from left to right. + */ + public ref List<weak Expression> get_sizes () { + return sizes.copy (); + } + + public ArrayCreationExpression (TypeReference _element_type, int _rank, InitializerList _initializer, SourceReference source) { + element_type = _element_type; + rank = _rank; + initializer_list = _initializer; + source_reference = source; + } + + public override void accept (CodeVisitor! visitor) { + if (element_type != null) { + element_type.accept (visitor); + } + + if (sizes != null) { + foreach (Expression e in sizes) { + e.accept (visitor); + } + } + + visitor.visit_begin_array_creation_expression (this); + + if (initializer_list != null) { + initializer_list.accept (visitor); + } + + visitor.visit_end_array_creation_expression (this); + } +} diff --git a/vala/valaarraylengthfield.vala b/vala/valaarraylengthfield.vala new file mode 100644 index 000000000..5e332c760 --- /dev/null +++ b/vala/valaarraylengthfield.vala @@ -0,0 +1,46 @@ +/* valaarraylengthfield.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 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 the Array.length field. + */ +public class Vala.ArrayLengthField : Field { + construct { + access = MemberAccessibility.PUBLIC; + + var root_symbol = source_reference.file.context.get_root (); + type_reference.data_type = (DataType) root_symbol.lookup ("int").node; + } + + /** + * Creates a new array length field. + * + * @return newly created field + */ + public ArrayLengthField (SourceReference! source) { + name = "length"; + type_reference = new TypeReference (); + source_reference = source; + } +} diff --git a/vala/valaarrayresizemethod.vala b/vala/valaarrayresizemethod.vala new file mode 100644 index 000000000..d2a5bf51a --- /dev/null +++ b/vala/valaarrayresizemethod.vala @@ -0,0 +1,53 @@ +/* valaarrayresizemethod.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 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 the Array.resize method. + */ +public class Vala.ArrayResizeMethod : Method { + construct { + access = MemberAccessibility.PUBLIC; + + set_cname ("g_renew"); + + var root_symbol = source_reference.file.context.get_root (); + var int_type = new TypeReference (); + int_type.data_type = (DataType) root_symbol.lookup ("int").node; + + add_parameter (new FormalParameter ("length", int_type)); + + returns_modified_pointer = true; + } + + /** + * Creates a new array resize method. + * + * @return newly created method + */ + public ArrayResizeMethod (SourceReference! _source_reference) { + name = "resize"; + return_type = new TypeReference (); + source_reference = _source_reference; + } +} diff --git a/vala/valaassignment.vala b/vala/valaassignment.vala new file mode 100644 index 000000000..09076a23d --- /dev/null +++ b/vala/valaassignment.vala @@ -0,0 +1,113 @@ +/* valaassignment.vala + * + * Copyright (C) 2006 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 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 an assignment expression in the source code. + * + * Supports =, |=, &=, ^=, +=, -=, *=, /=, %=, <<=, >>=. + */ +public class Vala.Assignment : Expression { + /** + * Left hand side of the assignment. + */ + public Expression! left { + get { + return _left; + } + set construct { + _left = value; + _left.parent_node = this; + } + } + + /** + * Assignment operator. + */ + public AssignmentOperator operator { get; set; } + + /** + * Right hand side of the assignment. + */ + public Expression! right { + get { + return _right; + } + set construct { + _right = value; + _right.parent_node = this; + } + } + + private Expression! _left; + private Expression! _right; + + /** + * Creates a new assignment. + * + * @param left left hand side + * @param op assignment operator + * @param right right hand side + * @param source reference to source code + * @return newly created assignment + */ + public Assignment (Expression! _left, Expression! _right, AssignmentOperator _op = AssignmentOperator.SIMPLE, SourceReference _source = null) { + left = _left; + operator = _op; + right = _right; + source_reference = _source; + } + + public override void accept (CodeVisitor! visitor) { + left.accept (visitor); + + visitor.visit_begin_assignment (this); + + right.accept (visitor); + + visitor.visit_end_assignment (this); + } + + public override void replace (CodeNode! old_node, CodeNode! new_node) { + if (left == old_node) { + left = (Expression) new_node; + } + if (right == old_node) { + right = (Expression) new_node; + } + } +} + +public enum Vala.AssignmentOperator { + SIMPLE, + BITWISE_OR, + BITWISE_AND, + BITWISE_XOR, + ADD, + SUB, + MUL, + DIV, + PERCENT, + SHIFT_LEFT, + SHIFT_RIGHT +} diff --git a/vala/valaattribute.vala b/vala/valaattribute.vala new file mode 100644 index 000000000..2978afd8e --- /dev/null +++ b/vala/valaattribute.vala @@ -0,0 +1,142 @@ +/* valaattribute.vala + * + * Copyright (C) 2006 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 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 an attribute specified in the source code. + */ +public class Vala.Attribute : CodeNode { + /** + * The name of the attribute type. + */ + public string! name { get; set construct; } + + /** + * Contains all specified attribute arguments. + */ + public List<NamedArgument> args; + + /** + * Creates a new attribute. + * + * @param name attribute type name + * @param source reference to source code + * @return newly created attribute + */ + public Attribute (string! _name, SourceReference source) { + name = _name; + source_reference = source; + } + + /** + * Adds an attribute argument. + * + * @param arg named argument + */ + public void add_argument (NamedArgument! arg) { + args.append (arg); + } + + /** + * Returns whether this attribute has the specified named argument. + * + * @param name argument name + * @return true if the argument has been found, false otherwise + */ + public bool has_argument (string! name) { + // FIXME: use hash table + foreach (NamedArgument arg in args) { + if (arg.name == name) { + return true; + } + } + + return false; + } + + /** + * Returns the string value of the specified named argument. + * + * @param name argument name + * @return string value + */ + public ref string get_string (string! name) { + // FIXME: use hash table + foreach (NamedArgument arg in args) { + if (arg.name == name) { + if (arg.argument is LiteralExpression) { + var lit = ((LiteralExpression) arg.argument).literal; + if (lit is StringLiteral) { + return ((StringLiteral) lit).eval (); + } + } + } + } + + return null; + } + + /** + * Returns the integer value of the specified named argument. + * + * @param name argument name + * @return integer value + */ + public int get_integer (string! name) { + // FIXME: use hash table + foreach (NamedArgument arg in args) { + if (arg.name == name) { + if (arg.argument is LiteralExpression) { + var lit = ((LiteralExpression) arg.argument).literal; + if (lit is IntegerLiteral) { + return ((IntegerLiteral) lit).value.to_int (); + } + } + } + } + + return 0; + } + + /** + * Returns the boolean value of the specified named argument. + * + * @param name argument name + * @return boolean value + */ + public bool get_bool (string! name) { + // FIXME: use hash table + foreach (NamedArgument arg in args) { + if (arg.name == name) { + if (arg.argument is LiteralExpression) { + var lit = ((LiteralExpression) arg.argument).literal; + if (lit is BooleanLiteral) { + return ((BooleanLiteral) lit).value; + } + } + } + } + + return false; + } +} diff --git a/vala/valaattributeprocessor.vala b/vala/valaattributeprocessor.vala new file mode 100644 index 000000000..2c4901f8f --- /dev/null +++ b/vala/valaattributeprocessor.vala @@ -0,0 +1,86 @@ +/* valaattributeprocessor.vala + * + * Copyright (C) 2006-2007 Jürg Billeter, Raffaele Sandrini + * + * 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 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> + * Raffaele Sandrini <rasa@gmx.ch> + */ + +using GLib; + +/** + * Code visitor processing attributes associated with code nodes. + */ +public class Vala.AttributeProcessor : CodeVisitor { + /** + * Process all attributes found in specified code context. + * + * @param context a code context + */ + public void process (CodeContext! context) { + context.accept (this); + } + + public override void visit_begin_namespace (Namespace! ns) { + ns.process_attributes (); + } + + public override void visit_begin_class (Class! cl) { + cl.process_attributes (); + } + + public override void visit_begin_struct (Struct! st) { + st.process_attributes (); + } + + public override void visit_begin_interface (Interface! iface) { + iface.process_attributes (); + } + + public override void visit_begin_enum (Enum! en) { + en.process_attributes (); + } + + public override void visit_begin_flags (Flags! fl) { + fl.process_attributes (); + } + + public override void visit_begin_method (Method! m) { + m.process_attributes (); + } + + public override void visit_begin_creation_method (CreationMethod! m) { + m.process_attributes (); + } + + public override void visit_begin_property (Property! prop) { + prop.process_attributes (); + } + + public override void visit_begin_callback (Callback! cb) { + cb.process_attributes (); + } + + public override void visit_field (Field! f) { + f.process_attributes (); + } + + public override void visit_begin_signal (Signal! sig) { + sig.process_attributes (); + } +} diff --git a/vala/valabaseaccess.vala b/vala/valabaseaccess.vala new file mode 100644 index 000000000..3530e8952 --- /dev/null +++ b/vala/valabaseaccess.vala @@ -0,0 +1,46 @@ +/* valabaseaccess.vala + * + * Copyright (C) 2006 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 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 an access to base class members in the source code. + */ +public class Vala.BaseAccess : Expression { + /** + * Creates a new base access expression. + * + * @param source reference to source code + * @return newly created base access expression + */ + public BaseAccess (SourceReference source = null) { + source_reference = source; + } + + public override void accept (CodeVisitor! visitor) { + visitor.visit_base_access (this); + } + + public override ref string! to_string () { + return "base"; + } +} diff --git a/vala/valabinaryexpression.vala b/vala/valabinaryexpression.vala new file mode 100644 index 000000000..e7853c944 --- /dev/null +++ b/vala/valabinaryexpression.vala @@ -0,0 +1,117 @@ +/* valabinaryexpression.vala + * + * Copyright (C) 2006 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 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 an expression with two operands in the source code. + * + * Supports +, -, *, /, %, <<, >>, <, >, <=, >=, ==, !=, &, |, ^, &&, ||. + */ +public class Vala.BinaryExpression : Expression { + /** + * The binary operator. + */ + public BinaryOperator operator { get; set; } + + /** + * The left operand. + */ + public Expression! left { + get { + return _left; + } + set construct { + _left = value; + _left.parent_node = this; + } + } + + /** + * The right operand. + */ + public Expression! right { + get { + return _right; + } + set construct { + _right = value; + _right.parent_node = this; + } + } + + private Expression! _left; + private Expression! _right; + + /** + * Creates a new binary expression. + * + * @param op binary operator + * @param left left operand + * @param right right operand + * @param source reference to source code + * @return newly created binary expression + */ + public BinaryExpression (BinaryOperator op, Expression! _left, Expression! _right, SourceReference source = null) { + operator = op; + left = _left; + right = _right; + source_reference = source; + } + + public override void accept (CodeVisitor! visitor) { + left.accept (visitor); + right.accept (visitor); + + visitor.visit_binary_expression (this); + } + + public override void replace (CodeNode! old_node, CodeNode! new_node) { + if (left == old_node) { + left = (Expression) new_node; + } + if (right == old_node) { + right = (Expression) new_node; + } + } +} + +public enum Vala.BinaryOperator { + PLUS, + MINUS, + MUL, + DIV, + MOD, + SHIFT_LEFT, + SHIFT_RIGHT, + LESS_THAN, + GREATER_THAN, + LESS_THAN_OR_EQUAL, + GREATER_THAN_OR_EQUAL, + EQUALITY, + INEQUALITY, + BITWISE_AND, + BITWISE_OR, + BITWISE_XOR, + AND, + OR +} diff --git a/vala/valablock.vala b/vala/valablock.vala new file mode 100644 index 000000000..f25da4bdb --- /dev/null +++ b/vala/valablock.vala @@ -0,0 +1,92 @@ +/* valablock.vala + * + * Copyright (C) 2006 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 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 source code block. + */ +public class Vala.Block : Statement { + /** + * Specifies whether this block contains a jump statement. This + * information can be used to remove unreachable block cleanup code. + */ + public bool contains_jump_statement { get; set; } + + private List<Statement> statement_list; + private List<VariableDeclarator> local_variables; + + /** + * Creates a new block. + * + * @param source reference to source code + */ + public Block (SourceReference source = null) { + source_reference = source; + } + + /** + * Append a statement to this block. + * + * @param stmt a statement + */ + public void add_statement (Statement! stmt) { + statement_list.append (stmt); + } + + /** + * Returns a copy of the list of statements. + * + * @return statement list + */ + public ref List<weak Statement> get_statements () { + return statement_list.copy (); + } + + /** + * Add a local variable to this block. + * + * @param decl a variable declarator + */ + public void add_local_variable (VariableDeclarator! decl) { + local_variables.append (decl); + } + + /** + * Returns a copy of the list of local variables. + * + * @return variable declarator list + */ + public ref List<weak VariableDeclarator> get_local_variables () { + return local_variables.copy (); + } + + public override void accept (CodeVisitor! visitor) { + visitor.visit_begin_block (this); + + foreach (Statement! stmt in statement_list) { + stmt.accept (visitor); + } + + visitor.visit_end_block (this); + } +} diff --git a/vala/valabooleanliteral.vala b/vala/valabooleanliteral.vala new file mode 100644 index 000000000..9d10994b7 --- /dev/null +++ b/vala/valabooleanliteral.vala @@ -0,0 +1,57 @@ +/* valabooleanliteral.vala + * + * Copyright (C) 2006 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 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 literal boolean, i.e. true or false. + */ +public class Vala.BooleanLiteral : Literal { + /** + * The literal value. + */ + public bool value { get; set; } + + /** + * Creates a new boolean literal. + * + * @param b boolean value + * @param source reference to source code + * @return newly created boolean literal + */ + public BooleanLiteral (bool b, SourceReference source) { + value = b; + source_reference = source; + } + + 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/valabreakstatement.vala b/vala/valabreakstatement.vala new file mode 100644 index 000000000..25f91b837 --- /dev/null +++ b/vala/valabreakstatement.vala @@ -0,0 +1,42 @@ +/* valabreakstatement.vala + * + * Copyright (C) 2006 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 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 break statement in the source code. + */ +public class Vala.BreakStatement : Statement { + /** + * Creates a new break statement. + * + * @param source reference to source code + * @return newly created break statement + */ + public BreakStatement (SourceReference source) { + source_reference = source; + } + + public override void accept (CodeVisitor! visitor) { + visitor.visit_break_statement (this); + } +} diff --git a/vala/valacallback.vala b/vala/valacallback.vala new file mode 100644 index 000000000..c563622f0 --- /dev/null +++ b/vala/valacallback.vala @@ -0,0 +1,202 @@ +/* valacallback.vala + * + * Copyright (C) 2006-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 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 function callback type. + */ +public class Vala.Callback : DataType { + /** + * The return type of this callback. + */ + public TypeReference return_type { get; set; } + + /** + * Specifies whether callback supports calling instance methods. + * The reference to the object instance will be appended to the end of + * the argument list in the generated C code. + */ + public bool instance { get; set; } + + private List<TypeParameter> type_parameters; + + private List<FormalParameter> parameters; + private string cname; + + /** + * Creates a new callback. + * + * @param name callback type name + * @param return_type return type + * @param source reference to source code + * @return newly created callback + */ + public Callback (string _name, TypeReference _return_type, SourceReference source = null) { + name = _name; + return_type = _return_type; + source_reference = source; + } + + /** + * Appends the specified parameter to the list of type parameters. + * + * @param p a type parameter + */ + public void add_type_parameter (TypeParameter! p) { + type_parameters.append (p); + p.type = this; + } + + /** + * Appends paramater to this callback function. + * + * @param param a formal parameter + */ + public void add_parameter (FormalParameter! param) { + parameters.append (param); + } + + /** + * Return copy of parameter list. + * + * @return parameter list + */ + public ref List<weak FormalParameter> get_parameters () { + return parameters.copy (); + } + + /** + * Checks whether the arguments and return type of the specified method + * matches this callback. + * + * @param m a method + * @return true if the specified method is compatible to this callback + */ + public bool matches_method (Method! m) { + if (!m.return_type.stricter (return_type)) { + return false; + } + + var method_params = m.get_parameters (); + weak List<weak FormalParameter> method_params_it = method_params; + bool first = true; + foreach (FormalParameter param in parameters) { + /* use first callback parameter as instance parameter if + * an instance method is being compared to a static + * callback + */ + if (first && m.instance && !instance) { + first = false; + continue; + } + + /* method is allowed to accept less arguments */ + if (method_params_it == null) { + break; + } + + var method_param = (FormalParameter) method_params_it.data; + if (!param.type_reference.stricter (method_param.type_reference)) { + return false; + } + + method_params_it = method_params_it.next; + } + + /* method may not expect more arguments */ + if (method_params_it != null) { + return false; + } + + return true; + } + + public override void accept (CodeVisitor! visitor) { + visitor.visit_begin_callback (this); + + foreach (TypeParameter p in type_parameters) { + p.accept (visitor); + } + + return_type.accept (visitor); + + foreach (FormalParameter! param in parameters) { + param.accept (visitor); + } + + visitor.visit_end_callback (this); + } + + public override string get_cname (bool const_type = false) { + if (cname == null) { + cname = "%s%s".printf (@namespace.get_cprefix (), name); + } + return cname; + } + + /** + * Sets the name of this callback as it is used in C code. + * + * @param cname the name to be used in C code + */ + public void set_cname (string cname) { + this.cname = cname; + } + + private void process_ccode_attribute (Attribute a) { + if (a.has_argument ("cname")) { + set_cname (a.get_string ("cname")); + } + } + + /** + * Process all associated attributes. + */ + public void process_attributes () { + foreach (Attribute a in attributes) { + if (a.name == "CCode") { + process_ccode_attribute (a); + } + } + } + + public override bool is_reference_type () { + return false; + } + + public override string get_type_id () { + return "G_TYPE_POINTER"; + } + + public override string get_marshaller_type_name () { + return "POINTER"; + } + + public override string get_get_value_function () { + return "g_value_get_pointer"; + } + + public override string get_set_value_function () { + return "g_value_set_pointer"; + } +} diff --git a/vala/valacastexpression.vala b/vala/valacastexpression.vala new file mode 100644 index 000000000..8900ed9b6 --- /dev/null +++ b/vala/valacastexpression.vala @@ -0,0 +1,74 @@ +/* valacastexpression.vala + * + * Copyright (C) 2006 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 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 type cast in the source code. + */ +public class Vala.CastExpression : Expression { + /** + * The expression to be cast. + */ + public Expression! inner { + get { + return _inner; + } + set construct { + _inner = value; + _inner.parent_node = this; + } + } + + /** + * The target type. + */ + public TypeReference! type_reference { get; set construct; } + + private Expression! _inner; + + /** + * Creates a new cast expression. + * + * @param inner expression to be cast + * @param type target type + * @return newly created cast expression + */ + public CastExpression (Expression! _inner, TypeReference! type, SourceReference source) { + inner = _inner; + type_reference = type; + source_reference = source; + } + + public override void accept (CodeVisitor! visitor) { + inner.accept (visitor); + type_reference.accept (visitor); + + visitor.visit_cast_expression (this); + } + + public override void replace (CodeNode! old_node, CodeNode! new_node) { + if (inner == old_node) { + inner = (Expression) new_node; + } + } +} diff --git a/vala/valacatchclause.vala b/vala/valacatchclause.vala new file mode 100644 index 000000000..3c8af19e7 --- /dev/null +++ b/vala/valacatchclause.vala @@ -0,0 +1,69 @@ +/* valacatchclause.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 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 catch clause in a try statement in the source code. + */ +public class Vala.CatchClause : CodeNode { + /** + * Specifies the error type. + */ + public TypeReference type_reference { get; set; } + + /** + * Specifies the error variable name. + */ + public string variable_name { get; set; } + + /** + * Specifies the error handler body. + */ + public Block body { get; set; } + + /** + * Specifies the declarator for the generated error variable. + */ + public VariableDeclarator variable_declarator { get; set; } + + /** + * Creates a new catch clause. + * + * @param type_reference error type + * @param variable_name error variable name + * @param body error handler body + * @param source_reference reference to source code + * @return newly created catch clause + */ + public CatchClause (construct TypeReference type_reference, construct string variable_name, construct Block body, construct SourceReference source_reference = null) { + } + + public override void accept (CodeVisitor! visitor) { + visitor.visit_begin_catch_clause (this); + + type_reference.accept (visitor); + body.accept (visitor); + + visitor.visit_end_catch_clause (this); + } +} diff --git a/vala/valacharacterliteral.vala b/vala/valacharacterliteral.vala new file mode 100644 index 000000000..21605709a --- /dev/null +++ b/vala/valacharacterliteral.vala @@ -0,0 +1,80 @@ +/* valacharacterliteral.vala + * + * Copyright (C) 2006-2007 Jürg Billeter, Raffaele Sandrini + * + * 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 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> + * Raffaele Sandrini <rasa@gmx.ch> + */ + +using GLib; + +/** + * Represents a single literal character. + */ +public class Vala.CharacterLiteral : Literal { + /** + * The literal value. + */ + public string! value { + get { + return _value; + } + set construct { + _value = value; + + if (!value.validate () || (value.len () != 3 && value.next_char ().get_char () != '\\')) { + error = true; + } + } + } + + private string! _value; + + /** + * Creates a new character literal. + * + * @param c character + * @param source reference to source code + * @return newly created character literal + */ + public CharacterLiteral (string! c, SourceReference source) { + value = c; + source_reference = source; + + } + + construct { + if (error) { + Report.error (source_reference, "invalid character literal"); + } + } + + public override void accept (CodeVisitor! visitor) { + visitor.visit_character_literal (this); + } + + /** + * Returns the unicode character value this character literal + * represents. + * + * @return unicode character value + */ + public unichar get_char () { + return value.next_char ().get_char (); + } +} diff --git a/vala/valaclass.vala b/vala/valaclass.vala new file mode 100644 index 000000000..3f111eb41 --- /dev/null +++ b/vala/valaclass.vala @@ -0,0 +1,398 @@ +/* valaclass.vala + * + * Copyright (C) 2006-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 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 class declaration in the source code. + */ +public class Vala.Class : DataType { + /** + * Specifies the base class. + */ + public Class base_class { get; set; } + + /** + * Specifies whether this class is abstract. Abstract classes may not be + * instantiated. + */ + public bool is_abstract { get; set; } + + /** + * Specifies whether this class is static. Static classes may not be + * instantiated and may only contain static members. + */ + public bool is_static { get; set; } + + /** + * Specifies whether this class has private fields. + */ + public bool has_private_fields { + get { + return _has_private_fields; + } + } + + private string cname; + private string lower_case_csuffix; + private string type_id; + + private bool _has_private_fields; + + private List<TypeParameter> type_parameters; + + private List<TypeReference> base_types; + + private List<Constant> constants; + private List<Field> fields; + private List<Method> methods; + private List<Property> properties; + private List<Signal> signals; + + /** + * Specifies the default construction method. + */ + public Method default_construction_method { get; set; } + + /** + * Specifies the instance constructor. + */ + public Constructor constructor { get; set; } + + /** + * Specifies the instance destructor. + */ + public Destructor destructor { get; set; } + + /** + * Creates a new class. + * + * @param name type name + * @param source reference to source code + * @return newly created class + */ + public Class (string! _name, SourceReference source = null) { + name = _name; + source_reference = source; + } + + /** + * Adds the specified class or interface to the list of base types of + * this class. + * + * @param type a class or interface reference + */ + public void add_base_type (TypeReference! type) { + base_types.append (type); + } + + /** + * Returns a copy of the base type list. + * + * @return list of base types + */ + public ref List<weak TypeReference> get_base_types () { + return base_types.copy (); + } + + /** + * Appends the specified parameter to the list of type parameters. + * + * @param p a type parameter + */ + public void add_type_parameter (TypeParameter! p) { + type_parameters.append (p); + p.type = this; + } + + /** + * Returns a copy of the type parameter list. + * + * @return list of type parameters + */ + public List<weak TypeParameter> get_type_parameters () { + return type_parameters.copy (); + } + + /** + * Adds the specified constant as a member to this class. + * + * @param c a constant + */ + public void add_constant (Constant! c) { + constants.append (c); + } + + /** + * Adds the specified field as a member to this class. + * + * @param f a field + */ + public void add_field (Field! f) { + // non_null fields not yet supported due to initialization issues + f.type_reference.non_null = false; + fields.append (f); + if (f.access == MemberAccessibility.PRIVATE && f.instance) { + _has_private_fields = true; + } + } + + /** + * Returns a copy of the list of fields. + * + * @return list of fields + */ + public ref List<weak Field> get_fields () { + return fields.copy (); + } + + /** + * Adds the specified method as a member to this class. + * + * @param m a method + */ + public void add_method (Method! m) { + methods.append (m); + } + + /** + * Returns a copy of the list of methods. + * + * @return list of methods + */ + public ref List<weak Method> get_methods () { + return methods.copy (); + } + + /** + * Adds the specified property as a member to this class. + * + * @param prop a property + */ + public void add_property (Property! prop, bool no_field = false) { + properties.append (prop); + + if (!no_field && prop.set_accessor != null && prop.set_accessor.body == null && + source_reference != null && !source_reference.file.pkg) { + /* automatic property accessor body generation */ + var field_type = prop.type_reference.copy (); + // non_null fields not yet supported due to initialization issues + field_type.non_null = false; + var f = new Field ("_%s".printf (prop.name), field_type, null, prop.source_reference); + f.access = MemberAccessibility.PRIVATE; + add_field (f); + } + } + + /** + * Returns a copy of the list of properties. + * + * @return list of properties + */ + public ref List<weak Property> get_properties () { + return properties.copy (); + } + + /** + * Adds the specified signal as a member to this class. + * + * @param sig a signal + */ + public void add_signal (Signal! sig) { + signals.append (sig); + } + + /** + * Returns a copy of the list of signals. + * + * @return list of signals + */ + public ref List<weak Signal> get_signals () { + return signals.copy (); + } + + public override void accept (CodeVisitor! visitor) { + visitor.visit_begin_class (this); + + foreach (TypeReference type in base_types) { + type.accept (visitor); + } + + foreach (TypeParameter p in type_parameters) { + p.accept (visitor); + } + + foreach (Field f in fields) { + f.accept (visitor); + } + + foreach (Constant c in constants) { + c.accept (visitor); + } + + foreach (Method m in methods) { + m.accept (visitor); + } + + foreach (Property prop in properties) { + prop.accept (visitor); + } + + foreach (Signal sig in signals) { + sig.accept (visitor); + } + + if (constructor != null) { + constructor.accept (visitor); + } + + if (destructor != null) { + destructor.accept (visitor); + } + + visitor.visit_end_class (this); + } + + public override string get_cname (bool const_type = false) { + if (cname == null) { + cname = "%s%s".printf (@namespace.get_cprefix (), name); + } + return cname; + } + + /** + * Sets the name of this class as it is used in C code. + * + * @param cname the name to be used in C code + */ + public void set_cname (string! cname) { + this.cname = cname; + } + + private string get_lower_case_csuffix () { + if (lower_case_csuffix == null) { + lower_case_csuffix = Namespace.camel_case_to_lower_case (name); + } + return lower_case_csuffix; + } + + private void set_lower_case_csuffix (string! csuffix) { + this.lower_case_csuffix = csuffix; + } + + public override ref string get_lower_case_cname (string infix) { + if (infix == null) { + infix = ""; + } + return "%s%s%s".printf (@namespace.get_lower_case_cprefix (), infix, get_lower_case_csuffix ()); + } + + public override ref string get_lower_case_cprefix () { + return "%s_".printf (get_lower_case_cname (null)); + } + + public override ref string get_upper_case_cname (string infix) { + return get_lower_case_cname (infix).up (); + } + + public override bool is_reference_type () { + return true; + } + + private void process_ccode_attribute (Attribute! a) { + if (a.has_argument ("cname")) { + set_cname (a.get_string ("cname")); + } + if (a.has_argument ("cheader_filename")) { + var val = a.get_string ("cheader_filename"); + foreach (string filename in val.split (",")) { + add_cheader_filename (filename); + } + } + } + + /** + * Process all associated attributes. + */ + public void process_attributes () { + foreach (Attribute a in attributes) { + if (a.name == "CCode") { + process_ccode_attribute (a); + } + } + } + + public override string get_type_id () { + if (type_id == null) { + type_id = get_upper_case_cname ("TYPE_"); + } + + return type_id; + } + + public override string get_marshaller_type_name () { + return "OBJECT"; + } + + public override string get_get_value_function () { + return "g_value_get_object"; + } + + public override string get_set_value_function () { + return "g_value_set_object"; + } + + public override bool is_reference_counting () { + return true; + } + + public override string get_ref_function () { + return "g_object_ref"; + } + + public override string get_unref_function () { + return "g_object_unref"; + } + + public override bool is_subtype_of (DataType! t) { + foreach (TypeReference base_type in base_types) { + if (base_type.data_type == t || + base_type.data_type.is_subtype_of (t)) { + return true; + } + } + + return false; + } + + public override int get_type_parameter_index (string! name) { + int i = 0; + foreach (TypeParameter parameter in type_parameters) { + if (parameter.name == name) { + return i; + } + i++; + } + return -1; + } +} + diff --git a/vala/valaclassregisterfunction.vala b/vala/valaclassregisterfunction.vala new file mode 100644 index 000000000..607a04994 --- /dev/null +++ b/vala/valaclassregisterfunction.vala @@ -0,0 +1,105 @@ +/* valaclassregisterfunction.vala + * + * Copyright (C) 2006-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 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; + +/** + * C function to register a class at runtime. + */ +public class Vala.ClassRegisterFunction : TypeRegisterFunction { + /** + * Specifies the class to be registered. + */ + public Class! class_reference { get; set construct; } + + /** + * Creates a new C function to register the specified class at runtime. + * + * @param cl a class + * @return newly created class register function + */ + public ClassRegisterFunction (Class! cl) { + class_reference = cl; + } + + public override DataType! get_type_declaration () { + return class_reference; + } + + public override ref string! get_type_struct_name () { + return "%sClass".printf (class_reference.get_cname ()); + } + + public override ref string! get_base_init_func_name () { + return "NULL"; + } + + public override ref string! get_class_init_func_name () { + return "%s_class_init".printf (class_reference.get_lower_case_cname (null)); + } + + public override ref string! get_instance_struct_size () { + return "sizeof (%s)".printf (class_reference.get_cname ()); + } + + public override ref string! get_instance_init_func_name () { + return "%s_init".printf (class_reference.get_lower_case_cname (null)); + } + + public override ref string! get_parent_type_name () { + return class_reference.base_class.get_upper_case_cname ("TYPE_"); + } + + public override string get_type_flags () { + if (class_reference.is_abstract) { + return "G_TYPE_FLAG_ABSTRACT"; + } else { + return "0"; + } + } + + public override ref CCodeFragment! get_type_interface_init_statements () { + var frag = new CCodeFragment (); + + foreach (TypeReference base_type in class_reference.get_base_types ()) { + if (!(base_type.data_type is Interface)) { + continue; + } + + var iface = (Interface) base_type.data_type; + + var iface_info_name = "%s_info".printf (iface.get_lower_case_cname (null)); + + var ctypedecl = new CCodeDeclaration ("const GInterfaceInfo"); + ctypedecl.modifiers = CCodeModifiers.STATIC; + ctypedecl.add_declarator (new CCodeVariableDeclarator.with_initializer (iface_info_name, new CCodeConstant ("{ (GInterfaceInitFunc) %s_%s_interface_init, (GInterfaceFinalizeFunc) NULL, NULL}".printf (class_reference.get_lower_case_cname (null), iface.get_lower_case_cname (null))))); + frag.append (ctypedecl); + var reg_call = new CCodeFunctionCall (new CCodeIdentifier ("g_type_add_interface_static")); + reg_call.add_argument (new CCodeIdentifier ("%s_type_id".printf (class_reference.get_lower_case_cname (null)))); + reg_call.add_argument (new CCodeIdentifier (iface.get_upper_case_cname ("TYPE_"))); + reg_call.add_argument (new CCodeIdentifier ("&%s".printf (iface_info_name))); + frag.append (new CCodeExpressionStatement (reg_call)); + } + + return frag; + } +} diff --git a/vala/valacodecontext.vala b/vala/valacodecontext.vala new file mode 100644 index 000000000..40d64d85b --- /dev/null +++ b/vala/valacodecontext.vala @@ -0,0 +1,237 @@ +/* valacodecontext.vala + * + * Copyright (C) 2006-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 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; + +/** + * The root of the code tree. + */ +public class Vala.CodeContext { + /** + * Specifies the name of the library to be built. + * + * Public header files of a library will be assumed to be installed in + * a subdirectory named like the library. + */ + public string library { get; set; } + + /** + * Specifies the optional module initialization method. + */ + public Method module_init_method { get; set; } + + List<SourceFile> source_files; + private Symbol! root = new Symbol (); + + List<SourceFileCycle> cycles; + + /** + * Returns the root symbol of the code tree. + * + * @return root symbol + */ + public Symbol! get_root () { + return root; + } + + /** + * Returns a copy of the list of source files. + * + * @return list of source files + */ + public ref List<weak SourceFile> get_source_files () { + return source_files.copy (); + } + + /** + * Adds the specified file to the list of source files. + * + * @param file a source file + */ + public void add_source_file (SourceFile! file) { + source_files.append (file); + } + + /** + * Visits the complete code tree file by file. + * + * @param visitor the visitor to be called when traversing + */ + public void accept (CodeVisitor! visitor) { + foreach (SourceFile file in source_files) { + file.accept (visitor); + } + } + + /** + * Find and resolve cycles in source file dependencies. + */ + public void find_header_cycles () { + /* find cycles in dependencies between source files */ + foreach (SourceFile file in source_files) { + /* we're only interested in internal source files */ + if (file.pkg) { + continue; + } + + if (file.mark == 0) { + visit (file, null); + } + } + + /* find one head for each cycle, it must not have any + * hard dependencies on other files in the cycle + */ + foreach (SourceFileCycle cycle in cycles) { + cycle.head = find_cycle_head ((SourceFile) cycle.files.data); + cycle.head.is_cycle_head = true; + } + + /* connect the source files in a non-cyclic way + * cycle members connect to the head of their cycle + */ + foreach (SourceFile file2 in source_files) { + /* we're only interested in internal source files */ + if (file2.pkg) { + continue; + } + + foreach (SourceFile dep in file2.get_header_internal_dependencies ()) { + if (file2.cycle != null && dep.cycle == file2.cycle) { + /* in the same cycle */ + if (!file2.is_cycle_head) { + /* include header of cycle head */ + file2.add_header_internal_include (file2.cycle.head.get_cinclude_filename ()); + } + } else { + /* we can just include the headers if they are not in a cycle or not in the same cycle as the current file */ + file2.add_header_internal_include (dep.get_cinclude_filename ()); + } + } + } + + } + + private weak SourceFile find_cycle_head (SourceFile! file) { + foreach (SourceFile dep in file.get_header_internal_full_dependencies ()) { + if (dep == file) { + /* ignore file-internal dependencies */ + continue; + } + + foreach (SourceFile cycle_file in file.cycle.files) { + if (dep == cycle_file) { + return find_cycle_head (dep); + } + } + } + /* no hard dependencies on members of the same cycle found + * source file suitable as cycle head + */ + return file; + } + + private void visit (SourceFile! file, List<SourceFile> chain) { + /* no deep copy available yet + * var l = chain.copy (); + */ + ref List<weak SourceFile> l = null; + foreach (SourceFile chain_file in chain) { + l.append (chain_file); + } + l.append (file); + /* end workaround */ + + /* mark file as currently being visited */ + file.mark = 1; + + foreach (SourceFile dep in file.get_header_internal_dependencies ()) { + if (file == dep) { + continue; + } + + if (dep.mark == 1) { + /* found cycle */ + + var cycle = new SourceFileCycle (); + cycles.append (cycle); + + bool cycle_start_found = false; + foreach (SourceFile cycle_file in l) { + ref SourceFileCycle ref_cycle_file_cycle = cycle_file.cycle; + if (!cycle_start_found) { + if (cycle_file == dep) { + cycle_start_found = true; + } + } + + if (!cycle_start_found) { + continue; + } + + if (cycle_file.cycle != null) { + /* file already in a cycle */ + + if (cycle_file.cycle == cycle) { + /* file is in the same cycle, nothing to do */ + continue; + } + + /* file is in an other cycle, merge the two cycles */ + + /* broken memory management cycles.remove (cycle_file.cycle); */ + ref List<weak SourceFileCycle> newlist = null; + foreach (SourceFileCycle oldcycle in cycles) { + if (oldcycle != cycle_file.cycle) { + newlist.append (oldcycle); + } + } + cycles = null; + foreach (SourceFileCycle newcycle in newlist) { + cycles.append (newcycle); + } + newlist = null; + /* end workaround for broken memory management */ + + foreach (SourceFile inner_cycle_file in cycle_file.cycle.files) { + if (inner_cycle_file.cycle != cycle) { + /* file in inner cycle not yet added to outer cycle */ + cycle.files.append (inner_cycle_file); + inner_cycle_file.cycle = cycle; + } + } + } else { + cycle.files.append (cycle_file); + cycle_file.cycle = cycle; + } + } + } else if (dep.mark == 0) { + /* found not yet visited file */ + + visit (dep, l); + } + } + + /* mark file as successfully visited */ + file.mark = 2; + } +} diff --git a/vala/valacodegenerator.vala b/vala/valacodegenerator.vala new file mode 100644 index 000000000..8a8807142 --- /dev/null +++ b/vala/valacodegenerator.vala @@ -0,0 +1,4177 @@ +/* valacodegenerator.vala + * + * Copyright (C) 2006-2007 Jürg Billeter, Raffaele Sandrini + * + * 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 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> + * Raffaele Sandrini <rasa@gmx.ch> + */ + +using GLib; + +/** + * Code visitor generating C Code. + */ +public class Vala.CodeGenerator : CodeVisitor { + /** + * Specifies whether automatic memory management is active. + */ + public bool memory_management { get; set; } + + private CodeContext context; + + Symbol root_symbol; + Symbol current_symbol; + Symbol current_type_symbol; + Class current_class; + TypeReference current_return_type; + + CCodeFragment header_begin; + CCodeFragment header_type_declaration; + CCodeFragment header_type_definition; + CCodeFragment header_type_member_declaration; + CCodeFragment source_begin; + CCodeFragment source_include_directives; + CCodeFragment source_type_member_declaration; + CCodeFragment source_signal_marshaller_declaration; + CCodeFragment source_type_member_definition; + CCodeFragment instance_init_fragment; + CCodeFragment instance_dispose_fragment; + CCodeFragment source_signal_marshaller_definition; + CCodeFragment module_init_fragment; + + CCodeStruct instance_struct; + CCodeStruct type_struct; + CCodeStruct instance_priv_struct; + CCodeEnum prop_enum; + CCodeEnum cenum; + CCodeFunction function; + CCodeBlock block; + + /* all temporary variables */ + List<VariableDeclarator> temp_vars; + /* temporary variables that own their content */ + List<VariableDeclarator> temp_ref_vars; + /* cache to check whether a certain marshaller has been created yet */ + HashTable<string,bool> user_marshal_list; + /* (constant) hash table with all predefined marshallers */ + HashTable<string,bool> predefined_marshal_list; + + private int next_temp_var_id = 0; + private bool in_creation_method = false; + + TypeReference bool_type; + TypeReference char_type; + TypeReference unichar_type; + TypeReference short_type; + TypeReference ushort_type; + TypeReference int_type; + TypeReference uint_type; + TypeReference long_type; + TypeReference ulong_type; + TypeReference int64_type; + TypeReference uint64_type; + TypeReference string_type; + TypeReference float_type; + TypeReference double_type; + DataType list_type; + DataType slist_type; + TypeReference mutex_type; + DataType type_module_type; + + private bool in_plugin = false; + private string module_init_param_name; + + private bool string_h_needed; + + public CodeGenerator (bool manage_memory = true) { + memory_management = manage_memory; + } + + construct { + predefined_marshal_list = new HashTable (str_hash, str_equal); + predefined_marshal_list.insert ("VOID:VOID", true); + predefined_marshal_list.insert ("VOID:BOOLEAN", true); + predefined_marshal_list.insert ("VOID:CHAR", true); + predefined_marshal_list.insert ("VOID:UCHAR", true); + predefined_marshal_list.insert ("VOID:INT", true); + predefined_marshal_list.insert ("VOID:UINT", true); + predefined_marshal_list.insert ("VOID:LONG", true); + predefined_marshal_list.insert ("VOID:ULONG", true); + predefined_marshal_list.insert ("VOID:ENUM", true); + predefined_marshal_list.insert ("VOID:FLAGS", true); + predefined_marshal_list.insert ("VOID:FLOAT", true); + predefined_marshal_list.insert ("VOID:DOUBLE", true); + predefined_marshal_list.insert ("VOID:STRING", true); + predefined_marshal_list.insert ("VOID:POINTER", true); + predefined_marshal_list.insert ("VOID:OBJECT", true); + predefined_marshal_list.insert ("STRING:OBJECT,POINTER", true); + predefined_marshal_list.insert ("VOID:UINT,POINTER", true); + predefined_marshal_list.insert ("BOOLEAN:FLAGS", true); + } + + /** + * Generate and emit C code for the specified code context. + * + * @param context a code context + */ + public void emit (CodeContext! context) { + this.context = context; + + context.find_header_cycles (); + + root_symbol = context.get_root (); + + bool_type = new TypeReference (); + bool_type.data_type = (DataType) root_symbol.lookup ("bool").node; + + char_type = new TypeReference (); + char_type.data_type = (DataType) root_symbol.lookup ("char").node; + + unichar_type = new TypeReference (); + unichar_type.data_type = (DataType) root_symbol.lookup ("unichar").node; + + short_type = new TypeReference (); + short_type.data_type = (DataType) root_symbol.lookup ("short").node; + + ushort_type = new TypeReference (); + ushort_type.data_type = (DataType) root_symbol.lookup ("ushort").node; + + int_type = new TypeReference (); + int_type.data_type = (DataType) root_symbol.lookup ("int").node; + + uint_type = new TypeReference (); + uint_type.data_type = (DataType) root_symbol.lookup ("uint").node; + + long_type = new TypeReference (); + long_type.data_type = (DataType) root_symbol.lookup ("long").node; + + ulong_type = new TypeReference (); + ulong_type.data_type = (DataType) root_symbol.lookup ("ulong").node; + + int64_type = new TypeReference (); + int64_type.data_type = (DataType) root_symbol.lookup ("int64").node; + + uint64_type = new TypeReference (); + uint64_type.data_type = (DataType) root_symbol.lookup ("uint64").node; + + float_type = new TypeReference (); + float_type.data_type = (DataType) root_symbol.lookup ("float").node; + + double_type = new TypeReference (); + double_type.data_type = (DataType) root_symbol.lookup ("double").node; + + string_type = new TypeReference (); + string_type.data_type = (DataType) root_symbol.lookup ("string").node; + + var glib_ns = root_symbol.lookup ("GLib"); + + list_type = (DataType) glib_ns.lookup ("List").node; + slist_type = (DataType) glib_ns.lookup ("SList").node; + + mutex_type = new TypeReference (); + mutex_type.data_type = (DataType) glib_ns.lookup ("Mutex").node; + + type_module_type = (DataType) glib_ns.lookup ("TypeModule").node; + + if (context.module_init_method != null) { + module_init_fragment = new CCodeFragment (); + foreach (FormalParameter parameter in context.module_init_method.get_parameters ()) { + if (parameter.type_reference.data_type == type_module_type) { + in_plugin = true; + module_init_param_name = parameter.name; + break; + } + } + } + + /* we're only interested in non-pkg source files */ + var source_files = context.get_source_files (); + foreach (SourceFile file in source_files) { + if (!file.pkg) { + file.accept (this); + } + } + } + + private ref CCodeIncludeDirective get_internal_include (string! filename) { + return new CCodeIncludeDirective (filename, context.library == null); + } + + public override void visit_begin_source_file (SourceFile! source_file) { + header_begin = new CCodeFragment (); + header_type_declaration = new CCodeFragment (); + header_type_definition = new CCodeFragment (); + header_type_member_declaration = new CCodeFragment (); + source_begin = new CCodeFragment (); + source_include_directives = new CCodeFragment (); + source_type_member_declaration = new CCodeFragment (); + source_type_member_definition = new CCodeFragment (); + source_signal_marshaller_definition = new CCodeFragment (); + source_signal_marshaller_declaration = new CCodeFragment (); + + user_marshal_list = new HashTable (str_hash, str_equal); + + next_temp_var_id = 0; + + string_h_needed = false; + + header_begin.append (new CCodeIncludeDirective ("glib.h")); + header_begin.append (new CCodeIncludeDirective ("glib-object.h")); + source_include_directives.append (new CCodeIncludeDirective (source_file.get_cheader_filename (), true)); + + ref List<weak string> used_includes = null; + used_includes.append ("glib.h"); + used_includes.append ("glib-object.h"); + used_includes.append (source_file.get_cheader_filename ()); + + foreach (string filename1 in source_file.get_header_external_includes ()) { + if (used_includes.find_custom (filename1, strcmp) == null) { + header_begin.append (new CCodeIncludeDirective (filename1)); + used_includes.append (filename1); + } + } + foreach (string filename2 in source_file.get_header_internal_includes ()) { + if (used_includes.find_custom (filename2, strcmp) == null) { + header_begin.append (get_internal_include (filename2)); + used_includes.append (filename2); + } + } + foreach (string filename3 in source_file.get_source_external_includes ()) { + if (used_includes.find_custom (filename3, strcmp) == null) { + source_include_directives.append (new CCodeIncludeDirective (filename3)); + used_includes.append (filename3); + } + } + foreach (string filename4 in source_file.get_source_internal_includes ()) { + if (used_includes.find_custom (filename4, strcmp) == null) { + source_include_directives.append (get_internal_include (filename4)); + used_includes.append (filename4); + } + } + if (source_file.is_cycle_head) { + foreach (SourceFile cycle_file in source_file.cycle.files) { + var namespaces = cycle_file.get_namespaces (); + foreach (Namespace ns in namespaces) { + var structs = ns.get_structs (); + foreach (Struct st in structs) { + header_type_declaration.append (new CCodeTypeDefinition ("struct _%s".printf (st.get_cname ()), new CCodeVariableDeclarator (st.get_cname ()))); + } + var classes = ns.get_classes (); + foreach (Class cl in classes) { + header_type_declaration.append (new CCodeTypeDefinition ("struct _%s".printf (cl.get_cname ()), new CCodeVariableDeclarator (cl.get_cname ()))); + header_type_declaration.append (new CCodeTypeDefinition ("struct _%sClass".printf (cl.get_cname ()), new CCodeVariableDeclarator ("%sClass".printf (cl.get_cname ())))); + } + var ifaces = ns.get_interfaces (); + foreach (Interface iface in ifaces) { + header_type_declaration.append (new CCodeTypeDefinition ("struct _%s".printf (iface.get_cname ()), new CCodeVariableDeclarator (iface.get_cname ()))); + header_type_declaration.append (new CCodeTypeDefinition ("struct _%s".printf (iface.get_type_cname ()), new CCodeVariableDeclarator (iface.get_type_cname ()))); + } + } + } + } + + /* generate hardcoded "well-known" macros */ + source_begin.append (new CCodeMacroReplacement ("VALA_FREE_CHECKED(o,f)", "((o) == NULL ? NULL : ((o) = (f (o), NULL)))")); + source_begin.append (new CCodeMacroReplacement ("VALA_FREE_UNCHECKED(o,f)", "((o) = (f (o), NULL))")); + } + + private static ref string get_define_for_filename (string! filename) { + var define = new String ("__"); + + var i = filename; + while (i.len () > 0) { + var c = i.get_char (); + if (c.isalnum () && c < 0x80) { + define.append_unichar (c.toupper ()); + } else { + define.append_c ('_'); + } + + i = i.next_char (); + } + + define.append ("__"); + + return define.str; + } + + public override void visit_end_source_file (SourceFile! source_file) { + var header_define = get_define_for_filename (source_file.get_cheader_filename ()); + + if (string_h_needed) { + source_include_directives.append (new CCodeIncludeDirective ("string.h")); + } + + CCodeComment comment = null; + if (source_file.comment != null) { + comment = new CCodeComment (source_file.comment); + } + + var writer = new CCodeWriter (source_file.get_cheader_filename ()); + if (comment != null) { + comment.write (writer); + } + writer.write_newline (); + var once = new CCodeOnceSection (header_define); + once.append (new CCodeNewline ()); + once.append (header_begin); + once.append (new CCodeNewline ()); + once.append (new CCodeIdentifier ("G_BEGIN_DECLS")); + once.append (new CCodeNewline ()); + once.append (new CCodeNewline ()); + once.append (header_type_declaration); + once.append (new CCodeNewline ()); + once.append (header_type_definition); + once.append (new CCodeNewline ()); + once.append (header_type_member_declaration); + once.append (new CCodeNewline ()); + once.append (new CCodeIdentifier ("G_END_DECLS")); + once.append (new CCodeNewline ()); + once.append (new CCodeNewline ()); + once.write (writer); + writer.close (); + + writer = new CCodeWriter (source_file.get_csource_filename ()); + if (comment != null) { + comment.write (writer); + } + source_begin.write (writer); + writer.write_newline (); + source_include_directives.write (writer); + writer.write_newline (); + source_type_member_declaration.write (writer); + writer.write_newline (); + source_signal_marshaller_declaration.write (writer); + writer.write_newline (); + source_type_member_definition.write (writer); + writer.write_newline (); + source_signal_marshaller_definition.write (writer); + writer.write_newline (); + writer.close (); + + header_begin = null; + header_type_declaration = null; + header_type_definition = null; + header_type_member_declaration = null; + source_begin = null; + source_include_directives = null; + source_type_member_declaration = null; + source_type_member_definition = null; + source_signal_marshaller_definition = null; + source_signal_marshaller_declaration = null; + } + + public override void visit_begin_class (Class! cl) { + current_symbol = cl.symbol; + current_type_symbol = cl.symbol; + current_class = cl; + + if (cl.is_static) { + return; + } + + instance_struct = new CCodeStruct ("_%s".printf (cl.get_cname ())); + type_struct = new CCodeStruct ("_%sClass".printf (cl.get_cname ())); + instance_priv_struct = new CCodeStruct ("_%sPrivate".printf (cl.get_cname ())); + prop_enum = new CCodeEnum (); + prop_enum.add_value ("%s_DUMMY_PROPERTY".printf (cl.get_upper_case_cname (null)), null); + instance_init_fragment = new CCodeFragment (); + instance_dispose_fragment = new CCodeFragment (); + + + header_type_declaration.append (new CCodeNewline ()); + var macro = "(%s_get_type ())".printf (cl.get_lower_case_cname (null)); + header_type_declaration.append (new CCodeMacroReplacement (cl.get_upper_case_cname ("TYPE_"), macro)); + + macro = "(G_TYPE_CHECK_INSTANCE_CAST ((obj), %s, %s))".printf (cl.get_upper_case_cname ("TYPE_"), cl.get_cname ()); + header_type_declaration.append (new CCodeMacroReplacement ("%s(obj)".printf (cl.get_upper_case_cname (null)), macro)); + + macro = "(G_TYPE_CHECK_CLASS_CAST ((klass), %s, %sClass))".printf (cl.get_upper_case_cname ("TYPE_"), cl.get_cname ()); + header_type_declaration.append (new CCodeMacroReplacement ("%s_CLASS(klass)".printf (cl.get_upper_case_cname (null)), macro)); + + macro = "(G_TYPE_CHECK_INSTANCE_TYPE ((obj), %s))".printf (cl.get_upper_case_cname ("TYPE_")); + header_type_declaration.append (new CCodeMacroReplacement ("%s(obj)".printf (cl.get_upper_case_cname ("IS_")), macro)); + + macro = "(G_TYPE_CHECK_CLASS_TYPE ((klass), %s))".printf (cl.get_upper_case_cname ("TYPE_")); + header_type_declaration.append (new CCodeMacroReplacement ("%s_CLASS(klass)".printf (cl.get_upper_case_cname ("IS_")), macro)); + + macro = "(G_TYPE_INSTANCE_GET_CLASS ((obj), %s, %sClass))".printf (cl.get_upper_case_cname ("TYPE_"), cl.get_cname ()); + header_type_declaration.append (new CCodeMacroReplacement ("%s_GET_CLASS(obj)".printf (cl.get_upper_case_cname (null)), macro)); + header_type_declaration.append (new CCodeNewline ()); + + + if (cl.source_reference.file.cycle == null) { + header_type_declaration.append (new CCodeTypeDefinition ("struct %s".printf (instance_struct.name), new CCodeVariableDeclarator (cl.get_cname ()))); + header_type_declaration.append (new CCodeTypeDefinition ("struct %s".printf (type_struct.name), new CCodeVariableDeclarator ("%sClass".printf (cl.get_cname ())))); + } + header_type_declaration.append (new CCodeTypeDefinition ("struct %s".printf (instance_priv_struct.name), new CCodeVariableDeclarator ("%sPrivate".printf (cl.get_cname ())))); + + instance_struct.add_field (cl.base_class.get_cname (), "parent"); + instance_struct.add_field ("%sPrivate *".printf (cl.get_cname ()), "priv"); + type_struct.add_field ("%sClass".printf (cl.base_class.get_cname ()), "parent"); + + if (cl.source_reference.comment != null) { + header_type_definition.append (new CCodeComment (cl.source_reference.comment)); + } + header_type_definition.append (instance_struct); + header_type_definition.append (type_struct); + source_type_member_declaration.append (instance_priv_struct); + macro = "(G_TYPE_INSTANCE_GET_PRIVATE ((o), %s, %sPrivate))".printf (cl.get_upper_case_cname ("TYPE_"), cl.get_cname ()); + source_type_member_declaration.append (new CCodeMacroReplacement ("%s_GET_PRIVATE(o)".printf (cl.get_upper_case_cname (null)), macro)); + source_type_member_declaration.append (prop_enum); + } + + public override void visit_end_class (Class! cl) { + if (!cl.is_static) { + add_get_property_function (cl); + add_set_property_function (cl); + add_class_init_function (cl); + + foreach (TypeReference base_type in cl.get_base_types ()) { + if (base_type.data_type is Interface) { + add_interface_init_function (cl, (Interface) base_type.data_type); + } + } + + add_instance_init_function (cl); + if (memory_management && cl.get_fields () != null) { + add_dispose_function (cl); + } + + var type_fun = new ClassRegisterFunction (cl); + type_fun.init_from_type (in_plugin); + header_type_member_declaration.append (type_fun.get_declaration ()); + source_type_member_definition.append (type_fun.get_definition ()); + + if (in_plugin) { + // FIXME resolve potential dependency issues, i.e. base types have to be registered before derived types + var register_call = new CCodeFunctionCall (new CCodeIdentifier ("%s_register_type".printf (cl.get_lower_case_cname (null)))); + register_call.add_argument (new CCodeIdentifier (module_init_param_name)); + module_init_fragment.append (new CCodeExpressionStatement (register_call)); + } + } + + current_type_symbol = null; + current_class = null; + instance_dispose_fragment = null; + } + + private void add_class_init_function (Class! cl) { + var class_init = new CCodeFunction ("%s_class_init".printf (cl.get_lower_case_cname (null)), "void"); + class_init.add_parameter (new CCodeFormalParameter ("klass", "%sClass *".printf (cl.get_cname ()))); + class_init.modifiers = CCodeModifiers.STATIC; + + var init_block = new CCodeBlock (); + class_init.block = init_block; + + ref CCodeFunctionCall ccall; + + /* save pointer to parent class */ + var parent_decl = new CCodeDeclaration ("gpointer"); + var parent_var_decl = new CCodeVariableDeclarator ("%s_parent_class".printf (cl.get_lower_case_cname (null))); + parent_var_decl.initializer = new CCodeConstant ("NULL"); + parent_decl.add_declarator (parent_var_decl); + parent_decl.modifiers = CCodeModifiers.STATIC; + source_type_member_declaration.append (parent_decl); + ccall = new CCodeFunctionCall (new CCodeIdentifier ("g_type_class_peek_parent")); + ccall.add_argument (new CCodeIdentifier ("klass")); + var parent_assignment = new CCodeAssignment (new CCodeIdentifier ("%s_parent_class".printf (cl.get_lower_case_cname (null))), ccall); + init_block.add_statement (new CCodeExpressionStatement (parent_assignment)); + + /* add struct for private fields */ + if (cl.has_private_fields) { + ccall = new CCodeFunctionCall (new CCodeIdentifier ("g_type_class_add_private")); + ccall.add_argument (new CCodeIdentifier ("klass")); + ccall.add_argument (new CCodeConstant ("sizeof (%sPrivate)".printf (cl.get_cname ()))); + init_block.add_statement (new CCodeExpressionStatement (ccall)); + } + + /* set property handlers */ + ccall = new CCodeFunctionCall (new CCodeIdentifier ("G_OBJECT_CLASS")); + ccall.add_argument (new CCodeIdentifier ("klass")); + init_block.add_statement (new CCodeExpressionStatement (new CCodeAssignment (new CCodeMemberAccess.pointer (ccall, "get_property"), new CCodeIdentifier ("%s_get_property".printf (cl.get_lower_case_cname (null)))))); + init_block.add_statement (new CCodeExpressionStatement (new CCodeAssignment (new CCodeMemberAccess.pointer (ccall, "set_property"), new CCodeIdentifier ("%s_set_property".printf (cl.get_lower_case_cname (null)))))); + + /* set constructor */ + if (cl.constructor != null) { + var ccast = new CCodeFunctionCall (new CCodeIdentifier ("G_OBJECT_CLASS")); + ccast.add_argument (new CCodeIdentifier ("klass")); + init_block.add_statement (new CCodeExpressionStatement (new CCodeAssignment (new CCodeMemberAccess.pointer (ccast, "constructor"), new CCodeIdentifier ("%s_constructor".printf (cl.get_lower_case_cname (null)))))); + } + + /* set dispose function */ + if (memory_management && cl.get_fields () != null) { + var ccast = new CCodeFunctionCall (new CCodeIdentifier ("G_OBJECT_CLASS")); + ccast.add_argument (new CCodeIdentifier ("klass")); + init_block.add_statement (new CCodeExpressionStatement (new CCodeAssignment (new CCodeMemberAccess.pointer (ccast, "dispose"), new CCodeIdentifier ("%s_dispose".printf (cl.get_lower_case_cname (null)))))); + } + + /* connect overridden methods */ + var methods = cl.get_methods (); + foreach (Method m in methods) { + if (m.base_method == null) { + continue; + } + var base_type = m.base_method.symbol.parent_symbol.node; + + var ccast = new CCodeFunctionCall (new CCodeIdentifier ("%s_CLASS".printf (((Class) base_type).get_upper_case_cname (null)))); + ccast.add_argument (new CCodeIdentifier ("klass")); + init_block.add_statement (new CCodeExpressionStatement (new CCodeAssignment (new CCodeMemberAccess.pointer (ccast, m.name), new CCodeIdentifier (m.get_real_cname ())))); + } + + /* create destroy_func properties for generic types */ + foreach (TypeParameter type_param in cl.get_type_parameters ()) { + string func_name = "%s_destroy_func".printf (type_param.name.down ()); + var func_name_constant = new CCodeConstant ("\"%s-destroy-func\"".printf (type_param.name.down ())); + string enum_value = "%s_%s".printf (cl.get_lower_case_cname (null), func_name).up (); + var cinst = new CCodeFunctionCall (new CCodeIdentifier ("g_object_class_install_property")); + cinst.add_argument (ccall); + cinst.add_argument (new CCodeConstant (enum_value)); + var cspec = new CCodeFunctionCall (new CCodeIdentifier ("g_param_spec_pointer")); + cspec.add_argument (func_name_constant); + cspec.add_argument (new CCodeConstant ("\"destroy func\"")); + cspec.add_argument (new CCodeConstant ("\"destroy func\"")); + cspec.add_argument (new CCodeConstant ("G_PARAM_STATIC_NAME | G_PARAM_STATIC_NICK | G_PARAM_STATIC_BLURB | G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY")); + cinst.add_argument (cspec); + init_block.add_statement (new CCodeExpressionStatement (cinst)); + prop_enum.add_value (enum_value, null); + + instance_priv_struct.add_field ("GDestroyNotify", func_name); + } + + /* create properties */ + var props = cl.get_properties (); + foreach (Property prop in props) { + if (prop.overrides || prop.base_interface_property != null) { + var cinst = new CCodeFunctionCall (new CCodeIdentifier ("g_object_class_override_property")); + cinst.add_argument (ccall); + cinst.add_argument (new CCodeConstant (prop.get_upper_case_cname ())); + cinst.add_argument (prop.get_canonical_cconstant ()); + + init_block.add_statement (new CCodeExpressionStatement (cinst)); + } else { + var cinst = new CCodeFunctionCall (new CCodeIdentifier ("g_object_class_install_property")); + cinst.add_argument (ccall); + cinst.add_argument (new CCodeConstant (prop.get_upper_case_cname ())); + cinst.add_argument (get_param_spec (prop)); + + init_block.add_statement (new CCodeExpressionStatement (cinst)); + } + } + + /* create signals */ + foreach (Signal sig in cl.get_signals ()) { + init_block.add_statement (new CCodeExpressionStatement (get_signal_creation (sig, cl))); + } + + source_type_member_definition.append (class_init); + } + + private void add_interface_init_function (Class! cl, Interface! iface) { + var iface_init = new CCodeFunction ("%s_%s_interface_init".printf (cl.get_lower_case_cname (null), iface.get_lower_case_cname (null)), "void"); + iface_init.add_parameter (new CCodeFormalParameter ("iface", "%s *".printf (iface.get_type_cname ()))); + iface_init.modifiers = CCodeModifiers.STATIC; + + var init_block = new CCodeBlock (); + iface_init.block = init_block; + + ref CCodeFunctionCall ccall; + + /* save pointer to parent vtable */ + string parent_iface_var = "%s_%s_parent_iface".printf (cl.get_lower_case_cname (null), iface.get_lower_case_cname (null)); + var parent_decl = new CCodeDeclaration (iface.get_type_cname () + "*"); + var parent_var_decl = new CCodeVariableDeclarator (parent_iface_var); + parent_var_decl.initializer = new CCodeConstant ("NULL"); + parent_decl.add_declarator (parent_var_decl); + parent_decl.modifiers = CCodeModifiers.STATIC; + source_type_member_declaration.append (parent_decl); + ccall = new CCodeFunctionCall (new CCodeIdentifier ("g_type_interface_peek_parent")); + ccall.add_argument (new CCodeIdentifier ("iface")); + var parent_assignment = new CCodeAssignment (new CCodeIdentifier (parent_iface_var), ccall); + init_block.add_statement (new CCodeExpressionStatement (parent_assignment)); + + var methods = cl.get_methods (); + foreach (Method m in methods) { + if (m.base_interface_method == null) { + continue; + } + + var base_type = m.base_interface_method.symbol.parent_symbol.node; + if (base_type != iface) { + continue; + } + + var ciface = new CCodeIdentifier ("iface"); + init_block.add_statement (new CCodeExpressionStatement (new CCodeAssignment (new CCodeMemberAccess.pointer (ciface, m.name), new CCodeIdentifier (m.get_real_cname ())))); + } + + source_type_member_definition.append (iface_init); + } + + private void add_instance_init_function (Class! cl) { + var instance_init = new CCodeFunction ("%s_init".printf (cl.get_lower_case_cname (null)), "void"); + instance_init.add_parameter (new CCodeFormalParameter ("self", "%s *".printf (cl.get_cname ()))); + instance_init.modifiers = CCodeModifiers.STATIC; + + var init_block = new CCodeBlock (); + instance_init.block = init_block; + + if (cl.has_private_fields) { + var ccall = new CCodeFunctionCall (new CCodeIdentifier ("%s_GET_PRIVATE".printf (cl.get_upper_case_cname (null)))); + ccall.add_argument (new CCodeIdentifier ("self")); + init_block.add_statement (new CCodeExpressionStatement (new CCodeAssignment (new CCodeMemberAccess.pointer (new CCodeIdentifier ("self"), "priv"), ccall))); + } + + init_block.add_statement (instance_init_fragment); + + var init_sym = cl.symbol.lookup ("init"); + if (init_sym != null) { + var init_fun = (Method) init_sym.node; + init_block.add_statement (init_fun.body.ccodenode); + } + + source_type_member_definition.append (instance_init); + } + + private void add_dispose_function (Class! cl) { + function = new CCodeFunction ("%s_dispose".printf (cl.get_lower_case_cname (null)), "void"); + function.modifiers = CCodeModifiers.STATIC; + + function.add_parameter (new CCodeFormalParameter ("obj", "GObject *")); + + source_type_member_declaration.append (function.copy ()); + + + var cblock = new CCodeBlock (); + + var ccall = new CCodeFunctionCall (new CCodeIdentifier (cl.get_upper_case_cname (null))); + ccall.add_argument (new CCodeIdentifier ("obj")); + + var cdecl = new CCodeDeclaration ("%s *".printf (cl.get_cname ())); + cdecl.add_declarator (new CCodeVariableDeclarator.with_initializer ("self", ccall)); + + cblock.add_statement (cdecl); + + cblock.add_statement (instance_dispose_fragment); + + cdecl = new CCodeDeclaration ("%sClass *".printf (cl.get_cname ())); + cdecl.add_declarator (new CCodeVariableDeclarator ("klass")); + cblock.add_statement (cdecl); + + cdecl = new CCodeDeclaration ("GObjectClass *"); + cdecl.add_declarator (new CCodeVariableDeclarator ("parent_class")); + cblock.add_statement (cdecl); + + + ccall = new CCodeFunctionCall (new CCodeIdentifier ("g_type_class_peek")); + ccall.add_argument (new CCodeIdentifier (cl.get_upper_case_cname ("TYPE_"))); + var ccast = new CCodeFunctionCall (new CCodeIdentifier ("%s_CLASS".printf (cl.get_upper_case_cname (null)))); + ccast.add_argument (ccall); + cblock.add_statement (new CCodeExpressionStatement (new CCodeAssignment (new CCodeIdentifier ("klass"), ccast))); + + ccall = new CCodeFunctionCall (new CCodeIdentifier ("g_type_class_peek_parent")); + ccall.add_argument (new CCodeIdentifier ("klass")); + ccast = new CCodeFunctionCall (new CCodeIdentifier ("G_OBJECT_CLASS")); + ccast.add_argument (ccall); + cblock.add_statement (new CCodeExpressionStatement (new CCodeAssignment (new CCodeIdentifier ("parent_class"), ccast))); + + + ccall = new CCodeFunctionCall (new CCodeMemberAccess.pointer (new CCodeIdentifier ("parent_class"), "dispose")); + ccall.add_argument (new CCodeIdentifier ("obj")); + cblock.add_statement (new CCodeExpressionStatement (ccall)); + + + function.block = cblock; + + source_type_member_definition.append (function); + } + + private ref CCodeIdentifier! get_value_setter_function (TypeReference! type_reference) { + if (type_reference.data_type is Class || type_reference.data_type is Interface) { + return new CCodeIdentifier ("g_value_set_object"); + } else if (type_reference.data_type == string_type.data_type) { + return new CCodeIdentifier ("g_value_set_string"); + } else if (type_reference.data_type == int_type.data_type + || type_reference.data_type is Enum) { + return new CCodeIdentifier ("g_value_set_int"); + } else if (type_reference.data_type == uint_type.data_type) { + return new CCodeIdentifier ("g_value_set_uint"); + } else if (type_reference.data_type == long_type.data_type) { + return new CCodeIdentifier ("g_value_set_long"); + } else if (type_reference.data_type == ulong_type.data_type) { + return new CCodeIdentifier ("g_value_set_ulong"); + } else if (type_reference.data_type == bool_type.data_type) { + return new CCodeIdentifier ("g_value_set_boolean"); + } else if (type_reference.data_type == float_type.data_type) { + return new CCodeIdentifier ("g_value_set_float"); + } else if (type_reference.data_type == double_type.data_type) { + return new CCodeIdentifier ("g_value_set_double"); + } else { + return new CCodeIdentifier ("g_value_set_pointer"); + } + } + + private void add_get_property_function (Class! cl) { + var get_prop = new CCodeFunction ("%s_get_property".printf (cl.get_lower_case_cname (null)), "void"); + get_prop.modifiers = CCodeModifiers.STATIC; + get_prop.add_parameter (new CCodeFormalParameter ("object", "GObject *")); + get_prop.add_parameter (new CCodeFormalParameter ("property_id", "guint")); + get_prop.add_parameter (new CCodeFormalParameter ("value", "GValue *")); + get_prop.add_parameter (new CCodeFormalParameter ("pspec", "GParamSpec *")); + + var block = new CCodeBlock (); + + var ccall = new CCodeFunctionCall (new CCodeIdentifier (cl.get_upper_case_cname (null))); + ccall.add_argument (new CCodeIdentifier ("object")); + var cdecl = new CCodeDeclaration ("%s *".printf (cl.get_cname ())); + cdecl.add_declarator (new CCodeVariableDeclarator.with_initializer ("self", ccall)); + block.add_statement (cdecl); + + var cswitch = new CCodeSwitchStatement (new CCodeIdentifier ("property_id")); + var props = cl.get_properties (); + foreach (Property prop in props) { + if (prop.get_accessor == null || prop.is_abstract) { + continue; + } + + bool is_virtual = prop.base_property != null || prop.base_interface_property != null; + + string prefix = cl.get_lower_case_cname (null); + if (is_virtual) { + prefix += "_real"; + } + + var ccase = new CCodeCaseStatement (new CCodeIdentifier (prop.get_upper_case_cname ())); + var ccall = new CCodeFunctionCall (new CCodeIdentifier ("%s_get_%s".printf (prefix, prop.name))); + ccall.add_argument (new CCodeIdentifier ("self")); + var csetcall = new CCodeFunctionCall (); + csetcall.call = get_value_setter_function (prop.type_reference); + csetcall.add_argument (new CCodeIdentifier ("value")); + csetcall.add_argument (ccall); + ccase.add_statement (new CCodeExpressionStatement (csetcall)); + ccase.add_statement (new CCodeBreakStatement ()); + cswitch.add_case (ccase); + } + block.add_statement (cswitch); + + get_prop.block = block; + + source_type_member_definition.append (get_prop); + } + + private void add_set_property_function (Class! cl) { + var set_prop = new CCodeFunction ("%s_set_property".printf (cl.get_lower_case_cname (null)), "void"); + set_prop.modifiers = CCodeModifiers.STATIC; + set_prop.add_parameter (new CCodeFormalParameter ("object", "GObject *")); + set_prop.add_parameter (new CCodeFormalParameter ("property_id", "guint")); + set_prop.add_parameter (new CCodeFormalParameter ("value", "const GValue *")); + set_prop.add_parameter (new CCodeFormalParameter ("pspec", "GParamSpec *")); + + var block = new CCodeBlock (); + + var ccall = new CCodeFunctionCall (new CCodeIdentifier (cl.get_upper_case_cname (null))); + ccall.add_argument (new CCodeIdentifier ("object")); + var cdecl = new CCodeDeclaration ("%s *".printf (cl.get_cname ())); + cdecl.add_declarator (new CCodeVariableDeclarator.with_initializer ("self", ccall)); + block.add_statement (cdecl); + + var cswitch = new CCodeSwitchStatement (new CCodeIdentifier ("property_id")); + var props = cl.get_properties (); + foreach (Property prop in props) { + if (prop.set_accessor == null || prop.is_abstract) { + continue; + } + + bool is_virtual = prop.base_property != null || prop.base_interface_property != null; + + string prefix = cl.get_lower_case_cname (null); + if (is_virtual) { + prefix += "_real"; + } + + var ccase = new CCodeCaseStatement (new CCodeIdentifier (prop.get_upper_case_cname ())); + var ccall = new CCodeFunctionCall (new CCodeIdentifier ("%s_set_%s".printf (prefix, prop.name))); + ccall.add_argument (new CCodeIdentifier ("self")); + var cgetcall = new CCodeFunctionCall (); + if (prop.type_reference.data_type is Class || prop.type_reference.data_type is Interface) { + cgetcall.call = new CCodeIdentifier ("g_value_get_object"); + } else if (prop.type_reference.type_name == "string") { + cgetcall.call = new CCodeIdentifier ("g_value_get_string"); + } else if (prop.type_reference.type_name == "int" || prop.type_reference.data_type is Enum) { + cgetcall.call = new CCodeIdentifier ("g_value_get_int"); + } else if (prop.type_reference.type_name == "uint") { + cgetcall.call = new CCodeIdentifier ("g_value_get_uint"); + } else if (prop.type_reference.type_name == "long") { + cgetcall.call = new CCodeIdentifier ("g_value_get_long"); + } else if (prop.type_reference.type_name == "ulong") { + cgetcall.call = new CCodeIdentifier ("g_value_get_ulong"); + } else if (prop.type_reference.type_name == "bool") { + cgetcall.call = new CCodeIdentifier ("g_value_get_boolean"); + } else if (prop.type_reference.type_name == "float") { + cgetcall.call = new CCodeIdentifier ("g_value_get_float"); + } else if (prop.type_reference.type_name == "double") { + cgetcall.call = new CCodeIdentifier ("g_value_get_double"); + } else { + cgetcall.call = new CCodeIdentifier ("g_value_get_pointer"); + } + cgetcall.add_argument (new CCodeIdentifier ("value")); + ccall.add_argument (cgetcall); + ccase.add_statement (new CCodeExpressionStatement (ccall)); + ccase.add_statement (new CCodeBreakStatement ()); + cswitch.add_case (ccase); + } + block.add_statement (cswitch); + + /* destroy func properties for generic types */ + foreach (TypeParameter type_param in cl.get_type_parameters ()) { + string func_name = "%s_destroy_func".printf (type_param.name.down ()); + string enum_value = "%s_%s".printf (cl.get_lower_case_cname (null), func_name).up (); + + var ccase = new CCodeCaseStatement (new CCodeIdentifier (enum_value)); + var cfield = new CCodeMemberAccess.pointer (new CCodeMemberAccess.pointer (new CCodeIdentifier ("self"), "priv"), func_name); + var cgetcall = new CCodeFunctionCall (new CCodeIdentifier ("g_value_get_pointer")); + cgetcall.add_argument (new CCodeIdentifier ("value")); + ccase.add_statement (new CCodeExpressionStatement (new CCodeAssignment (cfield, cgetcall))); + ccase.add_statement (new CCodeBreakStatement ()); + cswitch.add_case (ccase); + } + + set_prop.block = block; + + source_type_member_definition.append (set_prop); + } + + public override void visit_begin_struct (Struct! st) { + current_type_symbol = st.symbol; + + instance_struct = new CCodeStruct ("_%s".printf (st.get_cname ())); + + if (st.source_reference.file.cycle == null) { + header_type_declaration.append (new CCodeTypeDefinition ("struct _%s".printf (st.get_cname ()), new CCodeVariableDeclarator (st.get_cname ()))); + } + + if (st.source_reference.comment != null) { + header_type_definition.append (new CCodeComment (st.source_reference.comment)); + } + header_type_definition.append (instance_struct); + } + + public override void visit_end_struct (Struct! st) { + current_type_symbol = null; + } + + public override void visit_begin_interface (Interface! iface) { + current_symbol = iface.symbol; + current_type_symbol = iface.symbol; + + if (iface.is_static) { + return; + } + + type_struct = new CCodeStruct ("_%s".printf (iface.get_type_cname ())); + + header_type_declaration.append (new CCodeNewline ()); + var macro = "(%s_get_type ())".printf (iface.get_lower_case_cname (null)); + header_type_declaration.append (new CCodeMacroReplacement (iface.get_upper_case_cname ("TYPE_"), macro)); + + macro = "(G_TYPE_CHECK_INSTANCE_CAST ((obj), %s, %s))".printf (iface.get_upper_case_cname ("TYPE_"), iface.get_cname ()); + header_type_declaration.append (new CCodeMacroReplacement ("%s(obj)".printf (iface.get_upper_case_cname (null)), macro)); + + macro = "(G_TYPE_CHECK_INSTANCE_TYPE ((obj), %s))".printf (iface.get_upper_case_cname ("TYPE_")); + header_type_declaration.append (new CCodeMacroReplacement ("%s(obj)".printf (iface.get_upper_case_cname ("IS_")), macro)); + + macro = "(G_TYPE_INSTANCE_GET_INTERFACE ((obj), %s, %s))".printf (iface.get_upper_case_cname ("TYPE_"), iface.get_type_cname ()); + header_type_declaration.append (new CCodeMacroReplacement ("%s_GET_INTERFACE(obj)".printf (iface.get_upper_case_cname (null)), macro)); + header_type_declaration.append (new CCodeNewline ()); + + + if (iface.source_reference.file.cycle == null) { + header_type_declaration.append (new CCodeTypeDefinition ("struct _%s".printf (iface.get_cname ()), new CCodeVariableDeclarator (iface.get_cname ()))); + header_type_declaration.append (new CCodeTypeDefinition ("struct %s".printf (type_struct.name), new CCodeVariableDeclarator (iface.get_type_cname ()))); + } + + type_struct.add_field ("GTypeInterface", "parent"); + + if (iface.source_reference.comment != null) { + header_type_definition.append (new CCodeComment (iface.source_reference.comment)); + } + header_type_definition.append (type_struct); + } + + public override void visit_end_interface (Interface! iface) { + if (!iface.is_static) { + add_interface_base_init_function (iface); + + var type_fun = new InterfaceRegisterFunction (iface); + type_fun.init_from_type (); + header_type_member_declaration.append (type_fun.get_declaration ()); + source_type_member_definition.append (type_fun.get_definition ()); + } + + current_type_symbol = null; + } + + private ref CCodeFunctionCall! get_param_spec (Property! prop) { + var cspec = new CCodeFunctionCall (); + cspec.add_argument (prop.get_canonical_cconstant ()); + cspec.add_argument (new CCodeConstant ("\"foo\"")); + cspec.add_argument (new CCodeConstant ("\"bar\"")); + if (prop.type_reference.data_type is Class || prop.type_reference.data_type is Interface) { + cspec.call = new CCodeIdentifier ("g_param_spec_object"); + cspec.add_argument (new CCodeIdentifier (prop.type_reference.data_type.get_upper_case_cname ("TYPE_"))); + } else if (prop.type_reference.data_type == string_type.data_type) { + cspec.call = new CCodeIdentifier ("g_param_spec_string"); + cspec.add_argument (new CCodeConstant ("NULL")); + } else if (prop.type_reference.data_type == int_type.data_type + || prop.type_reference.data_type is Enum) { + cspec.call = new CCodeIdentifier ("g_param_spec_int"); + cspec.add_argument (new CCodeConstant ("G_MININT")); + cspec.add_argument (new CCodeConstant ("G_MAXINT")); + cspec.add_argument (new CCodeConstant ("0")); + } else if (prop.type_reference.data_type == uint_type.data_type) { + cspec.call = new CCodeIdentifier ("g_param_spec_uint"); + cspec.add_argument (new CCodeConstant ("0")); + cspec.add_argument (new CCodeConstant ("G_MAXUINT")); + cspec.add_argument (new CCodeConstant ("0U")); + } else if (prop.type_reference.data_type == long_type.data_type) { + cspec.call = new CCodeIdentifier ("g_param_spec_long"); + cspec.add_argument (new CCodeConstant ("G_MINLONG")); + cspec.add_argument (new CCodeConstant ("G_MAXLONG")); + cspec.add_argument (new CCodeConstant ("0L")); + } else if (prop.type_reference.data_type == ulong_type.data_type) { + cspec.call = new CCodeIdentifier ("g_param_spec_ulong"); + cspec.add_argument (new CCodeConstant ("0")); + cspec.add_argument (new CCodeConstant ("G_MAXULONG")); + cspec.add_argument (new CCodeConstant ("0UL")); + } else if (prop.type_reference.data_type == bool_type.data_type) { + cspec.call = new CCodeIdentifier ("g_param_spec_boolean"); + cspec.add_argument (new CCodeConstant ("FALSE")); + } else if (prop.type_reference.data_type == float_type.data_type) { + cspec.call = new CCodeIdentifier ("g_param_spec_float"); + cspec.add_argument (new CCodeConstant ("-G_MAXFLOAT")); + cspec.add_argument (new CCodeConstant ("G_MAXFLOAT")); + cspec.add_argument (new CCodeConstant ("0.0F")); + } else if (prop.type_reference.data_type == double_type.data_type) { + cspec.call = new CCodeIdentifier ("g_param_spec_double"); + cspec.add_argument (new CCodeConstant ("-G_MAXDOUBLE")); + cspec.add_argument (new CCodeConstant ("G_MAXDOUBLE")); + cspec.add_argument (new CCodeConstant ("0.0")); + } else { + cspec.call = new CCodeIdentifier ("g_param_spec_pointer"); + } + + var pflags = "G_PARAM_STATIC_NAME | G_PARAM_STATIC_NICK | G_PARAM_STATIC_BLURB"; + if (prop.get_accessor != null) { + pflags = "%s%s".printf (pflags, " | G_PARAM_READABLE"); + } + if (prop.set_accessor != null) { + pflags = "%s%s".printf (pflags, " | G_PARAM_WRITABLE"); + if (prop.set_accessor.construction) { + if (prop.set_accessor.writable) { + pflags = "%s%s".printf (pflags, " | G_PARAM_CONSTRUCT"); + } else { + pflags = "%s%s".printf (pflags, " | G_PARAM_CONSTRUCT_ONLY"); + } + } + } + cspec.add_argument (new CCodeConstant (pflags)); + + return cspec; + } + + private ref CCodeFunctionCall! get_signal_creation (Signal! sig, DataType! type) { + var csignew = new CCodeFunctionCall (new CCodeIdentifier ("g_signal_new")); + csignew.add_argument (new CCodeConstant ("\"%s\"".printf (sig.name))); + csignew.add_argument (new CCodeIdentifier (type.get_upper_case_cname ("TYPE_"))); + csignew.add_argument (new CCodeConstant ("G_SIGNAL_RUN_LAST")); + csignew.add_argument (new CCodeConstant ("0")); + csignew.add_argument (new CCodeConstant ("NULL")); + csignew.add_argument (new CCodeConstant ("NULL")); + + string marshaller = get_signal_marshaller_function (sig); + + var marshal_arg = new CCodeIdentifier (marshaller); + csignew.add_argument (marshal_arg); + + var params = sig.get_parameters (); + var params_len = params.length (); + if (sig.return_type.type_parameter != null) { + csignew.add_argument (new CCodeConstant ("G_TYPE_POINTER")); + } else if (sig.return_type.data_type == null) { + csignew.add_argument (new CCodeConstant ("G_TYPE_NONE")); + } else { + csignew.add_argument (new CCodeConstant (sig.return_type.data_type.get_type_id ())); + } + csignew.add_argument (new CCodeConstant ("%d".printf (params_len))); + foreach (FormalParameter param in params) { + if (param.type_reference.type_parameter != null) { + csignew.add_argument (new CCodeConstant ("G_TYPE_POINTER")); + } else { + csignew.add_argument (new CCodeConstant (param.type_reference.data_type.get_type_id ())); + } + } + + marshal_arg.name = marshaller; + + return csignew; + } + + private void add_interface_base_init_function (Interface! iface) { + var base_init = new CCodeFunction ("%s_base_init".printf (iface.get_lower_case_cname (null)), "void"); + base_init.add_parameter (new CCodeFormalParameter ("iface", "%sIface *".printf (iface.get_cname ()))); + base_init.modifiers = CCodeModifiers.STATIC; + + var init_block = new CCodeBlock (); + + /* make sure not to run the initialization code twice */ + base_init.block = new CCodeBlock (); + var decl = new CCodeDeclaration (bool_type.get_cname ()); + decl.modifiers |= CCodeModifiers.STATIC; + decl.add_declarator (new CCodeVariableDeclarator.with_initializer ("initialized", new CCodeConstant ("FALSE"))); + base_init.block.add_statement (decl); + var cif = new CCodeIfStatement (new CCodeUnaryExpression (CCodeUnaryOperator.LOGICAL_NEGATION, new CCodeIdentifier ("initialized")), init_block); + base_init.block.add_statement (cif); + init_block.add_statement (new CCodeExpressionStatement (new CCodeAssignment (new CCodeIdentifier ("initialized"), new CCodeConstant ("TRUE")))); + + /* create properties */ + var props = iface.get_properties (); + foreach (Property prop in props) { + var cinst = new CCodeFunctionCall (new CCodeIdentifier ("g_object_interface_install_property")); + cinst.add_argument (new CCodeIdentifier ("iface")); + cinst.add_argument (get_param_spec (prop)); + + init_block.add_statement (new CCodeExpressionStatement (cinst)); + } + + /* create signals */ + foreach (Signal sig in iface.get_signals ()) { + init_block.add_statement (new CCodeExpressionStatement (get_signal_creation (sig, iface))); + } + + source_type_member_definition.append (base_init); + } + + public override void visit_begin_enum (Enum! en) { + cenum = new CCodeEnum (en.get_cname ()); + + if (en.source_reference.comment != null) { + header_type_definition.append (new CCodeComment (en.source_reference.comment)); + } + header_type_definition.append (cenum); + } + + public override void visit_enum_value (EnumValue! ev) { + string val; + if (ev.value is LiteralExpression) { + var lit = ((LiteralExpression) ev.value).literal; + if (lit is IntegerLiteral) { + val = ((IntegerLiteral) lit).value; + } + } + cenum.add_value (ev.get_cname (), val); + } + + public override void visit_begin_flags (Flags! fl) { + cenum = new CCodeEnum (fl.get_cname ()); + + if (fl.source_reference.comment != null) { + header_type_definition.append (new CCodeComment (fl.source_reference.comment)); + } + header_type_definition.append (cenum); + } + + public override void visit_flags_value (FlagsValue! fv) { + string val; + if (fv.value is LiteralExpression) { + var lit = ((LiteralExpression) fv.value).literal; + if (lit is IntegerLiteral) { + val = ((IntegerLiteral) lit).value; + } + } + cenum.add_value (fv.get_cname (), val); + } + + public override void visit_end_callback (Callback! cb) { + var cfundecl = new CCodeFunctionDeclarator (cb.get_cname ()); + foreach (FormalParameter param in cb.get_parameters ()) { + cfundecl.add_parameter ((CCodeFormalParameter) param.ccodenode); + } + + var ctypedef = new CCodeTypeDefinition (cb.return_type.get_cname (), cfundecl); + + if (cb.access != MemberAccessibility.PRIVATE) { + header_type_declaration.append (ctypedef); + } else { + source_type_member_declaration.append (ctypedef); + } + } + + public override void visit_member (Member! m) { + /* stuff meant for all lockable members */ + if (m is Lockable && ((Lockable)m).get_lock_used ()) { + instance_priv_struct.add_field (mutex_type.get_cname (), get_symbol_lock_name (m.symbol)); + + instance_init_fragment.append ( + new CCodeExpressionStatement ( + new CCodeAssignment ( + new CCodeMemberAccess.pointer ( + new CCodeMemberAccess.pointer (new CCodeIdentifier ("self"), "priv"), + get_symbol_lock_name (m.symbol)), + new CCodeFunctionCall (new CCodeIdentifier (((Struct)mutex_type.data_type).default_construction_method.get_cname ()))))); + + var fc = new CCodeFunctionCall (new CCodeIdentifier ("VALA_FREE_CHECKED")); + fc.add_argument ( + new CCodeMemberAccess.pointer ( + new CCodeMemberAccess.pointer (new CCodeIdentifier ("self"), "priv"), + get_symbol_lock_name (m.symbol))); + fc.add_argument (new CCodeIdentifier (mutex_type.data_type.get_free_function ())); + if (instance_dispose_fragment != null) { + instance_dispose_fragment.append (new CCodeExpressionStatement (fc)); + } + } + } + + public override void visit_constant (Constant! c) { + if (c.symbol.parent_symbol.node is DataType) { + var t = (DataType) c.symbol.parent_symbol.node; + var cdecl = new CCodeDeclaration (c.type_reference.get_const_cname ()); + var arr = ""; + if (c.type_reference.data_type is Array) { + arr = "[]"; + } + cdecl.add_declarator (new CCodeVariableDeclarator.with_initializer ("%s%s".printf (c.get_cname (), arr), (CCodeExpression) c.initializer.ccodenode)); + cdecl.modifiers = CCodeModifiers.STATIC; + + if (c.access != MemberAccessibility.PRIVATE) { + header_type_member_declaration.append (cdecl); + } else { + source_type_member_declaration.append (cdecl); + } + } + } + + public override void visit_field (Field! f) { + CCodeExpression lhs = null; + CCodeStruct st = null; + + if (f.access != MemberAccessibility.PRIVATE) { + st = instance_struct; + if (f.instance) { + lhs = new CCodeMemberAccess.pointer (new CCodeIdentifier ("self"), f.get_cname ()); + } + } else if (f.access == MemberAccessibility.PRIVATE) { + if (f.instance) { + st = instance_priv_struct; + lhs = new CCodeMemberAccess.pointer (new CCodeMemberAccess.pointer (new CCodeIdentifier ("self"), "priv"), f.get_cname ()); + } else { + if (f.symbol.parent_symbol.node is DataType) { + var t = (DataType) f.symbol.parent_symbol.node; + var cdecl = new CCodeDeclaration (f.type_reference.get_cname ()); + var var_decl = new CCodeVariableDeclarator (f.get_cname ()); + if (f.initializer != null) { + var_decl.initializer = (CCodeExpression) f.initializer.ccodenode; + } + cdecl.add_declarator (var_decl); + cdecl.modifiers = CCodeModifiers.STATIC; + source_type_member_declaration.append (cdecl); + } + } + } + + if (f.instance) { + st.add_field (f.type_reference.get_cname (), f.get_cname ()); + if (f.type_reference.data_type is Array && !f.no_array_length) { + // create fields to store array dimensions + var arr = (Array) f.type_reference.data_type; + + for (int dim = 1; dim <= arr.rank; dim++) { + var len_type = new TypeReference (); + len_type.data_type = int_type.data_type; + + st.add_field (len_type.get_cname (), get_array_length_cname (f.name, dim)); + } + } + + if (f.initializer != null) { + instance_init_fragment.append (new CCodeExpressionStatement (new CCodeAssignment (lhs, (CCodeExpression) f.initializer.ccodenode))); + + if (f.type_reference.data_type is Array && !f.no_array_length && + f.initializer is ArrayCreationExpression) { + var ma = new MemberAccess.simple (f.name); + ma.symbol_reference = f.symbol; + + var array_len_lhs = get_array_length_cexpression (ma, 1); + var sizes = ((ArrayCreationExpression) f.initializer).get_sizes (); + var size = (Expression) sizes.data; + instance_init_fragment.append (new CCodeExpressionStatement (new CCodeAssignment (array_len_lhs, (CCodeExpression) size.ccodenode))); + } + } + + if (f.type_reference.takes_ownership && instance_dispose_fragment != null) { + instance_dispose_fragment.append (new CCodeExpressionStatement (get_unref_expression (lhs, f.type_reference))); + } + } + } + + public override void visit_begin_method (Method! m) { + current_symbol = m.symbol; + current_return_type = m.return_type; + } + + private ref CCodeStatement create_method_type_check_statement (Method! m, DataType! t, bool non_null, string! var_name) { + return create_type_check_statement (m, m.return_type.data_type, t, non_null, var_name); + } + + private ref CCodeStatement create_property_type_check_statement (Property! prop, bool getter, DataType! t, bool non_null, string! var_name) { + if (getter) { + return create_type_check_statement (prop, prop.type_reference.data_type, t, non_null, var_name); + } else { + return create_type_check_statement (prop, null, t, non_null, var_name); + } + } + + private ref CCodeStatement create_type_check_statement (CodeNode! method_node, DataType ret_type, DataType! t, bool non_null, string! var_name) { + var ccheck = new CCodeFunctionCall (); + + if (t is Class || t is Interface) { + var ctype_check = new CCodeFunctionCall (new CCodeIdentifier (t.get_upper_case_cname ("IS_"))); + ctype_check.add_argument (new CCodeIdentifier (var_name)); + + ref CCodeExpression cexpr = ctype_check; + if (!non_null) { + var cnull = new CCodeBinaryExpression (CCodeBinaryOperator.EQUALITY, new CCodeIdentifier (var_name), new CCodeConstant ("NULL")); + + cexpr = new CCodeBinaryExpression (CCodeBinaryOperator.OR, cnull, ctype_check); + } + ccheck.add_argument (cexpr); + } else if (!non_null) { + return null; + } else { + var cnonnull = new CCodeBinaryExpression (CCodeBinaryOperator.INEQUALITY, new CCodeIdentifier (var_name), new CCodeConstant ("NULL")); + ccheck.add_argument (cnonnull); + } + + if (ret_type == null) { + /* void function */ + ccheck.call = new CCodeIdentifier ("g_return_if_fail"); + } else { + ccheck.call = new CCodeIdentifier ("g_return_val_if_fail"); + + if (ret_type.is_reference_type () || ret_type is Pointer) { + ccheck.add_argument (new CCodeConstant ("NULL")); + } else if (ret_type.get_default_value () != null) { + ccheck.add_argument (new CCodeConstant (ret_type.get_default_value ())); + } else { + Report.warning (method_node.source_reference, "not supported return type for runtime type checks"); + return new CCodeExpressionStatement (new CCodeConstant ("0")); + } + } + + return new CCodeExpressionStatement (ccheck); + } + + private DataType find_parent_type (CodeNode node) { + var sym = node.symbol; + while (sym != null) { + if (sym.node is DataType) { + return (DataType) sym.node; + } + sym = sym.parent_symbol; + } + return null; + } + + private ref string! get_array_length_cname (string! array_cname, int dim) { + return "%s_length%d".printf (array_cname, dim); + } + + public override void visit_end_method (Method! m) { + current_symbol = current_symbol.parent_symbol; + current_return_type = null; + + if (current_type_symbol != null && current_type_symbol.node is Interface) { + var iface = (Interface) current_type_symbol.node; + if (iface.is_static) { + return; + } + } + + if (current_symbol.parent_symbol != null && + current_symbol.parent_symbol.node is Method) { + /* lambda expressions produce nested methods */ + var up_method = (Method) current_symbol.parent_symbol.node; + current_return_type = up_method.return_type; + } + + function = new CCodeFunction (m.get_real_cname (), m.return_type.get_cname ()); + CCodeFunctionDeclarator vdeclarator = null; + + CCodeFormalParameter instance_param = null; + + if (m.instance) { + var this_type = new TypeReference (); + this_type.data_type = find_parent_type (m); + if (m.base_interface_method != null) { + var base_type = new TypeReference (); + base_type.data_type = (DataType) m.base_interface_method.symbol.parent_symbol.node; + instance_param = new CCodeFormalParameter ("base", base_type.get_cname ()); + } else if (m.overrides) { + var base_type = new TypeReference (); + base_type.data_type = (DataType) m.base_method.symbol.parent_symbol.node; + instance_param = new CCodeFormalParameter ("base", base_type.get_cname ()); + } else { + if (m.instance_by_reference) { + instance_param = new CCodeFormalParameter ("*self", this_type.get_cname ()); + } else { + instance_param = new CCodeFormalParameter ("self", this_type.get_cname ()); + } + } + if (!m.instance_last) { + function.add_parameter (instance_param); + } + + if (m.is_abstract || m.is_virtual) { + var vdecl = new CCodeDeclaration (m.return_type.get_cname ()); + vdeclarator = new CCodeFunctionDeclarator (m.name); + vdecl.add_declarator (vdeclarator); + type_struct.add_declaration (vdecl); + + vdeclarator.add_parameter (instance_param); + } + } + + if (m is CreationMethod && current_class != null) { + // memory management for generic types + foreach (TypeParameter type_param in current_class.get_type_parameters ()) { + var cparam = new CCodeFormalParameter ("%s_destroy_func".printf (type_param.name.down ()), "GDestroyNotify"); + function.add_parameter (cparam); + } + } + + var params = m.get_parameters (); + foreach (FormalParameter param in params) { + if (!param.no_array_length && param.type_reference.data_type is Array) { + var arr = (Array) param.type_reference.data_type; + + var length_ctype = "int"; + if (param.type_reference.is_out) { + length_ctype = "int*"; + } + + for (int dim = 1; dim <= arr.rank; dim++) { + var cparam = new CCodeFormalParameter (get_array_length_cname (param.name, dim), length_ctype); + function.add_parameter (cparam); + if (vdeclarator != null) { + vdeclarator.add_parameter (cparam); + } + } + } + + function.add_parameter ((CCodeFormalParameter) param.ccodenode); + if (vdeclarator != null) { + vdeclarator.add_parameter ((CCodeFormalParameter) param.ccodenode); + } + } + + if (m.instance && m.instance_last) { + function.add_parameter (instance_param); + } + + /* real function declaration and definition not needed + * for abstract methods */ + if (!m.is_abstract) { + if (m.access != MemberAccessibility.PRIVATE && m.base_method == null && m.base_interface_method == null) { + /* public methods need function declaration in + * header file except virtual/overridden methods */ + header_type_member_declaration.append (function.copy ()); + } else { + /* declare all other functions in source file to + * avoid dependency on order within source file */ + function.modifiers |= CCodeModifiers.STATIC; + source_type_member_declaration.append (function.copy ()); + } + + /* Methods imported from a plain C file don't + * have a body, e.g. Vala.Parser.parse_file () */ + if (m.body != null) { + function.block = (CCodeBlock) m.body.ccodenode; + + var cinit = new CCodeFragment (); + function.block.prepend_statement (cinit); + + if (m.symbol.parent_symbol.node is Class) { + var cl = (Class) m.symbol.parent_symbol.node; + if (m.overrides || m.base_interface_method != null) { + var ccall = new CCodeFunctionCall (new CCodeIdentifier (cl.get_upper_case_cname (null))); + ccall.add_argument (new CCodeIdentifier ("base")); + + var cdecl = new CCodeDeclaration ("%s *".printf (cl.get_cname ())); + cdecl.add_declarator (new CCodeVariableDeclarator.with_initializer ("self", ccall)); + + cinit.append (cdecl); + } else if (m.instance) { + cinit.append (create_method_type_check_statement (m, cl, true, "self")); + } + } + foreach (FormalParameter param in m.get_parameters ()) { + var t = param.type_reference.data_type; + if (t != null && t.is_reference_type () && !param.type_reference.is_out) { + var type_check = create_method_type_check_statement (m, t, param.type_reference.non_null, param.name); + if (type_check != null) { + cinit.append (type_check); + } + } + } + + if (m.source_reference != null && m.source_reference.comment != null) { + source_type_member_definition.append (new CCodeComment (m.source_reference.comment)); + } + source_type_member_definition.append (function); + + if (m is CreationMethod) { + if (current_class != null) { + int n_params = ((CreationMethod) m).n_construction_params; + n_params += (int) current_class.get_type_parameters ().length (); + + // declare construction parameter array + var cparamsinit = new CCodeFunctionCall (new CCodeIdentifier ("g_new0")); + cparamsinit.add_argument (new CCodeIdentifier ("GParameter")); + cparamsinit.add_argument (new CCodeConstant (n_params.to_string ())); + + var cdecl = new CCodeDeclaration ("GParameter *"); + cdecl.add_declarator (new CCodeVariableDeclarator.with_initializer ("__params", cparamsinit)); + cinit.append (cdecl); + + cdecl = new CCodeDeclaration ("GParameter *"); + cdecl.add_declarator (new CCodeVariableDeclarator.with_initializer ("__params_it", new CCodeIdentifier ("__params"))); + cinit.append (cdecl); + + /* destroy func properties for generic types */ + foreach (TypeParameter type_param in current_class.get_type_parameters ()) { + string func_name = "%s_destroy_func".printf (type_param.name.down ()); + var func_name_constant = new CCodeConstant ("\"%s-destroy-func\"".printf (type_param.name.down ())); + + // this property is used as a construction parameter + var cpointer = new CCodeIdentifier ("__params_it"); + + var ccomma = new CCodeCommaExpression (); + // set name in array for current parameter + var cnamemember = new CCodeMemberAccess.pointer (cpointer, "name"); + ccomma.append_expression (new CCodeAssignment (cnamemember, func_name_constant)); + var gvaluearg = new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeMemberAccess.pointer (cpointer, "value")); + + // initialize GValue in array for current parameter + var cvalueinit = new CCodeFunctionCall (new CCodeIdentifier ("g_value_init")); + cvalueinit.add_argument (gvaluearg); + cvalueinit.add_argument (new CCodeIdentifier ("G_TYPE_POINTER")); + ccomma.append_expression (cvalueinit); + + // set GValue for current parameter + var cvalueset = new CCodeFunctionCall (new CCodeIdentifier ("g_value_set_pointer")); + cvalueset.add_argument (gvaluearg); + cvalueset.add_argument (new CCodeIdentifier (func_name)); + ccomma.append_expression (cvalueset); + + // move pointer to next parameter in array + ccomma.append_expression (new CCodeUnaryExpression (CCodeUnaryOperator.POSTFIX_INCREMENT, cpointer)); + + cinit.append (new CCodeExpressionStatement (ccomma)); + } + } else { + var st = (Struct) m.symbol.parent_symbol.node; + var cdecl = new CCodeDeclaration (st.get_cname () + "*"); + var ccall = new CCodeFunctionCall (new CCodeIdentifier ("g_new0")); + ccall.add_argument (new CCodeConstant (st.get_cname ())); + ccall.add_argument (new CCodeConstant ("1")); + cdecl.add_declarator (new CCodeVariableDeclarator.with_initializer ("self", ccall)); + cinit.append (cdecl); + } + } + + if (context.module_init_method == m && in_plugin) { + // GTypeModule-based plug-in, register types + cinit.append (module_init_fragment); + } + } + } + + if (m.is_abstract || m.is_virtual) { + var vfunc = new CCodeFunction (m.get_cname (), m.return_type.get_cname ()); + + var this_type = new TypeReference (); + this_type.data_type = (DataType) m.symbol.parent_symbol.node; + + var cparam = new CCodeFormalParameter ("self", this_type.get_cname ()); + vfunc.add_parameter (cparam); + + var vblock = new CCodeBlock (); + + CCodeFunctionCall vcast = null; + if (m.symbol.parent_symbol.node is Interface) { + var iface = (Interface) m.symbol.parent_symbol.node; + + vcast = new CCodeFunctionCall (new CCodeIdentifier ("%s_GET_INTERFACE".printf (iface.get_upper_case_cname (null)))); + } else { + var cl = (Class) m.symbol.parent_symbol.node; + + vcast = new CCodeFunctionCall (new CCodeIdentifier ("%s_GET_CLASS".printf (cl.get_upper_case_cname (null)))); + } + vcast.add_argument (new CCodeIdentifier ("self")); + + var vcall = new CCodeFunctionCall (new CCodeMemberAccess.pointer (vcast, m.name)); + vcall.add_argument (new CCodeIdentifier ("self")); + + var params = m.get_parameters (); + foreach (FormalParameter param in params) { + vfunc.add_parameter ((CCodeFormalParameter) param.ccodenode); + vcall.add_argument (new CCodeIdentifier (param.name)); + } + + if (m.return_type.data_type == null) { + vblock.add_statement (new CCodeExpressionStatement (vcall)); + } else { + /* pass method return value */ + vblock.add_statement (new CCodeReturnStatement (vcall)); + } + + header_type_member_declaration.append (vfunc.copy ()); + + vfunc.block = vblock; + + source_type_member_definition.append (vfunc); + } + + if (m is CreationMethod) { + var creturn = new CCodeReturnStatement (); + creturn.return_expression = new CCodeIdentifier ("self"); + function.block.add_statement (creturn); + } + + bool return_value = true; + bool args_parameter = true; + if (is_possible_entry_point (m, ref return_value, ref args_parameter)) { + // m is possible entry point, add appropriate startup code + var cmain = new CCodeFunction ("main", "int"); + cmain.add_parameter (new CCodeFormalParameter ("argc", "int")); + cmain.add_parameter (new CCodeFormalParameter ("argv", "char **")); + var main_block = new CCodeBlock (); + main_block.add_statement (new CCodeExpressionStatement (new CCodeFunctionCall (new CCodeIdentifier ("g_type_init")))); + var main_call = new CCodeFunctionCall (new CCodeIdentifier (function.name)); + if (args_parameter) { + main_call.add_argument (new CCodeIdentifier ("argc")); + main_call.add_argument (new CCodeIdentifier ("argv")); + } + if (return_value) { + main_block.add_statement (new CCodeReturnStatement (main_call)); + } else { + // method returns void, always use 0 as exit code + main_block.add_statement (new CCodeExpressionStatement (main_call)); + main_block.add_statement (new CCodeReturnStatement (new CCodeConstant ("0"))); + } + cmain.block = main_block; + source_type_member_definition.append (cmain); + } + } + + public override void visit_begin_creation_method (CreationMethod! m) { + current_symbol = m.symbol; + current_return_type = m.return_type; + in_creation_method = true; + } + + public override void visit_end_creation_method (CreationMethod! m) { + if (current_class != null && m.body != null) { + add_object_creation ((CCodeBlock) m.body.ccodenode); + } + + in_creation_method = false; + + visit_end_method (m); + } + + private bool is_possible_entry_point (Method! m, ref bool return_value, ref bool args_parameter) { + if (m.name == null || m.name != "main") { + // method must be called "main" + return false; + } + + if (m.instance) { + // method must be static + return false; + } + + if (m.return_type.data_type == null) { + return_value = false; + } else if (m.return_type.data_type == int_type.data_type) { + return_value = true; + } else { + // return type must be void or int + return false; + } + + var params = m.get_parameters (); + if (params.length () == 0) { + // method may have no parameters + args_parameter = false; + return true; + } + + if (params.length () > 1) { + // method must not have more than one parameter + return false; + } + + var param = (FormalParameter) params.data; + + if (param.type_reference.is_out) { + // parameter must not be an out parameter + return false; + } + + if (!(param.type_reference.data_type is Array)) { + // parameter must be an array + return false; + } + + var array_type = (Array) param.type_reference.data_type; + if (array_type.element_type != string_type.data_type) { + // parameter must be an array of strings + return false; + } + + args_parameter = true; + return true; + } + + public override void visit_formal_parameter (FormalParameter! p) { + if (!p.ellipsis) { + p.ccodenode = new CCodeFormalParameter (p.name, p.type_reference.get_cname (false, !p.type_reference.takes_ownership)); + } + } + + public override void visit_end_property (Property! prop) { + prop_enum.add_value (prop.get_upper_case_cname (), null); + } + + public override void visit_begin_property_accessor (PropertyAccessor! acc) { + var prop = (Property) acc.symbol.parent_symbol.node; + + if (acc.readable) { + current_return_type = prop.type_reference; + } else { + // void + current_return_type = new TypeReference (); + } + } + + public override void visit_end_property_accessor (PropertyAccessor! acc) { + var prop = (Property) acc.symbol.parent_symbol.node; + + current_return_type = null; + + var t = (DataType) prop.symbol.parent_symbol.node; + + var this_type = new TypeReference (); + this_type.data_type = t; + var cselfparam = new CCodeFormalParameter ("self", this_type.get_cname ()); + var cvalueparam = new CCodeFormalParameter ("value", prop.type_reference.get_cname (false, true)); + + if (prop.is_abstract || prop.is_virtual) { + if (acc.readable) { + function = new CCodeFunction ("%s_get_%s".printf (t.get_lower_case_cname (null), prop.name), prop.type_reference.get_cname ()); + } else { + function = new CCodeFunction ("%s_set_%s".printf (t.get_lower_case_cname (null), prop.name), "void"); + } + function.add_parameter (cselfparam); + if (acc.writable || acc.construction) { + function.add_parameter (cvalueparam); + } + + header_type_member_declaration.append (function.copy ()); + + var block = new CCodeBlock (); + function.block = block; + + if (acc.readable) { + // declare temporary variable to save the property value + var decl = new CCodeDeclaration (prop.type_reference.get_cname ()); + decl.add_declarator (new CCodeVariableDeclarator ("value")); + block.add_statement (decl); + + var ccall = new CCodeFunctionCall (new CCodeIdentifier ("g_object_get")); + + var ccast = new CCodeFunctionCall (new CCodeIdentifier ("G_OBJECT")); + ccast.add_argument (new CCodeIdentifier ("self")); + ccall.add_argument (ccast); + + // property name is second argument of g_object_get + ccall.add_argument (prop.get_canonical_cconstant ()); + + ccall.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier ("value"))); + + ccall.add_argument (new CCodeConstant ("NULL")); + + block.add_statement (new CCodeExpressionStatement (ccall)); + block.add_statement (new CCodeReturnStatement (new CCodeIdentifier ("value"))); + } else { + var ccall = new CCodeFunctionCall (new CCodeIdentifier ("g_object_set")); + + var ccast = new CCodeFunctionCall (new CCodeIdentifier ("G_OBJECT")); + ccast.add_argument (new CCodeIdentifier ("self")); + ccall.add_argument (ccast); + + // property name is second argument of g_object_set + ccall.add_argument (prop.get_canonical_cconstant ()); + + ccall.add_argument (new CCodeIdentifier ("value")); + + ccall.add_argument (new CCodeConstant ("NULL")); + + block.add_statement (new CCodeExpressionStatement (ccall)); + } + + source_type_member_definition.append (function); + } + + if (!prop.is_abstract) { + bool is_virtual = prop.base_property != null || prop.base_interface_property != null; + + string prefix = t.get_lower_case_cname (null); + if (is_virtual) { + prefix += "_real"; + } + if (acc.readable) { + function = new CCodeFunction ("%s_get_%s".printf (prefix, prop.name), prop.type_reference.get_cname ()); + } else { + function = new CCodeFunction ("%s_set_%s".printf (prefix, prop.name), "void"); + } + if (is_virtual) { + function.modifiers |= CCodeModifiers.STATIC; + } + function.add_parameter (cselfparam); + if (acc.writable || acc.construction) { + function.add_parameter (cvalueparam); + } + + if (!is_virtual) { + header_type_member_declaration.append (function.copy ()); + } + + if (acc.body != null) { + function.block = (CCodeBlock) acc.body.ccodenode; + + function.block.prepend_statement (create_property_type_check_statement (prop, acc.readable, t, true, "self")); + } + + source_type_member_definition.append (function); + } + } + + private string get_marshaller_type_name (TypeReference t) { + if (t.type_parameter != null) { + return ("POINTER"); + } else if (t.data_type == null) { + return ("VOID"); + } else { + return t.data_type.get_marshaller_type_name (); + } + } + + private ref string get_signal_marshaller_function (Signal! sig, string prefix = null) { + var signature = get_signal_signature (sig); + string ret; + var params = sig.get_parameters (); + + if (prefix == null) { + // FIXME remove equality check with cast in next revision + if (predefined_marshal_list.lookup (signature) != (bool) null) { + prefix = "g_cclosure_marshal"; + } else { + prefix = "g_cclosure_user_marshal"; + } + } + + ret = "%s_%s_".printf (prefix, get_marshaller_type_name (sig.return_type)); + + if (params == null) { + ret = ret + "_VOID"; + } else { + foreach (FormalParameter p in params) { + ret = "%s_%s".printf (ret, get_marshaller_type_name (p.type_reference)); + } + } + + return ret; + } + + private string get_value_type_name_from_type_reference (TypeReference! t) { + if (t.type_parameter != null) { + return "gpointer"; + } else if (t.data_type == null) { + return "void"; + } else if (t.data_type is Class || t.data_type is Interface) { + return "GObject *"; + } else if (t.data_type is Struct) { + if (((Struct) t.data_type).is_reference_type ()) { + return "gpointer"; + } else { + return t.data_type.get_cname (); + } + } else if (t.data_type is Enum) { + return "gint"; + } else if (t.data_type is Flags) { + return "guint"; + } else if (t.data_type is Array) { + return "gpointer"; + } + + return null; + } + + private ref string get_signal_signature (Signal! sig) { + string signature; + var params = sig.get_parameters (); + + signature = "%s:".printf (get_marshaller_type_name (sig.return_type)); + if (params == null) { + signature = signature + "VOID"; + } else { + bool first = true; + foreach (FormalParameter p in params) { + if (first) { + signature = signature + get_marshaller_type_name (p.type_reference); + first = false; + } else { + signature = "%s,%s".printf (signature, get_marshaller_type_name (p.type_reference)); + } + } + } + + return signature; + } + + public override void visit_end_signal (Signal! sig) { + string signature; + var params = sig.get_parameters (); + int n_params, i; + + /* check whether a signal with the same signature already exists for this source file (or predefined) */ + signature = get_signal_signature (sig); + // FIXME remove equality checks with cast in next revision + if (predefined_marshal_list.lookup (signature) != (bool) null || user_marshal_list.lookup (signature) != (bool) null) { + return; + } + + var signal_marshaller = new CCodeFunction (get_signal_marshaller_function (sig), "void"); + signal_marshaller.modifiers = CCodeModifiers.STATIC; + + signal_marshaller.add_parameter (new CCodeFormalParameter ("closure", "GClosure *")); + signal_marshaller.add_parameter (new CCodeFormalParameter ("return_value", "GValue *")); + signal_marshaller.add_parameter (new CCodeFormalParameter ("n_param_values", "guint")); + signal_marshaller.add_parameter (new CCodeFormalParameter ("param_values", "const GValue *")); + signal_marshaller.add_parameter (new CCodeFormalParameter ("invocation_hint", "gpointer")); + signal_marshaller.add_parameter (new CCodeFormalParameter ("marshal_data", "gpointer")); + + source_signal_marshaller_declaration.append (signal_marshaller.copy ()); + + var marshaller_body = new CCodeBlock (); + + var callback_decl = new CCodeFunctionDeclarator (get_signal_marshaller_function (sig, "GMarshalFunc")); + callback_decl.add_parameter (new CCodeFormalParameter ("data1", "gpointer")); + n_params = 1; + foreach (FormalParameter p in params) { + callback_decl.add_parameter (new CCodeFormalParameter ("arg_%d".printf (n_params), get_value_type_name_from_type_reference (p.type_reference))); + n_params++; + } + callback_decl.add_parameter (new CCodeFormalParameter ("data2", "gpointer")); + marshaller_body.add_statement (new CCodeTypeDefinition (get_value_type_name_from_type_reference (sig.return_type), callback_decl)); + + var var_decl = new CCodeDeclaration (get_signal_marshaller_function (sig, "GMarshalFunc")); + var_decl.modifiers = CCodeModifiers.REGISTER; + var_decl.add_declarator (new CCodeVariableDeclarator ("callback")); + marshaller_body.add_statement (var_decl); + + var_decl = new CCodeDeclaration ("GCClosure *"); + var_decl.modifiers = CCodeModifiers.REGISTER; + var_decl.add_declarator (new CCodeVariableDeclarator.with_initializer ("cc", new CCodeCastExpression (new CCodeIdentifier ("closure"), "GCClosure *"))); + marshaller_body.add_statement (var_decl); + + var_decl = new CCodeDeclaration ("gpointer"); + var_decl.modifiers = CCodeModifiers.REGISTER; + var_decl.add_declarator (new CCodeVariableDeclarator ("data1")); + var_decl.add_declarator (new CCodeVariableDeclarator ("data2")); + marshaller_body.add_statement (var_decl); + + CCodeFunctionCall fc; + + if (sig.return_type.data_type != null) { + var_decl = new CCodeDeclaration (get_value_type_name_from_type_reference (sig.return_type)); + var_decl.add_declarator (new CCodeVariableDeclarator ("v_return")); + marshaller_body.add_statement (var_decl); + + fc = new CCodeFunctionCall (new CCodeIdentifier ("g_return_if_fail")); + fc.add_argument (new CCodeBinaryExpression (CCodeBinaryOperator.INEQUALITY, new CCodeIdentifier ("return_value"), new CCodeConstant ("NULL"))); + marshaller_body.add_statement (new CCodeExpressionStatement (fc)); + } + + fc = new CCodeFunctionCall (new CCodeIdentifier ("g_return_if_fail")); + fc.add_argument (new CCodeBinaryExpression (CCodeBinaryOperator.EQUALITY, new CCodeIdentifier ("n_param_values"), new CCodeConstant (n_params.to_string()))); + marshaller_body.add_statement (new CCodeExpressionStatement (fc)); + + var data = new CCodeMemberAccess (new CCodeIdentifier ("closure"), "data", true); + var param = new CCodeMemberAccess (new CCodeMemberAccess (new CCodeIdentifier ("param_values"), "data[0]", true), "v_pointer"); + var cond = new CCodeFunctionCall (new CCodeConstant ("G_CCLOSURE_SWAP_DATA")); + cond.add_argument (new CCodeIdentifier ("closure")); + var true_block = new CCodeBlock (); + true_block.add_statement (new CCodeExpressionStatement (new CCodeAssignment (new CCodeIdentifier ("data1"), data))); + true_block.add_statement (new CCodeExpressionStatement (new CCodeAssignment (new CCodeIdentifier ("data2"), param))); + var false_block = new CCodeBlock (); + false_block.add_statement (new CCodeExpressionStatement (new CCodeAssignment (new CCodeIdentifier ("data1"), param))); + false_block.add_statement (new CCodeExpressionStatement (new CCodeAssignment (new CCodeIdentifier ("data2"), data))); + marshaller_body.add_statement (new CCodeIfStatement (cond, true_block, false_block)); + + var c_assign = new CCodeAssignment (new CCodeIdentifier ("callback"), new CCodeCastExpression (new CCodeConditionalExpression (new CCodeIdentifier ("marshal_data"), new CCodeIdentifier ("marshal_data"), new CCodeMemberAccess (new CCodeIdentifier ("cc"), "callback", true)), get_signal_marshaller_function (sig, "GMarshalFunc"))); + marshaller_body.add_statement (new CCodeExpressionStatement (c_assign)); + + fc = new CCodeFunctionCall (new CCodeIdentifier ("callback")); + fc.add_argument (new CCodeIdentifier ("data1")); + i = 1; + foreach (FormalParameter p in params) { + string get_value_function; + if (p.type_reference.type_parameter != null) { + get_value_function = "g_value_get_pointer"; + } else { + get_value_function = p.type_reference.data_type.get_get_value_function (); + } + var inner_fc = new CCodeFunctionCall (new CCodeIdentifier (get_value_function)); + inner_fc.add_argument (new CCodeBinaryExpression (CCodeBinaryOperator.PLUS, new CCodeIdentifier ("param_values"), new CCodeIdentifier (i.to_string ()))); + fc.add_argument (inner_fc); + i++; + } + fc.add_argument (new CCodeIdentifier ("data2")); + + if (sig.return_type.data_type != null) { + marshaller_body.add_statement (new CCodeExpressionStatement (new CCodeAssignment (new CCodeIdentifier ("v_return"), fc))); + + CCodeFunctionCall set_fc; + if (sig.return_type.type_parameter != null) { + set_fc = new CCodeFunctionCall (new CCodeIdentifier ("g_value_set_pointer")); + } else if (sig.return_type.data_type is Class || sig.return_type.data_type is Interface) { + set_fc = new CCodeFunctionCall (new CCodeIdentifier ("g_value_take_object")); + } else if (sig.return_type.data_type == string_type.data_type) { + set_fc = new CCodeFunctionCall (new CCodeIdentifier ("g_value_take_string")); + } else { + set_fc = new CCodeFunctionCall (new CCodeIdentifier (sig.return_type.data_type.get_set_value_function ())); + } + set_fc.add_argument (new CCodeIdentifier ("return_value")); + set_fc.add_argument (new CCodeIdentifier ("v_return")); + + marshaller_body.add_statement (new CCodeExpressionStatement (set_fc)); + } else { + marshaller_body.add_statement (new CCodeExpressionStatement (fc)); + } + + signal_marshaller.block = marshaller_body; + + source_signal_marshaller_definition.append (signal_marshaller); + user_marshal_list.insert (signature, true); + } + + public override void visit_end_constructor (Constructor! c) { + var cl = (Class) c.symbol.parent_symbol.node; + + function = new CCodeFunction ("%s_constructor".printf (cl.get_lower_case_cname (null)), "GObject *"); + function.modifiers = CCodeModifiers.STATIC; + + function.add_parameter (new CCodeFormalParameter ("type", "GType")); + function.add_parameter (new CCodeFormalParameter ("n_construct_properties", "guint")); + function.add_parameter (new CCodeFormalParameter ("construct_properties", "GObjectConstructParam *")); + + source_type_member_declaration.append (function.copy ()); + + + var cblock = new CCodeBlock (); + var cdecl = new CCodeDeclaration ("GObject *"); + cdecl.add_declarator (new CCodeVariableDeclarator ("obj")); + cblock.add_statement (cdecl); + + cdecl = new CCodeDeclaration ("%sClass *".printf (cl.get_cname ())); + cdecl.add_declarator (new CCodeVariableDeclarator ("klass")); + cblock.add_statement (cdecl); + + cdecl = new CCodeDeclaration ("GObjectClass *"); + cdecl.add_declarator (new CCodeVariableDeclarator ("parent_class")); + cblock.add_statement (cdecl); + + + var ccall = new CCodeFunctionCall (new CCodeIdentifier ("g_type_class_peek")); + ccall.add_argument (new CCodeIdentifier (cl.get_upper_case_cname ("TYPE_"))); + var ccast = new CCodeFunctionCall (new CCodeIdentifier ("%s_CLASS".printf (cl.get_upper_case_cname (null)))); + ccast.add_argument (ccall); + cblock.add_statement (new CCodeExpressionStatement (new CCodeAssignment (new CCodeIdentifier ("klass"), ccast))); + + ccall = new CCodeFunctionCall (new CCodeIdentifier ("g_type_class_peek_parent")); + ccall.add_argument (new CCodeIdentifier ("klass")); + ccast = new CCodeFunctionCall (new CCodeIdentifier ("G_OBJECT_CLASS")); + ccast.add_argument (ccall); + cblock.add_statement (new CCodeExpressionStatement (new CCodeAssignment (new CCodeIdentifier ("parent_class"), ccast))); + + + ccall = new CCodeFunctionCall (new CCodeMemberAccess.pointer (new CCodeIdentifier ("parent_class"), "constructor")); + ccall.add_argument (new CCodeIdentifier ("type")); + ccall.add_argument (new CCodeIdentifier ("n_construct_properties")); + ccall.add_argument (new CCodeIdentifier ("construct_properties")); + cblock.add_statement (new CCodeExpressionStatement (new CCodeAssignment (new CCodeIdentifier ("obj"), ccall))); + + + ccall = new CCodeFunctionCall (new CCodeIdentifier (cl.get_upper_case_cname (null))); + ccall.add_argument (new CCodeIdentifier ("obj")); + + cdecl = new CCodeDeclaration ("%s *".printf (cl.get_cname ())); + cdecl.add_declarator (new CCodeVariableDeclarator.with_initializer ("self", ccall)); + + cblock.add_statement (cdecl); + + + cblock.add_statement (c.body.ccodenode); + + cblock.add_statement (new CCodeReturnStatement (new CCodeIdentifier ("obj"))); + + function.block = cblock; + + if (c.source_reference.comment != null) { + source_type_member_definition.append (new CCodeComment (c.source_reference.comment)); + } + source_type_member_definition.append (function); + } + + 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 (new CCodeIdentifier ("g_object_newv")); + ccall.add_argument (new CCodeConstant (cl.get_type_id ())); + ccall.add_argument (new CCodeConstant ("__params_it - __params")); + ccall.add_argument (new CCodeConstant ("__params")); + + var cdecl = new CCodeVariableDeclarator ("self"); + cdecl.initializer = ccall; + + var cdeclaration = new CCodeDeclaration ("%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; + } + + var cblock = new CCodeBlock (); + + foreach (Statement stmt in b.get_statements ()) { + var src = stmt.source_reference; + if (src != null && src.comment != null) { + cblock.add_statement (new CCodeComment (src.comment)); + } + + if (stmt.ccodenode is CCodeFragment) { + foreach (CCodeStatement cstmt in ((CCodeFragment) stmt.ccodenode).get_children ()) { + cblock.add_statement (cstmt); + } + } else { + cblock.add_statement ((CCodeStatement) stmt.ccodenode); + } + } + + if (memory_management) { + foreach (VariableDeclarator decl in local_vars) { + if (decl.type_reference.takes_ownership) { + cblock.add_statement (new CCodeExpressionStatement (get_unref_expression (new CCodeIdentifier (decl.name), decl.type_reference))); + } + } + } + + b.ccodenode = cblock; + + current_symbol = current_symbol.parent_symbol; + } + + public override void visit_empty_statement (EmptyStatement! stmt) { + stmt.ccodenode = new CCodeEmptyStatement (); + } + + private bool struct_has_instance_fields (Struct! st) { + foreach (Field f in st.get_fields ()) { + if (f.instance) { + return true; + } + } + + return false; + } + + public override void visit_declaration_statement (DeclarationStatement! stmt) { + /* split declaration statement as var declarators + * might have different types */ + + var cfrag = new CCodeFragment (); + + foreach (VariableDeclarator decl in stmt.declaration.get_variable_declarators ()) { + var cdecl = new CCodeDeclaration (decl.type_reference.get_cname (false, !decl.type_reference.takes_ownership)); + + cdecl.add_declarator ((CCodeVariableDeclarator) decl.ccodenode); + + cfrag.append (cdecl); + + /* try to initialize uninitialized variables */ + if (decl.initializer == null && decl.type_reference.data_type is Struct) { + if (decl.type_reference.data_type.is_reference_type ()) { + ((CCodeVariableDeclarator) decl.ccodenode).initializer = new CCodeConstant ("NULL"); + } else if (decl.type_reference.data_type.get_default_value () != null) { + ((CCodeVariableDeclarator) decl.ccodenode).initializer = new CCodeConstant (decl.type_reference.data_type.get_default_value ()); + } else if (decl.type_reference.data_type is Struct && + struct_has_instance_fields ((Struct) decl.type_reference.data_type)) { + var st = (Struct) decl.type_reference.data_type; + + /* memset needs string.h */ + string_h_needed = true; + + var czero = new CCodeFunctionCall (new CCodeIdentifier ("memset")); + czero.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier (decl.name))); + czero.add_argument (new CCodeConstant ("0")); + czero.add_argument (new CCodeIdentifier ("sizeof (%s)".printf (decl.type_reference.get_cname ()))); + + cfrag.append (new CCodeExpressionStatement (czero)); + } else { + Report.warning (decl.source_reference, "unable to initialize a variable of type `%s'".printf (decl.type_reference.data_type.symbol.get_full_name ())); + } + } + } + + stmt.ccodenode = cfrag; + + foreach (VariableDeclarator decl in stmt.declaration.get_variable_declarators ()) { + if (decl.initializer != null) { + create_temp_decl (stmt, decl.initializer.temp_vars); + } + } + + create_temp_decl (stmt, temp_vars); + temp_vars = null; + } + + public override void visit_variable_declarator (VariableDeclarator! decl) { + if (decl.type_reference.data_type is Array) { + // create variables to store array dimensions + var arr = (Array) decl.type_reference.data_type; + + for (int dim = 1; dim <= arr.rank; dim++) { + var len_decl = new VariableDeclarator (get_array_length_cname (decl.name, dim)); + len_decl.type_reference = new TypeReference (); + len_decl.type_reference.data_type = int_type.data_type; + + temp_vars.prepend (len_decl); + } + } + + CCodeExpression rhs = null; + if (decl.initializer != null) { + rhs = (CCodeExpression) decl.initializer.ccodenode; + + if (decl.type_reference.data_type != null + && decl.initializer.static_type.data_type != null + && decl.type_reference.data_type.is_reference_type () + && decl.initializer.static_type.data_type != decl.type_reference.data_type) { + // FIXME: use C cast if debugging disabled + rhs = new InstanceCast (rhs, decl.type_reference.data_type); + } + + if (decl.type_reference.data_type is Array) { + var ccomma = new CCodeCommaExpression (); + + var temp_decl = get_temp_variable_declarator (decl.type_reference); + temp_vars.prepend (temp_decl); + ccomma.append_expression (new CCodeAssignment (new CCodeIdentifier (temp_decl.name), rhs)); + + var lhs_array_len = new CCodeIdentifier (get_array_length_cname (decl.name, 1)); + var rhs_array_len = get_array_length_cexpression (decl.initializer, 1); + ccomma.append_expression (new CCodeAssignment (lhs_array_len, rhs_array_len)); + + ccomma.append_expression (new CCodeIdentifier (temp_decl.name)); + + rhs = ccomma; + } + } else if (decl.type_reference.data_type != null && decl.type_reference.data_type.is_reference_type ()) { + rhs = new CCodeConstant ("NULL"); + } + + decl.ccodenode = new CCodeVariableDeclarator.with_initializer (decl.name, rhs); + + decl.symbol.active = true; + } + + public override void visit_end_initializer_list (InitializerList! list) { + if (list.expected_type != null && list.expected_type.data_type is Array) { + /* TODO */ + } else { + var clist = new CCodeInitializerList (); + foreach (Expression expr in list.get_initializers ()) { + clist.append ((CCodeExpression) expr.ccodenode); + } + list.ccodenode = clist; + } + } + + private ref VariableDeclarator get_temp_variable_declarator (TypeReference! type, bool takes_ownership = true) { + var decl = new VariableDeclarator ("__temp%d".printf (next_temp_var_id)); + decl.type_reference = type.copy (); + decl.type_reference.reference_to_value_type = false; + decl.type_reference.is_out = false; + decl.type_reference.takes_ownership = takes_ownership; + + next_temp_var_id++; + + return decl; + } + + private CCodeExpression get_destroy_func_expression (TypeReference! type) { + if (type.data_type != null) { + string unref_function; + if (type.data_type.is_reference_counting ()) { + unref_function = type.data_type.get_unref_function (); + } else { + unref_function = type.data_type.get_free_function (); + } + return new CCodeIdentifier (unref_function); + } else if (type.type_parameter != null && current_class != null) { + string func_name = "%s_destroy_func".printf (type.type_parameter.name.down ()); + return new CCodeMemberAccess.pointer (new CCodeMemberAccess.pointer (new CCodeIdentifier ("self"), "priv"), func_name); + } else { + return new CCodeConstant ("NULL"); + } + } + + private ref CCodeExpression get_unref_expression (CCodeExpression! cvar, TypeReference! type) { + /* (foo == NULL ? NULL : foo = (unref (foo), NULL)) */ + + /* can be simplified to + * foo = (unref (foo), NULL) + * if foo is of static type non-null + */ + + if (type.is_null) { + return new CCodeConstant ("NULL"); + } + + var cisnull = new CCodeBinaryExpression (CCodeBinaryOperator.EQUALITY, cvar, new CCodeConstant ("NULL")); + if (type.data_type == null) { + if (current_class == null) { + return new CCodeConstant ("NULL"); + } + + // unref functions are optional for type parameters + var cunrefisnull = new CCodeBinaryExpression (CCodeBinaryOperator.EQUALITY, get_destroy_func_expression (type), new CCodeConstant ("NULL")); + cisnull = new CCodeBinaryExpression (CCodeBinaryOperator.OR, cisnull, cunrefisnull); + } + + var ccall = new CCodeFunctionCall (get_destroy_func_expression (type)); + ccall.add_argument (cvar); + + /* set freed references to NULL to prevent further use */ + var ccomma = new CCodeCommaExpression (); + + // TODO cleanup + if (type.data_type != null && !type.data_type.is_reference_counting ()) { + string unref_function = type.data_type.get_free_function (); + if (unref_function == "g_list_free") { + bool is_ref = false; + bool is_class = false; + bool is_interface = false; + + foreach (TypeReference type_arg in type.get_type_arguments ()) { + is_ref |= type_arg.takes_ownership; + is_class |= type_arg.data_type is Class; + is_interface |= type_arg.data_type is Interface; + } + + if (is_ref) { + var cunrefcall = new CCodeFunctionCall (new CCodeIdentifier ("g_list_foreach")); + cunrefcall.add_argument (cvar); + if (is_class || is_interface) { + cunrefcall.add_argument (new CCodeIdentifier ("(GFunc) g_object_unref")); + } else { + cunrefcall.add_argument (new CCodeIdentifier ("(GFunc) g_free")); + } + cunrefcall.add_argument (new CCodeConstant ("NULL")); + ccomma.append_expression (cunrefcall); + } + } else if (unref_function == "g_string_free") { + ccall.add_argument (new CCodeConstant ("TRUE")); + } + } + + ccomma.append_expression (ccall); + ccomma.append_expression (new CCodeConstant ("NULL")); + + var cassign = new CCodeAssignment (cvar, ccomma); + + // g_free (NULL) is allowed + if (type.non_null || (type.data_type != null && !type.data_type.is_reference_counting () && type.data_type.get_free_function () == "g_free")) { + return new CCodeParenthesizedExpression (cassign); + } + + return new CCodeConditionalExpression (cisnull, new CCodeConstant ("NULL"), new CCodeParenthesizedExpression (cassign)); + } + + public override void visit_end_full_expression (Expression! expr) { + if (!memory_management) { + temp_vars = null; + temp_ref_vars = null; + return; + } + + /* expr is a full expression, i.e. an initializer, the + * expression in an expression statement, the controlling + * expression in if, while, for, or foreach statements + * + * we unref temporary variables at the end of a full + * expression + */ + + /* can't automatically deep copy lists yet, so do it + * manually for now + * replace with + * expr.temp_vars = temp_vars; + * when deep list copying works + */ + expr.temp_vars = null; + foreach (VariableDeclarator decl1 in temp_vars) { + expr.temp_vars.append (decl1); + } + temp_vars = null; + + if (temp_ref_vars == null) { + /* nothing to do without temporary variables */ + return; + } + + var full_expr_decl = get_temp_variable_declarator (expr.static_type); + expr.temp_vars.append (full_expr_decl); + + var expr_list = new CCodeCommaExpression (); + expr_list.append_expression (new CCodeAssignment (new CCodeIdentifier (full_expr_decl.name), (CCodeExpression) expr.ccodenode)); + + foreach (VariableDeclarator decl in temp_ref_vars) { + expr_list.append_expression (get_unref_expression (new CCodeIdentifier (decl.name), decl.type_reference)); + } + + expr_list.append_expression (new CCodeIdentifier (full_expr_decl.name)); + + expr.ccodenode = expr_list; + + temp_ref_vars = null; + } + + private void append_temp_decl (CCodeFragment! cfrag, List<VariableDeclarator> temp_vars) { + foreach (VariableDeclarator decl in temp_vars) { + var cdecl = new CCodeDeclaration (decl.type_reference.get_cname (true, !decl.type_reference.takes_ownership)); + + var vardecl = new CCodeVariableDeclarator (decl.name); + cdecl.add_declarator (vardecl); + + if (decl.type_reference.data_type != null && decl.type_reference.data_type.is_reference_type ()) { + vardecl.initializer = new CCodeConstant ("NULL"); + } + + cfrag.append (cdecl); + } + } + + public override void visit_expression_statement (ExpressionStatement! stmt) { + stmt.ccodenode = new CCodeExpressionStatement ((CCodeExpression) stmt.expression.ccodenode); + + /* free temporary objects */ + if (!memory_management) { + temp_vars = null; + temp_ref_vars = null; + return; + } + + if (temp_vars == null) { + /* nothing to do without temporary variables */ + return; + } + + var cfrag = new CCodeFragment (); + append_temp_decl (cfrag, temp_vars); + + cfrag.append (stmt.ccodenode); + + foreach (VariableDeclarator decl in temp_ref_vars) { + cfrag.append (new CCodeExpressionStatement (get_unref_expression (new CCodeIdentifier (decl.name), decl.type_reference))); + } + + stmt.ccodenode = cfrag; + + temp_vars = null; + temp_ref_vars = null; + } + + private void create_temp_decl (Statement! stmt, List<VariableDeclarator> temp_vars) { + /* declare temporary variables */ + + if (temp_vars == null) { + /* nothing to do without temporary variables */ + return; + } + + var cfrag = new CCodeFragment (); + append_temp_decl (cfrag, temp_vars); + + cfrag.append (stmt.ccodenode); + + stmt.ccodenode = cfrag; + } + + public override void visit_if_statement (IfStatement! stmt) { + if (stmt.false_statement != null) { + stmt.ccodenode = new CCodeIfStatement ((CCodeExpression) stmt.condition.ccodenode, (CCodeStatement) stmt.true_statement.ccodenode, (CCodeStatement) stmt.false_statement.ccodenode); + } else { + stmt.ccodenode = new CCodeIfStatement ((CCodeExpression) stmt.condition.ccodenode, (CCodeStatement) stmt.true_statement.ccodenode); + } + + create_temp_decl (stmt, stmt.condition.temp_vars); + } + + public override void visit_switch_statement (SwitchStatement! stmt) { + // we need a temporary variable to save the property value + var temp_decl = get_temp_variable_declarator (stmt.expression.static_type); + stmt.expression.temp_vars.prepend (temp_decl); + + var ctemp = new CCodeIdentifier (temp_decl.name); + + var cinit = new CCodeAssignment (ctemp, (CCodeExpression) stmt.expression.ccodenode); + + var cswitchblock = new CCodeFragment (); + cswitchblock.append (new CCodeExpressionStatement (cinit)); + stmt.ccodenode = cswitchblock; + + create_temp_decl (stmt, stmt.expression.temp_vars); + + List<weak Statement> default_statements = null; + + // generate nested if statements + ref CCodeStatement ctopstmt = null; + CCodeIfStatement coldif = null; + foreach (SwitchSection section in stmt.get_sections ()) { + if (section.has_default_label ()) { + default_statements = section.get_statements (); + } else { + CCodeBinaryExpression cor = null; + foreach (SwitchLabel label in section.get_labels ()) { + var ccmp = new CCodeBinaryExpression (CCodeBinaryOperator.EQUALITY, ctemp, (CCodeExpression) label.expression.ccodenode); + if (cor == null) { + cor = ccmp; + } else { + cor = new CCodeBinaryExpression (CCodeBinaryOperator.OR, cor, ccmp); + } + } + + var cblock = new CCodeBlock (); + foreach (Statement body_stmt in section.get_statements ()) { + if (body_stmt.ccodenode is CCodeFragment) { + foreach (CCodeStatement cstmt in ((CCodeFragment) body_stmt.ccodenode).get_children ()) { + cblock.add_statement (cstmt); + } + } else { + cblock.add_statement ((CCodeStatement) body_stmt.ccodenode); + } + } + + var cdo = new CCodeDoStatement (cblock, new CCodeConstant ("0")); + + var cif = new CCodeIfStatement (cor, cdo); + if (coldif != null) { + coldif.false_statement = cif; + } else { + ctopstmt = cif; + } + coldif = cif; + } + } + + if (default_statements != null) { + var cblock = new CCodeBlock (); + foreach (Statement body_stmt in default_statements) { + cblock.add_statement ((CCodeStatement) body_stmt.ccodenode); + } + + var cdo = new CCodeDoStatement (cblock, new CCodeConstant ("0")); + + if (coldif == null) { + // there is only one section and that section + // contains a default label + ctopstmt = cdo; + } else { + coldif.false_statement = cdo; + } + } + + cswitchblock.append (ctopstmt); + } + + public override void visit_while_statement (WhileStatement! stmt) { + stmt.ccodenode = new CCodeWhileStatement ((CCodeExpression) stmt.condition.ccodenode, (CCodeStatement) stmt.body.ccodenode); + + create_temp_decl (stmt, stmt.condition.temp_vars); + } + + public override void visit_do_statement (DoStatement! stmt) { + stmt.ccodenode = new CCodeDoStatement ((CCodeStatement) stmt.body.ccodenode, (CCodeExpression) stmt.condition.ccodenode); + + create_temp_decl (stmt, stmt.condition.temp_vars); + } + + public override void visit_for_statement (ForStatement! stmt) { + var cfor = new CCodeForStatement ((CCodeExpression) stmt.condition.ccodenode, (CCodeStatement) stmt.body.ccodenode); + stmt.ccodenode = cfor; + + foreach (Expression init_expr in stmt.get_initializer ()) { + cfor.add_initializer ((CCodeExpression) init_expr.ccodenode); + create_temp_decl (stmt, init_expr.temp_vars); + } + + foreach (Expression it_expr in stmt.get_iterator ()) { + cfor.add_iterator ((CCodeExpression) it_expr.ccodenode); + create_temp_decl (stmt, it_expr.temp_vars); + } + + create_temp_decl (stmt, stmt.condition.temp_vars); + } + + public override void visit_end_foreach_statement (ForeachStatement! stmt) { + var cblock = new CCodeBlock (); + CCodeForStatement cfor; + VariableDeclarator collection_backup = get_temp_variable_declarator (stmt.collection.static_type); + + stmt.collection.temp_vars.prepend (collection_backup); + var cfrag = new CCodeFragment (); + append_temp_decl (cfrag, stmt.collection.temp_vars); + cblock.add_statement (cfrag); + cblock.add_statement (new CCodeExpressionStatement (new CCodeAssignment (new CCodeIdentifier (collection_backup.name), (CCodeExpression) stmt.collection.ccodenode))); + + stmt.ccodenode = cblock; + + if (stmt.collection.static_type.data_type is Array) { + var arr = (Array) stmt.collection.static_type.data_type; + + var array_len = get_array_length_cexpression (stmt.collection, 1); + + /* the array has no length parameter i.e. is NULL-terminated array */ + if (array_len is CCodeConstant) { + var it_name = "%s_it".printf (stmt.variable_name); + + var citdecl = new CCodeDeclaration (stmt.collection.static_type.get_cname ()); + citdecl.add_declarator (new CCodeVariableDeclarator (it_name)); + cblock.add_statement (citdecl); + + var cbody = new CCodeBlock (); + + var cdecl = new CCodeDeclaration (stmt.type_reference.get_cname ()); + cdecl.add_declarator (new CCodeVariableDeclarator.with_initializer (stmt.variable_name, new CCodeIdentifier ("*%s".printf (it_name)))); + cbody.add_statement (cdecl); + + cbody.add_statement (stmt.body.ccodenode); + + var ccond = new CCodeBinaryExpression (CCodeBinaryOperator.INEQUALITY, new CCodeIdentifier ("*%s".printf (it_name)), new CCodeConstant ("NULL")); + + var cfor = new CCodeForStatement (ccond, cbody); + + cfor.add_initializer (new CCodeAssignment (new CCodeIdentifier (it_name), new CCodeIdentifier (collection_backup.name))); + + cfor.add_iterator (new CCodeAssignment (new CCodeIdentifier (it_name), new CCodeBinaryExpression (CCodeBinaryOperator.PLUS, new CCodeIdentifier (it_name), new CCodeConstant ("1")))); + cblock.add_statement (cfor); + /* the array has a length parameter */ + } else { + var it_name = (stmt.variable_name + "_it"); + + var citdecl = new CCodeDeclaration ("int"); + citdecl.add_declarator (new CCodeVariableDeclarator (it_name)); + cblock.add_statement (citdecl); + + var cbody = new CCodeBlock (); + + var cdecl = new CCodeDeclaration (stmt.type_reference.get_cname ()); + cdecl.add_declarator (new CCodeVariableDeclarator.with_initializer (stmt.variable_name, new CCodeElementAccess (new CCodeIdentifier (collection_backup.name), new CCodeIdentifier (it_name)))); + cbody.add_statement (cdecl); + + cbody.add_statement (stmt.body.ccodenode); + + var ccond_ind1 = new CCodeBinaryExpression (CCodeBinaryOperator.INEQUALITY, array_len, new CCodeConstant ("-1")); + var ccond_ind2 = new CCodeBinaryExpression (CCodeBinaryOperator.LESS_THAN, new CCodeIdentifier (it_name), array_len); + var ccond_ind = new CCodeBinaryExpression (CCodeBinaryOperator.AND, ccond_ind1, ccond_ind2); + + /* only check for null if the containers elements are of reference-type */ + CCodeBinaryExpression ccond; + if (arr.element_type.is_reference_type ()) { + var ccond_term1 = new CCodeBinaryExpression (CCodeBinaryOperator.EQUALITY, array_len, new CCodeConstant ("-1")); + var ccond_term2 = new CCodeBinaryExpression (CCodeBinaryOperator.INEQUALITY, new CCodeElementAccess (new CCodeIdentifier (collection_backup.name), new CCodeIdentifier (it_name)), new CCodeConstant ("NULL")); + var ccond_term = new CCodeBinaryExpression (CCodeBinaryOperator.AND, ccond_term1, ccond_term2); + + ccond = new CCodeBinaryExpression (CCodeBinaryOperator.OR, new CCodeParenthesizedExpression (ccond_ind), new CCodeParenthesizedExpression (ccond_term)); + } else { + ccond = ccond_ind; + } + + var cfor = new CCodeForStatement (ccond, cbody); + cfor.add_initializer (new CCodeAssignment (new CCodeIdentifier (it_name), new CCodeConstant ("0"))); + cfor.add_iterator (new CCodeAssignment (new CCodeIdentifier (it_name), new CCodeBinaryExpression (CCodeBinaryOperator.PLUS, new CCodeIdentifier (it_name), new CCodeConstant ("1")))); + cblock.add_statement (cfor); + } + } else if (stmt.collection.static_type.data_type == list_type || + stmt.collection.static_type.data_type == slist_type) { + var it_name = "%s_it".printf (stmt.variable_name); + + var citdecl = new CCodeDeclaration (stmt.collection.static_type.get_cname ()); + citdecl.add_declarator (new CCodeVariableDeclarator (it_name)); + cblock.add_statement (citdecl); + + var cbody = new CCodeBlock (); + + CCodeExpression element_expr = new CCodeMemberAccess.pointer (new CCodeIdentifier (it_name), "data"); + + /* cast pointer to actual type if appropriate */ + if (stmt.type_reference.data_type is Struct) { + var st = (Struct) stmt.type_reference.data_type; + if (st == uint_type.data_type) { + var cconv = new CCodeFunctionCall (new CCodeIdentifier ("GPOINTER_TO_UINT")); + cconv.add_argument (element_expr); + element_expr = cconv; + } else if (st == bool_type.data_type || st.is_integer_type ()) { + var cconv = new CCodeFunctionCall (new CCodeIdentifier ("GPOINTER_TO_INT")); + cconv.add_argument (element_expr); + element_expr = cconv; + } + } + + var cdecl = new CCodeDeclaration (stmt.type_reference.get_cname ()); + cdecl.add_declarator (new CCodeVariableDeclarator.with_initializer (stmt.variable_name, element_expr)); + cbody.add_statement (cdecl); + + cbody.add_statement (stmt.body.ccodenode); + + var ccond = new CCodeBinaryExpression (CCodeBinaryOperator.INEQUALITY, new CCodeIdentifier (it_name), new CCodeConstant ("NULL")); + + var cfor = new CCodeForStatement (ccond, cbody); + + cfor.add_initializer (new CCodeAssignment (new CCodeIdentifier (it_name), new CCodeIdentifier (collection_backup.name))); + + cfor.add_iterator (new CCodeAssignment (new CCodeIdentifier (it_name), new CCodeMemberAccess.pointer (new CCodeIdentifier (it_name), "next"))); + cblock.add_statement (cfor); + } + + if (memory_management && stmt.collection.static_type.transfers_ownership) { + cblock.add_statement (new CCodeExpressionStatement (get_unref_expression (new CCodeIdentifier (collection_backup.name), stmt.collection.static_type))); + } + } + + public override void visit_break_statement (BreakStatement! stmt) { + stmt.ccodenode = new CCodeBreakStatement (); + } + + public override void visit_continue_statement (ContinueStatement! stmt) { + stmt.ccodenode = new CCodeContinueStatement (); + } + + private void append_local_free (Symbol sym, CCodeFragment cfrag, bool stop_at_loop) { + var b = (Block) sym.node; + + var local_vars = b.get_local_variables (); + foreach (VariableDeclarator decl in local_vars) { + if (decl.symbol.active && decl.type_reference.data_type.is_reference_type () && decl.type_reference.takes_ownership) { + cfrag.append (new CCodeExpressionStatement (get_unref_expression (new CCodeIdentifier (decl.name), decl.type_reference))); + } + } + + if (sym.parent_symbol.node is Block) { + append_local_free (sym.parent_symbol, cfrag, stop_at_loop); + } + } + + private void create_local_free (Statement stmt) { + if (!memory_management) { + return; + } + + var cfrag = new CCodeFragment (); + + append_local_free (current_symbol, cfrag, false); + + cfrag.append (stmt.ccodenode); + stmt.ccodenode = cfrag; + } + + private bool append_local_free_expr (Symbol sym, CCodeCommaExpression ccomma, bool stop_at_loop) { + var found = false; + + var b = (Block) sym.node; + + var local_vars = b.get_local_variables (); + foreach (VariableDeclarator decl in local_vars) { + if (decl.symbol.active && decl.type_reference.data_type.is_reference_type () && decl.type_reference.takes_ownership) { + found = true; + ccomma.append_expression (get_unref_expression (new CCodeIdentifier (decl.name), decl.type_reference)); + } + } + + if (sym.parent_symbol.node is Block) { + found = found || append_local_free_expr (sym.parent_symbol, ccomma, stop_at_loop); + } + + return found; + } + + private void create_local_free_expr (Expression expr) { + if (!memory_management) { + return; + } + + var return_expr_decl = get_temp_variable_declarator (expr.static_type); + + var ccomma = new CCodeCommaExpression (); + ccomma.append_expression (new CCodeAssignment (new CCodeIdentifier (return_expr_decl.name), (CCodeExpression) expr.ccodenode)); + + if (!append_local_free_expr (current_symbol, ccomma, false)) { + /* no local variables need to be freed */ + return; + } + + ccomma.append_expression (new CCodeIdentifier (return_expr_decl.name)); + + expr.ccodenode = ccomma; + expr.temp_vars.append (return_expr_decl); + } + + public override void visit_begin_return_statement (ReturnStatement! stmt) { + if (stmt.return_expression != null) { + // avoid unnecessary ref/unref pair + if (stmt.return_expression.ref_missing && + stmt.return_expression.symbol_reference != null && + stmt.return_expression.symbol_reference.node is VariableDeclarator) { + var decl = (VariableDeclarator) stmt.return_expression.symbol_reference.node; + if (decl.type_reference.takes_ownership) { + /* return expression is local variable taking ownership and + * current method is transferring ownership */ + + stmt.return_expression.ref_sink = true; + + // don't ref expression + stmt.return_expression.ref_missing = false; + } + } + } + } + + public override void visit_end_return_statement (ReturnStatement! stmt) { + if (stmt.return_expression == null) { + stmt.ccodenode = new CCodeReturnStatement (); + + create_local_free (stmt); + } else { + Symbol return_expression_symbol = null; + + // avoid unnecessary ref/unref pair + if (stmt.return_expression.ref_sink && + stmt.return_expression.symbol_reference != null && + stmt.return_expression.symbol_reference.node is VariableDeclarator) { + var decl = (VariableDeclarator) stmt.return_expression.symbol_reference.node; + if (decl.type_reference.takes_ownership) { + /* return expression is local variable taking ownership and + * current method is transferring ownership */ + + // don't unref expression + return_expression_symbol = decl.symbol; + return_expression_symbol.active = false; + } + } + + create_local_free_expr (stmt.return_expression); + + if (stmt.return_expression.static_type != null && + stmt.return_expression.static_type.data_type != current_return_type.data_type) { + /* cast required */ + if (current_return_type.data_type is Class || current_return_type.data_type is Interface) { + stmt.return_expression.ccodenode = new InstanceCast ((CCodeExpression) stmt.return_expression.ccodenode, current_return_type.data_type); + } + } + + stmt.ccodenode = new CCodeReturnStatement ((CCodeExpression) stmt.return_expression.ccodenode); + + create_temp_decl (stmt, stmt.return_expression.temp_vars); + + if (return_expression_symbol != null) { + return_expression_symbol.active = true; + } + } + } + + private ref string get_symbol_lock_name (Symbol! sym) { + return "__lock_%s".printf (sym.name); + } + + /** + * Visit operation called for lock statements. + * + * @param stmt a lock statement + */ + public override void visit_lock_statement (LockStatement! stmt) { + var cn = new CCodeFragment (); + CCodeExpression l = null; + CCodeFunctionCall fc; + var inner_node = ((MemberAccess)stmt.resource).inner; + + if (inner_node == null) { + l = new CCodeIdentifier ("self"); + } else if (stmt.resource.symbol_reference.parent_symbol.node != current_class) { + l = new CCodeFunctionCall (new CCodeIdentifier (((DataType) stmt.resource.symbol_reference.parent_symbol.node).get_upper_case_cname ())); + ((CCodeFunctionCall) l).add_argument ((CCodeExpression)inner_node.ccodenode); + } else { + l = (CCodeExpression)inner_node.ccodenode; + } + l = new CCodeMemberAccess.pointer (new CCodeMemberAccess.pointer (l, "priv"), get_symbol_lock_name (stmt.resource.symbol_reference)); + + fc = new CCodeFunctionCall (new CCodeIdentifier (((Method)mutex_type.data_type.symbol.lookup ("lock").node).get_cname ())); + fc.add_argument (l); + cn.append (new CCodeExpressionStatement (fc)); + + cn.append (stmt.body.ccodenode); + + fc = new CCodeFunctionCall (new CCodeIdentifier (((Method)mutex_type.data_type.symbol.lookup ("unlock").node).get_cname ())); + fc.add_argument (l); + cn.append (new CCodeExpressionStatement (fc)); + + stmt.ccodenode = cn; + } + + /** + * Visit operations called for array creation expresions. + * + * @param expr an array creation expression + */ + public override void visit_end_array_creation_expression (ArrayCreationExpression! expr) { + /* FIXME: rank > 1 not supported yet */ + if (expr.rank > 1) { + expr.error = true; + Report.error (expr.source_reference, "Creating arrays with rank greater than 1 is not supported yet"); + } + + var sizes = expr.get_sizes (); + var gnew = new CCodeFunctionCall (new CCodeIdentifier ("g_new0")); + gnew.add_argument (new CCodeIdentifier (expr.element_type.get_cname ())); + /* FIXME: had to add Expression cast due to possible compiler bug */ + gnew.add_argument ((CCodeExpression) ((Expression) sizes.first ().data).ccodenode); + + if (expr.initializer_list != null) { + var ce = new CCodeCommaExpression (); + var temp_var = get_temp_variable_declarator (expr.static_type); + var name_cnode = new CCodeIdentifier (temp_var.name); + int i = 0; + + temp_vars.prepend (temp_var); + + /* FIXME: had to add Expression cast due to possible compiler bug */ + ce.append_expression (new CCodeAssignment (name_cnode, gnew)); + + foreach (Expression e in expr.initializer_list.get_initializers ()) { + ce.append_expression (new CCodeAssignment (new CCodeElementAccess (name_cnode, new CCodeConstant (i.to_string ())), (CCodeExpression) e.ccodenode)); + i++; + } + + ce.append_expression (name_cnode); + + expr.ccodenode = ce; + } else { + expr.ccodenode = gnew; + } + } + + public override void visit_boolean_literal (BooleanLiteral! expr) { + expr.ccodenode = new CCodeConstant (expr.value ? "TRUE" : "FALSE"); + } + + public override void visit_character_literal (CharacterLiteral! expr) { + if (expr.get_char () >= 0x20 && expr.get_char () < 0x80) { + expr.ccodenode = new CCodeConstant (expr.value); + } else { + expr.ccodenode = new CCodeConstant ("%uU".printf (expr.get_char ())); + } + } + + public override void visit_integer_literal (IntegerLiteral! expr) { + expr.ccodenode = new CCodeConstant (expr.value); + } + + public override void visit_real_literal (RealLiteral! expr) { + expr.ccodenode = new CCodeConstant (expr.value); + } + + public override void visit_string_literal (StringLiteral! expr) { + expr.ccodenode = new CCodeConstant (expr.value); + } + + public override void visit_null_literal (NullLiteral! expr) { + expr.ccodenode = new CCodeConstant ("NULL"); + } + + public override void visit_literal_expression (LiteralExpression! expr) { + expr.ccodenode = expr.literal.ccodenode; + + visit_expression (expr); + } + + private void process_cmember (MemberAccess! expr, CCodeExpression pub_inst, DataType base_type) { + if (expr.symbol_reference.node is Method) { + var m = (Method) expr.symbol_reference.node; + + if (expr.inner is BaseAccess) { + if (m.base_interface_method != null) { + var base_iface = (Interface) m.base_interface_method.symbol.parent_symbol.node; + string parent_iface_var = "%s_%s_parent_iface".printf (current_class.get_lower_case_cname (null), base_iface.get_lower_case_cname (null)); + + expr.ccodenode = new CCodeMemberAccess.pointer (new CCodeIdentifier (parent_iface_var), m.name); + return; + } else if (m.base_method != null) { + var base_class = (Class) m.base_method.symbol.parent_symbol.node; + var vcast = new CCodeFunctionCall (new CCodeIdentifier ("%s_CLASS".printf (base_class.get_upper_case_cname (null)))); + vcast.add_argument (new CCodeIdentifier ("%s_parent_class".printf (current_class.get_lower_case_cname (null)))); + + expr.ccodenode = new CCodeMemberAccess.pointer (vcast, m.name); + return; + } + } + + if (m.base_interface_method != null) { + expr.ccodenode = new CCodeIdentifier (m.base_interface_method.get_cname ()); + } else if (m.base_method != null) { + expr.ccodenode = new CCodeIdentifier (m.base_method.get_cname ()); + } else { + expr.ccodenode = new CCodeIdentifier (m.get_cname ()); + } + } else if (expr.symbol_reference.node is ArrayLengthField) { + expr.ccodenode = get_array_length_cexpression (expr.inner, 1); + } else if (expr.symbol_reference.node is Field) { + var f = (Field) expr.symbol_reference.node; + if (f.instance) { + ref CCodeExpression typed_inst; + if (f.symbol.parent_symbol.node != base_type) { + // FIXME: use C cast if debugging disabled + typed_inst = new CCodeFunctionCall (new CCodeIdentifier (((DataType) f.symbol.parent_symbol.node).get_upper_case_cname (null))); + ((CCodeFunctionCall) typed_inst).add_argument (pub_inst); + } else { + typed_inst = pub_inst; + } + ref CCodeExpression inst; + if (f.access == MemberAccessibility.PRIVATE) { + inst = new CCodeMemberAccess.pointer (typed_inst, "priv"); + } else { + inst = typed_inst; + } + if (((DataType) f.symbol.parent_symbol.node).is_reference_type ()) { + expr.ccodenode = new CCodeMemberAccess.pointer (inst, f.get_cname ()); + } else { + expr.ccodenode = new CCodeMemberAccess (inst, f.get_cname ()); + } + } else { + expr.ccodenode = new CCodeIdentifier (f.get_cname ()); + } + } else if (expr.symbol_reference.node is Constant) { + var c = (Constant) expr.symbol_reference.node; + expr.ccodenode = new CCodeIdentifier (c.get_cname ()); + } else if (expr.symbol_reference.node is Property) { + var prop = (Property) expr.symbol_reference.node; + + if (!prop.no_accessor_method) { + var base_property = prop; + if (prop.base_property != null) { + base_property = prop.base_property; + } else if (prop.base_interface_property != null) { + base_property = prop.base_interface_property; + } + var base_property_type = (DataType) base_property.symbol.parent_symbol.node; + var ccall = new CCodeFunctionCall (new CCodeIdentifier ("%s_get_%s".printf (base_property_type.get_lower_case_cname (null), base_property.name))); + + /* explicitly use strong reference as ccast + * gets unrefed at the end of the inner block + */ + ref CCodeExpression typed_pub_inst = pub_inst; + + /* cast if necessary */ + if (base_property_type != base_type) { + // FIXME: use C cast if debugging disabled + var ccast = new CCodeFunctionCall (new CCodeIdentifier (base_property_type.get_upper_case_cname (null))); + ccast.add_argument (pub_inst); + typed_pub_inst = ccast; + } + + ccall.add_argument (typed_pub_inst); + expr.ccodenode = ccall; + } else { + var ccall = new CCodeFunctionCall (new CCodeIdentifier ("g_object_get")); + + var ccast = new CCodeFunctionCall (new CCodeIdentifier ("G_OBJECT")); + ccast.add_argument (pub_inst); + ccall.add_argument (ccast); + + // property name is second argument of g_object_get + ccall.add_argument (prop.get_canonical_cconstant ()); + + + // we need a temporary variable to save the property value + var temp_decl = get_temp_variable_declarator (expr.static_type); + temp_vars.prepend (temp_decl); + + var ctemp = new CCodeIdentifier (temp_decl.name); + ccall.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, ctemp)); + + + ccall.add_argument (new CCodeConstant ("NULL")); + + var ccomma = new CCodeCommaExpression (); + ccomma.append_expression (ccall); + ccomma.append_expression (ctemp); + expr.ccodenode = ccomma; + } + } else if (expr.symbol_reference.node is EnumValue) { + var ev = (EnumValue) expr.symbol_reference.node; + expr.ccodenode = new CCodeConstant (ev.get_cname ()); + } else if (expr.symbol_reference.node is VariableDeclarator) { + var decl = (VariableDeclarator) expr.symbol_reference.node; + expr.ccodenode = new CCodeIdentifier (decl.name); + } else if (expr.symbol_reference.node is FormalParameter) { + var p = (FormalParameter) expr.symbol_reference.node; + if (p.name == "this") { + expr.ccodenode = pub_inst; + } else { + if (p.type_reference.is_out || p.type_reference.reference_to_value_type) { + expr.ccodenode = new CCodeIdentifier ("(*%s)".printf (p.name)); + } else { + expr.ccodenode = new CCodeIdentifier (p.name); + } + } + } else if (expr.symbol_reference.node is Signal) { + var sig = (Signal) expr.symbol_reference.node; + var cl = (DataType) sig.symbol.parent_symbol.node; + + if (sig.has_emitter) { + var ccall = new CCodeFunctionCall (new CCodeIdentifier ("%s_%s".printf (cl.get_lower_case_cname (null), sig.name))); + + /* explicitly use strong reference as ccast + * gets unrefed at the end of the inner block + */ + ref CCodeExpression typed_pub_inst = pub_inst; + + /* cast if necessary */ + if (cl != base_type) { + // FIXME: use C cast if debugging disabled + var ccast = new CCodeFunctionCall (new CCodeIdentifier (cl.get_upper_case_cname (null))); + ccast.add_argument (pub_inst); + typed_pub_inst = ccast; + } + + ccall.add_argument (typed_pub_inst); + expr.ccodenode = ccall; + } else { + var ccall = new CCodeFunctionCall (new CCodeIdentifier ("g_signal_emit_by_name")); + + // FIXME: use C cast if debugging disabled + var ccast = new CCodeFunctionCall (new CCodeIdentifier ("G_OBJECT")); + ccast.add_argument (pub_inst); + ccall.add_argument (ccast); + + ccall.add_argument (sig.get_canonical_cconstant ()); + + expr.ccodenode = ccall; + } + } + } + + public override void visit_parenthesized_expression (ParenthesizedExpression! expr) { + expr.ccodenode = new CCodeParenthesizedExpression ((CCodeExpression) expr.inner.ccodenode); + + visit_expression (expr); + } + + public override void visit_member_access (MemberAccess! expr) { + CCodeExpression pub_inst = null; + DataType base_type = null; + + if (expr.inner == null) { + pub_inst = new CCodeIdentifier ("self"); + + if (current_type_symbol != null) { + /* base type is available if this is a type method */ + base_type = (DataType) current_type_symbol.node; + + if (!base_type.is_reference_type ()) { + pub_inst = new CCodeIdentifier ("(*self)"); + } + } + } else { + pub_inst = (CCodeExpression) expr.inner.ccodenode; + + if (expr.inner.static_type != null) { + base_type = expr.inner.static_type.data_type; + } + } + + process_cmember (expr, pub_inst, base_type); + + visit_expression (expr); + } + + private ref CCodeExpression! get_array_length_cexpression (Expression! array_expr, int dim) { + bool is_out = false; + + if (array_expr is UnaryExpression) { + var unary_expr = (UnaryExpression) array_expr; + if (unary_expr.operator == UnaryOperator.OUT) { + array_expr = unary_expr.inner; + is_out = true; + } + } + + if (array_expr is ArrayCreationExpression) { + var size = ((ArrayCreationExpression) array_expr).get_sizes (); + var length_expr = (Expression) size.nth_data (dim - 1); + return (CCodeExpression) length_expr.ccodenode; + } else if (array_expr.symbol_reference != null) { + if (array_expr.symbol_reference.node is FormalParameter) { + var param = (FormalParameter) array_expr.symbol_reference.node; + if (!param.no_array_length) { + var length_expr = new CCodeIdentifier (get_array_length_cname (param.name, dim)); + if (is_out) { + return new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, length_expr); + } else { + return length_expr; + } + } + } else if (array_expr.symbol_reference.node is VariableDeclarator) { + var decl = (VariableDeclarator) array_expr.symbol_reference.node; + var length_expr = new CCodeIdentifier (get_array_length_cname (decl.name, dim)); + if (is_out) { + return new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, length_expr); + } else { + return length_expr; + } + } else if (array_expr.symbol_reference.node is Field) { + var field = (Field) array_expr.symbol_reference.node; + if (!field.no_array_length) { + var length_cname = get_array_length_cname (field.name, dim); + + var ma = (MemberAccess) array_expr; + + CCodeExpression pub_inst = null; + DataType base_type = null; + CCodeExpression length_expr = null; + + if (ma.inner == null) { + pub_inst = new CCodeIdentifier ("self"); + + if (current_type_symbol != null) { + /* base type is available if this is a type method */ + base_type = (DataType) current_type_symbol.node; + } + } else { + pub_inst = (CCodeExpression) ma.inner.ccodenode; + + if (ma.inner.static_type != null) { + base_type = ma.inner.static_type.data_type; + } + } + + if (field.instance) { + ref CCodeExpression typed_inst; + if (field.symbol.parent_symbol.node != base_type) { + // FIXME: use C cast if debugging disabled + typed_inst = new CCodeFunctionCall (new CCodeIdentifier (((DataType) field.symbol.parent_symbol.node).get_upper_case_cname (null))); + ((CCodeFunctionCall) typed_inst).add_argument (pub_inst); + } else { + typed_inst = pub_inst; + } + ref CCodeExpression inst; + if (field.access == MemberAccessibility.PRIVATE) { + inst = new CCodeMemberAccess.pointer (typed_inst, "priv"); + } else { + inst = typed_inst; + } + if (((DataType) field.symbol.parent_symbol.node).is_reference_type ()) { + length_expr = new CCodeMemberAccess.pointer (inst, length_cname); + } else { + length_expr = new CCodeMemberAccess (inst, length_cname); + } + } else { + length_expr = new CCodeIdentifier (length_cname); + } + + if (is_out) { + return new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, length_expr); + } else { + return length_expr; + } + } + } + } + + /* if we reach this point we were not able to get the explicit length of the array + * this is not allowed for an array of non-reference-type structs + */ + if (((Array)array_expr.static_type.data_type).element_type is Struct) { + var s = (Struct)((Array)array_expr.static_type.data_type).element_type; + if (!s.is_reference_type ()) { + array_expr.error = true; + Report.error (array_expr.source_reference, "arrays of value-type structs with no explicit length parameter are not supported"); + } + } + + if (!is_out) { + return new CCodeConstant ("-1"); + } else { + return new CCodeConstant ("NULL"); + } + } + + public override void visit_end_invocation_expression (InvocationExpression! expr) { + var ccall = new CCodeFunctionCall ((CCodeExpression) expr.call.ccodenode); + + Method m = null; + List<weak FormalParameter> params; + + if (!(expr.call is MemberAccess)) { + expr.error = true; + Report.error (expr.source_reference, "unsupported method invocation"); + return; + } + + var ma = (MemberAccess) expr.call; + + if (expr.call.symbol_reference.node is Invokable) { + var i = (Invokable) expr.call.symbol_reference.node; + params = i.get_parameters (); + + if (i is Method) { + m = (Method) i; + } else if (i is Signal) { + ccall = (CCodeFunctionCall) expr.call.ccodenode; + } + } + + if (m is ArrayResizeMethod) { + var array = (Array) m.symbol.parent_symbol.node; + ccall.add_argument (new CCodeIdentifier (array.get_cname ())); + } + + /* explicitly use strong reference as ccall gets unrefed + * at end of inner block + */ + ref CCodeExpression instance; + if (m != null && m.instance) { + var base_method = m; + if (m.base_interface_method != null) { + base_method = m.base_interface_method; + } else if (m.base_method != null) { + base_method = m.base_method; + } + + var req_cast = false; + if (ma.inner == null) { + instance = new CCodeIdentifier ("self"); + /* require casts for overriden and inherited methods */ + req_cast = m.overrides || m.base_interface_method != null || (m.symbol.parent_symbol != current_type_symbol); + } else { + instance = (CCodeExpression) ma.inner.ccodenode; + /* reqiure casts if the type of the used instance is + * different than the type which declared the method */ + req_cast = base_method.symbol.parent_symbol.node != ma.inner.static_type.data_type; + } + + if (m.instance_by_reference && (ma.inner != null || m.symbol.parent_symbol != current_type_symbol)) { + instance = new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, instance); + } + + if (req_cast && ((DataType) m.symbol.parent_symbol.node).is_reference_type ()) { + // FIXME: use C cast if debugging disabled + var ccall = new CCodeFunctionCall (new CCodeIdentifier (((DataType) base_method.symbol.parent_symbol.node).get_upper_case_cname (null))); + ccall.add_argument (instance); + instance = ccall; + } + + if (!m.instance_last) { + ccall.add_argument (instance); + } + } + + bool ellipsis = false; + + var i = 1; + weak List<weak FormalParameter> params_it = params; + 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_it != null) { + var param = (FormalParameter) params_it.data; + ellipsis = param.ellipsis; + if (!ellipsis) { + if (param.type_reference.data_type != null + && param.type_reference.data_type.is_reference_type () + && arg.static_type.data_type != null) { + if (!param.no_array_length && param.type_reference.data_type is Array) { + var arr = (Array) param.type_reference.data_type; + for (int dim = 1; dim <= arr.rank; dim++) { + ccall.add_argument (get_array_length_cexpression (arg, dim)); + } + } + if (param.type_reference.data_type != arg.static_type.data_type) { + // FIXME: use C cast if debugging disabled + var ccall = new CCodeFunctionCall (new CCodeIdentifier (param.type_reference.data_type.get_upper_case_cname (null))); + ccall.add_argument (cexpr); + cexpr = ccall; + } + } else if (param.type_reference.data_type is Callback) { + cexpr = new CCodeCastExpression (cexpr, param.type_reference.data_type.get_cname ()); + } else if (param.type_reference.data_type == null + && arg.static_type.data_type is Struct) { + /* convert integer to pointer if this is a generic method parameter */ + var st = (Struct) arg.static_type.data_type; + if (st == bool_type.data_type || st.is_integer_type ()) { + var cconv = new CCodeFunctionCall (new CCodeIdentifier ("GINT_TO_POINTER")); + cconv.add_argument (cexpr); + cexpr = cconv; + } + } + } + } + + ccall.add_argument (cexpr); + i++; + + if (params_it != null) { + params_it = params_it.next; + } + } + while (params_it != null) { + var param = (FormalParameter) params_it.data; + + if (param.ellipsis) { + ellipsis = true; + 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); + + if (!param.no_array_length && param.type_reference != null && + param.type_reference.data_type is Array) { + var arr = (Array) param.type_reference.data_type; + for (int dim = 1; dim <= arr.rank; dim++) { + ccall.add_argument (get_array_length_cexpression (param.default_expression, dim)); + } + } + + ccall.add_argument ((CCodeExpression) param.default_expression.ccodenode); + i++; + + params_it = params_it.next; + } + + if (m != null && m.instance && m.instance_last) { + ccall.add_argument (instance); + } else if (ellipsis) { + /* ensure variable argument list ends with NULL + * except when using printf-style arguments */ + if (m == null || !m.printf_format) { + ccall.add_argument (new CCodeConstant ("NULL")); + } + } + + if (m != null && m.instance && m.returns_modified_pointer) { + expr.ccodenode = new CCodeAssignment (instance, ccall); + } else { + /* cast pointer to actual type if this is a generic method return value */ + if (m != null && m.return_type.type_parameter != null && expr.static_type.data_type != null) { + if (expr.static_type.data_type is Struct) { + var st = (Struct) expr.static_type.data_type; + if (st == uint_type.data_type) { + var cconv = new CCodeFunctionCall (new CCodeIdentifier ("GPOINTER_TO_UINT")); + cconv.add_argument (ccall); + ccall = cconv; + } else if (st == bool_type.data_type || st.is_integer_type ()) { + var cconv = new CCodeFunctionCall (new CCodeIdentifier ("GPOINTER_TO_INT")); + cconv.add_argument (ccall); + ccall = cconv; + } + } + } + + expr.ccodenode = ccall; + + visit_expression (expr); + } + + if (m is ArrayResizeMethod) { + // FIXME: size expression must not be evaluated twice at runtime (potential side effects) + var new_size = (CCodeExpression) ((CodeNode) expr.get_argument_list ().data).ccodenode; + + var temp_decl = get_temp_variable_declarator (int_type); + var temp_ref = new CCodeIdentifier (temp_decl.name); + + temp_vars.prepend (temp_decl); + + /* memset needs string.h */ + string_h_needed = true; + + var clen = get_array_length_cexpression (ma.inner, 1); + var celems = (CCodeExpression)ma.inner.ccodenode; + var csizeof = new CCodeIdentifier ("sizeof (%s)".printf (ma.inner.static_type.data_type.get_cname ())); + var cdelta = new CCodeParenthesizedExpression (new CCodeBinaryExpression (CCodeBinaryOperator.MINUS, temp_ref, clen)); + var ccheck = new CCodeBinaryExpression (CCodeBinaryOperator.GREATER_THAN, temp_ref, clen); + + var czero = new CCodeFunctionCall (new CCodeIdentifier ("memset")); + czero.add_argument (new CCodeBinaryExpression (CCodeBinaryOperator.PLUS, celems, clen)); + czero.add_argument (new CCodeConstant ("0")); + czero.add_argument (new CCodeBinaryExpression (CCodeBinaryOperator.MUL, csizeof, cdelta)); + + var ccomma = new CCodeCommaExpression (); + ccomma.append_expression (new CCodeAssignment (temp_ref, new_size)); + ccomma.append_expression ((CCodeExpression) expr.ccodenode); + ccomma.append_expression (new CCodeConditionalExpression (ccheck, czero, new CCodeConstant ("NULL"))); + ccomma.append_expression (new CCodeAssignment (get_array_length_cexpression (ma.inner, 1), temp_ref)); + + expr.ccodenode = ccomma; + } + } + + public override void visit_element_access (ElementAccess! expr) + { + List<weak Expression> indices = expr.get_indices (); + int rank = indices.length (); + + if (rank == 1) { + /* FIXME: had to add Expression cast due to possible compiler bug */ + expr.ccodenode = new CCodeElementAccess ((CCodeExpression)expr.container.ccodenode, (CCodeExpression)((Expression)indices.first ().data).ccodenode); + } else { + expr.error = true; + Report.error (expr.source_reference, "Arrays with more then one dimension are not supported yet"); + return; + } + + visit_expression (expr); + } + + public override void visit_base_access (BaseAccess! expr) { + expr.ccodenode = new InstanceCast (new CCodeIdentifier ("self"), expr.static_type.data_type); + } + + public override void visit_postfix_expression (PostfixExpression! expr) { + MemberAccess ma = find_property_access (expr.inner); + if (ma != null) { + // property postfix expression + var prop = (Property) ma.symbol_reference.node; + + var ccomma = new CCodeCommaExpression (); + + // assign current value to temp variable + var temp_decl = get_temp_variable_declarator (prop.type_reference); + temp_vars.prepend (temp_decl); + ccomma.append_expression (new CCodeAssignment (new CCodeIdentifier (temp_decl.name), (CCodeExpression) expr.inner.ccodenode)); + + // increment/decrement property + var op = expr.increment ? CCodeBinaryOperator.PLUS : CCodeBinaryOperator.MINUS; + var cexpr = new CCodeBinaryExpression (op, new CCodeIdentifier (temp_decl.name), new CCodeConstant ("1")); + var ccall = get_property_set_call (prop, ma, cexpr); + ccomma.append_expression (ccall); + + // return previous value + ccomma.append_expression (new CCodeIdentifier (temp_decl.name)); + + expr.ccodenode = ccomma; + return; + } + + var op = expr.increment ? CCodeUnaryOperator.POSTFIX_INCREMENT : CCodeUnaryOperator.POSTFIX_DECREMENT; + + expr.ccodenode = new CCodeUnaryExpression (op, (CCodeExpression) expr.inner.ccodenode); + + visit_expression (expr); + } + + private MemberAccess find_property_access (Expression! expr) { + if (expr is ParenthesizedExpression) { + var pe = (ParenthesizedExpression) expr; + return find_property_access (pe.inner); + } + + if (!(expr is MemberAccess)) { + return null; + } + + var ma = (MemberAccess) expr; + if (ma.symbol_reference.node is Property) { + return ma; + } + + return null; + } + + private ref CCodeExpression get_ref_expression (Expression! expr) { + /* (temp = expr, temp == NULL ? NULL : ref (temp)) + * + * can be simplified to + * ref (expr) + * if static type of expr is non-null + */ + + if (expr.static_type.data_type == null && + expr.static_type.type_parameter != null) { + Report.warning (expr.source_reference, "Missing generics support for memory management"); + return (CCodeExpression) expr.ccodenode; + } + + string ref_function; + if (expr.static_type.data_type.is_reference_counting ()) { + ref_function = expr.static_type.data_type.get_ref_function (); + } else { + if (expr.static_type.data_type != string_type.data_type) { + // duplicating non-reference counted structs may cause side-effects (and performance issues) + Report.warning (expr.source_reference, "duplicating %s instance, use weak variable or explicitly invoke copy method".printf (expr.static_type.data_type.name)); + } + ref_function = expr.static_type.data_type.get_dup_function (); + } + + var ccall = new CCodeFunctionCall (new CCodeIdentifier (ref_function)); + + if (expr.static_type.non_null) { + ccall.add_argument ((CCodeExpression) expr.ccodenode); + + return ccall; + } else { + var decl = get_temp_variable_declarator (expr.static_type, false); + temp_vars.prepend (decl); + + var ctemp = new CCodeIdentifier (decl.name); + + var cisnull = new CCodeBinaryExpression (CCodeBinaryOperator.EQUALITY, ctemp, new CCodeConstant ("NULL")); + + ccall.add_argument (ctemp); + + var ccomma = new CCodeCommaExpression (); + ccomma.append_expression (new CCodeAssignment (ctemp, (CCodeExpression) expr.ccodenode)); + + if (ref_function == "g_list_copy") { + bool is_ref = false; + bool is_class = false; + bool is_interface = false; + + foreach (TypeReference type_arg in expr.static_type.get_type_arguments ()) { + is_ref |= type_arg.takes_ownership; + is_class |= type_arg.data_type is Class; + is_interface |= type_arg.data_type is Interface; + } + + if (is_ref && (is_class || is_interface)) { + var crefcall = new CCodeFunctionCall (new CCodeIdentifier ("g_list_foreach")); + + crefcall.add_argument (ctemp); + crefcall.add_argument (new CCodeIdentifier ("(GFunc) g_object_ref")); + crefcall.add_argument (new CCodeConstant ("NULL")); + + ccomma.append_expression (crefcall); + } + } + + ccomma.append_expression (new CCodeConditionalExpression (cisnull, new CCodeConstant ("NULL"), ccall)); + + return ccomma; + } + } + + private void visit_expression (Expression! expr) { + if (expr.static_type != null && + expr.static_type.transfers_ownership && + expr.static_type.floating_reference) { + /* constructor of GInitiallyUnowned subtype + * returns floating reference, sink it + */ + var csink = new CCodeFunctionCall (new CCodeIdentifier ("g_object_ref_sink")); + csink.add_argument ((CCodeExpression) expr.ccodenode); + + expr.ccodenode = csink; + } + + if (expr.ref_leaked) { + var decl = get_temp_variable_declarator (expr.static_type); + temp_vars.prepend (decl); + temp_ref_vars.prepend (decl); + expr.ccodenode = new CCodeParenthesizedExpression (new CCodeAssignment (new CCodeIdentifier (decl.name), (CCodeExpression) expr.ccodenode)); + } else if (expr.ref_missing) { + expr.ccodenode = get_ref_expression (expr); + } + } + + public override void visit_end_object_creation_expression (ObjectCreationExpression! expr) { + if (expr.symbol_reference == null) { + // no creation method + if (expr.type_reference.data_type is Class) { + var ccall = new CCodeFunctionCall (new CCodeIdentifier ("g_object_new")); + + ccall.add_argument (new CCodeConstant (expr.type_reference.data_type.get_type_id ())); + + ccall.add_argument (new CCodeConstant ("NULL")); + + expr.ccodenode = ccall; + } else if (expr.type_reference.data_type == list_type || + expr.type_reference.data_type == slist_type) { + // NULL is an empty list + expr.ccodenode = new CCodeConstant ("NULL"); + } else { + var ccall = new CCodeFunctionCall (new CCodeIdentifier ("g_new0")); + + ccall.add_argument (new CCodeConstant (expr.type_reference.data_type.get_cname ())); + + ccall.add_argument (new CCodeConstant ("1")); + + expr.ccodenode = ccall; + } + } else { + // use creation method + var m = (Method) expr.symbol_reference.node; + var params = m.get_parameters (); + + var ccall = new CCodeFunctionCall (new CCodeIdentifier (m.get_cname ())); + + if (expr.type_reference.data_type is Class) { + foreach (TypeReference type_arg in expr.type_reference.get_type_arguments ()) { + if (type_arg.takes_ownership) { + ccall.add_argument (get_destroy_func_expression (type_arg)); + } else { + ccall.add_argument (new CCodeConstant ("NULL")); + } + } + } + + bool ellipsis = false; + + int i = 1; + weak List<weak FormalParameter> params_it = params; + 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_it != null) { + var param = (FormalParameter) params_it.data; + ellipsis = param.ellipsis; + 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) { + // FIXME: use C cast if debugging disabled + var ccall = new CCodeFunctionCall (new CCodeIdentifier (param.type_reference.data_type.get_upper_case_cname (null))); + ccall.add_argument (cexpr); + cexpr = ccall; + } + } + + ccall.add_argument (cexpr); + i++; + + if (params_it != null) { + params_it = params_it.next; + } + } + while (params_it != null) { + var param = (FormalParameter) params_it.data; + + if (param.ellipsis) { + ellipsis = true; + 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 ((CCodeExpression) param.default_expression.ccodenode); + i++; + + params_it = params_it.next; + } + + if (ellipsis) { + // ensure variable argument list ends with NULL + ccall.add_argument (new CCodeConstant ("NULL")); + } + + expr.ccodenode = ccall; + } + + visit_expression (expr); + } + + public override void visit_typeof_expression (TypeofExpression! expr) { + expr.ccodenode = new CCodeIdentifier (expr.type_reference.data_type.get_type_id ()); + } + + public override void visit_unary_expression (UnaryExpression! expr) { + CCodeUnaryOperator op; + if (expr.operator == UnaryOperator.PLUS) { + op = CCodeUnaryOperator.PLUS; + } else if (expr.operator == UnaryOperator.MINUS) { + op = CCodeUnaryOperator.MINUS; + } else if (expr.operator == UnaryOperator.LOGICAL_NEGATION) { + op = CCodeUnaryOperator.LOGICAL_NEGATION; + } else if (expr.operator == UnaryOperator.BITWISE_COMPLEMENT) { + op = CCodeUnaryOperator.BITWISE_COMPLEMENT; + } else if (expr.operator == UnaryOperator.INCREMENT) { + op = CCodeUnaryOperator.PREFIX_INCREMENT; + } else if (expr.operator == UnaryOperator.DECREMENT) { + op = CCodeUnaryOperator.PREFIX_DECREMENT; + } else if (expr.operator == UnaryOperator.REF) { + op = CCodeUnaryOperator.ADDRESS_OF; + } else if (expr.operator == UnaryOperator.OUT) { + op = CCodeUnaryOperator.ADDRESS_OF; + } + expr.ccodenode = new CCodeUnaryExpression (op, (CCodeExpression) expr.inner.ccodenode); + + visit_expression (expr); + } + + public override void visit_cast_expression (CastExpression! expr) { + if (expr.type_reference.data_type is Class || expr.type_reference.data_type is Interface) { + // GObject cast + expr.ccodenode = new InstanceCast ((CCodeExpression) expr.inner.ccodenode, expr.type_reference.data_type); + } else { + expr.ccodenode = new CCodeCastExpression ((CCodeExpression) expr.inner.ccodenode, expr.type_reference.get_cname ()); + } + + visit_expression (expr); + } + + public override void visit_pointer_indirection (PointerIndirection! expr) { + expr.ccodenode = new CCodeUnaryExpression (CCodeUnaryOperator.POINTER_INDIRECTION, (CCodeExpression) expr.inner.ccodenode); + } + + public override void visit_addressof_expression (AddressofExpression! expr) { + expr.ccodenode = new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, (CCodeExpression) expr.inner.ccodenode); + } + + public override void visit_reference_transfer_expression (ReferenceTransferExpression! expr) { + /* (tmp = var, var = null, tmp) */ + var ccomma = new CCodeCommaExpression (); + var temp_decl = get_temp_variable_declarator (expr.static_type); + temp_vars.prepend (temp_decl); + var cvar = new CCodeIdentifier (temp_decl.name); + + ccomma.append_expression (new CCodeAssignment (cvar, (CCodeExpression) expr.inner.ccodenode)); + ccomma.append_expression (new CCodeAssignment ((CCodeExpression) expr.inner.ccodenode, new CCodeConstant ("NULL"))); + ccomma.append_expression (cvar); + expr.ccodenode = ccomma; + + visit_expression (expr); + } + + public override void visit_binary_expression (BinaryExpression! expr) { + CCodeBinaryOperator op; + if (expr.operator == BinaryOperator.PLUS) { + op = CCodeBinaryOperator.PLUS; + } else if (expr.operator == BinaryOperator.MINUS) { + op = CCodeBinaryOperator.MINUS; + } else if (expr.operator == BinaryOperator.MUL) { + op = CCodeBinaryOperator.MUL; + } else if (expr.operator == BinaryOperator.DIV) { + op = CCodeBinaryOperator.DIV; + } else if (expr.operator == BinaryOperator.MOD) { + op = CCodeBinaryOperator.MOD; + } else if (expr.operator == BinaryOperator.SHIFT_LEFT) { + op = CCodeBinaryOperator.SHIFT_LEFT; + } else if (expr.operator == BinaryOperator.SHIFT_RIGHT) { + op = CCodeBinaryOperator.SHIFT_RIGHT; + } else if (expr.operator == BinaryOperator.LESS_THAN) { + op = CCodeBinaryOperator.LESS_THAN; + } else if (expr.operator == BinaryOperator.GREATER_THAN) { + op = CCodeBinaryOperator.GREATER_THAN; + } else if (expr.operator == BinaryOperator.LESS_THAN_OR_EQUAL) { + op = CCodeBinaryOperator.LESS_THAN_OR_EQUAL; + } else if (expr.operator == BinaryOperator.GREATER_THAN_OR_EQUAL) { + op = CCodeBinaryOperator.GREATER_THAN_OR_EQUAL; + } else if (expr.operator == BinaryOperator.EQUALITY) { + op = CCodeBinaryOperator.EQUALITY; + } else if (expr.operator == BinaryOperator.INEQUALITY) { + op = CCodeBinaryOperator.INEQUALITY; + } else if (expr.operator == BinaryOperator.BITWISE_AND) { + op = CCodeBinaryOperator.BITWISE_AND; + } else if (expr.operator == BinaryOperator.BITWISE_OR) { + op = CCodeBinaryOperator.BITWISE_OR; + } else if (expr.operator == BinaryOperator.BITWISE_XOR) { + op = CCodeBinaryOperator.BITWISE_XOR; + } else if (expr.operator == BinaryOperator.AND) { + op = CCodeBinaryOperator.AND; + } else if (expr.operator == BinaryOperator.OR) { + op = CCodeBinaryOperator.OR; + } + + var cleft = (CCodeExpression) expr.left.ccodenode; + var cright = (CCodeExpression) expr.right.ccodenode; + + if (expr.operator == BinaryOperator.EQUALITY || + expr.operator == BinaryOperator.INEQUALITY) { + if (expr.left.static_type != null && expr.right.static_type != null && + expr.left.static_type.data_type is Class && expr.right.static_type.data_type is Class) { + var left_cl = (Class) expr.left.static_type.data_type; + var right_cl = (Class) expr.right.static_type.data_type; + + if (left_cl != right_cl) { + if (left_cl.is_subtype_of (right_cl)) { + cleft = new InstanceCast (cleft, right_cl); + } else if (right_cl.is_subtype_of (left_cl)) { + cright = new InstanceCast (cright, left_cl); + } + } + } + } + + expr.ccodenode = new CCodeBinaryExpression (op, cleft, cright); + + visit_expression (expr); + } + + public override void visit_type_check (TypeCheck! expr) { + var ccheck = new CCodeFunctionCall (new CCodeIdentifier (expr.type_reference.data_type.get_upper_case_cname ("IS_"))); + ccheck.add_argument ((CCodeExpression) expr.expression.ccodenode); + expr.ccodenode = ccheck; + } + + public override void visit_conditional_expression (ConditionalExpression! expr) { + expr.ccodenode = new CCodeConditionalExpression ((CCodeExpression) expr.condition.ccodenode, (CCodeExpression) expr.true_expression.ccodenode, (CCodeExpression) expr.false_expression.ccodenode); + } + + public override void visit_end_lambda_expression (LambdaExpression! l) { + l.ccodenode = new CCodeIdentifier (l.method.get_cname ()); + } + + public override void visit_end_assignment (Assignment! a) { + MemberAccess ma = null; + + if (a.left is MemberAccess) { + ma = (MemberAccess)a.left; + } + + if (a.left.symbol_reference != null && a.left.symbol_reference.node is Property) { + var prop = (Property) a.left.symbol_reference.node; + + if (current_class != null && ma.inner == null && in_creation_method) { + // this property is used as a construction parameter + var cpointer = new CCodeIdentifier ("__params_it"); + + var ccomma = new CCodeCommaExpression (); + // set name in array for current parameter + var cnamemember = new CCodeMemberAccess.pointer (cpointer, "name"); + var cnameassign = new CCodeAssignment (cnamemember, prop.get_canonical_cconstant ()); + ccomma.append_expression (cnameassign); + + var gvaluearg = new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeMemberAccess.pointer (cpointer, "value")); + + // initialize GValue in array for current parameter + var cvalueinit = new CCodeFunctionCall (new CCodeIdentifier ("g_value_init")); + cvalueinit.add_argument (gvaluearg); + cvalueinit.add_argument (new CCodeIdentifier (prop.type_reference.data_type.get_type_id ())); + ccomma.append_expression (cvalueinit); + + // set GValue for current parameter + var cvalueset = new CCodeFunctionCall (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 (CCodeUnaryOperator.POSTFIX_INCREMENT, cpointer)); + + a.ccodenode = ccomma; + } else { + ref CCodeExpression cexpr = (CCodeExpression) a.right.ccodenode; + + if (!prop.no_accessor_method + && 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 (new CCodeIdentifier (prop.type_reference.data_type.get_upper_case_cname (null))); + ccast.add_argument (cexpr); + cexpr = ccast; + } + + if (a.operator != AssignmentOperator.SIMPLE) { + CCodeBinaryOperator cop; + if (a.operator == AssignmentOperator.BITWISE_OR) { + cop = CCodeBinaryOperator.BITWISE_OR; + } else if (a.operator == AssignmentOperator.BITWISE_AND) { + cop = CCodeBinaryOperator.BITWISE_AND; + } else if (a.operator == AssignmentOperator.BITWISE_XOR) { + cop = CCodeBinaryOperator.BITWISE_XOR; + } else if (a.operator == AssignmentOperator.ADD) { + cop = CCodeBinaryOperator.PLUS; + } else if (a.operator == AssignmentOperator.SUB) { + cop = CCodeBinaryOperator.MINUS; + } else if (a.operator == AssignmentOperator.MUL) { + cop = CCodeBinaryOperator.MUL; + } else if (a.operator == AssignmentOperator.DIV) { + cop = CCodeBinaryOperator.DIV; + } else if (a.operator == AssignmentOperator.PERCENT) { + cop = CCodeBinaryOperator.MOD; + } else if (a.operator == AssignmentOperator.SHIFT_LEFT) { + cop = CCodeBinaryOperator.SHIFT_LEFT; + } else if (a.operator == AssignmentOperator.SHIFT_RIGHT) { + cop = CCodeBinaryOperator.SHIFT_RIGHT; + } + cexpr = new CCodeBinaryExpression (cop, (CCodeExpression) a.left.ccodenode, new CCodeParenthesizedExpression (cexpr)); + } + + var ccall = get_property_set_call (prop, ma, cexpr); + + // assignments are expressions, so return the current property value + var ccomma = new CCodeCommaExpression (); + ccomma.append_expression (ccall); // update property + ccomma.append_expression ((CCodeExpression) ma.ccodenode); // current property value + + a.ccodenode = ccomma; + } + } else if (a.left.symbol_reference != null && a.left.symbol_reference.node is Signal) { + var sig = (Signal) a.left.symbol_reference.node; + + var m = (Method) a.right.symbol_reference.node; + + string connect_func; + bool disconnect = false; + + if (a.operator == AssignmentOperator.ADD) { + connect_func = "g_signal_connect_object"; + if (!m.instance) { + connect_func = "g_signal_connect"; + } + } else if (a.operator == AssignmentOperator.SUB) { + connect_func = "g_signal_handlers_disconnect_matched"; + disconnect = true; + } else { + a.error = true; + Report.error (a.source_reference, "Specified compound assignment type for signals not supported."); + return; + } + + var ccall = new CCodeFunctionCall (new CCodeIdentifier (connect_func)); + + if (ma.inner != null) { + ccall.add_argument ((CCodeExpression) ma.inner.ccodenode); + } else { + ccall.add_argument (new CCodeIdentifier ("self")); + } + + if (!disconnect) { + ccall.add_argument (sig.get_canonical_cconstant ()); + } else { + ccall.add_argument (new CCodeConstant ("G_SIGNAL_MATCH_ID | G_SIGNAL_MATCH_FUNC | G_SIGNAL_MATCH_DATA")); + + // get signal id + var ccomma = new CCodeCommaExpression (); + var temp_decl = get_temp_variable_declarator (uint_type); + temp_vars.prepend (temp_decl); + var parse_call = new CCodeFunctionCall (new CCodeIdentifier ("g_signal_parse_name")); + parse_call.add_argument (sig.get_canonical_cconstant ()); + var decl_type = (DataType) sig.symbol.parent_symbol.node; + parse_call.add_argument (new CCodeIdentifier (decl_type.get_type_id ())); + parse_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier (temp_decl.name))); + parse_call.add_argument (new CCodeConstant ("NULL")); + parse_call.add_argument (new CCodeConstant ("FALSE")); + ccomma.append_expression (parse_call); + ccomma.append_expression (new CCodeIdentifier (temp_decl.name)); + + ccall.add_argument (ccomma); + + ccall.add_argument (new CCodeConstant ("0")); + ccall.add_argument (new CCodeConstant ("NULL")); + } + + ccall.add_argument (new CCodeCastExpression (new CCodeIdentifier (m.get_cname ()), "GCallback")); + + if (m.instance) { + if (a.right is MemberAccess) { + var right_ma = (MemberAccess) a.right; + if (right_ma.inner != null) { + ccall.add_argument ((CCodeExpression) right_ma.inner.ccodenode); + } else { + ccall.add_argument (new CCodeIdentifier ("self")); + } + } else if (a.right is LambdaExpression) { + ccall.add_argument (new CCodeIdentifier ("self")); + } + if (!disconnect) { + ccall.add_argument (new CCodeConstant ("0")); + } + } else { + ccall.add_argument (new CCodeConstant ("NULL")); + } + + a.ccodenode = ccall; + } else { + /* explicitly use strong reference as ccast gets + * unrefed at end of inner block + */ + ref CCodeExpression rhs = (CCodeExpression) a.right.ccodenode; + + if (a.left.static_type.data_type != null + && a.right.static_type.data_type != null + && a.left.static_type.data_type.is_reference_type () + && a.right.static_type.data_type != a.left.static_type.data_type) { + var ccast = new CCodeFunctionCall (new CCodeIdentifier (a.left.static_type.data_type.get_upper_case_cname (null))); + ccast.add_argument (rhs); + rhs = ccast; + } + + bool unref_old = (memory_management && a.left.static_type.takes_ownership); + bool array = false; + if (a.left.static_type.data_type is Array) { + array = !(get_array_length_cexpression (a.left, 1) is CCodeConstant); + } + + if (unref_old || array) { + var ccomma = new CCodeCommaExpression (); + + var temp_decl = get_temp_variable_declarator (a.left.static_type); + temp_vars.prepend (temp_decl); + ccomma.append_expression (new CCodeAssignment (new CCodeIdentifier (temp_decl.name), rhs)); + if (unref_old) { + /* unref old value */ + ccomma.append_expression (get_unref_expression ((CCodeExpression) a.left.ccodenode, a.left.static_type)); + } + + if (array) { + var lhs_array_len = get_array_length_cexpression (a.left, 1); + var rhs_array_len = get_array_length_cexpression (a.right, 1); + ccomma.append_expression (new CCodeAssignment (lhs_array_len, rhs_array_len)); + } + + ccomma.append_expression (new CCodeIdentifier (temp_decl.name)); + + rhs = ccomma; + } + + var cop = CCodeAssignmentOperator.SIMPLE; + if (a.operator == AssignmentOperator.BITWISE_OR) { + cop = CCodeAssignmentOperator.BITWISE_OR; + } else if (a.operator == AssignmentOperator.BITWISE_AND) { + cop = CCodeAssignmentOperator.BITWISE_AND; + } else if (a.operator == AssignmentOperator.BITWISE_XOR) { + cop = CCodeAssignmentOperator.BITWISE_XOR; + } else if (a.operator == AssignmentOperator.ADD) { + cop = CCodeAssignmentOperator.ADD; + } else if (a.operator == AssignmentOperator.SUB) { + cop = CCodeAssignmentOperator.SUB; + } else if (a.operator == AssignmentOperator.MUL) { + cop = CCodeAssignmentOperator.MUL; + } else if (a.operator == AssignmentOperator.DIV) { + cop = CCodeAssignmentOperator.DIV; + } else if (a.operator == AssignmentOperator.PERCENT) { + cop = CCodeAssignmentOperator.PERCENT; + } else if (a.operator == AssignmentOperator.SHIFT_LEFT) { + cop = CCodeAssignmentOperator.SHIFT_LEFT; + } else if (a.operator == AssignmentOperator.SHIFT_RIGHT) { + cop = CCodeAssignmentOperator.SHIFT_RIGHT; + } + + a.ccodenode = new CCodeAssignment ((CCodeExpression) a.left.ccodenode, rhs, cop); + } + } + + private ref CCodeFunctionCall get_property_set_call (Property! prop, MemberAccess! ma, CCodeExpression! cexpr) { + 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 (new CCodeIdentifier (set_func)); + + /* target instance is first argument */ + ref CCodeExpression instance; + var req_cast = false; + + if (ma.inner == null) { + instance = new CCodeIdentifier ("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 (new CCodeIdentifier (((DataType) prop.symbol.parent_symbol.node).get_upper_case_cname (null))); + ccast.add_argument (instance); + instance = ccast; + } + + ccall.add_argument (instance); + + if (prop.no_accessor_method) { + /* property name is second argument of g_object_set */ + ccall.add_argument (prop.get_canonical_cconstant ()); + } + + ccall.add_argument (cexpr); + + if (prop.no_accessor_method) { + ccall.add_argument (new CCodeConstant ("NULL")); + } + + return ccall; + } +} diff --git a/vala/valacodenode.vala b/vala/valacodenode.vala new file mode 100644 index 000000000..92df6fcb1 --- /dev/null +++ b/vala/valacodenode.vala @@ -0,0 +1,118 @@ +/* valacodenode.vala + * + * Copyright (C) 2006-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 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 part of the parsed source code. + * + * Code nodes get created by the parser and are used throughout the whole + * compilation process. + */ +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; } + + /** + * References the location in the source file where this code node has + * been written. + */ + public SourceReference source_reference { get; set construct; } + + /** + * Contains all attributes that have been specified for this code node. + */ + public List<Attribute> attributes; + + /** + * Generated CCodeNode that corresponds to this code node. + */ + public CCodeNode ccodenode { + get { + return _ccodenode; + } + set { + if (source_reference != null) { + value.line = new CCodeLineDirective ( + source_reference.file.filename, + source_reference.first_line); + } + + _ccodenode = value; + } + } + + /** + * Specifies whether a fatal error has been detected in this code node. + */ + public bool error { get; set; } + + /** + * Visits this code node and all children with the specified + * CodeVisitor. + * + * @param visitor the visitor to be called while traversing + */ + public virtual void accept (CodeVisitor! visitor) { + } + + public virtual void replace (CodeNode! old_node, CodeNode! new_node) { + } + + /** + * Returns the specified attribute. + * + * @param name attribute name + * @return attribute + */ + public Attribute get_attribute (string! name) { + // FIXME: use hash table + foreach (Attribute a in attributes) { + if (a.name == name) { + return a; + } + } + + return null; + } + + private CCodeNode _ccodenode; + + /** + * Returns a string that represents this code node. + * + * @return a string representation + */ + public virtual ref string! to_string () { + if (source_reference != null) { + return source_reference.to_string (); + } + return "(unknown)"; + } +} diff --git a/vala/valacodevisitor.vala b/vala/valacodevisitor.vala new file mode 100644 index 000000000..e5624f5f9 --- /dev/null +++ b/vala/valacodevisitor.vala @@ -0,0 +1,838 @@ +/* valacodevisitor.vala + * + * Copyright (C) 2006-2007 Jürg Billeter, Raffaele Sandrini + * + * 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 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> + * Raffaele Sandrini <rasa@gmx.ch> + */ + +using GLib; + +/** + * Abstract code node visitor for traversing source code tree. + */ +public abstract class Vala.CodeVisitor { + /** + * Visit operation called at beginning of source files. + * + * @param source_file a source file + */ + public virtual void visit_begin_source_file (SourceFile! source_file) { + } + + /** + * Visit operation called at end of source files. + * + * @param source_file a source file + */ + public virtual void visit_end_source_file (SourceFile! source_file) { + } + + /** + * Visit operation called at beginning of namespaces. + * + * @param ns a namespace + */ + public virtual void visit_begin_namespace (Namespace! ns) { + } + + /** + * Visit operation called at end of namespaces. + * + * @param ns a namespace + */ + public virtual void visit_end_namespace (Namespace! ns) { + } + + /** + * Visit operation called at beginning of classes. + * + * @param cl a class + */ + public virtual void visit_begin_class (Class! cl) { + } + + /** + * Visit operation called at end of classes. + * + * @param cl a class + */ + public virtual void visit_end_class (Class! cl) { + } + + /** + * Visit operation called at beginning of structs. + * + * @param st a struct + */ + public virtual void visit_begin_struct (Struct! st) { + } + + /** + * Visit operation called at end of structs. + * + * @param st a struct + */ + public virtual void visit_end_struct (Struct! st) { + } + + /** + * Visit operation called at beginning of interfaces. + * + * @param iface an interface + */ + public virtual void visit_begin_interface (Interface! iface) { + } + + /** + * Visit operation called at end of interfaces. + * + * @param iface an interface + */ + public virtual void visit_end_interface (Interface! iface) { + } + + /** + * Visit operation called at beginning of enums. + * + * @param en an enum + */ + public virtual void visit_begin_enum (Enum! en) { + } + + /** + * Visit operation called at end of enums. + * + * @param en an enum + */ + public virtual void visit_end_enum (Enum! en) { + } + + /** + * Visit operation called for enum values. + * + * @param ev an enum value + */ + public virtual void visit_enum_value (EnumValue! ev) { + } + + /** + * Visit operation called at beginning of flags. + * + * @param fl a flags + */ + public virtual void visit_begin_flags (Flags! fl) { + } + + /** + * Visit operation called at end of flags. + * + * @param fl a flags + */ + public virtual void visit_end_flags (Flags! fl) { + } + + /** + * Visit operation called for flags values. + * + * @param fv an flags value + */ + public virtual void visit_flags_value (FlagsValue! fv) { + } + + /** + * Visit operation called at beginning of callbacks. + * + * @param cb a callback + */ + public virtual void visit_begin_callback (Callback! cb) { + } + + /** + * Visit operation called at end of callbacks. + * + * @param cb a callback + */ + public virtual void visit_end_callback (Callback! cb) { + } + + /** + * Visit operation called for Members. + * + * @param m a member + */ + public virtual void visit_member (Member! m) { + } + + /** + * Visit operation called for constants. + * + * @param c a constant + */ + public virtual void visit_constant (Constant! c) { + } + + /** + * Visit operation called for fields. + * + * @param f a field + */ + public virtual void visit_field (Field! f) { + } + + /** + * Visit operation called at beginning of methods. + * + * @param m a method + */ + public virtual void visit_begin_method (Method! m) { + } + + /** + * Visit operation called at end of methods. + * + * @param m a method + */ + public virtual void visit_end_method (Method! m) { + } + + /** + * Visit operation called at beginning of creation methods. + * + * @param m a method + */ + public virtual void visit_begin_creation_method (CreationMethod! m) { + } + + /** + * Visit operation called at end of creation methods. + * + * @param m a method + */ + public virtual void visit_end_creation_method (CreationMethod! m) { + } + + /** + * Visit operation called for formal parameters. + * + * @param p a formal parameter + */ + public virtual void visit_formal_parameter (FormalParameter! p) { + } + + /** + * Visit operation called at beginning of properties. + * + * @param prop a property + */ + public virtual void visit_begin_property (Property! prop) { + } + + /** + * Visit operation called at end of properties. + * + * @param prop a property + */ + public virtual void visit_end_property (Property! prop) { + } + + /** + * Visit operation called at beginning of property accessors. + * + * @param acc a property accessor + */ + public virtual void visit_begin_property_accessor (PropertyAccessor! acc) { + } + + /** + * Visit operation called at end of property accessors. + * + * @param acc a property accessor + */ + public virtual void visit_end_property_accessor (PropertyAccessor! acc) { + } + + /** + * Visit operation called at beginning of signals. + * + * @param sig a signal + */ + public virtual void visit_begin_signal (Signal! sig) { + } + + /** + * Visit operation called at end of signals. + * + * @param sig a signal + */ + public virtual void visit_end_signal (Signal! sig) { + } + + /** + * Visit operation called at beginning of constructors. + * + * @param c a constructor + */ + public virtual void visit_begin_constructor (Constructor! c) { + } + + /** + * Visit operation called at end of constructors. + * + * @param c a constructor + */ + public virtual void visit_end_constructor (Constructor! c) { + } + + /** + * Visit operation called at beginning of destructors. + * + * @param d a destructor + */ + public virtual void visit_begin_destructor (Destructor! d) { + } + + /** + * Visit operation called at end of destructors. + * + * @param d a destructor + */ + public virtual void visit_end_destructor (Destructor! d) { + } + + /** + * Visit operation called for named arguments. + * + * @param n a named argument + */ + public virtual void visit_named_argument (NamedArgument! n) { + } + + /** + * Visit operation called for type parameters. + * + * @param p a type parameter + */ + public virtual void visit_type_parameter (TypeParameter! p) { + } + + /** + * Visit operation called for namespace references. + * + * @param ns a namespace reference + */ + public virtual void visit_namespace_reference (NamespaceReference! ns) { + } + + /** + * Visit operation called for type references. + * + * @param type a type reference + */ + public virtual void visit_type_reference (TypeReference! type) { + } + + /** + * Visit operation called at beginning of blocks. + * + * @param b a block + */ + public virtual void visit_begin_block (Block! b) { + } + + /** + * Visit operation called at end of blocks. + * + * @param b a block + */ + public virtual void visit_end_block (Block! b) { + } + + /** + * Visit operation called for empty statements. + * + * @param stmt an empty statement + */ + public virtual void visit_empty_statement (EmptyStatement! stmt) { + } + + /** + * Visit operation called for declaration statements. + * + * @param stmt a declaration statement + */ + public virtual void visit_declaration_statement (DeclarationStatement! stmt) { + } + + /** + * Visit operation called for local variable declarations. + * + * @param decl a local variable declaration + */ + public virtual void visit_local_variable_declaration (LocalVariableDeclaration! decl) { + } + + /** + * Visit operation called for variable declarators. + * + * @param decl a variable declarator + */ + public virtual void visit_variable_declarator (VariableDeclarator! decl) { + } + + /** + * Visit operation called for initializer lists + * + * @param list an initializer list + */ + public virtual void visit_begin_initializer_list (InitializerList! list) { + } + + /** + * Visit operation called for initializer lists + * + * @param list an initializer list + */ + public virtual void visit_end_initializer_list (InitializerList! list) { + } + + /** + * Visit operation called for expression statements. + * + * @param stmt an expression statement + */ + public virtual void visit_expression_statement (ExpressionStatement! stmt) { + } + + /** + * Visit operation called for if statements. + * + * @param stmt an if statement + */ + public virtual void visit_if_statement (IfStatement! stmt) { + } + + /** + * Visit operation called for switch statements. + * + * @param stmt a switch statement + */ + public virtual void visit_switch_statement (SwitchStatement! stmt) { + } + + /** + * Visit operation called for switch sections. + * + * @param section a switch section + */ + public virtual void visit_switch_section (SwitchSection! section) { + } + + /** + * Visit operation called for switch label. + * + * @param label a switch label + */ + public virtual void visit_switch_label (SwitchLabel! label) { + } + + /** + * Visit operation called for while statements. + * + * @param stmt an while statement + */ + public virtual void visit_while_statement (WhileStatement! stmt) { + } + + /** + * Visit operation called for do statements. + * + * @param stmt a do statement + */ + public virtual void visit_do_statement (DoStatement! stmt) { + } + + /** + * Visit operation called for for statements. + * + * @param stmt a for statement + */ + public virtual void visit_for_statement (ForStatement! stmt) { + } + + /** + * Visit operation called at beginning of foreach statements. + * + * @param stmt a foreach statement + */ + public virtual void visit_begin_foreach_statement (ForeachStatement! stmt) { + } + + /** + * Visit operation called at end of foreach statements. + * + * @param stmt a foreach statement + */ + public virtual void visit_end_foreach_statement (ForeachStatement! stmt) { + } + + /** + * Visit operation called for break statements. + * + * @param stmt a break statement + */ + public virtual void visit_break_statement (BreakStatement! stmt) { + } + + /** + * Visit operation called for continue statements. + * + * @param stmt a continue statement + */ + public virtual void visit_continue_statement (ContinueStatement! stmt) { + } + + /** + * Visit operation called at beginning of return statements. + * + * @param stmt a return statement + */ + public virtual void visit_begin_return_statement (ReturnStatement! stmt) { + } + + /** + * Visit operation called at end of return statements. + * + * @param stmt a return statement + */ + public virtual void visit_end_return_statement (ReturnStatement! stmt) { + } + + /** + * Visit operation called at beginning of throw statements. + * + * @param stmt a throw statement + */ + public virtual void visit_begin_throw_statement (ThrowStatement! stmt) { + } + + /** + * Visit operation called at end of throw statements. + * + * @param stmt a throw statement + */ + public virtual void visit_end_throw_statement (ThrowStatement! stmt) { + } + + /** + * Visit operation called at beginning of try statements. + * + * @param stmt a try statement + */ + public virtual void visit_begin_try_statement (TryStatement! stmt) { + } + + /** + * Visit operation called at end of try statements. + * + * @param stmt a try statement + */ + public virtual void visit_end_try_statement (TryStatement! stmt) { + } + + /** + * Visit operation called at beginning of catch clauses. + * + * @param clause a catch cluase + */ + public virtual void visit_begin_catch_clause (CatchClause! clause) { + } + + /** + * Visit operation called at end of catch clauses. + * + * @param clause a catch clause + */ + public virtual void visit_end_catch_clause (CatchClause! clause) { + } + + /** + * Visit operation called for lock statements before the body has been visited. + * + * @param stmt a lock statement + */ + public virtual void visit_lock_statement (LockStatement! stmt) { + } + + /** + * Visit operations called for array creation expresions. + * + * @param expr an array creation expression + */ + public virtual void visit_begin_array_creation_expression (ArrayCreationExpression! expr) { + } + + /** + * Visit operations called for array creation expresions. + * + * @param expr an array creation expression + */ + public virtual void visit_end_array_creation_expression (ArrayCreationExpression! expr) { + } + + /** + * Visit operation called for boolean literals. + * + * @param lit a boolean literal + */ + public virtual void visit_boolean_literal (BooleanLiteral! lit) { + } + + /** + * Visit operation called for character literals. + * + * @param lit a character literal + */ + public virtual void visit_character_literal (CharacterLiteral! lit) { + } + + /** + * Visit operation called for integer literals. + * + * @param lit an integer literal + */ + public virtual void visit_integer_literal (IntegerLiteral! lit) { + } + + /** + * Visit operation called for real literals. + * + * @param lit a real literal + */ + public virtual void visit_real_literal (RealLiteral! lit) { + } + + /** + * Visit operation called for string literals. + * + * @param lit a string literal + */ + public virtual void visit_string_literal (StringLiteral! lit) { + } + + /** + * Visit operation called for null literals. + * + * @param lit a null literal + */ + public virtual void visit_null_literal (NullLiteral! lit) { + } + + /** + * Visit operation called for literal expressions. + * + * @param expr a literal expression + */ + public virtual void visit_literal_expression (LiteralExpression! expr) { + } + + /** + * Visit operation called for parenthesized expressions. + * + * @param expr a parenthesized expression + */ + public virtual void visit_parenthesized_expression (ParenthesizedExpression! expr) { + } + + /** + * Visit operation called for member access expressions. + * + * @param expr a member access expression + */ + public virtual void visit_member_access (MemberAccess! expr) { + } + + /** + * Visit operation called at beginning of invocation expressions. + * + * @param expr an invocation expression + */ + public virtual void visit_begin_invocation_expression (InvocationExpression! expr) { + } + + /** + * Visit operation called at end of invocation expressions. + * + * @param expr an invocation expression + */ + public virtual void visit_end_invocation_expression (InvocationExpression! expr) { + } + + /** + * Visit operation called for element access expressions. + * + * @param expr an element access expression + */ + public virtual void visit_element_access (ElementAccess! expr) { + } + + /** + * Visit operation called for base access expressions. + * + * @param expr a base access expression + */ + public virtual void visit_base_access (BaseAccess! expr) { + } + + /** + * Visit operation called for postfix expressions. + * + * @param expr a postfix expression + */ + public virtual void visit_postfix_expression (PostfixExpression! expr) { + } + + /** + * Visit operation called at beginning of object creation + * expressions. + * + * @param expr an object creation expression + */ + 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) { + } + + /** + * Visit operation called for typeof expressions. + * + * @param expr a typeof expression + */ + public virtual void visit_typeof_expression (TypeofExpression! expr) { + } + + /** + * Visit operation called for unary expressions. + * + * @param expr an unary expression + */ + public virtual void visit_unary_expression (UnaryExpression! expr) { + } + + /** + * Visit operation called for call expressions. + * + * @param expr a call expression + */ + public virtual void visit_cast_expression (CastExpression! expr) { + } + + /** + * Visit operation called for pointer indirections. + * + * @param expr a pointer indirection + */ + public virtual void visit_pointer_indirection (PointerIndirection! expr) { + } + + /** + * Visit operation called for address-of expressions. + * + * @param expr an address-of expression + */ + public virtual void visit_addressof_expression (AddressofExpression! expr) { + } + + /** + * Visit operation called for reference transfer expressions. + * + * @param expr a reference transfer expression + */ + public virtual void visit_reference_transfer_expression (ReferenceTransferExpression! expr) { + } + + /** + * Visit operation called for binary expressions. + * + * @param expr a binary expression + */ + public virtual void visit_binary_expression (BinaryExpression! expr) { + } + + /** + * Visit operation called for type checks. + * + * @param expr a type check expression + */ + public virtual void visit_type_check (TypeCheck! expr) { + } + + /** + * Visit operation called for conditional expressions. + * + * @param expr a conditional expression + */ + public virtual void visit_conditional_expression (ConditionalExpression! expr) { + } + + /** + * Visit operation called at beginning of lambda expressions. + * + * @param expr a lambda expression + */ + public virtual void visit_begin_lambda_expression (LambdaExpression! expr) { + } + + /** + * Visit operation called at end of lambda expressions. + * + * @param expr a lambda expression + */ + public virtual void visit_end_lambda_expression (LambdaExpression! expr) { + } + + /** + * Visit operation called at beginning of assignments. + * + * @param a an assignment + */ + public virtual void visit_begin_assignment (Assignment! a) { + } + + /** + * Visit operation called at end of assignments. + * + * @param a an assignment + */ + public virtual void visit_end_assignment (Assignment! a) { + } + + /** + * Visit operation called at end of full expressions. + * + * @param expr a full expression + */ + public virtual void visit_end_full_expression (Expression! expr) { + } +} diff --git a/vala/valaconditionalexpression.vala b/vala/valaconditionalexpression.vala new file mode 100644 index 000000000..92590dfcb --- /dev/null +++ b/vala/valaconditionalexpression.vala @@ -0,0 +1,66 @@ +/* valaconditionalexpression.vala + * + * Copyright (C) 2006 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 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 conditional expression in the source code. + */ +public class Vala.ConditionalExpression : Expression { + /** + * The condition. + */ + public Expression! condition { get; set construct; } + + /** + * The expression to be evaluated if the condition holds. + */ + public Expression! true_expression { get; set construct; } + + /** + * The expression to be evaluated if the condition doesn't hold. + */ + public Expression! false_expression { get; set construct; } + + /** + * Creates a new conditional expression. + * + * @param cond a condition + * @param true_expr expression to be evaluated if condition is true + * @param false_expr expression to be evaluated if condition is false + * @return newly created conditional expression + */ + public ConditionalExpression (Expression! cond, Expression! true_expr, Expression! false_expr, SourceReference source) { + condition = cond; + true_expression = true_expr; + false_expression = false_expr; + source_reference = source; + } + + public override void accept (CodeVisitor! visitor) { + condition.accept (visitor); + true_expression.accept (visitor); + false_expression.accept (visitor); + + visitor.visit_conditional_expression (this); + } +} diff --git a/vala/valaconstant.vala b/vala/valaconstant.vala new file mode 100644 index 000000000..8f7853520 --- /dev/null +++ b/vala/valaconstant.vala @@ -0,0 +1,114 @@ +/* valaconstant.vala + * + * Copyright (C) 2006 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 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 type member with a constant value. + */ +public class Vala.Constant : Member, Lockable { + /** + * The symbol name of this constant. + */ + public string! name { get; set construct; } + + /** + * The data type of this constant. + */ + public TypeReference! type_reference { get; set construct; } + + /** + * The value of this constant. + */ + public Expression initializer { get; set; } + + /** + * Specifies the accessibility of this constant. Public accessibility + * doesn't limit access. Default accessibility limits access to this + * program or library. Private accessibility limits access to instances + * of the contained type. + */ + public MemberAccessibility access; + + private string cname; + + private bool lock_used = false; + + /** + * Creates a new constant. + * + * @param name constant name + * @param type constant type + * @param init constant value + * @param source reference to source code + * @return newly created constant + */ + public Constant (string! _name, TypeReference! type, Expression init, SourceReference source) { + name = _name; + type_reference = type; + initializer = init; + source_reference = source; + } + + public override void accept (CodeVisitor! visitor) { + visitor.visit_member (this); + + type_reference.accept (visitor); + + if (initializer != null) { + initializer.accept (visitor); + } + + visitor.visit_constant (this); + } + + /** + * Returns the name of this constant as it is used in C code. + * + * @return the name to be used in C code + */ + public string! get_cname () { + if (cname == null) { + if (symbol.parent_symbol.node is DataType) { + var t = (DataType) symbol.parent_symbol.node; + cname = "%s%s".printf (t.get_lower_case_cprefix ().up (), name); + } else { + var ns = (Namespace) symbol.parent_symbol.node; + if (ns == null) { + // global constant + cname = name; + } else { + cname = "%s%s".printf (ns.get_lower_case_cprefix ().up (), name); + } + } + } + return cname; + } + + public bool get_lock_used () { + return lock_used; + } + + public void set_lock_used (bool used) { + lock_used = used; + } +} diff --git a/vala/valaconstructor.vala b/vala/valaconstructor.vala new file mode 100644 index 000000000..21c164a73 --- /dev/null +++ b/vala/valaconstructor.vala @@ -0,0 +1,67 @@ +/* valaconstructor.vala + * + * Copyright (C) 2006 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 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 class or instance constructor. + */ +public class Vala.Constructor : CodeNode { + /** + * The body of this constructor. + */ + public Statement body { get; set; } + + private bool _instance = true; + + /** + * Specifies whether this is an instance or a class constructor. + */ + public bool instance { + get { + return _instance; + } + set { + _instance = value; + } + } + + /** + * Creates a new constructor. + * + * @param source reference to source code + * @return newly created constructor + */ + public Constructor (SourceReference source) { + source_reference = source; + } + + public override void accept (CodeVisitor! visitor) { + visitor.visit_begin_constructor (this); + + if (body != null) { + body.accept (visitor); + } + + visitor.visit_end_constructor (this); + } +} diff --git a/vala/valacontinuestatement.vala b/vala/valacontinuestatement.vala new file mode 100644 index 000000000..da0f0d502 --- /dev/null +++ b/vala/valacontinuestatement.vala @@ -0,0 +1,42 @@ +/* valacontinuestatement.vala + * + * Copyright (C) 2006 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 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 continue statement in the source code. + */ +public class Vala.ContinueStatement : Statement { + /** + * Creates a new continue statement. + * + * @param source reference to source code + * @return newly created continue statement + */ + public ContinueStatement (SourceReference source) { + source_reference = source; + } + + public override void accept (CodeVisitor! visitor) { + visitor.visit_continue_statement (this); + } +} diff --git a/vala/valacreationmethod.vala b/vala/valacreationmethod.vala new file mode 100644 index 000000000..2113ab1ee --- /dev/null +++ b/vala/valacreationmethod.vala @@ -0,0 +1,67 @@ +/* valacreationmethod.vala + * + * Copyright (C) 2007 Raffaele Sandrini + * + * 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 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: + * Raffaele Sandrini <j@bitron.ch> + */ + +using GLib; + +/** + * Represents a type creation method. + */ +public class Vala.CreationMethod : Method { + /** + * Specifies the number of parameters this creation method sets. + */ + public int n_construction_params { get; set; } + + /** + * Creates a new method. + * + * @param name method name + * @param source_reference reference to source code + * @return newly created method + */ + public CreationMethod (construct string name, construct SourceReference source_reference = null) { + } + + public override void accept (CodeVisitor! visitor) { + visitor.visit_begin_creation_method (this); + + foreach (FormalParameter param in get_parameters()) { + param.accept (visitor); + } + + if (body != null) { + body.accept (visitor); + } + + visitor.visit_end_creation_method (this); + } + + public override ref string! get_default_cname () { + var parent = symbol.parent_symbol.node; + assert (parent is DataType); + if (name == null) { + return "%snew".printf (((DataType) parent).get_lower_case_cprefix ()); + } else { + return "%snew_%s".printf (((DataType) parent).get_lower_case_cprefix (), name); + } + } +} diff --git a/vala/valadatatype.vala b/vala/valadatatype.vala new file mode 100644 index 000000000..7ea6b433c --- /dev/null +++ b/vala/valadatatype.vala @@ -0,0 +1,310 @@ +/* valatype.vala + * + * Copyright (C) 2006-2007 Jürg Billeter, Raffaele Sandrini + * + * 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 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> + * Raffaele Sandrini <rasa@gmx.ch> + */ + +using GLib; + +/** + * Represents a runtime data type. This data type may be defined in Vala source + * code or imported from an external library with a Vala API file. + */ +public abstract class Vala.DataType : CodeNode { + /** + * The symbol name of this data type. + */ + public string name { get; set; } + + /** + * Specifies the accessibility of the class. Public accessibility + * doesn't limit access. Default accessibility limits access to this + * program or library. Protected and private accessibility is not + * supported for types. + */ + public MemberAccessibility access; + + /** + * The namespace containing this data type. + */ + public weak Namespace @namespace; + + private List<string> cheader_filenames; + + private Pointer pointer_type; + + /* holds the array types of this type; each rank is a separate one */ + /* FIXME: uses string because int does not work as key yet */ + private HashTable<string,Array> array_types = new HashTable.full (str_hash, str_equal, g_free, g_object_unref); + + /** + * Returns the name of this data type as it is used in C code. + * + * @return the name to be used in C code + */ + public abstract string get_cname (bool const_type = false); + + /** + * Checks whether this data type has value or reference type semantics. + * + * @return true if this data type has reference type semantics + */ + public virtual bool is_reference_type () { + return false; + } + + /** + * Returns the C function name that duplicates instances of this data + * type. The specified C function must accept one argument referencing + * the instance of this data type and return a reference to the + * duplicate. + * + * @return the name of the C function if supported or null otherwise + */ + public virtual string get_dup_function () { + return null; + } + + /** + * Returns the C function name that frees instances of this data type. + * This is only valid for data types with reference type semantics that + * do not support reference counting. The specified C function must + * accept one argument pointing to the instance to be freed. + * + * @return the name of the C function or null if this data type is not a + * reference type or if it supports reference counting + */ + public virtual string get_free_function () { + return null; + } + + /** + * Checks whether this data type supports reference counting. This is + * only valid for reference types. + * + * @return true if this data type supports reference counting + */ + public virtual bool is_reference_counting () { + return false; + } + + /** + * Returns the C function name that increments the reference count of + * instances of this data type. This is only valid for data types + * supporting reference counting. The specified C function must accept + * one argument referencing the instance of this data type and return + * the reference. + * + * @return the name of the C function or null if this data type does not + * support reference counting + */ + public virtual string get_ref_function () { + return null; + } + + /** + * Returns the C function name that decrements the reference count of + * instances of this data type. This is only valid for data types + * supporting reference counting. The specified C function must accept + * one argument referencing the instance of this data type. + * + * @return the name of the C function or null if this data type does not + * support reference counting + */ + public virtual string get_unref_function () { + return null; + } + + /** + * Returns the C symbol representing the runtime type id for this data + * type. The specified symbol must express a registered GType. + * + * @return the name of the GType name in C code or null if this data + * type is not registered with GType + */ + public virtual string get_type_id () { + return null; + } + + /** + * Returns the name of this data type as used in C code marshallers + * + * @return type name for marshallers + */ + public virtual string get_marshaller_type_name () { + return null; + } + + /** + * Returns the cname of the GValue getter function, + */ + public virtual string get_get_value_function () { + return null; + } + + /** + * Returns the cname of the GValue setter function, + */ + public virtual string get_set_value_function () { + return null; + } + + /** + * Returns the C name of this data type in upper case. Words are + * separated by underscores. The upper case C name of the namespace is + * prefix of the result. + * + * @param infix a string to be placed between namespace and data type + * name or null + * @return the upper case name to be used in C code + */ + public virtual ref string get_upper_case_cname (string infix = null) { + return null; + } + + /** + * Returns the C name of this data type in lower case. Words are + * separated by underscores. The lower case C name of the namespace is + * prefix of the result. + * + * @param infix a string to be placed between namespace and data type + * name or null + * @return the lower case name to be used in C code + */ + public virtual ref string get_lower_case_cname (string infix = null) { + return null; + } + + /** + * Returns the string to be prefixed to members of this data type in + * lower case when used in C code. + * + * @return the lower case prefix to be used in C code + */ + public virtual ref string get_lower_case_cprefix () { + return null; + } + + /** + * Returns the default value for the given type. Returning null means + * there is no default value (i.e. not that the default name is NULL). + * + * @return the name of the default value + */ + public virtual string get_default_value () { + return null; + } + + /** + * Returns a list of C header filenames users of this data type must + * include. + * + * @return list of C header filenames for this data type + */ + public virtual ref List<string> get_cheader_filenames () { + if (cheader_filenames == null) { + /* default to header filenames of the namespace */ + foreach (string filename in @namespace.get_cheader_filenames ()) { + add_cheader_filename (filename); + } + } + return cheader_filenames.copy (); + } + + /** + * Adds a filename to the list of C header filenames users of this data + * type must include. + * + * @param filename a C header filename + */ + public void add_cheader_filename (string! filename) { + cheader_filenames.append (filename); + } + + /** + * Returns the pointer type of this data type. + * + * @return pointer-type for this data type + */ + public Pointer! get_pointer () { + if (pointer_type == null) { + pointer_type = new Pointer (this, source_reference); + /* create a new Symbol */ + pointer_type.symbol = new Symbol (pointer_type); + this.symbol.parent_symbol.add (pointer_type.name, pointer_type.symbol); + + /* link the namespace */ + pointer_type.@namespace = this.@namespace; + } + + return pointer_type; + } + + /** + * Returns the array type for elements of this data type. + * + * @param rank the rank the array should be of + * @return array type for this data type + */ + public Array! get_array (int rank) { + Array array_type = (Array) array_types.lookup (rank.to_string ()); + + if (array_type == null) { + var new_array_type = new Array (this, rank, source_reference); + /* create a new Symbol */ + new_array_type.symbol = new Symbol (new_array_type); + this.symbol.parent_symbol.add (new_array_type.name, new_array_type.symbol); + + /* add internal length field */ + new_array_type.symbol.add (new_array_type.get_length_field ().name, new_array_type.get_length_field ().symbol); + /* add internal resize method */ + new_array_type.symbol.add (new_array_type.get_resize_method ().name, new_array_type.get_resize_method ().symbol); + + /* link the array type to the same source as the container type */ + new_array_type.source_reference = this.source_reference; + /* link the namespace */ + new_array_type.@namespace = this.@namespace; + + array_types.insert (rank.to_string (), new_array_type); + + array_type = new_array_type; + } + + return array_type; + } + + /** + * Checks whether this data type is a subtype of the specified data + * type. + * + * @param t a data type + * @return true if t is a supertype of this data type, false otherwise + */ + public virtual bool is_subtype_of (DataType! t) { + return false; + } + + /** + * Return the index of the specified type parameter name. + */ + public virtual int get_type_parameter_index (string! name) { + return -1; + } +} diff --git a/vala/valadeclarationstatement.vala b/vala/valadeclarationstatement.vala new file mode 100644 index 000000000..44b5172d6 --- /dev/null +++ b/vala/valadeclarationstatement.vala @@ -0,0 +1,51 @@ +/* valadeclarationstatement.vala + * + * Copyright (C) 2006 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 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 local variable declaration statement in the source code. + */ +public class Vala.DeclarationStatement : Statement { + /** + * The local variable declaration. + */ + public LocalVariableDeclaration! declaration { get; set construct; } + + /** + * Creates a new declaration statement. + * + * @param decl local variable declaration + * @param source reference to source code + * @return newly created declaration statement + */ + public DeclarationStatement (LocalVariableDeclaration! decl, SourceReference source) { + declaration = decl; + source_reference = source; + } + + public override void accept (CodeVisitor! visitor) { + declaration.accept (visitor); + + visitor.visit_declaration_statement (this); + } +} diff --git a/vala/valadestructor.vala b/vala/valadestructor.vala new file mode 100644 index 000000000..726639f1e --- /dev/null +++ b/vala/valadestructor.vala @@ -0,0 +1,67 @@ +/* valadestructor.vala + * + * Copyright (C) 2006 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 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 class or instance destructor. + */ +public class Vala.Destructor : CodeNode { + /** + * The body of this constructor. + */ + public Statement body { get; set; } + + private bool _instance = true; + + /** + * Specifies whether this is an instance or a class destructor. + */ + public bool instance { + get { + return _instance; + } + set { + _instance = value; + } + } + + /** + * Creates a new destructor. + * + * @param source reference to source code + * @return newly created destructor + */ + public Destructor (SourceReference source) { + source_reference = source; + } + + public override void accept (CodeVisitor! visitor) { + visitor.visit_begin_destructor (this); + + if (body != null) { + body.accept (visitor); + } + + visitor.visit_end_destructor (this); + } +} diff --git a/vala/valadostatement.vala b/vala/valadostatement.vala new file mode 100644 index 000000000..92ea9e99b --- /dev/null +++ b/vala/valadostatement.vala @@ -0,0 +1,78 @@ +/* valadostatement.vala + * + * Copyright (C) 2006 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 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 do iteration statement in the source code. + */ +public class Vala.DoStatement : Statement { + /** + * Specifies the loop body. + */ + public Statement body { get; set; } + + /** + * Specifies the loop condition. + */ + public Expression! condition { + get { + return _condition; + } + set construct { + _condition = value; + _condition.parent_node = this; + } + } + + private Expression! _condition; + + /** + * Creates a new do statement. + * + * @param cond loop condition + * @param body loop body + * @param source reference to source code + * @return newly created do statement + */ + public DoStatement (Statement! _body, Expression! cond, SourceReference source) { + body = _body; + condition = cond; + source_reference = source; + } + + public override void accept (CodeVisitor! visitor) { + body.accept (visitor); + + condition.accept (visitor); + + visitor.visit_end_full_expression (condition); + + visitor.visit_do_statement (this); + } + + public override void replace (CodeNode! old_node, CodeNode! new_node) { + if (condition == old_node) { + condition = (Expression) new_node; + } + } +} diff --git a/vala/valaelementaccess.vala b/vala/valaelementaccess.vala new file mode 100644 index 000000000..6b2825a95 --- /dev/null +++ b/vala/valaelementaccess.vala @@ -0,0 +1,60 @@ +/* valaelementaccess.vala + * + * Copyright (C) 2006 Raffaele Sandrini + * + * 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 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: + * Raffaele Sandrini <rasa@gmx.ch> + */ + +using GLib; + +/** + * Represents an array access expression e.g. "a[1,2]". + */ +public class Vala.ElementAccess : Expression { + /** + * Expression representing the container on wich we want to access. + */ + public Expression! container { get; set; } + + /** + * Expressions representing the indices we want to access inside the container. + */ + private List<Expression>! indices; + + public void append_index (Expression! index) { + indices.append (index); + } + + public ref List<weak Expression> get_indices () { + return indices.copy (); + } + + public ElementAccess (Expression _container, SourceReference source) { + container = _container; + source_reference = source; + } + + public override void accept (CodeVisitor! visitor) { + container.accept (visitor); + foreach (Expression e in indices) { + e.accept (visitor); + } + + visitor.visit_element_access (this); + } +} diff --git a/vala/valaemptystatement.vala b/vala/valaemptystatement.vala new file mode 100644 index 000000000..9dd75fe1b --- /dev/null +++ b/vala/valaemptystatement.vala @@ -0,0 +1,42 @@ +/* valaemptystatement.vala + * + * Copyright (C) 2006 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 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; + +/** + * An empty statement. + */ +public class Vala.EmptyStatement : Statement { + /** + * Creates a new empty statement. + * + * @param source reference to source code + * @return newly created empty statement + */ + public EmptyStatement (SourceReference source) { + source_reference = source; + } + + public override void accept (CodeVisitor! visitor) { + visitor.visit_empty_statement (this); + } +} diff --git a/vala/valaenum.vala b/vala/valaenum.vala new file mode 100644 index 000000000..a759c00cd --- /dev/null +++ b/vala/valaenum.vala @@ -0,0 +1,152 @@ +/* valaenum.vala + * + * Copyright (C) 2006 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 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 an enum declaration in the source code. + */ +public class Vala.Enum : DataType { + private List<EnumValue> values; + private string cname; + private string cprefix; + + /** + * Creates a new enum. + * + * @param name type name + * @param source reference to source code + * @return newly created enum + */ + public Enum (string! _name, SourceReference source = null) { + name = _name; + source_reference = source; + } + + /** + * Appends the specified enum value to the list of values. + * + * @param value an enum value + */ + public void add_value (EnumValue! value) { + values.append (value); + } + + public override void accept (CodeVisitor! visitor) { + visitor.visit_begin_enum (this); + + foreach (EnumValue value in values) { + value.accept (visitor); + } + + visitor.visit_end_enum (this); + } + + public override string get_cname (bool const_type = false) { + if (cname == null) { + cname = "%s%s".printf (@namespace.get_cprefix (), name); + } + return cname; + } + + public override ref string get_upper_case_cname (string infix) { + return "%s%s".printf (@namespace.get_lower_case_cprefix (), Namespace.camel_case_to_lower_case (name)).up (); + } + + public override bool is_reference_type () { + return false; + } + + private void set_cname (string! cname) { + this.cname = cname; + } + + /** + * Returns the string to be prepended to the name of members of this + * enum when used in C code. + * + * @return the prefix to be used in C code + */ + public string! get_cprefix () { + if (cprefix == null) { + cprefix = "%s_".printf (get_upper_case_cname (null)); + } + return cprefix; + } + + /** + * Sets the string to be prepended to the name of members of this enum + * when used in C code. + * + * @param cprefix the prefix to be used in C code + */ + public void set_cprefix (string! cprefix) { + this.cprefix = cprefix; + } + + private void process_ccode_attribute (Attribute! a) { + if (a.has_argument ("cname")) { + set_cname (a.get_string ("cname")); + } + if (a.has_argument ("cprefix")) { + set_cprefix (a.get_string ("cprefix")); + } + if (a.has_argument ("cheader_filename")) { + var val = a.get_string ("cheader_filename"); + foreach (string filename in val.split (",")) { + add_cheader_filename (filename); + } + } + } + + /** + * Process all associated attributes. + */ + public void process_attributes () { + foreach (Attribute a in attributes) { + if (a.name == "CCode") { + process_ccode_attribute (a); + } + } + } + + public override string get_type_id () { + // FIXME: use GType-registered enums + return "G_TYPE_INT"; + } + + public override string get_marshaller_type_name () { + return "ENUM"; + } + + public override string get_get_value_function () { + return "g_value_get_enum"; + } + + public override string get_set_value_function () { + return "g_value_set_enum"; + } + + public override string get_default_value () { + return "0"; + } +} diff --git a/vala/valaenumvalue.vala b/vala/valaenumvalue.vala new file mode 100644 index 000000000..740983ef2 --- /dev/null +++ b/vala/valaenumvalue.vala @@ -0,0 +1,79 @@ +/* valaenumvalue.vala + * + * Copyright (C) 2006 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 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 an enum member in the source code. + */ +public class Vala.EnumValue : CodeNode { + /** + * The symbol name of this enum value. + */ + public string! name { get; set construct; } + + /** + * Specifies the numerical representation of this enum value. + */ + public Expression value { get; set; } + + private string cname; + + /** + * Creates a new enum value. + * + * @param name enum value name + * @return newly created enum value + */ + public EnumValue (string! _name) { + name = _name; + } + + /** + * Creates a new enum value with the specified numerical representation. + * + * @param name enum value name + * @param value numerical representation + * @return newly created enum value + */ + public EnumValue.with_value (string! _name, Expression _value) { + name = _name; + value = _value; + } + + public override void accept (CodeVisitor! visitor) { + visitor.visit_enum_value (this); + } + + /** + * Returns the name of this enum value as it is used in C code. + * + * @return the name to be used in C code + */ + public string! get_cname () { + if (cname == null) { + var en = (Enum) symbol.parent_symbol.node; + cname = "%s%s".printf (en.get_cprefix (), name); + } + return cname; + } +} diff --git a/vala/valaexpression.vala b/vala/valaexpression.vala new file mode 100644 index 000000000..38a8a9f72 --- /dev/null +++ b/vala/valaexpression.vala @@ -0,0 +1,76 @@ +/* valaexpression.vala + * + * Copyright (C) 2006-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 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; + +/** + * Base class for all code nodes that might be used as an expression. + */ +public abstract class Vala.Expression : CodeNode { + /** + * The static type of this expression. + * + * The semantic analyzer computes this value. + */ + public TypeReference static_type { get; set; } + + /* + * The static type this expression is expected to have. + * + * The semantic analyzer computes this value, lambda expressions use it. + */ + public TypeReference expected_type { get; set; } + + /** + * The symbol this expression refers to. + */ + public Symbol symbol_reference { get; set; } + + /** + * Specifies that this expression transfers ownership without a receiver + * being present. + * + * The memory manager computes this value, the code generator uses it. + */ + public bool ref_leaked { get; set; } + + /** + * Specifies that this expression is expected to transfer ownership but + * doesn't. + * + * The memory manager computes this value, the code generator uses it. + */ + public bool ref_missing { get; set; } + + /** + * Specifies that this expression successfully transfers ownership. + */ + public bool ref_sink { get; set; } + + /** + * Contains all temporary variables this expression requires for + * execution. + * + * The code generator sets and uses them for memory management. + */ + public List<VariableDeclarator> temp_vars; +} diff --git a/vala/valaexpressionstatement.vala b/vala/valaexpressionstatement.vala new file mode 100644 index 000000000..472ec195f --- /dev/null +++ b/vala/valaexpressionstatement.vala @@ -0,0 +1,85 @@ +/* valaexpressionstatement.vala + * + * Copyright (C) 2006 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 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; + +/** + * A code statement that evaluates a given expression. The value computed by the + * expression, if any, is discarded. + */ +public class Vala.ExpressionStatement : Statement { + /** + * Specifies the expression to evaluate. + */ + public Expression! expression { + get { + return _expression; + } + set construct { + _expression = value; + _expression.parent_node = this; + } + } + + private Expression! _expression; + + /** + * Creates a new expression statement. + * + * @param expr expression to evaluate + * @param source reference to source code + * @return newly created expression statement + */ + public ExpressionStatement (Expression! expr, SourceReference source = null) { + expression = expr; + source_reference = source; + } + + public override void accept (CodeVisitor! visitor) { + expression.accept (visitor); + + visitor.visit_expression_statement (this); + } + + public override void replace (CodeNode! old_node, CodeNode! new_node) { + if (expression == old_node) { + expression = (Expression) new_node; + } + } + + 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/valafield.vala b/vala/valafield.vala new file mode 100644 index 000000000..884de7545 --- /dev/null +++ b/vala/valafield.vala @@ -0,0 +1,173 @@ +/* valafield.vala + * + * Copyright (C) 2006 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 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 type or namespace field. + */ +public class Vala.Field : Member, Invokable, Lockable { + /** + * The symbol name of this field. + */ + public string! name { get; set construct; } + + /** + * The data type of this field. + */ + public TypeReference! type_reference { get; set construct; } + + /** + * Specifies the expression to be used to initialize this field. + */ + public Expression initializer { get; set; } + + /** + * Specifies the accessibility of this field. Public accessibility + * doesn't limit access. Default accessibility limits access to this + * program or library. Private accessibility limits access to instances + * of the contained type. + */ + public MemberAccessibility access; + + /** + * Specifies whether this field may only be accessed with an instance of + * the contained type. + */ + public bool instance { + get { + return _instance; + } + set { + _instance = value; + } + } + + /** + * Specifies whether an array length field should implicitly be created + * if the field type is an array. + */ + public bool no_array_length { get; set; } + + private string cname; + private bool _instance = true; + + private bool lock_used = false; + + /** + * Creates a new field. + * + * @param name field name + * @param type field type + * @param init initializer expression + * @param source reference to source code + * @return newly created field + */ + public Field (string! _name, TypeReference! type, Expression init, SourceReference source) { + name = _name; + type_reference = type; + initializer = init; + source_reference = source; + } + + public override void accept (CodeVisitor! visitor) { + visitor.visit_member (this); + + type_reference.accept (visitor); + + if (initializer != null) { + initializer.accept (visitor); + } + + visitor.visit_field (this); + } + + /** + * Returns the name of this field as it is used in C code. + * + * @return the name to be used in C code + */ + public string! get_cname () { + if (cname == null) { + if (!instance && symbol.parent_symbol.node is DataType) { + var t = (DataType) symbol.parent_symbol.node; + cname = "%s_%s".printf (t.get_lower_case_cname (null), name); + } else { + cname = name; + } + } + return cname; + } + + private void set_cname (string! cname) { + this.cname = cname; + } + + private void process_ccode_attribute (Attribute! a) { + if (a.has_argument ("cname")) { + set_cname (a.get_string ("cname")); + } + } + + /** + * Process all associated attributes. + */ + public void process_attributes () { + foreach (Attribute a in attributes) { + if (a.name == "CCode") { + process_ccode_attribute (a); + } else if (a.name == "NoArrayLength") { + no_array_length = true; + } + } + } + + public ref List<weak FormalParameter> get_parameters () { + if (!is_invokable ()) { + return null; + } + + var cb = (Callback) type_reference.data_type; + return cb.get_parameters (); + } + + public TypeReference get_return_type () { + if (!is_invokable ()) { + return null; + } + + var cb = (Callback) type_reference.data_type; + return cb.return_type; + } + + public bool is_invokable () { + return (type_reference.data_type is Callback); + } + + public bool get_lock_used () { + return lock_used; + } + + public void set_lock_used (bool used) { + lock_used = used; + } +} diff --git a/vala/valaflags.vala b/vala/valaflags.vala new file mode 100644 index 000000000..d47cb8b82 --- /dev/null +++ b/vala/valaflags.vala @@ -0,0 +1,150 @@ +/* valaflags.vala + * + * Copyright (C) 2006-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 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 flags declaration in the source code. + */ +public class Vala.Flags : DataType { + private List<FlagsValue> values; + private string cname; + private string cprefix; + + /** + * Creates a new flags. + * + * @param name type name + * @param source reference to source code + * @return newly created flags + */ + public Flags (construct string! name, construct SourceReference source_reference = null) { + } + + /** + * Appends the specified flags value to the list of values. + * + * @param value a flags value + */ + public void add_value (FlagsValue! value) { + values.append (value); + } + + public override void accept (CodeVisitor! visitor) { + visitor.visit_begin_flags (this); + + foreach (FlagsValue value in values) { + value.accept (visitor); + } + + visitor.visit_end_flags (this); + } + + public override string get_cname (bool const_type = false) { + if (cname == null) { + cname = "%s%s".printf (@namespace.get_cprefix (), name); + } + return cname; + } + + public override ref string get_upper_case_cname (string infix) { + return "%s%s".printf (@namespace.get_lower_case_cprefix (), Namespace.camel_case_to_lower_case (name)).up (); + } + + public override bool is_reference_type () { + return false; + } + + private void set_cname (string! cname) { + this.cname = cname; + } + + /** + * Returns the string to be prepended to the name of members of this + * enum when used in C code. + * + * @return the prefix to be used in C code + */ + public string! get_cprefix () { + if (cprefix == null) { + cprefix = "%s_".printf (get_upper_case_cname (null)); + } + return cprefix; + } + + /** + * Sets the string to be prepended to the name of members of this enum + * when used in C code. + * + * @param cprefix the prefix to be used in C code + */ + public void set_cprefix (string! cprefix) { + this.cprefix = cprefix; + } + + private void process_ccode_attribute (Attribute! a) { + if (a.has_argument ("cname")) { + set_cname (a.get_string ("cname")); + } + if (a.has_argument ("cprefix")) { + set_cprefix (a.get_string ("cprefix")); + } + if (a.has_argument ("cheader_filename")) { + var val = a.get_string ("cheader_filename"); + foreach (string filename in val.split (",")) { + add_cheader_filename (filename); + } + } + } + + /** + * Process all associated attributes. + */ + public void process_attributes () { + foreach (Attribute a in attributes) { + if (a.name == "CCode") { + process_ccode_attribute (a); + } + } + } + + public override string get_type_id () { + // FIXME: use GType-registered flags + return "G_TYPE_INT"; + } + + public override string get_marshaller_type_name () { + return "FLAGS"; + } + + public override string get_get_value_function () { + return "g_value_get_flags"; + } + + public override string get_set_value_function () { + return "g_value_set_flags"; + } + + public override string get_default_value () { + return "0"; + } +} diff --git a/vala/valaflagsvalue.vala b/vala/valaflagsvalue.vala new file mode 100644 index 000000000..232bc322d --- /dev/null +++ b/vala/valaflagsvalue.vala @@ -0,0 +1,80 @@ +/* valaflagsvalue.vala + * + * Copyright (C) 2006 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 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 flags member in the source code. + */ +public class Vala.FlagsValue : CodeNode { + /** + * The symbol name of this flags value. + */ + public string! name { get; set construct; } + + /** + * Specifies the numerical representation of this flags value. + */ + public Expression value { get; set; } + + private string cname; + + /** + * Creates a new flags value. + * + * @param name flags value name + * @return newly created flags value + */ + public FlagsValue (string! _name) { + name = _name; + } + + /** + * Creates a new flags value with the specified numerical + * representation. + * + * @param name flags value name + * @param value numerical representation + * @return newly created flags value + */ + public FlagsValue.with_value (string! _name, Expression _value) { + name = _name; + value = _value; + } + + public override void accept (CodeVisitor! visitor) { + visitor.visit_flags_value (this); + } + + /** + * Returns the name of this flags value as it is used in C code. + * + * @return the name to be used in C code + */ + public string! get_cname () { + if (cname == null) { + var fl = (Flags) symbol.parent_symbol.node; + cname = "%s_%s".printf (fl.get_upper_case_cname (null), name); + } + return cname; + } +} diff --git a/vala/valaforeachstatement.vala b/vala/valaforeachstatement.vala new file mode 100644 index 000000000..f4ec9a962 --- /dev/null +++ b/vala/valaforeachstatement.vala @@ -0,0 +1,97 @@ +/* valaforeachstatement.vala + * + * Copyright (C) 2006 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 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 foreach statement in the source code. Foreach statements iterate + * over the elements of a collection. + */ +public class Vala.ForeachStatement : Statement { + /** + * Specifies the element type. + */ + public TypeReference! type_reference { get; set construct; } + + /** + * Specifies the element variable name. + */ + public string! variable_name { get; set construct; } + + /** + * Specifies the container. + */ + public Expression! collection { + get { + return _collection; + } + set construct { + _collection = value; + _collection.parent_node = this; + } + } + + /** + * Specifies the loop body. + */ + public Statement body { get; set; } + + /** + * Specifies the declarator for the generated element variable. + */ + public VariableDeclarator variable_declarator { get; set; } + + private Expression! _collection; + + /** + * Creates a new foreach statement. + * + * @param type element type + * @param id element variable name + * @param col loop body + * @param source reference to source code + * @return newly created foreach statement + */ + public ForeachStatement (TypeReference! type, string! id, Expression! col, Statement _body, SourceReference source) { + type_reference = type; + variable_name = id; + collection = col; + body = _body; + source_reference = source; + } + + public override void accept (CodeVisitor! visitor) { + visitor.visit_begin_foreach_statement (this); + + type_reference.accept (visitor); + collection.accept (visitor); + body.accept (visitor); + + visitor.visit_end_foreach_statement (this); + } + + public override void replace (CodeNode! old_node, CodeNode! new_node) { + if (collection == old_node) { + collection = (Expression) new_node; + } + } +} diff --git a/vala/valaformalparameter.vala b/vala/valaformalparameter.vala new file mode 100644 index 000000000..4b4d3cf71 --- /dev/null +++ b/vala/valaformalparameter.vala @@ -0,0 +1,120 @@ +/* valaformalparameter.vala + * + * Copyright (C) 2006-2007 Jürg Billeter, Raffaele Sandrini + * + * 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 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> + * Raffaele Sandrini <rasa@gmx.ch> + */ + +using GLib; + +/** + * Represents a formal parameter in method and callback signatures. + */ +public class Vala.FormalParameter : CodeNode, Invokable { + /** + * The parameter name. + */ + public string! name { get; set construct; } + + /** + * The parameter type. + */ + public TypeReference type_reference { get; set; } + + /** + * Specifies whether the methods accepts an indefinite number of + * parameters. + */ + public bool ellipsis { get; set; } + + /** + * Specifies the expression used when the caller doesn't supply an + * argument for this parameter. + */ + public Expression default_expression { get; set; } + + /** + * Specifies whether the array length should implicitly be passed + * if the parameter type is an array. + */ + public bool no_array_length { get; set; } + + /** + * Specifies whether this parameter holds a value to be assigned to a + * construct property. This is only allowed in CreationMethod headers. + */ + public bool construct_parameter { get; set; } + + /** + * Creates a new formal parameter. + * + * @param name parameter name + * @param type parameter type + * @param source reference to source code + * @return newly created formal parameter + */ + public FormalParameter (string! _name, TypeReference type, SourceReference source = null) { + name = _name; + type_reference = type; + source_reference = source; + } + + /** + * Creates a new ellipsis parameter representing an indefinite number of + * parameters. + */ + public FormalParameter.with_ellipsis (SourceReference source = null) { + ellipsis = true; + source_reference = source; + } + + 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); + } + + public ref List<weak FormalParameter> get_parameters () { + if (!is_invokable ()) { + return null; + } + + var cb = (Callback) type_reference.data_type; + return cb.get_parameters (); + } + + public TypeReference get_return_type () { + if (!is_invokable ()) { + return null; + } + + var cb = (Callback) type_reference.data_type; + return cb.return_type; + } + + public bool is_invokable () { + return (type_reference.data_type is Callback); + } +} diff --git a/vala/valaforstatement.vala b/vala/valaforstatement.vala new file mode 100644 index 000000000..e7d7238de --- /dev/null +++ b/vala/valaforstatement.vala @@ -0,0 +1,150 @@ +/* valaforstatement.vala + * + * Copyright (C) 2006-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 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 for iteration statement in the source code. + */ +public class Vala.ForStatement : Statement { + /** + * Specifies the loop condition. + */ + public Expression! condition { + get { + return _condition; + } + set construct { + _condition = value; + _condition.parent_node = this; + } + } + + /** + * Specifies the loop body. + */ + public Statement body { get; set; } + + private List<Expression> initializer; + private List<Expression> iterator; + + private Expression! _condition; + + /** + * Creates a new for statement. + * + * @param cond loop condition + * @param body loop body + * @param source reference to source code + * @return newly created for statement + */ + public ForStatement (Expression cond, Statement _body, SourceReference source) { + condition = cond; + body = _body; + source_reference = source; + } + + /** + * Appends the specified expression to the list of initializers. + * + * @param init an initializer expression + */ + public void add_initializer (Expression! init) { + init.parent_node = this; + initializer.append (init); + } + + /** + * Returns a copy of the list of initializers. + * + * @return initializer list + */ + public ref List<weak Expression> get_initializer () { + return initializer.copy (); + } + + /** + * Appends the specified expression to the iterator. + * + * @param iter an iterator expression + */ + public void add_iterator (Expression! iter) { + iter.parent_node = this; + iterator.append (iter); + } + + /** + * Returns a copy of the iterator. + * + * @return iterator + */ + public ref List<weak Expression> get_iterator () { + return iterator.copy (); + } + + public override void accept (CodeVisitor! visitor) { + foreach (Expression init_expr in initializer) { + init_expr.accept (visitor); + visitor.visit_end_full_expression (init_expr); + } + + condition.accept (visitor); + + visitor.visit_end_full_expression (condition); + + foreach (Expression it_expr in iterator) { + it_expr.accept (visitor); + visitor.visit_end_full_expression (it_expr); + } + + body.accept (visitor); + + visitor.visit_for_statement (this); + } + + public override void replace (CodeNode! old_node, CodeNode! new_node) { + weak List<Expression> iter; + + if (condition == old_node) { + condition = (Expression) new_node; + return; + } + + for (iter = initializer; iter != null; iter = iter.next) { + if (iter.data == old_node) { + weak List<Expression> silbling = iter.next; + initializer.delete_link (iter); + initializer.insert_before (silbling, new_node); + return; + } + } + + for (iter = iterator; iter != null; iter = iter.next) { + if (iter.data == old_node) { + weak List<Expression> silbling = iter.next; + iterator.delete_link (iter); + iterator.insert_before (silbling, new_node); + return; + } + } + } +} diff --git a/vala/valaifstatement.vala b/vala/valaifstatement.vala new file mode 100644 index 000000000..2912db849 --- /dev/null +++ b/vala/valaifstatement.vala @@ -0,0 +1,87 @@ +/* valaifstatement.vala + * + * Copyright (C) 2006 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 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 an if selection statement in the source code. + */ +public class Vala.IfStatement : Statement { + /** + * The boolean condition to evaluate. + */ + public Expression! condition { + get { + return _condition; + } + set construct { + _condition = value; + _condition.parent_node = this; + } + } + + /** + * The statement to be evaluated if the condition holds. + */ + public Block! true_statement { get; set construct; } + + /** + * The optional statement to be evaluated if the condition doesn't hold. + */ + public Block false_statement { get; set construct; } + + private Expression! _condition; + + /** + * Creates a new if statement. + * + * @param cond a boolean condition + * @param true_stmt statement to be evaluated if condition is true + * @param false_stmt statement to be evaluated if condition is false + * @return newly created if statement + */ + public IfStatement (Expression! cond, Block! true_stmt, Block false_stmt, SourceReference source) { + condition = cond; + true_statement = true_stmt; + false_statement = false_stmt; + source_reference = source; + } + + public override void accept (CodeVisitor! visitor) { + condition.accept (visitor); + + visitor.visit_end_full_expression (condition); + + true_statement.accept (visitor); + if (false_statement != null) { + false_statement.accept (visitor); + } + + visitor.visit_if_statement (this); + } + + public override void replace (CodeNode! old_node, CodeNode! new_node) { + if (condition == old_node) { + condition = (Expression) new_node; + } + } +} diff --git a/vala/valainitializerlist.vala b/vala/valainitializerlist.vala new file mode 100644 index 000000000..b20528bc4 --- /dev/null +++ b/vala/valainitializerlist.vala @@ -0,0 +1,68 @@ +/* valainitializerlist.vala + * + * Copyright (C) 2006 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 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 an array or struct initializer list in the source code. + */ +public class Vala.InitializerList : Expression { + private List<Expression> initializers; + + /** + * Appends the specified expression to this initializer list. + * + * @param expr an expression + */ + public void append (Expression! expr) { + initializers.append (expr); + } + + /** + * Returns a copy of the expression list. + * + * @return expression list + */ + public ref List<weak Expression> get_initializers () { + return initializers.copy (); + } + + /** + * Creates a new initializer list. + * + * @param source reference to source code + * @return newly created initializer list + */ + public InitializerList (SourceReference source) { + source_reference = source; + } + + public override void accept (CodeVisitor! visitor) { + visitor.visit_begin_initializer_list (this); + + foreach (Expression expr in initializers) { + expr.accept (visitor); + } + + visitor.visit_end_initializer_list (this); + } +} diff --git a/vala/valainstancecast.vala b/vala/valainstancecast.vala new file mode 100644 index 000000000..f154ce99f --- /dev/null +++ b/vala/valainstancecast.vala @@ -0,0 +1,58 @@ +/* valainstancecast.vala + * + * Copyright (C) 2006 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 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 runtime checked object instance cast expression in the C code. + */ +public class Vala.InstanceCast : CCodeFunctionCall { + /** + * The target type. + */ + public DataType! type_reference { get; set construct; } + + /** + * The expression to be cast. + */ + public CCodeExpression! inner { get; set construct; } + + /** + * Creates a new instance cast expression. + * + * @param expr an expression + * @param type the target type + * @return newly created instance cast expression + */ + public InstanceCast (CCodeExpression! expr, DataType! type) { + inner = expr; + type_reference = type; + } + + construct { + call = new CCodeIdentifier (type_reference.get_upper_case_cname (null)); + add_argument ((CCodeExpression) inner); + } +} + + + diff --git a/vala/valaintegerliteral.vala b/vala/valaintegerliteral.vala new file mode 100644 index 000000000..671381f11 --- /dev/null +++ b/vala/valaintegerliteral.vala @@ -0,0 +1,103 @@ +/* valaintegerliteral.vala + * + * Copyright (C) 2006 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 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 an integer literal in the source code. + */ +public class Vala.IntegerLiteral : Literal { + /** + * The literal value. + */ + public string! value { get; set; } + + /** + * Creates a new integer literal. + * + * @param i literal value + * @param source reference to source code + * @return newly created integer literal + */ + public IntegerLiteral (string! i, SourceReference source = null) { + value = i; + source_reference = source; + } + + public override void accept (CodeVisitor! visitor) { + visitor.visit_integer_literal (this); + } + + public override ref string! to_string () { + return value; + } + + /** + * Returns the type name of the value this literal represents. + * + * @return the name of literal type + */ + public string! get_type_name () { + string number = value; + + int l = 0; + while (number.has_suffix ("L")) { + l++; + number = number.ndup (number.size () - 1); + } + + bool u = false; + if (number.has_suffix ("U")) { + u = true; + number = number.ndup (number.size () - 1); + } + + int64 n = number.to_int64 (); + if (!u && n > 0x7fffffff) { + // value doesn't fit into signed 32-bit + l = 2; + } else if (u && n > 0xffffffff) { + // value doesn't fit into unsigned 32-bit + l = 2; + } + + if (l == 0) { + if (u) { + return "uint"; + } else { + return "int"; + } + } else if (l == 1) { + if (u) { + return "ulong"; + } else { + return "long"; + } + } else { + if (u) { + return "uint64"; + } else { + return "int64"; + } + } + } +} diff --git a/vala/valainterface.vala b/vala/valainterface.vala new file mode 100644 index 000000000..a9abea8f4 --- /dev/null +++ b/vala/valainterface.vala @@ -0,0 +1,309 @@ +/* valainterface.vala + * + * Copyright (C) 2006-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 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 class declaration in the source code. + */ +public class Vala.Interface : DataType { + /** + * Specifies whether this interface is static. Static interfaces are not + * available at run-time. They can be implemented by structs. + */ + public bool is_static { get; set; } + + private List<TypeParameter> type_parameters; + + private List<TypeReference> prerequisites; + + private List<Method> methods; + private List<Property> properties; + private List<Signal> signals; + + private string cname; + private string lower_case_csuffix; + private string type_cname; + private string type_id; + + /** + * Creates a new interface. + * + * @param name type name + * @param source reference to source code + * @return newly created interface + */ + public Interface (string! _name, SourceReference source = null) { + name = _name; + source_reference = source; + } + + /** + * Appends the specified parameter to the list of type parameters. + * + * @param p a type parameter + */ + public void add_type_parameter (TypeParameter! p) { + type_parameters.append (p); + p.type = this; + } + + /** + * Adds the specified interface or class to the list of prerequisites of + * this interface. + * + * @param type an interface or class reference + */ + public void add_prerequisite (TypeReference! type) { + prerequisites.append (type); + } + + /** + * Returns a copy of the base type list. + * + * @return list of base types + */ + public ref List<weak TypeReference> get_prerequisites () { + return prerequisites.copy (); + } + + /** + * Adds the specified method as a member to this interface. + * + * @param m a method + */ + public void add_method (Method! m) { + methods.append (m); + } + + /** + * Returns a copy of the list of methods. + * + * @return list of methods + */ + public ref List<weak Method> get_methods () { + return methods.copy (); + } + + /** + * Adds the specified property as a member to this interface. + * + * @param prop a property + */ + public void add_property (Property! prop) { + properties.append (prop); + } + + /** + * Returns a copy of the list of properties. + * + * @return list of properties + */ + public ref List<weak Property> get_properties () { + return properties.copy (); + } + + /** + * Adds the specified signal as a member to this interface. + * + * @param sig a signal + */ + public void add_signal (Signal! sig) { + signals.append (sig); + } + + /** + * Returns a copy of the list of signals. + * + * @return list of signals + */ + public ref List<weak Signal> get_signals () { + return signals.copy (); + } + + public override string get_cname (bool const_type = false) { + if (cname == null) { + cname = "%s%s".printf (@namespace.get_cprefix (), name); + } + return cname; + } + + /** + * Returns the string to be prepended to the name of members of this + * interface when used in C code. + * + * @return the suffix to be used in C code + */ + public string! get_lower_case_csuffix () { + if (lower_case_csuffix == null) { + lower_case_csuffix = Namespace.camel_case_to_lower_case (name); + } + return lower_case_csuffix; + } + + /** + * Sets the string to be prepended to the name of members of this + * interface when used in C code. + * + * @param csuffix the suffix to be used in C code + */ + public void set_lower_case_csuffix (string! csuffix) { + this.lower_case_csuffix = csuffix; + } + + public override ref string get_lower_case_cname (string infix) { + if (infix == null) { + infix = ""; + } + return "%s%s%s".printf (@namespace.get_lower_case_cprefix (), infix, get_lower_case_csuffix ()); + } + + public override ref string get_lower_case_cprefix () { + return "%s_".printf (get_lower_case_cname (null)); + } + + public override ref string get_upper_case_cname (string infix) { + return get_lower_case_cname (infix).up (); + } + + public override void accept (CodeVisitor! visitor) { + visitor.visit_begin_interface (this); + + foreach (TypeReference type in prerequisites) { + type.accept (visitor); + } + + foreach (TypeParameter p in type_parameters) { + p.accept (visitor); + } + + foreach (Method m in methods) { + m.accept (visitor); + } + + foreach (Property prop in properties) { + prop.accept (visitor); + } + + foreach (Signal sig in signals) { + sig.accept (visitor); + } + + visitor.visit_end_interface (this); + } + + public override bool is_reference_type () { + return true; + } + + public override bool is_reference_counting () { + return true; + } + + public override string get_ref_function () { + return "g_object_ref"; + } + + public override string get_unref_function () { + return "g_object_unref"; + } + + public override bool is_subtype_of (DataType! t) { + foreach (TypeReference prerequisite in prerequisites) { + if (prerequisite.data_type == t || + prerequisite.data_type.is_subtype_of (t)) { + return true; + } + } + + return false; + } + + private void process_ccode_attribute (Attribute! a) { + if (a.has_argument ("type_cname")) { + set_type_cname (a.get_string ("type_cname")); + } + } + + /** + * Process all associated attributes. + */ + public void process_attributes () { + foreach (Attribute a in attributes) { + if (a.name == "CCode") { + process_ccode_attribute (a); + } + } + } + + /** + * Returns the name of the type struct as it is used in C code. + * + * @return the type struct name to be used in C code + */ + public string get_type_cname () { + if (type_cname == null) { + type_cname = "%sIface".printf (get_cname ()); + } + return type_cname; + } + + /** + * Sets the name of the type struct as it is used in C code. + * + * @param type_cname the type struct name to be used in C code + */ + public void set_type_cname (string! type_cname) { + this.type_cname = type_cname; + } + + public override string get_marshaller_type_name () { + return "OBJECT"; + } + + public override string get_get_value_function () { + return "g_value_get_object"; + } + + public override string get_set_value_function () { + return "g_value_set_object"; + } + + public override string get_type_id () { + if (type_id == null) { + type_id = get_upper_case_cname ("TYPE_"); + } + + return type_id; + } + + public override int get_type_parameter_index (string! name) { + int i = 0; + foreach (TypeParameter parameter in type_parameters) { + if (parameter.name == name) { + return i; + } + i++; + } + return -1; + } +} diff --git a/vala/valainterfaceregisterfunction.vala b/vala/valainterfaceregisterfunction.vala new file mode 100644 index 000000000..7b9a94d07 --- /dev/null +++ b/vala/valainterfaceregisterfunction.vala @@ -0,0 +1,83 @@ +/* valainterfaceregisterfunction.vala + * + * Copyright (C) 2006-2007 Jürg Billeter, Raffaele Sandrini + * + * 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 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> + * Raffaele Sandrini <rasa@gmx.ch> + */ + +using GLib; + +/** + * C function to register an interface at runtime. + */ +public class Vala.InterfaceRegisterFunction : TypeRegisterFunction { + /** + * Specifies the interface to be registered. + */ + public Interface! interface_reference { get; set construct; } + + public InterfaceRegisterFunction (Interface! iface) { + interface_reference = iface; + } + + public override DataType! get_type_declaration () { + return interface_reference; + } + + public override ref string! get_type_struct_name () { + return interface_reference.get_type_cname (); + } + + public override ref string! get_base_init_func_name () { + return "%s_base_init".printf (interface_reference.get_lower_case_cname (null)); + } + + public override ref string! get_class_init_func_name () { + return "NULL"; + } + + public override ref string! get_instance_struct_size () { + return "0"; + } + + public override ref string! get_instance_init_func_name () { + return "NULL"; + } + + public override ref string! get_parent_type_name () { + return "G_TYPE_INTERFACE"; + } + + public override ref CCodeFragment! get_type_interface_init_statements () { + var frag = new CCodeFragment (); + + /* register all prerequisites */ + foreach (TypeReference prereq_ref in interface_reference.get_prerequisites ()) { + var prereq = prereq_ref.data_type; + + var func = new CCodeFunctionCall (new CCodeIdentifier ("g_type_interface_add_prerequisite")); + func.add_argument (new CCodeIdentifier ("%s_type_id".printf (interface_reference.get_lower_case_cname (null)))); + func.add_argument (new CCodeIdentifier (prereq.get_type_id())); + + frag.append (new CCodeExpressionStatement (func)); + } + + return frag; + } +} diff --git a/vala/valainterfacewriter.vala b/vala/valainterfacewriter.vala new file mode 100644 index 000000000..e518ffcab --- /dev/null +++ b/vala/valainterfacewriter.vala @@ -0,0 +1,619 @@ +/* valainterfacewriter.vala + * + * Copyright (C) 2006-2007 Jürg Billeter, Raffaele Sandrini + * + * 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 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> + * Raffaele Sandrini <rasa@gmx.ch> + */ + +using GLib; + +/** + * Code visitor generating Vala API file for the public interface. + */ +public class Vala.InterfaceWriter : CodeVisitor { + private CodeContext context; + + File stream; + + int indent; + /* at begin of line */ + bool bol = true; + + bool internal_scope = false; + + string current_cheader_filename; + + /** + * Writes the public interface of the specified code context into the + * specified file. + * + * @param context a code context + * @param filename a relative or absolute filename + */ + public void write_file (CodeContext! context, string! filename) { + this.context = context; + + stream = File.open (filename, "w"); + + /* we're only interested in non-pkg source files */ + foreach (SourceFile file in context.get_source_files ()) { + if (!file.pkg) { + file.accept (this); + } + } + + stream = null; + } + + public override void visit_begin_namespace (Namespace! ns) { + if (ns.name == null) { + return; + } + + current_cheader_filename = ns.get_cheader_filename (); + + write_indent (); + write_string ("[CCode (cheader_filename = \"%s\")]".printf (current_cheader_filename)); + write_newline (); + + write_indent (); + write_string ("namespace "); + write_identifier (ns.name); + write_begin_block (); + } + + public override void visit_end_namespace (Namespace! ns) { + if (ns.name == null) { + return; + } + + write_end_block (); + write_newline (); + } + + public override void visit_begin_class (Class! cl) { + if (cl.access == MemberAccessibility.PRIVATE) { + internal_scope = true; + return; + } + + write_indent (); + + var first = true; + string cheaders; + foreach (string cheader in cl.get_cheader_filenames ()) { + if (first) { + cheaders = cheader; + first = false; + } else { + cheaders = "%s, %s".printf (cheaders, cheader); + } + } + write_string ("[CCode (cheader_filename = \"%s\")]".printf (cheaders)); + write_newline (); + + write_indent (); + write_string ("public "); + if (cl.is_abstract) { + write_string ("abstract "); + } + write_string ("class "); + write_identifier (cl.name); + + var base_types = cl.get_base_types (); + if (base_types != null) { + write_string (" : "); + + bool first = true; + foreach (TypeReference base_type in base_types) { + if (!first) { + write_string (", "); + } else { + first = false; + } + write_string (base_type.data_type.symbol.get_full_name ()); + } + } + write_begin_block (); + } + + public override void visit_end_class (Class! cl) { + if (cl.access == MemberAccessibility.PRIVATE) { + internal_scope = false; + return; + } + + write_end_block (); + write_newline (); + } + + public override void visit_begin_struct (Struct! st) { + if (st.access == MemberAccessibility.PRIVATE) { + internal_scope = true; + return; + } + + if (st.is_reference_type ()) { + write_indent (); + write_string ("[ReferenceType]"); + } + + write_indent (); + write_string ("public struct "); + write_identifier (st.name); + write_begin_block (); + } + + public override void visit_end_struct (Struct! st) { + if (st.access == MemberAccessibility.PRIVATE) { + internal_scope = false; + return; + } + + write_end_block (); + write_newline (); + } + + public override void visit_begin_interface (Interface! iface) { + if (iface.access == MemberAccessibility.PRIVATE) { + internal_scope = true; + return; + } + + write_indent (); + write_string ("public "); + write_string ("interface "); + write_identifier (iface.name); + + write_begin_block (); + } + + public override void visit_end_interface (Interface! iface) { + if (iface.access == MemberAccessibility.PRIVATE) { + internal_scope = false; + return; + } + + write_end_block (); + write_newline (); + } + + public override void visit_begin_enum (Enum! en) { + if (en.access == MemberAccessibility.PRIVATE) { + internal_scope = true; + return; + } + + write_indent (); + write_string ("[CCode (cprefix = \"%s\")]".printf (en.get_cprefix ())); + + write_indent (); + write_string ("public enum "); + write_identifier (en.name); + write_begin_block (); + } + + public override void visit_end_enum (Enum! en) { + if (en.access == MemberAccessibility.PRIVATE) { + internal_scope = false; + return; + } + + write_end_block (); + write_newline (); + } + + public override void visit_enum_value (EnumValue! ev) { + if (internal_scope) { + return; + } + + write_indent (); + write_identifier (ev.name); + write_string (","); + write_newline (); + } + + public override void visit_begin_flags (Flags! fl) { + if (fl.access == MemberAccessibility.PRIVATE) { + internal_scope = true; + return; + } + + write_indent (); + write_string ("[CCode (cprefix = \"%s\")]".printf (fl.get_cprefix ())); + + write_indent (); + write_string ("public flags "); + write_identifier (fl.name); + write_begin_block (); + } + + public override void visit_end_flags (Flags! fl) { + if (fl.access == MemberAccessibility.PRIVATE) { + internal_scope = false; + return; + } + + write_end_block (); + write_newline (); + } + + public override void visit_flags_value (FlagsValue! fv) { + if (internal_scope) { + return; + } + + write_indent (); + write_identifier (fv.name); + write_string (","); + write_newline (); + } + + public override void visit_constant (Constant! c) { + if (internal_scope) { + return; + } + + write_indent (); + write_string ("public const "); + write_string (c.type_reference.data_type.symbol.get_full_name ()); + + write_string (" "); + write_identifier (c.name); + write_string (";"); + write_newline (); + } + + public override void visit_field (Field! f) { + if (internal_scope || f.access == MemberAccessibility.PRIVATE) { + return; + } + + write_indent (); + write_string ("public "); + if (f.type_reference.data_type != null && + f.type_reference.data_type.is_reference_type () && + !f.type_reference.takes_ownership) { + write_string ("weak "); + } + write_string (f.type_reference.data_type.symbol.get_full_name ()); + + var type_args = f.type_reference.get_type_arguments (); + if (!(f.type_reference.data_type is Array) && type_args != null) { + write_string ("<"); + foreach (TypeReference type_arg in type_args) { + if (!type_arg.takes_ownership) { + write_string ("weak "); + } + write_string (type_arg.data_type.symbol.get_full_name ()); + } + write_string (">"); + } + + write_string (" "); + write_identifier (f.name); + write_string (";"); + write_newline (); + } + + private void write_params (List<FormalParameter> params) { + write_string ("("); + + bool first = true; + foreach (FormalParameter param in params) { + if (!first) { + write_string (", "); + } else { + first = false; + } + + if (param.ellipsis) { + write_string ("..."); + continue; + } + + if (param.type_reference.reference_to_value_type || + param.type_reference.takes_ownership) { + write_string ("ref "); + } else if (param.type_reference.is_out) { + write_string ("out "); + } + write_string (param.type_reference.data_type.symbol.get_full_name ()); + + var type_args = param.type_reference.get_type_arguments (); + if (!(param.type_reference.data_type is Array) && type_args != null) { + write_string ("<"); + foreach (TypeReference type_arg in type_args) { + if (type_arg.takes_ownership) { + write_string ("ref "); + } + write_string (type_arg.data_type.symbol.get_full_name ()); + } + write_string (">"); + } + + if (param.type_reference.non_null) { + write_string ("!"); + } + + write_string (" "); + write_identifier (param.name); + + if (param.default_expression != null) { + write_string (" = "); + write_string (param.default_expression.to_string ()); + } + } + + write_string (")"); + } + + public override void visit_begin_callback (Callback! cb) { + if (internal_scope || cb.access == MemberAccessibility.PRIVATE) { + return; + } + + write_indent (); + write_string ("public callback "); + + var type = cb.return_type.data_type; + if (type == null) { + write_string ("void"); + } else { + if (cb.return_type.transfers_ownership) { + write_string ("ref "); + } + write_string (cb.return_type.data_type.symbol.get_full_name ()); + } + + write_string (" "); + write_identifier (cb.name); + + write_string (" "); + + write_params (cb.get_parameters ()); + + write_string (";"); + + write_newline (); + } + + public override void visit_begin_method (Method! m) { + if (internal_scope || m.access == MemberAccessibility.PRIVATE || m.overrides) { + return; + } + + if (m.no_array_length) { + bool array_found = (m.return_type != null && m.return_type.data_type is Array); + foreach (FormalParameter param in m.get_parameters ()) { + if (param.type_reference != null && param.type_reference.data_type is Array) { + array_found = true; + break; + } + } + if (array_found) { + write_indent (); + write_string ("[NoArrayLength]"); + } + } + if (m.instance_last) { + write_indent (); + write_string ("[InstanceLast]"); + } + if (m.instance_by_reference) { + write_indent (); + write_string ("[InstanceByReference]"); + } + if (m.get_cname () != m.get_default_cname ()) { + write_indent (); + write_string ("[CCode (cname = \"%s\")]".printf (m.get_cname ())); + } + + write_indent (); + write_string ("public"); + + if (m is CreationMethod) { + write_string (" "); + var datatype = (DataType) m.symbol.parent_symbol.node; + write_identifier (datatype.name); + + if (m.name != null) { + write_string ("."); + write_identifier (m.name); + } + } else if (!m.instance) { + write_string (" static"); + } else if (m.is_abstract) { + write_string (" abstract"); + } else if (m.is_virtual) { + write_string (" virtual"); + } + + if (!(m is CreationMethod)) { + write_string (" "); + + var type = m.return_type.data_type; + if (type == null) { + write_string ("void"); + } else { + if (m.return_type.transfers_ownership) { + } else if ((m.return_type.data_type != null && m.return_type.data_type.is_reference_type ()) || m.return_type.type_parameter != null) { + write_string ("weak "); + } + write_string (m.return_type.data_type.symbol.get_full_name ()); + if (m.return_type.non_null) { + write_string ("!"); + } + } + + write_string (" "); + write_identifier (m.name); + } + + write_string (" "); + + write_params (m.get_parameters ()); + + write_string (";"); + + write_newline (); + } + + public override void visit_begin_creation_method (CreationMethod! m) { + visit_begin_method (m); + } + + public override void visit_begin_property (Property! prop) { + if (internal_scope) { + return; + } + + if (prop.no_accessor_method) { + write_indent (); + write_string ("[NoAccessorMethod]"); + } + + write_indent (); + write_string ("public "); + if (!prop.type_reference.takes_ownership) { + write_string ("weak "); + } + write_string (prop.type_reference.data_type.symbol.get_full_name ()); + + var type_args = prop.type_reference.get_type_arguments (); + if (!(prop.type_reference.data_type is Array) && type_args != null) { + write_string ("<"); + foreach (TypeReference type_arg in type_args) { + if (!type_arg.takes_ownership) { + write_string ("weak "); + } + write_string (type_arg.data_type.symbol.get_full_name ()); + } + write_string (">"); + } + + write_string (" "); + write_identifier (prop.name); + write_string (" {"); + if (prop.get_accessor != null) { + write_string (" get;"); + } + if (prop.set_accessor != null) { + if (prop.set_accessor.writable) { + write_string (" set"); + } + if (prop.set_accessor.construction) { + write_string (" construct"); + } + write_string (";"); + } + write_string (" }"); + write_newline (); + } + + public override void visit_begin_signal (Signal! sig) { + if (internal_scope || sig.access == MemberAccessibility.PRIVATE) { + return; + } + + if (sig.has_emitter) { + write_indent (); + write_string ("[HasEmitter]"); + } + + write_indent (); + write_string ("public signal "); + + var type = sig.return_type.data_type; + if (type == null) { + write_string ("void"); + } else { + if (sig.return_type.transfers_ownership) { + write_string ("ref "); + } + write_string (sig.return_type.data_type.symbol.get_full_name ()); + if (sig.return_type.non_null) { + write_string ("!"); + } + } + + write_string (" "); + write_identifier (sig.name); + + write_string (" "); + + write_params (sig.get_parameters ()); + + write_string (";"); + + write_newline (); + } + + private void write_indent () { + int i; + + if (!bol) { + stream.putc ('\n'); + } + + for (i = 0; i < indent; i++) { + stream.putc ('\t'); + } + + bol = false; + } + + private void write_identifier (string! s) { + if (s == "base" || s == "callback" || s == "class" || + s == "construct" || s == "flags" || s == "foreach" || + s == "in" || s == "interface" || s == "lock" || + s == "namespace" || s == "out" || s == "ref") { + stream.putc ('@'); + } + write_string (s); + } + + private void write_string (string! s) { + stream.printf ("%s", s); + bol = false; + } + + private void write_newline () { + stream.putc ('\n'); + bol = true; + } + + private void write_begin_block () { + if (!bol) { + stream.putc (' '); + } else { + write_indent (); + } + stream.putc ('{'); + write_newline (); + indent++; + } + + private void write_end_block () { + indent--; + write_indent (); + stream.printf ("}"); + } +} diff --git a/vala/valainvocationexpression.vala b/vala/valainvocationexpression.vala new file mode 100644 index 000000000..8255d76e3 --- /dev/null +++ b/vala/valainvocationexpression.vala @@ -0,0 +1,106 @@ +/* valainvocationexpression.vala + * + * Copyright (C) 2006 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 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 an invocation expression in the source code. + */ +public class Vala.InvocationExpression : Expression { + /** + * The method to call. + */ + public Expression! call { + get { + return _call; + } + set construct { + _call = value; + _call.parent_node = this; + } + } + + public Expression! _call; + + private List<Expression> argument_list; + + /** + * Creates a new invocation expression. + * + * @param call method to call + * @param source reference to source code + * @return newly created invocation expression + */ + public InvocationExpression (Expression! _call, SourceReference source = null) { + call = _call; + 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); + arg.parent_node = this; + } + + /** + * Returns a copy of the argument list. + * + * @return argument list + */ + public ref List<weak Expression> get_argument_list () { + return argument_list.copy (); + } + + public override void accept (CodeVisitor! visitor) { + call.accept (visitor); + + visitor.visit_begin_invocation_expression (this); + + // iterate over list copy as list may change in loop body + foreach (Expression expr in argument_list.copy ()) { + expr.accept (visitor); + } + + visitor.visit_end_invocation_expression (this); + } + + public override void replace (CodeNode! old_node, CodeNode! new_node) { + if (call == old_node) { + call = (Expression) new_node; + } + + weak List<Expression> l = argument_list.find (old_node); + if (l != null) { + if (new_node.parent_node != null) { + return; + } + + argument_list.insert_before (l, new_node); + argument_list.remove_link (l); + new_node.parent_node = this; + } + } +} diff --git a/vala/valainvokable.vala b/vala/valainvokable.vala new file mode 100644 index 000000000..f5dc56dc0 --- /dev/null +++ b/vala/valainvokable.vala @@ -0,0 +1,49 @@ +/* valainvokable.vala + * + * Copyright (C) 2006-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 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 possibly invokable code object. + */ +public interface Vala.Invokable /* : CodeNode */ { + /** + * Returns whether this code object is invokable. + * + * @return true if invokable, false otherwise + */ + public abstract bool is_invokable (); + + /** + * Returns the return type of this invokable. + * + * @return return type + */ + public abstract TypeReference get_return_type (); + + /** + * Returns copy of the list of invocation parameters. + * + * @return parameter list + */ + public abstract ref List<weak FormalParameter> get_parameters (); +} diff --git a/vala/valalambdaexpression.vala b/vala/valalambdaexpression.vala new file mode 100644 index 000000000..03dbae637 --- /dev/null +++ b/vala/valalambdaexpression.vala @@ -0,0 +1,109 @@ +/* valalambdaexpression.vala + * + * Copyright (C) 2006 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 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 lambda expression in the source code. Lambda expressions are + * anonymous methods with implicitly typed parameters. + */ +public class Vala.LambdaExpression : Expression { + /** + * The expression body of this lambda expression. Only one of + * expression_body or statement_body may be set. + */ + public Expression expression_body { get; set; } + + /** + * The statement body of this lambda expression. Only one of + * expression_body or statement_body may be set. + */ + public Block statement_body { get; set; } + + /** + * The generated method. + */ + public Method method { get; set; } + + private List<string> parameters; + + /** + * Creates a new lambda expression. + * + * @param body expression body + * @param source reference to source code + * @return newly created lambda expression + */ + public LambdaExpression (Expression! body, SourceReference source) { + expression_body = body; + source_reference = source; + } + + /** + * Creates a new lambda expression with statement body. + * + * @param body statement body + * @param source reference to source code + * @return newly created lambda expression + */ + public LambdaExpression.with_statement_body (Block! body, SourceReference source) { + statement_body = body; + source_reference = source; + } + + /** + * Appends implicitly typed parameter. + * + * @param param parameter name + */ + public void add_parameter (string! param) { + parameters.append (param); + } + + /** + * Returns copy of parameter list. + * + * @return parameter list + */ + public ref List<weak string> get_parameters () { + return parameters.copy (); + } + + public override void accept (CodeVisitor! visitor) { + visitor.visit_begin_lambda_expression (this); + + if (method == null) { + if (expression_body != null) { + expression_body.accept (visitor); + visitor.visit_end_full_expression (expression_body); + } else if (statement_body != null) { + statement_body.accept (visitor); + } + } + + visitor.visit_end_lambda_expression (this); + + if (method != null) { + method.accept (visitor); + } + } +} diff --git a/vala/valaliteral.vala b/vala/valaliteral.vala new file mode 100644 index 000000000..01886bf9f --- /dev/null +++ b/vala/valaliteral.vala @@ -0,0 +1,33 @@ +/* valaliteral.vala + * + * Copyright (C) 2006-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 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; + +/** + * Base class for all literals in the source code. + */ +public abstract class Vala.Literal : CodeNode { + /** + * Specifies the type of this literal. + */ + public TypeReference static_type { get; set; } +} diff --git a/vala/valaliteralexpression.vala b/vala/valaliteralexpression.vala new file mode 100644 index 000000000..af96424f6 --- /dev/null +++ b/vala/valaliteralexpression.vala @@ -0,0 +1,55 @@ +/* valaliteralexpression.vala + * + * Copyright (C) 2006 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 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 literal expression in the source code. + */ +public class Vala.LiteralExpression : Expression { + /** + * The literal. + */ + public Literal literal { get; construct; } + + /** + * Creates a new literal expression. + * + * @param literal a literal + * @param source reference to source code + * @return newly created literal expression + */ + public LiteralExpression (Literal! _literal, SourceReference source = null) { + literal = _literal; + source_reference = source; + } + + public override void accept (CodeVisitor! visitor) { + literal.accept (visitor); + + visitor.visit_literal_expression (this); + } + + public override ref string! to_string () { + return literal.to_string (); + } +} diff --git a/vala/valalocalvariabledeclaration.vala b/vala/valalocalvariabledeclaration.vala new file mode 100644 index 000000000..acf9427df --- /dev/null +++ b/vala/valalocalvariabledeclaration.vala @@ -0,0 +1,90 @@ +/* valalocalvariabledeclaration.vala + * + * Copyright (C) 2006 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 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 local variable declaration in the source code. + */ +public class Vala.LocalVariableDeclaration : CodeNode { + /** + * The type of the local variable. + */ + public TypeReference type_reference { get; set; } + + private List<VariableDeclarator> variable_declarators; + + /** + * Creates a new local variable declaration. + * + * @param type type of the variable + * @param source reference to source code + * @return newly created local variable declaration + */ + public LocalVariableDeclaration (TypeReference type, SourceReference source) { + type_reference = type; + source_reference = source; + } + + /** + * Creates a new implicitly typed local variable declaration. The type + * of the variable is inferred from the expression used to initialize + * the variable. + * + * @param source reference to source code + * @return newly created local variable declaration + */ + public LocalVariableDeclaration.var_type (SourceReference source) { + source_reference = source; + } + + /** + * Add the specified variable declarator to this local variable + * declaration. + * + * @param declarator a variable declarator + */ + public void add_declarator (VariableDeclarator! declarator) { + variable_declarators.append (declarator); + } + + /** + * Returns a copy of the list of variable declarators. + * + * @return variable declarator list + */ + public ref List<weak VariableDeclarator> get_variable_declarators () { + return variable_declarators.copy (); + } + + public override void accept (CodeVisitor! visitor) { + if (type_reference != null) { + type_reference.accept (visitor); + } + + foreach (VariableDeclarator decl in variable_declarators) { + decl.accept (visitor); + } + + visitor.visit_local_variable_declaration (this); + } +} diff --git a/vala/valalockable.vala b/vala/valalockable.vala new file mode 100644 index 000000000..69bcae50f --- /dev/null +++ b/vala/valalockable.vala @@ -0,0 +1,36 @@ +/* valalockable.vala + * + * Copyright (C) 2006 Raffaele Sandrini + * + * 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 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: + * Raffaele Sandrini <rasa@gmx.ch> + */ + +/** + * Represents a lockable object. + */ +public interface Vala.Lockable { + /** + * Indicates a specific lockable object beeing actually locked somewhere. + */ + public abstract bool get_lock_used (); + + /** + * Set this lockable object as beeing locked somewhere. + */ + public abstract void set_lock_used (bool used); +} diff --git a/vala/valalockstatement.vala b/vala/valalockstatement.vala new file mode 100644 index 000000000..775725e08 --- /dev/null +++ b/vala/valalockstatement.vala @@ -0,0 +1,50 @@ +/* valalockstatement.vala + * + * Copyright (C) 2006 Raffaele Sandrini + * + * 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 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: + * Raffaele Sandrini <rasa@gmx.ch> + */ + +using GLib; + +/** + * Represents a lock statement e.g. "lock (a) { f(a) }". + */ +public class Vala.LockStatement : Statement { + /** + * Expression representing the resource to be locked. + */ + public Expression! resource { get; set construct; } + + /** + * The statement during its execution the resource is locked. + */ + public Statement! body { get; set construct; } + + public LockStatement (Expression _resource, Statement _body, SourceReference source) { + resource = _resource; + body = _body; + source_reference = source; + } + + public override void accept (CodeVisitor! visitor) { + resource.accept (visitor); + body.accept (visitor); + visitor.visit_lock_statement (this); + } +} diff --git a/vala/valamember.vala b/vala/valamember.vala new file mode 100644 index 000000000..651a98b1e --- /dev/null +++ b/vala/valamember.vala @@ -0,0 +1,30 @@ +/* valamember.vala + * + * Copyright (C) 2006 Raffaele Sandrini + * + * 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 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: + * Raffaele Sandrini <rasa@gmx.ch> + */ + +/** + * Represents a general class member. + */ +public class Vala.Member : CodeNode { + public override void accept (CodeVisitor! visitor) { + visitor.visit_member (this); + } +} diff --git a/vala/valamemberaccess.vala b/vala/valamemberaccess.vala new file mode 100644 index 000000000..d8052ee2d --- /dev/null +++ b/vala/valamemberaccess.vala @@ -0,0 +1,114 @@ +/* valamemberaccess.vala + * + * Copyright (C) 2006-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 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 an access to a type member in the source code. + */ +public class Vala.MemberAccess : Expression { + /** + * The parent of the member. + */ + public Expression inner { + get { + return _inner; + } + set { + _inner = value; + if (_inner != null) { + _inner.parent_node = this; + } + } + } + + /** + * The name of the member. + */ + public string! member_name { get; set construct; } + + private Expression _inner; + private List<TypeReference> type_argument_list; + + /** + * Creates a new member access expression. + * + * @param inner parent of the member + * @param member member name + * @param source reference to source code + * @return newly created member access expression + */ + public MemberAccess (Expression _inner, string! member, SourceReference source = null) { + inner = _inner; + member_name = member; + source_reference = source; + } + + public MemberAccess.simple (string! member, SourceReference source = null) { + 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<weak TypeReference> get_type_arguments () { + return type_argument_list.copy (); + } + + public override void accept (CodeVisitor! visitor) { + if (inner != null) { + inner.accept (visitor); + } + + foreach (TypeReference type_arg in type_argument_list) { + type_arg.accept (visitor); + } + + 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); + } + } + + public override void replace (CodeNode! old_node, CodeNode! new_node) { + if (inner == old_node) { + inner = (Expression) new_node; + } + } +} diff --git a/vala/valamemberaccessibility.vala b/vala/valamemberaccessibility.vala new file mode 100644 index 000000000..b8912194c --- /dev/null +++ b/vala/valamemberaccessibility.vala @@ -0,0 +1,30 @@ +/* valamemberaccessibility.vala + * + * Copyright (C) 2006 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 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; + +public enum Vala.MemberAccessibility { + PRIVATE, + INTERNAL, + PROTECTED, + PUBLIC +} diff --git a/vala/valamemorymanager.vala b/vala/valamemorymanager.vala new file mode 100644 index 000000000..4d1cca382 --- /dev/null +++ b/vala/valamemorymanager.vala @@ -0,0 +1,252 @@ +/* valamemorymanager.vala + * + * Copyright (C) 2006-2007 Jürg Billeter, Raffaele Sandrini + * + * 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 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> + * Raffaele Sandrini <rasa@gmx.ch> + */ + +using GLib; + +/** + * Code visitor analyzing memory usage. The memory manager finds leaked and + * copied references. + */ +public class Vala.MemoryManager : CodeVisitor { + Symbol current_symbol; + + /** + * Analyze memory usage in the specified code context. + * + * @param context a code context + */ + public void analyze (CodeContext! context) { + context.accept (this); + } + + private void visit_possibly_leaked_expression (Expression! expr) { + if (expr.static_type != null && + ((expr.static_type.data_type != null && + expr.static_type.data_type.is_reference_type ()) || + expr.static_type.type_parameter != null) && + expr.static_type.transfers_ownership) { + /* mark reference as leaked */ + expr.ref_leaked = true; + } + } + + private void visit_possibly_missing_copy_expression (Expression! expr) { + if (expr.static_type != null && + ((expr.static_type.data_type != null && + expr.static_type.data_type.is_reference_type ()) || + expr.static_type.type_parameter != null) && + !expr.static_type.transfers_ownership) { + /* mark reference as missing */ + expr.ref_missing = true; + } + } + + public override void visit_field (Field! f) { + if (f.initializer != null) { + if (f.type_reference.takes_ownership) { + visit_possibly_missing_copy_expression (f.initializer); + } else { + visit_possibly_leaked_expression (f.initializer); + } + } + } + + public override void visit_begin_method (Method! m) { + current_symbol = m.symbol; + } + + public override void visit_begin_creation_method (CreationMethod! m) { + current_symbol = m.symbol; + } + + public override void visit_begin_property (Property! prop) { + current_symbol = prop.symbol; + } + + public override void visit_named_argument (NamedArgument! n) { + visit_possibly_leaked_expression (n.argument); + } + + public override void visit_variable_declarator (VariableDeclarator! decl) { + if (decl.initializer != null) { + if (decl.type_reference.takes_ownership) { + visit_possibly_missing_copy_expression (decl.initializer); + } else { + visit_possibly_leaked_expression (decl.initializer); + } + } + } + + public override void visit_expression_statement (ExpressionStatement! stmt) { + visit_possibly_leaked_expression (stmt.expression); + } + + public override void visit_end_return_statement (ReturnStatement! stmt) { + if (stmt.return_expression != null) { + if (current_symbol.node is Method) { + var m = (Method) current_symbol.node; + + if (m.return_type.transfers_ownership) { + visit_possibly_missing_copy_expression (stmt.return_expression); + } else { + visit_possibly_leaked_expression (stmt.return_expression); + } + } else { + /* property get accessor */ + visit_possibly_leaked_expression (stmt.return_expression); + } + } + } + + public override void visit_member_access (MemberAccess! expr) { + if (expr.inner != null) { + visit_possibly_leaked_expression (expr.inner); + } + } + + public override void visit_end_invocation_expression (InvocationExpression! expr) { + List<weak FormalParameter> params; + + var msym = expr.call.symbol_reference; + if (msym.node is VariableDeclarator) { + var decl = (VariableDeclarator) msym.node; + var cb = (Callback) decl.type_reference.data_type; + params = cb.get_parameters (); + } else if (msym.node is FormalParameter) { + var param = (FormalParameter) msym.node; + var cb = (Callback) param.type_reference.data_type; + params = cb.get_parameters (); + } else if (msym.node is Field) { + var f = (Field) msym.node; + var cb = (Callback) f.type_reference.data_type; + params = cb.get_parameters (); + } else if (msym.node is Method) { + var m = (Method) msym.node; + params = m.get_parameters (); + } else if (msym.node is Signal) { + var sig = (Signal) msym.node; + params = sig.get_parameters (); + } + weak List<weak FormalParameter> params_it = params; + foreach (Expression arg in expr.get_argument_list ()) { + if (params_it != null) { + var param = (FormalParameter) params_it.data; + if (!param.ellipsis + && ((param.type_reference.data_type != null + && param.type_reference.data_type.is_reference_type ()) + || param.type_reference.type_parameter != null)) { + bool is_ref = param.type_reference.takes_ownership; + if (is_ref && param.type_reference.type_parameter != null) { + // TODO move this to semantic analyzer + if (expr.call is MemberAccess) { + var ma = (MemberAccess) expr.call; + ref TypeReference instance_type = ma.inner.static_type; + // trace type arguments back to the datatype where the method has been declared + while (instance_type.data_type != msym.parent_symbol.node) { + List<weak TypeReference> base_types = null; + if (instance_type.data_type is Class) { + var cl = (Class) instance_type.data_type; + base_types = cl.get_base_types (); + } else if (instance_type.data_type is Interface) { + var iface = (Interface) instance_type.data_type; + base_types = iface.get_prerequisites (); + } else { + Report.error (expr.source_reference, "internal error: unsupported generic type"); + expr.error = true; + return; + } + foreach (TypeReference base_type in base_types) { + if (SemanticAnalyzer.symbol_lookup_inherited (base_type.data_type.symbol, msym.name) != null) { + // construct a new type reference for the base type with correctly linked type arguments + var instance_base_type = new TypeReference (); + instance_base_type.data_type = base_type.data_type; + foreach (TypeReference type_arg in base_type.get_type_arguments ()) { + if (type_arg.type_parameter != null) { + // link to type argument of derived type + int param_index = instance_type.data_type.get_type_parameter_index (type_arg.type_parameter.name); + if (param_index == -1) { + Report.error (expr.source_reference, "internal error: unknown type parameter %s".printf (type_arg.type_parameter.name)); + expr.error = true; + return; + } + type_arg = instance_type.get_type_arguments ().nth_data (param_index); + } + instance_base_type.add_type_argument (type_arg); + } + instance_type = instance_base_type; + } + } + } + if (instance_type.data_type != msym.parent_symbol.node) { + Report.error (expr.source_reference, "internal error: generic type parameter tracing not supported yet"); + expr.error = true; + return; + } + int param_index = instance_type.data_type.get_type_parameter_index (param.type_reference.type_parameter.name); + if (param_index == -1) { + Report.error (expr.source_reference, "internal error: unknown type parameter %s".printf (param.type_reference.type_parameter.name)); + expr.error = true; + return; + } + var param_type = (TypeReference) instance_type.get_type_arguments ().nth_data (param_index); + if (param_type == null) { + Report.error (expr.source_reference, "internal error: no actual argument found for type parameter %s".printf (param.type_reference.type_parameter.name)); + expr.error = true; + return; + } + is_ref = param_type.takes_ownership; + } + } + + if (is_ref) { + visit_possibly_missing_copy_expression (arg); + } else { + visit_possibly_leaked_expression (arg); + } + } else { + visit_possibly_leaked_expression (arg); + } + + params_it = params_it.next; + } else { + visit_possibly_leaked_expression (arg); + } + } + } + + public override void visit_binary_expression (BinaryExpression! expr) { + visit_possibly_leaked_expression (expr.left); + visit_possibly_leaked_expression (expr.right); + } + + public override void visit_end_assignment (Assignment! a) { + if (a.left is PointerIndirection || (a.left.symbol_reference != null && a.left.symbol_reference.node is Signal)) { + } else { + if (a.left.static_type.takes_ownership) { + visit_possibly_missing_copy_expression (a.right); + } else { + visit_possibly_leaked_expression (a.right); + } + } + } +} diff --git a/vala/valamethod.vala b/vala/valamethod.vala new file mode 100644 index 000000000..0e9dd4e2e --- /dev/null +++ b/vala/valamethod.vala @@ -0,0 +1,322 @@ +/* valamethod.vala + * + * Copyright (C) 2006-2007 Jürg Billeter, Raffaele Sandrini + * + * 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 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> + * Raffaele Sandrini <rasa@gmx.ch> + */ + +using GLib; + +/** + * Represents a type or namespace method. + */ +public class Vala.Method : Member, Invokable { + /** + * The symbol name of this method. + */ + public string name { get; set; } + + /** + * The return type of this method. + */ + public TypeReference return_type { get; set; } + + public Block body { get; set; } + + /** + * Specifies the accessibility of this method. Public accessibility + * doesn't limit access. Default accessibility limits access to this + * program or library. Private accessibility limits access to instances + * of the contained type. + */ + public MemberAccessibility access; + + /** + * Specifies whether this method may only be called with an instance of + * the contained type. + */ + public bool instance { + get { + return _instance; + } + set { + _instance = value; + } + } + + /** + * Specifies whether this method is abstract. Abstract methods have no + * body, may only be specified within abstract classes, and must be + * overriden by derived non-abstract classes. + */ + public bool is_abstract { get; set; } + + /** + * Specifies whether this method is virtual. Virtual methods may be + * overridden by derived classes. + */ + public bool is_virtual { get; set; } + + /** + * Specifies whether this method overrides a virtual or abstract method + * of a base type. + */ + public bool overrides { get; set; } + + /** + * Specifies whether the C method returns a new instance pointer which + * may be different from the previous instance pointer. Only valid for + * imported methods. + */ + public bool returns_modified_pointer { get; set; } + + /** + * Specifies whether the instance pointer should be passed as the first + * or as the last argument in C code. Defaults to first. + */ + public bool instance_last { get; set; } + + /** + * Specifies whether the instance of a value type should be passed by + * reference. Only valid for instance methods of value types. + */ + public bool instance_by_reference { get; set; } + + /** + * Specifies the virtual or abstract method this method overrides. + * Reference must be weak as virtual methods set base_method to + * themselves. + */ + public weak Method base_method { get; set; } + + /** + * Specifies the abstract interface method this method implements. + */ + public Method base_interface_method { get; set; } + + /** + * Specifies the generated `this' parameter for instance methods. + */ + public FormalParameter this_parameter { get; set; } + + /** + * Specifies whether the array length should implicitly be passed + * if the parameter type is an array. + */ + public bool no_array_length { + get { + return _no_array_length; + } + set { + _no_array_length = value; + foreach (FormalParameter param in parameters) { + param.no_array_length = value; + } + } + } + + /** + * Specifies whether this method expects printf-style format arguments. + */ + public bool printf_format { get; set; } + + private bool _instance = true; + private List<FormalParameter> parameters; + private string cname; + private bool _no_array_length; + + /** + * Creates a new method. + * + * @param name method name + * @param return_type method return type + * @param source reference to source code + * @return newly created method + */ + public Method (string _name, TypeReference _return_type, SourceReference source = null) { + name = _name; + return_type = _return_type; + source_reference = source; + } + + /** + * Appends parameter to this method. + * + * @param param a formal parameter + */ + public void add_parameter (FormalParameter! param) { + if (no_array_length) { + param.no_array_length = true; + } + + parameters.append (param); + } + + public ref List<weak FormalParameter> get_parameters () { + return parameters.copy (); + } + + public TypeReference get_return_type () { + return return_type; + } + + public bool is_invokable () { + return true; + } + + public override void accept (CodeVisitor! visitor) { + visitor.visit_begin_method (this); + + if (return_type != null) { + return_type.accept (visitor); + } + + foreach (FormalParameter param in parameters) { + param.accept (visitor); + } + + if (body != null) { + body.accept (visitor); + } + + visitor.visit_end_method (this); + } + + /** + * Returns the interface name of this method as it is used in C code. + * + * @return the name to be used in C code + */ + public string! get_cname () { + if (cname == null) { + cname = get_default_cname (); + } + return cname; + } + + /** + * Returns the default interface name of this method as it is used in C + * code. + * + * @return the name to be used in C code by default + */ + public virtual ref string! get_default_cname () { + var parent = symbol.parent_symbol.node; + if (parent is DataType) { + if (name.has_prefix ("_")) { + return "_%s%s".printf (((DataType) parent).get_lower_case_cprefix (), name.offset (1)); + } else { + return "%s%s".printf (((DataType) parent).get_lower_case_cprefix (), name); + } + } else if (parent is Namespace) { + return "%s%s".printf (((Namespace) parent).get_lower_case_cprefix (), name); + } else { + return name; + } + } + + /** + * Returns the implementation name of this data type as it is used in C + * code. + * + * @return the name to be used in C code + */ + public ref string! get_real_cname () { + if (base_method != null || base_interface_method != null) { + var parent = (Class) symbol.parent_symbol.node; + return "%s_real_%s".printf (parent.get_lower_case_cname (null), name); + } else { + return get_cname (); + } + } + + /** + * Sets the name of this method as it is used in C code. + * + * @param cname the name to be used in C code + */ + public void set_cname (string cname) { + this.cname = cname; + } + + private void process_ccode_attribute (Attribute a) { + if (a.has_argument ("cname")) { + set_cname (a.get_string ("cname")); + } + } + + /** + * Process all associated attributes. + */ + public void process_attributes () { + foreach (Attribute a in attributes) { + if (a.name == "CCode") { + process_ccode_attribute (a); + } else if (a.name == "ReturnsModifiedPointer") { + returns_modified_pointer = true; + } else if (a.name == "InstanceLast") { + instance_last = true; + } else if (a.name == "InstanceByReference") { + instance_by_reference = true; + } else if (a.name == "FloatingReference") { + return_type.floating_reference = true; + } else if (a.name == "NoArrayLength") { + no_array_length = true; + } else if (a.name == "PrintfFormat") { + printf_format = true; + } + } + } + + /** + * Checks whether the arguments and return type of the specified method + * matches this method. + * + * @param m a method + * @return true if the specified method is compatible to this method + */ + public bool equals (Method! m2) { + if (!m2.return_type.equals (return_type)) { + return false; + } + + var method_params = m2.get_parameters (); + weak List<weak FormalParameter> method_params_it = method_params; + foreach (FormalParameter param in parameters) { + /* method may not expect less arguments */ + if (method_params_it == null) { + return false; + } + + var method_param = (FormalParameter) method_params_it.data; + if (!method_param.type_reference.equals (param.type_reference)) { + return false; + } + + method_params_it = method_params_it.next; + } + + /* method may not expect more arguments */ + if (method_params_it != null) { + return false; + } + + return true; + } +} diff --git a/vala/valanamedargument.vala b/vala/valanamedargument.vala new file mode 100644 index 000000000..cb7012d7c --- /dev/null +++ b/vala/valanamedargument.vala @@ -0,0 +1,59 @@ +/* valanamedargument.vala + * + * Copyright (C) 2006 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 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 named argument in the source code. A named argument may be used + * when creating objects and attributes where no parameter list exists. + */ +public class Vala.NamedArgument : CodeNode { + /** + * The name of a property. + */ + public string! name { get; set construct; } + + /** + * The expression the property should assign. + */ + public Expression! argument { get; set construct; } + + /** + * Creates a new named argument. + * + * @param name property name + * @param arg property value expression + * @param source reference to source code + * @return newly created named argument + */ + public NamedArgument (string! _name, Expression! arg, SourceReference source) { + name = _name; + argument = arg; + source_reference = source; + } + + public override void accept (CodeVisitor! visitor) { + argument.accept (visitor); + + visitor.visit_named_argument (this); + } +} diff --git a/vala/valanamespace.vala b/vala/valanamespace.vala new file mode 100644 index 000000000..3b63cba42 --- /dev/null +++ b/vala/valanamespace.vala @@ -0,0 +1,379 @@ +/* valanamespace.vala + * + * Copyright (C) 2006-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 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 namespace declaration in the source code. + */ +public class Vala.Namespace : CodeNode { + /** + * The name of this namespace. + */ + public string name { get; set; } + + private List<Class> classes; + private List<Interface> interfaces; + private List<Struct> structs; + private List<Enum> enums; + private List<Flags> flags_; + private List<Callback> callbacks; + private List<Constant> constants; + private List<Field> fields; + private List<Method> methods; + + private string cprefix; + private string lower_case_cprefix; + + private List<string> cheader_filenames; + + /** + * Creates a new namespace. + * + * @param name namespace name + * @param source reference to source code + * @return newly created namespace + */ + public Namespace (string _name, SourceReference source = null) { + name = _name; + source_reference = source; + } + + /** + * Adds the specified class to this namespace. + * + * @param cl a class + */ + public void add_class (Class! cl) { + classes.append (cl); + cl.@namespace = this; + } + + /** + * Removes the specified class from this namespace. + * + * @param cl a class + */ + public void remove_class (Class! cl) { + cl.@namespace = null; + classes.remove (cl); + } + + /** + * Adds the specified interface to this namespace. + * + * @param iface an interface + */ + public void add_interface (Interface! iface) { + interfaces.append (iface); + iface.@namespace = this; + } + + /** + * Adds the specified struct to this namespace. + * + * @param st a struct + */ + public void add_struct (Struct! st) { + structs.append (st); + st.@namespace = this; + } + + /** + * Adds the specified enum to this namespace. + * + * @param en an enum + */ + public void add_enum (Enum! en) { + enums.append (en); + en.@namespace = this; + } + + /** + * Adds the specified flags to this namespace. + * + * @param fl a flags + */ + public void add_flags (Flags! fl) { + flags_.append (fl); + fl.@namespace = this; + } + + /** + * Adds the specified callback to this namespace. + * + * @param cb a callback + */ + public void add_callback (Callback! cb) { + callbacks.append (cb); + cb.@namespace = this; + } + + /** + * Returns a copy of the list of structs. + * + * @return struct list + */ + public ref List<weak Struct> get_structs () { + return structs.copy (); + } + + /** + * Returns a copy of the list of classes. + * + * @return class list + */ + public ref List<weak Class> get_classes () { + return classes.copy (); + } + + /** + * Returns a copy of the list of interfaces. + * + * @return interface list + */ + public ref List<weak Interface> get_interfaces () { + return interfaces.copy (); + } + + /** + * Adds the specified constant to this namespace. + * + * @param constant a constant + */ + public void add_constant (Constant! constant) { + constants.append (constant); + } + + /** + * Adds the specified field to this namespace. + * + * @param f a field + */ + public void add_field (Field! f) { + fields.append (f); + } + + /** + * Adds the specified method to this namespace. + * + * @param m a method + */ + public void add_method (Method! m) { + methods.append (m); + } + + public override void accept (CodeVisitor! visitor) { + visitor.visit_begin_namespace (this); + + /* process enums and flags first to avoid order problems in C code */ + foreach (Enum en in enums) { + en.accept (visitor); + } + + foreach (Flags fl in flags_) { + fl.accept (visitor); + } + + foreach (Class cl in classes) { + cl.accept (visitor); + } + + foreach (Interface iface in interfaces) { + iface.accept (visitor); + } + + foreach (Struct st in structs) { + st.accept (visitor); + } + + foreach (Callback cb in callbacks) { + cb.accept (visitor); + } + + foreach (Constant c in constants) { + c.accept (visitor); + } + + foreach (Field f in fields) { + f.accept (visitor); + } + + foreach (Method m in methods) { + m.accept (visitor); + } + + visitor.visit_end_namespace (this); + } + + /** + * Converts a string from CamelCase to lower_case. + * + * @param camel_case a string in camel case + * @return the specified string converted to lower case + */ + public static ref string! camel_case_to_lower_case (string! camel_case) { + String result = new String (""); + + string i = camel_case; + + bool first = true; + while (i.len () > 0) { + unichar c = i.get_char (); + if (c.isupper () && !first) { + /* current character is upper case and + * we're not at the beginning */ + string t = i.prev_char (); + bool prev_upper = t.get_char ().isupper (); + t = i.next_char (); + bool next_upper = t.get_char ().isupper (); + if (!prev_upper || (i.len () >= 2 && !next_upper)) { + /* previous character wasn't upper case or + * next character isn't upper case*/ + int len = result.str.len (); + if (len != 1 && result.str.offset (len - 2).get_char () != '_') { + /* we're not creating 1 character words */ + result.append_c ('_'); + } + } + } + + result.append_unichar (c.tolower ()); + + first = false; + i = i.next_char (); + } + + return result.str; + } + + /** + * Returns the camel case string to be prepended to the name of members + * of this namespace when used in C code. + * + * @return the camel case prefix to be used in C code + */ + public string! get_cprefix () { + if (cprefix == null) { + if (name == null) { + cprefix = ""; + } else { + cprefix = name; + } + } + return cprefix; + } + + private void set_cprefix (string cprefix) { + this.cprefix = cprefix; + } + + /** + * Returns the lower case string to be prepended to the name of members + * of this namespace when used in C code. + * + * @return the lower case prefix to be used in C code + */ + public string! get_lower_case_cprefix () { + if (lower_case_cprefix == null) { + if (name == null) { + lower_case_cprefix = ""; + } else { + lower_case_cprefix = "%s_".printf (camel_case_to_lower_case (name)); + } + } + return lower_case_cprefix; + } + + private void set_lower_case_cprefix (string cprefix) { + this.lower_case_cprefix = cprefix; + } + + /** + * Returns a list of C header filenames users of this namespace must + * include. + * + * @return list of C header filenames for this namespace + */ + public ref List<weak string> get_cheader_filenames () { + if (cheader_filenames == null) { + cheader_filenames.append (source_reference.file.get_cinclude_filename ()); + } + return cheader_filenames.copy (); + } + + /** + * Returns the C header filename of this namespace. + * + * @return header filename + */ + public ref string get_cheader_filename () { + var s = new String (); + bool first = true; + foreach (string cheader_filename in get_cheader_filenames ()) { + if (first) { + first = false; + } else { + s.append_c (','); + } + s.append (cheader_filename); + } + return s.str; + } + + /** + * Sets the C header filename of this namespace to the specified + * filename. + * + * @param cheader_filename header filename + */ + public void set_cheader_filename (string! cheader_filename) { + cheader_filenames = null; + cheader_filenames.append (cheader_filename); + } + + private void process_ccode_attribute (Attribute! a) { + if (a.has_argument ("cprefix")) { + set_cprefix (a.get_string ("cprefix")); + } + if (a.has_argument ("lower_case_cprefix")) { + set_lower_case_cprefix (a.get_string ("lower_case_cprefix")); + } + if (a.has_argument ("cheader_filename")) { + var val = a.get_string ("cheader_filename"); + foreach (string filename in val.split (",")) { + cheader_filenames.append (filename); + } + } + } + + /** + * Process all associated attributes. + */ + public void process_attributes () { + foreach (Attribute a in attributes) { + if (a.name == "CCode") { + process_ccode_attribute (a); + } + } + } +} diff --git a/vala/valanamespacereference.vala b/vala/valanamespacereference.vala new file mode 100644 index 000000000..6b78b81fc --- /dev/null +++ b/vala/valanamespacereference.vala @@ -0,0 +1,54 @@ +/* valanamespacereference.vala + * + * Copyright (C) 2006 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 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; + +/** + * A reference to a namespace symbol. + */ +public class Vala.NamespaceReference : CodeNode { + /** + * The name of the namespace this reference is referring to. + */ + public string! name { get; set construct; } + + /** + * The resolved symbol of the namespace this reference is referring to. + */ + public weak Symbol namespace_symbol { get; set; } + + /** + * Creates a new namespace reference. + * + * @param name namespace name + * @param source reference to source code + * @return newly created namespace reference + */ + public NamespaceReference (string! _name, SourceReference source) { + name = _name; + source_reference = source; + } + + public override void accept (CodeVisitor! visitor) { + visitor.visit_namespace_reference (this); + } +} diff --git a/vala/valanullliteral.vala b/vala/valanullliteral.vala new file mode 100644 index 000000000..0356d01cf --- /dev/null +++ b/vala/valanullliteral.vala @@ -0,0 +1,46 @@ +/* valanullliteral.vala + * + * Copyright (C) 2006 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 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 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 NullLiteral (SourceReference source = null) { + 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/valaobjectcreationexpression.vala b/vala/valaobjectcreationexpression.vala new file mode 100644 index 000000000..fa81d93a9 --- /dev/null +++ b/vala/valaobjectcreationexpression.vala @@ -0,0 +1,110 @@ +/* valaobjectcreationexpression.vala + * + * Copyright (C) 2006 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 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 an object creation expression in the source code. + */ +public class Vala.ObjectCreationExpression : Expression { + /** + * The object type to create. + */ + public TypeReference type_reference { get; set; } + + /** + * 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<Expression> 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 ObjectCreationExpression (MemberAccess! name, SourceReference source) { + 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); + arg.parent_node = this; + } + + /** + * Returns a copy of the argument list. + * + * @return argument list + */ + public ref List<weak Expression> get_argument_list () { + return argument_list.copy (); + } + + public override void accept (CodeVisitor! visitor) { + if (type_reference != null) { + type_reference.accept (visitor); + } + + if (member_name != null) { + member_name.accept (visitor); + } + + visitor.visit_begin_object_creation_expression (this); + + // iterate over list copy as list may change in loop body + foreach (Expression arg in argument_list.copy ()) { + arg.accept (visitor); + } + + visitor.visit_end_object_creation_expression (this); + } + + public override void replace (CodeNode! old_node, CodeNode! new_node) { + weak List<Expression> l = argument_list.find (old_node); + if (l != null) { + if (new_node.parent_node != null) { + return; + } + + argument_list.insert_before (l, new_node); + argument_list.remove_link (l); + new_node.parent_node = this; + } + } +} diff --git a/vala/valaparenthesizedexpression.vala b/vala/valaparenthesizedexpression.vala new file mode 100644 index 000000000..e26662665 --- /dev/null +++ b/vala/valaparenthesizedexpression.vala @@ -0,0 +1,67 @@ +/* valaparenthesizedexpression.vala + * + * Copyright (C) 2006 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 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 parenthesized expression in the source code. + */ +public class Vala.ParenthesizedExpression : Expression { + /** + * The inner expression. + */ + public Expression! inner { + get { + return _inner; + } + set construct { + _inner = value; + _inner.parent_node = this; + } + } + + private Expression! _inner; + + /** + * Creates a new parenthesized expression. + * + * @param inner an expression + * @param source reference to source code + * @return newly created parenthesized expression + */ + public ParenthesizedExpression (Expression! _inner, SourceReference source) { + inner = _inner; + source_reference = source; + } + + public override void accept (CodeVisitor! visitor) { + inner.accept (visitor); + + visitor.visit_parenthesized_expression (this); + } + + public override void replace (CodeNode! old_node, CodeNode! new_node) { + if (inner == old_node) { + inner = (Expression) new_node; + } + } +} diff --git a/vala/valaparser.vala b/vala/valaparser.vala new file mode 100644 index 000000000..16144680b --- /dev/null +++ b/vala/valaparser.vala @@ -0,0 +1,94 @@ +/* valaparser.vala + * + * Copyright (C) 2006 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 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; + +/** + * Code visitor parsing all Vala source files. + */ +public class Vala.Parser : CodeVisitor { + private string comment; + private string _file_comment; + + /** + * Parse all source files in the specified code context and build a + * code tree. + * + * @param context a code context + */ + public void parse (CodeContext! context) { + context.accept (this); + } + + public override void visit_begin_source_file (SourceFile! source_file) { + if (source_file.filename.has_suffix (".vala")) { + parse_file (source_file); + source_file.comment = _file_comment; + } + } + + public override void visit_end_source_file (SourceFile! source_file) { + _file_comment = null; + } + + /** + * Adds the specified comment to the comment stack. + * + * @param comment_item a comment string + * @param file_comment true if file header comment, false otherwise + */ + public void push_comment (string! comment_item, bool file_comment) { + if (comment == null) { + comment = comment_item; + } else { + comment = "%s\n%s".printf (comment, comment_item); + } + if (file_comment) { + _file_comment = comment; + comment = null; + } + } + + /** + * Clears and returns the content of the comment stack. + * + * @return saved comment + */ + public ref string pop_comment () { + if (comment == null) { + return null; + } + + String result = new String (comment); + comment = null; + + weak string index; + while ((index = result.str.chr (-1, '\t')) != null) { + result.erase (result.str.pointer_to_offset (index), 1); + } + + return result.str; + } + + [Import ()] + public void parse_file (SourceFile! source_file); +} diff --git a/vala/valapointer.vala b/vala/valapointer.vala new file mode 100644 index 000000000..12b3afea9 --- /dev/null +++ b/vala/valapointer.vala @@ -0,0 +1,90 @@ +/* valapointer.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 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 pointer-type. + */ +public class Vala.Pointer : DataType { + /** + * The type to which this pointer type points. + */ + public DataType! referent_type { get; set construct; } + + private string cname; + + public Pointer (construct DataType! referent_type, construct SourceReference source_reference = null) { + } + + construct { + name = referent_type.name + "*"; + } + + public override string get_cname (bool const_type = false) { + if (cname == null) { + if (referent_type.is_reference_type ()) { + cname = "%s**".printf (referent_type.get_cname ()); + } else { + cname = "%s*".printf (referent_type.get_cname ()); + } + } + + return cname; + } + + public override bool is_reference_type () { + return false; + } + + public override ref string get_upper_case_cname (string infix) { + return null; + } + + public override ref string get_lower_case_cname (string infix) { + return null; + } + + public override string get_free_function () { + return null; + } + + public override ref List<string> get_cheader_filenames () { + return referent_type.get_cheader_filenames (); + } + + public override string get_type_id () { + return "G_TYPE_POINTER"; + } + + public override string get_marshaller_type_name () { + return "POINTER"; + } + + public override string get_get_value_function () { + return "g_value_get_pointer"; + } + + public override string get_set_value_function () { + return "g_value_set_pointer"; + } +} diff --git a/vala/valapointerindirection.vala b/vala/valapointerindirection.vala new file mode 100644 index 000000000..747001e11 --- /dev/null +++ b/vala/valapointerindirection.vala @@ -0,0 +1,64 @@ +/* valapointerindirection.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 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 pointer indirection in the source code, e.g. `*pointer'. + */ +public class Vala.PointerIndirection : Expression { + /** + * The pointer to dereference. + */ + public Expression! inner { + get { + return _inner; + } + set construct { + _inner = value; + _inner.parent_node = this; + } + } + + private Expression! _inner; + + /** + * Creates a new pointer indirection. + * + * @param inner pointer to be dereferenced + * @return newly created pointer indirection + */ + public PointerIndirection (construct Expression! inner, construct SourceReference source_reference = null) { + } + + public override void accept (CodeVisitor! visitor) { + inner.accept (visitor); + + visitor.visit_pointer_indirection (this); + } + + public override void replace (CodeNode! old_node, CodeNode! new_node) { + if (inner == old_node) { + inner = (Expression) new_node; + } + } +} diff --git a/vala/valapostfixexpression.vala b/vala/valapostfixexpression.vala new file mode 100644 index 000000000..66ecbb71d --- /dev/null +++ b/vala/valapostfixexpression.vala @@ -0,0 +1,58 @@ +/* valapostfixexpression.vala + * + * Copyright (C) 2006 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 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 postfix increment or decrement expression. + */ +public class Vala.PostfixExpression : Expression { + /** + * The operand, must be a variable or a property. + */ + public Expression! inner { get; set construct; } + + /** + * Specifies whether value should be incremented or decremented. + */ + public bool increment { get; set; } + + /** + * Creates a new postfix expression. + * + * @param inner operand expression + * @param inc true for increment, false for decrement + * @param source reference to source code + * @return newly created postfix expression + */ + public PostfixExpression (Expression! _inner, bool inc, SourceReference source) { + inner = _inner; + increment = inc; + source_reference = source; + } + + public override void accept (CodeVisitor! visitor) { + inner.accept (visitor); + + visitor.visit_postfix_expression (this); + } +} diff --git a/vala/valaproperty.vala b/vala/valaproperty.vala new file mode 100644 index 000000000..16b5b29bb --- /dev/null +++ b/vala/valaproperty.vala @@ -0,0 +1,231 @@ +/* valaproperty.vala + * + * Copyright (C) 2006-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 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 property declaration in the source code. + */ +public class Vala.Property : Member, Lockable { + /** + * 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; } + + /** + * Specifies whether automatic accessor code generation should be + * disabled. + */ + public bool interface_only { get; set; } + + /** + * Specifies whether this property is abstract. Abstract properties have + * no accessor bodies, may only be specified within abstract classes and + * interfaces, and must be overriden by derived non-abstract classes. + */ + public bool is_abstract { get; set; } + + /** + * Specifies whether this property is virtual. Virtual properties may be + * overridden by derived classes. + */ + public bool is_virtual { get; set; } + + /** + * Specifies whether this property overrides a virtual or abstract + * property of a base type. + */ + public bool overrides { get; set; } + + /** + * Specifies the virtual or abstract property this property overrides. + * Reference must be weak as virtual properties set base_property to + * themselves. + */ + public weak Property base_property { get; set; } + + /** + * Specifies the abstract interface property this property implements. + */ + public Property base_interface_property { get; set; } + + private bool lock_used = false; + + /** + * 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 Property (string! _name, TypeReference! type, PropertyAccessor _get_accessor, PropertyAccessor _set_accessor, SourceReference source) { + name = _name; + type_reference = type; + get_accessor = _get_accessor; + set_accessor = _set_accessor; + source_reference = source; + } + + public override void accept (CodeVisitor! visitor) { + visitor.visit_member (this); + 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); + } + + 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 (((DataType) 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 = new String ("\""); + + 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 (); + } + + str.append_c ('"'); + + return new CCodeConstant (str.str); + } + + /** + * Process all associated attributes. + */ + public void process_attributes () { + foreach (Attribute a in attributes) { + if (a.name == "NoAccessorMethod") { + no_accessor_method = true; + } + } + } + + public bool get_lock_used () { + return lock_used; + } + + public void set_lock_used (bool used) { + lock_used = used; + } + + /** + * Checks whether the accessors and type of the specified property + * matches this property. + * + * @param prop a property + * @return true if the specified property is compatible to this + * property + */ + public bool equals (Property! prop2) { + if (!prop2.type_reference.equals (type_reference)) { + return false; + } + + if ((get_accessor == null && prop2.get_accessor != null) || + (get_accessor != null && prop2.get_accessor == null)) { + return false; + } + + if ((set_accessor == null && prop2.set_accessor != null) || + (set_accessor != null && prop2.set_accessor == null)) { + return false; + } + + if (set_accessor != null) { + if (set_accessor.writable != prop2.set_accessor.writable) { + return false; + } + if (set_accessor.construction != prop2.set_accessor.construction) { + return false; + } + } + + return true; + } +} diff --git a/vala/valapropertyaccessor.vala b/vala/valapropertyaccessor.vala new file mode 100644 index 000000000..3177aa5d7 --- /dev/null +++ b/vala/valapropertyaccessor.vala @@ -0,0 +1,82 @@ +/* valapropertyaccessor.vala + * + * Copyright (C) 2006 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 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 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 PropertyAccessor (bool _readable, bool _writable, bool _construction, Statement _body, SourceReference source) { + 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); + } +} diff --git a/vala/valarealliteral.vala b/vala/valarealliteral.vala new file mode 100644 index 000000000..a85cf2073 --- /dev/null +++ b/vala/valarealliteral.vala @@ -0,0 +1,62 @@ +/* valarealliteral.vala + * + * Copyright (C) 2006 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 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 real literal in the source code. + */ +public class Vala.RealLiteral : Literal { + /** + * The literal value. + */ + public string value { get; set; } + + /** + * Creates a new real literal. + * + * @param r literal value + * @param source reference to source code + * @return newly created real literal + */ + public RealLiteral (string r, SourceReference source) { + value = r; + source_reference = source; + } + + public override void accept (CodeVisitor! visitor) { + visitor.visit_real_literal (this); + } + + /** + * Returns the type name of the value this literal represents. + * + * @return the name of literal type + */ + public string! get_type_name () { + if (value.has_suffix ("F")) { + return "float"; + } + + return "double"; + } +} diff --git a/vala/valareferencetransferexpression.vala b/vala/valareferencetransferexpression.vala new file mode 100644 index 000000000..ec6000d09 --- /dev/null +++ b/vala/valareferencetransferexpression.vala @@ -0,0 +1,64 @@ +/* valareferencetransferexpression.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 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 reference transfer expression in the source code, e.g. `#foo'. + */ +public class Vala.ReferenceTransferExpression : Expression { + /** + * The variable whose reference is to be transferred. + */ + public Expression! inner { + get { + return _inner; + } + set construct { + _inner = value; + _inner.parent_node = this; + } + } + + private Expression! _inner; + + /** + * Creates a new reference transfer expression. + * + * @param inner variable whose reference is to be transferred + * @return newly created reference transfer expression + */ + public ReferenceTransferExpression (construct Expression! inner, construct SourceReference source_reference = null) { + } + + public override void accept (CodeVisitor! visitor) { + inner.accept (visitor); + + visitor.visit_reference_transfer_expression (this); + } + + public override void replace (CodeNode! old_node, CodeNode! new_node) { + if (inner == old_node) { + inner = (Expression) new_node; + } + } +} diff --git a/vala/valareport.vala b/vala/valareport.vala new file mode 100644 index 000000000..8936fbb21 --- /dev/null +++ b/vala/valareport.vala @@ -0,0 +1,75 @@ +/* valareport.vala + * + * Copyright (C) 2006 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 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; + +/** + * Static class to centralize reporting warnings and errors. + */ +public class Vala.Report { + private static int warnings; + private static int errors; + + /** + * Returns the total number of warnings reported. + */ + public static int get_warnings () { + return warnings; + } + + /** + * Returns the total number of errors reported. + */ + public static int get_errors () { + return errors; + } + + /** + * Reports the specified message as warning. + * + * @param source reference to source code + * @param message warning message + */ + public static void warning (SourceReference source, string! message) { + warnings++; + if (source == null) { + stderr.printf ("warning: %s\n", message); + } else { + stderr.printf ("%s: warning: %s\n", source.to_string (), message); + } + } + + /** + * Reports the specified message as error. + * + * @param source reference to source code + * @param message error message + */ + public static void error (SourceReference source, string! message) { + errors++; + if (source == null) { + stderr.printf ("error: %s\n", message); + } else { + stderr.printf ("%s: error: %s\n", source.to_string (), message); + } + } +} diff --git a/vala/valareturnstatement.vala b/vala/valareturnstatement.vala new file mode 100644 index 000000000..52e7b0841 --- /dev/null +++ b/vala/valareturnstatement.vala @@ -0,0 +1,75 @@ +/* valareturnstatement.vala + * + * Copyright (C) 2006 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 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 return statement in the source code. + */ +public class Vala.ReturnStatement : Statement { + /** + * The optional expression to return. + */ + public Expression return_expression { + get { + return _return_expression; + } + set { + _return_expression = value; + if (_return_expression != null) { + _return_expression.parent_node = this; + } + } + } + + private Expression! _return_expression; + + /** + * Creates a new return statement. + * + * @param result the return expression + * @param source reference to source code + * @return newly created return statement + */ + public ReturnStatement (Expression result = null, SourceReference source = null) { + return_expression = result; + source_reference = source; + } + + public override void accept (CodeVisitor! visitor) { + visitor.visit_begin_return_statement (this); + + if (return_expression != null) { + return_expression.accept (visitor); + + visitor.visit_end_full_expression (return_expression); + } + + visitor.visit_end_return_statement (this); + } + + public override void replace (CodeNode! old_node, CodeNode! new_node) { + if (return_expression == old_node) { + return_expression = (Expression) new_node; + } + } +} diff --git a/vala/valasemanticanalyzer.vala b/vala/valasemanticanalyzer.vala new file mode 100644 index 000000000..4b03fa61e --- /dev/null +++ b/vala/valasemanticanalyzer.vala @@ -0,0 +1,2341 @@ +/* valasemanticanalyzer.vala + * + * Copyright (C) 2006-2007 Jürg Billeter, Raffaele Sandrini + * + * 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 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> + * Raffaele Sandrini <rasa@gmx.ch> + */ + +using GLib; + +/** + * Code visitor analyzing and checking code. + */ +public class Vala.SemanticAnalyzer : CodeVisitor { + /** + * Specifies whether automatic memory management is active. + */ + public bool memory_management { get; set; } + + Symbol root_symbol; + Symbol current_symbol; + SourceFile current_source_file; + TypeReference current_return_type; + Class current_class; + Struct current_struct; + + List<weak NamespaceReference> current_using_directives; + + TypeReference bool_type; + TypeReference string_type; + TypeReference int_type; + TypeReference uint_type; + TypeReference type_type; + DataType pointer_type; + DataType initially_unowned_type; + DataType glist_type; + DataType gslist_type; + + private int next_lambda_id = 0; + + public SemanticAnalyzer (bool manage_memory = true) { + memory_management = manage_memory; + } + + /** + * Analyze and check code in the specified context. + * + * @param context a code context + */ + public void analyze (CodeContext! context) { + root_symbol = context.get_root (); + + bool_type = new TypeReference (); + bool_type.data_type = (DataType) root_symbol.lookup ("bool").node; + + string_type = new TypeReference (); + string_type.data_type = (DataType) root_symbol.lookup ("string").node; + + pointer_type = (DataType) root_symbol.lookup ("pointer").node; + + int_type = new TypeReference (); + int_type.data_type = (DataType) root_symbol.lookup ("int").node; + + uint_type = new TypeReference (); + uint_type.data_type = (DataType) root_symbol.lookup ("uint").node; + + // TODO: don't require GLib namespace in semantic analyzer + var glib_ns = root_symbol.lookup ("GLib"); + if (glib_ns != null) { + initially_unowned_type = (DataType) glib_ns.lookup ("InitiallyUnowned").node; + + type_type = new TypeReference (); + type_type.data_type = (DataType) glib_ns.lookup ("Type").node; + + glist_type = (DataType) glib_ns.lookup ("List").node; + gslist_type = (DataType) glib_ns.lookup ("SList").node; + } + + current_symbol = root_symbol; + context.accept (this); + } + + public override void visit_begin_source_file (SourceFile! file) { + current_source_file = file; + current_using_directives = file.get_using_directives (); + + next_lambda_id = 0; + } + + public override void visit_end_source_file (SourceFile! file) { + current_using_directives = null; + } + + public override void visit_begin_namespace (Namespace! ns) { + current_symbol = ns.symbol; + } + + public override void visit_end_namespace (Namespace! ns) { + current_symbol = current_symbol.parent_symbol; + } + + public override void visit_begin_class (Class! cl) { + current_symbol = cl.symbol; + current_class = cl; + + if (cl.base_class != null) { + current_source_file.add_symbol_dependency (cl.base_class.symbol, SourceFileDependencyType.HEADER_FULL); + } + + foreach (TypeReference base_type_reference in cl.get_base_types ()) { + current_source_file.add_symbol_dependency (base_type_reference.data_type.symbol, SourceFileDependencyType.HEADER_FULL); + } + } + + private ref List<DataType> get_all_prerequisites (Interface! iface) { + List<DataType> ret = null; + + foreach (TypeReference prereq in iface.get_prerequisites ()) { + DataType type = prereq.data_type; + /* skip on previous errors */ + if (type == null) { + continue; + } + + ret.prepend (type); + if (type is Interface) { + ret.concat (get_all_prerequisites ((Interface) type)); + + } + } + + ret.reverse (); + return #ret; + } + + private bool class_is_a (Class! cl, DataType! t) { + if (cl == t) { + return true; + } + + foreach (TypeReference base_type in cl.get_base_types ()) { + if (base_type.data_type is Class) { + if (class_is_a ((Class) base_type.data_type, t)) { + return true; + } + } else if (base_type.data_type == t) { + return true; + } + } + + return false; + } + + public override void visit_end_class (Class! cl) { + /* gather all prerequisites */ + List<DataType> prerequisites = null; + foreach (TypeReference base_type in cl.get_base_types ()) { + if (base_type.data_type is Interface) { + prerequisites.concat (get_all_prerequisites ((Interface) base_type.data_type)); + } + } + /* check whether all prerequisites are met */ + List<string> missing_prereqs = null; + foreach (DataType prereq in prerequisites) { + if (!class_is_a (cl, prereq)) { + missing_prereqs.prepend (prereq.symbol.get_full_name ()); + } + } + /* report any missing prerequisites */ + if (missing_prereqs != null) { + cl.error = true; + + string error_string = "%s: some prerequisites (".printf (cl.symbol.get_full_name ()); + bool first = true; + foreach (string s in missing_prereqs) { + if (first) { + error_string = "%s`%s'".printf (error_string, s); + first = false; + } else { + error_string = "%s, `%s'".printf (error_string, s); + } + } + error_string += ") are not met"; + Report.error (cl.source_reference, error_string); + } + + /* all abstract symbols defined in base types have to be at least defined (or implemented) also in this type */ + foreach (TypeReference base_type in cl.get_base_types ()) { + if (base_type.data_type is Interface) { + Interface iface = (Interface) base_type.data_type; + + /* We do not need to do expensive equality checking here since this is done + * already. We only need to guarantee the symbols are present. + */ + + /* check methods */ + foreach (Method m in iface.get_methods ()) { + if (m.is_abstract) { + var sym = cl.symbol.lookup (m.name); + if (sym == null || !(sym.node is Method) || ((Method) sym.node).base_interface_method != m) { + cl.error = true; + Report.error (cl.source_reference, "`%s' does not implement interface method `%s'".printf (cl.symbol.get_full_name (), m.symbol.get_full_name ())); + } + } + } + } + } + + /* all abstract symbols defined in base classes have to be implemented in non-abstract classes + * VAPI classes don't have to specify overridden methods + */ + if (!cl.is_abstract && !cl.source_reference.file.pkg) { + var base_class = cl.base_class; + while (base_class != null && base_class.is_abstract) { + foreach (Method m in base_class.get_methods ()) { + if (m.is_abstract) { + var sym = cl.symbol.lookup (m.name); + if (sym == null || !(sym.node is Method) || ((Method) sym.node).base_method != m) { + cl.error = true; + Report.error (cl.source_reference, "`%s' does not implement abstract method `%s'".printf (cl.symbol.get_full_name (), m.symbol.get_full_name ())); + } + } + } + base_class = base_class.base_class; + } + } + + current_symbol = current_symbol.parent_symbol; + current_class = null; + } + + public override void visit_begin_struct (Struct! st) { + current_symbol = st.symbol; + current_struct = st; + } + + public override void visit_end_struct (Struct! st) { + current_symbol = current_symbol.parent_symbol; + current_struct = null; + } + + public override void visit_begin_interface (Interface! iface) { + current_symbol = iface.symbol; + + foreach (TypeReference prerequisite_reference in iface.get_prerequisites ()) { + current_source_file.add_symbol_dependency (prerequisite_reference.data_type.symbol, SourceFileDependencyType.HEADER_FULL); + } + } + + public override void visit_end_interface (Interface! iface) { + /* check prerequisites */ + Class prereq_class; + foreach (TypeReference prereq in iface.get_prerequisites ()) { + DataType class_or_interface = prereq.data_type; + /* skip on previous errors */ + if (class_or_interface == null) { + iface.error = true; + continue; + } + /* interfaces are not allowed to have multiple instantiable prerequisites */ + if (class_or_interface is Class) { + if (prereq_class != null) { + iface.error = true; + Report.error (iface.source_reference, "%s: Interfaces cannot have multiple instantiable prerequisites (`%s' and `%s')".printf (iface.symbol.get_full_name (), class_or_interface.symbol.get_full_name (), prereq_class.symbol.get_full_name ())); + return; + } + + prereq_class = (Class)class_or_interface; + } + } + + current_symbol = current_symbol.parent_symbol; + } + + public override void visit_constant (Constant! c) { + if (!current_source_file.pkg) { + if (c.initializer == null) { + c.error = true; + Report.error (c.source_reference, "A const field requires a initializer to be provided"); + } + } + } + + public override void visit_field (Field! f) { + if (f.access != MemberAccessibility.PRIVATE) { + if (f.type_reference.data_type != null) { + /* is null if it references a type parameter */ + current_source_file.add_symbol_dependency (f.type_reference.data_type.symbol, SourceFileDependencyType.HEADER_SHALLOW); + } + } else { + if (f.type_reference.data_type != null) { + /* is null if it references a type parameter */ + current_source_file.add_symbol_dependency (f.type_reference.data_type.symbol, SourceFileDependencyType.SOURCE); + } + } + } + + public override void visit_begin_method (Method! m) { + current_symbol = m.symbol; + current_return_type = m.return_type; + + var init_attr = m.get_attribute ("ModuleInit"); + if (init_attr != null) { + m.source_reference.file.context.module_init_method = m; + } + + if (m.return_type.data_type != null) { + /* is null if it is void or a reference to a type parameter */ + current_source_file.add_symbol_dependency (m.return_type.data_type.symbol, SourceFileDependencyType.HEADER_SHALLOW); + } + } + + private void find_base_class_method (Method! m, Class! cl) { + var sym = cl.symbol.lookup (m.name); + if (sym != null && sym.node is Method) { + var base_method = (Method) sym.node; + if (base_method.is_abstract || base_method.is_virtual) { + if (!m.equals (base_method)) { + m.error = true; + Report.error (m.source_reference, "Return type and/or parameters of overriding method `%s' do not match overridden method `%s'.".printf (m.symbol.get_full_name (), base_method.symbol.get_full_name ())); + return; + } + + m.base_method = base_method; + return; + } + } + + if (cl.base_class != null) { + find_base_class_method (m, cl.base_class); + } + } + + private void find_base_interface_method (Method! m, Class! cl) { + // FIXME report error if multiple possible base methods are found + foreach (TypeReference type in cl.get_base_types ()) { + if (type.data_type is Interface) { + var sym = type.data_type.symbol.lookup (m.name); + if (sym != null && sym.node is Method) { + var base_method = (Method) sym.node; + if (base_method.is_abstract) { + if (!m.equals (base_method)) { + m.error = true; + Report.error (m.source_reference, "Return type and/or parameters of overriding method `%s' do not match overridden method `%s'.".printf (m.symbol.get_full_name (), base_method.symbol.get_full_name ())); + return; + } + + m.base_interface_method = base_method; + return; + } + } + } + } + } + + public override void visit_end_method (Method! m) { + current_symbol = current_symbol.parent_symbol; + current_return_type = null; + + if (current_symbol.parent_symbol != null && + current_symbol.parent_symbol.node is Method) { + /* lambda expressions produce nested methods */ + var up_method = (Method) current_symbol.parent_symbol.node; + current_return_type = up_method.return_type; + } + + if (current_symbol.node is Class) { + if (!(m is CreationMethod)) { + find_base_interface_method (m, (Class) current_symbol.node); + if (m.is_virtual || m.overrides) { + find_base_class_method (m, (Class) current_symbol.node); + if (m.base_method == null) { + Report.error (m.source_reference, "%s: no suitable method found to override".printf (m.symbol.get_full_name ())); + } + } + } + } else if (current_symbol.node is Struct) { + if (m.is_abstract || m.is_virtual || m.overrides) { + Report.error (m.source_reference, "A struct member `%s' cannot be marked as override, virtual, or abstract".printf (m.symbol.get_full_name ())); + return; + } + } + } + + public override void visit_begin_creation_method (CreationMethod! m) { + m.return_type = new TypeReference (); + m.return_type.data_type = (DataType) current_symbol.node; + m.return_type.transfers_ownership = true; + + if (current_symbol.node is Class) { + // check for floating reference + var cl = (Class) current_symbol.node; + while (cl != null) { + if (cl == initially_unowned_type) { + m.return_type.floating_reference = true; + break; + } + + cl = cl.base_class; + } + } + + current_symbol = m.symbol; + current_return_type = m.return_type; + } + + public override void visit_end_creation_method (CreationMethod! m) { + visit_end_method (m); + + if (m.body != null && current_class != 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) { + m.error = true; + Report.error (stmt.source_reference, "class creation methods only allow property assignment statements"); + return; + } + n_params += params; + } + m.n_construction_params = n_params; + } + } + + public override void visit_formal_parameter (FormalParameter! p) { + if (!p.ellipsis) { + if (p.type_reference.data_type != null) { + /* is null if it references a type parameter */ + current_source_file.add_symbol_dependency (p.type_reference.data_type.symbol, SourceFileDependencyType.HEADER_SHALLOW); + current_source_file.add_symbol_dependency (p.type_reference.data_type.symbol, SourceFileDependencyType.SOURCE); + } + } + + /* special treatment for construct formal parameters used in creation methods */ + if (p.construct_parameter) { + if (!(p.symbol.parent_symbol.node is CreationMethod)) { + p.error = true; + Report.error (p.source_reference, "construct parameters are only allowed in type creation methods"); + return; + } + + var method_body = ((CreationMethod)p.symbol.parent_symbol.node).body; + var left = new MemberAccess.simple (p.name); + var right = new MemberAccess.simple (p.name); + + /* try to lookup the requested property */ + var prop_sym = symbol_lookup_inherited (current_class.symbol, p.name); + if (!(prop_sym.node is Property)) { + p.error = true; + Report.error (p.source_reference, "class `%s' does not contain a property named `%s'".printf (current_class.symbol.get_full_name (), p.name)); + return; + } + left.symbol_reference = prop_sym; + + right.symbol_reference = p.symbol; + + method_body.add_statement (new ExpressionStatement (new Assignment (left, right))); + } + } + + private void find_base_class_property (Property! prop, Class! cl) { + var sym = cl.symbol.lookup (prop.name); + if (sym != null && sym.node is Property) { + var base_property = (Property) sym.node; + if (base_property.is_abstract || base_property.is_virtual) { + if (!prop.equals (base_property)) { + prop.error = true; + Report.error (prop.source_reference, "Type and/or accessors of overriding property `%s' do not match overridden property `%s'.".printf (prop.symbol.get_full_name (), base_property.symbol.get_full_name ())); + return; + } + + prop.base_property = base_property; + return; + } + } + + if (cl.base_class != null) { + find_base_class_property (prop, cl.base_class); + } + } + + private void find_base_interface_property (Property! prop, Class! cl) { + // FIXME report error if multiple possible base properties are found + foreach (TypeReference type in cl.get_base_types ()) { + if (type.data_type is Interface) { + var sym = type.data_type.symbol.lookup (prop.name); + if (sym != null && sym.node is Property) { + var base_property = (Property) sym.node; + if (base_property.is_abstract) { + if (!prop.equals (base_property)) { + prop.error = true; + Report.error (prop.source_reference, "Type and/or accessors of overriding property `%s' do not match overridden property `%s'.".printf (prop.symbol.get_full_name (), base_property.symbol.get_full_name ())); + return; + } + + prop.base_interface_property = base_property; + return; + } + } + } + } + } + + public override void visit_end_property (Property! prop) { + if (prop.type_reference.data_type != null) { + /* is null if it references a type parameter */ + current_source_file.add_symbol_dependency (prop.type_reference.data_type.symbol, SourceFileDependencyType.HEADER_SHALLOW); + current_source_file.add_symbol_dependency (prop.type_reference.data_type.symbol, SourceFileDependencyType.SOURCE); + } + + if (prop.symbol.parent_symbol.node is Class) { + var cl = (Class) prop.symbol.parent_symbol.node; + find_base_interface_property (prop, cl); + if (prop.is_virtual || prop.overrides) { + find_base_class_property (prop, cl); + if (prop.base_property == null) { + prop.error = true; + Report.error (prop.source_reference, "%s: no suitable property found to override".printf (prop.symbol.get_full_name ())); + } + } + } + } + + public override void visit_begin_property_accessor (PropertyAccessor! acc) { + var prop = (Property) acc.symbol.parent_symbol.node; + + if (acc.readable) { + current_return_type = prop.type_reference; + } else { + // void + current_return_type = new TypeReference (); + } + } + + public override void visit_end_property_accessor (PropertyAccessor! acc) { + current_return_type = null; + } + + public override void visit_begin_constructor (Constructor! c) { + current_symbol = c.symbol; + } + + public override void visit_end_constructor (Constructor! c) { + current_symbol = current_symbol.parent_symbol; + } + + public override void visit_begin_destructor (Destructor! d) { + current_symbol = d.symbol; + } + + public override void visit_end_destructor (Destructor! d) { + current_symbol = current_symbol.parent_symbol; + } + + public override void visit_named_argument (NamedArgument! n) { + } + + public override void visit_begin_block (Block! b) { + current_symbol = b.symbol; + } + + public override void visit_end_block (Block! b) { + foreach (VariableDeclarator decl in b.get_local_variables ()) { + decl.symbol.active = false; + } + + current_symbol = current_symbol.parent_symbol; + } + + public override void visit_variable_declarator (VariableDeclarator! decl) { + if (decl.type_reference == null) { + /* var type */ + + if (decl.initializer == null) { + decl.error = true; + Report.error (decl.source_reference, "var declaration not allowed without initializer"); + return; + } + if (decl.initializer.static_type == null) { + decl.error = true; + Report.error (decl.source_reference, "var declaration not allowed with non-typed initializer"); + return; + } + + decl.type_reference = decl.initializer.static_type.copy (); + decl.type_reference.takes_ownership = (decl.type_reference.data_type == null || decl.type_reference.data_type.is_reference_type ()); + decl.type_reference.transfers_ownership = false; + } + + if (decl.initializer != null) { + if (decl.initializer.static_type == null) { + if (!(decl.initializer is MemberAccess)) { + decl.error = true; + Report.error (decl.source_reference, "expression type not allowed as initializer"); + return; + } + + if (decl.initializer.symbol_reference.node is Method && + decl.type_reference.data_type is Callback) { + var m = (Method) decl.initializer.symbol_reference.node; + var cb = (Callback) decl.type_reference.data_type; + + /* check whether method matches callback type */ + if (!cb.matches_method (m)) { + decl.error = true; + Report.error (decl.source_reference, "declaration of method `%s' doesn't match declaration of callback `%s'".printf (m.symbol.get_full_name (), cb.symbol.get_full_name ())); + return; + } + + decl.initializer.static_type = decl.type_reference; + } else { + decl.error = true; + Report.error (decl.source_reference, "expression type not allowed as initializer"); + return; + } + } + + if (memory_management) { + if (decl.initializer.static_type.transfers_ownership) { + /* rhs transfers ownership of the expression */ + if (!decl.type_reference.takes_ownership) { + /* lhs doesn't own the value */ + decl.error = true; + Report.error (decl.source_reference, "Invalid assignment from owned expression to unowned variable"); + return; + } + } + } + } + + if (decl.type_reference.data_type != null) { + current_source_file.add_symbol_dependency (decl.type_reference.data_type.symbol, SourceFileDependencyType.SOURCE); + } + + decl.symbol = new Symbol (decl); + current_symbol.add (decl.name, decl.symbol); + + var block = (Block) current_symbol.node; + block.add_local_variable (decl); + + decl.symbol.active = true; + } + + /** + * Visit operation called for initializer lists + * + * @param list an initializer list + */ + public override void visit_begin_initializer_list (InitializerList! list) { + if (list.expected_type != null && list.expected_type.data_type is Array) { + /* initializer is used as array initializer */ + Array edt = (Array)list.expected_type.data_type; + var inits = list.get_initializers (); + int rank = ((Array)list.expected_type.data_type).rank; + var child_type = list.expected_type.copy (); + + if (rank > 1) { + child_type.data_type = edt.element_type.get_array (rank - 1); + } else { + child_type.data_type = edt.element_type; + } + + foreach (Expression e in inits) { + e.expected_type = child_type.copy (); + } + } + } + + /** + * Visit operation called for initializer lists + * + * @param list an initializer list + */ + public override void visit_end_initializer_list (InitializerList! list) { + if (list.expected_type != null && list.expected_type.data_type is Array) { + Array edt = (Array)list.expected_type.data_type; + var inits = list.get_initializers (); + int rank = edt.rank; + var child_type = list.expected_type.copy (); + bool error = false; + + if (rank > 1) { + child_type.data_type = edt.element_type.get_array (rank - 1); + foreach (Expression e in inits) { + if (e.static_type == null) { + error = true; + continue; + } + if (!(e is InitializerList)) { + error = true; + e.error = true; + Report.error (e.source_reference, "Initializer list expected"); + continue; + } + if (!e.static_type.equals (child_type)) { + error = true; + e.error = true; + Report.error (e.source_reference, "Expected initializer list of type `%s' but got `%s'".printf (child_type.data_type.name, e.static_type.data_type.name)); + } + } + } else { + child_type.data_type = edt.element_type; + foreach (Expression e in inits) { + if (e.static_type == null) { + error = true; + continue; + } + if (!is_type_compatible (e.static_type, child_type)) { + error = true; + e.error = true; + Report.error (e.source_reference, "Expected initializer of type `%s' but got `%s'".printf (child_type.data_type.name, e.static_type.data_type.name)); + } + } + } + + if (!error) { + /* everything seems to be correct */ + list.static_type = list.expected_type; + } + } + } + + public override void visit_expression_statement (ExpressionStatement! stmt) { + if (stmt.expression.static_type != null && + stmt.expression.static_type.transfers_ownership) { + Report.warning (stmt.source_reference, "Short-living reference"); + return; + } + } + + public override void visit_if_statement (IfStatement! stmt) { + if (stmt.condition.error) { + /* if there was an error in the condition, skip this check */ + stmt.error = true; + return; + } + + if (stmt.condition.static_type.data_type != bool_type.data_type) { + stmt.error = true; + Report.error (stmt.condition.source_reference, "Condition must be boolean"); + return; + } + } + + public override void visit_while_statement (WhileStatement! stmt) { + if (stmt.condition.static_type.data_type != bool_type.data_type) { + stmt.error = true; + Report.error (stmt.condition.source_reference, "Condition must be boolean"); + return; + } + } + + public override void visit_for_statement (ForStatement! stmt) { + if (stmt.condition.static_type.data_type != bool_type.data_type) { + stmt.error = true; + Report.error (stmt.condition.source_reference, "Condition must be boolean"); + return; + } + } + + public override void visit_begin_foreach_statement (ForeachStatement! stmt) { + if (stmt.type_reference.data_type != null) { + current_source_file.add_symbol_dependency (stmt.type_reference.data_type.symbol, SourceFileDependencyType.SOURCE); + } + + stmt.variable_declarator = new VariableDeclarator (stmt.variable_name); + stmt.variable_declarator.type_reference = stmt.type_reference; + + stmt.variable_declarator.symbol = new Symbol (stmt.variable_declarator); + stmt.body.symbol.add (stmt.variable_name, stmt.variable_declarator.symbol); + } + + public override void visit_end_foreach_statement (ForeachStatement! stmt) { + var collection_type = stmt.collection.static_type.data_type; + if (!(collection_type is Array || collection_type == glist_type || collection_type == gslist_type)) { + stmt.error = true; + Report.error (stmt.source_reference, "Collection not iterable"); + return; + } + } + + public override void visit_end_return_statement (ReturnStatement! stmt) { + if (current_return_type == null) { + stmt.error = true; + Report.error (stmt.source_reference, "Return not allowed in this context"); + return; + } + + if (stmt.return_expression == null && current_return_type.data_type != null) { + stmt.error = true; + Report.error (stmt.source_reference, "Return without value in non-void function"); + return; + } + + if (stmt.return_expression != null && + current_return_type.data_type == null && + current_return_type.type_parameter == null) { + Report.error (stmt.source_reference, "Return with value in void function"); + return; + } + + if (stmt.return_expression != null && + !is_type_compatible (stmt.return_expression.static_type, current_return_type)) { + Report.error (stmt.source_reference, "Return: Cannot convert from `%s' to `%s'".printf (stmt.return_expression.static_type.to_string (), current_return_type.to_string ())); + return; + } + + if (stmt.return_expression != null && + stmt.return_expression.static_type.transfers_ownership && + !current_return_type.transfers_ownership) { + stmt.error = true; + Report.error (stmt.source_reference, "Return value transfers ownership but method return type hasn't been declared to transfer ownership"); + return; + } + + if (stmt.return_expression != null && + stmt.return_expression.symbol_reference != null && + stmt.return_expression.symbol_reference.node is VariableDeclarator && + stmt.return_expression.static_type.takes_ownership && + !current_return_type.transfers_ownership) { + Report.warning (stmt.source_reference, "Local variable with strong reference used as return value and method return type hasn't been declared to transfer ownership"); + } + } + + /** + * Visit operation called for lock statements. + * + * @param stmt a lock statement + */ + public override void visit_lock_statement (LockStatement! stmt) { + /* resource must be a member access and denote a Lockable */ + if (!(stmt.resource is MemberAccess && stmt.resource.symbol_reference.node is Lockable)) { + stmt.error = true; + stmt.resource.error = true; + Report.error (stmt.resource.source_reference, "Expression is either not a member access or does not denote a lockable member"); + return; + } + + /* parent symbol must be the current class */ + if (stmt.resource.symbol_reference.parent_symbol.node != current_class) { + stmt.error = true; + stmt.resource.error = true; + Report.error (stmt.resource.source_reference, "Only members of the current class are lockable"); + } + + ((Lockable)stmt.resource.symbol_reference.node).set_lock_used (true); + } + + public override void visit_begin_array_creation_expression (ArrayCreationExpression! expr) { + if (expr.initializer_list != null) { + expr.initializer_list.expected_type = expr.element_type.copy (); + expr.initializer_list.expected_type.data_type = expr.initializer_list.expected_type.data_type.get_array (expr.rank); + // FIXME: add element type to type_argument + } + } + + /** + * Visit operations called for array creation expresions. + * + * @param expr an array creation expression + */ + public override void visit_end_array_creation_expression (ArrayCreationExpression! expr) { + int i; + List<weak Expression> size = expr.get_sizes (); + + /* check for errors in the size list */ + if (size != null) { + foreach (Expression e in size) { + if (e.static_type == null) { + /* return on previous error */ + return; + } else if (!(e.static_type.data_type is Struct) || !((Struct) e.static_type.data_type).is_integer_type ()) { + expr.error = true; + Report.error (e.source_reference, "Expression of integer type expected"); + } + } + + if (expr.error) { + return; + } + } + + /* check for wrong elements inside the initializer */ + if (expr.initializer_list != null && expr.initializer_list.static_type == null) { + return; + } + + /* try to construct the type of the array */ + if (expr.element_type == null) { + expr.error = true; + Report.error (expr.source_reference, "Cannot determine the element type of the created array"); + return; + } + + expr.static_type = expr.element_type.copy (); + if (expr.element_type.data_type != null) { + expr.static_type.data_type = expr.element_type.data_type.get_array (expr.rank); + } else { + expr.static_type.data_type = expr.element_type.type_parameter.get_array (expr.rank); + } + expr.static_type.transfers_ownership = true; + expr.static_type.takes_ownership = true; + + expr.static_type.add_type_argument (expr.element_type); + } + + public override void visit_boolean_literal (BooleanLiteral! expr) { + expr.static_type = bool_type; + } + + public override void visit_character_literal (CharacterLiteral! expr) { + expr.static_type = new TypeReference (); + expr.static_type.data_type = (DataType) root_symbol.lookup ("char").node; + } + + public override void visit_integer_literal (IntegerLiteral! expr) { + expr.static_type = new TypeReference (); + expr.static_type.data_type = (DataType) root_symbol.lookup (expr.get_type_name ()).node; + } + + public override void visit_real_literal (RealLiteral! expr) { + expr.static_type = new TypeReference (); + expr.static_type.data_type = (DataType) root_symbol.lookup (expr.get_type_name ()).node; + } + + public override void visit_string_literal (StringLiteral! expr) { + expr.static_type = string_type.copy (); + expr.static_type.non_null = true; + } + + public override void visit_null_literal (NullLiteral! expr) { + /* empty TypeReference represents null */ + + expr.static_type = new TypeReference (); + } + + public override void visit_literal_expression (LiteralExpression! expr) { + expr.static_type = expr.literal.static_type; + } + + ref TypeReference get_static_type_for_node (CodeNode! node) { + if (node is Field) { + var f = (Field) node; + return f.type_reference; + } else if (node is Constant) { + var c = (Constant) node; + return c.type_reference; + } else if (node is Property) { + var prop = (Property) node; + var type = prop.type_reference.copy (); + type.takes_ownership = false; + return type; + } else if (node is FormalParameter) { + var p = (FormalParameter) node; + return p.type_reference; + } else if (node is TypeReference) { + return (TypeReference) node; + } else if (node is VariableDeclarator) { + var decl = (VariableDeclarator) node; + return decl.type_reference; + } else if (node is EnumValue || node is FlagsValue) { + var type = new TypeReference (); + type.data_type = (DataType) node.symbol.parent_symbol.node; + return type; + } + return null; + } + + public static Symbol symbol_lookup_inherited (Symbol! sym, string! name) { + var result = sym.lookup (name); + if (result != null) { + return result; + } + + if (sym.node is Class) { + var cl = (Class) sym.node; + foreach (TypeReference base_type in cl.get_base_types ()) { + result = symbol_lookup_inherited (base_type.data_type.symbol, name); + if (result != null) { + return result; + } + } + } else if (sym.node is Struct) { + var st = (Struct) sym.node; + foreach (TypeReference base_type in st.get_base_types ()) { + result = symbol_lookup_inherited (base_type.data_type.symbol, name); + if (result != null) { + return result; + } + } + } else if (sym.node is Interface) { + var iface = (Interface) sym.node; + foreach (TypeReference prerequisite in iface.get_prerequisites ()) { + result = symbol_lookup_inherited (prerequisite.data_type.symbol, name); + if (result != null) { + return result; + } + } + } + + return null; + } + + public override void visit_parenthesized_expression (ParenthesizedExpression! expr) { + expr.static_type = expr.inner.static_type.copy (); + // don't call g_object_ref_sink on inner and outer expression + expr.static_type.floating_reference = false; + } + + private DataType find_parent_type (Symbol sym) { + while (sym != null) { + if (sym.node is DataType) { + return (DataType) sym.node; + } + sym = sym.parent_symbol; + } + return null; + } + + public override void visit_member_access (MemberAccess! expr) { + Symbol base_symbol = null; + + if (expr.inner == null) { + base_symbol = current_symbol; + + var sym = current_symbol; + while (sym != null && expr.symbol_reference == null) { + expr.symbol_reference = symbol_lookup_inherited (sym, expr.member_name); + sym = sym.parent_symbol; + } + + if (expr.symbol_reference == null) { + foreach (NamespaceReference ns in current_using_directives) { + var local_sym = ns.namespace_symbol.lookup (expr.member_name); + if (local_sym != null) { + if (expr.symbol_reference != null) { + expr.error = true; + Report.error (expr.source_reference, "`%s' is an ambiguous reference between `%s' and `%s'".printf (expr.member_name, expr.symbol_reference.get_full_name (), local_sym.get_full_name ())); + return; + } + expr.symbol_reference = local_sym; + } + } + } + } else { + if (expr.inner.error) { + /* if there was an error in the inner expression, skip this check */ + expr.error = true; + return; + } + + if (expr.inner is MemberAccess || expr.inner is BaseAccess) { + base_symbol = expr.inner.symbol_reference; + if (base_symbol.node is Namespace || + base_symbol.node is DataType) { + expr.symbol_reference = base_symbol.lookup (expr.member_name); + } + } + + if (expr.symbol_reference == null && expr.inner.static_type != null) { + base_symbol = expr.inner.static_type.data_type.symbol; + expr.symbol_reference = symbol_lookup_inherited (base_symbol, expr.member_name); + } + } + + if (expr.symbol_reference == null) { + expr.error = true; + Report.error (expr.source_reference, "The name `%s' does not exist in the context of `%s'".printf (expr.member_name, base_symbol.get_full_name ())); + return; + } + + var member = expr.symbol_reference.node; + MemberAccessibility access = MemberAccessibility.PUBLIC; + if (member is Field) { + access = ((Field) member).access; + } else if (member is Method) { + access = ((Method) member).access; + } + + if (access == MemberAccessibility.PRIVATE) { + var target_type = (DataType) member.symbol.parent_symbol.node; + var this_type = find_parent_type (current_symbol); + + if (target_type != this_type) { + expr.error = true; + Report.error (expr.source_reference, "Access to private member `%s' denied".printf (member.symbol.get_full_name ())); + return; + } + } + + current_source_file.add_symbol_dependency (expr.symbol_reference, SourceFileDependencyType.SOURCE); + + expr.static_type = get_static_type_for_node (expr.symbol_reference.node); + } + + private bool is_type_compatible (TypeReference! expression_type, TypeReference! expected_type) { + /* only null is compatible to null */ + if (expected_type.data_type == null && expected_type.type_parameter == null) { + return (expression_type.data_type == null && expected_type.type_parameter == null); + } + + if (expression_type.data_type == null) { + /* null can be cast to any reference or array type or pointer type */ + if (expected_type.type_parameter != null || + expected_type.data_type.is_reference_type () || + expected_type.reference_to_value_type || + expected_type.data_type is Pointer || + expected_type.data_type is Array || + expected_type.data_type is Callback || + expected_type.data_type == pointer_type) { + return true; + } + + /* null is not compatible with any other type (i.e. value types) */ + return false; + } + + /* temporarily ignore type parameters */ + if (expected_type.type_parameter != null) { + return true; + } + + if (expression_type.data_type is Array != expected_type.data_type is Array) { + return false; + } + + if (expression_type.data_type is Enum && expected_type.data_type == int_type.data_type) { + return true; + } + + if (expression_type.data_type == expected_type.data_type) { + return true; + } + + if (expression_type.data_type is Struct && expected_type.data_type is Struct) { + var expr_struct = (Struct) expression_type.data_type; + var expect_struct = (Struct) expected_type.data_type; + + /* integer types may be implicitly cast to floating point types */ + if (expr_struct.is_integer_type () && expect_struct.is_floating_type ()) { + return true; + } + + if ((expr_struct.is_integer_type () && expect_struct.is_integer_type ()) || + (expr_struct.is_floating_type () && expect_struct.is_floating_type ())) { + if (expr_struct.get_rank () <= expect_struct.get_rank ()) { + return true; + } + } + } + + return expression_type.data_type.is_subtype_of (expected_type.data_type); + } + + public override void visit_begin_invocation_expression (InvocationExpression! expr) { + if (expr.call.error) { + /* if method resolving didn't succeed, skip this check */ + expr.error = true; + return; + } + + var msym = expr.call.symbol_reference; + + if (msym == null) { + /* if no symbol found, skip this check */ + expr.error = true; + return; + } + + List<weak FormalParameter> params; + + if (msym.node is Invokable) { + var m = (Invokable) msym.node; + if (m.is_invokable ()) { + params = m.get_parameters (); + } else { + expr.error = true; + Report.error (expr.source_reference, "invocation not supported in this context"); + return; + } + } else { + expr.error = true; + Report.error (expr.source_reference, "invocation not supported in this context"); + return; + } + + var args = expr.get_argument_list (); + weak List<weak Expression> arg_it = args; + foreach (FormalParameter param in params) { + if (param.ellipsis) { + break; + } + + if (arg_it != null) { + var arg = (Expression) arg_it.data; + + /* store expected type for callback parameters */ + arg.expected_type = param.type_reference; + + arg_it = arg_it.next; + } + } + } + + private bool check_arguments (Expression! expr, Symbol! msym, List<FormalParameter> params, List<Expression> args) { + weak List<weak Expression> prev_arg_it = null; + weak List<weak Expression> arg_it = args; + + bool diag = (msym.node.get_attribute ("Diagnostics") != null); + + bool ellipsis = false; + int i = 0; + foreach (FormalParameter param in params) { + if (param.ellipsis) { + ellipsis = true; + break; + } + + /* header file necessary if we need to cast argument */ + if (param.type_reference.data_type != null) { + current_source_file.add_symbol_dependency (param.type_reference.data_type.symbol, SourceFileDependencyType.SOURCE); + } + + 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 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 false; + } + + prev_arg_it = arg_it; + arg_it = arg_it.next; + + i++; + } + } + + 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; + } + + if (diag && prev_arg_it != null) { + var format_arg = (Expression) prev_arg_it.data; + if (format_arg is LiteralExpression) { + var format_lit = (StringLiteral) ((LiteralExpression) format_arg).literal; + format_lit.value = "\"%s:%d: %s".printf (expr.source_reference.file.filename, expr.source_reference.first_line, format_lit.value.offset (1)); + } + } + + return true; + } + + public override void visit_end_invocation_expression (InvocationExpression! expr) { + if (expr.error) { + return; + } + + var msym = expr.call.symbol_reference; + + ref TypeReference ret_type; + List<weak FormalParameter> params; + + if (msym.node is Invokable) { + var m = (Invokable) msym.node; + ret_type = m.get_return_type (); + params = m.get_parameters (); + + if (ret_type.data_type == null && ret_type.type_parameter == null) { + // void return type + if (!(expr.parent_node is ExpressionStatement)) { + expr.error = true; + Report.error (expr.source_reference, "invocation of void method not allowed as expression"); + return; + } + } + + // resolve generic return values + if (ret_type.type_parameter != null) { + if (!(expr.call is MemberAccess)) { + Report.error (((CodeNode) m).source_reference, "internal error: unsupported generic return value"); + expr.error = true; + return; + } + var ma = (MemberAccess) expr.call; + if (ma.inner == null) { + // TODO resolve generic return values within the type hierarchy if possible + Report.error (expr.source_reference, "internal error: resolving generic return values within type hierarchy not supported yet"); + expr.error = true; + return; + } else { + ref TypeReference instance_type = ma.inner.static_type; + // trace type arguments back to the datatype where the method has been declared + while (instance_type.data_type != msym.parent_symbol.node) { + List<weak TypeReference> base_types = null; + if (instance_type.data_type is Class) { + var cl = (Class) instance_type.data_type; + base_types = cl.get_base_types (); + } else if (instance_type.data_type is Interface) { + var iface = (Interface) instance_type.data_type; + base_types = iface.get_prerequisites (); + } else { + Report.error (expr.source_reference, "internal error: unsupported generic type"); + expr.error = true; + return; + } + foreach (TypeReference base_type in base_types) { + if (symbol_lookup_inherited (base_type.data_type.symbol, msym.name) != null) { + // construct a new type reference for the base type with correctly linked type arguments + var instance_base_type = new TypeReference (); + instance_base_type.data_type = base_type.data_type; + foreach (TypeReference type_arg in base_type.get_type_arguments ()) { + if (type_arg.type_parameter != null) { + // link to type argument of derived type + int param_index = instance_type.data_type.get_type_parameter_index (type_arg.type_parameter.name); + if (param_index == -1) { + Report.error (expr.source_reference, "internal error: unknown type parameter %s".printf (type_arg.type_parameter.name)); + expr.error = true; + return; + } + type_arg = instance_type.get_type_arguments ().nth_data (param_index); + } + instance_base_type.add_type_argument (type_arg); + } + instance_type = instance_base_type; + } + } + } + if (instance_type.data_type != msym.parent_symbol.node) { + Report.error (expr.source_reference, "internal error: generic type parameter tracing not supported yet"); + expr.error = true; + return; + } + int param_index = instance_type.data_type.get_type_parameter_index (ret_type.type_parameter.name); + if (param_index == -1) { + Report.error (expr.source_reference, "internal error: unknown type parameter %s".printf (ret_type.type_parameter.name)); + expr.error = true; + return; + } + ret_type = (TypeReference) instance_type.get_type_arguments ().nth_data (param_index); + if (ret_type == null) { + Report.error (expr.source_reference, "internal error: no actual argument found for type parameter %s".printf (ret_type.type_parameter.name)); + expr.error = true; + return; + } + } + } + } + + expr.static_type = ret_type; + + check_arguments (expr, msym, params, expr.get_argument_list ()); + } + + public override void visit_element_access (ElementAccess! expr) { + if (expr.container.static_type == null) { + /* don't proceed if a child expression failed */ + expr.error = true; + return; + } + + /* assign a static_type when possible */ + if (expr.container.static_type.data_type is Array) { + var args = expr.container.static_type.get_type_arguments (); + + if (args.length () != 1) { + expr.error = true; + Report.error (expr.source_reference, "internal error: array reference with %d type arguments, expected 1".printf (args.length ())); + return; + } + + expr.static_type = (TypeReference) args.data; + } else { + expr.error = true; + Report.error (expr.source_reference, "The expression `%s' does not denote an Array".printf (expr.container.static_type.to_string ())); + } + + /* check if the index is of type integer */ + foreach (Expression e in expr.get_indices ()) { + /* don't proceed if a child expression failed */ + if (e.static_type == null) { + return; + } + + /* check if the index is of type integer */ + if (!(e.static_type.data_type is Struct) || !((Struct) e.static_type.data_type).is_integer_type ()) { + expr.error = true; + Report.error (e.source_reference, "Expression of integer type expected"); + } + } + } + + public override void visit_base_access (BaseAccess! expr) { + if (current_class == null) { + if (current_struct == null) { + expr.error = true; + Report.error (expr.source_reference, "Base access invalid outside of class and struct"); + return; + } else if (current_struct.get_base_types ().length () != 1) { + expr.error = true; + Report.error (expr.source_reference, "Base access invalid without base type %d".printf (current_struct.get_base_types ().length ())); + return; + } + expr.static_type = current_struct.get_base_types ().first ().data; + } else { + expr.static_type = new TypeReference (); + expr.static_type.data_type = current_class.base_class; + } + + expr.symbol_reference = expr.static_type.data_type.symbol; + } + + public override void visit_postfix_expression (PostfixExpression! expr) { + expr.static_type = expr.inner.static_type; + } + + public override void visit_end_object_creation_expression (ObjectCreationExpression! expr) { + DataType type = null; + + 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; + + var type_args = expr.member_name.get_type_arguments (); + + if (constructor_node is Method) { + type_node = constructor_node.symbol.parent_symbol.node; + + var constructor = (Method) constructor_node; + if (!(constructor_node is CreationMethod)) { + expr.error = true; + Report.error (expr.source_reference, "`%s' is not a creation method".printf (constructor.symbol.get_full_name ())); + return; + } + + expr.symbol_reference = constructor.symbol; + + type_args = ((MemberAccess) expr.member_name.inner).get_type_arguments (); + } + + 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; + } + + expr.type_reference = new TypeReference (); + expr.type_reference.data_type = type; + foreach (TypeReference type_arg in type_args) { + expr.type_reference.add_type_argument (type_arg); + } + } else { + type = expr.type_reference.data_type; + } + + 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 (type.symbol, SourceFileDependencyType.SOURCE); + + expr.static_type = expr.type_reference.copy (); + expr.static_type.transfers_ownership = true; + + 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 (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; + break; + } + + cl = cl.base_class; + } + } 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 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_typeof_expression (TypeofExpression! expr) { + expr.static_type = type_type; + } + + private bool is_numeric_type (TypeReference! type) { + if (!(type.data_type is Struct)) { + return false; + } + + var st = (Struct) type.data_type; + return st.is_integer_type () || st.is_floating_type (); + } + + private bool is_integer_type (TypeReference! type) { + if (!(type.data_type is Struct)) { + return false; + } + + var st = (Struct) type.data_type; + return st.is_integer_type (); + } + + public override void visit_unary_expression (UnaryExpression! expr) { + if (expr.inner.error) { + /* if there was an error in the inner expression, skip type check */ + expr.error = true; + return; + } + + if (expr.operator == UnaryOperator.PLUS || expr.operator == UnaryOperator.MINUS) { + // integer or floating point type + if (!is_numeric_type (expr.inner.static_type)) { + expr.error = true; + Report.error (expr.source_reference, "Operator not supported for `%s'".printf (expr.inner.static_type.to_string ())); + return; + } + + expr.static_type = expr.inner.static_type; + } else if (expr.operator == UnaryOperator.LOGICAL_NEGATION) { + // boolean type + if (expr.inner.static_type.data_type != bool_type.data_type) { + expr.error = true; + Report.error (expr.source_reference, "Operator not supported for `%s'".printf (expr.inner.static_type.to_string ())); + return; + } + + expr.static_type = expr.inner.static_type; + } else if (expr.operator == UnaryOperator.BITWISE_COMPLEMENT) { + // integer type + if (!is_integer_type (expr.inner.static_type)) { + expr.error = true; + Report.error (expr.source_reference, "Operator not supported for `%s'".printf (expr.inner.static_type.to_string ())); + return; + } + + expr.static_type = expr.inner.static_type; + } else if (expr.operator == UnaryOperator.INCREMENT || + expr.operator == UnaryOperator.DECREMENT) { + // integer type + if (!is_integer_type (expr.inner.static_type)) { + expr.error = true; + Report.error (expr.source_reference, "Operator not supported for `%s'".printf (expr.inner.static_type.to_string ())); + return; + } + + var ma = find_member_access (expr.inner); + if (ma == null) { + expr.error = true; + Report.error (expr.source_reference, "Prefix operators not supported for this expression"); + return; + } + + var old_value = new MemberAccess (ma.inner, ma.member_name); + var bin = new BinaryExpression (expr.operator == UnaryOperator.INCREMENT ? BinaryOperator.PLUS : BinaryOperator.MINUS, old_value, new LiteralExpression (new IntegerLiteral ("1"))); + + var assignment = new Assignment (ma, bin); + expr.parent_node.replace (expr, assignment); + assignment.accept (this); + return; + } else if (expr.operator == UnaryOperator.REF) { + // value type + + expr.static_type = expr.inner.static_type; + } else if (expr.operator == UnaryOperator.OUT) { + // reference type + + expr.static_type = expr.inner.static_type; + } else { + expr.error = true; + Report.error (expr.source_reference, "internal error: unsupported unary operator"); + return; + } + } + + private MemberAccess find_member_access (Expression! expr) { + if (expr is ParenthesizedExpression) { + var pe = (ParenthesizedExpression) expr; + return find_member_access (pe.inner); + } + + if (expr is MemberAccess) { + return (MemberAccess) expr; + } + + return null; + } + + public override void visit_cast_expression (CastExpression! expr) { + if (expr.type_reference.data_type == null && expr.type_reference.type_parameter == null) { + /* if type resolving didn't succeed, skip this check */ + return; + } + + // FIXME: check whether cast is allowed + + if (expr.type_reference.data_type != null) { + current_source_file.add_symbol_dependency (expr.type_reference.data_type.symbol, SourceFileDependencyType.SOURCE); + } + + expr.static_type = expr.type_reference; + } + + public override void visit_pointer_indirection (PointerIndirection! expr) { + if (expr.inner.error) { + return; + } + if (expr.inner.static_type == null) { + expr.error = true; + Report.error (expr.source_reference, "internal error: unknown type of inner expression"); + return; + } + if (!(expr.inner.static_type.data_type is Pointer)) { + expr.error = true; + Report.error (expr.source_reference, "Pointer indirection not supported for this expression"); + return; + } + + var pointer = (Pointer) expr.inner.static_type.data_type; + + expr.static_type = new TypeReference (); + expr.static_type.data_type = pointer.referent_type; + expr.static_type.takes_ownership = expr.inner.static_type.takes_ownership; + } + + public override void visit_addressof_expression (AddressofExpression! expr) { + if (expr.inner.error) { + return; + } + if (expr.inner.static_type == null) { + expr.error = true; + Report.error (expr.source_reference, "internal error: unknown type of inner expression"); + return; + } + if (expr.inner.static_type.data_type == null) { + expr.error = true; + Report.error (expr.source_reference, "Address-of operator not supported for this expression"); + return; + } + + expr.static_type = new TypeReference (); + expr.static_type.data_type = expr.inner.static_type.data_type.get_pointer (); + expr.static_type.takes_ownership = expr.inner.static_type.takes_ownership; + } + + public override void visit_reference_transfer_expression (ReferenceTransferExpression! expr) { + if (expr.inner.error) { + /* if there was an error in the inner expression, skip type check */ + expr.error = true; + return; + } + + if (!(expr.inner is MemberAccess || expr.inner is ElementAccess)) { + expr.error = true; + Report.error (expr.source_reference, "Reference transfer not supported for this expression"); + return; + } + + if (!expr.inner.static_type.takes_ownership) { + expr.error = true; + Report.error (expr.source_reference, "No reference to be transferred"); + return; + } + + expr.static_type = expr.inner.static_type.copy (); + expr.static_type.transfers_ownership = true; + expr.static_type.takes_ownership = false; + } + + private ref TypeReference get_arithmetic_result_type (TypeReference! left_type, TypeReference! right_type) { + if (!(left_type.data_type is Struct) || !(right_type.data_type is Struct)) { + // at least one operand not struct + return null; + } + + var left = (Struct) left_type.data_type; + var right = (Struct) right_type.data_type; + + if ((!left.is_floating_type () && !left.is_integer_type ()) || + (!right.is_floating_type () && !right.is_integer_type ())) { + // at least one operand not numeric + return null; + } + + if (left.is_floating_type () == right.is_floating_type ()) { + // both operands integer or floating type + if (left.get_rank () >= right.get_rank ()) { + return left_type; + } else { + return right_type; + } + } else { + // one integer and one floating type operand + if (left.is_floating_type ()) { + return left_type; + } else { + return right_type; + } + } + } + + public override void visit_binary_expression (BinaryExpression! expr) { + if (expr.left.error || expr.right.error) { + /* if there were any errors in inner expressions, skip type check */ + expr.error = true; + return; + } + + if (expr.left.static_type.data_type == string_type.data_type + && expr.operator == BinaryOperator.PLUS) { + if (expr.right.static_type.data_type != string_type.data_type) { + expr.error = true; + Report.error (expr.source_reference, "Operands must be strings"); + return; + } + + /* string concatenation: convert to a.concat (b) */ + + var concat_call = new InvocationExpression (new MemberAccess (expr.left, "concat")); + concat_call.add_argument (expr.right); + + expr.parent_node.replace (expr, concat_call); + + concat_call.accept (this); + } else if (expr.operator == BinaryOperator.PLUS + || expr.operator == BinaryOperator.MINUS + || expr.operator == BinaryOperator.MUL + || expr.operator == BinaryOperator.DIV) { + expr.static_type = get_arithmetic_result_type (expr.left.static_type, expr.right.static_type); + + if (expr.static_type == null) { + expr.error = true; + Report.error (expr.source_reference, "Arithmetic operation not supported for types `%s' and `%s'".printf (expr.left.static_type.to_string (), expr.right.static_type.to_string ())); + return; + } + } else if (expr.operator == BinaryOperator.MOD + || expr.operator == BinaryOperator.SHIFT_LEFT + || expr.operator == BinaryOperator.SHIFT_RIGHT + || expr.operator == BinaryOperator.BITWISE_XOR) { + expr.static_type = get_arithmetic_result_type (expr.left.static_type, expr.right.static_type); + + if (expr.static_type == null) { + expr.error = true; + Report.error (expr.source_reference, "Arithmetic operation not supported for types `%s' and `%s'".printf (expr.left.static_type.to_string (), expr.right.static_type.to_string ())); + return; + } + } else if (expr.operator == BinaryOperator.LESS_THAN + || expr.operator == BinaryOperator.GREATER_THAN + || expr.operator == BinaryOperator.LESS_THAN_OR_EQUAL + || expr.operator == BinaryOperator.GREATER_THAN_OR_EQUAL) { + if (expr.left.static_type.data_type == string_type.data_type + && expr.right.static_type.data_type == string_type.data_type) { + /* string comparison: convert to a.collate (b) OP 0 */ + + var cmp_call = new InvocationExpression (new MemberAccess (expr.left, "collate")); + cmp_call.add_argument (expr.right); + expr.left = cmp_call; + + expr.right = new LiteralExpression (new IntegerLiteral ("0")); + + expr.left.accept (this); + } else { + var resulting_type = get_arithmetic_result_type (expr.left.static_type, expr.right.static_type); + + if (resulting_type == null) { + expr.error = true; + Report.error (expr.source_reference, "Relational operation not supported for types `%s' and `%s'".printf (expr.left.static_type.to_string (), expr.right.static_type.to_string ())); + return; + } + } + + expr.static_type = bool_type; + } else if (expr.operator == BinaryOperator.EQUALITY + || expr.operator == BinaryOperator.INEQUALITY) { + /* relational operation */ + + if (!is_type_compatible (expr.right.static_type, expr.left.static_type) + && !is_type_compatible (expr.left.static_type, expr.right.static_type)) { + Report.error (expr.source_reference, "Equality operation: `%s' and `%s' are incompatible, comparison would always evaluate to false".printf (expr.right.static_type.to_string (), expr.left.static_type.to_string ())); + expr.error = true; + return; + } + + if (expr.left.static_type.data_type == string_type.data_type + && expr.right.static_type.data_type == string_type.data_type) { + /* string comparison: convert to a.collate (b) OP 0 */ + + var cmp_call = new InvocationExpression (new MemberAccess (expr.left, "collate")); + cmp_call.add_argument (expr.right); + expr.left = cmp_call; + + expr.right = new LiteralExpression (new IntegerLiteral ("0")); + + expr.left.accept (this); + } + + expr.static_type = bool_type; + } else if (expr.operator == BinaryOperator.BITWISE_AND + || expr.operator == BinaryOperator.BITWISE_OR) { + // integer type or flags type + + expr.static_type = expr.left.static_type; + } else if (expr.operator == BinaryOperator.AND + || expr.operator == BinaryOperator.OR) { + if (expr.left.static_type.data_type != bool_type.data_type || expr.right.static_type.data_type != bool_type.data_type) { + expr.error = true; + Report.error (expr.source_reference, "Operands must be boolean"); + } + + expr.static_type = bool_type; + } else { + assert_not_reached (); + } + } + + public override void visit_type_check (TypeCheck! expr) { + if (expr.type_reference.data_type == null) { + /* if type resolving didn't succeed, skip this check */ + expr.error = true; + return; + } + + current_source_file.add_symbol_dependency (expr.type_reference.data_type.symbol, SourceFileDependencyType.SOURCE); + + expr.static_type = bool_type; + } + + private TypeReference compute_common_base_type (List<TypeReference> types) { + bool null_found = false; + bool class_or_iface_found = false; + bool type_param_found = false; + bool ref_struct_found = false; + bool val_struct_found = false; + bool enum_found = false; + bool callback_found = false; + TypeReference base_type = null; + TypeReference last_type = null; + foreach (TypeReference type in types) { + last_type = type; + if (type.error) { + base_type = new TypeReference (); + base_type.error = true; + return base_type; + } + if (type.data_type == null && type.type_parameter == null) { + if (!null_found) { + null_found = true; + if (val_struct_found || enum_found) { + base_type.error = true; + break; + } + } + } else if (type.data_type is Class || type.data_type is Interface) { + if (!class_or_iface_found) { + class_or_iface_found = true; + if (type_param_found || ref_struct_found || val_struct_found || enum_found || callback_found) { + base_type.error = true; + break; + } + } + } else if (type.type_parameter != null) { + if (!type_param_found) { + type_param_found = true; + if (class_or_iface_found || ref_struct_found || val_struct_found || enum_found || callback_found) { + base_type.error = true; + break; + } + } + } else if (type.data_type is Struct) { + var st = (Struct) type.data_type; + if (st.is_reference_type ()) { + if (!ref_struct_found) { + ref_struct_found = true; + if (class_or_iface_found || type_param_found || val_struct_found || enum_found || callback_found) { + base_type.error = true; + break; + } + } + } else { + if (!val_struct_found) { + val_struct_found = true; + if (class_or_iface_found || type_param_found || ref_struct_found || enum_found || callback_found) { + base_type.error = true; + break; + } + } + } + } else if (type.data_type is Enum) { + if (!enum_found) { + enum_found = true; + if (class_or_iface_found || type_param_found || ref_struct_found || val_struct_found) { + base_type.error = true; + break; + } + } + } else if (type.data_type is Callback) { + if (!callback_found) { + callback_found = true; + if (class_or_iface_found || type_param_found || ref_struct_found || val_struct_found || enum_found) { + base_type.error = true; + break; + } + } + } else { + base_type = new TypeReference (); + base_type.error = true; + Report.error (type.source_reference, "internal error: unsupported type `%s'".printf (type.to_string ())); + return base_type; + } + if (base_type == null) { + base_type = new TypeReference (); + base_type.data_type = type.data_type; + base_type.type_parameter = type.type_parameter; + base_type.non_null = type.non_null; + base_type.is_null = type.is_null; + base_type.transfers_ownership = type.transfers_ownership; + } else { + if (base_type.data_type != type.data_type) { + if (is_type_compatible (type, base_type)) { + } else if (is_type_compatible (base_type, type)) { + base_type.data_type = type.data_type; + } else { + base_type.error = true; + break; + } + } + base_type.non_null = base_type.non_null && type.non_null; + base_type.is_null = base_type.is_null && type.is_null; + // if one subexpression transfers ownership, all subexpressions must transfer ownership + // FIXME add ref calls to subexpressions that don't transfer ownership + base_type.transfers_ownership = base_type.transfers_ownership || type.transfers_ownership; + } + } + if (base_type != null && base_type.error) { + Report.error (last_type.source_reference, "`%s' is incompatible with `%s'".printf (last_type.to_string (), base_type.to_string ())); + } + return base_type; + } + + public override void visit_conditional_expression (ConditionalExpression! expr) { + if (expr.condition.static_type.data_type != bool_type.data_type) { + expr.error = true; + Report.error (expr.condition.source_reference, "Condition must be boolean"); + return; + } + + /* FIXME: support memory management */ + List<TypeReference> types; + types.append (expr.true_expression.static_type); + types.append (expr.false_expression.static_type); + expr.static_type = compute_common_base_type (types); + } + + private ref string get_lambda_name () { + var result = "__lambda%d".printf (next_lambda_id); + + next_lambda_id++; + + return result; + } + + private Method find_current_method () { + var sym = current_symbol; + while (sym != null) { + if (sym.node is Method) { + return (Method) sym.node; + } + sym = sym.parent_symbol; + } + return null; + } + + private bool is_in_constructor () { + var sym = current_symbol; + while (sym != null) { + if (sym.node is Constructor) { + return true; + } + sym = sym.parent_symbol; + } + return false; + } + + public override void visit_begin_lambda_expression (LambdaExpression! l) { + if (l.expected_type == null || !(l.expected_type.data_type is Callback)) { + l.error = true; + Report.error (l.source_reference, "lambda expression not allowed in this context"); + return; + } + + bool in_instance_method = false; + var current_method = find_current_method (); + if (current_method != null) { + in_instance_method = current_method.instance; + } else { + in_instance_method = is_in_constructor (); + } + + var cb = (Callback) l.expected_type.data_type; + l.method = new Method (get_lambda_name (), cb.return_type); + l.method.instance = cb.instance && in_instance_method; + l.method.symbol = new Symbol (l.method); + l.method.symbol.parent_symbol = current_symbol; + + var lambda_params = l.get_parameters (); + weak List<weak FormalParameter> lambda_param_it = lambda_params; + foreach (FormalParameter cb_param in cb.get_parameters ()) { + if (lambda_param_it == null) { + /* lambda expressions are allowed to have less parameters */ + break; + } + + var lambda_param = (string) lambda_param_it.data; + + var param = new FormalParameter (lambda_param, cb_param.type_reference); + param.symbol = new Symbol (param); + l.method.symbol.add (param.name, param.symbol); + + l.method.add_parameter (param); + + lambda_param_it = lambda_param_it.next; + } + + if (lambda_param_it != null) { + /* lambda expressions may not expect more parameters */ + l.error = true; + Report.error (l.source_reference, "lambda expression: too many parameters"); + return; + } + + if (l.expression_body != null) { + var block = new Block (); + block.symbol = new Symbol (block); + block.symbol.parent_symbol = l.method.symbol; + + if (l.method.return_type.data_type != null) { + block.add_statement (new ReturnStatement (l.expression_body)); + } else { + block.add_statement (new ExpressionStatement (l.expression_body)); + } + + l.method.body = block; + } else { + l.method.body = l.statement_body; + l.method.body.symbol.parent_symbol = l.method.symbol; + } + + /* lambda expressions should be usable like MemberAccess of a method */ + l.symbol_reference = l.method.symbol; + } + + public override void visit_begin_assignment (Assignment! a) { + if (a.left is MemberAccess) { + var ma = (MemberAccess) a.left; + + if (ma.error || ma.symbol_reference == null) { + a.error = true; + /* if no symbol found, skip this check */ + return; + } + + if (ma.symbol_reference.node is Signal) { + var sig = (Signal) ma.symbol_reference.node; + + a.right.expected_type = new TypeReference (); + a.right.expected_type.data_type = sig.get_callback (); + } + } else if (a.left is ElementAccess) { + // do nothing + } else if (a.left is PointerIndirection) { + // do nothing + } else { + a.error = true; + Report.error (a.source_reference, "unsupported lvalue in assignment"); + } + } + + public override void visit_end_assignment (Assignment! a) { + if (a.error || a.left.error || a.right.error) { + a.error = true; + return; + } + + if (a.operator != AssignmentOperator.SIMPLE && a.left is MemberAccess) { + // transform into simple assignment + // FIXME: only do this if the backend doesn't support + // the assignment natively + + var ma = (MemberAccess) a.left; + + if (!(ma.symbol_reference.node is Signal)) { + var old_value = new MemberAccess (ma.inner, ma.member_name); + + var bin = new BinaryExpression (BinaryOperator.PLUS, old_value, new ParenthesizedExpression (a.right, a.right.source_reference)); + + if (a.operator == AssignmentOperator.BITWISE_OR) { + bin.operator = BinaryOperator.BITWISE_OR; + } else if (a.operator == AssignmentOperator.BITWISE_AND) { + bin.operator = BinaryOperator.BITWISE_AND; + } else if (a.operator == AssignmentOperator.BITWISE_XOR) { + bin.operator = BinaryOperator.BITWISE_XOR; + } else if (a.operator == AssignmentOperator.ADD) { + bin.operator = BinaryOperator.PLUS; + } else if (a.operator == AssignmentOperator.SUB) { + bin.operator = BinaryOperator.MINUS; + } else if (a.operator == AssignmentOperator.MUL) { + bin.operator = BinaryOperator.MUL; + } else if (a.operator == AssignmentOperator.DIV) { + bin.operator = BinaryOperator.DIV; + } else if (a.operator == AssignmentOperator.PERCENT) { + bin.operator = BinaryOperator.MOD; + } else if (a.operator == AssignmentOperator.SHIFT_LEFT) { + bin.operator = BinaryOperator.SHIFT_LEFT; + } else if (a.operator == AssignmentOperator.SHIFT_RIGHT) { + bin.operator = BinaryOperator.SHIFT_RIGHT; + } + + a.right = bin; + a.right.accept (this); + + a.operator = AssignmentOperator.SIMPLE; + } + } + + if (a.left is MemberAccess) { + var ma = (MemberAccess) a.left; + + if (ma.symbol_reference.node is Signal) { + var sig = (Signal) ma.symbol_reference.node; + + if (a.right.symbol_reference == null) { + a.error = true; + Report.error (a.right.source_reference, "unsupported expression for signal handler"); + return; + } + + var m = (Method) a.right.symbol_reference.node; + + if (m.instance && m.access != MemberAccessibility.PRIVATE) { + /* TODO: generate wrapper function */ + + ma.error = true; + Report.error (a.right.source_reference, "public instance methods not yet supported as signal handlers"); + return; + } + + if (m.instance) { + /* instance signal handlers must have the self + * parameter at the end + * do not use G_CONNECT_SWAPPED as this would + * rearrange the parameters for instance + * methods and non-instance methods + */ + m.instance_last = true; + } + } else if (ma.symbol_reference.node is Property) { + var prop = (Property) ma.symbol_reference.node; + + if (prop.set_accessor == null) { + ma.error = true; + Report.error (ma.source_reference, "Property `%s' is read-only".printf (prop.symbol.get_full_name ())); + return; + } + } else if (ma.symbol_reference.node is VariableDeclarator && a.right.static_type == null) { + var decl = (VariableDeclarator) ma.symbol_reference.node; + + var right_ma = (MemberAccess) a.right; + if (right_ma.symbol_reference.node is Method && + decl.type_reference.data_type is Callback) { + var m = (Method) right_ma.symbol_reference.node; + var cb = (Callback) decl.type_reference.data_type; + + /* check whether method matches callback type */ + if (!cb.matches_method (m)) { + decl.error = true; + Report.error (a.source_reference, "declaration of method `%s' doesn't match declaration of callback `%s'".printf (m.symbol.get_full_name (), cb.symbol.get_full_name ())); + return; + } + + a.right.static_type = decl.type_reference; + } else { + a.error = true; + Report.error (a.source_reference, "Assignment: Invalid callback assignment attempt"); + return; + } + } else if (ma.symbol_reference.node is Field && a.right.static_type == null) { + var f = (Field) ma.symbol_reference.node; + + var right_ma = (MemberAccess) a.right; + if (right_ma.symbol_reference.node is Method && + f.type_reference.data_type is Callback) { + var m = (Method) right_ma.symbol_reference.node; + var cb = (Callback) f.type_reference.data_type; + + /* check whether method matches callback type */ + if (!cb.matches_method (m)) { + f.error = true; + Report.error (a.source_reference, "declaration of method `%s' doesn't match declaration of callback `%s'".printf (m.symbol.get_full_name (), cb.symbol.get_full_name ())); + return; + } + + a.right.static_type = f.type_reference; + } else { + a.error = true; + Report.error (a.source_reference, "Assignment: Invalid callback assignment attempt"); + return; + } + } else if (a.left.static_type != null && a.right.static_type != null) { + if (!is_type_compatible (a.right.static_type, a.left.static_type)) { + /* if there was an error on either side, + * i.e. a.{left|right}.static_type == null, skip type check */ + a.error = true; + Report.error (a.source_reference, "Assignment: Cannot convert from `%s' to `%s'".printf (a.right.static_type.to_string (), a.left.static_type.to_string ())); + return; + } + + if (memory_management) { + if (a.right.static_type.transfers_ownership) { + /* rhs transfers ownership of the expression */ + if (!a.left.static_type.takes_ownership) { + /* lhs doesn't own the value */ + a.error = true; + Report.error (a.source_reference, "Invalid assignment from owned expression to unowned variable"); + } + } else if (a.left.static_type.takes_ownership) { + /* lhs wants to own the value + * rhs doesn't transfer the ownership + * code generator needs to add reference + * increment calls */ + } + } + } + } else if (a.left is ElementAccess) { + var ea = (ElementAccess) a.left; + + if (!is_type_compatible (a.right.static_type, a.left.static_type)) { + /* if there was an error on either side, + * i.e. a.{left|right}.static_type == null, skip type check */ + a.error = true; + Report.error (a.source_reference, "Assignment: Cannot convert from `%s' to `%s'".printf (a.right.static_type.to_string (), a.left.static_type.to_string ())); + return; + } + + if (memory_management) { + if (a.right.static_type.transfers_ownership) { + /* rhs transfers ownership of the expression */ + + var args = ea.container.static_type.get_type_arguments (); + if (args.length () != 1) { + a.error = true; + Report.error (ea.source_reference, "internal error: array reference without type arguments"); + return; + } + var element_type = (TypeReference) args.data; + + if (!element_type.takes_ownership) { + /* lhs doesn't own the value */ + a.error = true; + Report.error (a.source_reference, "Invalid assignment from owned expression to unowned variable"); + return; + } + } else if (a.left.static_type.takes_ownership) { + /* lhs wants to own the value + * rhs doesn't transfer the ownership + * code generator needs to add reference + * increment calls */ + } + } + } else { + return; + } + + a.static_type = a.left.static_type; + } +} diff --git a/vala/valasignal.vala b/vala/valasignal.vala new file mode 100644 index 000000000..5e10a2c97 --- /dev/null +++ b/vala/valasignal.vala @@ -0,0 +1,189 @@ +/* valasignal.vala + * + * Copyright (C) 2006 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 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 an object signal. Signals enable objects to provide notifications. + */ +public class Vala.Signal : Member, Invokable, Lockable { + /** + * The symbol name of this signal. + */ + public string! name { get; set construct; } + + /** + * The return type of handlers of this signal. + */ + public TypeReference! return_type { get; set construct; } + + /** + * Specifies the accessibility of the signal. Currently only public + * accessibility is supported for signals. + */ + public MemberAccessibility access { get; set; } + + /** + * Specifies whether this signal has an emitter wrapper function. + */ + public bool has_emitter { get; set; } + + private List<FormalParameter> parameters; + private Callback generated_callback; + + private string cname; + + private bool lock_used = false; + + /** + * Creates a new signal. + * + * @param name signal name + * @param return_type signal return type + * @param source reference to source code + * @return newly created signal + */ + public Signal (string! _name, TypeReference! _return_type, SourceReference source) { + name = _name; + return_type = _return_type; + source_reference = source; + } + + /** + * Appends parameter to signal handler. + * + * @param param a formal parameter + */ + public void add_parameter (FormalParameter! param) { + parameters.append (param); + } + + public ref List<weak FormalParameter> get_parameters () { + return parameters.copy (); + } + + public TypeReference get_return_type () { + return return_type; + } + + public bool is_invokable () { + return true; + } + + /** + * Returns generated callback to be used for signal handlers. + * + * @return callback + */ + public Callback! get_callback () { + if (generated_callback == null) { + generated_callback = new Callback (null, return_type); + generated_callback.instance = true; + + var sender_type = new TypeReference (); + sender_type.data_type = (DataType) symbol.parent_symbol.node; + var sender_param = new FormalParameter ("sender", sender_type); + generated_callback.add_parameter (sender_param); + + foreach (FormalParameter! param in parameters) { + generated_callback.add_parameter (param); + } + } + + return generated_callback; + } + + /** + * Returns the name of this signal as it is used in C code. + * + * @return the name to be used in C code + */ + public string! get_cname () { + if (cname == null) { + cname = name; + } + return cname; + } + + public void set_cname (string cname) { + this.cname = cname; + } + + /** + * Returns the string literal of this signal to be used in C code. + * + * @return string literal to be used in C code + */ + public ref CCodeConstant! get_canonical_cconstant () { + var str = new String ("\""); + + 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 (); + } + + str.append_c ('"'); + + return new CCodeConstant (str.str); + } + + public override void accept (CodeVisitor! visitor) { + visitor.visit_member (this); + + visitor.visit_begin_signal (this); + + return_type.accept (visitor); + + foreach (FormalParameter param in parameters) { + param.accept (visitor); + } + + visitor.visit_end_signal (this); + } + + /** + * Process all associated attributes. + */ + public void process_attributes () { + foreach (Attribute a in attributes) { + if (a.name == "HasEmitter") { + has_emitter = true; + } + } + } + + public bool get_lock_used () { + return lock_used; + } + + public void set_lock_used (bool used) { + lock_used = used; + } +} diff --git a/vala/valasourcefile.vala b/vala/valasourcefile.vala new file mode 100644 index 000000000..11972d536 --- /dev/null +++ b/vala/valasourcefile.vala @@ -0,0 +1,355 @@ +/* valasourcefile.vala + * + * Copyright (C) 2006 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 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 Vala source or VAPI package file. + */ +public class Vala.SourceFile { + /** + * The name of this source file. + */ + public string! filename { get; set construct; } + + /** + * The header comment of this source file. + */ + public string comment { get; set; } + + /** + * Specifies whether this file is a VAPI package file. + */ + public bool pkg { get; set; } + + /** + * Specifies the dependency cycle this source file is member of. If this + * source file is in a cycle, all type definitions of that cycle will + * only be written to the C header file of the cycle head. + */ + public SourceFileCycle cycle { get; set; } + + /** + * Specifies whether this source file is the head of the cycle, if it is + * in a cycle at all. + */ + public bool is_cycle_head { get; set; } + + /** + * Mark used for cycle detection. + * + * 0: not yet visited + * 1: currently visiting + * 2: already visited + */ + public int mark { get; set; } + + /** + * The context this source file belongs to. + */ + public weak CodeContext context { get; set; } + + private List<NamespaceReference> using_directives; + + private Namespace global_namespace; + private List<Namespace> namespaces; + + private string cheader_filename = null; + private string csource_filename = null; + private string cinclude_filename = null; + + private List<string> header_external_includes; + private List<string> header_internal_includes; + private List<string> source_external_includes; + private List<string> source_internal_includes; + + private List<weak SourceFile> header_internal_full_dependencies; + private List<weak SourceFile> header_internal_dependencies; + + /** + * Creates a new source file. + * + * @param filename source file name + * @param pkg true if this is a VAPI package file + * @return newly created source file + */ + public SourceFile (CodeContext! _context, string! _filename, bool _pkg = false) { + context = _context; + filename = _filename; + pkg = _pkg; + } + + construct { + global_namespace = new Namespace (null, new SourceReference (this)); + } + + /** + * Adds a new using directive with the specified namespace. + * + * @param ns reference to namespace + */ + public void add_using_directive (NamespaceReference! ns) { + using_directives.append (ns); + } + + /** + * Returns a copy of the list of using directives. + * + * @return using directive list + */ + public ref List<weak NamespaceReference> get_using_directives () { + return using_directives.copy (); + } + + /** + * Adds the specified namespace to this source file. + * + * @param ns a namespace + */ + public void add_namespace (Namespace! ns) { + namespaces.append (ns); + } + + /** + * Returns the implicitly declared root namespace of this source file. + * + * @return root namespace + */ + public Namespace! get_global_namespace () { + return global_namespace; + } + + /** + * Returns a copy of the list of namespaces. + * + * @return namespace list + */ + public ref List<weak Namespace> get_namespaces () { + return namespaces.copy (); + } + + /** + * Visits this source file and all children with the specified + * CodeVisitor. + * + * @param visitor the visitor to be called while traversing + */ + public void accept (CodeVisitor! visitor) { + visitor.visit_begin_source_file (this); + + foreach (NamespaceReference ns_ref in using_directives) { + ns_ref.accept (visitor); + } + + global_namespace.accept (visitor); + + foreach (Namespace ns in namespaces) { + ns.accept (visitor); + } + + visitor.visit_end_source_file (this); + } + + /** + * Returns the filename to use when generating C header files. + * + * @return generated C header filename + */ + public string! get_cheader_filename () { + if (cheader_filename == null) { + var basename = filename.ndup ((uint) (filename.len () - ".vala".len ())); + cheader_filename = "%s.h".printf (basename); + } + return cheader_filename; + } + + /** + * Returns the filename to use when generating C source files. + * + * @return generated C source filename + */ + public string! get_csource_filename () { + if (csource_filename == null) { + var basename = filename.ndup ((uint) (filename.len () - ".vala".len ())); + csource_filename = "%s.c".printf (basename); + } + return csource_filename; + } + + /** + * Returns the filename to use when including the generated C header + * file. + * + * @return C header filename to include + */ + public string! get_cinclude_filename () { + if (cinclude_filename == null) { + var basename = filename.ndup ((uint) (filename.len () - ".vala".len ())); + if (context.library != null) { + cinclude_filename = "%s/%s.h".printf (context.library, basename); + } else { + cinclude_filename = "%s.h".printf (basename); + } + } + return cinclude_filename; + } + + /** + * Adds the specified symbol to the list of symbols code in this source + * file depends on. + * + * @param sym a symbol + * @param dep_type type of dependency + */ + public void add_symbol_dependency (Symbol! sym, SourceFileDependencyType dep_type) { + DataType t; + + if (sym.node is DataType) { + t = (DataType) sym.node; + } else if (sym.node is Method || sym.node is Field) { + if (sym.parent_symbol.node is DataType) { + t = (DataType) sym.parent_symbol.node; + } else { + return; + } + } else if (sym.node is Property) { + t = (DataType) sym.parent_symbol.node; + } else if (sym.node is Constant) { + if (sym.parent_symbol.node is DataType) { + t = (DataType) sym.parent_symbol.node; + } else if (sym.parent_symbol.node is Namespace) { + var ns = (Namespace) sym.parent_symbol.node; + source_internal_includes.concat (ns.get_cheader_filenames ()); + return; + } else { + return; + } + } else if (sym.node is FormalParameter) { + var fp = (FormalParameter) sym.node; + t = fp.type_reference.data_type; + if (t == null) { + /* generic type parameter */ + return; + } + } else { + return; + } + + if (dep_type == SourceFileDependencyType.SOURCE) { + if (t.source_reference.file.pkg) { + source_external_includes.concat (t.get_cheader_filenames ()); + } else { + source_internal_includes.concat (t.get_cheader_filenames ()); + } + return; + } + + if (t.source_reference.file.pkg) { + /* external package */ + header_external_includes.concat (t.get_cheader_filenames ()); + return; + } + + if (dep_type == SourceFileDependencyType.HEADER_FULL || !t.is_reference_type ()) { + header_internal_includes.concat (t.get_cheader_filenames ()); + header_internal_full_dependencies.append (t.source_reference.file); + } + + header_internal_dependencies.append (t.source_reference.file); + } + + /** + * Returns the list of external includes the generated C header file + * requires. + * + * @return external include list for C header file + */ + public weak List<string> get_header_external_includes () { + return header_external_includes; + } + + /** + * Adds the specified filename to the list of package-internal includes + * the generated C header file requires. + * + * @param include internal include for C header file + */ + public void add_header_internal_include (string! include) { + header_internal_includes.append (include); + } + + /** + * Returns the list of package-internal includes the generated C header + * file requires. + * + * @return internal include list for C header file + */ + public weak List<string> get_header_internal_includes () { + return header_internal_includes; + } + + /** + * Returns the list of external includes the generated C source file + * requires. + * + * @return include list for C source file + */ + public weak List<string> get_source_external_includes () { + return source_external_includes; + } + + /** + * Returns the list of package-internal includes the generated C source + * file requires. + * + * @return include list for C source file + */ + public weak List<string> get_source_internal_includes () { + return source_internal_includes; + } + + /** + * Returns the list of source files the generated C header file requires + * definitely. + * + * @return definite source file dependencies + */ + public weak List<SourceFile> get_header_internal_full_dependencies () { + return header_internal_full_dependencies; + } + + /** + * Returns the list of source files the generated C header file loosely + * depends on. + * + * @return loose source file dependencies + */ + public weak List<SourceFile> get_header_internal_dependencies () { + return header_internal_dependencies; + } +} + +public enum Vala.SourceFileDependencyType { + HEADER_FULL, + HEADER_SHALLOW, + SOURCE +} diff --git a/vala/valasourcefilecycle.vala b/vala/valasourcefilecycle.vala new file mode 100644 index 000000000..e77f6cd4e --- /dev/null +++ b/vala/valasourcefilecycle.vala @@ -0,0 +1,38 @@ +/* valasourcefilecycle.vala + * + * Copyright (C) 2006 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 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 dependency cycle of source files. + */ +public class Vala.SourceFileCycle { + /** + * The members of this source file cycle. + */ + public List<weak SourceFile> files; + + /** + * The head of this source file cycle. + */ + public weak SourceFile head; +} diff --git a/vala/valasourcereference.vala b/vala/valasourcereference.vala new file mode 100644 index 000000000..8bc2f2d60 --- /dev/null +++ b/vala/valasourcereference.vala @@ -0,0 +1,103 @@ +/* valasourcereference.vala + * + * Copyright (C) 2006 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 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> + */ + +/** + * Represents a reference to a location in a source file. + */ +public class Vala.SourceReference { + /** + * The source file to be referenced. + */ + public weak SourceFile file { get; set; } + + /** + * The first line number of the referenced source code. + */ + public int first_line { get; set; } + + /** + * The first column number of the referenced source code. + */ + public int first_column { get; set; } + + /** + * The last line number of the referenced source code. + */ + public int last_line { get; set; } + + /** + * The last column number of the referenced source code. + */ + public int last_column { get; set; } + + /** + * The text describing the referenced source code. + */ + public string comment { get; set; } + + /** + * Creates a new source reference. + * + * @param file a source file + * @param first_line first line number + * @param first_column first column number + * @param last_line last line number + * @param last_column last column number + * @return newly created source reference + */ + public SourceReference (SourceFile _file, int _first_line = 0, int _first_column = 0, int _last_line = 0, int _last_column = 0) { + file = _file; + first_line = _first_line; + first_column = _first_column; + last_line = _last_line; + last_column = _last_column; + } + + /** + * Creates a new commented source reference. + * + * @param file a source file + * @param first_line first line number + * @param first_column first column number + * @param last_line last line number + * @param last_column last column number + * @param comment code comment + * @return newly created source reference + */ + public SourceReference.with_comment (SourceFile _file, int _first_line, int _first_column, int _last_line, int _last_column, string _comment) { + file = _file; + first_line = _first_line; + first_column = _first_column; + last_line = _last_line; + last_column = _last_column; + comment = _comment; + } + + /** + * Returns a string representation of this source reference. + * + * @return human-readable string + */ + public ref string! to_string () { + return ("%s:%d.%d-%d.%d".printf (file.filename, first_line, first_column, last_line, last_column)); + } +} diff --git a/vala/valastatement.vala b/vala/valastatement.vala new file mode 100644 index 000000000..75cc69af5 --- /dev/null +++ b/vala/valastatement.vala @@ -0,0 +1,39 @@ +/* valastatement.vala + * + * Copyright (C) 2006-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 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; + +/** + * Base class for all statement types. + */ +public abstract class Vala.Statement : CodeNode { + /** + * 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/valastringliteral.vala b/vala/valastringliteral.vala new file mode 100644 index 000000000..82485910f --- /dev/null +++ b/vala/valastringliteral.vala @@ -0,0 +1,65 @@ +/* valastringliteral.vala + * + * Copyright (C) 2006 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 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 string literal in the source code. + */ +public class Vala.StringLiteral : Literal { + /** + * The literal value. + */ + public string value { get; set; } + + /** + * Creates a new string literal. + * + * @param s the literal value + * @param source reference to source code + * @return newly created string literal + */ + public StringLiteral (string s, SourceReference source) { + value = s; + source_reference = source; + } + + /** + * Evaluates the literal string value. + * + * @return the unescaped string + */ + public ref string eval () { + if (value == null) { + return null; + } + + /* remove quotes */ + var noquotes = value.offset (1).ndup ((uint) (value.len () - 2)); + /* unescape string */ + return noquotes.compress (); + } + + public override void accept (CodeVisitor! visitor) { + visitor.visit_string_literal (this); + } +} diff --git a/vala/valastruct.vala b/vala/valastruct.vala new file mode 100644 index 000000000..3e57c6b93 --- /dev/null +++ b/vala/valastruct.vala @@ -0,0 +1,436 @@ +/* valastruct.vala + * + * Copyright (C) 2006-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 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 struct declaration in the source code. + */ +public class Vala.Struct : DataType { + private List<TypeParameter> type_parameters; + private List<Constant> constants; + private List<Field> fields; + private List<Method> methods; + + private List<TypeReference> base_types; + + private string cname; + private string const_cname; + private string dup_function; + private string free_function; + private string type_id; + private string lower_case_cprefix; + private string lower_case_csuffix; + private bool reference_type; + private bool integer_type; + private bool floating_type; + private int rank; + private string marshaller_type_name; + private string get_value_function; + private string set_value_function; + private string default_value = null; + + /** + * Specifies the default construction method. + */ + public Method default_construction_method { get; set; } + + /** + * Creates a new struct. + * + * @param name type name + * @param source reference to source code + * @return newly created struct + */ + public Struct (string! _name, SourceReference source = null) { + name = _name; + source_reference = source; + } + + /** + * Appends the specified parameter to the list of type parameters. + * + * @param p a type parameter + */ + public void add_type_parameter (TypeParameter! p) { + type_parameters.append (p); + p.type = this; + } + + /** + * Adds the specified constant as a member to this struct. + * + * @param c a constant + */ + public void add_constant (Constant! c) { + constants.append (c); + } + + /** + * Adds the specified field as a member to this struct. + * + * @param f a field + */ + public void add_field (Field! f) { + fields.append (f); + } + + /** + * Returns a copy of the list of fields. + * + * @return list of fields + */ + public ref List<weak Field> get_fields () { + return fields.copy (); + } + + /** + * Adds the specified method as a member to this struct. + * + * @param m a method + */ + public void add_method (Method! m) { + return_if_fail (m != null); + + methods.append (m); + } + + /** + * Returns a copy of the list of methods. + * + * @return list of methods + */ + public ref List<weak Method> get_methods () { + return methods.copy (); + } + + public override void accept (CodeVisitor! visitor) { + visitor.visit_begin_struct (this); + + foreach (TypeParameter p in type_parameters) { + p.accept (visitor); + } + + foreach (Field f in fields) { + f.accept (visitor); + } + + foreach (Constant c in constants) { + c.accept (visitor); + } + + foreach (Method m in methods) { + m.accept (visitor); + } + + visitor.visit_end_struct (this); + } + + public override string get_cname (bool const_type = false) { + if (const_type && const_cname != null) { + return const_cname; + } + + if (cname == null) { + cname = "%s%s".printf (@namespace.get_cprefix (), name); + } + return cname; + } + + private void set_cname (string! cname) { + this.cname = cname; + } + + private void set_const_cname (string! cname) { + this.const_cname = cname; + } + + public override ref string get_lower_case_cprefix () { + if (lower_case_cprefix == null) { + lower_case_cprefix = "%s_".printf (get_lower_case_cname (null)); + } + return lower_case_cprefix; + } + + private string get_lower_case_csuffix () { + if (lower_case_csuffix == null) { + lower_case_csuffix = Namespace.camel_case_to_lower_case (name); + } + return lower_case_csuffix; + } + + private void set_lower_case_csuffix (string! csuffix) { + this.lower_case_csuffix = csuffix; + } + + public override ref string get_lower_case_cname (string infix) { + if (infix == null) { + infix = ""; + } + return "%s%s%s".printf (@namespace.get_lower_case_cprefix (), infix, get_lower_case_csuffix ()); + } + + public override ref string get_upper_case_cname (string infix) { + return get_lower_case_cname (infix).up (); + } + + public override bool is_reference_type () { + return reference_type; + } + + /** + * Returns whether this is an integer type. + * + * @return true if this is an integer type, false otherwise + */ + public bool is_integer_type () { + return integer_type; + } + + /** + * Returns whether this is a floating point type. + * + * @return true if this is a floating point type, false otherwise + */ + public bool is_floating_type () { + return floating_type; + } + + /** + * Returns the rank of this integer or floating point type. + * + * @return the rank if this is an integer or floating point type + */ + public int get_rank () { + return rank; + } + + /** + * Sets whether this data type has value or reference type semantics. + * + * @param ref_type true if this data type has reference type semantics + */ + public void set_is_reference_type (bool ref_type) { + reference_type = ref_type; + } + + private void process_ccode_attribute (Attribute! a) { + if (a.has_argument ("cname")) { + set_cname (a.get_string ("cname")); + } + if (a.has_argument ("const_cname")) { + set_const_cname (a.get_string ("const_cname")); + } + if (a.has_argument ("cprefix")) { + lower_case_cprefix = a.get_string ("cprefix"); + } + if (a.has_argument ("cheader_filename")) { + var val = a.get_string ("cheader_filename"); + foreach (string filename in val.split (",")) { + add_cheader_filename (filename); + } + } + if (a.has_argument ("type_id")) { + set_type_id (a.get_string ("type_id")); + } + if (a.has_argument ("marshaller_type_name")) { + set_marshaller_type_name (a.get_string ("marshaller_type_name")); + } + if (a.has_argument ("get_value_function")) { + set_get_value_function (a.get_string ("get_value_function")); + } + if (a.has_argument ("set_value_function")) { + set_set_value_function (a.get_string ("set_value_function")); + } + if (a.has_argument ("default_value")) { + set_default_value (a.get_string ("default_value")); + } + } + + private void process_ref_type_attribute (Attribute! a) { + reference_type = true; + if (a.has_argument ("dup_function")) { + set_dup_function (a.get_string ("dup_function")); + } + if (a.has_argument ("free_function")) { + set_free_function (a.get_string ("free_function")); + } + } + + private void process_integer_type_attribute (Attribute! a) { + integer_type = true; + if (a.has_argument ("rank")) { + rank = a.get_integer ("rank"); + } + } + + private void process_floating_type_attribute (Attribute! a) { + floating_type = true; + if (a.has_argument ("rank")) { + rank = a.get_integer ("rank"); + } + } + + /** + * Process all associated attributes. + */ + public void process_attributes () { + foreach (Attribute a in attributes) { + if (a.name == "CCode") { + process_ccode_attribute (a); + } else if (a.name == "ReferenceType") { + process_ref_type_attribute (a); + } else if (a.name == "IntegerType") { + process_integer_type_attribute (a); + } else if (a.name == "FloatingType") { + process_floating_type_attribute (a); + } + } + } + + public override bool is_reference_counting () { + return false; + } + + public override string get_dup_function () { + if (dup_function == null) { + Report.error (source_reference, "The type `%s` doesn't contain a copy function".printf (symbol.get_full_name ())); + } + return dup_function; + } + + public void set_dup_function (string! name) { + this.dup_function = name; + } + + public override string get_free_function () { + if (free_function == null) { + Report.error (source_reference, "The type `%s` doesn't contain a free function".printf (symbol.get_full_name ())); + } + return free_function; + } + + private void set_free_function (string! name) { + this.free_function = name; + } + + public override string get_type_id () { + if (type_id == null) { + if (is_reference_type ()) { + type_id = "G_TYPE_POINTER"; + } else { + Report.error (source_reference, "The type `%s` doesn't declare a type id".printf (symbol.get_full_name ())); + } + } + return type_id; + } + + public void set_type_id (string! name) { + this.type_id = name; + } + + public override string get_marshaller_type_name () { + if (marshaller_type_name == null) { + if (is_reference_type ()) { + marshaller_type_name = "POINTER"; + } else { + Report.error (source_reference, "The type `%s` doesn't declare a marshaller type name".printf (symbol.get_full_name ())); + } + } + return marshaller_type_name; + } + + private void set_marshaller_type_name (string! name) { + this.marshaller_type_name = name; + } + + public override string get_get_value_function () { + if (get_value_function == null) { + if (is_reference_type ()) { + return "g_value_get_pointer"; + } else { + Report.error (source_reference, "The value type `%s` doesn't declare a GValue get function".printf (symbol.get_full_name ())); + } + } else { + return get_value_function; + } + } + + public override string get_set_value_function () { + if (set_value_function == null) { + if (is_reference_type ()) { + return "g_value_set_pointer"; + } else { + Report.error (source_reference, "The value type `%s` doesn't declare a GValue set function".printf (symbol.get_full_name ())); + } + } else { + return set_value_function; + } + } + + private void set_get_value_function (string! function) { + get_value_function = function; + } + + private void set_set_value_function (string! function) { + set_value_function = function; + } + + public override string get_default_value () { + return default_value; + } + + private void set_default_value (string! value) { + default_value = value; + } + + /** + * Adds the specified struct to the list of base types of this struct. + * + * @param type a class or interface reference + */ + public void add_base_type (TypeReference! type) { + base_types.append (type); + } + + /** + * Returns a copy of the base type list. + * + * @return list of base types + */ + public ref List<weak TypeReference> get_base_types () { + return base_types.copy (); + } + + public override int get_type_parameter_index (string! name) { + int i = 0; + + foreach (TypeParameter p in type_parameters) { + if (p.name == name) { + return (i); + } + i++; + } + + return -1; + } +} diff --git a/vala/valaswitchlabel.vala b/vala/valaswitchlabel.vala new file mode 100644 index 000000000..6a2e5f9fb --- /dev/null +++ b/vala/valaswitchlabel.vala @@ -0,0 +1,65 @@ +/* valaswitchlabel.vala + * + * Copyright (C) 2006 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 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 switch label in the source code. + */ +public class Vala.SwitchLabel : CodeNode { + /** + * Specifies the label expression. + */ + public Expression expression { get; set; } + + /** + * Creates a new switch case label. + * + * @param expr label expression + * @param source reference to source code + * @return newly created switch case label + */ + public SwitchLabel (Expression expr, SourceReference source = null) { + expression = expr; + source_reference = source; + } + + /** + * Creates a new switch default label. + * + * @param source reference to source code + * @return newly created switch default label + */ + public SwitchLabel.with_default (SourceReference source = null) { + source_reference = source; + } + + public override void accept (CodeVisitor! visitor) { + if (expression != null) { + expression.accept (visitor); + + visitor.visit_end_full_expression (expression); + } + + visitor.visit_switch_label (this); + } +} diff --git a/vala/valaswitchsection.vala b/vala/valaswitchsection.vala new file mode 100644 index 000000000..0bb6fa7a1 --- /dev/null +++ b/vala/valaswitchsection.vala @@ -0,0 +1,99 @@ +/* valaswitchsection.vala + * + * Copyright (C) 2006 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 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 switch section in the source code. + */ +public class Vala.SwitchSection : CodeNode { + private List<SwitchLabel> labels; + private List<Statement> statement_list; + + /** + * Creates a new switch section. + * + * @param source reference to source code + * @return newly created switch section + */ + public SwitchSection (SourceReference source) { + source_reference = source; + } + + /** + * Appends the specified label to the list of switch labels. + * + * @param label a switch label + */ + public void add_label (SwitchLabel! label) { + labels.append (label); + } + + /** + * Returns a copy of the list of switch labels. + * + * @return switch label list + */ + public ref List<weak SwitchLabel> get_labels () { + return labels.copy (); + } + + public bool has_default_label () { + foreach (SwitchLabel label in labels) { + if (label.expression == null) { + return true; + } + } + + return false; + } + + /** + * Appends the specified statement to this switch section. + * + * @param stmt a statement + */ + public void add_statement (Statement! stmt) { + statement_list.append (stmt); + } + + /** + * Returns a copy of the list of statements. + * + * @return statement list + */ + public ref List<weak Statement> get_statements () { + return statement_list.copy (); + } + + public override void accept (CodeVisitor! visitor) { + foreach (SwitchLabel label in labels) { + label.accept (visitor); + } + + foreach (Statement st in statement_list) { + st.accept (visitor); + } + + visitor.visit_switch_section (this); + } +} diff --git a/vala/valaswitchstatement.vala b/vala/valaswitchstatement.vala new file mode 100644 index 000000000..cf7edc641 --- /dev/null +++ b/vala/valaswitchstatement.vala @@ -0,0 +1,92 @@ +/* valaswitchstatement.vala + * + * Copyright (C) 2006 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 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 switch selection statement in the source code. + */ +public class Vala.SwitchStatement : Statement { + /** + * Specifies the switch expression. + */ + public Expression! expression { + get { + return _expression; + } + set construct { + _expression = value; + _expression.parent_node = this; + } + } + + private Expression! _expression; + private List<SwitchSection> sections; + + /** + * Creates a new switch statement. + * + * @param expr switch expression + * @param source reference to source code + * @return newly created switch statement + */ + public SwitchStatement (Expression! expr, SourceReference source) { + expression = expr; + source_reference = source; + } + + /** + * Appends the specified section to the list of switch sections. + * + * @param section a switch section + */ + public void add_section (SwitchSection! section) { + sections.append (section); + } + + /** + * Returns a copy of the list of switch sections. + * + * @return section list + */ + public ref List<weak SwitchSection> get_sections () { + return sections.copy (); + } + + public override void accept (CodeVisitor! visitor) { + expression.accept (visitor); + + visitor.visit_end_full_expression (expression); + + foreach (SwitchSection section in sections) { + section.accept (visitor); + } + + visitor.visit_switch_statement (this); + } + + public override void replace (CodeNode! old_node, CodeNode! new_node) { + if (expression == old_node) { + expression = (Expression) new_node; + } + } +} diff --git a/vala/valasymbol.vala b/vala/valasymbol.vala new file mode 100644 index 000000000..d93eff738 --- /dev/null +++ b/vala/valasymbol.vala @@ -0,0 +1,119 @@ +/* valasymbol.vala + * + * Copyright (C) 2006 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 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 node in the symbol tree. + */ +public class Vala.Symbol { + /** + * The code node that created this symbol, if applicable. + */ + public weak CodeNode node { get; set; } + + /** + * The parent of this symbol. + */ + public weak Symbol parent_symbol { get; set; } + + /** + * The symbol name. + */ + public string name { get; set; } + + /** + * Specifies whether this symbol is active. + * + * Symbols may become inactive when they only apply to a part of a + * scope. This is used for local variables not declared at the beginning + * of the block to determine which variables need to be freed before + * jump statements. + */ + public bool active { get; set; } + + private HashTable<string,Symbol> symbol_table = new HashTable.full (str_hash, str_equal, g_free, g_object_unref); + + /** + * Creates a new symbol. + * + * @param node the corresponding code node + * @return newly created symbol + */ + public Symbol (CodeNode _node = null) { + node = _node; + } + + construct { + active = true; + } + + /** + * Returns the fully expanded name of this symbol for use in + * human-readable messages. + * + * @return full name + */ + public ref string get_full_name () { + if (parent_symbol == null) { + return name; + } + + if (name == null) { + return parent_symbol.get_full_name (); + } + + if (parent_symbol.get_full_name () == null) { + return name; + } + + return "%s.%s".printf (parent_symbol.get_full_name (), name); + } + + /** + * Adds the specified symbol with the specified name to the symbol table + * of this symbol. + * + * @param name name for the specified symbol + * @param sym a symbol + */ + public void add (string! name, Symbol! sym) { + symbol_table.insert (name, sym); + sym.parent_symbol = this; + sym.name = name; + } + + /** + * Returns the symbol stored in the symbol table with the specified + * name. + * + * @param name name of the symbol to be returned + * @return found symbol or null + */ + public Symbol lookup (string! name) { + Symbol sym = symbol_table.lookup (name); + if (sym != null && !sym.active) { + sym = null; + } + return sym; + } +} diff --git a/vala/valasymbolbuilder.vala b/vala/valasymbolbuilder.vala new file mode 100644 index 000000000..0bceb41b5 --- /dev/null +++ b/vala/valasymbolbuilder.vala @@ -0,0 +1,429 @@ +/* valasymbolbuilder.vala + * + * Copyright (C) 2006-2007 Jürg Billeter, Raffaele Sandrini + * + * 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 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> + * Raffaele Sandrini <rasa@gmx.ch> + */ + +using GLib; + +/** + * Code visitor building the symbol tree. + */ +public class Vala.SymbolBuilder : CodeVisitor { + Symbol root; + Symbol current_type; + Symbol current_symbol; + SourceFile current_source_file; + + /** + * Build the symbol tree for the specified code context. + * + * @param context a code context + */ + public void build (CodeContext! context) { + root = context.get_root (); + context.accept (this); + } + + public override void visit_begin_source_file (SourceFile! file) { + current_source_file = file; + } + + public override void visit_begin_namespace (Namespace! ns) { + if (ns.name == null) { + ns.symbol = root; + } + + if (ns.symbol == null) { + ns.symbol = root.lookup (ns.name); + } + if (ns.symbol == null) { + ns.symbol = new Symbol (ns); + root.add (ns.name, ns.symbol); + } + + current_symbol = ns.symbol; + } + + public override void visit_end_namespace (Namespace! ns) { + current_symbol = current_symbol.parent_symbol; + } + + private weak 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); + if (name != null) { + current_symbol.add (name, node.symbol); + } else { + node.symbol.parent_symbol = current_symbol; + } + + return node.symbol; + } + + public override void visit_begin_class (Class! cl) { + var class_symbol = current_symbol.lookup (cl.name); + if (class_symbol == null || !(class_symbol.node is Class)) { + class_symbol = add_symbol (cl.name, cl); + } else { + /* merge this class declaration with existing class symbol */ + var main_class = (Class) class_symbol.node; + foreach (TypeReference base_type in cl.get_base_types ()) { + main_class.add_base_type (base_type); + } + foreach (Field f in cl.get_fields ()) { + main_class.add_field (f); + } + foreach (Method m in cl.get_methods ()) { + main_class.add_method (m); + } + foreach (Property prop in cl.get_properties ()) { + main_class.add_property (prop, true); + } + foreach (Signal sig in cl.get_signals ()) { + main_class.add_signal (sig); + } + if (cl.constructor != null) { + if (main_class.constructor != null) { + cl.error = true; + Report.error (cl.constructor.source_reference, "`%s' already contains a constructor".printf (current_symbol.get_full_name ())); + return; + } + main_class.constructor = cl.constructor; + } + if (cl.destructor != null) { + if (main_class.destructor != null) { + cl.error = true; + Report.error (cl.destructor.source_reference, "`%s' already contains a destructor".printf (current_symbol.get_full_name ())); + return; + } + main_class.destructor = cl.destructor; + } + } + + current_symbol = class_symbol; + } + + public override void visit_end_class (Class! cl) { + if (cl.error) { + /* skip classes with errors */ + return; + } + + current_symbol = current_symbol.parent_symbol; + + if (cl.symbol == null) { + /* remove merged class */ + cl.@namespace.remove_class (cl); + } + } + + public override void visit_begin_struct (Struct! st) { + if (add_symbol (st.name, st) == null) { + return; + } + + current_symbol = st.symbol; + } + + public override void visit_end_struct (Struct! st) { + if (st.error) { + /* skip structs with errors */ + return; + } + + current_symbol = current_symbol.parent_symbol; + } + + public override void visit_begin_interface (Interface! iface) { + if (add_symbol (iface.name, iface) == null) { + return; + } + + current_symbol = iface.symbol; + } + + public override void visit_end_interface (Interface! iface) { + if (iface.error) { + /* skip interfaces with errors */ + return; + } + + current_symbol = current_symbol.parent_symbol; + } + + public override void visit_begin_enum (Enum! en) { + if (add_symbol (en.name, en) == null) { + return; + } + + current_symbol = en.symbol; + } + + public override void visit_end_enum (Enum! en) { + if (en.error) { + /* skip enums with errors */ + return; + } + + current_symbol = current_symbol.parent_symbol; + } + + public override void visit_enum_value (EnumValue! ev) { + ev.symbol = new Symbol (ev); + current_symbol.add (ev.name, ev.symbol); + } + + public override void visit_begin_flags (Flags! fl) { + if (add_symbol (fl.name, fl) == null) { + return; + } + + current_symbol = fl.symbol; + } + + public override void visit_end_flags (Flags! fl) { + if (fl.error) { + /* skip flags with errors */ + return; + } + + current_symbol = current_symbol.parent_symbol; + } + + public override void visit_flags_value (FlagsValue! fv) { + fv.symbol = new Symbol (fv); + current_symbol.add (fv.name, fv.symbol); + } + + public override void visit_begin_callback (Callback! cb) { + if (add_symbol (cb.name, cb) == null) { + return; + } + + current_symbol = cb.symbol; + } + + public override void visit_end_callback (Callback! cb) { + if (cb.error) { + /* skip enums with errors */ + return; + } + + current_symbol = current_symbol.parent_symbol; + } + + public override void visit_constant (Constant! c) { + add_symbol (c.name, c); + } + + public override void visit_field (Field! f) { + add_symbol (f.name, f); + } + + public override void visit_begin_method (Method! m) { + if (add_symbol (m.name, m) == null) { + return; + } + + if (m.instance) { + if (!(m.symbol.parent_symbol.node is DataType)) { + Report.error (m.source_reference, "instance methods not allowed outside of data types"); + + m.error = true; + return; + } + + m.this_parameter = new FormalParameter ("this", new TypeReference ()); + m.this_parameter.type_reference.data_type = (DataType) m.symbol.parent_symbol.node; + m.this_parameter.symbol = new Symbol (m.this_parameter); + current_symbol.add (m.this_parameter.name, m.this_parameter.symbol); + } + + current_symbol = m.symbol; + } + + public override void visit_end_method (Method! m) { + if (m.error) { + /* skip methods with errors */ + return; + } + + current_symbol = current_symbol.parent_symbol; + } + + public override void visit_begin_creation_method (CreationMethod! m) { + if (add_symbol (m.name, m) == null) { + return; + } + + 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; + } + } + + current_symbol = m.symbol; + } + + public override void visit_end_creation_method (CreationMethod! m) { + if (m.error) { + /* skip methods with errors */ + return; + } + + current_symbol = current_symbol.parent_symbol; + } + + public override void visit_formal_parameter (FormalParameter! p) { + if (!p.ellipsis) { + add_symbol (p.name, p); + } + } + + public override void visit_begin_property (Property! prop) { + if (add_symbol (prop.name, prop) == null) { + return; + } + + current_symbol = prop.symbol; + + prop.this_parameter = new FormalParameter ("this", new TypeReference ()); + prop.this_parameter.type_reference.data_type = (DataType) prop.symbol.parent_symbol.node; + prop.this_parameter.symbol = new Symbol (prop.this_parameter); + current_symbol.add (prop.this_parameter.name, prop.this_parameter.symbol); + } + + public override void visit_end_property (Property! prop) { + if (prop.error) { + /* skip properties with errors */ + return; + } + + current_symbol = current_symbol.parent_symbol; + } + + public override void visit_begin_property_accessor (PropertyAccessor! acc) { + acc.symbol = new Symbol (acc); + acc.symbol.parent_symbol = current_symbol; + current_symbol = acc.symbol; + + if (current_source_file.pkg) { + return; + } + + if (acc.writable || acc.construction) { + acc.value_parameter = new FormalParameter ("value", ((Property) current_symbol.parent_symbol.node).type_reference); + acc.value_parameter.symbol = new Symbol (acc.value_parameter); + + current_symbol.add (acc.value_parameter.name, acc.value_parameter.symbol); + } + + if (acc.body == null) { + /* no accessor body specified, insert default body */ + + var prop = (Property) acc.symbol.parent_symbol.node; + + if (prop.interface_only || prop.is_abstract) { + return; + } + + var block = new Block (); + if (acc.readable) { + block.add_statement (new ReturnStatement (new MemberAccess.simple ("_%s".printf (prop.name)))); + } else { + block.add_statement (new ExpressionStatement (new Assignment (new MemberAccess.simple ("_%s".printf (prop.name)), new MemberAccess.simple ("value")))); + } + acc.body = block; + } + } + + public override void visit_end_property_accessor (PropertyAccessor! acc) { + current_symbol = current_symbol.parent_symbol; + } + + public override void visit_begin_signal (Signal! sig) { + if (add_symbol (sig.name, sig) == null) { + return; + } + + current_symbol = sig.symbol; + } + + public override void visit_end_signal (Signal! sig) { + if (sig.error) { + /* skip signals with errors */ + return; + } + + current_symbol = current_symbol.parent_symbol; + } + + public override void visit_begin_constructor (Constructor! c) { + c.symbol = new Symbol (c); + c.symbol.parent_symbol = current_symbol; + current_symbol = c.symbol; + } + + public override void visit_end_constructor (Constructor! c) { + current_symbol = current_symbol.parent_symbol; + } + + public override void visit_begin_destructor (Destructor! d) { + d.symbol = new Symbol (d); + d.symbol.parent_symbol = current_symbol; + current_symbol = d.symbol; + } + + public override void visit_end_destructor (Destructor! d) { + current_symbol = current_symbol.parent_symbol; + } + + public override void visit_begin_block (Block! b) { + b.symbol = new Symbol (b); + b.symbol.parent_symbol = current_symbol; + current_symbol = b.symbol; + } + + public override void visit_end_block (Block! b) { + current_symbol = current_symbol.parent_symbol; + } + + public override void visit_type_parameter (TypeParameter! p) { + add_symbol (p.name, p); + } +} + diff --git a/vala/valasymbolresolver.vala b/vala/valasymbolresolver.vala new file mode 100644 index 000000000..483871bce --- /dev/null +++ b/vala/valasymbolresolver.vala @@ -0,0 +1,249 @@ +/* valasymbolresolver.vala + * + * Copyright (C) 2006-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 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; + +/** + * Code visitor resolving symbol names. + */ +public class Vala.SymbolResolver : CodeVisitor { + Symbol root_symbol; + Symbol current_scope; + List<weak NamespaceReference> current_using_directives; + + Class object_class; + + /** + * Resolve symbol names in the specified code context. + * + * @param context a code context + */ + public void resolve (CodeContext! context) { + root_symbol = context.get_root (); + current_scope = root_symbol; + + // TODO: don't require GLib namespace in symbol resolver + var glib_ns = root_symbol.lookup ("GLib"); + if (glib_ns != null) { + object_class = (Class) glib_ns.lookup ("Object").node; + } + + context.accept (this); + } + + public override void visit_begin_source_file (SourceFile! file) { + current_using_directives = file.get_using_directives (); + } + + public override void visit_end_source_file (SourceFile! file) { + current_using_directives = null; + } + + public override void visit_begin_namespace (Namespace! ns) { + current_scope = ns.symbol; + } + + public override void visit_end_namespace (Namespace! ns) { + // don't use current_scope.parent_symbol as that would be null + // if the current namespace is SourceFile.global_namespace + current_scope = root_symbol; + } + + public override void visit_begin_class (Class! cl) { + current_scope = cl.symbol; + } + + public override void visit_end_class (Class! cl) { + foreach (TypeReference type in cl.get_base_types ()) { + if (type.data_type is Class) { + if (cl.base_class != null) { + Report.error (type.source_reference, "%s: Classes cannot have multiple base classes (`%s' and `%s')".printf (cl.symbol.get_full_name (), cl.base_class.symbol.get_full_name (), type.data_type.symbol.get_full_name ())); + return; + } + cl.base_class = (Class) type.data_type; + } + } + if (cl.base_class == null && cl != object_class) { + var object_type = new TypeReference (); + object_type.data_type = object_class; + cl.add_base_type (object_type); + cl.base_class = object_class; + } + + current_scope = current_scope.parent_symbol; + } + + public override void visit_begin_struct (Struct! st) { + current_scope = st.symbol; + } + + public override void visit_end_struct (Struct! st) { + current_scope = current_scope.parent_symbol; + } + + public override void visit_begin_interface (Interface! iface) { + current_scope = iface.symbol; + } + + public override void visit_end_interface (Interface! iface) { + current_scope = current_scope.parent_symbol; + } + + public override void visit_begin_callback (Callback! cb) { + current_scope = cb.symbol; + } + + public override void visit_end_callback (Callback! cb) { + current_scope = current_scope.parent_symbol; + } + + public override void visit_formal_parameter (FormalParameter! p) { + if (!p.ellipsis && p.type_reference.is_ref) { + if ((p.type_reference.data_type != null && + p.type_reference.data_type.is_reference_type ()) || + p.type_reference.type_parameter != null) { + p.type_reference.takes_ownership = true; + } else { + p.type_reference.reference_to_value_type = true; + } + } + } + + public override void visit_namespace_reference (NamespaceReference! ns) { + ns.namespace_symbol = current_scope.lookup (ns.name); + if (ns.namespace_symbol == null) { + ns.error = true; + Report.error (ns.source_reference, "The namespace name `%s' could not be found".printf (ns.name)); + return; + } + } + + public override void visit_type_reference (TypeReference! type) { + if (type.type_name == null || type.type_name == "void") { + // reset transfers_ownership + type.transfers_ownership = false; + return; + } + + if (type.namespace_name == null) { + Symbol sym = null; + Symbol scope = current_scope; + while (sym == null && scope != null) { + sym = scope.lookup (type.type_name); + scope = scope.parent_symbol; + if (sym != null && !(sym.node is DataType) && !(sym.node is TypeParameter)) { + // ignore non-type symbols + sym = null; + } + } + if (sym == null) { + foreach (NamespaceReference ns in current_using_directives) { + if (ns.error) { + continue; + } + + var local_sym = ns.namespace_symbol.lookup (type.type_name); + if (local_sym != null) { + if (sym != null) { + Report.error (type.source_reference, "`%s' is an ambiguous reference between `%s' and `%s'".printf (type.type_name, sym.get_full_name (), local_sym.get_full_name ())); + return; + } + sym = local_sym; + } + } + } + if (sym == null) { + Report.error (type.source_reference, "The type name `%s' could not be found".printf (type.type_name)); + return; + } + if (sym.node is TypeParameter) { + type.type_parameter = (TypeParameter) sym.node; + } else { + type.data_type = (DataType) sym.node; + } + } else { + var ns_symbol = root_symbol.lookup (type.namespace_name); + if (ns_symbol == null) { + type.error = true; + Report.error (type.source_reference, "The namespace name `%s' could not be found".printf (type.namespace_name)); + return; + } + + var sym = ns_symbol.lookup (type.type_name); + if (sym == null) { + Report.error (type.source_reference, "The type name `%s' does not exist in the namespace `%s'".printf (type.type_name, type.namespace_name)); + return; + } + type.data_type = (DataType) sym.node; + } + + if (type.pointer_level > 0) { + if (type.data_type == null) { + type.error = true; + Report.error (type.source_reference, "Pointer to `%s' not supported".printf (type.type_name)); + return; + } + var referent_type = new TypeReference (); + referent_type.data_type = type.data_type; + referent_type.pointer_level = type.pointer_level - 1; + + if (type.data_type.is_reference_type ()) { + referent_type.takes_ownership = type.takes_ownership; + } + type.data_type = referent_type.data_type.get_pointer (); + type.add_type_argument (referent_type); + + visit_type_reference (referent_type); + } + + /* check for array */ + if (type.array_rank > 0) { + var element_type = new TypeReference (); + element_type.data_type = type.data_type; + element_type.type_parameter = type.type_parameter; + foreach (TypeReference type_arg in type.get_type_arguments ()) { + element_type.add_type_argument (type_arg); + } + type.remove_all_type_arguments (); + + if (type.data_type != null) { + if (type.data_type.is_reference_type ()) { + element_type.takes_ownership = type.takes_ownership; + } + type.data_type = element_type.data_type.get_array (type.array_rank); + } else { + type.data_type = element_type.type_parameter.get_array (type.array_rank); + type.type_parameter = null; + } + type.add_type_argument (element_type); + } + + if (type.data_type != null && !type.data_type.is_reference_type ()) { + /* reset takes_ownership and transfers_ownership of + * value-types for contexts where types are ref by + * default (field declarations and method return types) + */ + type.takes_ownership = false; + type.transfers_ownership = false; + } + } +} diff --git a/vala/valathrowstatement.vala b/vala/valathrowstatement.vala new file mode 100644 index 000000000..3a69ae520 --- /dev/null +++ b/vala/valathrowstatement.vala @@ -0,0 +1,73 @@ +/* valathrowstatement.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 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 throw statement in the source code. + */ +public class Vala.ThrowStatement : Statement { + /** + * The error expression to throw. + */ + public Expression error_expression { + get { + return _error_expression; + } + set { + _error_expression = value; + if (_error_expression != null) { + _error_expression.parent_node = this; + } + } + } + + private Expression! _error_expression; + + /** + * Creates a new throw statement. + * + * @param error_expression the error expression + * @param source_reference reference to source code + * @return newly created throw statement + */ + public ThrowStatement (construct Expression! error_expression, construct SourceReference source_reference = null) { + } + + public override void accept (CodeVisitor! visitor) { + visitor.visit_begin_throw_statement (this); + + if (error_expression != null) { + error_expression.accept (visitor); + + visitor.visit_end_full_expression (error_expression); + } + + visitor.visit_end_throw_statement (this); + } + + public override void replace (CodeNode! old_node, CodeNode! new_node) { + if (error_expression == old_node) { + error_expression = (Expression) new_node; + } + } +} diff --git a/vala/valatrystatement.vala b/vala/valatrystatement.vala new file mode 100644 index 000000000..b1a1ccf81 --- /dev/null +++ b/vala/valatrystatement.vala @@ -0,0 +1,66 @@ +/* valatrystatement.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 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 try statement in the source code. + */ +public class Vala.TryStatement : Statement { + /** + * Specifies the body of the try statement. + */ + public Block! body { get; set construct; } + + /** + * Specifies the body of the optional finally clause. + */ + public Block finally_body { get; set; } + + private List<CatchClause> catch_clauses; + + /** + * Creates a new try statement. + * + * @param body body of the try statement + * @param finally_body body of the optional finally clause + * @param source_reference reference to source code + * @return newly created try statement + */ + public TryStatement (construct Block! body, construct Block finally_body, construct SourceReference source_reference = null) { + } + + /** + * Appends the specified clause to the list of catch clauses. + * + * @param clause a catch clause + */ + public void add_catch_clause (CatchClause! clause) { + catch_clauses.append (clause); + } + + public override void accept (CodeVisitor! visitor) { + visitor.visit_begin_try_statement (this); + + visitor.visit_end_try_statement (this); + } +} diff --git a/vala/valatypecheck.vala b/vala/valatypecheck.vala new file mode 100644 index 000000000..bb9f605c7 --- /dev/null +++ b/vala/valatypecheck.vala @@ -0,0 +1,60 @@ +/* valatypecheck.vala + * + * Copyright (C) 2006 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 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 type check (`is') expression in the source code. + */ +public class Vala.TypeCheck : Expression { + /** + * The expression to be checked. + */ + public Expression! expression { get; set construct; } + + /** + * The type to be matched against. + */ + public TypeReference! type_reference { get; set construct; } + + /** + * Creates a new type check expression. + * + * @param expr an expression + * @param type a data type + * @param source reference to source code + * @return newly created type check expression + */ + public TypeCheck (Expression! expr, TypeReference! type, SourceReference source) { + expression = expr; + type_reference = type; + source_reference = source; + } + + public override void accept (CodeVisitor! visitor) { + expression.accept (visitor); + + type_reference.accept (visitor); + + visitor.visit_type_check (this); + } +} diff --git a/vala/valatypeofexpression.vala b/vala/valatypeofexpression.vala new file mode 100644 index 000000000..9589a5433 --- /dev/null +++ b/vala/valatypeofexpression.vala @@ -0,0 +1,51 @@ +/* valatypeofexpression.vala + * + * Copyright (C) 2006 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 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 typeof expression in the source code. + */ +public class Vala.TypeofExpression : Expression { + /** + * The type to be retrieved. + */ + public TypeReference! type_reference { get; set construct; } + + /** + * Creates a new typeof expression. + * + * @param type a data type + * @param source reference to source code + * @return newly created typeof expression + */ + public TypeofExpression (TypeReference! type, SourceReference source) { + type_reference = type; + source_reference = source; + } + + public override void accept (CodeVisitor! visitor) { + type_reference.accept (visitor); + + visitor.visit_typeof_expression (this); + } +} diff --git a/vala/valatypeparameter.vala b/vala/valatypeparameter.vala new file mode 100644 index 000000000..46d1f35aa --- /dev/null +++ b/vala/valatypeparameter.vala @@ -0,0 +1,104 @@ +/* valatypeparameter.vala + * + * Copyright (C) 2006-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 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 generic type parameter in the source code. + */ +public class Vala.TypeParameter : CodeNode { + /** + * The parameter name. + */ + public string! name { get; set construct; } + + /** + * The generic type declaring this parameter. + */ + public weak DataType type; + + /* holds the array types of this type; each rank is a separate one */ + /* FIXME: uses string because int does not work as key yet */ + private HashTable<string,Array> array_types = new HashTable.full (str_hash, str_equal, g_free, g_object_unref); + + /** + * Creates a new generic type parameter. + * + * @param name parameter name + * @param source reference to source code + * @return newly created generic type parameter + */ + public TypeParameter (string! _name, SourceReference source) { + name = _name; + source_reference = source; + } + + public override void accept (CodeVisitor! visitor) { + visitor.visit_type_parameter (this); + } + + /** + * Returns the array type for elements of this type parameter. + * + * @param rank the rank the array should be of + * @return array type for this type parameter + */ + public Array! get_array (int rank) { + Array array_type = (Array) array_types.lookup (rank.to_string ()); + + if (array_type == null) { + var new_array_type = new Array.with_type_parameter (this, rank, source_reference); + /* create a new Symbol */ + new_array_type.symbol = new Symbol (new_array_type); + this.symbol.parent_symbol.add (new_array_type.name, new_array_type.symbol); + + /* add internal length field */ + new_array_type.symbol.add (new_array_type.get_length_field ().name, new_array_type.get_length_field ().symbol); + /* add internal resize method */ + new_array_type.symbol.add (new_array_type.get_resize_method ().name, new_array_type.get_resize_method ().symbol); + + /* link the array type to the same source as the container type */ + new_array_type.source_reference = this.source_reference; + + array_types.insert (rank.to_string (), new_array_type); + + array_type = new_array_type; + } + + return array_type; + } + + /** + * Checks two type parameters for equality. + * + * @param param2 a type parameter + * @return true if this type parameter is equal to param2, false + * otherwise + */ + public bool equals (TypeParameter! param2) { + // FIXME check whether the corresponding data type of one of the + // parameters is a base type of the corresponding data + // type of the other parameter and check along the path + // whether one parameter maps to the other + return true; + } +} diff --git a/vala/valatypereference.vala b/vala/valatypereference.vala new file mode 100644 index 000000000..f3824ced4 --- /dev/null +++ b/vala/valatypereference.vala @@ -0,0 +1,389 @@ +/* valatypereference.vala + * + * Copyright (C) 2006-2007 Jürg Billeter, Raffaele Sandrini + * + * 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 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> + * Raffaele Sandrini <rasa@gmx.ch> + */ + +using GLib; + +/** + * A reference to a data type. This is used to specify static types of + * expressions. + */ +public class Vala.TypeReference : CodeNode { + /** + * Specifies that the expression is a reference to a value type. + * References to value types are used in ref parameters. + */ + public bool reference_to_value_type { get; set; } + + /** + * Specifies that the expression transfers ownership of its value. + */ + public bool transfers_ownership { get; set; } + + /** + * Specifies that the expression assumes ownership if used as an lvalue + * in an assignment. + */ + public bool takes_ownership { get; set; } + + /** + * Specifies that the expression is a reference to a reference type. + * References to reference types are used in out parameters. + */ + public bool is_out { get; set; } + + /** + * Specifies that the expression is guaranteed not to be null. + */ + public bool non_null { get; set; } + + /** + * Specifies that the expression is known to be null. + */ + public bool is_null { get; set; } + + /** + * The referred data type. + */ + public weak DataType data_type { get; set; } + + /** + * The referred generic type parameter. + */ + public TypeParameter type_parameter { get; set; } + + /** + * Specifies that the expression transfers a floating reference. + */ + public bool floating_reference { get; set; } + + /** + * The name of the namespace containing the referred data type. May only + * be used with unresolved type references. + */ + public string namespace_name { get; set; } + + /** + * The name of the referred data type. May only be used with unresolved + * type references. + */ + public string type_name { get; set; } + + /** + * Specifies the rank of the array this reference is possibly referring to. "0" indicates no array. + * WARNING: This property may only be set by the parser and only be read by the symbol resolver. + */ + public int array_rank { get; set; } + + /** + * Specifies the level of the pointer if this is a pointer-type. "0" indicates no pointer-type. + * WARNING: This property may only be set by the parser and only be read by the symbol resolver. + */ + public int pointer_level { get; set; } + + /** + * The ref modifier has been specified, may only be used with unresolved + * type references. + */ + public bool is_ref { get; set; } + + /** + * The weak modifier has been specified. May only be used with + * unresolved type references. + */ + public bool is_weak { get; set; } + + private List<TypeReference> type_argument_list; + + public TypeReference () { + } + + /** + * Creates a new type reference. + * + * @param ns optional namespace name + * @param type_name type symbol name + * @param source reference to source code + * @return newly created type reference + */ + public TypeReference.from_name (string ns, string! type, SourceReference source = null) { + namespace_name = ns; + type_name = type; + source_reference = source; + } + + /** + * Creates a new type reference from a code expression. + * + * @param expr member access expression + * @param source reference to source code + * @return newly created type reference + */ + public static ref TypeReference new_from_expression (Expression! expr) { + 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; + type_ref = new TypeReference.from_name (simple.member_name, ma.member_name, ma.source_reference); + } + } else { + type_ref = new TypeReference.from_name (null, ma.member_name, ma.source_reference); + } + + 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; + } + } + + Report.error (expr.source_reference, "Type reference must be simple name or member access expression"); + return null; + } + + /** + * 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<weak TypeReference> get_type_arguments () { + return type_argument_list.copy (); + } + + /** + * Removes all generic type arguments. + */ + public void remove_all_type_arguments () { + type_argument_list = null; + } + + public override void accept (CodeVisitor! visitor) { + foreach (TypeReference type_arg in type_argument_list) { + type_arg.accept (visitor); + } + + visitor.visit_type_reference (this); + } + + /** + * Returns the name and qualifiers of this type as it is used in C code. + * + * @return the type string to be used in C code + */ + public ref string get_cname (bool var_type = false, bool const_type = false) { + if (data_type == null && type_parameter == null) { + if (var_type) { + return "gpointer"; + } else { + return "void"; + } + } + + string ptr; + string arr; + if (type_parameter != null || (!data_type.is_reference_type () && !reference_to_value_type)) { + ptr = ""; + } else if ((data_type.is_reference_type () && !is_out) || reference_to_value_type) { + ptr = "*"; + } else { + ptr = "**"; + } + if (data_type != null) { + return data_type.get_cname (const_type).concat (ptr, arr, null); + } else if (type_parameter != null) { + return "gpointer".concat (ptr, arr, null); + } else { + /* raise error */ + Report.error (source_reference, "unresolved type reference"); + return null; + } + } + + /** + * Returns the name and qualifiers of this type as it is used in C code + * in a const declaration. + * + * @return the type string to be used in C code const declarations + */ + public ref string get_const_cname () { + string ptr; + DataType t; + /* FIXME: dirty hack to make constant arrays possible */ + if (data_type is Array) { + t = ((Array) data_type).element_type; + } else { + t = data_type; + } + if (!t.is_reference_type ()) { + ptr = ""; + } else { + ptr = "*"; + } + + return "const %s%s".printf (t.get_cname (), ptr); + } + + /** + * Returns a user-readable name of the type corresponding to this type + * reference. + * + * @return display name + */ + public ref string! to_string () { + if (data_type != null) { + return data_type.symbol.get_full_name (); + } else if (type_parameter != null) { + return type_parameter.name; + } else { + return "null"; + } + } + + /** + * Creates a shallow copy of this type reference. + * + * @return copy of this type reference + */ + public ref TypeReference! copy () { + var result = new TypeReference (); + result.source_reference = source_reference; + result.reference_to_value_type = reference_to_value_type; + result.transfers_ownership = transfers_ownership; + result.takes_ownership = takes_ownership; + result.is_out = is_out; + result.non_null = non_null; + result.data_type = data_type; + result.type_parameter = type_parameter; + result.floating_reference = floating_reference; + result.namespace_name = namespace_name; + result.type_name = type_name; + result.array_rank = array_rank; + result.pointer_level = pointer_level; + result.is_ref = is_ref; + result.is_weak = is_weak; + + foreach (TypeReference arg in type_argument_list) { + result.type_argument_list.append (arg.copy ()); + } + + return result; + } + + /** + * Checks two type references for equality. May only be used with + * resolved type references. + * + * @param type2 a type reference + * @return true if this type reference is equal to type2, false + * otherwise + */ + public bool equals (TypeReference! type2) { + if (type2.reference_to_value_type != reference_to_value_type) { + return false; + } + if (type2.transfers_ownership != transfers_ownership) { + return false; + } + if (type2.takes_ownership != takes_ownership) { + return false; + } + if (type2.is_out != is_out) { + return false; + } + if (type2.non_null != non_null) { + return false; + } + if (type2.data_type != data_type) { + return false; + } + if (type2.type_parameter != null || type_parameter != null) { + if (type2.type_parameter == null || type_parameter == null) { + return false; + } + if (!type2.type_parameter.equals (type_parameter)) { + return false; + } + } + if (type2.floating_reference != floating_reference) { + return false; + } + + return true; + } + + /** + * Checks whether this type reference is at least as strict as the + * specified type reference type2. + * + * @param type2 a type reference + * @return true if this type reference is stricter or equal + */ + public bool stricter (TypeReference! type2) { + if (type2.reference_to_value_type != reference_to_value_type) { + return false; + } + if (type2.transfers_ownership != transfers_ownership) { + return false; + } + if (type2.takes_ownership != takes_ownership) { + return false; + } + if (type2.is_out != is_out) { + return false; + } + + if (type2.non_null && !non_null) { + return false; + } + + if (type2.data_type != data_type) { + // FIXME: allow this type reference to refer to a + // subtype of the type type2 is referring to + return false; + } + if (type2.type_parameter != type_parameter) { + return false; + } + if (type2.floating_reference != floating_reference) { + return false; + } + + return true; + } +} diff --git a/vala/valatyperegisterfunction.vala b/vala/valatyperegisterfunction.vala new file mode 100644 index 000000000..d8a3044af --- /dev/null +++ b/vala/valatyperegisterfunction.vala @@ -0,0 +1,186 @@ +/* valatyperegisterfunction.vala + * + * Copyright (C) 2006-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 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; + +/** + * C function to register a type at runtime. + */ +public abstract class Vala.TypeRegisterFunction { + private CCodeFragment declaration_fragment = new CCodeFragment (); + + private CCodeFragment definition_fragment = new CCodeFragment (); + + /** + * Constructs the C function from the specified type. + */ + public void init_from_type (bool plugin = false) { + string type_id_name = "%s_type_id".printf (get_type_declaration ().get_lower_case_cname (null)); + + var type_block = new CCodeBlock (); + var cdecl = new CCodeDeclaration ("GType"); + cdecl.add_declarator (new CCodeVariableDeclarator.with_initializer (type_id_name, new CCodeConstant ("0"))); + cdecl.modifiers = CCodeModifiers.STATIC; + if (!plugin) { + type_block.add_statement (cdecl); + } else { + definition_fragment.append (cdecl); + } + + CCodeFunction fun; + if (!plugin) { + fun = new CCodeFunction ("%s_get_type".printf (get_type_declaration ().get_lower_case_cname (null)), "GType"); + } else { + fun = new CCodeFunction ("%s_register_type".printf (get_type_declaration ().get_lower_case_cname (null)), "GType"); + fun.add_parameter (new CCodeFormalParameter ("module", "GTypeModule *")); + + var get_fun = new CCodeFunction ("%s_get_type".printf (get_type_declaration ().get_lower_case_cname (null)), "GType"); + + declaration_fragment.append (get_fun.copy ()); + + get_fun.block = new CCodeBlock (); + get_fun.block.add_statement (new CCodeReturnStatement (new CCodeIdentifier (type_id_name))); + + definition_fragment.append (get_fun); + } + + var type_init = new CCodeBlock (); + var ctypedecl = new CCodeDeclaration ("const GTypeInfo"); + ctypedecl.modifiers = CCodeModifiers.STATIC; + ctypedecl.add_declarator (new CCodeVariableDeclarator.with_initializer ("g_define_type_info", new CCodeConstant ("{ sizeof (%s), (GBaseInitFunc) %s, (GBaseFinalizeFunc) NULL, (GClassInitFunc) %s, (GClassFinalizeFunc) NULL, NULL, %s, 0, (GInstanceInitFunc) %s }".printf (get_type_struct_name (), get_base_init_func_name (), get_class_init_func_name (), get_instance_struct_size (), get_instance_init_func_name ())))); + type_init.add_statement (ctypedecl); + CCodeFunctionCall reg_call; + if (!plugin) { + reg_call = new CCodeFunctionCall (new CCodeIdentifier ("g_type_register_static")); + } else { + reg_call = new CCodeFunctionCall (new CCodeIdentifier ("g_type_module_register_type")); + reg_call.add_argument (new CCodeIdentifier ("module")); + } + reg_call.add_argument (new CCodeIdentifier (get_parent_type_name ())); + reg_call.add_argument (new CCodeConstant ("\"%s\"".printf (get_type_declaration ().get_cname ()))); + reg_call.add_argument (new CCodeIdentifier ("&g_define_type_info")); + reg_call.add_argument (new CCodeConstant (get_type_flags ())); + type_init.add_statement (new CCodeExpressionStatement (new CCodeAssignment (new CCodeIdentifier (type_id_name), reg_call))); + + type_init.add_statement (get_type_interface_init_statements ()); + + if (!plugin) { + var cond = new CCodeFunctionCall (new CCodeIdentifier ("G_UNLIKELY")); + cond.add_argument (new CCodeBinaryExpression (CCodeBinaryOperator.EQUALITY, new CCodeIdentifier (type_id_name), new CCodeConstant ("0"))); + var cif = new CCodeIfStatement (cond, type_init); + type_block.add_statement (cif); + } else { + type_block = type_init; + } + + type_block.add_statement (new CCodeReturnStatement (new CCodeIdentifier (type_id_name))); + + declaration_fragment.append (fun.copy ()); + + fun.block = type_block; + + definition_fragment.append (fun); + } + + /** + * Returns the data type to be registered. + * + * @return type to be registered + */ + public abstract DataType! get_type_declaration (); + + /** + * Returns the name of the type struct in C code. + * + * @return C struct name + */ + public abstract ref string! get_type_struct_name (); + + /** + * Returns the name of the base_init function in C code. + * + * @return C function name + */ + public abstract ref string! get_base_init_func_name (); + + /** + * Returns the name of the class_init function in C code. + * + * @return C function name + */ + public abstract ref string! get_class_init_func_name (); + + /** + * Returns the size of the instance struct in C code. + * + * @return C instance struct size + */ + public abstract ref string! get_instance_struct_size (); + + /** + * Returns the name of the instance_init function in C code. + * + * @return C function name + */ + public abstract ref string! get_instance_init_func_name (); + + /** + * Returns the name of the parent type in C code. + * + * @return C parent type name + */ + public abstract ref string! get_parent_type_name (); + + /** + * Returns the set of type flags to be applied when registering. + * + * @return type flags + */ + public virtual string get_type_flags () { + return "0"; + } + + /** + * Returns additional C initialization statements to setup interfaces. + * + * @return C statements + */ + public abstract ref CCodeFragment! get_type_interface_init_statements (); + + /** + * Returns the declaration for this type register function in C code. + * + * @return C function declaration fragment + */ + public CCodeFragment! get_declaration () { + return declaration_fragment; + } + + /** + * Returns the definition for this type register function in C code. + * + * @return C function definition fragment + */ + public CCodeFragment! get_definition () { + return definition_fragment; + } +} diff --git a/vala/valaunaryexpression.vala b/vala/valaunaryexpression.vala new file mode 100644 index 000000000..2ecf8a2b5 --- /dev/null +++ b/vala/valaunaryexpression.vala @@ -0,0 +1,87 @@ +/* valaunaryexpression.vala + * + * Copyright (C) 2006 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 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 an expression with one operand in the source code. + * + * Supports +, -, !, ~, ref, out. + */ +public class Vala.UnaryExpression : Expression { + /** + * The unary operator. + */ + public UnaryOperator operator { get; set; } + + /** + * The operand. + */ + public Expression! inner { + get { + return _inner; + } + set construct { + _inner = value; + _inner.parent_node = this; + } + } + + private Expression! _inner; + + /** + * Creates a new unary expression. + * + * @param op unary operator + * @param inner operand + * @param source reference to source code + * @return newly created binary expression + */ + public UnaryExpression (UnaryOperator op, Expression! _inner, SourceReference source) { + operator = op; + inner = _inner; + source_reference = source; + } + + public override void accept (CodeVisitor! visitor) { + inner.accept (visitor); + + visitor.visit_unary_expression (this); + } + + public override void replace (CodeNode! old_node, CodeNode! new_node) { + if (inner == old_node) { + inner = (Expression) new_node; + } + } +} + +public enum Vala.UnaryOperator { + PLUS, + MINUS, + LOGICAL_NEGATION, + BITWISE_COMPLEMENT, + INCREMENT, + DECREMENT, + REF, + OUT +} diff --git a/vala/valavariabledeclarator.vala b/vala/valavariabledeclarator.vala new file mode 100644 index 000000000..321a5b5d7 --- /dev/null +++ b/vala/valavariabledeclarator.vala @@ -0,0 +1,111 @@ +/* valavariabledeclarator.vala + * + * Copyright (C) 2006 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 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 variable declarator in the source code. + */ +public class Vala.VariableDeclarator : CodeNode, Invokable { + /** + * The variable name. + */ + public string! name { get; set construct; } + + /** + * The optional initializer expression. + */ + public Expression initializer { + get { + return _initializer; + } + set { + _initializer = value; + if (_initializer != null) { + _initializer.parent_node = this; + } + } + } + + /** + * The variable type. + */ + public TypeReference type_reference { get; set; } + + private Expression _initializer; + + /** + * Creates a new variable declarator. + * + * @param name name of the variable + * @param init optional initializer expression + * @param source reference to source code + * @return newly created variable declarator + */ + public VariableDeclarator (string! _name, Expression init = null, SourceReference source = null) { + name = _name; + initializer = init; + source_reference = source; + } + + public override void accept (CodeVisitor! visitor) { + if (initializer != null) { + initializer.accept (visitor); + + visitor.visit_end_full_expression (initializer); + } + + if (type_reference != null) { + type_reference.accept (visitor); + } + + visitor.visit_variable_declarator (this); + } + + public ref List<weak FormalParameter> get_parameters () { + if (!is_invokable ()) { + return null; + } + + var cb = (Callback) type_reference.data_type; + return cb.get_parameters (); + } + + public TypeReference get_return_type () { + if (!is_invokable ()) { + return null; + } + + var cb = (Callback) type_reference.data_type; + return cb.return_type; + } + + public bool is_invokable () { + return (type_reference.data_type is Callback); + } + + public override void replace (CodeNode! old_node, CodeNode! new_node) { + if (initializer == old_node) { + initializer = (Expression) new_node; + } + } +} diff --git a/vala/valawhilestatement.vala b/vala/valawhilestatement.vala new file mode 100644 index 000000000..ea22ea8db --- /dev/null +++ b/vala/valawhilestatement.vala @@ -0,0 +1,78 @@ +/* valawhilestatement.vala + * + * Copyright (C) 2006 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 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 while iteration statement in the source code. + */ +public class Vala.WhileStatement : Statement { + /** + * Specifies the loop condition. + */ + public Expression! condition { + get { + return _condition; + } + set construct { + _condition = value; + _condition.parent_node = this; + } + } + + /** + * Specifies the loop body. + */ + public Statement body { get; set; } + + private Expression! _condition; + + /** + * Creates a new while statement. + * + * @param cond loop condition + * @param body loop body + * @param source reference to source code + * @return newly created while statement + */ + public WhileStatement (Expression! cond, Statement! _body, SourceReference source) { + condition = cond; + body = _body; + source_reference = source; + } + + public override void accept (CodeVisitor! visitor) { + condition.accept (visitor); + + visitor.visit_end_full_expression (condition); + + body.accept (visitor); + + visitor.visit_while_statement (this); + } + + public override void replace (CodeNode! old_node, CodeNode! new_node) { + if (condition == old_node) { + condition = (Expression) new_node; + } + } +} |