parseCommand: use do
This commit is contained in:
parent
f37b700e6e
commit
83f331b5e2
1 changed files with 36 additions and 25 deletions
|
|
@ -72,32 +72,43 @@ private def consumeInput (c : ParserContext) (pos : String.Pos) : String.Pos :=
|
|||
def topLevelCommandParserFn : ParserFn :=
|
||||
commandParser.fn
|
||||
|
||||
partial def parseCommand (inputCtx : InputContext) (pmctx : ParserModuleContext) (s : ModuleParserState) (messages : MessageLog) : Syntax × ModuleParserState × MessageLog :=
|
||||
let rec parse (s : ModuleParserState) (messages : MessageLog) :=
|
||||
let { pos := pos, recovering := recovering } := s
|
||||
partial def parseCommand (inputCtx : InputContext) (pmctx : ParserModuleContext) (mps : ModuleParserState) (messages : MessageLog) : Syntax × ModuleParserState × MessageLog := Id.run do
|
||||
let mut pos := mps.pos
|
||||
let mut recovering := mps.recovering
|
||||
let mut messages := messages
|
||||
let mut stx := Syntax.missing -- will always be assigned below
|
||||
repeat
|
||||
if inputCtx.input.atEnd pos then
|
||||
(mkEOI pos, s, messages)
|
||||
else
|
||||
let c := mkParserContext inputCtx pmctx
|
||||
let s := { cache := initCacheForInput c.input, pos := pos : ParserState }
|
||||
let s := whitespace c s
|
||||
let s := topLevelCommandParserFn c s
|
||||
match s.errorMsg with
|
||||
| none =>
|
||||
(s.stxStack.back, { pos := s.pos }, messages)
|
||||
| some errorMsg =>
|
||||
-- advance at least one token to prevent infinite loops
|
||||
let pos := if s.pos == pos then consumeInput c s.pos else s.pos
|
||||
/- We ignore commands where `getPos?` is none. This happens only on commands that have a prefix comprised of optional elements.
|
||||
For example, unification hints start with `optional («scoped» <|> «local»)`.
|
||||
We claim a syntactically incorrect command containing no token or identifier is irrelevant for intellisense and should be ignored. -/
|
||||
let ignore := s.stxStack.isEmpty || s.stxStack.back.getPos?.isNone
|
||||
let messages := if recovering && ignore then messages else messages.add <| mkErrorMessage c s.pos (toString errorMsg)
|
||||
if ignore then
|
||||
parse { pos := pos, recovering := true } messages
|
||||
else
|
||||
(s.stxStack.back, { pos := pos, recovering := true }, messages)
|
||||
parse s messages
|
||||
stx := mkEOI pos
|
||||
break
|
||||
let pos' := pos
|
||||
let c := mkParserContext inputCtx pmctx
|
||||
let s := { cache := initCacheForInput c.input, pos := pos : ParserState }
|
||||
let s := whitespace c s
|
||||
let s := topLevelCommandParserFn c s
|
||||
pos := s.pos
|
||||
match s.errorMsg with
|
||||
| none =>
|
||||
stx := s.stxStack.back
|
||||
recovering := false
|
||||
break
|
||||
| some errorMsg =>
|
||||
-- advance at least one token to prevent infinite loops
|
||||
if pos == pos' then
|
||||
pos := consumeInput c pos
|
||||
/- We ignore commands where `getPos?` is none. This happens only on commands that have a prefix comprised of optional elements.
|
||||
For example, unification hints start with `optional («scoped» <|> «local»)`.
|
||||
We claim a syntactically incorrect command containing no token or identifier is irrelevant for intellisense and should be ignored. -/
|
||||
let ignore := s.stxStack.isEmpty || s.stxStack.back.getPos?.isNone
|
||||
unless recovering && ignore do
|
||||
messages := messages.add <| mkErrorMessage c s.pos (toString errorMsg)
|
||||
recovering := true
|
||||
if ignore then
|
||||
continue
|
||||
else
|
||||
stx := s.stxStack.back
|
||||
break
|
||||
return (stx, { pos, recovering }, messages)
|
||||
|
||||
-- only useful for testing since most Lean files cannot be parsed without elaboration
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue