summaryrefslogtreecommitdiff
path: root/vala/valagenieparser.vala
diff options
context:
space:
mode:
Diffstat (limited to 'vala/valagenieparser.vala')
-rw-r--r--vala/valagenieparser.vala3210
1 files changed, 3210 insertions, 0 deletions
diff --git a/vala/valagenieparser.vala b/vala/valagenieparser.vala
new file mode 100644
index 000000000..f2f2e90ef
--- /dev/null
+++ b/vala/valagenieparser.vala
@@ -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;
+ }
+ }
+}
+