Skip to content

Commit 1b884e6

Browse files
committed
fix misparsing in/after JSX (#6677)
1 parent 5a0a21d commit 1b884e6

File tree

5 files changed

+108
-33
lines changed

5 files changed

+108
-33
lines changed

jscomp/syntax/src/res_core.ml

Lines changed: 42 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -2612,6 +2612,7 @@ and parseJsxOpeningOrSelfClosingElement ~startPos p =
26122612
let childrenStartPos = p.Parser.startPos in
26132613
Parser.next p;
26142614
let childrenEndPos = p.Parser.startPos in
2615+
Scanner.popMode p.scanner Jsx;
26152616
Parser.expect GreaterThan p;
26162617
let loc = mkLoc childrenStartPos childrenEndPos in
26172618
makeListExpression loc [] None (* no children *)
@@ -2621,8 +2622,6 @@ and parseJsxOpeningOrSelfClosingElement ~startPos p =
26212622
Parser.next p;
26222623
let spread, children = parseJsxChildren p in
26232624
let childrenEndPos = p.Parser.startPos in
2624-
Scanner.popMode p.scanner Jsx;
2625-
Scanner.setJsxMode p.scanner;
26262625
let () =
26272626
match p.token with
26282627
| LessThanSlash -> Parser.next p
@@ -2634,12 +2633,14 @@ and parseJsxOpeningOrSelfClosingElement ~startPos p =
26342633
in
26352634
match p.Parser.token with
26362635
| (Lident _ | Uident _) when verifyJsxOpeningClosingName p name -> (
2636+
Scanner.popMode p.scanner Jsx;
26372637
Parser.expect GreaterThan p;
26382638
let loc = mkLoc childrenStartPos childrenEndPos in
26392639
match (spread, children) with
26402640
| true, child :: _ -> child
26412641
| _ -> makeListExpression loc children None)
26422642
| token -> (
2643+
Scanner.popMode p.scanner Jsx;
26432644
let () =
26442645
if Grammar.isStructureItemStart token then
26452646
let closing = "</" ^ string_of_pexp_ident name ^ ">" in
@@ -2660,6 +2661,7 @@ and parseJsxOpeningOrSelfClosingElement ~startPos p =
26602661
| true, child :: _ -> child
26612662
| _ -> makeListExpression loc children None))
26622663
| token ->
2664+
Scanner.popMode p.scanner Jsx;
26632665
Parser.err p (Diagnostics.unexpected token p.breadcrumbs);
26642666
makeListExpression Location.none [] None
26652667
in
@@ -2687,7 +2689,6 @@ and parseJsxOpeningOrSelfClosingElement ~startPos p =
26872689
* jsx-children ::= primary-expr* * => 0 or more
26882690
*)
26892691
and parseJsx p =
2690-
Scanner.popMode p.scanner Jsx;
26912692
Scanner.setJsxMode p.Parser.scanner;
26922693
Parser.leaveBreadcrumb p Grammar.Jsx;
26932694
let startPos = p.Parser.startPos in
@@ -2700,7 +2701,6 @@ and parseJsx p =
27002701
parseJsxFragment p
27012702
| _ -> parseJsxName p
27022703
in
2703-
Scanner.popMode p.scanner Jsx;
27042704
Parser.eatBreadcrumb p;
27052705
{jsxExpr with pexp_attributes = [jsxAttr]}
27062706

@@ -2714,9 +2714,10 @@ and parseJsxFragment p =
27142714
Parser.expect GreaterThan p;
27152715
let _spread, children = parseJsxChildren p in
27162716
let childrenEndPos = p.Parser.startPos in
2717+
if p.token = LessThan then p.token <- Scanner.reconsiderLessThan p.scanner;
27172718
Parser.expect LessThanSlash p;
2718-
Parser.expect GreaterThan p;
27192719
Scanner.popMode p.scanner Jsx;
2720+
Parser.expect GreaterThan p;
27202721
let loc = mkLoc childrenStartPos childrenEndPos in
27212722
makeListExpression loc children None
27222723

