module Language.Sifflet.Export.Exporter
(Exporter
, simplifyExpr
, commonRuleHigherPrec
, commonRuleAtomic
, commonRuleLeftToRight
, commonRuleAssocRight
, commonRuleFuncOp
, commonRulesForSimplifyingExprs
, ruleIfRight
, ruleRightToLeft
, applyFirstMatch
, findFixed
)
where
import Language.Sifflet.Expr
type Exporter = Functions -> FilePath -> IO ()
simplifyExpr :: [Expr -> Expr] -> Expr -> Expr
simplifyExpr rules expr =
findFixed (topDown (applyFirstMatch rules)) expr
findFixed :: (Eq a) => (a -> a) -> a -> a
findFixed f x =
let x' = f x
in if x' == x then x else findFixed f x'
commonRuleHigherPrec :: Expr -> Expr
commonRuleHigherPrec e =
case e of
EOp op1 (EGroup (EOp op2 subleft subright)) right ->
if opPrec op2 > opPrec op1
then EOp op1 (EOp op2 subleft subright) right
else e
EOp op1 left (EGroup (EOp op2 subleft subright)) ->
if opPrec op2 > opPrec op1
then EOp op1 left (EOp op2 subleft subright)
else e
_ -> e
commonRuleAtomic :: Expr -> Expr
commonRuleAtomic e =
case e of
EGroup e' ->
if exprIsAtomic e'
then e'
else e
_ -> e
commonRuleLeftToRight :: Expr -> Expr
commonRuleLeftToRight e =
case e of
EOp op2 (EGroup (EOp op1 a b)) c ->
if opPrec op1 == opPrec op2 &&
opGrouping op1 == GroupLtoR &&
opGrouping op2 == GroupLtoR
then EOp op2 (EOp op1 a b) c
else e
_ -> e
ruleRightToLeft :: Expr -> Expr
ruleRightToLeft e =
case e of
EOp op1 a (EGroup (EOp op2 b c)) ->
if op1 == op2 && opGrouping op1 == GroupRtoL
then EOp op1 a (EOp op2 b c)
else e
_ -> e
commonRuleAssocRight :: Expr -> Expr
commonRuleAssocRight e =
case e of
EOp op1 a (EGroup (EOp op2 b c)) ->
if op1 == op2 && opAssoc op1
then EOp op1 a (EOp op2 b c)
else e
_ -> e
ruleIfRight :: Expr -> Expr
ruleIfRight e =
case e of
EOp op a (EGroup i@(EIf _ _ _)) -> EOp op a i
_ -> e
commonRuleFuncOp :: Expr -> Expr
commonRuleFuncOp e =
case e of
EOp op a (EGroup c@(ECall _ _)) -> EOp op a c
EOp op (EGroup c@(ECall _ _)) b -> EOp op c b
_ -> e
commonRulesForSimplifyingExprs :: [Expr -> Expr]
commonRulesForSimplifyingExprs =
[commonRuleHigherPrec
, commonRuleAtomic
, commonRuleLeftToRight
, commonRuleAssocRight
, commonRuleFuncOp]
applyFirstMatch :: [Expr -> Expr] -> Expr -> Expr
applyFirstMatch [] e = e
applyFirstMatch (r:rs) e =
let e' = r e
in if e' /= e
then e'
else applyFirstMatch rs e
topDown :: (Expr -> Expr) -> Expr -> Expr
topDown f e =
let tdf = topDown f
e' = f e
in case e' of
EIf c a b -> EIf (tdf c) (tdf a) (tdf b)
EList xs -> EList (map tdf xs)
ELambda x body -> ELambda x (tdf body)
ECall fsym args -> ECall fsym (map tdf args)
EOp op left right -> EOp op (tdf left) (tdf right)
EGroup e'' -> EGroup (tdf e'')
_ -> e'