From e53b00f5a50f6b287e8be2e4dbf8a7b997a43ab0 Mon Sep 17 00:00:00 2001 From: Jamie McCracken Date: Sun, 27 Sep 2009 11:42:47 -0400 Subject: [PATCH] Genie: Briought Genie up to date with Vala Added Async support Added bug fixes Added improved warnings Added improved array handling code Added support for constants in interfaces --- vala/valagenieparser.vala | 155 ++++++++++++++++++++++++++--------- vala/valageniescanner.vala | 43 +++++++--- vala/valagenietokentype.vala | 6 +- 3 files changed, 150 insertions(+), 54 deletions(-) diff --git a/vala/valagenieparser.vala b/vala/valagenieparser.vala index 9aa9652c5..0741593f8 100644 --- a/vala/valagenieparser.vala +++ b/vala/valagenieparser.vala @@ -65,7 +65,8 @@ public class Vala.Genie.Parser : CodeVisitor { OVERRIDE = 1 << 5, STATIC = 1 << 6, VIRTUAL = 1 << 7, - PRIVATE = 1 << 8 + PRIVATE = 1 << 8, + ASYNC = 1 << 9 } public Parser () { @@ -218,6 +219,7 @@ public class Vala.Genie.Parser : CodeVisitor { case TokenType.ABSTRACT: case TokenType.AS: case TokenType.ASSERT: + case TokenType.ASYNC: case TokenType.BREAK: case TokenType.CLASS: case TokenType.CONST: @@ -290,7 +292,6 @@ public class Vala.Genie.Parser : CodeVisitor { case TokenType.WHEN: case TokenType.WHILE: case TokenType.YIELD: - case TokenType.YIELDS: next (); return; case TokenType.INTEGER_LITERAL: @@ -379,7 +380,7 @@ public class Vala.Genie.Parser : CodeVisitor { } } - parse_using_directives (); + parse_using_directives (context.root); parse_declarations (context.root, true); } catch (ParseError e) { // already reported @@ -522,18 +523,15 @@ public class Vala.Genie.Parser : CodeVisitor { prev (); while (accept (TokenType.OPEN_BRACKET)) { - int array_length = -1; + bool invalid_array = false; int array_rank = 0; do { array_rank++; - // support for stack-allocated arrays - // also required for decision between expression and declaration statement + // required for decision between expression and declaration statement if (current () != TokenType.COMMA && current () != TokenType.CLOSE_BRACKET) { - var length_expression = parse_expression (); - var length_literal = length_expression as IntegerLiteral; - if (length_literal != null) { - array_length = length_literal.value.to_int (); - } + parse_expression (); + // only used for parsing, reject use as real type + invalid_array = true; } } while (accept (TokenType.COMMA)); @@ -543,11 +541,7 @@ public class Vala.Genie.Parser : CodeVisitor { var array_type = new ArrayType (type, array_rank, get_src (begin)); array_type.nullable = accept (TokenType.INTERR); - if (array_rank == 1 && array_length > 0) { - // fixed length (stack-allocated) array - array_type.fixed_length = true; - array_type.length = array_length; - } + array_type.invalid_syntax = invalid_array; type = array_type; } @@ -563,6 +557,36 @@ public class Vala.Genie.Parser : CodeVisitor { return type; } + DataType? parse_inline_array_type (DataType? type) throws ParseError { + var begin = get_location (); + + // inline-allocated array + if (type != null && accept (TokenType.OPEN_BRACKET)) { + int array_length = -1; + + if (current () != TokenType.CLOSE_BRACKET) { + if (current () != TokenType.INTEGER_LITERAL) { + throw new ParseError.SYNTAX (get_error ("expected `]' or integer literal")); + } + + var length_literal = (IntegerLiteral) parse_literal (); + array_length = length_literal.value.to_int (); + } + expect (TokenType.CLOSE_BRACKET); + + var array_type = new ArrayType (type, 1, get_src (begin)); + array_type.inline_allocated = true; + if (array_length > 0) { + array_type.fixed_length = true; + array_type.length = array_length; + } + + return array_type; + } + return type; + } + + Gee.List parse_argument_list () throws ParseError { var list = new ArrayList (); if (current () != TokenType.CLOSE_PARENS) { @@ -628,6 +652,9 @@ public class Vala.Genie.Parser : CodeVisitor { case TokenType.TYPEOF: expr = parse_typeof_expression (); break; + case TokenType.YIELD: + expr = parse_yield_expression (); + break; default: expr = parse_simple_name (); break; @@ -1059,6 +1086,15 @@ public class Vala.Genie.Parser : CodeVisitor { return new MemberInitializer (id, expr, get_src (begin)); } + Expression parse_yield_expression () throws ParseError { + var begin = get_location (); + expect (TokenType.YIELD); + var member = parse_member_name (); + var call = (MethodCall) parse_method_call (begin, member); + call.is_yield_expression = true; + return call; + } + Expression parse_sizeof_expression () throws ParseError { var begin = get_location (); expect (TokenType.SIZEOF); @@ -1784,11 +1820,12 @@ public class Vala.Genie.Parser : CodeVisitor { expect (TokenType.COLON); variable_type = parse_type (); + var type = parse_inline_array_type (variable_type); foreach (string id in id_list) { DataType type_copy = null; - if (variable_type != null) { - type_copy = variable_type.copy (); + if (type != null) { + type_copy = type.copy (); } var local = parse_local_variable (type_copy, id); block.add_statement (new DeclarationStatement (local, local.source_reference)); @@ -2065,14 +2102,18 @@ public class Vala.Genie.Parser : CodeVisitor { expr = parse_expression (); } expect_terminator (); - return new ReturnStatement (expr, get_src (begin)); + return new ReturnStatement (expr, get_src (begin)); } Statement parse_yield_statement () throws ParseError { var begin = get_location (); expect (TokenType.YIELD); + if (current () != TokenType.SEMICOLON && current () != TokenType.EOL && current () != TokenType.RETURN) { + prev (); + return parse_expression_statement (); + } Expression expr = null; - if (current () != TokenType.SEMICOLON && current () != TokenType.EOL) { + if (accept (TokenType.RETURN)) { expr = parse_expression (); } expect_terminator (); @@ -2205,7 +2246,11 @@ public class Vala.Genie.Parser : CodeVisitor { if (is_root) { return parse_main_method_declaration (attrs); } - return parse_constructor_declaration (attrs); + if (context.profile == Profile.GOBJECT) { + rollback (begin); + return parse_constructor_declaration (attrs); + } + break; case TokenType.DELEGATE: return parse_delegate_declaration (attrs); case TokenType.DEF: @@ -2396,29 +2441,29 @@ public class Vala.Genie.Parser : CodeVisitor { } - void add_uses_clause () throws ParseError { + void add_uses_clause (Namespace ns) throws ParseError { var begin = get_location (); var sym = parse_symbol_name (); var ns_ref = new UsingDirective (sym, get_src (begin)); - + scanner.source_file.add_using_directive (ns_ref); - context.root.add_using_directive (ns_ref); + ns.add_using_directive (ns_ref); } - void parse_using_directives () throws ParseError { + void parse_using_directives (Namespace ns) throws ParseError { while (accept (TokenType.USES)) { if (accept_block ()) { expect (TokenType.INDENT); while (current () != TokenType.DEDENT && current () != TokenType.EOF) { - add_uses_clause (); + add_uses_clause (ns); expect (TokenType.EOL); } expect (TokenType.DEDENT); } else { do { - add_uses_clause (); + add_uses_clause (ns); } while (accept (TokenType.COMMA)); expect_terminator (); @@ -2480,7 +2525,6 @@ public class Vala.Genie.Parser : CodeVisitor { // ensure there is always a default construction method if (!scanner.source_file.external_package - && !cl.is_abstract && cl.default_construction_method == null) { var m = new CreationMethod (cl.name, null, cl.source_reference); m.access = SymbolAccessibility.PUBLIC; @@ -2554,8 +2598,10 @@ public class Vala.Genie.Parser : CodeVisitor { var flags = parse_member_declaration_modifiers (); string id = parse_identifier (); + expect (TokenType.COLON); var type = parse_type (false); + type = parse_inline_array_type (type); Expression initializer = null; if (accept (TokenType.ASSIGN)) { @@ -2591,8 +2637,10 @@ public class Vala.Genie.Parser : CodeVisitor { var flags = parse_member_declaration_modifiers (); var type = parse_type (); + + type = parse_inline_array_type (type); - var f = new Field (id, type, null, get_src (begin), comment); + var f = new Field (id, type, null, get_src (begin), comment); 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"); @@ -2701,13 +2749,15 @@ public class Vala.Genie.Parser : CodeVisitor { expect (TokenType.CLOSE_PARENS); + /* deal with return value */ if (accept (TokenType.COLON)) { type = parse_type (); - parse_type_parameter_list (); } + + var type_param_list = parse_type_parameter_list (); - var method = new Method (id, type, get_src (begin), comment); + var method = new Method (id, type, get_src (begin), comment); if (ModifierFlags.PRIVATE in flags) { method.access = SymbolAccessibility.PRIVATE; } else { @@ -2717,12 +2767,13 @@ public class Vala.Genie.Parser : CodeVisitor { set_attributes (method, attrs); - foreach (FormalParameter param in params) { - method.add_parameter (param); + foreach (TypeParameter type_param in type_param_list) { + method.add_type_parameter (type_param); } + - if (accept (TokenType.YIELDS)) { - method.coroutine = true; + foreach (FormalParameter param in params) { + method.add_parameter (param); } if (accept (TokenType.RAISES)) { @@ -2737,6 +2788,10 @@ public class Vala.Genie.Parser : CodeVisitor { } else if (ModifierFlags.CLASS in flags) { method.binding = MemberBinding.CLASS; } + if (ModifierFlags.ASYNC in flags) { + method.coroutine = true; + } + if (ModifierFlags.NEW in flags) { method.hides = true; } @@ -2869,6 +2924,10 @@ public class Vala.Genie.Parser : CodeVisitor { if (ModifierFlags.EXTERN in flags || scanner.source_file.external_package) { prop.external = true; } + + if (ModifierFlags.ASYNC in flags) { + Report.error (prop.source_reference, "async properties are not supported yet"); + } if (accept (TokenType.ASSIGN)) { prop.default_expression = parse_expression (); @@ -2902,8 +2961,8 @@ public class Vala.Genie.Parser : CodeVisitor { if (readonly) { throw new ParseError.SYNTAX (get_error ("set block not allowed for a read only property")); } - _construct = accept (TokenType.CONSTRUCT); - } else if (accept (TokenType.CONSTRUCT)) { + _construct = (context.profile == Profile.GOBJECT) && accept (TokenType.CONSTRUCT); + } else if (context.profile == Profile.GOBJECT && accept (TokenType.CONSTRUCT)) { _construct = true; } else if (!accept (TokenType.EOL)) { throw new ParseError.SYNTAX (get_error ("expected get, set, or construct")); @@ -2956,6 +3015,7 @@ public class Vala.Genie.Parser : CodeVisitor { var field_type = prop.property_type.copy (); prop.field = new Field ("_%s".printf (prop.name), field_type, prop.default_expression, prop.source_reference); prop.field.access = SymbolAccessibility.PRIVATE; + prop.field.binding = prop.binding; } } @@ -3003,11 +3063,19 @@ public class Vala.Genie.Parser : CodeVisitor { } set_attributes (sig, attrs); + if (ModifierFlags.STATIC in flags) { + throw new ParseError.SYNTAX (get_error ("`static' modifier not allowed on signals")); + } else if (ModifierFlags.CLASS in flags) { + throw new ParseError.SYNTAX (get_error ("`class' modifier not allowed on signals")); + } + foreach (FormalParameter formal_param in params) { sig.add_parameter (formal_param); } - expect_terminator (); + if (!accept_terminator ()) { + sig.body = parse_block (); + } return sig; } @@ -3165,6 +3233,8 @@ public class Vala.Genie.Parser : CodeVisitor { iface.add_signal ((Vala.Signal) sym); } else if (sym is Field) { iface.add_field ((Field) sym); + } else if (sym is Constant) { + iface.add_constant ((Constant) sym); } else if (sym is Property) { iface.add_property ((Property) sym); } else { @@ -3270,6 +3340,7 @@ public class Vala.Genie.Parser : CodeVisitor { while (sym.inner != null) { sym = sym.inner; var ns = new Namespace (sym.name, ed.source_reference); + if (result is Namespace) { ns.add_namespace ((Namespace) result); } else { @@ -3319,6 +3390,10 @@ public class Vala.Genie.Parser : CodeVisitor { next (); flags |= ModifierFlags.ABSTRACT; break; + case TokenType.ASYNC: + next (); + flags |= ModifierFlags.ASYNC; + break; case TokenType.CLASS: next (); flags |= ModifierFlags.CLASS; @@ -3425,9 +3500,6 @@ public class Vala.Genie.Parser : CodeVisitor { } while (accept (TokenType.COMMA)); } expect (TokenType.CLOSE_PARENS); - if (accept (TokenType.YIELDS)) { - method.coroutine = true; - } if (accept (TokenType.RAISES)) { do { method.add_error_type (parse_type ()); @@ -3520,6 +3592,7 @@ public class Vala.Genie.Parser : CodeVisitor { while (sym.inner != null) { sym = sym.inner; var ns = new Namespace (sym.name, d.source_reference); + if (result is Namespace) { ns.add_namespace ((Namespace) result); } else { diff --git a/vala/valageniescanner.vala b/vala/valageniescanner.vala index e39191c48..718a70b96 100644 --- a/vala/valageniescanner.vala +++ b/vala/valageniescanner.vala @@ -226,7 +226,14 @@ public class Vala.Genie.Scanner { case 5: switch (begin[0]) { case 'a': - if (matches (begin, "array")) return TokenType.ARRAY; + switch (begin[1]) { + case 'r': + if (matches (begin, "array")) return TokenType.ARRAY; + break; + case 's': + if (matches (begin, "async")) return TokenType.ASYNC; + break; + } break; case 'b': if (matches (begin, "break")) return TokenType.BREAK; @@ -346,9 +353,6 @@ public class Vala.Genie.Scanner { case 't': if (matches (begin, "typeof")) return TokenType.TYPEOF; break; - case 'y': - if (matches (begin, "yields")) return TokenType.YIELDS; - break; } break; case 7: @@ -884,7 +888,24 @@ public class Vala.Genie.Scanner { if (current[0] == '\\') { current++; token_length_in_chars++; - if (current < end && current[0] == 'x') { + if (current >= end) { + break; + } + + switch (current[0]) { + case '\'': + case '"': + case '\\': + case '0': + case 'b': + case 'f': + case 'n': + case 'r': + case 't': + current++; + token_length_in_chars++; + break; + case 'x': // hexadecimal escape character current++; token_length_in_chars++; @@ -892,9 +913,10 @@ public class Vala.Genie.Scanner { current++; token_length_in_chars++; } - } else { - current++; - token_length_in_chars++; + break; + default: + Report.error (new SourceReference (source_file, line, column + token_length_in_chars, line, column + token_length_in_chars), "invalid escape sequence"); + break; } } else if (current[0] == '\n') { break; @@ -904,6 +926,7 @@ public class Vala.Genie.Scanner { current += u.to_utf8 (null); token_length_in_chars++; } else { + current++; Report.error (new SourceReference (source_file, line, column + token_length_in_chars, line, column + token_length_in_chars), "invalid UTF-8 character"); } } @@ -978,7 +1001,7 @@ public class Vala.Genie.Scanner { } bool matches (char* begin, string keyword) { - char* keyword_array = keyword; + char* keyword_array = (char *) keyword; long len = keyword.len (); for (int i = 0; i < len; i++) { if (begin[i] != keyword_array[i]) { @@ -997,7 +1020,7 @@ public class Vala.Genie.Scanner { column++; } - if ((column == 1) && (current[0] == '#')) { + if ((column == 1) && (current < end) && (current[0] == '#')) { pp_directive (); return true; } diff --git a/vala/valagenietokentype.vala b/vala/valagenietokentype.vala index 700902991..a814ade8b 100644 --- a/vala/valagenietokentype.vala +++ b/vala/valagenietokentype.vala @@ -39,6 +39,7 @@ public enum Vala.Genie.TokenType { ASSIGN_PERCENT, ASSIGN_SHIFT_LEFT, ASSIGN_SUB, + ASYNC, BITWISE_AND, BITWISE_OR, BREAK, @@ -163,8 +164,7 @@ public enum Vala.Genie.TokenType { WHEN, WHILE, WRITEONLY, - YIELD, - YIELDS; + YIELD; public weak string to_string () { switch (this) { @@ -182,6 +182,7 @@ public enum Vala.Genie.TokenType { case ASSIGN_PERCENT: return "`%='"; case ASSIGN_SHIFT_LEFT: return "`<<='"; case ASSIGN_SUB: return "`-='"; + case ASYNC: return "`async'"; case BITWISE_AND: return "`&'"; case BITWISE_OR: return "`|'"; case BREAK: return "`break'"; @@ -306,7 +307,6 @@ public enum Vala.Genie.TokenType { case WHILE: return "`while'"; case WRITEONLY: return "`writeonly'"; case YIELD: return "`yield'"; - case YIELDS: return "`yields'"; default: return "unknown token"; } } -- 2.47.3