@@ -2756,6 +2757,7 @@ and parseJsxProp p =
27562757
let label =
27572758
if optional then Asttypes.Optional name else Asttypes.Labelled name
27582759
in
2760+
Scanner.setJsxMode p.scanner;
27592761
Some (label, attrExpr)
27602762
| _ ->
27612763
let attrExpr =
@@ -2767,34 +2769,39 @@ and parseJsxProp p =
27672769
in
27682770
Some (label, attrExpr))
27692771
(* {...props} *)
2770-
| Lbrace -> (
2772+
| Lbrace ->
2773+
Scanner.popMode p.scanner Jsx;
27712774
Parser.next p;
2772-
match p.Parser.token with
2773-
| DotDotDot -> (
2774-
Scanner.popMode p.scanner Jsx;
2775-
Parser.next p;
2776-
let loc = mkLoc p.Parser.startPos p.prevEndPos in
2777-
let propLocAttr =
2778-
(Location.mkloc "res.namedArgLoc" loc, Parsetree.PStr [])
2779-
in
2780-
let attrExpr =
2781-
let e = parsePrimaryExpr ~operand:(parseExpr p) p in
2782-
{e with pexp_attributes = propLocAttr :: e.pexp_attributes}
2783-
in
2784-
(* using label "spreadProps" to distinguish from others *)
2785-
let label = Asttypes.Labelled "_spreadProps" in
2775+
let props =
27862776
match p.Parser.token with
2787-
| Rbrace ->
2777+
| DotDotDot -> (
27882778
Parser.next p;
2789-
Some (label, attrExpr)
2790-
| _ -> None)
2791-
| _ -> None)
2779+
let loc = mkLoc p.Parser.startPos p.prevEndPos in
2780+
let propLocAttr =
2781+
(Location.mkloc "res.namedArgLoc" loc, Parsetree.PStr [])
2782+
in
2783+
let attrExpr =
2784+
let e = parsePrimaryExpr ~operand:(parseExpr p) p in
2785+
{e with pexp_attributes = propLocAttr :: e.pexp_attributes}
2786+
in
2787+
(* using label "spreadProps" to distinguish from others *)
2788+
let label = Asttypes.Labelled "_spreadProps" in
2789+
match p.Parser.token with
2790+
| Rbrace ->
2791+
Parser.next p;
2792+
Some (label, attrExpr)
2793+
| _ -> None)
2794+
| _ -> None
2795+
in
2796+
Scanner.setJsxMode p.scanner;
2797+
props
27922798
| _ -> None
27932799

27942800
and parseJsxProps p =
27952801
parseRegion ~grammar:Grammar.JsxAttribute ~f:parseJsxProp p
27962802

27972803
and parseJsxChildren p =
2804+
Scanner.popMode p.scanner Jsx;
27982805
let rec loop p children =
27992806
match p.Parser.token with
28002807
| Token.Eof | LessThanSlash -> children
@@ -2815,21 +2822,23 @@ and parseJsxChildren p =
28152822
let () = p.token <- token in
28162823
children
28172824
| token when Grammar.isJsxChildStart token ->
2818-
let () = Scanner.popMode p.scanner Jsx in
28192825
let child =
28202826
parsePrimaryExpr ~operand:(parseAtomicExpr p) ~noCall:true p
28212827
in
28222828
loop p (child :: children)
28232829
| _ -> children
28242830
in
2825-
match p.Parser.token with
2826-
| DotDotDot ->
2827-
Parser.next p;
2828-
(true, [parsePrimaryExpr ~operand:(parseAtomicExpr p) ~noCall:true p])
2829-
| _ ->
2830-
let children = List.rev (loop p []) in
2831-
Scanner.popMode p.scanner Jsx;
2832-
(false, children)
2831+
let spread, children =
2832+
match p.Parser.token with
2833+
| DotDotDot ->
2834+
Parser.next p;
2835+
(true, [parsePrimaryExpr ~operand:(parseAtomicExpr p) ~noCall:true p])
2836+
| _ ->
2837+
let children = List.rev (loop p []) in
2838+
(false, children)
2839+
in
2840+
Scanner.setJsxMode p.scanner;
2841+
(spread, children)
28332842

