vala r1194 - in trunk: . vala
- From: juergbi svn gnome org
- To: svn-commits-list gnome org
- Subject: vala r1194 - in trunk: . vala
- Date: Sun, 13 Apr 2008 10:25:26 +0100 (BST)
Author: juergbi
Date: Sun Apr 13 10:25:25 2008
New Revision: 1194
URL: http://svn.gnome.org/viewvc/vala?rev=1194&view=rev
Log:
2008-04-13 Juerg Billeter <j bitron ch>
* vala/Makefile.am, vala/valaassignment.vala,
vala/valabinaryexpression.vala, vala/valaclass.vala,
vala/valanamespace.vala, vala/valaparser.vala,
vala/valascanner.vala, vala/valascope.vala,
vala/valasourcefile.vala, vala/valasourcelocation.vala,
vala/valatokentype.vala, vala/valatuple.vala,
vala/valaunaryexpression.vala, vala/valaunresolvedtype.vala:
Replace generated Vala scanner and parser by handwritten classes
Added:
trunk/vala/valascanner.vala
trunk/vala/valasourcelocation.vala
trunk/vala/valatokentype.vala
trunk/vala/valatuple.vala
Removed:
trunk/vala/parser.y
trunk/vala/scanner.l
Modified:
trunk/ChangeLog
trunk/vala/Makefile.am
trunk/vala/valaassignment.vala
trunk/vala/valabinaryexpression.vala
trunk/vala/valaclass.vala
trunk/vala/valanamespace.vala
trunk/vala/valaparser.vala
trunk/vala/valascope.vala
trunk/vala/valasourcefile.vala
trunk/vala/valaunaryexpression.vala
trunk/vala/valaunresolvedtype.vala
Modified: trunk/vala/Makefile.am
==============================================================================
--- trunk/vala/Makefile.am (original)
+++ trunk/vala/Makefile.am Sun Apr 13 10:25:25 2008
@@ -7,8 +7,7 @@
-DPACKAGE_DATADIR=\"$(pkgdatadir)\" \
$(NULL)
-BUILT_SOURCES = parser.h vala.vala.stamp
-AM_YFLAGS = -d
+BUILT_SOURCES = vala.vala.stamp
noinst_LTLIBRARIES = \
libvalacore.la
@@ -106,6 +105,7 @@
valareferencetype.vala \
valareport.vala \
valareturnstatement.vala \
+ valascanner.vala \
valascope.vala \
valasemanticanalyzer.vala \
valasignal.vala \
@@ -113,6 +113,7 @@
valasizeofexpression.vala \
valasourcefile.vala \
valasourcefilecycle.vala \
+ valasourcelocation.vala \
valasourcereference.vala \
valastatement.vala \
valastringliteral.vala \
@@ -123,7 +124,9 @@
valasymbol.vala \
valasymbolresolver.vala \
valathrowstatement.vala \
+ valatokentype.vala \
valatrystatement.vala \
+ valatuple.vala \
valatypecheck.vala \
valatypeofexpression.vala \
valatypeparameter.vala \
@@ -139,8 +142,6 @@
$(NULL)
libvalacore_la_SOURCES = \
- parser.y \
- scanner.l \
vala.h \
vala.vala.stamp \
$(libvalacore_la_VALASOURCES:.vala=.c) \
Modified: trunk/vala/valaassignment.vala
==============================================================================
--- trunk/vala/valaassignment.vala (original)
+++ trunk/vala/valaassignment.vala Sun Apr 13 10:25:25 2008
@@ -94,6 +94,7 @@
}
public enum Vala.AssignmentOperator {
+ NONE,
SIMPLE,
BITWISE_OR,
BITWISE_AND,
Modified: trunk/vala/valabinaryexpression.vala
==============================================================================
--- trunk/vala/valabinaryexpression.vala (original)
+++ trunk/vala/valabinaryexpression.vala Sun Apr 13 10:25:25 2008
@@ -130,6 +130,7 @@
}
public enum Vala.BinaryOperator {
+ NONE,
PLUS,
MINUS,
MUL,
Modified: trunk/vala/valaclass.vala
==============================================================================
--- trunk/vala/valaclass.vala (original)
+++ trunk/vala/valaclass.vala Sun Apr 13 10:25:25 2008
@@ -193,10 +193,16 @@
*/
public void add_method (Method! m) {
if (m.instance || m is CreationMethod) {
+ if (m.this_parameter != null) {
+ m.scope.remove (m.this_parameter.name);
+ }
m.this_parameter = new FormalParameter ("this", new ClassType (this));
m.scope.add (m.this_parameter.name, m.this_parameter);
}
if (!(m.return_type is VoidType) && m.get_postconditions ().size > 0) {
+ if (m.result_var != null) {
+ m.scope.remove (m.result_var.name);
+ }
m.result_var = new VariableDeclarator ("result");
m.result_var.type_reference = m.return_type.copy ();
m.scope.add (m.result_var.name, m.result_var);
Modified: trunk/vala/valanamespace.vala
==============================================================================
--- trunk/vala/valanamespace.vala (original)
+++ trunk/vala/valanamespace.vala Sun Apr 13 10:25:25 2008
@@ -167,6 +167,60 @@
}
/**
+ * Returns a copy of the list of enums.
+ *
+ * @return enum list
+ */
+ public Collection<Enum> get_enums () {
+ return new ReadOnlyCollection<Enum> (enums);
+ }
+
+ /**
+ * Returns a copy of the list of error domains.
+ *
+ * @return error domain list
+ */
+ public Collection<ErrorDomain> get_error_domains () {
+ return new ReadOnlyCollection<ErrorDomain> (error_domains);
+ }
+
+ /**
+ * Returns a copy of the list of fields.
+ *
+ * @return field list
+ */
+ public Collection<Field> get_fields () {
+ return new ReadOnlyCollection<Field> (fields);
+ }
+
+ /**
+ * Returns a copy of the list of constants.
+ *
+ * @return constant list
+ */
+ public Collection<Constant> get_constants () {
+ return new ReadOnlyCollection<Constant> (constants);
+ }
+
+ /**
+ * Returns a copy of the list of delegates.
+ *
+ * @return delegate list
+ */
+ public Collection<Delegate> get_delegates () {
+ return new ReadOnlyCollection<Delegate> (delegates);
+ }
+
+ /**
+ * Returns a copy of the list of methods.
+ *
+ * @return method list
+ */
+ public Collection<Method> get_methods () {
+ return new ReadOnlyCollection<Method> (methods);
+ }
+
+ /**
* Adds the specified constant to this namespace.
*
* @param constant a constant
Modified: trunk/vala/valaparser.vala
==============================================================================
--- trunk/vala/valaparser.vala (original)
+++ trunk/vala/valaparser.vala Sun Apr 13 10:25:25 2008
@@ -1,6 +1,6 @@
/* valaparser.vala
*
- * Copyright (C) 2006-2007 JÃrg Billeter
+ * Copyright (C) 2006-2008 JÃrg Billeter
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@@ -21,14 +21,47 @@
*/
using GLib;
+using Gee;
/**
* Code visitor parsing all Vala source files.
*/
public class Vala.Parser : CodeVisitor {
- private string comment;
- private string _file_comment;
-
+ Scanner scanner;
+
+ CodeContext context;
+
+ // token buffer
+ TokenInfo[] tokens;
+ // index of current token in buffer
+ int index;
+ // number of tokens in buffer
+ int size;
+
+ string comment;
+
+ const int BUFFER_SIZE = 32;
+
+ struct TokenInfo {
+ public TokenType type;
+ public SourceLocation begin;
+ public SourceLocation end;
+ }
+
+ enum ModifierFlags {
+ NONE,
+ ABSTRACT = 1 << 0,
+ CLASS = 1 << 1,
+ INLINE = 1 << 2,
+ OVERRIDE = 1 << 3,
+ STATIC = 1 << 4,
+ VIRTUAL = 1 << 5
+ }
+
+ construct {
+ tokens = new TokenInfo[BUFFER_SIZE];
+ }
+
/**
* Parse all source files in the specified code context and build a
* code tree.
@@ -36,57 +69,2608 @@
* @param context a code context
*/
public void parse (CodeContext! context) {
+ this.context = context;
context.accept (this);
}
public override void visit_source_file (SourceFile! source_file) {
if (source_file.filename.has_suffix (".vala") || source_file.filename.has_suffix (".vapi")) {
parse_file (source_file);
- source_file.comment = _file_comment;
}
+ }
- _file_comment = null;
+ inline bool next () {
+ index = (index + 1) % BUFFER_SIZE;
+ size--;
+ if (size <= 0) {
+ SourceLocation begin, end;
+ TokenType type = scanner.read_token (out begin, out end);
+ tokens[index].type = type;
+ tokens[index].begin = begin;
+ tokens[index].end = end;
+ size = 1;
+ }
+ return (tokens[index].type != TokenType.EOF);
}
- /**
- * Adds the specified comment to the comment stack.
- *
- * @param comment_item a comment string
- * @param file_comment true if file header comment, false otherwise
- */
- public void push_comment (string! comment_item, bool file_comment) {
- if (comment == null) {
- comment = comment_item;
- } else {
- comment = "%s\n%s".printf (comment, comment_item);
- }
- if (file_comment) {
- _file_comment = comment;
- comment = null;
+ 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;
}
-
- /**
- * Clears and returns the content of the comment stack.
- *
- * @return saved comment
- */
- public string pop_comment () {
- if (comment == null) {
- return null;
+
+ 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;
}
-
- String result = new String (comment);
+
+ throw new ParseError.SYNTAX (get_error ("expected %s".printf (type.to_string ())));
+ }
+
+ inline SourceLocation get_location () {
+ return tokens[index].begin;
+ }
+
+ string get_last_string () {
+ int last_index = (index + BUFFER_SIZE - 1) % BUFFER_SIZE;
+ return ((string) tokens[last_index].begin.pos).ndup ((tokens[last_index].end.pos - tokens[last_index].begin.pos));
+ }
+
+ SourceReference get_src (SourceLocation begin) {
+ int last_index = (index + BUFFER_SIZE - 1) % BUFFER_SIZE;
+
+ return new SourceReference (scanner.source_file, begin.line, begin.column, tokens[last_index].end.line, tokens[last_index].end.column);
+ }
+
+ SourceReference get_src_com (SourceLocation begin) {
+ int last_index = (index + BUFFER_SIZE - 1) % BUFFER_SIZE;
+
+ var src = new SourceReference.with_comment (scanner.source_file, begin.line, begin.column, tokens[last_index].end.line, tokens[last_index].end.column, comment);
comment = null;
+ return src;
+ }
+
+ void rollback (SourceLocation location) {
+ while (tokens[index].begin.pos != location.pos) {
+ prev ();
+ }
+ }
+
+ void skip_identifier () throws ParseError {
+ // also accept keywords as identifiers where there is no conflict
+ switch (current ()) {
+ case TokenType.ABSTRACT:
+ case TokenType.AS:
+ case TokenType.BASE:
+ case TokenType.BREAK:
+ case TokenType.CASE:
+ case TokenType.CATCH:
+ case TokenType.CLASS:
+ case TokenType.CONST:
+ case TokenType.CONSTRUCT:
+ case TokenType.CONTINUE:
+ case TokenType.DEFAULT:
+ case TokenType.DELEGATE:
+ case TokenType.DELETE:
+ case TokenType.DO:
+ case TokenType.ELSE:
+ case TokenType.ENUM:
+ case TokenType.ENSURES:
+ case TokenType.ERRORDOMAIN:
+ case TokenType.FALSE:
+ case TokenType.FINALLY:
+ case TokenType.FOR:
+ case TokenType.FOREACH:
+ case TokenType.GET:
+ case TokenType.IDENTIFIER:
+ case TokenType.IF:
+ case TokenType.IN:
+ case TokenType.INLINE:
+ case TokenType.INTERFACE:
+ case TokenType.IS:
+ case TokenType.LOCK:
+ case TokenType.NAMESPACE:
+ case TokenType.NEW:
+ case TokenType.NULL:
+ case TokenType.OUT:
+ case TokenType.OVERRIDE:
+ case TokenType.PRIVATE:
+ case TokenType.PROTECTED:
+ case TokenType.PUBLIC:
+ case TokenType.REF:
+ case TokenType.REQUIRES:
+ case TokenType.RETURN:
+ case TokenType.SET:
+ case TokenType.SIGNAL:
+ case TokenType.SIZEOF:
+ case TokenType.STATIC:
+ case TokenType.STRUCT:
+ case TokenType.SWITCH:
+ case TokenType.THIS:
+ case TokenType.THROW:
+ case TokenType.THROWS:
+ case TokenType.TRUE:
+ case TokenType.TRY:
+ case TokenType.TYPEOF:
+ case TokenType.USING:
+ case TokenType.VAR:
+ case TokenType.VIRTUAL:
+ case TokenType.VOID:
+ case TokenType.VOLATILE:
+ case TokenType.WEAK:
+ case TokenType.WHILE:
+ next ();
+ return;
+ }
+
+ throw new ParseError.SYNTAX (get_error ("expected identifier"));
+ }
+
+ string parse_identifier () throws ParseError {
+ skip_identifier ();
+ return get_last_string ();
+ }
+
+ Expression parse_literal () throws ParseError {
+ var begin = get_location ();
+
+ switch (current ()) {
+ case TokenType.TRUE:
+ next ();
+ return context.create_boolean_literal (true, get_src (begin));
+ case TokenType.FALSE:
+ next ();
+ return context.create_boolean_literal (false, get_src (begin));
+ case TokenType.INTEGER_LITERAL:
+ next ();
+ return context.create_integer_literal (get_last_string (), get_src (begin));
+ case TokenType.REAL_LITERAL:
+ next ();
+ return context.create_real_literal (get_last_string (), get_src (begin));
+ case TokenType.CHARACTER_LITERAL:
+ next ();
+ return context.create_character_literal (get_last_string (), get_src (begin));
+ case TokenType.STRING_LITERAL:
+ next ();
+ return context.create_string_literal (get_last_string (), get_src (begin));
+ case TokenType.NULL:
+ next ();
+ return context.create_null_literal (get_src (begin));
+ }
+
+ throw new ParseError.SYNTAX (get_error ("expected literal"));
+ }
+
+ public void parse_file (SourceFile source_file) {
+ scanner = new Scanner (source_file);
+
+ index = -1;
+ size = 0;
- weak string index;
- while ((index = result.str.chr (-1, '\t')) != null) {
- result.erase (result.str.pointer_to_offset (index), 1);
+ next ();
+
+ try {
+ parse_using_directives ();
+ parse_declarations (context.root, true);
+ } catch (ParseError e) {
+ // already reported
}
- return result.str;
+ scanner = null;
+ }
+
+ void skip_symbol_name () throws ParseError {
+ do {
+ skip_identifier ();
+ } while (accept (TokenType.DOT));
+ }
+
+ UnresolvedSymbol parse_symbol_name () throws ParseError {
+ var begin = get_location ();
+ UnresolvedSymbol sym = null;
+ do {
+ string name = parse_identifier ();
+ sym = new UnresolvedSymbol (sym, name, get_src (begin));
+ } while (accept (TokenType.DOT));
+ return sym;
+ }
+
+ void skip_type () throws ParseError {
+ if (accept (TokenType.VOID)) {
+ while (accept (TokenType.STAR)) {
+ }
+ return;
+ }
+ accept (TokenType.REF);
+ accept (TokenType.OUT);
+ accept (TokenType.WEAK);
+ skip_symbol_name ();
+ skip_type_argument_list ();
+ while (accept (TokenType.STAR)) {
+ }
+ if (accept (TokenType.OPEN_BRACKET)) {
+ do {
+ if (current () != TokenType.COMMA && current () != TokenType.CLOSE_BRACKET) {
+ parse_expression ();
+ }
+ } while (accept (TokenType.COMMA));
+ expect (TokenType.CLOSE_BRACKET);
+ }
+ accept (TokenType.OP_NEG);
+ accept (TokenType.INTERR);
+ accept (TokenType.HASH);
+ }
+
+ DataType parse_type () throws ParseError {
+ var begin = get_location ();
+
+ if (accept (TokenType.VOID)) {
+ DataType type = new VoidType ();
+ while (accept (TokenType.STAR)) {
+ type = new PointerType (type);
+ }
+ return type;
+ }
+
+ bool is_ref = accept (TokenType.REF);
+ bool is_out = !is_ref && accept (TokenType.OUT);
+
+ bool is_weak = accept (TokenType.WEAK);
+
+ var sym = parse_symbol_name ();
+ var type_arg_list = parse_type_argument_list (false);
+
+ int stars = 0;
+ while (accept (TokenType.STAR)) {
+ stars++;
+ }
+
+ int array_rank = 0;
+ if (accept (TokenType.OPEN_BRACKET)) {
+ do {
+ array_rank++;
+ // support for stack-allocated arrays
+ // also required for decision between expression and declaration statement
+ if (current () != TokenType.COMMA && current () != TokenType.CLOSE_BRACKET) {
+ parse_expression ();
+ }
+ }
+ while (accept (TokenType.COMMA));
+ expect (TokenType.CLOSE_BRACKET);
+ }
+
+ // deprecated
+ accept (TokenType.OP_NEG);
+
+ bool nullable = accept (TokenType.INTERR);
+
+ bool transfers_ownership = accept (TokenType.HASH);
+
+ var type = new UnresolvedType.from_symbol (sym, get_src (begin));
+ if (type_arg_list != null) {
+ foreach (DataType type_arg in type_arg_list) {
+ type.add_type_argument (type_arg);
+ }
+ }
+ type.is_ref = is_ref;
+ type.is_out = is_out;
+ type.is_weak = is_weak;
+ type.pointer_level = stars;
+ type.array_rank = array_rank;
+ type.nullable = nullable;
+ type.requires_null_check = nullable;
+ type.transfers_ownership = transfers_ownership;
+ return type;
+ }
+
+ Gee.List<Expression> parse_argument_list () throws ParseError {
+ var list = new ArrayList<Expression> ();
+ if (current () != TokenType.CLOSE_PARENS) {
+ do {
+ list.add (parse_expression ());
+ } while (accept (TokenType.COMMA));
+ }
+ return list;
+ }
+
+ Expression parse_primary_expression () throws ParseError {
+ var begin = get_location ();
+
+ Expression expr;
+
+ switch (current ()) {
+ case TokenType.TRUE:
+ case TokenType.FALSE:
+ case TokenType.INTEGER_LITERAL:
+ case TokenType.REAL_LITERAL:
+ case TokenType.CHARACTER_LITERAL:
+ case TokenType.STRING_LITERAL:
+ case TokenType.NULL:
+ expr = parse_literal ();
+ break;
+ case TokenType.OPEN_PARENS:
+ expr = parse_tuple ();
+ break;
+ case TokenType.THIS:
+ expr = parse_this_access ();
+ break;
+ case TokenType.BASE:
+ expr = parse_base_access ();
+ break;
+ case TokenType.NEW:
+ expr = parse_object_or_array_creation_expression ();
+ break;
+ case TokenType.SIZEOF:
+ expr = parse_sizeof_expression ();
+ break;
+ case TokenType.TYPEOF:
+ expr = parse_typeof_expression ();
+ break;
+ default:
+ expr = parse_simple_name ();
+ break;
+ }
+
+ // process primary expressions that start with an inner primary expression
+ bool found = true;
+ while (found) {
+ switch (current ()) {
+ case TokenType.DOT:
+ expr = parse_member_access (begin, expr);
+ break;
+ case TokenType.OP_PTR:
+ expr = parse_pointer_member_access (begin, expr);
+ break;
+ case TokenType.OPEN_PARENS:
+ expr = parse_invocation_expression (begin, expr);
+ break;
+ case TokenType.OPEN_BRACKET:
+ expr = parse_element_access (begin, expr);
+ break;
+ case TokenType.OP_INC:
+ expr = parse_post_increment_expression (begin, expr);
+ break;
+ case TokenType.OP_DEC:
+ expr = parse_post_decrement_expression (begin, expr);
+ break;
+ default:
+ found = false;
+ break;
+ }
+ }
+
+ return expr;
+ }
+
+ Expression parse_simple_name () throws ParseError {
+ var begin = get_location ();
+ string id = parse_identifier ();
+ var type_arg_list = parse_type_argument_list (true);
+ var expr = context.create_member_access (null, id, get_src (begin));
+ if (type_arg_list != null) {
+ foreach (DataType type_arg in type_arg_list) {
+ expr.add_type_argument (type_arg);
+ }
+ }
+ return expr;
+ }
+
+ Expression parse_tuple () throws ParseError {
+ var begin = get_location ();
+ expect (TokenType.OPEN_PARENS);
+ var expr_list = new ArrayList<Expression> ();
+ if (current () != TokenType.CLOSE_PARENS) {
+ do {
+ expr_list.add (parse_expression ());
+ } while (accept (TokenType.COMMA));
+ }
+ expect (TokenType.CLOSE_PARENS);
+ if (expr_list.size != 1) {
+ var tuple = new Tuple ();
+ foreach (Expression expr in expr_list) {
+ tuple.add_expression (expr);
+ }
+ return tuple;
+ }
+ return context.create_parenthesized_expression (expr_list.get (0), get_src (begin));
+ }
+
+ Expression parse_member_access (SourceLocation begin, Expression inner) throws ParseError {
+ expect (TokenType.DOT);
+ string id = parse_identifier ();
+ var type_arg_list = parse_type_argument_list (true);
+ var expr = context.create_member_access (inner, id, get_src (begin));
+ if (type_arg_list != null) {
+ foreach (DataType type_arg in type_arg_list) {
+ expr.add_type_argument (type_arg);
+ }
+ }
+ return expr;
+ }
+
+ Expression parse_pointer_member_access (SourceLocation begin, Expression inner) throws ParseError {
+ expect (TokenType.OP_PTR);
+ string id = parse_identifier ();
+ var type_arg_list = parse_type_argument_list (true);
+ var expr = context.create_member_access_pointer (inner, id, get_src (begin));
+ if (type_arg_list != null) {
+ foreach (DataType type_arg in type_arg_list) {
+ expr.add_type_argument (type_arg);
+ }
+ }
+ return expr;
+ }
+
+ Expression parse_invocation_expression (SourceLocation begin, Expression inner) throws ParseError {
+ expect (TokenType.OPEN_PARENS);
+ var arg_list = parse_argument_list ();
+ expect (TokenType.CLOSE_PARENS);
+
+ var expr = context.create_invocation_expression (inner, get_src (begin));
+ foreach (Expression arg in arg_list) {
+ expr.add_argument (arg);
+ }
+ return expr;
+ }
+
+ Expression parse_element_access (SourceLocation begin, Expression inner) throws ParseError {
+ expect (TokenType.OPEN_BRACKET);
+ var index_list = parse_expression_list ();
+ expect (TokenType.CLOSE_BRACKET);
+
+ var expr = context.create_element_access (inner, get_src (begin));
+ foreach (Expression index in index_list) {
+ expr.append_index (index);
+ }
+ return expr;
+ }
+
+ Gee.List<Expression> parse_expression_list () throws ParseError {
+ var list = new ArrayList<Expression> ();
+ do {
+ list.add (parse_expression ());
+ } while (accept (TokenType.COMMA));
+ return list;
+ }
+
+ Expression parse_this_access () throws ParseError {
+ var begin = get_location ();
+ expect (TokenType.THIS);
+ return context.create_member_access (null, "this", get_src (begin));
+ }
+
+ Expression parse_base_access () throws ParseError {
+ var begin = get_location ();
+ expect (TokenType.BASE);
+ return context.create_base_access (get_src (begin));
+ }
+
+ Expression parse_post_increment_expression (SourceLocation begin, Expression inner) throws ParseError {
+ expect (TokenType.OP_INC);
+ return context.create_postfix_expression (inner, true, get_src (begin));
+ }
+
+ Expression parse_post_decrement_expression (SourceLocation begin, Expression inner) throws ParseError {
+ expect (TokenType.OP_DEC);
+ return context.create_postfix_expression (inner, false, get_src (begin));
+ }
+
+ Expression parse_object_or_array_creation_expression () throws ParseError {
+ var begin = get_location ();
+ expect (TokenType.NEW);
+ var member = parse_member_name ();
+ if (accept (TokenType.OPEN_PARENS)) {
+ return parse_object_creation_expression (begin, member);
+ } else if (accept (TokenType.OPEN_BRACKET)) {
+ return parse_array_creation_expression (begin, member);
+ } else {
+ 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 = context.create_object_creation_expression (member, get_src (begin));
+ foreach (Expression arg in arg_list) {
+ expr.add_argument (arg);
+ }
+ foreach (MemberInitializer initializer in init_list) {
+ expr.add_member_initializer (initializer);
+ }
+ return expr;
+ }
+
+ Expression parse_array_creation_expression (SourceLocation begin, MemberAccess member) throws ParseError {
+ bool size_specified = false;
+ var size_specifier_list = new ArrayList<Expression> ();
+ do {
+ Expression size = null;
+ if (current () != TokenType.CLOSE_BRACKET && current () != TokenType.COMMA) {
+ size = parse_expression ();
+ size_specified = true;
+ }
+ size_specifier_list.add (size);
+ } while (accept (TokenType.COMMA));
+ expect (TokenType.CLOSE_BRACKET);
+ InitializerList initializer = null;
+ if (current () == TokenType.OPEN_BRACE) {
+ initializer = parse_initializer ();
+ }
+ var expr = context.create_array_creation_expression (UnresolvedType.new_from_expression (member), size_specifier_list.size, initializer, get_src (begin));
+ if (size_specified) {
+ foreach (Expression size in size_specifier_list) {
+ expr.append_size (size);
+ }
+ }
+ return expr;
+ }
+
+ Gee.List<MemberInitializer> parse_object_initializer () throws ParseError {
+ var list = new ArrayList<MemberInitializer> ();
+ if (accept (TokenType.OPEN_BRACE)) {
+ do {
+ list.add (parse_member_initializer ());
+ } while (accept (TokenType.COMMA));
+ expect (TokenType.CLOSE_BRACE);
+ }
+ return list;
+ }
+
+ MemberInitializer parse_member_initializer () throws ParseError {
+ var begin = get_location ();
+ string id = parse_identifier ();
+ expect (TokenType.ASSIGN);
+ var expr = parse_expression ();
+
+ return new MemberInitializer (id, expr, get_src (begin));
+ }
+
+ Expression parse_sizeof_expression () throws ParseError {
+ var begin = get_location ();
+ expect (TokenType.SIZEOF);
+ expect (TokenType.OPEN_PARENS);
+ var type = parse_type ();
+ expect (TokenType.CLOSE_PARENS);
+
+ return context.create_sizeof_expression (type, get_src (begin));
+ }
+
+ Expression parse_typeof_expression () throws ParseError {
+ var begin = get_location ();
+ expect (TokenType.TYPEOF);
+ expect (TokenType.OPEN_PARENS);
+ var type = parse_type ();
+ expect (TokenType.CLOSE_PARENS);
+
+ return context.create_typeof_expression (type, get_src (begin));
+ }
+
+ UnaryOperator get_unary_operator (TokenType token_type) {
+ switch (token_type) {
+ case TokenType.PLUS: return UnaryOperator.PLUS;
+ case TokenType.MINUS: return UnaryOperator.MINUS;
+ case TokenType.OP_NEG: return UnaryOperator.LOGICAL_NEGATION;
+ case TokenType.TILDE: return UnaryOperator.BITWISE_COMPLEMENT;
+ case TokenType.OP_INC: return UnaryOperator.INCREMENT;
+ case TokenType.OP_DEC: return UnaryOperator.DECREMENT;
+ case TokenType.REF: return UnaryOperator.REF;
+ case TokenType.OUT: return UnaryOperator.OUT;
+ default: return UnaryOperator.NONE;
+ }
+ }
+
+ Expression parse_unary_expression () throws ParseError {
+ var begin = get_location ();
+ var operator = get_unary_operator (current ());
+ if (operator != UnaryOperator.NONE) {
+ next ();
+ var op = parse_unary_expression ();
+ return context.create_unary_expression (operator, op, get_src (begin));
+ }
+ switch (current ()) {
+ case TokenType.HASH:
+ next ();
+ var op = parse_unary_expression ();
+ return context.create_reference_transfer_expression (op, get_src (begin));
+ case TokenType.OPEN_PARENS:
+ next ();
+ switch (current ()) {
+ case TokenType.VOID:
+ case TokenType.IDENTIFIER:
+ var type = parse_type ();
+ if (accept (TokenType.CLOSE_PARENS)) {
+ // check follower to decide whether to create cast expression
+ switch (current ()) {
+ case TokenType.OP_NEG:
+ case TokenType.TILDE:
+ case TokenType.OPEN_PARENS:
+ case TokenType.TRUE:
+ case TokenType.FALSE:
+ case TokenType.INTEGER_LITERAL:
+ case TokenType.REAL_LITERAL:
+ case TokenType.CHARACTER_LITERAL:
+ case TokenType.STRING_LITERAL:
+ case TokenType.NULL:
+ case TokenType.THIS:
+ case TokenType.BASE:
+ case TokenType.NEW:
+ case TokenType.SIZEOF:
+ case TokenType.TYPEOF:
+ case TokenType.IDENTIFIER:
+ var inner = parse_unary_expression ();
+ return context.create_cast_expression (inner, type, get_src (begin), false);
+ }
+ }
+ break;
+ }
+ // no cast expression
+ rollback (begin);
+ break;
+ case TokenType.STAR:
+ next ();
+ var op = parse_unary_expression ();
+ return context.create_pointer_indirection (op, get_src (begin));
+ case TokenType.BITWISE_AND:
+ next ();
+ var op = parse_unary_expression ();
+ return context.create_addressof_expression (op, get_src (begin));
+ }
+
+ return parse_primary_expression ();
+ }
+
+ BinaryOperator get_binary_operator (TokenType token_type) {
+ switch (token_type) {
+ case TokenType.STAR: return BinaryOperator.MUL;
+ case TokenType.DIV: return BinaryOperator.DIV;
+ case TokenType.PERCENT: return BinaryOperator.MOD;
+ case TokenType.PLUS: return BinaryOperator.PLUS;
+ case TokenType.MINUS: return BinaryOperator.MINUS;
+ case TokenType.OP_LT: return BinaryOperator.LESS_THAN;
+ case TokenType.OP_GT: return BinaryOperator.GREATER_THAN;
+ case TokenType.OP_LE: return BinaryOperator.LESS_THAN_OR_EQUAL;
+ case TokenType.OP_GE: return BinaryOperator.GREATER_THAN_OR_EQUAL;
+ case TokenType.OP_EQ: return BinaryOperator.EQUALITY;
+ case TokenType.OP_NE: return BinaryOperator.INEQUALITY;
+ default: return BinaryOperator.NONE;
+ }
+ }
+
+ Expression parse_multiplicative_expression () throws ParseError {
+ var begin = get_location ();
+ var left = parse_unary_expression ();
+ bool found = true;
+ while (found) {
+ var operator = get_binary_operator (current ());
+ switch (operator) {
+ case BinaryOperator.MUL:
+ case BinaryOperator.DIV:
+ case BinaryOperator.MOD:
+ next ();
+ var right = parse_unary_expression ();
+ left = context.create_binary_expression (operator, left, right, get_src (begin));
+ break;
+ default:
+ found = false;
+ break;
+ }
+ }
+ return left;
+ }
+
+ Expression parse_additive_expression () throws ParseError {
+ var begin = get_location ();
+ var left = parse_multiplicative_expression ();
+ bool found = true;
+ while (found) {
+ var operator = get_binary_operator (current ());
+ switch (operator) {
+ case BinaryOperator.PLUS:
+ case BinaryOperator.MINUS:
+ next ();
+ var right = parse_multiplicative_expression ();
+ left = context.create_binary_expression (operator, left, right, get_src (begin));
+ break;
+ default:
+ found = false;
+ break;
+ }
+ }
+ return left;
+ }
+
+ Expression parse_shift_expression () throws ParseError {
+ var begin = get_location ();
+ var left = parse_additive_expression ();
+ bool found = true;
+ while (found) {
+ switch (current ()) {
+ case TokenType.OP_SHIFT_LEFT:
+ next ();
+ var right = parse_additive_expression ();
+ left = context.create_binary_expression (BinaryOperator.SHIFT_LEFT, left, right, get_src (begin));
+ break;
+ // don't use OP_SHIFT_RIGHT to support >> for nested generics
+ case TokenType.OP_GT:
+ char* first_gt_pos = tokens[index].begin.pos;
+ next ();
+ // only accept >> when there is no space between the two > signs
+ if (current () == TokenType.OP_GT && tokens[index].begin.pos == first_gt_pos + 1) {
+ next ();
+ var right = parse_additive_expression ();
+ left = context.create_binary_expression (BinaryOperator.SHIFT_RIGHT, left, right, get_src (begin));
+ } else {
+ prev ();
+ found = false;
+ }
+ break;
+ default:
+ found = false;
+ break;
+ }
+ }
+ return left;
+ }
+
+ Expression parse_relational_expression () throws ParseError {
+ var begin = get_location ();
+ var left = parse_shift_expression ();
+ bool found = true;
+ while (found) {
+ var operator = get_binary_operator (current ());
+ switch (operator) {
+ case BinaryOperator.LESS_THAN:
+ case BinaryOperator.LESS_THAN_OR_EQUAL:
+ case BinaryOperator.GREATER_THAN_OR_EQUAL:
+ next ();
+ var right = parse_shift_expression ();
+ left = context.create_binary_expression (operator, left, right, get_src (begin));
+ break;
+ case BinaryOperator.GREATER_THAN:
+ next ();
+ // ignore >> and >>= (two tokens due to generics)
+ if (current () != TokenType.OP_GT && current () != TokenType.OP_GE) {
+ var right = parse_shift_expression ();
+ left = context.create_binary_expression (operator, left, right, get_src (begin));
+ } else {
+ prev ();
+ found = false;
+ }
+ break;
+ default:
+ switch (current ()) {
+ case TokenType.IS:
+ next ();
+ var type = parse_type ();
+ left = context.create_type_check (left, type, get_src (begin));
+ break;
+ case TokenType.AS:
+ next ();
+ var type = parse_type ();
+ left = context.create_cast_expression (left, type, get_src (begin), true);
+ break;
+ default:
+ found = false;
+ break;
+ }
+ break;
+ }
+ }
+ return left;
+ }
+
+ Expression parse_equality_expression () throws ParseError {
+ var begin = get_location ();
+ var left = parse_relational_expression ();
+ bool found = true;
+ while (found) {
+ var operator = get_binary_operator (current ());
+ switch (operator) {
+ case BinaryOperator.EQUALITY:
+ case BinaryOperator.INEQUALITY:
+ next ();
+ var right = parse_relational_expression ();
+ left = context.create_binary_expression (operator, left, right, get_src (begin));
+ break;
+ default:
+ found = false;
+ break;
+ }
+ }
+ return left;
+ }
+
+ Expression parse_and_expression () throws ParseError {
+ var begin = get_location ();
+ var left = parse_equality_expression ();
+ while (accept (TokenType.BITWISE_AND)) {
+ var right = parse_equality_expression ();
+ left = context.create_binary_expression (BinaryOperator.BITWISE_AND, left, right, get_src (begin));
+ }
+ return left;
+ }
+
+ Expression parse_exclusive_or_expression () throws ParseError {
+ var begin = get_location ();
+ var left = parse_and_expression ();
+ while (accept (TokenType.CARRET)) {
+ var right = parse_and_expression ();
+ left = context.create_binary_expression (BinaryOperator.BITWISE_XOR, left, right, get_src (begin));
+ }
+ return left;
+ }
+
+ Expression parse_inclusive_or_expression () throws ParseError {
+ var begin = get_location ();
+ var left = parse_exclusive_or_expression ();
+ while (accept (TokenType.BITWISE_OR)) {
+ var right = parse_exclusive_or_expression ();
+ left = context.create_binary_expression (BinaryOperator.BITWISE_OR, left, right, get_src (begin));
+ }
+ return left;
+ }
+
+ Expression parse_in_expression () throws ParseError {
+ var begin = get_location ();
+ var left = parse_inclusive_or_expression ();
+ while (accept (TokenType.IN)) {
+ var right = parse_inclusive_or_expression ();
+ left = context.create_binary_expression (BinaryOperator.IN, left, right, get_src (begin));
+ }
+ return left;
+ }
+
+ Expression parse_conditional_and_expression () throws ParseError {
+ var begin = get_location ();
+ var left = parse_in_expression ();
+ while (accept (TokenType.OP_AND)) {
+ var right = parse_in_expression ();
+ left = context.create_binary_expression (BinaryOperator.AND, left, right, get_src (begin));
+ }
+ return left;
+ }
+
+ Expression parse_conditional_or_expression () throws ParseError {
+ var begin = get_location ();
+ var left = parse_conditional_and_expression ();
+ while (accept (TokenType.OP_OR)) {
+ var right = parse_conditional_and_expression ();
+ left = context.create_binary_expression (BinaryOperator.OR, left, right, get_src (begin));
+ }
+ return left;
+ }
+
+ Expression parse_conditional_expression () throws ParseError {
+ var begin = get_location ();
+ var condition = parse_conditional_or_expression ();
+ if (accept (TokenType.INTERR)) {
+ var true_expr = parse_expression ();
+ expect (TokenType.COLON);
+ var false_expr = parse_expression ();
+ return context.create_conditional_expression (condition, true_expr, false_expr, get_src (begin));
+ } else {
+ return condition;
+ }
+ }
+
+ Expression parse_lambda_expression () throws ParseError {
+ var begin = get_location ();
+ Gee.List<string> params = new ArrayList<string> ();
+ if (accept (TokenType.OPEN_PARENS)) {
+ if (current () != TokenType.CLOSE_PARENS) {
+ do {
+ params.add (parse_identifier ());
+ } while (accept (TokenType.COMMA));
+ }
+ expect (TokenType.CLOSE_PARENS);
+ } else {
+ params.add (parse_identifier ());
+ }
+ expect (TokenType.LAMBDA);
+
+ LambdaExpression lambda;
+ if (current () == TokenType.OPEN_BRACE) {
+ var block = parse_block ();
+ lambda = context.create_lambda_expression_with_statement_body (block, get_src (begin));
+ } else {
+ var expr = parse_expression ();
+ lambda = context.create_lambda_expression (expr, get_src (begin));
+ }
+ foreach (string param in params) {
+ lambda.add_parameter (param);
+ }
+ return lambda;
+ }
+
+ AssignmentOperator get_assignment_operator (TokenType token_type) {
+ switch (token_type) {
+ case TokenType.ASSIGN: return AssignmentOperator.SIMPLE;
+ case TokenType.ASSIGN_ADD: return AssignmentOperator.ADD;
+ case TokenType.ASSIGN_SUB: return AssignmentOperator.SUB;
+ case TokenType.ASSIGN_BITWISE_OR: return AssignmentOperator.BITWISE_OR;
+ case TokenType.ASSIGN_BITWISE_AND: return AssignmentOperator.BITWISE_AND;
+ case TokenType.ASSIGN_BITWISE_XOR: return AssignmentOperator.BITWISE_XOR;
+ case TokenType.ASSIGN_DIV: return AssignmentOperator.DIV;
+ case TokenType.ASSIGN_MUL: return AssignmentOperator.MUL;
+ case TokenType.ASSIGN_PERCENT: return AssignmentOperator.PERCENT;
+ case TokenType.ASSIGN_SHIFT_LEFT: return AssignmentOperator.SHIFT_LEFT;
+ default: return AssignmentOperator.NONE;
+ }
+ }
+
+ Expression parse_expression () throws ParseError {
+ var begin = get_location ();
+ Expression expr = parse_conditional_expression ();
+
+ if (current () == TokenType.LAMBDA) {
+ rollback (begin);
+ return parse_lambda_expression ();
+ }
+
+ while (true) {
+ var operator = get_assignment_operator (current ());
+ if (operator != AssignmentOperator.NONE) {
+ next ();
+ var rhs = parse_expression ();
+ expr = context.create_assignment (expr, rhs, operator);
+ } else if (current () == TokenType.OP_GT) { // >>=
+ char* first_gt_pos = tokens[index].begin.pos;
+ next ();
+ // only accept >>= when there is no space between the two > signs
+ if (current () == TokenType.OP_GE && tokens[index].begin.pos == first_gt_pos + 1) {
+ next ();
+ var rhs = parse_expression ();
+ expr = context.create_assignment (expr, rhs, AssignmentOperator.SHIFT_RIGHT);
+ } else {
+ prev ();
+ break;
+ }
+ } else {
+ break;
+ }
+ }
+
+ return expr;
+ }
+
+ Statement parse_statement () throws ParseError {
+ comment = scanner.pop_comment ();
+ switch (current ()) {
+ case TokenType.OPEN_BRACE:
+ return parse_block ();
+ case TokenType.SEMICOLON:
+ return parse_empty_statement ();
+ case TokenType.IF:
+ return parse_if_statement ();
+ case TokenType.SWITCH:
+ return parse_switch_statement ();
+ case TokenType.WHILE:
+ return parse_while_statement ();
+ case TokenType.DO:
+ return parse_do_statement ();
+ case TokenType.FOR:
+ return parse_for_statement ();
+ case TokenType.FOREACH:
+ return parse_foreach_statement ();
+ case TokenType.BREAK:
+ return parse_break_statement ();
+ case TokenType.CONTINUE:
+ return parse_continue_statement ();
+ case TokenType.RETURN:
+ return parse_return_statement ();
+ case TokenType.THROW:
+ return parse_throw_statement ();
+ case TokenType.TRY:
+ return parse_try_statement ();
+ case TokenType.LOCK:
+ return parse_lock_statement ();
+ case TokenType.DELETE:
+ return parse_delete_statement ();
+ case TokenType.VAR:
+ return parse_declaration_statement ();
+ case TokenType.OP_INC:
+ case TokenType.OP_DEC:
+ case TokenType.BASE:
+ case TokenType.THIS:
+ case TokenType.OPEN_PARENS:
+ case TokenType.STAR:
+ return parse_expression_statement ();
+ }
+
+ if (is_expression ()) {
+ return parse_expression_statement ();
+ } else {
+ return parse_declaration_statement ();
+ }
+ }
+
+ bool is_expression () throws ParseError {
+ var begin = get_location ();
+
+ // decide between declaration and expression statement
+ skip_type ();
+ switch (current ()) {
+ // invocation expression
+ case TokenType.OPEN_PARENS:
+ // postfix increment
+ case TokenType.OP_INC:
+ // postfix decrement
+ case TokenType.OP_DEC:
+ // assignments
+ case TokenType.ASSIGN:
+ case TokenType.ASSIGN_ADD:
+ case TokenType.ASSIGN_BITWISE_AND:
+ case TokenType.ASSIGN_BITWISE_OR:
+ case TokenType.ASSIGN_BITWISE_XOR:
+ case TokenType.ASSIGN_DIV:
+ case TokenType.ASSIGN_MUL:
+ case TokenType.ASSIGN_PERCENT:
+ case TokenType.ASSIGN_SHIFT_LEFT:
+ case TokenType.ASSIGN_SUB:
+ case TokenType.OP_GT: // >>=
+ // member access
+ case TokenType.DOT:
+ // pointer member access
+ case TokenType.OP_PTR:
+ rollback (begin);
+ return true;
+ }
+
+ rollback (begin);
+ return false;
+ }
+
+ Block parse_embedded_statement () throws ParseError {
+ if (current () == TokenType.OPEN_BRACE) {
+ return parse_block ();
+ }
+
+ comment = scanner.pop_comment ();
+
+ var block = context.create_block ();
+ block.add_statement (parse_embedded_statement_without_block ());
+ return block;
+
+ }
+
+ Statement parse_embedded_statement_without_block () throws ParseError {
+ switch (current ()) {
+ case TokenType.SEMICOLON: return parse_empty_statement ();
+ case TokenType.IF: return parse_if_statement ();
+ case TokenType.SWITCH: return parse_switch_statement ();
+ case TokenType.WHILE: return parse_while_statement ();
+ case TokenType.DO: return parse_do_statement ();
+ case TokenType.FOR: return parse_for_statement ();
+ case TokenType.FOREACH: return parse_foreach_statement ();
+ case TokenType.BREAK: return parse_break_statement ();
+ case TokenType.CONTINUE: return parse_continue_statement ();
+ case TokenType.RETURN: return parse_return_statement ();
+ case TokenType.THROW: return parse_throw_statement ();
+ case TokenType.TRY: return parse_try_statement ();
+ case TokenType.LOCK: return parse_lock_statement ();
+ case TokenType.DELETE: return parse_delete_statement ();
+ default: return parse_expression_statement ();
+ }
+ }
+
+ Block parse_block () throws ParseError {
+ var begin = get_location ();
+ Gee.List<Statement> list = new ArrayList<Statement> ();
+ expect (TokenType.OPEN_BRACE);
+ var block = context.create_block (get_src_com (begin));
+ while (current () != TokenType.CLOSE_BRACE) {
+ try {
+ var stmt = parse_statement ();
+ if (stmt == null) {
+ // workaround for current limitation of exception handling
+ throw new ParseError.SYNTAX ("syntax error in statement");
+ }
+ block.add_statement (stmt);
+ } catch (ParseError e) {
+ if (recover () != RecoveryState.STATEMENT_BEGIN) {
+ // beginning of next declaration or end of file reached
+ // return what we have so far
+ return block;
+ }
+ }
+ }
+ if (!accept (TokenType.CLOSE_BRACE)) {
+ Report.error (new SourceReference (scanner.source_file, tokens[index].begin.line, tokens[index].begin.column, tokens[index].end.line, tokens[index].end.column), "expected `}'");
+ }
+
+ return block;
+ }
+
+ Statement parse_empty_statement () throws ParseError {
+ var begin = get_location ();
+ expect (TokenType.SEMICOLON);
+ return context.create_empty_statement (get_src_com (begin));
+ }
+
+ Statement parse_declaration_statement () throws ParseError {
+ var begin = get_location ();
+ var decl = parse_local_variable_declaration ();
+ expect (TokenType.SEMICOLON);
+ return context.create_declaration_statement (decl, get_src_com (begin));
+ }
+
+ LocalVariableDeclaration parse_local_variable_declaration () throws ParseError {
+ var begin = get_location ();
+ LocalVariableDeclaration decl;
+ if (accept (TokenType.VAR)) {
+ var declarators = parse_variable_declarators ();
+ decl = context.create_local_variable_declaration_var_type (get_src (begin));
+ foreach (VariableDeclarator var_decl in declarators) {
+ decl.add_declarator (var_decl);
+ }
+ } else {
+ var type = parse_type ();
+ var declarators = parse_variable_declarators ();
+ if (!((UnresolvedType) type).is_weak) {
+ type.takes_ownership = true;
+ }
+ type.requires_null_check = false;
+ type.nullable = true;
+ decl = context.create_local_variable_declaration (type, get_src (begin));
+ foreach (VariableDeclarator var_decl in declarators) {
+ var_decl.type_reference = type.copy ();
+ decl.add_declarator (var_decl);
+ }
+ }
+ return decl;
+ }
+
+ Statement parse_expression_statement () throws ParseError {
+ var begin = get_location ();
+ var expr = parse_statement_expression ();
+ expect (TokenType.SEMICOLON);
+ return context.create_expression_statement (expr, get_src_com (begin));
+ }
+
+ Expression parse_statement_expression () throws ParseError {
+ // invocation expression, assignment,
+ // or pre/post increment/decrement expression
+ return parse_expression ();
+ }
+
+ Statement parse_if_statement () throws ParseError {
+ var begin = get_location ();
+ expect (TokenType.IF);
+ expect (TokenType.OPEN_PARENS);
+ var condition = parse_expression ();
+ expect (TokenType.CLOSE_PARENS);
+ var src = get_src_com (begin);
+ var true_stmt = parse_embedded_statement ();
+ Block false_stmt = null;
+ if (accept (TokenType.ELSE)) {
+ false_stmt = parse_embedded_statement ();
+ }
+ return context.create_if_statement (condition, true_stmt, false_stmt, src);
+ }
+
+ Statement parse_switch_statement () throws ParseError {
+ var begin = get_location ();
+ expect (TokenType.SWITCH);
+ expect (TokenType.OPEN_PARENS);
+ var condition = parse_expression ();
+ expect (TokenType.CLOSE_PARENS);
+ var stmt = context.create_switch_statement (condition, get_src_com (begin));
+ expect (TokenType.OPEN_BRACE);
+ while (current () != TokenType.CLOSE_BRACE) {
+ var section = context.create_switch_section (get_src_com (begin));
+ do {
+ if (accept (TokenType.CASE)) {
+ section.add_label (context.create_switch_label (parse_expression (), get_src_com (begin)));
+ } else {
+ expect (TokenType.DEFAULT);
+ section.add_label (context.create_switch_label_with_default (get_src_com (begin)));
+ }
+ expect (TokenType.COLON);
+ } while (current () == TokenType.CASE || current () == TokenType.DEFAULT);
+ while (current () != TokenType.CLOSE_BRACE
+ && current () != TokenType.CASE
+ && current () != TokenType.DEFAULT) {
+ section.add_statement (parse_statement ());
+ }
+ stmt.add_section (section);
+ }
+ expect (TokenType.CLOSE_BRACE);
+ return stmt;
+ }
+
+ Statement parse_while_statement () throws ParseError {
+ var begin = get_location ();
+ expect (TokenType.WHILE);
+ expect (TokenType.OPEN_PARENS);
+ var condition = parse_expression ();
+ expect (TokenType.CLOSE_PARENS);
+ var body = parse_embedded_statement ();
+ return context.create_while_statement (condition, body, get_src_com (begin));
+ }
+
+ Statement parse_do_statement () throws ParseError {
+ var begin = get_location ();
+ expect (TokenType.DO);
+ var body = parse_embedded_statement ();
+ expect (TokenType.WHILE);
+ expect (TokenType.OPEN_PARENS);
+ var condition = parse_expression ();
+ expect (TokenType.CLOSE_PARENS);
+ expect (TokenType.SEMICOLON);
+ return context.create_do_statement (body, condition, get_src_com (begin));
+ }
+
+ Statement parse_for_statement () throws ParseError {
+ var begin = get_location ();
+ Block block = null;
+ expect (TokenType.FOR);
+ expect (TokenType.OPEN_PARENS);
+ var initializer_list = new ArrayList<Expression> ();
+ if (!accept (TokenType.SEMICOLON)) {
+ bool is_expr;
+ switch (current ()) {
+ case TokenType.VAR:
+ is_expr = false;
+ break;
+ case TokenType.OP_INC:
+ case TokenType.OP_DEC:
+ is_expr = true;
+ break;
+ default:
+ is_expr = is_expression ();
+ break;
+ }
+
+ if (is_expr) {
+ do {
+ initializer_list.add (parse_statement_expression ());
+ } while (accept (TokenType.COMMA));
+ expect (TokenType.SEMICOLON);
+ } else {
+ block = context.create_block (get_src (begin));
+ block.add_statement (parse_declaration_statement ());
+ }
+ }
+ Expression condition = null;
+ if (current () != TokenType.SEMICOLON) {
+ condition = parse_expression ();
+ }
+ expect (TokenType.SEMICOLON);
+ var iterator_list = new ArrayList<Expression> ();
+ if (current () != TokenType.CLOSE_PARENS) {
+ do {
+ iterator_list.add (parse_statement_expression ());
+ } while (accept (TokenType.COMMA));
+ }
+ expect (TokenType.CLOSE_PARENS);
+ var src = get_src_com (begin);
+ var body = parse_embedded_statement ();
+ var stmt = context.create_for_statement (condition, body, src);
+ foreach (Expression init in initializer_list) {
+ stmt.add_initializer (init);
+ }
+ foreach (Expression iter in iterator_list) {
+ stmt.add_iterator (iter);
+ }
+ if (block != null) {
+ block.add_statement (stmt);
+ return block;
+ } else {
+ return stmt;
+ }
+ }
+
+ Statement parse_foreach_statement () throws ParseError {
+ var begin = get_location ();
+ expect (TokenType.FOREACH);
+ expect (TokenType.OPEN_PARENS);
+ var type = parse_type ();
+ var unresolved_type = type as UnresolvedType;
+ if (unresolved_type != null && !unresolved_type.is_weak) {
+ unresolved_type.takes_ownership = true;
+ }
+ string id = parse_identifier ();
+ expect (TokenType.IN);
+ var collection = parse_expression ();
+ expect (TokenType.CLOSE_PARENS);
+ var src = get_src_com (begin);
+ var body = parse_embedded_statement ();
+ return context.create_foreach_statement (type, id, collection, body, src);
+ }
+
+ Statement parse_break_statement () throws ParseError {
+ var begin = get_location ();
+ expect (TokenType.BREAK);
+ expect (TokenType.SEMICOLON);
+ return context.create_break_statement (get_src_com (begin));
+ }
+
+ Statement parse_continue_statement () throws ParseError {
+ var begin = get_location ();
+ expect (TokenType.CONTINUE);
+ expect (TokenType.SEMICOLON);
+ return context.create_continue_statement (get_src_com (begin));
+ }
+
+ Statement parse_return_statement () throws ParseError {
+ var begin = get_location ();
+ expect (TokenType.RETURN);
+ Expression expr = null;
+ if (current () != TokenType.SEMICOLON) {
+ expr = parse_expression ();
+ }
+ expect (TokenType.SEMICOLON);
+ return context.create_return_statement (expr, get_src_com (begin));
+ }
+
+ Statement parse_throw_statement () throws ParseError {
+ var begin = get_location ();
+ expect (TokenType.THROW);
+ var expr = parse_expression ();
+ expect (TokenType.SEMICOLON);
+ return context.create_throw_statement (expr, get_src_com (begin));
+ }
+
+ Statement parse_try_statement () throws ParseError {
+ var begin = get_location ();
+ expect (TokenType.TRY);
+ var try_block = parse_block ();
+ Block finally_clause = null;
+ var catch_clauses = new ArrayList<CatchClause> ();
+ if (current () == TokenType.CATCH) {
+ parse_catch_clauses (catch_clauses);
+ if (current () == TokenType.FINALLY) {
+ finally_clause = parse_finally_clause ();
+ }
+ } else {
+ finally_clause = parse_finally_clause ();
+ }
+ var stmt = context.create_try_statement (try_block, finally_clause, get_src_com (begin));
+ foreach (CatchClause clause in catch_clauses) {
+ stmt.add_catch_clause (clause);
+ }
+ return stmt;
+ }
+
+ void parse_catch_clauses (Gee.List<CatchClause> catch_clauses) throws ParseError {
+ while (accept (TokenType.CATCH)) {
+ var begin = get_location ();
+ DataType type = null;
+ string id = null;
+ if (accept (TokenType.OPEN_PARENS)) {
+ type = parse_type ();
+ id = parse_identifier ();
+ expect (TokenType.CLOSE_PARENS);
+ }
+ var block = parse_block ();
+ catch_clauses.add (context.create_catch_clause (type, id, block, get_src (begin)));
+ }
+ }
+
+ Block parse_finally_clause () throws ParseError {
+ expect (TokenType.FINALLY);
+ return parse_block ();
+ }
+
+ Statement parse_lock_statement () throws ParseError {
+ var begin = get_location ();
+ expect (TokenType.LOCK);
+ expect (TokenType.OPEN_PARENS);
+ var expr = parse_expression ();
+ expect (TokenType.CLOSE_PARENS);
+ var stmt = parse_embedded_statement ();
+ return context.create_lock_statement (expr, stmt, get_src_com (begin));
+ }
+
+ Statement parse_delete_statement () throws ParseError {
+ var begin = get_location ();
+ expect (TokenType.DELETE);
+ var expr = parse_expression ();
+ expect (TokenType.SEMICOLON);
+ return context.create_delete_statement (expr, get_src_com (begin));
}
+
+ Gee.List<Attribute> parse_attributes () throws ParseError {
+ if (current () != TokenType.OPEN_BRACKET) {
+ return null;
+ }
+ var attrs = new ArrayList<Attribute> ();
+ while (accept (TokenType.OPEN_BRACKET)) {
+ do {
+ var begin = get_location ();
+ string id = parse_identifier ();
+ var attr = new Attribute (id, get_src (begin));
+ if (accept (TokenType.OPEN_PARENS)) {
+ if (current () != TokenType.CLOSE_PARENS) {
+ do {
+ begin = get_location ();
+ string id = parse_identifier ();
+ expect (TokenType.ASSIGN);
+ var expr = parse_expression ();
+ attr.add_argument (new NamedArgument (id, expr, get_src (begin)));
+ } while (accept (TokenType.COMMA));
+ }
+ expect (TokenType.CLOSE_PARENS);
+ }
+ attrs.add (attr);
+ } while (accept (TokenType.COMMA));
+ expect (TokenType.CLOSE_BRACKET);
+ }
+ return attrs;
+ }
+
+ void set_attributes (CodeNode node, Gee.List<Attribute> attributes) {
+ if (attributes != null) {
+ foreach (Attribute attr in attributes) {
+ node.attributes.append (attr);
+ }
+ }
+ }
+
+ Symbol parse_declaration () throws ParseError {
+ comment = scanner.pop_comment ();
+ var attrs = parse_attributes ();
+
+ var begin = get_location ();
+
+ TokenType last_keyword = current ();
+
+ while (is_declaration_keyword (current ())) {
+ last_keyword = current ();
+ next ();
+ }
- [Import ()]
- public void parse_file (SourceFile! source_file);
+ switch (current ()) {
+ case TokenType.CONSTRUCT:
+ rollback (begin);
+ return parse_constructor_declaration (attrs);
+ case TokenType.TILDE:
+ rollback (begin);
+ return parse_destructor_declaration (attrs);
+ default:
+ skip_type ();
+ switch (current ()) {
+ case TokenType.OPEN_BRACE:
+ case TokenType.SEMICOLON:
+ case TokenType.COLON:
+ rollback (begin);
+ switch (last_keyword) {
+ case TokenType.CLASS: return parse_class_declaration (attrs);
+ case TokenType.ENUM: return parse_enum_declaration (attrs);
+ case TokenType.ERRORDOMAIN: return parse_errordomain_declaration (attrs);
+ case TokenType.INTERFACE: return parse_interface_declaration (attrs);
+ case TokenType.NAMESPACE: return parse_namespace_declaration (attrs);
+ case TokenType.STRUCT: return parse_struct_declaration (attrs);
+ }
+ break;
+ case TokenType.OPEN_PARENS:
+ rollback (begin);
+ return parse_creation_method_declaration (attrs);
+ default:
+ skip_type (); // might contain type parameter list
+ switch (current ()) {
+ case TokenType.OPEN_PARENS:
+ rollback (begin);
+ switch (last_keyword) {
+ case TokenType.DELEGATE: return parse_delegate_declaration (attrs);
+ case TokenType.SIGNAL: return parse_signal_declaration (attrs);
+ default: return parse_method_declaration (attrs);
+ }
+ case TokenType.ASSIGN:
+ case TokenType.SEMICOLON:
+ rollback (begin);
+ switch (last_keyword) {
+ case TokenType.CONST: return parse_constant_declaration (attrs);
+ default: return parse_field_declaration (attrs);
+ }
+ case TokenType.OPEN_BRACE:
+ rollback (begin);
+ return parse_property_declaration (attrs);
+ }
+ break;
+ }
+ break;
+ }
+
+ throw new ParseError.SYNTAX (get_error ("expected declaration"));
+ }
+
+ void parse_declarations (Symbol parent, bool root = false) throws ParseError {
+ if (!root) {
+ expect (TokenType.OPEN_BRACE);
+ }
+ while (current () != TokenType.CLOSE_BRACE && current () != TokenType.EOF) {
+ try {
+ if (parent is Namespace) {
+ parse_namespace_member ((Namespace) parent);
+ } else if (parent is Class) {
+ parse_class_member ((Class) parent);
+ } else if (parent is Struct) {
+ parse_struct_member ((Struct) parent);
+ } else if (parent is Interface) {
+ parse_interface_member ((Interface) parent);
+ }
+ } catch (ParseError e) {
+ int r;
+ do {
+ r = recover ();
+ } while (r == RecoveryState.STATEMENT_BEGIN);
+ if (r == RecoveryState.EOF) {
+ return;
+ }
+ }
+ }
+ if (!root) {
+ if (!accept (TokenType.CLOSE_BRACE)) {
+ Report.error (new SourceReference (scanner.source_file, tokens[index].begin.line, tokens[index].begin.column, tokens[index].end.line, tokens[index].end.column), "expected `}'");
+ }
+ }
+ }
+
+ enum RecoveryState {
+ EOF,
+ DECLARATION_BEGIN,
+ STATEMENT_BEGIN
+ }
+
+ RecoveryState recover () {
+ while (current () != TokenType.EOF) {
+ switch (current ()) {
+ case TokenType.ABSTRACT:
+ case TokenType.CLASS:
+ case TokenType.CONST:
+ case TokenType.CONSTRUCT:
+ case TokenType.DELEGATE:
+ case TokenType.ENUM:
+ case TokenType.ERRORDOMAIN:
+ case TokenType.INLINE:
+ case TokenType.INTERFACE:
+ case TokenType.NAMESPACE:
+ case TokenType.OVERRIDE:
+ case TokenType.PRIVATE:
+ case TokenType.PROTECTED:
+ case TokenType.PUBLIC:
+ case TokenType.SIGNAL:
+ case TokenType.STATIC:
+ case TokenType.STRUCT:
+ case TokenType.VIRTUAL:
+ case TokenType.VOLATILE:
+ return RecoveryState.DECLARATION_BEGIN;
+ case TokenType.BREAK:
+ case TokenType.CONTINUE:
+ case TokenType.DELETE:
+ case TokenType.DO:
+ case TokenType.FOR:
+ case TokenType.FOREACH:
+ case TokenType.IF:
+ case TokenType.LOCK:
+ case TokenType.RETURN:
+ case TokenType.SWITCH:
+ case TokenType.THROW:
+ case TokenType.TRY:
+ case TokenType.VAR:
+ case TokenType.WHILE:
+ return RecoveryState.STATEMENT_BEGIN;
+ default:
+ next ();
+ break;
+ }
+ }
+ return RecoveryState.EOF;
+ }
+
+ Namespace parse_namespace_declaration (Gee.List<Attribute> attrs) throws ParseError {
+ var begin = get_location ();
+ expect (TokenType.NAMESPACE);
+ var sym = parse_symbol_name ();
+ var ns = context.create_namespace (sym.name, get_src_com (begin));
+ ns.pkg = scanner.source_file.pkg;
+ set_attributes (ns, attrs);
+ parse_declarations (ns);
+ return ns;
+ }
+
+ void parse_namespace_member (Namespace ns) throws ParseError {
+ var sym = parse_declaration ();
+ if (sym is Namespace) {
+ if (ns.scope.lookup (sym.name) is Namespace) {
+ // merge if namespace already exists
+ var old_ns = (Namespace) ns.scope.lookup (sym.name);
+ var new_ns = (Namespace) sym;
+ if (!new_ns.pkg) {
+ old_ns.pkg = false;
+ }
+ foreach (Class cl in new_ns.get_classes ()) {
+ if (old_ns.scope.lookup (cl.name) is Class) {
+ // merge
+ var old_class = (Class) old_ns.scope.lookup (cl.name);
+ foreach (DataType base_type in cl.get_base_types ()) {
+ old_class.add_base_type (base_type);
+ }
+ foreach (Field f in cl.get_fields ()) {
+ old_class.add_field (f);
+ }
+ foreach (Method m in cl.get_methods ()) {
+ if (m == cl.default_construction_method && old_class.default_construction_method != null) {
+ // ignore secondary default creation method
+ continue;
+ }
+ old_class.add_method (m);
+ }
+ if (cl.constructor != null) {
+ old_class.constructor = cl.constructor;
+ }
+ scanner.source_file.remove_node (cl);
+ } else {
+ old_ns.add_class (cl);
+ }
+ }
+ foreach (Struct st in new_ns.get_structs ()) {
+ old_ns.add_struct (st);
+ }
+ foreach (Interface iface in new_ns.get_interfaces ()) {
+ old_ns.add_interface (iface);
+ }
+ foreach (Delegate d in new_ns.get_delegates ()) {
+ old_ns.add_delegate (d);
+ }
+ foreach (Enum en in new_ns.get_enums ()) {
+ old_ns.add_enum (en);
+ }
+ foreach (ErrorDomain ed in new_ns.get_error_domains ()) {
+ old_ns.add_error_domain (ed);
+ }
+ foreach (Constant c in new_ns.get_constants ()) {
+ old_ns.add_constant (c);
+ }
+ foreach (Field f in new_ns.get_fields ()) {
+ old_ns.add_field (f);
+ }
+ foreach (Method m in new_ns.get_methods ()) {
+ old_ns.add_method (m);
+ }
+ } else {
+ context.root.add_namespace ((Namespace) sym);
+ }
+ } else if (sym is Class) {
+ ns.add_class ((Class) sym);
+ } else if (sym is Interface) {
+ ns.add_interface ((Interface) sym);
+ } else if (sym is Struct) {
+ ns.add_struct ((Struct) sym);
+ } else if (sym is Enum) {
+ ns.add_enum ((Enum) sym);
+ } else if (sym is ErrorDomain) {
+ ns.add_error_domain ((ErrorDomain) sym);
+ } else if (sym is Delegate) {
+ ns.add_delegate ((Delegate) sym);
+ } else if (sym is Method) {
+ var method = (Method) sym;
+ method.instance = false;
+ ns.add_method (method);
+ } else if (sym is Field) {
+ var field = (Field) sym;
+ field.instance = false;
+ ns.add_field (field);
+ } else if (sym is Constant) {
+ ns.add_constant ((Constant) sym);
+ } else if (sym == null) {
+ // workaround for current limitation of exception handling
+ throw new ParseError.SYNTAX ("syntax error in declaration");
+ } else {
+ Report.error (sym.source_reference, "unexpected declaration in namespace");
+ }
+ scanner.source_file.add_node (sym);
+ }
+
+ void parse_using_directives () throws ParseError {
+ while (accept (TokenType.USING)) {
+ var begin = get_location ();
+
+ do {
+ var begin = get_location ();
+ var sym = parse_symbol_name ();
+ var ns_ref = new NamespaceReference (sym.name, get_src (begin));
+ scanner.source_file.add_using_directive (ns_ref);
+ } while (accept (TokenType.COMMA));
+ expect (TokenType.SEMICOLON);
+ }
+ }
+
+ Symbol parse_class_declaration (Gee.List<Attribute> attrs) throws ParseError {
+ var begin = get_location ();
+ var access = parse_access_modifier ();
+ var flags = parse_type_declaration_modifiers ();
+ expect (TokenType.CLASS);
+ var sym = parse_symbol_name ();
+ var type_param_list = parse_type_parameter_list ();
+ var base_types = new ArrayList<DataType> ();
+ if (accept (TokenType.COLON)) {
+ do {
+ base_types.add (parse_type ());
+ } while (accept (TokenType.COMMA));
+ }
+
+ var cl = context.create_class (sym.name, get_src_com (begin));
+ cl.access = access;
+ if (ModifierFlags.ABSTRACT in flags) {
+ cl.is_abstract = true;
+ }
+ if (ModifierFlags.STATIC in flags) {
+ cl.is_static = true;
+ }
+ set_attributes (cl, attrs);
+ foreach (TypeParameter type_param in type_param_list) {
+ cl.add_type_parameter (type_param);
+ }
+ foreach (DataType base_type in base_types) {
+ cl.add_base_type (base_type);
+ }
+
+ parse_declarations (cl);
+
+ // ensure there is always a default construction method
+ if (!scanner.source_file.pkg
+ && !cl.is_abstract
+ && !cl.is_static
+ && cl.default_construction_method == null) {
+ var m = context.create_creation_method (cl.name, null, cl.source_reference);
+ m.instance = false;
+ m.access = SymbolAccessibility.PUBLIC;
+ m.body = context.create_block (cl.source_reference);
+ cl.add_method (m);
+ }
+
+ Symbol result = cl;
+ while (sym.inner != null) {
+ sym = sym.inner;
+ var ns = context.create_namespace (sym.name, cl.source_reference);
+ ns.pkg = scanner.source_file.pkg;
+ if (result is Namespace) {
+ ns.add_namespace ((Namespace) result);
+ } else {
+ ns.add_class ((Class) result);
+ scanner.source_file.add_node (result);
+ }
+ result = ns;
+ }
+ return result;
+ }
+
+ void parse_class_member (Class cl) throws ParseError {
+ var sym = parse_declaration ();
+ if (sym is Class) {
+ cl.add_class ((Class) sym);
+ } else if (sym is Struct) {
+ cl.add_struct ((Struct) sym);
+ } else if (sym is Enum) {
+ cl.add_enum ((Enum) sym);
+ } else if (sym is Delegate) {
+ cl.add_delegate ((Delegate) sym);
+ } else if (sym is Method) {
+ cl.add_method ((Method) sym);
+ } else if (sym is Signal) {
+ cl.add_signal ((Signal) sym);
+ } else if (sym is Field) {
+ cl.add_field ((Field) sym);
+ } else if (sym is Constant) {
+ cl.add_constant ((Constant) sym);
+ } else if (sym is Property) {
+ cl.add_property ((Property) sym);
+ } else if (sym is Constructor) {
+ var c = (Constructor) sym;
+ if (c.instance) {
+ cl.constructor = c;
+ } else {
+ cl.static_constructor = c;
+ }
+ } else if (sym is Destructor) {
+ cl.destructor = (Destructor) sym;
+ } else if (sym == null) {
+ // workaround for current limitation of exception handling
+ throw new ParseError.SYNTAX ("syntax error in declaration");
+ } else {
+ Report.error (sym.source_reference, "unexpected declaration in class");
+ }
+ }
+
+ Constant parse_constant_declaration (Gee.List<Attribute> attrs) throws ParseError {
+ var begin = get_location ();
+ var access = parse_access_modifier ();
+ parse_member_declaration_modifiers ();
+ expect (TokenType.CONST);
+ var type = parse_type ();
+ string id = parse_identifier ();
+ Expression initializer = null;
+ if (accept (TokenType.ASSIGN)) {
+ initializer = parse_variable_initializer ();
+ }
+ expect (TokenType.SEMICOLON);
+ var c = context.create_constant (id, type, initializer, get_src_com (begin));
+ c.access = access;
+ set_attributes (c, attrs);
+ return c;
+ }
+
+ Field parse_field_declaration (Gee.List<Attribute> attrs) throws ParseError {
+ var begin = get_location ();
+ var access = parse_access_modifier ();
+ var flags = parse_member_declaration_modifiers ();
+ var type = parse_type ();
+ var unresolved_type = type as UnresolvedType;
+ if (unresolved_type != null && !unresolved_type.is_weak) {
+ unresolved_type.takes_ownership = true;
+ }
+ string id = parse_identifier ();
+ var f = context.create_field (id, type, null, get_src_com (begin));
+ f.access = access;
+ set_attributes (f, attrs);
+ if (ModifierFlags.STATIC in flags) {
+ f.instance = false;
+ }
+ if (accept (TokenType.ASSIGN)) {
+ f.initializer = parse_expression ();
+ }
+ expect (TokenType.SEMICOLON);
+ return f;
+ }
+
+ Gee.List<VariableDeclarator> parse_variable_declarators () throws ParseError {
+ var list = new ArrayList<VariableDeclarator> ();
+ do {
+ var var_decl = parse_variable_declarator ();
+ list.add (var_decl);
+ } while (accept (TokenType.COMMA));
+ return list;
+ }
+
+ VariableDeclarator parse_variable_declarator () throws ParseError {
+ var begin = get_location ();
+ string id = parse_identifier ();
+ Expression initializer = null;
+ if (accept (TokenType.ASSIGN)) {
+ initializer = parse_variable_initializer ();
+ }
+ return context.create_variable_declarator (id, initializer, get_src (begin));
+ }
+
+ InitializerList parse_initializer () throws ParseError {
+ var begin = get_location ();
+ expect (TokenType.OPEN_BRACE);
+ var initializer = context.create_initializer_list (get_src (begin));
+ if (current () != TokenType.CLOSE_BRACE) {
+ do {
+ initializer.append (parse_variable_initializer ());
+ } while (accept (TokenType.COMMA));
+ }
+ expect (TokenType.CLOSE_BRACE);
+ return initializer;
+ }
+
+ Expression parse_variable_initializer () throws ParseError {
+ if (current () == TokenType.OPEN_BRACE) {
+ return parse_initializer ();
+ } else {
+ return parse_expression ();
+ }
+ }
+
+ Method parse_method_declaration (Gee.List<Attribute> attrs) throws ParseError {
+ var begin = get_location ();
+ var access = parse_access_modifier ();
+ var flags = parse_member_declaration_modifiers ();
+ var type = parse_type ();
+ var unresolved_type = type as UnresolvedType;
+ if (unresolved_type != null && !unresolved_type.is_weak) {
+ unresolved_type.transfers_ownership = true;
+ }
+ string id = parse_identifier ();
+ parse_type_parameter_list ();
+ var method = context.create_method (id, type, get_src_com (begin));
+ method.access = access;
+ set_attributes (method, attrs);
+ if (ModifierFlags.STATIC in flags) {
+ method.instance = false;
+ }
+ if (ModifierFlags.ABSTRACT in flags) {
+ method.is_abstract = true;
+ }
+ if (ModifierFlags.VIRTUAL in flags) {
+ method.is_virtual = true;
+ }
+ if (ModifierFlags.OVERRIDE in flags) {
+ method.overrides = true;
+ }
+ if (ModifierFlags.INLINE in flags) {
+ method.is_inline = true;
+ }
+ expect (TokenType.OPEN_PARENS);
+ if (current () != TokenType.CLOSE_PARENS) {
+ do {
+ method.add_parameter (parse_parameter ());
+ } while (accept (TokenType.COMMA));
+ }
+ expect (TokenType.CLOSE_PARENS);
+ if (accept (TokenType.THROWS)) {
+ do {
+ method.add_error_domain (parse_type ());
+ } while (accept (TokenType.COMMA));
+ }
+ if (!accept (TokenType.SEMICOLON)) {
+ method.body = parse_block ();
+ }
+ return method;
+ }
+
+ Property parse_property_declaration (Gee.List<Attribute> attrs) throws ParseError {
+ var begin = get_location ();
+ var access = parse_access_modifier ();
+ var flags = parse_member_declaration_modifiers ();
+ var type = parse_type ();
+ if (!((UnresolvedType) type).is_weak) {
+ type.takes_ownership = true;
+ }
+ string id = parse_identifier ();
+ var prop = context.create_property (id, type, null, null, get_src_com (begin));
+ prop.access = access;
+ set_attributes (prop, attrs);
+ if (ModifierFlags.ABSTRACT in flags) {
+ prop.is_abstract = true;
+ }
+ if (ModifierFlags.VIRTUAL in flags) {
+ prop.is_virtual = true;
+ }
+ if (ModifierFlags.OVERRIDE in flags) {
+ prop.overrides = true;
+ }
+ expect (TokenType.OPEN_BRACE);
+ while (current () != TokenType.CLOSE_BRACE) {
+ if (accept (TokenType.DEFAULT)) {
+ if (prop.default_expression != null) {
+ throw new ParseError.SYNTAX (get_error ("property default value already defined"));
+ }
+ if (accept (TokenType.OPEN_PARENS)) {
+ // deprecated
+ prop.default_expression = parse_expression ();
+ expect (TokenType.CLOSE_PARENS);
+ } else {
+ expect (TokenType.ASSIGN);
+ prop.default_expression = parse_expression ();
+ }
+ expect (TokenType.SEMICOLON);
+ } else {
+ parse_attributes ();
+ var accessor_access = parse_access_modifier (SymbolAccessibility.PUBLIC);
+ if (accept (TokenType.GET)) {
+ if (prop.get_accessor != null) {
+ throw new ParseError.SYNTAX (get_error ("property get accessor already defined"));
+ }
+ Block block = null;
+ if (!accept (TokenType.SEMICOLON)) {
+ block = parse_block ();
+ }
+ prop.get_accessor = context.create_property_accessor (true, false, false, block, get_src (begin));
+ prop.get_accessor.access = accessor_access;
+ } else {
+ bool writable, _construct;
+ if (accept (TokenType.SET)) {
+ writable = true;
+ _construct = accept (TokenType.CONSTRUCT);
+ } else if (accept (TokenType.CONSTRUCT)) {
+ _construct = true;
+ writable = accept (TokenType.SET);
+ } else {
+ throw new ParseError.SYNTAX (get_error ("expected get, set, or construct"));
+ }
+ if (prop.set_accessor != null) {
+ throw new ParseError.SYNTAX (get_error ("property set accessor already defined"));
+ }
+ Block block = null;
+ if (!accept (TokenType.SEMICOLON)) {
+ block = parse_block ();
+ }
+ prop.set_accessor = context.create_property_accessor (false, writable, _construct, block, get_src (begin));
+ prop.set_accessor.access = accessor_access;
+ }
+ }
+ }
+ expect (TokenType.CLOSE_BRACE);
+ return prop;
+ }
+
+ Signal parse_signal_declaration (Gee.List<Attribute> attrs) throws ParseError {
+ var begin = get_location ();
+ parse_access_modifier ();
+ parse_member_declaration_modifiers ();
+ expect (TokenType.SIGNAL);
+ var type = parse_type ();
+ string id = parse_identifier ();
+ var sig = context.create_signal (id, type, get_src_com (begin));
+ set_attributes (sig, attrs);
+ expect (TokenType.OPEN_PARENS);
+ if (current () != TokenType.CLOSE_PARENS) {
+ do {
+ var param = parse_parameter ();
+ sig.add_parameter (param);
+ } while (accept (TokenType.COMMA));
+ }
+ expect (TokenType.CLOSE_PARENS);
+ expect (TokenType.SEMICOLON);
+ return sig;
+ }
+
+ Constructor parse_constructor_declaration (Gee.List<Attribute> attrs) throws ParseError {
+ var begin = get_location ();
+ var flags = parse_member_declaration_modifiers ();
+ expect (TokenType.CONSTRUCT);
+ var c = context.create_constructor (get_src_com (begin));
+ if (ModifierFlags.STATIC in flags) {
+ c.instance = false;
+ }
+ c.body = parse_block ();
+ return c;
+ }
+
+ Destructor parse_destructor_declaration (Gee.List<Attribute> attrs) throws ParseError {
+ var begin = get_location ();
+ expect (TokenType.TILDE);
+ parse_identifier ();
+ expect (TokenType.OPEN_PARENS);
+ expect (TokenType.CLOSE_PARENS);
+ var d = context.create_destructor (get_src_com (begin));
+ d.body = parse_block ();
+ return d;
+ }
+
+ Symbol parse_struct_declaration (Gee.List<Attribute> attrs) throws ParseError {
+ var begin = get_location ();
+ var access = parse_access_modifier ();
+ parse_type_declaration_modifiers ();
+ expect (TokenType.STRUCT);
+ var sym = parse_symbol_name ();
+ var base_types = new ArrayList<DataType> ();
+ if (accept (TokenType.COLON)) {
+ do {
+ base_types.add (parse_type ());
+ } while (accept (TokenType.COMMA));
+ }
+ var st = context.create_struct (sym.name, get_src_com (begin));
+ st.access = access;
+ set_attributes (st, attrs);
+ foreach (DataType base_type in base_types) {
+ st.add_base_type (base_type);
+ }
+
+ parse_declarations (st);
+
+ Symbol result = st;
+ while (sym.inner != null) {
+ sym = sym.inner;
+ var ns = context.create_namespace (sym.name, st.source_reference);
+ ns.pkg = scanner.source_file.pkg;
+ if (result is Namespace) {
+ ns.add_namespace ((Namespace) result);
+ } else {
+ ns.add_struct ((Struct) result);
+ scanner.source_file.add_node (result);
+ }
+ result = ns;
+ }
+ return result;
+ }
+
+ void parse_struct_member (Struct st) throws ParseError {
+ var sym = parse_declaration ();
+ if (sym is Method) {
+ st.add_method ((Method) sym);
+ } else if (sym is Field) {
+ st.add_field ((Field) sym);
+ } else if (sym is Constant) {
+ st.add_constant ((Constant) sym);
+ } else if (sym == null) {
+ // workaround for current limitation of exception handling
+ throw new ParseError.SYNTAX ("syntax error in declaration");
+ } else {
+ Report.error (sym.source_reference, "unexpected declaration in struct");
+ }
+ }
+
+ Symbol parse_interface_declaration (Gee.List<Attribute> attrs) throws ParseError {
+ var begin = get_location ();
+ var access = parse_access_modifier ();
+ parse_type_declaration_modifiers ();
+ expect (TokenType.INTERFACE);
+ var sym = parse_symbol_name ();
+ var type_param_list = parse_type_parameter_list ();
+ var base_types = new ArrayList<DataType> ();
+ if (accept (TokenType.COLON)) {
+ do {
+ base_types.add (parse_type ());
+ } while (accept (TokenType.COMMA));
+ }
+ var iface = context.create_interface (sym.name, get_src_com (begin));
+ iface.access = access;
+ set_attributes (iface, attrs);
+ foreach (TypeParameter type_param in type_param_list) {
+ iface.add_type_parameter (type_param);
+ }
+ foreach (DataType base_type in base_types) {
+ iface.add_prerequisite (base_type);
+ }
+
+ parse_declarations (iface);
+
+ Symbol result = iface;
+ while (sym.inner != null) {
+ sym = sym.inner;
+ var ns = context.create_namespace (sym.name, iface.source_reference);
+ ns.pkg = scanner.source_file.pkg;
+ if (result is Namespace) {
+ ns.add_namespace ((Namespace) result);
+ } else {
+ ns.add_interface ((Interface) result);
+ scanner.source_file.add_node (result);
+ }
+ result = ns;
+ }
+ return result;
+ }
+
+ void parse_interface_member (Interface iface) throws ParseError {
+ var sym = parse_declaration ();
+ if (sym is Class) {
+ iface.add_class ((Class) sym);
+ } else if (sym is Struct) {
+ iface.add_struct ((Struct) sym);
+ } else if (sym is Enum) {
+ iface.add_enum ((Enum) sym);
+ } else if (sym is Delegate) {
+ iface.add_delegate ((Delegate) sym);
+ } else if (sym is Method) {
+ iface.add_method ((Method) sym);
+ } else if (sym is Signal) {
+ iface.add_signal ((Signal) sym);
+ } else if (sym is Field) {
+ iface.add_field ((Field) sym);
+ } else if (sym is Property) {
+ iface.add_property ((Property) sym);
+ } else if (sym == null) {
+ // workaround for current limitation of exception handling
+ throw new ParseError.SYNTAX ("syntax error in declaration");
+ } else {
+ Report.error (sym.source_reference, "unexpected declaration in interface");
+ }
+ }
+
+ Symbol parse_enum_declaration (Gee.List<Attribute> attrs) throws ParseError {
+ var begin = get_location ();
+ var access = parse_access_modifier ();
+ parse_type_declaration_modifiers ();
+ expect (TokenType.ENUM);
+ var sym = parse_symbol_name ();
+ var en = context.create_enum (sym.name, get_src_com (begin));
+ en.access = access;
+ set_attributes (en, attrs);
+
+ expect (TokenType.OPEN_BRACE);
+ do {
+ if (current () == TokenType.CLOSE_BRACE) {
+ // allow trailing comma
+ break;
+ }
+ string id = parse_identifier ();
+ var ev = context.create_enum_value (id, get_src (begin));
+ if (accept (TokenType.ASSIGN)) {
+ ev.value = parse_expression ();
+ }
+ en.add_value (ev);
+ } while (accept (TokenType.COMMA));
+ if (accept (TokenType.SEMICOLON)) {
+ // enum methods
+ while (current () != TokenType.CLOSE_BRACE) {
+ var sym = parse_declaration ();
+ if (sym is Method) {
+ en.add_method ((Method) sym);
+ } else if (sym == null) {
+ // workaround for current limitation of exception handling
+ throw new ParseError.SYNTAX ("syntax error in declaration");
+ } else {
+ Report.error (sym.source_reference, "unexpected declaration in enum");
+ }
+ }
+ }
+ expect (TokenType.CLOSE_BRACE);
+
+ Symbol result = en;
+ while (sym.inner != null) {
+ sym = sym.inner;
+ var ns = context.create_namespace (sym.name, en.source_reference);
+ ns.pkg = scanner.source_file.pkg;
+ if (result is Namespace) {
+ ns.add_namespace ((Namespace) result);
+ } else {
+ ns.add_enum ((Enum) result);
+ scanner.source_file.add_node (result);
+ }
+ result = ns;
+ }
+ return result;
+ }
+
+ Symbol parse_errordomain_declaration (Gee.List<Attribute> attrs) throws ParseError {
+ var begin = get_location ();
+ var access = parse_access_modifier ();
+ parse_type_declaration_modifiers ();
+ expect (TokenType.ERRORDOMAIN);
+ var sym = parse_symbol_name ();
+ var ed = context.create_error_domain (sym.name, get_src_com (begin));
+ ed.access = access;
+ set_attributes (ed, attrs);
+
+ expect (TokenType.OPEN_BRACE);
+ do {
+ if (current () == TokenType.CLOSE_BRACE) {
+ // allow trailing comma
+ break;
+ }
+ string id = parse_identifier ();
+ var ec = context.create_error_code (id);
+ if (accept (TokenType.ASSIGN)) {
+ ec.value = parse_expression ();
+ }
+ ed.add_code (ec);
+ } while (accept (TokenType.COMMA));
+ if (accept (TokenType.SEMICOLON)) {
+ // errordomain methods
+ while (current () != TokenType.CLOSE_BRACE) {
+ var sym = parse_declaration ();
+ if (sym is Method) {
+ ed.add_method ((Method) sym);
+ } else if (sym == null) {
+ // workaround for current limitation of exception handling
+ throw new ParseError.SYNTAX ("syntax error in declaration");
+ } else {
+ Report.error (sym.source_reference, "unexpected declaration in errordomain");
+ }
+ }
+ }
+ expect (TokenType.CLOSE_BRACE);
+
+ Symbol result = ed;
+ while (sym.inner != null) {
+ sym = sym.inner;
+ var ns = context.create_namespace (sym.name, ed.source_reference);
+ ns.pkg = scanner.source_file.pkg;
+ if (result is Namespace) {
+ ns.add_namespace ((Namespace) result);
+ } else {
+ ns.add_error_domain ((ErrorDomain) result);
+ scanner.source_file.add_node (result);
+ }
+ result = ns;
+ }
+ return result;
+ }
+
+ SymbolAccessibility parse_access_modifier (SymbolAccessibility default_access = SymbolAccessibility.PRIVATE) {
+ switch (current ()) {
+ case TokenType.PRIVATE:
+ next ();
+ return SymbolAccessibility.PRIVATE;
+ case TokenType.PROTECTED:
+ next ();
+ return SymbolAccessibility.PROTECTED;
+ case TokenType.PUBLIC:
+ next ();
+ return SymbolAccessibility.PUBLIC;
+ default:
+ return default_access;
+ }
+ }
+
+ ModifierFlags parse_type_declaration_modifiers () {
+ ModifierFlags flags = 0;
+ while (true) {
+ switch (current ()) {
+ case TokenType.ABSTRACT:
+ next ();
+ flags |= ModifierFlags.ABSTRACT;
+ break;
+ case TokenType.STATIC:
+ next ();
+ flags |= ModifierFlags.STATIC;
+ break;
+ default:
+ return flags;
+ }
+ }
+ return flags;
+ }
+
+ ModifierFlags parse_member_declaration_modifiers () {
+ ModifierFlags flags = 0;
+ while (true) {
+ switch (current ()) {
+ case TokenType.ABSTRACT:
+ next ();
+ flags |= ModifierFlags.ABSTRACT;
+ break;
+ case TokenType.CLASS:
+ next ();
+ flags |= ModifierFlags.CLASS;
+ break;
+ case TokenType.INLINE:
+ next ();
+ flags |= ModifierFlags.INLINE;
+ break;
+ case TokenType.OVERRIDE:
+ next ();
+ flags |= ModifierFlags.OVERRIDE;
+ break;
+ case TokenType.STATIC:
+ next ();
+ flags |= ModifierFlags.STATIC;
+ break;
+ case TokenType.VIRTUAL:
+ next ();
+ flags |= ModifierFlags.VIRTUAL;
+ break;
+ default:
+ return flags;
+ }
+ }
+ return flags;
+ }
+
+ FormalParameter parse_parameter () throws ParseError {
+ var attrs = parse_attributes ();
+ var begin = get_location ();
+ if (accept (TokenType.ELLIPSIS)) {
+ // varargs
+ return context.create_formal_parameter_with_ellipsis (get_src (begin));
+ }
+ bool construct_param = accept (TokenType.CONSTRUCT);
+ var type = parse_type ();
+ var ut = type as UnresolvedType;
+ if (ut != null) {
+ if (!ut.is_weak) {
+ ut.takes_ownership = true;
+ }
+ if (!ut.is_ref && !ut.is_out && !ut.transfers_ownership) {
+ // take_ownership for in parameters that don't transfer ownership is not supported
+ ut.takes_ownership = false;
+ }
+ }
+ string id = parse_identifier ();
+ var param = context.create_formal_parameter (id, type, get_src (begin));
+ set_attributes (param, attrs);
+ param.construct_parameter = construct_param;
+ if (accept (TokenType.ASSIGN)) {
+ param.default_expression = parse_expression ();
+ }
+ return param;
+ }
+
+ CreationMethod parse_creation_method_declaration (Gee.List<Attribute> attrs) throws ParseError {
+ var begin = get_location ();
+ var access = parse_access_modifier ();
+ parse_member_declaration_modifiers ();
+ var sym = parse_symbol_name ();
+ CreationMethod method;
+ if (sym.inner == null) {
+ method = context.create_creation_method (sym.name, null, get_src_com (begin));
+ } else {
+ method = context.create_creation_method (sym.inner.name, sym.name, get_src_com (begin));
+ }
+ expect (TokenType.OPEN_PARENS);
+ if (current () != TokenType.CLOSE_PARENS) {
+ do {
+ method.add_parameter (parse_parameter ());
+ } while (accept (TokenType.COMMA));
+ }
+ expect (TokenType.CLOSE_PARENS);
+ if (accept (TokenType.THROWS)) {
+ do {
+ method.add_error_domain (parse_type ());
+ } while (accept (TokenType.COMMA));
+ }
+ method.access = access;
+ set_attributes (method, attrs);
+ method.instance = false;
+ if (!accept (TokenType.SEMICOLON)) {
+ method.body = parse_block ();
+ }
+ return method;
+ }
+
+ Symbol parse_delegate_declaration (Gee.List<Attribute> attrs) throws ParseError {
+ var begin = get_location ();
+ var access = parse_access_modifier ();
+ var flags = parse_member_declaration_modifiers ();
+ expect (TokenType.DELEGATE);
+ var type = parse_type ();
+ var sym = parse_symbol_name ();
+ var type_param_list = parse_type_parameter_list ();
+ var d = context.create_delegate (sym.name, type, get_src_com (begin));
+ d.access = access;
+ set_attributes (d, attrs);
+ if (!(ModifierFlags.STATIC in flags)) {
+ d.instance = true;
+ }
+ foreach (TypeParameter type_param in type_param_list) {
+ d.add_type_parameter (type_param);
+ }
+ expect (TokenType.OPEN_PARENS);
+ if (current () != TokenType.CLOSE_PARENS) {
+ do {
+ d.add_parameter (parse_parameter ());
+ } while (accept (TokenType.COMMA));
+ }
+ expect (TokenType.CLOSE_PARENS);
+ if (accept (TokenType.THROWS)) {
+ do {
+ parse_type ();
+ } while (accept (TokenType.COMMA));
+ }
+ expect (TokenType.SEMICOLON);
+
+ Symbol result = d;
+ while (sym.inner != null) {
+ sym = sym.inner;
+ var ns = context.create_namespace (sym.name, d.source_reference);
+ ns.pkg = scanner.source_file.pkg;
+ if (result is Namespace) {
+ ns.add_namespace ((Namespace) result);
+ } else {
+ ns.add_delegate ((Delegate) result);
+ scanner.source_file.add_node (result);
+ }
+ result = ns;
+ }
+ return result;
+ }
+
+ Gee.List<TypeParameter> parse_type_parameter_list () throws ParseError {
+ var list = new ArrayList<TypeParameter> ();
+ if (accept (TokenType.OP_LT)) {
+ do {
+ var begin = get_location ();
+ string id = parse_identifier ();
+ list.add (context.create_type_parameter (id, get_src (begin)));
+ } while (accept (TokenType.COMMA));
+ expect (TokenType.OP_GT);
+ }
+ return list;
+ }
+
+ void skip_type_argument_list () throws ParseError {
+ if (accept (TokenType.OP_LT)) {
+ do {
+ skip_type ();
+ } while (accept (TokenType.COMMA));
+ expect (TokenType.OP_GT);
+ }
+ }
+
+ // try to parse type argument list
+ Gee.List<DataType> parse_type_argument_list (bool maybe_expression) throws ParseError {
+ var begin = get_location ();
+ if (accept (TokenType.OP_LT)) {
+ var list = new ArrayList<DataType> ();
+ do {
+ switch (current ()) {
+ case TokenType.VOID:
+ case TokenType.WEAK:
+ case TokenType.IDENTIFIER:
+ var type = parse_type ();
+ if (!((UnresolvedType) type).is_weak) {
+ type.takes_ownership = true;
+ }
+ list.add (type);
+ break;
+ default:
+ rollback (begin);
+ return null;
+ }
+ } while (accept (TokenType.COMMA));
+ if (!accept (TokenType.OP_GT)) {
+ rollback (begin);
+ return null;
+ }
+ if (maybe_expression) {
+ // check follower to decide whether to keep type argument list
+ switch (current ()) {
+ case TokenType.OPEN_PARENS:
+ case TokenType.CLOSE_PARENS:
+ case TokenType.CLOSE_BRACKET:
+ case TokenType.COLON:
+ case TokenType.SEMICOLON:
+ case TokenType.COMMA:
+ case TokenType.DOT:
+ case TokenType.INTERR:
+ case TokenType.OP_EQ:
+ case TokenType.OP_NE:
+ // keep type argument list
+ break;
+ default:
+ // interpret tokens as expression
+ rollback (begin);
+ return null;
+ }
+ }
+ return list;
+ }
+ return null;
+ }
+
+ MemberAccess parse_member_name () throws ParseError {
+ var begin = get_location ();
+ MemberAccess expr = null;
+ do {
+ string id = parse_identifier ();
+ var type_arg_list = parse_type_argument_list (false);
+ expr = context.create_member_access (expr, id, get_src (begin));
+ if (type_arg_list != null) {
+ foreach (DataType type_arg in type_arg_list) {
+ expr.add_type_argument (type_arg);
+ }
+ }
+ } while (accept (TokenType.DOT));
+ return expr;
+ }
+
+ bool is_declaration_keyword (TokenType type) {
+ switch (type) {
+ case TokenType.ABSTRACT:
+ case TokenType.CLASS:
+ case TokenType.CONST:
+ case TokenType.DELEGATE:
+ case TokenType.ENUM:
+ case TokenType.ERRORDOMAIN:
+ case TokenType.INLINE:
+ case TokenType.INTERFACE:
+ case TokenType.NAMESPACE:
+ case TokenType.OVERRIDE:
+ case TokenType.PRIVATE:
+ case TokenType.PROTECTED:
+ case TokenType.PUBLIC:
+ case TokenType.SIGNAL:
+ case TokenType.STATIC:
+ case TokenType.STRUCT:
+ case TokenType.VIRTUAL:
+ case TokenType.VOLATILE:
+ return true;
+ default:
+ return false;
+ }
+ }
}
+
+public errordomain Vala.ParseError {
+ FAILED,
+ SYNTAX
+}
+
Added: trunk/vala/valascanner.vala
==============================================================================
--- (empty file)
+++ trunk/vala/valascanner.vala Sun Apr 13 10:25:25 2008
@@ -0,0 +1,774 @@
+/* valascanner.vala
+ *
+ * Copyright (C) 2008 JÃrg Billeter
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * Author:
+ * JÃrg Billeter <j bitron ch>
+ */
+
+using GLib;
+using Gee;
+
+/**
+ * Lexical scanner for Vala source files.
+ */
+public class Vala.Scanner : Object {
+ public SourceFile source_file { get; construct; }
+
+ char* begin;
+ char* current;
+ char* end;
+
+ int line;
+ int column;
+
+ string _comment;
+
+ public Scanner (SourceFile source_file) {
+ this.source_file = source_file;
+ }
+
+ construct {
+ begin = source_file.get_mapped_contents ();
+ end = begin + source_file.get_mapped_length ();
+
+ current = begin;
+
+ line = 1;
+ column = 1;
+ }
+
+ bool is_ident_char (char c) {
+ return (c.isalnum () || c == '_');
+ }
+
+ TokenType get_identifier_or_keyword (char* begin, int len) {
+ switch (len) {
+ case 2:
+ switch (begin[0]) {
+ case 'a':
+ if (matches (begin, "as")) return TokenType.AS;
+ break;
+ case 'd':
+ if (matches (begin, "do")) return TokenType.DO;
+ break;
+ case 'i':
+ switch (begin[1]) {
+ case 'f':
+ return TokenType.IF;
+ case 'n':
+ return TokenType.IN;
+ case 's':
+ return TokenType.IS;
+ }
+ break;
+ }
+ break;
+ case 3:
+ switch (begin[0]) {
+ case 'f':
+ if (matches (begin, "for")) return TokenType.FOR;
+ break;
+ case 'g':
+ if (matches (begin, "get")) return TokenType.GET;
+ break;
+ case 'n':
+ if (matches (begin, "new")) return TokenType.NEW;
+ break;
+ case 'o':
+ if (matches (begin, "out")) return TokenType.OUT;
+ break;
+ case 'r':
+ if (matches (begin, "ref")) return TokenType.REF;
+ break;
+ case 's':
+ if (matches (begin, "set")) return TokenType.SET;
+ break;
+ case 't':
+ if (matches (begin, "try")) return TokenType.TRY;
+ break;
+ case 'v':
+ if (matches (begin, "var")) return TokenType.VAR;
+ break;
+ }
+ break;
+ case 4:
+ switch (begin[0]) {
+ case 'b':
+ if (matches (begin, "base")) return TokenType.BASE;
+ break;
+ case 'c':
+ if (matches (begin, "case")) return TokenType.CASE;
+ break;
+ case 'e':
+ switch (begin[1]) {
+ case 'l':
+ if (matches (begin, "else")) return TokenType.ELSE;
+ break;
+ case 'n':
+ if (matches (begin, "enum")) return TokenType.ENUM;
+ break;
+ }
+ break;
+ case 'l':
+ if (matches (begin, "lock")) return TokenType.LOCK;
+ break;
+ case 'n':
+ if (matches (begin, "null")) return TokenType.NULL;
+ break;
+ case 't':
+ switch (begin[1]) {
+ case 'h':
+ if (matches (begin, "this")) return TokenType.THIS;
+ break;
+ case 'r':
+ if (matches (begin, "true")) return TokenType.TRUE;
+ break;
+ }
+ break;
+ case 'v':
+ if (matches (begin, "void")) return TokenType.VOID;
+ break;
+ case 'w':
+ if (matches (begin, "weak")) return TokenType.WEAK;
+ break;
+ }
+ break;
+ case 5:
+ switch (begin[0]) {
+ case 'b':
+ if (matches (begin, "break")) return TokenType.BREAK;
+ break;
+ case 'c':
+ switch (begin[1]) {
+ case 'a':
+ if (matches (begin, "catch")) return TokenType.CATCH;
+ break;
+ case 'l':
+ if (matches (begin, "class")) return TokenType.CLASS;
+ break;
+ case 'o':
+ if (matches (begin, "const")) return TokenType.CONST;
+ break;
+ }
+ break;
+ case 'f':
+ if (matches (begin, "false")) return TokenType.FALSE;
+ break;
+ case 't':
+ if (matches (begin, "throw")) return TokenType.THROW;
+ break;
+ case 'u':
+ if (matches (begin, "using")) return TokenType.USING;
+ break;
+ case 'w':
+ if (matches (begin, "while")) return TokenType.WHILE;
+ break;
+ }
+ break;
+ case 6:
+ switch (begin[0]) {
+ case 'd':
+ if (matches (begin, "delete")) return TokenType.DELETE;
+ break;
+ case 'i':
+ if (matches (begin, "inline")) return TokenType.INLINE;
+ break;
+ case 'p':
+ if (matches (begin, "public")) return TokenType.PUBLIC;
+ break;
+ case 'r':
+ if (matches (begin, "return")) return TokenType.RETURN;
+ break;
+ case 's':
+ switch (begin[1]) {
+ case 'i':
+ switch (begin[2]) {
+ case 'g':
+ if (matches (begin, "signal")) return TokenType.SIGNAL;
+ break;
+ case 'z':
+ if (matches (begin, "sizeof")) return TokenType.SIZEOF;
+ break;
+ }
+ break;
+ case 't':
+ switch (begin[2]) {
+ case 'a':
+ if (matches (begin, "static")) return TokenType.STATIC;
+ break;
+ case 'r':
+ if (matches (begin, "struct")) return TokenType.STRUCT;
+ break;
+ }
+ break;
+ case 'w':
+ if (matches (begin, "switch")) return TokenType.SWITCH;
+ break;
+ }
+ break;
+ case 't':
+ switch (begin[1]) {
+ case 'h':
+ if (matches (begin, "throws")) return TokenType.THROWS;
+ break;
+ case 'y':
+ if (matches (begin, "typeof")) return TokenType.TYPEOF;
+ break;
+ }
+ break;
+ }
+ break;
+ case 7:
+ switch (begin[0]) {
+ case 'd':
+ if (matches (begin, "default")) return TokenType.DEFAULT;
+ break;
+ case 'e':
+ if (matches (begin, "ensures")) return TokenType.ENSURES;
+ break;
+ case 'f':
+ switch (begin[1]) {
+ case 'i':
+ if (matches (begin, "finally")) return TokenType.FINALLY;
+ break;
+ case 'o':
+ if (matches (begin, "foreach")) return TokenType.FOREACH;
+ break;
+ }
+ break;
+ case 'p':
+ if (matches (begin, "private")) return TokenType.PRIVATE;
+ break;
+ case 'v':
+ if (matches (begin, "virtual")) return TokenType.VIRTUAL;
+ break;
+ }
+ break;
+ case 8:
+ switch (begin[0]) {
+ case 'a':
+ if (matches (begin, "abstract")) return TokenType.ABSTRACT;
+ break;
+ case 'c':
+ if (matches (begin, "continue")) return TokenType.CONTINUE;
+ break;
+ case 'd':
+ if (matches (begin, "delegate")) return TokenType.DELEGATE;
+ break;
+ case 'o':
+ if (matches (begin, "override")) return TokenType.OVERRIDE;
+ break;
+ case 'r':
+ if (matches (begin, "requires")) return TokenType.REQUIRES;
+ break;
+ case 'v':
+ if (matches (begin, "volatile")) return TokenType.VOLATILE;
+ break;
+ }
+ break;
+ case 9:
+ switch (begin[0]) {
+ case 'c':
+ if (matches (begin, "construct")) return TokenType.CONSTRUCT;
+ break;
+ case 'i':
+ if (matches (begin, "interface")) return TokenType.INTERFACE;
+ break;
+ case 'n':
+ if (matches (begin, "namespace")) return TokenType.NAMESPACE;
+ break;
+ case 'p':
+ if (matches (begin, "protected")) return TokenType.PROTECTED;
+ break;
+ }
+ break;
+ case 11:
+ if (matches (begin, "errordomain")) return TokenType.ERRORDOMAIN;
+ break;
+ }
+ return TokenType.IDENTIFIER;
+ }
+
+ public TokenType read_token (out SourceLocation token_begin, out SourceLocation token_end) {
+ space ();
+
+ TokenType type;
+ char* begin = current;
+ token_begin.pos = begin;
+ token_begin.line = line;
+ token_begin.column = column;
+
+ int token_length_in_chars = -1;
+
+ if (current >= end) {
+ type = TokenType.EOF;
+ } else if (current[0].isalpha () || current[0] == '_') {
+ int len = 0;
+ while (current < end && is_ident_char (current[0])) {
+ current++;
+ len++;
+ }
+ type = get_identifier_or_keyword (begin, len);
+ } else if (current[0] == '@') {
+ token_begin.pos++; // @ is not part of the identifier
+ current++;
+ int len = 0;
+ while (current < end && is_ident_char (current[0])) {
+ current++;
+ len++;
+ }
+ type = TokenType.IDENTIFIER;
+ } else if (current[0].isdigit ()) {
+ while (current < end && current[0].isdigit ()) {
+ current++;
+ }
+ type = TokenType.INTEGER_LITERAL;
+ if (current < end && current[0].tolower () == 'l') {
+ current++;
+ if (current < end && current[0].tolower () == 'l') {
+ current++;
+ }
+ } else if (current < end && current[0].tolower () == 'u') {
+ current++;
+ if (current < end && current[0].tolower () == 'l') {
+ current++;
+ if (current < end && current[0].tolower () == 'l') {
+ current++;
+ }
+ }
+ } else if (current < end && current[0] == '.') {
+ current++;
+ while (current < end && current[0].isdigit ()) {
+ current++;
+ }
+ if (current < end && current[0].tolower () == 'e') {
+ current++;
+ if (current < end && (current[0] == '+' || current[0] == '-')) {
+ current++;
+ }
+ while (current < end && current[0].isdigit ()) {
+ current++;
+ }
+ }
+ if (current < end && current[0].tolower () == 'f') {
+ current++;
+ }
+ type = TokenType.REAL_LITERAL;
+ } else if (current < end && current == begin + 1
+ && begin[0] == '0' && begin[1] == 'x' && begin[2].isxdigit ()) {
+ // hexadecimal integer literal
+ current++;
+ while (current < end && current[0].isxdigit ()) {
+ current++;
+ }
+ } else if (current < end && is_ident_char (current[0])) {
+ // allow identifiers to start with a digit
+ // as long as they contain at least one char
+ while (current < end && is_ident_char (current[0])) {
+ current++;
+ }
+ type = TokenType.IDENTIFIER;
+ }
+ } else {
+ switch (current[0]) {
+ case '{':
+ type = TokenType.OPEN_BRACE;
+ current++;
+ break;
+ case '}':
+ type = TokenType.CLOSE_BRACE;
+ current++;
+ break;
+ case '(':
+ type = TokenType.OPEN_PARENS;
+ current++;
+ break;
+ case ')':
+ type = TokenType.CLOSE_PARENS;
+ current++;
+ break;
+ case '[':
+ type = TokenType.OPEN_BRACKET;
+ current++;
+ break;
+ case ']':
+ type = TokenType.CLOSE_BRACKET;
+ current++;
+ break;
+ case '.':
+ type = TokenType.DOT;
+ current++;
+ if (current < end - 1) {
+ if (current[0] == '.' && current[1] == '.') {
+ type = TokenType.ELLIPSIS;
+ current += 2;
+ }
+ }
+ break;
+ case ':':
+ type = TokenType.COLON;
+ current++;
+ break;
+ case ',':
+ type = TokenType.COMMA;
+ current++;
+ break;
+ case ';':
+ type = TokenType.SEMICOLON;
+ current++;
+ break;
+ case '#':
+ type = TokenType.HASH;
+ current++;
+ break;
+ case '?':
+ type = TokenType.INTERR;
+ current++;
+ break;
+ case '|':
+ type = TokenType.BITWISE_OR;
+ current++;
+ if (current < end) {
+ switch (current[0]) {
+ case '=':
+ type = TokenType.ASSIGN_BITWISE_OR;
+ current++;
+ break;
+ case '|':
+ type = TokenType.OP_OR;
+ current++;
+ break;
+ }
+ }
+ break;
+ case '&':
+ type = TokenType.BITWISE_AND;
+ current++;
+ if (current < end) {
+ switch (current[0]) {
+ case '=':
+ type = TokenType.ASSIGN_BITWISE_AND;
+ current++;
+ break;
+ case '&':
+ type = TokenType.OP_AND;
+ current++;
+ break;
+ }
+ }
+ break;
+ case '^':
+ type = TokenType.CARRET;
+ current++;
+ if (current < end && current[0] == '=') {
+ type = TokenType.ASSIGN_BITWISE_XOR;
+ current++;
+ }
+ break;
+ case '~':
+ type = TokenType.TILDE;
+ current++;
+ break;
+ case '=':
+ type = TokenType.ASSIGN;
+ current++;
+ if (current < end) {
+ switch (current[0]) {
+ case '=':
+ type = TokenType.OP_EQ;
+ current++;
+ break;
+ case '>':
+ type = TokenType.LAMBDA;
+ current++;
+ break;
+ }
+ }
+ break;
+ case '<':
+ type = TokenType.OP_LT;
+ current++;
+ if (current < end) {
+ switch (current[0]) {
+ case '=':
+ type = TokenType.OP_LE;
+ current++;
+ break;
+ case '<':
+ type = TokenType.OP_SHIFT_LEFT;
+ current++;
+ if (current < end && current[0] == '=') {
+ type = TokenType.ASSIGN_SHIFT_LEFT;
+ current++;
+ }
+ break;
+ }
+ }
+ break;
+ case '>':
+ type = TokenType.OP_GT;
+ current++;
+ if (current < end && current[0] == '=') {
+ type = TokenType.OP_GE;
+ current++;
+ }
+ break;
+ case '!':
+ type = TokenType.OP_NEG;
+ current++;
+ if (current < end && current[0] == '=') {
+ type = TokenType.OP_NE;
+ current++;
+ }
+ break;
+ case '+':
+ type = TokenType.PLUS;
+ current++;
+ if (current < end) {
+ switch (current[0]) {
+ case '=':
+ type = TokenType.ASSIGN_ADD;
+ current++;
+ break;
+ case '+':
+ type = TokenType.OP_INC;
+ current++;
+ break;
+ }
+ }
+ break;
+ case '-':
+ type = TokenType.MINUS;
+ current++;
+ if (current < end) {
+ switch (current[0]) {
+ case '=':
+ type = TokenType.ASSIGN_SUB;
+ current++;
+ break;
+ case '-':
+ type = TokenType.OP_DEC;
+ current++;
+ break;
+ case '>':
+ type = TokenType.OP_PTR;
+ current++;
+ break;
+ }
+ }
+ break;
+ case '*':
+ type = TokenType.STAR;
+ current++;
+ if (current < end && current[0] == '=') {
+ type = TokenType.ASSIGN_MUL;
+ current++;
+ }
+ break;
+ case '/':
+ type = TokenType.DIV;
+ current++;
+ if (current < end && current[0] == '=') {
+ type = TokenType.ASSIGN_DIV;
+ current++;
+ }
+ break;
+ case '%':
+ type = TokenType.PERCENT;
+ current++;
+ if (current < end && current[0] == '=') {
+ type = TokenType.ASSIGN_PERCENT;
+ current++;
+ }
+ break;
+ case '\'':
+ case '"':
+ if (begin[0] == '\'') {
+ type = TokenType.CHARACTER_LITERAL;
+ } else {
+ type = TokenType.STRING_LITERAL;
+ }
+ token_length_in_chars = 2;
+ current++;
+ while (current < end && current[0] != begin[0]) {
+ if (current[0] == '\\') {
+ current++;
+ token_length_in_chars++;
+ if (current < end && current[0] == 'x') {
+ // hexadecimal escape character
+ current++;
+ token_length_in_chars++;
+ while (current < end && current[0].isxdigit ()) {
+ current++;
+ token_length_in_chars++;
+ }
+ } else {
+ current++;
+ token_length_in_chars++;
+ }
+ } else if (current[0] == '\n') {
+ break;
+ } else {
+ unichar u = ((string) current).get_char_validated ((long) (end - current));
+ if (u != (unichar) (-1)) {
+ current += u.to_utf8 (null);
+ token_length_in_chars++;
+ } else {
+ Report.error (new SourceReference (source_file, line, column + token_length_in_chars, line, column + token_length_in_chars), "invalid UTF-8 character");
+ }
+ }
+ }
+ if (current < end && current[0] != '\n') {
+ current++;
+ } else {
+ Report.error (new SourceReference (source_file, line, column + token_length_in_chars, line, column + token_length_in_chars), "syntax error, expected %c".printf (begin[0]));
+ }
+ break;
+ default:
+ unichar u = ((string) current).get_char_validated ((long) (end - current));
+ if (u != (unichar) (-1)) {
+ current += u.to_utf8 (null);
+ Report.error (new SourceReference (source_file, line, column, line, column), "syntax error, unexpected character");
+ } else {
+ current++;
+ Report.error (new SourceReference (source_file, line, column, line, column), "invalid UTF-8 character");
+ }
+ column++;
+ return read_token (out token_begin, out token_end);
+ }
+ }
+
+ if (token_length_in_chars < 0) {
+ column += (int) (current - begin);
+ } else {
+ column += token_length_in_chars;
+ }
+
+ token_end.pos = current;
+ token_end.line = line;
+ token_end.column = column - 1;
+
+ return type;
+ }
+
+ bool matches (char* begin, string keyword) {
+ char* keyword_array = keyword;
+ long len = keyword.len ();
+ for (int i = 0; i < len; i++) {
+ if (begin[i] != keyword_array[i]) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ bool whitespace () {
+ bool found = false;
+ while (current < end && current[0].isspace ()) {
+ if (current[0] == '\n') {
+ line++;
+ column = 0;
+ }
+ found = true;
+ current++;
+ column++;
+ }
+ return found;
+ }
+
+ bool comment () {
+ if (current > end - 2
+ || current[0] != '/'
+ || (current[1] != '/' && current[1] != '*')) {
+ return false;
+ }
+
+ if (current[1] == '/') {
+ // single-line comment
+ current += 2;
+ char* begin = current;
+ // skip until end of line or end of file
+ while (current < end && current[0] != '\n') {
+ current++;
+ }
+ push_comment (((string) begin).ndup ((long) (current - begin)), line == 1);
+ } else {
+ // delimited comment
+ current += 2;
+ char* begin = current;
+ int begin_line = line;
+ while (current < end - 1
+ && (current[0] != '*' || current[1] != '/')) {
+ if (current[0] == '\n') {
+ line++;
+ column = 0;
+ }
+ current++;
+ column++;
+ }
+ if (current == end - 1) {
+ Report.error (new SourceReference (source_file, line, column, line, column), "syntax error, expected */");
+ return true;
+ }
+ push_comment (((string) begin).ndup ((long) (current - begin)), begin_line == 1);
+ current += 2;
+ column += 2;
+ }
+
+ return true;
+ }
+
+ void space () {
+ while (whitespace () || comment ()) {
+ }
+ }
+
+ void push_comment (string! comment_item, bool file_comment) {
+ if (_comment == null) {
+ _comment = comment_item;
+ } else {
+ _comment = "%s\n%s".printf (_comment, comment_item);
+ }
+ if (file_comment) {
+ source_file.comment = _comment;
+ _comment = null;
+ }
+ }
+
+ /**
+ * Clears and returns the content of the comment stack.
+ *
+ * @return saved comment
+ */
+ public string pop_comment () {
+ if (_comment == null) {
+ return null;
+ }
+
+ var result = new StringBuilder (_comment);
+ _comment = null;
+
+ weak string index;
+ while ((index = result.str.chr (-1, '\t')) != null) {
+ result.erase (result.str.pointer_to_offset (index), 1);
+ }
+
+ return result.str;
+ }
+}
+
Modified: trunk/vala/valascope.vala
==============================================================================
--- trunk/vala/valascope.vala (original)
+++ trunk/vala/valascope.vala Sun Apr 13 10:25:25 2008
@@ -60,7 +60,7 @@
symbol_table = new HashMap<string,Symbol> (str_hash, str_equal);
} else if (lookup (name) != null) {
owner.error = true;
- Report.error (owner.source_reference, "`%s' already contains a definition for `%s'".printf (owner.get_full_name (), name));
+ Report.error (sym.source_reference, "`%s' already contains a definition for `%s'".printf (owner.get_full_name (), name));
return;
}
@@ -68,7 +68,11 @@
}
sym.owner = this;
}
-
+
+ public void remove (string name) {
+ symbol_table.remove (name);
+ }
+
/**
* Returns the symbol stored in the symbol table with the specified
* name.
Modified: trunk/vala/valasourcefile.vala
==============================================================================
--- trunk/vala/valasourcefile.vala (original)
+++ trunk/vala/valasourcefile.vala Sun Apr 13 10:25:25 2008
@@ -87,6 +87,8 @@
private Gee.ArrayList<string> source_array = null;
+ private MappedFile mapped_file = null;
+
/**
* Creates a new source file.
*
@@ -124,6 +126,10 @@
nodes.add (node);
}
+ public void remove_node (CodeNode! node) {
+ nodes.remove (node);
+ }
+
/**
* Returns a copy of the list of code nodes.
*
@@ -396,6 +402,17 @@
}
}
+ public char* get_mapped_contents () {
+ if (mapped_file == null) {
+ mapped_file = new MappedFile (filename, false);
+ }
+
+ return mapped_file.get_contents ();
+ }
+
+ public size_t get_mapped_length () {
+ return mapped_file.get_length ();
+ }
}
public enum Vala.SourceFileDependencyType {
Added: trunk/vala/valasourcelocation.vala
==============================================================================
--- (empty file)
+++ trunk/vala/valasourcelocation.vala Sun Apr 13 10:25:25 2008
@@ -0,0 +1,39 @@
+/* valasourcelocation.vala
+ *
+ * Copyright (C) 2008 JÃrg Billeter
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * Author:
+ * JÃrg Billeter <j bitron ch>
+ */
+
+using GLib;
+
+/**
+ * Represents a position in a source file.
+ */
+public struct Vala.SourceLocation {
+ public char* pos;
+ public int line;
+ public int column;
+
+ public SourceLocation (char* _pos, int _line, int _column) {
+ pos = _pos;
+ line = _line;
+ column = _column;
+ }
+}
+
Added: trunk/vala/valatokentype.vala
==============================================================================
--- (empty file)
+++ trunk/vala/valatokentype.vala Sun Apr 13 10:25:25 2008
@@ -0,0 +1,256 @@
+/* valatokentype.vala
+ *
+ * Copyright (C) 2008 JÃrg Billeter
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * Author:
+ * JÃrg Billeter <j bitron ch>
+ */
+
+using GLib;
+
+public enum Vala.TokenType {
+ NONE,
+ ABSTRACT,
+ AS,
+ ASSIGN,
+ ASSIGN_ADD,
+ ASSIGN_BITWISE_AND,
+ ASSIGN_BITWISE_OR,
+ ASSIGN_BITWISE_XOR,
+ ASSIGN_DIV,
+ ASSIGN_MUL,
+ ASSIGN_PERCENT,
+ ASSIGN_SHIFT_LEFT,
+ ASSIGN_SUB,
+ BASE,
+ BITWISE_AND,
+ BITWISE_OR,
+ BREAK,
+ CARRET,
+ CASE,
+ CATCH,
+ CHARACTER_LITERAL,
+ CLASS,
+ CLOSE_BRACE,
+ CLOSE_BRACKET,
+ CLOSE_PARENS,
+ COLON,
+ COMMA,
+ CONST,
+ CONSTRUCT,
+ CONTINUE,
+ DEFAULT,
+ DELEGATE,
+ DELETE,
+ DIV,
+ DO,
+ DOT,
+ ELLIPSIS,
+ ELSE,
+ ENUM,
+ ENSURES,
+ ERRORDOMAIN,
+ EOF,
+ FALSE,
+ FINALLY,
+ FOR,
+ FOREACH,
+ GET,
+ HASH,
+ IDENTIFIER,
+ IF,
+ IN,
+ INLINE,
+ INTEGER_LITERAL,
+ INTERFACE,
+ INTERR,
+ IS,
+ LAMBDA,
+ LOCK,
+ MINUS,
+ NAMESPACE,
+ NEW,
+ NULL,
+ OUT,
+ OP_AND,
+ OP_DEC,
+ OP_EQ,
+ OP_GE,
+ OP_GT,
+ OP_INC,
+ OP_LE,
+ OP_LT,
+ OP_NE,
+ OP_NEG,
+ OP_OR,
+ OP_PTR,
+ OP_SHIFT_LEFT,
+ OPEN_BRACE,
+ OPEN_BRACKET,
+ OPEN_PARENS,
+ OVERRIDE,
+ PERCENT,
+ PLUS,
+ PRIVATE,
+ PROTECTED,
+ PUBLIC,
+ REAL_LITERAL,
+ REF,
+ REQUIRES,
+ RETURN,
+ SEMICOLON,
+ SET,
+ SIGNAL,
+ SIZEOF,
+ STAR,
+ STATIC,
+ STRING_LITERAL,
+ STRUCT,
+ SWITCH,
+ THIS,
+ THROW,
+ THROWS,
+ TILDE,
+ TRUE,
+ TRY,
+ TYPEOF,
+ USING,
+ VAR,
+ VIRTUAL,
+ VOID,
+ VOLATILE,
+ WEAK,
+ WHILE;
+
+ public weak string to_string () {
+ switch (this) {
+ case ABSTRACT: return "`abstract'";
+ case AS: return "`as'";
+ case ASSIGN: return "`='";
+ case ASSIGN_ADD: return "`+='";
+ case ASSIGN_BITWISE_AND: return "`&='";
+ case ASSIGN_BITWISE_OR: return "`|='";
+ case ASSIGN_BITWISE_XOR: return "`^='";
+ case ASSIGN_DIV: return "`/='";
+ case ASSIGN_MUL: return "`*='";
+ case ASSIGN_PERCENT: return "`%='";
+ case ASSIGN_SHIFT_LEFT: return "`<<='";
+ case ASSIGN_SUB: return "`-='";
+ case BASE: return "`base'";
+ case BITWISE_AND: return "`&'";
+ case BITWISE_OR: return "`|'";
+ case BREAK: return "`break'";
+ case CARRET: return "`^'";
+ case CASE: return "`case'";
+ case CATCH: return "`catch'";
+ case CHARACTER_LITERAL: return "character literal";
+ case CLASS: return "`class'";
+ case CLOSE_BRACE: return "`}'";
+ case CLOSE_BRACKET: return "`]'";
+ case CLOSE_PARENS: return "`)'";
+ case COLON: return "`:'";
+ case COMMA: return "`,'";
+ case CONST: return "`const'";
+ case CONSTRUCT: return "`construct'";
+ case CONTINUE: return "`continue'";
+ case DEFAULT: return "`default'";
+ case DELEGATE: return "`delegate'";
+ case DELETE: return "`delete'";
+ case DIV: return "`/'";
+ case DO: return "`do'";
+ case DOT: return "`.'";
+ case ELLIPSIS: return "`...'";
+ case ELSE: return "`else'";
+ case ENUM: return "`enum'";
+ case ENSURES: return "`ensures'";
+ case ERRORDOMAIN: return "`errordomain'";
+ case EOF: return "end of file";
+ case FALSE: return "`false'";
+ case FINALLY: return "`finally'";
+ case FOR: return "`for'";
+ case FOREACH: return "`foreach'";
+ case GET: return "`get'";
+ case HASH: return "`hash'";
+ case IDENTIFIER: return "identifier";
+ case IF: return "`if'";
+ case IN: return "`in'";
+ case INLINE: return "`inline'";
+ case INTEGER_LITERAL: return "integer literal";
+ case INTERFACE: return "`interface'";
+ case INTERR: return "`?'";
+ case IS: return "`is'";
+ case LAMBDA: return "`=>'";
+ case LOCK: return "`lock'";
+ case MINUS: return "`-'";
+ case NAMESPACE: return "`namespace'";
+ case NEW: return "`new'";
+ case NULL: return "`null'";
+ case OUT: return "`out'";
+ case OP_AND: return "`&&'";
+ case OP_DEC: return "`--'";
+ case OP_EQ: return "`=='";
+ case OP_GE: return "`>='";
+ case OP_GT: return "`>'";
+ case OP_INC: return "`++'";
+ case OP_LE: return "`<='";
+ case OP_LT: return "`<'";
+ case OP_NE: return "`!='";
+ case OP_NEG: return "`!'";
+ case OP_OR: return "`||'";
+ case OP_PTR: return "`->'";
+ case OP_SHIFT_LEFT: return "`<<'";
+ case OPEN_BRACE: return "`{'";
+ case OPEN_BRACKET: return "`['";
+ case OPEN_PARENS: return "`('";
+ case OVERRIDE: return "`override'";
+ case PERCENT: return "`%'";
+ case PLUS: return "`+'";
+ case PRIVATE: return "`private'";
+ case PROTECTED: return "`protected'";
+ case PUBLIC: return "`public'";
+ case REAL_LITERAL: return "real literal";
+ case REF: return "`ref'";
+ case REQUIRES: return "`requires'";
+ case RETURN: return "`return'";
+ case SEMICOLON: return "`;'";
+ case SET: return "`set'";
+ case SIGNAL: return "`signal'";
+ case SIZEOF: return "`sizeof'";
+ case STAR: return "`*'";
+ case STATIC: return "`static'";
+ case STRING_LITERAL: return "string literal";
+ case STRUCT: return "`struct'";
+ case SWITCH: return "`switch'";
+ case THIS: return "`this'";
+ case THROW: return "`throw'";
+ case THROWS: return "`throws'";
+ case TILDE: return "`~'";
+ case TRUE: return "`true'";
+ case TRY: return "`try'";
+ case TYPEOF: return "`typeof'";
+ case USING: return "`using'";
+ case VAR: return "`var'";
+ case VIRTUAL: return "`virtual'";
+ case VOID: return "`void'";
+ case VOLATILE: return "`volatile'";
+ case WEAK: return "`weak'";
+ case WHILE: return "`while'";
+ default: return "unknown token";
+ }
+ }
+}
+
Added: trunk/vala/valatuple.vala
==============================================================================
--- (empty file)
+++ trunk/vala/valatuple.vala Sun Apr 13 10:25:25 2008
@@ -0,0 +1,47 @@
+/* valatuple.vala
+ *
+ * Copyright (C) 2006-2008 JÃrg Billeter
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * Author:
+ * JÃrg Billeter <j bitron ch>
+ */
+
+using GLib;
+using Gee;
+
+/**
+ * Represents a fixed-length sequence of expressions in the source code.
+ */
+public class Vala.Tuple : Expression {
+ private Gee.List<Expression> expression_list = new ArrayList<Expression> ();
+
+ public Tuple () {
+ }
+
+ public void add_expression (Expression expr) {
+ expression_list.add (expr);
+ }
+
+ public Gee.List<Expression> get_expressions () {
+ return expression_list;
+ }
+
+ public override bool is_pure () {
+ return false;
+ }
+}
+
Modified: trunk/vala/valaunaryexpression.vala
==============================================================================
--- trunk/vala/valaunaryexpression.vala (original)
+++ trunk/vala/valaunaryexpression.vala Sun Apr 13 10:25:25 2008
@@ -103,6 +103,7 @@
}
public enum Vala.UnaryOperator {
+ NONE,
PLUS,
MINUS,
LOGICAL_NEGATION,
Modified: trunk/vala/valaunresolvedtype.vala
==============================================================================
--- trunk/vala/valaunresolvedtype.vala (original)
+++ trunk/vala/valaunresolvedtype.vala Sun Apr 13 10:25:25 2008
@@ -122,4 +122,8 @@
return result;
}
+
+ public override string to_string () {
+ return unresolved_symbol.to_string ();
+ }
}
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]