feat(library/init/lean/parser/term): add support for "named" patterns n@(x :: s)
@kha, the implementation is a little bit hackish. It is whitespace sensitive to avoid `f @g`, an application with argument `@g` to be parsed as a named pattern. Here are other approaches I have considered: 1- In the `namedPattern`, we add a guard that ensures the pattern is *not* an identifier. Thus, `f @g` would not be considered a valid `namedPattern`. Drawback: we would always try to parse it as a namedPattern first, fail, and then try as an application. 2- Enforce whitespace before application arguments. Drawback: `f(a+b)` would not be a valid application anymore.
This commit is contained in:
parent
260ea04add
commit
0dcdc2c198
2 changed files with 17 additions and 6 deletions
|
|
@ -925,6 +925,20 @@ def checkWsBefore {k : ParserKind} (errorMsg : String) : Parser k :=
|
|||
{ info := epsilonInfo,
|
||||
fn := fun _ => checkWsBeforeFn errorMsg }
|
||||
|
||||
def checkTailNoWs (prev : Syntax) : Bool :=
|
||||
match prev.getTailInfo with
|
||||
| some info => info.trailing.stopPos == info.trailing.startPos
|
||||
| none => false
|
||||
|
||||
def checkNoWsBeforeFn (errorMsg : String) : BasicParserFn :=
|
||||
fun c s =>
|
||||
let prev := s.stxStack.back;
|
||||
if checkTailNoWs prev then s else s.mkError errorMsg
|
||||
|
||||
def checkNoWsBefore {k : ParserKind} (errorMsg : String) : Parser k :=
|
||||
{ info := epsilonInfo,
|
||||
fn := fun _ => checkNoWsBeforeFn errorMsg }
|
||||
|
||||
def insertNoWsToken (sym : String) (lbpNoWs : Option Nat) (tks : TokenTable) : ExceptT String Id TokenTable :=
|
||||
if sym == "" then throw "invalid empty symbol"
|
||||
else match tks.find sym, lbpNoWs with
|
||||
|
|
@ -939,11 +953,6 @@ def symbolNoWsInfo (sym : String) (lbpNoWs : Option Nat) : ParserInfo :=
|
|||
{ updateTokens := insertNoWsToken sym lbpNoWs,
|
||||
firstTokens := FirstTokens.tokens [ { val := sym, lbpNoWs := lbpNoWs } ] }
|
||||
|
||||
def checkTailNoWs (left : Syntax) : Bool :=
|
||||
match left.getTailInfo with
|
||||
| some info => info.trailing.stopPos == info.trailing.startPos
|
||||
| none => false
|
||||
|
||||
@[inline] def symbolNoWsFnAux (sym : String) (errorMsg : String) : ParserFn trailing :=
|
||||
fun left c s =>
|
||||
if checkTailNoWs left then
|
||||
|
|
|
|||
|
|
@ -41,7 +41,9 @@ def infixL (sym : String) (lbp : Nat) : TrailingParser :=
|
|||
pushLeading >> symbol sym lbp >> termParser lbp
|
||||
|
||||
/- Builting parsers -/
|
||||
@[builtinTermParser] def id := parser! ident >> optional (".{" >> sepBy1 levelParser ", " >> "}")
|
||||
def explicitUniv := parser! ".{" >> sepBy1 levelParser ", " >> "}"
|
||||
def namedPattern := parser! checkNoWsBefore "no space before '@'" >> "@" >> termParser appPrec
|
||||
@[builtinTermParser] def id := parser! ident >> optional (explicitUniv <|> namedPattern)
|
||||
@[builtinTermParser] def num : Parser := numLit
|
||||
@[builtinTermParser] def str : Parser := strLit
|
||||
@[builtinTermParser] def char : Parser := charLit
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue