Skip to content

Commit

Permalink
Js-parser: add support for for await (#1550)
Browse files Browse the repository at this point in the history
* Compiler: js-parser support for await

* Changes
  • Loading branch information
hhugo authored Dec 10, 2023
1 parent 94bee37 commit 9c6b587
Show file tree
Hide file tree
Showing 9 changed files with 121 additions and 3 deletions.
2 changes: 2 additions & 0 deletions CHANGES.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,14 @@

## Features/Changes
* Compiler: try to preserve clorures ordering between ml and js
* Compiler: js-parser accept for await

## Bug fixes
* Compiler: js-parser now accept all the line terminators defined in the spec
* Compiler: js-parser: fix support for LHS assignment target
* Compiler: js-parser: fix parser of default export
* Compiler: js-parser: allow 'as' as ident
* Compiler: js-parser: fix for in rewriting

# 5.5.2 (2023-12-01) - Lille

Expand Down
4 changes: 4 additions & 0 deletions compiler/lib/javascript.ml
Original file line number Diff line number Diff line change
Expand Up @@ -336,6 +336,10 @@ and statement =
(expression, variable_declaration_kind * for_binding) either
* expression
* (statement * location)
| ForAwaitOf_statement of
(expression, variable_declaration_kind * for_binding) either
* expression
* (statement * location)
| Continue_statement of Label.t option
| Break_statement of Label.t option
| Return_statement of expression option
Expand Down
4 changes: 4 additions & 0 deletions compiler/lib/javascript.mli
Original file line number Diff line number Diff line change
Expand Up @@ -254,6 +254,10 @@ and statement =
(expression, variable_declaration_kind * for_binding) either
* expression
* (statement * location)
| ForAwaitOf_statement of
(expression, variable_declaration_kind * for_binding) either
* expression
* (statement * location)
| Continue_statement of Label.t option
| Break_statement of Label.t option
| Return_statement of expression option
Expand Down
23 changes: 23 additions & 0 deletions compiler/lib/js_output.ml
Original file line number Diff line number Diff line change
Expand Up @@ -275,6 +275,7 @@ struct
| For_statement (_, _, _, st)
| ForIn_statement (_, _, st) -> ends_with_if_without_else st
| ForOf_statement (_, _, st) -> ends_with_if_without_else st
| ForAwaitOf_statement (_, _, st) -> ends_with_if_without_else st
| If_statement (_, _, None) -> true
| Block _
| Variable_statement _
Expand Down Expand Up @@ -1313,6 +1314,28 @@ struct
PP.end_group f;
statement1 ~last f s;
PP.end_group f
| ForAwaitOf_statement (e1, e2, s) ->
PP.start_group f 0;
PP.start_group f 0;
PP.string f "for await";
PP.break f;
PP.start_group f 1;
PP.string f "(";
(match e1 with
| Left e ->
(* Should not starts with "let" *)
parenthesized_expression ~let_identifier:true Expression f e
| Right (k, v) -> for_binding f k v);
PP.space f;
PP.string f "of";
PP.break f;
PP.space f;
expression Expression f e2;
PP.string f ")";
PP.end_group f;
PP.end_group f;
statement1 ~last f s;
PP.end_group f
| Continue_statement None ->
PP.string f "continue";
last_semi ()
Expand Down
5 changes: 5 additions & 0 deletions compiler/lib/js_parser.mly
Original file line number Diff line number Diff line change
Expand Up @@ -713,6 +713,11 @@ iteration_stmt:
ForOf_statement (Left left, right, body) }
| T_FOR "(" left=for_single_variable_decl T_OF right=assignment_expr ")" body=stmt
{ ForOf_statement (Right left, right, body) }
| T_FOR T_AWAIT "(" left=left_hand_side_expr T_OF right=assignment_expr ")" body=stmt
{ let left = assignment_target_of_expr None left in
ForAwaitOf_statement (Left left, right, body) }
| T_FOR T_AWAIT "(" left=for_single_variable_decl T_OF right=assignment_expr ")" body=stmt
{ ForAwaitOf_statement (Right left, right, body) }

