module Language.Sifflet.Export.ToHaskell
(
HaskellOptions(..)
, defaultHaskellOptions
, exportHaskell
, functionsToHsModule
, functionToHsDecl
, exprToHsExpr
)
where
import Data.Char (toUpper)
import qualified Data.Map as M
import System.FilePath (dropExtension, takeFileName)
import Language.Sifflet.Export.Exporter
import Language.Sifflet.Export.Haskell
import Language.Sifflet.Expr
import Language.Sifflet.Util
data HaskellOptions =
HaskellOptions {optionsSoftMaxLineWidth :: Int
, optionsHardMaxLineWidth :: Int
}
deriving (Eq, Show)
defaultHaskellOptions :: HaskellOptions
defaultHaskellOptions = HaskellOptions {optionsSoftMaxLineWidth = 72,
optionsHardMaxLineWidth = 80}
exportHaskell :: HaskellOptions -> Exporter
exportHaskell _options functions path =
let header = "-- File: " ++ path ++
"\n-- Generated by the Sifflet->Haskell exporter.\n\n"
in writeFile path (header ++
hsPretty (functionsToHsModule
(pathToModuleName path)
functions))
pathToModuleName :: FilePath -> String
pathToModuleName path =
case dropExtension (takeFileName path) of
[] -> "Test"
c : cs -> toUpper c : cs
functionsToHsModule :: String -> Functions -> Module
functionsToHsModule modname (Functions fs) =
Module {moduleName = modname
, moduleExports = Nothing
, moduleImports = ImportDecl ["Data.Number.Sifflet"]
, moduleDecls = map functionToHsDecl fs
}
functionToHsDecl :: Function -> Decl
functionToHsDecl (Function mname _atypes _rtype impl) =
case (mname, impl) of
(Nothing, _) -> error "functionToHsDecl: function has no name"
(_, Primitive _) -> error "functionToHsDecl: function is primitive"
(Just fname, Compound args body) ->
Decl {declIdent = fname
, declType = Nothing
, declParams = args
, declExpr = (simplifyExpr haskellRules)
(exprToHsExpr body)}
haskellRules :: [Expr -> Expr]
haskellRules = commonRulesForSimplifyingExprs ++
[ruleIfRight, ruleRightToLeft]
exprToHsExpr :: Expr -> Expr
exprToHsExpr expr =
case expr of
EUndefined -> ESymbol (Symbol "undefined")
ESymbol _ -> expr
EBool _ -> expr
EChar _ -> expr
ENumber _ -> expr
EString _ -> expr
EIf c a b -> EIf (exprToHsExpr c) (exprToHsExpr a) (exprToHsExpr b)
EList es -> EList (map exprToHsExpr es)
ELambda x body -> ELambda x (EGroup body)
ECall (Symbol fname) args ->
case nameToHaskell fname of
Left op ->
case args of
[left, right] ->
EOp op (EGroup (exprToHsExpr left))
(EGroup (exprToHsExpr right))
_ -> error
"exprToHsExpr: operation does not have 2 operands"
Right funcName ->
ECall (Symbol funcName) (map (EGroup . exprToHsExpr) args)
_ -> errcats ["exprToHsExpr: extended expr:", show expr]
nameToHaskell :: String -> Either Operator String
nameToHaskell name =
case M.lookup name operatorTable of
Just op -> Left op
Nothing ->
Right (case name of
"zero?" -> "eqZero"
"positive?" -> "gtZero"
"negative?" -> "ltZero"
"add1" -> "succ"
"sub1" -> "pred"
_ -> name)