diff --git a/src/globals.h b/src/globals.h index 1bdea3a40..a65a91eb1 100644 --- a/src/globals.h +++ b/src/globals.h @@ -97,12 +97,16 @@ typedef enum */ extern uint32_t jerry_unreferenced_expression; -extern void __noreturn jerry_assert_fail (const char *assertion, const char *file, const uint32_t line); -extern void __noreturn jerry_unreachable (const char *comment, const char *file, const uint32_t line); -extern void __noreturn jerry_unimplemented (const char *comment, const char *file, const uint32_t line); +extern void __noreturn jerry_assert_fail (const char *assertion, const char *file, const char *function, + const uint32_t line); +extern void __noreturn jerry_unreachable (const char *comment, const char *file, const char *function, + const uint32_t line); +extern void __noreturn jerry_unimplemented (const char *comment, const char *file, const char *function, + const uint32_t line); #ifndef JERRY_NDEBUG -#define JERRY_ASSERT(x) do { if (__builtin_expect (!(x), 0)) { jerry_assert_fail (#x, __FILE__, __LINE__); } } while (0) +#define JERRY_ASSERT(x) do { if (__builtin_expect (!(x), 0)) { \ + jerry_assert_fail (#x, __FILE__, __FUNCTION__, __LINE__); } } while (0) #else /* !JERRY_NDEBUG */ #define JERRY_ASSERT(x) (void) (x) #endif /* !JERRY_NDEBUG */ @@ -114,19 +118,19 @@ extern void jerry_ref_unused_variables (int unused_variables_follow, ...); #define JERRY_UNREACHABLE() \ do \ { \ - jerry_unreachable (NULL, __FILE__, __LINE__); \ + jerry_unreachable (NULL, __FILE__, __FUNCTION__, __LINE__); \ } while (0) #define JERRY_UNIMPLEMENTED() \ do \ { \ - jerry_unimplemented (NULL, __FILE__, __LINE__); \ + jerry_unimplemented (NULL, __FILE__, __FUNCTION__, __LINE__); \ } while (0) #define JERRY_UNIMPLEMENTED_REF_UNUSED_VARS(...) \ do \ { \ - jerry_unimplemented (NULL, __FILE__, __LINE__); \ + jerry_unimplemented (NULL, __FILE__, __FUNCTION__, __LINE__); \ if (false) \ { \ jerry_ref_unused_variables (0, __VA_ARGS__); \ diff --git a/src/libjsparser/lexer.c b/src/libjsparser/lexer.c index 1655194b1..5b20368a1 100644 --- a/src/libjsparser/lexer.c +++ b/src/libjsparser/lexer.c @@ -19,12 +19,14 @@ #include "parser.h" #include "stack.h" #include "opcodes.h" +#include "parse-error.h" static token saved_token, prev_token, sent_token; static token empty_token = { .type = TOK_EMPTY, - .uid = 0 + .uid = 0, + .locus = 0 }; static bool allow_dump_lines = false; @@ -71,7 +73,6 @@ get_char (size_t i) return *(buffer + i); } -#ifdef __TARGET_HOST_x64 static void dump_current_line (void) { @@ -90,7 +91,29 @@ dump_current_line (void) } __putchar ('\n'); } -#endif + +static token +create_token (token_type type, size_t loc __unused, uint8_t uid) +{ + return (token) + { + .type = type, + .locus = loc, + .uid = uid + }; +} + +static token +create_token_from_current_token (token_type type, uint8_t uid) +{ + return create_token (type, (size_t) (token_start - buffer_start), uid); +} + +static token +create_token_from_buffer_state (token_type type, uint8_t uid) +{ + return create_token (type, (size_t) (buffer - buffer_start), uid); +} static bool current_token_equals_to (const char *str) @@ -128,371 +151,187 @@ decode_keyword (void) { if (current_token_equals_to ("break")) { - return (token) - { - .type = TOK_KEYWORD, - .uid = KW_BREAK - }; + return create_token_from_current_token (TOK_KEYWORD, KW_BREAK); } if (current_token_equals_to ("case")) { - return (token) - { - .type = TOK_KEYWORD, - .uid = KW_CASE - }; + return create_token_from_current_token (TOK_KEYWORD, KW_CASE); } if (current_token_equals_to ("catch")) { - return (token) - { - .type = TOK_KEYWORD, - .uid = KW_CATCH - }; + return create_token_from_current_token (TOK_KEYWORD, KW_CATCH); } if (current_token_equals_to ("class")) { - return (token) - { - .type = TOK_KEYWORD, - .uid = KW_RESERVED - }; + return create_token_from_current_token (TOK_KEYWORD, KW_RESERVED); } if (current_token_equals_to ("const")) { - return (token) - { - .type = TOK_KEYWORD, - .uid = KW_RESERVED - }; + return create_token_from_current_token (TOK_KEYWORD, KW_RESERVED); } if (current_token_equals_to ("continue")) { - return (token) - { - .type = TOK_KEYWORD, - .uid = KW_CONTINUE - }; + return create_token_from_current_token (TOK_KEYWORD, KW_CONTINUE); } if (current_token_equals_to ("debugger")) { - return (token) - { - .type = TOK_KEYWORD, - .uid = KW_DEBUGGER - }; + return create_token_from_current_token (TOK_KEYWORD, KW_DEBUGGER); } if (current_token_equals_to ("default")) { - return (token) - { - .type = TOK_KEYWORD, - .uid = KW_DEFAULT - }; + return create_token_from_current_token (TOK_KEYWORD, KW_DEFAULT); } if (current_token_equals_to ("delete")) { - return (token) - { - .type = TOK_KEYWORD, - .uid = KW_DELETE - }; + return create_token_from_current_token (TOK_KEYWORD, KW_DELETE); } if (current_token_equals_to ("do")) { - return (token) - { - .type = TOK_KEYWORD, - .uid = KW_DO - }; + return create_token_from_current_token (TOK_KEYWORD, KW_DO); } if (current_token_equals_to ("else")) { - return (token) - { - .type = TOK_KEYWORD, - .uid = KW_ELSE - }; + return create_token_from_current_token (TOK_KEYWORD, KW_ELSE); } if (current_token_equals_to ("enum")) { - return (token) - { - .type = TOK_KEYWORD, - .uid = KW_RESERVED - }; + return create_token_from_current_token (TOK_KEYWORD, KW_RESERVED); } if (current_token_equals_to ("export")) { - return (token) - { - .type = TOK_KEYWORD, - .uid = KW_RESERVED - }; + return create_token_from_current_token (TOK_KEYWORD, KW_RESERVED); } if (current_token_equals_to ("extends")) { - return (token) - { - .type = TOK_KEYWORD, - .uid = KW_RESERVED - }; + return create_token_from_current_token (TOK_KEYWORD, KW_RESERVED); } if (current_token_equals_to ("false")) { - return (token) - { - .type = TOK_BOOL, - .uid = false - }; + return create_token_from_current_token (TOK_BOOL, false); } if (current_token_equals_to ("finally")) { - return (token) - { - .type = TOK_KEYWORD, - .uid = KW_FINALLY - }; + return create_token_from_current_token (TOK_KEYWORD, KW_FINALLY); } if (current_token_equals_to ("for")) { - return (token) - { - .type = TOK_KEYWORD, - .uid = KW_FOR - }; + return create_token_from_current_token (TOK_KEYWORD, KW_FOR); } if (current_token_equals_to ("function")) { - return (token) - { - .type = TOK_KEYWORD, - .uid = KW_FUNCTION - }; + return create_token_from_current_token (TOK_KEYWORD, KW_FUNCTION); } if (current_token_equals_to ("if")) { - return (token) - { - .type = TOK_KEYWORD, - .uid = KW_IF - }; + return create_token_from_current_token (TOK_KEYWORD, KW_IF); } if (current_token_equals_to ("instanceof")) { - return (token) - { - .type = TOK_KEYWORD, - .uid = KW_INSTANCEOF - }; + return create_token_from_current_token (TOK_KEYWORD, KW_INSTANCEOF); } if (current_token_equals_to ("interface")) { - return (token) - { - .type = TOK_KEYWORD, - .uid = KW_RESERVED - }; + return create_token_from_current_token (TOK_KEYWORD, KW_RESERVED); } if (current_token_equals_to ("in")) { - return (token) - { - .type = TOK_KEYWORD, - .uid = KW_IN - }; + return create_token_from_current_token (TOK_KEYWORD, KW_IN); } if (current_token_equals_to ("import")) { - return (token) - { - .type = TOK_KEYWORD, - .uid = KW_RESERVED - }; + return create_token_from_current_token (TOK_KEYWORD, KW_RESERVED); } if (current_token_equals_to ("implements")) { - return (token) - { - .type = TOK_KEYWORD, - .uid = KW_RESERVED - }; + return create_token_from_current_token (TOK_KEYWORD, KW_RESERVED); } if (current_token_equals_to ("let")) { - return (token) - { - .type = TOK_KEYWORD, - .uid = KW_RESERVED - }; + return create_token_from_current_token (TOK_KEYWORD, KW_RESERVED); } if (current_token_equals_to ("new")) { - return (token) - { - .type = TOK_KEYWORD, - .uid = KW_NEW - }; + return create_token_from_current_token (TOK_KEYWORD, KW_NEW); } if (current_token_equals_to ("null")) { - return (token) - { - .type = TOK_NULL, - .uid = 0 - }; + return create_token_from_current_token (TOK_NULL, 0); } if (current_token_equals_to ("package")) { - return (token) - { - .type = TOK_KEYWORD, - .uid = KW_RESERVED - }; + return create_token_from_current_token (TOK_KEYWORD, KW_RESERVED); } if (current_token_equals_to ("private")) { - return (token) - { - .type = TOK_KEYWORD, - .uid = KW_RESERVED - }; + return create_token_from_current_token (TOK_KEYWORD, KW_RESERVED); } if (current_token_equals_to ("protected")) { - return (token) - { - .type = TOK_KEYWORD, - .uid = KW_RESERVED - }; + return create_token_from_current_token (TOK_KEYWORD, KW_RESERVED); } if (current_token_equals_to ("public")) { - return (token) - { - .type = TOK_KEYWORD, - .uid = KW_RESERVED - }; + return create_token_from_current_token (TOK_KEYWORD, KW_RESERVED); } if (current_token_equals_to ("return")) { - return (token) - { - .type = TOK_KEYWORD, - .uid = KW_RETURN - }; + return create_token_from_current_token (TOK_KEYWORD, KW_RETURN); } if (current_token_equals_to ("static")) { - return (token) - { - .type = TOK_KEYWORD, - .uid = KW_RESERVED - }; + return create_token_from_current_token (TOK_KEYWORD, KW_RESERVED); } if (current_token_equals_to ("super")) { - return (token) - { - .type = TOK_KEYWORD, - .uid = KW_RESERVED - }; + return create_token_from_current_token (TOK_KEYWORD, KW_RESERVED); } if (current_token_equals_to ("switch")) { - return (token) - { - .type = TOK_KEYWORD, - .uid = KW_SWITCH - }; + return create_token_from_current_token (TOK_KEYWORD, KW_SWITCH); } if (current_token_equals_to ("this")) { - return (token) - { - .type = TOK_KEYWORD, - .uid = KW_THIS - }; + return create_token_from_current_token (TOK_KEYWORD, KW_THIS); } if (current_token_equals_to ("throw")) { - return (token) - { - .type = TOK_KEYWORD, - .uid = KW_THROW - }; + return create_token_from_current_token (TOK_KEYWORD, KW_THROW); } if (current_token_equals_to ("true")) { - return (token) - { - .type = TOK_BOOL, - .uid = true - }; + return create_token_from_current_token (TOK_BOOL, true); } if (current_token_equals_to ("try")) { - return (token) - { - .type = TOK_KEYWORD, - .uid = KW_TRY - }; + return create_token_from_current_token (TOK_KEYWORD, KW_TRY); } if (current_token_equals_to ("typeof")) { - return (token) - { - .type = TOK_KEYWORD, - .uid = KW_TYPEOF - }; + return create_token_from_current_token (TOK_KEYWORD, KW_TYPEOF); } if (current_token_equals_to ("var")) { - return (token) - { - .type = TOK_KEYWORD, - .uid = KW_VAR - }; + return create_token_from_current_token (TOK_KEYWORD, KW_VAR); } if (current_token_equals_to ("void")) { - return (token) - { - .type = TOK_KEYWORD, - .uid = KW_VOID - }; + return create_token_from_current_token (TOK_KEYWORD, KW_VOID); } if (current_token_equals_to ("while")) { - return (token) - { - .type = TOK_KEYWORD, - .uid = KW_WHILE - }; + return create_token_from_current_token (TOK_KEYWORD, KW_WHILE); } if (current_token_equals_to ("with")) { - return (token) - { - .type = TOK_KEYWORD, - .uid = KW_WITH - }; + return create_token_from_current_token (TOK_KEYWORD, KW_WITH); } if (current_token_equals_to ("yield")) { - return (token) - { - .type = TOK_KEYWORD, - .uid = KW_RESERVED - }; + return create_token_from_current_token (TOK_KEYWORD, KW_RESERVED); } if (current_token_equals_to ("undefined")) { - return (token) - { - .type = TOK_UNDEFINED, - .uid = 0 - }; + return create_token_from_current_token (TOK_UNDEFINED, 0); } return empty_token; } @@ -506,11 +345,7 @@ convert_current_token_to_token (token_type tt) { if (current_token_equals_to_lp (STACK_ELEMENT (strings, i))) { - return (token) - { - .type = tt, - .uid = i - }; + return create_token_from_current_token (tt, i); } } @@ -522,11 +357,7 @@ convert_current_token_to_token (token_type tt) STACK_PUSH (strings, str); - return (token) - { - .type = tt, - .uid = (idx_t) (STACK_SIZE (strings) - 1) - }; + return create_token_from_current_token (tt, (idx_t) (STACK_SIZE (strings) - 1)); } static token @@ -539,11 +370,7 @@ convert_seen_num_to_token (ecma_number_t num) { if (STACK_ELEMENT (numbers, i) == num) { - return (token) - { - .type = TOK_NUMBER, - .uid = STACK_ELEMENT (num_ids, i) - }; + return create_token_from_current_token (TOK_NUMBER, STACK_ELEMENT (num_ids, i)); } } @@ -551,11 +378,7 @@ convert_seen_num_to_token (ecma_number_t num) STACK_PUSH (num_ids, num_id); STACK_PUSH (numbers, num); - return (token) - { - .type = TOK_NUMBER, - .uid = num_id - }; + return create_token_from_current_token (TOK_NUMBER, num_id); } const lp_string * @@ -635,11 +458,7 @@ consume_char (void) do \ { \ buffer += NUM; \ - return (token) \ - { \ - .type = TOK, \ - .uid = 0 \ - }; \ + return create_token_from_buffer_state (TOK, 0); \ } \ while (0) @@ -803,7 +622,7 @@ parse_number (void) if (__isalpha (c) || c == '_' || c == '$') { - parser_fatal (ERR_INT_LITERAL); + PARSE_ERROR ("Integer literal shall not contain non-digit characters", buffer - buffer_start); } tok_length = (size_t) (buffer - token_start); @@ -820,20 +639,18 @@ parse_number (void) #endif } - token_start = NULL; - if (res <= 255) { - return (token) - { - .type = TOK_SMALL_INT, - .uid = (uint8_t) res - }; + known_token = create_token_from_current_token (TOK_SMALL_INT, (uint8_t) res); + token_start = NULL; + return known_token; } known_token = convert_seen_num_to_token ((ecma_number_t) res); JERRY_ASSERT (!is_empty (known_token)); + token_start = NULL; + return known_token; } @@ -852,18 +669,20 @@ parse_number (void) c = LA (0); if (is_fp && c == '.') { - parser_fatal (ERR_INT_LITERAL); + PARSE_ERROR ("Integer literal shall not contain more than one dot character", buffer - buffer_start); } if (is_exp && (c == 'e' || c == 'E')) { - parser_fatal (ERR_INT_LITERAL); + PARSE_ERROR ("Integer literal shall not contain more than exponential marker ('e' or 'E')", + buffer - buffer_start); } if (c == '.') { if (__isalpha (LA (1)) || LA (1) == '_' || LA (1) == '$') { - parser_fatal (ERR_INT_LITERAL); + PARSE_ERROR ("Integer literal shall not contain non-digit character after got character", + buffer - buffer_start); } is_fp = true; consume_char (); @@ -878,7 +697,8 @@ parse_number (void) } if (!__isdigit (LA (1))) { - parser_fatal (ERR_INT_LITERAL); + PARSE_ERROR ("Integer literal shall not contain non-digit character after exponential marker ('e' or 'E')", + buffer - buffer_start); } is_exp = true; consume_char (); @@ -887,7 +707,7 @@ parse_number (void) if (__isalpha (c) || c == '_' || c == '$') { - parser_fatal (ERR_INT_LITERAL); + PARSE_ERROR ("Integer literal shall not contain non-digit characters", buffer - buffer_start); } if (!__isdigit (c)) @@ -901,10 +721,9 @@ parse_number (void) if (is_fp || is_exp) { ecma_number_t res = __strtof (token_start, NULL); - token_start = NULL; known_token = convert_seen_num_to_token (res); - + token_start = NULL; return known_token; } @@ -914,18 +733,15 @@ parse_number (void) res = res * 10 + hex_to_int (token_start[i]); } - token_start = NULL; - if (res <= 255) { - return (token) - { - .type = TOK_SMALL_INT, - .uid = (uint8_t) res - }; + known_token = create_token_from_current_token (TOK_SMALL_INT, (uint8_t) res); + token_start = NULL; + return known_token; } known_token = convert_seen_num_to_token ((ecma_number_t) res); + token_start = NULL; return known_token; } @@ -949,18 +765,18 @@ parse_string (void) c = LA (0); if (c == '\0') { - parser_fatal (ERR_UNCLOSED); + PARSE_ERROR ("Unclosed string", token_start - buffer_start); } if (c == '\n') { - parser_fatal (ERR_STRING); + PARSE_ERROR ("String literal shall not contain newline character", token_start - buffer_start); } if (c == '\\') { /* Only single escape character is allowed. */ if (LA (1) == 'x' || LA (1) == 'u' || __isdigit (LA (1))) { - parser_fatal (ERR_STRING); + PARSE_SORRY ("Escape sequences are not supported yet", token_start - buffer_start); } if ((LA (1) == '\'' && !is_double_quoted) || (LA (1) == '"' && is_double_quoted) @@ -980,9 +796,9 @@ parse_string (void) consume_char (); } - // Eat up '"' result = convert_current_token_to_token (TOK_STRING); + // Eat up '"' consume_char (); token_start = NULL; @@ -1058,7 +874,7 @@ replace_comment_by_newline (void) } if (multiline && c == '\0') { - parser_fatal (ERR_UNCLOSED); + PARSE_ERROR ("Unclosed multiline comment", buffer - buffer_start); } consume_char (); } @@ -1091,20 +907,12 @@ lexer_next_token_private (void) if (c == '\n') { consume_char (); - return (token) - { - .type = TOK_NEWLINE, - .uid = 0 - }; + return create_token_from_buffer_state (TOK_NEWLINE, 0); } if (c == '\0') { - return (token) - { - .type = TOK_EOF, - .uid = 0 - }; + return create_token_from_buffer_state (TOK_EOF, 0); } if (c == '\'' || c == '"') @@ -1218,31 +1026,27 @@ lexer_next_token_private (void) } break; } - default: JERRY_UNREACHABLE (); + default: PARSE_SORRY ("Unknown character", buffer - buffer_start); } - parser_fatal (ERR_NON_CHAR); + PARSE_SORRY ("Unknown character", buffer - buffer_start); } token lexer_next_token (void) { -#ifdef __TARGET_HOST_x64 if (buffer == buffer_start) { dump_current_line (); } -#endif /* __TARGET_HOST_x64 */ prev_token = sent_token; sent_token = lexer_next_token_private (); -#ifdef __TARGET_HOST_x64 if (sent_token.type == TOK_NEWLINE) { dump_current_line (); return sent_token; } -#endif /* __TARGET_HOST_x64 */ return sent_token; } @@ -1258,12 +1062,6 @@ lexer_prev_token (void) return prev_token; } -void -lexer_dump_buffer_state (void) -{ - __printf ("%s\n", buffer); -} - void lexer_run_first_pass (void) { @@ -1276,6 +1074,172 @@ lexer_run_first_pass (void) lexer_rewind (); } +void +lexer_locus_to_line_and_column (size_t locus, size_t *line, size_t *column) +{ + JERRY_ASSERT (locus < buffer_size); + const char *buf; + size_t l = 0, c = 0; + for (buf = buffer_start; (size_t) (buf - buffer_start) < locus; buf++) + { + if (*buf == '\n') + { + c = 0; + l++; + continue; + } + c++; + } + + if (line) + { + *line = l; + } + if (column) + { + *column = c; + } +} + +void +lexer_dump_line (size_t line) +{ + size_t l = 0; + for (const char *buf = buffer_start; *buf != '\0'; buf++) + { + if (l == line) + { + for (; *buf != '\n' && *buf != '\0'; buf++) + { + __putchar (*buf); + } + return; + } + if (*buf == '\n') + { + l++; + } + } +} + +const char * +lexer_keyword_to_string (keyword kw) +{ + switch (kw) + { + case KW_BREAK: return "break"; + case KW_CASE: return "case"; + case KW_CATCH: return "catch"; + + case KW_CONTINUE: return "continue"; + case KW_DEBUGGER: return "debugger"; + case KW_DEFAULT: return "default"; + case KW_DELETE: return "delete"; + case KW_DO: return "do"; + + case KW_ELSE: return "else"; + case KW_FINALLY: return "finally"; + case KW_FOR: return "for"; + case KW_FUNCTION: return "function"; + case KW_IF: return "if"; + + case KW_IN: return "in"; + case KW_INSTANCEOF: return "instanceof"; + case KW_NEW: return "new"; + case KW_RETURN: return "return"; + case KW_SWITCH: return "switch"; + + case KW_THIS: return "this"; + case KW_THROW: return "throw"; + case KW_TRY: return "try"; + case KW_TYPEOF: return "typeof"; + case KW_VAR: return "var"; + + case KW_VOID: return "void"; + case KW_WHILE: return "while"; + case KW_WITH: return "with"; + default: JERRY_UNREACHABLE (); + } +} + +const char * +lexer_token_type_to_string (token_type tt) +{ + switch (tt) + { + case TOK_EOF: return "End of file"; + case TOK_NAME: return "Identifier"; + case TOK_KEYWORD: return "Keyword"; + case TOK_SMALL_INT: /* FALLTHRU */ + case TOK_NUMBER: return "Number"; + + case TOK_NULL: return "null"; + case TOK_BOOL: return "bool"; + case TOK_NEWLINE: return "newline"; + case TOK_STRING: return "string"; + case TOK_OPEN_BRACE: return "{"; + + case TOK_CLOSE_BRACE: return "}"; + case TOK_OPEN_PAREN: return "("; + case TOK_CLOSE_PAREN: return ")"; + case TOK_OPEN_SQUARE: return "["; + case TOK_CLOSE_SQUARE: return "]"; + + case TOK_DOT: return "."; + case TOK_SEMICOLON: return ";"; + case TOK_COMMA: return ","; + case TOK_LESS: return "<"; + case TOK_GREATER: return ">"; + + case TOK_LESS_EQ: return "<="; + case TOK_GREATER_EQ: return "<="; + case TOK_DOUBLE_EQ: return "=="; + case TOK_NOT_EQ: return "!="; + case TOK_TRIPLE_EQ: return "==="; + + case TOK_NOT_DOUBLE_EQ: return "!=="; + case TOK_PLUS: return "+"; + case TOK_MINUS: return "-"; + case TOK_MULT: return "*"; + case TOK_MOD: return "%%"; + + case TOK_DOUBLE_PLUS: return "++"; + case TOK_DOUBLE_MINUS: return "--"; + case TOK_LSHIFT: return "<<"; + case TOK_RSHIFT: return ">>"; + case TOK_RSHIFT_EX: return ">>>"; + + case TOK_AND: return "&"; + case TOK_OR: return "|"; + case TOK_XOR: return "^"; + case TOK_NOT: return "!"; + case TOK_COMPL: return "~"; + + case TOK_DOUBLE_AND: return "&&"; + case TOK_DOUBLE_OR: return "||"; + case TOK_QUERY: return "?"; + case TOK_COLON: return ":"; + case TOK_EQ: return "="; + + case TOK_PLUS_EQ: return "+="; + case TOK_MINUS_EQ: return "-="; + case TOK_MULT_EQ: return "*="; + case TOK_MOD_EQ: return "%%="; + case TOK_LSHIFT_EQ: return "<<="; + + case TOK_RSHIFT_EQ: return ">>="; + case TOK_RSHIFT_EX_EQ: return ">>>="; + case TOK_AND_EQ: return "&="; + case TOK_OR_EQ: return "|="; + case TOK_XOR_EQ: return "^="; + + case TOK_DIV: return "/"; + case TOK_DIV_EQ: return "/="; + case TOK_UNDEFINED: return "undefined"; + default: JERRY_UNREACHABLE (); + } +} + void lexer_init (const char *source, size_t source_size, bool show_opcodes) { diff --git a/src/libjsparser/lexer.h b/src/libjsparser/lexer.h index 2ccc71e53..59099f447 100644 --- a/src/libjsparser/lexer.h +++ b/src/libjsparser/lexer.h @@ -139,8 +139,8 @@ typedef uint8_t token_type; typedef struct { token_type type; - uint8_t uid; + size_t locus; } __packed token; @@ -154,8 +154,6 @@ token lexer_next_token (void); void lexer_save_token (token); token lexer_prev_token (void); -void lexer_dump_buffer_state (void); - uint8_t lexer_get_reserved_ids_count (void); const lp_string *lexer_get_strings (void); @@ -168,4 +166,9 @@ uint8_t lexer_get_nums_count (void); void lexer_adjust_num_ids (void); +void lexer_locus_to_line_and_column (size_t, size_t *, size_t *); +void lexer_dump_line (size_t); +const char *lexer_keyword_to_string (keyword); +const char *lexer_token_type_to_string (token_type); + #endif diff --git a/src/libjsparser/parse-error.h b/src/libjsparser/parse-error.h new file mode 100644 index 000000000..e000f543a --- /dev/null +++ b/src/libjsparser/parse-error.h @@ -0,0 +1,58 @@ +/* Copyright 2014 Samsung Electronics Co., Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef PARSE_ERROR_H +#define PARSE_ERROR_H + +#define PARSE_ERROR(MESSAGE, LOCUS) do { \ + size_t line, column; \ + lexer_locus_to_line_and_column ((size_t) (LOCUS), &line, &column); \ + lexer_dump_line (line); \ + __printf ("\n"); \ + for (size_t i = 0; i < column; i++) { \ + __putchar (' '); \ + } \ + __printf ("^\n"); \ + __printf ("ERROR: Ln %d, Col %d: %s\n", line + 1, column + 1, MESSAGE); \ + __exit (-1); \ +} while (0) +#define PARSE_ERROR_VARG(MESSAGE, LOCUS, ...) do { \ + size_t line, column; \ + lexer_locus_to_line_and_column ((size_t) (LOCUS), &line, &column); \ + lexer_dump_line (line); \ + __printf ("\n"); \ + for (size_t i = 0; i < column; i++) { \ + __putchar (' '); \ + } \ + __printf ("\n^\n"); \ + __printf ("ERROR: Ln %d, Col %d: ", line + 1, column + 1); \ + __printf (MESSAGE, __VA_ARGS__); \ + __printf ("\n"); \ + __exit (-1); \ +} while (0) +#define PARSE_SORRY(MESSAGE, LOCUS) do { \ + size_t line, column; \ + lexer_locus_to_line_and_column ((size_t) (LOCUS), &line, &column); \ + lexer_dump_line (line); \ + __printf ("\n"); \ + for (size_t i = 0; i < column; i++) { \ + __putchar (' '); \ + } \ + __printf ("^\n"); \ + __printf ("SORRY, Unimplemented: Ln %d, Col %d: %s\n", line + 1, column + 1, MESSAGE); \ + __exit (-1); \ +} while (0) + +#endif /* PARSE_ERROR_H */ diff --git a/src/libjsparser/parser.c b/src/libjsparser/parser.c index 213ad4aee..6a1f171ab 100644 --- a/src/libjsparser/parser.c +++ b/src/libjsparser/parser.c @@ -24,6 +24,7 @@ #include "hash-table.h" #include "deserializer.h" #include "opcodes-native-call.h" +#include "parse-error.h" #define INVALID_VALUE 255 #define INTRINSICS_COUNT 1 @@ -266,6 +267,17 @@ do { \ STACK_CHECK_USAGE (IDX); \ } while (0) +#define EMIT_ERROR(MESSAGE) PARSE_ERROR(MESSAGE, TOK().locus) +#define EMIT_SORRY(MESSAGE) PARSE_SORRY(MESSAGE, TOK().locus) +#define EMIT_ERROR_VARG(MESSAGE, ...) PARSE_ERROR_VARG(MESSAGE, TOK().locus, __VA_ARGS__) + +#define NESTING_TO_STRING(I) (I == NESTING_FUNCTION \ + ? "function" \ + : I == NESTING_ITERATIONAL \ + ? "iterational" \ + : I == NESTING_SWITCH \ + ? "switch" : "unknown") + typedef enum { AL_FUNC_DECL, @@ -348,7 +360,7 @@ must_be_inside_but_not_in (uint8_t *inside, uint8_t insides_count, uint8_t not_i if (STACK_SIZE(nestings) == 0) { - parser_fatal (ERR_PARSER); + EMIT_ERROR ("Shall be inside a nesting"); } SET_I(STACK_SIZE(nestings)); @@ -356,7 +368,7 @@ must_be_inside_but_not_in (uint8_t *inside, uint8_t insides_count, uint8_t not_i { if (STACK_ELEMENT (nestings, I() - 1) == not_in) { - parser_fatal (ERR_PARSER); + EMIT_ERROR_VARG ("Shall not be inside a '%s' nesting", NESTING_TO_STRING(not_in)); } SET_J(0); @@ -371,7 +383,13 @@ must_be_inside_but_not_in (uint8_t *inside, uint8_t insides_count, uint8_t not_i SET_I(I()-1); } - parser_fatal (ERR_PARSER); + switch (insides_count) + { + case 1: EMIT_ERROR_VARG ("Shall be inside a '%s' nesting", NESTING_TO_STRING(inside[0])); break; + case 2: EMIT_ERROR_VARG ("Shall be inside '%s' or '%s' nestings", + NESTING_TO_STRING(inside[0]), NESTING_TO_STRING(inside[1])); break; + default: JERRY_UNREACHABLE (); + } cleanup: STACK_DROP (U8, 2); @@ -405,9 +423,7 @@ assert_keyword (keyword kw) { if (!token_is (TOK_KEYWORD) || token_data () != kw) { -#ifdef __TARGET_HOST_x64 - __printf ("assert_keyword: %d\n", kw); -#endif + EMIT_ERROR_VARG ("Expected keyword '%s'", lexer_keyword_to_string (kw)); JERRY_UNREACHABLE (); } } @@ -423,10 +439,7 @@ current_token_must_be (token_type tt) { if (!token_is (tt)) { -#ifdef __TARGET_HOST_x64 - __printf ("current_token_must_be: %d\n", tt); -#endif - parser_fatal (ERR_PARSER); + EMIT_ERROR_VARG ("Expected '%s' token", lexer_token_type_to_string (tt)); } } @@ -446,10 +459,7 @@ next_token_must_be (token_type tt) skip_token (); if (!token_is (tt)) { -#ifdef __TARGET_HOST_x64 - __printf ("next_token_must_be: %d\n", tt); -#endif - parser_fatal (ERR_PARSER); + EMIT_ERROR_VARG ("Expected '%s' token", lexer_token_type_to_string (tt)); } } @@ -459,7 +469,7 @@ token_after_newlines_must_be (token_type tt) skip_newlines (); if (!token_is (tt)) { - parser_fatal (ERR_PARSER); + EMIT_ERROR_VARG ("Expected '%s' token", lexer_token_type_to_string (tt)); } } @@ -469,7 +479,7 @@ token_after_newlines_must_be_keyword (keyword kw) skip_newlines (); if (!is_keyword (kw)) { - parser_fatal (ERR_PARSER); + EMIT_ERROR_VARG ("Expected keyword '%s'", lexer_keyword_to_string (kw)); } } @@ -1348,7 +1358,7 @@ parse_member_expression (idx_t *this_arg) skip_newlines (); if (!token_is (TOK_NAME)) { - parser_fatal (ERR_PARSER); + EMIT_ERROR ("Expected identifier"); } STACK_PUSH (IDX, next_temp_name ()); DUMP_OPCODE_3 (assignment, ID(1), OPCODE_ARG_TYPE_STRING, token_data ()); @@ -1579,11 +1589,11 @@ parse_unary_expression (void) lhs = delete_prop for 'delete expr[expr]'; lhs = true - otherwise; */); // DUMP_OPCODE_2 (delete, lhs, expr); - JERRY_UNIMPLEMENTED (); + EMIT_SORRY ("Operation 'delete' is not supported yet"); } if (is_keyword (KW_VOID)) { - JERRY_UNIMPLEMENTED (); + EMIT_SORRY ("Operation 'void' is not supported yet"); } if (is_keyword (KW_TYPEOF)) { @@ -2331,7 +2341,7 @@ parse_for_or_for_in_statement (void) } else { - parser_fatal (ERR_PARSER); + EMIT_ERROR ("Expected either ':' or 'in' token"); } } } @@ -2351,7 +2361,7 @@ parse_for_or_for_in_statement (void) } else { - parser_fatal (ERR_PARSER); + EMIT_ERROR ("Expected either ':' or 'in' token"); } JERRY_UNREACHABLE (); @@ -2430,7 +2440,7 @@ plain_for: goto cleanup; for_in: - JERRY_UNIMPLEMENTED (); + EMIT_SORRY ("'for in' loops are not supported yet"); cleanup: STACK_CHECK_USAGE (IDX); @@ -2644,7 +2654,7 @@ parse_with_statement (void) static void parse_switch_statement (void) { - JERRY_UNIMPLEMENTED (); + EMIT_SORRY ("'switch' is not supported yet"); } /* catch_clause @@ -2751,7 +2761,7 @@ parse_try_statement (void) } else { - parser_fatal (ERR_PARSER); + EMIT_ERROR ("Expected either 'catch' or 'finally' token"); } DUMP_OPCODE_3 (meta, OPCODE_META_TYPE_END_TRY_CATCH_FINALLY, INVALID_VALUE, INVALID_VALUE); @@ -2772,7 +2782,7 @@ insert_semicolon (void) } if (!token_is (TOK_SEMICOLON)) { - parser_fatal (ERR_PARSER); + EMIT_ERROR ("Expected either ';' or newline token"); } } @@ -2962,7 +2972,7 @@ parse_statement (void) if (token_is (TOK_COLON)) { // STMT_LABELLED; - JERRY_UNIMPLEMENTED (); + EMIT_SORRY ("Labelled statements are not supported yet"); } else { @@ -3145,12 +3155,3 @@ parser_free (void) serializer_free (); lexer_free (); } - -void -parser_fatal (jerry_status_t code) -{ - __printf ("FATAL: %d\n", code); - lexer_dump_buffer_state (); - - jerry_exit (code); -} diff --git a/src/libjsparser/parser.h b/src/libjsparser/parser.h index 80f8bcb7d..16ca1e4d0 100644 --- a/src/libjsparser/parser.h +++ b/src/libjsparser/parser.h @@ -22,6 +22,4 @@ void parser_init (const char *, size_t, bool); void parser_parse_program (void); void parser_free (void); -void parser_fatal (jerry_status_t code); - #endif diff --git a/src/libruntime/target/linux/jerry-assert.c b/src/libruntime/target/linux/jerry-assert.c index a0822394d..f0cf0ea33 100644 --- a/src/libruntime/target/linux/jerry-assert.c +++ b/src/libruntime/target/linux/jerry-assert.c @@ -22,10 +22,11 @@ void __noreturn jerry_assert_fail (const char *assertion, /**< assertion condition string */ const char *file, /**< file name */ + const char *function, /**< function name */ const uint32_t line) /** line */ { - __printf ("Assertion '%s' failed at %s:%u.\n", - assertion, file, line); + __printf ("ICE: Assertion '%s' failed at %s(%s):%u.\n", + assertion, file, function, line); __exit (-ERR_FAILED_INTERNAL_ASSERTION); } /* jerry_assert_fail */ @@ -37,9 +38,10 @@ void __noreturn jerry_unreachable (const char *comment, /**< comment to unreachable mark if exists, NULL - otherwise */ const char *file, /**< file name */ + const char *function, /**< function name */ const uint32_t line) /**< line */ { - __printf ("Unreachable control path at %s:%u was executed", file, line); + __printf ("ICE: Unreachable control path at %s(%s):%u was executed", file, function, line); if (comment != NULL) { __printf ("(%s)", comment); @@ -56,9 +58,10 @@ void __noreturn jerry_unimplemented (const char *comment, /**< comment to unimplemented mark if exists, NULL - otherwise */ const char *file, /**< file name */ + const char *function, /**< function name */ const uint32_t line) /**< line */ { - __printf ("Unimplemented case at %s:%u was executed", file, line); + __printf ("SORRY: Unimplemented case at %s(%s):%u was executed", file, function, line); if (comment != NULL) { __printf ("(%s)", comment); diff --git a/src/libruntime/target/stm32f4/jerry-assert.c b/src/libruntime/target/stm32f4/jerry-assert.c index 3f260de93..a986cda97 100644 --- a/src/libruntime/target/stm32f4/jerry-assert.c +++ b/src/libruntime/target/stm32f4/jerry-assert.c @@ -22,6 +22,7 @@ void __noreturn jerry_assert_fail (const char *assertion __unused, /**< assertion condition string */ const char *file __unused, /**< file name */ + const char *function __unused, /**< function name */ const uint32_t line __unused) /** line */ { __exit (-ERR_FAILED_INTERNAL_ASSERTION); @@ -34,6 +35,7 @@ void __noreturn jerry_unreachable (const char *comment __unused, /**< comment to unreachable mark if exists, NULL - otherwise */ const char *file __unused, /**< file name */ + const char *function __unused, /**< function name */ const uint32_t line __unused) /**< line */ { __exit (-ERR_FAILED_INTERNAL_ASSERTION); @@ -46,6 +48,7 @@ void __noreturn jerry_unimplemented (const char *comment __unused, /**< comment to unimplemented mark if exists, NULL - otherwise */ const char *file __unused, /**< file name */ + const char *function __unused, /**< function name */ const uint32_t line __unused) /**< line */ { __exit (-ERR_UNIMPLEMENTED_CASE);