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

Commit ab23e08

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 f283e85 commit ab23e08

File tree

6 files changed

+58
-8
lines changed

6 files changed

+58
-8
lines changed

src/res_core.ml

+34-4
Original file line numberDiff line numberDiff line change
@@ -3267,14 +3267,13 @@ and parseArgument p =
32673267
match p.Parser.token with
32683268
| Dot ->
32693269
let uncurried = true in
3270-
let startPos = p.Parser.startPos in
32713270
Parser.next(p);
32723271
begin match p.token with
32733272
(* apply(.) *)
32743273
| Rparen ->
3275-
let loc = mkLoc startPos p.prevEndPos in
3276-
let unitExpr = Ast_helper.Exp.construct ~loc
3277-
(Location.mkloc (Longident.Lident "()") loc) None
3274+
let unitExpr = Ast_helper.Exp.construct
3275+
(Location.mknoloc (Longident.Lident "()"))
3276+
None
32783277
in
32793278
Some (uncurried, Asttypes.Nolabel, unitExpr)
32803279
| _ ->
@@ -3368,6 +3367,37 @@ and parseCallExpr p funExpr =
33683367
Ast_helper.Exp.construct
33693368
~loc (Location.mkloc (Longident.Lident "()") loc) None
33703369
]
3370+
| [
3371+
true,
3372+
Asttypes.Nolabel,
3373+
({
3374+
pexp_desc = Pexp_construct ({txt = Longident.Lident "()"}, None);
3375+
pexp_loc = loc;
3376+
pexp_attributes = []
3377+
} as expr)
3378+
] when (not loc.loc_ghost) && p.mode = ParseForTypeChecker ->
3379+
(* Since there is no syntax space for arity zero vs arity one,
3380+
* we expand
3381+
* `fn(. ())` into
3382+
* `fn(. {let __res_unit = (); __res_unit})`
3383+
* when the parsetree is intended for type checking
3384+
*
3385+
* Note:
3386+
* `fn(.)` is treated as zero arity application.
3387+
* The invisible unit expression here has loc_ghost === true
3388+
*
3389+
* Related: https://github.com/rescript-lang/syntax/issues/138
3390+
*)
3391+
[
3392+
true,
3393+
Asttypes.Nolabel,
3394+
Ast_helper.Exp.let_
3395+
Asttypes.Nonrecursive
3396+
[Ast_helper.Vb.mk
3397+
(Ast_helper.Pat.var (Location.mknoloc "__res_unit"))
3398+
expr]
3399+
(Ast_helper.Exp.ident (Location.mknoloc (Longident.Lident "__res_unit")))
3400+
]
33713401
| args -> args
33723402
in
33733403
let loc = {funExpr.pexp_loc with loc_end = p.prevEndPos} in

src/res_printer.ml

+9-2
Original file line numberDiff line numberDiff line change
@@ -4013,8 +4013,15 @@ and printArgumentsWithCallbackInLastPosition ~uncurried args cmtTbl =
40134013

40144014
and printArguments ~uncurried (args : (Asttypes.arg_label * Parsetree.expression) list) cmtTbl =
40154015
match args with
4016-
| [Nolabel, {pexp_desc = Pexp_construct ({txt = Longident.Lident "()"}, _)}] ->
4017-
if uncurried then Doc.text "(.)" else Doc.text "()"
4016+
| [Nolabel, {pexp_desc = Pexp_construct ({txt = Longident.Lident "()"}, _); pexp_loc = loc}] ->
4017+
(* See "parseCallExpr", ghost unit expression is used the implement
4018+
* arity zero vs arity one syntax.
4019+
* Related: https://github.com/rescript-lang/syntax/issues/138 *)
4020+
begin match uncurried, loc.loc_ghost with
4021+
| true, true -> Doc.text "(.)" (* arity zero *)
4022+
| true, false -> Doc.text "(. ())" (* arity one *)
4023+
| _ -> Doc.text "()"
4024+
end
40184025
| [(Nolabel, arg)] when ParsetreeViewer.isHuggableExpression arg ->
40194026
let argDoc =
40204027
let doc = printExpressionWithComments arg cmtTbl in

tests/parsing/grammar/expressions/__snapshots__/parse.spec.js.snap

+5-2
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,8 @@ let unitUncurried = ((apply ())[@bs ])
1212
`;
1313

1414
exports[`argument.js 1`] = `
15-
"let foo ~a:((a)[@ns.namedArgLoc ]) = ((a ())[@bs ]) +. 1.
15+
"let foo ~a:((a)[@ns.namedArgLoc ]) =
16+
((a (let __res_unit = () in __res_unit))[@bs ]) +. 1.
1617
let a = ((fun () -> 2)[@bs ])
1718
let bar = foo ~a:((a)[@ns.namedArgLoc ])
1819
let comparisonResult =
@@ -21,7 +22,9 @@ let comparisonResult =
2122
;;((callback firstNode ~y:((y)[@ns.namedArgLoc ]))[@bs ])
2223
;;((document.createElementWithOptions \\"div\\"
2324
(elementProps ~onClick:((fun _ -> Js.log \\"hello world\\")
24-
[@ns.namedArgLoc ])))[@bs ])"
25+
[@ns.namedArgLoc ])))[@bs ])
26+
;;((resolve ())[@bs ])
27+
;;((resolve (let __res_unit = () in __res_unit))[@bs ])"
2528
`;
2629

2730
exports[`array.js 1`] = `

tests/parsing/grammar/expressions/argument.js

+4
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(. ())

tests/printer/expr/__snapshots__/render.spec.js.snap

+3
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,9 @@ document.createElementWithOptions(.
7373
\\"div\\",
7474
elementProps(~onClick=_ => Js.log(\\"hello world\\")),
7575
)
76+
77+
resolve(.)
78+
resolve(. ())
7679
"
7780
`;
7881

tests/printer/expr/apply.js

+3
Original file line numberDiff line numberDiff line change
@@ -46,3 +46,6 @@ call(~\"let": int)
4646
document.createElementWithOptions(. "div", elementProps(~onClick=_ =>
4747
Js.log("hello world")
4848
))
49+
50+
resolve(.)
51+
resolve(. ())

0 commit comments

Comments
 (0)