Replace generated Vala scanner and parser by handwritten classes
authorJuerg Billeter <j@bitron.ch>
Sun, 13 Apr 2008 09:25:25 +0000 (09:25 +0000)
committerJürg Billeter <juergbi@src.gnome.org>
Sun, 13 Apr 2008 09:25:25 +0000 (09:25 +0000)
2008-04-13  Juerg Billeter  <j@bitron.ch>

* vala/Makefile.am, vala/valaassignment.vala,
  vala/valabinaryexpression.vala, vala/valaclass.vala,
  vala/valanamespace.vala, vala/valaparser.vala,
  vala/valascanner.vala, vala/valascope.vala,
  vala/valasourcefile.vala, vala/valasourcelocation.vala,
  vala/valatokentype.vala, vala/valatuple.vala,
  vala/valaunaryexpression.vala, vala/valaunresolvedtype.vala:

  Replace generated Vala scanner and parser by handwritten classes

svn path=/trunk/; revision=1194

17 files changed:
ChangeLog
vala/Makefile.am
vala/parser.y [deleted file]
vala/scanner.l [deleted file]
vala/valaassignment.vala
vala/valabinaryexpression.vala
vala/valaclass.vala
vala/valanamespace.vala
vala/valaparser.vala
vala/valascanner.vala [new file with mode: 0644]
vala/valascope.vala
vala/valasourcefile.vala
vala/valasourcelocation.vala [new file with mode: 0644]
vala/valatokentype.vala [new file with mode: 0644]
vala/valatuple.vala [new file with mode: 0644]
vala/valaunaryexpression.vala
vala/valaunresolvedtype.vala

index 108ca3c..4787fdc 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,17 @@
 2008-04-13  Jürg Billeter  <j@bitron.ch>
 
+       * vala/Makefile.am, vala/valaassignment.vala,
+         vala/valabinaryexpression.vala, vala/valaclass.vala,
+         vala/valanamespace.vala, vala/valaparser.vala,
+         vala/valascanner.vala, vala/valascope.vala,
+         vala/valasourcefile.vala, vala/valasourcelocation.vala,
+         vala/valatokentype.vala, vala/valatuple.vala,
+         vala/valaunaryexpression.vala, vala/valaunresolvedtype.vala:
+
+         Replace generated Vala scanner and parser by handwritten classes
+
+2008-04-13  Jürg Billeter  <j@bitron.ch>
+
        * vapi/glib-2.0.vapi: add GEnumClass and GEnumValue bindings
 
 2008-04-13  Jürg Billeter  <j@bitron.ch>
index b52b2fe..7b6f0ef 100644 (file)
@@ -7,8 +7,7 @@ AM_CPPFLAGS = \
        -DPACKAGE_DATADIR=\"$(pkgdatadir)\" \
        $(NULL)
 
-BUILT_SOURCES = parser.h vala.vala.stamp
-AM_YFLAGS = -d
+BUILT_SOURCES = vala.vala.stamp
 
 noinst_LTLIBRARIES = \
        libvalacore.la
@@ -106,6 +105,7 @@ libvalacore_la_VALASOURCES = \
        valareferencetype.vala \
        valareport.vala \
        valareturnstatement.vala \
+       valascanner.vala \
        valascope.vala \
        valasemanticanalyzer.vala \
        valasignal.vala \
@@ -113,6 +113,7 @@ libvalacore_la_VALASOURCES = \
        valasizeofexpression.vala \
        valasourcefile.vala \
        valasourcefilecycle.vala \
+       valasourcelocation.vala \
        valasourcereference.vala \
        valastatement.vala \
        valastringliteral.vala \
@@ -123,7 +124,9 @@ libvalacore_la_VALASOURCES = \
        valasymbol.vala \
        valasymbolresolver.vala \
        valathrowstatement.vala \
+       valatokentype.vala \
        valatrystatement.vala \
+       valatuple.vala \
        valatypecheck.vala \
        valatypeofexpression.vala \
        valatypeparameter.vala \
@@ -139,8 +142,6 @@ libvalacore_la_VALASOURCES = \
        $(NULL)
 
 libvalacore_la_SOURCES = \
-       parser.y \
-       scanner.l \
        vala.h \
        vala.vala.stamp \
        $(libvalacore_la_VALASOURCES:.vala=.c) \
