未验证 提交 d7d91d94 编写于 作者: E Eugene Auduchinok 提交者: GitHub

Add parser recovery for unfinished interface implementation (#10416)

* Add parser recovery for unfinished interface implementation

* Report indentation problem via parser

* Update public area
上级 40604022
......@@ -22,7 +22,7 @@ let outputPos os (p: Position) = Printf.fprintf os "(%d:%d)" p.OriginalLine p.Co
/// Used for warning strings, which should display columns as 1-based and display
/// the lines after taking '# line' directives into account (i.e. do not use
/// p.OriginalLine)
let warningStringOfPos (p: Position) = sprintf "(%d:%d)" p.Line (p.Column + 1)
let warningStringOfPosition (p: Position) = warningStringOfCoords p.Line p.Column
type Context =
// Position is position of keyword.
......@@ -651,7 +651,7 @@ type LexFilterImpl (lightStatus: LightSyntaxStatus, compilingFsLib, lexer, lexbu
initialLookaheadTokenTup
let warn (s: TokenTup) msg =
warning(Lexhelp.IndentationProblem(msg, mkSynRange (startPosOfTokenTup s) s.LexbufState.EndPos))
warning(IndentationProblem(msg, mkSynRange (startPosOfTokenTup s) s.LexbufState.EndPos))
// 'query { join x in ys ... }'
// 'query { ...
......@@ -865,9 +865,9 @@ type LexFilterImpl (lightStatus: LightSyntaxStatus, compilingFsLib, lexer, lexbu
warn tokenTup
(if debug then
sprintf "possible incorrect indentation: this token is offside of context at position %s, newCtxt = %A, stack = %A, newCtxtPos = %s, c1 = %d, c2 = %d"
(warningStringOfPos p1.Position) newCtxt offsideStack (stringOfPos (newCtxt.StartPos)) p1.Column c2
(warningStringOfPosition p1.Position) newCtxt offsideStack (stringOfPos (newCtxt.StartPos)) p1.Column c2
else
FSComp.SR.lexfltTokenIsOffsideOfContextStartedEarlier(warningStringOfPos p1.Position))
FSComp.SR.lexfltTokenIsOffsideOfContextStartedEarlier(warningStringOfPosition p1.Position))
let newOffsideStack = newCtxt :: offsideStack
if debug then dprintf "--> pushing, stack = %A\n" newOffsideStack
offsideStack <- newOffsideStack
......@@ -1749,7 +1749,7 @@ type LexFilterImpl (lightStatus: LightSyntaxStatus, compilingFsLib, lexer, lexbu
let cond1 = tokenStartCol + (if leadingBar then 0 else 2) < offsidePos.Column
let cond2 = tokenStartCol + (if leadingBar then 1 else 2) < offsidePos.Column
if (cond1 <> cond2) then
errorR(Lexhelp.IndentationProblem(FSComp.SR.lexfltSeparatorTokensOfPatternMatchMisaligned(), mkSynRange (startPosOfTokenTup tokenTup) tokenTup.LexbufState.EndPos))
errorR(IndentationProblem(FSComp.SR.lexfltSeparatorTokensOfPatternMatchMisaligned(), mkSynRange (startPosOfTokenTup tokenTup) tokenTup.LexbufState.EndPos))
cond1
| END -> tokenStartCol + (if leadingBar then -1 else 1) < offsidePos.Column
| _ -> tokenStartCol + (if leadingBar then -1 else 1) < offsidePos.Column)) ->
......@@ -2066,6 +2066,11 @@ type LexFilterImpl (lightStatus: LightSyntaxStatus, compilingFsLib, lexer, lexbu
let offsidePos = tokenStartPos
pushCtxt tokenTup (CtxtWithAsLet offsidePos)
returnToken tokenLexbufState OWITH
// Recovery for `interface ... with` member without further indented member implementations
elif lookaheadTokenStartPos.Column <= limCtxt.StartCol && (match limCtxt with CtxtInterfaceHead _ -> true | _ -> false) then
returnToken tokenLexbufState token
else
// In these situations
// interface I with
......
......@@ -23,6 +23,14 @@ open Internal.Utilities.Text.Parsing
[<NoEquality; NoComparison>]
exception SyntaxError of obj (* ParseErrorContext<_> *) * range: range
exception IndentationProblem of string * range
let warningStringOfCoords line column =
sprintf "(%d:%d)" line (column + 1)
let warningStringOfPos (p: pos) =
warningStringOfCoords p.Line p.Column
//------------------------------------------------------------------------
// Parsing: getting positions from the lexer
//------------------------------------------------------------------------
......
......@@ -230,7 +230,6 @@ let escape c =
//-----------------------------------------------------------------------
exception ReservedKeyword of string * range
exception IndentationProblem of string * range
module Keywords =
type private compatibilityMode =
......
......@@ -93,8 +93,6 @@ val escape: char -> char
exception ReservedKeyword of string * Range.range
exception IndentationProblem of string * Range.range
module Keywords =
val KeywordOrIdentifierToken: LexArgs -> UnicodeLexing.Lexbuf -> string -> token
......
......@@ -1649,9 +1649,13 @@ classDefnMembers:
/* The members of an object type definition or type augmentation */
classDefnMembersAtLeastOne:
| classDefnMember opt_seps classDefnMembers
{ $1 @ $3 }
classDefnMembersAtLeastOne:
| classDefnMember opt_seps classDefnMembers
{ match $1, $3 with
| [ SynMemberDefn.Interface (_, Some [], m) ], nextMember :: _ ->
warning(IndentationProblem(FSComp.SR.lexfltTokenIsOffsideOfContextStartedEarlier(warningStringOfPos m.Start), nextMember.Range))
| _ -> ()
$1 @ $3 }
/* The "with get, set" part of a member definition */
......@@ -1904,11 +1908,12 @@ classDefnMember:
| opt_attributes opt_declVisibility interfaceMember appType opt_interfaceImplDefn
{ if not (isNil $1) then errorR(Error(FSComp.SR.parsAttributesAreNotPermittedOnInterfaceImplementations(), rhs parseState 1))
if Option.isSome $2 then errorR(Error(FSComp.SR.parsInterfacesHaveSameVisibilityAsEnclosingType(), rhs parseState 3))
let mWhole =
let members = Option.map fst $5
let mWhole =
match $5 with
| None -> rhs2 parseState 1 4
| Some(mems) -> (rhs2 parseState 1 4, mems) ||> unionRangeWithListBy (fun (mem:SynMemberDefn) -> mem.Range)
[ SynMemberDefn.Interface ($4, $5, mWhole) ] }
| Some (_, m) -> unionRanges (rhs2 parseState 1 4) m
[ SynMemberDefn.Interface ($4, members, mWhole) ] }
| opt_attributes opt_declVisibility abstractMemberFlags opt_inline nameop opt_explicitValTyparDecls COLON topTypeWithTypeConstraints classMemberSpfnGetSet opt_ODECLEND
{ let ty, arity = $8
......@@ -2042,9 +2047,14 @@ opt_declVisibility:
{ None }
opt_interfaceImplDefn:
opt_interfaceImplDefn:
| WITH objectImplementationBlock declEnd
{ Some($2) }
{ let members = $2
let m = (rhs parseState 1, members) ||> unionRangeWithListBy (fun (mem:SynMemberDefn) -> mem.Range)
Some (members, m) }
| WITH
{ Some ([], rhs parseState 1) }
| /* EMPTY */
{ None }
......
......@@ -67,6 +67,9 @@
<Compile Include="..\service\ScriptOptionsTests.fs">
<Link>ScriptOptionsTests.fs</Link>
</Compile>
<Compile Include="..\service\ParserTests.fs" >
<Link>ParserTests.fs</Link>
</Compile>
<Compile Include="..\service\Program.fs">
<Link>Program.fs</Link>
</Compile>
......
......@@ -20020,6 +20020,20 @@ FSharp.Compiler.ParseHelpers: FSharp.Compiler.ParseHelpers+LexerStringStyle
FSharp.Compiler.ParseHelpers: FSharp.Compiler.ParseHelpers+SyntaxError
FSharp.Compiler.ParseHelpers: ILInstr[] ParseAssemblyCodeInstructions(System.String, range)
FSharp.Compiler.ParseHelpers: ILType ParseAssemblyCodeType(System.String, range)
FSharp.Compiler.ParseHelpers+IndentationProblem: Boolean Equals(System.Exception)
FSharp.Compiler.ParseHelpers+IndentationProblem: Boolean Equals(System.Object)
FSharp.Compiler.ParseHelpers+IndentationProblem: Boolean Equals(System.Object, System.Collections.IEqualityComparer)
FSharp.Compiler.ParseHelpers+IndentationProblem: Int32 GetHashCode()
FSharp.Compiler.ParseHelpers+IndentationProblem: Int32 GetHashCode(System.Collections.IEqualityComparer)
FSharp.Compiler.ParseHelpers+IndentationProblem: System.String Data0
FSharp.Compiler.ParseHelpers+IndentationProblem: System.String get_Data0()
FSharp.Compiler.ParseHelpers+IndentationProblem: Void .ctor()
FSharp.Compiler.ParseHelpers+IndentationProblem: Void .ctor(System.String, range)
FSharp.Compiler.ParseHelpers+IndentationProblem: range Data1
FSharp.Compiler.ParseHelpers+IndentationProblem: range get_Data1()
FSharp.Compiler.ParseHelpers: FSharp.Compiler.ParseHelpers+IndentationProblem
FSharp.Compiler.ParseHelpers: System.String warningStringOfCoords(Int32, Int32)
FSharp.Compiler.ParseHelpers: System.String warningStringOfPos(pos)
FSharp.Compiler.PartialLongName: Boolean Equals(FSharp.Compiler.PartialLongName)
FSharp.Compiler.PartialLongName: Boolean Equals(System.Object)
FSharp.Compiler.PartialLongName: Boolean Equals(System.Object, System.Collections.IEqualityComparer)
......@@ -337,9 +337,14 @@ let rec allSymbolsInEntities compGen (entities: IList<FSharpEntity>) =
yield (x :> FSharpSymbol)
yield! allSymbolsInEntities compGen e.NestedEntities ]
let getParseResults (source: string) =
parseSourceCode("/home/user/Test.fsx", source)
let getParseAndCheckResults (source: string) =
parseAndCheckScript("/home/user/Test.fsx", source)
let inline dumpErrors results =
(^TResults: (member Errors: FSharpErrorInfo[]) results)
|> Array.map (fun e ->
......
module Tests.Parser
open FSharp.Compiler.Service.Tests.Common
open FSharp.Compiler.SyntaxTree
open NUnit.Framework
module Recovery =
[<Test>]
let ``Unfinished interface member`` () =
let parseResults = getParseResults """
type T =
interface I with
member x.P2 = ()
let x = ()
"""
let (SynModuleOrNamespace (decls = decls)) = getSingleModuleLikeDecl parseResults
match decls with
| [ SynModuleDecl.Types ([ TypeDefn (typeRepr = SynTypeDefnRepr.ObjectModel (members = [ _; _ ])) ], _)
SynModuleDecl.Let _ ] -> ()
| _ -> failwith "Unexpected tree"
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册