initializer_no_in:
| "=" e=assignment_expr_no_in { e, p $symbolstartpos }
Expand Down
1 change: 1 addition & 0 deletions compiler/lib/js_simpl.ml
Original file line number Diff line number Diff line change
Expand Up @@ -160,6 +160,7 @@ let rec depth = function
| For_statement (_, _, _, (s, _)) -> depth s + 1
| ForIn_statement (_, _, (s, _)) -> depth s + 1
| ForOf_statement (_, _, (s, _)) -> depth s + 1
| ForAwaitOf_statement (_, _, (s, _)) -> depth s + 1
| Continue_statement _ -> 1
| Break_statement _ -> 1
| Return_statement _ -> 1
Expand Down
37 changes: 35 additions & 2 deletions compiler/lib/js_traverse.ml
Original file line number Diff line number Diff line change
Expand Up @@ -176,6 +176,13 @@ class map : mapper =
| Right (k, d) -> Right (k, m#for_binding k d)
in
ForOf_statement (e1, m#expression e2, (m#statement s, m#loc loc))
| ForAwaitOf_statement (e1, e2, (s, loc)) ->
let e1 =
match e1 with
| Left e -> Left (m#expression e)
| Right (k, d) -> Right (k, m#for_binding k d)
in
ForAwaitOf_statement (e1, m#expression e2, (m#statement s, m#loc loc))
| Continue_statement s -> Continue_statement s
| Break_statement s -> Break_statement s
| Return_statement e -> Return_statement (m#expression_o e)
Expand Down Expand Up @@ -516,7 +523,12 @@ class iter : iterator =
(match e1 with
| Left e -> m#expression e
| Right (k, d) -> m#for_binding k d);

m#expression e2;
m#statement s
| ForAwaitOf_statement (e1, e2, (s, _)) ->
(match e1 with
| Left e -> m#expression e
| Right (k, d) -> m#for_binding k d);
m#expression e2;
m#statement s
| Continue_statement _ -> ()
Expand Down Expand Up @@ -1063,6 +1075,15 @@ class free =
m'#record_block Normal;
m#merge_block_info m';
ForOf_statement (Right (k, l), e2, (st, m#loc loc))
| ForAwaitOf_statement (Right (((Const | Let) as k), l), e2, (st, loc)) ->
let same_level = level in
let m' = {<state_ = empty; level = same_level>} in
let l = m'#for_binding k l in
let e2 = m'#expression e2 in
let st = m'#statement st in
m'#record_block Normal;
m#merge_block_info m';
ForAwaitOf_statement (Right (k, l), e2, (st, m#loc loc))
| Switch_statement (e, l, def, l') ->
let same_level = level in
let m' = {<state_ = empty; level = same_level>} in
Expand Down Expand Up @@ -1186,6 +1207,10 @@ class rename_variable ~esm =
let m = {<depth = depth + 1>} in
m#for_binding k l;
m#statement st
| _, ForAwaitOf_statement (Right (((Const | Let) as k), l), _e2, (st, _loc)) ->
let m = {<depth = depth + 1>} in
m#for_binding k l;
m#statement st
| _, ForIn_statement (Right (((Const | Let) as k), l), _e2, (st, _loc)) ->
let m = {<depth = depth + 1>} in
m#for_binding k l;
Expand Down Expand Up @@ -1352,10 +1377,17 @@ class rename_variable ~esm =
( Right (k, m'#for_binding k l)
, m'#expression e2
, (m'#statement st, m'#loc loc) )
| ForAwaitOf_statement (Right (((Const | Let) as k), l), e2, (st, loc)) ->
let ids = bound_idents_of_binding l in
let m' = m#update_state Lexical_block ids [] in
ForAwaitOf_statement
( Right (k, m'#for_binding k l)
, m'#expression e2
, (m'#statement st, m'#loc loc) )
| ForIn_statement (Right (((Const | Let) as k), l), e2, (st, loc)) ->
let ids = bound_idents_of_binding l in
let m' = m#update_state Lexical_block ids [] in
ForOf_statement
ForIn_statement
( Right (k, m'#for_binding k l)
, m'#expression e2
, (m'#statement st, m'#loc loc) )
Expand Down Expand Up @@ -1632,6 +1664,7 @@ class clean =
| For_statement (p1, p2, p3, st) -> For_statement (p1, p2, p3, b st)
| ForIn_statement (param, e, st) -> ForIn_statement (param, e, b st)
| ForOf_statement (param, e, st) -> ForOf_statement (param, e, b st)
| ForAwaitOf_statement (param, e, st) -> ForAwaitOf_statement (param, e, b st)
| Switch_statement (e, l, Some [], []) -> Switch_statement (e, l, None, [])
| s -> s
end
Expand Down
21 changes: 21 additions & 0 deletions compiler/tests-compiler/js_parser_printer.ml
Original file line number Diff line number Diff line change
Expand Up @@ -451,6 +451,27 @@ let%expect_test "assignment pattern" =
/*<<fake:17:4>>*/ for([a, b, {c, d = e, [f]: [g, h, a, i, j]}] of 3)
/*<<fake:17:43>>*/ ; |}]

let%expect_test "for loops" =
(* GH#1017 *)
print
~report:true
~compact:false
{|
for(x in 3);
for(x of 3);
async function f(x) {
for await(x of 3);
}
|};

[%expect
{|
/*<<fake:2:4>>*/ for(x in 3) /*<<fake:2:15>>*/ ;
/*<<fake:3:4>>*/ for(x of 3) /*<<fake:3:15>>*/ ;
/*<<fake:4:4>>*/ async function f(x){
/*<<fake:5:4>>*/ for await(x of 3) /*<<fake:5:21>>*/ ;
/*<<fake:4:4>>*/ } |}]

let%expect_test "string template" =
(* GH#1017 *)
print
Expand Down
27 changes: 26 additions & 1 deletion compiler/tests-compiler/scopes.ml
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ let%expect_test "let inside forin" =
1: (function(){
2: let v2 = 2;
3: var v3 = 0, v1 = [1, 2, 3];
4: for(let v4 of v1){console.log(v4); v3 += v1[v4];}
4: for(let v4 in v1){console.log(v4); v3 += v1[v4];}
5: console.log(v3);
6: console.log(v2);
7: }
Expand Down Expand Up @@ -121,6 +121,31 @@ let%expect_test "let inside forof" =
6
2 |}]

let%expect_test "let inside forawaitof" =
test
{|
async function f () {
let x = 2
var y = 0;
for await(let x of [1,2,3]) {
console.log(x);
y += x;
}
console.log(y);
console.log(x);
}
|};
[%expect
{|
$ cat "test.min.js"
1: async function f(){
2: let v1 = 2;
3: var v2 = 0;
4: for await(let v3 of [1, 2, 3]){console.log(v3); v2 += v3;}
5: console.log(v2);
6: console.log(v1);
7: } |}]

let%expect_test "let inside switch" =
test
{|
Expand Down

0 comments on commit 9c6b587

Please sign in to comment.