refactor: simplify withPosition combinator

Add `checkColGt`
This commit is contained in:
Leonardo de Moura 2020-09-28 11:17:35 -07:00
parent 5b4247a9c7
commit 6ddec22763
6 changed files with 33 additions and 32 deletions

View file

@ -125,6 +125,7 @@ structure ParserContext extends InputContext :=
(env : Environment)
(tokens : TokenTable)
(insideQuot : Bool := false)
(savedPos : Position := { line := 1, column := 0 })
structure Error :=
(unexpected : String := "")
@ -1373,29 +1374,30 @@ def anyOfFn : List Parser → ParserFn
| [p], c, s => p.fn c s
| p::ps, c, s => orelseFn p.fn (anyOfFn ps) c s
@[inline] def checkColGeFn (col : Nat) (errorMsg : String) : ParserFn :=
@[inline] def checkColGeFn (errorMsg : String) : ParserFn :=
fun c s =>
let pos := c.fileMap.toPosition s.pos;
if pos.column ≥ col then s
if pos.column ≥ c.savedPos.column then s
else s.mkError errorMsg
@[inline] def checkColGe (col : Nat) (errorMsg : String) : Parser :=
{ fn := checkColGeFn col errorMsg }
@[inline] def checkColGe (errorMsg : String) : Parser :=
{ fn := checkColGeFn errorMsg }
@[inline] def checkLineLeFn (line : Nat) (errorMsg : String) : ParserFn :=
@[inline] def checkColGtFn (errorMsg : String) : ParserFn :=
fun c s =>
let pos := c.fileMap.toPosition s.pos;
if pos.line ≤ line then s
if pos.column > c.savedPos.column then s
else s.mkError errorMsg
@[inline] def checkLineLe (line : Nat) (errorMsg : String) : Parser :=
{ fn := checkLineLeFn line errorMsg }
@[inline] def checkColGt (errorMsg : String) : Parser :=
{ fn := checkColGtFn errorMsg }
@[inline] def withPosition (p : Position → Parser) : Parser :=
{ info := (p { line := 1, column := 0 }).info,
@[inline] def withPosition (p : Parser) : Parser :=
{ info := p.info,
fn := fun c s =>
let pos := c.fileMap.toPosition s.pos;
(p pos).fn c s }
p.fn { c with savedPos := pos } s }
def eoiFn : ParserFn :=
fun c s =>
@ -1407,7 +1409,7 @@ fun c s =>
{ fn := eoiFn }
@[inline] def many1Indent (p : Parser) (errorMsg : String) : Parser :=
withPosition $ fun pos => many1 (checkColGe pos.column errorMsg >> p)
withPosition $ many1 (checkColGe errorMsg >> p)
open Std (RBMap RBMap.empty)

View file

