From: Dmitry Volyntsev Date: Tue, 27 Nov 2018 15:58:30 +0000 (+0300) Subject: Fixed automatic semicolon insertion. X-Git-Tag: 0.2.7~19 X-Git-Url: http://www.kaiwu.me/postgresql/commit/?a=commitdiff_plain;h=ca2bcd23933b9c7ec58400ac752c13b6043702bb;p=njs.git Fixed automatic semicolon insertion. --- diff --git a/njs/njs_lexer.c b/njs/njs_lexer.c index 361c47a5..b2de9045 100644 --- a/njs/njs_lexer.c +++ b/njs/njs_lexer.c @@ -277,6 +277,7 @@ njs_lexer_token(njs_lexer_t *lexer) { njs_token_t token; + lexer->prev_start = lexer->start; lexer->prev_token = lexer->token; token = njs_lexer_next_token(lexer); @@ -287,6 +288,13 @@ njs_lexer_token(njs_lexer_t *lexer) } +void +njs_lexer_rollback(njs_lexer_t *lexer) +{ + lexer->start = lexer->prev_start; +} + + static njs_token_t njs_lexer_next_token(njs_lexer_t *lexer) { diff --git a/njs/njs_parser.c b/njs/njs_parser.c index 5a608e87..3942cea9 100644 --- a/njs/njs_parser.c +++ b/njs/njs_parser.c @@ -10,17 +10,6 @@ #include -/* - * The LL(2) parser. The two lookahead tokens are required because - * JavaScript inserts automatically semicolon at the end of line in - * a = 1 - * b = 2 - * whilst - * a = 1 - * + b - * is treated as a single expiression. - */ - static njs_ret_t njs_parser_scope_begin(njs_vm_t *vm, njs_parser_t *parser, njs_scope_t type); static void njs_parser_scope_end(njs_vm_t *vm, njs_parser_t *parser); @@ -282,9 +271,7 @@ njs_parser_statement_chain(njs_vm_t *vm, njs_parser_t *parser, node->right = parser->node; parser->node = node; - while (token == NJS_TOKEN_SEMICOLON - || token == NJS_TOKEN_LINE_END) - { + while (token == NJS_TOKEN_SEMICOLON) { token = njs_parser_token(parser); if (nxt_slow_path(token <= NJS_TOKEN_ILLEGAL)) { break; @@ -1811,7 +1798,7 @@ njs_parser_terminal(njs_vm_t *vm, njs_parser_t *parser, njs_token_t token) if (token == NJS_TOKEN_OPEN_PARENTHESIS) { - token = njs_lexer_token(parser->lexer); + token = njs_parser_token(parser); if (nxt_slow_path(token <= NJS_TOKEN_ILLEGAL)) { return token; } @@ -2109,7 +2096,7 @@ njs_parser_terminal(njs_vm_t *vm, njs_parser_t *parser, njs_token_t token) parser->node = node; - return njs_lexer_token(parser->lexer); + return njs_parser_token(parser); } @@ -2142,7 +2129,7 @@ njs_parser_builtin_object(njs_vm_t *vm, njs_parser_t *parser, parser->node = node; parser->code_size += sizeof(njs_vmcode_object_copy_t); - return njs_lexer_token(parser->lexer); + return njs_parser_token(parser); } @@ -2175,7 +2162,7 @@ njs_parser_builtin_function(njs_vm_t *vm, njs_parser_t *parser, parser->node = node; parser->code_size += sizeof(njs_vmcode_object_copy_t); - return njs_lexer_token(parser->lexer); + return njs_parser_token(parser); } diff --git a/njs/njs_parser.h b/njs/njs_parser.h index 23ffdebb..659b4468 100644 --- a/njs/njs_parser.h +++ b/njs/njs_parser.h @@ -31,8 +31,6 @@ typedef enum { NJS_TOKEN_DOT, NJS_TOKEN_SEMICOLON, -#define NJS_TOKEN_FIRST_OPERATOR NJS_TOKEN_COLON - NJS_TOKEN_COLON, NJS_TOKEN_CONDITIONAL, @@ -103,8 +101,6 @@ typedef enum { NJS_TOKEN_DELETE, NJS_TOKEN_YIELD, -#define NJS_TOKEN_LAST_OPERATOR NJS_TOKEN_YIELD - NJS_TOKEN_DIGIT, NJS_TOKEN_LETTER, @@ -223,6 +219,7 @@ typedef struct { nxt_lvlhsh_t keywords_hash; u_char *start; + u_char *prev_start; u_char *end; } njs_lexer_t; @@ -360,6 +357,7 @@ typedef struct { njs_token_t njs_lexer_token(njs_lexer_t *lexer); +void njs_lexer_rollback(njs_lexer_t *lexer); nxt_int_t njs_lexer_keywords_init(nxt_mem_cache_pool_t *mcp, nxt_lvlhsh_t *hash); njs_token_t njs_lexer_keyword(njs_lexer_t *lexer); diff --git a/njs/njs_parser_expression.c b/njs/njs_parser_expression.c index bad37464..f23f9dfd 100644 --- a/njs/njs_parser_expression.c +++ b/njs/njs_parser_expression.c @@ -230,14 +230,6 @@ njs_parser_expression(njs_vm_t *vm, njs_parser_t *parser, njs_token_t token) } -nxt_inline nxt_bool_t -njs_parser_expression_operator(njs_token_t token) -{ - return (token >= NJS_TOKEN_FIRST_OPERATOR - && token <= NJS_TOKEN_LAST_OPERATOR); -} - - njs_token_t njs_parser_var_expression(njs_vm_t *vm, njs_parser_t *parser, njs_token_t token) { @@ -259,18 +251,6 @@ njs_parser_var_expression(njs_vm_t *vm, njs_parser_t *parser, njs_token_t token) size = sizeof(njs_vmcode_move_t); break; - case NJS_TOKEN_LINE_END: - token = njs_lexer_token(parser->lexer); - if (nxt_slow_path(token <= NJS_TOKEN_ILLEGAL)) { - return token; - } - - if (njs_parser_expression_operator(token)) { - continue; - } - - /* Fall through. */ - default: return token; } @@ -397,18 +377,6 @@ njs_parser_assignment_expression(njs_vm_t *vm, njs_parser_t *parser, operation = njs_vmcode_bitwise_or; break; - case NJS_TOKEN_LINE_END: - token = njs_lexer_token(parser->lexer); - if (nxt_slow_path(token <= NJS_TOKEN_ILLEGAL)) { - return token; - } - - if (njs_parser_expression_operator(token)) { - continue; - } - - /* Fall through. */ - default: return token; } @@ -588,18 +556,6 @@ njs_parser_binary_expression(njs_vm_t *vm, njs_parser_t *parser, } while (n != 0); - if (token == NJS_TOKEN_LINE_END) { - - token = njs_lexer_token(parser->lexer); - if (nxt_slow_path(token <= NJS_TOKEN_ILLEGAL)) { - return token; - } - - if (njs_parser_expression_operator(token)) { - continue; - } - } - return token; found: @@ -676,18 +632,6 @@ njs_parser_exponential_expression(njs_vm_t *vm, njs_parser_t *parser, parser->node = node; } - if (token == NJS_TOKEN_LINE_END) { - - token = njs_lexer_token(parser->lexer); - if (nxt_slow_path(token <= NJS_TOKEN_ILLEGAL)) { - return token; - } - - if (njs_parser_expression_operator(token)) { - continue; - } - } - return token; } } @@ -902,6 +846,13 @@ njs_parser_post_inc_dec_expression(njs_vm_t *vm, njs_parser_t *parser, return token; } + /* Automatic semicolon insertion. */ + + if (parser->lexer->prev_token == NJS_TOKEN_LINE_END) { + njs_lexer_rollback(parser->lexer); + return NJS_TOKEN_SEMICOLON; + } + if (!njs_parser_is_lvalue(parser->node)) { njs_parser_ref_error(vm, parser, "Invalid left-hand side in postfix operation"); diff --git a/njs/test/njs_unit_test.c b/njs/test/njs_unit_test.c index 32acda11..850f442d 100644 --- a/njs/test/njs_unit_test.c +++ b/njs/test/njs_unit_test.c @@ -2046,6 +2046,15 @@ static njs_unit_test_t njs_test[] = { nxt_string("a = 0; a \n ++"), nxt_string("SyntaxError: Unexpected end of input in 2") }, + { nxt_string("a = 0; a \n --"), + nxt_string("SyntaxError: Unexpected end of input in 2") }, + + { nxt_string("var a = 0; a \n + 1"), + nxt_string("1") }, + + { nxt_string("var a = 0; a \n +\n 1"), + nxt_string("1") }, + { nxt_string("var a; a = 1 ? 2 \n : 3"), nxt_string("2") }, @@ -2119,6 +2128,11 @@ static njs_unit_test_t njs_test[] = { nxt_string("var a \n if (!a) a = 3; a"), nxt_string("3") }, + /* automatic semicolon insertion. */ + + { nxt_string("var x = 0, y = 2; x\n--\ny; [x,y]"), + nxt_string("0,1") }, + /* if. */ { nxt_string("if (0);"), @@ -2193,6 +2207,21 @@ static njs_unit_test_t njs_test[] = { nxt_string("(function(){ for (var p in [1] ){ if (1) continue; else return 0; }})()"), nxt_string("undefined") }, + { nxt_string("(function(x){ if\n(x) return -1; else return 0; })(0)"), + nxt_string("0") }, + + { nxt_string("(function(x){ if\n(\nx) return -1; else return 0; })(0)"), + nxt_string("0") }, + + { nxt_string("(function(x){ if\n(\nx)\nreturn -1; else return 0; })(0)"), + nxt_string("0") }, + + { nxt_string("(function(x){ if\n(\nx)\nreturn -1\n else return 0; })(0)"), + nxt_string("0") }, + + { nxt_string("(function(x){ if\n(\nx)\nreturn -1\n else\nreturn 0; })(0)"), + nxt_string("0") }, + /* do while. */ { nxt_string("do { break } if (false)"), @@ -2957,6 +2986,15 @@ static njs_unit_test_t njs_test[] = { nxt_string("var a = [1,2]; a.length"), nxt_string("2") }, + { nxt_string("[\n1]"), + nxt_string("1") }, + + { nxt_string("\n[\n1\n]"), + nxt_string("1") }, + + { nxt_string("\n[\n1\n,\n2]\n[\n0]"), + nxt_string("1") }, + #if 0 { nxt_string("Object.create([1,2]).length"), nxt_string("2") }, @@ -3808,6 +3846,9 @@ static njs_unit_test_t njs_test[] = { nxt_string("'a'.my"), nxt_string("undefined") }, + { nxt_string("var a = '123'\n[2].toString();a"), + nxt_string("3") }, + /* Escape strings. */ { nxt_string("'\\a \\' \\\" \\\\ \\0 \\b \\f \\n \\r \\t \\v'"), @@ -5318,6 +5359,33 @@ static njs_unit_test_t njs_test[] = "eval"), nxt_string("X") }, + { nxt_string("var o = {f:function(x){ return x**2}}; o.f\n(2)"), + nxt_string("4") }, + + { nxt_string("var o = {f:function(x){ return x**2}}; o\n.f\n(2)"), + nxt_string("4") }, + + { nxt_string("var o = {f:function(x){ return x**2}}; o\n.\nf\n(2)"), + nxt_string("4") }, + + { nxt_string("function f(x){ return x**2}; [f(2)\n, f\n(2),\nf\n(\n2),\nf\n(\n2\n)]"), + nxt_string("4,4,4,4") }, + + { nxt_string("function f (x){ return x**2}; f\n(2)"), + nxt_string("4") }, + + { nxt_string("function f (x){ return x**2}; f\n(\n2)"), + nxt_string("4") }, + + { nxt_string("function f (x){ return x**2}; f\n(\n2\n)"), + nxt_string("4") }, + + { nxt_string("function f (x){ return x**2}; f\n(2\n)"), + nxt_string("4") }, + + { nxt_string("function f (x){ return x**2}; f(2\n)"), + nxt_string("4") }, + /* Recursive factorial. */ { nxt_string("function f(a) {"