feat: relax eager antiquotation parsing
This commit is contained in:
parent
9e9786203f
commit
b1a9c58d43
1 changed files with 29 additions and 14 deletions
|
|
@ -485,9 +485,14 @@ def mergeOrElseErrors (s : ParserState) (error1 : Error) (iniPos : String.Pos) (
|
|||
else s
|
||||
| other => other
|
||||
|
||||
-- When `mergeAntiquots` is true, if `p` parses an antiquotation, we try `q` as well and return a choice node if they
|
||||
-- both return antiquotations
|
||||
def orelseFnCore (p q : ParserFn) (mergeAntiquots : Bool) : ParserFn := fun c s => Id.run do
|
||||
-- When `p` in `p <|> q` parses exactly one antiquotation, ...
|
||||
inductive OrElseOnAntiquotBehavior where
|
||||
| acceptLhs -- return it
|
||||
| takeLongest -- return result of `q` instead if it made more progress
|
||||
| merge -- ... and create choice node if both made the same progress
|
||||
deriving BEq
|
||||
|
||||
def orelseFnCore (p q : ParserFn) (antiquotBehavior := OrElseOnAntiquotBehavior.merge) : ParserFn := fun c s => Id.run do
|
||||
let s0 := s
|
||||
let iniSz := s.stackSize
|
||||
let iniPos := s.pos
|
||||
|
|
@ -500,17 +505,24 @@ def orelseFnCore (p q : ParserFn) (mergeAntiquots : Bool) : ParserFn := fun c s
|
|||
s
|
||||
| none =>
|
||||
let back := s.stxStack.back
|
||||
if mergeAntiquots && back.isAntiquots then
|
||||
if antiquotBehavior != .acceptLhs && s.stackSize == iniSz + 1 && back.isAntiquots then
|
||||
let s' := q c s0
|
||||
if !s'.hasError && s'.stxStack.back.isAntiquot then
|
||||
if back.isOfKind choiceKind then
|
||||
s := { s with stxStack := s.stxStack.pop ++ back.getArgs }
|
||||
s := s.pushSyntax s'.stxStack.back
|
||||
s := s.mkNode choiceKind iniSz
|
||||
if !s'.hasError then
|
||||
-- If `q` made more progress than `p`, we prefer its result.
|
||||
-- Thus `(structInstField| $id := $val) is interpreted as
|
||||
-- `(structInstField| $id:ident := $val:term), not
|
||||
-- `(structInstField| $id:structInstField <ERROR: expected ')'>.
|
||||
if s'.pos > s.pos then
|
||||
return s'
|
||||
else if antiquotBehavior == .merge && s'.stackSize == iniSz + 1 && s'.stxStack.back.isAntiquot then
|
||||
if back.isOfKind choiceKind then
|
||||
s := { s with stxStack := s.stxStack.pop ++ back.getArgs }
|
||||
s := s.pushSyntax s'.stxStack.back
|
||||
s := s.mkNode choiceKind iniSz
|
||||
s
|
||||
|
||||
@[inline] def orelseFn (p q : ParserFn) : ParserFn :=
|
||||
orelseFnCore (mergeAntiquots := true) p q
|
||||
orelseFnCore p q
|
||||
|
||||
@[noinline] def orelseInfo (p q : ParserInfo) : ParserInfo := {
|
||||
collectTokens := p.collectTokens ∘ q.collectTokens,
|
||||
|
|
@ -1740,11 +1752,14 @@ def mkAntiquot (name : String) (kind : SyntaxNodeKind) (anonymous := true) (isPs
|
|||
checkNoWsBefore "no space before spliced term" >> antiquotExpr >>
|
||||
nameP
|
||||
|
||||
@[inline] def withAntiquotFn (antiquotP p : ParserFn) : ParserFn := fun c s =>
|
||||
@[inline] def withAntiquotFn (antiquotP p : ParserFn) (isCatAntiquot := false) : ParserFn := fun c s =>
|
||||
-- fast check that is false in most cases
|
||||
if c.input.get s.pos == '$' then
|
||||
-- do not allow antiquotation choice nodes here as `antiquotP` is the strictly more general antiquotation than any in `p`
|
||||
orelseFnCore (mergeAntiquots := false) antiquotP p c s
|
||||
-- Do not allow antiquotation choice nodes here as `antiquotP` is the strictly more general
|
||||
-- antiquotation than any in `p`.
|
||||
-- If it is a category antiquotation, do not backtrack into the category at all as that would
|
||||
-- run *all* parsers of the category, and trailing parsers will later be applied anyway.
|
||||
orelseFnCore (antiquotBehavior := if isCatAntiquot then .acceptLhs else .takeLongest) antiquotP p c s
|
||||
else
|
||||
p c s
|
||||
|
||||
|
|
@ -1833,7 +1848,7 @@ def leadingParserAux (kind : Name) (tables : PrattParsingTables) (behavior : Lea
|
|||
mkResult s iniSz
|
||||
|
||||
@[inline] def leadingParser (kind : Name) (tables : PrattParsingTables) (behavior : LeadingIdentBehavior) (antiquotParser : ParserFn) : ParserFn :=
|
||||
withAntiquotFn antiquotParser (leadingParserAux kind tables behavior)
|
||||
withAntiquotFn (isCatAntiquot := true) antiquotParser (leadingParserAux kind tables behavior)
|
||||
|
||||
def trailingLoopStep (tables : PrattParsingTables) (left : Syntax) (ps : List (Parser × Nat)) : ParserFn := fun c s =>
|
||||
longestMatchFn left (ps ++ tables.trailingParsers) c s
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue