Skip to content
This repository was archived by the owner on Jun 15, 2023. It is now read-only.

Treat await as an almost-unary operator. #711

Merged
merged 5 commits into from
Oct 31, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
2 changes: 1 addition & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@
- Fix issue where the JSX key type is not an optional string https://github.com/rescript-lang/syntax/pull/693
- Fix issue where the JSX fragment without children build error https://github.com/rescript-lang/syntax/pull/704
- Fix issue where async as an id cannot be used with application and labelled arguments https://github.com/rescript-lang/syntax/issues/707

- Treat await as almost-unary operator weaker than pipe so `await foo->bar` means `await (foo->bar)` https://github.com/rescript-lang/syntax/pull/711

#### :eyeglasses: Spec Compliance

Expand Down
3 changes: 2 additions & 1 deletion src/res_core.ml
Original file line number Diff line number Diff line change
Expand Up @@ -3134,7 +3134,8 @@ and parseAwaitExpression p =
let awaitLoc = mkLoc p.Parser.startPos p.endPos in
let awaitAttr = makeAwaitAttr awaitLoc in
Parser.expect Await p;
let expr = parseUnaryExpr p in
let tokenPrec = Token.precedence MinusGreater in
let expr = parseBinaryExpr ~context:OrdinaryExpr p tokenPrec in
{
expr with
pexp_attributes = awaitAttr :: expr.pexp_attributes;
Expand Down
19 changes: 16 additions & 3 deletions src/res_parens.ml
Original file line number Diff line number Diff line change
Expand Up @@ -175,7 +175,11 @@ let flattenOperandRhs parentOperator rhs =
| _ when ParsetreeViewer.isTernaryExpr rhs -> true
| _ -> false

let lazyOrAssertOrAwaitExprRhs expr =
let binaryOperatorInsideAwaitNeedsParens operator =
ParsetreeViewer.operatorPrecedence operator
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there a behind history? it seems different from Res_token.precedence.

< ParsetreeViewer.operatorPrecedence "|."

let lazyOrAssertOrAwaitExprRhs ?(inAwait = false) expr =
let optBraces, _ = ParsetreeViewer.processBracesAttr expr in
match optBraces with
| Some ({Location.loc = bracesLoc}, _) -> Braced bracesLoc
Expand All @@ -186,7 +190,14 @@ let lazyOrAssertOrAwaitExprRhs expr =
| _ :: _ -> true
| [] -> false ->
Parenthesized
| expr when ParsetreeViewer.isBinaryExpression expr -> Parenthesized
| {
pexp_desc =
Pexp_apply ({pexp_desc = Pexp_ident {txt = Longident.Lident operator}}, _);
}
when ParsetreeViewer.isBinaryExpression expr ->
if inAwait && not (binaryOperatorInsideAwaitNeedsParens operator) then
Nothing
else Parenthesized
| {
pexp_desc =
Pexp_constraint ({pexp_desc = Pexp_pack _}, {ptyp_desc = Ptyp_package _});
Expand All @@ -202,7 +213,9 @@ let lazyOrAssertOrAwaitExprRhs expr =
| Pexp_try _ | Pexp_while _ | Pexp_for _ | Pexp_ifthenelse _ );
} ->
Parenthesized
| _ when ParsetreeViewer.hasAwaitAttribute expr.pexp_attributes ->
| _
when (not inAwait)
&& ParsetreeViewer.hasAwaitAttribute expr.pexp_attributes ->
Parenthesized
| _ -> Nothing)

Expand Down
3 changes: 2 additions & 1 deletion src/res_parens.mli
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,8 @@ val subBinaryExprOperand : string -> string -> bool
val rhsBinaryExprOperand : string -> Parsetree.expression -> bool
val flattenOperandRhs : string -> Parsetree.expression -> bool

val lazyOrAssertOrAwaitExprRhs : Parsetree.expression -> kind
val binaryOperatorInsideAwaitNeedsParens : string -> bool
val lazyOrAssertOrAwaitExprRhs : ?inAwait:bool -> Parsetree.expression -> kind

val fieldExpr : Parsetree.expression -> kind

Expand Down
11 changes: 8 additions & 3 deletions src/res_printer.ml
Original file line number Diff line number Diff line change
Expand Up @@ -3330,13 +3330,13 @@ and printExpression ~customLayout (e : Parsetree.expression) cmtTbl =
if ParsetreeViewer.hasAwaitAttribute e.pexp_attributes then
let rhs =
match
Parens.lazyOrAssertOrAwaitExprRhs
Parens.lazyOrAssertOrAwaitExprRhs ~inAwait:true
{
e with
pexp_attributes =
List.filter
(function
| {Location.txt = "res.await" | "ns.braces"}, _ -> false
| {Location.txt = "ns.braces"}, _ -> false
| _ -> true)
e.pexp_attributes;
}
Expand Down Expand Up @@ -3612,13 +3612,18 @@ and printBinaryExpression ~customLayout (expr : Parsetree.expression) cmtTbl =
in
let doc =
if isAwait then
let parens =
Res_parens.binaryOperatorInsideAwaitNeedsParens operator
in
Doc.concat
[
Doc.text "await ";
Doc.lparen;
Doc.text "await ";
(if parens then Doc.lparen else Doc.nil);
leftPrinted;
printBinaryOperator ~inlineRhs:false operator;
rightPrinted;
(if parens then Doc.rparen else Doc.nil);
Doc.rparen;
]
else
Expand Down
7 changes: 6 additions & 1 deletion tests/parsing/grammar/expressions/async.res
Original file line number Diff line number Diff line change
Expand Up @@ -29,4 +29,9 @@ let async = {
let f = isPositive ? (async (a, b) : int => a + b) : async (c, d) : int => c - d

let foo = async(~a=34)
let bar = async(~a)=>a+1
let bar = async(~a)=>a+1

let ex1 = await 3 + await 4
let ex2 = await 3 ** await 4
let ex3 = await foo->bar(~arg)
let ex4 = await foo.bar.baz
6 changes: 5 additions & 1 deletion tests/parsing/grammar/expressions/expected/async.res.txt
Original file line number Diff line number Diff line change
Expand Up @@ -27,4 +27,8 @@ let f =
else (((fun c -> fun d -> (c - d : int)))[@res.async ]))
[@ns.ternary ])
let foo = async ~a:((34)[@ns.namedArgLoc ])
let bar = ((fun ~a:((a)[@ns.namedArgLoc ]) -> a + 1)[@res.async ])
let bar = ((fun ~a:((a)[@ns.namedArgLoc ]) -> a + 1)[@res.async ])
let ex1 = ((3)[@res.await ]) + ((4)[@res.await ])
let ex2 = ((3)[@res.await ]) ** ((4)[@res.await ])
let ex3 = ((foo |. (bar ~arg:((arg)[@ns.namedArgLoc ])))[@res.await ])
let ex4 = (((foo.bar).baz)[@res.await ])
13 changes: 12 additions & 1 deletion tests/printer/expr/asyncAwait.res
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,17 @@ let f13 = @a @b (~x) => 3

let aw = (await (server->start))->foo
let aw = (@foo (server->start))->foo
let aw = (await (3**4))->foo

let foo = async(~a=34)
let bar = async(~a)=>a+1
let bar = async(~a)=>a+1

let a1 = await 3 + await 4
let a2 = await 3 ** await 4
let a3 = await foo->bar(~arg)
let a4 = await foo.bar.baz

let b1 = await (3+4)
let b2 = await (3**4)
let b3 = await (foo->bar(~arg))
let b4 = await (foo.bar.baz)
21 changes: 16 additions & 5 deletions tests/printer/expr/expected/asyncAwait.res.txt
Original file line number Diff line number Diff line change
Expand Up @@ -30,14 +30,14 @@ user.data = await fetch()

<Navbar promise={await gc()}> {await weirdReactSuspenseApi} </Navbar>

let inBinaryExpression = (await x)->Js.Promise.resolve + 1
let inBinaryExpression = (await x)->Js.Promise.resolve + (await y)->Js.Promise.resolve
let inBinaryExpression = await x->Js.Promise.resolve + 1
let inBinaryExpression = await x->Js.Promise.resolve + await y->Js.Promise.resolve

let withCallback = async (. ()) => {
async (. x) => await (x->Js.promise.resolve) + 1
async (. x) => await x->Js.promise.resolve + 1
}

let () = (await fetch(url))->(await resolve)
let () = await (await fetch(url))->(await resolve)

let _ = await (1 + 1)
let _ = (await 1) + 1
Expand Down Expand Up @@ -119,8 +119,19 @@ let f11 = (. ~x) => (. ~y) => 3
let f12 = @a x => 3
let f13 = (@a @b ~x) => 3

let aw = await (server->start)->foo
let aw = (await server->start)->foo
let aw = @foo (server->start)->foo
let aw = (await (3 ** 4))->foo

let foo = async(~a=34)
let bar = async (~a) => a + 1

let a1 = (await 3) + (await 4)
let a2 = (await 3) ** (await 4)
let a3 = await foo->bar(~arg)
let a4 = await foo.bar.baz

let b1 = await (3 + 4)
let b2 = await (3 ** 4)
let b3 = await foo->bar(~arg)
let b4 = await foo.bar.baz