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

Commit 2e0b219

Browse files
committed
Add if let syntax
1 parent 5e87f9d commit 2e0b219

File tree

8 files changed

+778
-120
lines changed

8 files changed

+778
-120
lines changed

src/napkin_core.ml

Lines changed: 75 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,7 @@ end
8383
let jsxAttr = (Location.mknoloc "JSX", Parsetree.PStr [])
8484
let uncurryAttr = (Location.mknoloc "bs", Parsetree.PStr [])
8585
let ternaryAttr = (Location.mknoloc "ns.ternary", Parsetree.PStr [])
86+
let ifLetAttr = (Location.mknoloc "ns.iflet", Parsetree.PStr [])
8687
let makeBracesAttr loc = (Location.mkloc "ns.braces" loc, Parsetree.PStr [])
8788

8889
type typDefOrExt =
@@ -2000,7 +2001,7 @@ and parseOperandExpr ~context p =
20002001
| Try ->
20012002
parseTryExpression p
20022003
| If ->
2003-
parseIfExpression p
2004+
parseIfOrIfLetExpression p
20042005
| For ->
20052006
parseForExpression p
20062007
| While ->
@@ -2996,20 +2997,30 @@ and parseTryExpression p =
29962997
let loc = mkLoc startPos p.prevEndPos in
29972998
Ast_helper.Exp.try_ ~loc expr cases
29982999

