From d196338e3a6b06808254b5ff3d092f1d2379c8cf Mon Sep 17 00:00:00 2001 From: Cristiano Calcagno Date: Thu, 12 May 2022 16:49:23 +0200 Subject: [PATCH] More robust parse recovery after ".". See https://github.com/rescript-lang/rescript-vscode/issues/416 for examples where parser recovery goes wrong in template expressions. Basically, if the token after "." is consumed in recovery, the entire template expression is eaten up and never recovers. This PR changes error recovery to not consume the token after Dot so the parser can recover properly inside a template. --- src/res_core.ml | 27 +++++++++++++++++++++------ 1 file changed, 21 insertions(+), 6 deletions(-) diff --git a/src/res_core.ml b/src/res_core.ml index 67204be9..9f804445 100644 --- a/src/res_core.ml +++ b/src/res_core.ml @@ -728,6 +728,16 @@ let parseValuePath p = Parser.next p; Location.mkloc ident (mkLoc startPos p.prevEndPos) +let parseValuePathAfterDot p = + let startPos = p.Parser.startPos in + match p.Parser.token with + | Lident _ + | Uident _ -> + parseValuePath p + | token -> + Parser.err p (Diagnostics.unexpected token p.breadcrumbs); + Location.mkloc (Longident.Lident "_") (mkLoc startPos p.prevEndPos) + let parseValuePathTail p startPos ident = let rec loop p path = match p.Parser.token with @@ -2052,7 +2062,7 @@ and parsePrimaryExpr ~operand ?(noCall=false) p = match p.Parser.token with | Dot -> Parser.next p; - let lident = parseValuePath p in + let lident = parseValuePathAfterDot p in begin match p.Parser.token with | Equal when noCall = false -> Parser.leaveBreadcrumb p Grammar.ExprSetField; @@ -3591,11 +3601,16 @@ and parseValueOrConstructor p = let lident = buildLongident (ident::acc) in Ast_helper.Exp.ident ~loc (Location.mkloc lident loc) | token -> - Parser.next p; - let loc = mkLoc startPos p.prevEndPos in - Parser.err p (Diagnostics.unexpected token p.breadcrumbs); - let lident = buildLongident ("_"::acc) in - Ast_helper.Exp.ident ~loc (Location.mkloc lident loc) + if acc = [] then ( + Parser.next p; + Parser.err p (Diagnostics.unexpected token p.breadcrumbs); + Recover.defaultExpr() + ) else ( + let loc = mkLoc startPos p.prevEndPos in + Parser.err p (Diagnostics.unexpected token p.breadcrumbs); + let lident = buildLongident ("_"::acc) in + Ast_helper.Exp.ident ~loc (Location.mkloc lident loc) + ) in aux p []