Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Async await support #5537

Merged
merged 51 commits into from
Jul 18, 2022
Merged
Changes from all commits
Commits
Show all changes
51 commits
Select commit Hold shift + click to select a range
0b07581
Experiment with async-await.
cristianoc May 19, 2022
0270e9c
Add example project `example-async`.
cristianoc May 19, 2022
1c501d0
Use @async attribute instead of an external.
cristianoc May 19, 2022
8ccd6fa
Remove old support for async primitive.
cristianoc May 19, 2022
e2dc279
Add recursive function to run all tests.
cristianoc May 19, 2022
1e3c8a8
Support for @await decorator.
cristianoc May 20, 2022
9e4f143
Support async callbacks.
cristianoc May 20, 2022
804a40f
tweak callback example
cristianoc May 20, 2022
c11c3ca
Add async list example.
cristianoc May 20, 2022
64c0057
Clean up treatment of async attribute.
cristianoc May 20, 2022
d3ce0a8
Work around funny pretty printer formatting of await.
cristianoc May 20, 2022
1d55824
Clean up.
cristianoc May 20, 2022
cb1568c
clean up dump
cristianoc May 20, 2022
813d98e
format dump
cristianoc May 20, 2022
b98bc9a
More cleanup.
cristianoc May 20, 2022
ee80cf6
Give error when awaiting not in an async context.
cristianoc May 20, 2022
cc05e6e
Give error when async is applied to a curried function.
cristianoc May 20, 2022
bf7fe9c
Less invasive change to the ppx.
cristianoc May 22, 2022
7384191
More ppx cleanup.
cristianoc May 22, 2022
42db790
Use dedicated ast functions.
cristianoc May 22, 2022
3d1d2e6
Add module Ast_await.
cristianoc May 22, 2022
af913a4
Lift restriction to uncurried functions.
cristianoc May 22, 2022
ab2cbec
Braces are preserved by reformatting, but belong to the same function.
cristianoc May 22, 2022
f8bb32d
Unusual uncurried function with 2 arguments.
cristianoc May 22, 2022
60809c5
Use .mjs in source dir.
cristianoc May 27, 2022
b3bb5e6
Add example fetch using result type.
cristianoc May 27, 2022
6ad7eb7
Add imaginary syntax.
cristianoc May 27, 2022
2811546
tweak imaginary syntax, free up "&&".
cristianoc May 27, 2022
2febc63
"and" seems more idiomatic
cristianoc May 27, 2022
7358623
Example with exception-annotated fetch.
cristianoc May 29, 2022
dc257ce
tweak example
cristianoc May 31, 2022
9456dfd
snapshot
cristianoc Jun 12, 2022
1aedc89
Rebase on latest 10.0 alpha compiler.
cristianoc Jul 5, 2022
412e390
Begin preparing for source syntax.
cristianoc Jul 7, 2022
815568e
Pull in the surface syntax from the syntax submodule.
cristianoc Jul 7, 2022
a3bc904
Make sure the example still builds.
cristianoc Jul 7, 2022
e00ef8b
Example: switch to the new `res.*` attributes.
cristianoc Jul 7, 2022
00ea266
Example: switch `async` to surface syntax.
cristianoc Jul 7, 2022
58f6857
Switch over await's to surface syntax.
cristianoc Jul 7, 2022
1fe1149
Sync latest surface syntax.
cristianoc Jul 7, 2022
57758b1
Almost reformat.
cristianoc Jul 7, 2022
2420fd1
One more syntax sync.
cristianoc Jul 7, 2022
6b0ed47
Update .prettierignore
cristianoc Jul 7, 2022
0c318fb
Rebase on latest compiler.
cristianoc Jul 11, 2022
ea05f76
remove example from experiments repo
cristianoc Jul 11, 2022
8cd6abe
Update .prettierignore
cristianoc Jul 11, 2022
8a38fb4
rebase on master and use latest syntax
cristianoc Jul 18, 2022
0787a02
Update CHANGELOG.md
cristianoc Jul 18, 2022
4928972
Update CHANGELOG.md
cristianoc Jul 18, 2022
9cc7c55
Only accept `res.async` and clean up Js_promise.
cristianoc Jul 18, 2022
920a2ba
Use record type for Fun payload in j.ml.
cristianoc Jul 18, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -16,6 +16,10 @@

