pi/src/Parser/Parse.idr

471 lines
13 KiB
Idris
Raw Blame History

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

module Parser.Parse
import Text.Lexer
import Text.Parser
import Data.Vect
import Data.List
import Data.List1
import Data.Maybe
-- eventually start using elaborator representation here, or just a parser
-- exclusive one
import Core.Term
import Core.Misc
%default total
data PiTokenKind
= PTLambda
| PTIdentifier
| PTDot
| PTArrow
| PTPi
| PTSigma
| PTComma
| PTLParen
| PTRParen
| PTColon
| PTLet
| PTDefEq
| PTIn
| PTIgnore
| PTType
| PTTop
| PTStar
| PTTopInd
| PTBot
| PTBotInd
| PTNat
| PTNum
| PTSuc
| PTNatInd
| PTSigInd
| PTId
| PTRefl
| PTJ
Eq PiTokenKind where
(==) PTLambda PTLambda = True
(==) PTIdentifier PTIdentifier = True
(==) PTDot PTDot = True
(==) PTArrow PTArrow = True
(==) PTPi PTPi = True
(==) PTSigma PTSigma = True
(==) PTComma PTComma = True
(==) PTLParen PTLParen = True
(==) PTRParen PTRParen = True
(==) PTColon PTColon = True
(==) PTLet PTLet = True
(==) PTDefEq PTDefEq = True
(==) PTIn PTIn = True
(==) PTIgnore PTIgnore = True
(==) PTType PTType = True
(==) PTTop PTTop = True
(==) PTStar PTStar = True
(==) PTTopInd PTTopInd = True
(==) PTBot PTBot = True
(==) PTBotInd PTBotInd = True
(==) PTNat PTNat = True
(==) PTNum PTNum = True
(==) PTSuc PTSuc = True
(==) PTNatInd PTNatInd = True
(==) PTSigInd PTSigInd = True
(==) PTId PTId = True
(==) PTRefl PTRefl = True
(==) PTJ PTJ = True
(==) _ _ = False
Show PiTokenKind where
show PTLambda = "PTLambda"
show PTIdentifier = "PTIdentifier"
show PTDot = "PTDot"
show PTArrow = "PTArrow"
show PTPi = "PTPi"
show PTSigma = "PTSigma"
show PTComma = "PTComma"
show PTLParen = "PTLParen"
show PTRParen = "PTRParen"
show PTColon = "PTColon"
show PTLet = "PTLet"
show PTDefEq = "PTDefEq"
show PTIn = "PTIn"
show PTIgnore = "PTIgnore"
show PTType = "PTType"
show PTTop = "PTTop"
show PTStar = "PTSTar"
show PTTopInd = "PTTopInd"
show PTBot = "PTBot"
show PTBotInd = "PTBotInd"
show PTNat = "PTNat"
show PTNum = "PTNum "
show PTSuc = "PTSuc"
show PTNatInd = "PTNatInd"
show PTSigInd = "PTSigInd"
show PTId = "PTId"
show PTRefl = "PTRefl"
show PTJ = "PTJ"
PiToken : Type
PiToken = Token PiTokenKind
Show PiToken where
show (Tok kind text) = "Tok kind: " ++ show kind ++ " text: " ++ text
TokenKind PiTokenKind where
TokType PTIdentifier = String
TokType PTNum = Nat
TokType _ = ()
tokValue PTLambda _ = ()
tokValue PTIdentifier s = s
tokValue PTDot _ = ()
tokValue PTArrow _ = ()
tokValue PTPi _ = ()
tokValue PTSigma _ = ()
tokValue PTComma _ = ()
tokValue PTLParen _ = ()
tokValue PTRParen _ = ()
tokValue PTColon _ = ()
tokValue PTLet _ = ()
tokValue PTDefEq _ = ()
tokValue PTIn _ = ()
tokValue PTIgnore _ = ()
tokValue PTType _ = ()
tokValue PTTop _ = ()
tokValue PTStar _ = ()
tokValue PTTopInd _ = ()
tokValue PTBot _ = ()
tokValue PTBotInd _ = ()
tokValue PTNat _ = ()
tokValue PTNum s = cast s
tokValue PTSuc _ = ()
tokValue PTNatInd _ = ()
tokValue PTSigInd _ = ()
tokValue PTId _ = ()
tokValue PTRefl _ = ()
tokValue PTJ _ = ()
ignored : WithBounds PiToken -> Bool
ignored (MkBounded (Tok PTIgnore _) _ _) = True
ignored _ = False
identifier : Lexer
identifier = some (alphaNum <|> oneOf "-_")
keywords : List (String, PiTokenKind)
keywords = [
("in", PTIn),
("let", PTLet),
("suc", PTSuc),
("Type", PTType),
("J", PTJ),
("Id", PTId),
("refl", PTRefl)
]
tokenmap : List (Lexer, PiTokenKind)
tokenmap = [
(exact "-ind", PTTopInd),
(exact "⊥-ind", PTBotInd),
(exact "-ind", PTNatInd),
(exact "Σ-ind", PTSigInd),
(is 'λ', PTLambda),
(is '.', PTDot),
(is '', PTArrow),
(is 'Π', PTPi),
(is '', PTPi),
(is 'Σ', PTSigma),
(is '', PTSigma),
(is ',', PTComma),
(is '(', PTLParen),
(is ')', PTRParen),
(is ':', PTColon),
(is '', PTDefEq),
(is '', PTTop),
(is '', PTBot),
(is '', PTNat),
(is '', PTStar),
(digits, PTNum)
]
piTokenMap : TokenMap PiToken
piTokenMap =
(spaces, Tok PTIgnore) ::
(lineComment (exact "--"), Tok PTIgnore) ::
(blockComment (exact "{-") (exact "-}"), Tok PTIgnore) ::
toTokenMap tokenmap ++
[(identifier, \s =>
case lookup s keywords of
(Just kind) => Tok kind s
Nothing => Tok PTIdentifier s
)
]
lexPi : String -> Maybe (List (WithBounds PiToken))
lexPi str =
case lex piTokenMap str of
(tokens, _, _, "") => Just tokens
_ => Nothing
{- Basic idea, parsing has a list of the identifiers to convert to -}
{- de bruijn indecies, and a Nat to keep track of context size -}
mutual
expr : List String -> (n : Nat) -> Vect n String -> Grammar () PiToken True (Term n)
expr defs n env = tpi defs n env
<|> tsigma defs n env
<|> tarr defs n env
<|> (do
e <- expr1 defs n env
tapp defs n env e <|> pure e)
expr1 : List String -> (n : Nat) -> Vect n String -> Grammar () PiToken True (Term n)
expr1 defs n env = ttopind defs n env
<|> tbotind defs n env
<|> tsuc defs n env
<|> tnatind defs n env
<|> tsigind defs n env
<|> tid defs n env
<|> trefl defs n env
<|> tj defs n env
<|> (do
t <- term defs n env
tapp defs n env t <|> pure t)
term : List String -> (n : Nat) -> Vect n String -> Grammar () PiToken True (Term n)
term defs n env = ttype
<|> ttop
<|> tstar
<|> tbot
<|> tnat
<|> tnum
<|> tpair defs n env
<|> tlet defs n env
<|> tlam defs n env
<|> tvar defs n env
<|> paren defs n env
ttype : Grammar () PiToken True (Term n)
ttype = match PTType >> pure TType
ttop : Grammar () PiToken True (Term n)
ttop = match PTTop >> pure TTop
tstar : Grammar () PiToken True (Term n)
tstar = match PTStar >> pure TStar
ttopind : List String -> (n : Nat) -> Vect n String -> Grammar () PiToken True (Term n)
ttopind defs n env = do
match PTTopInd
commit
c <- term defs n env
st <- term defs n env
pure (TTopInd c st)
tbot : Grammar () PiToken True (Term n)
tbot = match PTBot >> pure TBot
tbotind : List String -> (n : Nat) -> Vect n String -> Grammar () PiToken True (Term n)
tbotind defs n env = do
match PTBotInd
commit
c <- term defs n env
pure (TBotInd c)
tnat : Grammar () PiToken True (Term n)
tnat = match PTNat >> pure TNat
tnum : Grammar () PiToken True (Term n)
tnum = do
n <- match PTNum
pure (conv n)
where
conv : Nat -> Term n
conv 0 = TZero
conv (S n) = TSuc (conv n)
tsuc : List String -> (n : Nat) -> Vect n String -> Grammar () PiToken True (Term n)
tsuc defs n env = do
match PTSuc
commit
TSuc <$> term defs n env
tnatind : List String -> (n : Nat) -> Vect n String -> Grammar () PiToken True (Term n)
tnatind defs n env = do
match PTNatInd
commit
c <- term defs n env
z <- term defs n env
s <- term defs n env
pure (TNatInd c z s)
tsigma : List String -> (n : Nat) -> Vect n String -> Grammar () PiToken True (Term n)
tsigma defs n env = do
match PTSigma
commit
match PTLParen
arg <- match PTIdentifier
match PTColon
a <- expr defs n env
match PTRParen
b <- expr defs (S n) (arg :: env)
pure (TSigma a (TLam b))
tpair : List String -> (n : Nat) -> Vect n String -> Grammar () PiToken True (Term n)
tpair defs n env = do
match PTLParen
x <- expr defs n env
match PTComma
commit
y <- expr defs n env
match PTRParen
pure (TPair x y)
tsigind : List String -> (n : Nat) -> Vect n String -> Grammar () PiToken True (Term n)
tsigind defs n env = do
match PTSigInd
commit
a <- term defs n env
b <- term defs n env
c <- term defs n env
f <- term defs n env
pure (TSigInd a b c f)
tid : List String -> (n : Nat) -> Vect n String -> Grammar () PiToken True (Term n)
tid defs n env = do
match PTId
commit
ty <- term defs n env
a <- term defs n env
b <- term defs n env
pure (TId ty a b)
trefl : List String -> (n : Nat) -> Vect n String -> Grammar () PiToken True (Term n)
trefl defs n env = do
match PTRefl
commit
ty <- term defs n env
tr <- term defs n env
pure (TRefl ty tr)
tj : List String -> (n : Nat) -> Vect n String -> Grammar () PiToken True (Term n)
tj defs n env = do
match PTJ
commit
ty <- term defs n env
a <- term defs n env
b <- term defs n env
c <- term defs n env
d <- term defs n env
pure (TJ ty a b c d)
tlet : List String -> (n : Nat) -> Vect n String -> Grammar () PiToken True (Term n)
tlet defs n env = do
match PTLet
commit
arg <- match PTIdentifier
match PTColon
ty <- expr defs n env
match PTDefEq
tr <- expr defs n env
match PTIn
tri <- expr defs (S n) (arg :: env)
pure (TLet ty tr tri)
tlam : List String -> (n : Nat) -> Vect n String -> Grammar () PiToken True (Term n)
tlam defs n env = do
match PTLambda
commit
arg <- match PTIdentifier
match PTDot
e <- expr defs (S n) (arg :: env)
pure (TLam e)
tpi : List String -> (n : Nat) -> Vect n String -> Grammar () PiToken True (Term n)
tpi defs n env = do
match PTPi
commit
match PTLParen
arg <- match PTIdentifier
match PTColon
a <- expr defs n env
match PTRParen
b <- expr defs (S n) (arg :: env)
pure (TPi a b)
tarr : List String -> (n : Nat) -> Vect n String -> Grammar () PiToken True (Term n)
tarr defs n env = do
l <- expr1 defs n env
match PTArrow
commit
r <- expr defs (S n) ("" :: env)
pure (TPi l r)
tapp : List String -> (n : Nat) -> Vect n String -> Term n -> Grammar () PiToken True (Term n)
tapp defs n env e1 = do
e2 <- term defs n env
tapp1 defs n env (TApp e1 e2)
tapp1 : List String -> (n : Nat) -> Vect n String -> Term n -> Grammar () PiToken False (Term n)
tapp1 defs n env e = tapp defs n env e <|> pure e
tvar : List String -> (n : Nat) -> Vect n String -> Grammar () PiToken True (Term n)
tvar defs n env = do
str <- match PTIdentifier
commit
fromMaybe (fromMaybe (fail ("'" ++ str ++ "' not idefs n env"))
(pure . TDef . cast . finToInteger <$> findIndex (== str) defs))
(pure . TVar <$> findIndex (== str) env)
paren : List String -> (n : Nat) -> Vect n String -> Grammar () PiToken True (Term n)
paren defs n env = do
match PTLParen
commit
e <- expr defs n env
match PTRParen
pure e
definitions : List String -> Grammar () PiToken True (List String, List (Term 0, Term 0))
definitions defs = do
match PTLet
commit
arg <- match PTIdentifier
match PTColon
ty <- expr defs 0 []
match PTDefEq
tr <- expr defs 0 []
next <- definitions (arg :: defs) <|> pure ([], [])
pure (arg :: fst next, (ty, tr) :: snd next)
parsePi : List String -> Grammar () PiToken True a -> List (WithBounds PiToken) -> Either String a
parsePi defs parseEntry toks =
case parse parseEntry $ filter (not . ignored) toks of
Right (l, []) => Right l
Right (_, l) => Left ("contains tokens that were not consumed: " ++ show l)
Left e => (Left . show . map getErr) e
where
getErr : ParsingError tok -> String
getErr (Error "Unrecognised input" _) = ""
getErr (Error s _) = s
public export
parse : List String -> Grammar () PiToken True a -> String -> Either String a
parse defs parseEntry x =
case lexPi x of
Just toks => parsePi defs parseEntry toks
Nothing => Left "Failed to lex."
public export
parse0 : String -> Either String (Term 0)
parse0 = parse [] (expr [] 0 [])
public export
parseEnv : List String -> String -> Either String (Term 0)
parseEnv defs = parse defs (expr defs 0 [])
public export
toplevel : String -> Either String (List String, List (Term 0, Term 0))
toplevel = parse [] (definitions [])