module Text.Parser.String where
open import Data.Bool as Bool using (Bool; T; not; if_then_else_)
open import Data.Char as Char using (Char)
open import Data.Empty as Empty using (⊥)
open import Data.Integer as Int using (ℤ)
open import Data.List as List using (List; _∷_; [])
open import Data.List.NonEmpty as List⁺ using (List⁺)
import Data.List.Categorical as ListCat
open import Data.List.Sized.Interface
open import Data.Maybe as Maybe using (Maybe; just; nothing)
import Data.Maybe.Categorical as MaybeCat
open import Data.Nat as Nat using (ℕ)
import Data.Nat.Properties as Nat
open import Data.Product as Prod using (_×_; _,_)
open import Data.String as String using (String; _<+>_; length; toVec)
open import Data.Sum as Sum using (_⊎_; inj₁; inj₂)
open import Data.Subset
open import Data.Unit as Unit using (⊤; tt)
open import Data.Unit.Polymorphic using () renaming (⊤ to ⊤ₚ)
open import Data.Vec as Vec using (Vec)
open import Function.Base using (id; const; _∘_; _∘′_; _$_; case_of_)
open import Function.Reasoning
open import Level using (Lift; lift; 0ℓ)
open import Induction.Nat.Strong as Box using (□_) public
open import Relation.Nullary using (Dec; yes; no)
open import Relation.Nullary.Decidable using (True; ⌊_⌋)
open import Relation.Unary using (IUniversal; _⇒_) public
open import Relation.Binary.PropositionalEquality.Decidable
open import Data.Subset public
open import Level.Bounded as Bounded using ([_])
import Text.Parser.Monad as ParserMonad
open import Text.Parser.Types as Parser using (_^_,_)
import Text.Parser.Position as Position
data ParseErrorMsg : Set where
no-parse : ParseErrorMsg
ambiguous-parse : ParseErrorMsg
private
variable
n : ℕ
A B C : Set
private
Success : (A : Set) (n : ℕ) → Set
Success A n = Parser.Success (Bounded.Vec [ Char ]) [ A ] n
runSuccess : Success A n → Maybe A
runSuccess s = if ⌊ Parser.Success.size s Nat.≟ 0 ⌋
then just (Bounded.lower (Parser.Success.value s))
else nothing
private
Result : (A : Set) → Set
Result A = ParserMonad.Result ⊤ₚ (A × Lift 0ℓ (Position.Position × List ⊥))
discardErrors : Result A → List A
discardErrors = ParserMonad.result (const []) (const []) ((_∷ []) ∘ Prod.proj₁)
discardIncompleteParses : List (Success A n) → List A
discardIncompleteParses = Maybe.maybe id [] ∘ ListCat.TraversableM.mapM MaybeCat.monad runSuccess
discardNonUniqueParses : List A → ParseErrorMsg ⊎ A
discardNonUniqueParses [] = inj₁ no-parse
discardNonUniqueParses (v ∷ []) = inj₂ v
discardNonUniqueParses (_ ∷ _ ∷ _) = inj₁ ambiguous-parse
Parser : (A : Set) (n : ℕ) → Set
Parser A = Parser.Parser ParserMonad.Agdarsec′.chars [ A ]
runParser : ∀[ Parser A ] → String → ParseErrorMsg ⊎ A
runParser {A} p str =
str ∶ String
|> runParser′ ∶ Result (Success A (length str))
|> discardErrors ∶ List (Success A (length str))
|> discardIncompleteParses ∶ List A
|> discardNonUniqueParses ∶ ParseErrorMsg ⊎ A
where
runParser′ : (input : String) → Result (Success A (length input))
runParser′ input = Parser.runParser p (Nat.n≤1+n _)
(lift (toVec input)) (lift (Position.start , []))
import Text.Parser.Combinators as PC
import Text.Parser.Combinators.Char as PCC
import Text.Parser.Combinators.Numbers as PCN
private
instance
Agdarsec′M = ParserMonad.Agdarsec′.monad
Agdarsec′M0 = ParserMonad.Agdarsec′.monadZero
Agdarsec′M+ = ParserMonad.Agdarsec′.monadPlus
guardM : (A → Maybe B) → ∀[ Parser A ⇒ Parser B ]
guardM = PC.guardM
_>>=_ : ∀[ Parser A ⇒ (const A ⇒ □ Parser B) ⇒ Parser B ]
_>>=_ = PC._>>=_
infixl 4 _<&>_ _<&_ _&>_
_<&>_ : ∀[ Parser A ⇒ □ Parser B ⇒ Parser (A × B) ]
_<&>_ = PC._<&>_
_<&_ : ∀[ Parser A ⇒ □ Parser B ⇒ Parser A ]
_<&_ = PC._<&_
_&>_ : ∀[ Parser A ⇒ □ Parser B ⇒ Parser B ]
_&>_ = PC._&>_
infixl 4 _<&?>_ _<&?_ _&?>_
_<&?>_ : ∀[ Parser A ⇒ □ Parser B ⇒ Parser (A × Maybe B) ]
_<&?>_ = PC._<&?>_
_<&?_ : ∀[ Parser A ⇒ □ Parser B ⇒ Parser A ]
_<&?_ = PC._<&?_
_&?>_ : ∀[ Parser A ⇒ □ Parser B ⇒ Parser (Maybe B) ]
_&?>_ = PC._&?>_
infixl 4 _<?&>_ _<?&_ _?&>_
_<?&>_ : ∀[ Parser A ⇒ Parser B ⇒ Parser (Maybe A × B) ]
_<?&>_ = PC._<?&>_
_<?&_ : ∀[ Parser A ⇒ Parser B ⇒ Parser (Maybe A) ]
_<?&_ = PC._<?&_
_?&>_ : ∀[ Parser A ⇒ Parser B ⇒ Parser B ]
_?&>_ = PC._?&>_
box : ∀[ Parser A ⇒ □ Parser A ]
box = PC.box
fail : ∀[ Parser A ]
fail = PC.fail
infixr 3 _<|>_
_<|>_ : ∀[ Parser A ⇒ Parser A ⇒ Parser A ]
_<|>_ = PC._<|>_
infixr 5 _<$>_
_<$>_ : (A → B) → ∀[ Parser A ⇒ Parser B ]
_<$>_ = PC._<$>_
infixr 5 _<$_
_<$_ : B → ∀[ Parser A ⇒ Parser B ]
_<$_ = PC._<$_
infixl 4 _<*>_
_<*>_ : ∀[ Parser (A → B) ⇒ □ Parser A ⇒ Parser B ]
_<*>_ = PC._<*>_
alts : ∀[ List ∘′ Parser A ⇒ Parser A ]
alts = PC.alts
ands : ∀[ List⁺ ∘′ Parser A ⇒ Parser (List⁺ A) ]
ands = PC.ands
list⁺ : ∀[ Parser A ⇒ Parser (List⁺ A) ]
list⁺ = PC.list⁺
char : Char → ∀[ Parser Char ]
char = PCC.char
anyCharBut : Char → ∀[ Parser Char ]
anyCharBut = PCC.anyCharBut
space : ∀[ Parser Char ]
space = PCC.space
spaces : ∀[ Parser (List⁺ Char) ]
spaces = PCC.spaces
isEmpty : String → Bool
isEmpty = List.null ∘ String.toList
text : (str : String) {p : T (not (isEmpty str))} → ∀[ Parser (List⁺ Char) ]
text = PCC.text
withSpaces : ∀[ Parser A ⇒ Parser A ]
withSpaces = PCC.withSpaces
lexeme : (str : String) {p : T (not (isEmpty str))} → ∀[ Parser (List⁺ Char) ]
lexeme str {p} = withSpaces (text str {p})
exact : Char → ∀[ Parser Char ]
exact = PC.exact
exacts : (str : List⁺ Char) → ∀[ Parser (List⁺ Char) ]
exacts = PC.exacts
between : ∀[ Parser A ⇒ □ Parser C ⇒ □ Parser B ⇒ Parser B ]
between A C B = A &> B <& C
between? : ∀[ Parser A ⇒ □ Parser C ⇒ Parser B ⇒ Parser B ]
between? A C B = between A C (box B) <|> B
parens : ∀[ □ Parser A ⇒ Parser A ]
parens = PCC.parens
lower : ∀[ Parser Char ]
lower = PCC.lowerAlpha
upper : ∀[ Parser Char ]
upper = PCC.upperAlpha
alpha : ∀[ Parser Char ]
alpha = PCC.alpha
alphas⁺ : ∀[ Parser (List⁺ Char) ]
alphas⁺ = PCC.alphas⁺
num : ∀[ Parser ℕ ]
num = PCC.num
alphanum : ∀[ Parser (Char ⊎ ℕ) ]
alphanum = PCC.alphanum
decimalDigit : ∀[ Parser ℕ ]
decimalDigit = PCN.decimalDigit
decimalℕ : ∀[ Parser ℕ ]
decimalℕ = PCN.decimalℕ
decimalℤ : ∀[ Parser ℤ ]
decimalℤ = PCN.decimalℤ
data ParseError : ParseErrorMsg → Set where
infix 0 !_
data Singleton {A : Set} : (x : A) → Set where
!_ : (x : A) → Singleton x
private
testHelper : (p : ∀[ Parser A ]) (str : String) (f : ParseErrorMsg → Set) (t : A → Set) → Set
testHelper p str f t = case runParser p str of Sum.[ f , t ]′
_parses_ : (p : ∀[ Parser A ]) (str : String) → Set
p parses str = testHelper p str ParseError Singleton
_ : decimalℕ parses "10"
_ = ! 10
_accepts_ : (p : ∀[ Parser A ]) (str : String) → Set
p accepts str = testHelper p str (const ⊥) (const ⊤)
_ : decimalℤ accepts "-10"
_ = _
_rejects_ : (p : ∀[ Parser A ]) (str : String) → Set
p rejects str = testHelper p str (const ⊤) (const ⊥)
_ : decimalℕ rejects "-10"
_ = _