{-# OPTIONS --guardedness --sized-types #-}
module Parser where
open import Lexer public
module TermParserThings where
data Term : Set where
atom : Atom → Term
list : List Term → Term
mutual
showTerm : Term → String
showTerm (atom a) = showAtom a
showTerm (list tms) = showTerms tms
showTerms : List Term → String
showTerms [] = "()"
showTerms (tm ∷ tms) = "(" ++ showTerm tm ++ aux tms
where
aux : List Term → String
aux [] = ")"
aux (tm ∷ tms) = " " ++ showTerm tm ++ aux tms
showMaybeTerms : List (Maybe Term) → String
showMaybeTerms [] = ""
showMaybeTerms (nothing ∷ ms) = "nothing ; " ++ showMaybeTerms ms
showMaybeTerms (just tm ∷ ms) = "(just " ++ showTerm tm ++ ") ; " ++ showMaybeTerms ms
data TermParserErr : Set where
impossible : String → TermParserErr
endOfList : TermParserErr
endOfLine : TermParserErr
endOfLineInList : TermParserErr
showTermParserErr : TermParserErr → String
showTermParserErr (impossible str) = "impossible! " ++ str
showTermParserErr endOfList = "unexpected end of list while awaiting term"
showTermParserErr endOfLine = "unexpected end of line while awaiting term"
showTermParserErr endOfLineInList = "unexpected end of line while awaiting term or end of list"
listFrom : List Term → Term
listFrom acc = list (reverse acc)
TermParser : Set
TermParser = ∞Machine (Maybe Token) (Either TermParserErr (Maybe Term))
mutual
awaitTerm : TermParser
awaitTerm .on (just beginList) = ok nothing , just (awaitList [ [] ])
awaitTerm .on (just endList) = fail endOfList , nothing
awaitTerm .on (just (atom a)) = ok (just (atom a)) , just awaitTerm
awaitTerm .on nothing = ok nothing , nothing
awaitList : List⁺ (List Term) → TermParser
awaitList accs .on (just beginList) = ok nothing , just (awaitList
([] ∷ List⁺′.toList accs))
awaitList (acc ∷ []) .on (just endList) = ok (just (listFrom acc)) , just awaitTerm
awaitList (acc ∷ acc′ ∷ accs) .on (just endList) = ok nothing , just (awaitList
((listFrom acc ∷ acc′) ∷ accs))
awaitList (acc ∷ accs) .on (just (atom a)) = ok nothing , just (awaitList
((atom a ∷ acc) ∷ accs))
awaitList _ .on nothing = fail endOfLineInList , nothing
parseTerm : List Token → Either TermParserErr (List Term)
parseTerm tks with ∞MachineThings.GetEither.run* awaitTerm (map just tks List′.++ [ nothing ])
parseTerm tks | (_ , just err) , _ , _ = fail err
parseTerm tks | (tms , nothing) , [] , _ with catMaybes tms
parseTerm tks | (tms , nothing) , [] , _ | [] = fail endOfLine
parseTerm tks | (tms , nothing) , [] , _ | tms′ = ok tms′
parseTerm tks | (tms , nothing) , tks′ , _ = fail (impossible ("\ntms = " ++
showMaybeTerms tms ++ "\ntks′ = " ++
LexerThings.showMaybeTokens tks′))
open TermParserThings public using (Term ; atom ; list ; showTerm ; showTerms ; TermParserErr ;
showTermParserErr ; parseTerm)
data NatParserErr : Set where
notAtom : Term → NatParserErr
notDigit : Char → NatParserErr
showNatParserErr : NatParserErr → String
showNatParserErr (notAtom tm) = "invalid natural '" ++ showTerm tm ++ "'"
showNatParserErr (notDigit c) = "invalid digit '" ++ showChar c ++ "'"
NatParser : Set
NatParser = ∞Machine Term (Either NatParserErr Nat)
awaitNat : NatParser
awaitNat .on (atom a) = aux 0 (String.toList a) , just awaitNat
where
aux : Nat → List Char → Either NatParserErr Nat
aux n [] = ok n
aux n (c ∷ cs) with isDigit c
... | false = fail (notDigit c)
... | true = aux (10 * n + natFrom c - natFrom '0') cs
awaitNat .on tm = fail (notAtom tm) , just awaitNat
parseNat : Term → Either NatParserErr Nat
parseNat tm = ∞MachineThings.GetEither.step awaitNat tm