- Vendor genType, which does not need to be installed separately anymore. **Only TypeScript back-end** supported.

#### :rocket: New Feature

- Add support for for `async`/`await` https://github.com/rescript-lang/rescript-compiler/pull/5537

#### :nail_care: Polish

- Print patterns in warnings using rescript printer https://github.com/rescript-lang/rescript-compiler/pull/5492
7 changes: 0 additions & 7 deletions jscomp/build_tests/top/demo.bs.js

This file was deleted.

42 changes: 15 additions & 27 deletions jscomp/core/j.ml
Original file line number Diff line number Diff line change
@@ -32,27 +32,17 @@
*)

type mutable_flag = Js_op.mutable_flag

type binop = Js_op.binop

type int_op = Js_op.int_op

type kind = Js_op.kind

type property = Js_op.property

type number = Js_op.number

type ident_info = Js_op.ident_info

type exports = Js_op.exports

type tag_info = Js_op.tag_info

type property_name = Js_op.property_name

type label = string

and ident = Ident.t
(* we override `method ident` *)

@@ -64,7 +54,6 @@ and ident = Ident.t
and module_id = { id : ident; kind : Js_op.kind }

and required_modules = module_id list

and vident = Id of ident | Qualified of module_id * string option
(* Since camldot is only available for toplevel module accessors,
we don't need print `A.length$2`
@@ -83,13 +72,9 @@ and vident = Id of ident | Qualified of module_id * string option
*)

and exception_ident = ident

and for_ident = ident

and for_direction = Js_op.direction_flag

and property_map = (property_name * expression) list

and length_object = Js_op.length_object

and expression_desc =
@@ -142,12 +127,15 @@ and expression_desc =
*)
| New of expression * expression list option (* TODO: option remove *)
| Var of vident
| Fun of bool * ident list * block * Js_fun_env.t * bool
(* The first parameter by default is false,
it will be true when it's a method
The last pararemter [true] return unit
*)
| Str of {delim: string option; txt: string}
| Fun of {
is_method : bool;
params : ident list;
body : block;
env : Js_fun_env.t;
return_unit : bool;
async : bool;
}
| Str of { delim : string option; txt : string }
(* A string is UTF-8 encoded, and may contain
escape sequences.
*)
@@ -182,6 +170,7 @@ and expression_desc =
| Object of property_map
| Undefined
| Null
| Await of expression

and for_ident_expression = expression
(* pure*)
@@ -265,7 +254,6 @@ and case_clause = {
}

and string_clause = string * case_clause

and int_clause = int * case_clause

