static njs_int_t njs_parser_for_expression_map_continue(
njs_parser_t *parser, njs_lexer_token_t *token,
njs_queue_link_t *current);
-static njs_int_t njs_parser_for_expression_map_reparse(
- njs_parser_t *parser, njs_lexer_token_t *token,
- njs_queue_link_t *current);
static njs_int_t njs_parser_expression_continue_op(njs_parser_t *parser,
njs_lexer_token_t *token, njs_queue_link_t *current);
static njs_int_t njs_parser_expression_continue_assign_comma(
}
-static njs_int_t
-njs_parser_for_expression_map_reparse(njs_parser_t *parser,
- njs_lexer_token_t *token, njs_queue_link_t *current)
-{
- if (parser->ret != NJS_OK && parser->node != NULL) {
- return njs_parser_failed(parser);
- }
-
- if (parser->node == NULL) {
- njs_lexer_in_fail_set(parser->lexer, 1);
-
- njs_parser_next(parser, njs_parser_expression);
-
- return NJS_OK;
- }
-
- return njs_parser_stack_pop(parser);
-}
-
-
static njs_int_t
njs_parser_for_expression_map_continue(njs_parser_t *parser,
njs_lexer_token_t *token, njs_queue_link_t *current)
goto expression_after;
- case NJS_TOKEN_AWAIT:
- njs_parser_next(parser, njs_parser_expression);
-
- goto expression_after;
-
default:
ret = njs_parser_match_arrow_expression(parser, token);
if (ret == NJS_OK) {
return NJS_ERROR;
}
+ /* The speculative parse below has no way back, see the log. */
+
+ switch (token->type) {
+ case NJS_TOKEN_DELETE:
+ case NJS_TOKEN_VOID:
+ case NJS_TOKEN_TYPEOF:
+ case NJS_TOKEN_AWAIT:
+ case NJS_TOKEN_ADDITION:
+ case NJS_TOKEN_SUBTRACTION:
+ case NJS_TOKEN_BITWISE_NOT:
+ case NJS_TOKEN_LOGICAL_NOT:
+ case NJS_TOKEN_INCREMENT:
+ case NJS_TOKEN_DECREMENT:
+ njs_lexer_in_fail_set(parser->lexer, 1);
+
+ parser->target = NULL;
+ njs_parser_next(parser, njs_parser_expression);
+
+ goto expression_after;
+
+ default:
+ break;
+ }
+
parser->target = NULL;
njs_parser_next(parser, njs_parser_left_hand_side_expression);
*text = token->text;
- ret = njs_parser_after(parser, current, text, 0,
- njs_parser_for_expression_map_reparse);
- if (ret != NJS_OK) {
- return NJS_ERROR;
- }
-
return njs_parser_after(parser, current, text, 1,
njs_parser_for_expression_map_continue);
}
{ njs_str("for (in + j;;) {}"),
njs_str("SyntaxError: Unexpected token \"in\"") },
+ { njs_str("for (var x = [1 in {}];;) break;"),
+ njs_str("undefined") },
+
+ { njs_str("for (var x = true ? 1 in {} : 0;;) break;"),
+ njs_str("undefined") },
+
{ njs_str("for (true ? 0 in {}: 0; false; ) ;"),
njs_str("undefined") },
{ njs_str("for(i;;)for(-new+3;;)break;"),
njs_str("SyntaxError: Unexpected token \"+\"") },
+ { njs_str("for(function(){r({/a/;0;1)1"),
+ njs_str("SyntaxError: Unexpected token \"/\"") },
+
+ { njs_str("for(a(function(){r({/a/;0;1)1"),
+ njs_str("SyntaxError: Unexpected token \"/\"") },
+
+ { njs_str("for(async function(){r({/a/;0;1)1"),
+ njs_str("SyntaxError: Unexpected token \"/\"") },
+
+ { njs_str("for({/a/;0;1)1"),
+ njs_str("SyntaxError: Unexpected token \"/\"") },
+
+ { njs_str("for(function f(){}.x in {a:1}); 1"),
+ njs_str("1") },
+
+ { njs_str("var o={}; for(function(){return o}().x in {a:1,b:2}); o.x"),
+ njs_str("b") },
+
+ { njs_str("async function f(){for(await p in o;;)break;} f()"),
+ njs_str("SyntaxError: Invalid left-hand side in for-loop") },
+
+ { njs_str("var a=0; for(-a;;)break; a"),
+ njs_str("0") },
+
+ { njs_str("var a=0; for(typeof a;;)break; a"),
+ njs_str("0") },
+
+ { njs_str("var a=0; for(++a;;)break; a"),
+ njs_str("1") },
+
+ { njs_str("var a={b:0}; for(delete a.b;;)break; a.b"),
+ njs_str("undefined") },
+
/* switch. */
{ njs_str("switch"),
"f().then($r.retval)"),
njs_str("X:4") },
+ { njs_str("async function f() {"
+ " var r = [];"
+ " for (var k in await Promise.resolve({a:1, b:2})) {"
+ " r.push(k);"
+ " }"
+ " return r.join(':');"
+ "}"
+ "f().then($r.retval)"),
+ njs_str("a:b") },
+
{ njs_str("async function f() {"
" return ((...a) => a[1] + ':' + a[2] + ':' + a[0].length)"
" `a${await Promise.resolve(2)}b"