jacinda-0.1.0.0: src/Jacinda/Backend/Normalize.hs
-- TODO: test this module?
module Jacinda.Backend.Normalize ( compileR
, eClosed
, closedProgram
, readDigits
, readFloat
, mkI
, mkF
, mkStr
, parseAsEInt
, parseAsF
) where
import Control.Monad.State.Strict (State, evalState, gets, modify)
import Control.Recursion (cata, embed)
import qualified Data.ByteString as BS
import qualified Data.ByteString.Char8 as ASCII
import Data.Foldable (traverse_)
import qualified Data.IntMap as IM
import Data.Semigroup ((<>))
import qualified Data.Vector as V
import Intern.Name
import Intern.Unique
import Jacinda.AST
import Jacinda.Backend.Printf
import Jacinda.Regex
import Jacinda.Rename
import Jacinda.Ty.Const
mkI :: Integer -> E (T K)
mkI = IntLit tyI
mkF :: Double -> E (T K)
mkF = FloatLit tyF
mkStr :: BS.ByteString -> E (T K)
mkStr = StrLit tyStr
parseAsEInt :: BS.ByteString -> E (T K)
parseAsEInt = mkI . readDigits
parseAsF :: BS.ByteString -> E (T K)
parseAsF = FloatLit tyF . readFloat
readDigits :: BS.ByteString -> Integer
readDigits = ASCII.foldl' (\seed x -> 10 * seed + f x) 0
where f '0' = 0
f '1' = 1
f '2' = 2
f '3' = 3
f '4' = 4
f '5' = 5
f '6' = 6
f '7' = 7
f '8' = 8
f '9' = 9
f c = error (c:" is not a valid digit!")
readFloat :: BS.ByteString -> Double
readFloat = read . ASCII.unpack
-- fill in regex with compiled.
compileR :: E (T K)
-> E (T K)
compileR = cata a where -- TODO: combine with eNorm pass?
a (RegexLitF _ rr) = RegexCompiled (compileDefault rr)
a x = embed x
desugar :: a
desugar = error "Should have been desugared by this stage."
data LetCtx = LetCtx { binds :: IM.IntMap (E (T K))
, renames_ :: Renames
}
instance HasRenames LetCtx where
rename f s = fmap (\x -> s { renames_ = x }) (f (renames_ s))
mapBinds :: (IM.IntMap (E (T K)) -> IM.IntMap (E (T K))) -> LetCtx -> LetCtx
mapBinds f (LetCtx b r) = LetCtx (f b) r
type EvalM = State LetCtx
mkLetCtx :: Int -> LetCtx
mkLetCtx i = LetCtx IM.empty (Renames i IM.empty)
eClosed :: Int
-> E (T K)
-> E (T K)
eClosed i = flip evalState (mkLetCtx i) . eNorm
closedProgram :: Int
-> Program (T K)
-> E (T K)
closedProgram i (Program ds e) = flip evalState (mkLetCtx i) $
traverse_ processDecl ds *>
eNorm e
processDecl :: D (T K)
-> EvalM ()
processDecl SetFS{} = pure ()
processDecl (FunDecl (Name _ (Unique i) _) [] e) = do
e' <- eNorm e
modify (mapBinds (IM.insert i e'))
-- TODO: equality on tuples, lists
eNorm :: E (T K)
-> EvalM (E (T K))
eNorm e@Field{} = pure e
eNorm e@IntLit{} = pure e
eNorm e@FloatLit{} = pure e
eNorm e@BoolLit{} = pure e
eNorm e@StrLit{} = pure e
eNorm e@RegexLit{} = pure e
eNorm e@RegexCompiled{} = pure e
eNorm e@UBuiltin{} = pure e
eNorm e@Column{} = pure e
eNorm e@AllColumn{} = pure e
eNorm e@IParseCol{} = pure e
eNorm e@FParseCol{} = pure e
eNorm e@AllField{} = pure e
eNorm (Guarded ty pe e) = Guarded ty <$> eNorm pe <*> eNorm e
eNorm (Implicit ty e) = Implicit ty <$> eNorm e
eNorm (Lam ty n e) = Lam ty n <$> eNorm e
eNorm e@BBuiltin{} = pure e
eNorm e@TBuiltin{} = pure e
eNorm (Tup tys es) = Tup tys <$> traverse eNorm es
eNorm e@Ix{} = pure e
eNorm (EApp ty op@BBuiltin{} e) = EApp ty op <$> eNorm e
eNorm (EApp ty (EApp ty' op@(BBuiltin _ Matches) e) e') = do
eI <- eNorm e
eI' <- eNorm e'
pure $ case (eI, eI') of
(RegexCompiled re, StrLit _ str) -> BoolLit tyBool (isMatch' re str)
(StrLit _ str, RegexCompiled re) -> BoolLit tyBool (isMatch' re str)
_ -> EApp ty (EApp ty' op eI) eI'
eNorm (EApp ty (EApp ty' op@(BBuiltin _ NotMatches) e) e') = do
eI <- eNorm e
eI' <- eNorm e'
pure $ case (eI, eI') of
(RegexCompiled re, StrLit _ str) -> BoolLit tyBool (not $ isMatch' re str)
(StrLit _ str, RegexCompiled re) -> BoolLit tyBool (not $ isMatch' re str)
_ -> EApp ty (EApp ty' op eI) eI'
eNorm (EApp ty0 (EApp ty1 op@(BBuiltin (TyArr _ (TyB _ TyInteger) _) Plus) e) e') = do
eI <- eNorm e
eI' <- eNorm e'
pure $ case (eI, eI') of
(IntLit _ i, IntLit _ j) -> IntLit tyI (i+j)
_ -> EApp ty0 (EApp ty1 op eI) eI'
eNorm (EApp ty (EApp ty' op@(BBuiltin (TyArr _ (TyB _ TyStr) _) Plus) e) e') = do
eI <- eNorm e
eI' <- eNorm e'
pure $ case (eI, eI') of
(StrLit _ s, StrLit _ s') -> StrLit tyStr (s <> s')
(RegexLit _ rr, RegexLit _ rr') -> RegexLit tyStr (rr <> rr')
_ -> EApp ty (EApp ty' op eI) eI'
eNorm (EApp ty (EApp ty' op@(BBuiltin (TyArr _ (TyB _ TyInteger) _) Max) e) e') = do
eI <- eNorm e
eI' <- eNorm e'
pure $ case (eI, eI') of
(IntLit _ i, IntLit _ j) -> IntLit tyI (max i j)
_ -> EApp ty (EApp ty' op eI) eI'
eNorm (EApp ty (EApp ty' op@(BBuiltin (TyArr _ (TyB _ TyInteger) _) Min) e) e') = do
eI <- eNorm e
eI' <- eNorm e'
pure $ case (eI, eI') of
(IntLit _ i, IntLit _ j) -> IntLit tyI (min i j)
_ -> EApp ty (EApp ty' op eI) eI'
eNorm (EApp ty (EApp ty' op@(BBuiltin (TyArr _ (TyB _ TyFloat) _) Max) e) e') = do
eI <- eNorm e
eI' <- eNorm e'
pure $ case (eI, eI') of
(FloatLit _ x, FloatLit _ y) -> FloatLit tyF (max x y)
_ -> EApp ty (EApp ty' op eI) eI'
eNorm (EApp ty (EApp ty' op@(BBuiltin (TyArr _ (TyB _ TyFloat) _) Min) e) e') = do
eI <- eNorm e
eI' <- eNorm e'
pure $ case (eI, eI') of
(FloatLit _ x, FloatLit _ y) -> FloatLit tyF (min x y)
_ -> EApp ty (EApp ty' op eI) eI'
eNorm (EApp ty (EApp ty' op@(BBuiltin _ Split) e) e') = do
eI <- eNorm e
eI' <- eNorm e'
pure $ case (eI, eI') of
(StrLit l str, RegexCompiled re) -> let bss = splitBy re str in Arr l (StrLit l <$> bss) -- FIXME type of Arr (l) is wrong
_ -> EApp ty (EApp ty' op eI) eI'
eNorm (EApp ty op@(UBuiltin _ Floor) e) = do
eI <- eNorm e
pure $ case eI of
(FloatLit _ f) -> mkI (floor f)
_ -> EApp ty op eI
eNorm (EApp ty op@(UBuiltin _ Ceiling) e) = do
eI <- eNorm e
pure $ case eI of
(FloatLit _ f) -> mkI (ceiling f)
_ -> EApp ty op eI
eNorm (EApp ty0 (EApp ty1 op@(BBuiltin (TyArr _ (TyB _ TyInteger) _) Minus) e) e') = do
eI <- eNorm e
eI' <- eNorm e'
pure $ case (eI, eI') of
(IntLit _ i, IntLit _ j) -> IntLit tyI (i-j)
_ -> EApp ty0 (EApp ty1 op eI) eI'
eNorm (EApp ty (EApp ty' op@(BBuiltin (TyArr _ (TyB _ TyInteger) _) Times) e) e') = do
eI <- eNorm e
eI' <- eNorm e'
pure $ case (eI, eI') of
(IntLit _ i, IntLit _ j) -> IntLit tyI (i*j)
_ -> EApp ty (EApp ty' op eI) eI'
eNorm (EApp ty (EApp ty' op@(BBuiltin (TyArr _ (TyB _ TyFloat) _) Plus) e) e') = do
eI <- eNorm e
eI' <- eNorm e'
pure $ case (eI, eI') of
(FloatLit _ i, FloatLit _ j) -> FloatLit tyF (i+j)
_ -> EApp ty (EApp ty' op eI) eI'
eNorm (EApp ty (EApp ty' op@(BBuiltin (TyArr _ (TyB _ TyFloat) _) Minus) e) e') = do
eI <- eNorm e
eI' <- eNorm e'
pure $ case (eI, eI') of
(FloatLit _ i, FloatLit _ j) -> FloatLit tyF (i-j)
_ -> EApp ty (EApp ty' op eI) eI'
eNorm (EApp ty (EApp ty' op@(BBuiltin (TyArr _ (TyB _ TyFloat) _) Times) e) e') = do
eI <- eNorm e
eI' <- eNorm e'
pure $ case (eI, eI') of
(FloatLit _ i, FloatLit _ j) -> FloatLit tyF (i*j)
_ -> EApp ty (EApp ty' op eI) eI'
eNorm (EApp ty (EApp ty' op@(BBuiltin (TyArr _ (TyB _ TyFloat) _) Div) e) e') = do
eI <- eNorm e
eI' <- eNorm e'
pure $ case (eI, eI') of
(FloatLit _ i, FloatLit _ j) -> FloatLit tyF (i/j)
_ -> EApp ty (EApp ty' op eI) eI'
eNorm (EApp ty (UBuiltin ty' Tally) e) = do
eI <- eNorm e
pure $ case eI of
StrLit _ str -> IntLit tyI (fromIntegral $ BS.length str)
_ -> EApp ty (UBuiltin ty' Tally) eI
eNorm (EApp ty (EApp ty' op@(BBuiltin (TyArr _ (TyB _ TyStr) _) Eq) e) e') = do
eI <- eNorm e
eI' <- eNorm e'
pure $ case (eI, eI') of
(StrLit _ i, StrLit _ j) -> BoolLit tyBool (i == j)
_ -> EApp ty (EApp ty' op eI) eI'
eNorm (EApp ty (EApp ty' op@(BBuiltin (TyArr _ (TyB _ TyInteger) _) Lt) e) e') = do
eI <- eNorm e
eI' <- eNorm e'
pure $ case (eI, eI') of
(IntLit _ i, IntLit _ j) -> BoolLit tyBool (i < j)
_ -> EApp ty (EApp ty' op eI) eI'
eNorm (EApp ty (EApp ty' op@(BBuiltin (TyArr _ (TyB _ TyInteger) _) Gt) e) e') = do
eI <- eNorm e
eI' <- eNorm e'
pure $ case (eI, eI') of
(IntLit _ i, IntLit _ j) -> BoolLit tyBool (i > j)
_ -> EApp ty (EApp ty' op eI) eI'
eNorm (EApp ty (EApp ty' op@(BBuiltin (TyArr _ (TyB _ TyInteger) _) Eq) e) e') = do
eI <- eNorm e
eI' <- eNorm e'
pure $ case (eI, eI') of
(IntLit _ i, IntLit _ j) -> BoolLit tyBool (i == j)
_ -> EApp ty (EApp ty' op eI) eI'
eNorm (EApp ty (EApp ty' op@(BBuiltin (TyArr _ (TyB _ TyInteger) _) Neq) e) e') = do
eI <- eNorm e
eI' <- eNorm e'
pure $ case (eI, eI') of
(IntLit _ i, IntLit _ j) -> BoolLit tyBool (i /= j)
_ -> EApp ty (EApp ty' op eI) eI'
eNorm (EApp ty (EApp ty' op@(BBuiltin (TyArr _ (TyB _ TyInteger) _) Leq) e) e') = do
eI <- eNorm e
eI' <- eNorm e'
pure $ case (eI, eI') of
(IntLit _ i, IntLit _ j) -> BoolLit tyBool (i <= j)
_ -> EApp ty (EApp ty' op eI) eI'
eNorm (EApp ty (EApp ty' op@(BBuiltin (TyArr _ (TyB _ TyInteger) _) Geq) e) e') = do
eI <- eNorm e
eI' <- eNorm e'
pure $ case (eI, eI') of
(IntLit _ i, IntLit _ j) -> BoolLit tyBool (i >= j)
_ -> EApp ty (EApp ty' op eI) eI'
eNorm (EApp ty (EApp ty' op@(BBuiltin (TyArr _ (TyB _ TyFloat) _) Eq) e) e') = do
eI <- eNorm e
eI' <- eNorm e'
pure $ case (eI, eI') of
(FloatLit _ i, FloatLit _ j) -> BoolLit tyBool (i == j)
_ -> EApp ty (EApp ty' op eI) eI'
eNorm (EApp ty (EApp ty' op@(BBuiltin (TyArr _ (TyB _ TyFloat) _) Neq) e) e') = do
eI <- eNorm e
eI' <- eNorm e'
pure $ case (eI, eI') of
(FloatLit _ i, FloatLit _ j) -> BoolLit tyBool (i /= j)
_ -> EApp ty (EApp ty' op eI) eI'
eNorm (EApp ty (EApp ty' op@(BBuiltin (TyArr _ (TyB _ TyFloat) _) Leq) e) e') = do
eI <- eNorm e
eI' <- eNorm e'
pure $ case (eI, eI') of
(FloatLit _ i, FloatLit _ j) -> BoolLit tyBool (i <= j)
_ -> EApp ty (EApp ty' op eI) eI'
eNorm (EApp ty (EApp ty' op@(BBuiltin (TyArr _ (TyB _ TyFloat) _) Geq) e) e') = do
eI <- eNorm e
eI' <- eNorm e'
pure $ case (eI, eI') of
(FloatLit _ i, FloatLit _ j) -> BoolLit tyBool (i >= j)
_ -> EApp ty (EApp ty' op eI) eI'
eNorm (EApp ty (EApp ty' op@(BBuiltin (TyArr _ (TyB _ TyFloat) _) Gt) e) e') = do
eI <- eNorm e
eI' <- eNorm e'
pure $ case (eI, eI') of
(FloatLit _ i, FloatLit _ j) -> BoolLit tyBool (i > j)
_ -> EApp ty (EApp ty' op eI) eI'
eNorm (EApp ty (EApp ty' op@(BBuiltin (TyArr _ (TyB _ TyFloat) _) Lt) e) e') = do
eI <- eNorm e
eI' <- eNorm e'
pure $ case (eI, eI') of
(FloatLit _ i, FloatLit _ j) -> BoolLit tyBool (i < j)
_ -> EApp ty (EApp ty' op eI) eI'
eNorm (EApp ty (EApp ty' op@(BBuiltin (TyArr _ (TyB _ TyStr) _) Neq) e) e') = do
eI <- eNorm e
eI' <- eNorm e'
pure $ case (eI, eI') of
(StrLit _ i, StrLit _ j) -> BoolLit tyBool (i /= j)
_ -> EApp ty (EApp ty' op eI) eI'
eNorm (EApp ty0 (EApp ty1 op@(BBuiltin _ And) e) e') = do
eI <- eNorm e
eI' <- eNorm e'
pure $ case (eI, eI') of
(BoolLit _ b, BoolLit _ b') -> BoolLit tyBool (b && b')
_ -> EApp ty0 (EApp ty1 op eI) eI'
eNorm (EApp ty0 (EApp ty1 op@(BBuiltin _ Or) e) e') = do
eI <- eNorm e
eI' <- eNorm e'
pure $ case (eI, eI') of
(BoolLit _ b, BoolLit _ b') -> BoolLit tyBool (b || b')
_ -> EApp ty0 (EApp ty1 op eI) eI'
eNorm (EApp _ (EApp _ (UBuiltin _ Const) e) _) = eNorm e
eNorm (EApp ty op@(UBuiltin _ Const) e) = EApp ty op <$> eNorm e
eNorm (EApp ty op@(UBuiltin _ (At i)) e) = do
eI <- eNorm e
pure $ case eI of
(Arr _ es) -> es V.! (i-1)
_ -> EApp ty op eI
eNorm (EApp ty op@(UBuiltin _ Not) e) = do
eI <- eNorm e
pure $ case eI of
(BoolLit _ b) -> BoolLit tyBool (not b)
_ -> EApp ty op eI
eNorm (EApp ty op@(UBuiltin _ IParse) e) = do
eI <- eNorm e
pure $ case eI of
(StrLit _ str) -> parseAsEInt str
_ -> EApp ty op eI
eNorm (EApp ty op@(UBuiltin _ FParse) e) = do
eI <- eNorm e
pure $ case eI of
(StrLit _ str) -> parseAsF str
_ -> EApp ty op eI
eNorm Dfn{} = desugar
eNorm ResVar{} = desugar
eNorm (Let _ (Name _ (Unique i) _, b) e) = do
b' <- eNorm b
modify (mapBinds (IM.insert i b'))
eNorm e
eNorm e@(Var _ (Name _ (Unique i) _)) = do
st <- gets binds
case IM.lookup i st of
Just e'@Var{} -> eNorm e' -- no cyclic binds!!
Just e' -> renameE e'
Nothing -> pure e -- default to e in case var was bound in a lambda
eNorm (EApp ty e@Var{} e') = eNorm =<< (EApp ty <$> eNorm e <*> pure e')
eNorm (EApp _ (Lam _ (Name _ (Unique i) _) e) e') = do
e'' <- eNorm e'
modify (mapBinds (IM.insert i e''))
eNorm e
eNorm (EApp ty0 (EApp ty1 (EApp ty2 (TBuiltin ty3 Substr) e0) e1) e2) = do
e0' <- eNorm e0
e1' <- eNorm e1
e2' <- eNorm e2
pure $ case (e0', e1', e2') of
(StrLit _ str, IntLit _ i, IntLit _ j) -> mkStr (substr str (fromIntegral i) (fromIntegral j))
_ -> EApp ty0 (EApp ty1 (EApp ty2 (TBuiltin ty3 Substr) e0') e1') e2'
eNorm (EApp ty0 (EApp ty1 op@(BBuiltin _ Sprintf) e) e') = do
eI <- eNorm e
eI' <- eNorm e'
case (eI, eI') of
(StrLit _ fmt, _) | isReady eI' -> pure $ mkStr $ sprintf fmt eI'
_ -> EApp ty0 (EApp ty1 op eI) <$> eNorm e'
eNorm (EApp ty0 (EApp ty1 (EApp ty2 op@TBuiltin{} f) x) y) = EApp ty0 <$> (EApp ty1 <$> (EApp ty2 op <$> eNorm f) <*> eNorm x) <*> eNorm y
eNorm (EApp ty0 (EApp ty1 op@(BBuiltin _ Prior) x) y) = EApp ty0 <$> (EApp ty1 op <$> eNorm x) <*> eNorm y
eNorm (EApp ty0 (EApp ty1 op@(BBuiltin _ Map) x) y) = EApp ty0 <$> (EApp ty1 op <$> eNorm x) <*> eNorm y
eNorm (EApp ty0 (EApp ty1 op@(BBuiltin _ Filter) x) y) = EApp ty0 <$> (EApp ty1 op <$> eNorm x) <*> eNorm y
-- FIXME: this will almost surely run into trouble; if the above pattern matches
-- are not complete it will bottom!
eNorm (EApp ty e@EApp{} e') =
eNorm =<< (EApp ty <$> eNorm e <*> pure e')
eNorm (Arr ty es) = Arr ty <$> traverse eNorm es