{-# OPTIONS --cubical-compatible --safe #-}
module Grammar.Abstract where
open import Data.Bool
open import Data.Char
open import Data.Empty
open import Data.List
open import Data.Product
open import Data.Sum
open import Function.Base
open import Relation.Binary.PropositionalEquality using (_≡_)
Grammar : Set → Set₁
Grammar A = A → List Char → Set
fail : ∀ {A} → Grammar A
fail = λ _ _ → ⊥
infixl 10 _∣_
_∣_ : ∀ {A} → Grammar A → Grammar A → Grammar A
g₁ ∣ g₂ = λ x s → g₁ x s ⊎ g₂ x s
return : ∀ {A} → A → Grammar A
return x = λ y s → y ≡ x × s ≡ []
infixl 20 _<$>_ _<$_
_<$>_ : ∀ {A B} → (A → B) → Grammar A → Grammar B
f <$> g = λ x s → ∃ λ y → g y s × x ≡ f y
_<$_ : ∀ {A B} → A → Grammar B → Grammar A
x <$ g = const x <$> g
seq : (List Char → Set) → (List Char → Set) → (List Char → Set)
seq p₁ p₂ = λ s → ∃₂ λ s₁ s₂ → p₁ s₁ × p₂ s₂ × s ≡ s₁ ++ s₂
infixl 15 _>>=_ _>>_
_>>=_ : ∀ {A B} → Grammar A → (A → Grammar B) → Grammar B
g₁ >>= g₂ = λ y s → ∃ λ x → seq (g₁ x) (g₂ x y) s
_>>_ : ∀ {A B} → Grammar A → Grammar B → Grammar B
g₁ >> g₂ = g₁ >>= λ _ → g₂
infixl 20 _⊛_ _<⊛_ _⊛>_
_⊛_ : ∀ {A B} → Grammar (A → B) → Grammar A → Grammar B
g₁ ⊛ g₂ = g₁ >>= λ f → f <$> g₂
_<⊛_ : ∀ {A B} → Grammar A → Grammar B → Grammar A
g₁ <⊛ g₂ = λ x s → ∃ λ y → seq (g₁ x) (g₂ y) s
_⊛>_ : ∀ {A B} → Grammar A → Grammar B → Grammar B
_⊛>_ = _>>_
infix 30 _⋆ _+
_⋆ : ∀ {A} → Grammar A → Grammar (List A)
(g ⋆) [] s = s ≡ []
(g ⋆) (x ∷ xs) s = seq (g x) ((g ⋆) xs) s
_+ : ∀ {A} → Grammar A → Grammar (List A)
(g +) [] s = ⊥
(g +) (x ∷ xs) s = (g ⋆) (x ∷ xs) s
infixl 18 _sep-by_
_sep-by_ : ∀ {A B} → Grammar A → Grammar B → Grammar (List A)
g sep-by sep = _∷_ <$> g ⊛ (sep >> g) ⋆
token : Grammar Char
token = λ c s → s ≡ [ c ]
tok : Char → Grammar Char
tok c = λ c′ s → c′ ≡ c × token c′ s
sat : (p : Char → Bool) → Grammar (∃ λ t → T (p t))
sat _ = λ { (c , _) s → token c s }
whitespace : Grammar Char
whitespace = tok ' ' ∣ tok '\n'
string : List Char → Grammar (List Char)
string s = λ s′ s″ → s′ ≡ s × s″ ≡ s
symbol : List Char → Grammar (List Char)
symbol s = string s <⊛ whitespace ⋆