diff --git a/vala/parser.y b/vala/parser.y
deleted file mode 100644 (file)
index fc7b3ac..0000000
+++ /dev/null
@@ -1,4563 +0,0 @@
-/* parser.y
- *
- * Copyright (C) 2006-2008  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.1 of the License, or (at your option) any later version.
-
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
-
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301  USA
- *
- * Author:
- *     Jürg Billeter <j@bitron.ch>
- *     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 ValaCodeContext *context;
-static ValaSourceFile *current_source_file;
-static GList *symbol_stack;
-static GList *scope_stack;
-
-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,
-       VALA_MODIFIER_VOLATILE = 1 << 4,
-       VALA_MODIFIER_INLINE = 1 << 5
-} ValaModifier;
-
-int yylex (YYSTYPE *yylval_param, YYLTYPE *yylloc_param, ValaParser *parser);
-static void yyerror (YYLTYPE *locp, ValaParser *parser, const char *msg);
-
-static void push_symbol (ValaSymbol *symbol);
-static ValaSymbol *pop_symbol (void);
-
-static gboolean check_is_namespace (ValaSymbol *symbol, ValaSourceReference *src);
-static gboolean check_is_class (ValaSymbol *symbol, ValaSourceReference *src);
-static gboolean check_is_struct (ValaSymbol *symbol, ValaSourceReference *src);
-%}
-
-%defines
-%locations
-%pure-parser
-%parse-param {ValaParser *parser}
-%lex-param {ValaParser *parser}
-%error-verbose
-%union {
-       int num;
-       char *str;
-       GList *list;
-       ValaUnresolvedSymbol *unresolved_symbol;
-       ValaDataType *type_reference;
-       ValaExpression *expression;
-       ValaStatement *statement;
-       ValaBlock *block;
-       ValaInterface *interface;
-       ValaEnumValue *enum_value;
-       ValaErrorCode *error_code;
-       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;
-       ValaMemberInitializer *member_initializer;
-       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_ARRAY_TYPE_BRACKET "array ["
-%token OPEN_BRACKET "["
-%token CLOSE_BRACKET "]"
-%token ELLIPSIS "..."
-%token DOT "."
-%token COLON ":"
-%token COMMA ","
-%token SEMICOLON ";"
-%token HASH "#"
-%token INTERR "?"
-%token NULLABLE_INTERR "nullable ?"
-
-%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 OP_PTR "->"
-
-%token ASSIGN "="
-%token PLUS "+"
-%token MINUS "-"
-%token STAR "*"
-%token DIV "/"
-%token PERCENT "%"
-
-%token ABSTRACT "abstract"
-%token AS "as"
-%token BASE "base"
-%token BREAK "break"
-%token CASE "case"
-%token CATCH "catch"
-%token CLASS "class"
-%token CONST "const"
-%token CONSTRUCT "construct"
-%token CONTINUE "continue"
-%token DEFAULT "default"
-%token DELEGATE "delegate"
-%token DELETE "delete"
-%token DO "do"
-%token ELSE "else"
-%token ENSURES "ensures"
-%token ENUM "enum"
-%token ERRORDOMAIN "errordomain"
-%token VALA_FALSE "false"
-%token FINALLY "finally"
-%token FOR "for"
-%token FOREACH "foreach"
-%token GET "get"
-%token IF "if"
-%token IN "in"
-%token INLINE "inline"
-%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 REQUIRES "requires"
-%token RETURN "return"
-%token SET "set"
-%token SIGNAL "signal"
-%token SIZEOF "sizeof"
-%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 VOID "void"
-%token VOLATILE "volatile"
-%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 <str> identifier_or_keyword
-%type <expression> literal
-%type <expression> boolean_literal
-%type <num> stars
-%type <unresolved_symbol> symbol_name
-%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> pointer_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 <list> opt_object_initializer
-%type <list> object_initializer
-%type <list> member_initializer_list
-%type <member_initializer> member_initializer
-%type <expression> sizeof_expression
-%type <expression> typeof_expression
-%type <expression> unary_expression
-%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> in_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 <block> embedded_statement
-%type <block> 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 <num> opt_any_interr
-%type <num> opt_nullable_interr
-%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 <block> opt_finally_clause
-%type <block> finally_clause
-%type <statement> lock_statement
-%type <statement> delete_statement
-%type <str> opt_name_specifier
-%type <str> name_specifier
-%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> opt_get_accessor_declaration
-%type <property_accessor> get_accessor_declaration
-%type <property_accessor> opt_set_accessor_declaration
-%type <property_accessor> set_accessor_declaration
-%type <expression> opt_default_value
-%type <expression> default_value
-%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 <block> 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 <list> opt_requires_declarations
-%type <list> requires_declarations
-%type <expression> requires_declaration
-%type <list> opt_ensures_declarations
-%type <list> ensures_declarations
-%type <expression> ensures_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, set, requires, or ensures */
-identifier
-       : IDENTIFIER
-       | GET { $$ = g_strdup ("get"); }
-       | SET { $$ = g_strdup ("set"); }
-       | REQUIRES { $$ = g_strdup ("requires"); }
-       | ENSURES { $$ = g_strdup ("ensures"); }
-       ;
-
-/* identifiers never conflict with context-specific keywords get, set, requires, or ensures */
-identifier_or_keyword
-       : IDENTIFIER
-       | ABSTRACT { $$ = g_strdup ("abstract"); }
-       | AS { $$ = g_strdup ("as"); }
-       | BASE { $$ = g_strdup ("base"); }
-       | BREAK { $$ = g_strdup ("break"); }
-       | CASE { $$ = g_strdup ("case"); }
-       | CATCH { $$ = g_strdup ("catch"); }
-       | CLASS { $$ = g_strdup ("class"); }
-       | CONST { $$ = g_strdup ("const"); }
-       | CONSTRUCT { $$ = g_strdup ("construct"); }
-       | CONTINUE { $$ = g_strdup ("continue"); }
-       | DEFAULT { $$ = g_strdup ("default"); }
-       | DELEGATE { $$ = g_strdup ("delegate"); }
-       | DELETE { $$ = g_strdup ("delete"); }
-       | DO { $$ = g_strdup ("do"); }
-       | ELSE { $$ = g_strdup ("else"); }
-       | ENSURES { $$ = g_strdup ("ensures"); }
-       | ENUM { $$ = g_strdup ("enum"); }
-       | ERRORDOMAIN { $$ = g_strdup ("errordomain"); }
-       | VALA_FALSE { $$ = g_strdup ("false"); }
-       | FINALLY { $$ = g_strdup ("finally"); }
-       | FOR { $$ = g_strdup ("for"); }
-       | FOREACH { $$ = g_strdup ("foreach"); }
-       | GET { $$ = g_strdup ("get"); }
-       | IF { $$ = g_strdup ("if"); }
-       | IN { $$ = g_strdup ("in"); }
-       | INLINE { $$ = g_strdup ("inline"); }
-       | INTERFACE { $$ = g_strdup ("interface"); }
-       | IS { $$ = g_strdup ("is"); }
-       | LOCK { $$ = g_strdup ("lock"); }
-       | NAMESPACE { $$ = g_strdup ("namespace"); }
-       | NEW { $$ = g_strdup ("new"); }
-       | VALA_NULL { $$ = g_strdup ("null"); }
-       | OUT { $$ = g_strdup ("out"); }
-       | OVERRIDE { $$ = g_strdup ("override"); }
-       | PRIVATE { $$ = g_strdup ("private"); }
-       | PROTECTED { $$ = g_strdup ("protected"); }
-       | PUBLIC { $$ = g_strdup ("public"); }
-       | REF { $$ = g_strdup ("ref"); }
-       | REQUIRES { $$ = g_strdup ("requires"); }
-       | RETURN { $$ = g_strdup ("return"); }
-       | SET { $$ = g_strdup ("set"); }
-       | SIGNAL { $$ = g_strdup ("signal"); }
-       | SIZEOF { $$ = g_strdup ("sizeof"); }
-       | STATIC { $$ = g_strdup ("static"); }
-       | STRUCT { $$ = g_strdup ("struct"); }
-       | SWITCH { $$ = g_strdup ("switch"); }
-       | THIS { $$ = g_strdup ("this"); }
-       | THROW { $$ = g_strdup ("throw"); }
-       | THROWS { $$ = g_strdup ("throws"); }
-       | VALA_TRUE { $$ = g_strdup ("true"); }
-       | TRY { $$ = g_strdup ("try"); }
-       | TYPEOF { $$ = g_strdup ("typeof"); }
-       | USING { $$ = g_strdup ("using"); }
-       | VAR { $$ = g_strdup ("var"); }
-       | VIRTUAL { $$ = g_strdup ("virtual"); }
-       | VOID { $$ = g_strdup ("void"); }
-       | VOLATILE { $$ = g_strdup ("volatile"); }
-       | WEAK { $$ = g_strdup ("weak"); }
-       | WHILE { $$ = g_strdup ("while"); }
-       ;
-
-literal
-       : boolean_literal
-       | INTEGER_LITERAL
-         {
-               ValaSourceReference *src = src(@1);
-               $$ = VALA_EXPRESSION (vala_code_context_create_integer_literal (context, $1, src));
-               g_object_unref (src);
-               g_free ($1);
-         }
-       | REAL_LITERAL
-         {
-               ValaSourceReference *src = src(@1);
-               $$ = VALA_EXPRESSION (vala_code_context_create_real_literal (context, $1, src));
-               g_free ($1);
-               g_object_unref (src);
-         }
-       | CHARACTER_LITERAL
-         {
-               ValaSourceReference *src = src(@1);
-               $$ = VALA_EXPRESSION (vala_code_context_create_character_literal (context, $1, src));
-               g_object_unref (src);
-               g_free ($1);
-         }
-       | STRING_LITERAL
-         {
-               ValaSourceReference *src = src(@1);
-               $$ = VALA_EXPRESSION (vala_code_context_create_string_literal (context, $1, src));
-               g_object_unref (src);
-               g_free ($1);
-         }
-       | VALA_NULL
-         {
-               ValaSourceReference *src = src(@1);
-               $$ = VALA_EXPRESSION (vala_code_context_create_null_literal (context, src));
-               g_object_unref (src);
-         }
-       ;
-
-boolean_literal
-       : VALA_TRUE
-         {
-               ValaSourceReference *src = src(@1);
-               $$ = VALA_EXPRESSION (vala_code_context_create_boolean_literal (context, TRUE, src));
-               g_object_unref (src);
-         }
-       | VALA_FALSE
-         {
-               ValaSourceReference *src = src(@1);
-               $$ = VALA_EXPRESSION (vala_code_context_create_boolean_literal (context, FALSE, src));
-               g_object_unref (src);
-         }
-       ;
-
-compilation_unit
-       : opt_using_directives opt_outer_declarations
-       ;
-
-symbol_name
-       : identifier
-         {
-               ValaSourceReference *src = src(@1);
-               $$ = vala_unresolved_symbol_new (NULL, $1, src);
-               g_free ($1);
-               g_object_unref (src);
-         }
-       | symbol_name DOT identifier
-         {
-               ValaSourceReference *src = src(@1);
-               $$ = vala_unresolved_symbol_new ($1, $3, src);
-               g_free ($3);
-               g_object_unref (src);
-         }
-       ;
-
-type_name
-       : symbol_name opt_type_argument_list
-         {
-               GList *l;
-               ValaSourceReference *src = src(@1);
-               $$ = VALA_DATA_TYPE (vala_unresolved_type_new_from_symbol ($1, src));
-               g_object_unref ($1);
-               g_object_unref (src);
-               for (l = $2; l != NULL; l = l->next) {
-                       vala_data_type_add_type_argument (VALA_DATA_TYPE ($$), l->data);
-                       g_object_unref (l->data);
-               }
-               g_list_free ($2);
-         }
-       ;
-
-stars
-       : STAR
-         {
-               $$ = 1;
-         }
-       | stars STAR
-         {
-               $$ = $1 + 1;
-         }
-       ;
-
-type
-       : type_name opt_rank_specifier opt_op_neg opt_any_interr
-         {
-               $$ = $1;
-               vala_unresolved_type_set_array_rank (VALA_UNRESOLVED_TYPE ($$), $2);
-               if ($4) {
-                       vala_data_type_set_nullable ($$, TRUE);
-                       vala_data_type_set_requires_null_check ($$, TRUE);
-               }
-         }
-       | WEAK type_name opt_rank_specifier opt_op_neg opt_any_interr
-         {
-               $$ = $2;
-               vala_unresolved_type_set_is_weak (VALA_UNRESOLVED_TYPE ($$), TRUE);
-               vala_unresolved_type_set_array_rank (VALA_UNRESOLVED_TYPE ($$), $3);
-               if ($5) {
-                       vala_data_type_set_nullable ($$, TRUE);
-                       vala_data_type_set_requires_null_check ($$, TRUE);
-               }
-         }
-       | type_name opt_rank_specifier opt_op_neg opt_any_interr HASH
-         {
-               $$ = $1;
-               vala_data_type_set_transfers_ownership ($$, TRUE);
-               vala_unresolved_type_set_array_rank (VALA_UNRESOLVED_TYPE ($$), $2);
-               if ($4) {
-                       vala_data_type_set_nullable ($$, TRUE);
-                       vala_data_type_set_requires_null_check ($$, TRUE);
-               }
-         }
-       | REF type_name opt_rank_specifier opt_op_neg opt_any_interr
-         {
-               $$ = $2;
-               vala_data_type_set_is_ref ($$, TRUE);
-               vala_unresolved_type_set_array_rank (VALA_UNRESOLVED_TYPE ($$), $3);
-               if ($5) {
-                       vala_data_type_set_nullable ($$, TRUE);
-                       vala_data_type_set_requires_null_check ($$, TRUE);
-               }
-         }
-       | OUT type_name opt_rank_specifier opt_op_neg opt_any_interr
-         {
-               $$ = $2;
-               vala_data_type_set_is_out ($$, TRUE);
-               vala_unresolved_type_set_array_rank (VALA_UNRESOLVED_TYPE ($$), $3);
-               if ($5) {
-                       vala_data_type_set_nullable ($$, TRUE);
-                       vala_data_type_set_requires_null_check ($$, TRUE);
-               }
-         }
-       | OUT WEAK type_name opt_rank_specifier opt_op_neg opt_any_interr
-         {
-               $$ = $3;
-               vala_unresolved_type_set_is_weak (VALA_UNRESOLVED_TYPE ($$), TRUE);
-               vala_data_type_set_is_out ($$, TRUE);
-               vala_unresolved_type_set_array_rank (VALA_UNRESOLVED_TYPE ($$), $4);
-               if ($6) {
-                       vala_data_type_set_nullable ($$, TRUE);
-                       vala_data_type_set_requires_null_check ($$, TRUE);
-               }
-         }
-       | type_name stars opt_rank_specifier
-         {
-               $$ = $1;
-               vala_unresolved_type_set_pointer_level (VALA_UNRESOLVED_TYPE ($$), $2);
-               vala_unresolved_type_set_array_rank (VALA_UNRESOLVED_TYPE ($$), $3);
-         }
-       | VOID
-         {
-               $$ = VALA_DATA_TYPE (vala_void_type_new ());
-         }
-       | VOID stars
-         {
-               int pointer_level;
-
-               $$ = VALA_DATA_TYPE (vala_void_type_new ());
-
-               for (pointer_level = $2; pointer_level > 0; pointer_level--) {
-                       ValaDataType *base_type = $$;
-                       $$ = VALA_DATA_TYPE (vala_pointer_type_new (base_type));
-                       g_object_unref (base_type);
-               }
-         }
-       ;
-
-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);
-               ValaDataType *t = VALA_DATA_TYPE (vala_unresolved_type_new_from_expression (VALA_EXPRESSION ($2)));
-               $$ = VALA_EXPRESSION (vala_code_context_create_array_creation_expression (context, 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);
-               ValaDataType *t = VALA_DATA_TYPE (vala_unresolved_type_new_from_expression (VALA_EXPRESSION ($2)));
-               $$ = VALA_EXPRESSION (vala_code_context_create_array_creation_expression (context, 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
-       : OPEN_ARRAY_TYPE_BRACKET opt_comma_list CLOSE_BRACKET
-         {
-               $$ = $2;
-         }
-       ;
-
-opt_comma_list
-       : /* empty */
-         {
-               $$ = 1;
-         }
-       | comma_list
-       ;
-
-comma_list
-       : COMMA
-         {
-               $$ = 2;
-         }
-       | comma_list COMMA
-         {
-               $$ = $1 + 1;
-         }
-       ;
-
-primary_no_array_creation_expression
-       : literal
-       | simple_name
-       | parenthesized_expression
-       | member_access
-       | pointer_member_access
-       | invocation_expression
-       | element_access
-       | this_access
-       | base_access
-       | post_increment_expression
-       | post_decrement_expression
-       | object_creation_expression
-       | sizeof_expression
-       | typeof_expression
-       ;
-
-simple_name
-       : identifier opt_type_argument_list
-         {
-               ValaSourceReference *src = src(@1);
-               $$ = VALA_EXPRESSION (vala_code_context_create_member_access (context, 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);
-               if ($2 == NULL) {
-                       // error in subexpression
-                       $$ = NULL;
-               } else {
-                       $$ = VALA_EXPRESSION (vala_code_context_create_parenthesized_expression (context, $2, src));
-                       g_object_unref (src);
-                       g_object_unref ($2);
-               }
-         }
-       ;
-
-member_access
-       : primary_expression DOT identifier_or_keyword opt_type_argument_list
-         {
-               ValaSourceReference *src = src(@3);
-               $$ = VALA_EXPRESSION (vala_code_context_create_member_access (context, $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);
-               }
-         }
-       ;
-
-pointer_member_access
-       : primary_expression OP_PTR identifier opt_type_argument_list
-         {
-               ValaSourceReference *src = src(@3);
-               $$ = VALA_EXPRESSION (vala_code_context_create_member_access_pointer (context, $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_code_context_create_invocation_expression (context, $1, src));
-               g_object_unref ($1);
-               g_object_unref (src);
-               
-               if ($3 != NULL) {
-                       GList *l;
-                       for (l = $3; l != NULL; l = l->next) {
-                               if (l->data == NULL) {
-                                       // error in subexpression
-                               } else {
-                                       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_code_context_create_element_access (context, $1, src));
-               for (l = $3; l != NULL; l = l->next) {
-                       if (l->data == NULL) {
-                               // error in subexpression
-                       } else {
-                               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_code_context_create_member_access (context, NULL, "this", src));
-               g_object_unref (src);
-         }
-       ;
-
-base_access
-       : BASE
-         {
-               ValaSourceReference *src = src(@1);
-               $$ = VALA_EXPRESSION (vala_code_context_create_base_access (context, src));
-               g_object_unref (src);
-         }
-       ;
-
-post_increment_expression
-       : primary_expression OP_INC
-         {
-               ValaSourceReference *src = src(@1);
-               $$ = VALA_EXPRESSION (vala_code_context_create_postfix_expression (context, $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_code_context_create_postfix_expression (context, $1, FALSE, src));
-               g_object_unref (src);
-               g_object_unref ($1);
-         }
-       ;
-
-object_creation_expression
-       : NEW member_name open_parens opt_argument_list CLOSE_PARENS opt_object_initializer
-         {
-               ValaSourceReference *src = src(@2);
-               ValaObjectCreationExpression *expr;
-               vala_member_access_set_creation_member (VALA_MEMBER_ACCESS ($2), TRUE);
-               expr = vala_code_context_create_object_creation_expression (context, 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);
-               }
-
-               if ($6 != NULL) {
-                       GList *l;
-                       for (l = $6; l != NULL; l = l->next) {
-                               vala_object_creation_expression_add_member_initializer (expr, l->data);
-                               g_object_unref (l->data);
-                       }
-                       g_list_free ($6);
-               }
-
-               $$ = VALA_EXPRESSION (expr);
-         }
-       ;
-
-opt_object_initializer
-       : /* empty */
-         {
-               $$ = NULL;
-         }
-       | object_initializer
-       ;
-
-object_initializer
-       : OPEN_BRACE member_initializer_list CLOSE_BRACE
-         {
-               $$ = $2;
-         }
-       ;
-
-member_initializer_list
-       : member_initializer
-         {
-               $$ = g_list_append (NULL, $1);
-         }
-       | member_initializer_list COMMA member_initializer
-         {
-               $$ = g_list_append ($1, $3);
-         }
-       ;
-
-member_initializer
-       : IDENTIFIER ASSIGN expression
-         {
-               if ($1 == NULL || $3 == NULL) {
-                       // error in subexpression
-                       $$ = NULL;
-               } else {
-                       ValaSourceReference *src = src(@2);
-                       $$ = vala_member_initializer_new ($1, $3, src);
-                       g_object_unref (src);
-                       g_free ($1);
-                       g_object_unref ($3);
-               }
-         }
-       ;
-
-sizeof_expression
-       : SIZEOF open_parens type_name CLOSE_PARENS
-         {
-               if ($3 == NULL) {
-                       // error in subexpression
-                       $$ = NULL;
-               } else {
-                       ValaSourceReference *src = src(@1);
-                       $$ = VALA_EXPRESSION (vala_code_context_create_sizeof_expression (context, $3, src));
-                       g_object_unref ($3);
-                       g_object_unref (src);
-               }
-         }
-
-typeof_expression
-       : TYPEOF open_parens type CLOSE_PARENS
-         {
-               if ($3 == NULL) {
-                       // error in subexpression
-                       $$ = NULL;
-               } else {
-                       ValaSourceReference *src = src(@1);
-                       $$ = VALA_EXPRESSION (vala_code_context_create_typeof_expression (context, $3, src));
-                       g_object_unref ($3);
-                       g_object_unref (src);
-               }
-         }
-
-unary_expression
-       : primary_expression
-       | PLUS unary_expression
-         {
-               if ($2 == NULL) {
-                       // error in subexpression
-                       $$ = NULL;
-               } else {
-                       ValaSourceReference *src = src(@1);
-                       $$ = VALA_EXPRESSION (vala_code_context_create_unary_expression (context, VALA_UNARY_OPERATOR_PLUS, $2, src));
-                       g_object_unref (src);
-                       g_object_unref ($2);
-               }
-         }
-       | MINUS unary_expression
-         {
-               if ($2 == NULL) {
-                       // error in subexpression
-                       $$ = NULL;
-               } else {
-                       ValaSourceReference *src = src(@1);
-                       $$ = VALA_EXPRESSION (vala_code_context_create_unary_expression (context, VALA_UNARY_OPERATOR_MINUS, $2, src));
-                       g_object_unref (src);
-                       g_object_unref ($2);
-               }
-         }
-       | OP_NEG unary_expression
-         {
-               if ($2 == NULL) {
-                       // error in subexpression
-                       $$ = NULL;
-               } else {
-                       ValaSourceReference *src = src(@1);
-                       $$ = VALA_EXPRESSION (vala_code_context_create_unary_expression (context, VALA_UNARY_OPERATOR_LOGICAL_NEGATION, $2, src));
-                       g_object_unref (src);
-                       g_object_unref ($2);
-               }
-         }
-       | TILDE unary_expression
-         {
-               if ($2 == NULL) {
-                       // error in subexpression
-                       $$ = NULL;
-               } else {
-                       ValaSourceReference *src = src(@1);
-                       $$ = VALA_EXPRESSION (vala_code_context_create_unary_expression (context, VALA_UNARY_OPERATOR_BITWISE_COMPLEMENT, $2, src));
-                       g_object_unref (src);
-                       g_object_unref ($2);
-               }
-         }
-       | pre_increment_expression
-       | pre_decrement_expression
-       | REF unary_expression
-         {
-               if ($2 == NULL) {
-                       // error in subexpression
-                       $$ = NULL;
-               } else {
-                       ValaSourceReference *src = src(@1);
-                       $$ = VALA_EXPRESSION (vala_code_context_create_unary_expression (context, VALA_UNARY_OPERATOR_REF, $2, src));
-                       g_object_unref (src);
-                       g_object_unref ($2);
-               }
-         }
-       | OUT unary_expression
-         {
-               if ($2 == NULL) {
-                       // error in subexpression
-                       $$ = NULL;
-               } else {
-                       ValaSourceReference *src = src(@1);
-                       $$ = VALA_EXPRESSION (vala_code_context_create_unary_expression (context, VALA_UNARY_OPERATOR_OUT, $2, src));
-                       g_object_unref (src);
-                       g_object_unref ($2);
-               }
-         }
-       | HASH unary_expression
-         {
-               if ($2 == NULL) {
-                       // error in subexpression
-                       $$ = NULL;
-               } else {
-                       ValaSourceReference *src = src(@1);
-                       $$ = VALA_EXPRESSION (vala_code_context_create_reference_transfer_expression (context, $2, src));
-                       g_object_unref (src);
-                       g_object_unref ($2);
-               }
-         }
-       | cast_expression
-       | pointer_indirection_expression
-       | addressof_expression
-       ;
-
-pre_increment_expression
-       : OP_INC unary_expression
-         {
-               if ($2 == NULL) {
-                       // error in subexpression
-                       $$ = NULL;
-               } else {
-                       ValaSourceReference *src = src(@1);
-                       $$ = VALA_EXPRESSION (vala_code_context_create_unary_expression (context, VALA_UNARY_OPERATOR_INCREMENT, $2, src));
-                       g_object_unref ($2);
-                       g_object_unref (src);
-               }
-         }
-       ;
-
-pre_decrement_expression
-       : OP_DEC unary_expression
-         {
-               if ($2 == NULL) {
-                       // error in subexpression
-                       $$ = NULL;
-               } else {
-                       ValaSourceReference *src = src(@1);
-                       $$ = VALA_EXPRESSION (vala_code_context_create_unary_expression (context, VALA_UNARY_OPERATOR_DECREMENT, $2, src));
-                       g_object_unref ($2);
-                       g_object_unref (src);
-               }
-         }
-       ;
-
-cast_expression
-       : OPEN_CAST_PARENS type CLOSE_PARENS unary_expression
-         {
-               if ($2 == NULL || $4 == NULL) {
-                       // error in subexpression
-                       $$ = NULL;
-               } else {
-                       ValaSourceReference *src = src(@1);
-                       $$ = VALA_EXPRESSION (vala_code_context_create_cast_expression (context, $4, $2, src, FALSE));
-                       g_object_unref (src);
-                       g_object_unref ($2);
-                       g_object_unref ($4);
-               }
-         }
-       ;
-
-pointer_indirection_expression
-       : STAR unary_expression
-         {
-               if ($2 == NULL) {
-                       // error in subexpression
-                       $$ = NULL;
-               } else {
-                       ValaSourceReference *src = src(@1);
-                       $$ = VALA_EXPRESSION (vala_code_context_create_pointer_indirection (context, $2, src));
-                       g_object_unref (src);
-                       g_object_unref ($2);
-               }
-         }
-       ;
-
-addressof_expression
-       : BITWISE_AND unary_expression
-         {
-               if ($2 == NULL) {
-                       // error in subexpression
-                       $$ = NULL;
-               } else {
-                       ValaSourceReference *src = src(@1);
-                       $$ = VALA_EXPRESSION (vala_code_context_create_addressof_expression (context, $2, src));
-                       g_object_unref (src);
-                       g_object_unref ($2);
-               }
-         }
-       ;
-
-multiplicative_expression
-       : unary_expression
-       | multiplicative_expression STAR unary_expression
-         {
-               if ($1 == NULL || $3 == NULL) {
-                       // error in subexpression
-                       $$ = NULL;
-               } else {
-                       ValaSourceReference *src = src(@2);
-                       $$ = VALA_EXPRESSION (vala_code_context_create_binary_expression (context, VALA_BINARY_OPERATOR_MUL, $1, $3, src));
-                       g_object_unref (src);
-                       g_object_unref ($1);
-                       g_object_unref ($3);
-               }
-         }
-       | multiplicative_expression DIV unary_expression
-         {
-               if ($1 == NULL || $3 == NULL) {
-                       // error in subexpression
-                       $$ = NULL;
-               } else {
-                       ValaSourceReference *src = src(@2);
-                       $$ = VALA_EXPRESSION (vala_code_context_create_binary_expression (context, VALA_BINARY_OPERATOR_DIV, $1, $3, src));
-                       g_object_unref (src);
-                       g_object_unref ($1);
-                       g_object_unref ($3);
-               }
-         }
-       | multiplicative_expression PERCENT unary_expression
-         {
-               if ($1 == NULL || $3 == NULL) {
-                       // error in subexpression
-                       $$ = NULL;
-               } else {
-                       ValaSourceReference *src = src(@2);
-                       $$ = VALA_EXPRESSION (vala_code_context_create_binary_expression (context, 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
-         {
-               if ($1 == NULL || $3 == NULL) {
-                       // error in subexpression
-                       $$ = NULL;
-               } else {
-                       ValaSourceReference *src = src(@2);
-                       $$ = VALA_EXPRESSION (vala_code_context_create_binary_expression (context, VALA_BINARY_OPERATOR_PLUS, $1, $3, src));
-                       g_object_unref (src);
-                       g_object_unref ($1);
-                       g_object_unref ($3);
-               }
-         }
-       | additive_expression MINUS multiplicative_expression
-         {
-               if ($1 == NULL || $3 == NULL) {
-                       // error in subexpression
-                       $$ = NULL;
-               } else {
-                       ValaSourceReference *src = src(@2);
-                       $$ = VALA_EXPRESSION (vala_code_context_create_binary_expression (context, 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
-         {
-               if ($1 == NULL || $3 == NULL) {
-                       // error in subexpression
-                       $$ = NULL;
-               } else {
-                       ValaSourceReference *src = src(@2);
-                       $$ = VALA_EXPRESSION (vala_code_context_create_binary_expression (context, 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 to resolve parse conflicts
-        * stacked generics won't be that common in vala */
-       | shift_expression OP_SHIFT_RIGHT additive_expression
-         {
-               if ($1 == NULL || $3 == NULL) {
-                       // error in subexpression
-                       $$ = NULL;
-               } else {
-                       ValaSourceReference *src = src(@2);
-                       $$ = VALA_EXPRESSION (vala_code_context_create_binary_expression (context, 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
-         {
-               if ($1 == NULL || $3 == NULL) {
-                       // error in subexpression
-                       $$ = NULL;
-               } else {
-                       ValaSourceReference *src = src(@2);
-                       $$ = VALA_EXPRESSION (vala_code_context_create_binary_expression (context, 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
-         {
-               if ($1 == NULL || $3 == NULL) {
-                       // error in subexpression
-                       $$ = NULL;
-               } else {
-                       ValaSourceReference *src = src(@2);
-                       $$ = VALA_EXPRESSION (vala_code_context_create_binary_expression (context, 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
-         {
-               if ($1 == NULL || $3 == NULL) {
-                       // error in subexpression
-                       $$ = NULL;
-               } else {
-                       ValaSourceReference *src = src(@2);
-                       $$ = VALA_EXPRESSION (vala_code_context_create_binary_expression (context, 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
-         {
-               if ($1 == NULL || $3 == NULL) {
-                       // error in subexpression
-                       $$ = NULL;
-               } else {
-                       ValaSourceReference *src = src(@2);
-                       $$ = VALA_EXPRESSION (vala_code_context_create_binary_expression (context, 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_name
-         {
-               if ($1 == NULL || $3 == NULL) {
-                       // error in subexpression
-                       $$ = NULL;
-               } else {
-                       ValaSourceReference *src = src(@2);
-                       $$ = VALA_EXPRESSION (vala_code_context_create_type_check (context, $1, $3, src));
-                       g_object_unref (src);
-                       g_object_unref ($1);
-                       g_object_unref ($3);
-               }
-         }
-       | relational_expression AS type_name
-         {
-               if ($1 == NULL || $3 == NULL) {
-                       // error in subexpression
-                       $$ = NULL;
-               } else {
-                       ValaSourceReference *src = src(@2);
-                       $$ = VALA_EXPRESSION (vala_code_context_create_cast_expression (context, $1, $3, src, TRUE));
-                       g_object_unref (src);
-                       g_object_unref ($1);
-                       g_object_unref ($3);
-               }
-         }
-       ;
-
-equality_expression
-       : relational_expression
-       | equality_expression OP_EQ relational_expression
-         {
-               if ($1 == NULL || $3 == NULL) {
-                       // error in subexpression
-                       $$ = NULL;
-               } else {
-                       ValaSourceReference *src = src(@2);
-                       $$ = VALA_EXPRESSION (vala_code_context_create_binary_expression (context, 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
-         {
-               if ($1 == NULL || $3 == NULL) {
-                       // error in subexpression
-                       $$ = NULL;
-               } else {
-                       ValaSourceReference *src = src(@2);
-                       $$ = VALA_EXPRESSION (vala_code_context_create_binary_expression (context, 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
-         {
-               if ($1 == NULL || $3 == NULL) {
-                       // error in subexpression
-                       $$ = NULL;
-               } else {
-                       ValaSourceReference *src = src(@2);
-                       $$ = VALA_EXPRESSION (vala_code_context_create_binary_expression (context, 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
-         {
-               if ($1 == NULL || $3 == NULL) {
-                       // error in subexpression
-                       $$ = NULL;
-               } else {
-                       ValaSourceReference *src = src(@2);
-                       $$ = VALA_EXPRESSION (vala_code_context_create_binary_expression (context, 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
-         {
-               if ($1 == NULL || $3 == NULL) {
-                       // error in subexpression
-                       $$ = NULL;
-               } else {
-                       ValaSourceReference *src = src(@2);
-                       $$ = VALA_EXPRESSION (vala_code_context_create_binary_expression (context, VALA_BINARY_OPERATOR_BITWISE_OR, $1, $3, src));
-                       g_object_unref (src);
-                       g_object_unref ($1);
-                       g_object_unref ($3);
-               }
-         }
-       ;
-
-in_expression
-       : inclusive_or_expression
-       | in_expression IN inclusive_or_expression
-         {
-               if ($1 == NULL || $3 == NULL) {
-                       // error in subexpression
-                       $$ = NULL;
-               } else {
-                       ValaSourceReference *src = src(@2);
-                       $$ = VALA_EXPRESSION (vala_code_context_create_binary_expression (context, VALA_BINARY_OPERATOR_IN, $1, $3, src));
-                       g_object_unref (src);
-                       g_object_unref ($1);
-                       g_object_unref ($3);
-               }
-         }
-       ;
-
-
-conditional_and_expression
-       : in_expression
-       | conditional_and_expression OP_AND in_expression
-         {
-               if ($1 == NULL || $3 == NULL) {
-                       // error in subexpression
-                       $$ = NULL;
-               } else {
-                       ValaSourceReference *src = src(@2);
-                       $$ = VALA_EXPRESSION (vala_code_context_create_binary_expression (context, 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
-         {
-               if ($1 == NULL || $3 == NULL) {
-                       // error in subexpression
-                       $$ = NULL;
-               } else {
-                       ValaSourceReference *src = src(@2);
-                       $$ = VALA_EXPRESSION (vala_code_context_create_binary_expression (context, 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
-         {
-               if ($1 == NULL || $3 == NULL || $5 == NULL) {
-                       // error in subexpression
-                       $$ = NULL;
-               } else {
-                       ValaSourceReference *src = src(@2);
-                       $$ = VALA_EXPRESSION (vala_code_context_create_conditional_expression (context, $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
-         {
-               if ($5 == NULL) {
-                       // error in lambda expression
-                       $$ = NULL;
-               } else {
-                       ValaSourceReference *src = src(@4);
-                       $$ = VALA_EXPRESSION (vala_code_context_create_lambda_expression (context, $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
-         {
-               if ($3 == NULL) {
-                       // error in lambda expression
-                       $$ = NULL;
-               } else {
-                       ValaSourceReference *src = src(@2);
-                       $$ = VALA_EXPRESSION (vala_code_context_create_lambda_expression (context, $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
-         {
-               if ($5 == NULL) {
-                       // error in lambda block
-                       $$ = NULL;
-               } else {
-                       ValaSourceReference *src = src(@4);
-                       $$ = VALA_EXPRESSION (vala_code_context_create_lambda_expression_with_statement_body (context, 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
-         {
-               if ($3 == NULL) {
-                       // error in lambda block
-                       $$ = NULL;
-               } else {
-                       ValaSourceReference *src = src(@2);
-                       $$ = VALA_EXPRESSION (vala_code_context_create_lambda_expression_with_statement_body (context, 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
-         {
-               if ($1 == NULL || $3 == NULL) {
-                       // error in subexpression
-                       $$ = NULL;
-               } else {
-                       ValaSourceReference *src = src(@2);
-                       $$ = VALA_EXPRESSION (vala_code_context_create_assignment (context, $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
-         {
-               $$ = VALA_STATEMENT ($1);
-         }
-       | empty_statement
-       | expression_statement
-       | selection_statement
-       | iteration_statement
-       | jump_statement
-       | try_statement
-       | lock_statement
-       | delete_statement
-       ;
-
-embedded_statement
-       : block
-       | empty_statement
-         {
-               ValaSourceReference *src = src(@1);
-               if ($1 == NULL) {
-                       // error in subexpression
-                       $$ = NULL;
-               } else {
-                       $$ = vala_code_context_create_block (context, src);
-                       vala_block_add_statement ($$, $1);
-                       g_object_unref ($1);
-                       g_object_unref (src);
-               }
-         }
-       | expression_statement
-         {
-               ValaSourceReference *src = src(@1);
-               if ($1 == NULL) {
-                       // error in subexpression
-                       $$ = NULL;
-               } else {
-                       $$ = vala_code_context_create_block (context, src);
-                       vala_block_add_statement ($$, $1);
-                       g_object_unref ($1);
-                       g_object_unref (src);
-               }
-         }
-       | selection_statement
-         {
-               ValaSourceReference *src = src(@1);
-               if ($1 == NULL) {
-                       // error in subexpression
-                       $$ = NULL;
-               } else {
-                       $$ = vala_code_context_create_block (context, src);
-                       vala_block_add_statement ($$, $1);
-                       g_object_unref ($1);
-                       g_object_unref (src);
-               }
-         }
-       | iteration_statement
-         {
-               ValaSourceReference *src = src(@1);
-               if ($1 == NULL) {
-                       // error in subexpression
-                       $$ = NULL;
-               } else {
-                       $$ = vala_code_context_create_block (context, src);
-                       vala_block_add_statement ($$, $1);
-                       g_object_unref ($1);
-                       g_object_unref (src);
-               }
-         }
-       | jump_statement
-         {
-               ValaSourceReference *src = src(@1);
-               if ($1 == NULL) {
-                       // error in subexpression
-                       $$ = NULL;
-               } else {
-                       $$ = vala_code_context_create_block (context, src);
-                       vala_block_add_statement ($$, $1);
-                       g_object_unref ($1);
-                       g_object_unref (src);
-               }
-         }
-       | try_statement
-         {
-               ValaSourceReference *src = src(@1);
-               if ($1 == NULL) {
-                       // error in subexpression
-                       $$ = NULL;
-               } else {
-                       $$ = vala_code_context_create_block (context, src);
-                       vala_block_add_statement ($$, $1);
-                       g_object_unref ($1);
-                       g_object_unref (src);
-               }
-         }
-       | lock_statement
-         {
-               ValaSourceReference *src = src(@1);
-               if ($1 == NULL) {
-                       // error in subexpression
-                       $$ = NULL;
-               } else {
-                       $$ = vala_code_context_create_block (context, src);
-                       vala_block_add_statement ($$, $1);
-                       g_object_unref ($1);
-                       g_object_unref (src);
-               }
-         }
-       | delete_statement
-         {
-               ValaSourceReference *src = src(@1);
-               if ($1 == NULL) {
-                       // error in subexpression
-                       $$ = NULL;
-               } else {
-                       $$ = vala_code_context_create_block (context, src);
-                       vala_block_add_statement ($$, $1);
-                       g_object_unref ($1);
-                       g_object_unref (src);
-               }
-         }
-       ;
-
-block
-       : OPEN_BRACE opt_statement_list CLOSE_BRACE
-         {
-               ValaSourceReference *src = src(@1);
-               $$ = vala_code_context_create_block (context, src);
-               if ($2 != NULL) {
-                       GList *l;
-                       for (l = $2; l != NULL; l = l->next) {
-                               if (l->data == NULL) {
-                                       // error in subexpression
-                               } else {
-                                       vala_block_add_statement ($$, 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_code_context_create_empty_statement (context, src));
-               g_object_unref (src);
-         }
-       ;
-
-declaration_statement
-       : comment local_variable_declaration SEMICOLON
-         {
-               ValaSourceReference *src = src_com(@2, $1);
-               $$ = VALA_STATEMENT (vala_code_context_create_declaration_statement (context, $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_code_context_create_local_variable_declaration (context, $1, src);
-               g_object_unref (src);
-               for (l = $2; l != NULL; l = l->next) {
-                       ValaVariableDeclarator *decl = l->data;
-                       ValaDataType *type = vala_data_type_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_code_context_create_local_variable_declaration_var_type (context, 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 opt_nullable_interr
-         {
-               ValaSourceReference *src = src(@1);
-               $$ = VALA_DATA_TYPE (vala_unresolved_type_new_from_expression ($1));
-               g_object_unref ($1);
-               g_object_unref (src);
-               vala_data_type_set_takes_ownership ($$, TRUE);
-               vala_unresolved_type_set_array_rank (VALA_UNRESOLVED_TYPE ($$), $2);
-               vala_data_type_set_nullable ($$, TRUE);
-         }
-       | primary_expression stars
-         {
-               ValaSourceReference *src = src(@1);
-               $$ = VALA_DATA_TYPE (vala_unresolved_type_new_from_expression ($1));
-               g_object_unref ($1);
-               g_object_unref (src);
-               vala_unresolved_type_set_pointer_level (VALA_UNRESOLVED_TYPE ($$), $2);
-         }
-       | WEAK primary_expression opt_bracket_pair opt_op_neg opt_nullable_interr
-         {
-               ValaSourceReference *src = src(@2);
-               $$ = VALA_DATA_TYPE (vala_unresolved_type_new_from_expression ($2));
-               g_object_unref ($2);
-               g_object_unref (src);
-               vala_unresolved_type_set_array_rank (VALA_UNRESOLVED_TYPE ($$), $3);
-               vala_data_type_set_nullable ($$, TRUE);
-         }
-       | VOID
-         {
-               ValaSourceReference *src = src(@1);
-               $$ = VALA_DATA_TYPE (vala_void_type_new ());
-               g_object_unref (src);
-         }
-       | VOID stars
-         {
-               int pointer_level;
-               ValaSourceReference *src = src(@1);
-               $$ = VALA_DATA_TYPE (vala_void_type_new ());
-               g_object_unref (src);
-
-               for (pointer_level = $2; pointer_level > 0; pointer_level--) {
-                       ValaDataType *base_type = $$;
-                       $$ = VALA_DATA_TYPE (vala_pointer_type_new (base_type));
-                       g_object_unref (base_type);
-               }
-         }
-       ;
-
-opt_op_neg
-       : /* empty */
-         {
-               $$ = FALSE;
-         }
-       | OP_NEG
-         {
-               $$ = TRUE;
-         }
-       ;
-
-opt_any_interr
-       : /* empty */
-         {
-               $$ = FALSE;
-         }
-       | INTERR
-         {
-               $$ = TRUE;
-         }
-       | NULLABLE_INTERR
-         {
-               $$ = TRUE;
-         }
-       ;
-
-opt_nullable_interr
-       : /* empty */
-         {
-               $$ = FALSE;
-         }
-       | NULLABLE_INTERR
-         {
-               $$ = TRUE;
-         }
-       ;
-
-expression_statement
-       : comment statement_expression SEMICOLON
-         {
-               ValaSourceReference *src = src_com(@2, $1);
-               $$ = VALA_STATEMENT (vala_code_context_create_expression_statement (context, $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
-         {
-               ValaSourceReference *src;
-
-               if ($4 == NULL || $6 == NULL) {
-                       // error in subexpression
-                       $$ = NULL;
-               } else {
-                       src = src_com(@4, $1);
-                       $$ = VALA_STATEMENT (vala_code_context_create_if_statement (context, $4, $6, NULL, src));
-                       g_object_unref (src);
-                       g_object_unref ($4);
-                       g_object_unref ($6);
-               }
-         }
-       | comment IF open_parens expression CLOSE_PARENS embedded_statement ELSE embedded_statement
-         {
-               ValaSourceReference *src;
-
-               if ($4 == NULL || $6 == NULL || $8 == NULL) {
-                       // error in subexpression
-                       $$ = NULL;
-               } else {
-                       src = src_com(@4, $1);
-                       $$ = VALA_STATEMENT (vala_code_context_create_if_statement (context, $4, $6, $8, src));
-                       g_object_unref (src);
-                       g_object_unref ($4);
-                       g_object_unref ($6);
-                       g_object_unref ($8);
-               }
-         }
-       ;
-
-switch_statement
-       : comment SWITCH open_parens expression CLOSE_PARENS switch_block
-         {
-               ValaSourceReference *src = src_com(@4, $1);
-               $$ = VALA_STATEMENT (vala_code_context_create_switch_statement (context, $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
-         {
-               GList *l;
-               ValaSourceReference *src = src_com(@2, $1);
-               $$ = vala_code_context_create_switch_section (context, src);
-               g_object_unref (src);
-               
-               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_code_context_create_switch_label (context, $2, src);
-               g_object_unref ($2);
-               g_object_unref (src);
-         }
-       | DEFAULT COLON
-         {
-               ValaSourceReference *src = src(@1);
-               $$ = vala_code_context_create_switch_label_with_default (context, 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_code_context_create_while_statement (context, $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_code_context_create_do_statement (context, $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
-         {
-               GList *l;
-               ValaSourceReference *src = src(@1);
-               $$ = VALA_STATEMENT (vala_code_context_create_for_statement (context, $5, $9, src));
-               if ($5 != NULL) {
-                       g_object_unref ($5);
-               }
-               g_object_unref ($9);
-               g_object_unref (src);
-               
-               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
-         {
-               GeeCollection *decls;
-               GeeIterator *decls_it;
-
-               ValaDeclarationStatement *decl_statement;
-
-               ValaSourceReference *src = src(@1);
-
-               ValaBlock *block = vala_code_context_create_block (context, src);
-         
-               ValaForStatement *for_statement = vala_code_context_create_for_statement (context, $5, $9, src);
-               if ($5 != NULL) {
-                       g_object_unref ($5);
-               }
-               g_object_unref ($9);
-               
-
-               decls = vala_local_variable_declaration_get_variable_declarators ($3);
-               decls_it = gee_iterable_iterator (GEE_ITERABLE (decls));
-               g_object_unref (decls);
-               while (gee_iterator_next (decls_it)) {
-                       ValaVariableDeclarator *decl = gee_iterator_get (decls_it);
-                       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_code_context_create_member_access (context, NULL, vala_symbol_get_name (VALA_SYMBOL (decl)), decl_src);
-                               ValaAssignment *assign = vala_code_context_create_assignment (context, 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_object_unref (decls_it);
-               
-               decl_statement = vala_code_context_create_declaration_statement (context, $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) {
-                       GList *l;
-                       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);
-               if (!vala_unresolved_type_get_is_weak (VALA_UNRESOLVED_TYPE ($3))) {
-                       vala_data_type_set_takes_ownership ($3, TRUE);
-               }
-               $$ = VALA_STATEMENT (vala_code_context_create_foreach_statement (context, $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_code_context_create_break_statement (context, src));
-               g_object_unref (src);
-         }
-       ;
-
-continue_statement
-       : CONTINUE SEMICOLON
-         {
-               ValaSourceReference *src = src(@1);
-               $$ = VALA_STATEMENT (vala_code_context_create_continue_statement (context, src));
-               g_object_unref (src);
-         }
-       ;
-
-return_statement
-       : RETURN opt_expression SEMICOLON
-         {
-               ValaSourceReference *src = src(@1);
-               $$ = VALA_STATEMENT (vala_code_context_create_return_statement (context, $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_code_context_create_throw_statement (context, $2, src));
-               g_object_unref (src);
-               if ($2 != NULL) {
-                       g_object_unref ($2);
-               }
-         }
-       ;
-
-try_statement
-       : TRY block catch_clauses opt_finally_clause
-         {
-               GList *l;
-               ValaSourceReference *src = src(@1);
-               $$ = VALA_STATEMENT (vala_code_context_create_try_statement (context, $2, $4, src));
-               g_object_unref ($2);
-               if ($4 != NULL) {
-                       g_object_unref ($4);
-               }
-               g_object_unref (src);
-
-               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_code_context_create_try_statement (context, $2, $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_code_context_create_catch_clause (context, $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_code_context_create_catch_clause (context, 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_code_context_create_lock_statement (context, $4, $6, src));
-               g_object_unref (src);
-               g_object_unref ($4);
-               g_object_unref ($6);
-         }
-       ;
-
-delete_statement
-       : comment DELETE expression SEMICOLON
-         {
-               ValaSourceReference *src = src_com(@2, $1);
-               $$ = VALA_STATEMENT (vala_code_context_create_delete_statement (context, $3, src));
-               g_object_unref (src);
-               g_object_unref ($3);
-         }
-       ;
-
-namespace_declaration
-       : comment opt_attributes NAMESPACE identifier
-         {
-               ValaSourceReference *src = src_com(@4, $1);
-               ValaSymbol *current_symbol = vala_scope_lookup (scope_stack->data, $4);
-               if (current_symbol != NULL) {
-                       if (check_is_namespace (current_symbol, src)) {
-                               // merge namespace declarations
-                               if (!vala_source_file_get_pkg (current_source_file)) {
-                                       vala_namespace_set_pkg (VALA_NAMESPACE (current_symbol), FALSE);
-                               }
-                               VALA_CODE_NODE (current_symbol)->attributes = $2;
-                       }
-               } else {
-                       current_symbol = VALA_SYMBOL (vala_code_context_create_namespace (context, $4, src));
-                       vala_namespace_set_pkg (VALA_NAMESPACE (current_symbol), vala_source_file_get_pkg (current_source_file));
-                       VALA_CODE_NODE (current_symbol)->attributes = g_list_concat (VALA_CODE_NODE (current_symbol)->attributes, $2);
-                       vala_namespace_add_namespace (VALA_NAMESPACE (symbol_stack->data), VALA_NAMESPACE (current_symbol));
-               }
-               g_object_unref (src);
-               g_free ($4);
-               
-               push_symbol (current_symbol);
-         }
-         namespace_body
-         {
-               g_object_unref (pop_symbol ());
-         }
-       ;
-
-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 using_list SEMICOLON
-       ;
-
-using_list
-       : using_list COMMA namespace_identifier
-       | namespace_identifier
-       ;
-
-namespace_identifier
-       : identifier
-         {
-               ValaSourceReference *src = src(@1);
-               ValaNamespaceReference *ns_ref = vala_namespace_reference_new ($1, src);
-               g_object_unref (src);
-               g_free ($1);
-               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_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
-       : namespace_declaration
-       | class_declaration
-       | struct_declaration
-       | interface_declaration
-       | enum_declaration
-       | errordomain_declaration
-       | delegate_declaration
-       | constant_declaration
-         {
-               /* skip declarations with errors */
-               if ($1 != NULL) {
-                       vala_namespace_add_constant (VALA_NAMESPACE (symbol_stack->data), $1);
-                       vala_source_file_add_node (current_source_file, VALA_CODE_NODE ($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 (VALA_NAMESPACE (symbol_stack->data), $1);
-                       vala_source_file_add_node (current_source_file, VALA_CODE_NODE ($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 (VALA_NAMESPACE (symbol_stack->data), $1);
-                       vala_source_file_add_node (current_source_file, VALA_CODE_NODE ($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
-         {
-               ValaSourceReference *src;
-
-               char *name = $6;
-
-               ValaSymbol *parent_symbol = VALA_SYMBOL (g_object_ref (symbol_stack->data));
-               ValaScope *parent_scope = VALA_SCOPE (scope_stack->data);
-               ValaSymbol *current_symbol;
-
-               if ($7 != NULL) {
-                       ValaSourceReference *ns_src = src(@6);
-                       g_object_unref (parent_symbol);
-                       parent_symbol = vala_scope_lookup (parent_scope, $6);
-                       if (parent_symbol != NULL) {
-                               if (check_is_namespace (parent_symbol, ns_src)) {
-                                       if (!vala_source_file_get_pkg (current_source_file)) {
-                                               vala_namespace_set_pkg (VALA_NAMESPACE (parent_symbol), FALSE);
-                                       }
-                               }
-                       } else {
-                               parent_symbol = VALA_SYMBOL (vala_code_context_create_namespace (context, $6, ns_src));
-                               vala_namespace_set_pkg (VALA_NAMESPACE (parent_symbol), vala_source_file_get_pkg (current_source_file));
-                               vala_namespace_add_namespace (VALA_NAMESPACE (symbol_stack->data), VALA_NAMESPACE (parent_symbol));
-                       }
-                       parent_scope = vala_symbol_get_scope (parent_symbol);
-                       g_free ($6);
-                       g_object_unref (ns_src);
-                       
-                       name = $7;
-               }
-
-               src = src_com(@6, $1);
-               current_symbol = vala_scope_lookup (parent_scope, name);
-               if (current_symbol != NULL) {
-                       if (check_is_class (current_symbol, src)) {
-                               // merge class declarations
-                       }
-               } else {
-                       current_symbol = VALA_SYMBOL (vala_code_context_create_class (context, name, src));
-                       g_free (name);
-                       g_object_unref (src);
-
-                       if (VALA_IS_CLASS (parent_symbol)) {
-                               vala_class_add_class (VALA_CLASS (parent_symbol), VALA_CLASS (current_symbol));
-                       } else if (VALA_IS_INTERFACE (parent_symbol)) {
-                               vala_interface_add_class (VALA_INTERFACE (parent_symbol), VALA_CLASS (current_symbol));
-                       } else if (VALA_IS_NAMESPACE (parent_symbol)) {
-                               vala_namespace_add_class (VALA_NAMESPACE (parent_symbol), VALA_CLASS (current_symbol));
-                               vala_source_file_add_node (current_source_file, VALA_CODE_NODE (current_symbol));
-                       } else {
-                               g_assert_not_reached ();
-                       }
-                       
-                       VALA_CODE_NODE (current_symbol)->attributes = $2;
-                       if ($3 != -1) {
-                               vala_symbol_set_access (VALA_SYMBOL (current_symbol), $3);
-                       }
-                       if (($4 & VALA_MODIFIER_ABSTRACT) == VALA_MODIFIER_ABSTRACT) {
-                               vala_class_set_is_abstract (VALA_CLASS (current_symbol), TRUE);
-                       }
-                       if (($4 & VALA_MODIFIER_STATIC) == VALA_MODIFIER_STATIC) {
-                               vala_class_set_is_static (VALA_CLASS (current_symbol), TRUE);
-                       }
-                       if ($8 != NULL) {
-                               GList *l;
-                               for (l = $8; l != NULL; l = l->next) {
-                                       vala_class_add_type_parameter (VALA_CLASS (current_symbol), 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_class_add_base_type (VALA_CLASS (current_symbol), l->data);
-                                       g_object_unref (l->data);
-                               }
-                               g_list_free ($9);
-                       }
-               }
-
-               g_object_unref (parent_symbol);
-               push_symbol (current_symbol);
-         }
-         class_body
-         {
-               /* ensure there is always a default construction method */
-               ValaClass *cl = VALA_CLASS (symbol_stack->data);
-               if (!vala_source_file_get_pkg (current_source_file) &&
-                   !vala_class_get_is_abstract (cl) &&
-                   !vala_class_get_is_static (cl) &&
-                   vala_class_get_default_construction_method (cl) == NULL) {
-                       ValaSourceReference *src;
-                       ValaMethod *m;
-                       ValaBlock *block;
-                       src = vala_code_node_get_source_reference (VALA_CODE_NODE (cl));
-                       m = VALA_METHOD (vala_code_context_create_creation_method (context, vala_symbol_get_name (VALA_SYMBOL (cl)), NULL, src));
-                       vala_method_set_instance (m, FALSE);
-                       vala_symbol_set_access (VALA_SYMBOL (m), VALA_SYMBOL_ACCESSIBILITY_PUBLIC);
-                       block = vala_code_context_create_block (context, src);
-                       vala_method_set_body (m, block);
-                       g_object_unref (block);
-                       vala_class_add_method (cl, m);
-                       g_object_unref (m);
-               }
-               g_object_unref (pop_symbol ());
-         }
-       ;
-
-opt_access_modifier
-       : /* empty */
-         {
-               $$ = -1;
-         }
-       | access_modifier
-       ;
-
-access_modifier
-       : PUBLIC
-         {
-               $$ = VALA_SYMBOL_ACCESSIBILITY_PUBLIC;
-         }
-       | PROTECTED
-         {
-               $$ = VALA_SYMBOL_ACCESSIBILITY_PROTECTED;
-         }
-       | PRIVATE
-         {
-               $$ = VALA_SYMBOL_ACCESSIBILITY_PRIVATE;
-         }
-       ;
-
-opt_modifiers
-       : /* empty */
-         {
-               $$ = VALA_MODIFIER_NONE;
-         }
-       | modifiers
-       ;
-
-modifiers
-       : modifier
-       | modifiers modifier
-         {
-               if (($1 & $2) == $2) {
-                       ValaSourceReference *src = src(@2);
-                       vala_report_error (src, "Modifier may only be specified once.");
-                       g_object_unref (src);
-               }
-               $$ = $1 | $2;
-         }
-       ;
-
-modifier
-       : ABSTRACT
-         {
-               $$ = VALA_MODIFIER_ABSTRACT;
-         }
-       | OVERRIDE
-         {
-               $$ = VALA_MODIFIER_OVERRIDE;
-         }
-       | STATIC
-         {
-               $$ = VALA_MODIFIER_STATIC;
-         }
-       | VIRTUAL
-         {
-               $$ = VALA_MODIFIER_VIRTUAL;
-         }
-       | VOLATILE
-         {
-               $$ = VALA_MODIFIER_VOLATILE;
-         }
-       | INLINE
-         {
-               $$ = VALA_MODIFIER_INLINE;
-         }
-       ;
-
-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 (VALA_CLASS (symbol_stack->data), $1);
-                       g_object_unref ($1);
-               }
-         }
-       | field_declaration
-         {
-               /* skip declarations with errors */
-               if ($1 != NULL) {
-                       vala_class_add_field (VALA_CLASS (symbol_stack->data), $1);
-                       g_object_unref ($1);
-               }
-         }
-       | method_declaration
-         {
-               /* skip declarations with errors */
-               if ($1 != NULL) {
-                       vala_class_add_method (VALA_CLASS (symbol_stack->data), $1);
-                       g_object_unref ($1);
-               }
-         }
-       | property_declaration
-         {
-               /* skip declarations with errors */
-               if ($1 != NULL) {
-                       vala_class_add_property (VALA_CLASS (symbol_stack->data), $1, FALSE);
-                       g_object_unref ($1);
-               }
-         }
-       | signal_declaration
-         {
-               /* skip declarations with errors */
-               if ($1 != NULL) {
-                       vala_class_add_signal (VALA_CLASS (symbol_stack->data), $1);
-                       g_object_unref ($1);
-               }
-         }
-       | constructor_declaration
-         {
-               /* skip declarations with errors */
-               if ($1 != NULL) {
-                       if (vala_constructor_get_instance ($1)) {
-                               vala_class_set_constructor (VALA_CLASS (symbol_stack->data), $1);
-                       } else {
-                               vala_class_set_static_constructor (VALA_CLASS (symbol_stack->data), $1);
-                       }
-                       g_object_unref ($1);
-               }
-         }
-       | destructor_declaration
-         {
-               /* skip declarations with errors */
-               if ($1 != NULL) {
-                       vala_class_set_destructor (VALA_CLASS (symbol_stack->data), $1);
-                       g_object_unref ($1);
-               }
-         }
-       | class_declaration
-       | struct_declaration
-       | enum_declaration
-       | delegate_declaration
-       ;
-
-constant_declaration
-       : comment opt_attributes opt_access_modifier CONST type variable_declarator SEMICOLON
-         {
-               ValaSourceReference *src = src_com(@5, $1);
-               $$ = vala_code_context_create_constant (context, vala_symbol_get_name (VALA_SYMBOL ($6)), $5, vala_variable_declarator_get_initializer ($6), src);
-               g_object_unref (src);
-               g_object_unref ($5);
-               g_object_unref ($6);
-               if ($3 != -1) {
-                       vala_symbol_set_access (VALA_SYMBOL ($$), $3);
-               }
-               VALA_CODE_NODE($$)->attributes = $2;
-         }
-       ;
-
-field_declaration
-       : comment opt_attributes opt_access_modifier opt_modifiers type variable_declarator SEMICOLON
-         {
-               ValaSourceReference *src;
-
-               src = src_com(@6, $1);
-
-               if (VALA_IS_UNRESOLVED_TYPE ($5)) {
-                       if (vala_data_type_get_is_ref ($5) || vala_data_type_get_is_out ($5)) {
-                               vala_report_error (src, "`ref' and `out' may only be used for parameters.");
-                       }
-                       if (!vala_unresolved_type_get_is_weak (VALA_UNRESOLVED_TYPE ($5))) {
-                               vala_data_type_set_takes_ownership ($5, TRUE);
-                       }
-               }
-
-               $$ = vala_code_context_create_field (context, vala_symbol_get_name (VALA_SYMBOL ($6)), $5, vala_variable_declarator_get_initializer ($6), src);
-               g_object_unref (src);
-               if ($3 != -1) {
-                       vala_symbol_set_access (VALA_SYMBOL ($$), $3);
-               }
-               if (($4 & VALA_MODIFIER_STATIC) == VALA_MODIFIER_STATIC) {
-                       vala_field_set_instance ($$, FALSE);
-               }
-               if (($4 & VALA_MODIFIER_VOLATILE) == VALA_MODIFIER_VOLATILE) {
-                       vala_field_set_is_volatile ($$, TRUE);
-               }
-               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_code_context_create_variable_declarator (context, $1, NULL, src);
-               g_object_unref (src);
-               g_free ($1);
-         }
-       | identifier ASSIGN variable_initializer
-         {
-               ValaSourceReference *src = src(@1);
-               $$ = vala_code_context_create_variable_declarator (context, $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_code_context_create_initializer_list (context, 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
-         {
-               ValaCodeNode *n = VALA_CODE_NODE ($1);
-               if (n != NULL) {
-                       ValaAttribute *a = vala_code_node_get_attribute (n, "Import");
-                       gboolean imported;
-                       if (a != NULL) {
-                               imported = TRUE;
-                               g_object_unref (a);
-                       } else {
-                               imported = FALSE;
-                       }
-                       $$ = $1;
-                       vala_method_set_body ($$, $2);
-               
-                       if ($2 != NULL) {
-                               g_object_unref ($2);
-                               /* method must not be imported, abstract or from a VAPI file */
-                               if (imported || vala_method_get_is_abstract ($1) || vala_source_file_get_pkg (current_source_file)) {
-                                       ValaSourceReference *sr = vala_code_node_get_source_reference (n);
-                                       vala_report_error (sr, "unexpected method body found");
-                                       g_object_unref (sr);
-                               }
-                       } else {
-                               /* only imported, abstract and VAPI methods are allowed to have no body */
-                               if (!imported && !vala_method_get_is_abstract ($1) && !vala_source_file_get_pkg (current_source_file)) {
-                                       ValaSourceReference *sr = vala_code_node_get_source_reference (n);
-                                       vala_report_error (sr, "expected method body got `;'");
-                                       g_object_unref (sr);
-                               }
-                       }
-               }
-         }
-       | 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 opt_requires_declarations opt_ensures_declarations
-         {
-               GList *l;
-               ValaSourceReference *src;
-               ValaModifier vmodifiers;
-
-               src = src_com(@6, $1);
-
-               if (VALA_IS_UNRESOLVED_TYPE ($5)) {
-                       if (vala_data_type_get_is_ref ($5) || vala_data_type_get_is_out ($5)) {
-                               vala_report_error (src, "`ref' and `out' may only be used for parameters.");
-                       }
-                       if (!vala_unresolved_type_get_is_weak (VALA_UNRESOLVED_TYPE ($5))) {
-                               vala_data_type_set_transfers_ownership ($5, TRUE);
-                       }
-               }
-
-               $$ = vala_code_context_create_method (context, $6, $5, src);
-               g_object_unref (src);
-               if ($3 != -1) {
-                       vala_symbol_set_access (VALA_SYMBOL ($$), $3);
-               }
-               if (($4 & VALA_MODIFIER_STATIC) == VALA_MODIFIER_STATIC) {
-                       vala_method_set_instance ($$, FALSE);
-               }
-               vmodifiers = $4 & (VALA_MODIFIER_ABSTRACT | VALA_MODIFIER_VIRTUAL | VALA_MODIFIER_OVERRIDE);
-               if (vmodifiers == 0) {
-               } else if (vmodifiers == VALA_MODIFIER_ABSTRACT) {
-                       vala_method_set_is_abstract ($$, TRUE);
-               } else if (vmodifiers == VALA_MODIFIER_VIRTUAL) {
-                       vala_method_set_is_virtual ($$, TRUE);
-               } else if (vmodifiers == VALA_MODIFIER_OVERRIDE) {
-                       vala_method_set_overrides ($$, TRUE);
-               } else {
-                       vala_report_error (vala_code_node_get_source_reference (VALA_CODE_NODE ($$)), "Only one of `abstract', `virtual', and `override' may be specified.");
-                       vala_code_node_set_error (VALA_CODE_NODE ($$), TRUE);
-               }
-               if (($4 & VALA_MODIFIER_INLINE) == VALA_MODIFIER_INLINE) {
-                       vala_method_set_is_inline ($$, 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);
-               }
-
-               for (l = $10; l != NULL; l = l->next) {
-                       vala_method_add_error_domain ($$, l->data);
-                       g_object_unref (l->data);
-               }
-               if ($10 != NULL) {
-                       g_list_free ($10);
-               }
-
-               if ($11 != NULL) {
-                       for (l = $11; l != NULL; l = l->next) {
-                               vala_method_add_precondition ($$, l->data);
-                               g_object_unref (l->data);
-                       }
-                       g_list_free ($11);
-               }
-
-               if ($12 != NULL) {
-                       for (l = $12; l != NULL; l = l->next) {
-                               vala_method_add_postcondition ($$, l->data);
-                               g_object_unref (l->data);
-                       }
-                       g_list_free ($12);
-               }
-
-               g_object_unref ($5);
-               g_free ($6);
-
-               if (vala_code_context_ignore_node (context, VALA_CODE_NODE ($$))) {
-                       g_object_unref ($$);
-                       $$ = NULL;
-               }
-         }
-       | comment opt_attributes opt_access_modifier opt_modifiers symbol_name OPEN_PARENS opt_formal_parameter_list CLOSE_PARENS opt_throws_declaration
-         {
-               GList *l;
-               
-               ValaSourceReference *src = src_com(@5, $1);
-               if (vala_unresolved_symbol_get_inner ($5) == NULL) {
-                       $$ = VALA_METHOD (vala_code_context_create_creation_method (context, vala_unresolved_symbol_get_name ($5), NULL, src)); } else {
-                       $$ = VALA_METHOD (vala_code_context_create_creation_method (context, vala_unresolved_symbol_get_name (vala_unresolved_symbol_get_inner ($5)), vala_unresolved_symbol_get_name ($5), src));
-               }
-               g_object_unref ($5);
-               g_object_unref (src);
-               vala_method_set_instance ($$, FALSE);
-               if ($3 != -1) {
-                       vala_symbol_set_access (VALA_SYMBOL ($$), $3);
-               }
-               VALA_CODE_NODE($$)->attributes = $2;
-               
-               if ($7 != NULL) {
-                       for (l = $7; l != NULL; l = l->next) {
-                               vala_method_add_parameter ($$, l->data);
-                               g_object_unref (l->data);
-                       }
-                       g_list_free ($7);
-               }
-
-               for (l = $9; l != NULL; l = l->next) {
-                       vala_method_add_error_domain ($$, l->data);
-                       g_object_unref (l->data);
-               }
-               if ($9 != NULL) {
-                       g_list_free ($9);
-               }
-         }
-       ;
-
-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_code_context_create_formal_parameter_with_ellipsis (context, src));
-               g_object_unref (src);
-         }
-       | ELLIPSIS
-         {
-               ValaSourceReference *src = src(@1);
-               $$ = g_list_append (NULL, vala_code_context_create_formal_parameter_with_ellipsis (context, 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
-         {
-               ValaSourceReference *src;
-
-               src = src(@3);
-               if (VALA_IS_UNRESOLVED_TYPE ($3)) {
-                       if (!vala_unresolved_type_get_is_weak (VALA_UNRESOLVED_TYPE ($3))) {
-                               vala_data_type_set_takes_ownership ($3, TRUE);
-                       }
-
-                       if (!vala_data_type_get_is_ref ($3)
-                               && !vala_data_type_get_is_out ($3)
-                               && !vala_data_type_get_transfers_ownership ($3)) {
-                               /* take_ownership for in parameters that don't transfer ownership is not supported */
-                               vala_data_type_set_takes_ownership ($3, FALSE);
-                       }
-               }
-
-               $$ = vala_code_context_create_formal_parameter (context, $4, $3, src);
-               g_object_unref (src);
-               vala_formal_parameter_set_construct_parameter ($$, $2);
-               g_object_unref ($3);
-               g_free ($4);
-
-               VALA_CODE_NODE($$)->attributes = $1;
-         }
-       | opt_attributes opt_construct type identifier ASSIGN expression
-         {
-               ValaSourceReference *src;
-
-               src = src(@3);
-               if (VALA_IS_UNRESOLVED_TYPE ($3)) {
-                       if (!vala_unresolved_type_get_is_weak (VALA_UNRESOLVED_TYPE ($3))) {
-                               vala_data_type_set_takes_ownership ($3, TRUE);
-                       }
-
-                       if (!vala_data_type_get_is_ref ($3)
-                               && !vala_data_type_get_is_out ($3)
-                               && !vala_data_type_get_transfers_ownership ($3)) {
-                               /* take_ownership for in parameters that don't transfer ownership is not supported */
-                               vala_data_type_set_takes_ownership ($3, FALSE);
-                       }
-               }
-
-               $$ = vala_code_context_create_formal_parameter (context, $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);
-
-               VALA_CODE_NODE($$)->attributes = $1;
-         }
-       ;
-
-opt_throws_declaration
-       : /* empty */
-         {
-               $$ = NULL;
-         }
-       | throws_declaration
-       ;
-
-throws_declaration
-       : THROWS type_list
-         {
-               $$ = $2;
-         }
-       ;
-
-opt_requires_declarations
-       : /* empty */
-         {
-               $$ = NULL;
-         }
-       | requires_declarations
-       ;
-
-requires_declarations
-       : requires_declaration
-         {
-               $$ = g_list_append (NULL, $1);
-         }
-       | requires_declarations requires_declaration
-         {
-               $$ = g_list_append ($1, $2);
-         }
-       ;
-
-requires_declaration
-       : REQUIRES open_parens expression CLOSE_PARENS
-         {
-               $$ = $3;
-         }
-       ;
-
-opt_ensures_declarations
-       : /* empty */
-         {
-               $$ = NULL;
-         }
-       | ensures_declarations
-       ;
-
-ensures_declarations
-       : ensures_declaration
-         {
-               $$ = g_list_append (NULL, $1);
-         }
-       | ensures_declarations ensures_declaration
-         {
-               $$ = g_list_append ($1, $2);
-         }
-       ;
-
-ensures_declaration
-       : ENSURES open_parens expression CLOSE_PARENS
-         {
-               $$ = $3;
-         }
-       ;
-
-property_declaration
-       : comment opt_attributes opt_access_modifier opt_modifiers type identifier OPEN_BRACE get_accessor_declaration opt_set_accessor_declaration opt_default_value CLOSE_BRACE
-         {
-               ValaSourceReference *src;
-
-               if (!vala_unresolved_type_get_is_weak (VALA_UNRESOLVED_TYPE ($5))) {
-                       vala_data_type_set_takes_ownership ($5, TRUE);
-               }
-
-               src = src_com(@5, $1);
-               $$ = vala_code_context_create_property (context, $6, $5, $8, $9, src);
-               g_object_unref (src);
-
-               VALA_CODE_NODE($$)->attributes = $2;
-
-               if ($3 != -1) {
-                       vala_symbol_set_access (VALA_SYMBOL ($$), $3);
-               }
-
-               g_object_unref ($5);
-               g_free ($6);
-               g_object_unref ($8);
-               if ($9 != NULL) {
-                       g_object_unref ($9);
-               }
-
-               if ($10 != NULL) {
-                       vala_property_set_default_expression ($$, $10);
-                       g_object_unref ($10);
-               }
-
-               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);
-               }
-               if (($4 & VALA_MODIFIER_STATIC) == VALA_MODIFIER_STATIC) {
-                       vala_property_set_instance ($$, FALSE);
-               }
-         }
-       | comment opt_attributes opt_access_modifier opt_modifiers type identifier OPEN_BRACE set_accessor_declaration opt_get_accessor_declaration opt_default_value CLOSE_BRACE
-         {
-               ValaSourceReference *src;
-
-               if (!vala_unresolved_type_get_is_weak (VALA_UNRESOLVED_TYPE ($5))) {
-                       vala_data_type_set_takes_ownership ($5, TRUE);
-               }
-
-               src = src_com(@5, $1);
-               $$ = vala_code_context_create_property (context, $6, $5, $9, $8, src);
-               g_object_unref (src);
-
-               VALA_CODE_NODE($$)->attributes = $2;
-
-               if ($3 != -1) {
-                       vala_symbol_set_access (VALA_SYMBOL ($$), $3);
-               }
-
-               g_object_unref ($5);
-               g_free ($6);
-               g_object_unref ($8);
-               if ($9 != NULL) {
-                       g_object_unref ($9);
-               }
-
-               if ($10 != NULL) {
-                       vala_property_set_default_expression ($$, $10);
-                       g_object_unref ($10);
-               }
-
-               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);
-               }
-               if (($4 & VALA_MODIFIER_STATIC) == VALA_MODIFIER_STATIC) {
-                       vala_property_set_instance ($$, FALSE);
-               }
-         }
-       ;
-
-opt_get_accessor_declaration
-       : /* empty */
-         {
-               $$ = NULL;
-         }
-       | get_accessor_declaration
-       ;
-
-get_accessor_declaration
-       : opt_attributes opt_access_modifier GET method_body
-         {
-               ValaSourceReference *src = src(@3);
-               $$ = vala_code_context_create_property_accessor (context, TRUE, FALSE, FALSE, $4, src);
-               g_object_unref (src);
-               if ($4 != NULL) {
-                       g_object_unref ($4);
-               }
-
-               if ($2 != -1) {
-                       vala_property_accessor_set_access ($$, $2);
-               } else {
-                       vala_property_accessor_set_access ($$, VALA_SYMBOL_ACCESSIBILITY_PUBLIC);
-               }
-         }
-       ;
-
-opt_set_accessor_declaration
-       : /* empty */
-         {
-               $$ = NULL;
-         }
-       | set_accessor_declaration
-       ;
-
-set_accessor_declaration
-       : opt_attributes opt_access_modifier SET method_body
-         {
-               ValaSourceReference *src = src(@3);
-               $$ = vala_code_context_create_property_accessor (context, FALSE, TRUE, FALSE, $4, src);
-               g_object_unref (src);
-               if ($4 != NULL) {
-                       g_object_unref ($4);
-               }
-
-               if ($2 != -1) {
-                       vala_property_accessor_set_access ($$, $2);
-               } else {
-                       vala_property_accessor_set_access ($$, VALA_SYMBOL_ACCESSIBILITY_PUBLIC);
-               }
-         }
-       | opt_attributes opt_access_modifier SET CONSTRUCT method_body
-         {
-               ValaSourceReference *src = src(@3);
-               $$ = vala_code_context_create_property_accessor (context, FALSE, TRUE, TRUE, $5, src);
-               g_object_unref (src);
-               if ($5 != NULL) {
-                       g_object_unref ($5);
-               }
-
-               if ($2 != -1) {
-                       vala_property_accessor_set_access ($$, $2);
-               } else {
-                       vala_property_accessor_set_access ($$, VALA_SYMBOL_ACCESSIBILITY_PUBLIC);
-               }
-         }
-       | opt_attributes opt_access_modifier CONSTRUCT method_body
-         {
-               ValaSourceReference *src = src(@3);
-               $$ = vala_code_context_create_property_accessor (context, FALSE, FALSE, TRUE, $4, src);
-               g_object_unref (src);
-               if ($4 != NULL) {
-                       g_object_unref ($4);
-               }
-
-               if ($2 != -1) {
-                       vala_property_accessor_set_access ($$, $2);
-               } else {
-                       vala_property_accessor_set_access ($$, VALA_SYMBOL_ACCESSIBILITY_PUBLIC);
-               }
-         }
-       | opt_attributes opt_access_modifier CONSTRUCT SET method_body
-         {
-               ValaSourceReference *src = src(@3);
-               $$ = vala_code_context_create_property_accessor (context, FALSE, TRUE, TRUE, $5, src);
-               g_object_unref (src);
-               if ($5 != NULL) {
-                       g_object_unref ($5);
-               }
-
-               if ($2 != -1) {
-                       vala_property_accessor_set_access ($$, $2);
-               } else {
-                       vala_property_accessor_set_access ($$, VALA_SYMBOL_ACCESSIBILITY_PUBLIC);
-               }
-         }
-       ;
-
-opt_default_value
-       : /* empty */
-         {
-               $$ = NULL;
-         }
-       | default_value
-       ;
-
-default_value
-       : DEFAULT OPEN_PARENS expression CLOSE_PARENS SEMICOLON
-         {
-               $$ = $3;
-         }
-       | DEFAULT ASSIGN expression SEMICOLON
-         {
-               $$ = $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_code_context_create_signal (context, $6, $5, src);
-               g_object_unref (src);
-               if ($3 != -1) {
-                       vala_symbol_set_access (VALA_SYMBOL ($$), $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 opt_access_modifier opt_modifiers CONSTRUCT block
-         {
-               ValaSourceReference *src = src_com(@5, $1);
-               $$ = vala_code_context_create_constructor (context, src);
-               g_object_unref (src);
-               vala_constructor_set_body ($$, $6);
-               g_object_unref ($6);
-
-               if (($4 & VALA_MODIFIER_STATIC) == VALA_MODIFIER_STATIC) {
-                       vala_constructor_set_instance ($$, FALSE);
-               }
-         }
-       ;
-
-destructor_declaration
-       : comment opt_attributes opt_access_modifier opt_modifiers TILDE identifier OPEN_PARENS CLOSE_PARENS block
-         {
-               ValaSourceReference *src = src_com(@6, $1);
-               $$ = vala_code_context_create_destructor (context, src);
-               g_object_unref (src);
-               vala_destructor_set_body ($$, $9);
-               
-               g_free ($6);
-               g_object_unref ($9);
-         }
-       ;
-
-struct_declaration
-       : comment opt_attributes opt_access_modifier STRUCT identifier opt_name_specifier opt_type_parameter_list opt_class_base
-         {
-               GList *l;
-               ValaSourceReference *src;
-
-               char *name = $5;
-         
-               ValaSymbol *parent_symbol = VALA_SYMBOL (g_object_ref (symbol_stack->data));
-               ValaScope *parent_scope = VALA_SCOPE (scope_stack->data);
-               ValaSymbol *current_symbol;
-
-               if ($6 != NULL) {
-                       ValaSourceReference *ns_src = src(@5);
-                       g_object_unref (parent_symbol);
-                       parent_symbol = vala_scope_lookup (parent_scope, $5);
-                       if (parent_symbol != NULL) {
-                               if (check_is_namespace (parent_symbol, ns_src)) {
-                                       if (!vala_source_file_get_pkg (current_source_file)) {
-                                               vala_namespace_set_pkg (VALA_NAMESPACE (parent_symbol), FALSE);
-                                       }
-                               }
-                       } else {
-                               parent_symbol = VALA_SYMBOL (vala_code_context_create_namespace (context, $5, ns_src));
-                               vala_namespace_set_pkg (VALA_NAMESPACE (parent_symbol), vala_source_file_get_pkg (current_source_file));
-                               vala_namespace_add_namespace (VALA_NAMESPACE (symbol_stack->data), VALA_NAMESPACE (parent_symbol));
-                       }
-                       parent_scope = vala_symbol_get_scope (parent_symbol);
-                       g_free ($5);
-                       g_object_unref (ns_src);
-                       
-                       name = $6;
-               }
-               
-               src = src_com(@5, $1);
-               current_symbol = vala_scope_lookup (parent_scope, name);
-               if (current_symbol != NULL) {
-                       if (check_is_struct (current_symbol, src)) {
-                               // merge class declarations
-                       }
-               } else {
-                       current_symbol = VALA_SYMBOL (vala_code_context_create_struct (context, name, src));
-                       g_free (name);
-                       g_object_unref (src);
-
-                       if (VALA_IS_CLASS (parent_symbol)) {
-                               vala_class_add_struct (VALA_CLASS (parent_symbol), VALA_STRUCT (current_symbol));
-                       } else if (VALA_IS_INTERFACE (parent_symbol)) {
-                               vala_interface_add_struct (VALA_INTERFACE (parent_symbol), VALA_STRUCT (current_symbol));
-                       } else if (VALA_IS_NAMESPACE (parent_symbol)) {
-                               vala_namespace_add_struct (VALA_NAMESPACE (parent_symbol), VALA_STRUCT (current_symbol));
-                               vala_source_file_add_node (current_source_file, VALA_CODE_NODE (current_symbol));
-                       } else {
-                               g_assert_not_reached ();
-                       }
-
-                       for (l = $7; l != NULL; l = l->next) {
-                               vala_struct_add_type_parameter (VALA_STRUCT (current_symbol), l->data);
-                       }
-                       VALA_CODE_NODE(current_symbol)->attributes = $2;
-                       if ($3 != -1) {
-                               vala_symbol_set_access (VALA_SYMBOL (current_symbol), $3);
-                       }
-                       if ($8 != NULL) {
-                               for (l = $8; l != NULL; l = l->next) {
-                                       vala_struct_add_base_type (VALA_STRUCT (current_symbol), l->data);
-                                       g_object_unref (l->data);
-                               }
-                               g_list_free ($8);
-                       }
-               }
-
-               g_object_unref (parent_symbol);
-               push_symbol (current_symbol);
-         }
-         struct_body
-         {
-               g_object_unref (pop_symbol ());
-         }
-       ;
-
-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
-       : constant_declaration
-         {
-               /* skip declarations with errors */
-               if ($1 != NULL) {
-                       vala_struct_add_constant (VALA_STRUCT (symbol_stack->data), $1);
-                       g_object_unref ($1);
-               }
-         }
-       | field_declaration
-         {
-               /* skip declarations with errors */
-               if ($1 != NULL) {
-                       /* struct fields must not have initializers */
-                       ValaExpression *init = vala_field_get_initializer ($1);
-                       if (init != NULL) {
-                               ValaSourceReference *src = src(@1);
-                               vala_report_error (src, "Unexpected field initializer found");
-                               g_object_unref (src);
-                       }
-                       vala_struct_add_field (VALA_STRUCT (symbol_stack->data), $1);
-                       g_object_unref ($1);
-               }
-         }
-       | method_declaration
-         {
-               /* skip declarations with errors */
-               if ($1 != NULL) {
-                       vala_struct_add_method (VALA_STRUCT (symbol_stack->data), $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
-         {
-               ValaSourceReference *src;
-               char *name = $6;
-         
-               ValaSymbol *parent_symbol = VALA_SYMBOL (g_object_ref (symbol_stack->data));
-               ValaScope *parent_scope = VALA_SCOPE (scope_stack->data);
-               ValaInterface *iface;
-
-               if ($7 != NULL) {
-                       ValaSourceReference *ns_src = src(@6);
-                       g_object_unref (parent_symbol);
-                       parent_symbol = vala_scope_lookup (parent_scope, $6);
-                       if (parent_symbol != NULL) {
-                               if (check_is_namespace (parent_symbol, ns_src)) {
-                                       if (!vala_source_file_get_pkg (current_source_file)) {
-                                               vala_namespace_set_pkg (VALA_NAMESPACE (parent_symbol), FALSE);
-                                       }
-                               }
-                       } else {
-                               parent_symbol = VALA_SYMBOL (vala_code_context_create_namespace (context, $6, ns_src));
-                               vala_namespace_set_pkg (VALA_NAMESPACE (parent_symbol), vala_source_file_get_pkg (current_source_file));
-                               vala_namespace_add_namespace (VALA_NAMESPACE (symbol_stack->data), VALA_NAMESPACE (parent_symbol));
-                       }
-                       parent_scope = vala_symbol_get_scope (parent_symbol);
-                       g_free ($6);
-                       g_object_unref (ns_src);
-                       
-                       name = $7;
-               }
-               
-               src = src_com(@6, $1);
-               iface = vala_code_context_create_interface (context, name, src);
-               g_free (name);
-               g_object_unref (src);
-
-               vala_namespace_add_interface (VALA_NAMESPACE (parent_symbol), iface);
-               vala_source_file_add_node (current_source_file, VALA_CODE_NODE (iface));
-               g_object_unref (parent_symbol);
-
-               VALA_CODE_NODE (iface)->attributes = $2;
-               if ($3 != -1) {
-                       vala_symbol_set_access (VALA_SYMBOL (iface), $3);
-               }
-               if (($4 & VALA_MODIFIER_STATIC) == VALA_MODIFIER_STATIC) {
-                       vala_interface_set_is_static (iface, TRUE);
-               }
-               if ($8 != NULL) {
-                       GList *l;
-                       for (l = $8; l != NULL; l = l->next) {
-                               vala_interface_add_type_parameter (iface, 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 (iface, l->data);
-                               g_object_unref (l->data);
-                       }
-                       g_list_free ($9);
-               }
-               
-               push_symbol (VALA_SYMBOL (iface));
-         }
-         interface_body
-         {
-               g_object_unref (pop_symbol ());
-         }
-       ;
-
-interface_body
-       : OPEN_BRACE opt_interface_member_declarations CLOSE_BRACE
-       | SEMICOLON
-         {
-               vala_symbol_set_is_imported (symbol_stack->data, TRUE);
-               vala_interface_set_declaration_only (VALA_INTERFACE (symbol_stack->data), TRUE);
-         }
-       ;
-
-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 (VALA_INTERFACE (symbol_stack->data), $1);
-                       g_object_unref ($1);
-               }
-         }
-       | field_declaration
-         {
-               /* skip declarations with errors */
-               if ($1 != NULL) {
-                       vala_interface_add_field (VALA_INTERFACE (symbol_stack->data), $1);
-                       g_object_unref ($1);
-               }
-         }
-       | property_declaration
-         {
-               /* skip declarations with errors */
-               if ($1 != NULL) {
-                       vala_interface_add_property (VALA_INTERFACE (symbol_stack->data), $1);
-                       g_object_unref ($1);
-               }
-         }
-       | signal_declaration
-         {
-               /* skip declarations with errors */
-               if ($1 != NULL) {
-                       vala_interface_add_signal (VALA_INTERFACE (symbol_stack->data), $1);
-                       g_object_unref ($1);
-               }
-         }
-       | class_declaration
-       | struct_declaration
-       | enum_declaration
-       | delegate_declaration
-       ;
-
-enum_declaration
-       : comment opt_attributes opt_access_modifier ENUM identifier opt_name_specifier
-         {
-               ValaSourceReference *src;
-
-               char *name = $5;
-         
-               ValaSymbol *parent_symbol = VALA_SYMBOL (g_object_ref (symbol_stack->data));
-               ValaScope *parent_scope = VALA_SCOPE (scope_stack->data);
-               ValaEnum *en;
-
-               if ($6 != NULL) {
-                       ValaSourceReference *ns_src = src(@5);
-                       g_object_unref (parent_symbol);
-                       parent_symbol = vala_scope_lookup (parent_scope, $5);
-                       if (parent_symbol != NULL) {
-                               if (check_is_namespace (parent_symbol, ns_src)) {
-                                       if (!vala_source_file_get_pkg (current_source_file)) {
-                                               vala_namespace_set_pkg (VALA_NAMESPACE (parent_symbol), FALSE);
-                                       }
-                               }
-                       } else {
-                               parent_symbol = VALA_SYMBOL (vala_code_context_create_namespace (context, $5, ns_src));
-                               vala_namespace_set_pkg (VALA_NAMESPACE (parent_symbol), vala_source_file_get_pkg (current_source_file));
-                               vala_namespace_add_namespace (VALA_NAMESPACE (symbol_stack->data), VALA_NAMESPACE (parent_symbol));
-                       }
-                       parent_scope = vala_symbol_get_scope (parent_symbol);
-                       g_free ($5);
-                       g_object_unref (ns_src);
-                       
-                       name = $6;
-               }
-               
-               src = src_com(@5, $1);
-               en = vala_code_context_create_enum (context, name, src);
-               g_free (name);
-               g_object_unref (src);
-
-               if (VALA_IS_CLASS (parent_symbol)) {
-                       vala_class_add_enum (VALA_CLASS (parent_symbol), en);
-               } else if (VALA_IS_INTERFACE (parent_symbol)) {
-                       vala_interface_add_enum (VALA_INTERFACE (parent_symbol), en);
-               } else if (VALA_IS_NAMESPACE (parent_symbol)) {
-                       vala_namespace_add_enum (VALA_NAMESPACE (parent_symbol), en);
-                       vala_source_file_add_node (current_source_file, VALA_CODE_NODE (en));
-               } else {
-                       g_assert_not_reached ();
-               }
-               g_object_unref (parent_symbol);
-
-               VALA_CODE_NODE (en)->attributes = $2;
-
-               if ($3 != -1) {
-                       vala_symbol_set_access (VALA_SYMBOL (en), $3);
-               }
-               
-               push_symbol (VALA_SYMBOL (en));
-         }
-         enum_body
-         {
-               g_object_unref (pop_symbol ());
-         }
-       ;
-
-enum_body
-       : OPEN_BRACE opt_enum_member_declarations opt_enum_method_declarations CLOSE_BRACE
-       ;
-
-opt_enum_member_declarations
-       : /* empty */
-       | enum_member_declarations opt_comma
-       ;
-
-enum_member_declarations
-       : enum_member_declaration
-       | enum_member_declarations COMMA enum_member_declaration
-       ;
-
-enum_member_declaration
-       : comment opt_attributes identifier
-         {
-               ValaSourceReference *src;
-               ValaEnumValue *ev;
-
-               src = src_com(@3, $1);
-               ev = vala_code_context_create_enum_value (context, $3, src);
-               g_free ($3);
-               vala_enum_add_value (VALA_ENUM (symbol_stack->data), ev);
-               g_object_unref (ev);
-         }
-       | comment opt_attributes identifier ASSIGN expression
-         {
-               ValaSourceReference *src;
-               ValaEnumValue *ev;
-
-               src = src_com(@3, $1);
-               ev = vala_code_context_create_enum_value_with_value (context, $3, $5, src);
-               g_free ($3);
-               g_object_unref ($5);
-               vala_enum_add_value (VALA_ENUM (symbol_stack->data), ev);
-               g_object_unref (ev);
-         }
-       ;
-
-opt_enum_method_declarations
-       : /* empty */
-       | enum_method_declarations
-       ;
-
-enum_method_declarations
-       : SEMICOLON enum_method_declaration
-       | enum_method_declarations enum_method_declaration
-       ;
-
-enum_method_declaration
-       : method_declaration
-         {
-               /* skip declarations with errors */
-               if ($1 != NULL) {
-                       vala_enum_add_method (VALA_ENUM (symbol_stack->data), $1);
-                       g_object_unref ($1);
-               }
-         }
-       ;
-
-errordomain_declaration
-       : comment opt_attributes opt_access_modifier ERRORDOMAIN identifier opt_name_specifier
-         {
-               ValaSourceReference *src;
-
-               char *name = $5;
-         
-               ValaSymbol *parent_symbol = VALA_SYMBOL (g_object_ref (symbol_stack->data));
-               ValaScope *parent_scope = VALA_SCOPE (scope_stack->data);
-               ValaErrorDomain *edomain;
-
-               if ($6 != NULL) {
-                       ValaSourceReference *ns_src = src(@5);
-                       g_object_unref (parent_symbol);
-                       parent_symbol = vala_scope_lookup (parent_scope, $5);
-                       if (parent_symbol != NULL) {
-                               if (check_is_namespace (parent_symbol, ns_src)) {
-                                       if (!vala_source_file_get_pkg (current_source_file)) {
-                                               vala_namespace_set_pkg (VALA_NAMESPACE (parent_symbol), FALSE);
-                                       }
-                               }
-                       } else {
-                               parent_symbol = VALA_SYMBOL (vala_code_context_create_namespace (context, $5, ns_src));
-                               vala_namespace_set_pkg (VALA_NAMESPACE (parent_symbol), vala_source_file_get_pkg (current_source_file));
-                               vala_namespace_add_namespace (VALA_NAMESPACE (symbol_stack->data), VALA_NAMESPACE (parent_symbol));
-                       }
-                       parent_scope = vala_symbol_get_scope (parent_symbol);
-                       g_free ($5);
-                       g_object_unref (ns_src);
-                       
-                       name = $6;
-               }
-               
-               src = src_com(@5, $1);
-               edomain = vala_code_context_create_error_domain (context, name, src);
-               g_free (name);
-               g_object_unref (src);
-
-               vala_namespace_add_error_domain (VALA_NAMESPACE (parent_symbol), edomain);
-               vala_source_file_add_node (current_source_file, VALA_CODE_NODE (edomain));
-               g_object_unref (parent_symbol);
-
-               VALA_CODE_NODE (edomain)->attributes = $2;
-
-               if ($3 != -1) {
-                       vala_symbol_set_access (VALA_SYMBOL (edomain), $3);
-               }
-               
-               push_symbol (VALA_SYMBOL (edomain));
-         }
-         errordomain_body
-         {
-               g_object_unref (pop_symbol ());
-         }
-       ;
-
-errordomain_body
-       : OPEN_BRACE opt_errordomain_member_declarations opt_errordomain_method_declarations CLOSE_BRACE
-       ;
-
-opt_errordomain_member_declarations
-       : /* empty */
-       | errordomain_member_declarations opt_comma
-       ;
-
-errordomain_member_declarations
-       : errordomain_member_declaration
-       | errordomain_member_declarations COMMA errordomain_member_declaration
-       ;
-
-errordomain_member_declaration
-       : opt_attributes identifier
-         {
-               ValaErrorCode *ec = vala_code_context_create_error_code (context, $2);
-               g_free ($2);
-               vala_error_domain_add_code (VALA_ERROR_DOMAIN (symbol_stack->data), ec);
-               g_object_unref (ec);
-         }
-       | opt_attributes identifier ASSIGN expression
-         {
-               ValaErrorCode *ec = vala_code_context_create_error_code_with_value (context, $2, $4);
-               g_free ($2);
-               g_object_unref ($4);
-               vala_error_domain_add_code (VALA_ERROR_DOMAIN (symbol_stack->data), ec);
-               g_object_unref (ec);
-         }
-       ;
-
-opt_errordomain_method_declarations
-       : /* empty */
-       | errordomain_method_declarations
-       ;
-
-errordomain_method_declarations
-       : SEMICOLON errordomain_method_declaration
-       | errordomain_method_declarations errordomain_method_declaration
-       ;
-
-errordomain_method_declaration
-       : method_declaration
-         {
-               /* skip declarations with errors */
-               if ($1 != NULL) {
-                       vala_error_domain_add_method (VALA_ERROR_DOMAIN (symbol_stack->data), $1);
-                       g_object_unref ($1);
-               }
-         }
-       ;
-
-delegate_declaration
-       : comment opt_attributes opt_access_modifier opt_modifiers DELEGATE type identifier opt_name_specifier opt_type_parameter_list OPEN_PARENS opt_formal_parameter_list CLOSE_PARENS opt_throws_declaration SEMICOLON
-         {
-               ValaSourceReference *src;
-               GList *l;
-               char *name = $7;
-         
-               ValaSymbol *parent_symbol = VALA_SYMBOL (g_object_ref (symbol_stack->data));
-               ValaScope *parent_scope = VALA_SCOPE (scope_stack->data);
-               ValaDelegate *cb;
-
-               if ($8 != NULL) {
-                       ValaSourceReference *ns_src = src(@7);
-                       g_object_unref (parent_symbol);
-                       parent_symbol = vala_scope_lookup (parent_scope, $7);
-                       if (parent_symbol != NULL) {
-                               if (check_is_namespace (parent_symbol, ns_src)) {
-                                       if (!vala_source_file_get_pkg (current_source_file)) {
-                                               vala_namespace_set_pkg (VALA_NAMESPACE (parent_symbol), FALSE);
-                                       }
-                               }
-                       } else {
-                               parent_symbol = VALA_SYMBOL (vala_code_context_create_namespace (context, $7, ns_src));
-                               vala_namespace_set_pkg (VALA_NAMESPACE (parent_symbol), vala_source_file_get_pkg (current_source_file));
-                               vala_namespace_add_namespace (VALA_NAMESPACE (symbol_stack->data), VALA_NAMESPACE (parent_symbol));
-                       }
-                       parent_scope = vala_symbol_get_scope (parent_symbol);
-                       g_free ($7);
-                       g_object_unref (ns_src);
-                       
-                       name = $8;
-               }
-               
-               src = src_com(@7, $1);
-               cb = vala_code_context_create_delegate (context, name, $6, src);
-               g_free (name);
-               g_object_unref ($6);
-               g_object_unref (src);
-
-               if (VALA_IS_CLASS (parent_symbol)) {
-                       vala_class_add_delegate (VALA_CLASS (parent_symbol), cb);
-               } else if (VALA_IS_INTERFACE (parent_symbol)) {
-                       vala_interface_add_delegate (VALA_INTERFACE (parent_symbol), cb);
-               } else if (VALA_IS_NAMESPACE (parent_symbol)) {
-                       vala_namespace_add_delegate (VALA_NAMESPACE (parent_symbol), cb);
-                       vala_source_file_add_node (current_source_file, VALA_CODE_NODE (cb));
-               } else {
-                       g_assert_not_reached ();
-               }
-               g_object_unref (parent_symbol);
-
-               if ($3 != -1) {
-                       vala_symbol_set_access (VALA_SYMBOL (cb), $3);
-               }
-               VALA_CODE_NODE (cb)->attributes = $2;
-               if (($4 & VALA_MODIFIER_STATIC) == 0) {
-                       vala_delegate_set_instance (cb, TRUE);
-               }
-
-               if ($9 != NULL) {
-                       for (l = $9; l != NULL; l = l->next) {
-                               vala_delegate_add_type_parameter (cb, l->data);
-                               g_object_unref (l->data);
-                       }
-                       g_list_free ($9);
-               }
-               if ($11 != NULL) {
-                       for (l = $11; l != NULL; l = l->next) {
-                               vala_delegate_add_parameter (cb, l->data);
-                               g_object_unref (l->data);
-                       }
-                       g_list_free ($11);
-               }
-
-               g_object_unref (cb);
-         }
-       ;
-
-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_code_context_create_type_parameter (context, $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_IS_UNRESOLVED_TYPE ($$)) {
-                       if (!vala_unresolved_type_get_is_weak (VALA_UNRESOLVED_TYPE ($$))) {
-                               vala_data_type_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_code_context_create_member_access (context, 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_code_context_create_member_access (context, $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;
-       context = vala_source_file_get_context (current_source_file);
-       push_symbol (VALA_SYMBOL (vala_code_context_get_root (context)));
-       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;
-}
-
-static void push_symbol (ValaSymbol *symbol) {
-       symbol_stack = g_list_prepend (symbol_stack, symbol);
-       scope_stack = g_list_prepend (scope_stack, vala_symbol_get_scope (symbol));
-}
-
-static ValaSymbol *pop_symbol (void) {
-       ValaSymbol *sym = VALA_SYMBOL (symbol_stack->data);
-       symbol_stack = g_list_delete_link (symbol_stack, symbol_stack);
-       scope_stack = g_list_delete_link (scope_stack, scope_stack);
-       return sym;
-}
-
-static gboolean check_is_namespace (ValaSymbol *symbol, ValaSourceReference *src) {
-       if (!VALA_IS_NAMESPACE (symbol)) {
-               char *sym_name = vala_symbol_get_full_name (symbol);
-               char *error_msg = g_strdup_printf ("`%s` already exists but is not a namespace", sym_name);
-               g_free (sym_name);
-               vala_report_error (src, error_msg);
-               g_free (error_msg);
-               return FALSE;
-       }
-       return TRUE;
-}
-
-static gboolean check_is_class (ValaSymbol *symbol, ValaSourceReference *src) {
-       if (!VALA_IS_CLASS (symbol)) {
-               char *sym_name = vala_symbol_get_full_name (symbol);
-               char *error_msg = g_strdup_printf ("`%s` already exists but is not a class", sym_name);
-               g_free (sym_name);
-               vala_report_error (src, error_msg);
-               g_free (error_msg);
-               return FALSE;
-       }
-       return TRUE;
-}
-
-static gboolean check_is_struct (ValaSymbol *symbol, ValaSourceReference *src) {
-       if (!VALA_IS_STRUCT (symbol)) {
-               char *sym_name = vala_symbol_get_full_name (symbol);
-               char *error_msg = g_strdup_printf ("`%s` already exists but is not a struct", sym_name);
-               g_free (sym_name);
-               vala_report_error (src, error_msg);
-               g_free (error_msg);
-               return FALSE;
-       }
-       return TRUE;
-}
diff --git a/vala/scanner.l b/vala/scanner.l
deleted file mode 100644 (file)
index 5d04ecd..0000000
+++ /dev/null
@@ -1,209 +0,0 @@
-/* scanner.l
- *
- * Copyright (C) 2006-2008  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.1 of the License, or (at your option) any later version.
-
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
-
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301  USA
- *
- * Author:
- *     Jürg Billeter <j@bitron.ch>
- *     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:]]*{exponent_part}?{real_suffix}?
-hex_digit                      [[:digit:]A-Fa-f]
-octal_digit                    [0-7]
-octal_integer_literal          0{octal_digit}+
-hexadecimal_integer_literal    0x{hex_digit}+
-exponent_part                  (e|E){sign}?[[:digit:]]+
-sign                           "+"|"-"
-integer_suffix                 L|LL|U|UL|ULL
-real_suffix                    F
-single_character               [^\'\\]
-single_string_literal_character        [^\"\\]
-simple_escape_sequence         \\[\'\"\?\\abfnrtv0]
-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})
-
-type_name                      ("weak"{space})?({ident}".")?{ident}
-generic_type                   {type_name}("<"{space}{type_name}("?"|"*"+)?(","{space}{type_name}("?"|"*"+)?)*">")?("?"|"*"+)?
-
-%%
-
-"/*"                           { 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; }
-"["{space}(","{space})*"]"     { yyless (1); uploc; return OPEN_ARRAY_TYPE_BRACKET; }
-"["            { 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; }
-"?"{space}({ident}{space}("="|";")|"[")        { yyless (1); uploc; return NULLABLE_INTERR; }
-"?"            { 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; }
-"<"{space}{generic_type}{space}(","{space}{generic_type}{space})*">"   { 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 OP_PTR; }
-
-"="            { 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; }
-"as"           { uploc; return AS; }
-"base"         { uploc; return BASE; }
-"break"                { uploc; return BREAK; }
-"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; }
-"delegate"     { uploc; return DELEGATE; }
-"delete"       { uploc; return DELETE; }
-"do"           { uploc; return DO; }
-"else"         { uploc; return ELSE; }
-"ensures"      { uploc; return ENSURES; }
-"enum"         { uploc; return ENUM; }
-"errordomain"  { uploc; return ERRORDOMAIN; }
-"false"                { uploc; return VALA_FALSE; }
-"finally"      { uploc; return FINALLY; }
-"for"          { uploc; return FOR; }
-"foreach"      { uploc; return FOREACH; }
-"get"          { uploc; return GET; }
-"if"           { uploc; return IF; }
-"in"           { uploc; return IN; }
-"inline"       { uploc; return INLINE; }
-"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; }
-"requires"     { uploc; return REQUIRES; }
-"set"          { uploc; return SET; }
-"signal"       { uploc; return SIGNAL; }
-"sizeof"       { uploc; return SIZEOF; }
-"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; }
-"void"         { uploc; return VOID; }
-"volatile"     { uploc; return VOLATILE; }
-"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\r]+       { 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); }
index 23ff065..5e62a7e 100644 (file)
@@ -94,6 +94,7 @@ public class Vala.Assignment : Expression {
 }
        
 public enum Vala.AssignmentOperator {
+       NONE,
        SIMPLE,
        BITWISE_OR,
        BITWISE_AND,
index e60acc4..4ba7b0e 100644 (file)
@@ -130,6 +130,7 @@ public class Vala.BinaryExpression : Expression {
 }
 
 public enum Vala.BinaryOperator {
+       NONE,
        PLUS,
        MINUS,
        MUL,
index f760ebe..efb0865 100644 (file)
@@ -193,10 +193,16 @@ public class Vala.Class : Typesymbol {
         */
        public void add_method (Method! m) {
                if (m.instance || m is CreationMethod) {
+                       if (m.this_parameter != null) {
+                               m.scope.remove (m.this_parameter.name);
+                       }
                        m.this_parameter = new FormalParameter ("this", new ClassType (this));
                        m.scope.add (m.this_parameter.name, m.this_parameter);
                }
                if (!(m.return_type is VoidType) && m.get_postconditions ().size > 0) {
+                       if (m.result_var != null) {
+                               m.scope.remove (m.result_var.name);
+                       }
                        m.result_var = new VariableDeclarator ("result");
                        m.result_var.type_reference = m.return_type.copy ();
                        m.scope.add (m.result_var.name, m.result_var);
index c136523..ef31866 100644 (file)
@@ -167,6 +167,60 @@ public class Vala.Namespace : Symbol {
        }
        
        /**
+        * Returns a copy of the list of enums.
+        *
+        * @return enum list
+        */
+       public Collection<Enum> get_enums () {
+               return new ReadOnlyCollection<Enum> (enums);
+       }
+       
+       /**
+        * Returns a copy of the list of error domains.
+        *
+        * @return error domain list
+        */
+       public Collection<ErrorDomain> get_error_domains () {
+               return new ReadOnlyCollection<ErrorDomain> (error_domains);
+       }
+       
+       /**
+        * Returns a copy of the list of fields.
+        *
+        * @return field list
+        */
+       public Collection<Field> get_fields () {
+               return new ReadOnlyCollection<Field> (fields);
+       }
+       
+       /**
+        * Returns a copy of the list of constants.
+        *
+        * @return constant list
+        */
+       public Collection<Constant> get_constants () {
+               return new ReadOnlyCollection<Constant> (constants);
+       }
+       
+       /**
+        * Returns a copy of the list of delegates.
+        *
+        * @return delegate list
+        */
+       public Collection<Delegate> get_delegates () {
+               return new ReadOnlyCollection<Delegate> (delegates);
+       }
+       
+       /**
+        * Returns a copy of the list of methods.
+        *
+        * @return method list
+        */
+       public Collection<Method> get_methods () {
+               return new ReadOnlyCollection<Method> (methods);
+       }
+       
+       /**
         * Adds the specified constant to this namespace.
         *
         * @param constant a constant
index cc4039a..9b65799 100644 (file)
@@ -1,6 +1,6 @@
 /* valaparser.vala
  *
- * Copyright (C) 2006-2007  Jürg Billeter
+ * Copyright (C) 2006-2008  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
  */
 
 using GLib;
+using Gee;
 
 /**
  * Code visitor parsing all Vala source files.
  */
 public class Vala.Parser : CodeVisitor {
-       private string comment;
-       private string _file_comment;
-       
+       Scanner scanner;
+
+       CodeContext context;
+
+       // token buffer
+       TokenInfo[] tokens;
+       // index of current token in buffer
+       int index;
+       // number of tokens in buffer
+       int size;
+
+       string comment;
+
+       const int BUFFER_SIZE = 32;
+
+       struct TokenInfo {
+               public TokenType type;
+               public SourceLocation begin;
+               public SourceLocation end;
+       }
+
+       enum ModifierFlags {
+               NONE,
+               ABSTRACT = 1 << 0,
+               CLASS = 1 << 1,
+               INLINE = 1 << 2,
+               OVERRIDE = 1 << 3,
+               STATIC = 1 << 4,
+               VIRTUAL = 1 << 5
+       }
+
+       construct {
+               tokens = new TokenInfo[BUFFER_SIZE];
+       }
+
        /**
         * Parse all source files in the specified code context and build a
         * code tree.
@@ -36,57 +69,2608 @@ public class Vala.Parser : CodeVisitor {
         * @param context a code context
         */
        public void parse (CodeContext! context) {
+               this.context = context;
                context.accept (this);
        }
 
        public override void visit_source_file (SourceFile! source_file) {
                if (source_file.filename.has_suffix (".vala") || source_file.filename.has_suffix (".vapi")) {
                        parse_file (source_file);
-                       source_file.comment = _file_comment;
                }
+       }
 
-               _file_comment = null;
+       inline bool next () {
+               index = (index + 1) % BUFFER_SIZE;
+               size--;
+               if (size <= 0) {
+                       SourceLocation begin, end;
+                       TokenType type = scanner.read_token (out begin, out end);
+                       tokens[index].type = type;
+                       tokens[index].begin = begin;
+                       tokens[index].end = end;
+                       size = 1;
+               }
+               return (tokens[index].type != TokenType.EOF);
        }
 
-       /**
-        * 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;
+       inline void prev () {
+               index = (index - 1 + BUFFER_SIZE) % BUFFER_SIZE;
+               size++;
+               assert (size <= BUFFER_SIZE);
+       }
+
+       inline TokenType current () {
+               return tokens[index].type;
+       }
+
+       inline bool accept (TokenType type) {
+               if (current () == type) {
+                       next ();
+                       return true;
+               }
+               return false;
+       }
+
+       string get_error (string msg) {
+               var begin = get_location ();
+               next ();
+               Report.error (get_src (begin), "syntax error, " + msg);
+               return msg;
+       }
+
+       inline bool expect (TokenType type) throws ParseError {
+               if (accept (type)) {
+                       return true;
+               }
+
+               throw new ParseError.SYNTAX (get_error ("expected %s".printf (type.to_string ())));
+       }
+
+       inline SourceLocation get_location () {
+               return tokens[index].begin;
+       }
+
+       string get_last_string () {
+               int last_index = (index + BUFFER_SIZE - 1) % BUFFER_SIZE;
+               return ((string) tokens[last_index].begin.pos).ndup ((tokens[last_index].end.pos - tokens[last_index].begin.pos));
+       }
+
+       SourceReference get_src (SourceLocation begin) {
+               int last_index = (index + BUFFER_SIZE - 1) % BUFFER_SIZE;
+
+               return new SourceReference (scanner.source_file, begin.line, begin.column, tokens[last_index].end.line, tokens[last_index].end.column);
+       }
+
+       SourceReference get_src_com (SourceLocation begin) {
+               int last_index = (index + BUFFER_SIZE - 1) % BUFFER_SIZE;
+
+               var src = new SourceReference.with_comment (scanner.source_file, begin.line, begin.column, tokens[last_index].end.line, tokens[last_index].end.column, comment);
+               comment = null;
+               return src;
+       }
+
+       void rollback (SourceLocation location) {
+               while (tokens[index].begin.pos != location.pos) {
+                       prev ();
+               }
+       }
+
+       void skip_identifier () throws ParseError {
+               // also accept keywords as identifiers where there is no conflict
+               switch (current ()) {
+               case TokenType.ABSTRACT:
+               case TokenType.AS:
+               case TokenType.BASE:
+               case TokenType.BREAK:
+               case TokenType.CASE:
+               case TokenType.CATCH:
+               case TokenType.CLASS:
+               case TokenType.CONST:
+               case TokenType.CONSTRUCT:
+               case TokenType.CONTINUE:
+               case TokenType.DEFAULT:
+               case TokenType.DELEGATE:
+               case TokenType.DELETE:
+               case TokenType.DO:
+               case TokenType.ELSE:
+               case TokenType.ENUM:
+               case TokenType.ENSURES:
+               case TokenType.ERRORDOMAIN:
+               case TokenType.FALSE:
+               case TokenType.FINALLY:
+               case TokenType.FOR:
+               case TokenType.FOREACH:
+               case TokenType.GET:
+               case TokenType.IDENTIFIER:
+               case TokenType.IF:
+               case TokenType.IN:
+               case TokenType.INLINE:
+               case TokenType.INTERFACE:
+               case TokenType.IS:
+               case TokenType.LOCK:
+               case TokenType.NAMESPACE:
+               case TokenType.NEW:
+               case TokenType.NULL:
+               case TokenType.OUT:
+               case TokenType.OVERRIDE:
+               case TokenType.PRIVATE:
+               case TokenType.PROTECTED:
+               case TokenType.PUBLIC:
+               case TokenType.REF:
+               case TokenType.REQUIRES:
+               case TokenType.RETURN:
+               case TokenType.SET:
+               case TokenType.SIGNAL:
+               case TokenType.SIZEOF:
+               case TokenType.STATIC:
+               case TokenType.STRUCT:
+               case TokenType.SWITCH:
+               case TokenType.THIS:
+               case TokenType.THROW:
+               case TokenType.THROWS:
+               case TokenType.TRUE:
+               case TokenType.TRY:
+               case TokenType.TYPEOF:
+               case TokenType.USING:
+               case TokenType.VAR:
+               case TokenType.VIRTUAL:
+               case TokenType.VOID:
+               case TokenType.VOLATILE:
+               case TokenType.WEAK:
+               case TokenType.WHILE:
+                       next ();
+                       return;
+               }
+
+               throw new ParseError.SYNTAX (get_error ("expected identifier"));
+       }
+
+       string parse_identifier () throws ParseError {
+               skip_identifier ();
+               return get_last_string ();
+       }
+
+       Expression parse_literal () throws ParseError {
+               var begin = get_location ();
+
+               switch (current ()) {
+               case TokenType.TRUE:
+                       next ();
+                       return context.create_boolean_literal (true, get_src (begin));
+               case TokenType.FALSE:
+                       next ();
+                       return context.create_boolean_literal (false, get_src (begin));
+               case TokenType.INTEGER_LITERAL:
+                       next ();
+                       return context.create_integer_literal (get_last_string (), get_src (begin));
+               case TokenType.REAL_LITERAL:
+                       next ();
+                       return context.create_real_literal (get_last_string (), get_src (begin));
+               case TokenType.CHARACTER_LITERAL:
+                       next ();
+                       return context.create_character_literal (get_last_string (), get_src (begin));
+               case TokenType.STRING_LITERAL:
+                       next ();
+                       return context.create_string_literal (get_last_string (), get_src (begin));
+               case TokenType.NULL:
+                       next ();
+                       return context.create_null_literal (get_src (begin));
+               }
+
+               throw new ParseError.SYNTAX (get_error ("expected literal"));
+       }
+
+       public void parse_file (SourceFile source_file) {
+               scanner = new Scanner (source_file);
+
+               index = -1;
+               size = 0;
+               
+               next ();
+
+               try {
+                       parse_using_directives ();
+                       parse_declarations (context.root, true);
+               } catch (ParseError e) {
+                       // already reported
+               }
+               
+               scanner = null;
+       }
+
+       void skip_symbol_name () throws ParseError {
+               do {
+                       skip_identifier ();
+               } while (accept (TokenType.DOT));
+       }
+
+       UnresolvedSymbol parse_symbol_name () throws ParseError {
+               var begin = get_location ();
+               UnresolvedSymbol sym = null;
+               do {
+                       string name = parse_identifier ();
+                       sym = new UnresolvedSymbol (sym, name, get_src (begin));
+               } while (accept (TokenType.DOT));
+               return sym;
+       }
+
+       void skip_type () throws ParseError {
+               if (accept (TokenType.VOID)) {
+                       while (accept (TokenType.STAR)) {
+                       }
+                       return;
+               }
+               accept (TokenType.REF);
+               accept (TokenType.OUT);
+               accept (TokenType.WEAK);
+               skip_symbol_name ();
+               skip_type_argument_list ();
+               while (accept (TokenType.STAR)) {
+               }
+               if (accept (TokenType.OPEN_BRACKET)) {
+                       do {
+                               if (current () != TokenType.COMMA && current () != TokenType.CLOSE_BRACKET) {
+                                       parse_expression ();
+                               }
+                       } while (accept (TokenType.COMMA));
+                       expect (TokenType.CLOSE_BRACKET);
+               }
+               accept (TokenType.OP_NEG);
+               accept (TokenType.INTERR);
+               accept (TokenType.HASH);
+       }
+
+       DataType parse_type () throws ParseError {
+               var begin = get_location ();
+
+               if (accept (TokenType.VOID)) {
+                       DataType type = new VoidType ();
+                       while (accept (TokenType.STAR)) {
+                               type = new PointerType (type);
+                       }
+                       return type;
+               }
+
+               bool is_ref = accept (TokenType.REF);
+               bool is_out = !is_ref && accept (TokenType.OUT);
+
+               bool is_weak = accept (TokenType.WEAK);
+
+               var sym = parse_symbol_name ();
+               var type_arg_list = parse_type_argument_list (false);
+
+               int stars = 0;
+               while (accept (TokenType.STAR)) {
+                       stars++;
+               }
+
+               int array_rank = 0;
+               if (accept (TokenType.OPEN_BRACKET)) {
+                       do {
+                               array_rank++;
+                               // support for stack-allocated arrays
+                               // also required for decision between expression and declaration statement
+                               if (current () != TokenType.COMMA && current () != TokenType.CLOSE_BRACKET) {
+                                       parse_expression ();
+                               }
+                       }
+                       while (accept (TokenType.COMMA));
+                       expect (TokenType.CLOSE_BRACKET);
+               }
+
+               // deprecated
+               accept (TokenType.OP_NEG);
+
+               bool nullable = accept (TokenType.INTERR);
+
+               bool transfers_ownership = accept (TokenType.HASH);
+
+               var type = new UnresolvedType.from_symbol (sym, get_src (begin));
+               if (type_arg_list != null) {
+                       foreach (DataType type_arg in type_arg_list) {
+                               type.add_type_argument (type_arg);
+                       }
+               }
+               type.is_ref = is_ref;
+               type.is_out = is_out;
+               type.is_weak = is_weak;
+               type.pointer_level = stars;
+               type.array_rank = array_rank;
+               type.nullable = nullable;
+               type.requires_null_check = nullable;
+               type.transfers_ownership = transfers_ownership;
+               return type;
+       }
+
+       Gee.List<Expression> parse_argument_list () throws ParseError {
+               var list = new ArrayList<Expression> ();
+               if (current () != TokenType.CLOSE_PARENS) {
+                       do {
+                               list.add (parse_expression ());
+                       } while (accept (TokenType.COMMA));
+               }
+               return list;
+       }
+
+       Expression parse_primary_expression () throws ParseError {
+               var begin = get_location ();
+
+               Expression expr;
+
+               switch (current ()) {
+               case TokenType.TRUE:
+               case TokenType.FALSE:
+               case TokenType.INTEGER_LITERAL:
+               case TokenType.REAL_LITERAL:
+               case TokenType.CHARACTER_LITERAL:
+               case TokenType.STRING_LITERAL:
+               case TokenType.NULL:
+                       expr = parse_literal ();
+                       break;
+               case TokenType.OPEN_PARENS:
+                       expr = parse_tuple ();
+                       break;
+               case TokenType.THIS:
+                       expr = parse_this_access ();
+                       break;
+               case TokenType.BASE:
+                       expr = parse_base_access ();
+                       break;
+               case TokenType.NEW:
+                       expr = parse_object_or_array_creation_expression ();
+                       break;
+               case TokenType.SIZEOF:
+                       expr = parse_sizeof_expression ();
+                       break;
+               case TokenType.TYPEOF:
+                       expr = parse_typeof_expression ();
+                       break;
+               default:
+                       expr = parse_simple_name ();
+                       break;
+               }
+
+               // process primary expressions that start with an inner primary expression
+               bool found = true;
+               while (found) {
+                       switch (current ()) {
+                       case TokenType.DOT:
+                               expr = parse_member_access (begin, expr);
+                               break;
+                       case TokenType.OP_PTR:
+                               expr = parse_pointer_member_access (begin, expr);
+                               break;
+                       case TokenType.OPEN_PARENS:
+                               expr = parse_invocation_expression (begin, expr);
+                               break;
+                       case TokenType.OPEN_BRACKET:
+                               expr = parse_element_access (begin, expr);
+                               break;
+                       case TokenType.OP_INC:
+                               expr = parse_post_increment_expression (begin, expr);
+                               break;
+                       case TokenType.OP_DEC:
+                               expr = parse_post_decrement_expression (begin, expr);
+                               break;
+                       default:
+                               found = false;
+                               break;
+                       }
+               }
+
+               return expr;
+       }
+
+       Expression parse_simple_name () throws ParseError {
+               var begin = get_location ();
+               string id = parse_identifier ();
+               var type_arg_list = parse_type_argument_list (true);
+               var expr = context.create_member_access (null, id, get_src (begin));
+               if (type_arg_list != null) {
+                       foreach (DataType type_arg in type_arg_list) {
+                               expr.add_type_argument (type_arg);
+                       }
+               }
+               return expr;
+       }
+
+       Expression parse_tuple () throws ParseError {
+               var begin = get_location ();
+               expect (TokenType.OPEN_PARENS);
+               var expr_list = new ArrayList<Expression> ();
+               if (current () != TokenType.CLOSE_PARENS) {
+                       do {
+                               expr_list.add (parse_expression ());
+                       } while (accept (TokenType.COMMA));
+               }
+               expect (TokenType.CLOSE_PARENS);
+               if (expr_list.size != 1) {
+                       var tuple = new Tuple ();
+                       foreach (Expression expr in expr_list) {
+                               tuple.add_expression (expr);
+                       }
+                       return tuple;
+               }
+               return context.create_parenthesized_expression (expr_list.get (0), get_src (begin));
+       }
+
+       Expression parse_member_access (SourceLocation begin, Expression inner) throws ParseError {
+               expect (TokenType.DOT);
+               string id = parse_identifier ();
+               var type_arg_list = parse_type_argument_list (true);
+               var expr = context.create_member_access (inner, id, get_src (begin));
+               if (type_arg_list != null) {
+                       foreach (DataType type_arg in type_arg_list) {
+                               expr.add_type_argument (type_arg);
+                       }
+               }
+               return expr;
+       }
+
+       Expression parse_pointer_member_access (SourceLocation begin, Expression inner) throws ParseError {
+               expect (TokenType.OP_PTR);
+               string id = parse_identifier ();
+               var type_arg_list = parse_type_argument_list (true);
+               var expr = context.create_member_access_pointer (inner, id, get_src (begin));
+               if (type_arg_list != null) {
+                       foreach (DataType type_arg in type_arg_list) {
+                               expr.add_type_argument (type_arg);
+                       }
+               }
+               return expr;
+       }
+
+       Expression parse_invocation_expression (SourceLocation begin, Expression inner) throws ParseError {
+               expect (TokenType.OPEN_PARENS);
+               var arg_list = parse_argument_list ();
+               expect (TokenType.CLOSE_PARENS);
+
+               var expr = context.create_invocation_expression (inner, get_src (begin));
+               foreach (Expression arg in arg_list) {
+                       expr.add_argument (arg);
+               }
+               return expr;
+       }
+
+       Expression parse_element_access (SourceLocation begin, Expression inner) throws ParseError {
+               expect (TokenType.OPEN_BRACKET);
+               var index_list = parse_expression_list ();
+               expect (TokenType.CLOSE_BRACKET);
+
+               var expr = context.create_element_access (inner, get_src (begin));
+               foreach (Expression index in index_list) {
+                       expr.append_index (index);
+               }
+               return expr;
+       }
+
+       Gee.List<Expression> parse_expression_list () throws ParseError {
+               var list = new ArrayList<Expression> ();
+               do {
+                       list.add (parse_expression ());
+               } while (accept (TokenType.COMMA));
+               return list;
+       }
+
+       Expression parse_this_access () throws ParseError {
+               var begin = get_location ();
+               expect (TokenType.THIS);
+               return context.create_member_access (null, "this", get_src (begin));
+       }
+
+       Expression parse_base_access () throws ParseError {
+               var begin = get_location ();
+               expect (TokenType.BASE);
+               return context.create_base_access (get_src (begin));
+       }
+
+       Expression parse_post_increment_expression (SourceLocation begin, Expression inner) throws ParseError {
+               expect (TokenType.OP_INC);
+               return context.create_postfix_expression (inner, true, get_src (begin));
+       }
+
+       Expression parse_post_decrement_expression (SourceLocation begin, Expression inner) throws ParseError {
+               expect (TokenType.OP_DEC);
+               return context.create_postfix_expression (inner, false, get_src (begin));
+       }
+
+       Expression parse_object_or_array_creation_expression () throws ParseError {
+               var begin = get_location ();
+               expect (TokenType.NEW);
+               var member = parse_member_name ();
+               if (accept (TokenType.OPEN_PARENS)) {
+                       return parse_object_creation_expression (begin, member);
+               } else if (accept (TokenType.OPEN_BRACKET)) {
+                       return parse_array_creation_expression (begin, member);
                } else {
-                       comment = "%s\n%s".printf (comment, comment_item);
+                       throw new ParseError.SYNTAX (get_error ("expected ( or ["));
                }
-               if (file_comment) {
-                       _file_comment = comment;
-                       comment = null;
+       }
+
+       Expression parse_object_creation_expression (SourceLocation begin, MemberAccess member) throws ParseError {
+               member.creation_member = true;
+               var arg_list = parse_argument_list ();
+               expect (TokenType.CLOSE_PARENS);
+               var init_list = parse_object_initializer ();
+
+               var expr = context.create_object_creation_expression (member, get_src (begin));
+               foreach (Expression arg in arg_list) {
+                       expr.add_argument (arg);
                }
+               foreach (MemberInitializer initializer in init_list) {
+                       expr.add_member_initializer (initializer);
+               }
+               return expr;
        }
-       
-       /**
-        * Clears and returns the content of the comment stack.
-        *
-        * @return saved comment
-        */
-       public string pop_comment () {
-               if (comment == null) {
+
+       Expression parse_array_creation_expression (SourceLocation begin, MemberAccess member) throws ParseError {
+               bool size_specified = false;
+               var size_specifier_list = new ArrayList<Expression> ();
+               do {
+                       Expression size = null;
+                       if (current () != TokenType.CLOSE_BRACKET && current () != TokenType.COMMA) {
+                               size = parse_expression ();
+                               size_specified = true;
+                       }
+                       size_specifier_list.add (size);
+               } while (accept (TokenType.COMMA));
+               expect (TokenType.CLOSE_BRACKET);
+               InitializerList initializer = null;
+               if (current () == TokenType.OPEN_BRACE) {
+                       initializer = parse_initializer ();
+               }
+               var expr = context.create_array_creation_expression (UnresolvedType.new_from_expression (member), size_specifier_list.size, initializer, get_src (begin));
+               if (size_specified) {
+                       foreach (Expression size in size_specifier_list) {
+                               expr.append_size (size);
+                       }
+               }
+               return expr;
+       }
+
+       Gee.List<MemberInitializer> parse_object_initializer () throws ParseError {
+               var list = new ArrayList<MemberInitializer> ();
+               if (accept (TokenType.OPEN_BRACE)) {
+                       do {
+                               list.add (parse_member_initializer ());
+                       } while (accept (TokenType.COMMA));
+                       expect (TokenType.CLOSE_BRACE);
+               }
+               return list;
+       }
+
+       MemberInitializer parse_member_initializer () throws ParseError {
+               var begin = get_location ();
+               string id = parse_identifier ();
+               expect (TokenType.ASSIGN);
+               var expr = parse_expression ();
+
+               return new MemberInitializer (id, expr, get_src (begin));
+       }
+
+       Expression parse_sizeof_expression () throws ParseError {
+               var begin = get_location ();
+               expect (TokenType.SIZEOF);
+               expect (TokenType.OPEN_PARENS);
+               var type = parse_type ();
+               expect (TokenType.CLOSE_PARENS);
+
+               return context.create_sizeof_expression (type, get_src (begin));
+       }
+
+       Expression parse_typeof_expression () throws ParseError {
+               var begin = get_location ();
+               expect (TokenType.TYPEOF);
+               expect (TokenType.OPEN_PARENS);
+               var type = parse_type ();
+               expect (TokenType.CLOSE_PARENS);
+
+               return context.create_typeof_expression (type, get_src (begin));
+       }
+
+       UnaryOperator get_unary_operator (TokenType token_type) {
+               switch (token_type) {
+               case TokenType.PLUS:   return UnaryOperator.PLUS;
+               case TokenType.MINUS:  return UnaryOperator.MINUS;
+               case TokenType.OP_NEG: return UnaryOperator.LOGICAL_NEGATION;
+               case TokenType.TILDE:  return UnaryOperator.BITWISE_COMPLEMENT;
+               case TokenType.OP_INC: return UnaryOperator.INCREMENT;
+               case TokenType.OP_DEC: return UnaryOperator.DECREMENT;
+               case TokenType.REF:    return UnaryOperator.REF;
+               case TokenType.OUT:    return UnaryOperator.OUT;
+               default:               return UnaryOperator.NONE;
+               }
+       }
+
+       Expression parse_unary_expression () throws ParseError {
+               var begin = get_location ();
+               var operator = get_unary_operator (current ());
+               if (operator != UnaryOperator.NONE) {
+                       next ();
+                       var op = parse_unary_expression ();
+                       return context.create_unary_expression (operator, op, get_src (begin));
+               }
+               switch (current ()) {
+               case TokenType.HASH:
+                       next ();
+                       var op = parse_unary_expression ();
+                       return context.create_reference_transfer_expression (op, get_src (begin));
+               case TokenType.OPEN_PARENS:
+                       next ();
+                       switch (current ()) {
+                       case TokenType.VOID:
+                       case TokenType.IDENTIFIER:
+                               var type = parse_type ();
+                               if (accept (TokenType.CLOSE_PARENS)) {
+                                       // check follower to decide whether to create cast expression
+                                       switch (current ()) {
+                                       case TokenType.OP_NEG:
+                                       case TokenType.TILDE:
+                                       case TokenType.OPEN_PARENS:
+                                       case TokenType.TRUE:
+                                       case TokenType.FALSE:
+                                       case TokenType.INTEGER_LITERAL:
+                                       case TokenType.REAL_LITERAL:
+                                       case TokenType.CHARACTER_LITERAL:
+                                       case TokenType.STRING_LITERAL:
+                                       case TokenType.NULL:
+                                       case TokenType.THIS:
+                                       case TokenType.BASE:
+                                       case TokenType.NEW:
+                                       case TokenType.SIZEOF:
+                                       case TokenType.TYPEOF:
+                                       case TokenType.IDENTIFIER:
+                                               var inner = parse_unary_expression ();
+                                               return context.create_cast_expression (inner, type, get_src (begin), false);
+                                       }
+                               }
+                               break;
+                       }
+                       // no cast expression
+                       rollback (begin);
+                       break;
+               case TokenType.STAR:
+                       next ();
+                       var op = parse_unary_expression ();
+                       return context.create_pointer_indirection (op, get_src (begin));
+               case TokenType.BITWISE_AND:
+                       next ();
+                       var op = parse_unary_expression ();
+                       return context.create_addressof_expression (op, get_src (begin));
+               }
+
+               return parse_primary_expression ();
+       }
+
+       BinaryOperator get_binary_operator (TokenType token_type) {
+               switch (token_type) {
+               case TokenType.STAR:    return BinaryOperator.MUL;
+               case TokenType.DIV:     return BinaryOperator.DIV;
+               case TokenType.PERCENT: return BinaryOperator.MOD;
+               case TokenType.PLUS:    return BinaryOperator.PLUS;
+               case TokenType.MINUS:   return BinaryOperator.MINUS;
+               case TokenType.OP_LT:   return BinaryOperator.LESS_THAN;
+               case TokenType.OP_GT:   return BinaryOperator.GREATER_THAN;
+               case TokenType.OP_LE:   return BinaryOperator.LESS_THAN_OR_EQUAL;
+               case TokenType.OP_GE:   return BinaryOperator.GREATER_THAN_OR_EQUAL;
+               case TokenType.OP_EQ:   return BinaryOperator.EQUALITY;
+               case TokenType.OP_NE:   return BinaryOperator.INEQUALITY;
+               default:                return BinaryOperator.NONE;
+               }
+       }
+
+       Expression parse_multiplicative_expression () throws ParseError {
+               var begin = get_location ();
+               var left = parse_unary_expression ();
+               bool found = true;
+               while (found) {
+                       var operator = get_binary_operator (current ());
+                       switch (operator) {
+                       case BinaryOperator.MUL:
+                       case BinaryOperator.DIV:
+                       case BinaryOperator.MOD:
+                               next ();
+                               var right = parse_unary_expression ();
+                               left = context.create_binary_expression (operator, left, right, get_src (begin));
+                               break;
+                       default:
+                               found = false;
+                               break;
+                       }
+               }
+               return left;
+       }
+
+       Expression parse_additive_expression () throws ParseError {
+               var begin = get_location ();
+               var left = parse_multiplicative_expression ();
+               bool found = true;
+               while (found) {
+                       var operator = get_binary_operator (current ());
+                       switch (operator) {
+                       case BinaryOperator.PLUS:
+                       case BinaryOperator.MINUS:
+                               next ();
+                               var right = parse_multiplicative_expression ();
+                               left = context.create_binary_expression (operator, left, right, get_src (begin));
+                               break;
+                       default:
+                               found = false;
+                               break;
+                       }
+               }
+               return left;
+       }
+
+       Expression parse_shift_expression () throws ParseError {
+               var begin = get_location ();
+               var left = parse_additive_expression ();
+               bool found = true;
+               while (found) {
+                       switch (current ()) {
+                       case TokenType.OP_SHIFT_LEFT:
+                               next ();
+                               var right = parse_additive_expression ();
+                               left = context.create_binary_expression (BinaryOperator.SHIFT_LEFT, left, right, get_src (begin));
+                               break;
+                       // don't use OP_SHIFT_RIGHT to support >> for nested generics
+                       case TokenType.OP_GT:
+                               char* first_gt_pos = tokens[index].begin.pos;
+                               next ();
+                               // only accept >> when there is no space between the two > signs
+                               if (current () == TokenType.OP_GT && tokens[index].begin.pos == first_gt_pos + 1) {
+                                       next ();
+                                       var right = parse_additive_expression ();
+                                       left = context.create_binary_expression (BinaryOperator.SHIFT_RIGHT, left, right, get_src (begin));
+                               } else {
+                                       prev ();
+                                       found = false;
+                               }
+                               break;
+                       default:
+                               found = false;
+                               break;
+                       }
+               }
+               return left;
+       }
+
+       Expression parse_relational_expression () throws ParseError {
+               var begin = get_location ();
+               var left = parse_shift_expression ();
+               bool found = true;
+               while (found) {
+                       var operator = get_binary_operator (current ());
+                       switch (operator) {
+                       case BinaryOperator.LESS_THAN:
+                       case BinaryOperator.LESS_THAN_OR_EQUAL:
+                       case BinaryOperator.GREATER_THAN_OR_EQUAL:
+                               next ();
+                               var right = parse_shift_expression ();
+                               left = context.create_binary_expression (operator, left, right, get_src (begin));
+                               break;
+                       case BinaryOperator.GREATER_THAN:
+                               next ();
+                               // ignore >> and >>= (two tokens due to generics)
+                               if (current () != TokenType.OP_GT && current () != TokenType.OP_GE) {
+                                       var right = parse_shift_expression ();
+                                       left = context.create_binary_expression (operator, left, right, get_src (begin));
+                               } else {
+                                       prev ();
+                                       found = false;
+                               }
+                               break;
+                       default:
+                               switch (current ()) {
+                               case TokenType.IS:
+                                       next ();
+                                       var type = parse_type ();
+                                       left = context.create_type_check (left, type, get_src (begin));
+                                       break;
+                               case TokenType.AS:
+                                       next ();
+                                       var type = parse_type ();
+                                       left = context.create_cast_expression (left, type, get_src (begin), true);
+                                       break;
+                               default:
+                                       found = false;
+                                       break;
+                               }
+                               break;
+                       }
+               }
+               return left;
+       }
+
+       Expression parse_equality_expression () throws ParseError {
+               var begin = get_location ();
+               var left = parse_relational_expression ();
+               bool found = true;
+               while (found) {
+                       var operator = get_binary_operator (current ());
+                       switch (operator) {
+                       case BinaryOperator.EQUALITY:
+                       case BinaryOperator.INEQUALITY:
+                               next ();
+                               var right = parse_relational_expression ();
+                               left = context.create_binary_expression (operator, left, right, get_src (begin));
+                               break;
+                       default:
+                               found = false;
+                               break;
+                       }
+               }
+               return left;
+       }
+
+       Expression parse_and_expression () throws ParseError {
+               var begin = get_location ();
+               var left = parse_equality_expression ();
+               while (accept (TokenType.BITWISE_AND)) {
+                       var right = parse_equality_expression ();
+                       left = context.create_binary_expression (BinaryOperator.BITWISE_AND, left, right, get_src (begin));
+               }
+               return left;
+       }
+
+       Expression parse_exclusive_or_expression () throws ParseError {
+               var begin = get_location ();
+               var left = parse_and_expression ();
+               while (accept (TokenType.CARRET)) {
+                       var right = parse_and_expression ();
+                       left = context.create_binary_expression (BinaryOperator.BITWISE_XOR, left, right, get_src (begin));
+               }
+               return left;
+       }
+
+       Expression parse_inclusive_or_expression () throws ParseError {
+               var begin = get_location ();
+               var left = parse_exclusive_or_expression ();
+               while (accept (TokenType.BITWISE_OR)) {
+                       var right = parse_exclusive_or_expression ();
+                       left = context.create_binary_expression (BinaryOperator.BITWISE_OR, left, right, get_src (begin));
+               }
+               return left;
+       }
+
+       Expression parse_in_expression () throws ParseError {
+               var begin = get_location ();
+               var left = parse_inclusive_or_expression ();
+               while (accept (TokenType.IN)) {
+                       var right = parse_inclusive_or_expression ();
+                       left = context.create_binary_expression (BinaryOperator.IN, left, right, get_src (begin));
+               }
+               return left;
+       }
+
+       Expression parse_conditional_and_expression () throws ParseError {
+               var begin = get_location ();
+               var left = parse_in_expression ();
+               while (accept (TokenType.OP_AND)) {
+                       var right = parse_in_expression ();
+                       left = context.create_binary_expression (BinaryOperator.AND, left, right, get_src (begin));
+               }
+               return left;
+       }
+
+       Expression parse_conditional_or_expression () throws ParseError {
+               var begin = get_location ();
+               var left = parse_conditional_and_expression ();
+               while (accept (TokenType.OP_OR)) {
+                       var right = parse_conditional_and_expression ();
+                       left = context.create_binary_expression (BinaryOperator.OR, left, right, get_src (begin));
+               }
+               return left;
+       }
+
+       Expression parse_conditional_expression () throws ParseError {
+               var begin = get_location ();
+               var condition = parse_conditional_or_expression ();
+               if (accept (TokenType.INTERR)) {
+                       var true_expr = parse_expression ();
+                       expect (TokenType.COLON);
+                       var false_expr = parse_expression ();
+                       return context.create_conditional_expression (condition, true_expr, false_expr, get_src (begin));
+               } else {
+                       return condition;
+               }
+       }
+
+       Expression parse_lambda_expression () throws ParseError {
+               var begin = get_location ();
+               Gee.List<string> params = new ArrayList<string> ();
+               if (accept (TokenType.OPEN_PARENS)) {
+                       if (current () != TokenType.CLOSE_PARENS) {
+                               do {
+                                       params.add (parse_identifier ());
+                               } while (accept (TokenType.COMMA));
+                       }
+                       expect (TokenType.CLOSE_PARENS);
+               } else {
+                       params.add (parse_identifier ());
+               }
+               expect (TokenType.LAMBDA);
+
+               LambdaExpression lambda;
+               if (current () == TokenType.OPEN_BRACE) {
+                       var block = parse_block ();
+                       lambda = context.create_lambda_expression_with_statement_body (block, get_src (begin));
+               } else {
+                       var expr = parse_expression ();
+                       lambda = context.create_lambda_expression (expr, get_src (begin));
+               }
+               foreach (string param in params) {
+                       lambda.add_parameter (param);
+               }
+               return lambda;
+       }
+
+       AssignmentOperator get_assignment_operator (TokenType token_type) {
+               switch (token_type) {
+               case TokenType.ASSIGN:             return AssignmentOperator.SIMPLE;
+               case TokenType.ASSIGN_ADD:         return AssignmentOperator.ADD;
+               case TokenType.ASSIGN_SUB:         return AssignmentOperator.SUB;
+               case TokenType.ASSIGN_BITWISE_OR:  return AssignmentOperator.BITWISE_OR;
+               case TokenType.ASSIGN_BITWISE_AND: return AssignmentOperator.BITWISE_AND;
+               case TokenType.ASSIGN_BITWISE_XOR: return AssignmentOperator.BITWISE_XOR;
+               case TokenType.ASSIGN_DIV:         return AssignmentOperator.DIV;
+               case TokenType.ASSIGN_MUL:         return AssignmentOperator.MUL;
+               case TokenType.ASSIGN_PERCENT:     return AssignmentOperator.PERCENT;
+               case TokenType.ASSIGN_SHIFT_LEFT:  return AssignmentOperator.SHIFT_LEFT;
+               default:                           return AssignmentOperator.NONE;
+               }
+       }
+
+       Expression parse_expression () throws ParseError {
+               var begin = get_location ();
+               Expression expr = parse_conditional_expression ();
+
+               if (current () == TokenType.LAMBDA) {
+                       rollback (begin);
+                       return parse_lambda_expression ();
+               }
+
+               while (true) {
+                       var operator = get_assignment_operator (current ());
+                       if (operator != AssignmentOperator.NONE) {
+                               next ();
+                               var rhs = parse_expression ();
+                               expr = context.create_assignment (expr, rhs, operator);
+                       } else if (current () == TokenType.OP_GT) { // >>=
+                               char* first_gt_pos = tokens[index].begin.pos;
+                               next ();
+                               // only accept >>= when there is no space between the two > signs
+                               if (current () == TokenType.OP_GE && tokens[index].begin.pos == first_gt_pos + 1) {
+                                       next ();
+                                       var rhs = parse_expression ();
+                                       expr = context.create_assignment (expr, rhs, AssignmentOperator.SHIFT_RIGHT);
+                               } else {
+                                       prev ();
+                                       break;
+                               }
+                       } else {
+                               break;
+                       }
+               }
+
+               return expr;
+       }
+
+       Statement parse_statement () throws ParseError {
+               comment = scanner.pop_comment ();
+               switch (current ()) {
+               case TokenType.OPEN_BRACE:
+                       return parse_block ();
+               case TokenType.SEMICOLON:
+                       return parse_empty_statement ();
+               case TokenType.IF:
+                       return parse_if_statement ();
+               case TokenType.SWITCH:
+                       return parse_switch_statement ();
+               case TokenType.WHILE:
+                       return parse_while_statement ();
+               case TokenType.DO:
+                       return parse_do_statement ();
+               case TokenType.FOR:
+                       return parse_for_statement ();
+               case TokenType.FOREACH:
+                       return parse_foreach_statement ();
+               case TokenType.BREAK:
+                       return parse_break_statement ();
+               case TokenType.CONTINUE:
+                       return parse_continue_statement ();
+               case TokenType.RETURN:
+                       return parse_return_statement ();
+               case TokenType.THROW:
+                       return parse_throw_statement ();
+               case TokenType.TRY:
+                       return parse_try_statement ();
+               case TokenType.LOCK:
+                       return parse_lock_statement ();
+               case TokenType.DELETE:
+                       return parse_delete_statement ();
+               case TokenType.VAR:
+                       return parse_declaration_statement ();
+               case TokenType.OP_INC:
+               case TokenType.OP_DEC:
+               case TokenType.BASE:
+               case TokenType.THIS:
+               case TokenType.OPEN_PARENS:
+               case TokenType.STAR:
+                       return parse_expression_statement ();
+               }
+
+               if (is_expression ()) {
+                       return parse_expression_statement ();
+               } else {
+                       return parse_declaration_statement ();
+               }
+       }
+
+       bool is_expression () throws ParseError {
+               var begin = get_location ();
+
+               // decide between declaration and expression statement
+               skip_type ();
+               switch (current ()) {
+               // invocation expression
+               case TokenType.OPEN_PARENS:
+               // postfix increment
+               case TokenType.OP_INC:
+               // postfix decrement
+               case TokenType.OP_DEC:
+               // assignments
+               case TokenType.ASSIGN:
+               case TokenType.ASSIGN_ADD:
+               case TokenType.ASSIGN_BITWISE_AND:
+               case TokenType.ASSIGN_BITWISE_OR:
+               case TokenType.ASSIGN_BITWISE_XOR:
+               case TokenType.ASSIGN_DIV:
+               case TokenType.ASSIGN_MUL:
+               case TokenType.ASSIGN_PERCENT:
+               case TokenType.ASSIGN_SHIFT_LEFT:
+               case TokenType.ASSIGN_SUB:
+               case TokenType.OP_GT: // >>=
+               // member access
+               case TokenType.DOT:
+               // pointer member access
+               case TokenType.OP_PTR:
+                       rollback (begin);
+                       return true;
+               }
+
+               rollback (begin);
+               return false;
+       }
+
+       Block parse_embedded_statement () throws ParseError {
+               if (current () == TokenType.OPEN_BRACE) {
+                       return parse_block ();
+               }
+
+               comment = scanner.pop_comment ();
+
+               var block = context.create_block ();
+               block.add_statement (parse_embedded_statement_without_block ());
+               return block;
+
+       }
+
+       Statement parse_embedded_statement_without_block () throws ParseError {
+               switch (current ()) {
+               case TokenType.SEMICOLON: return parse_empty_statement ();
+               case TokenType.IF:        return parse_if_statement ();
+               case TokenType.SWITCH:    return parse_switch_statement ();
+               case TokenType.WHILE:     return parse_while_statement ();
+               case TokenType.DO:        return parse_do_statement ();
+               case TokenType.FOR:       return parse_for_statement ();
+               case TokenType.FOREACH:   return parse_foreach_statement ();
+               case TokenType.BREAK:     return parse_break_statement ();
+               case TokenType.CONTINUE:  return parse_continue_statement ();
+               case TokenType.RETURN:    return parse_return_statement ();
+               case TokenType.THROW:     return parse_throw_statement ();
+               case TokenType.TRY:       return parse_try_statement ();
+               case TokenType.LOCK:      return parse_lock_statement ();
+               case TokenType.DELETE:    return parse_delete_statement ();
+               default:                  return parse_expression_statement ();
+               }
+       }
+
+       Block parse_block () throws ParseError {
+               var begin = get_location ();
+               Gee.List<Statement> list = new ArrayList<Statement> ();
+               expect (TokenType.OPEN_BRACE);
+               var block = context.create_block (get_src_com (begin));
+               while (current () != TokenType.CLOSE_BRACE) {
+                       try {
+                               var stmt = parse_statement ();
+                               if (stmt == null) {
+                                       // workaround for current limitation of exception handling
+                                       throw new ParseError.SYNTAX ("syntax error in statement");
+                               }
+                               block.add_statement (stmt);
+                       } catch (ParseError e) {
+                               if (recover () != RecoveryState.STATEMENT_BEGIN) {
+                                       // beginning of next declaration or end of file reached
+                                       // return what we have so far
+                                       return block;
+                               }
+                       }
+               }
+               if (!accept (TokenType.CLOSE_BRACE)) {
+                       Report.error (new SourceReference (scanner.source_file, tokens[index].begin.line, tokens[index].begin.column, tokens[index].end.line, tokens[index].end.column), "expected `}'");
+               }
+
+               return block;
+       }
+
+       Statement parse_empty_statement () throws ParseError {
+               var begin = get_location ();
+               expect (TokenType.SEMICOLON);
+               return context.create_empty_statement (get_src_com (begin));
+       }
+
+       Statement parse_declaration_statement () throws ParseError {
+               var begin = get_location ();
+               var decl = parse_local_variable_declaration ();
+               expect (TokenType.SEMICOLON);
+               return context.create_declaration_statement (decl, get_src_com (begin));
+       }
+
+       LocalVariableDeclaration parse_local_variable_declaration () throws ParseError {
+               var begin = get_location ();
+               LocalVariableDeclaration decl;
+               if (accept (TokenType.VAR)) {
+                       var declarators = parse_variable_declarators ();
+                       decl = context.create_local_variable_declaration_var_type (get_src (begin));
+                       foreach (VariableDeclarator var_decl in declarators) {
+                               decl.add_declarator (var_decl);
+                       }
+               } else {
+                       var type = parse_type ();
+                       var declarators = parse_variable_declarators ();
+                       if (!((UnresolvedType) type).is_weak) {
+                               type.takes_ownership = true;
+                       }
+                       type.requires_null_check = false;
+                       type.nullable = true;
+                       decl = context.create_local_variable_declaration (type, get_src (begin));
+                       foreach (VariableDeclarator var_decl in declarators) {
+                               var_decl.type_reference = type.copy ();
+                               decl.add_declarator (var_decl);
+                       }
+               }
+               return decl;
+       }
+
+       Statement parse_expression_statement () throws ParseError {
+               var begin = get_location ();
+               var expr = parse_statement_expression ();
+               expect (TokenType.SEMICOLON);
+               return context.create_expression_statement (expr, get_src_com (begin));
+       }
+
+       Expression parse_statement_expression () throws ParseError {
+               // invocation expression, assignment,
+               // or pre/post increment/decrement expression
+               return parse_expression ();
+       }
+
+       Statement parse_if_statement () throws ParseError {
+               var begin = get_location ();
+               expect (TokenType.IF);
+               expect (TokenType.OPEN_PARENS);
+               var condition = parse_expression ();
+               expect (TokenType.CLOSE_PARENS);
+               var src = get_src_com (begin);
+               var true_stmt = parse_embedded_statement ();
+               Block false_stmt = null;
+               if (accept (TokenType.ELSE)) {
+                       false_stmt = parse_embedded_statement ();
+               }
+               return context.create_if_statement (condition, true_stmt, false_stmt, src);
+       }
+
+       Statement parse_switch_statement () throws ParseError {
+               var begin = get_location ();
+               expect (TokenType.SWITCH);
+               expect (TokenType.OPEN_PARENS);
+               var condition = parse_expression ();
+               expect (TokenType.CLOSE_PARENS);
+               var stmt = context.create_switch_statement (condition, get_src_com (begin));
+               expect (TokenType.OPEN_BRACE);
+               while (current () != TokenType.CLOSE_BRACE) {
+                       var section = context.create_switch_section (get_src_com (begin));
+                       do {
+                               if (accept (TokenType.CASE)) {
+                                       section.add_label (context.create_switch_label (parse_expression (), get_src_com (begin)));
+                               } else {
+                                       expect (TokenType.DEFAULT);
+                                       section.add_label (context.create_switch_label_with_default (get_src_com (begin)));
+                               }
+                               expect (TokenType.COLON);
+                       } while (current () == TokenType.CASE || current () == TokenType.DEFAULT);
+                       while (current () != TokenType.CLOSE_BRACE
+                              && current () != TokenType.CASE
+                              && current () != TokenType.DEFAULT) {
+                               section.add_statement (parse_statement ());
+                       }
+                       stmt.add_section (section);
+               }
+               expect (TokenType.CLOSE_BRACE);
+               return stmt;
+       }
+
+       Statement parse_while_statement () throws ParseError {
+               var begin = get_location ();
+               expect (TokenType.WHILE);
+               expect (TokenType.OPEN_PARENS);
+               var condition = parse_expression ();
+               expect (TokenType.CLOSE_PARENS);
+               var body = parse_embedded_statement ();
+               return context.create_while_statement (condition, body, get_src_com (begin));
+       }
+
+       Statement parse_do_statement () throws ParseError {
+               var begin = get_location ();
+               expect (TokenType.DO);
+               var body = parse_embedded_statement ();
+               expect (TokenType.WHILE);
+               expect (TokenType.OPEN_PARENS);
+               var condition = parse_expression ();
+               expect (TokenType.CLOSE_PARENS);
+               expect (TokenType.SEMICOLON);
+               return context.create_do_statement (body, condition, get_src_com (begin));
+       }
+
+       Statement parse_for_statement () throws ParseError {
+               var begin = get_location ();
+               Block block = null;
+               expect (TokenType.FOR);
+               expect (TokenType.OPEN_PARENS);
+               var initializer_list = new ArrayList<Expression> ();
+               if (!accept (TokenType.SEMICOLON)) {
+                       bool is_expr;
+                       switch (current ()) {
+                       case TokenType.VAR:
+                               is_expr = false;
+                               break;
+                       case TokenType.OP_INC:
+                       case TokenType.OP_DEC:
+                               is_expr = true;
+                               break;
+                       default:
+                               is_expr = is_expression ();
+                               break;
+                       }
+
+                       if (is_expr) {
+                               do {
+                                       initializer_list.add (parse_statement_expression ());
+                               } while (accept (TokenType.COMMA));
+                               expect (TokenType.SEMICOLON);
+                       } else {
+                               block = context.create_block (get_src (begin));
+                               block.add_statement (parse_declaration_statement ());
+                       }
+               }
+               Expression condition = null;
+               if (current () != TokenType.SEMICOLON) {
+                       condition = parse_expression ();
+               }
+               expect (TokenType.SEMICOLON);
+               var iterator_list = new ArrayList<Expression> ();
+               if (current () != TokenType.CLOSE_PARENS) {
+                       do {
+                               iterator_list.add (parse_statement_expression ());
+                       } while (accept (TokenType.COMMA));
+               }
+               expect (TokenType.CLOSE_PARENS);
+               var src = get_src_com (begin);
+               var body = parse_embedded_statement ();
+               var stmt = context.create_for_statement (condition, body, src);
+               foreach (Expression init in initializer_list) {
+                       stmt.add_initializer (init);
+               }
+               foreach (Expression iter in iterator_list) {
+                       stmt.add_iterator (iter);
+               }
+               if (block != null) {
+                       block.add_statement (stmt);
+                       return block;
+               } else {
+                       return stmt;
+               }
+       }
+
+       Statement parse_foreach_statement () throws ParseError {
+               var begin = get_location ();
+               expect (TokenType.FOREACH);
+               expect (TokenType.OPEN_PARENS);
+               var type = parse_type ();
+               var unresolved_type = type as UnresolvedType;
+               if (unresolved_type != null && !unresolved_type.is_weak) {
+                       unresolved_type.takes_ownership = true;
+               }
+               string id = parse_identifier ();
+               expect (TokenType.IN);
+               var collection = parse_expression ();
+               expect (TokenType.CLOSE_PARENS);
+               var src = get_src_com (begin);
+               var body = parse_embedded_statement ();
+               return context.create_foreach_statement (type, id, collection, body, src);
+       }
+
+       Statement parse_break_statement () throws ParseError {
+               var begin = get_location ();
+               expect (TokenType.BREAK);
+               expect (TokenType.SEMICOLON);
+               return context.create_break_statement (get_src_com (begin));
+       }
+
+       Statement parse_continue_statement () throws ParseError {
+               var begin = get_location ();
+               expect (TokenType.CONTINUE);
+               expect (TokenType.SEMICOLON);
+               return context.create_continue_statement (get_src_com (begin));
+       }
+
+       Statement parse_return_statement () throws ParseError {
+               var begin = get_location ();
+               expect (TokenType.RETURN);
+               Expression expr = null;
+               if (current () != TokenType.SEMICOLON) {
+                       expr = parse_expression ();
+               }
+               expect (TokenType.SEMICOLON);
+               return context.create_return_statement (expr, get_src_com (begin));
+       }
+
+       Statement parse_throw_statement () throws ParseError {
+               var begin = get_location ();
+               expect (TokenType.THROW);
+               var expr = parse_expression ();
+               expect (TokenType.SEMICOLON);
+               return context.create_throw_statement (expr, get_src_com (begin));
+       }
+
+       Statement parse_try_statement () throws ParseError {
+               var begin = get_location ();
+               expect (TokenType.TRY);
+               var try_block = parse_block ();
+               Block finally_clause = null;
+               var catch_clauses = new ArrayList<CatchClause> ();
+               if (current () == TokenType.CATCH) {
+                       parse_catch_clauses (catch_clauses);
+                       if (current () == TokenType.FINALLY) {
+                               finally_clause = parse_finally_clause ();
+                       }
+               } else {
+                       finally_clause = parse_finally_clause ();
+               }
+               var stmt = context.create_try_statement (try_block, finally_clause, get_src_com (begin));
+               foreach (CatchClause clause in catch_clauses) {
+                       stmt.add_catch_clause (clause);
+               }
+               return stmt;
+       }
+
+       void parse_catch_clauses (Gee.List<CatchClause> catch_clauses) throws ParseError {
+               while (accept (TokenType.CATCH)) {
+                       var begin = get_location ();
+                       DataType type = null;
+                       string id = null;
+                       if (accept (TokenType.OPEN_PARENS)) {
+                               type = parse_type ();
+                               id = parse_identifier ();
+                               expect (TokenType.CLOSE_PARENS);
+                       }
+                       var block = parse_block ();
+                       catch_clauses.add (context.create_catch_clause (type, id, block, get_src (begin)));
+               }
+       }
+
+       Block parse_finally_clause () throws ParseError {
+               expect (TokenType.FINALLY);
+               return parse_block ();
+       }
+
+       Statement parse_lock_statement () throws ParseError {
+               var begin = get_location ();
+               expect (TokenType.LOCK);
+               expect (TokenType.OPEN_PARENS);
+               var expr = parse_expression ();
+               expect (TokenType.CLOSE_PARENS);
+               var stmt = parse_embedded_statement ();
+               return context.create_lock_statement (expr, stmt, get_src_com (begin));
+       }
+
+       Statement parse_delete_statement () throws ParseError {
+               var begin = get_location ();
+               expect (TokenType.DELETE);
+               var expr = parse_expression ();
+               expect (TokenType.SEMICOLON);
+               return context.create_delete_statement (expr, get_src_com (begin));
+       }
+
+       Gee.List<Attribute> parse_attributes () throws ParseError {
+               if (current () != TokenType.OPEN_BRACKET) {
                        return null;
                }
+               var attrs = new ArrayList<Attribute> ();
+               while (accept (TokenType.OPEN_BRACKET)) {
+                       do {
+                               var begin = get_location ();
+                               string id = parse_identifier ();
+                               var attr = new Attribute (id, get_src (begin));
+                               if (accept (TokenType.OPEN_PARENS)) {
+                                       if (current () != TokenType.CLOSE_PARENS) {
+                                               do {
+                                                       begin = get_location ();
+                                                       string id = parse_identifier ();
+                                                       expect (TokenType.ASSIGN);
+                                                       var expr = parse_expression ();
+                                                       attr.add_argument (new NamedArgument (id, expr, get_src (begin)));
+                                               } while (accept (TokenType.COMMA));
+                                       }
+                                       expect (TokenType.CLOSE_PARENS);
+                               }
+                               attrs.add (attr);
+                       } while (accept (TokenType.COMMA));
+                       expect (TokenType.CLOSE_BRACKET);
+               }
+               return attrs;
+       }
+
+       void set_attributes (CodeNode node, Gee.List<Attribute> attributes) {
+               if (attributes != null) {
+                       foreach (Attribute attr in attributes) {
+                               node.attributes.append (attr);
+                       }
+               }
+       }
+
+       Symbol parse_declaration () throws ParseError {
+               comment = scanner.pop_comment ();
+               var attrs = parse_attributes ();
                
-               String result = new String (comment);
-               comment = null;
+               var begin = get_location ();
                
-               weak string index;
-               while ((index = result.str.chr (-1, '\t')) != null) {
-                       result.erase (result.str.pointer_to_offset (index), 1);
-               }
+               TokenType last_keyword = current ();
                
-               return result.str;
-       }
+               while (is_declaration_keyword (current ())) {
+                       last_keyword = current ();
+                       next ();
+               }
        
-       [Import ()]
-       public void parse_file (SourceFile! source_file);
+               switch (current ()) {   
+               case TokenType.CONSTRUCT:
+                       rollback (begin);
+                       return parse_constructor_declaration (attrs);
+               case TokenType.TILDE:
+                       rollback (begin);
+                       return parse_destructor_declaration (attrs);
+               default:
+                       skip_type ();
+                       switch (current ()) {
+                       case TokenType.OPEN_BRACE:
+                       case TokenType.SEMICOLON:
+                       case TokenType.COLON:
+                               rollback (begin);
+                               switch (last_keyword) {
+                               case TokenType.CLASS:       return parse_class_declaration (attrs);
+                               case TokenType.ENUM:        return parse_enum_declaration (attrs);
+                               case TokenType.ERRORDOMAIN: return parse_errordomain_declaration (attrs);
+                               case TokenType.INTERFACE:   return parse_interface_declaration (attrs);
+                               case TokenType.NAMESPACE:   return parse_namespace_declaration (attrs);
+                               case TokenType.STRUCT:      return parse_struct_declaration (attrs);
+                               }
+                               break;
+                       case TokenType.OPEN_PARENS:
+                               rollback (begin);
+                               return parse_creation_method_declaration (attrs);
+                       default:
+                               skip_type (); // might contain type parameter list
+                               switch (current ()) {
+                               case TokenType.OPEN_PARENS:
+                                       rollback (begin);
+                                       switch (last_keyword) {
+                                       case TokenType.DELEGATE: return parse_delegate_declaration (attrs);
+                                       case TokenType.SIGNAL:   return parse_signal_declaration (attrs);
+                                       default:                 return parse_method_declaration (attrs);
+                                       }
+                               case TokenType.ASSIGN:
+                               case TokenType.SEMICOLON:
+                                       rollback (begin);
+                                       switch (last_keyword) {
+                                       case TokenType.CONST: return parse_constant_declaration (attrs);
+                                       default:              return parse_field_declaration (attrs);
+                                       }
+                               case TokenType.OPEN_BRACE:
+                                       rollback (begin);
+                                       return parse_property_declaration (attrs);
+                               }
+                               break;
+                       }
+                       break;
+               }
+
+               throw new ParseError.SYNTAX (get_error ("expected declaration"));
+       }
+
+       void parse_declarations (Symbol parent, bool root = false) throws ParseError {
+               if (!root) {
+                       expect (TokenType.OPEN_BRACE);
+               }
+               while (current () != TokenType.CLOSE_BRACE && current () != TokenType.EOF) {
+                       try {
+                               if (parent is Namespace) {
+                                       parse_namespace_member ((Namespace) parent);
+                               } else if (parent is Class) {
+                                       parse_class_member ((Class) parent);
+                               } else if (parent is Struct) {
+                                       parse_struct_member ((Struct) parent);
+                               } else if (parent is Interface) {
+                                       parse_interface_member ((Interface) parent);
+                               }
+                       } catch (ParseError e) {
+                               int r;
+                               do {
+                                       r = recover ();
+                               } while (r == RecoveryState.STATEMENT_BEGIN);
+                               if (r == RecoveryState.EOF) {
+                                       return;
+                               }
+                       }
+               }
+               if (!root) {
+                       if (!accept (TokenType.CLOSE_BRACE)) {
+                               Report.error (new SourceReference (scanner.source_file, tokens[index].begin.line, tokens[index].begin.column, tokens[index].end.line, tokens[index].end.column), "expected `}'");
+                       }
+               }
+       }
+
+       enum RecoveryState {
+               EOF,
+               DECLARATION_BEGIN,
+               STATEMENT_BEGIN
+       }
+
+       RecoveryState recover () {
+               while (current () != TokenType.EOF) {
+                       switch (current ()) {
+                       case TokenType.ABSTRACT:
+                       case TokenType.CLASS:
+                       case TokenType.CONST:
+                       case TokenType.CONSTRUCT:
+                       case TokenType.DELEGATE:
+                       case TokenType.ENUM:
+                       case TokenType.ERRORDOMAIN:
+                       case TokenType.INLINE:
+                       case TokenType.INTERFACE:
+                       case TokenType.NAMESPACE:
+                       case TokenType.OVERRIDE:
+                       case TokenType.PRIVATE:
+                       case TokenType.PROTECTED:
+                       case TokenType.PUBLIC:
+                       case TokenType.SIGNAL:
+                       case TokenType.STATIC:
+                       case TokenType.STRUCT:
+                       case TokenType.VIRTUAL:
+                       case TokenType.VOLATILE:
+                               return RecoveryState.DECLARATION_BEGIN;
+                       case TokenType.BREAK:
+                       case TokenType.CONTINUE:
+                       case TokenType.DELETE:
+                       case TokenType.DO:
+                       case TokenType.FOR:
+                       case TokenType.FOREACH:
+                       case TokenType.IF:
+                       case TokenType.LOCK:
+                       case TokenType.RETURN:
+                       case TokenType.SWITCH:
+                       case TokenType.THROW:
+                       case TokenType.TRY:
+                       case TokenType.VAR:
+                       case TokenType.WHILE:
+                               return RecoveryState.STATEMENT_BEGIN;
+                       default:
+                               next ();
+                               break;
+                       }
+               }
+               return RecoveryState.EOF;
+       }
+
+       Namespace parse_namespace_declaration (Gee.List<Attribute> attrs) throws ParseError {
+               var begin = get_location ();
+               expect (TokenType.NAMESPACE);
+               var sym = parse_symbol_name ();
+               var ns = context.create_namespace (sym.name, get_src_com (begin));
+               ns.pkg = scanner.source_file.pkg;
+               set_attributes (ns, attrs);
+               parse_declarations (ns);
+               return ns;
+       }
+
+       void parse_namespace_member (Namespace ns) throws ParseError {
+               var sym = parse_declaration ();
+               if (sym is Namespace) {
+                       if (ns.scope.lookup (sym.name) is Namespace) {
+                               // merge if namespace already exists
+                               var old_ns = (Namespace) ns.scope.lookup (sym.name);
+                               var new_ns = (Namespace) sym;
+                               if (!new_ns.pkg) {
+                                       old_ns.pkg = false;
+                               }
+                               foreach (Class cl in new_ns.get_classes ()) {
+                                       if (old_ns.scope.lookup (cl.name) is Class) {
+                                               // merge
+                                               var old_class = (Class) old_ns.scope.lookup (cl.name);
+                                               foreach (DataType base_type in cl.get_base_types ()) {
+                                                       old_class.add_base_type (base_type);
+                                               }
+                                               foreach (Field f in cl.get_fields ()) {
+                                                       old_class.add_field (f);
+                                               }
+                                               foreach (Method m in cl.get_methods ()) {
+                                                       if (m == cl.default_construction_method && old_class.default_construction_method != null) {
+                                                               // ignore secondary default creation method
+                                                               continue;
+                                                       }
+                                                       old_class.add_method (m);
+                                               }
+                                               if (cl.constructor != null) {
+                                                       old_class.constructor = cl.constructor;
+                                               }
+                                               scanner.source_file.remove_node (cl);
+                                       } else {
+                                               old_ns.add_class (cl);
+                                       }
+                               }
+                               foreach (Struct st in new_ns.get_structs ()) {
+                                       old_ns.add_struct (st);
+                               }
+                               foreach (Interface iface in new_ns.get_interfaces ()) {
+                                       old_ns.add_interface (iface);
+                               }
+                               foreach (Delegate d in new_ns.get_delegates ()) {
+                                       old_ns.add_delegate (d);
+                               }
+                               foreach (Enum en in new_ns.get_enums ()) {
+                                       old_ns.add_enum (en);
+                               }
+                               foreach (ErrorDomain ed in new_ns.get_error_domains ()) {
+                                       old_ns.add_error_domain (ed);
+                               }
+                               foreach (Constant c in new_ns.get_constants ()) {
+                                       old_ns.add_constant (c);
+                               }
+                               foreach (Field f in new_ns.get_fields ()) {
+                                       old_ns.add_field (f);
+                               }
+                               foreach (Method m in new_ns.get_methods ()) {
+                                       old_ns.add_method (m);
+                               }
+                       } else {
+                               context.root.add_namespace ((Namespace) sym);
+                       }
+               } else if (sym is Class) {
+                       ns.add_class ((Class) sym);
+               } else if (sym is Interface) {
+                       ns.add_interface ((Interface) sym);
+               } else if (sym is Struct) {
+                       ns.add_struct ((Struct) sym);
+               } else if (sym is Enum) {
+                       ns.add_enum ((Enum) sym);
+               } else if (sym is ErrorDomain) {
+                       ns.add_error_domain ((ErrorDomain) sym);
+               } else if (sym is Delegate) {
+                       ns.add_delegate ((Delegate) sym);
+               } else if (sym is Method) {
+                       var method = (Method) sym;
+                       method.instance = false;
+                       ns.add_method (method);
+               } else if (sym is Field) {
+                       var field = (Field) sym;
+                       field.instance = false;
+                       ns.add_field (field);
+               } else if (sym is Constant) {
+                       ns.add_constant ((Constant) sym);
+               } else if (sym == null) {
+                       // workaround for current limitation of exception handling
+                       throw new ParseError.SYNTAX ("syntax error in declaration");
+               } else {
+                       Report.error (sym.source_reference, "unexpected declaration in namespace");
+               }
+               scanner.source_file.add_node (sym);
+       }
+
+       void parse_using_directives () throws ParseError {
+               while (accept (TokenType.USING)) {
+                       var begin = get_location ();
+
+                       do {
+                               var begin = get_location ();
+                               var sym = parse_symbol_name ();
+                               var ns_ref = new NamespaceReference (sym.name, get_src (begin));
+                               scanner.source_file.add_using_directive (ns_ref);
+                       } while (accept (TokenType.COMMA));
+                       expect (TokenType.SEMICOLON);
+               }
+       }
+
+       Symbol parse_class_declaration (Gee.List<Attribute> attrs) throws ParseError {
+               var begin = get_location ();
+               var access = parse_access_modifier ();
+               var flags = parse_type_declaration_modifiers ();
+               expect (TokenType.CLASS);
+               var sym = parse_symbol_name ();
+               var type_param_list = parse_type_parameter_list ();
+               var base_types = new ArrayList<DataType> ();
+               if (accept (TokenType.COLON)) {
+                       do {
+                               base_types.add (parse_type ());
+                       } while (accept (TokenType.COMMA));
+               }
+
+               var cl = context.create_class (sym.name, get_src_com (begin));
+               cl.access = access;
+               if (ModifierFlags.ABSTRACT in flags) {
+                       cl.is_abstract = true;
+               }
+               if (ModifierFlags.STATIC in flags) {
+                       cl.is_static = true;
+               }
+               set_attributes (cl, attrs);
+               foreach (TypeParameter type_param in type_param_list) {
+                       cl.add_type_parameter (type_param);
+               }
+               foreach (DataType base_type in base_types) {
+                       cl.add_base_type (base_type);
+               }
+
+               parse_declarations (cl);
+
+               // ensure there is always a default construction method
+               if (!scanner.source_file.pkg
+                   && !cl.is_abstract
+                   && !cl.is_static
+                   && cl.default_construction_method == null) {
+                       var m = context.create_creation_method (cl.name, null, cl.source_reference);
+                       m.instance = false;
+                       m.access = SymbolAccessibility.PUBLIC;
+                       m.body = context.create_block (cl.source_reference);
+                       cl.add_method (m);
+               }
+
+               Symbol result = cl;
+               while (sym.inner != null) {
+                       sym = sym.inner;
+                       var ns = context.create_namespace (sym.name, cl.source_reference);
+                       ns.pkg = scanner.source_file.pkg;
+                       if (result is Namespace) {
+                               ns.add_namespace ((Namespace) result);
+                       } else {
+                               ns.add_class ((Class) result);
+                               scanner.source_file.add_node (result);
+                       }
+                       result = ns;
+               }
+               return result;
+       }
+
+       void parse_class_member (Class cl) throws ParseError {
+               var sym = parse_declaration ();
+               if (sym is Class) {
+                       cl.add_class ((Class) sym);
+               } else if (sym is Struct) {
+                       cl.add_struct ((Struct) sym);
+               } else if (sym is Enum) {
+                       cl.add_enum ((Enum) sym);
+               } else if (sym is Delegate) {
+                       cl.add_delegate ((Delegate) sym);
+               } else if (sym is Method) {
+                       cl.add_method ((Method) sym);
+               } else if (sym is Signal) {
+                       cl.add_signal ((Signal) sym);
+               } else if (sym is Field) {
+                       cl.add_field ((Field) sym);
+               } else if (sym is Constant) {
+                       cl.add_constant ((Constant) sym);
+               } else if (sym is Property) {
+                       cl.add_property ((Property) sym);
+               } else if (sym is Constructor) {
+                       var c = (Constructor) sym;
+                       if (c.instance) {
+                               cl.constructor = c;
+                       } else {
+                               cl.static_constructor = c;
+                       }
+               } else if (sym is Destructor) {
+                       cl.destructor = (Destructor) sym;
+               } else if (sym == null) {
+                       // workaround for current limitation of exception handling
+                       throw new ParseError.SYNTAX ("syntax error in declaration");
+               } else {
+                       Report.error (sym.source_reference, "unexpected declaration in class");
+               }
+       }
+
+       Constant parse_constant_declaration (Gee.List<Attribute> attrs) throws ParseError {
+               var begin = get_location ();
+               var access = parse_access_modifier ();
+               parse_member_declaration_modifiers ();
+               expect (TokenType.CONST);
+               var type = parse_type ();
+               string id = parse_identifier ();
+               Expression initializer = null;
+               if (accept (TokenType.ASSIGN)) {
+                       initializer = parse_variable_initializer ();
+               }
+               expect (TokenType.SEMICOLON);
+               var c = context.create_constant (id, type, initializer, get_src_com (begin));
+               c.access = access;
+               set_attributes (c, attrs);
+               return c;
+       }
+
+       Field parse_field_declaration (Gee.List<Attribute> attrs) throws ParseError {
+               var begin = get_location ();
+               var access = parse_access_modifier ();
+               var flags = parse_member_declaration_modifiers ();
+               var type = parse_type ();
+               var unresolved_type = type as UnresolvedType;
+               if (unresolved_type != null && !unresolved_type.is_weak) {
+                       unresolved_type.takes_ownership = true;
+               }
+               string id = parse_identifier ();
+               var f = context.create_field (id, type, null, get_src_com (begin));
+               f.access = access;
+               set_attributes (f, attrs);
+               if (ModifierFlags.STATIC in flags) {
+                       f.instance = false;
+               }
+               if (accept (TokenType.ASSIGN)) {
+                       f.initializer = parse_expression ();
+               }
+               expect (TokenType.SEMICOLON);
+               return f;
+       }
+
+       Gee.List<VariableDeclarator> parse_variable_declarators () throws ParseError {
+               var list = new ArrayList<VariableDeclarator> ();
+               do {
+                       var var_decl = parse_variable_declarator ();
+                       list.add (var_decl);
+               } while (accept (TokenType.COMMA));
+               return list;
+       }
+
+       VariableDeclarator parse_variable_declarator () throws ParseError {
+               var begin = get_location ();
+               string id = parse_identifier ();
+               Expression initializer = null;
+               if (accept (TokenType.ASSIGN)) {
+                       initializer = parse_variable_initializer ();
+               }
+               return context.create_variable_declarator (id, initializer, get_src (begin));
+       }
+
+       InitializerList parse_initializer () throws ParseError {
+               var begin = get_location ();
+               expect (TokenType.OPEN_BRACE);
+               var initializer = context.create_initializer_list (get_src (begin));
+               if (current () != TokenType.CLOSE_BRACE) {
+                       do {
+                               initializer.append (parse_variable_initializer ());
+                       } while (accept (TokenType.COMMA));
+               }
+               expect (TokenType.CLOSE_BRACE);
+               return initializer;
+       }
+
+       Expression parse_variable_initializer () throws ParseError {
+               if (current () == TokenType.OPEN_BRACE) {
+                       return parse_initializer ();
+               } else {
+                       return parse_expression ();
+               }
+       }
+
+       Method parse_method_declaration (Gee.List<Attribute> attrs) throws ParseError {
+               var begin = get_location ();
+               var access = parse_access_modifier ();
+               var flags = parse_member_declaration_modifiers ();
+               var type = parse_type ();
+               var unresolved_type = type as UnresolvedType;
+               if (unresolved_type != null && !unresolved_type.is_weak) {
+                       unresolved_type.transfers_ownership = true;
+               }
+               string id = parse_identifier ();
+               parse_type_parameter_list ();
+               var method = context.create_method (id, type, get_src_com (begin));
+               method.access = access;
+               set_attributes (method, attrs);
+               if (ModifierFlags.STATIC in flags) {
+                       method.instance = false;
+               }
+               if (ModifierFlags.ABSTRACT in flags) {
+                       method.is_abstract = true;
+               }
+               if (ModifierFlags.VIRTUAL in flags) {
+                       method.is_virtual = true;
+               }
+               if (ModifierFlags.OVERRIDE in flags) {
+                       method.overrides = true;
+               }
+               if (ModifierFlags.INLINE in flags) {
+                       method.is_inline = true;
+               }
+               expect (TokenType.OPEN_PARENS);
+               if (current () != TokenType.CLOSE_PARENS) {
+                       do {
+                               method.add_parameter (parse_parameter ());
+                       } while (accept (TokenType.COMMA));
+               }
+               expect (TokenType.CLOSE_PARENS);
+               if (accept (TokenType.THROWS)) {
+                       do {
+                               method.add_error_domain (parse_type ());
+                       } while (accept (TokenType.COMMA));
+               }
+               if (!accept (TokenType.SEMICOLON)) {
+                       method.body = parse_block ();
+               }
+               return method;
+       }
+
+       Property parse_property_declaration (Gee.List<Attribute> attrs) throws ParseError {
+               var begin = get_location ();
+               var access = parse_access_modifier ();
+               var flags = parse_member_declaration_modifiers ();
+               var type = parse_type ();
+               if (!((UnresolvedType) type).is_weak) {
+                       type.takes_ownership = true;
+               }
+               string id = parse_identifier ();
+               var prop = context.create_property (id, type, null, null, get_src_com (begin));
+               prop.access = access;
+               set_attributes (prop, attrs);
+               if (ModifierFlags.ABSTRACT in flags) {
+                       prop.is_abstract = true;
+               }
+               if (ModifierFlags.VIRTUAL in flags) {
+                       prop.is_virtual = true;
+               }
+               if (ModifierFlags.OVERRIDE in flags) {
+                       prop.overrides = true;
+               }
+               expect (TokenType.OPEN_BRACE);
+               while (current () != TokenType.CLOSE_BRACE) {
+                       if (accept (TokenType.DEFAULT)) {
+                               if (prop.default_expression != null) {
+                                       throw new ParseError.SYNTAX (get_error ("property default value already defined"));
+                               }
+                               if (accept (TokenType.OPEN_PARENS)) {
+                                       // deprecated
+                                       prop.default_expression = parse_expression ();
+                                       expect (TokenType.CLOSE_PARENS);
+                               } else {
+                                       expect (TokenType.ASSIGN);
+                                       prop.default_expression = parse_expression ();
+                               }
+                               expect (TokenType.SEMICOLON);
+                       } else {
+                               parse_attributes ();
+                               var accessor_access = parse_access_modifier (SymbolAccessibility.PUBLIC);
+                               if (accept (TokenType.GET)) {
+                                       if (prop.get_accessor != null) {
+                                               throw new ParseError.SYNTAX (get_error ("property get accessor already defined"));
+                                       }
+                                       Block block = null;
+                                       if (!accept (TokenType.SEMICOLON)) {
+                                               block = parse_block ();
+                                       }
+                                       prop.get_accessor = context.create_property_accessor (true, false, false, block, get_src (begin));
+                                       prop.get_accessor.access = accessor_access;
+                               } else {
+                                       bool writable, _construct;
+                                       if (accept (TokenType.SET)) {
+                                               writable = true;
+                                               _construct = accept (TokenType.CONSTRUCT);
+                                       } else if (accept (TokenType.CONSTRUCT)) {
+                                               _construct = true;
+                                               writable = accept (TokenType.SET);
+                                       } else {
+                                               throw new ParseError.SYNTAX (get_error ("expected get, set, or construct"));
+                                       }
+                                       if (prop.set_accessor != null) {
+                                               throw new ParseError.SYNTAX (get_error ("property set accessor already defined"));
+                                       }
+                                       Block block = null;
+                                       if (!accept (TokenType.SEMICOLON)) {
+                                               block = parse_block ();
+                                       }
+                                       prop.set_accessor = context.create_property_accessor (false, writable, _construct, block, get_src (begin));
+                                       prop.set_accessor.access = accessor_access;
+                               }
+                       }
+               }
+               expect (TokenType.CLOSE_BRACE);
+               return prop;
+       }
+
+       Signal parse_signal_declaration (Gee.List<Attribute> attrs) throws ParseError {
+               var begin = get_location ();
+               parse_access_modifier ();
+               parse_member_declaration_modifiers ();
+               expect (TokenType.SIGNAL);
+               var type = parse_type ();
+               string id = parse_identifier ();
+               var sig = context.create_signal (id, type, get_src_com (begin));
+               set_attributes (sig, attrs);
+               expect (TokenType.OPEN_PARENS);
+               if (current () != TokenType.CLOSE_PARENS) {
+                       do {
+                               var param = parse_parameter ();
+                               sig.add_parameter (param);
+                       } while (accept (TokenType.COMMA));
+               }
+               expect (TokenType.CLOSE_PARENS);
+               expect (TokenType.SEMICOLON);
+               return sig;
+       }
+
+       Constructor parse_constructor_declaration (Gee.List<Attribute> attrs) throws ParseError {
+               var begin = get_location ();
+               var flags = parse_member_declaration_modifiers ();
+               expect (TokenType.CONSTRUCT);
+               var c = context.create_constructor (get_src_com (begin));
+               if (ModifierFlags.STATIC in flags) {
+                       c.instance = false;
+               }
+               c.body = parse_block ();
+               return c;
+       }
+
+       Destructor parse_destructor_declaration (Gee.List<Attribute> attrs) throws ParseError {
+               var begin = get_location ();
+               expect (TokenType.TILDE);
+               parse_identifier ();
+               expect (TokenType.OPEN_PARENS);
+               expect (TokenType.CLOSE_PARENS);
+               var d = context.create_destructor (get_src_com (begin));
+               d.body = parse_block ();
+               return d;
+       }
+
+       Symbol parse_struct_declaration (Gee.List<Attribute> attrs) throws ParseError {
+               var begin = get_location ();
+               var access = parse_access_modifier ();
+               parse_type_declaration_modifiers ();
+               expect (TokenType.STRUCT);
+               var sym = parse_symbol_name ();
+               var base_types = new ArrayList<DataType> ();
+               if (accept (TokenType.COLON)) {
+                       do {
+                               base_types.add (parse_type ());
+                       } while (accept (TokenType.COMMA));
+               }
+               var st = context.create_struct (sym.name, get_src_com (begin));
+               st.access = access;
+               set_attributes (st, attrs);
+               foreach (DataType base_type in base_types) {
+                       st.add_base_type (base_type);
+               }
+
+               parse_declarations (st);
+
+               Symbol result = st;
+               while (sym.inner != null) {
+                       sym = sym.inner;
+                       var ns = context.create_namespace (sym.name, st.source_reference);
+                       ns.pkg = scanner.source_file.pkg;
+                       if (result is Namespace) {
+                               ns.add_namespace ((Namespace) result);
+                       } else {
+                               ns.add_struct ((Struct) result);
+                               scanner.source_file.add_node (result);
+                       }
+                       result = ns;
+               }
+               return result;
+       }
+
+       void parse_struct_member (Struct st) throws ParseError {
+               var sym = parse_declaration ();
+               if (sym is Method) {
+                       st.add_method ((Method) sym);
+               } else if (sym is Field) {
+                       st.add_field ((Field) sym);
+               } else if (sym is Constant) {
+                       st.add_constant ((Constant) sym);
+               } else if (sym == null) {
+                       // workaround for current limitation of exception handling
+                       throw new ParseError.SYNTAX ("syntax error in declaration");
+               } else {
+                       Report.error (sym.source_reference, "unexpected declaration in struct");
+               }
+       }
+
+       Symbol parse_interface_declaration (Gee.List<Attribute> attrs) throws ParseError {
+               var begin = get_location ();
+               var access = parse_access_modifier ();
+               parse_type_declaration_modifiers ();
+               expect (TokenType.INTERFACE);
+               var sym = parse_symbol_name ();
+               var type_param_list = parse_type_parameter_list ();
+               var base_types = new ArrayList<DataType> ();
+               if (accept (TokenType.COLON)) {
+                       do {
+                               base_types.add (parse_type ());
+                       } while (accept (TokenType.COMMA));
+               }
+               var iface = context.create_interface (sym.name, get_src_com (begin));
+               iface.access = access;
+               set_attributes (iface, attrs);
+               foreach (TypeParameter type_param in type_param_list) {
+                       iface.add_type_parameter (type_param);
+               }
+               foreach (DataType base_type in base_types) {
+                       iface.add_prerequisite (base_type);
+               }
+
+               parse_declarations (iface);
+
+               Symbol result = iface;
+               while (sym.inner != null) {
+                       sym = sym.inner;
+                       var ns = context.create_namespace (sym.name, iface.source_reference);
+                       ns.pkg = scanner.source_file.pkg;
+                       if (result is Namespace) {
+                               ns.add_namespace ((Namespace) result);
+                       } else {
+                               ns.add_interface ((Interface) result);
+                               scanner.source_file.add_node (result);
+                       }
+                       result = ns;
+               }
+               return result;
+       }
+
+       void parse_interface_member (Interface iface) throws ParseError {
+               var sym = parse_declaration ();
+               if (sym is Class) {
+                       iface.add_class ((Class) sym);
+               } else if (sym is Struct) {
+                       iface.add_struct ((Struct) sym);
+               } else if (sym is Enum) {
+                       iface.add_enum ((Enum) sym);
+               } else if (sym is Delegate) {
+                       iface.add_delegate ((Delegate) sym);
+               } else if (sym is Method) {
+                       iface.add_method ((Method) sym);
+               } else if (sym is Signal) {
+                       iface.add_signal ((Signal) sym);
+               } else if (sym is Field) {
+                       iface.add_field ((Field) sym);
+               } else if (sym is Property) {
+                       iface.add_property ((Property) sym);
+               } else if (sym == null) {
+                       // workaround for current limitation of exception handling
+                       throw new ParseError.SYNTAX ("syntax error in declaration");
+               } else {
+                       Report.error (sym.source_reference, "unexpected declaration in interface");
+               }
+       }
+
+       Symbol parse_enum_declaration (Gee.List<Attribute> attrs) throws ParseError {
+               var begin = get_location ();
+               var access = parse_access_modifier ();
+               parse_type_declaration_modifiers ();
+               expect (TokenType.ENUM);
+               var sym = parse_symbol_name ();
+               var en = context.create_enum (sym.name, get_src_com (begin));
+               en.access = access;
+               set_attributes (en, attrs);
+
+               expect (TokenType.OPEN_BRACE);
+               do {
+                       if (current () == TokenType.CLOSE_BRACE) {
+                               // allow trailing comma
+                               break;
+                       }
+                       string id = parse_identifier ();
+                       var ev = context.create_enum_value (id, get_src (begin));
+                       if (accept (TokenType.ASSIGN)) {
+                               ev.value = parse_expression ();
+                       }
+                       en.add_value (ev);
+               } while (accept (TokenType.COMMA));
+               if (accept (TokenType.SEMICOLON)) {
+                       // enum methods
+                       while (current () != TokenType.CLOSE_BRACE) {
+                               var sym = parse_declaration ();
+                               if (sym is Method) {
+                                       en.add_method ((Method) sym);
+                               } else if (sym == null) {
+                                       // workaround for current limitation of exception handling
+                                       throw new ParseError.SYNTAX ("syntax error in declaration");
+                               } else {
+                                       Report.error (sym.source_reference, "unexpected declaration in enum");
+                               }
+                       }
+               }
+               expect (TokenType.CLOSE_BRACE);
+
+               Symbol result = en;
+               while (sym.inner != null) {
+                       sym = sym.inner;
+                       var ns = context.create_namespace (sym.name, en.source_reference);
+                       ns.pkg = scanner.source_file.pkg;
+                       if (result is Namespace) {
+                               ns.add_namespace ((Namespace) result);
+                       } else {
+                               ns.add_enum ((Enum) result);
+                               scanner.source_file.add_node (result);
+                       }
+                       result = ns;
+               }
+               return result;
+       }
+
+       Symbol parse_errordomain_declaration (Gee.List<Attribute> attrs) throws ParseError {
+               var begin = get_location ();
+               var access = parse_access_modifier ();
+               parse_type_declaration_modifiers ();
+               expect (TokenType.ERRORDOMAIN);
+               var sym = parse_symbol_name ();
+               var ed = context.create_error_domain (sym.name, get_src_com (begin));
+               ed.access = access;
+               set_attributes (ed, attrs);
+
+               expect (TokenType.OPEN_BRACE);
+               do {
+                       if (current () == TokenType.CLOSE_BRACE) {
+                               // allow trailing comma
+                               break;
+                       }
+                       string id = parse_identifier ();
+                       var ec = context.create_error_code (id);
+                       if (accept (TokenType.ASSIGN)) {
+                               ec.value = parse_expression ();
+                       }
+                       ed.add_code (ec);
+               } while (accept (TokenType.COMMA));
+               if (accept (TokenType.SEMICOLON)) {
+                       // errordomain methods
+                       while (current () != TokenType.CLOSE_BRACE) {
+                               var sym = parse_declaration ();
+                               if (sym is Method) {
+                                       ed.add_method ((Method) sym);
+                               } else if (sym == null) {
+                                       // workaround for current limitation of exception handling
+                                       throw new ParseError.SYNTAX ("syntax error in declaration");
+                               } else {
+                                       Report.error (sym.source_reference, "unexpected declaration in errordomain");
+                               }
+                       }
+               }
+               expect (TokenType.CLOSE_BRACE);
+
+               Symbol result = ed;
+               while (sym.inner != null) {
+                       sym = sym.inner;
+                       var ns = context.create_namespace (sym.name, ed.source_reference);
+                       ns.pkg = scanner.source_file.pkg;
+                       if (result is Namespace) {
+                               ns.add_namespace ((Namespace) result);
+                       } else {
+                               ns.add_error_domain ((ErrorDomain) result);
+                               scanner.source_file.add_node (result);
+                       }
+                       result = ns;
+               }
+               return result;
+       }
+
+       SymbolAccessibility parse_access_modifier (SymbolAccessibility default_access = SymbolAccessibility.PRIVATE) {
+               switch (current ()) {
+               case TokenType.PRIVATE:
+                       next ();
+                       return SymbolAccessibility.PRIVATE;
+               case TokenType.PROTECTED:
+                       next ();
+                       return SymbolAccessibility.PROTECTED;
+               case TokenType.PUBLIC:
+                       next ();
+                       return SymbolAccessibility.PUBLIC;
+               default:
+                       return default_access;
+               }
+       }
+
+       ModifierFlags parse_type_declaration_modifiers () {
+               ModifierFlags flags = 0;
+               while (true) {
+                       switch (current ()) {
+                       case TokenType.ABSTRACT:
+                               next ();
+                               flags |= ModifierFlags.ABSTRACT;
+                               break;
+                       case TokenType.STATIC:
+                               next ();
+                               flags |= ModifierFlags.STATIC;
+                               break;
+                       default:
+                               return flags;
+                       }
+               }
+               return flags;
+       }
+
+       ModifierFlags parse_member_declaration_modifiers () {
+               ModifierFlags flags = 0;
+               while (true) {
+                       switch (current ()) {
+                       case TokenType.ABSTRACT:
+                               next ();
+                               flags |= ModifierFlags.ABSTRACT;
+                               break;
+                       case TokenType.CLASS:
+                               next ();
+                               flags |= ModifierFlags.CLASS;
+                               break;
+                       case TokenType.INLINE:
+                               next ();
+                               flags |= ModifierFlags.INLINE;
+                               break;
+                       case TokenType.OVERRIDE:
+                               next ();
+                               flags |= ModifierFlags.OVERRIDE;
+                               break;
+                       case TokenType.STATIC:
+                               next ();
+                               flags |= ModifierFlags.STATIC;
+                               break;
+                       case TokenType.VIRTUAL:
+                               next ();
+                               flags |= ModifierFlags.VIRTUAL;
+                               break;
+                       default:
+                               return flags;
+                       }
+               }
+               return flags;
+       }
+
+       FormalParameter parse_parameter () throws ParseError {
+               var attrs = parse_attributes ();
+               var begin = get_location ();
+               if (accept (TokenType.ELLIPSIS)) {
+                       // varargs
+                       return context.create_formal_parameter_with_ellipsis (get_src (begin));
+               }
+               bool construct_param = accept (TokenType.CONSTRUCT);
+               var type = parse_type ();
+               var ut = type as UnresolvedType;
+               if (ut != null) {
+                       if (!ut.is_weak) {
+                               ut.takes_ownership = true;
+                       }
+                       if (!ut.is_ref && !ut.is_out && !ut.transfers_ownership) {
+                               //  take_ownership for in parameters that don't transfer ownership is not supported
+                               ut.takes_ownership = false;
+                       }
+               }
+               string id = parse_identifier ();
+               var param = context.create_formal_parameter (id, type, get_src (begin));
+               set_attributes (param, attrs);
+               param.construct_parameter = construct_param;
+               if (accept (TokenType.ASSIGN)) {
+                       param.default_expression = parse_expression ();
+               }
+               return param;
+       }
+
+       CreationMethod parse_creation_method_declaration (Gee.List<Attribute> attrs) throws ParseError {
+               var begin = get_location ();
+               var access = parse_access_modifier ();
+               parse_member_declaration_modifiers ();
+               var sym = parse_symbol_name ();
+               CreationMethod method;
+               if (sym.inner == null) {
+                       method = context.create_creation_method (sym.name, null, get_src_com (begin));
+               } else {
+                       method = context.create_creation_method (sym.inner.name, sym.name, get_src_com (begin));
+               }
+               expect (TokenType.OPEN_PARENS);
+               if (current () != TokenType.CLOSE_PARENS) {
+                       do {
+                               method.add_parameter (parse_parameter ());
+                       } while (accept (TokenType.COMMA));
+               }
+               expect (TokenType.CLOSE_PARENS);
+               if (accept (TokenType.THROWS)) {
+                       do {
+                               method.add_error_domain (parse_type ());
+                       } while (accept (TokenType.COMMA));
+               }
+               method.access = access;
+               set_attributes (method, attrs);
+               method.instance = false;
+               if (!accept (TokenType.SEMICOLON)) {
+                       method.body = parse_block ();
+               }
+               return method;
+       }
+
+       Symbol parse_delegate_declaration (Gee.List<Attribute> attrs) throws ParseError {
+               var begin = get_location ();
+               var access = parse_access_modifier ();
+               var flags = parse_member_declaration_modifiers ();
+               expect (TokenType.DELEGATE);
+               var type = parse_type ();
+               var sym = parse_symbol_name ();
+               var type_param_list = parse_type_parameter_list ();
+               var d = context.create_delegate (sym.name, type, get_src_com (begin));
+               d.access = access;
+               set_attributes (d, attrs);
+               if (!(ModifierFlags.STATIC in flags)) {
+                       d.instance = true;
+               }
+               foreach (TypeParameter type_param in type_param_list) {
+                       d.add_type_parameter (type_param);
+               }
+               expect (TokenType.OPEN_PARENS);
+               if (current () != TokenType.CLOSE_PARENS) {
+                       do {
+                               d.add_parameter (parse_parameter ());
+                       } while (accept (TokenType.COMMA));
+               }
+               expect (TokenType.CLOSE_PARENS);
+               if (accept (TokenType.THROWS)) {
+                       do {
+                               parse_type ();
+                       } while (accept (TokenType.COMMA));
+               }
+               expect (TokenType.SEMICOLON);
+
+               Symbol result = d;
+               while (sym.inner != null) {
+                       sym = sym.inner;
+                       var ns = context.create_namespace (sym.name, d.source_reference);
+                       ns.pkg = scanner.source_file.pkg;
+                       if (result is Namespace) {
+                               ns.add_namespace ((Namespace) result);
+                       } else {
+                               ns.add_delegate ((Delegate) result);
+                               scanner.source_file.add_node (result);
+                       }
+                       result = ns;
+               }
+               return result;
+       }
+
+       Gee.List<TypeParameter> parse_type_parameter_list () throws ParseError {
+               var list = new ArrayList<TypeParameter> ();
+               if (accept (TokenType.OP_LT)) {
+                       do {
+                               var begin = get_location ();
+                               string id = parse_identifier ();
+                               list.add (context.create_type_parameter (id, get_src (begin)));
+                       } while (accept (TokenType.COMMA));
+                       expect (TokenType.OP_GT);
+               }
+               return list;
+       }
+
+       void skip_type_argument_list () throws ParseError {
+               if (accept (TokenType.OP_LT)) {
+                       do {
+                               skip_type ();
+                       } while (accept (TokenType.COMMA));
+                       expect (TokenType.OP_GT);
+               }
+       }
+
+       // try to parse type argument list
+       Gee.List<DataType> parse_type_argument_list (bool maybe_expression) throws ParseError {
+               var begin = get_location ();
+               if (accept (TokenType.OP_LT)) {
+                       var list = new ArrayList<DataType> ();
+                       do {
+                               switch (current ()) {
+                               case TokenType.VOID:
+                               case TokenType.WEAK:
+                               case TokenType.IDENTIFIER:
+                                       var type = parse_type ();
+                                       if (!((UnresolvedType) type).is_weak) {
+                                               type.takes_ownership = true;
+                                       }
+                                       list.add (type);
+                                       break;
+                               default:
+                                       rollback (begin);
+                                       return null;
+                               }
+                       } while (accept (TokenType.COMMA));
+                       if (!accept (TokenType.OP_GT)) {
+                               rollback (begin);
+                               return null;
+                       }
+                       if (maybe_expression) {
+                               // check follower to decide whether to keep type argument list
+                               switch (current ()) {
+                               case TokenType.OPEN_PARENS:
+                               case TokenType.CLOSE_PARENS:
+                               case TokenType.CLOSE_BRACKET:
+                               case TokenType.COLON:
+                               case TokenType.SEMICOLON:
+                               case TokenType.COMMA:
+                               case TokenType.DOT:
+                               case TokenType.INTERR:
+                               case TokenType.OP_EQ:
+                               case TokenType.OP_NE:
+                                       // keep type argument list
+                                       break;
+                               default:
+                                       // interpret tokens as expression
+                                       rollback (begin);
+                                       return null;
+                               }
+                       }
+                       return list;
+               }
+               return null;
+       }
+
+       MemberAccess parse_member_name () throws ParseError {
+               var begin = get_location ();
+               MemberAccess expr = null;
+               do {
+                       string id = parse_identifier ();
+                       var type_arg_list = parse_type_argument_list (false);
+                       expr = context.create_member_access (expr, id, get_src (begin));
+                       if (type_arg_list != null) {
+                               foreach (DataType type_arg in type_arg_list) {
+                                       expr.add_type_argument (type_arg);
+                               }
+                       }
+               } while (accept (TokenType.DOT));
+               return expr;
+       }
+
+       bool is_declaration_keyword (TokenType type) {
+               switch (type) {
+               case TokenType.ABSTRACT:
+               case TokenType.CLASS:
+               case TokenType.CONST:
+               case TokenType.DELEGATE:
+               case TokenType.ENUM:
+               case TokenType.ERRORDOMAIN:
+               case TokenType.INLINE:
+               case TokenType.INTERFACE:
+               case TokenType.NAMESPACE:
+               case TokenType.OVERRIDE:
+               case TokenType.PRIVATE:
+               case TokenType.PROTECTED:
+               case TokenType.PUBLIC:
+               case TokenType.SIGNAL:
+               case TokenType.STATIC:
+               case TokenType.STRUCT:
+               case TokenType.VIRTUAL:
+               case TokenType.VOLATILE:
+                       return true;
+               default:
+                       return false;
+               }
+       }
 }
+
+public errordomain Vala.ParseError {
+       FAILED,
+       SYNTAX
+}
+
diff --git a/vala/valascanner.vala b/vala/valascanner.vala
new file mode 100644 (file)
index 0000000..761a89f
--- /dev/null
@@ -0,0 +1,774 @@
+/* valascanner.vala
+ *
+ * Copyright (C) 2008  Jürg Billeter
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301  USA
+ *
+ * Author:
+ *     Jürg Billeter <j@bitron.ch>
+ */
+
+using GLib;
+using Gee;
+
+/**
+ * Lexical scanner for Vala source files.
+ */
+public class Vala.Scanner : Object {
+       public SourceFile source_file { get; construct; }
+
+       char* begin;
+       char* current;
+       char* end;
+
+       int line;
+       int column;
+
+       string _comment;
+
+       public Scanner (SourceFile source_file) {
+               this.source_file = source_file;
+       }
+       
+       construct {
+               begin = source_file.get_mapped_contents ();
+               end = begin + source_file.get_mapped_length ();
+
+               current = begin;
+
+               line = 1;
+               column = 1;
+       }
+
+       bool is_ident_char (char c) {
+               return (c.isalnum () || c == '_');
+       }
+
+       TokenType get_identifier_or_keyword (char* begin, int len) {
+               switch (len) {
+               case 2:
+                       switch (begin[0]) {
+                       case 'a':
+                               if (matches (begin, "as")) return TokenType.AS;
+                               break;
+                       case 'd':
+                               if (matches (begin, "do")) return TokenType.DO;
+                               break;
+                       case 'i':
+                               switch (begin[1]) {
+                               case 'f':
+                                       return TokenType.IF;
+                               case 'n':
+                                       return TokenType.IN;
+                               case 's':
+                                       return TokenType.IS;
+                               }
+                               break;
+                       }
+                       break;
+               case 3:
+                       switch (begin[0]) {
+                       case 'f':
+                               if (matches (begin, "for")) return TokenType.FOR;
+                               break;
+                       case 'g':
+                               if (matches (begin, "get")) return TokenType.GET;
+                               break;
+                       case 'n':
+                               if (matches (begin, "new")) return TokenType.NEW;
+                               break;
+                       case 'o':
+                               if (matches (begin, "out")) return TokenType.OUT;
+                               break;
+                       case 'r':
+                               if (matches (begin, "ref")) return TokenType.REF;
+                               break;
+                       case 's':
+                               if (matches (begin, "set")) return TokenType.SET;
+                               break;
+                       case 't':
+                               if (matches (begin, "try")) return TokenType.TRY;
+                               break;
+                       case 'v':
+                               if (matches (begin, "var")) return TokenType.VAR;
+                               break;
+                       }
+                       break;
+               case 4:
+                       switch (begin[0]) {
+                       case 'b':
+                               if (matches (begin, "base")) return TokenType.BASE;
+                               break;
+                       case 'c':
+                               if (matches (begin, "case")) return TokenType.CASE;
+                               break;
+                       case 'e':
+                               switch (begin[1]) {
+                               case 'l':
+                                       if (matches (begin, "else")) return TokenType.ELSE;
+                                       break;
+                               case 'n':
+                                       if (matches (begin, "enum")) return TokenType.ENUM;
+                                       break;
+                               }
+                               break;
+                       case 'l':
+                               if (matches (begin, "lock")) return TokenType.LOCK;
+                               break;
+                       case 'n':
+                               if (matches (begin, "null")) return TokenType.NULL;
+                               break;
+                       case 't':
+                               switch (begin[1]) {
+                               case 'h':
+                                       if (matches (begin, "this")) return TokenType.THIS;
+                                       break;
+                               case 'r':
+                                       if (matches (begin, "true")) return TokenType.TRUE;
+                                       break;
+                               }
+                               break;
+                       case 'v':
+                               if (matches (begin, "void")) return TokenType.VOID;
+                               break;
+                       case 'w':
+                               if (matches (begin, "weak")) return TokenType.WEAK;
+                               break;
+                       }
+                       break;
+               case 5:
+                       switch (begin[0]) {
+                       case 'b':
+                               if (matches (begin, "break")) return TokenType.BREAK;
+                               break;
+                       case 'c':
+                               switch (begin[1]) {
+                               case 'a':
+                                       if (matches (begin, "catch")) return TokenType.CATCH;
+                                       break;
+                               case 'l':
+                                       if (matches (begin, "class")) return TokenType.CLASS;
+                                       break;
+                               case 'o':
+                                       if (matches (begin, "const")) return TokenType.CONST;
+                                       break;
+                               }
+                               break;
+                       case 'f':
+                               if (matches (begin, "false")) return TokenType.FALSE;
+                               break;
+                       case 't':
+                               if (matches (begin, "throw")) return TokenType.THROW;
+                               break;
+                       case 'u':
+                               if (matches (begin, "using")) return TokenType.USING;
+                               break;
+                       case 'w':
+                               if (matches (begin, "while")) return TokenType.WHILE;
+                               break;
+                       }
+                       break;
+               case 6:
+                       switch (begin[0]) {
+                       case 'd':
+                               if (matches (begin, "delete")) return TokenType.DELETE;
+                               break;
+                       case 'i':
+                               if (matches (begin, "inline")) return TokenType.INLINE;
+                               break;
+                       case 'p':
+                               if (matches (begin, "public")) return TokenType.PUBLIC;
+                               break;
+                       case 'r':
+                               if (matches (begin, "return")) return TokenType.RETURN;
+                               break;
+                       case 's':
+                               switch (begin[1]) {
+                               case 'i':
+                                       switch (begin[2]) {
+                                       case 'g':
+                                               if (matches (begin, "signal")) return TokenType.SIGNAL;
+                                               break;
+                                       case 'z':
+                                               if (matches (begin, "sizeof")) return TokenType.SIZEOF;
+                                               break;
+                                       }
+                                       break;
+                               case 't':
+                                       switch (begin[2]) {
+                                       case 'a':
+                                               if (matches (begin, "static")) return TokenType.STATIC;
+                                               break;
+                                       case 'r':
+                                               if (matches (begin, "struct")) return TokenType.STRUCT;
+                                               break;
+                                       }
+                                       break;
+                               case 'w':
+                                       if (matches (begin, "switch")) return TokenType.SWITCH;
+                                       break;
+                               }
+                               break;
+                       case 't':
+                               switch (begin[1]) {
+                               case 'h':
+                                       if (matches (begin, "throws")) return TokenType.THROWS;
+                                       break;
+                               case 'y':
+                                       if (matches (begin, "typeof")) return TokenType.TYPEOF;
+                                       break;
+                               }
+                               break;
+                       }
+                       break;
+               case 7:
+                       switch (begin[0]) {
+                       case 'd':
+                               if (matches (begin, "default")) return TokenType.DEFAULT;
+                               break;
+                       case 'e':
+                               if (matches (begin, "ensures")) return TokenType.ENSURES;
+                               break;
+                       case 'f':
+                               switch (begin[1]) {
+                               case 'i':
+                                       if (matches (begin, "finally")) return TokenType.FINALLY;
+                                       break;
+                               case 'o':
+                                       if (matches (begin, "foreach")) return TokenType.FOREACH;
+                                       break;
+                               }
+                               break;
+                       case 'p':
+                               if (matches (begin, "private")) return TokenType.PRIVATE;
+                               break;
+                       case 'v':
+                               if (matches (begin, "virtual")) return TokenType.VIRTUAL;
+                               break;
+                       }
+                       break;
+               case 8:
+                       switch (begin[0]) {
+                       case 'a':
+                               if (matches (begin, "abstract")) return TokenType.ABSTRACT;
+                               break;
+                       case 'c':
+                               if (matches (begin, "continue")) return TokenType.CONTINUE;
+                               break;
+                       case 'd':
+                               if (matches (begin, "delegate")) return TokenType.DELEGATE;
+                               break;
+                       case 'o':
+                               if (matches (begin, "override")) return TokenType.OVERRIDE;
+                               break;
+                       case 'r':
+                               if (matches (begin, "requires")) return TokenType.REQUIRES;
+                               break;
+                       case 'v':
+                               if (matches (begin, "volatile")) return TokenType.VOLATILE;
+                               break;
+                       }
+                       break;
+               case 9:
+                       switch (begin[0]) {
+                       case 'c':
+                               if (matches (begin, "construct")) return TokenType.CONSTRUCT;
+                               break;
+                       case 'i':
+                               if (matches (begin, "interface")) return TokenType.INTERFACE;
+                               break;
+                       case 'n':
+                               if (matches (begin, "namespace")) return TokenType.NAMESPACE;
+                               break;
+                       case 'p':
+                               if (matches (begin, "protected")) return TokenType.PROTECTED;
+                               break;
+                       }
+                       break;
+               case 11:
+                       if (matches (begin, "errordomain")) return TokenType.ERRORDOMAIN;
+                       break;
+               }
+               return TokenType.IDENTIFIER;
+       }
+
+       public TokenType read_token (out SourceLocation token_begin, out SourceLocation token_end) {
+               space ();
+
+               TokenType type;
+               char* begin = current;
+               token_begin.pos = begin;
+               token_begin.line = line;
+               token_begin.column = column;
+
+               int token_length_in_chars = -1;
+
+               if (current >= end) {
+                       type = TokenType.EOF;
+               } else if (current[0].isalpha () || current[0] == '_') {
+                       int len = 0;
+                       while (current < end && is_ident_char (current[0])) {
+                               current++;
+                               len++;
+                       }
+                       type = get_identifier_or_keyword (begin, len);
+               } else if (current[0] == '@') {
+                       token_begin.pos++; // @ is not part of the identifier
+                       current++;
+                       int len = 0;
+                       while (current < end && is_ident_char (current[0])) {
+                               current++;
+                               len++;
+                       }
+                       type = TokenType.IDENTIFIER;
+               } else if (current[0].isdigit ()) {
+                       while (current < end && current[0].isdigit ()) {
+                               current++;
+                       }
+                       type = TokenType.INTEGER_LITERAL;
+                       if (current < end && current[0].tolower () == 'l') {
+                               current++;
+                               if (current < end && current[0].tolower () == 'l') {
+                                       current++;
+                               }
+                       } else if (current < end && current[0].tolower () == 'u') {
+                               current++;
+                               if (current < end && current[0].tolower () == 'l') {
+                                       current++;
+                                       if (current < end && current[0].tolower () == 'l') {
+                                               current++;
+                                       }
+                               }
+                       } else if (current < end && current[0] == '.') {
+                               current++;
+                               while (current < end && current[0].isdigit ()) {
+                                       current++;
+                               }
+                               if (current < end && current[0].tolower () == 'e') {
+                                       current++;
+                                       if (current < end && (current[0] == '+' || current[0] == '-')) {
+                                               current++;
+                                       }
+                                       while (current < end && current[0].isdigit ()) {
+                                               current++;
+                                       }
+                               }
+                               if (current < end && current[0].tolower () == 'f') {
+                                       current++;
+                               }
+                               type = TokenType.REAL_LITERAL;
+                       } else if (current < end && current == begin + 1
+                                  && begin[0] == '0' && begin[1] == 'x' && begin[2].isxdigit ()) {
+                               // hexadecimal integer literal
+                               current++;
+                               while (current < end && current[0].isxdigit ()) {
+                                       current++;
+                               }
+                       } else if (current < end && is_ident_char (current[0])) {
+                               // allow identifiers to start with a digit
+                               // as long as they contain at least one char
+                               while (current < end && is_ident_char (current[0])) {
+                                       current++;
+                               }
+                               type = TokenType.IDENTIFIER;
+                       }
+               } else {
+                       switch (current[0]) {
+                       case '{':
+                               type = TokenType.OPEN_BRACE;
+                               current++;
+                               break;
+                       case '}':
+                               type = TokenType.CLOSE_BRACE;
+                               current++;
+                               break;
+                       case '(':
+                               type = TokenType.OPEN_PARENS;
+                               current++;
+                               break;
+                       case ')':
+                               type = TokenType.CLOSE_PARENS;
+                               current++;
+                               break;
+                       case '[':
+                               type = TokenType.OPEN_BRACKET;
+                               current++;
+                               break;
+                       case ']':
+                               type = TokenType.CLOSE_BRACKET;
+                               current++;
+                               break;
+                       case '.':
+                               type = TokenType.DOT;
+                               current++;
+                               if (current < end - 1) {
+                                       if (current[0] == '.' && current[1] == '.') {
+                                               type = TokenType.ELLIPSIS;
+                                               current += 2;
+                                       }
+                               }
+                               break;
+                       case ':':
+                               type = TokenType.COLON;
+                               current++;
+                               break;
+                       case ',':
+                               type = TokenType.COMMA;
+                               current++;
+                               break;
+                       case ';':
+                               type = TokenType.SEMICOLON;
+                               current++;
+                               break;
+                       case '#':
+                               type = TokenType.HASH;
+                               current++;
+                               break;
+                       case '?':
+                               type = TokenType.INTERR;
+                               current++;
+                               break;
+                       case '|':
+                               type = TokenType.BITWISE_OR;
+                               current++;
+                               if (current < end) {
+                                       switch (current[0]) {
+                                       case '=':
+                                               type = TokenType.ASSIGN_BITWISE_OR;
+                                               current++;
+                                               break;
+                                       case '|':
+                                               type = TokenType.OP_OR;
+                                               current++;
+                                               break;
+                                       }
+                               }
+                               break;
+                       case '&':
+                               type = TokenType.BITWISE_AND;
+                               current++;
+                               if (current < end) {
+                                       switch (current[0]) {
+                                       case '=':
+                                               type = TokenType.ASSIGN_BITWISE_AND;
+                                               current++;
+                                               break;
+                                       case '&':
+                                               type = TokenType.OP_AND;
+                                               current++;
+                                               break;
+                                       }
+                               }
+                               break;
+                       case '^':
+                               type = TokenType.CARRET;
+                               current++;
+                               if (current < end && current[0] == '=') {
+                                       type = TokenType.ASSIGN_BITWISE_XOR;
+                                       current++;
+                               }
+                               break;
+                       case '~':
+                               type = TokenType.TILDE;
+                               current++;
+                               break;
+                       case '=':
+                               type = TokenType.ASSIGN;
+                               current++;
+                               if (current < end) {
+                                       switch (current[0]) {
+                                       case '=':
+                                               type = TokenType.OP_EQ;
+                                               current++;
+                                               break;
+                                       case '>':
+                                               type = TokenType.LAMBDA;
+                                               current++;
+                                               break;
+                                       }
+                               }
+                               break;
+                       case '<':
+                               type = TokenType.OP_LT;
+                               current++;
+                               if (current < end) {
+                                       switch (current[0]) {
+                                       case '=':
+                                               type = TokenType.OP_LE;
+                                               current++;
+                                               break;
+                                       case '<':
+                                               type = TokenType.OP_SHIFT_LEFT;
+                                               current++;
+                                               if (current < end && current[0] == '=') {
+                                                       type = TokenType.ASSIGN_SHIFT_LEFT;
+                                                       current++;
+                                               }
+                                               break;
+                                       }
+                               }
+                               break;
+                       case '>':
+                               type = TokenType.OP_GT;
+                               current++;
+                               if (current < end && current[0] == '=') {
+                                       type = TokenType.OP_GE;
+                                       current++;
+                               }
+                               break;
+                       case '!':
+                               type = TokenType.OP_NEG;
+                               current++;
+                               if (current < end && current[0] == '=') {
+                                       type = TokenType.OP_NE;
+                                       current++;
+                               }
+                               break;
+                       case '+':
+                               type = TokenType.PLUS;
+                               current++;
+                               if (current < end) {
+                                       switch (current[0]) {
+                                       case '=':
+                                               type = TokenType.ASSIGN_ADD;
+                                               current++;
+                                               break;
+                                       case '+':
+                                               type = TokenType.OP_INC;
+                                               current++;
+                                               break;
+                                       }
+                               }
+                               break;
+                       case '-':
+                               type = TokenType.MINUS;
+                               current++;
+                               if (current < end) {
+                                       switch (current[0]) {
+                                       case '=':
+                                               type = TokenType.ASSIGN_SUB;
+                                               current++;
+                                               break;
+                                       case '-':
+                                               type = TokenType.OP_DEC;
+                                               current++;
+                                               break;
+                                       case '>':
+                                               type = TokenType.OP_PTR;
+                                               current++;
+                                               break;
+                                       }
+                               }
+                               break;
+                       case '*':
+                               type = TokenType.STAR;
+                               current++;
+                               if (current < end && current[0] == '=') {
+                                       type = TokenType.ASSIGN_MUL;
+                                       current++;
+                               }
+                               break;
+                       case '/':
+                               type = TokenType.DIV;
+                               current++;
+                               if (current < end && current[0] == '=') {
+                                       type = TokenType.ASSIGN_DIV;
+                                       current++;
+                               }
+                               break;
+                       case '%':
+                               type = TokenType.PERCENT;
+                               current++;
+                               if (current < end && current[0] == '=') {
+                                       type = TokenType.ASSIGN_PERCENT;
+                                       current++;
+                               }
+                               break;
+                       case '\'':
+                       case '"':
+                               if (begin[0] == '\'') {
+                                       type = TokenType.CHARACTER_LITERAL;
+                               } else {
+                                       type = TokenType.STRING_LITERAL;
+                               }
+                               token_length_in_chars = 2;
+                               current++;
+                               while (current < end && current[0] != begin[0]) {
+                                       if (current[0] == '\\') {
+                                               current++;
+                                               token_length_in_chars++;
+                                               if (current < end && current[0] == 'x') {
+                                                       // hexadecimal escape character
+                                                       current++;
+                                                       token_length_in_chars++;
+                                                       while (current < end && current[0].isxdigit ()) {
+                                                               current++;
+                                                               token_length_in_chars++;
+                                                       }
+                                               } else {
+                                                       current++;
+                                                       token_length_in_chars++;
+                                               }
+                                       } else if (current[0] == '\n') {
+                                               break;
+                                       } else {
+                                               unichar u = ((string) current).get_char_validated ((long) (end - current));
+                                               if (u != (unichar) (-1)) {
+                                                       current += u.to_utf8 (null);
+                                                       token_length_in_chars++;
+                                               } else {
+                                                       Report.error (new SourceReference (source_file, line, column + token_length_in_chars, line, column + token_length_in_chars), "invalid UTF-8 character");
+                                               }
+                                       }
+                               }
+                               if (current < end && current[0] != '\n') {
+                                       current++;
+                               } else {
+                                       Report.error (new SourceReference (source_file, line, column + token_length_in_chars, line, column + token_length_in_chars), "syntax error, expected %c".printf (begin[0]));
+                               }
+                               break;
+                       default:
+                               unichar u = ((string) current).get_char_validated ((long) (end - current));
+                               if (u != (unichar) (-1)) {
+                                       current += u.to_utf8 (null);
+                                       Report.error (new SourceReference (source_file, line, column, line, column), "syntax error, unexpected character");
+                               } else {
+                                       current++;
+                                       Report.error (new SourceReference (source_file, line, column, line, column), "invalid UTF-8 character");
+                               }
+                               column++;
+                               return read_token (out token_begin, out token_end);
+                       }
+               }
+
+               if (token_length_in_chars < 0) {
+                       column += (int) (current - begin);
+               } else {
+                       column += token_length_in_chars;
+               }
+
+               token_end.pos = current;
+               token_end.line = line;
+               token_end.column = column - 1;
+
+               return type;
+       }
+
+       bool matches (char* begin, string keyword) {
+               char* keyword_array = keyword;
+               long len = keyword.len ();
+               for (int i = 0; i < len; i++) {
+                       if (begin[i] != keyword_array[i]) {
+                               return false;
+                       }
+               }
+               return true;
+       }
+
+       bool whitespace () {
+               bool found = false;
+               while (current < end && current[0].isspace ()) {
+                       if (current[0] == '\n') {
+                               line++;
+                               column = 0;
+                       }
+                       found = true;
+                       current++;
+                       column++;
+               }
+               return found;
+       }
+
+       bool comment () {
+               if (current > end - 2
+                   || current[0] != '/'
+                   || (current[1] != '/' && current[1] != '*')) {
+                       return false;
+               }
+
+               if (current[1] == '/') {
+                       // single-line comment
+                       current += 2;
+                       char* begin = current;
+                       // skip until end of line or end of file
+                       while (current < end && current[0] != '\n') {
+                               current++;
+                       }
+                       push_comment (((string) begin).ndup ((long) (current - begin)), line == 1);
+               } else {
+                       // delimited comment
+                       current += 2;
+                       char* begin = current;
+                       int begin_line = line;
+                       while (current < end - 1
+                              && (current[0] != '*' || current[1] != '/')) {
+                               if (current[0] == '\n') {
+                                       line++;
+                                       column = 0;
+                               }
+                               current++;
+                               column++;
+                       }
+                       if (current == end - 1) {
+                               Report.error (new SourceReference (source_file, line, column, line, column), "syntax error, expected */");
+                               return true;
+                       }
+                       push_comment (((string) begin).ndup ((long) (current - begin)), begin_line == 1);
+                       current += 2;
+                       column += 2;
+               }
+
+               return true;
+       }
+
+       void space () {
+               while (whitespace () || comment ()) {
+               }
+       }
+
+       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) {
+                       source_file.comment = _comment;
+                       _comment = null;
+               }
+       }
+       
+       /**
+        * Clears and returns the content of the comment stack.
+        *
+        * @return saved comment
+        */
+       public string pop_comment () {
+               if (_comment == null) {
+                       return null;
+               }
+               
+               var result = new StringBuilder (_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;
+       }
+}
+
index a223ba4..d2ae791 100644 (file)
@@ -60,7 +60,7 @@ public class Vala.Scope : Object {
                                symbol_table = new HashMap<string,Symbol> (str_hash, str_equal);
                        } else if (lookup (name) != null) {
                                owner.error = true;
-                               Report.error (owner.source_reference, "`%s' already contains a definition for `%s'".printf (owner.get_full_name (), name));
+                               Report.error (sym.source_reference, "`%s' already contains a definition for `%s'".printf (owner.get_full_name (), name));
                                return;
                        }
 
@@ -68,7 +68,11 @@ public class Vala.Scope : Object {
                }
                sym.owner = this;
        }
-       
+
+       public void remove (string name) {
+               symbol_table.remove (name);
+       }
+
        /**
         * Returns the symbol stored in the symbol table with the specified
         * name.
index db955a6..ddb7aef 100644 (file)
@@ -87,6 +87,8 @@ public class Vala.SourceFile : Object {
 
        private Gee.ArrayList<string> source_array = null;
 
+       private MappedFile mapped_file = null;
+
        /**
         * Creates a new source file.
         *
@@ -124,6 +126,10 @@ public class Vala.SourceFile : Object {
                nodes.add (node);
        }
 
+       public void remove_node (CodeNode! node) {
+               nodes.remove (node);
+       }
+
        /**
         * Returns a copy of the list of code nodes.
         *
@@ -396,6 +402,17 @@ public class Vala.SourceFile : Object {
                }
        }
 
+       public char* get_mapped_contents () {
+               if (mapped_file == null) {
+                       mapped_file = new MappedFile (filename, false);
+               }
+
+               return mapped_file.get_contents ();
+       }
+       
+       public size_t get_mapped_length () {
+               return mapped_file.get_length ();
+       }
 }
 
 public enum Vala.SourceFileDependencyType {
diff --git a/vala/valasourcelocation.vala b/vala/valasourcelocation.vala
new file mode 100644 (file)
index 0000000..374a683
--- /dev/null
@@ -0,0 +1,39 @@
+/* valasourcelocation.vala
+ *
+ * Copyright (C) 2008  Jürg Billeter
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301  USA
+ *
+ * Author:
+ *     Jürg Billeter <j@bitron.ch>
+ */
+
+using GLib;
+
+/**
+ * Represents a position in a source file.
+ */
+public struct Vala.SourceLocation {
+       public char* pos;
+       public int line;
+       public int column;
+
+       public SourceLocation (char* _pos, int _line, int _column) {
+               pos = _pos;
+               line = _line;
+               column = _column;
+       }
+}
+
diff --git a/vala/valatokentype.vala b/vala/valatokentype.vala
new file mode 100644 (file)
index 0000000..5a50847
--- /dev/null
@@ -0,0 +1,256 @@
+/* valatokentype.vala
+ *
+ * Copyright (C) 2008  Jürg Billeter
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301  USA
+ *
+ * Author:
+ *     Jürg Billeter <j@bitron.ch>
+ */
+
+using GLib;
+
+public enum Vala.TokenType {
+       NONE,
+       ABSTRACT,
+       AS,
+       ASSIGN,
+       ASSIGN_ADD,
+       ASSIGN_BITWISE_AND,
+       ASSIGN_BITWISE_OR,
+       ASSIGN_BITWISE_XOR,
+       ASSIGN_DIV,
+       ASSIGN_MUL,
+       ASSIGN_PERCENT,
+       ASSIGN_SHIFT_LEFT,
+       ASSIGN_SUB,
+       BASE,
+       BITWISE_AND,
+       BITWISE_OR,
+       BREAK,
+       CARRET,
+       CASE,
+       CATCH,
+       CHARACTER_LITERAL,
+       CLASS,
+       CLOSE_BRACE,
+       CLOSE_BRACKET,
+       CLOSE_PARENS,
+       COLON,
+       COMMA,
+       CONST,
+       CONSTRUCT,
+       CONTINUE,
+       DEFAULT,
+       DELEGATE,
+       DELETE,
+       DIV,
+       DO,
+       DOT,
+       ELLIPSIS,
+       ELSE,
+       ENUM,
+       ENSURES,
+       ERRORDOMAIN,
+       EOF,
+       FALSE,
+       FINALLY,
+       FOR,
+       FOREACH,
+       GET,
+       HASH,
+       IDENTIFIER,
+       IF,
+       IN,
+       INLINE,
+       INTEGER_LITERAL,
+       INTERFACE,
+       INTERR,
+       IS,
+       LAMBDA,
+       LOCK,
+       MINUS,
+       NAMESPACE,
+       NEW,
+       NULL,
+       OUT,
+       OP_AND,
+       OP_DEC,
+       OP_EQ,
+       OP_GE,
+       OP_GT,
+       OP_INC,
+       OP_LE,
+       OP_LT,
+       OP_NE,
+       OP_NEG,
+       OP_OR,
+       OP_PTR,
+       OP_SHIFT_LEFT,
+       OPEN_BRACE,
+       OPEN_BRACKET,
+       OPEN_PARENS,
+       OVERRIDE,
+       PERCENT,
+       PLUS,
+       PRIVATE,
+       PROTECTED,
+       PUBLIC,
+       REAL_LITERAL,
+       REF,
+       REQUIRES,
+       RETURN,
+       SEMICOLON,
+       SET,
+       SIGNAL,
+       SIZEOF,
+       STAR,
+       STATIC,
+       STRING_LITERAL,
+       STRUCT,
+       SWITCH,
+       THIS,
+       THROW,
+       THROWS,
+       TILDE,
+       TRUE,
+       TRY,
+       TYPEOF,
+       USING,
+       VAR,
+       VIRTUAL,
+       VOID,
+       VOLATILE,
+       WEAK,
+       WHILE;
+
+       public weak string to_string () {
+               switch (this) {
+               case ABSTRACT: return "`abstract'";
+               case AS: return "`as'";
+               case ASSIGN: return "`='";
+               case ASSIGN_ADD: return "`+='";
+               case ASSIGN_BITWISE_AND: return "`&='";
+               case ASSIGN_BITWISE_OR: return "`|='";
+               case ASSIGN_BITWISE_XOR: return "`^='";
+               case ASSIGN_DIV: return "`/='";
+               case ASSIGN_MUL: return "`*='";
+               case ASSIGN_PERCENT: return "`%='";
+               case ASSIGN_SHIFT_LEFT: return "`<<='";
+               case ASSIGN_SUB: return "`-='";
+               case BASE: return "`base'";
+               case BITWISE_AND: return "`&'";
+               case BITWISE_OR: return "`|'";
+               case BREAK: return "`break'";
+               case CARRET: return "`^'";
+               case CASE: return "`case'";
+               case CATCH: return "`catch'";
+               case CHARACTER_LITERAL: return "character literal";
+               case CLASS: return "`class'";
+               case CLOSE_BRACE: return "`}'";
+               case CLOSE_BRACKET: return "`]'";
+               case CLOSE_PARENS: return "`)'";
+               case COLON: return "`:'";
+               case COMMA: return "`,'";
+               case CONST: return "`const'";
+               case CONSTRUCT: return "`construct'";
+               case CONTINUE: return "`continue'";
+               case DEFAULT: return "`default'";
+               case DELEGATE: return "`delegate'";
+               case DELETE: return "`delete'";
+               case DIV: return "`/'";
+               case DO: return "`do'";
+               case DOT: return "`.'";
+               case ELLIPSIS: return "`...'";
+               case ELSE: return "`else'";
+               case ENUM: return "`enum'";
+               case ENSURES: return "`ensures'";
+               case ERRORDOMAIN: return "`errordomain'";
+               case EOF: return "end of file";
+               case FALSE: return "`false'";
+               case FINALLY: return "`finally'";
+               case FOR: return "`for'";
+               case FOREACH: return "`foreach'";
+               case GET: return "`get'";
+               case HASH: return "`hash'";
+               case IDENTIFIER: return "identifier";
+               case IF: return "`if'";
+               case IN: return "`in'";
+               case INLINE: return "`inline'";
+               case INTEGER_LITERAL: return "integer literal";
+               case INTERFACE: return "`interface'";
+               case INTERR: return "`?'";
+               case IS: return "`is'";
+               case LAMBDA: return "`=>'";
+               case LOCK: return "`lock'";
+               case MINUS: return "`-'";
+               case NAMESPACE: return "`namespace'";
+               case NEW: return "`new'";
+               case NULL: return "`null'";
+               case OUT: return "`out'";
+               case OP_AND: return "`&&'";
+               case OP_DEC: return "`--'";
+               case OP_EQ: return "`=='";
+               case OP_GE: return "`>='";
+               case OP_GT: return "`>'";
+               case OP_INC: return "`++'";
+               case OP_LE: return "`<='";
+               case OP_LT: return "`<'";
+               case OP_NE: return "`!='";
+               case OP_NEG: return "`!'";
+               case OP_OR: return "`||'";
+               case OP_PTR: return "`->'";
+               case OP_SHIFT_LEFT: return "`<<'";
+               case OPEN_BRACE: return "`{'";
+               case OPEN_BRACKET: return "`['";
+               case OPEN_PARENS: return "`('";
+               case OVERRIDE: return "`override'";
+               case PERCENT: return "`%'";
+               case PLUS: return "`+'";
+               case PRIVATE: return "`private'";
+               case PROTECTED: return "`protected'";
+               case PUBLIC: return "`public'";
+               case REAL_LITERAL: return "real literal";
+               case REF: return "`ref'";
+               case REQUIRES: return "`requires'";
+               case RETURN: return "`return'";
+               case SEMICOLON: return "`;'";
+               case SET: return "`set'";
+               case SIGNAL: return "`signal'";
+               case SIZEOF: return "`sizeof'";
+               case STAR: return "`*'";
+               case STATIC: return "`static'";
+               case STRING_LITERAL: return "string literal";
+               case STRUCT: return "`struct'";
+               case SWITCH: return "`switch'";
+               case THIS: return "`this'";
+               case THROW: return "`throw'";
+               case THROWS: return "`throws'";
+               case TILDE: return "`~'";
+               case TRUE: return "`true'";
+               case TRY: return "`try'";
+               case TYPEOF: return "`typeof'";
+               case USING: return "`using'";
+               case VAR: return "`var'";
+               case VIRTUAL: return "`virtual'";
+               case VOID: return "`void'";
+               case VOLATILE: return "`volatile'";
+               case WEAK: return "`weak'";
+               case WHILE: return "`while'";
+               default: return "unknown token";
+               }
+       }
+}
+
diff --git a/vala/valatuple.vala b/vala/valatuple.vala
new file mode 100644 (file)
index 0000000..fc05984
--- /dev/null
@@ -0,0 +1,47 @@
+/* valatuple.vala
+ *
+ * Copyright (C) 2006-2008  Jürg Billeter
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301  USA
+ *
+ * Author:
+ *     Jürg Billeter <j@bitron.ch>
+ */
+
+using GLib;
+using Gee;
+
+/**
+ * Represents a fixed-length sequence of expressions in the source code.
+ */
+public class Vala.Tuple : Expression {
+       private Gee.List<Expression> expression_list = new ArrayList<Expression> ();
+
+       public Tuple () {
+       }
+
+       public void add_expression (Expression expr) {
+               expression_list.add (expr);
+       }
+
+       public Gee.List<Expression> get_expressions () {
+               return expression_list;
+       }
+
+       public override bool is_pure () {
+               return false;
+       }
+}
+
index 5b34458..cc6c964 100644 (file)
@@ -103,6 +103,7 @@ public class Vala.UnaryExpression : Expression {
 }
 
 public enum Vala.UnaryOperator {
+       NONE,
        PLUS,
        MINUS,
        LOGICAL_NEGATION,
index 97207bb..5330051 100644 (file)
@@ -122,4 +122,8 @@ public class Vala.UnresolvedType : DataType {
                
                return result;
        }
+
+       public override string to_string () {
+               return unresolved_symbol.to_string ();
+       }
 }