/* valagenieparser.vala
*
- * Copyright (C) 2008 Jamie McCracken, Jürg Billeter
+ * Copyright (C) 2008-2012 Jamie McCracken, Jürg Billeter
* Based on code by Jürg Billeter
*
* This library is free software; you can redistribute it and/or
STATIC = 1 << 6,
VIRTUAL = 1 << 7,
PRIVATE = 1 << 8,
- ASYNC = 1 << 9
+ ASYNC = 1 << 9,
+ SEALED = 1 << 10
}
public Parser () {
case TokenType.REF:
case TokenType.REQUIRES:
case TokenType.RETURN:
+ case TokenType.SEALED:
case TokenType.SET:
case TokenType.SIZEOF:
case TokenType.STATIC:
}
void skip_type () throws ParseError {
- if (accept (TokenType.VOID)) {
- while (accept (TokenType.STAR)) {
- }
- return;
- }
+
accept (TokenType.DYNAMIC);
accept (TokenType.OWNED);
accept (TokenType.UNOWNED);
accept (TokenType.WEAK);
+
+
if (accept (TokenType.ARRAY) || accept (TokenType.LIST) || accept (TokenType.DICT)) {
accept (TokenType.OF);
}
- skip_symbol_name ();
- skip_type_argument_list ();
+ if (accept (TokenType.VOID)) {
+ } else {
+ skip_symbol_name ();
+ skip_type_argument_list ();
+ }
+
while (accept (TokenType.OPEN_BRACKET)) {
do {
if (current () != TokenType.COMMA && current () != TokenType.CLOSE_BRACKET) {
return expr;
}
- DataType parse_type (bool owned_by_default = true) throws ParseError {
+ DataType parse_type (bool owned_by_default, bool can_weak_ref) throws ParseError {
var begin = get_location ();
- if (accept (TokenType.VOID)) {
- DataType type = new VoidType ();
- while (accept (TokenType.STAR)) {
- type = new PointerType (type);
- }
- return type;
- }
-
List<DataType> type_arg_list = null;
UnresolvedSymbol sym = null;
bool is_dynamic = accept (TokenType.DYNAMIC);
bool value_owned = owned_by_default;
+
if (owned_by_default) {
- if (accept (TokenType.UNOWNED)
- || accept (TokenType.WEAK)) {
+ if (accept (TokenType.UNOWNED)) {
+ value_owned = false;
+ } else if (accept (TokenType.WEAK)) {
+ if (!can_weak_ref && !context.deprecated) {
+ Report.warning (get_src (begin), "deprecated syntax, use `unowned` modifier");
+ }
value_owned = false;
}
} else {
is_dict = true;
}
- if (is_list) {
- var sym_parent = new UnresolvedSymbol (null, "Gee", get_src (begin));
- sym = new UnresolvedSymbol (sym_parent, "ArrayList", get_src (begin));
- } else if (is_dict) {
- var sym_parent = new UnresolvedSymbol (null, "Gee", get_src (begin));
- sym = new UnresolvedSymbol (sym_parent, "HashMap", get_src (begin));
- } else {
- sym = parse_symbol_name ();
- }
+ DataType type;
- type_arg_list = parse_type_argument_list (false);
+ if (!is_dynamic && value_owned == owned_by_default && accept (TokenType.VOID)) {
+ type = new VoidType (get_src (begin));
+ } else {
+
+ if (is_list) {
+ var sym_parent = new UnresolvedSymbol (null, "Gee", get_src (begin));
+ sym = new UnresolvedSymbol (sym_parent, "ArrayList", get_src (begin));
+ } else if (is_dict) {
+ var sym_parent = new UnresolvedSymbol (null, "Gee", get_src (begin));
+ sym = new UnresolvedSymbol (sym_parent, "HashMap", get_src (begin));
+ } else {
+ sym = parse_symbol_name ();
+ }
+
+ type_arg_list = parse_type_argument_list (false);
- DataType type = new UnresolvedType.from_symbol (sym, get_src (begin));
- if (type_arg_list != null) {
- foreach (DataType type_arg in type_arg_list) {
- type.add_type_argument (type_arg);
+ type = new UnresolvedType.from_symbol (sym, get_src (begin));
+ if (type_arg_list != null) {
+ foreach (DataType type_arg in type_arg_list) {
+ type.add_type_argument (type_arg);
+ }
}
}
-
+
while (accept (TokenType.STAR)) {
type = new PointerType (type, get_src (begin));
}
// only used for parsing, reject use as real type
invalid_array = true;
}
- }
- while (accept (TokenType.COMMA));
+ } while (accept (TokenType.COMMA));
expect (TokenType.CLOSE_BRACKET);
type.value_owned = true;
value_owned = accept (TokenType.HASH);
}
+ if (type is PointerType) {
+ value_owned = false;
+ }
+
type.is_dynamic = is_dynamic;
type.value_owned = value_owned;
return type;
expect (TokenType.OPEN_PARENS);
var arg_list = parse_argument_list ();
expect (TokenType.CLOSE_PARENS);
+
var init_list = parse_object_initializer ();
if (init_list.size > 0 && inner is MemberAccess) {
if (accept (TokenType.ARRAY)) {
expect (TokenType.OF);
- var mtype = parse_type ();
+ var mtype = parse_type (true, false);
var expr = parse_array_creation_expression (begin, mtype);
return expr;
}
if (accept (TokenType.LIST)) {
expect (TokenType.OF);
- var mtype = parse_type ();
+ var mtype = parse_type (true, false);
var expr = parse_list_creation_expression (begin, mtype);
return expr;
}
if (accept (TokenType.DICT)) {
expect (TokenType.OF);
- var mtype1 = parse_type ();
+ var mtype1 = parse_type (true, false);
expect (TokenType.COMMA);
- var mtype2 = parse_type ();
+ var mtype2 = parse_type (true, false);
var expr = parse_dict_creation_expression (begin, mtype1, mtype2);
return expr;
}
}
Expression parse_yield_expression () throws ParseError {
- var begin = get_location ();
expect (TokenType.YIELD);
- Expression base_expr = null;
- if (current () == TokenType.SUPER) {
- base_expr = parse_base_access ();
- expect (TokenType.DOT);
+
+ var expr = parse_expression ();
+
+ var call = expr as MethodCall;
+ var object_creation = expr as ObjectCreationExpression;
+ if (call == null && object_creation == null) {
+ Report.error (expr.source_reference, "syntax error, expected method call");
+ throw new ParseError.SYNTAX ("expected method call");
+ }
+
+ if (call != null) {
+ call.is_yield_expression = true;
+ } else if (object_creation != null) {
+ object_creation.is_yield_expression = true;
}
- var member = parse_member_name (base_expr);
- var call = (MethodCall) parse_method_call (begin, member);
- call.is_yield_expression = true;
- return call;
+
+ return expr;
}
Expression parse_sizeof_expression () throws ParseError {
var begin = get_location ();
expect (TokenType.SIZEOF);
expect (TokenType.OPEN_PARENS);
- var type = parse_type ();
+ var type = parse_type (true, false);
expect (TokenType.CLOSE_PARENS);
return new SizeofExpression (type, get_src (begin));
var begin = get_location ();
expect (TokenType.TYPEOF);
expect (TokenType.OPEN_PARENS);
- var type = parse_type ();
+ var type = parse_type (true, false);
expect (TokenType.CLOSE_PARENS);
return new TypeofExpression (type, get_src (begin));
case TokenType.TILDE: return UnaryOperator.BITWISE_COMPLEMENT;
case TokenType.OP_INC: return UnaryOperator.INCREMENT;
case TokenType.OP_DEC: return UnaryOperator.DECREMENT;
- default: return UnaryOperator.NONE;
+ default: return UnaryOperator.NONE;
}
}
}
switch (current ()) {
case TokenType.HASH:
+ if (!context.deprecated) {
+ Report.warning (get_src (begin), "deprecated syntax, use `(owned)` cast");
+ }
next ();
var op = parse_unary_expression ();
return new ReferenceTransferExpression (op, get_src (begin));
case TokenType.ARRAY:
case TokenType.LIST:
case TokenType.DICT:
- var type = parse_type ();
+ var type = parse_type (true, false);
if (accept (TokenType.CLOSE_PARENS)) {
// check follower to decide whether to create cast expression
switch (current ()) {
case TokenType.TYPEOF:
case TokenType.IDENTIFIER:
case TokenType.PARAMS:
+ case TokenType.YIELD:
var inner = parse_unary_expression ();
return new CastExpression (inner, type, get_src (begin), false);
default:
BinaryOperator get_binary_operator (TokenType token_type) {
switch (token_type) {
- case TokenType.STAR: return BinaryOperator.MUL;
- case TokenType.DIV: return BinaryOperator.DIV;
+ 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.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;
prev ();
return BinaryOperator.EQUALITY;
case TokenType.OP_NE: return BinaryOperator.INEQUALITY;
- default: return BinaryOperator.NONE;
+ default: return BinaryOperator.NONE;
}
}
switch (current ()) {
case TokenType.ISA:
next ();
- var type = parse_type ();
+ var type = parse_type (true, false);
left = new TypeCheck (left, type, get_src (begin));
break;
case TokenType.AS:
next ();
- var type = parse_type ();
+ var type = parse_type (true, false);
left = new CastExpression (left, type, get_src (begin), true);
break;
default:
}
}
+ Parameter parse_lambda_parameter () throws ParseError {
+ var begin = get_location ();
+ var direction = ParameterDirection.IN;
+ if (accept (TokenType.OUT)) {
+ direction = ParameterDirection.OUT;
+ } else if (accept (TokenType.REF)) {
+ direction = ParameterDirection.REF;
+ }
+
+ string id = parse_identifier ();
+
+ var param = new Parameter (id, null, get_src (begin));
+ param.direction = direction;
+ return param;
+ }
+
Expression parse_lambda_expression () throws ParseError {
var begin = get_location ();
List<Parameter> params = new ArrayList<Parameter> ();
if (accept (TokenType.OPEN_PARENS)) {
if (current () != TokenType.CLOSE_PARENS) {
do {
- var param = new Parameter (parse_identifier (), null, get_src (get_location ()));
- params.add (param);
+ params.add (parse_lambda_parameter ());
} while (accept (TokenType.COMMA));
}
expect (TokenType.CLOSE_PARENS);
} else {
- var param = new Parameter (parse_identifier (), null, get_src (get_location ()));
- params.add (param);
+ params.add (parse_lambda_parameter ());
}
-
LambdaExpression lambda;
+
if (accept_block ()) {
var block = parse_block ();
lambda = new LambdaExpression.with_statement_body (block, get_src (begin));
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;
+ 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;
}
}
var lambda = parse_lambda_expression ();
current_expr_is_lambda = true;
return lambda;
+ } else {
+ current_expr_is_lambda = false;
}
var begin = get_location ();
void parse_statements (Block block) throws ParseError {
while (current () != TokenType.DEDENT
- && current () != TokenType.WHEN
- && current () != TokenType.DEFAULT) {
+ && current () != TokenType.WHEN
+ && current () != TokenType.DEFAULT) {
try {
Statement stmt = null;
bool is_decl = false;
switch (current ()) {
case TokenType.PASS:
case TokenType.SEMICOLON: return parse_empty_statement ();
- case TokenType.IF: return parse_if_statement ();
- case TokenType.CASE: return parse_switch_statement ();
- case TokenType.WHILE: return parse_while_statement ();
- case TokenType.DO: return parse_do_statement ();
- case TokenType.FOR: return get_for_statement_type ();
- case TokenType.BREAK: return parse_break_statement ();
+ case TokenType.IF: return parse_if_statement ();
+ case TokenType.CASE: return parse_switch_statement ();
+ case TokenType.WHILE: return parse_while_statement ();
+ case TokenType.DO: return parse_do_statement ();
+ case TokenType.FOR: return get_for_statement_type ();
+ case TokenType.BREAK: return parse_break_statement ();
case TokenType.CONTINUE: return parse_continue_statement ();
- case TokenType.RETURN: return parse_return_statement ();
- case TokenType.YIELD: return parse_yield_statement ();
- case TokenType.RAISE: return parse_throw_statement ();
- case TokenType.TRY: return parse_try_statement ();
- case TokenType.LOCK: return parse_lock_statement ();
- case TokenType.DELETE: return parse_delete_statement ();
- default: return parse_expression_statement ();
+ case TokenType.RETURN: return parse_return_statement ();
+ case TokenType.YIELD: return parse_yield_statement ();
+ case TokenType.RAISE: return parse_throw_statement ();
+ case TokenType.TRY: return parse_try_statement ();
+ case TokenType.LOCK: return parse_lock_statement ();
+ case TokenType.DELETE: return parse_delete_statement ();
+ case TokenType.VAR:
+ case TokenType.CONST:
+ throw new ParseError.SYNTAX (get_error ("embedded statement cannot be declaration "));
+ case TokenType.OP_INC:
+ case TokenType.OP_DEC:
+ case TokenType.SUPER:
+ case TokenType.THIS:
+ case TokenType.OPEN_PARENS:
+ case TokenType.STAR:
+ case TokenType.NEW:
+ return parse_expression_statement ();
+ default:
+ if (is_expression ()) {
+ return parse_expression_statement ();
+ } else {
+ throw new ParseError.SYNTAX (get_error ("embedded statement cannot be declaration"));
+ }
}
}
expect (TokenType.COLON);
- variable_type = parse_type ();
+ variable_type = parse_type (true, true);
var type = parse_inline_array_type (variable_type);
foreach (string id in id_list) {
} else {
id = parse_identifier ();
expect (TokenType.COLON);
- variable_type = parse_type ();
+ variable_type = parse_type (true, true);
}
DataType type_copy = null;
} else {
id = parse_identifier ();
if (accept (TokenType.COLON)) {
- type = parse_type ();
+ type = parse_type (true, true);
}
}
if (!accept (TokenType.EOL)) {
id = parse_identifier ();
expect (TokenType.COLON);
- type = parse_type ();
+ type = parse_type (true, true);
expect (TokenType.EOL);
}
void set_attributes (CodeNode node, List<Attribute>? attributes) {
if (attributes != null) {
foreach (Attribute attr in (List<Attribute>) attributes) {
+ if (node.get_attribute (attr.name) != null) {
+ Report.error (attr.source_reference, "duplicate attribute `%s`".printf (attr.name));
+ }
node.attributes.append (attr);
}
}
var type_param_list = parse_type_parameter_list ();
var base_types = new ArrayList<DataType> ();
if (accept (TokenType.COLON)) {
- var type1 = parse_type ();
+ var type1 = parse_type (true, false);
base_types.add (type1);
if (accept (TokenType.IMPLEMENTS)) {
do {
- var type2 = parse_type ();
+ var type2 = parse_type (true, true);
base_types.add (type2);
} while (accept (TokenType.COMMA));
}
// ensure there is always a default construction method
if (scanner.source_file.file_type == SourceFileType.SOURCE
- && cl.default_construction_method == null) {
+ && cl.default_construction_method == null) {
var m = new CreationMethod (cl.name, null, cl.source_reference);
m.access = SymbolAccessibility.PUBLIC;
m.body = new Block (cl.source_reference);
string id = parse_identifier ();
expect (TokenType.COLON);
- var type = parse_type (false);
+ var type = parse_type (false, false);
type = parse_inline_array_type (type);
Expression initializer = null;
var flags = parse_member_declaration_modifiers ();
- var type = parse_type ();
+ var type = parse_type (true, true);
type = parse_inline_array_type (type);
if (ModifierFlags.ABSTRACT in flags || ModifierFlags.VIRTUAL in flags || ModifierFlags.OVERRIDE in flags) {
Report.error (f.source_reference, "abstract, virtual, and override modifiers are not applicable to fields");
- }
+ }
if (ModifierFlags.PRIVATE in flags) {
f.access = SymbolAccessibility.PRIVATE;
/* deal with return value */
if (accept (TokenType.COLON)) {
- type = parse_type ();
+ type = parse_type (true, false);
}
var type_param_list = parse_type_parameter_list ();
if (accept (TokenType.RAISES)) {
do {
- method.add_error_type (parse_type ());
+ method.add_error_type (parse_type (true, false));
} while (accept (TokenType.COMMA));
}
method.overrides = true;
}
if ((method.is_abstract && method.is_virtual)
- || (method.is_abstract && method.overrides)
- || (method.is_virtual && method.overrides)) {
+ || (method.is_abstract && method.overrides)
+ || (method.is_virtual && method.overrides)) {
throw new ParseError.SYNTAX (get_error ("only one of `abstract', `virtual', or `override' may be specified"));
}
} else {
if (ModifierFlags.ABSTRACT in flags
- || ModifierFlags.VIRTUAL in flags
- || ModifierFlags.OVERRIDE in flags) {
+ || ModifierFlags.VIRTUAL in flags
+ || ModifierFlags.OVERRIDE in flags) {
throw new ParseError.SYNTAX (get_error ("the modifiers `abstract', `virtual', and `override' are not valid for static methods"));
}
}
string id = parse_identifier ();
expect (TokenType.COLON);
- var type = parse_type (false);
+ var type = parse_type (true, true);
var prop = new Property (id, type, null, null, get_src (begin), comment);
if (ModifierFlags.PRIVATE in flags) {
expect (TokenType.CLOSE_PARENS);
if (accept (TokenType.COLON)) {
- type = parse_type ();
+ type = parse_type (true, false);
} else {
type = new VoidType ();
}
var type_param_list = parse_type_parameter_list ();
DataType base_type = null;
if (accept (TokenType.COLON)) {
- base_type = parse_type ();
+ base_type = parse_type (true, false);
}
var st = new Struct (sym.name, get_src (begin), comment);
st.add_field ((Field) sym);
} else if (sym is Constant) {
st.add_constant ((Constant) sym);
+ } else if (sym is Property) {
+ st.add_property ((Property) sym);
} else {
Report.error (sym.source_reference, "unexpected declaration in struct");
}
var base_types = new ArrayList<DataType> ();
if (accept (TokenType.COLON)) {
do {
- var type = parse_type ();
+ var type = parse_type (true, false);
base_types.add (type);
} while (accept (TokenType.COMMA));
}
expect (TokenType.EOL);
expect (TokenType.INDENT);
do {
- if (current () == TokenType.DEDENT) {
+ if (current () == TokenType.DEDENT && en.get_values ().size > 0) {
// allow trailing comma
break;
}
expect (TokenType.INDENT);
do {
- if (current () == TokenType.DEDENT) {
+ if (current () == TokenType.DEDENT && ed.get_codes ().size > 0) {
// allow trailing comma
break;
}
next ();
flags |= ModifierFlags.OVERRIDE;
break;
+ case TokenType.SEALED:
+ next ();
+ flags |= ModifierFlags.SEALED;
+ break;
case TokenType.STATIC:
next ();
flags |= ModifierFlags.STATIC;
DataType type;
if (direction == ParameterDirection.IN) {
- type = parse_type (false);
+ type = parse_type (false, false);
+ } else if (direction == ParameterDirection.REF) {
+ // ref parameters own the value by default
+ type = parse_type (true, true);
} else {
- type = parse_type (true);
+ // out parameters own the value by default
+ type = parse_type (true, false);
}
var param = new Parameter (id, type, get_src (begin));
expect (TokenType.CLOSE_PARENS);
if (accept (TokenType.RAISES)) {
do {
- method.add_error_type (parse_type ());
+ method.add_error_type (parse_type (true, false));
} while (accept (TokenType.COMMA));
}
method.access = SymbolAccessibility.PUBLIC;
expect (TokenType.CLOSE_PARENS);
if (accept (TokenType.COLON)) {
- type = parse_type ();
+ type = parse_type (true, false);
} else {
type = new VoidType ();
if (accept (TokenType.RAISES)) {
do {
- d.add_error_type (parse_type ());
+ d.add_error_type (parse_type (true, false));
} while (accept (TokenType.COMMA));
}
void skip_type_argument_list () throws ParseError {
if (accept (TokenType.OF)) {
- if (accept (TokenType.OPEN_PARENS)) {
- do {
- skip_type ();
- } while (accept (TokenType.COMMA));
- expect (TokenType.CLOSE_PARENS);
- } else {
- do {
- skip_type ();
- } while (accept (TokenType.COMMA));
+ if (accept (TokenType.OPEN_PARENS)) {
+ do {
+ skip_type ();
+ } while (accept (TokenType.COMMA));
+ expect (TokenType.CLOSE_PARENS);
+ } else {
+ do {
+ skip_type ();
+ } while (accept (TokenType.COMMA));
}
}
}
-
+
// try to parse type argument list
List<DataType>? parse_type_argument_list (bool maybe_expression) throws ParseError {
var begin = get_location ();
// Optional parens allow multi arg types in function signature: "dict of (int, string)"
// See: https://bugzilla.gnome.org/show_bug.cgi?id=611191
if (accept (TokenType.OPEN_PARENS)) {
- inParens = true;
- }
-
- do {
- switch (current ()) {
- case TokenType.VOID:
- case TokenType.DYNAMIC:
- case TokenType.UNOWNED:
- case TokenType.WEAK:
- case TokenType.IDENTIFIER:
- var type = parse_type ();
-
- list.add (type);
- break;
- default:
- rollback (begin);
- return null;
- }
- } while (accept (TokenType.COMMA));
-
- if (inParens) {
- expect (TokenType.CLOSE_PARENS);
+ inParens = true;
+ }
+
+ do {
+ switch (current ()) {
+ case TokenType.VOID:
+ case TokenType.DYNAMIC:
+ case TokenType.UNOWNED:
+ case TokenType.WEAK:
+ case TokenType.IDENTIFIER:
+ var type = parse_type (true, true);
+
+ list.add (type);
+ break;
+ default:
+ rollback (begin);
+ return null;
+ }
+ } while (accept (TokenType.COMMA));
+
+ if (inParens) {
+ expect (TokenType.CLOSE_PARENS);
}
return list;
state_stack = null;
}
- TokenType get_identifier_or_keyword (char* begin, int len) {
+ public static TokenType get_identifier_or_keyword (char* begin, int len) {
switch (len) {
case 2:
switch (begin[0]) {
break;
case 's':
switch (begin[1]) {
+ case 'e':
+ if (matches (begin, "sealed")) return TokenType.SEALED;
+ break;
case 'i':
if (matches (begin, "sizeof")) return TokenType.SIZEOF;
break;
break;
}
} else if (current[0] == '\n') {
- break;
+ current++;
+ line++;
+ column = 1;
+ token_length_in_chars = 1;
} else {
unichar u = ((string) current).get_char_validated ((long) (end - current));
if (u != (unichar) (-1)) {
}
}
}
- if (current >= end || current[0] == '\n') {
+ if (current >= end) {
Report.error (get_source_reference (token_length_in_chars), "syntax error, expected \"");
state_stack.length--;
return read_token (out token_begin, out token_end);
/* handle automatic line continuations (when inside parens or braces) */
while (current < end && current[0] == '\n' && (open_parens_count > 0 || open_brace_count > 0)) {
- current++;
+ current++;
line++;
skip_space_tabs ();
}
}
type = TokenType.REAL_LITERAL;
} else if (current < end && current == begin + 1
- && begin[0] == '0' && begin[1] == 'x' && begin[2].isxdigit ()) {
+ && begin[0] == '0' && begin[1] == 'x' && begin[2].isxdigit ()) {
// hexadecimal integer literal
current++;
while (current < end && current[0].isxdigit ()) {
case TokenType.COMMA:
case TokenType.MINUS:
case TokenType.OP_AND:
- case TokenType.OP_DEC:
case TokenType.OP_EQ:
case TokenType.OP_GE:
case TokenType.OP_GT:
token_length_in_chars = 6;
current += 3;
while (current < end - 4) {
- if (current[0] == '"' && current[1] == '"' && current[2] == '"') {
+ if (current[0] == '"' && current[1] == '"' && current[2] == '"' && current[3] != '"') {
break;
} else if (current[0] == '\n') {
current++;
break;
}
} else if (current[0] == '\n') {
- break;
+ current++;
+ line++;
+ column = 1;
+ token_length_in_chars = 1;
} else {
unichar u = ((string) current).get_char_validated ((long) (end - current));
if (u != (unichar) (-1)) {
Report.error (get_source_reference (token_length_in_chars), "invalid UTF-8 character");
}
}
+ if (current < end && begin[0] == '\'' && current[0] != '\'') {
+ // multiple characters in single character literal
+ Report.error (get_source_reference (token_length_in_chars), "invalid character literal");
+ }
}
- if (current < end && current[0] != '\n') {
+ if (current < end) {
current++;
} else {
Report.error (get_source_reference (token_length_in_chars), "syntax error, expected %c".printf (begin[0]));
Report.error (get_source_reference (0), "invalid UTF-8 character");
}
column++;
- last_token = TokenType.STRING_LITERAL;
return read_token (out token_begin, out token_end);
}
}
return tab_count;
}
- bool matches (char* begin, string keyword) {
+ static bool matches (char* begin, string keyword) {
char* keyword_array = (char *) keyword;
long len = keyword.length;
for (int i = 0; i < len; i++) {
}
bool comment (bool file_comment = false) {
- if (current > end - 2
- || current[0] != '/'
- || (current[1] != '/' && current[1] != '*')) {
+ if (current == null
+ || current > end - 2
+ || current[0] != '/'
+ || (current[1] != '/' && current[1] != '*')) {
return false;
}
return false;
}
- if (current[2] == '*' || file_comment) {
+ if (current[2] == '*' || file_comment) {
source_reference = get_source_reference (0);
}
char* begin = current;
while (current < end - 1
- && (current[0] != '*' || current[1] != '/')) {
+ && (current[0] != '*' || current[1] != '/')) {
if (current[0] == '\n') {
line++;
column = 0;
}
}
- public void parse_file_comments () {
+ public void parse_file_comments () {
while (whitespace () || comment (true)) {
}
void push_comment (string comment_item, SourceReference source_reference, bool file_comment) {
if (comment_item[0] == '*') {
+ if (_comment != null) {
+ // extra doc comment, add it to source file comments
+ source_file.add_comment (_comment);
+ }
_comment = new Comment (comment_item, source_reference);
}
return found;
}
+ void pp_space () {
+ while (pp_whitespace () || comment ()) {
+ }
+ }
+
void pp_directive () {
// hash sign
current++;
column++;
- pp_whitespace ();
+ pp_space ();
char* begin = current;
int len = 0;
}
if (conditional_stack.length > 0
- && conditional_stack[conditional_stack.length - 1].skip_section) {
+ && conditional_stack[conditional_stack.length - 1].skip_section) {
// skip lines until next preprocessing directive
bool bol = false;
while (current < end) {
- if (bol && current[0] == '#') {
+ if (bol && current < end && current[0] == '#') {
// go back to begin of line
current -= (column - 1);
column = 1;
}
void pp_eol () {
- pp_whitespace ();
+ pp_space ();
if (current >= end || current[0] != '\n') {
Report.error (get_source_reference (0), "syntax error, expected newline");
}
}
void parse_pp_if () {
- pp_whitespace ();
+ pp_space ();
bool condition = parse_pp_expression ();
}
void parse_pp_elif () {
- pp_whitespace ();
+ pp_space ();
bool condition = parse_pp_expression ();
}
if (condition && !conditional_stack[conditional_stack.length - 1].matched
- && (conditional_stack.length == 1 || !conditional_stack[conditional_stack.length - 2].skip_section)) {
+ && (conditional_stack.length == 1 || !conditional_stack[conditional_stack.length - 2].skip_section)) {
// condition true => process code within if
conditional_stack[conditional_stack.length - 1].matched = true;
conditional_stack[conditional_stack.length - 1].skip_section = false;
}
if (!conditional_stack[conditional_stack.length - 1].matched
- && (conditional_stack.length == 1 || !conditional_stack[conditional_stack.length - 2].skip_section)) {
+ && (conditional_stack.length == 1 || !conditional_stack[conditional_stack.length - 2].skip_section)) {
// condition true => process code within if
conditional_stack[conditional_stack.length - 1].matched = true;
conditional_stack[conditional_stack.length - 1].skip_section = false;
} else if (current[0] == '(') {
current++;
column++;
- pp_whitespace ();
+ pp_space ();
bool result = parse_pp_expression ();
- pp_whitespace ();
+ pp_space ();
if (current < end && current[0] == ')') {
current++;
column++;
if (current < end && current[0] == '!') {
current++;
column++;
- pp_whitespace ();
+ pp_space ();
return !parse_pp_unary_expression ();
}
bool parse_pp_equality_expression () {
bool left = parse_pp_unary_expression ();
- pp_whitespace ();
+ pp_space ();
while (true) {
if (current < end - 1 && current[0] == '=' && current[1] == '=') {
current += 2;
column += 2;
- pp_whitespace ();
+ pp_space ();
bool right = parse_pp_unary_expression ();
left = (left == right);
} else if (current < end - 1 && current[0] == '!' && current[1] == '=') {
current += 2;
column += 2;
- pp_whitespace ();
+ pp_space ();
bool right = parse_pp_unary_expression ();
left = (left != right);
} else {
bool parse_pp_and_expression () {
bool left = parse_pp_equality_expression ();
- pp_whitespace ();
+ pp_space ();
while (current < end - 1 && current[0] == '&' && current[1] == '&') {
current += 2;
column += 2;
- pp_whitespace ();
+ pp_space ();
bool right = parse_pp_equality_expression ();
left = left && right;
}
bool parse_pp_or_expression () {
bool left = parse_pp_and_expression ();
- pp_whitespace ();
+ pp_space ();
while (current < end - 1 && current[0] == '|' && current[1] == '|') {
current += 2;
column += 2;
- pp_whitespace ();
+ pp_space ();
bool right = parse_pp_and_expression ();
left = left || right;
}