and statement_desc =
@@ -274,7 +262,8 @@ and statement_desc =
(* Function declaration and Variable declaration *)
| Exp of expression
| If of expression * block * block
| While of label option * expression * block * Js_closure.t (* check if it contains loop mutable values, happens in nested loop *)
| While of label option * expression * block * Js_closure.t
(* check if it contains loop mutable values, happens in nested loop *)
| ForRange of
for_ident_expression option
* finish_ident_expression
@@ -284,8 +273,9 @@ and statement_desc =
* Js_closure.t
| Continue of label
| Break (* only used when inline a fucntion *)
| Return of expression (* Here we need track back a bit ?, move Return to Function ...
Then we can only have one Return, which is not good *)
| Return of expression
(* Here we need track back a bit ?, move Return to Function ...
Then we can only have one Return, which is not good *)
(* since in ocaml, it's expression oriented langauge, [return] in
general has no jumps, it only happens when we do
tailcall conversion, in that case there is a jump.
@@ -303,7 +293,6 @@ and statement_desc =
| Debugger

and expression = { expression_desc : expression_desc; comment : string option }

and statement = { statement_desc : statement_desc; comment : string option }

and variable_declaration = {
@@ -317,7 +306,6 @@ and variable_declaration = {
be concatenated in both ways
*)
and block = statement list

and program = { block : block; exports : exports; export_set : Set_ident.t }

and deps_program = {
4 changes: 3 additions & 1 deletion jscomp/core/js_analyzer.ml
Original file line number Diff line number Diff line change
@@ -53,7 +53,7 @@ let free_variables (stats : idents_stats) =
expression =
(fun self exp ->
match exp.expression_desc with
| Fun (_, _, _, env, _)
| Fun {env}
(* a optimization to avoid walking into funciton again
if it's already comuted
*) ->
@@ -107,6 +107,7 @@ let rec no_side_effect_expression_desc (x : J.expression_desc) =
(* | Caml_block_set_tag _ *)
(* actually true? *) ->
false
| Await _ -> false

and no_side_effect (x : J.expression) =
no_side_effect_expression_desc x.expression_desc
@@ -207,6 +208,7 @@ let rec eq_expression ({ expression_desc = x0 } : J.expression)
| Caml_block_tag _ | Object _
| Number (Uint _) ->
false
| Await _ -> false

and eq_expression_list xs ys = Ext_list.for_all2_no_exn xs ys eq_expression

59 changes: 34 additions & 25 deletions jscomp/core/js_dump.ml
Original file line number Diff line number Diff line change
@@ -93,13 +93,11 @@ module Curry_gen = struct
end

let return_indent = String.length L.return / Ext_pp.indent_length

let throw_indent = String.length L.throw / Ext_pp.indent_length

type cxt = Ext_pp_scope.t

let semi f = P.string f L.semi

let comma f = P.string f L.comma

let exn_block_as_obj ~(stack : bool) (el : J.expression list) (ext : J.tag_info)
@@ -166,6 +164,7 @@ let exp_need_paren (e : J.expression) =
| Optional_block _ | Caml_block _ | FlatCall _ | Typeof _ | Number _
| Js_not _ | Bool _ | New _ ->
false
| Await _ -> false

let comma_idents (cxt : cxt) f ls = iter_lst cxt f ls Ext_pp_scope.ident comma

@@ -295,7 +294,7 @@ let rec try_optimize_curry cxt f len function_id =
Curry_gen.pp_optimize_curry f len;
P.paren_group f 1 (fun _ -> expression ~level:1 cxt f function_id)

and pp_function ~return_unit ~is_method cxt (f : P.t) ~fn_state
and pp_function ~return_unit ~async ~is_method cxt (f : P.t) ~fn_state
(l : Ident.t list) (b : J.block) (env : Js_fun_env.t) : cxt =
match b with
| [
@@ -391,23 +390,23 @@ and pp_function ~return_unit ~is_method cxt (f : P.t) ~fn_state
match fn_state with
| Is_return ->
return_sp f;
P.string f L.function_;
P.string f (L.function_async ~async);
P.space f;
param_body ()
| No_name { single_arg } ->
(* see # 1692, add a paren for annoymous function for safety *)
P.cond_paren_group f (not single_arg) 1 (fun _ ->
P.string f L.function_;
P.string f (L.function_async ~async);
P.space f;
param_body ())
| Name_non_top x ->
ignore (pp_var_assign inner_cxt f x : cxt);
P.string f L.function_;
P.string f (L.function_async ~async);
P.space f;
param_body ();
semi f
| Name_top x ->
P.string f L.function_;
P.string f (L.function_async ~async);
P.space f;
ignore (Ext_pp_scope.ident inner_cxt f x : cxt);
param_body ())
@@ -423,7 +422,7 @@ and pp_function ~return_unit ~is_method cxt (f : P.t) ~fn_state
| Name_non_top name | Name_top name ->
ignore (pp_var_assign inner_cxt f name : cxt));
P.string f L.lparen;
P.string f L.function_;
P.string f (L.function_async ~async);
pp_paren_params inner_cxt f lexical;
P.brace_vgroup f 0 (fun _ ->
return_sp f;
@@ -530,10 +529,10 @@ and expression_desc cxt ~(level : int) f x : cxt =
let cxt = expression ~level:0 cxt f e1 in
comma_sp f;
expression ~level:0 cxt f e2)
| Fun (is_method, l, b, env, return_unit) ->
| Fun { is_method; params; body; env; return_unit; async } ->
(* TODO: dump for comments *)
pp_function ~is_method cxt f ~fn_state:default_fn_exp_state l b env
~return_unit
pp_function ~is_method cxt f ~fn_state:default_fn_exp_state params body
env ~return_unit ~async
(* TODO:
when [e] is [Js_raw_code] with arity
print it in a more precise way
@@ -554,12 +553,20 @@ and expression_desc cxt ~(level : int) f x : cxt =
| [
{
expression_desc =
Fun (is_method, l, b, env, return_unit);
Fun
{
is_method;
params;
body;
env;
return_unit;
async;
};
};
] ->
pp_function ~is_method ~return_unit cxt f
pp_function ~is_method ~return_unit ~async cxt f
~fn_state:(No_name { single_arg = true })
l b env
params body env
| _ -> arguments cxt f el)
| _, _ ->
let len = List.length el in
@@ -586,16 +593,14 @@ and expression_desc cxt ~(level : int) f x : cxt =
P.string f L.codePointAt;
(* FIXME: use code_point_at *)
P.paren_group f 1 (fun _ -> expression ~level:0 cxt f b))
| Str {delim; txt} ->
| Str { delim; txt } ->
(*TODO --
when utf8-> it will not escape '\\' which is definitely not we want
*)
if delim = Some "j" || delim = Some "*j" then
P.string f ("\"" ^ txt ^ "\"")
else if delim = Some "json" then
P.string f txt
else
Js_dump_string.pp_string f txt;
else if delim = Some "json" then P.string f txt
else Js_dump_string.pp_string f txt;
cxt
| Raw_js_code { code = s; code_info = info } -> (
match info with
@@ -856,6 +861,10 @@ and expression_desc cxt ~(level : int) f x : cxt =
cxt)
else
P.brace_vgroup f 1 (fun _ -> property_name_and_value_list cxt f lst))
| Await e ->
P.cond_paren_group f (level > 13) 1 (fun _ ->
P.string f "await ";
expression ~level:13 cxt f e)

and property_name_and_value_list cxt f (l : J.property_map) =
iter_lst cxt f l
@@ -897,10 +906,10 @@ and variable_declaration top cxt f (variable : J.variable_declaration) : cxt =
statement_desc top cxt f (J.Exp e)
| _ -> (
match e.expression_desc with
| Fun (is_method, params, b, env, return_unit) ->
pp_function ~is_method cxt f ~return_unit
| Fun { is_method; params; body; env; return_unit; async } ->
pp_function ~is_method cxt f ~return_unit ~async
~fn_state:(if top then Name_top name else Name_non_top name)
params b env
params body env
| _ ->
let cxt = pp_var_assign cxt f name in
let cxt = expression ~level:1 cxt f e in
@@ -1124,10 +1133,10 @@ and statement_desc top cxt f (s : J.statement_desc) : cxt =
cxt
| Return e -> (
match e.expression_desc with
| Fun (is_method, l, b, env, return_unit) ->
| Fun { is_method; params; body; env; return_unit; async } ->
let cxt =
pp_function ~return_unit ~is_method cxt f ~fn_state:Is_return l b
env
pp_function ~return_unit ~is_method ~async cxt f ~fn_state:Is_return
params body env
in
semi f;
cxt
2 changes: 2 additions & 0 deletions jscomp/core/js_dump_lit.ml
Original file line number Diff line number Diff line change
@@ -24,6 +24,8 @@

let function_ = "function"

let function_async ~async = if async then "async function" else "function"

let var = "var" (* should be able to switch to [let] easily*)

let return = "return"
Loading