2023-03-12 13:28:37 -04:00
|
|
|
|
module Quox.Parser.Parser
|
|
|
|
|
|
|
|
|
|
import public Quox.Parser.Lexer
|
|
|
|
|
import public Quox.Parser.Syntax
|
|
|
|
|
|
2023-04-24 16:25:00 -04:00
|
|
|
|
import Data.Bool
|
2023-03-12 13:28:37 -04:00
|
|
|
|
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
|
|
|
|
|
|
|
|
|
|
|
2023-04-24 16:25:00 -04:00
|
|
|
|
public export
|
|
|
|
|
data Error =
|
|
|
|
|
LexError Lexer.Error
|
|
|
|
|
| ParseError (List1 (ParsingError Token))
|
|
|
|
|
%hide Lexer.Error
|
|
|
|
|
%runElab derive "Error" [Show]
|
2023-03-12 13:28:37 -04:00
|
|
|
|
|
2023-04-25 20:47:42 -04:00
|
|
|
|
|
2023-03-12 13:28:37 -04:00
|
|
|
|
export
|
2023-04-24 16:25:00 -04:00
|
|
|
|
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
|
2023-03-12 13:28:37 -04:00
|
|
|
|
|
2023-04-25 20:47:42 -04:00
|
|
|
|
export
|
|
|
|
|
withLoc : {c : Bool} -> FileName -> (Grammar c (Loc -> a)) -> Grammar c a
|
|
|
|
|
withLoc fname act = bounds act <&> \res =>
|
2023-05-01 21:06:25 -04:00
|
|
|
|
if res.isIrrelevant then res.val noLoc
|
2023-04-25 20:47:42 -04:00
|
|
|
|
else res.val $ makeLoc fname res.bounds
|
|
|
|
|
|
|
|
|
|
export
|
|
|
|
|
defLoc : FileName -> (Loc -> a) -> Grammar False a
|
|
|
|
|
defLoc fname f = position <&> f . makeLoc fname
|
|
|
|
|
|
|
|
|
|
export
|
|
|
|
|
unused : FileName -> Grammar False PatVar
|
|
|
|
|
unused fname = defLoc fname Unused
|
|
|
|
|
|
2023-03-12 13:28:37 -04:00
|
|
|
|
|
2023-04-24 16:25:00 -04:00
|
|
|
|
||| reserved token, like punctuation or keywords etc
|
2023-03-12 13:28:37 -04:00
|
|
|
|
export
|
2023-04-24 16:25:00 -04:00
|
|
|
|
res : (str : String) -> (0 _ : IsReserved str) => Grammar True ()
|
|
|
|
|
res str = terminal "expected \"\{str}\"" $ guard . (== Reserved str)
|
2023-03-12 13:28:37 -04:00
|
|
|
|
|
2023-04-24 16:25:00 -04:00
|
|
|
|
||| optional reserved token, e.g. trailing comma
|
2023-03-12 13:28:37 -04:00
|
|
|
|
export
|
2023-04-24 16:25:00 -04:00
|
|
|
|
optRes : (str : String) -> (0 _ : IsReserved str) => Grammar False ()
|
|
|
|
|
optRes str = ignore $ optional $ res str
|
2023-03-12 13:28:37 -04:00
|
|
|
|
|
2023-04-24 16:25:00 -04:00
|
|
|
|
||| reserved token, then commit
|
2023-03-12 13:28:37 -04:00
|
|
|
|
export
|
2023-04-24 16:25:00 -04:00
|
|
|
|
resC : (str : String) -> (0 _ : IsReserved str) => Grammar True ()
|
|
|
|
|
resC str = do res str; commit
|
2023-03-12 13:28:37 -04:00
|
|
|
|
|
2023-04-24 16:25:00 -04:00
|
|
|
|
||| reserved token or fatal error
|
2023-03-12 13:28:37 -04:00
|
|
|
|
export
|
2023-04-24 16:25:00 -04:00
|
|
|
|
needRes : (str : String) -> (0 _ : IsReserved str) => Grammar True ()
|
|
|
|
|
needRes str = resC str <|> fatalError "expected \"\{str}\""
|
2023-03-12 13:28:37 -04:00
|
|
|
|
|
|
|
|
|
|
2023-04-24 16:25:00 -04:00
|
|
|
|
private
|
|
|
|
|
terminalMatchN_ : String -> List (TTImp, TTImp) -> Elab (Grammar True a)
|
|
|
|
|
terminalMatchN_ what matches = do
|
|
|
|
|
func <- check $ lam (lambdaArg `{x}) $
|
|
|
|
|
iCase `(x) implicitFalse $
|
|
|
|
|
map (\(l, r) => patClause l `(Just ~(r))) matches ++
|
|
|
|
|
[patClause `(_) `(Nothing)]
|
|
|
|
|
pure $ terminal "expected \{what}" func
|
|
|
|
|
|
|
|
|
|
private %macro
|
|
|
|
|
terminalMatchN : String -> List (TTImp, TTImp) -> Elab (Grammar True a)
|
|
|
|
|
terminalMatchN = terminalMatchN_
|
|
|
|
|
|
|
|
|
|
private %macro
|
|
|
|
|
terminalMatch : String -> TTImp -> TTImp -> Elab (Grammar True a)
|
|
|
|
|
terminalMatch what l r = terminalMatchN_ what [(l, r)]
|
|
|
|
|
|
|
|
|
|
||| tag without leading `'`
|
2023-03-12 13:28:37 -04:00
|
|
|
|
export
|
2023-04-24 16:25:00 -04:00
|
|
|
|
bareTag : Grammar True TagVal
|
2023-05-25 12:34:13 -04:00
|
|
|
|
bareTag = terminalMatchN "bare tag"
|
|
|
|
|
[(`(Name t), `(toDotsP t)), (`(Str s), `(s))]
|
2023-03-12 13:28:37 -04:00
|
|
|
|
|
2023-04-24 16:25:00 -04:00
|
|
|
|
||| tag with leading quote
|
2023-03-12 13:28:37 -04:00
|
|
|
|
export
|
2023-04-24 16:25:00 -04:00
|
|
|
|
tag : Grammar True TagVal
|
|
|
|
|
tag = terminalMatch "tag" `(Tag t) `(t)
|
2023-03-12 13:28:37 -04:00
|
|
|
|
|
2023-04-24 16:25:00 -04:00
|
|
|
|
||| natural number
|
2023-03-12 13:28:37 -04:00
|
|
|
|
export
|
|
|
|
|
nat : Grammar True Nat
|
2023-04-24 16:25:00 -04:00
|
|
|
|
nat = terminalMatch "natural number" `(Nat n) `(n)
|
2023-03-12 13:28:37 -04:00
|
|
|
|
|
2023-04-24 16:25:00 -04:00
|
|
|
|
||| string literal
|
2023-03-12 13:28:37 -04:00
|
|
|
|
export
|
2023-04-24 16:25:00 -04:00
|
|
|
|
strLit : Grammar True String
|
|
|
|
|
strLit = terminalMatch "string literal" `(Str s) `(s)
|
2023-03-12 13:28:37 -04:00
|
|
|
|
|
2023-05-21 14:09:34 -04:00
|
|
|
|
||| single-token universe, like ★0 or Type1
|
2023-03-12 13:28:37 -04:00
|
|
|
|
export
|
2023-05-21 14:09:34 -04:00
|
|
|
|
universeTok : Grammar True Universe
|
|
|
|
|
universeTok = terminalMatch "universe" `(TYPE u) `(u)
|
|
|
|
|
|
|
|
|
|
export
|
|
|
|
|
super : Grammar True Nat
|
|
|
|
|
super = terminalMatch "superscript number or '^'" `(Sup n) `(n)
|
2023-03-12 13:28:37 -04:00
|
|
|
|
|
2023-04-24 16:25:00 -04:00
|
|
|
|
||| possibly-qualified name
|
2023-03-12 13:28:37 -04:00
|
|
|
|
export
|
2023-04-24 16:25:00 -04:00
|
|
|
|
qname : Grammar True PName
|
|
|
|
|
qname = terminalMatch "name" `(Name n) `(n)
|
2023-03-12 13:28:37 -04:00
|
|
|
|
|
2023-04-24 16:25:00 -04:00
|
|
|
|
||| unqualified name
|
2023-03-12 13:28:37 -04:00
|
|
|
|
export
|
2023-04-24 16:25:00 -04:00
|
|
|
|
baseName : Grammar True PBaseName
|
2024-04-11 16:08:07 -04:00
|
|
|
|
baseName = terminalMatch "unqualified name" `(Name (MkPName [<] b)) `(b)
|
2023-03-12 13:28:37 -04:00
|
|
|
|
|
2023-04-24 16:25:00 -04:00
|
|
|
|
||| dimension constant (0 or 1)
|
2023-03-12 13:28:37 -04:00
|
|
|
|
export
|
2023-03-18 15:00:29 -04:00
|
|
|
|
dimConst : Grammar True DimConst
|
2023-04-24 16:25:00 -04:00
|
|
|
|
dimConst = terminalMatchN "dimension constant"
|
|
|
|
|
[(`(Nat 0), `(Zero)), (`(Nat 1), `(One))]
|
2023-03-12 13:28:37 -04:00
|
|
|
|
|
2023-04-24 16:25:00 -04:00
|
|
|
|
||| quantity (0, 1, or ω)
|
2023-03-18 15:00:29 -04:00
|
|
|
|
export
|
2023-04-25 20:47:42 -04:00
|
|
|
|
qtyVal : Grammar True Qty
|
|
|
|
|
qtyVal = terminalMatchN "quantity"
|
2023-04-24 16:25:00 -04:00
|
|
|
|
[(`(Nat 0), `(Zero)), (`(Nat 1), `(One)), (`(Reserved "ω"), `(Any))]
|
2023-03-18 15:00:29 -04:00
|
|
|
|
|
2023-03-26 08:40:54 -04:00
|
|
|
|
|
2023-05-21 14:09:34 -04:00
|
|
|
|
||| optional superscript number
|
|
|
|
|
export
|
|
|
|
|
displacement : Grammar False (Maybe Universe)
|
|
|
|
|
displacement = optional super
|
|
|
|
|
|
2023-04-25 20:47:42 -04:00
|
|
|
|
||| quantity (0, 1, or ω)
|
|
|
|
|
export
|
|
|
|
|
qty : FileName -> Grammar True PQty
|
|
|
|
|
qty fname = withLoc fname [|PQ qtyVal|]
|
|
|
|
|
|
2023-09-21 19:29:23 -04:00
|
|
|
|
export
|
|
|
|
|
exactName : String -> Grammar True ()
|
|
|
|
|
exactName name = terminal "expected '\{name}'" $ \case
|
2024-04-11 16:08:07 -04:00
|
|
|
|
Name (MkPName [<] x) => guard $ x == name
|
|
|
|
|
_ => Nothing
|
2023-09-21 19:29:23 -04:00
|
|
|
|
|
2023-04-25 20:47:42 -04:00
|
|
|
|
|
2023-04-24 16:25:00 -04:00
|
|
|
|
||| pattern var (unqualified name or _)
|
|
|
|
|
export
|
2023-04-25 20:47:42 -04:00
|
|
|
|
patVar : FileName -> Grammar True PatVar
|
|
|
|
|
patVar fname = withLoc fname $
|
|
|
|
|
[|PV baseName|] <|> Unused <$ res "_"
|
2023-03-18 15:00:29 -04:00
|
|
|
|
|
|
|
|
|
|
2023-04-24 16:25:00 -04:00
|
|
|
|
||| dimension (without `@` prefix)
|
2023-03-18 15:00:29 -04:00
|
|
|
|
export
|
2023-04-25 20:47:42 -04:00
|
|
|
|
dim : FileName -> Grammar True PDim
|
|
|
|
|
dim fname = withLoc fname $ [|K dimConst|] <|> [|V baseName|]
|
2023-03-18 15:00:29 -04:00
|
|
|
|
|
2023-04-24 16:25:00 -04:00
|
|
|
|
||| dimension argument (with @)
|
2023-03-18 15:00:29 -04:00
|
|
|
|
export
|
2023-04-25 20:47:42 -04:00
|
|
|
|
dimArg : FileName -> Grammar True PDim
|
|
|
|
|
dimArg fname = do resC "@"; mustWork $ dim fname
|
2023-04-24 16:25:00 -04:00
|
|
|
|
|
2023-03-18 15:00:29 -04:00
|
|
|
|
|
2023-04-24 16:25:00 -04:00
|
|
|
|
delim : (o, c : String) -> (0 _ : IsReserved o) => (0 _ : IsReserved c) =>
|
|
|
|
|
{k : Bool} -> Grammar k a -> Grammar True a
|
|
|
|
|
delim o c p = resC o *> p <* needRes c
|
2023-03-12 13:28:37 -04:00
|
|
|
|
|
2023-04-24 16:25:00 -04:00
|
|
|
|
-- this stuff is Like This (rather than just being delim + sepEndBy{1})
|
|
|
|
|
-- so that it checks for the close bracket before trying another list element,
|
|
|
|
|
-- giving (imo) a better error
|
|
|
|
|
parameters (o, c, s : String)
|
|
|
|
|
{auto 0 _ : IsReserved o} {auto 0 _ : IsReserved c}
|
|
|
|
|
{auto 0 _ : IsReserved s}
|
|
|
|
|
(p : Grammar True a)
|
|
|
|
|
private
|
|
|
|
|
dsBeforeDelim, dsAfterDelim : Grammar True (List a)
|
|
|
|
|
dsBeforeDelim = [] <$ resC c <|> resC s *> assert_total dsAfterDelim
|
|
|
|
|
dsAfterDelim = [] <$ resC c <|> [|p :: assert_total dsBeforeDelim|]
|
|
|
|
|
|
|
|
|
|
export
|
|
|
|
|
delimSep1 : Grammar True (List1 a)
|
|
|
|
|
delimSep1 = resC o *> [|p ::: dsBeforeDelim|]
|
|
|
|
|
|
|
|
|
|
export
|
|
|
|
|
delimSep : Grammar True (List a)
|
|
|
|
|
delimSep = resC o *> dsAfterDelim
|
2023-03-12 13:28:37 -04:00
|
|
|
|
|
|
|
|
|
|
2023-04-24 16:25:00 -04:00
|
|
|
|
||| enum type, e.g. `{a, b, c.d, "e f g"}`
|
2023-03-18 15:00:29 -04:00
|
|
|
|
export
|
2023-04-24 16:25:00 -04:00
|
|
|
|
enumType : Grammar True (List TagVal)
|
|
|
|
|
enumType = delimSep "{" "}" "," bareTag
|
2023-03-12 13:28:37 -04:00
|
|
|
|
|
2023-07-18 17:12:04 -04:00
|
|
|
|
||| e.g. `case1` or `case 1.`
|
2023-04-24 16:25:00 -04:00
|
|
|
|
export
|
2023-04-25 20:47:42 -04:00
|
|
|
|
caseIntro : FileName -> Grammar True PQty
|
|
|
|
|
caseIntro fname =
|
|
|
|
|
withLoc fname (PQ Zero <$ res "case0")
|
|
|
|
|
<|> withLoc fname (PQ One <$ res "case1")
|
|
|
|
|
<|> withLoc fname (PQ Any <$ res "caseω")
|
2023-07-18 17:12:04 -04:00
|
|
|
|
<|> do resC "case"
|
|
|
|
|
qty fname <* needRes "." <|> defLoc fname (PQ One)
|
2023-03-12 13:28:37 -04:00
|
|
|
|
|
2023-04-24 16:25:00 -04:00
|
|
|
|
export
|
2023-04-25 20:47:42 -04:00
|
|
|
|
qtyPatVar : FileName -> Grammar True (PQty, PatVar)
|
2023-07-18 17:12:04 -04:00
|
|
|
|
qtyPatVar fname =
|
|
|
|
|
[|(,) (qty fname) (needRes "." *> patVar fname)|]
|
|
|
|
|
<|> [|(,) (defLoc fname $ PQ One) (patVar fname)|]
|
2023-03-12 13:28:37 -04:00
|
|
|
|
|
|
|
|
|
|
2023-04-25 20:47:42 -04:00
|
|
|
|
export
|
|
|
|
|
ptag : FileName -> Grammar True PTagVal
|
|
|
|
|
ptag fname = withLoc fname $ [|PT tag|]
|
|
|
|
|
|
2023-04-24 16:25:00 -04:00
|
|
|
|
public export
|
|
|
|
|
data PCasePat =
|
2023-04-25 20:47:42 -04:00
|
|
|
|
PPair PatVar PatVar Loc
|
|
|
|
|
| PTag PTagVal Loc
|
|
|
|
|
| PZero Loc
|
|
|
|
|
| PSucc PatVar PQty PatVar Loc
|
|
|
|
|
| PBox PatVar Loc
|
2023-04-24 16:25:00 -04:00
|
|
|
|
%runElab derive "PCasePat" [Eq, Ord, Show]
|
2023-03-12 13:28:37 -04:00
|
|
|
|
|
2023-04-25 20:47:42 -04:00
|
|
|
|
export
|
|
|
|
|
Located PCasePat where
|
|
|
|
|
(PPair _ _ loc).loc = loc
|
|
|
|
|
(PTag _ loc).loc = loc
|
|
|
|
|
(PZero loc).loc = loc
|
|
|
|
|
(PSucc _ _ _ loc).loc = loc
|
|
|
|
|
(PBox _ loc).loc = loc
|
|
|
|
|
|
2023-04-24 16:25:00 -04:00
|
|
|
|
||| either `zero` or `0`
|
|
|
|
|
export
|
|
|
|
|
zeroPat : Grammar True ()
|
|
|
|
|
zeroPat = resC "zero" <|> terminal "expected '0'" (guard . (== Nat 0))
|
|
|
|
|
|
|
|
|
|
export
|
2023-04-25 20:47:42 -04:00
|
|
|
|
casePat : FileName -> Grammar True PCasePat
|
|
|
|
|
casePat fname = withLoc fname $
|
|
|
|
|
delim "(" ")" [|PPair (patVar fname) (needRes "," *> patVar fname)|]
|
|
|
|
|
<|> [|PTag (ptag fname)|]
|
2023-04-24 16:25:00 -04:00
|
|
|
|
<|> PZero <$ zeroPat
|
2023-04-25 20:47:42 -04:00
|
|
|
|
<|> do p <- resC "succ" *> patVar fname
|
|
|
|
|
ih <- resC "," *> qtyPatVar fname
|
|
|
|
|
<|> [|(,) (defLoc fname $ PQ Zero) (unused fname)|]
|
2023-04-24 16:25:00 -04:00
|
|
|
|
pure $ PSucc p (fst ih) (snd ih)
|
2023-04-25 20:47:42 -04:00
|
|
|
|
<|> delim "[" "]" [|PBox (patVar fname)|]
|
2023-04-24 16:25:00 -04:00
|
|
|
|
<|> fatalError "invalid pattern"
|
|
|
|
|
|
2023-05-01 21:06:25 -04:00
|
|
|
|
export
|
2023-04-25 20:47:42 -04:00
|
|
|
|
term : FileName -> Grammar True PTerm
|
|
|
|
|
-- defined after all the subterm parsers
|
2023-04-25 20:23:59 -04:00
|
|
|
|
|
|
|
|
|
||| box term `[t]` or type `[π.A]`
|
2023-05-01 21:06:25 -04:00
|
|
|
|
export
|
2023-04-25 20:47:42 -04:00
|
|
|
|
boxTerm : FileName -> Grammar True PTerm
|
|
|
|
|
boxTerm fname = withLoc fname $ do
|
2023-04-25 20:23:59 -04:00
|
|
|
|
res "["; commit
|
2023-05-01 21:06:25 -04:00
|
|
|
|
q <- optional $ qty fname <* res "."
|
|
|
|
|
t <- mustWork $ assert_total term fname <* needRes "]"
|
2023-04-25 20:23:59 -04:00
|
|
|
|
pure $ maybe (Box t) (\q => BOX q t) q
|
|
|
|
|
|
|
|
|
|
||| tuple term like `(a, b)`, or parenthesised single term.
|
|
|
|
|
||| allows terminating comma. more than two elements are nested on the right:
|
|
|
|
|
||| `(a, b, c, d) = (a, (b, (c, d)))`.
|
2023-05-01 21:06:25 -04:00
|
|
|
|
export
|
2023-04-25 20:47:42 -04:00
|
|
|
|
tupleTerm : FileName -> Grammar True PTerm
|
|
|
|
|
tupleTerm fname = withLoc fname $ do
|
2023-05-01 21:06:25 -04:00
|
|
|
|
terms <- delimSep1 "(" ")" "," $ assert_total term fname
|
2023-04-25 20:47:42 -04:00
|
|
|
|
pure $ \loc => foldr1 (\s, t => Pair s t loc) terms
|
2023-04-25 20:23:59 -04:00
|
|
|
|
|
2023-05-21 14:09:34 -04:00
|
|
|
|
export
|
|
|
|
|
universe1 : Grammar True Universe
|
2023-05-21 14:33:42 -04:00
|
|
|
|
universe1 = universeTok <|> res "★" *> option 0 super
|
2023-05-21 14:09:34 -04:00
|
|
|
|
|
2023-12-04 12:28:57 -05:00
|
|
|
|
|
|
|
|
|
public export
|
|
|
|
|
PCaseArm : Type
|
|
|
|
|
PCaseArm = (PCasePat, PTerm)
|
|
|
|
|
|
|
|
|
|
export
|
|
|
|
|
caseArm : FileName -> Grammar True PCaseArm
|
|
|
|
|
caseArm fname =
|
|
|
|
|
[|(,) (casePat fname) (needRes "⇒" *> assert_total term fname)|]
|
|
|
|
|
|
|
|
|
|
export
|
|
|
|
|
checkCaseArms : Loc -> List PCaseArm -> Grammar False PCaseBody
|
|
|
|
|
checkCaseArms loc [] = pure $ CaseEnum [] loc
|
|
|
|
|
checkCaseArms loc ((PPair x y _, rhs) :: rest) =
|
|
|
|
|
if null rest then pure $ CasePair (x, y) rhs loc
|
|
|
|
|
else fatalError "unexpected pattern after pair"
|
|
|
|
|
checkCaseArms loc ((PTag tag _, rhs1) :: rest) = do
|
|
|
|
|
let rest = for rest $ \case
|
|
|
|
|
(PTag tag _, rhs) => Just (tag, rhs)
|
|
|
|
|
_ => Nothing
|
|
|
|
|
maybe (fatalError "expected all patterns to be tags")
|
|
|
|
|
(\rest => pure $ CaseEnum ((tag, rhs1) :: rest) loc) rest
|
|
|
|
|
checkCaseArms loc ((PZero _, rhs1) :: rest) = do
|
|
|
|
|
let [(PSucc p q ih _, rhs2)] = rest
|
|
|
|
|
| _ => fatalError "expected succ pattern after zero"
|
|
|
|
|
pure $ CaseNat rhs1 (p, q, ih, rhs2) loc
|
|
|
|
|
checkCaseArms loc ((PSucc p q ih _, rhs1) :: rest) = do
|
|
|
|
|
let [(PZero _, rhs2)] = rest
|
|
|
|
|
| _ => fatalError "expected zero pattern after succ"
|
|
|
|
|
pure $ CaseNat rhs2 (p, q, ih, rhs1) loc
|
|
|
|
|
checkCaseArms loc ((PBox x _, rhs) :: rest) =
|
|
|
|
|
if null rest then pure $ CaseBox x rhs loc
|
|
|
|
|
else fatalError "unexpected pattern after box"
|
|
|
|
|
|
|
|
|
|
export
|
|
|
|
|
caseBody : FileName -> Grammar True PCaseBody
|
|
|
|
|
caseBody fname = do
|
|
|
|
|
body <- bounds $ delimSep "{" "}" ";" $ caseArm fname
|
|
|
|
|
let loc = makeLoc fname body.bounds
|
|
|
|
|
checkCaseArms loc body.val
|
|
|
|
|
|
|
|
|
|
export
|
|
|
|
|
caseReturn : FileName -> Grammar True (PatVar, PTerm)
|
|
|
|
|
caseReturn fname = do
|
|
|
|
|
x <- patVar fname <* resC "⇒" <|> unused fname
|
|
|
|
|
ret <- assert_total term fname
|
|
|
|
|
pure (x, ret)
|
|
|
|
|
|
|
|
|
|
export
|
|
|
|
|
caseTerm : FileName -> Grammar True PTerm
|
|
|
|
|
caseTerm fname = withLoc fname $ do
|
|
|
|
|
qty <- caseIntro fname; commit
|
|
|
|
|
head <- mustWork $ assert_total term fname; needRes "return"
|
|
|
|
|
ret <- mustWork $ caseReturn fname; needRes "of"
|
|
|
|
|
body <- mustWork $ caseBody fname
|
|
|
|
|
pure $ Case qty head ret body
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
||| argument/atomic term: single-token terms, or those with delimiters
|
|
|
|
|
||| e.g. `[t]`. includes `case` because the end delimiter is the `}`.
|
2023-05-01 21:06:25 -04:00
|
|
|
|
export
|
2023-04-25 20:47:42 -04:00
|
|
|
|
termArg : FileName -> Grammar True PTerm
|
|
|
|
|
termArg fname = withLoc fname $
|
|
|
|
|
[|TYPE universe1|]
|
2023-11-01 10:17:15 -04:00
|
|
|
|
<|> IOState <$ res "IOState"
|
2023-04-25 20:47:42 -04:00
|
|
|
|
<|> [|Enum enumType|]
|
|
|
|
|
<|> [|Tag tag|]
|
|
|
|
|
<|> const <$> boxTerm fname
|
2023-11-02 15:01:34 -04:00
|
|
|
|
<|> NAT <$ res "ℕ"
|
|
|
|
|
<|> Nat 0 <$ res "zero"
|
|
|
|
|
<|> [|Nat nat|]
|
2023-11-01 10:17:15 -04:00
|
|
|
|
<|> STRING <$ res "String"
|
|
|
|
|
<|> [|Str strLit|]
|
2023-05-21 14:09:34 -04:00
|
|
|
|
<|> [|V qname displacement|]
|
2023-12-04 12:28:57 -05:00
|
|
|
|
<|> const <$> caseTerm fname
|
2023-04-25 20:47:42 -04:00
|
|
|
|
<|> const <$> tupleTerm fname
|
2023-04-25 20:23:59 -04:00
|
|
|
|
|
2023-05-16 12:14:42 -04:00
|
|
|
|
export
|
|
|
|
|
properTypeLine : FileName -> Grammar True (PatVar, PTerm)
|
|
|
|
|
properTypeLine fname = do
|
|
|
|
|
resC "("
|
|
|
|
|
i <- patVar fname <* resC "⇒" <|> unused fname
|
|
|
|
|
t <- assert_total term fname <* needRes ")"
|
|
|
|
|
pure (i, t)
|
|
|
|
|
|
|
|
|
|
export
|
|
|
|
|
typeLine : FileName -> Grammar True (PatVar, PTerm)
|
|
|
|
|
typeLine fname =
|
|
|
|
|
properTypeLine fname <|> [|(,) (unused fname) (termArg fname)|]
|
|
|
|
|
|
2023-05-15 13:57:10 -04:00
|
|
|
|
||| optionally, two dimension arguments. if absent default to `@0 @1`
|
|
|
|
|
private
|
|
|
|
|
optDirection : FileName -> Grammar False (PDim, PDim)
|
|
|
|
|
optDirection fname = withLoc fname $ do
|
|
|
|
|
dims <- optional [|(,) (dimArg fname) (dimArg fname)|]
|
|
|
|
|
pure $ \loc => fromMaybe (K Zero loc, K One loc) dims
|
|
|
|
|
|
2023-05-01 21:06:25 -04:00
|
|
|
|
export
|
2023-04-25 20:47:42 -04:00
|
|
|
|
coeTerm : FileName -> Grammar True PTerm
|
|
|
|
|
coeTerm fname = withLoc fname $ do
|
|
|
|
|
resC "coe"
|
2023-05-15 13:57:10 -04:00
|
|
|
|
mustWork $ do
|
|
|
|
|
line <- typeLine fname
|
|
|
|
|
(p, q) <- optDirection fname
|
|
|
|
|
val <- termArg fname
|
|
|
|
|
pure $ Coe line p q val
|
2023-04-25 20:47:42 -04:00
|
|
|
|
|
|
|
|
|
public export
|
|
|
|
|
CompBranch : Type
|
|
|
|
|
CompBranch = (DimConst, PatVar, PTerm)
|
2023-04-25 20:23:59 -04:00
|
|
|
|
|
2023-05-01 21:06:25 -04:00
|
|
|
|
export
|
2023-04-25 20:47:42 -04:00
|
|
|
|
compBranch : FileName -> Grammar True CompBranch
|
2023-05-01 21:06:25 -04:00
|
|
|
|
compBranch fname =
|
2023-05-15 13:57:10 -04:00
|
|
|
|
[|(,,) dimConst (patVar fname) (needRes "⇒" *> assert_total term fname)|]
|
2023-04-25 20:47:42 -04:00
|
|
|
|
|
|
|
|
|
private
|
|
|
|
|
checkCompTermBody : (PatVar, PTerm) -> PDim -> PDim -> PTerm -> PDim ->
|
|
|
|
|
CompBranch -> CompBranch -> Bounds ->
|
|
|
|
|
Grammar False (Loc -> PTerm)
|
|
|
|
|
checkCompTermBody a p q s r (e0, s0) (e1, s1) bounds =
|
|
|
|
|
case (e0, e1) of
|
|
|
|
|
(Zero, One) => pure $ Comp a p q s r s0 s1
|
|
|
|
|
(One, Zero) => pure $ Comp a p q s r s1 s0
|
|
|
|
|
(_, _) =>
|
|
|
|
|
fatalLoc bounds "body of 'comp' needs one 0 case and one 1 case"
|
2023-04-25 20:23:59 -04:00
|
|
|
|
|
2023-05-01 21:06:25 -04:00
|
|
|
|
export
|
2023-04-25 20:47:42 -04:00
|
|
|
|
compTerm : FileName -> Grammar True PTerm
|
|
|
|
|
compTerm fname = withLoc fname $ do
|
2023-04-25 20:23:59 -04:00
|
|
|
|
resC "comp"
|
|
|
|
|
mustWork $ do
|
2023-04-25 20:47:42 -04:00
|
|
|
|
a <- typeLine fname
|
2023-05-15 13:57:10 -04:00
|
|
|
|
(p, q) <- optDirection fname
|
2023-04-25 20:47:42 -04:00
|
|
|
|
s <- termArg fname; r <- dimArg fname
|
|
|
|
|
bodyStart <- bounds $ needRes "{"
|
|
|
|
|
s0 <- compBranch fname; needRes ";"
|
|
|
|
|
s1 <- compBranch fname; optRes ";"
|
|
|
|
|
bodyEnd <- bounds $ needRes "}"
|
|
|
|
|
let body = bounds $ mergeBounds bodyStart bodyEnd
|
|
|
|
|
checkCompTermBody a p q s r s0 s1 body
|
2023-04-25 20:23:59 -04:00
|
|
|
|
|
2023-05-01 21:06:25 -04:00
|
|
|
|
export
|
2023-04-25 20:47:42 -04:00
|
|
|
|
splitUniverseTerm : FileName -> Grammar True PTerm
|
2023-05-21 14:09:34 -04:00
|
|
|
|
splitUniverseTerm fname =
|
2023-05-21 14:33:42 -04:00
|
|
|
|
withLoc fname $ resC "★" *> [|TYPE $ option 0 $ nat <|> super|]
|
|
|
|
|
-- some of this looks redundant, but when parsing a non-atomic term
|
2023-05-21 14:09:34 -04:00
|
|
|
|
-- this branch will be taken first
|
2023-04-25 20:23:59 -04:00
|
|
|
|
|
2023-05-01 21:06:25 -04:00
|
|
|
|
export
|
2023-04-25 20:47:42 -04:00
|
|
|
|
eqTerm : FileName -> Grammar True PTerm
|
|
|
|
|
eqTerm fname = withLoc fname $
|
|
|
|
|
resC "Eq" *> mustWork [|Eq (typeLine fname) (termArg fname) (termArg fname)|]
|
2023-04-25 20:23:59 -04:00
|
|
|
|
|
2023-12-04 12:21:27 -05:00
|
|
|
|
private
|
|
|
|
|
appArg : Loc -> PTerm -> Either PDim PTerm -> PTerm
|
|
|
|
|
appArg loc f (Left p) = DApp f p loc
|
|
|
|
|
appArg loc f (Right s) = App f s loc
|
|
|
|
|
|
|
|
|
|
||| a dimension argument with an `@` prefix, or
|
|
|
|
|
||| a term argument with no prefix
|
|
|
|
|
export
|
|
|
|
|
anyArg : FileName -> Grammar True (Either PDim PTerm)
|
|
|
|
|
anyArg fname = dimArg fname <||> termArg fname
|
|
|
|
|
|
2023-09-18 15:52:51 -04:00
|
|
|
|
export
|
|
|
|
|
resAppTerm : FileName -> (word : String) -> (0 _ : IsReserved word) =>
|
|
|
|
|
(PTerm -> Loc -> PTerm) -> Grammar True PTerm
|
2023-12-04 12:21:27 -05:00
|
|
|
|
resAppTerm fname word f = withLoc fname $ do
|
|
|
|
|
head <- withLoc fname $ resC word *> mustWork [|f (termArg fname)|]
|
|
|
|
|
args <- many $ anyArg fname
|
|
|
|
|
pure $ \loc => foldl (appArg loc) head args
|
2023-09-18 15:52:51 -04:00
|
|
|
|
|
2023-05-01 21:06:25 -04:00
|
|
|
|
export
|
2023-04-25 20:47:42 -04:00
|
|
|
|
succTerm : FileName -> Grammar True PTerm
|
2023-09-18 15:52:51 -04:00
|
|
|
|
succTerm fname = resAppTerm fname "succ" Succ
|
|
|
|
|
|
|
|
|
|
export
|
|
|
|
|
fstTerm : FileName -> Grammar True PTerm
|
|
|
|
|
fstTerm fname = resAppTerm fname "fst" Fst
|
|
|
|
|
|
|
|
|
|
export
|
|
|
|
|
sndTerm : FileName -> Grammar True PTerm
|
|
|
|
|
sndTerm fname = resAppTerm fname "snd" Snd
|
2023-04-25 20:23:59 -04:00
|
|
|
|
|
2023-05-01 21:06:25 -04:00
|
|
|
|
export
|
2023-04-25 20:47:42 -04:00
|
|
|
|
normalAppTerm : FileName -> Grammar True PTerm
|
|
|
|
|
normalAppTerm fname = withLoc fname $ do
|
|
|
|
|
head <- termArg fname
|
|
|
|
|
args <- many $ anyArg fname
|
2023-12-04 12:21:27 -05:00
|
|
|
|
pure $ \loc => foldl (appArg loc) head args
|
2023-04-25 20:23:59 -04:00
|
|
|
|
|
|
|
|
|
||| application term `f x @y z`, or other terms that look like application
|
|
|
|
|
||| like `succ` or `coe`.
|
2023-05-01 21:06:25 -04:00
|
|
|
|
export
|
2023-04-25 20:47:42 -04:00
|
|
|
|
appTerm : FileName -> Grammar True PTerm
|
|
|
|
|
appTerm fname =
|
|
|
|
|
coeTerm fname
|
|
|
|
|
<|> compTerm fname
|
|
|
|
|
<|> splitUniverseTerm fname
|
|
|
|
|
<|> eqTerm fname
|
|
|
|
|
<|> succTerm fname
|
2023-09-18 15:52:51 -04:00
|
|
|
|
<|> fstTerm fname
|
|
|
|
|
<|> sndTerm fname
|
2023-04-25 20:47:42 -04:00
|
|
|
|
<|> normalAppTerm fname
|
2023-04-25 20:23:59 -04:00
|
|
|
|
|
2023-05-01 21:06:25 -04:00
|
|
|
|
export
|
2023-04-25 20:47:42 -04:00
|
|
|
|
infixEqTerm : FileName -> Grammar True PTerm
|
|
|
|
|
infixEqTerm fname = withLoc fname $ do
|
|
|
|
|
l <- appTerm fname; commit
|
2023-05-01 21:06:25 -04:00
|
|
|
|
rest <- optional $ res "≡" *>
|
|
|
|
|
[|(,) (assert_total term fname) (needRes ":" *> appTerm fname)|]
|
2023-04-25 20:47:42 -04:00
|
|
|
|
let u = Unused $ onlyStart l.loc
|
|
|
|
|
pure $ \loc => maybe l (\rest => Eq (u, snd rest) l (fst rest) loc) rest
|
2023-04-25 20:23:59 -04:00
|
|
|
|
|
2023-05-01 21:06:25 -04:00
|
|
|
|
export
|
2023-04-25 20:47:42 -04:00
|
|
|
|
annTerm : FileName -> Grammar True PTerm
|
|
|
|
|
annTerm fname = withLoc fname $ do
|
|
|
|
|
tm <- infixEqTerm fname; commit
|
2023-05-01 21:06:25 -04:00
|
|
|
|
ty <- optional $ res "∷" *> assert_total term fname
|
2023-04-25 20:47:42 -04:00
|
|
|
|
pure $ \loc => maybe tm (\ty => Ann tm ty loc) ty
|
2023-04-25 20:23:59 -04:00
|
|
|
|
|
2023-05-01 21:06:25 -04:00
|
|
|
|
export
|
2023-04-25 20:47:42 -04:00
|
|
|
|
lamTerm : FileName -> Grammar True PTerm
|
|
|
|
|
lamTerm fname = withLoc fname $ do
|
2023-04-25 20:23:59 -04:00
|
|
|
|
k <- DLam <$ res "δ" <|> Lam <$ res "λ"
|
|
|
|
|
mustWork $ do
|
2023-05-01 21:06:25 -04:00
|
|
|
|
xs <- some $ patVar fname; needRes "⇒"
|
|
|
|
|
body <- assert_total term fname; commit
|
2023-04-25 20:47:42 -04:00
|
|
|
|
pure $ \loc => foldr (\x, s => k x s loc) body xs
|
2023-04-25 20:23:59 -04:00
|
|
|
|
|
|
|
|
|
-- [todo] fix the backtracking in e.g. (F x y z × B)
|
2023-05-01 21:06:25 -04:00
|
|
|
|
export
|
2023-04-25 20:47:42 -04:00
|
|
|
|
properBinders : FileName -> Grammar True (List1 PatVar, PTerm)
|
2023-05-01 21:06:25 -04:00
|
|
|
|
properBinders fname = assert_total $ do
|
|
|
|
|
-- putting assert_total directly on `term`, in this one function,
|
|
|
|
|
-- doesn't work. i cannot tell why
|
2023-04-25 20:23:59 -04:00
|
|
|
|
res "("
|
2023-04-25 20:47:42 -04:00
|
|
|
|
xs <- some $ patVar fname; resC ":"
|
|
|
|
|
t <- term fname; needRes ")"
|
2023-04-25 20:23:59 -04:00
|
|
|
|
pure (xs, t)
|
|
|
|
|
|
2023-05-01 21:06:25 -04:00
|
|
|
|
export
|
2023-04-25 20:47:42 -04:00
|
|
|
|
sigmaTerm : FileName -> Grammar True PTerm
|
|
|
|
|
sigmaTerm fname =
|
|
|
|
|
(properBinders fname >>= continueDep)
|
|
|
|
|
<|> (annTerm fname >>= continueNondep)
|
2023-04-25 20:23:59 -04:00
|
|
|
|
where
|
2023-04-25 20:47:42 -04:00
|
|
|
|
continueDep : (List1 PatVar, PTerm) -> Grammar True PTerm
|
|
|
|
|
continueDep (names, fst) = withLoc fname $ do
|
|
|
|
|
snd <- needRes "×" *> sigmaTerm fname
|
|
|
|
|
pure $ \loc => foldr (\x, snd => Sig x fst snd loc) snd names
|
|
|
|
|
|
|
|
|
|
cross : PTerm -> PTerm -> PTerm
|
|
|
|
|
cross l r = let loc = extend' l.loc r.loc.bounds in
|
|
|
|
|
Sig (Unused $ onlyStart l.loc) l r loc
|
2023-04-25 20:23:59 -04:00
|
|
|
|
|
2023-04-25 20:47:42 -04:00
|
|
|
|
continueNondep : PTerm -> Grammar False PTerm
|
|
|
|
|
continueNondep fst = do
|
|
|
|
|
rest <- optional $ resC "×" *> sepBy1 (res "×") (annTerm fname)
|
|
|
|
|
pure $ foldr1 cross $ fst ::: maybe [] toList rest
|
2023-04-25 20:23:59 -04:00
|
|
|
|
|
2023-07-18 17:12:04 -04:00
|
|
|
|
export
|
|
|
|
|
piTerm : FileName -> Grammar True PTerm
|
|
|
|
|
piTerm fname = withLoc fname $ do
|
|
|
|
|
q <- [|GivenQ $ qty fname <* resC "."|] <|> defLoc fname DefaultQ
|
|
|
|
|
dom <- [|Dep $ properBinders fname|] <|> [|Nondep $ ndDom q fname|]
|
|
|
|
|
cod <- optional $ do resC "→"; assert_total term fname <* commit
|
|
|
|
|
when (needCod q dom && isNothing cod) $ fail "missing function type result"
|
|
|
|
|
pure $ maybe (const $ toTerm dom) (makePi q dom) cod
|
|
|
|
|
where
|
|
|
|
|
data PiQty = GivenQ PQty | DefaultQ Loc
|
|
|
|
|
data PiDom = Dep (List1 PatVar, PTerm) | Nondep PTerm
|
|
|
|
|
|
|
|
|
|
ndDom : PiQty -> FileName -> Grammar True PTerm
|
|
|
|
|
ndDom (GivenQ _) = termArg -- 「1.(List A)」, not 「1.List A」
|
|
|
|
|
ndDom (DefaultQ _) = sigmaTerm
|
|
|
|
|
|
|
|
|
|
needCod : PiQty -> PiDom -> Bool
|
|
|
|
|
needCod (DefaultQ _) (Nondep _) = False
|
|
|
|
|
needCod _ _ = True
|
|
|
|
|
|
|
|
|
|
toTerm : PiDom -> PTerm
|
|
|
|
|
toTerm (Dep (_, s)) = s
|
|
|
|
|
toTerm (Nondep s) = s
|
|
|
|
|
|
|
|
|
|
toQty : PiQty -> PQty
|
|
|
|
|
toQty (GivenQ qty) = qty
|
|
|
|
|
toQty (DefaultQ loc) = PQ One loc
|
|
|
|
|
|
|
|
|
|
toDoms : PQty -> PiDom -> List1 (PQty, PatVar, PTerm)
|
|
|
|
|
toDoms qty (Dep (xs, s)) = [(qty, x, s) | x <- xs]
|
|
|
|
|
toDoms qty (Nondep s) = singleton (qty, Unused s.loc, s)
|
|
|
|
|
|
|
|
|
|
makePi : PiQty -> PiDom -> PTerm -> Loc -> PTerm
|
|
|
|
|
makePi q doms cod loc =
|
|
|
|
|
foldr (\(q, x, s), t => Pi q x s t loc) cod $ toDoms (toQty q) doms
|
|
|
|
|
|
2023-04-25 20:23:59 -04:00
|
|
|
|
|
2023-12-04 17:27:59 -05:00
|
|
|
|
export
|
|
|
|
|
letIntro : FileName -> Grammar True (Maybe PQty)
|
2023-12-04 12:48:25 -05:00
|
|
|
|
letIntro fname =
|
2023-12-04 17:27:59 -05:00
|
|
|
|
withLoc fname (Just . PQ Zero <$ res "let0")
|
|
|
|
|
<|> withLoc fname (Just . PQ One <$ res "let1")
|
|
|
|
|
<|> withLoc fname (Just . PQ Any <$ res "letω")
|
|
|
|
|
<|> Nothing <$ resC "let"
|
|
|
|
|
|
2023-12-21 11:54:31 -05:00
|
|
|
|
private
|
2023-12-04 17:27:59 -05:00
|
|
|
|
letBinder : FileName -> Maybe PQty -> Grammar True (PQty, PatVar, PTerm)
|
|
|
|
|
letBinder fname mq = do
|
2023-12-21 11:54:31 -05:00
|
|
|
|
qty <- letQty fname mq
|
|
|
|
|
x <- patVar fname
|
|
|
|
|
type <- optional $ resC ":" *> term fname
|
|
|
|
|
rhs <- resC "=" *> term fname
|
|
|
|
|
pure (qty, x, makeLetRhs rhs type)
|
|
|
|
|
where
|
|
|
|
|
letQty : FileName -> Maybe PQty -> Grammar False PQty
|
|
|
|
|
letQty fname Nothing = qty fname <* mustWork (resC ".") <|> defLoc fname (PQ One)
|
|
|
|
|
letQty fname (Just q) = pure q
|
|
|
|
|
|
|
|
|
|
makeLetRhs : PTerm -> Maybe PTerm -> PTerm
|
|
|
|
|
makeLetRhs tm ty = maybe tm (\t => Ann tm t (extendL tm.loc t.loc)) ty
|
2023-04-25 20:47:42 -04:00
|
|
|
|
|
2023-04-24 16:25:00 -04:00
|
|
|
|
export
|
2023-12-04 12:48:25 -05:00
|
|
|
|
letTerm : FileName -> Grammar True PTerm
|
|
|
|
|
letTerm fname = withLoc fname $ do
|
2023-12-04 17:27:59 -05:00
|
|
|
|
qty <- letIntro fname
|
|
|
|
|
binds <- sepEndBy1 (res ";") $ assert_total letBinder fname qty
|
|
|
|
|
mustWork $ resC "in"
|
|
|
|
|
body <- assert_total term fname
|
|
|
|
|
pure $ \loc => foldr (\b, s => Let b s loc) body binds
|
2023-04-25 20:23:59 -04:00
|
|
|
|
|
2023-04-25 20:47:42 -04:00
|
|
|
|
-- term : FileName -> Grammar True PTerm
|
|
|
|
|
term fname = lamTerm fname
|
|
|
|
|
<|> piTerm fname
|
|
|
|
|
<|> sigmaTerm fname
|
2023-12-04 12:48:25 -05:00
|
|
|
|
<|> letTerm fname
|
2023-03-12 13:28:37 -04:00
|
|
|
|
|
2023-04-17 15:41:00 -04:00
|
|
|
|
|
2023-09-21 19:29:23 -04:00
|
|
|
|
export
|
2024-04-12 15:49:15 -04:00
|
|
|
|
attr' : FileName -> (o : String) -> (0 _ : IsReserved o) =>
|
|
|
|
|
Grammar True PAttr
|
|
|
|
|
attr' fname o = withLoc fname $ do
|
|
|
|
|
resC o
|
2023-11-05 14:49:02 -05:00
|
|
|
|
name <- baseName
|
|
|
|
|
args <- many $ termArg fname
|
|
|
|
|
mustWork $ resC "]"
|
|
|
|
|
pure $ PA name args
|
2023-09-21 19:29:23 -04:00
|
|
|
|
|
2024-04-12 15:49:15 -04:00
|
|
|
|
export %inline
|
|
|
|
|
attr : FileName -> Grammar True PAttr
|
|
|
|
|
attr fname = attr' fname "#["
|
|
|
|
|
|
2023-09-21 19:29:23 -04:00
|
|
|
|
export
|
2023-11-05 14:49:02 -05:00
|
|
|
|
findDups : List PAttr -> List String
|
|
|
|
|
findDups attrs =
|
|
|
|
|
SortedSet.toList $ snd $ foldl check (empty, empty) attrs
|
|
|
|
|
where
|
|
|
|
|
Seen = SortedSet String; Dups = SortedSet String
|
|
|
|
|
check : (Seen, Dups) -> PAttr -> (Seen, Dups)
|
|
|
|
|
check (seen, dups) (PA a _ _) =
|
|
|
|
|
(insert a seen, if contains a seen then insert a dups else dups)
|
2023-09-21 19:29:23 -04:00
|
|
|
|
|
2023-05-01 21:06:25 -04:00
|
|
|
|
export
|
2023-11-05 14:49:02 -05:00
|
|
|
|
noDups : List PAttr -> Grammar False ()
|
|
|
|
|
noDups attrs = do
|
|
|
|
|
let dups = findDups attrs
|
|
|
|
|
when (not $ null dups) $
|
|
|
|
|
fatalError "duplicate attribute names: \{joinBy "," dups}"
|
|
|
|
|
|
|
|
|
|
export
|
|
|
|
|
attrList : FileName -> Grammar False (List PAttr)
|
|
|
|
|
attrList fname = do
|
|
|
|
|
res <- many $ attr fname
|
|
|
|
|
noDups res $> res
|
|
|
|
|
|
|
|
|
|
public export
|
2024-04-12 15:49:15 -04:00
|
|
|
|
data AttrMatch a =
|
|
|
|
|
Matched a
|
|
|
|
|
| NoMatch String (List String)
|
|
|
|
|
| Malformed String String
|
2023-11-05 14:49:02 -05:00
|
|
|
|
|
|
|
|
|
export
|
|
|
|
|
Functor AttrMatch where
|
|
|
|
|
map f (Matched x) = Matched $ f x
|
2024-04-12 15:49:15 -04:00
|
|
|
|
map f (NoMatch s w) = NoMatch s w
|
2023-11-05 14:49:02 -05:00
|
|
|
|
map f (Malformed a e) = Malformed a e
|
|
|
|
|
|
|
|
|
|
export
|
|
|
|
|
(<|>) : AttrMatch a -> AttrMatch a -> AttrMatch a
|
|
|
|
|
Matched x <|> _ = Matched x
|
2024-04-12 15:49:15 -04:00
|
|
|
|
NoMatch {} <|> y = y
|
2023-11-05 14:49:02 -05:00
|
|
|
|
Malformed a e <|> _ = Malformed a e
|
|
|
|
|
|
|
|
|
|
export
|
2024-04-12 15:49:15 -04:00
|
|
|
|
isFail : PAttr -> List String -> AttrMatch PFail
|
|
|
|
|
isFail (PA "fail" [] _) _ = Matched PFailAny
|
|
|
|
|
isFail (PA "fail" [Str s _] _) _ = Matched $ PFailMatch s
|
|
|
|
|
isFail (PA "fail" _ _) _ = Malformed "fail" "be absent or a string literal"
|
|
|
|
|
isFail a w = NoMatch a.name w
|
2023-11-05 14:49:02 -05:00
|
|
|
|
|
|
|
|
|
export
|
2024-04-12 15:49:15 -04:00
|
|
|
|
isMain : PAttr -> List String -> AttrMatch ()
|
|
|
|
|
isMain (PA "main" [] _) _ = Matched ()
|
|
|
|
|
isMain (PA "main" _ _) _ = Malformed "main" "have no arguments"
|
|
|
|
|
isMain a w = NoMatch a.name w
|
2023-11-05 14:49:02 -05:00
|
|
|
|
|
|
|
|
|
export
|
2024-04-12 15:49:15 -04:00
|
|
|
|
isScheme : PAttr -> List String -> AttrMatch String
|
|
|
|
|
isScheme (PA "compile-scheme" [Str s _] _) _ = Matched s
|
|
|
|
|
isScheme (PA "compile-scheme" _ _) _ =
|
2023-11-05 14:49:02 -05:00
|
|
|
|
Malformed "compile-scheme" "be a string literal"
|
2024-04-12 15:49:15 -04:00
|
|
|
|
isScheme a w = NoMatch a.name w
|
2023-11-05 14:49:02 -05:00
|
|
|
|
|
|
|
|
|
export
|
|
|
|
|
matchAttr : String -> AttrMatch a -> Either String a
|
|
|
|
|
matchAttr _ (Matched x) = Right x
|
2024-04-12 15:49:15 -04:00
|
|
|
|
matchAttr d (NoMatch a w) = Left $ unlines
|
|
|
|
|
["unrecognised \{d} attribute \{a}", "expected one of: \{show w}"]
|
2023-11-05 14:49:02 -05:00
|
|
|
|
matchAttr _ (Malformed a s) = Left $ unlines
|
|
|
|
|
["invalid \{a} attribute", "(should \{s})"]
|
|
|
|
|
|
|
|
|
|
export
|
|
|
|
|
mkPDef : List PAttr -> PQty -> PBaseName -> PBody ->
|
|
|
|
|
Either String (Loc -> PDefinition)
|
|
|
|
|
mkPDef attrs qty name body = do
|
|
|
|
|
let start = MkPDef qty name body PSucceed False Nothing noLoc
|
|
|
|
|
res <- foldlM addAttr start attrs
|
|
|
|
|
pure $ \l => {loc_ := l} (the PDefinition res)
|
|
|
|
|
where
|
|
|
|
|
data PDefAttr = DefFail PFail | DefMain | DefScheme String
|
|
|
|
|
|
|
|
|
|
isDefAttr : PAttr -> Either String PDefAttr
|
2024-04-12 15:49:15 -04:00
|
|
|
|
isDefAttr attr =
|
|
|
|
|
let defAttrs = ["fail", "main", "compile-scheme"] in
|
|
|
|
|
matchAttr "definition" $
|
|
|
|
|
DefFail <$> isFail attr defAttrs
|
|
|
|
|
<|> DefMain <$ isMain attr defAttrs
|
|
|
|
|
<|> DefScheme <$> isScheme attr defAttrs
|
2023-11-05 14:49:02 -05:00
|
|
|
|
|
|
|
|
|
addAttr : PDefinition -> PAttr -> Either String PDefinition
|
|
|
|
|
addAttr def attr =
|
|
|
|
|
case !(isDefAttr attr) of
|
|
|
|
|
DefFail f => pure $ {fail := f} def
|
|
|
|
|
DefMain => pure $ {main := True} def
|
|
|
|
|
DefScheme str => pure $ {scheme := Just str} def
|
|
|
|
|
|
|
|
|
|
export
|
|
|
|
|
mkPNamespace : List PAttr -> Mods -> List PDecl ->
|
|
|
|
|
Either String (Loc -> PNamespace)
|
|
|
|
|
mkPNamespace attrs name decls = do
|
|
|
|
|
let start = MkPNamespace name decls PSucceed noLoc
|
|
|
|
|
res <- foldlM addAttr start attrs
|
|
|
|
|
pure $ \l => {loc_ := l} (the PNamespace res)
|
|
|
|
|
where
|
2024-04-12 15:49:15 -04:00
|
|
|
|
isNsAttr a = matchAttr "namespace" $ isFail a ["fail"]
|
2023-11-05 14:49:02 -05:00
|
|
|
|
|
|
|
|
|
addAttr : PNamespace -> PAttr -> Either String PNamespace
|
|
|
|
|
addAttr ns attr = pure $ {fail := !(isNsAttr attr)} ns
|
2023-03-12 13:28:37 -04:00
|
|
|
|
|
2023-11-01 07:56:27 -04:00
|
|
|
|
||| `def` alone means `defω`; same for `postulate`
|
|
|
|
|
export
|
|
|
|
|
defIntro' : (bare, zero, omega : String) ->
|
|
|
|
|
(0 _ : IsReserved bare) =>
|
|
|
|
|
(0 _ : IsReserved zero) =>
|
|
|
|
|
(0 _ : IsReserved omega) =>
|
|
|
|
|
FileName -> Grammar True PQty
|
|
|
|
|
defIntro' bare zero omega fname =
|
|
|
|
|
withLoc fname (PQ Zero <$ resC zero)
|
|
|
|
|
<|> withLoc fname (PQ Any <$ resC omega)
|
|
|
|
|
<|> do pos <- bounds $ resC bare
|
2023-04-25 20:47:42 -04:00
|
|
|
|
let any = PQ Any $ makeLoc fname pos.bounds
|
|
|
|
|
option any $ qty fname <* needRes "."
|
2023-04-25 20:23:59 -04:00
|
|
|
|
|
2023-05-01 21:06:25 -04:00
|
|
|
|
export
|
2023-11-01 07:56:27 -04:00
|
|
|
|
defIntro : FileName -> Grammar True PQty
|
|
|
|
|
defIntro = defIntro' "def" "def0" "defω"
|
|
|
|
|
|
|
|
|
|
export
|
|
|
|
|
postulateIntro : FileName -> Grammar True PQty
|
|
|
|
|
postulateIntro = defIntro' "postulate" "postulate0" "postulateω"
|
|
|
|
|
|
|
|
|
|
export
|
2023-11-05 14:49:02 -05:00
|
|
|
|
postulate : FileName -> List PAttr -> Grammar True PDefinition
|
|
|
|
|
postulate fname attrs = withLoc fname $ do
|
2023-11-01 07:56:27 -04:00
|
|
|
|
qty <- postulateIntro fname
|
|
|
|
|
name <- baseName
|
|
|
|
|
type <- resC ":" *> mustWork (term fname)
|
2023-11-05 14:49:02 -05:00
|
|
|
|
optRes ";"
|
|
|
|
|
either fatalError pure $ mkPDef attrs qty name $ PPostulate type
|
2023-11-01 07:56:27 -04:00
|
|
|
|
|
|
|
|
|
export
|
2023-11-05 14:49:02 -05:00
|
|
|
|
concrete : FileName -> List PAttr -> Grammar True PDefinition
|
|
|
|
|
concrete fname attrs = withLoc fname $ do
|
2023-04-25 20:47:42 -04:00
|
|
|
|
qty <- defIntro fname
|
2023-04-25 20:23:59 -04:00
|
|
|
|
name <- baseName
|
2023-04-25 20:47:42 -04:00
|
|
|
|
type <- optional $ resC ":" *> mustWork (term fname)
|
|
|
|
|
term <- needRes "=" *> mustWork (term fname)
|
2023-04-25 20:23:59 -04:00
|
|
|
|
optRes ";"
|
2023-11-05 14:49:02 -05:00
|
|
|
|
either fatalError pure $ mkPDef attrs qty name $ PConcrete type term
|
|
|
|
|
|
|
|
|
|
export
|
|
|
|
|
definition : FileName -> List PAttr -> Grammar True PDefinition
|
|
|
|
|
definition fname attrs =
|
|
|
|
|
try (postulate fname attrs) <|> concrete fname attrs
|
2023-11-01 07:56:27 -04:00
|
|
|
|
|
|
|
|
|
export
|
2023-11-05 14:49:02 -05:00
|
|
|
|
nsname : Grammar True Mods
|
|
|
|
|
nsname = do ns <- qname; pure $ ns.mods :< ns.base
|
|
|
|
|
|
2024-04-12 15:49:15 -04:00
|
|
|
|
export
|
|
|
|
|
pragma : FileName -> Grammar True PPragma
|
|
|
|
|
pragma fname = do
|
|
|
|
|
a <- attr' fname "#!["
|
|
|
|
|
either fatalError pure $ case a.name of
|
|
|
|
|
"log" => logArgs a.args a.loc
|
|
|
|
|
_ => Left $
|
|
|
|
|
#"unrecognised pragma "\#{a.name}"\n"# ++
|
|
|
|
|
#"known pragmas: ["log"]"#
|
|
|
|
|
where
|
|
|
|
|
levelOOB : Nat -> Either String a
|
|
|
|
|
levelOOB n = Left $
|
|
|
|
|
"log level \{show n} out of bounds\n" ++
|
|
|
|
|
"expected number in range 0–\{show maxLogLevel} inclusive"
|
|
|
|
|
|
|
|
|
|
toLevel : Nat -> Either String LogLevel
|
|
|
|
|
toLevel lvl = maybe (levelOOB lvl) Right $ toLogLevel lvl
|
|
|
|
|
|
|
|
|
|
unknownCat : String -> Either String a
|
|
|
|
|
unknownCat cat = Left $
|
|
|
|
|
"unknown log category \{show cat}\n" ++
|
|
|
|
|
"known categories: \{show $ ["all", "default"] ++ logCategories}"
|
|
|
|
|
|
|
|
|
|
toCat : String -> Either String LogCategory
|
|
|
|
|
toCat cat = maybe (unknownCat cat) Right $ toLogCategory cat
|
|
|
|
|
|
|
|
|
|
fromPair : PTerm -> Either String (String, Nat)
|
|
|
|
|
fromPair (Pair (V (MkPName [<] x) Nothing _) (Nat n _) _) = Right (x, n)
|
|
|
|
|
fromPair _ = Left "invalid argument to log pragma"
|
|
|
|
|
|
|
|
|
|
logCatArg : (String, Nat) -> Either String Log.PushArg
|
|
|
|
|
logCatArg ("default", lvl) = [|SetDefault $ toLevel lvl|]
|
|
|
|
|
logCatArg ("all", lvl) = [|SetAll $ toLevel lvl|]
|
|
|
|
|
logCatArg (cat, lvl) = [|SetCat (toCat cat) (toLevel lvl)|]
|
|
|
|
|
|
|
|
|
|
logArgs : List PTerm -> Loc -> Either String PPragma
|
|
|
|
|
logArgs [] _ = Left "missing arguments to log pragma"
|
|
|
|
|
logArgs [V "pop" Nothing _] loc = Right $ PLogPop loc
|
|
|
|
|
logArgs other loc = do
|
|
|
|
|
args <- traverse (logCatArg <=< fromPair) other
|
|
|
|
|
pure $ PLogPush args loc
|
|
|
|
|
|
2023-11-05 14:49:02 -05:00
|
|
|
|
|
|
|
|
|
export
|
|
|
|
|
decl : FileName -> Grammar True PDecl
|
2023-04-25 20:23:59 -04:00
|
|
|
|
|
2023-05-01 21:06:25 -04:00
|
|
|
|
export
|
2023-11-05 14:49:02 -05:00
|
|
|
|
namespace_ : FileName -> List PAttr -> Grammar True PNamespace
|
|
|
|
|
namespace_ fname attrs = withLoc fname $ do
|
|
|
|
|
ns <- resC "namespace" *> nsname; needRes "{"
|
|
|
|
|
decls <- nsInner
|
|
|
|
|
either fatalError pure $ mkPNamespace attrs ns decls
|
2023-04-25 20:23:59 -04:00
|
|
|
|
where
|
|
|
|
|
nsInner : Grammar True (List PDecl)
|
|
|
|
|
nsInner = [] <$ resC "}"
|
2023-05-01 21:06:25 -04:00
|
|
|
|
<|> [|(assert_total decl fname <* commit) :: assert_total nsInner|]
|
2023-04-25 20:23:59 -04:00
|
|
|
|
|
2023-09-21 19:29:23 -04:00
|
|
|
|
export
|
2023-11-05 14:49:02 -05:00
|
|
|
|
declBody : FileName -> List PAttr -> Grammar True PDecl
|
|
|
|
|
declBody fname attrs =
|
|
|
|
|
[|PDef $ definition fname attrs|] <|> [|PNs $ namespace_ fname attrs|]
|
2023-09-21 19:29:23 -04:00
|
|
|
|
|
2023-11-05 14:49:02 -05:00
|
|
|
|
-- decl : FileName -> Grammar True PDecl
|
2024-04-12 15:49:15 -04:00
|
|
|
|
decl fname =
|
|
|
|
|
(attrList fname >>= declBody fname)
|
|
|
|
|
<|> PPrag <$> pragma fname
|
2023-04-24 16:25:00 -04:00
|
|
|
|
|
2023-05-01 21:06:25 -04:00
|
|
|
|
export
|
2023-04-25 20:47:42 -04:00
|
|
|
|
load : FileName -> Grammar True PTopLevel
|
|
|
|
|
load fname = withLoc fname $
|
|
|
|
|
resC "load" *> mustWork [|PLoad strLit|] <* optRes ";"
|
2023-03-12 13:28:37 -04:00
|
|
|
|
|
2023-05-01 21:06:25 -04:00
|
|
|
|
export
|
2023-04-25 20:47:42 -04:00
|
|
|
|
topLevel : FileName -> Grammar True PTopLevel
|
|
|
|
|
topLevel fname = load fname <|> [|PD $ decl fname|]
|
2023-03-12 13:28:37 -04:00
|
|
|
|
|
2023-05-01 21:06:25 -04:00
|
|
|
|
export
|
2023-10-19 23:23:56 -04:00
|
|
|
|
input : FileName -> Grammar False PFile
|
2023-04-25 20:47:42 -04:00
|
|
|
|
input fname = [] <$ eof
|
2023-05-01 21:06:25 -04:00
|
|
|
|
<|> [|(topLevel fname <* commit) :: assert_total input fname|]
|
2023-03-12 13:28:37 -04:00
|
|
|
|
|
2023-05-01 21:06:25 -04:00
|
|
|
|
export
|
2023-04-25 20:47:42 -04:00
|
|
|
|
lexParseTerm : FileName -> String -> Either Error PTerm
|
|
|
|
|
lexParseTerm = lexParseWith . term
|
2023-03-12 13:28:37 -04:00
|
|
|
|
|
2023-05-01 21:06:25 -04:00
|
|
|
|
export
|
2023-10-19 23:23:56 -04:00
|
|
|
|
lexParseInput : FileName -> String -> Either Error PFile
|
2023-04-25 20:47:42 -04:00
|
|
|
|
lexParseInput = lexParseWith . input
|