lean4-htt/library/init/lean/parser/term.lean

180 lines
10 KiB
Text
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/-
Copyright (c) 2019 Microsoft Corporation. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Leonardo de Moura, Sebastian Ullrich
-/
prelude
import init.lean.parser.parser
import init.lean.parser.level
namespace Lean
namespace Parser
@[init mkBuiltinParsingTablesRef]
constant builtinTermParsingTable : IO.Ref ParsingTables := default _
@[init] def regBuiltinTermParserAttr : IO Unit :=
registerBuiltinParserAttribute `builtinTermParser `Lean.Parser.builtinTermParsingTable
def mkTermParserAttribute : IO ParserAttribute :=
registerParserAttribute `termParser "term" "term parser" (some builtinTermParsingTable)
@[init mkTermParserAttribute]
constant termParserAttribute : ParserAttribute := default _
@[inline] def termParser {k : ParserKind} (rbp : Nat := 0) : Parser k :=
{ fn := fun _ => termParserAttribute.runParser rbp }
namespace Term
/- Helper functions for defining simple parsers -/
def unicodeInfixR (sym : String) (asciiSym : String) (lbp : Nat) : TrailingParser :=
pushLeading >> unicodeSymbol sym asciiSym lbp >> termParser (lbp - 1)
def infixR (sym : String) (lbp : Nat) : TrailingParser :=
pushLeading >> symbol sym lbp >> termParser (lbp - 1)
def unicodeInfixL (sym : String) (asciiSym : String) (lbp : Nat) : TrailingParser :=
pushLeading >> unicodeSymbol sym asciiSym lbp >> termParser lbp
def infixL (sym : String) (lbp : Nat) : TrailingParser :=
pushLeading >> symbol sym lbp >> termParser lbp
/- Builting parsers -/
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
@[builtinTermParser] def type := parser! symbol "Type" appPrec
@[builtinTermParser] def sort := parser! symbol "Sort" appPrec
@[builtinTermParser] def prop := parser! symbol "Prop" appPrec
@[builtinTermParser] def hole := parser! symbol "_" appPrec
@[builtinTermParser] def «sorry» := parser! symbol "sorry" appPrec
@[builtinTermParser] def cdot := parser! symbol "·" appPrec
@[builtinTermParser] def emptyC := parser! symbol "∅" appPrec
def typeAscription := parser! " : " >> termParser
def tupleTail := parser! ", " >> sepBy1 termParser ", "
def parenSpecial : Parser := optional (tupleTail <|> typeAscription)
@[builtinTermParser] def paren := parser! symbol "(" appPrec >> optional (termParser >> parenSpecial) >> ")"
@[builtinTermParser] def anonymousCtor := parser! symbol "⟨" appPrec >> sepBy termParser ", " >> "⟩"
def optIdent : Parser := optional (try (ident >> " : "))
@[builtinTermParser] def «if» := parser! "if " >> optIdent >> termParser >> " then " >> termParser >> " else " >> termParser
def fromTerm := parser! " from " >> termParser
def haveAssign := parser! " := " >> termParser
@[builtinTermParser] def «have» := parser! "have " >> optIdent >> termParser >> (haveAssign <|> fromTerm) >> "; " >> termParser
@[builtinTermParser] def «suffices» := parser! "suffices " >> optIdent >> termParser >> fromTerm >> "; " >> termParser
@[builtinTermParser] def «show» := parser! "show " >> termParser >> fromTerm
@[builtinTermParser] def «fun» := parser! unicodeSymbol "λ" "fun" >> many1 (termParser appPrec) >> unicodeSymbol "⇒" "=>" >> termParser
def structInstField := parser! ident >> " := " >> termParser
def structInstSource := parser! ".." >> optional termParser
@[builtinTermParser] def structInst := parser! symbol "{" appPrec >> optional (try (ident >> " . ")) >> sepBy (structInstField <|> structInstSource) ", " true >> "}"
def typeSpec := parser! " : " >> termParser
def optType : Parser := optional typeSpec
@[builtinTermParser] def subtype := parser! "{" >> ident >> optType >> " // " >> termParser >> "}"
@[builtinTermParser] def list := parser! symbol "[" appPrec >> sepBy termParser "," true >> "]"
@[builtinTermParser] def explicit := parser! symbol "@" appPrec >> id
@[builtinTermParser] def inaccessible := parser! symbol ".(" appPrec >> termParser >> ")"
def binderIdent : Parser := ident <|> hole
def binderType (requireType := false) : Parser := if requireType then " : " >> termParser else optional (" : " >> termParser)
def binderDefault := parser! " := " >> termParser
def binderTactic := parser! " . " >> termParser
def explicitBinder (requireType := false) := parser! "(" >> many1 binderIdent >> binderType requireType >> optional (binderDefault <|> binderTactic) >> ")"
def implicitBinder (requireType := false) := parser! "{" >> many1 binderIdent >> binderType requireType >> "}"
def instBinder := parser! "[" >> optIdent >> termParser >> "]"
def bracktedBinder (requireType := false) := explicitBinder requireType <|> implicitBinder requireType <|> instBinder
@[builtinTermParser] def depArrow := parser! bracktedBinder true >> unicodeSymbolCheckPrec " → " " -> " 25 >> termParser
def simpleBinder := parser! many1 binderIdent
@[builtinTermParser] def «forall» := parser! unicodeSymbol "∀" "forall" >> many1 (simpleBinder <|> bracktedBinder) >> ", " >> termParser
def matchAlt := parser! " | " >> sepBy1 termParser ", " >> unicodeSymbol "⇒" "=>" >> termParser
@[builtinTermParser] def «match» := parser! "match " >> sepBy1 termParser ", " >> optType >> " with " >> many1Indent matchAlt "'match' alternatives must be indented"
@[builtinTermParser] def «nomatch» := parser! "nomatch " >> termParser
@[builtinTermParser] def «parser!» := parser! "parser! " >> termParser
@[builtinTermParser] def «tparser!» := parser! "tparser! " >> termParser
@[builtinTermParser] def borrowed := parser! symbol "@&" appPrec >> termParser (appPrec - 1)
@[builtinTermParser] def quotedName := parser! symbol "`" appPrec >> rawIdent
/- Remark: we use `checkWsBefore` to ensure `let x[i] := e; b` is not parsed as `let x [i] := e; b` where `[i]` is an `instBinder`. -/
def letIdLhs : Parser := ident >> checkWsBefore "expected space before binders" >> many bracktedBinder >> optType
def letIdDecl := parser! try (letIdLhs >> " := ") >> termParser
def equation := matchAlt
def letEqns := parser! try (letIdLhs >> lookahead " | ") >> many1Indent equation "equations must be indented"
def letPatDecl := parser! termParser >> optType >> " := " >> termParser
def letDecl := try letIdDecl <|> letEqns <|> letPatDecl
@[builtinTermParser] def «let» := parser! "let " >> letDecl >> "; " >> termParser
def leftArrow : Parser := unicodeSymbol " ← " " <- "
def doLet := parser! "let " >> letDecl
def doId := parser! try (ident >> optType >> leftArrow) >> termParser
def doPat := parser! try (termParser >> leftArrow) >> termParser >> optional (" | " >> termParser)
def doExpr := parser! termParser
def doElem := doLet <|> doId <|> doPat <|> doExpr
def doSeq := parser! sepBy1 doElem "; "
def bracketedDoSeq := parser! "{" >> doSeq >> "}"
@[builtinTermParser] def «do» := parser! "do " >> (bracketedDoSeq <|> doSeq)
@[builtinTermParser] def not := parser! symbol "¬" 40 >> termParser 40
@[builtinTermParser] def bnot := parser! symbol "!" 40 >> termParser 40
@[builtinTermParser] def uminus := parser! "-" >> termParser 100
def namedArgument := tparser! try ("(" >> ident >> " := ") >> termParser >> ")"
@[builtinTermParser] def app := tparser! pushLeading >> (namedArgument <|> termParser appPrec)
def checkIsSort := checkLeading (fun leading => leading.isOfKind `Lean.Parser.Term.type || leading.isOfKind `Lean.Parser.Term.sort)
@[builtinTermParser] def sortApp := tparser! checkIsSort >> pushLeading >> levelParser appPrec
@[builtinTermParser] def proj := tparser! pushLeading >> symbolNoWs "." (appPrec+1) >> (fieldIdx <|> ident)
@[builtinTermParser] def arrow := tparser! unicodeInfixR " → " " -> " 25
@[builtinTermParser] def array := tparser! pushLeading >> symbolNoWs "[" (appPrec+1) >> termParser >>"]"
@[builtinTermParser] def dollar := tparser! infixR " $ " 1
@[builtinTermParser] def fcomp := tparser! infixR " ∘ " 90
@[builtinTermParser] def prod := tparser! infixR " × " 35
@[builtinTermParser] def add := tparser! infixL " + " 65
@[builtinTermParser] def sub := tparser! infixL " - " 65
@[builtinTermParser] def mul := tparser! infixL " * " 70
@[builtinTermParser] def div := tparser! infixL " / " 70
@[builtinTermParser] def mod := tparser! infixL " % " 70
@[builtinTermParser] def modN := tparser! infixL " %ₙ " 70
@[builtinTermParser] def pow := tparser! infixR " ^ " 80
@[builtinTermParser] def le := tparser! unicodeInfixL " ≤ " " <= " 50
@[builtinTermParser] def ge := tparser! unicodeInfixL " ≥ " " >= " 50
@[builtinTermParser] def lt := tparser! infixL " < " 50
@[builtinTermParser] def gt := tparser! infixL " > " 50
@[builtinTermParser] def eq := tparser! infixL " = " 50
@[builtinTermParser] def ne := tparser! infixL " ≠ " 50
@[builtinTermParser] def beq := tparser! infixL " == " 50
@[builtinTermParser] def bne := tparser! infixL " != " 50
@[builtinTermParser] def heq := tparser! unicodeInfixL " ≅ " " ~= " 50
@[builtinTermParser] def equiv := tparser! infixL " ≈ " 50
@[builtinTermParser] def subst := tparser! infixR " ▸ " 75
@[builtinTermParser] def and := tparser! unicodeInfixR " ∧ " " /\\ " 35
@[builtinTermParser] def or := tparser! unicodeInfixR " " " \\/ " 30
@[builtinTermParser] def iff := tparser! unicodeInfixL " ↔ " " <-> " 20
@[builtinTermParser] def band := tparser! infixL " && " 35
@[builtinTermParser] def bor := tparser! infixL " || " 30
@[builtinTermParser] def append := tparser! infixL " ++ " 65
@[builtinTermParser] def cons := tparser! infixR " :: " 67
@[builtinTermParser] def orelse := tparser! infixR " <|> " 2
@[builtinTermParser] def orM := tparser! infixR " <||> " 30
@[builtinTermParser] def andM := tparser! infixR " <&&> " 35
@[builtinTermParser] def andthen := tparser! infixR " >> " 60
@[builtinTermParser] def bind := tparser! infixR " >>= " 55
@[builtinTermParser] def mapRev := tparser! infixR " <&> " 100
@[builtinTermParser] def seq := tparser! infixL " <*> " 60
@[builtinTermParser] def seqLeft := tparser! infixL " <* " 60
@[builtinTermParser] def seqRight := tparser! infixR " *> " 60
@[builtinTermParser] def map := tparser! infixR " <$> " 100
@[builtinTermParser] def mapConst := tparser! infixR " <$ " 100
@[builtinTermParser] def mapConstRev := tparser! infixR " $> " 100
end Term
end Parser
end Lean