From: Igor Sysoev Date: Wed, 13 Jul 2016 10:56:12 +0000 (+0300) Subject: Syntax error messages are more verbose and have line number. X-Git-Tag: 0.1.0~12 X-Git-Url: http://www.kaiwu.me/postgresql/commit/?a=commitdiff_plain;h=c36f80df6887227d07da01f85b6613a814172553;p=njs.git Syntax error messages are more verbose and have line number. --- diff --git a/njs/njs_builtin.c b/njs/njs_builtin.c index c53a0047..a40a7f86 100644 --- a/njs/njs_builtin.c +++ b/njs/njs_builtin.c @@ -19,6 +19,8 @@ #include #include #include +#include +#include #include #include #include diff --git a/njs/njs_generator.c b/njs/njs_generator.c index eb18e45b..a06dd512 100644 --- a/njs/njs_generator.c +++ b/njs/njs_generator.c @@ -20,6 +20,13 @@ #include #include #include +#include + + +typedef enum { + NJS_GENERATOR_ERROR_ILLEGAL_CONTINUE = 0, + NJS_GENERATOR_ERROR_ILLEGAL_BREAK, +} njs_generator_error_t; static nxt_int_t njs_generator(njs_vm_t *vm, njs_parser_t *parser, @@ -117,6 +124,8 @@ static nxt_noinline nxt_int_t njs_generator_node_index_release(njs_vm_t *vm, static nxt_noinline nxt_int_t njs_generator_index_release(njs_vm_t *vm, njs_parser_t *parser, njs_index_t index); nxt_inline nxt_bool_t njs_generator_is_constant(njs_parser_node_t *node); +static nxt_int_t njs_generator_error(njs_vm_t *vm, njs_parser_node_t *node, + njs_generator_error_t err); static const nxt_str_t no_label = { 0, NULL }; @@ -1067,18 +1076,19 @@ njs_generate_continue_statement(njs_vm_t *vm, njs_parser_t *parser, { njs_vmcode_jump_t *jump; njs_parser_patch_t *patch; + njs_parser_block_t *block; - if (parser->block == NULL) { - vm->exception = &njs_exception_syntax_error; - return NXT_ERROR; + for (block = parser->block; block != NULL; block = block->next) { + if (block->type == NJS_PARSER_LOOP) { + goto found; + } } - /* TODO: LABEL */ + return njs_generator_error(vm, node, NJS_GENERATOR_ERROR_ILLEGAL_CONTINUE); - if (parser->block->type != NJS_PARSER_LOOP) { - vm->exception = &njs_exception_syntax_error; - return NXT_ERROR; - } +found: + + /* TODO: LABEL */ patch = nxt_mem_cache_alloc(vm->mem_cache_pool, sizeof(njs_parser_patch_t)); @@ -1105,12 +1115,20 @@ njs_generate_break_statement(njs_vm_t *vm, njs_parser_t *parser, { njs_vmcode_jump_t *jump; njs_parser_patch_t *patch; + njs_parser_block_t *block; - if (parser->block == NULL) { - vm->exception = &njs_exception_syntax_error; - return NXT_ERROR; + for (block = parser->block; block != NULL; block = block->next) { + if (block->type == NJS_PARSER_LOOP + || block->type == NJS_PARSER_SWITCH) + { + goto found; + } } + return njs_generator_error(vm, node, NJS_GENERATOR_ERROR_ILLEGAL_BREAK); + +found: + /* TODO: LABEL: loop and switch may have label, block must have label. */ patch = nxt_mem_cache_alloc(vm->mem_cache_pool, sizeof(njs_parser_patch_t)); @@ -2466,3 +2484,25 @@ njs_generator_is_constant(njs_parser_node_t *node) return (node->token >= NJS_TOKEN_FIRST_CONST && node->token <= NJS_TOKEN_LAST_CONST); } + + +static nxt_int_t +njs_generator_error(njs_vm_t *vm, njs_parser_node_t *node, + njs_generator_error_t err) +{ + uint32_t size; + const char *msg; + u_char buf[NJS_EXCEPTION_BUF_LENGTH]; + + static const char *errors[] = { + "SyntaxError: Illegal continue statement in %u", + "SyntaxError: Illegal break statement in %u", + }; + + msg = errors[err]; + + size = snprintf((char *) buf, NJS_EXCEPTION_BUF_LENGTH, + msg, node->token_line); + + return njs_vm_throw_exception(vm, buf, size); +} diff --git a/njs/njs_lexer.c b/njs/njs_lexer.c index 211086e5..94a0c914 100644 --- a/njs/njs_lexer.c +++ b/njs/njs_lexer.c @@ -47,7 +47,7 @@ static const uint8_t njs_tokens[256] nxt_aligned(64) = { NJS_TOKEN_ILLEGAL, NJS_TOKEN_ILLEGAL, /* \t */ NJS_TOKEN_ILLEGAL, NJS_TOKEN_SPACE, /* \n */ NJS_TOKEN_LINE_END, NJS_TOKEN_ILLEGAL, - /* \r */ NJS_TOKEN_ILLEGAL, NJS_TOKEN_LINE_END, + /* \r */ NJS_TOKEN_ILLEGAL, NJS_TOKEN_SPACE, NJS_TOKEN_ILLEGAL, NJS_TOKEN_ILLEGAL, /* 0x10 */ NJS_TOKEN_ILLEGAL, NJS_TOKEN_ILLEGAL, @@ -300,6 +300,8 @@ njs_lexer_next_token(njs_lexer_t *lexer) njs_token_t token; const njs_lexer_multi_t *multi; + lexer->text.data = lexer->start; + while (lexer->start < lexer->end) { c = *lexer->start++; @@ -308,6 +310,7 @@ njs_lexer_next_token(njs_lexer_t *lexer) switch (token) { case NJS_TOKEN_SPACE: + lexer->text.data = lexer->start; continue; case NJS_TOKEN_LETTER: @@ -396,6 +399,10 @@ njs_lexer_next_token(njs_lexer_t *lexer) goto multi; case NJS_TOKEN_LINE_END: + lexer->line++; + + /* Fall through. */ + case NJS_TOKEN_BITWISE_NOT: case NJS_TOKEN_OPEN_PARENTHESIS: case NJS_TOKEN_CLOSE_PARENTHESIS: @@ -408,6 +415,7 @@ njs_lexer_next_token(njs_lexer_t *lexer) case NJS_TOKEN_COLON: case NJS_TOKEN_SEMICOLON: case NJS_TOKEN_CONDITIONAL: + lexer->text.len = lexer->start - lexer->text.data; return token; default: /* NJS_TOKEN_ILLEGAL */ @@ -449,6 +457,7 @@ njs_lexer_word(njs_lexer_t *lexer, u_char c) 0x00, 0x00, 0x00, 0x00, /* 0000 0000 0000 0000 0000 0000 0000 0000 */ }; + lexer->token_line = lexer->line; lexer->key_hash = nxt_djb_hash_add(NXT_DJB_HASH_INIT, c); lexer->text.data = lexer->start - 1; @@ -489,7 +498,7 @@ njs_lexer_string(njs_lexer_t *lexer, u_char quote) if (c == '\\') { if (p == lexer->end) { - return NJS_TOKEN_ILLEGAL; + break; } p++; @@ -510,7 +519,10 @@ njs_lexer_string(njs_lexer_t *lexer, u_char quote) } } - return NJS_TOKEN_ILLEGAL; + lexer->text.data--; + lexer->text.len = p - lexer->text.data; + + return NJS_TOKEN_UNTERMINATED_STRING; } @@ -590,7 +602,8 @@ njs_lexer_multi(njs_lexer_t *lexer, njs_token_t token, nxt_uint_t n, lexer->start++; if (multi->count == 0) { - return multi->token; + token = multi->token; + break; } return njs_lexer_multi(lexer, multi->token, multi->count, @@ -603,6 +616,8 @@ njs_lexer_multi(njs_lexer_t *lexer, njs_token_t token, nxt_uint_t n, } while (n != 0); } + lexer->text.len = lexer->start - lexer->text.data; + return token; } diff --git a/njs/njs_nonrecursive_parser.c b/njs/njs_nonrecursive_parser.c index b92c0ba4..7e91fa3d 100644 --- a/njs/njs_nonrecursive_parser.c +++ b/njs/njs_nonrecursive_parser.c @@ -16,9 +16,9 @@ #include #include #include -#include #include #include +#include #include diff --git a/njs/njs_parser.c b/njs/njs_parser.c index cadfc3ce..dce0ef5d 100644 --- a/njs/njs_parser.c +++ b/njs/njs_parser.c @@ -18,10 +18,11 @@ #include #include #include -#include #include #include +#include #include +#include /* @@ -52,18 +53,22 @@ static njs_token_t njs_parser_var_statement(njs_vm_t *vm, njs_parser_t *parser); static njs_token_t njs_parser_if_statement(njs_vm_t *vm, njs_parser_t *parser); static njs_token_t njs_parser_switch_statement(njs_vm_t *vm, njs_parser_t *parser); +static njs_token_t njs_parser_duplicate_default_branch(njs_vm_t *vm, + njs_parser_t *parser); static njs_token_t njs_parser_while_statement(njs_vm_t *vm, njs_parser_t *parser); static njs_token_t njs_parser_do_while_statement(njs_vm_t *vm, njs_parser_t *parser); static njs_token_t njs_parser_for_statement(njs_vm_t *vm, njs_parser_t *parser); static njs_token_t njs_parser_for_in_statement(njs_vm_t *vm, - njs_parser_t *parser, njs_token_t token); + njs_parser_t *parser, nxt_str_t *name, njs_token_t token); static njs_token_t njs_parser_continue_statement(njs_vm_t *vm, njs_parser_t *parser); static njs_token_t njs_parser_break_statement(njs_vm_t *vm, njs_parser_t *parser); static njs_token_t njs_parser_try_statement(njs_vm_t *vm, njs_parser_t *parser); +static njs_token_t njs_parser_missing_catch_or_finally(njs_vm_t *vm, + njs_parser_t *parser); static njs_token_t njs_parser_try_block(njs_vm_t *vm, njs_parser_t *parser); static njs_token_t njs_parser_throw_statement(njs_vm_t *vm, njs_parser_t *parser); @@ -78,7 +83,9 @@ static njs_token_t njs_parser_object(njs_vm_t *vm, njs_parser_t *parser, static njs_token_t njs_parser_array(njs_vm_t *vm, njs_parser_t *parser, njs_parser_node_t *obj); static njs_token_t njs_parser_escape_string_create(njs_vm_t *vm, - njs_value_t *value); + njs_parser_t *parser, njs_value_t *value); +static njs_token_t njs_parser_unexpected_token(njs_vm_t *vm, + njs_parser_t *parser, njs_token_t token); njs_parser_node_t * @@ -154,7 +161,7 @@ njs_parser_statement_chain(njs_vm_t *vm, njs_parser_t *parser, } } else if (vm->exception == NULL) { - vm->exception = &njs_exception_syntax_error; + (void) njs_parser_unexpected_token(vm, parser, token); } return token; @@ -269,14 +276,14 @@ njs_parser_block(njs_vm_t *vm, njs_parser_t *parser) nxt_inline njs_token_t -njs_parser_match(njs_parser_t *parser, njs_token_t token, +njs_parser_match(njs_vm_t *vm, njs_parser_t *parser, njs_token_t token, njs_token_t match) { if (nxt_fast_path(token == match)) { return njs_parser_token(parser); } - return NJS_TOKEN_ILLEGAL; + return njs_parser_unexpected_token(vm, parser, token); } @@ -303,7 +310,7 @@ njs_parser_function_declaration(njs_vm_t *vm, njs_parser_t *parser) } if (token != NJS_TOKEN_NAME) { - return NJS_TOKEN_ERROR; + return NJS_TOKEN_ILLEGAL; } var = njs_parser_variable(vm, parser, &level); @@ -463,7 +470,7 @@ njs_parser_function_lambda(njs_vm_t *vm, njs_function_lambda_t *lambda, parser = lambda->u.parser; - token = njs_parser_match(parser, token, NJS_TOKEN_OPEN_PARENTHESIS); + token = njs_parser_match(vm, parser, token, NJS_TOKEN_OPEN_PARENTHESIS); if (nxt_slow_path(token <= NJS_TOKEN_ILLEGAL)) { return token; } @@ -640,12 +647,9 @@ njs_parser_var_statement(njs_vm_t *vm, njs_parser_t *parser) } if (token != NJS_TOKEN_NAME) { - /* TODO: message. */ return NJS_TOKEN_ILLEGAL; } - nxt_thread_log_debug("JS: %V", &parser->lexer->text); - var = njs_parser_variable(vm, parser, &level); if (nxt_slow_path(var == NULL)) { return NJS_TOKEN_ERROR; @@ -802,7 +806,7 @@ njs_parser_switch_statement(njs_vm_t *vm, njs_parser_t *parser) swtch->left = parser->node; last = &swtch->right; - token = njs_parser_match(parser, token, NJS_TOKEN_OPEN_BRACE); + token = njs_parser_match(vm, parser, token, NJS_TOKEN_OPEN_BRACE); if (nxt_slow_path(token <= NJS_TOKEN_ILLEGAL)) { return token; } @@ -841,8 +845,7 @@ njs_parser_switch_statement(njs_vm_t *vm, njs_parser_t *parser) } else { if (dflt != NULL) { - /* A duplicate "default" branch. */ - return NJS_TOKEN_ILLEGAL; + return njs_parser_duplicate_default_branch(vm, parser); } branch = node; @@ -858,7 +861,7 @@ njs_parser_switch_statement(njs_vm_t *vm, njs_parser_t *parser) *last = branch; last = &branch->left; - token = njs_parser_match(parser, token, NJS_TOKEN_COLON); + token = njs_parser_match(vm, parser, token, NJS_TOKEN_COLON); if (nxt_slow_path(token <= NJS_TOKEN_ILLEGAL)) { return token; } @@ -887,6 +890,22 @@ njs_parser_switch_statement(njs_vm_t *vm, njs_parser_t *parser) } +static njs_token_t +njs_parser_duplicate_default_branch(njs_vm_t *vm, njs_parser_t *parser) +{ + uint32_t size; + u_char buf[NJS_EXCEPTION_BUF_LENGTH]; + + size = snprintf((char *) buf, NJS_EXCEPTION_BUF_LENGTH, + "SyntaxError: More than one default clause " + "in switch statement in %u", parser->lexer->line); + + (void) njs_vm_throw_exception(vm, buf, size); + + return NJS_TOKEN_ILLEGAL; +} + + static njs_token_t njs_parser_while_statement(njs_vm_t *vm, njs_parser_t *parser) { @@ -954,7 +973,7 @@ njs_parser_do_while_statement(njs_vm_t *vm, njs_parser_t *parser) node = njs_parser_node_alloc(vm); if (nxt_slow_path(node == NULL)) { - return NJS_TOKEN_ILLEGAL; + return NJS_TOKEN_ERROR; } node->token = NJS_TOKEN_DO; @@ -970,6 +989,7 @@ njs_parser_do_while_statement(njs_vm_t *vm, njs_parser_t *parser) static njs_token_t njs_parser_for_statement(njs_vm_t *vm, njs_parser_t *parser) { + nxt_str_t name; njs_token_t token; njs_parser_node_t *node, *init, *condition, *update, *cond, *body; @@ -984,12 +1004,13 @@ njs_parser_for_statement(njs_vm_t *vm, njs_parser_t *parser) return token; } - token = njs_parser_match(parser, token, NJS_TOKEN_OPEN_PARENTHESIS); + token = njs_parser_match(vm, parser, token, NJS_TOKEN_OPEN_PARENTHESIS); if (nxt_slow_path(token <= NJS_TOKEN_ILLEGAL)) { return token; } if (token != NJS_TOKEN_SEMICOLON) { + name = parser->lexer->text; token = njs_parser_expression(vm, parser, token); if (nxt_slow_path(token <= NJS_TOKEN_ILLEGAL)) { @@ -999,11 +1020,11 @@ njs_parser_for_statement(njs_vm_t *vm, njs_parser_t *parser) init = parser->node; if (init->token == NJS_TOKEN_IN) { - return njs_parser_for_in_statement(vm, parser, token); + return njs_parser_for_in_statement(vm, parser, &name, token); } } - token = njs_parser_match(parser, token, NJS_TOKEN_SEMICOLON); + token = njs_parser_match(vm, parser, token, NJS_TOKEN_SEMICOLON); if (nxt_slow_path(token <= NJS_TOKEN_ILLEGAL)) { return token; } @@ -1018,7 +1039,7 @@ njs_parser_for_statement(njs_vm_t *vm, njs_parser_t *parser) condition = parser->node; } - token = njs_parser_match(parser, token, NJS_TOKEN_SEMICOLON); + token = njs_parser_match(vm, parser, token, NJS_TOKEN_SEMICOLON); if (nxt_slow_path(token <= NJS_TOKEN_ILLEGAL)) { return token; } @@ -1033,7 +1054,7 @@ njs_parser_for_statement(njs_vm_t *vm, njs_parser_t *parser) update = parser->node; } - token = njs_parser_match(parser, token, NJS_TOKEN_CLOSE_PARENTHESIS); + token = njs_parser_match(vm, parser, token, NJS_TOKEN_CLOSE_PARENTHESIS); if (nxt_slow_path(token <= NJS_TOKEN_ILLEGAL)) { return token; } @@ -1076,14 +1097,23 @@ njs_parser_for_statement(njs_vm_t *vm, njs_parser_t *parser) static njs_token_t -njs_parser_for_in_statement(njs_vm_t *vm, njs_parser_t *parser, +njs_parser_for_in_statement(njs_vm_t *vm, njs_parser_t *parser, nxt_str_t *name, njs_token_t token) { + uint32_t size; njs_parser_node_t *node; + u_char buf[NJS_EXCEPTION_BUF_LENGTH]; node = parser->node->left; if (node->token != NJS_TOKEN_NAME) { + size = snprintf((char *) buf, NJS_EXCEPTION_BUF_LENGTH, + "ReferenceError: Invalid left-hand side \"%.*s\" " + "in for-in statement in %u", + (int) name->len, name->data, parser->lexer->line); + + (void) njs_vm_throw_exception(vm, buf, size); + return NJS_TOKEN_ILLEGAL; } @@ -1097,7 +1127,7 @@ njs_parser_for_in_statement(njs_vm_t *vm, njs_parser_t *parser, node->token = NJS_TOKEN_FOR_IN; node->left = parser->node; - token = njs_parser_match(parser, token, NJS_TOKEN_CLOSE_PARENTHESIS); + token = njs_parser_match(vm, parser, token, NJS_TOKEN_CLOSE_PARENTHESIS); if (nxt_slow_path(token <= NJS_TOKEN_ILLEGAL)) { return token; } @@ -1127,6 +1157,7 @@ njs_parser_continue_statement(njs_vm_t *vm, njs_parser_t *parser) } node->token = NJS_TOKEN_CONTINUE; + node->token_line = parser->lexer->token_line; parser->node = node; parser->code_size += sizeof(njs_vmcode_jump_t); @@ -1161,6 +1192,7 @@ njs_parser_break_statement(njs_vm_t *vm, njs_parser_t *parser) } node->token = NJS_TOKEN_BREAK; + node->token_line = parser->lexer->token_line; parser->node = node; parser->code_size += sizeof(njs_vmcode_jump_t); @@ -1214,7 +1246,7 @@ njs_parser_try_statement(njs_vm_t *vm, njs_parser_t *parser) return token; } - token = njs_parser_match(parser, token, NJS_TOKEN_OPEN_PARENTHESIS); + token = njs_parser_match(vm, parser, token, NJS_TOKEN_OPEN_PARENTHESIS); if (nxt_slow_path(token <= NJS_TOKEN_ILLEGAL)) { return token; } @@ -1223,8 +1255,6 @@ njs_parser_try_statement(njs_vm_t *vm, njs_parser_t *parser) return NJS_TOKEN_ILLEGAL; } - nxt_thread_log_debug("CATCH: %V", &parser->lexer->text); - catch = njs_parser_node_alloc(vm); if (nxt_slow_path(catch == NULL)) { return NJS_TOKEN_ERROR; @@ -1297,8 +1327,7 @@ njs_parser_try_statement(njs_vm_t *vm, njs_parser_t *parser) } if (try->right == NULL) { - /* TODO: message */ - return NJS_TOKEN_ILLEGAL; + return njs_parser_missing_catch_or_finally(vm, parser); } parser->node = try; @@ -1308,6 +1337,22 @@ njs_parser_try_statement(njs_vm_t *vm, njs_parser_t *parser) } +static njs_token_t +njs_parser_missing_catch_or_finally(njs_vm_t *vm, njs_parser_t *parser) +{ + uint32_t size; + u_char buf[NJS_EXCEPTION_BUF_LENGTH]; + + size = snprintf((char *) buf, NJS_EXCEPTION_BUF_LENGTH, + "SyntaxError: Missing catch or finally after try in %u", + parser->lexer->line); + + (void) njs_vm_throw_exception(vm, buf, size); + + return NJS_TOKEN_ILLEGAL; +} + + static njs_token_t njs_parser_try_block(njs_vm_t *vm, njs_parser_t *parser) { @@ -1366,7 +1411,7 @@ njs_parser_grouping_expression(njs_vm_t *vm, njs_parser_t *parser) return token; } - token = njs_parser_match(parser, token, NJS_TOKEN_OPEN_PARENTHESIS); + token = njs_parser_match(vm, parser, token, NJS_TOKEN_OPEN_PARENTHESIS); if (nxt_slow_path(token <= NJS_TOKEN_ILLEGAL)) { return token; } @@ -1376,7 +1421,7 @@ njs_parser_grouping_expression(njs_vm_t *vm, njs_parser_t *parser) return token; } - return njs_parser_match(parser, token, NJS_TOKEN_CLOSE_PARENTHESIS); + return njs_parser_match(vm, parser, token, NJS_TOKEN_CLOSE_PARENTHESIS); } @@ -1435,7 +1480,7 @@ njs_parser_terminal(njs_vm_t *vm, njs_parser_t *parser, njs_token_t token) return token; } - return njs_parser_match(parser, token, NJS_TOKEN_CLOSE_PARENTHESIS); + return njs_parser_match(vm, parser, token, NJS_TOKEN_CLOSE_PARENTHESIS); } if (token == NJS_TOKEN_FUNCTION) { @@ -1534,9 +1579,9 @@ njs_parser_terminal(njs_vm_t *vm, njs_parser_t *parser, njs_token_t token) return token; case NJS_TOKEN_DIVISION: - ret = njs_regexp_literal(vm, parser, &node->u.value); - if (nxt_slow_path(ret != NXT_OK)) { - return NJS_TOKEN_ILLEGAL; + token = njs_regexp_literal(vm, parser, &node->u.value); + if (nxt_slow_path(token <= NJS_TOKEN_ILLEGAL)) { + return token; } nxt_thread_log_debug("REGEX: '%V'", &parser->lexer->text); @@ -1561,13 +1606,17 @@ njs_parser_terminal(njs_vm_t *vm, njs_parser_t *parser, njs_token_t token) nxt_thread_log_debug("JS: '%V'", &parser->lexer->text); - ret = njs_parser_escape_string_create(vm, &node->u.value); + ret = njs_parser_escape_string_create(vm, parser, &node->u.value); if (nxt_slow_path(ret != NJS_TOKEN_STRING)) { return ret; } break; + case NJS_TOKEN_UNTERMINATED_STRING: + return njs_parser_error(vm, parser, + NJS_PARSER_ERROR_UNTERMINATED_STRING); + case NJS_TOKEN_NUMBER: nxt_thread_log_debug("JS: %f", parser->lexer->number); @@ -1652,8 +1701,7 @@ njs_parser_terminal(njs_vm_t *vm, njs_parser_t *parser, njs_token_t token) return njs_parser_builtin_function(vm, parser, node); default: - vm->exception = &njs_exception_syntax_error; - return NJS_TOKEN_ILLEGAL; + return njs_parser_unexpected_token(vm, parser, token); } parser->node = node; @@ -1769,7 +1817,7 @@ njs_parser_object(njs_vm_t *vm, njs_parser_t *parser, njs_parser_node_t *obj) return token; } - token = njs_parser_match(parser, token, NJS_TOKEN_COLON); + token = njs_parser_match(vm, parser, token, NJS_TOKEN_COLON); if (nxt_slow_path(token <= NJS_TOKEN_ILLEGAL)) { return token; } @@ -1944,7 +1992,8 @@ njs_parser_string_create(njs_vm_t *vm, njs_value_t *value) static njs_token_t -njs_parser_escape_string_create(njs_vm_t *vm, njs_value_t *value) +njs_parser_escape_string_create(njs_vm_t *vm, njs_parser_t *parser, + njs_value_t *value) { u_char c, *p, *start, *dst, *src, *end, *hex_end; size_t size, length, hex_length, skip; @@ -1962,8 +2011,8 @@ njs_parser_escape_string_create(njs_vm_t *vm, njs_value_t *value) size = 0; length = 0; - src = vm->parser->lexer->text.data; - end = src + vm->parser->lexer->text.len; + src = parser->lexer->text.data; + end = src + parser->lexer->text.len; while (src < end) { c = *src++; @@ -1995,7 +2044,8 @@ njs_parser_escape_string_create(njs_vm_t *vm, njs_value_t *value) } if (hex_length == 0 || hex_length > 6) { - return NJS_TOKEN_ILLEGAL; + return njs_parser_error(vm, parser, + NJS_PARSER_ERROR_UNICODE); } skip = 1; @@ -2070,12 +2120,12 @@ njs_parser_escape_string_create(njs_vm_t *vm, njs_value_t *value) hex_end = src + hex_length; if (hex_end > end) { - return NJS_TOKEN_ILLEGAL; + return njs_parser_error(vm, parser, NJS_PARSER_ERROR_UNICODE); } u = njs_number_radix_parse(src, hex_end, 16, 1); if (nxt_slow_path(u < 0)) { - return NJS_TOKEN_ILLEGAL; + return njs_parser_error(vm, parser, NJS_PARSER_ERROR_UNICODE); } src = hex_end + skip; @@ -2154,3 +2204,52 @@ njs_parser_has_side_effect(njs_parser_node_t *node) return side_effect; } + + +static njs_token_t +njs_parser_unexpected_token(njs_vm_t *vm, njs_parser_t *parser, + njs_token_t token) +{ + uint32_t size; + u_char buf[NJS_EXCEPTION_BUF_LENGTH]; + + if (token != NJS_TOKEN_END) { + return njs_parser_error(vm, parser, NJS_PARSER_ERROR_UNEXPECTED_TOKEN); + } + + size = snprintf((char *) buf, NJS_EXCEPTION_BUF_LENGTH, + "SyntaxError: Unexpected end of input in %u", + parser->lexer->line); + + (void) njs_vm_throw_exception(vm, buf, size); + + return NJS_TOKEN_ILLEGAL; +} + + +njs_token_t +njs_parser_error(njs_vm_t *vm, njs_parser_t *parser, njs_parser_error_t err) +{ + uint32_t size; + njs_lexer_t *lexer; + const char *msg; + u_char buf[NJS_EXCEPTION_BUF_LENGTH]; + + static const char *errors[] = { + "SyntaxError: Unexpected token \"%.*s\" in %u", + "SyntaxError: Unterminated string \"%.*s\" in %u", + "SyntaxError: Invalid Unicode code point \"%.*s\" in %u", + "SyntaxError: Unterminated RegExp \"%.*s\" in %u", + "SyntaxError: Invalid RegExp flags \"%.*s\" in %u", + }; + + msg = errors[err]; + lexer = parser->lexer; + + size = snprintf((char *) buf, NJS_EXCEPTION_BUF_LENGTH, + msg, (int) lexer->text.len, lexer->text.data, lexer->line); + + (void) njs_vm_throw_exception(vm, buf, size); + + return NJS_TOKEN_ILLEGAL; +} diff --git a/njs/njs_parser.h b/njs/njs_parser.h index f8d4ca98..a40b4ae4 100644 --- a/njs/njs_parser.h +++ b/njs/njs_parser.h @@ -117,6 +117,7 @@ typedef enum { #define NJS_TOKEN_LAST_CONST NJS_TOKEN_STRING NJS_TOKEN_ESCAPE_STRING, + NJS_TOKEN_UNTERMINATED_STRING, NJS_TOKEN_NAME, NJS_TOKEN_OBJECT, @@ -191,6 +192,9 @@ typedef struct { uint8_t property; /* 1 bit */ uint32_t key_hash; + uint32_t token_line; + uint32_t line; + nxt_str_t text; double number; @@ -224,6 +228,7 @@ struct njs_parser_node_s { njs_lvalue_state_t lvalue:2; /* 2 bits */ uint8_t ctor:1; /* 1 bit */ uint8_t temporary; /* 1 bit */ + uint32_t token_line; union { uint32_t length; @@ -313,6 +318,15 @@ struct njs_parser_s { }; +typedef enum { + NJS_PARSER_ERROR_UNEXPECTED_TOKEN = 0, + NJS_PARSER_ERROR_UNTERMINATED_STRING, + NJS_PARSER_ERROR_UNICODE, + NJS_PARSER_ERROR_UNTERMINATED_REGEXP, + NJS_PARSER_ERROR_REGEXP_FLAGS, +} njs_parser_error_t; + + njs_token_t njs_lexer_token(njs_lexer_t *lexer); nxt_int_t njs_lexer_keywords_init(nxt_mem_cache_pool_t *mcp, nxt_lvlhsh_t *hash); @@ -339,6 +353,8 @@ njs_token_t njs_parser_token(njs_parser_t *parser); nxt_int_t njs_parser_string_create(njs_vm_t *vm, njs_value_t *value); njs_index_t njs_parser_index(njs_parser_t *parser, uint32_t scope); nxt_bool_t njs_parser_has_side_effect(njs_parser_node_t *node); +njs_token_t njs_parser_error(njs_vm_t *vm, njs_parser_t *parser, + njs_parser_error_t err); nxt_int_t njs_generate_scope(njs_vm_t *vm, njs_parser_t *parser, njs_parser_node_t *node); diff --git a/njs/njs_parser_expression.c b/njs/njs_parser_expression.c index c3536c2d..c6e02ecd 100644 --- a/njs/njs_parser_expression.c +++ b/njs/njs_parser_expression.c @@ -9,6 +9,7 @@ #include #include #include +#include #include #include #include @@ -16,11 +17,13 @@ #include #include #include +#include #include #include #include #include #include +#include typedef struct { @@ -71,6 +74,8 @@ static njs_token_t njs_parser_property_expression(njs_vm_t *vm, njs_parser_t *parser, njs_token_t token); static njs_token_t njs_parser_property_brackets(njs_vm_t *vm, njs_parser_t *parser, njs_token_t token); +static njs_token_t njs_parser_invalid_lvalue(njs_vm_t *vm, + njs_parser_t *parser, const char* operation); static const njs_parser_expression_t @@ -288,8 +293,7 @@ njs_parser_var_expression(njs_vm_t *vm, njs_parser_t *parser, njs_token_t token) node = parser->node; if (node->lvalue == NJS_LVALUE_NONE) { - nxt_thread_log_error(NXT_LOG_ALERT, "lvalue required"); - return NJS_TOKEN_ILLEGAL; + return njs_parser_invalid_lvalue(vm, parser, "assignment"); } pending = NULL; @@ -434,8 +438,7 @@ njs_parser_assignment_expression(njs_vm_t *vm, njs_parser_t *parser, node = parser->node; if (node->lvalue == NJS_LVALUE_NONE) { - nxt_thread_log_error(NXT_LOG_ALERT, "lvalue required"); - return NJS_TOKEN_ILLEGAL; + return njs_parser_invalid_lvalue(vm, parser, "assignment"); } pending = NULL; @@ -807,8 +810,7 @@ njs_parser_inc_dec_expression(njs_vm_t *vm, njs_parser_t *parser, } if (parser->node->lvalue == NJS_LVALUE_NONE) { - nxt_thread_log_error(NXT_LOG_ALERT, "lvalue required"); - return NJS_TOKEN_ILLEGAL; + return njs_parser_invalid_lvalue(vm, parser, "prefix operation"); } node = njs_parser_node_alloc(vm); @@ -860,8 +862,7 @@ njs_parser_post_inc_dec_expression(njs_vm_t *vm, njs_parser_t *parser, } if (parser->node->lvalue == NJS_LVALUE_NONE) { - nxt_thread_log_error(NXT_LOG_ALERT, "lvalue required"); - return NJS_TOKEN_ILLEGAL; + return njs_parser_invalid_lvalue(vm, parser, "postfix operation"); } node = njs_parser_node_alloc(vm); @@ -1142,3 +1143,21 @@ njs_parser_arguments(njs_vm_t *vm, njs_parser_t *parser, return token; } + + +static njs_token_t +njs_parser_invalid_lvalue(njs_vm_t *vm, njs_parser_t *parser, + const char *operation) +{ + uint32_t size; + u_char buf[NJS_EXCEPTION_BUF_LENGTH]; + + size = snprintf((char *) buf, NJS_EXCEPTION_BUF_LENGTH, + "ReferenceError: Invalid left-hand side in %s in %u", + operation, parser->lexer->line); + + (void) njs_vm_throw_exception(vm, buf, size); + + return NJS_TOKEN_ILLEGAL; + +} diff --git a/njs/njs_regexp.c b/njs/njs_regexp.c index 61452437..5c9f19d0 100644 --- a/njs/njs_regexp.c +++ b/njs/njs_regexp.c @@ -24,11 +24,12 @@ #include #include #include -#include -#include #include #include +#include +#include #include +#include static void *njs_regexp_malloc(size_t size, void *memory_data); @@ -133,7 +134,7 @@ njs_regexp_constructor(njs_vm_t *vm, njs_value_t *args, nxt_uint_t nargs, } -nxt_int_t +njs_token_t njs_regexp_literal(njs_vm_t *vm, njs_parser_t *parser, njs_value_t *value) { u_char *p; @@ -154,11 +155,15 @@ njs_regexp_literal(njs_vm_t *vm, njs_parser_t *parser, njs_value_t *value) lexer->text.data = lexer->start; lexer->text.len = p - lexer->text.data; p++; + lexer->start = p; flags = njs_regexp_flags(&p, lexer->end, 0); if (nxt_slow_path(flags < 0)) { - return NXT_ERROR; + lexer->text.data = lexer->start; + lexer->text.len = p - lexer->text.data; + return njs_parser_error(vm, parser, + NJS_PARSER_ERROR_REGEXP_FLAGS); } lexer->start = p; @@ -166,16 +171,19 @@ njs_regexp_literal(njs_vm_t *vm, njs_parser_t *parser, njs_value_t *value) pattern = njs_regexp_pattern_create(vm, lexer->text.data, lexer->text.len, flags); if (nxt_slow_path(pattern == NULL)) { - return NXT_ERROR; + return NJS_TOKEN_ILLEGAL; } value->data.u.data = pattern; - return NXT_OK; + return NJS_TOKEN_REGEXP; } } - return NXT_ERROR; + lexer->text.data = lexer->start - 1; + lexer->text.len = p - lexer->text.data; + + return njs_parser_error(vm, parser, NJS_PARSER_ERROR_UNTERMINATED_REGEXP); } @@ -203,16 +211,28 @@ njs_regexp_flags(u_char **start, u_char *end, nxt_bool_t bound) flag = NJS_REGEXP_MULTILINE; break; - default: - if (bound) { - return NJS_REGEXP_INVALID_FLAG; + case ';': + case ' ': + case '\t': + case '\r': + case '\n': + case ',': + case ')': + case ']': + case '}': + case '.': + if (!bound) { + goto done; } - goto done; + /* Fall through. */ + + default: + goto invalid; } if (nxt_slow_path((flags & flag) != 0)) { - return NJS_REGEXP_INVALID_FLAG; + goto invalid; } flags |= flag; @@ -223,6 +243,12 @@ done: *start = p; return flags; + +invalid: + + *start = p + 1; + + return NJS_REGEXP_INVALID_FLAG; } @@ -298,10 +324,7 @@ njs_regexp_pattern_create(njs_vm_t *vm, u_char *start, size_t length, if (nxt_fast_path(ret >= 0)) { if (nxt_slow_path((u_int) ret != pattern->ncaptures)) { - nxt_thread_log_error(NXT_LOG_ERR, "numbers of captures in byte " - "and UTF-8 versions of RegExp \"%s\" vary: %d vs %d", - &pattern->source[1], pattern->ncaptures, ret); - + vm->exception = &njs_exception_internal_error; nxt_mem_cache_free(vm->mem_cache_pool, pattern); return NULL; } @@ -321,7 +344,9 @@ static int njs_regexp_pattern_compile(njs_vm_t *vm, nxt_regex_t *regex, u_char *source, int options) { + uint32_t size; nxt_int_t ret; + u_char buf[NJS_EXCEPTION_BUF_LENGTH]; /* Zero length means a zero-terminated string. */ ret = nxt_regex_compile(regex, source, 0, options, vm->regex_context); @@ -330,7 +355,17 @@ njs_regexp_pattern_compile(njs_vm_t *vm, nxt_regex_t *regex, u_char *source, return regex->ncaptures; } - return njs_string_exception(vm, NJS_SYNTAX_ERROR, vm->regex_context->error); + if (vm->parser != NULL) { + size = snprintf((char *) buf, NJS_EXCEPTION_BUF_LENGTH, + "SyntaxError: %s in %u", + vm->regex_context->error, vm->parser->lexer->line); + + } else { + size = snprintf((char *) buf, NJS_EXCEPTION_BUF_LENGTH, + "SyntaxError: %s", vm->regex_context->error); + } + + return njs_vm_throw_exception(vm, buf, size); } @@ -487,8 +522,7 @@ njs_regexp_prototype_test(njs_vm_t *vm, njs_value_t *args, nxt_uint_t nargs, retval = &njs_value_true; } else if (ret != NGX_REGEX_NOMATCH) { - return njs_string_exception(vm, NJS_INTERNAL_ERROR, - vm->regex_context->error); + return njs_regexp_match_error(vm); } } @@ -564,8 +598,7 @@ njs_regexp_prototype_exec(njs_vm_t *vm, njs_value_t *args, nxt_uint_t nargs, if (nxt_slow_path(ret != NGX_REGEX_NOMATCH)) { nxt_regex_match_data_free(match_data, vm->regex_context); - return njs_string_exception(vm, NJS_INTERNAL_ERROR, - vm->regex_context->error); + return njs_regexp_match_error(vm); } } @@ -699,10 +732,24 @@ njs_regexp_string_create(njs_vm_t *vm, njs_value_t *value, u_char *start, } vm->exception = &njs_exception_internal_error; + return NXT_ERROR; } +njs_ret_t +njs_regexp_match_error(njs_vm_t *vm) +{ + uint32_t size; + u_char buf[NJS_EXCEPTION_BUF_LENGTH]; + + size = snprintf((char *) buf, NJS_EXCEPTION_BUF_LENGTH, + "RegExpError: %s", vm->regex_context->error); + + return njs_vm_throw_exception(vm, buf, size); +} + + static const njs_object_prop_t njs_regexp_constructor_properties[] = { /* RegExp.name == "RegExp". */ diff --git a/njs/njs_regexp.h b/njs/njs_regexp.h index 2743b679..dbafdc97 100644 --- a/njs/njs_regexp.h +++ b/njs/njs_regexp.h @@ -35,13 +35,14 @@ struct njs_regexp_s { njs_ret_t njs_regexp_init(njs_vm_t *vm); njs_ret_t njs_regexp_constructor(njs_vm_t *vm, njs_value_t *args, nxt_uint_t nargs, njs_index_t unused); -nxt_int_t njs_regexp_literal(njs_vm_t *vm, njs_parser_t *parser, +njs_token_t njs_regexp_literal(njs_vm_t *vm, njs_parser_t *parser, njs_value_t *value); njs_regexp_pattern_t *njs_regexp_pattern_create(njs_vm_t *vm, u_char *string, size_t length, njs_regexp_flags_t flags); njs_regexp_t *njs_regexp_alloc(njs_vm_t *vm, njs_regexp_pattern_t *pattern); njs_ret_t njs_regexp_prototype_exec(njs_vm_t *vm, njs_value_t *args, nxt_uint_t nargs, njs_index_t unused); +njs_ret_t njs_regexp_match_error(njs_vm_t *vm); extern const njs_object_init_t njs_regexp_constructor_init; diff --git a/njs/njs_string.c b/njs/njs_string.c index 7fcd26d8..098706e6 100644 --- a/njs/njs_string.c +++ b/njs/njs_string.c @@ -25,11 +25,12 @@ #include #include #include -#include -#include #include #include +#include +#include #include +#include static nxt_noinline void njs_string_slice_prop(njs_string_prop_t *string, @@ -1460,8 +1461,7 @@ njs_string_prototype_search(njs_vm_t *vm, njs_value_t *args, nxt_uint_t nargs, index = njs_string_index(&string, captures[0]); } else if (ret != NGX_REGEX_NOMATCH) { - return njs_string_exception(vm, NJS_INTERNAL_ERROR, - vm->regex_context->error); + return njs_regexp_match_error(vm); } } } @@ -1616,8 +1616,7 @@ njs_string_prototype_match(njs_vm_t *vm, njs_value_t *args, nxt_uint_t nargs, break; } else { - return njs_string_exception(vm, NJS_INTERNAL_ERROR, - vm->regex_context->error); + return njs_regexp_match_error(vm); } } while (string.size > 0); @@ -1769,8 +1768,7 @@ njs_string_prototype_split(njs_vm_t *vm, njs_value_t *args, nxt_uint_t nargs, next = (u_char *) end + 1; } else { - return njs_string_exception(vm, NJS_INTERNAL_ERROR, - vm->regex_context->error); + return njs_regexp_match_error(vm); } /* Empty split regexp. */ @@ -2248,49 +2246,3 @@ njs_value_index(njs_vm_t *vm, njs_parser_t *parser, const njs_value_t *src) return (njs_index_t) value; } - - -nxt_int_t -njs_string_exception(njs_vm_t *vm, njs_exception_error_t exception, u_char *msg) -{ - u_char *p, *start; - uint32_t msg_length, size, length; - nxt_str_t *error; - njs_value_t *value; - - static nxt_str_t errors[] = { - nxt_string("SyntaxError: "), - nxt_string("InternalError: "), - }; - - value = nxt_mem_cache_alloc(vm->mem_cache_pool, sizeof(njs_value_t)); - if (nxt_slow_path(value == NULL)) { - return NXT_ERROR; - } - - error = &errors[exception]; - - msg_length = (msg != NULL) ? strlen((char *) msg) : 0; - length = nxt_utf8_length(msg, msg_length); - - size = error->len + msg_length; - length += error->len; - - start = njs_string_alloc(vm, value, size, length); - - if (nxt_fast_path(start != NULL)) { - memcpy(start, error->data, error->len); - p = start + error->len; - - memcpy(p, msg, msg_length); - - if (size != length && length >= NJS_STRING_MAP_OFFSET) { - njs_string_offset_map_init(start, size); - } - } - - vm->exception = value; - - return NXT_ERROR; -} - diff --git a/njs/njs_string.h b/njs/njs_string.h index 79428f59..e651c705 100644 --- a/njs/njs_string.h +++ b/njs/njs_string.h @@ -107,8 +107,6 @@ double njs_string_to_number(njs_value_t *value, nxt_bool_t exact); njs_index_t njs_value_index(njs_vm_t *vm, njs_parser_t *parser, const njs_value_t *src); -nxt_int_t njs_string_exception(njs_vm_t *vm, njs_exception_error_t exception, - u_char *msg); extern const njs_object_init_t njs_string_constructor_init; extern const njs_object_init_t njs_string_prototype_init; diff --git a/njs/njs_vm.c b/njs/njs_vm.c index c2729036..caca69e7 100644 --- a/njs/njs_vm.c +++ b/njs/njs_vm.c @@ -8,6 +8,7 @@ #include #include #include +#include #include #include #include @@ -21,10 +22,10 @@ #include #include #include -#include #include #include #include +#include #include @@ -3316,6 +3317,27 @@ njs_value_string_copy(njs_vm_t *vm, nxt_str_t *retval, njs_value_t *value, } +njs_ret_t +njs_vm_throw_exception(njs_vm_t *vm, u_char *buf, uint32_t size) +{ + uint32_t length; + njs_value_t *value; + + value = nxt_mem_cache_alloc(vm->mem_cache_pool, sizeof(njs_value_t)); + if (nxt_slow_path(value == NULL)) { + return NJS_TOKEN_ERROR; + } + + vm->exception = value; + + length = nxt_utf8_length(buf, size); + + (void) njs_string_new(vm, value, buf, size, length); + + return NXT_ERROR; +} + + void njs_debug(njs_index_t index, njs_value_t *value) { diff --git a/njs/njs_vm.h b/njs/njs_vm.h index a21a0e9f..461b4cae 100644 --- a/njs/njs_vm.h +++ b/njs/njs_vm.h @@ -827,10 +827,7 @@ struct njs_vm_shared_s { }; -typedef enum { - NJS_SYNTAX_ERROR = 0, - NJS_INTERNAL_ERROR, -} njs_exception_error_t; +#define NJS_EXCEPTION_BUF_LENGTH 2048 nxt_int_t njs_vmcode_interpreter(njs_vm_t *vm); @@ -972,6 +969,8 @@ njs_ret_t njs_value_to_ext_string(njs_vm_t *vm, nxt_str_t *dst, const njs_value_t *src); void njs_number_set(njs_value_t *value, double num); +njs_ret_t njs_vm_throw_exception(njs_vm_t *vm, u_char *buf, uint32_t size); + nxt_int_t njs_builtin_objects_create(njs_vm_t *vm); nxt_int_t njs_builtin_objects_clone(njs_vm_t *vm); diff --git a/njs/njscript.c b/njs/njscript.c index 37144ed2..9938e4ee 100644 --- a/njs/njscript.c +++ b/njs/njscript.c @@ -18,9 +18,9 @@ #include #include #include -#include #include #include +#include #include @@ -192,6 +192,7 @@ njs_vm_compile(njs_vm_t *vm, u_char **start, u_char *end, parser->lexer = lexer; lexer->start = *start; lexer->end = end; + lexer->line = 1; lexer->keywords_hash = vm->shared->keywords_hash; parser->code_size = sizeof(njs_vmcode_stop_t); diff --git a/njs/test/njs_unit_test.c b/njs/test/njs_unit_test.c index 0f493fba..7acf67c8 100644 --- a/njs/test/njs_unit_test.c +++ b/njs/test/njs_unit_test.c @@ -47,7 +47,10 @@ static njs_unit_test_t njs_test[] = nxt_string("undefined") }, { nxt_string("var; a"), - nxt_string("SyntaxError") }, + nxt_string("SyntaxError: Unexpected token \";\" in 1") }, + + { nxt_string("var + a"), + nxt_string("SyntaxError: Unexpected token \"+\" in 1") }, { nxt_string("var \n a \n = 1; a"), nxt_string("1") }, @@ -1373,7 +1376,7 @@ static njs_unit_test_t njs_test[] = nxt_string("1") }, { nxt_string("a = 0; a \n ++"), - nxt_string("SyntaxError") }, + nxt_string("SyntaxError: Unexpected end of input in 2") }, { nxt_string("a = 1 ? 2 \n : 3"), nxt_string("2") }, @@ -1400,7 +1403,7 @@ static njs_unit_test_t njs_test[] = nxt_string("NaN undefined") }, { nxt_string("var a += 1"), - nxt_string("SyntaxError") }, + nxt_string("SyntaxError: Unexpected token \"+=\" in 1") }, { nxt_string("var a = a + 1"), nxt_string("undefined") }, @@ -1473,13 +1476,26 @@ static njs_unit_test_t njs_test[] = { nxt_string("var a = 3; if (true) if (false); else; a = 2; a"), nxt_string("2") }, + /* do while. */ + + { nxt_string("do { break } if (false)"), + nxt_string("SyntaxError: Unexpected token \"if\" in 1") }, + + /* for in. */ + + { nxt_string("for (null in undefined);"), + nxt_string("ReferenceError: Invalid left-hand side \"null\" in for-in statement in 1") }, + /* switch. */ { nxt_string("switch"), - nxt_string("SyntaxError") }, + nxt_string("SyntaxError: Unexpected end of input in 1") }, { nxt_string("switch (1);"), - nxt_string("SyntaxError") }, + nxt_string("SyntaxError: Unexpected token \";\" in 1") }, + + { nxt_string("switch (1) { do { } while (1) }"), + nxt_string("SyntaxError: Unexpected token \"do\" in 1") }, { nxt_string("switch (1) {}"), nxt_string("undefined") }, @@ -1493,6 +1509,9 @@ static njs_unit_test_t njs_test[] = { nxt_string("switch (1) {default:;}"), nxt_string("undefined") }, + { nxt_string("switch (1) {default:; default:}"), + nxt_string("SyntaxError: More than one default clause in switch statement in 1") }, + { nxt_string("switch (1) {case 0:;}"), nxt_string("undefined") }, @@ -1546,10 +1565,10 @@ static njs_unit_test_t njs_test[] = /* continue. */ { nxt_string("continue"), - nxt_string("SyntaxError") }, + nxt_string("SyntaxError: Illegal continue statement in 1") }, { nxt_string("do continue while (false)"), - nxt_string("SyntaxError") }, + nxt_string("SyntaxError: Unexpected token \"while\" in 1") }, { nxt_string("do continue; while (false)"), nxt_string("undefined") }, @@ -1604,10 +1623,10 @@ static njs_unit_test_t njs_test[] = /* break. */ { nxt_string("break"), - nxt_string("SyntaxError") }, + nxt_string("SyntaxError: Illegal break statement in 1") }, { nxt_string("do break while (true)"), - nxt_string("SyntaxError") }, + nxt_string("SyntaxError: Unexpected token \"while\" in 1") }, { nxt_string("do break; while (true)"), nxt_string("undefined") }, @@ -1750,8 +1769,17 @@ static njs_unit_test_t njs_test[] = { nxt_string("void 0"), nxt_string("undefined") }, + { nxt_string("null = 1"), + nxt_string("ReferenceError: Invalid left-hand side in assignment in 1") }, + { nxt_string("undefined = 1"), - nxt_string("SyntaxError") }, + nxt_string("ReferenceError: Invalid left-hand side in assignment in 1") }, + + { nxt_string("null++"), + nxt_string("ReferenceError: Invalid left-hand side in postfix operation in 1") }, + + { nxt_string("++null"), + nxt_string("ReferenceError: Invalid left-hand side in prefix operation in 1") }, { nxt_string("var a; b = a; a = 1; a +' '+ b"), nxt_string("1 undefined") }, @@ -1858,6 +1886,9 @@ static njs_unit_test_t njs_test[] = { nxt_string("var y = 5; x = { a:y }; x.a"), nxt_string("5") }, + { nxt_string("x = { a: 1; b: 2 }"), + nxt_string("SyntaxError: Unexpected token \";\" in 1") }, + { nxt_string("x = { a: 1, b: x.a }"), nxt_string("ReferenceError") }, @@ -1970,10 +2001,12 @@ static njs_unit_test_t njs_test[] = { nxt_string("3 * [5,7]"), nxt_string("NaN") }, - { nxt_string("a = [ 1, 2, 3 ]; a[0] + a[1] + a[2]"), nxt_string("6") }, + { nxt_string("a = [ 1, 2; 3 ]; a[0] + a[1] + a[2]"), + nxt_string("SyntaxError: Unexpected token \";\" in 1") }, + { nxt_string("a = [ 1, 2, 3 ]; a[0] +' '+ a[1] +' '+ a[2] +' '+ a[3]"), nxt_string("1 2 3 undefined") }, @@ -2285,32 +2318,38 @@ static njs_unit_test_t njs_test[] = { nxt_string("'a\\\r\nb'"), nxt_string("ab") }, + { nxt_string("'abcde"), + nxt_string("SyntaxError: Unterminated string \"'abcde\" in 1") }, + + { nxt_string("'\\"), + nxt_string("SyntaxError: Unterminated string \"'\\\" in 1") }, + { nxt_string("'\\'"), - nxt_string("SyntaxError") }, + nxt_string("SyntaxError: Unterminated string \"'\\'\" in 1") }, { nxt_string("'\\u03B1'"), nxt_string("α") }, { nxt_string("'\\u'"), - nxt_string("SyntaxError") }, + nxt_string("SyntaxError: Invalid Unicode code point \"\\u\" in 1") }, { nxt_string("'\\u03B'"), - nxt_string("SyntaxError") }, + nxt_string("SyntaxError: Invalid Unicode code point \"\\u03B\" in 1") }, { nxt_string("'\\u{61}\\u{3B1}\\u{20AC}'"), nxt_string("aα€") }, { nxt_string("'\\u'"), - nxt_string("SyntaxError") }, + nxt_string("SyntaxError: Invalid Unicode code point \"\\u\" in 1") }, { nxt_string("'\\u{'"), - nxt_string("SyntaxError") }, + nxt_string("SyntaxError: Invalid Unicode code point \"\\u{\" in 1") }, { nxt_string("'\\u{}'"), - nxt_string("SyntaxError") }, + nxt_string("SyntaxError: Invalid Unicode code point \"\\u{}\" in 1") }, { nxt_string("'\\u{1234567}'"), - nxt_string("SyntaxError") }, + nxt_string("SyntaxError: Invalid Unicode code point \"\\u{1234567}\" in 1") }, { nxt_string("'\\x61'"), nxt_string("a") }, @@ -2563,7 +2602,7 @@ static njs_unit_test_t njs_test[] = nxt_string("NaN") }, { nxt_string("a = 'abcdef'; a.3"), - nxt_string("SyntaxError") }, + nxt_string("SyntaxError: Unexpected token \"3\" in 1") }, { nxt_string("'abcdef'[3]"), nxt_string("d") }, @@ -2989,6 +3028,9 @@ static njs_unit_test_t njs_test[] = /* Functions. */ + { nxt_string("function () { } f()"), + nxt_string("SyntaxError: Unexpected token \"(\" in 1") }, + { nxt_string("function f() { } f()"), nxt_string("undefined") }, @@ -3163,7 +3205,7 @@ static njs_unit_test_t njs_test[] = nxt_string("20") }, { nxt_string("var f = function b(a) { a *= 2; return a } = 5"), - nxt_string("SyntaxError") }, + nxt_string("ReferenceError: Invalid left-hand side in assignment in 1") }, { nxt_string("function a() { return { x:2} }; var b = a(); b.x"), nxt_string("2") }, @@ -3211,7 +3253,7 @@ static njs_unit_test_t njs_test[] = nxt_string("3") }, { nxt_string("var a = 0, function(a) { return a + 1 }(2); a"), - nxt_string("SyntaxError") }, + nxt_string("SyntaxError: Unexpected token \"function\" in 1") }, { nxt_string("var a = (0, function(a) { return a + 1 }(2)); a"), nxt_string("3") }, @@ -3432,8 +3474,14 @@ static njs_unit_test_t njs_test[] = /* RegExp. */ + { nxt_string("/./x"), + nxt_string("SyntaxError: Invalid RegExp flags \"x\" in 1") }, + + { nxt_string("/"), + nxt_string("SyntaxError: Unterminated RegExp \"/\" in 1") }, + { nxt_string("/(/.test('')"), - nxt_string("SyntaxError: pcre_compile(\"(\") failed: missing )") }, + nxt_string("SyntaxError: pcre_compile(\"(\") failed: missing ) in 1") }, { nxt_string("/^$/.test('')"), nxt_string("true") }, @@ -3568,6 +3616,12 @@ static njs_unit_test_t njs_test[] = { nxt_string("try { throw null } catch (e) { throw e }"), nxt_string("") }, + { nxt_string("try { throw null } catch (null) { throw e }"), + nxt_string("SyntaxError: Unexpected token \"null\" in 1") }, + + { nxt_string("try {}"), + nxt_string("SyntaxError: Missing catch or finally after try in 1") }, + { nxt_string("var a = 0; try { a = 5 }" "catch (e) { a = 9 } finally { a++ } a"), nxt_string("6") }, @@ -4548,7 +4602,7 @@ static njs_unit_test_t njs_test[] = /* es5id: 8.2_A2 */ { nxt_string("var null;"), - nxt_string("SyntaxError") }, + nxt_string("SyntaxError: Unexpected token \"null\" in 1") }, /* es5id: 8.2_A3 */