@ -71,13 +71,13 @@ def leftArrow : Parser := unicodeSymbol " ← " " <- "
`notFollowedByTermToken >> notFollowedBy (ident <|> numLit <|> strLit <|> charLit <|> nameLit)`
-/
def doSeqIndent :=
withPosition fun pos₁ =>
withPosition $
sepBy1
doElemParser
-- The separator for the indented `do`-block
("; "
-- check indentation
>> checkColGe pos₁.column "do-elements must be indented"
>> checkColGe "do-elements must be indented"
>> notFollowedByCommandToken >> notFollowedBy eoi)
>> optional (try ("; " >> notFollowedByTermToken >> notFollowedBy (ident <|> numLit <|> strLit <|> charLit <|> nameLit)))
def doSeqBracketed := parser! "{" >> sepBy1 doElemParser "; " true >> "}"
@ -117,15 +117,15 @@ else if c_2 then
action_3
```
-/
@[builtinDoElemParser] def doIf := parser! withPosition fun pos =>
@[builtinDoElemParser] def doIf := parser! withPosition $
"if " >> termParser >> " then " >> doSeq
>> many (checkColGe pos.column "'else if' in 'do' must be indented" >> try (" else " >> " if ") >> termParser >> " then " >> doSeq)
>> optional (checkColGe pos.column "'else' in 'do' must be indented" >> " else " >> doSeq)
>> many (checkColGe "'else if' in 'do' must be indented" >> try (" else " >> " if ") >> termParser >> " then " >> doSeq)
>> optional (checkColGe "'else' in 'do' must be indented" >> " else " >> doSeq)
@[builtinDoElemParser] def doFor := parser! "for " >> termParser >> " in " >> termParser maxPrec >> doSeq
/- `match`-expression where the right-hand-side of alternatives is a `doSeq` instead of a `term` -/
def doMatchAlt : Parser := sepBy1 termParser ", " >> darrow >> doSeq
def doMatchAlts : Parser := parser! withPosition fun pos => (optional "| ") >> sepBy1 doMatchAlt (checkColGe pos.column "alternatives must be indented" >> "|")
def doMatchAlts : Parser := parser! withPosition $ (optional "| ") >> sepBy1 doMatchAlt (checkColGe "alternatives must be indented" >> "|")
@[builtinDoElemParser] def doMatch := parser!:leadPrec "match " >> sepBy1 matchDiscr ", " >> optType >> " with " >> doMatchAlts
@[builtinDoElemParser] def «break» := parser! "break"

View file

@ -63,7 +63,7 @@ def rwRuleSeq := parser! "[" >> sepBy1 rwRule ", " true >> "]"
def majorPremise := parser! optional (try (ident >> " : ")) >> termParser
def altRHS := Term.hole <|> Term.syntheticHole <|> indentedNonEmptySeq
def inductionAlt : Parser := nodeWithAntiquot "inductionAlt" `Lean.Parser.Tactic.inductionAlt $ ident' >> many ident' >> darrow >> altRHS
def inductionAlts : Parser := withPosition $ fun pos => "|" >> sepBy1 inductionAlt (checkColGe pos.column "alternatives must be indented" >> "|")
def inductionAlts : Parser := withPosition $ "|" >> sepBy1 inductionAlt (checkColGe "alternatives must be indented" >> "|")
def withAlts : Parser := optional (" with " >> inductionAlts)
def usingRec : Parser := optional (" using " >> ident)
def generalizingVars := optional (" generalizing " >> many1 ident)
@ -71,7 +71,7 @@ def generalizingVars := optional (" generalizing " >> many1 ident)
@[builtinTacticParser] def «cases» := parser! nonReservedSymbol "cases " >> majorPremise >> withAlts
def matchAlt : Parser := parser! sepBy1 termParser ", " >> darrow >> altRHS
def matchAlts : Parser := group $ withPosition $ fun pos => (optional "| ") >> sepBy1 matchAlt (checkColGe pos.column "alternatives must be indented" >> "|")
def matchAlts : Parser := group $ withPosition $ (optional "| ") >> sepBy1 matchAlt (checkColGe "alternatives must be indented" >> "|")
@[builtinTacticParser] def «match» := parser! nonReservedSymbol "match " >> sepBy1 Term.matchDiscr ", " >> Term.optType >> " with " >> matchAlts
@[builtinTacticParser] def «introMatch» := parser! nonReservedSymbol "intro " >> matchAlts

View file

@ -20,8 +20,8 @@ registerBuiltinDynamicParserAttribute `tacticParser `tactic
categoryParser `tactic rbp
def Tactic.indentedNonEmptySeq : Parser :=
nodeWithAntiquot "tacticSeq" `Lean.Parser.Tactic.seq $ withPosition fun pos =>
sepBy1 tacticParser (try ("; " >> checkColGe pos.column "tatic must be indented"))
nodeWithAntiquot "tacticSeq" `Lean.Parser.Tactic.seq $ withPosition $
sepBy1 tacticParser (try ("; " >> checkColGe "tatic must be indented"))
def darrow : Parser := " => "
@ -117,9 +117,9 @@ nodeWithAntiquot "matchAlt" `Lean.Parser.Term.matchAlt $
sepBy1 termParser ", " >> darrow >> termParser
def matchAlts (optionalFirstBar := true) : Parser :=
parser! withPosition fun pos =>
parser! withPosition $
(if optionalFirstBar then optional "| " else "| ") >>
sepBy1 matchAlt (checkColGe pos.column "alternatives must be indented" >> "|")
sepBy1 matchAlt (checkColGe "alternatives must be indented" >> "|")
def matchDiscr := parser! optional (try (ident >> checkNoWsBefore "no space before ':'" >> ":")) >> termParser

