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

Commit c696d8e

Browse files
author
Iwan
committed
implement syntax for arity zero vs arity one in uncurried application
Since there is no syntax space for arity zero vs arity one, we parse `fn(. ())` into `fn(. {let __res_unit = (); __res_unit})` when the parsetree is intended for type checking `fn(.)` is treated as zero arity application
1 parent 19f1147 commit c696d8e

File tree

7 files changed

+78
-8
lines changed

7 files changed

+78
-8
lines changed

src/res_ast_conversion.ml

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -318,6 +318,11 @@ let stringLiteralMapper stringData =
318318
)
319319
}
320320

321+
let hasUncurriedAttribute attrs = List.exists (fun attr -> match attr with
322+
| ({Asttypes.txt = "bs"}, Parsetree.PStr []) -> true
323+
| _ -> false
324+
) attrs
325+
321326
let normalize =
322327
let open Ast_mapper in
323328
{ default_mapper with
@@ -394,6 +399,21 @@ let normalize =
394399
pexp_attributes = mapper.attributes mapper expr.pexp_attributes;
395400
pexp_desc = Pexp_constant s
396401
}
402+
| Pexp_apply (
403+
callExpr,
404+
[
405+
Nolabel,
406+
({pexp_desc = Pexp_construct ({txt = Longident.Lident "()"}, None); pexp_attributes = []} as unitExpr)
407+
]
408+
) when hasUncurriedAttribute expr.pexp_attributes
409+
->
410+
{expr with
411+
pexp_attributes = mapper.attributes mapper expr.pexp_attributes;
412+
pexp_desc = Pexp_apply (
413+
callExpr,
414+
[Nolabel, {unitExpr with pexp_loc = {unitExpr.pexp_loc with loc_ghost = true}}]
415+
)
416+
}
397417
| Pexp_function cases ->
398418
let loc = match (cases, List.rev cases) with
399419
| (first::_), (last::_) ->

src/res_core.ml

Lines changed: 34 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3385,14 +3385,13 @@ and parseArgument p =
33853385
match p.Parser.token with
33863386
| Dot ->
33873387
let uncurried = true in
3388-
let startPos = p.Parser.startPos in
33893388
Parser.next(p);
33903389
begin match p.token with
33913390
(* apply(.) *)
33923391
| Rparen ->
3393-
let loc = mkLoc startPos p.prevEndPos in
3394-
let unitExpr = Ast_helper.Exp.construct ~loc
3395-
(Location.mkloc (Longident.Lident "()") loc) None
3392+
let unitExpr = Ast_helper.Exp.construct
3393+
(Location.mknoloc (Longident.Lident "()"))
3394+
None
33963395
in
33973396
Some (uncurried, Asttypes.Nolabel, unitExpr)
33983397
| _ ->
@@ -3486,6 +3485,37 @@ and parseCallExpr p funExpr =
34863485
Ast_helper.Exp.construct
34873486
~loc (Location.mkloc (Longident.Lident "()") loc) None
34883487
]
3488+
| [
3489+
true,
3490+
Asttypes.Nolabel,
3491+
({
3492+
pexp_desc = Pexp_construct ({txt = Longident.Lident "()"}, None);
3493+
pexp_loc = loc;
3494+
pexp_attributes = []
3495+
} as expr)
3496+
] when (not loc.loc_ghost) && p.mode = ParseForTypeChecker ->
3497+
(* Since there is no syntax space for arity zero vs arity one,
3498+
* we expand
3499+
* `fn(. ())` into
3500+
* `fn(. {let __res_unit = (); __res_unit})`
3501+
* when the parsetree is intended for type checking
3502+
*
3503+
* Note:
3504+
* `fn(.)` is treated as zero arity application.
3505+
* The invisible unit expression here has loc_ghost === true
3506+
*
3507+
* Related: https://github.com/rescript-lang/syntax/issues/138
3508+
*)
3509+
[
3510+
true,
3511+
Asttypes.Nolabel,
3512+
Ast_helper.Exp.let_
3513+
Asttypes.Nonrecursive
3514+
[Ast_helper.Vb.mk
3515+
(Ast_helper.Pat.var (Location.mknoloc "__res_unit"))
3516+
expr]
3517+
(Ast_helper.Exp.ident (Location.mknoloc (Longident.Lident "__res_unit")))
3518+
]
34893519
| args -> args
34903520
in
34913521
let loc = {funExpr.pexp_loc with loc_end = p.prevEndPos} in

src/res_printer.ml

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4248,8 +4248,15 @@ and printArgumentsWithCallbackInLastPosition ~uncurried args cmtTbl =
42484248

42494249
and printArguments ~uncurried (args : (Asttypes.arg_label * Parsetree.expression) list) cmtTbl =
42504250
match args with
4251-
| [Nolabel, {pexp_desc = Pexp_construct ({txt = Longident.Lident "()"}, _)}] ->
4252-
if uncurried then Doc.text "(.)" else Doc.text "()"
4251+
| [Nolabel, {pexp_desc = Pexp_construct ({txt = Longident.Lident "()"}, _); pexp_loc = loc}] ->
4252+
(* See "parseCallExpr", ghost unit expression is used the implement
4253+
* arity zero vs arity one syntax.
4254+
* Related: https://github.com/rescript-lang/syntax/issues/138 *)
4255+
begin match uncurried, loc.loc_ghost with
4256+
| true, true -> Doc.text "(.)" (* arity zero *)
4257+
| true, false -> Doc.text "(. ())" (* arity one *)
4258+
| _ -> Doc.text "()"
4259+
end
42534260
| [(Nolabel, arg)] when ParsetreeViewer.isHuggableExpression arg ->
42544261
let argDoc =
42554262
let doc = printExpressionWithComments arg cmtTbl in

tests/parsing/grammar/expressions/argument.res

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,3 +7,7 @@ callback(. firstNode, ~y)
77
document.createElementWithOptions(. "div", elementProps(~onClick=_ =>
88
Js.log("hello world")
99
))
10+
11+
12+
resolve(.)
13+
resolve(. ())
Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
let foo ~a:((a)[@ns.namedArgLoc ]) = ((a ())[@bs ]) +. 1.
1+
let foo ~a:((a)[@ns.namedArgLoc ]) =
2+
((a (let __res_unit = () in __res_unit))[@bs ]) +. 1.
23
let a = ((fun () -> 2)[@bs ])
34
let bar = foo ~a:((a)[@ns.namedArgLoc ])
45
let comparisonResult =
@@ -7,4 +8,6 @@ let comparisonResult =
78
;;((callback firstNode ~y:((y)[@ns.namedArgLoc ]))[@bs ])
89
;;((document.createElementWithOptions "div"
910
(elementProps ~onClick:((fun _ -> Js.log "hello world")
10-
[@ns.namedArgLoc ])))[@bs ])
11+
[@ns.namedArgLoc ])))[@bs ])
12+
;;((resolve ())[@bs ])
13+
;;((resolve (let __res_unit = () in __res_unit))[@bs ])

tests/printer/expr/apply.res

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,3 +70,6 @@ f(. {
7070
exception Exit
7171
raise(Exit)
7272
})
73+
74+
resolve(.)
75+
resolve(. ())

tests/printer/expr/expected/apply.res.txt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,3 +90,6 @@ f(. {
9090
exception Exit
9191
raise(Exit)
9292
})
93+
94+
resolve(.)
95+
resolve(. ())

0 commit comments

Comments
 (0)