module Unparser
( unparse
) where
import Data.List (intersperse)
import qualified Data.Map as M
import PureSyntax
unparse :: Program -> ETree
unparse p =
let (vmNoEq, pNoEq) = removeEquality (varMapProg p) p in
unparseProg vmNoEq pNoEq
type VarMap = M.Map Name Int
varMapProg :: Program -> VarMap
varMapProg (Program _ rd blk wrt) =
varMapName (varMapBlock (M.singleton rd 0) blk) wrt
varMapBlock :: VarMap -> Block -> VarMap
varMapBlock vm [] = vm
varMapBlock vm (c:cs) = varMapBlock (varMapComm vm c) cs
varMapComm :: VarMap -> Command -> VarMap
varMapComm vm comm = case comm of
Assign v x -> varMapExpr (varMapName vm v) x
While x b -> varMapBlock (varMapExpr vm x) b
IfElse e bt bf -> varMapExpr (varMapBlock (varMapBlock vm bf) bt) e
varMapExpr :: VarMap -> Expression -> VarMap
varMapExpr vm expr = case expr of
Var s -> varMapName vm s
Lit _ -> vm
Cons a b -> varMapExpr (varMapExpr vm a) b
Hd x -> varMapExpr vm x
Tl x -> varMapExpr vm x
IsEq a b -> varMapExpr (varMapExpr vm a) b
varMapName :: VarMap -> Name -> VarMap
varMapName vm n | M.member n vm = vm
| otherwise = M.insert n ((succ . maximum . M.elems) vm) vm
unparseProg :: VarMap -> Program -> ETree
unparseProg vm (Program _ x b y) =
treeFromHaskellList [unparseName vm x, unparseBlock vm b, unparseName vm y]
unparseBlock :: VarMap -> Block -> ETree
unparseBlock vm blk = treeFromHaskellList $ map (unparseComm vm) blk
unparseComm :: VarMap -> Command -> ETree
unparseComm vm comm = treeFromHaskellList $ case comm of
Assign v x ->
[ atomToTree AtomAsgn
, unparseName vm v
, unparseExpr vm x
]
While x b ->
[ atomToTree AtomWhile
, unparseExpr vm x
, unparseBlock vm b
]
IfElse x bt bf ->
[ atomToTree AtomIf
, unparseExpr vm x
, unparseBlock vm bt
, unparseBlock vm bf
]
unparseExpr :: VarMap -> Expression -> ETree
unparseExpr vm expr = treeFromHaskellList $ case expr of
Lit (ECons a b) ->
[ atomToTree AtomCons
, unparseExpr vm (Lit a)
, unparseExpr vm (Lit b)
]
Lit ENil ->
[ atomToTree AtomQuote
, ENil
]
Var s ->
[ atomToTree AtomVar
, unparseName vm s
]
Cons a b ->
[ atomToTree AtomCons
, unparseExpr vm a
, unparseExpr vm b
]
Hd x ->
[ atomToTree AtomHd
, unparseExpr vm x
]
Tl x ->
[ atomToTree AtomTl
, unparseExpr vm x
]
IsEq a b -> error "Unparse equality expression"
unparseName :: VarMap -> Name -> ETree
unparseName vm n = maybe (error "Unparse VarMap miss") intToTree (M.lookup n vm)
removeEquality :: VarMap -> Program -> (VarMap, Program)
removeEquality vm (Program n x blk y) =
let (vmB, rBlk) = removeEqualityBlock vm blk in (vmB, Program n x rBlk y)
removeEqualityBlock :: VarMap -> Block -> (VarMap, Block)
removeEqualityBlock vm [] = (vm, [])
removeEqualityBlock vm (c:cs) =
let (vmC , cBlk) = removeEqualityComm vm c
(vmCs, rBlk) = removeEqualityBlock vmC cs in
(vmCs, cBlk ++ rBlk)
removeEqualityComm :: VarMap -> Command -> (VarMap, Block)
removeEqualityComm vm comm = case comm of
Assign v x -> case removeEqualityExpr vm x of
(_ , _ , [] ) -> (vm , [ Assign v x ])
(vmX, rX, blk) -> (vmX, blk ++ [ Assign v rX ])
While x b -> let (vmB, blkN) = removeEqualityBlock vm b in
case removeEqualityExpr vmB x of
(_ , _ , [] ) -> (vmB , [ While x blkN ])
(vmBX, rX, blkX) -> (vmBX, blkX ++ [ While rX blkN ])
IfElse x bt bf -> let
(vmBT , blkT) = removeEqualityBlock vm bt
(vmBTBF, blkF) = removeEqualityBlock vmBT bf in
case removeEqualityExpr vmBTBF x of
(_ , _ , [] ) -> (vmBTBF , [ IfElse x blkT blkF ])
(vmBTBFX, rX, blkX) -> (vmBTBFX, blkX ++ [ IfElse rX blkT blkF ])
removeEqualityExpr ::
VarMap ->
Expression ->
( VarMap
, Expression
, Block
)
removeEqualityExpr vm exp = case exp of
Var _ -> (vm, exp, [])
Lit _ -> (vm, exp, [])
Hd x -> let (vmX, rX, blk) = removeEqualityExpr vm x in (vmX, Hd rX, blk)
Tl x -> let (vmX, rX, blk) = removeEqualityExpr vm x in (vmX, Tl rX, blk)
Cons a b -> let
(vmA , rA, blkA) = removeEqualityExpr vm a
(vmAB, rB, blkB) = removeEqualityExpr vmA b in
(vmAB, Cons rA rB, blkA ++ blkB)
IsEq a b -> let
(vmA , rA, blkA) = removeEqualityExpr vm a
(vmAB, rB, blkB) = removeEqualityExpr vmA b
nameNum = (succ . maximum . M.elems) vm
name = iname ("+EQ+" ++ show nameNum ++ "+")
vmABN = M.insert name nameNum vmAB
(vmABNE, eqComm) = equalityTester vmABN name
in
(vmABNE, Var name, blkA ++ blkB ++
[ Assign (iname stack) (lst [lst [rA, rB]])
, eqComm
])
equalityTester :: VarMap -> Name -> (VarMap, Command)
equalityTester vm equals = let
vmNew = foldl (\m n -> varMapName m (iname n)) vm [stack, next, a, b]
in (vmNew, IfElse (Lit ENil) []
[ Assign equals (Lit (intToTree 1))
, whilev stack
[ asgn next (Hd (v stack))
, asgn stack (Tl (v stack))
, asgn a (Hd (v next ))
, asgn b (Hd (Tl (v next)))
, ifv a
[ ifv b
[ asgn stack $ Cons (lst [Hd (v a), Hd (v b)]) (v stack)
, asgn stack $ Cons (lst [Tl (v a), Tl (v b)]) (v stack)
]
[ asgn stack (Lit ENil)
, Assign equals (Lit ENil)
]
]
[ ifv b
[ asgn stack (Lit ENil)
, Assign equals (Lit ENil)
] []
]
]
])
where
a :: String
a = "+NEXT+A+"
b :: String
b = "+NEXT+B+"
next :: String
next = "+NEXT+"
v :: String -> Expression
v = Var . iname
asgn :: String -> Expression -> Command
asgn n = Assign (iname n)
ifv :: String -> Block -> Block -> Command
ifv n = IfElse (Var (iname n))
whilev :: String -> Block -> Command
whilev n = While (Var (iname n))
lst :: [Expression] -> Expression
lst [] = Lit ENil
lst (e:es) = Cons e (lst es)
iname :: String -> Name
iname n = Name ("+IMPL+", n)
stack :: String
stack = "+STACK+"