{-# OPTIONS --without-K --safe #-}
module Text.Format where
open import Level using (0ℓ)
open import Category.Applicative
open import Data.List.Base as List
open import Data.Product
open import Data.Product.Nary.NonDependent
open import Data.Sum.Base
import Data.Sum.Categorical.Left as Sumₗ
open import Function
open import Function.Nary.NonDependent using (0ℓs; Sets)
open import Strict
open import Data.Char.Base
open import Data.Integer.Base
open import Data.Float
open import Data.Nat.Base
open import Data.String.Base
data Chunk : Set where
  `ℕ `ℤ `Float `Char `String : Chunk
  Raw : String → Chunk
Format : Set
Format = List Chunk
size : Format → ℕ
size = List.sum ∘′ List.map λ { (Raw _) → 0; _ → 1 }
⟦_⟧ : (fmt : Format) → Sets (size fmt) 0ℓs
⟦ []           ⟧ = _
⟦ `ℕ      ∷ cs ⟧ = ℕ      , ⟦ cs ⟧
⟦ `ℤ      ∷ cs ⟧ = ℤ      , ⟦ cs ⟧
⟦ `Float  ∷ cs ⟧ = Float  , ⟦ cs ⟧
⟦ `Char   ∷ cs ⟧ = Char   , ⟦ cs ⟧
⟦ `String ∷ cs ⟧ = String , ⟦ cs ⟧
⟦ Raw _   ∷ cs ⟧ =          ⟦ cs ⟧
data Error : Set where
  UnexpectedEndOfString : String → Error
  
  InvalidType : String → Char → String → Error
  
  
lexer : String → Error ⊎ List Chunk
lexer input = loop [] [] (toList input) where
  open RawApplicative (Sumₗ.applicative Error 0ℓ)
  
  RevWord = List Char 
  Prefix  = RevWord   
  toRevString : RevWord → String
  toRevString = fromList ∘′ reverse
  
  push : RevWord → List Chunk → List Chunk
  push [] ks = ks
  push cs ks = Raw (toRevString cs) ∷ ks
  
  loop : RevWord → Prefix → List Char → Error ⊎ List Chunk
  type :           Prefix → List Char → Error ⊎ List Chunk
  loop acc bef []               = pure (push acc [])
  
  loop acc bef ('%' ∷ '%' ∷ cs) = loop ('%' ∷ acc) ('%' ∷ '%' ∷ bef) cs
  
  loop acc bef ('%' ∷ cs)       = push acc <$> type ('%' ∷ bef) cs
  
  loop acc bef (c ∷ cs)         = loop (c ∷ acc) (c ∷ bef) cs
  type bef []       = inj₁ (UnexpectedEndOfString input)
  type bef (c ∷ cs) = _∷_ <$> chunk c ⊛ loop [] (c ∷ bef) cs where
    chunk : Char → Error ⊎ Chunk
    chunk 'd' = pure `ℤ
    chunk 'i' = pure `ℤ
    chunk 'u' = pure `ℕ
    chunk 'f' = pure `Float
    chunk 'c' = pure `Char
    chunk 's' = pure `String
    chunk _   = force′ (toRevString bef) $′ λ prefix →
                force′ (fromList cs)     $′ λ suffix →
                inj₁ (InvalidType prefix c suffix)