diff --git a/CHANGELOG.md b/CHANGELOG.md index ce537b34cd..8d5164d631 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,6 +12,10 @@ # 11.1.0-rc.5 (Unreleased) +#### :bug: Bug Fix + +- Fix misparsing in/after JSX. https://github.com/rescript-lang/rescript-compiler/pull/6686 + # 11.1.0-rc.4 #### :bug: Bug Fix diff --git a/jscomp/syntax/src/res_core.ml b/jscomp/syntax/src/res_core.ml index b88a9fd4cc..189f80de5d 100644 --- a/jscomp/syntax/src/res_core.ml +++ b/jscomp/syntax/src/res_core.ml @@ -2612,6 +2612,7 @@ and parseJsxOpeningOrSelfClosingElement ~startPos p = let childrenStartPos = p.Parser.startPos in Parser.next p; let childrenEndPos = p.Parser.startPos in + Scanner.popMode p.scanner Jsx; Parser.expect GreaterThan p; let loc = mkLoc childrenStartPos childrenEndPos in makeListExpression loc [] None (* no children *) @@ -2621,8 +2622,6 @@ and parseJsxOpeningOrSelfClosingElement ~startPos p = Parser.next p; let spread, children = parseJsxChildren p in let childrenEndPos = p.Parser.startPos in - Scanner.popMode p.scanner Jsx; - Scanner.setJsxMode p.scanner; let () = match p.token with | LessThanSlash -> Parser.next p @@ -2634,12 +2633,14 @@ and parseJsxOpeningOrSelfClosingElement ~startPos p = in match p.Parser.token with | (Lident _ | Uident _) when verifyJsxOpeningClosingName p name -> ( + Scanner.popMode p.scanner Jsx; Parser.expect GreaterThan p; let loc = mkLoc childrenStartPos childrenEndPos in match (spread, children) with | true, child :: _ -> child | _ -> makeListExpression loc children None) | token -> ( + Scanner.popMode p.scanner Jsx; let () = if Grammar.isStructureItemStart token then let closing = "" in @@ -2660,6 +2661,7 @@ and parseJsxOpeningOrSelfClosingElement ~startPos p = | true, child :: _ -> child | _ -> makeListExpression loc children None)) | token -> + Scanner.popMode p.scanner Jsx; Parser.err p (Diagnostics.unexpected token p.breadcrumbs); makeListExpression Location.none [] None in @@ -2687,7 +2689,6 @@ and parseJsxOpeningOrSelfClosingElement ~startPos p = * jsx-children ::= primary-expr* * => 0 or more *) and parseJsx p = - Scanner.popMode p.scanner Jsx; Scanner.setJsxMode p.Parser.scanner; Parser.leaveBreadcrumb p Grammar.Jsx; let startPos = p.Parser.startPos in @@ -2700,7 +2701,6 @@ and parseJsx p = parseJsxFragment p | _ -> parseJsxName p in - Scanner.popMode p.scanner Jsx; Parser.eatBreadcrumb p; {jsxExpr with pexp_attributes = [jsxAttr]} @@ -2714,9 +2714,10 @@ and parseJsxFragment p = Parser.expect GreaterThan p; let _spread, children = parseJsxChildren p in let childrenEndPos = p.Parser.startPos in + if p.token = LessThan then p.token <- Scanner.reconsiderLessThan p.scanner; Parser.expect LessThanSlash p; - Parser.expect GreaterThan p; Scanner.popMode p.scanner Jsx; + Parser.expect GreaterThan p; let loc = mkLoc childrenStartPos childrenEndPos in makeListExpression loc children None @@ -2768,6 +2769,7 @@ and parseJsxProp p = Some (label, attrExpr)) (* {...props} *) | Lbrace -> ( + Scanner.popMode p.scanner Jsx; Parser.next p; match p.Parser.token with | DotDotDot -> ( @@ -2786,6 +2788,7 @@ and parseJsxProp p = match p.Parser.token with | Rbrace -> Parser.next p; + Scanner.setJsxMode p.scanner; Some (label, attrExpr) | _ -> None) | _ -> None) @@ -2795,6 +2798,7 @@ and parseJsxProps p = parseRegion ~grammar:Grammar.JsxAttribute ~f:parseJsxProp p and parseJsxChildren p = + Scanner.popMode p.scanner Jsx; let rec loop p children = match p.Parser.token with | Token.Eof | LessThanSlash -> children @@ -2815,21 +2819,23 @@ and parseJsxChildren p = let () = p.token <- token in children | token when Grammar.isJsxChildStart token -> - let () = Scanner.popMode p.scanner Jsx in let child = parsePrimaryExpr ~operand:(parseAtomicExpr p) ~noCall:true p in loop p (child :: children) | _ -> children in - match p.Parser.token with - | DotDotDot -> - Parser.next p; - (true, [parsePrimaryExpr ~operand:(parseAtomicExpr p) ~noCall:true p]) - | _ -> - let children = List.rev (loop p []) in - Scanner.popMode p.scanner Jsx; - (false, children) + let spread, children = + match p.Parser.token with + | DotDotDot -> + Parser.next p; + (true, [parsePrimaryExpr ~operand:(parseAtomicExpr p) ~noCall:true p]) + | _ -> + let children = List.rev (loop p []) in + (false, children) + in + Scanner.setJsxMode p.scanner; + (spread, children) and parseBracedOrRecordExpr p = let startPos = p.Parser.startPos in diff --git a/jscomp/syntax/tests/parsing/grammar/expressions/expected/jsx.res.txt b/jscomp/syntax/tests/parsing/grammar/expressions/expected/jsx.res.txt index fccf7675bd..908cbf768a 100644 --- a/jscomp/syntax/tests/parsing/grammar/expressions/expected/jsx.res.txt +++ b/jscomp/syntax/tests/parsing/grammar/expressions/expected/jsx.res.txt @@ -580,11 +580,13 @@ let _ = ;;((div ~children:((span ~children:[] ())[@JSX ]) ())[@JSX ]) ;;((div ~children:[|a|] ())[@JSX ]) ;;((div ~children:(1, 2) ())[@JSX ]) +;;((div ~children:((array |. f)[@res.braces ]) ())[@JSX ]) ;;(([element])[@JSX ]) ;;(([(((fun a -> 1))[@res.braces ])])[@JSX ]) ;;(([((span ~children:[] ())[@JSX ])])[@JSX ]) ;;(([[|a|]])[@JSX ]) ;;(([(1, 2)])[@JSX ]) +;;(([((array |. f)[@res.braces ])])[@JSX ]) let _ = ((A.createElement ~x:(({js|y|js})[@res.namedArgLoc ]) ~_spreadProps:((str) [@res.namedArgLoc ]) ~children:[] ()) diff --git a/jscomp/syntax/tests/parsing/grammar/expressions/jsx.res b/jscomp/syntax/tests/parsing/grammar/expressions/jsx.res index 78287c37b3..e712324aa0 100644 --- a/jscomp/syntax/tests/parsing/grammar/expressions/jsx.res +++ b/jscomp/syntax/tests/parsing/grammar/expressions/jsx.res @@ -507,11 +507,13 @@ let _ =
...
...[a]
...(1, 2)
+
...{array->f}
<> ...element <> ...{(a) => 1} <> ... <> ...[a] <> ...(1, 2) +<> ...{array->f} let _ = \ No newline at end of file diff --git a/jscomp/syntax/tests/printer/expr/expected/jsx.res.txt b/jscomp/syntax/tests/printer/expr/expected/jsx.res.txt index fe0101d26c..8c689a829c 100644 --- a/jscomp/syntax/tests/printer/expr/expected/jsx.res.txt +++ b/jscomp/syntax/tests/printer/expr/expected/jsx.res.txt @@ -429,3 +429,34 @@ let x = props => {...props} className="inline-block px-6 py-2.5 bg-blue-600 text-white font-medium text-xs leading-tight" /> + +let x = ...{() => msg->React.string} + +let x = ...{array->Array.map(React.string)} + +let x = <> {array->Array.map(React.string)} + +let x = { + let _ =
+ msg->React.string +} + +let x = { + let _ =
{children}
+ msg->React.string +} + +let x = { + let _ = <> {children} + msg->React.string +} + +let x = { + let _ = + msg->React.string +} + +let x = { + let _ = {children} + msg->React.string +} diff --git a/jscomp/syntax/tests/printer/expr/jsx.res b/jscomp/syntax/tests/printer/expr/jsx.res index acd7debfbe..c86868bc38 100644 --- a/jscomp/syntax/tests/printer/expr/jsx.res +++ b/jscomp/syntax/tests/printer/expr/jsx.res @@ -414,3 +414,34 @@ let x = props => {...props} className="inline-block px-6 py-2.5 bg-blue-600 text-white font-medium text-xs leading-tight" /> + +let x = ...{() => msg->React.string} + +let x = ...{array->Array.map(React.string)} + +let x = <> ...{array->Array.map(React.string)} + +let x = { + let _ =
+ msg->React.string +} + +let x = { + let _ =
{children}
+ msg->React.string +} + +let x = { + let _ = <> {children} + msg->React.string +} + +let x = { + let _ = + msg->React.string +} + +let x = { + let _ = {children} + msg->React.string +}