vala r1401 - in trunk: . compiler vala



Author: juergbi
Date: Mon May 19 20:28:13 2008
New Revision: 1401
URL: http://svn.gnome.org/viewvc/vala?rev=1401&view=rev

Log:
2008-05-19  Juerg Billeter  <j bitron ch>

	* vala/Makefile.am:
	* vala/valagenieparser.vala:
	* vala/valageniescanner.vala:
	* vala/valagenietokentype.vala:
	* vala/valaparser.vala:
	* vala/valasourcefile.vala:
	* compiler/valacompiler.vala:

	Add parser for Genie, patch by Jamie McCracken


Added:
   trunk/vala/valagenieparser.vala
   trunk/vala/valageniescanner.vala
   trunk/vala/valagenietokentype.vala
Modified:
   trunk/ChangeLog
   trunk/compiler/valacompiler.vala
   trunk/vala/Makefile.am
   trunk/vala/valaparser.vala
   trunk/vala/valasourcefile.vala

Modified: trunk/compiler/valacompiler.vala
==============================================================================
--- trunk/compiler/valacompiler.vala	(original)
+++ trunk/compiler/valacompiler.vala	Mon May 19 20:28:13 2008
@@ -199,14 +199,14 @@
 		foreach (string source in sources) {
 			if (FileUtils.test (source, FileTest.EXISTS)) {
 				var rpath = realpath (source);
-				if (source.has_suffix (".vala")) {
+				if (source.has_suffix (".vala") || source.has_suffix (".gs")) {
 					context.add_source_file (new SourceFile (context, rpath));
 				} else if (source.has_suffix (".vapi")) {
 					context.add_source_file (new SourceFile (context, rpath, true));
 				} else if (source.has_suffix (".c")) {
 					context.add_c_source_file (rpath);
 				} else {
-					Report.error (null, "%s is not a supported source file type. Only .vala, .vapi, and .c files are supported.".printf (source));
+					Report.error (null, "%s is not a supported source file type. Only .vala, .vapi, .gs, and .c files are supported.".printf (source));
 				}
 			} else {
 				Report.error (null, "%s not found".printf (source));
@@ -220,7 +220,10 @@
 		
 		var parser = new Parser ();
 		parser.parse (context);
-		
+
+		var genie_parser = new Genie.Parser ();
+		genie_parser.parse (context);
+
 		if (Report.get_errors () > 0) {
 			return quit ();
 		}

Modified: trunk/vala/Makefile.am
==============================================================================
--- trunk/vala/Makefile.am	(original)
+++ trunk/vala/Makefile.am	Mon May 19 20:28:13 2008
@@ -70,6 +70,9 @@
 	valaforeachstatement.vala \
 	valaformalparameter.vala \
 	valaforstatement.vala \
+	valagenieparser.vala \
+	valageniescanner.vala \
+	valagenietokentype.vala \
 	valaifstatement.vala \
 	valainitializerlist.vala \
 	valainstancecast.vala \

Added: trunk/vala/valagenieparser.vala
==============================================================================
--- (empty file)
+++ trunk/vala/valagenieparser.vala	Mon May 19 20:28:13 2008
@@ -0,0 +1,3210 @@
+/* valagenieparser.vala
+ *
+ * Copyright (C) 2008  Jamie McCracken, JÃrg Billeter
+ * Based on code by 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:
+ * 	Jamie McCracken jamiemcc gnome org
+ */
+
+using GLib;
+using Gee;
+
+
+/**
+ * Code visitor parsing all Genie source files.
+ */
+public class Vala.Genie.Parser : CodeVisitor {
+	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;
+	
+	string class_name;
+
+	/* hack needed to know if any part of an expression is a lambda one */
+	bool current_expr_is_lambda;
+
+	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,
+		EXTERN = 1 << 2,
+		INLINE = 1 << 3,
+		OVERRIDE = 1 << 4,
+		STATIC = 1 << 5,
+		VIRTUAL = 1 << 6,
+		PRIVATE = 1 << 7
+	}
+
+	construct {
+		tokens = new TokenInfo[BUFFER_SIZE];
+		class_name = null;
+		current_expr_is_lambda = false;
+	}
+
+	/**
+	 * Parses all .gs source files in the specified code context and
+	 * builds a code tree.
+	 *
+	 * @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 (".gs")) {
+			parse_file (source_file);
+		}
+	}
+
+	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);
+	}
+
+	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;
+	}
+
+	inline bool accept_terminator () {
+		if (current () == TokenType.SEMICOLON || current () == TokenType.EOL) {
+			next ();
+			return true;
+		}
+		return false;
+	}
+	
+	inline bool accept_block () {
+	
+		bool has_term = accept_terminator ();
+
+		if (accept (TokenType.INDENT)) {
+			prev();
+			return true;
+		}
+
+		if (has_term) {
+			prev ();
+		}
+
+		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;
+		}
+
+		TokenType cur = current ();
+		TokenType pre =  tokens[index - 1].type;
+
+		throw new ParseError.SYNTAX (get_error ("expected %s but got %s with previous %s".printf (type.to_string (), cur.to_string (), pre.to_string())));
+	}
+
+	inline bool expect_terminator () throws ParseError {
+		if (accept_terminator ()) {
+			return true;
+		}
+
+		TokenType cur = current ();
+
+		throw new ParseError.SYNTAX (get_error ("expected line end or semicolon but got %s".printf (cur.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;
+	}
+
+	SourceReference get_current_src () {
+		return new SourceReference (scanner.source_file, tokens[index].begin.line, tokens[index].begin.column, tokens[index].end.line, tokens[index].end.column);
+	}
+
+	SourceReference get_last_src () {
+		int last_index = (index + BUFFER_SIZE - 1) % BUFFER_SIZE;
+
+		return new SourceReference (scanner.source_file, tokens[last_index].begin.line, tokens[last_index].begin.column, tokens[last_index].end.line, tokens[last_index].end.column);
+	}
+
+	void rollback (SourceLocation location) {
+		while (tokens[index].begin.pos != location.pos) {
+			prev ();
+		}
+	}
+
+	inline  SymbolAccessibility get_access (string s) {
+		if (s[0] == '_') {
+			return SymbolAccessibility.PRIVATE;
+		}
+
+		return SymbolAccessibility.PUBLIC;
+	}
+
+	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.ASSERT:
+		case TokenType.BREAK:
+		case TokenType.CLASS:
+		case TokenType.CONST:
+		case TokenType.CONTINUE:
+		case TokenType.DEDENT:
+		case TokenType.DEF:
+		case TokenType.DEFAULT:
+		case TokenType.DELEGATE:
+		case TokenType.DELETE:
+		case TokenType.DO:
+		case TokenType.DOWNTO:
+		case TokenType.DYNAMIC:
+		case TokenType.ELSE:
+		case TokenType.EOL:
+		case TokenType.ENUM:
+		case TokenType.ENSURES:
+		case TokenType.ERRORDOMAIN:
+		case TokenType.EVENT:
+		case TokenType.EXCEPT:
+		case TokenType.EXTERN:
+		case TokenType.FALSE:
+		case TokenType.FINAL:
+		case TokenType.FINALLY:
+		case TokenType.FOR:
+		case TokenType.FOREACH:
+		case TokenType.GET:
+		case TokenType.IDENTIFIER:
+		case TokenType.IF:
+		case TokenType.IN:
+		case TokenType.INDENT:
+		case TokenType.INIT:
+		case TokenType.INLINE:
+		case TokenType.INTERFACE:
+		case TokenType.IS:
+		case TokenType.ISA:
+		case TokenType.LOCK:
+		case TokenType.NAMESPACE:
+		case TokenType.NEW:
+		case TokenType.NULL:
+		case TokenType.OF:
+		case TokenType.OUT:
+		case TokenType.OVERRIDE:
+		case TokenType.PASS:
+		case TokenType.PRINT:
+		case TokenType.PRIVATE:
+		case TokenType.PROP:
+		case TokenType.RAISE:
+		case TokenType.RAISES:
+		case TokenType.REF:
+		case TokenType.REQUIRES:
+		case TokenType.RETURN:
+		case TokenType.SET:
+		case TokenType.SIZEOF:
+		case TokenType.STATIC:
+		case TokenType.STRUCT:
+		case TokenType.SUPER:
+		case TokenType.THIS:
+		case TokenType.TO:
+		case TokenType.TRUE:
+		case TokenType.TRY:
+		case TokenType.TYPEOF:
+		case TokenType.USES:
+		case TokenType.VAR:
+		case TokenType.VIRTUAL:
+		case TokenType.VOID:
+		case TokenType.VOLATILE:
+		case TokenType.WEAK:
+		case TokenType.WHEN:
+		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 new BooleanLiteral (true, get_src (begin));
+		case TokenType.FALSE:
+			next ();
+			return new BooleanLiteral (false, get_src (begin));
+		case TokenType.INTEGER_LITERAL:
+			next ();
+			return new IntegerLiteral (get_last_string (), get_src (begin));
+		case TokenType.REAL_LITERAL:
+			next ();
+			return new RealLiteral (get_last_string (), get_src (begin));
+		case TokenType.CHARACTER_LITERAL:
+			next ();
+			return new CharacterLiteral (get_last_string (), get_src (begin));
+		case TokenType.STRING_LITERAL:
+			next ();
+			return new StringLiteral (get_last_string (), get_src (begin));
+		case TokenType.NULL:
+			next ();
+			return new NullLiteral (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.DYNAMIC);
+
+		accept (TokenType.WEAK);
+		skip_symbol_name ();
+		skip_type_argument_list ();
+		while (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 (bool owned_by_default = true) 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_dynamic = accept (TokenType.DYNAMIC);
+		bool value_owned = owned_by_default;
+		if (owned_by_default) {
+			value_owned = !accept (TokenType.WEAK);
+		}
+
+		var sym = parse_symbol_name ();
+		Gee.List<DataType> type_arg_list = parse_type_argument_list (false);
+
+		DataType 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);
+			}
+		}
+
+		while (accept (TokenType.STAR)) {
+			 type = new PointerType (type, get_src (begin));
+		}
+
+		if (!(type is PointerType)) {
+			type.nullable = accept (TokenType.INTERR);
+		}
+
+		while (accept (TokenType.OPEN_BRACKET)) {
+			int array_rank = 0;
+			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);
+
+			type.value_owned = true;
+			type = new ArrayType (type, array_rank, get_src (begin));
+			type.nullable = accept (TokenType.INTERR);
+		}
+
+		if (!owned_by_default) {
+			value_owned = accept (TokenType.HASH);
+		}
+
+		type.is_dynamic = is_dynamic;
+		type.value_owned = value_owned;
+		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.ASSERT:
+			return parse_assert_expression ();	
+		case TokenType.OPEN_PARENS:
+			expr = parse_tuple ();
+			break;
+		case TokenType.THIS:
+			expr = parse_this_access ();
+			break;
+		case TokenType.SUPER:
+			expr = parse_base_access ();
+			break;
+		case TokenType.NEW:
+			expr = parse_object_or_array_creation_expression ();
+			break;
+		case TokenType.PRINT:
+			return parse_print_expression ();
+		case TokenType.SIZEOF:
+			expr = parse_sizeof_expression ();
+			break;
+		case TokenType.TYPEOF:
+			expr = parse_typeof_expression ();
+			break;
+		default:
+			expr = parse_simple_name ();
+			break;
+		}
+
+		if (expr == null) {
+			// workaround for current limitation of exception handling
+			throw new ParseError.SYNTAX ("syntax error in primary expression");
+		}
+
+		// 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;
+			}
+
+			if (expr == null) {
+				// workaround for current limitation of exception handling
+				throw new ParseError.SYNTAX ("syntax error in primary expression");
+			}
+		}
+
+		return expr;
+	}
+
+	Expression parse_simple_name () throws ParseError {
+		var begin = get_location ();
+		string id = parse_identifier ();
+		Gee.List<DataType> type_arg_list = parse_type_argument_list (true);
+		var expr = new MemberAccess (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 new ParenthesizedExpression (expr_list.get (0), get_src (begin));
+	}
+
+	Expression parse_member_access (SourceLocation begin, Expression inner) throws ParseError {
+		expect (TokenType.DOT);
+		string id = parse_identifier ();
+		Gee.List<DataType> type_arg_list = parse_type_argument_list (true);
+		var expr = new MemberAccess (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 ();
+		Gee.List<DataType> type_arg_list = parse_type_argument_list (true);
+		var expr = new MemberAccess.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;
+	}
+
+
+	Gee.List<Expression> parse_print_argument_list () throws ParseError {
+		var list = new ArrayList<Expression> ();
+		var i = 0;
+		var begin = get_location ();
+
+		if (current () != TokenType.CLOSE_PARENS) {
+			do {
+				var p_expr = parse_expression ();
+				if (i == 0) {
+					i++;
+					
+					if (p_expr != null) { 
+						string s = "\"\\n\"";
+						var rhs = new StringLiteral (s, get_src (begin));
+						p_expr = new BinaryExpression (BinaryOperator.PLUS, p_expr, rhs, get_src (begin));
+					}
+				
+				} 
+				list.add (p_expr);
+
+			} while (accept (TokenType.COMMA));
+		}
+		return list;
+	}
+
+	Expression parse_print_expression () throws ParseError {
+		var begin = get_location ();
+	
+		expect (TokenType.PRINT);
+		accept (TokenType.OPEN_PARENS);
+	
+		var expr = new MemberAccess (null, "print", get_src (begin));
+		
+		var arg_list = parse_print_argument_list ();
+		
+		accept (TokenType.CLOSE_PARENS);
+		
+		var print_expr = new InvocationExpression (expr, get_src (begin));
+		
+		foreach (Expression arg in arg_list) {
+			print_expr.add_argument (arg);
+		}
+		
+		return print_expr;
+		
+	}
+	
+	Expression parse_assert_expression () throws ParseError {
+		var begin = get_location ();
+	
+		expect (TokenType.ASSERT);
+		accept (TokenType.OPEN_PARENS);
+	
+		var expr = new MemberAccess (null, "assert", get_src (begin));
+		
+		var arg_list = parse_argument_list ();
+		
+		accept (TokenType.CLOSE_PARENS);
+		
+		var assert_expr = new InvocationExpression (expr, get_src (begin));
+		
+		foreach (Expression arg in arg_list) {
+			assert_expr.add_argument (arg);
+		}
+		
+		return assert_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 init_list = parse_object_initializer ();
+
+		if (init_list.size > 0 && inner is MemberAccess) {
+			// struct creation expression
+			var member = (MemberAccess) inner;
+			member.creation_member = true;
+
+			var expr = new ObjectCreationExpression (member, get_src (begin));
+			expr.struct_creation = true;
+			foreach (Expression arg in arg_list) {
+				expr.add_argument (arg);
+			}
+			foreach (MemberInitializer initializer in init_list) {
+				expr.add_member_initializer (initializer);
+			}
+			return expr;
+		} else {
+			var expr = new InvocationExpression (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 = new ElementAccess (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 new MemberAccess (null, "this", get_src (begin));
+	}
+
+	Expression parse_base_access () throws ParseError {
+		var begin = get_location ();
+		expect (TokenType.SUPER);
+		return new BaseAccess (get_src (begin));
+	}
+
+	Expression parse_post_increment_expression (SourceLocation begin, Expression inner) throws ParseError {
+		expect (TokenType.OP_INC);
+		return new PostfixExpression (inner, true, get_src (begin));
+	}
+
+	Expression parse_post_decrement_expression (SourceLocation begin, Expression inner) throws ParseError {
+		expect (TokenType.OP_DEC);
+		return new PostfixExpression (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)) {
+			var expr = parse_object_creation_expression (begin, member);
+			return expr;
+		} else if (accept (TokenType.OPEN_BRACKET)) {
+			var expr = parse_array_creation_expression (begin, member);
+			return expr;
+		} else {
+			throw new ParseError.SYNTAX (get_error ("expected ( or ["));
+		}
+	}
+
+	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 = new ObjectCreationExpression (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;
+	}
+
+	Expression parse_array_creation_expression (SourceLocation begin, MemberAccess member) throws ParseError {
+		bool size_specified = false;
+		Gee.List<Expression> size_specifier_list;
+		bool first = true;
+		DataType element_type = UnresolvedType.new_from_expression (member);
+		do {
+			if (!first) {
+ 				// array of arrays: new T[][42]
+				element_type = new ArrayType (element_type, size_specifier_list.size, element_type.source_reference);
+			} else {
+				first = false;
+			}
+
+			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);
+		} while (accept (TokenType.OPEN_BRACKET));
+
+		InitializerList initializer = null;
+		if (current () == TokenType.OPEN_BRACE) {
+			initializer = parse_initializer ();
+		}
+		var expr = new ArrayCreationExpression (element_type, 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 new SizeofExpression (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 new TypeofExpression (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 new UnaryExpression (operator, op, get_src (begin));
+		}
+		switch (current ()) {
+		case TokenType.HASH:
+			next ();
+			var op = parse_unary_expression ();
+			return new ReferenceTransferExpression (op, get_src (begin));
+		case TokenType.OPEN_PARENS:
+			next ();
+			switch (current ()) {
+			case TokenType.VOID:
+			case TokenType.DYNAMIC:
+			case TokenType.WEAK:
+			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.SUPER:
+					case TokenType.NEW:
+					case TokenType.SIZEOF:
+					case TokenType.TYPEOF:
+					case TokenType.IDENTIFIER:
+						if (!type.value_owned) {
+							Report.warning (get_src (begin), "obsolete syntax, weak type modifier unused in cast expressions");
+						}
+						var inner = parse_unary_expression ();
+						return new CastExpression (inner, type, get_src (begin), false);
+					}
+				}
+				break;
+			}
+			// no cast expression
+			rollback (begin);
+			break;
+		case TokenType.STAR:
+			next ();
+			var op = parse_unary_expression ();
+			return new PointerIndirection (op, get_src (begin));
+		case TokenType.BITWISE_AND:
+			next ();
+			var op = parse_unary_expression ();
+			return new AddressofExpression (op, get_src (begin));
+		}
+
+		var expr = parse_primary_expression ();
+		return expr;
+	}
+
+	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.IS:   
+			next();
+			if (current () == TokenType.OP_NEG) {
+				prev ();
+				return BinaryOperator.INEQUALITY;
+			}
+			prev ();
+			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 = new BinaryExpression (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 = new BinaryExpression (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 = new BinaryExpression (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 = new BinaryExpression (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 = new BinaryExpression (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 = new BinaryExpression (operator, left, right, get_src (begin));
+				} else {
+					prev ();
+					found = false;
+				}
+				break;
+			default:
+				switch (current ()) {
+				case TokenType.ISA:
+					next ();
+					var type = parse_type ();
+					left = new TypeCheck (left, type, get_src (begin));
+					break;
+				case TokenType.AS:
+					next ();
+					var type = parse_type ();
+					left = new CastExpression (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.INEQUALITY:
+			case BinaryOperator.EQUALITY:
+				if ((operator == BinaryOperator.INEQUALITY) && (current () == TokenType.IS)) {
+					next ();
+				}
+				next ();
+				var right = parse_relational_expression ();
+				left = new BinaryExpression (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 = new BinaryExpression (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 = new BinaryExpression (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 = new BinaryExpression (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 = new BinaryExpression (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 = new BinaryExpression (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 = new BinaryExpression (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 new ConditionalExpression (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> ();
+		
+		expect (TokenType.DEF);
+		
+		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 ());
+		}
+
+
+		LambdaExpression lambda;
+		if (accept_block ()) {
+			var block = parse_block ();
+			lambda = new LambdaExpression.with_statement_body (block, get_src (begin));
+		} else {
+			var expr = parse_expression ();
+			lambda = new LambdaExpression (expr, get_src (begin));
+			expect_terminator ();
+			
+		}
+
+
+		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 {
+		if (current () == TokenType.DEF) {
+			var lambda = parse_lambda_expression ();
+			current_expr_is_lambda = true;
+			return lambda;
+		}
+
+		var begin = get_location ();
+		Expression expr = parse_conditional_expression ();
+
+		while (true) {
+			var operator = get_assignment_operator (current ());
+			if (operator != AssignmentOperator.NONE) {
+				next ();
+				var rhs = parse_expression ();
+				expr = new Assignment (expr, rhs, operator, get_src (begin));
+				if (expr == null) {
+					// workaround for current limitation of exception handling
+					throw new ParseError.SYNTAX ("syntax error in assignment");
+				}
+			} 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 = new Assignment (expr, rhs, AssignmentOperator.SHIFT_RIGHT, get_src (begin));
+					if (expr == null) {
+						// workaround for current limitation of exception handling
+						throw new ParseError.SYNTAX ("syntax error in assignment");
+					}
+				} else {
+					prev ();
+					break;
+				}
+			} else {
+				break;
+			}
+		}
+
+		return expr;
+	}
+
+	void parse_statements (Block block) throws ParseError {
+		while (current () != TokenType.DEDENT
+		       && current () != TokenType.WHEN
+		       && current () != TokenType.DEFAULT) {
+			try {
+				Statement stmt;
+				bool is_decl = false;
+				comment = scanner.pop_comment ();
+				switch (current ()) {
+
+				/* skip over requires and ensures as we handled them in method declaration */	
+				case TokenType.REQUIRES:
+				case TokenType.ENSURES:
+					var begin = get_location ();	
+					next ();
+
+					if (accept (TokenType.EOL) && accept (TokenType.INDENT)) {
+						while (current () != TokenType.DEDENT) {
+							next();
+						}
+
+						expect (TokenType.DEDENT);
+					} else {
+						while (current () != TokenType.EOL) {
+							next();
+						}
+
+						expect (TokenType.EOL);
+					}
+		
+					stmt =  new EmptyStatement (get_src_com (begin));
+					break;				
+
+
+				case TokenType.INDENT:
+					stmt = parse_block ();
+					break;
+				case TokenType.SEMICOLON:
+				case TokenType.PASS:
+					stmt = parse_empty_statement ();
+					break;
+				case TokenType.PRINT:
+				case TokenType.ASSERT:
+					stmt = parse_expression_statement ();	
+					break;
+				case TokenType.IF:
+					stmt = parse_if_statement ();
+					break;
+				case TokenType.CASE:
+					stmt = parse_switch_statement ();
+					break;
+				case TokenType.WHILE:
+					stmt = parse_while_statement ();
+					break;
+				case TokenType.DO:
+					stmt = parse_do_statement ();
+					break;
+				case TokenType.FOR:
+					stmt = parse_for_statement ();
+					break;
+				case TokenType.FOREACH:
+					stmt = parse_foreach_statement ();
+					break;
+				case TokenType.BREAK:
+					stmt = parse_break_statement ();
+					break;
+				case TokenType.CONTINUE:
+					stmt = parse_continue_statement ();
+					break;
+				case TokenType.RETURN:
+					stmt = parse_return_statement ();
+					break;
+				case TokenType.RAISE:
+					stmt = parse_throw_statement ();
+					break;
+				case TokenType.TRY:
+					stmt = parse_try_statement ();
+					break;
+				case TokenType.LOCK:
+					stmt = parse_lock_statement ();
+					break;
+				case TokenType.DELETE:
+					stmt = parse_delete_statement ();
+					break;
+				case TokenType.VAR:
+					is_decl = true;
+					parse_local_variable_declarations (block);
+					break;
+
+
+				case TokenType.OP_INC:
+				case TokenType.OP_DEC:
+				case TokenType.SUPER:
+				case TokenType.THIS:
+				case TokenType.OPEN_PARENS:
+				case TokenType.STAR:
+				case TokenType.NEW:
+					stmt = parse_expression_statement ();
+					break;
+				default:
+					bool is_expr = is_expression ();
+					if (is_expr) {
+						stmt = parse_expression_statement ();
+					} else {
+						is_decl = true;
+						parse_local_variable_declarations (block);
+					}
+					break;
+				}
+
+				if (!is_decl) {
+					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
+					break;
+				}
+			}
+		}
+	}
+
+	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.INDENT) {
+			var block = parse_block ();
+			return block;
+		}
+
+		comment = scanner.pop_comment ();
+
+		var block = new Block ();
+		var stmt = parse_embedded_statement_without_block ();
+		if (stmt == null) {
+			// workaround for current limitation of exception handling
+			throw new ParseError.SYNTAX ("syntax error in embedded statement");
+		}
+		block.add_statement (stmt);
+		return block;
+
+	}
+
+	Statement parse_embedded_statement_without_block () throws ParseError {
+		switch (current ()) {
+		case TokenType.PASS:
+		case TokenType.SEMICOLON: return parse_empty_statement ();
+		case TokenType.IF:        return parse_if_statement ();
+		case TokenType.CASE:      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.RAISE:     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.INDENT);
+		var block = new Block (get_src_com (begin));
+		parse_statements (block);
+		if (!accept (TokenType.DEDENT)) {
+			// only report error if it's not a secondary error
+			if (Report.get_errors () == 0) {
+				Report.error (get_current_src (), "tab indentation is incorrect");
+			}
+		}
+
+		return block;
+	}
+
+	Statement parse_empty_statement () throws ParseError {
+		var begin = get_location ();
+
+		accept (TokenType.PASS);
+		accept (TokenType.SEMICOLON);
+		expect_terminator ();
+
+		return new EmptyStatement (get_src_com (begin));
+	}
+
+	void add_local_var_variable (Block block, string id)  throws ParseError {
+		DataType type_copy = null;
+		var local = parse_local_variable (type_copy, id);
+		block.add_statement (new DeclarationStatement (local, local.source_reference));
+	}
+
+	void parse_local_variable_declarations (Block block) throws ParseError {
+		var begin = get_location ();
+
+		if (accept (TokenType.VAR)) {
+			/* support block vars */
+			if (accept (TokenType.EOL) && accept (TokenType.INDENT)) {
+				while (current () != TokenType.DEDENT) {
+					var s = parse_identifier ();
+					add_local_var_variable (block, s);
+					accept (TokenType.EOL);
+					accept (TokenType.SEMICOLON);
+				}
+			
+				expect (TokenType.DEDENT);
+			} else {
+				var s = parse_identifier ();
+				add_local_var_variable (block, s);
+				expect_terminator ();
+			}
+			
+			return;
+		}
+
+		var id_list = new ArrayList<string> ();
+		DataType variable_type = null;
+
+		do {
+			id_list.add (parse_identifier ());
+		} while (accept (TokenType.COMMA));
+
+		expect (TokenType.COLON);
+
+		variable_type = parse_type ();
+
+		foreach (string id in id_list) {
+			DataType type_copy = null;
+			if (variable_type != null) {
+				type_copy = variable_type.copy ();
+			}
+			var local = parse_local_variable (type_copy, id);
+			block.add_statement (new DeclarationStatement (local, local.source_reference));
+		}
+
+		expect_terminator ();
+	}
+
+	LocalVariable parse_local_variable (DataType? variable_type, string id) throws ParseError {
+		var begin = get_location ();
+		Expression initializer = null;
+		if (accept (TokenType.ASSIGN)) {
+			initializer = parse_variable_initializer ();
+		}
+		return new LocalVariable (variable_type, id, initializer, get_src_com (begin));
+	}
+
+	Statement parse_expression_statement () throws ParseError {
+		var begin = get_location ();
+		var expr = parse_statement_expression ();
+
+		if (current_expr_is_lambda) {
+			current_expr_is_lambda = false;
+		} else {
+			expect_terminator ();
+		}
+
+		return new ExpressionStatement (expr, get_src_com (begin));
+	}
+
+	Expression parse_statement_expression () throws ParseError {
+		// invocation expression, assignment,
+		// or pre/post increment/decrement expression
+		var expr = parse_expression ();
+		return expr;
+	}
+
+	Statement parse_if_statement () throws ParseError {
+		var begin = get_location ();
+
+		expect (TokenType.IF);
+
+		var condition = parse_expression ();
+
+		if (!accept (TokenType.DO)) {
+			expect (TokenType.EOL);
+		} else {
+			accept (TokenType.EOL);
+		}
+
+		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 new IfStatement (condition, true_stmt, false_stmt, src);
+	}
+
+	Statement parse_switch_statement () throws ParseError {
+		var begin = get_location ();
+		expect (TokenType.CASE);
+		var condition = parse_expression ();
+
+		expect (TokenType.EOL);
+
+		var stmt = new SwitchStatement (condition, get_src_com (begin));
+		expect (TokenType.INDENT);
+		while (current () != TokenType.DEDENT) {
+			var section = new SwitchSection (get_src_com (begin));
+			
+			if (accept (TokenType.WHEN)) {
+				do {
+					section.add_label (new SwitchLabel (parse_expression (), get_src_com (begin)));
+				}
+				while (accept (TokenType.COMMA));
+			} else {
+				expect (TokenType.DEFAULT);
+				section.add_label (new SwitchLabel.with_default (get_src_com (begin)));
+			}
+
+			if (!accept (TokenType.EOL)) {
+				expect (TokenType.DO);
+			}
+
+			parse_statements (section);
+
+			/* add break statement for each block */
+			var break_stmt =  new BreakStatement (get_src_com (begin));
+			section.add_statement (break_stmt);
+
+			stmt.add_section (section);
+		}
+		expect (TokenType.DEDENT);
+		return stmt;
+	}
+
+	Statement parse_while_statement () throws ParseError {
+		var begin = get_location ();
+		expect (TokenType.WHILE);
+		var condition = parse_expression ();
+
+		if (!accept (TokenType.DO)) {
+			expect (TokenType.EOL);
+		} else {
+			accept (TokenType.EOL);
+		}
+
+		var body = parse_embedded_statement ();
+		return new WhileStatement (condition, body, get_src_com (begin));
+	}
+
+	Statement parse_do_statement () throws ParseError {
+		var begin = get_location ();
+		expect (TokenType.DO);
+		expect (TokenType.EOL);
+		var body = parse_embedded_statement ();
+		expect (TokenType.WHILE);
+
+		var condition = parse_expression ();
+
+		expect_terminator ();
+		
+		return new DoStatement (body, condition, get_src_com (begin));
+	}
+
+
+	Statement parse_for_statement () throws ParseError {
+		var begin = get_location ();
+		Block block = null;
+		Expression initializer = null;
+		Expression condition = null;
+		Expression iterator = null;
+		bool is_expr;
+		string id;
+
+		expect (TokenType.FOR);
+
+		switch (current ()) {
+		case TokenType.VAR:
+			is_expr = false;
+			break;
+		default:
+			
+			bool local_is_expr = is_expression ();
+			is_expr = local_is_expr;
+			break;
+		}
+
+		if (is_expr) {
+			initializer = parse_statement_expression ();
+		} else {
+			block = new Block (get_src (begin));
+			DataType variable_type;
+			if (accept (TokenType.VAR)) {
+				variable_type = null;
+				id = parse_identifier ();
+			} else {
+				id = parse_identifier ();
+				expect (TokenType.COLON);
+				variable_type = parse_type ();
+			}
+			
+			DataType type_copy = null;
+			if (variable_type != null) {
+				type_copy = variable_type.copy ();
+			}
+			var local = parse_local_variable (type_copy, id);
+
+			block.add_statement (new DeclarationStatement (local, local.source_reference));
+		}
+		
+		
+		
+		if (accept (TokenType.TO)) {
+			/* create expression for condition and incrementing iterator */		
+			var to_begin = get_location ();
+			var to_src = get_src (to_begin);
+			var left = new MemberAccess (null, id, to_src);
+			var right = parse_primary_expression ();
+
+			condition = new BinaryExpression (BinaryOperator.LESS_THAN_OR_EQUAL, left, right, to_src);
+			
+			iterator = new PostfixExpression (left, true, to_src);
+		} else {
+			expect (TokenType.DOWNTO);
+			var downto_begin = get_location ();
+			var downto_src = get_src (downto_begin);
+			/* create expression for condition and decrementing iterator */
+			var left = new MemberAccess (null, id, downto_src);
+			var right = parse_primary_expression ();
+
+			condition = new BinaryExpression (BinaryOperator.GREATER_THAN_OR_EQUAL, left, right, downto_src);
+
+			iterator = new PostfixExpression (left, false, downto_src);
+		}
+
+		expect (TokenType.EOL);
+
+		var src = get_src_com (begin);
+		var body = parse_embedded_statement ();
+		var stmt = new ForStatement (condition, body, src);
+
+		if (initializer != null) stmt.add_initializer (initializer);
+
+		stmt.add_iterator (iterator);
+
+
+		if (block != null) {
+			block.add_statement (stmt);
+			return block;
+		} else {
+			return stmt;
+		}
+	}
+
+	Statement parse_foreach_statement () throws ParseError {
+		var begin = get_location ();
+		DataType type = null;
+		string id = null;
+
+		expect (TokenType.FOREACH);
+
+		if (accept (TokenType.VAR)) {
+			 id = parse_identifier ();
+		} else {
+			id = parse_identifier ();
+			expect (TokenType.COLON);
+			type = parse_type ();
+		}
+
+		expect (TokenType.IN);
+		var collection = parse_expression ();
+		expect (TokenType.EOL);
+		var src = get_src_com (begin);
+		var body = parse_embedded_statement ();
+		return new ForeachStatement (type, id, collection, body, src);
+	}
+
+	Statement parse_break_statement () throws ParseError {
+		var begin = get_location ();
+		expect (TokenType.BREAK);
+		expect_terminator ();
+		return new BreakStatement (get_src_com (begin));
+	}
+
+	Statement parse_continue_statement () throws ParseError {
+		var begin = get_location ();
+		expect (TokenType.CONTINUE);
+		expect_terminator ();
+		return new ContinueStatement (get_src_com (begin));
+	}
+
+	Statement parse_return_statement () throws ParseError {
+		var begin = get_location ();
+		expect (TokenType.RETURN);
+		Expression expr = null;
+		if (current () != TokenType.SEMICOLON && current () != TokenType.EOL) {
+			expr = parse_expression ();
+		}
+		expect_terminator ();
+		return new ReturnStatement (expr, get_src_com (begin));
+	}
+
+	Statement parse_throw_statement () throws ParseError {
+		var begin = get_location ();
+		expect (TokenType.RAISE);
+		var expr = parse_expression ();
+		expect_terminator ();
+		return new ThrowStatement (expr, get_src_com (begin));
+	}
+
+	Statement parse_try_statement () throws ParseError {
+		var begin = get_location ();
+		expect (TokenType.TRY);
+		expect (TokenType.EOL);
+		var try_block = parse_block ();
+		Block finally_clause = null;
+		var catch_clauses = new ArrayList<CatchClause> ();
+		if (current () == TokenType.EXCEPT) {
+			parse_catch_clauses (catch_clauses);
+			if (current () == TokenType.FINALLY) {
+				finally_clause = parse_finally_clause ();
+			}
+		} else {
+			finally_clause = parse_finally_clause ();
+		}
+		var stmt = new TryStatement (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.EXCEPT)) {
+			var begin = get_location ();
+			DataType type = null;
+			string id = null;
+			if (!accept (TokenType.EOL)) {
+				id = parse_identifier ();
+				expect (TokenType.COLON);
+				type = parse_type ();
+				expect (TokenType.EOL);
+				
+			}
+			var block = parse_block ();
+			catch_clauses.add (new CatchClause (type, id, block, get_src (begin)));
+		}
+	}
+
+	Block parse_finally_clause () throws ParseError {
+		expect (TokenType.FINALLY);
+		accept_block ();
+		var block = parse_block ();
+		return 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 new LockStatement (expr, stmt, get_src_com (begin));
+	}
+
+	Statement parse_delete_statement () throws ParseError {
+		var begin = get_location ();
+		expect (TokenType.DELETE);
+		var expr = parse_expression ();
+		expect_terminator ();
+		return new DeleteStatement (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 (Gee.List<Attribute>) attributes) {
+				node.attributes.append (attr);
+			}
+		}
+	}
+
+	Symbol parse_declaration () throws ParseError {
+		comment = scanner.pop_comment ();
+		var attrs = parse_attributes ();
+		
+		switch (current ()) {
+		case TokenType.CONST:
+			return parse_constant_declaration (attrs);	
+		case TokenType.CONSTRUCT:
+			return parse_creation_method_declaration (attrs);
+		case TokenType.CLASS:
+			return parse_class_declaration (attrs);
+		case TokenType.INIT:
+			return parse_constructor_declaration (attrs);
+		case TokenType.DELEGATE:	
+			return parse_delegate_declaration (attrs);	
+		case TokenType.DEF:
+			return parse_method_declaration (attrs);
+		case TokenType.ENUM:
+			return parse_enum_declaration (attrs);
+		case TokenType.ERRORDOMAIN:
+			return parse_errordomain_declaration (attrs);
+		case TokenType.FINAL:
+			return parse_destructor_declaration (attrs);
+		case TokenType.INTERFACE:	
+			return parse_interface_declaration (attrs);		
+		case TokenType.NAMESPACE:	
+			return parse_namespace_declaration (attrs);	
+		case TokenType.PROP:	
+			return parse_property_declaration (attrs);
+		case TokenType.EVENT:	
+			return parse_signal_declaration (attrs);
+		case TokenType.STRUCT:	
+			return parse_struct_declaration (attrs);
+		default: 
+			var begin = get_location ();
+			while (current () != TokenType.EOL && current () != TokenType.SEMICOLON && current () != TokenType.EOF) {
+				if (current () == TokenType.COLON) {
+					rollback (begin);
+					return parse_field_declaration (attrs);
+				} else {
+					next ();
+				}
+			}
+			rollback (begin);
+			
+			break;	
+		}
+		
+		TokenType cur = current ();
+		TokenType pre =  tokens[index-1].type;
+
+		throw new ParseError.SYNTAX (get_error ("expected declaration  but got %s with previous %s".printf (cur.to_string (), pre.to_string())));
+	}
+
+	void parse_declarations (Symbol parent, bool root = false) throws ParseError {
+		if (!root) {
+			expect (TokenType.INDENT);
+		}
+		while (current () != TokenType.DEDENT && 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;
+				while (true) {
+					r = recover ();
+					if (r == RecoveryState.STATEMENT_BEGIN) {
+						next ();
+					} else {
+						break;
+					}
+				}
+				if (r == RecoveryState.EOF) {
+					return;
+				}
+			}
+		}
+		if (!root) {
+			if (!accept (TokenType.DEDENT)) {
+				// only report error if it's not a secondary error
+				if (Report.get_errors () == 0) {
+					Report.error (get_current_src (), "expected dedent");
+				}
+			}
+		}
+	}
+
+	enum RecoveryState {
+		EOF,
+		DECLARATION_BEGIN,
+		STATEMENT_BEGIN
+	}
+
+	RecoveryState recover () {
+		while (current () != TokenType.EOF) {
+			switch (current ()) {
+			case TokenType.CLASS:
+			case TokenType.CONST:
+			case TokenType.CONSTRUCT:
+			case TokenType.INIT:
+			case TokenType.DEF:
+			case TokenType.DELEGATE:
+			case TokenType.ENUM:
+			case TokenType.ERRORDOMAIN:
+			case TokenType.FINAL:
+			case TokenType.INTERFACE:
+			case TokenType.NAMESPACE:
+			case TokenType.PROP:
+			case TokenType.EVENT:
+			case TokenType.STRUCT:
+				return RecoveryState.DECLARATION_BEGIN;
+			case TokenType.BREAK:
+			case TokenType.CASE:
+			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.RAISE:
+			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 = new Namespace (sym.name, get_src_com (begin));
+		set_attributes (ns, attrs);
+		expect (TokenType.EOL);
+		parse_declarations (ns);
+		return ns;
+	}
+
+	void parse_namespace_member (Namespace ns) throws ParseError {
+		var sym = parse_declaration ();
+		if (sym is Namespace) {
+			ns.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.binding = MemberBinding.STATIC;
+			ns.add_method (method);
+		} else if (sym is Field) {
+			var field = (Field) sym;
+			field.binding = MemberBinding.STATIC;
+			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 add_uses_clause () throws ParseError {
+		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);
+	}
+
+	void parse_using_directives () throws ParseError {
+		while (accept (TokenType.USES)) {
+			var begin = get_location ();
+
+			if (accept_block ()) {
+				expect (TokenType.INDENT);
+
+				while (current () != TokenType.DEDENT && current () != TokenType.EOF) {
+					add_uses_clause ();
+					expect (TokenType.EOL);	
+				}
+
+				expect (TokenType.DEDENT);
+			} else {
+				do {
+					add_uses_clause ();	
+				} while (accept (TokenType.COMMA));
+
+				expect_terminator ();
+			}
+		}
+	}
+
+	Symbol parse_class_declaration (Gee.List<Attribute>? attrs) throws ParseError {
+		var begin = get_location ();
+		expect (TokenType.CLASS);
+
+		var flags = parse_type_declaration_modifiers ();
+
+		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));
+		}
+
+		accept (TokenType.EOL);
+
+		var cl = new Class (sym.name, get_src_com (begin));
+
+		if (ModifierFlags.PRIVATE in flags) {
+			cl.access = SymbolAccessibility.PRIVATE;
+		} else {
+			/* class must always be Public unless its name starts wtih underscore */
+			if (sym.name[0] == '_') {
+				cl.access = SymbolAccessibility.PRIVATE;
+			} else {
+				cl.access = SymbolAccessibility.PUBLIC;
+			}
+		}
+
+		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);
+		}
+
+		class_name = cl.name;
+
+		parse_declarations (cl);
+
+		// ensure there is always a default construction method
+		if (!scanner.source_file.external_package
+		    && !cl.is_static
+		    && cl.default_construction_method == null) {
+			var m = new CreationMethod (cl.name, null, cl.source_reference);
+			m.binding = MemberBinding.STATIC;
+			m.access = SymbolAccessibility.PUBLIC;
+			m.body = new Block (cl.source_reference);
+			cl.add_method (m);
+		}
+
+		Symbol result = cl;
+		while (sym.inner != null) {
+			sym = sym.inner;
+			var ns = new Namespace (sym.name, cl.source_reference);
+			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 Vala.Signal) {
+			cl.add_signal ((Vala.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.binding == MemberBinding.INSTANCE) {
+				cl.constructor = c;
+			 } else if (c.binding == MemberBinding.CLASS) {
+				cl.class_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 ();
+
+		expect (TokenType.CONST);
+
+		parse_member_declaration_modifiers ();
+
+		string id = parse_identifier ();
+		expect (TokenType.COLON);
+		var type = parse_type (false);
+
+		Expression initializer = null;
+		if (accept (TokenType.ASSIGN)) {
+			initializer = parse_variable_initializer ();
+		}
+		expect_terminator ();
+
+		var c = new Constant (id, type, initializer, get_src_com (begin));
+		c.access = get_access (id);
+		set_attributes (c, attrs);
+		return c;
+	}
+
+	Field parse_field_declaration (Gee.List<Attribute>? attrs) throws ParseError {
+		var begin = get_location ();
+		string id = parse_identifier ();
+		expect (TokenType.COLON);
+
+		var flags = parse_member_declaration_modifiers ();
+
+		var type = parse_type ();
+
+		var f = new Field (id, type, null, get_src_com (begin));
+
+		if (ModifierFlags.PRIVATE in flags) {
+			f.access = SymbolAccessibility.PRIVATE;
+		} else {
+			f.access = get_access (id);
+		}
+
+		set_attributes (f, attrs);
+
+		if (accept (TokenType.ASSIGN)) {
+			f.initializer = parse_expression ();
+		}
+
+
+		if (ModifierFlags.STATIC in flags) {
+			f.binding = MemberBinding.STATIC;
+		} else if (ModifierFlags.CLASS in flags) {
+			f.binding = MemberBinding.CLASS;
+		}
+
+		expect_terminator ();
+
+		return f;
+	}
+
+	InitializerList parse_initializer () throws ParseError {
+		var begin = get_location ();
+		expect (TokenType.OPEN_BRACE);
+		var initializer = new InitializerList (get_src (begin));
+		if (current () != TokenType.DEDENT) {
+			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) {
+			var expr = parse_initializer ();
+			return expr;
+		} else {
+			var expr = parse_expression ();
+			return expr;
+		}
+	}
+
+	Method parse_method_declaration (Gee.List<Attribute>? attrs) throws ParseError {
+		var begin = get_location ();
+		DataType type = new VoidType ();
+		expect (TokenType.DEF);
+		var flags = parse_member_declaration_modifiers ();
+
+		string id = parse_identifier ();
+
+		var params = new ArrayList<FormalParameter> ();
+		expect (TokenType.OPEN_PARENS);
+
+		if (current () != TokenType.CLOSE_PARENS) {
+			do {
+				var param = parse_parameter ();
+				params.add (param);
+			} while (accept (TokenType.COMMA));
+		}
+
+		expect (TokenType.CLOSE_PARENS);
+
+
+		/* deal with return value */
+		if (accept (TokenType.COLON)) {
+			type = parse_type ();
+			parse_type_parameter_list ();
+		}
+
+
+		var method = new Method (id, type, get_src_com (begin));
+		if (ModifierFlags.PRIVATE in flags) {
+			method.access = SymbolAccessibility.PRIVATE;
+		} else {
+			method.access = get_access (id);
+		}
+
+
+		set_attributes (method, attrs);
+
+		foreach (FormalParameter param in params) {
+			method.add_parameter (param);
+		}
+
+		if (accept (TokenType.RAISES)) {
+			do {
+				method.add_error_domain (parse_type ());
+			} while (accept (TokenType.COMMA));
+		}
+
+
+		if (ModifierFlags.STATIC in flags || id == "main") {
+			method.binding = MemberBinding.STATIC;
+		}
+		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.EOL);
+
+		var body_location = get_location ();
+
+
+		/* "requires" and "ensures" if present will be at  start of the method body */
+		if (accept (TokenType.INDENT)) {		
+			if (accept (TokenType.REQUIRES)) {
+			
+				if (accept (TokenType.EOL) && accept (TokenType.INDENT)) {
+					while (current() != TokenType.DEDENT) {
+						method.add_precondition (parse_expression ());
+						expect (TokenType.EOL);
+					}
+					
+					expect (TokenType.DEDENT);
+					accept_terminator ();
+				} else {
+				
+					method.add_precondition (parse_expression ());
+					expect_terminator ();
+				
+				}
+				
+			}
+
+			if (accept (TokenType.ENSURES)) {
+				if (accept (TokenType.EOL) && accept (TokenType.INDENT)) {
+					while (current() != TokenType.DEDENT) {
+						method.add_postcondition (parse_expression ());
+						expect (TokenType.EOL);
+					}
+
+					expect (TokenType.DEDENT);
+					accept_terminator ();
+				} else {
+					method.add_postcondition (parse_expression ());
+					expect_terminator ();
+				}
+			}
+		}
+
+		rollback (body_location);
+
+
+		if (accept_block ()) {
+			method.body = parse_block ();
+		}
+		return method;
+	}
+
+	Property parse_property_declaration (Gee.List<Attribute>? attrs) throws ParseError {
+		var begin = get_location ();
+		var readonly = false;
+
+		expect (TokenType.PROP);
+
+		var flags = parse_member_declaration_modifiers ();
+
+		readonly =  accept (TokenType.READONLY);
+
+		string id = parse_identifier ();
+		expect (TokenType.COLON);
+
+		bool is_weak = accept (TokenType.WEAK);
+		var type = parse_type (false);
+
+		var prop = new Property (id, type, null, null, get_src_com (begin));
+		if (ModifierFlags.PRIVATE in flags) {
+			prop.access = SymbolAccessibility.PRIVATE;
+		} else {
+			prop.access = get_access (id);
+		}
+
+		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;
+		}
+
+		if (accept (TokenType.ASSIGN)) {
+			prop.default_expression = parse_expression ();
+		}
+
+
+		if (accept_block ()) {
+			expect (TokenType.INDENT);
+			while (current () != TokenType.DEDENT) {
+				var accessor_begin = get_location ();
+				parse_attributes ();
+				var accessor_access = 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_block ()) {
+						block = parse_block ();
+					}
+					prop.get_accessor = new PropertyAccessor (true, false, false, block, get_src (accessor_begin));
+					prop.get_accessor.access = SymbolAccessibility.PUBLIC;
+				} else {
+					bool _construct;
+					if (accept (TokenType.SET)) {
+						if (readonly) {
+							throw new ParseError.SYNTAX (get_error ("set block not allowed for a read only property"));
+						}
+						_construct = accept (TokenType.CONSTRUCT);
+					} else if (accept (TokenType.CONSTRUCT)) {
+						_construct = true;
+					} else if (!accept (TokenType.EOL)) {
+						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_block ()) {
+						block = parse_block ();
+					}
+					prop.set_accessor = new PropertyAccessor (false, !readonly, _construct, block, get_src (accessor_begin));
+					prop.set_accessor.access = SymbolAccessibility.PUBLIC;
+				}
+			}
+			accept (TokenType.EOL);
+			expect (TokenType.DEDENT);
+		} else {
+			prop.get_accessor = new PropertyAccessor (true, false, false, null, get_src (begin));
+			prop.get_accessor.access = SymbolAccessibility.PUBLIC;
+
+			if (!readonly) {
+				prop.set_accessor = new PropertyAccessor (false, true, false, null, get_src (begin));
+				prop.set_accessor.access = SymbolAccessibility.PUBLIC;
+			
+			}
+
+			expect_terminator ();
+		}
+
+		if (!prop.is_abstract && !scanner.source_file.external_package) {
+			var needs_var = (readonly && (prop.get_accessor != null && prop.get_accessor.body == null));
+
+			if (!needs_var) {
+				needs_var = (prop.get_accessor != null && prop.get_accessor.body == null) || (prop.set_accessor != null && prop.set_accessor.body == null);	
+			}
+
+			if (needs_var) {
+				/* automatic property accessor body generation */
+				var field_type = prop.property_type.copy ();
+				field_type.value_owned = !is_weak;
+				prop.field = new Field ("_%s".printf (prop.name), field_type, prop.default_expression, prop.source_reference);
+				prop.field.access = SymbolAccessibility.PRIVATE;
+			}
+		}
+
+		return prop;
+	}
+
+	Vala.Signal parse_signal_declaration (Gee.List<Attribute>? attrs) throws ParseError {
+		var begin = get_location ();
+		DataType type;
+
+		expect (TokenType.EVENT);
+		var flags = parse_member_declaration_modifiers ();
+		string id = parse_identifier ();
+
+
+		var params = new ArrayList<FormalParameter> ();
+
+		expect (TokenType.OPEN_PARENS);
+		if (current () != TokenType.CLOSE_PARENS) {
+			do {
+				var param = parse_parameter ();
+				params.add (param);
+			} while (accept (TokenType.COMMA));
+		}
+		expect (TokenType.CLOSE_PARENS);
+
+		if (accept (TokenType.COLON)) {
+			type = parse_type ();
+		} else {
+			type = new VoidType ();
+		}
+
+		var sig = new Vala.Signal (id, type, get_src_com (begin));
+		if (ModifierFlags.PRIVATE in flags) {
+			sig.access = SymbolAccessibility.PRIVATE;
+		} else {
+			sig.access = get_access (id);
+		}
+
+		set_attributes (sig, attrs);
+		
+		foreach (FormalParameter formal_param in params) {
+			sig.add_parameter (formal_param);
+		}
+
+		expect_terminator ();
+		return sig;
+	}
+
+	Constructor parse_constructor_declaration (Gee.List<Attribute>? attrs) throws ParseError {
+		var begin = get_location ();
+
+		expect (TokenType.INIT);
+		var flags = parse_member_declaration_modifiers ();
+
+		var c = new Constructor (get_src_com (begin));
+		if (ModifierFlags.STATIC in flags) {
+			c.binding = MemberBinding.STATIC;
+		} else if (ModifierFlags.CLASS in flags) {
+			c.binding = MemberBinding.CLASS;
+		}
+
+		accept_block ();
+		c.body = parse_block ();
+		return c;
+	}
+
+	Destructor parse_destructor_declaration (Gee.List<Attribute>? attrs) throws ParseError {
+		var begin = get_location ();
+		expect (TokenType.FINAL);
+		var d = new Destructor (get_src_com (begin));
+		accept_block ();
+		d.body = parse_block ();
+		return d;
+	}
+
+	Symbol parse_struct_declaration (Gee.List<Attribute>? attrs) throws ParseError {
+		var begin = get_location ();
+
+		expect (TokenType.STRUCT);
+		var flags = parse_type_declaration_modifiers ();
+		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 st = new Struct (sym.name, get_src_com (begin));
+		if (ModifierFlags.PRIVATE in flags) {
+			st.access = SymbolAccessibility.PRIVATE;
+		} else {
+			st.access = get_access (sym.name);
+		}
+		set_attributes (st, attrs);
+		foreach (TypeParameter type_param in type_param_list) {
+			st.add_type_parameter (type_param);
+		}
+		foreach (DataType base_type in base_types) {
+			st.add_base_type (base_type);
+		}
+
+		expect (TokenType.EOL);
+
+		parse_declarations (st);
+
+		Symbol result = st;
+		while (sym.inner != null) {
+			sym = sym.inner;
+			var ns = new Namespace (sym.name, st.source_reference);
+			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 ();
+
+		expect (TokenType.INTERFACE);
+		var flags = parse_type_declaration_modifiers ();
+		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 = new Interface (sym.name, get_src_com (begin));
+		if (ModifierFlags.PRIVATE in flags) {
+			iface.access = SymbolAccessibility.PRIVATE;
+		} else {
+			iface.access = get_access (sym.name);
+		}
+		
+		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);
+		}
+
+
+		expect (TokenType.EOL);
+		
+		parse_declarations (iface);
+		
+
+		Symbol result = iface;
+		while (sym.inner != null) {
+			sym = sym.inner;
+			var ns = new Namespace (sym.name, iface.source_reference);
+			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 Vala.Signal) {
+			iface.add_signal ((Vala.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 ();
+		expect (TokenType.ENUM);
+		var flags = parse_type_declaration_modifiers ();
+
+		var sym = parse_symbol_name (); 
+		var en = new Enum (sym.name, get_src_com (begin));
+		if (ModifierFlags.PRIVATE in flags) {
+			en.access = SymbolAccessibility.PRIVATE;
+		} else {
+			en.access = get_access (sym.name);
+		}
+		set_attributes (en, attrs);
+
+		expect (TokenType.EOL);
+		expect (TokenType.INDENT);
+		do {
+			if (current () == TokenType.DEDENT) {
+				// allow trailing comma
+				break;
+			}
+			var value_attrs = parse_attributes ();
+			var value_begin = get_location (); 
+			string id = parse_identifier ();
+			
+			var ev = new EnumValue (id, get_src (value_begin));
+			set_attributes (ev, value_attrs);
+			
+			if (accept (TokenType.ASSIGN)) {
+				ev.value = parse_expression ();
+			}
+			en.add_value (ev);
+			expect (TokenType.EOL);
+		} while (true);
+		
+		expect (TokenType.DEDENT);
+
+		Symbol result = en;
+		while (sym.inner != null) {
+			sym = sym.inner;
+			var ns = new Namespace (sym.name, en.source_reference);
+			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 ();
+		expect (TokenType.ERRORDOMAIN);
+		var flags = parse_type_declaration_modifiers ();
+
+		var sym = parse_symbol_name ();
+		var ed = new ErrorDomain (sym.name, get_src_com (begin));
+		if (ModifierFlags.PRIVATE in flags) {
+			ed.access = SymbolAccessibility.PRIVATE;
+		} else {
+			ed.access = get_access (sym.name);
+		}
+
+		set_attributes (ed, attrs);
+
+		expect (TokenType.EOL);
+		expect (TokenType.INDENT);
+
+		do {
+			if (current () == TokenType.DEDENT) {
+				// allow trailing comma
+				break;
+			}
+			var code_attrs = parse_attributes ();
+			string id = parse_identifier ();
+
+			var ec = new ErrorCode (id);
+			set_attributes (ec, code_attrs);
+			if (accept (TokenType.ASSIGN)) {
+				ec.value = parse_expression ();
+			}
+			ed.add_code (ec);
+			accept (TokenType.EOL);
+		} while (true);
+		
+		
+		expect (TokenType.DEDENT);
+
+		Symbol result = ed;
+		while (sym.inner != null) {
+			sym = sym.inner;
+			var ns = new Namespace (sym.name, ed.source_reference);
+			
+			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;
+	}
+
+	ModifierFlags parse_type_declaration_modifiers () {
+		ModifierFlags flags = 0;
+		while (true) {
+			switch (current ()) {
+			case TokenType.ABSTRACT:
+				next ();
+				flags |= ModifierFlags.ABSTRACT;
+				break;
+
+			case TokenType.EXTERN:
+				next ();
+				flags |= ModifierFlags.EXTERN;
+				break;
+
+			case TokenType.STATIC:
+				next ();
+				flags |= ModifierFlags.STATIC;
+				break;
+
+			case TokenType.PRIVATE:
+				next ();
+				flags |= ModifierFlags.PRIVATE;
+				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.EXTERN:
+				next ();
+				flags |= ModifierFlags.EXTERN;
+				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;
+			case TokenType.PRIVATE:
+				next ();
+				flags |= ModifierFlags.PRIVATE;
+				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 new FormalParameter.with_ellipsis (get_src (begin));
+		}
+
+		var direction = ParameterDirection.IN;
+		if (accept (TokenType.OUT)) {
+			direction = ParameterDirection.OUT;
+		} else if (accept (TokenType.REF)) {
+			direction = ParameterDirection.REF;
+		}
+
+		string id = parse_identifier ();
+
+		expect (TokenType.COLON);
+
+		DataType type;
+		if (direction == ParameterDirection.IN) {
+			 type = parse_type (false);
+		} else {
+			 type = parse_type (true);
+		}
+
+		var param = new FormalParameter (id, type, get_src (begin));
+		set_attributes (param, attrs);
+		param.direction = direction;
+		param.construct_parameter = false;
+		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 ();
+		CreationMethod method;
+
+		expect (TokenType.CONSTRUCT);
+
+		var flags = parse_member_declaration_modifiers ();
+
+
+		if (accept (TokenType.OPEN_PARENS)) {
+			/* create default name using class name */
+			method = new CreationMethod (class_name, null, get_src_com (begin));
+		} else {
+			var sym = parse_symbol_name ();
+			if (sym.inner == null) {
+			
+				if (sym.name != class_name) {
+					method = new CreationMethod (class_name, sym.name, get_src_com (begin));
+				} else {
+					method = new CreationMethod (sym.name, null, get_src_com (begin));
+				}
+			} else {
+				method = new CreationMethod (sym.inner.name, sym.name, get_src_com (begin));
+			}
+			expect (TokenType.OPEN_PARENS);
+		}
+
+
+		if (current () != TokenType.CLOSE_PARENS) {
+			do {
+				var param = parse_parameter ();
+				method.add_parameter (param);
+			} while (accept (TokenType.COMMA));
+		}
+		expect (TokenType.CLOSE_PARENS);
+		if (accept (TokenType.RAISES)) {
+			do {
+				method.add_error_domain (parse_type ());
+			} while (accept (TokenType.COMMA));
+		}
+		method.access = SymbolAccessibility.PUBLIC;
+		set_attributes (method, attrs);
+		method.binding = MemberBinding.STATIC;
+
+		if (accept_block ()) {
+			method.body = parse_block ();
+		}
+		
+		return method;
+	}
+
+	Symbol parse_delegate_declaration (Gee.List<Attribute>? attrs) throws ParseError {
+		var begin = get_location ();
+		DataType type;
+
+		expect (TokenType.DELEGATE);
+
+		var flags = parse_member_declaration_modifiers ();
+
+		var sym = parse_symbol_name ();
+
+		var type_param_list = parse_type_parameter_list ();
+
+
+		var params = new ArrayList<FormalParameter> ();
+
+		expect (TokenType.OPEN_PARENS);
+		if (current () != TokenType.CLOSE_PARENS) {
+			do {
+				var param = parse_parameter ();
+				params.add (param);
+			} while (accept (TokenType.COMMA));
+		}
+		expect (TokenType.CLOSE_PARENS);
+
+		if (accept (TokenType.COLON)) {
+			type = parse_type ();
+			
+		} else {
+			type = new VoidType ();
+		}
+
+		if (accept (TokenType.RAISES)) {
+			do {
+				parse_type ();
+			} while (accept (TokenType.COMMA));
+		}
+
+		expect_terminator ();
+
+		var d = new Delegate (sym.name, type, get_src_com (begin));
+		if (ModifierFlags.PRIVATE in flags) {
+			d.access = SymbolAccessibility.PRIVATE;
+		} else {
+			d.access = get_access (sym.name);
+		}
+
+		set_attributes (d, attrs);
+
+		foreach (TypeParameter type_param in type_param_list) {
+			d.add_type_parameter (type_param);
+		}
+
+		foreach (FormalParameter formal_param in params) {
+			d.add_parameter (formal_param);
+		}
+
+		if (!(ModifierFlags.STATIC in flags)) {
+			d.has_target = true;
+		}
+
+
+		Symbol result = d;
+		while (sym.inner != null) {
+			sym = sym.inner;
+			var ns = new Namespace (sym.name, d.source_reference);
+
+			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.OF)) {
+			do {
+				var begin = get_location ();
+				string id = parse_identifier ();
+				list.add (new TypeParameter (id, get_src (begin)));
+			} while (accept (TokenType.COMMA));
+
+		}
+		return list;
+	}
+
+	void skip_type_argument_list () throws ParseError {
+		if (accept (TokenType.OF)) {
+			do {
+				skip_type ();
+			} while (accept (TokenType.COMMA));
+		}
+	}
+
+	// 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.OF)) {
+			var list = new ArrayList<DataType> ();
+			do {
+				switch (current ()) {
+				case TokenType.VOID:
+				case TokenType.DYNAMIC:
+				case TokenType.WEAK:
+				case TokenType.IDENTIFIER:
+					var type = parse_type ();
+
+					list.add (type);
+					break;
+				default:
+					rollback (begin);
+					return null;
+				}
+			} while (accept (TokenType.COMMA));
+
+			return list;
+		}
+		return null;
+	}
+
+	MemberAccess parse_member_name () throws ParseError {
+		var begin = get_location ();
+		MemberAccess expr = null;
+		do {
+			string id = parse_identifier ();
+			Gee.List<DataType> type_arg_list = parse_type_argument_list (false);
+			expr = new MemberAccess (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.CLASS:
+		case TokenType.CONST:
+		case TokenType.DEF:
+		case TokenType.DELEGATE:
+		case TokenType.ENUM:
+		case TokenType.ERRORDOMAIN:
+		case TokenType.EVENT:
+		case TokenType.FINAL:
+		case TokenType.INIT:
+		case TokenType.INTERFACE:
+		case TokenType.NAMESPACE:
+		case TokenType.OVERRIDE:
+		case TokenType.PROP:
+		case TokenType.STRUCT:
+			return true;
+		default:
+			return false;
+		}
+	}
+}
+

Added: trunk/vala/valageniescanner.vala
==============================================================================
--- (empty file)
+++ trunk/vala/valageniescanner.vala	Mon May 19 20:28:13 2008
@@ -0,0 +1,1017 @@
+/* valageniescanner.vala
+ *
+ * Copyright (C) 2008  Jamie McCracken, JÃrg Billeter
+ * Based on code by 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:
+ * 	Jamie McCracken jamiemcc gnome org
+ */
+
+using GLib;
+using Gee;
+
+/**
+ * Lexical scanner for Genie source files.
+ */
+public class Vala.Genie.Scanner : Object {
+	public SourceFile source_file { get; construct; }
+
+	char* begin;
+	char* current;
+	char* end;
+
+	int line;
+	int column;
+
+	int current_indent_level;
+	int indent_level;
+	int pending_dedents;
+
+	TokenType last_token;
+	bool parse_started;
+
+	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;
+		current_indent_level = 0;
+		indent_level = 0;
+		pending_dedents = 0;
+
+		parse_started = false;
+		last_token = TokenType.NONE;
+		
+	}
+
+	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;
+			case 'o':
+				if (matches (begin, "of")) return TokenType.OF;
+				
+				if (matches (begin, "or")) return TokenType.OP_OR;
+				break;
+			case 't':
+				if (matches (begin, "to")) return TokenType.TO;
+				break;
+			}
+			break;
+		case 3:
+			switch (begin[0]) {
+			case 'a':
+				if (matches (begin, "and")) return TokenType.OP_AND;
+				break;
+			case 'd':
+				if (matches (begin, "def")) return TokenType.DEF;
+				break;
+			case 'f':
+				if (matches (begin, "for")) return TokenType.FOR;
+				break;
+			case 'g':
+				if (matches (begin, "get")) return TokenType.GET;
+				break;
+			case 'i':
+				if (matches (begin, "isa")) return TokenType.ISA;
+				break;
+			case 'n':
+				switch (begin[1]) {
+				case 'e':
+					if (matches (begin, "new")) return TokenType.NEW;
+					break;
+				case 'o':
+					if (matches (begin, "not")) return TokenType.OP_NEG;
+					break;
+				}
+				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 '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 'i':
+				if (matches (begin, "init")) return TokenType.INIT;
+				break;
+			case 'l':
+				if (matches (begin, "lock")) return TokenType.LOCK;
+				break;
+			case 'n':
+				if (matches (begin, "null")) return TokenType.NULL;
+				break;
+			case 'p':
+				switch (begin[1]) {
+				case 'a':
+					if (matches (begin, "pass")) return TokenType.PASS;
+					break;
+				case 'r':
+					if (matches (begin, "prop")) return TokenType.PROP;
+					break;
+				}
+				break;
+			case 's':
+				if (matches (begin, "self")) return TokenType.THIS;
+				break;	
+			case 't':
+				if (matches (begin, "true")) return TokenType.TRUE;
+				break;
+			case 'u':
+				if (matches (begin, "uses")) return TokenType.USES;
+				break;
+			case 'v':
+				if (matches (begin, "void")) return TokenType.VOID;
+				break;
+			case 'w':
+				switch (begin[1]) {
+				case 'e':
+					if (matches (begin, "weak")) return TokenType.WEAK;
+					break;
+				case 'h':
+					if (matches (begin, "when")) return TokenType.WHEN;
+					break;
+				}
+				break;
+			}
+			break;
+		case 5:
+			switch (begin[0]) {
+			case 'b':
+				if (matches (begin, "break")) return TokenType.BREAK;
+				break;
+			case 'c':
+				switch (begin[1]) {
+				case 'l':
+					if (matches (begin, "class")) return TokenType.CLASS;
+					break;
+				case 'o':
+					if (matches (begin, "const")) return TokenType.CONST;
+					break;
+				}
+				break;
+			case 'e':
+				if (matches (begin, "event")) return TokenType.EVENT;
+				break;
+			case 'f':
+				switch (begin[1]) {
+				case 'a':
+					if (matches (begin, "false")) return TokenType.FALSE;
+					break;
+				case 'i':
+					if (matches (begin, "final")) return TokenType.FINAL;
+					break;
+				}
+				break;
+			case 'p':
+				if (matches (begin, "print")) return TokenType.PRINT;
+				break;
+			case 's':
+				if (matches (begin, "super")) return TokenType.SUPER;
+				break;
+			case 'r':
+				if (matches (begin, "raise")) return TokenType.RAISE;
+				break;
+			case 'w':
+				if (matches (begin, "while")) return TokenType.WHILE;
+				break;
+			}
+			break;
+		case 6:
+			switch (begin[0]) {
+			case 'a':
+				if (matches (begin, "assert")) return TokenType.ASSERT;
+				break;
+			case 'd':
+				switch (begin[1]) {
+				case 'e':
+					if (matches (begin, "delete")) return TokenType.DELETE;
+					break;
+				case 'o':
+					if (matches (begin, "downto")) return TokenType.DOWNTO;
+					break;
+				}
+				break;
+			case 'e':
+				switch (begin[1]) {
+				case 'x':
+					switch (begin[2]) {
+					case 'c':
+						if (matches (begin, "except")) return TokenType.EXCEPT;
+						break;
+					case 't':
+						if (matches (begin, "extern")) return TokenType.EXTERN;
+						break;
+					}
+					break;
+				}
+				break;
+			case 'i':
+				if (matches (begin, "inline")) return TokenType.INLINE;
+				break;
+			case 'p':
+				if (matches (begin, "public")) return TokenType.PUBLIC;
+				break;
+			case 'r':
+				switch (begin[1]) {
+				case 'a':
+					if (matches (begin, "raises")) return TokenType.RAISES;
+					break;
+				case 'e':
+					if (matches (begin, "return")) return TokenType.RETURN;
+					break;
+				}
+				break;
+			case 's':
+				switch (begin[1]) {
+				case 'i':
+					if (matches (begin, "sizeof")) return TokenType.SIZEOF;
+					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;
+				}
+				break;
+			case 't':
+				if (matches (begin, "typeof")) return TokenType.TYPEOF;
+				break;
+			}
+			break;
+		case 7:
+			switch (begin[0]) {
+			case 'd':
+				switch (begin[1]) {
+				case 'e':
+					if (matches (begin, "default")) return TokenType.DEFAULT;
+					break;
+				case 'y':
+					if (matches (begin, "dynamic")) return TokenType.DYNAMIC;
+					break;
+				}
+				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':
+				switch (begin[2]) {
+				case 'a':
+					if (matches (begin, "readonly")) return TokenType.READONLY;
+					break;
+				case 'q':
+					if (matches (begin, "requires")) return TokenType.REQUIRES;
+					break;
+				}
+				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 'e':
+				if (matches (begin, "exception")) return TokenType.ERRORDOMAIN;
+				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;
+			case 'w':
+				if (matches (begin, "writeonly")) return TokenType.WRITEONLY;
+				break;
+			}
+			break;
+
+		}
+		return TokenType.IDENTIFIER;
+	}
+
+	public TokenType read_token (out SourceLocation token_begin, out SourceLocation token_end) {
+		/* emit dedents if outstanding before checking any other chars */
+
+		if (pending_dedents > 0) {
+			pending_dedents--;
+			indent_level--;
+
+
+			token_begin.pos = current;
+			token_begin.line = line;
+			token_begin.column = column;
+
+			token_end.pos = current;
+			token_end.line = line;
+			token_end.column = column;
+
+			last_token = TokenType.DEDENT;
+
+			return TokenType.DEDENT;
+		}
+
+
+		/* scrub whitespace (excluding newlines) and comments */
+		space ();
+
+		/* handle line continuation */
+		while (current < end && current[0] == '\\' && current[1] == '\n') {
+			current += 2;
+		}
+
+		/* handle non-consecutive new line once parsing is underway - EOL */
+		if (newline () && parse_started && last_token != TokenType.EOL && last_token != TokenType.SEMICOLON) {
+			token_begin.pos = current;
+			token_begin.line = line;
+			token_begin.column = column;
+
+			token_end.pos = current;
+			token_end.line = line;
+			token_end.column = column;
+
+			last_token = TokenType.EOL;
+
+			return TokenType.EOL;
+		} 
+
+
+		while (skip_newlines ()) {
+			token_begin.pos = current;
+			token_begin.line = line;
+			token_begin.column = column;
+
+			current_indent_level = count_tabs ();
+
+			/* if its an empty new line then ignore */
+			if (current_indent_level == -1)  {
+				continue;
+			} 
+
+			if (current_indent_level > indent_level) {
+				indent_level = current_indent_level;
+
+				token_end.pos = current;
+				token_end.line = line;
+				token_end.column = column;
+
+				last_token = TokenType.INDENT;
+
+				return TokenType.INDENT;
+			} else if (current_indent_level < indent_level) {
+				indent_level--;
+
+				pending_dedents = (indent_level - current_indent_level);
+
+				token_end.pos = current;
+				token_end.line = line;
+				token_end.column = column;
+
+				last_token = TokenType.DEDENT;
+
+				return TokenType.DEDENT;
+			}
+		}
+
+		TokenType type;
+		char* begin = current;
+		token_begin.pos = begin;
+		token_begin.line = line;
+		token_begin.column = column;
+
+		int token_length_in_chars = -1;
+
+		parse_started = true;
+
+		if (current >= end) {
+			if (indent_level > 0) {
+				indent_level--;
+
+				pending_dedents = indent_level;
+
+				type = TokenType.DEDENT;
+			} else {
+				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] == '@') {
+			int len = 0;
+			if (current[1] == '@') {
+				token_begin.pos += 2; // @@ is not part of the identifier
+				current += 2;
+			} else {
+				current++;
+				len = 1;
+			}
+			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++;
+				last_token = TokenType.STRING_LITERAL;
+				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;
+		
+		last_token = type;
+
+		return type;
+	}
+
+	int count_tabs ()
+	{
+		int tab_count = 0;
+
+		while (current < end && current[0] == '\t') {
+			current++;
+			column++;
+			tab_count++;
+		}
+
+
+		/* ignore comments and whitspace and other lines that contain no code */
+
+		space ();
+
+		if ((current < end) && (current[0] == '\n')) return -1;
+
+		return tab_count;
+	}
+
+	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 () && current[0] != '\n' ) {
+			
+			found = true;
+			current++;
+			column++;
+		}
+		return found;
+	}
+
+	inline bool newline () {
+		if (current[0] == '\n') {
+			return true;
+		}
+
+		return false;
+	}
+
+	bool skip_newlines () {
+		bool new_lines = false;
+
+		while (newline ()) {
+			current++;
+
+			line++;
+			column = 1;
+			current_indent_level = 0;
+
+			new_lines = true;
+		}
+
+		return new_lines;
+	}
+
+	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);
+
+			if (current[0] == '\n') {
+				current++;
+				line++;
+				column = 1;
+				current_indent_level = 0;
+			}
+		} 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;
+	}
+}
+

