\begin{code}
{-# OPTIONS --experimental-lossy-unification --safe #-}
open import Prelude renaming (tt to ⟨⟩)
open import Signatures
open import FinitenessConditions
open import FreeMonad.PackagedTheory
open import Data.String.Properties renaming (discreteChar to _≟_)
module Effects.Parser.TreeParser
(choiceString : SplitQuotientedChoiceω String)
where
open import Effects.Parser choiceString
open import Hoare.Definition ℙ-theory
open import Hoare.Calculus ℙ-theory
open import Hoare.Lemmas ℙ-theory
open Signature (FullTheory.𝔽 ℙ-theory)
open import Truth
open import Data.Tree
\end{code}
%<*tree-parser-zero>
\begin{code}
parse-tree : ℕ → Term Tree
parse-tree zero = fail
\end{code}
%</tree-parser-zero>
%<*tree-parser-suc>
\begin{code}
parse-tree (suc n) = (do char '♢'; return ♢)
<|> (do char '♠'; return ♠)
<|> (do char '('; l ← parse-tree n
char '*'; r ← parse-tree n
char ')'; return (l ⊛ r))
\end{code}
%</tree-parser-suc>
%<*print>
\begin{code}[number=tree-print]
print : Tree → String
print ♢ = "♢"
print ♠ = "♠"
print (l ⊛ r) = "(" ++ print l ++ "*" ++ print r ++ ")"
\end{code}
%</print>
\begin{code}
tree-alt-di : Term Tree
tree-alt-di = do char '♢'; return ♢
tree-alt-sp : Term Tree
tree-alt-sp = do char '♠'; return ♠
tree-n-branch : ℕ → Term Tree
tree-n-branch n =
(do char '('
l ← parse-tree n
char '*'
r ← parse-tree n
char ')'
return (l ⊛ r))
sp-di-ne-lemma : ∀ s →
\end{code}
%<*sp-di-ne-lemma>
\begin{code}
⟅ remaining ('♠' ∷ s) ⟆ v ← (do char '♢'; return ♢) ⟅ return (♠ |≡| v) ⟨∧⟩ remaining s ⟆
\end{code}
%</sp-di-ne-lemma>
\begin{code}
sp-di-ne-lemma s =
char-ne (λ v → return (♠ |≡| v) ⟨∧⟩ remaining s , sef-<$> _ _ (sef-rem s) , det-<$> _ _ (det-rem s) ) '♠' '♢' s (return ♢) (from-dec-false ('♠' ≟ '♢') _)
something : ∀ s →
\end{code}
%<*sp-di-ne-lemma-2>
\begin{code}
⟅ remaining ('♠' ∷ s) ⟆ char '♢' ⟅ return ('♠' |≡| '♢') ⟨∧⟩ remaining s ⟆
\end{code}
%</sp-di-ne-lemma-2>
\begin{code}
something = parse-char '♠' '♢'
sp-lemma : ∀ s →
\end{code}
%<*sp-lemma>
\begin{code}
⟅ remaining ('♠' ∷ s) ⟆ v ← (do char '♠'; return ♠) ⟅ return (♠ |≡| v) ⟨∧⟩ remaining s ⟆
\end{code}
%</sp-lemma>
\begin{code}
sp-lemma s =
parse-char '♠' '♠' s ⦂
⟅ remaining (print ♠ ++ s) ⟆ char '♠' ⟅ return ('♠' |≡| '♠') ⟨∧⟩ remaining s ⟆
⇒⟨ ⟅∙⟆≡ (λ _ → cong (λ e → return e ⟨∧⟩ remaining s) (proves ∣ refl ∣ ; sym (proves ∣ refl ∣))) ⟩
⟅ remaining (print ♠ ++ s) ⟆ char '♠' ⟅ return (♠ |≡| ♠) ⟨∧⟩ remaining s ⟆
⇒⟨ focus (const ♠) ⟩
⟅ remaining (print ♠ ++ s) ⟆ v ← tree-alt-sp ⟅ return (♠ |≡| v) ⟨∧⟩ remaining s ⟆
di-lemma : ∀ s →
⟅ remaining (print ♢ ++ s) ⟆ v ← tree-alt-di ⟅ return (♢ |≡| v) ⟨∧⟩ remaining s ⟆
di-lemma s =
parse-char '♢' '♢' s ⦂
⟅ remaining (print ♢ ++ s) ⟆ char '♢' ⟅ return ('♢' |≡| '♢') ⟨∧⟩ remaining s ⟆
⇒⟨ ⟅∙⟆≡ (λ _ → cong (λ e → return e ⟨∧⟩ remaining s) (proves ∣ refl ∣ ; sym (proves ∣ refl ∣))) ⟩
⟅ remaining (print ♢ ++ s) ⟆ char '♢' ⟅ return (♢ |≡| ♢) ⟨∧⟩ remaining s ⟆
⇒⟨ focus (const ♢) ⟩
⟅ remaining (print ♢ ++ s) ⟆ v ← tree-alt-di ⟅ return (♢ |≡| v) ⟨∧⟩ remaining s ⟆
left-def : Tree → Tree → Tree
left-def d = from-maybe d ∘ left
right-def : Tree → Tree → Tree
right-def d = from-maybe d ∘ right
tr-lemma₁ : ∀ n l r s →
⟅ remaining (print (l ⊛ r) ++ s) ⟆ l′ ← char '(' >> parse-tree n ⟅ return (l |≡| l′) ⟨∧⟩ remaining ("*" ++ print r ++ ")" ++ s) ⟆ →
⟅ remaining (print (l ⊛ r) ++ s) ⟆ l′ ← (char '(' >> parse-tree n) << char '*' ⟅ return (l |≡| l′) ⟨∧⟩ (return ('*' |≡| '*') ⟨∧⟩ remaining (print r ++ ")" ++ s)) ⟆
tr-lemma₁ n l r s e =
seq-<< (⟨remaining⟩ (print (l ⊛ r) ++ s)) (λ _ → _ , sef-<$> _ _ (sef-rem ("*" ++ print r ++ ")" ++ s)) , det-<$> _ _ ( det-rem ("*" ++ print r ++ ")" ++ s)))
(λ l′ → _ , sef-<$> _ _ (sef-<$> _ _ (sef-rem (print r ++ ")" ++ s))) , det-<$> _ _ (det-<$> _ _ (det-rem (print r ++ ")" ++ s))) ) e
λ l′ → ⟅∧⟆ {p = (l |≡| l′)} (⟨remaining⟩ ("*" ++ print r ++ ")" ++ s)) (λ _ → _ , sef-<$> _ _ (sef-rem (print r ++ ")" ++ s)) , det-<$> _ _ (det-rem (print r ++ ")" ++ s)) ) (parse-char '*' '*' (print r ++ ")" ++ s))
tr-lemma₃ : ∀ n l r s →
⟅ remaining (print (l ⊛ r) ++ s) ⟆ (l′ , r′) ← (((char '(' >> parse-tree n) << char '*') ;, const (parse-tree n)) ⟅ (return (l |≡| l′) ⟨∧⟩ return (r |≡| r′)) ⟨∧⟩ remaining (")" ++ s) ⟆ →
⟅ remaining (print (l ⊛ r) ++ s) ⟆ (l′ , r′) ← (((char '(' >> parse-tree n) << char '*') ;, const (parse-tree n)) << char ')' ⟅ return (l |≡| l′) ⟨∧⟩ return (r |≡| r′) ⟨∧⟩ (return (')' |≡| ')' ) ⟨∧⟩ remaining s) ⟆
tr-lemma₃ n l r s e =
seq-<< (⟨remaining⟩ (print (l ⊛ r) ++ s))
(λ _ → _ , sef-<$> _ _ (sef-rem (")" ++ s)) , det-<$> _ _ (det-rem (")" ++ s)))
(λ _ → _ , sef-<$> _ _ (sef-<$> _ _ (sef-rem s)) , det-<$> _ _ (det-<$> _ _ (det-rem s)))
e λ _ → ⟅∧⟆
(⟨remaining⟩ (")" ++ s))
(λ _ → _ , sef-<$> _ _ (sef-rem s) , det-<$> _ _ (det-rem s) )
(parse-char ')' ')' s)
open import Effects.NonDetState String choiceString isSetString as NDS using (sef-<|>; fail-absurd; <|>-conj)
mutual
tr-lemma₂ : ∀ n l r s →
⟅ remaining (print (l ⊛ r) ++ s) ⟆ l′ ← (char '(' >> parse-tree n) << char '*' ⟅ return (l |≡| l′) ⟨∧⟩ remaining (print r ++ ")" ++ s) ⟆ →
⟅ remaining (print (l ⊛ r) ++ s) ⟆ (l′ , r′) ← (((char '(' >> parse-tree n) << char '*') ;, const (parse-tree n)) ⟅ return (l |≡| l′) ⟨∧⟩ (return (r |≡| r′) ⟨∧⟩ remaining (")" ++ s)) ⟆
tr-lemma₂ n l r s e =
seq (⟨remaining⟩ (print (l ⊛ r) ++ s)) (λ _ → _ , sef-<$> _ _ (sef-rem (print r ++ ")" ++ s) ) , det-<$> _ _ (det-rem (print r ++ ")" ++ s)) )
(λ _ → _ , sef-<$> _ _ (sef-<$> _ _ (sef-rem (")" ++ s))) , det-<$> _ _ (det-<$> _ _ (det-rem (")" ++ s))) ) e
λ l′ → ⟅∧⟆ {p = l |≡| l′}
(⟨remaining⟩ (print r ++ ")" ++ s) )
(λ _ → _ , sef-<$> _ _ (sef-rem (")" ++ s)) , det-<$> _ _ (det-rem (")" ++ s)))
(round-trip n r (")" ++ s))
tr-lemma : ∀ n l r s → ⟅ remaining (print (l ⊛ r) ++ s) ⟆ v ← tree-n-branch n ⟅ return ((l ⊛ r) |≡| v) ⟨∧⟩ remaining s ⟆
tr-lemma n l r s =
parse-char '(' '(' (tail (print (l ⊛ r) ++ s)) ⦂
⟅ remaining (print (l ⊛ r) ++ s) ⟆ char '(' ⟅ return ('(' |≡| '(') ⟨∧⟩ remaining (tail (print (l ⊛ r) ++ s)) ⟆
⇒⟨ ⟅∙⟆≡ (λ _ → cong (λ e → return e ⟨∧⟩ remaining (tail (print (l ⊛ r) ++ s))) (proves ∣ refl ∣)) ⟩
⟅ remaining (print (l ⊛ r) ++ s) ⟆ char '(' ⟅ return True ⟨∧⟩ remaining (tail (print (l ⊛ r) ++ s)) ⟆
⇒⟨ ⟅∙⟆≡ (λ _ → True⟨∧⟩ _) ⟩
⟅ remaining (print (l ⊛ r) ++ s) ⟆ char '(' ⟅ remaining (tail (print (l ⊛ r) ++ s)) ⟆
⇒⟨ (seq⁻ (⟨remaining⟩ (print (l ⊛ r) ++ s)) (λ _ → ⟨remaining⟩ ((print l ++ "*" ++ print r ++ ")") ++ s)) (λ _ → _ , sef-<$> _ _ (sef-rem ("*" ++ print r ++ ")" ++ s)) , det-<$> _ _ ( det-rem ("*" ++ print r ++ ")" ++ s))) (λ _ → ≡⟅∙⟆ (cong remaining (sym (++-assoc (print l) _ _ ; cong (print l ++_) (++-assoc "*" _ _ ; cong ("*" ++_) (++-assoc (print r) _ _))))) (round-trip n l (("*" ++ print r ++ ")" ++ s))) )) ⟩
⟅ remaining (print (l ⊛ r) ++ s) ⟆ l′ ← char '(' >> parse-tree n ⟅ return (l |≡| l′) ⟨∧⟩ remaining ("*" ++ print r ++ ")" ++ s) ⟆
⇒⟨ tr-lemma₁ n l r s ⟩
⟅ remaining (print (l ⊛ r) ++ s) ⟆ l′ ← (char '(' >> parse-tree n) << char '*' ⟅ return (l |≡| l′) ⟨∧⟩ (return ('*' |≡| '*') ⟨∧⟩ remaining (print r ++ ")" ++ s)) ⟆
⇒⟨ ⟅∙⟆≡ (λ l′ → cong (return (l |≡| l′) ⟨∧⟩_) ( cong (_⟨∧⟩ remaining (print r ++ ")" ++ s)) (cong return (proves ∣ refl ∣)) ; True⟨∧⟩ _) ) ⟩
⟅ remaining (print (l ⊛ r) ++ s) ⟆ l′ ← (char '(' >> parse-tree n) << char '*' ⟅ return (l |≡| l′) ⟨∧⟩ remaining (print r ++ ")" ++ s) ⟆
⇒⟨ tr-lemma₂ n l r s ⟩
⟅ remaining (print (l ⊛ r) ++ s) ⟆ (l′ , r′) ← (((char '(' >> parse-tree n) << char '*') ;, const (parse-tree n)) ⟅ return (l |≡| l′) ⟨∧⟩ (return (r |≡| r′) ⟨∧⟩ remaining (")" ++ s)) ⟆
⇒⟨ ⟅∙⟆≡ (λ { (l′ , r′) → sym (⟨∧⟩-assoc (return (l |≡| l′)) (return (r |≡| r′)) (remaining (")" ++ s))) }) ⟩
⟅ remaining (print (l ⊛ r) ++ s) ⟆ (l′ , r′) ← (((char '(' >> parse-tree n) << char '*') ;, const (parse-tree n)) ⟅ (return (l |≡| l′) ⟨∧⟩ return (r |≡| r′)) ⟨∧⟩ remaining (")" ++ s) ⟆
⇒⟨ tr-lemma₃ n l r s ⟩
⟅ remaining (print (l ⊛ r) ++ s) ⟆ (l′ , r′) ← (((char '(' >> parse-tree n) << char '*') ;, const (parse-tree n)) << char ')' ⟅ return (l |≡| l′) ⟨∧⟩ return (r |≡| r′) ⟨∧⟩ (return (')' |≡| ')' ) ⟨∧⟩ remaining s) ⟆
⇒⟨ ⟅∙⟆≡ (λ { (l′ , r′) → sym (⟨∧⟩-assoc (return ((l |≡| l′) |∧| (r |≡| r′))) _ _) ; cong (_⟨∧⟩ remaining s) (cong return (( λ { ((l″ , r″) , _) → ∥liftA2∥ (λ x y → cong₂ _⊛_ x y) l″ r″ }) iff ∥rec∥ (isProp× (isProp× squash squash) squash) λ p → (∣ cong (left-def l) p ∣ , ∣ cong (right-def r) p ∣) , ∣ refl ∣ )) }) ⟩
⟅ remaining (print (l ⊛ r) ++ s) ⟆ (l′ , r′) ← (((char '(' >> parse-tree n) << char '*') ;, const (parse-tree n)) << char ')' ⟅ return ((l ⊛ r) |≡| (l′ ⊛ r′)) ⟨∧⟩ remaining s ⟆
⇒⟨ focus (uncurry _⊛_) ⟩
⟅ remaining (print (l ⊛ r) ++ s) ⟆ v ← uncurry _⊛_ <$> (((char '(' >> parse-tree n) << char '*') ;, const (parse-tree n)) << char ')' ⟅ return ((l ⊛ r) |≡| v) ⟨∧⟩ remaining s ⟆
⇒⟨ subst-⟅⟆ (assoc (((char '(' >> parse-tree n) << char '*') ;, const (parse-tree n)) _ _ ; assoc ((char '(' >> parse-tree n) << char '*') _ _ ; assoc (char '(' >> parse-tree n) _ _ ; assoc (char '(') _ _ ; _ ⇐ char '(' ;/ l ⇐ parse-tree n ;/ assoc (char '*') _ _ ; _ ⇐ char '*' ;/ assoc (parse-tree n) _ _ ; r ⇐ parse-tree n ;/ assoc (char ')') _ _ ) ⟩
⟅ remaining (print (l ⊛ r) ++ s) ⟆ v ← tree-n-branch n ⟅ return ((l ⊛ r) |≡| v) ⟨∧⟩ remaining s ⟆
\end{code}
%<*round-trip-sig>
\begin{code}
round-trip : ∀ n t → print t ∈ parse-tree n ↦ t
\end{code}
%</round-trip-sig>
\begin{code}
round-trip zero t s =
fail-absurd _ ⦂
(⟅⟆ v ← parse-tree zero ⟅ return (t |≡| v) ⟨∧⟩ remaining s ⟆) ⇒⟨ weaken ⟨return True ⟩ (λ v → return (t |≡| v) ⟨∧⟩ remaining s , sef-<$> _ _ (sef-rem s) , det-<$> _ _ (det-rem s)) (⟨remaining⟩ (print t ++ s)) (⟅→⟆True _ _) ⟩
\end{code}
%<*goal-zero>
\begin{code}
⟅ remaining (print t ++ s) ⟆ v ← parse-tree zero ⟅ return (t |≡| v) ⟨∧⟩ remaining s ⟆
\end{code}
%</goal-zero>
\begin{code}
round-trip (suc n) ♢ s =
di-lemma s
⟨<|>⟩
char-ne (λ v → return (♢ |≡| v) ⟨∧⟩ remaining s , sef-<$> _ _ (sef-rem s) , det-<$> _ _ (det-rem s) ) '♢' '♠' s (return ♠) (from-dec-false ('♢' ≟ '♠') _)
⟨<|>⟩
char-ne (λ v → return (♢ |≡| v) ⟨∧⟩ remaining s , sef-<$> _ _ (sef-rem s) , det-<$> _ _ (det-rem s) ) '♢' '(' s _ (from-dec-false ('♢' ≟ '(') _)
round-trip (suc n) ♠ s =
char-ne (λ v → return (♠ |≡| v) ⟨∧⟩ remaining s , sef-<$> _ _ (sef-rem s) , det-<$> _ _ (det-rem s) ) '♠' '♢' s (return ♢) (from-dec-false ('♠' ≟ '♢') _)
⟨<|>⟩
sp-lemma s
⟨<|>⟩
char-ne (λ v → return (♠ |≡| v) ⟨∧⟩ remaining s , sef-<$> _ _ (sef-rem s) , det-<$> _ _ (det-rem s) ) '♠' '(' s _ (from-dec-false ('♠' ≟ '(') _)
round-trip (suc n) (l ⊛ r) s =
let s′ = print l ++ "*" ++ print r ++ ")" ++ s
in ≡⟅∙⟆ (cong remaining (sym (++-assoc ("(" ++ print l) _ _ ; cong (λ e → "(" ++ print l ++ e) (++-assoc ("*" ++ print r) _ _))))
(char-ne (λ v → return (l ⊛ r |≡| v) ⟨∧⟩ remaining s , sef-<$> _ _ (sef-rem s) , det-<$> _ _ (det-rem s) ) '(' '♢' s′ (return ♢) (from-dec-false ('(' ≟ '♢') _))
⟨<|>⟩
≡⟅∙⟆ (cong remaining (sym (++-assoc ("(" ++ print l) _ _ ; cong (λ e → "(" ++ print l ++ e) (++-assoc ("*" ++ print r) _ _))))
(char-ne (λ v → return (l ⊛ r |≡| v) ⟨∧⟩ remaining s , sef-<$> _ _ (sef-rem s) , det-<$> _ _ (det-rem s) ) '(' '♠' s′ (return ♠) (from-dec-false ('(' ≟ '♠') _))
⟨<|>⟩
tr-lemma n l r s
\end{code}