elm/compiler/Transform/Optimize.hs

135 lines
4.7 KiB
Haskell
Raw Normal View History

module Optimize (optimize) where
import Ast
import Context
import Control.Arrow (second)
import Data.Char (isAlpha)
import Substitute
optimize (Module name ims exs stmts) =
Module name ims exs (map optimizeStmt stmts)
optimizeStmt stmt = if stmt == stmt' then stmt' else optimizeStmt stmt'
where stmt' = simp stmt
class Simplify a where
simp :: a -> a
instance Simplify Statement where
simp (Definition def) = Definition (simp def)
simp (ImportEvent js b elm t) = ImportEvent js (simp b) elm t
simp stmt = stmt
instance Simplify Def where
simp (FnDef func args e) = FnDef func args (simp e)
simp (OpDef op a1 a2 e) = OpDef op a1 a2 (simp e)
instance Simplify e => Simplify (Context e) where
simp (C t s e) = C t s (simp e)
instance Simplify Expr where
simp expr =
let f = simp in
case expr of
Range e1 e2 -> Range (f e1) (f e2)
Binop op e1 e2 -> simp_binop op (f e1) (f e2)
Lambda x e -> Lambda x (f e)
Record fs -> Record (map (\(f,as,e) -> (f, as, simp e)) fs)
App (C t s (Lambda x e1)) e2 ->
if isValue e2' then subst x e2' e1' else App (C t s (Lambda x ce1')) ce2'
where ce1'@(C _ _ e1') = f e1
ce2'@(C _ _ e2') = f e2
App e1 e2 -> App (f e1) (f e2)
If e1 e2 e3 -> simp_if (f e1) (f e2) (f e3)
Let defs e -> Let (map simp defs) (f e)
Data name es -> Data name (map f es)
Case e cases -> Case (f e) (map (second f) cases)
_ -> expr
simp_if (C _ _ (Boolean b)) (C _ _ e2) (C _ _ e3) = if b then e2 else e3
simp_if a b c = If a b c
isValue e =
case e of { IntNum _ -> True
; FloatNum _ -> True
; Chr _ -> True
; Str _ -> True
; Boolean _ -> True
; Var _ -> True
; Data _ _ -> True
; _ -> False }
simp_binop = binop
binop op ce1@(C t1 s1 e1) ce2@(C t2 s2 e2) =
let c1 = C t1 s1 in
let c2 = C t2 s2 in
case (op, e1, e2) of
(_, IntNum n, IntNum m) -> case op of
{ "+" -> IntNum $ (+) n m
; "-" -> IntNum $ (-) n m
; "*" -> IntNum $ (*) n m
; "^" -> IntNum $ n ^ m
; "div" -> IntNum $ div n m
; "mod" -> IntNum $ mod n m
; "<" -> Boolean $ n < m
; ">" -> Boolean $ n < m
; "<=" -> Boolean $ n <= m
; ">=" -> Boolean $ n >= m
; "==" -> Boolean $ n == m
; "/=" -> Boolean $ n /= m
; _ -> Binop op ce1 ce2 }
-- flip order to move lone integers to the left
("+", _, IntNum n) -> binop "+" ce2 ce1
("*", _, IntNum n) -> binop "*" ce2 ce1
("+", IntNum 0, _) -> e2
("+", IntNum n, Binop "+" (C _ _ (IntNum m)) ce) ->
binop "+" (c1 $ IntNum (n+m)) ce
("+", Binop "+" (C _ _ (IntNum n)) ce1'
, Binop "+" (C _ _ (IntNum m)) ce2') ->
binop "+" (noContext $ IntNum (n+m)) (noContext $ Binop "+" ce1' ce2')
("*", IntNum 0, _) -> e1
("*", IntNum 1, _) -> e2
("*", IntNum n, Binop "*" (C _ _ (IntNum m)) ce) ->
binop "*" (noContext $ IntNum (n*m)) ce
("*", Binop "*" (C _ _ (IntNum n)) ce1'
, Binop "*" (C _ _ (IntNum m)) ce2') ->
binop "*" (noContext $ IntNum (n*m)) (noContext $ Binop "*" ce1' ce2')
("-", _, IntNum 0) -> e1
("/", _, IntNum 1) -> e1
("div", _, IntNum 1) -> e1
(_, Boolean n, Boolean m) -> case op of "&&" -> Boolean $ n && m
"||" -> Boolean $ n || m
_ -> Binop op ce1 ce2
("&&", Boolean True, _) -> e2
("&&", Boolean False, _) -> Boolean False
("||", Boolean True, _) -> Boolean True
("||", Boolean False, _) -> e2
(":", _, _) -> let (C _ _ e) = cons ce1 ce2 in e
("++", Str s1, Str s2) -> Str $ s1 ++ s2
("++", Str s1, Binop "++" (C _ _ (Str s2)) ce) ->
Binop "++" (c1 $ Str $ s1 ++ s2) ce
("++", Binop "++" e (C _ _ (Str s1)), Str s2) ->
Binop "++" e (c1 $ Str $ s1 ++ s2)
("++", Data "Nil" [], _) -> e2
("++", _, Data "Nil" []) -> e1
("++", Data "Cons" [h,t], _) -> Data "Cons" [h, noContext $ binop "++" t ce2]
("$", _, _) -> App ce1 ce2
(".", _, _) ->
Lambda "x" (noContext $
App ce1 (noContext $ App ce2 (noContext $ Var "x")))
_ | isAlpha (head op) || '_' == head op ->
App (noContext $ App (noContext $ Var op) ce1) ce2
| otherwise -> Binop op ce1 ce2