----------------------------------------------------------------
--
-- | Compilation
--   Monad and combinators for quickly assembling simple
--   compilers.
--
-- @Control\/Compilation\/String.hs@
--
--   A generic compilation monad and combinators for quickly
--   assembling simple compilers that emit an ASCII string
--   representation of the target language (well-suited for
--   direct syntax translators).
--

----------------------------------------------------------------
--

{-# LANGUAGE FlexibleInstances, TypeSynonymInstances #-}
{-# LANGUAGE ScopedTypeVariables #-}

module Control.Compilation.String
  where
  
import Control.Compilation

----------------------------------------------------------------
-- | Type synonyms and class memberships.

type Indentation = Integer
type StateExtensionString = (Indentation, String)

instance StateExtension StateExtensionString where
  initial = (0, "")

----------------------------------------------------------------
-- | State extension class definition, including combinators
--   and convenient synonyms for compiling directly into a raw
--   ASCII string.

class StateExtension a => HasString a where
  project :: a -> StateExtensionString
  inject :: StateExtensionString -> a -> a
  
  indent :: Compilation a ()
  indent =
    do state <- get
       (i, s) <- return $ project state
       set $ inject (i + 2, s) state

  unindent :: Compilation a ()
  unindent =
    do state <- get
       (i, s) <- return $ project state
       set $ inject (max 0 (i - 2), s) state
   
  space :: Compilation a ()
  space =
    do state <- get
       (i, s) <- return $ project state
       set $ inject (i, s ++ " ") state

  spaces :: Int -> Compilation a ()
  spaces k =
    do state <- get
       (i, s) <- return $ project state
       set $ inject (i, s ++ (take k $ repeat ' ')) state

  newline :: Compilation a ()
  newline =
    do state <- get
       (i, s) <- return $ project state
       set $ inject (i, s ++ "\n" ++ (take (fromInteger i) $ repeat ' ')) state

  newlines :: Int -> Compilation a ()
  newlines k =
    do state <- get
       (i, s) <- return $ project state
       set $ inject (i, s ++ (take k $ repeat '\n') ++ (take (fromInteger i) $ repeat ' ')) state

  string :: String -> Compilation a ()
  string s' =
    do state <- get
       (i, s) <- return $ project state
       set $ inject (i, s ++ s') state

  raw :: String -> Compilation a ()
  raw = string
  
  compiled :: Compilation a b -> String
  compiled c = let (_, s) :: StateExtensionString = project (extract c) in s

--eof