2999-
and parseIfExpression p =
3000-
Parser.beginRegion p;
3001-
Parser.leaveBreadcrumb p Grammar.ExprIf;
3002-
let startPos = p.Parser.startPos in
3003-
Parser.expect If p;
3000+
and parseIfCondition p =
30043001
Parser.leaveBreadcrumb p Grammar.IfCondition;
30053002
(* doesn't make sense to try es6 arrow here? *)
30063003
let conditionExpr = parseExpr ~context:WhenExpr p in
30073004
Parser.eatBreadcrumb p;
3005+
conditionExpr
3006+
3007+
and parseThenBranch p =
30083008
Parser.leaveBreadcrumb p IfBranch;
30093009
Parser.expect Lbrace p;
30103010
let thenExpr = parseExprBlock p in
30113011
Parser.expect Rbrace p;
30123012
Parser.eatBreadcrumb p;
3013+
thenExpr
3014+
3015+
and parseElseBranch p =
3016+
Parser.expect Lbrace p;
3017+
let blockExpr = parseExprBlock p in
3018+
Parser.expect Rbrace p;
3019+
blockExpr;
3020+
3021+
and parseIfExpr startPos p =
3022+
let conditionExpr = parseIfCondition p in
3023+
let thenExpr = parseThenBranch p in
30133024
let elseExpr = match p.Parser.token with
30143025
| Else ->
30153026
Parser.endRegion p;
@@ -3018,12 +3029,9 @@ and parseIfExpression p =
30183029
Parser.beginRegion p;
30193030
let elseExpr = match p.token with
30203031
| If ->
3021-
parseIfExpression p
3032+
parseIfOrIfLetExpression p
30223033
| _ ->
3023-
Parser.expect Lbrace p;
3024-
let blockExpr = parseExprBlock p in
3025-
Parser.expect Rbrace p;
3026-
blockExpr
3034+
parseElseBranch p
30273035
in
30283036
Parser.eatBreadcrumb p;
30293037
Parser.endRegion p;
@@ -3033,9 +3041,55 @@ and parseIfExpression p =
30333041
None
30343042
in
30353043
let loc = mkLoc startPos p.prevEndPos in
3036-
Parser.eatBreadcrumb p;
30373044
Ast_helper.Exp.ifthenelse ~loc conditionExpr thenExpr elseExpr
30383045

3046+
and parseIfLetExpr startPos p =
3047+
let pattern = parsePattern p in
3048+
Parser.expect Equal p;
3049+
let conditionExpr = parseIfCondition p in
3050+
let thenExpr = parseThenBranch p in
3051+
let elseExpr = match p.Parser.token with
3052+
| Else ->
3053+
Parser.endRegion p;
3054+
Parser.leaveBreadcrumb p Grammar.ElseBranch;
3055+
Parser.next p;
3056+
Parser.beginRegion p;
3057+
let elseExpr = match p.token with
3058+
| If ->
3059+
parseIfOrIfLetExpression p
3060+
| _ ->
3061+
parseElseBranch p
3062+
in
3063+
Parser.eatBreadcrumb p;
3064+
Parser.endRegion p;
3065+
elseExpr
3066+
| _ ->
3067+
Parser.endRegion p;
3068+
let startPos = p.Parser.startPos in
3069+
let loc = mkLoc startPos p.prevEndPos in
3070+
Ast_helper.Exp.construct ~loc (Location.mkloc (Longident.Lident "()") loc) None
3071+
in
3072+
let loc = mkLoc startPos p.prevEndPos in
3073+
Ast_helper.Exp.match_ ~attrs:[ifLetAttr] ~loc conditionExpr [
3074+
Ast_helper.Exp.case pattern thenExpr;
3075+
Ast_helper.Exp.case (Ast_helper.Pat.any ()) elseExpr;
3076+
]
3077+
3078+
and parseIfOrIfLetExpression p =
3079+
Parser.beginRegion p;
3080+
Parser.leaveBreadcrumb p Grammar.ExprIf;
3081+
let startPos = p.Parser.startPos in
3082+
Parser.expect If p;
3083+
let expr = match p.Parser.token with
3084+
| Let ->
3085+
Parser.next p;
3086+
parseIfLetExpr startPos p
3087+
| _ ->
3088+
parseIfExpr startPos p
3089+
in
3090+
Parser.eatBreadcrumb p;
3091+
expr;
3092+
30393093
and parseForRest hasOpeningParen pattern startPos p =
30403094
Parser.expect In p;
30413095
let e1 = parseExpr p in
@@ -3098,20 +3152,22 @@ and parseWhileExpression p =
30983152
let loc = mkLoc startPos p.prevEndPos in
30993153
Ast_helper.Exp.while_ ~loc expr1 expr2
31003154

3155+
and parsePatternGuard p =
3156+
match p.Parser.token with
3157+
| When ->
3158+
Parser.next p;
3159+
Some (parseExpr ~context:WhenExpr p)
3160+
| _ ->
3161+
None
3162+
31013163
and parsePatternMatchCase p =
31023164
Parser.beginRegion p;
31033165
Parser.leaveBreadcrumb p Grammar.PatternMatchCase;
31043166
match p.Parser.token with
31053167
| Token.Bar ->
31063168
Parser.next p;
31073169
let lhs = parsePattern p in
3108-
let guard = match p.Parser.token with
3109-
| When ->
3110-
Parser.next p;
3111-
Some (parseExpr ~context:WhenExpr p)
3112-
| _ ->
3113-
None
3114-
in
3170+
let guard = parsePatternGuard p in
31153171
let () = match p.token with
31163172
| EqualGreater -> Parser.next p
31173173
| _ -> Recover.recoverEqualGreater p

src/napkin_parsetree_viewer.ml

Lines changed: 51 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -42,18 +42,6 @@ open Parsetree
4242
in
4343
process false [] attrs
4444

45-
let collectIfExpressions expr =
46-
let rec collect acc expr = match expr.pexp_desc with
47-
| Pexp_ifthenelse (ifExpr, thenExpr, Some elseExpr) ->
48-
collect ((ifExpr, thenExpr)::acc) elseExpr
49-
| Pexp_ifthenelse (ifExpr, thenExpr, (None as elseExpr)) ->
50-
let ifs = List.rev ((ifExpr, thenExpr)::acc) in
51-
(ifs, elseExpr)
52-
| _ ->
53-
(List.rev acc, Some expr)
54-
in
55-
collect [] expr
56-
5745
let collectListExpressions expr =
5846
let rec collect acc expr = match expr.pexp_desc with
5947
| Pexp_construct ({txt = Longident.Lident "[]"}, _) ->
@@ -165,7 +153,7 @@ open Parsetree
165153
let filterParsingAttrs attrs =
166154
List.filter (fun attr ->
167155
match attr with
168-
| ({Location.txt = ("ns.ternary" | "ns.braces" | "bs" | "ns.namedArgLoc")}, _) -> false
156+
| ({Location.txt = ("ns.ternary" | "ns.braces" | "bs" | "ns.iflet" | "ns.namedArgLoc")}, _) -> false
169157
| _ -> true
170158
) attrs
171159

@@ -269,7 +257,7 @@ open Parsetree
269257

270258
let hasAttributes attrs =
271259
List.exists (fun attr -> match attr with
272-
| ({Location.txt = "bs" | "ns.ternary" | "ns.braces"}, _) -> false
260+
| ({Location.txt = "bs" | "ns.ternary" | "ns.braces" | "ns.iflet"}, _) -> false
273261
| _ -> true
274262
) attrs
275263

@@ -280,6 +268,52 @@ open Parsetree
280268
) -> true
281269
| _ -> false
282270

271+
let rec hasIfLetAttribute attrs =
272+
match attrs with
273+
| [] -> false
274+
| ({Location.txt="ns.iflet"},_)::_ -> true
275+
| _::attrs -> hasIfLetAttribute attrs
276+
277+
let isIfLetExpr expr = match expr with
278+
| {
279+
pexp_attributes = attrs;
280+
pexp_desc = Pexp_match _
281+
} when hasIfLetAttribute attrs -> true
282+
| _ -> false
283+
284+
type ifConditionKind =
285+
| If of Parsetree.expression
286+
| IfLet of Parsetree.pattern * Parsetree.expression
287+
288+
let collectIfExpressions expr =
289+
let rec collect acc expr = match expr.pexp_desc with
290+
| Pexp_ifthenelse (ifExpr, thenExpr, Some elseExpr) ->
291+
collect ((If(ifExpr), thenExpr)::acc) elseExpr
292+
| Pexp_ifthenelse (ifExpr, thenExpr, (None as elseExpr)) ->
293+
let ifs = List.rev ((If(ifExpr), thenExpr)::acc) in
294+
(ifs, elseExpr)
295+
| Pexp_match (condition, [{
296+
pc_lhs = pattern;
297+
pc_guard = None;
298+
pc_rhs = thenExpr;
299+
}; {
300+
pc_rhs = {pexp_desc = Pexp_construct ({txt = Longident.Lident "()"}, _)}
301+
}]) when isIfLetExpr expr ->
302+
let ifs = List.rev ((IfLet(pattern, condition), thenExpr)::acc) in
303+
(ifs, None)
304+
| Pexp_match (condition, [{
305+
pc_lhs = pattern;
306+
pc_guard = None;
307+
pc_rhs = thenExpr;
308+
}; {
309+
pc_rhs = elseExpr;
310+
}]) when isIfLetExpr expr ->
311+
collect ((IfLet(pattern, condition), thenExpr)::acc) elseExpr
312+
| _ ->
313+
(List.rev acc, Some expr)
314+
in
315+
collect [] expr
316+
283317
let rec hasTernaryAttribute attrs =
284318
match attrs with
285319
| [] -> false
@@ -371,13 +405,13 @@ open Parsetree
371405

372406
let filterPrinteableAttributes attrs =
373407
List.filter (fun attr -> match attr with
374-
| ({Location.txt="bs" | "ns.ternary"}, _) -> false
408+
| ({Location.txt="bs" | "ns.ternary" | "ns.iflet"}, _) -> false
375409
| _ -> true
376410
) attrs
377411

378412
let partitionPrinteableAttributes attrs =
379413
List.partition (fun attr -> match attr with
380-
| ({Location.txt="bs" | "ns.ternary"}, _) -> false
414+
| ({Location.txt="bs" | "ns.ternary" | "ns.iflet"}, _) -> false
381415
| _ -> true
382416
) attrs
383417

@@ -513,4 +547,4 @@ open Parsetree
513547
{ppat_desc = Ppat_var {txt="__x"}},
514548
{pexp_desc = Pexp_apply _}
515549
) -> true
516-
| _ -> false
550+
| _ -> false

src/napkin_parsetree_viewer.mli

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,12 +13,16 @@ val functorType: Parsetree.module_type ->
1313
(* filters @bs out of the provided attributes *)
1414
val processUncurriedAttribute: Parsetree.attributes -> bool * Parsetree.attributes
1515

16+
type ifConditionKind =
17+
| If of Parsetree.expression
18+
| IfLet of Parsetree.pattern * Parsetree.expression
19+
1620
(* if ... else if ... else ... is represented as nested expressions: if ... else { if ... }
1721
* The purpose of this function is to flatten nested ifs into one sequence.
1822
* Basically compute: ([if, else if, else if, else if], else) *)
1923
val collectIfExpressions:
2024
Parsetree.expression ->
21-
(Parsetree.expression * Parsetree.expression) list * Parsetree.expression option
25+
(ifConditionKind * Parsetree.expression) list * Parsetree.expression option
2226

2327
val collectListExpressions:
2428
Parsetree.expression -> (Parsetree.expression list * Parsetree.expression option)
@@ -62,6 +66,7 @@ val hasAttributes: Parsetree.attributes -> bool
6266

6367
val isArrayAccess: Parsetree.expression -> bool
6468
val isTernaryExpr: Parsetree.expression -> bool
69+
val isIfLetExpr: Parsetree.expression -> bool
6570

6671
val collectTernaryParts: Parsetree.expression -> ((Parsetree.expression * Parsetree.expression) list * Parsetree.expression)
6772

@@ -90,7 +95,7 @@ val modExprApply : Parsetree.module_expr -> (
9095
* Example: given a ptyp_arrow type, what are its arguments and what is the
9196
* returnType? *)
9297

93-
98+
9499
val modExprFunctor : Parsetree.module_expr -> (
95100
(Parsetree.attributes * string Asttypes.loc * Parsetree.module_type option) list *
96101
Parsetree.module_expr
@@ -130,4 +135,4 @@ val classifyJsImport: Parsetree.value_description -> jsImportScope
130135
val rewriteUnderscoreApply: Parsetree.expression -> Parsetree.expression
131136

132137
(* (__x) => f(a, __x, c) -----> f(a, _, c) *)
133-
val isUnderscoreApplySugar: Parsetree.expression -> bool
138+
val isUnderscoreApplySugar: Parsetree.expression -> bool

0 commit comments

Comments
 (0)