View file

@ -365,9 +365,8 @@ if stx.getKind == k then do
else
p
@[combinatorFormatter Lean.Parser.withPosition] def withPosition.formatter (p : Position → Formatter) : Formatter := do
-- call closure with dummy position
p ⟨0, 0⟩
@[combinatorFormatter Lean.Parser.withPosition] def withPosition.formatter (p : Formatter) : Formatter := do
p
@[combinatorFormatter Lean.Parser.setExpected]
def setExpected.formatter (expected : List String) (p : Formatter) : Formatter :=
@ -386,7 +385,8 @@ pushLine
@[combinatorFormatter checkNoWsBefore] def checkNoWsBefore.formatter : Formatter := pure ()
@[combinatorFormatter checkTailWs] def checkTailWs.formatter : Formatter := pure ()
@[combinatorFormatter checkColGe] def checkColGe.formatter : Formatter := pure ()
@[combinatorFormatter checkLineLe] def checkLineLe.formatter : Formatter := pure ()
@[combinatorFormatter checkColGt] def checkColGt.formatter : Formatter := pure ()
@[combinatorFormatter eoi] def eoi.formatter : Formatter := pure ()
@[combinatorFormatter notFollowedByCategoryToken] def notFollowedByCategoryToken.formatter : Formatter := pure ()
@[combinatorFormatter checkNoImmediateColon] def checkNoImmediateColon.formatter : Formatter := pure ()

View file

@ -430,9 +430,8 @@ if stx.getKind == k then
else
p
@[combinatorParenthesizer Lean.Parser.withPosition] def withPosition.parenthesizer (p : Position → Parenthesizer) : Parenthesizer := do
-- call closure with dummy position
p ⟨0, 0⟩
@[combinatorParenthesizer Lean.Parser.withPosition] def withPosition.parenthesizer (p : Parenthesizer) : Parenthesizer := do
p
@[combinatorParenthesizer Lean.Parser.setExpected]
def setExpected.parenthesizer (expected : List String) (p : Parenthesizer) : Parenthesizer :=
@ -447,9 +446,9 @@ p
@[combinatorParenthesizer Lean.Parser.checkNoWsBefore] def checkNoWsBefore.parenthesizer : Parenthesizer := pure ()
@[combinatorParenthesizer Lean.Parser.checkTailWs] def checkTailWs.parenthesizer : Parenthesizer := pure ()
@[combinatorParenthesizer Lean.Parser.checkColGe] def checkColGe.parenthesizer : Parenthesizer := pure ()
@[combinatorParenthesizer Lean.Parser.checkColGt] def checkColGt.parenthesizer : Parenthesizer := pure ()
@[combinatorParenthesizer Lean.Parser.eoi] def eoi.parenthesizer : Parenthesizer := pure ()
@[combinatorParenthesizer Lean.Parser.notFollowedByCategoryToken] def notFollowedByCategoryToken.parenthesizer : Parenthesizer := pure ()
@[combinatorParenthesizer Lean.Parser.checkLineLe] def checkLineLe.parenthesizer : Parenthesizer := pure ()
@[combinatorParenthesizer Lean.Parser.checkNoImmediateColon] def checkNoImmediateColon.parenthesizer : Parenthesizer := pure ()
@[combinatorParenthesizer Lean.Parser.checkInsideQuot] def checkInsideQuot.parenthesizer : Parenthesizer := pure ()
@[combinatorParenthesizer Lean.Parser.checkOutsideQuot] def checkOutsideQuot.parenthesizer : Parenthesizer := pure ()