Added: trunk/vala/valagenietokentype.vala
==============================================================================
--- (empty file)
+++ trunk/vala/valagenietokentype.vala	Mon May 19 20:28:13 2008
@@ -0,0 +1,293 @@
+/* valagenietokentype.vala
+ *
+ * Copyright (C) 2008  Jamie McCracken, JÃrg Billeter
+ * Based on code by 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:
+ * 	Jamie McCracken jamiemcc gnome org
+ */
+
+using GLib;
+
+public enum Vala.Genie.TokenType {
+	NONE,
+	ABSTRACT,
+	AS,
+	ASSERT,
+	ASSIGN,
+	ASSIGN_ADD,
+	ASSIGN_BITWISE_AND,
+	ASSIGN_BITWISE_OR,
+	ASSIGN_BITWISE_XOR,
+	ASSIGN_DIV,
+	ASSIGN_MUL,
+	ASSIGN_PERCENT,
+	ASSIGN_SHIFT_LEFT,
+	ASSIGN_SUB,
+	BITWISE_AND,
+	BITWISE_OR,
+	BREAK,
+	CARRET,
+	CASE,
+	CHARACTER_LITERAL,
+	CLASS,
+	CLOSE_BRACE,
+	CLOSE_BRACKET,
+	CLOSE_PARENS,
+	COLON,
+	COMMA,
+	CONST,
+	CONSTRUCT,
+	CONTINUE,
+	DEDENT,
+	DEF,
+	DEFAULT,
+	DELEGATE,
+	DELETE,
+	DIV,
+	DO,
+	DOT,
+	DOWNTO,
+	DYNAMIC,
+	ELLIPSIS,
+	ELSE,
+	ENUM,
+	ENSURES,
+	ERRORDOMAIN,
+	EOF,
+	EOL,
+	EVENT,
+	EXCEPT,
+	EXTERN,
+	FALSE,
+	FINAL,
+	FINALLY,
+	FOR,
+	FOREACH,
+	GET,
+	HASH,
+	IDENTIFIER,
+	IF,
+	IN,
+	INDENT,
+	INIT,
+	INLINE,
+	INTEGER_LITERAL,
+	INTERFACE,
+	INTERR,
+	IS,
+	ISA,
+	LAMBDA,
+	LOCK,
+	MINUS,
+	NAMESPACE,
+	NEW,
+	NULL,
+	OF,
+	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,
+	PASS,
+	PERCENT,
+	PLUS,
+	PRINT,
+	PRIVATE,
+	PROP,
+	PROTECTED,
+	PUBLIC,
+	RAISE,
+	RAISES,
+	REAL_LITERAL,
+	READONLY,
+	REF,
+	REQUIRES,
+	RETURN,
+	SEMICOLON,
+	SET,
+	SIZEOF,
+	STAR,
+	STATIC,
+	STRING_LITERAL,
+	STRUCT,
+	SUPER,
+	THIS,
+	TILDE,
+	TO,
+	TRUE,
+	TRY,
+	TYPEOF,
+	USES,
+	VAR,
+	VIRTUAL,
+	VOID,
+	VOLATILE,
+	WEAK,
+	WHEN,
+	WHILE,
+	WRITEONLY;
+
+	public weak string to_string () {
+		switch (this) {
+		case ABSTRACT: return "`abstract'";
+		case AS: return "`as'";
+		case ASSERT: return "`assert'";
+		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 BITWISE_AND: return "`&'";
+		case BITWISE_OR: return "`|'";
+		case BREAK: return "`break'";
+		case CARRET: return "`^'";
+		case CASE: return "`case'";
+		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 DEDENT: return "`dedent'";
+		case DEF: return "`def'";
+		case DEFAULT: return "`default'";
+		case DELEGATE: return "`delegate'";
+		case DELETE: return "`delete'";
+		case DIV: return "`/'";
+		case DO: return "`do'";
+		case DOT: return "`.'";
+		case DOWNTO: return "`downto'";
+		case DYNAMIC: return "`dynamic'";
+		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 EOL: return "end of line";
+		case EVENT: return "event";
+		case EXCEPT: return "`except'";
+		case EXTERN: return "`extern'";
+		case FALSE: return "`false'";
+		case FINAL: return "`final'";
+		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 INDENT: return "`tab indent'";
+		case INIT: return "`init'";
+		case INLINE: return "`inline'";
+		case INTEGER_LITERAL: return "integer literal";
+		case INTERFACE: return "`interface'";
+		case INTERR: return "`?'";
+		case IS: return "`is'";
+		case ISA: return "`isa'";
+		case LAMBDA: return "`=>'";
+		case LOCK: return "`lock'";
+		case MINUS: return "`-'";
+		case NAMESPACE: return "`namespace'";
+		case NEW: return "`new'";
+		case NULL: return "`null'";
+		case OF: return "`of'";		
+		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 PASS: return "`pass'";
+		case PERCENT: return "`%'";
+		case PLUS: return "`+'";
+		case PRINT: return "`print'";
+		case PRIVATE: return "`private'";
+		case PROP: return "`prop'";
+		case PROTECTED: return "`protected'";
+		case PUBLIC: return "`public'";
+		case RAISE: return "`raise'";
+		case RAISES: return "`raises'";
+		case READONLY: return "`readonly'";
+		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 SIZEOF: return "`sizeof'";
+		case STAR: return "`*'";
+		case STATIC: return "`static'";
+		case STRING_LITERAL: return "string literal";
+		case STRUCT: return "`struct'";
+		case SUPER: return "`super'";
+		case THIS: return "`self'";
+		case TILDE: return "`~'";
+		case TO: return "`to'";
+		case TRUE: return "`true'";
+		case TRY: return "`try'";
+		case TYPEOF: return "`typeof'";
+		case USES: return "`uses'";
+		case VAR: return "`var'";
+		case VIRTUAL: return "`virtual'";
+		case VOID: return "`void'";
+		case VOLATILE: return "`volatile'";
+		case WEAK: return "`weak'";
+		case WHEN: return "`when'";
+		case WHILE: return "`while'";
+		case WRITEONLY: return "`writeonly'";
+		default: return "unknown token";
+		}
+	}
+}
+

Modified: trunk/vala/valaparser.vala
==============================================================================
--- trunk/vala/valaparser.vala	(original)
+++ trunk/vala/valaparser.vala	Mon May 19 20:28:13 2008
@@ -64,8 +64,8 @@
 	}
 
 	/**
-	 * Parse all source files in the specified code context and build a
-	 * code tree.
+	 * Parses all .vala and .vapi source files in the specified code
+	 * context and builds a code tree.
 	 *
 	 * @param context a code context
 	 */

Modified: trunk/vala/valasourcefile.vala
==============================================================================
--- trunk/vala/valasourcefile.vala	(original)
+++ trunk/vala/valasourcefile.vala	Mon May 19 20:28:13 2008
@@ -180,6 +180,11 @@
 		return "%s/%s".printf (context.directory, get_subdir ());
 	}
 
+	private string get_basename () {
+		long dot = filename.pointer_to_offset (filename.rchr (-1, '.'));
+		return Path.get_basename (filename.substring (0, dot));
+	}
+
 	/**
 	 * Returns the filename to use when generating C header files.
 	 *
@@ -187,9 +192,7 @@
 	 */
 	public string get_cheader_filename () {
 		if (cheader_filename == null) {
-			var basename = filename.ndup ((uint) (filename.len () - ".vala".len ()));
-			basename = Path.get_basename (basename);
-			cheader_filename = "%s%s.h".printf (get_destination_directory (), basename);
+			cheader_filename = "%s%s.h".printf (get_destination_directory (), get_basename ());
 		}
 		return cheader_filename;
 	}
@@ -201,9 +204,7 @@
 	 */
 	public string get_csource_filename () {
 		if (csource_filename == null) {
-			var basename = filename.ndup ((uint) (filename.len () - ".vala".len ()));
-			basename = Path.get_basename (basename);
-			csource_filename = "%s%s.c".printf (get_destination_directory (), basename);
+			csource_filename = "%s%s.c".printf (get_destination_directory (), get_basename ());
 		}
 		return csource_filename;
 	}
@@ -216,9 +217,7 @@
 	 */
 	public string get_cinclude_filename () {
 		if (cinclude_filename == null) {
-			var basename = filename.ndup ((uint) (filename.len () - ".vala".len ()));
-			basename = Path.get_basename (basename);
-			cinclude_filename = "%s%s.h".printf (get_subdir (), basename);
+			cinclude_filename = "%s%s.h".printf (get_subdir (), get_basename ());
 		}
 		return cinclude_filename;
 	}



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]