packages feed

compdata-0.8: examples/Examples/Automata/SimpComp2.hs

{-# LANGUAGE TemplateHaskell, FlexibleContexts, MultiParamTypeClasses,
  TypeOperators, FlexibleInstances, UndecidableInstances,
  ScopedTypeVariables, TypeSynonymInstances, RankNTypes, ImplicitParams, DeriveDataTypeable #-}

module Examples.Automata.Compiler where

import Data.Comp.Automata
import Data.Comp.Zippable
import Data.Comp.Derive
import Data.Comp.Ops
import Data.Comp hiding (height)
import Data.Foldable
import Prelude hiding (foldl)

import Data.Set (Set, union, singleton, delete, member)
import qualified Data.Set as Set

import Data.Map (Map)
import qualified Data.Map as Map




type Var = String

data Sig e = Const Int | Plus e e | LetIn Var e e | Var Var


$(derive [makeFunctor, makeFoldable, smartConstructors, makeShowF] [''Sig])

instance Zippable Sig where
    fzip _ (Const i) = Const i
    fzip (Cons a (Cons b _)) (Plus x y) = Plus (a,x) (b,y)
    fzip (Cons a (Cons b _)) (LetIn v x y) = LetIn v (a,x) (b,y)
    fzip _ (Var v) = Var v


instance (Zippable f, Zippable g) => Zippable (f :+: g) where
    fzip x (Inl v) = Inl $ fzip x v
    fzip x (Inr v) = Inr $ fzip x v

-- evalSt :: UpState Sig Int
-- evalSt (Const i) = i
-- evalSt (Plus x y) = x + y

type Addr = Int

data Instr = Acc Int
           | Load Addr
           | Store Addr
           | Add Addr
             deriving (Show)

type Code = [Instr]



-- heightSt :: UpState Sig Int
-- heightSt (Const _) = 0
-- heightSt (Plus x y) = 1 + max x y
-- heightSt (LetIn _ e b) = 1 + max e b
-- heightSt (Var _) = 0

-- codeSt :: (Int :< q) => DUpState Sig q Code 
-- codeSt (Const x) = [Acc x]
-- codeSt (Plus x y) = below x ++ [Store a] ++ below y ++ [Add a] where a = below y


-- code :: Term Sig -> Code
-- code = fst . runDUpState (codeSt <*> dUpState heightSt)


type Vars = Set Var

fvSt :: UpState Sig Vars
fvSt (Var v)  = singleton v
fvSt (LetIn v e b)  | v `member` b  = e `union` delete v b
                    | otherwise     =  delete v b
fvSt t        = foldl union Set.empty t

-- | Stateful homomorphism that removes unnecessary let bindings.
remLetHom :: (Vars :< q) => QHom Sig q Sig
remLetHom (LetIn v _ y) | not (v `Set.member` below y) = Hole y
remLetHom  t = simpCxt t

remLet :: Term Sig -> Term Sig
remLet = runUpHom fvSt remLetHom

ldepthSt :: DownState Sig Int
ldepthSt (d,LetIn _ _ b) = b |-> d + 1
ldepthSt _               = o

type Ren = Map Var Var


newVar :: (?above :: q, Int :< q) => Var
newVar = show (above :: Int)

renSt :: (Int :< q) => DDownState Sig q Ren
renSt (LetIn v _ b) = b |-> (v |-> newVar & above)
renSt _             = o

renameHom :: (Ren :< q, Int :< q) => QHom Sig q Sig
renameHom (LetIn _ a b) = iLetIn newVar (Hole a) (Hole b)
renameHom (Var v) = case Map.lookup v above of
                      Nothing -> iVar v
                      Just v' -> iVar v'
renameHom t = simpCxt t

renameInit :: (Ren, Int)
renameInit = (o, 0)

rename :: Term Sig -> Term Sig
rename = runDownHom (downState (renSt >*< dDownState ldepthSt))
         renameHom renameInit


heightSt :: Foldable f => UpState f Int
heightSt t = foldl max 0 t + 1

newtype Height = Height {height :: Int}

heightSt' :: (Functor f,Foldable f) => UpState f Height
heightSt' = tagUpState Height height heightSt


newtype Depth = Depth {depth :: Int}

ldepthSt' :: DownState Sig Depth
ldepthSt' = tagDownState Depth depth ldepthSt

type Bind = Map Var Int

bindSt :: (Depth :< q) => DDownState Sig q Bind 
bindSt (LetIn v _ e)  = e |-> (v |-> 2 * depth above & above)
bindSt _              = o

codeSt :: (Height :< q, Depth :< q, Bind :< q) => DUpState Sig q Code 
codeSt (Const x) = [Acc x]
codeSt (Plus x y) = below x ++ [Store a] ++ below y ++ [Add a] 
    where a = 2 * height (below y) + 1
codeSt (LetIn _ b e) = below b ++ [Store a] ++ below e
    where a = 2 * depth above
codeSt (Var v) = case Map.lookup v above of
                       Nothing -> error $ "unbound variable " ++ v
                       Just i -> [Load i]


code :: Term Sig -> (Code, Height)
code = runDState 
          (codeSt <*> dUpState heightSt')
          (bindSt >*< dDownState ldepthSt')
          (o :: Bind, Depth 0)