{-# OPTIONS --without-K --safe #-}

module Data.String.Printf where

open import Data.List using (List; []; _∷_; foldr)
open import Data.String hiding (show)
open import Data.Nat hiding (_≟_)
open import Data.Char as Char using (Char)
import Level
open import Relation.Nullary

infixr 6 _%_
record FormatUnit : Set (Level.suc Level.zero) where
  constructor _%_
  field
    marker : Char
    {type} : Set
    conv   : type → String
open FormatUnit public

module Internal where
  data Formatter : Set (Level.suc Level.zero) where
    chr : Char → Formatter
    cnv : (t : Set) → (t → String) → Formatter

  formatUnitTy : Formatter → Set → Set
  formatUnitTy (chr _) xs = xs
  formatUnitTy (cnv t _) xs = t → xs

  formatTy : List Formatter → Set
  formatTy = foldr formatUnitTy String

  toFormat : List FormatUnit → List Char → List Formatter
  toFormat fs [] = []
  toFormat fs ('%' ∷ x ∷ xs) = go fs x xs where
    go : List FormatUnit → Char → List Char → List Formatter
    go [] x xs = chr x ∷ toFormat fs xs
    go (f ∷ fs) x xs with marker f Char.≟ x
    go (f ∷ _ ) x xs | yes p = cnv _ (conv f) ∷ toFormat fs xs
    go (f ∷ fs) x xs | no ¬p = go fs x xs
  toFormat fs (x ∷ xs) = chr x ∷ toFormat fs xs

  printf : (fs : List FormatUnit) → (xs : String) → formatTy (toFormat fs (toList xs))
  printf fs xs = go "" (toFormat fs (toList xs))
    where
    go : String → (xs : List Formatter) → formatTy xs
    go k [] = k
    go k (chr x ∷ xs) = go (k ++ fromList (x ∷ [])) xs
    go k (cnv _ c ∷ xs) = λ x → go (k ++ c x) xs
import Data.Nat.Show
open import Function

standard : List FormatUnit
standard = 'i' % Data.Nat.Show.show ∷ 's'% id ∷ []

module Printf (fs : List FormatUnit) where
  printf : (xs : String) → Internal.formatTy (Internal.toFormat fs (toList xs))
  printf = Internal.printf fs