2023-03-12 13:28:37 -04:00
|
|
|
|
module Quox.Parser.Parser
|
|
|
|
|
|
|
|
|
|
import public Quox.Parser.Lexer
|
|
|
|
|
import public Quox.Parser.Syntax
|
|
|
|
|
|
|
|
|
|
import Data.Fin
|
|
|
|
|
import Data.Vect
|
|
|
|
|
import public Text.Parser
|
2023-03-31 13:27:38 -04:00
|
|
|
|
import Derive.Prelude
|
2023-03-12 13:28:37 -04:00
|
|
|
|
|
2023-03-31 13:27:38 -04:00
|
|
|
|
%language ElabReflection
|
2023-03-12 13:28:37 -04:00
|
|
|
|
%default total
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public export
|
|
|
|
|
0 Grammar : Bool -> Type -> Type
|
|
|
|
|
Grammar = Core.Grammar () Token
|
|
|
|
|
%hide Core.Grammar
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
export
|
|
|
|
|
res : (str : String) -> (0 _ : IsReserved str) => Grammar True ()
|
2023-03-18 15:00:29 -04:00
|
|
|
|
res str = terminal "expecting \"\{str}\"" $ guard . (== Reserved str)
|
2023-03-12 13:28:37 -04:00
|
|
|
|
|
|
|
|
|
export
|
|
|
|
|
resC : (str : String) -> (0 _ : IsReserved str) => Grammar True ()
|
|
|
|
|
resC str = do res str; commit
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
parameters {default True commit : Bool}
|
|
|
|
|
private
|
|
|
|
|
maybeCommit : Grammar False ()
|
|
|
|
|
maybeCommit = when commit Core.commit
|
|
|
|
|
|
|
|
|
|
export
|
|
|
|
|
betweenR : {c : Bool} -> (op, cl : String) ->
|
|
|
|
|
(0 _ : IsReserved op) => (0 _ : IsReserved cl) =>
|
|
|
|
|
Grammar c a -> Grammar True a
|
|
|
|
|
betweenR o c p = res o *> maybeCommit *> p <* res c <* maybeCommit
|
|
|
|
|
|
|
|
|
|
export
|
|
|
|
|
parens, bracks, braces : {c : Bool} -> Grammar c a -> Grammar True a
|
|
|
|
|
parens = betweenR "(" ")"
|
|
|
|
|
bracks = betweenR "[" "]"
|
|
|
|
|
braces = betweenR "{" "}"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
export
|
|
|
|
|
commaSep : {c : Bool} -> Grammar c a -> Grammar False (List a)
|
|
|
|
|
commaSep = sepEndBy (res ",")
|
|
|
|
|
-- don't commit because of the possible terminating ","
|
|
|
|
|
|
|
|
|
|
export
|
|
|
|
|
semiSep : {c : Bool} -> Grammar c a -> Grammar False (List a)
|
|
|
|
|
semiSep = sepEndBy (res ";")
|
|
|
|
|
|
|
|
|
|
export
|
|
|
|
|
commaSep1 : {c : Bool} -> Grammar c a -> Grammar c (List1 a)
|
|
|
|
|
commaSep1 = sepEndBy1 (res ",")
|
|
|
|
|
|
|
|
|
|
export
|
|
|
|
|
darr : Grammar True ()
|
|
|
|
|
darr = resC "⇒"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
export
|
|
|
|
|
name : Grammar True PName
|
|
|
|
|
name = terminal "expecting name" $
|
|
|
|
|
\case Name i => Just i; _ => Nothing
|
|
|
|
|
|
|
|
|
|
export
|
|
|
|
|
mods : Grammar True Mods
|
|
|
|
|
mods = name <&> \n => n.mods :< n.base
|
|
|
|
|
|
|
|
|
|
export
|
|
|
|
|
baseName : Grammar True String
|
|
|
|
|
baseName = terminal "expecting unqualified name" $
|
|
|
|
|
\case Name i => guard (null i.mods) $> i.base
|
|
|
|
|
_ => Nothing
|
|
|
|
|
|
|
|
|
|
export
|
|
|
|
|
nat : Grammar True Nat
|
|
|
|
|
nat = terminal "expecting natural number" $
|
|
|
|
|
\case Nat n => pure n; _ => Nothing
|
|
|
|
|
|
|
|
|
|
export
|
|
|
|
|
string : Grammar True String
|
|
|
|
|
string = terminal "expecting string literal" $
|
|
|
|
|
\case Str s => pure s; _ => Nothing
|
|
|
|
|
|
|
|
|
|
export
|
|
|
|
|
tag : Grammar True String
|
|
|
|
|
tag = terminal "expecting tag constructor" $
|
|
|
|
|
\case Tag t => pure t; _ => Nothing
|
|
|
|
|
|
|
|
|
|
export
|
|
|
|
|
bareTag : Grammar True String
|
|
|
|
|
bareTag = string <|> [|toDotsP name|]
|
|
|
|
|
|
|
|
|
|
export
|
|
|
|
|
universe : Grammar True PUniverse
|
|
|
|
|
universe = terminal "expecting type universe" $
|
|
|
|
|
\case TYPE u => Just u; _ => Nothing
|
|
|
|
|
|
|
|
|
|
export
|
|
|
|
|
bname : Grammar True BName
|
|
|
|
|
bname = Nothing <$ res "_"
|
|
|
|
|
<|> [|Just baseName|]
|
|
|
|
|
|
|
|
|
|
export
|
2023-03-18 15:00:29 -04:00
|
|
|
|
dimConst : Grammar True DimConst
|
|
|
|
|
dimConst = terminal "expecting 0 or 1" $
|
|
|
|
|
\case Nat 0 => Just Zero; Nat 1 => Just One; _ => Nothing
|
2023-03-12 13:28:37 -04:00
|
|
|
|
|
2023-03-18 15:00:29 -04:00
|
|
|
|
export
|
2023-04-01 13:16:43 -04:00
|
|
|
|
qty : Grammar True Qty
|
2023-03-18 15:00:29 -04:00
|
|
|
|
qty = terminal "expecting quantity" $
|
|
|
|
|
\case Nat 0 => Just Zero; Nat 1 => Just One; Reserved "ω" => Just Any
|
|
|
|
|
_ => Nothing
|
|
|
|
|
|
2023-03-26 08:40:54 -04:00
|
|
|
|
export
|
|
|
|
|
zero : Grammar True ()
|
|
|
|
|
zero = terminal "expecting 0" $ guard . (== Nat 0)
|
|
|
|
|
|
2023-03-18 15:00:29 -04:00
|
|
|
|
|
|
|
|
|
public export
|
|
|
|
|
AllReserved : List (a, String) -> Type
|
|
|
|
|
AllReserved = foldr (\x, ps => (IsReserved $ snd x, ps)) ()
|
|
|
|
|
|
|
|
|
|
export
|
|
|
|
|
symbols : (lst : List (a, String)) -> (0 _ : AllReserved lst) =>
|
|
|
|
|
Grammar True a
|
|
|
|
|
symbols [] = fail "no symbols found"
|
2023-03-26 08:40:54 -04:00
|
|
|
|
symbols [(x, str)] = x <$ res str
|
2023-03-18 15:00:29 -04:00
|
|
|
|
symbols ((x, str) :: rest) = x <$ res str <|> symbols rest
|
|
|
|
|
|
|
|
|
|
export
|
|
|
|
|
symbolsC : (lst : List (a, String)) -> (0 _ : AllReserved lst) =>
|
|
|
|
|
Grammar True a
|
|
|
|
|
symbolsC lst = symbols lst <* commit
|
|
|
|
|
|
2023-03-12 13:28:37 -04:00
|
|
|
|
|
|
|
|
|
private covering
|
2023-04-01 13:16:43 -04:00
|
|
|
|
qtys : Grammar False (List Qty)
|
2023-03-17 16:54:09 -04:00
|
|
|
|
qtys = option [] [|toList $ some qty <* res "."|]
|
2023-03-12 13:28:37 -04:00
|
|
|
|
|
|
|
|
|
|
2023-03-18 15:00:29 -04:00
|
|
|
|
export
|
2023-03-12 13:28:37 -04:00
|
|
|
|
dim : Grammar True PDim
|
2023-03-18 15:00:29 -04:00
|
|
|
|
dim = [|V baseName|] <|> [|K dimConst|]
|
2023-03-12 13:28:37 -04:00
|
|
|
|
|
|
|
|
|
private
|
|
|
|
|
0 PBinderHead : Nat -> Type
|
2023-04-01 13:16:43 -04:00
|
|
|
|
PBinderHead n = (Vect n Qty, BName, PTerm)
|
2023-03-12 13:28:37 -04:00
|
|
|
|
|
|
|
|
|
private
|
|
|
|
|
toVect : List a -> (n ** Vect n a)
|
|
|
|
|
toVect [] = (_ ** [])
|
|
|
|
|
toVect (x :: xs) = (_ ** x :: snd (toVect xs))
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
private
|
|
|
|
|
lamIntro : Grammar True (BName -> PTerm -> PTerm)
|
2023-03-18 15:00:29 -04:00
|
|
|
|
lamIntro = symbolsC [(Lam, "λ"), (DLam, "δ")]
|
2023-03-12 13:28:37 -04:00
|
|
|
|
|
|
|
|
|
private covering
|
2023-04-01 13:16:43 -04:00
|
|
|
|
caseIntro : Grammar True Qty
|
2023-04-02 09:22:39 -04:00
|
|
|
|
caseIntro = symbols [(Zero, "case0"), (One, "case1"), (Any, "caseω")]
|
2023-03-31 13:33:40 -04:00
|
|
|
|
<|> resC "case" *>
|
|
|
|
|
(qty <* resC "." <|>
|
|
|
|
|
fatalError {c = True} "missing quantity on 'case'")
|
2023-03-12 13:28:37 -04:00
|
|
|
|
|
|
|
|
|
private
|
|
|
|
|
optNameBinder : Grammar False BName
|
|
|
|
|
optNameBinder = [|join $ optional $ bname <* darr|]
|
|
|
|
|
|
|
|
|
|
mutual
|
|
|
|
|
export covering
|
|
|
|
|
term : Grammar True PTerm
|
2023-04-15 09:13:01 -04:00
|
|
|
|
term = lamTerm <|> caseTerm <|> coeTerm <|> compTerm <|> bindTerm <|> annTerm
|
2023-03-12 13:28:37 -04:00
|
|
|
|
|
|
|
|
|
private covering
|
|
|
|
|
lamTerm : Grammar True PTerm
|
|
|
|
|
lamTerm = flip . foldr <$> lamIntro <*> some bname <* darr <*> term
|
|
|
|
|
|
|
|
|
|
private covering
|
|
|
|
|
caseTerm : Grammar True PTerm
|
|
|
|
|
caseTerm =
|
|
|
|
|
[|Case caseIntro term
|
|
|
|
|
(resC "return" *> optBinderTerm)
|
2023-03-18 15:00:29 -04:00
|
|
|
|
(resC "of" *> caseBody)|]
|
2023-03-12 13:28:37 -04:00
|
|
|
|
|
2023-04-15 09:13:01 -04:00
|
|
|
|
private covering
|
|
|
|
|
coeTerm : Grammar True PTerm
|
|
|
|
|
coeTerm = resC "coe" *> [|Coe typeLine dimArg dimArg aTerm|]
|
|
|
|
|
|
|
|
|
|
private covering
|
|
|
|
|
compTerm : Grammar True PTerm
|
|
|
|
|
compTerm = resC "comp" *> do
|
|
|
|
|
head <- [|Comp typeLine dimArg dimArg aTerm dimArg|]
|
|
|
|
|
uncurry head <$> compBody
|
|
|
|
|
where
|
|
|
|
|
compBranch : Grammar True (DimConst, BName, PTerm)
|
|
|
|
|
compBranch = [|(,,) dimConst bname (resC "⇒" *> term)|]
|
|
|
|
|
|
|
|
|
|
zeroOne : (DimConst, a) -> (DimConst, a) -> Grammar False (a, a)
|
|
|
|
|
zeroOne (Zero, x) (One, y) = pure (x, y)
|
|
|
|
|
zeroOne (One, x) (Zero, y) = pure (y, x)
|
|
|
|
|
zeroOne _ _ = fatalError "body of comp needs one 0 branch and one 1 branch"
|
|
|
|
|
|
|
|
|
|
compBody : Grammar True ((BName, PTerm), (BName, PTerm))
|
|
|
|
|
compBody = braces $ do
|
|
|
|
|
et0 <- compBranch <* resC ";"
|
|
|
|
|
et1 <- compBranch <* optional (resC ";")
|
|
|
|
|
zeroOne et0 et1
|
|
|
|
|
|
2023-03-12 13:28:37 -04:00
|
|
|
|
private covering
|
2023-03-18 15:00:29 -04:00
|
|
|
|
caseBody : Grammar True PCaseBody
|
|
|
|
|
caseBody = braces $
|
|
|
|
|
[|CasePair (pairPat <* darr) (term <* optSemi)|]
|
2023-04-01 09:59:16 -04:00
|
|
|
|
<|> [|CaseBox (bracks bname <* darr) (term <* optSemi)|]
|
2023-03-26 08:40:54 -04:00
|
|
|
|
<|> CaseNat <$> zeroCase <* resC ";" <*> succCase <* optSemi
|
|
|
|
|
<|> flip CaseNat <$> succCase <* resC ";" <*> zeroCase <* optSemi
|
2023-03-18 15:00:29 -04:00
|
|
|
|
<|> [|CaseEnum $ semiSep [|MkPair tag (darr *> term)|]|]
|
2023-03-12 13:28:37 -04:00
|
|
|
|
where
|
2023-03-18 15:00:29 -04:00
|
|
|
|
optSemi = optional $ res ";"
|
2023-03-12 13:28:37 -04:00
|
|
|
|
pairPat = parens [|MkPair bname (resC "," *> bname)|]
|
|
|
|
|
|
2023-03-26 08:40:54 -04:00
|
|
|
|
zeroCase : Grammar True PTerm
|
|
|
|
|
zeroCase = (resC "zero" <|> zero) *> darr *> term
|
|
|
|
|
|
2023-04-01 13:16:43 -04:00
|
|
|
|
succCase : Grammar True (BName, Qty, BName, PTerm)
|
2023-03-26 08:40:54 -04:00
|
|
|
|
succCase = do
|
|
|
|
|
resC "succ"
|
2023-03-31 13:11:35 -04:00
|
|
|
|
n <- bname
|
|
|
|
|
ih <- option (Zero, Nothing) $
|
|
|
|
|
resC "," *> [|MkPair qty (resC "." *> bname)|]
|
2023-03-26 08:40:54 -04:00
|
|
|
|
rhs <- darr *> term
|
|
|
|
|
pure $ (n, fst ih, snd ih, rhs)
|
|
|
|
|
|
2023-03-12 13:28:37 -04:00
|
|
|
|
private covering
|
|
|
|
|
bindTerm : Grammar True PTerm
|
2023-03-18 18:27:27 -04:00
|
|
|
|
bindTerm = pi <|> sigma
|
|
|
|
|
where
|
|
|
|
|
binderHead = parens {commit = False} [|MkPair bname (resC ":" *> term)|]
|
|
|
|
|
|
|
|
|
|
pi, sigma : Grammar True PTerm
|
|
|
|
|
pi = [|makePi (qty <* res ".") domain (resC "→" *> term)|]
|
|
|
|
|
where
|
2023-04-01 13:16:43 -04:00
|
|
|
|
makePi : Qty -> (BName, PTerm) -> PTerm -> PTerm
|
2023-03-18 18:27:27 -04:00
|
|
|
|
makePi q (x, s) t = Pi q x s t
|
|
|
|
|
domain = binderHead <|> [|(Nothing,) aTerm|]
|
|
|
|
|
|
|
|
|
|
sigma = [|makeSigma binderHead (resC "×" *> annTerm)|]
|
|
|
|
|
where
|
|
|
|
|
makeSigma : (BName, PTerm) -> PTerm -> PTerm
|
|
|
|
|
makeSigma (x, s) t = Sig x s t
|
2023-03-18 15:00:29 -04:00
|
|
|
|
|
|
|
|
|
private covering
|
|
|
|
|
annTerm : Grammar True PTerm
|
|
|
|
|
annTerm = [|annotate infixEqTerm (optional $ resC "∷" *> term)|]
|
|
|
|
|
where annotate s a = maybe s (s :#) a
|
2023-03-12 13:28:37 -04:00
|
|
|
|
|
|
|
|
|
private covering
|
|
|
|
|
infixEqTerm : Grammar True PTerm
|
|
|
|
|
infixEqTerm = do
|
2023-03-17 21:46:19 -04:00
|
|
|
|
l <- infixTimesTerm
|
|
|
|
|
rty <- optional [|MkPair (resC "≡" *> term) (resC ":" *> infixTimesTerm)|]
|
2023-03-12 13:28:37 -04:00
|
|
|
|
pure $ maybe l (\rty => Eq (Nothing, snd rty) l (fst rty)) rty
|
|
|
|
|
|
2023-03-17 21:46:19 -04:00
|
|
|
|
private covering
|
|
|
|
|
infixTimesTerm : Grammar True PTerm
|
|
|
|
|
infixTimesTerm = foldr1 (Sig Nothing) <$> sepBy1 (resC "×") appTerm
|
|
|
|
|
|
2023-03-12 13:28:37 -04:00
|
|
|
|
private covering
|
|
|
|
|
appTerm : Grammar True PTerm
|
2023-03-26 08:40:54 -04:00
|
|
|
|
appTerm = resC "★" *> [|TYPE nat|]
|
2023-04-15 09:13:01 -04:00
|
|
|
|
<|> resC "Eq" *> [|Eq typeLine aTerm aTerm|]
|
2023-03-26 08:40:54 -04:00
|
|
|
|
<|> resC "succ" *> [|Succ aTerm|]
|
2023-03-12 13:28:37 -04:00
|
|
|
|
<|> [|apply aTerm (many appArg)|]
|
|
|
|
|
where
|
|
|
|
|
data PArg = TermArg PTerm | DimArg PDim
|
|
|
|
|
|
|
|
|
|
appArg : Grammar True PArg
|
2023-04-15 09:13:01 -04:00
|
|
|
|
appArg = [|DimArg dimArg|] <|> [|TermArg aTerm|]
|
2023-03-12 13:28:37 -04:00
|
|
|
|
|
|
|
|
|
apply : PTerm -> List PArg -> PTerm
|
|
|
|
|
apply = foldl apply1 where
|
|
|
|
|
apply1 : PTerm -> PArg -> PTerm
|
|
|
|
|
apply1 f (TermArg x) = f :@ x
|
|
|
|
|
apply1 f (DimArg p) = f :% p
|
|
|
|
|
|
2023-04-15 09:13:01 -04:00
|
|
|
|
private covering
|
|
|
|
|
typeLine : Grammar True (BName, PTerm)
|
|
|
|
|
typeLine = bracks optBinderTerm
|
|
|
|
|
|
|
|
|
|
private covering
|
|
|
|
|
dimArg : Grammar True PDim
|
|
|
|
|
dimArg = resC "@" *> dim
|
|
|
|
|
|
2023-03-12 13:28:37 -04:00
|
|
|
|
private covering
|
|
|
|
|
aTerm : Grammar True PTerm
|
|
|
|
|
aTerm = [|Enum $ braces $ commaSep bareTag|]
|
2023-03-31 13:11:35 -04:00
|
|
|
|
<|> foldr1 Pair <$> parens (commaSep1 term)
|
|
|
|
|
<|> boxTerm
|
2023-03-12 13:28:37 -04:00
|
|
|
|
<|> [|TYPE universe|]
|
2023-03-26 08:40:54 -04:00
|
|
|
|
<|> Nat <$ resC "ℕ"
|
|
|
|
|
<|> Zero <$ resC "zero"
|
|
|
|
|
<|> (nat <&> \n => fromNat n :# Nat)
|
2023-03-12 13:28:37 -04:00
|
|
|
|
<|> [|V name|]
|
|
|
|
|
<|> [|Tag tag|]
|
2023-03-31 13:11:35 -04:00
|
|
|
|
|
|
|
|
|
private covering
|
|
|
|
|
boxTerm : Grammar True PTerm
|
|
|
|
|
boxTerm = bracks $
|
|
|
|
|
[|BOX (qty <* resC ".") term|]
|
|
|
|
|
<|> [|Box term|]
|
2023-03-12 13:28:37 -04:00
|
|
|
|
|
|
|
|
|
private covering
|
|
|
|
|
optBinderTerm : Grammar True (BName, PTerm)
|
|
|
|
|
optBinderTerm = [|MkPair optNameBinder term|]
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
export covering
|
2023-04-01 13:16:43 -04:00
|
|
|
|
defIntro : Grammar True Qty
|
2023-03-18 15:00:29 -04:00
|
|
|
|
defIntro = symbols [(Zero, "def0"), (Any, "defω")]
|
2023-03-17 16:54:09 -04:00
|
|
|
|
<|> resC "def" *> option Any (qty <* resC ".")
|
2023-03-12 13:28:37 -04:00
|
|
|
|
|
2023-04-17 15:41:00 -04:00
|
|
|
|
skipSemis : Grammar False ()
|
|
|
|
|
skipSemis = ignore $ many $ resC ";"
|
|
|
|
|
|
2023-03-12 13:28:37 -04:00
|
|
|
|
export covering
|
|
|
|
|
definition : Grammar True PDefinition
|
|
|
|
|
definition =
|
2023-03-17 16:54:09 -04:00
|
|
|
|
[|MkPDef defIntro name (optional (resC ":" *> term)) (resC "=" *> term)|]
|
2023-03-12 13:28:37 -04:00
|
|
|
|
|
|
|
|
|
export
|
|
|
|
|
load : Grammar True String
|
|
|
|
|
load = resC "load" *> string
|
|
|
|
|
|
|
|
|
|
mutual
|
|
|
|
|
export covering
|
|
|
|
|
namespace_ : Grammar True PNamespace
|
|
|
|
|
namespace_ =
|
2023-04-17 15:41:00 -04:00
|
|
|
|
[|MkPNamespace (resC "namespace" *> mods)
|
|
|
|
|
(braces $ many $ decl <* skipSemis)|]
|
2023-03-12 13:28:37 -04:00
|
|
|
|
|
|
|
|
|
export covering
|
|
|
|
|
decl : Grammar True PDecl
|
|
|
|
|
decl = [|PDef definition|]
|
|
|
|
|
<|> [|PNs namespace_|]
|
|
|
|
|
|
|
|
|
|
export covering
|
|
|
|
|
topLevel : Grammar True PTopLevel
|
|
|
|
|
topLevel = [|PLoad load|]
|
|
|
|
|
<|> [|PD decl|]
|
|
|
|
|
|
|
|
|
|
export covering
|
|
|
|
|
input : Grammar False (List PTopLevel)
|
|
|
|
|
input = skipSemis *> many (topLevel <* skipSemis)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public export
|
|
|
|
|
data Error =
|
|
|
|
|
LexError Lexer.Error
|
|
|
|
|
| ParseError (List1 (ParsingError Token))
|
|
|
|
|
%hide Lexer.Error
|
2023-03-31 13:27:38 -04:00
|
|
|
|
%runElab derive "Error" [Show]
|
2023-03-12 13:28:37 -04:00
|
|
|
|
|
|
|
|
|
export
|
|
|
|
|
lexParseWith : {c : Bool} -> Grammar c a -> String -> Either Error a
|
|
|
|
|
lexParseWith grm input = do
|
|
|
|
|
toks <- mapFst LexError $ lex input
|
|
|
|
|
bimap ParseError fst $ parse (grm <* eof) toks
|
|
|
|
|
|
|
|
|
|
export covering %inline
|
|
|
|
|
lexParseInput : String -> Either Error (List PTopLevel)
|
|
|
|
|
lexParseInput = lexParseWith input
|
|
|
|
|
|
|
|
|
|
export covering %inline
|
|
|
|
|
lexParseTerm : String -> Either Error PTerm
|
|
|
|
|
lexParseTerm = lexParseWith term
|