28342843
and parseBracedOrRecordExpr p =
28352844
let startPos = p.Parser.startPos in

jscomp/syntax/tests/parsing/grammar/expressions/expected/jsx.res.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -580,11 +580,13 @@ let _ =
580580
;;((div ~children:((span ~children:[] ())[@JSX ]) ())[@JSX ])
581581
;;((div ~children:[|a|] ())[@JSX ])
582582
;;((div ~children:(1, 2) ())[@JSX ])
583+
;;((div ~children:((array |. f)[@res.braces ]) ())[@JSX ])
583584
;;(([element])[@JSX ])
584585
;;(([(((fun a -> 1))[@res.braces ])])[@JSX ])
585586
;;(([((span ~children:[] ())[@JSX ])])[@JSX ])
586587
;;(([[|a|]])[@JSX ])
587588
;;(([(1, 2)])[@JSX ])
589+
;;(([((array |. f)[@res.braces ])])[@JSX ])
588590
let _ =
589591
((A.createElement ~x:(({js|y|js})[@res.namedArgLoc ]) ~_spreadProps:((str)
590592
[@res.namedArgLoc ]) ~children:[] ())

jscomp/syntax/tests/parsing/grammar/expressions/jsx.res

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -507,11 +507,13 @@ let _ = <View style=styles["backgroundImageWrapper"]>
507507
<div> ...<span /> </div>
508508
<div> ...[a] </div>
509509
<div> ...(1, 2) </div>
510+
<div> ...{array->f} </div>
510511

511512
<> ...element </>
512513
<> ...{(a) => 1} </>
513514
<> ...<span /> </>
514515
<> ...[a] </>
515516
<> ...(1, 2) </>
517+
<> ...{array->f} </>
516518

517519
let _ = <A x="y" {...str} />

jscomp/syntax/tests/printer/expr/expected/jsx.res.txt

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -429,3 +429,34 @@ let x = props =>
429429
{...props}
430430
className="inline-block px-6 py-2.5 bg-blue-600 text-white font-medium text-xs leading-tight"
431431
/>
432+
433+
let x = <C> ...{() => msg->React.string} </C>
434+
435+
let x = <C> ...{array->Array.map(React.string)} </C>
436+
437+
let x = <> {array->Array.map(React.string)} </>
438+
439+
let x = {
440+
let _ = <div />
441+
msg->React.string
442+
}
443+
444+
let x = {
445+
let _ = <div> {children} </div>
446+
msg->React.string
447+
}
448+
449+
let x = {
450+
let _ = <> {children} </>
451+
msg->React.string
452+
}
453+
454+
let x = {
455+
let _ = <C />
456+
msg->React.string
457+
}
458+
459+
let x = {
460+
let _ = <C> {children} </C>
461+
msg->React.string
462+
}

jscomp/syntax/tests/printer/expr/jsx.res

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -414,3 +414,34 @@ let x = props =>
414414
{...props}
415415
className="inline-block px-6 py-2.5 bg-blue-600 text-white font-medium text-xs leading-tight"
416416
/>
417+
418+
let x = <C> ...{() => msg->React.string} </C>
419+
420+
let x = <C> ...{array->Array.map(React.string)} </C>
421+
422+
let x = <> ...{array->Array.map(React.string)} </>
423+
424+
let x = {
425+
let _ = <div />
426+
msg->React.string
427+
}
428+
429+
let x = {
430+
let _ = <div> {children} </div>
431+
msg->React.string
432+
}
433+
434+
let x = {
435+
let _ = <> {children} </>
436+
msg->React.string
437+
}
438+
439+
let x = {
440+
let _ = <C />
441+
msg->React.string
442+
}
443+
444+
let x = {
445+
let _ = <C> {children} </C>
446+
msg->React.string
447+
}

0 commit comments

Comments
 (0)