module Language.Desugar where
import Language.Ast
import Language.Error (errorInMappy)
import Data.Char (ord)
import qualified Data.Map.Strict as M
desugarEachDef :: Definition -> Definition
desugarEachDef (DefSugar sugared) = desugarDef sugared
desugarEachDef (MappyDef name body) = MappyDef name $ desugarExpr body
desugarDef :: SugaredDefinition -> Definition
desugarDef (SugaredFnDefinition name args body) = MappyDef name $ MappyLambda args $ desugarExpr body
desugarExpr :: Expression -> Expression
desugarExpr (ExprSugar (SugaredLet defs body)) =
let
defs' = map desugarEachDef defs
body' = desugarExpr body
in
defsToLambda defs' body'
desugarExpr (ExprSugar (SugaredList [])) = MappyNamedValue "nil"
desugarExpr (ExprSugar (SugaredList (v:vs))) =
MappyApp (MappyNamedValue "cons") [desugarExpr v, desugarExpr $ ExprSugar $ SugaredList vs]
desugarExpr (ExprSugar (SugaredString str)) =
desugarExpr $ ExprSugar $ SugaredList $ map (desugarExpr . ExprSugar . SugaredChar) str
desugarExpr (ExprSugar (SugaredChar c)) =
mappyNat (ord c) $ M.singleton (MappyKeyword "__type") (MappyKeyword "char")
desugarExpr (MappyMap (StandardMap map')) = MappyMap $ StandardMap $ M.fromList $ map go $ M.toList map'
where
go (expr1, expr2) = (desugarExpr expr1, desugarExpr expr2)
desugarExpr (MappyApp fn args) = MappyApp (desugarExpr fn) $ map desugarExpr args
desugarExpr (MappyLambda args body) = MappyLambda (map desugarExpr args) $ desugarExpr body
desugarExpr expr = expr
mappyNat :: Int -> M.Map Expression Expression -> Expression
mappyNat 0 extra = MappyMap $ StandardMap extra
mappyNat n extra = MappyMap $ StandardMap $ M.insert (MappyKeyword "pred") (mappyNat (n 1 ) extra) extra
defsToLambda :: [Definition] -> Expression -> Expression
defsToLambda [] expr =
expr
defsToLambda (MappyDef name value:rest) expr =
MappyApp (MappyLambda [name] $ defsToLambda rest expr) [value]
defsToLambda (DefSugar _:_) _ = errorInMappy "A sugared def escaped to let."