{-# LANGUAGE DataKinds, DeriveFunctor, DeriveFoldable, DeriveTraversable, FlexibleContexts, FlexibleInstances, PatternSynonyms, TemplateHaskell, TypeOperators, ViewPatterns #-} module Formura.OrthotopeMachine.Translate where import Algebra.Lattice import Control.Applicative import Control.Lens hiding (op) import Control.Monad import Control.Monad.Reader import qualified Data.IntMap as G import qualified Data.Map as M import qualified Data.Set as S import Data.Ratio import Text.Trifecta (failed, raiseErr) import Formura.Language.Combinator import qualified Formura.Annotation as A import Formura.Annotation.Representation import Formura.Compiler import Formura.Syntax import Formura.Type import Formura.Vec import Formura.OrthotopeMachine.Graph type Binding = M.Map IdentName ValueExpr type LexBinding = M.Map IdentName ValueLexExpr class HasBinding s where binding :: Lens' s Binding instance HasBinding Binding where binding = simple data CodegenState = CodegenState { _codegenSyntacticState :: CompilerSyntacticState , _theGraph :: Graph } makeClassy ''CodegenState defaultCodegenState :: CodegenState defaultCodegenState = CodegenState { _codegenSyntacticState = defaultCompilerSyntacticState{ _compilerStage = "codegen"} , _theGraph = G.empty } defaultCodegenRead :: Binding defaultCodegenRead = M.empty instance HasCompilerSyntacticState CodegenState where compilerSyntacticState = codegenSyntacticState -- | the code generator monad. type GenM = CompilerMonad Binding () CodegenState type LexGenM = CompilerMonad LexBinding () CodegenState class Generatable f where gen :: f (GenM ValueExpr) -> GenM ValueExpr freeNodeID :: GenM NodeID freeNodeID = do g <- use theGraph return $ G.size g insert :: OMInstF NodeID -> NodeType -> GenM ValueExpr insert inst typ = do n0 <- freeNodeID foc <- use compilerFocus let a = case foc of Just meta -> A.singleton meta Nothing -> A.empty theGraph %= G.insert n0 (Node inst typ a) mmeta <- use compilerFocus case mmeta of Just meta -> theGraph . ix n0 . A.annotation %= A.set meta _ -> return () return $ NodeValue n0 typ -- | Find the type of a 'ValueExpr' . typeOfVal :: ValueExpr -> TypeExpr typeOfVal (Imm _) = ElemType "Rational" typeOfVal (NodeValue _ t) = subFix t typeOfVal (FunValue _ _) = FunType typeOfVal (Tuple xs) = Tuple $ map typeOfVal xs -- | convert a value to other value, so that the result may have the given type castVal :: TypeExpr -> ValueExpr -> GenM ValueExpr castVal t1 vx = let t0 = typeOfVal vx in case (t1, t0, vx) of _ | t1 == t0 -> return vx (ElemType _, ElemType _, _) -> return vx (GridType vec (ElemType te), ElemType _, n :. _) -> return (n :. (GridType vec (ElemType te))) (GridType vec0 _, GridType vec1 _, _) | vec0 == vec1 -> return vx _ -> raiseErr $ failed $ "cannot convert type " ++ show t0 ++ " to " ++ show t1 instance Generatable ImmF where gen (Imm r) = do insert (Imm r) (ElemType "Rational") instance Generatable OperatorF where gen (Uniop op gA) = do a <- gA ; goUniop op a gen (Binop op gA gB) = do a <- gA; b <- gB ; goBinop op a b gen (Triop op gA gB gC) = do a <- gA; b <- gB; c <- gC; goTriop op a b c goUniop :: IdentName -> ValueExpr -> GenM ValueExpr goUniop op (av :. at) = insert (Uniop op av) at goUniop _ _ = raiseErr $ failed $ "unimplemented path in unary operator" goBinop :: IdentName -> ValueExpr -> ValueExpr -> GenM ValueExpr goBinop op ax@(av :. at) bx@(bv :. bt) = case at /\ bt of TopType -> raiseErr $ failed $ unwords ["there is no common type that can accomodate both hand side:", show at, op , show bt] ct -> do (av2 :. _) <- castVal (subFix ct) ax (bv2 :. _) <- castVal (subFix ct) bx insert (Binop op av2 bv2) ct goBinop _ _ _ = raiseErr $ failed $ "unimplemented path in binary operator" goTriop :: IdentName -> ValueExpr -> ValueExpr -> ValueExpr -> GenM ValueExpr goTriop op (av :. at) (bv :. bt) (cv :. ct) | op == "ite" && at == ElemType "bool" && bt == ct = insert (Triop op av bv cv) bt goTriop _ _ _ _ = raiseErr $ failed $ "unimplemented path in trinary operator" instance Generatable IdentF where -- you should not generate this! gen (Ident n) = do b <- view binding case M.lookup n b of Nothing -> do raiseErr $ failed $ "undefined variable: " ++ n ++ "\n Bindings:\n" ++ show b Just x -> return $ subFix x instance Generatable TupleF where gen (Tuple xsGen) = do xs <- sequence xsGen return $ Tuple xs instance Generatable GridF where gen (Grid npks gen0) = do vt0@(val0 :. typ0) <- gen0 case typ0 of ElemType _ -> return vt0 GridType offs0 etyp0 -> do let patK = fmap (^. _2) (npks :: Vec NPlusK) newPos = offs0 - patK intOff = fmap floor newPos newOff = liftA2 (\r n -> r - fromIntegral n) newPos intOff typ1 = GridType newOff etyp0 if intOff == 0 then return (val0 :. typ1) else insert (Shift intOff val0) typ1 gen _ = raiseErr $ failed "unexpected happened in gen of grid" instance Generatable ApplyF where gen (Apply fgen agen) = do f0 <- fgen a0 <- agen goApply f0 a0 goApply :: ValueExpr -> ValueExpr -> GenM ValueExpr goApply (Tuple xs) (Imm r) = do when (denominator r /= 1) $ raiseErr $ failed "non-integer indexing in tuple access" let n = fromInteger $ numerator r l = length xs when (n < 0 || n >= l) $ raiseErr $ failed "tuple access out of bounds" return $ xs!!n goApply (Tuple xs) _ = raiseErr $ failed "tuple applied to non-constant integer" goApply (FunValue l r) x = do local (M.insert (nameOfLhs l) x) $ genRhs r goApply _ _ = raiseErr $ failed "unexpected combination of application" instance Generatable LambdaF where -- Expand all but bound variables, in order to implement lexical scope gen (Lambda l r) = do let conv :: Binding -> CodegenState -> (LexBinding, CodegenState) conv b s = (M.insert (nameOfLhs l) (Ident $ nameOfLhs l) $ M.map subFix b, s) r' <- withCompiler conv $ resolveLex $ subFix r return $ FunValue l r' resolveLex :: RXExpr -> LexGenM RXExpr resolveLex r = compilerMFold resolveLexAlg r resolveLexAlg :: RXExprF RXExpr -> LexGenM RXExpr resolveLexAlg (Ident n) = do b <- ask case M.lookup n b of Nothing -> raiseErr $ failed $ "undefined variable: " ++ n Just x -> return $ subFix x resolveLexAlg (Lambda l r) = do r' <- local (M.insert (nameOfLhs l) (Ident $ nameOfLhs l)) $ resolveLex $ subFix r return $ FunValue l r' resolveLexAlg (FunValue l r) = do r' <- local (M.insert (nameOfLhs l) (Ident $ nameOfLhs l)) $ resolveLex r return $ FunValue l r' resolveLexAlg fx = mTransAlg fx instance Generatable LetF where gen (Let b genX) = withBindings b genX nameOfLhs :: LExpr -> IdentName nameOfLhs (Ident n) = n nameOfLhs (Grid _ x) = nameOfLhs x nameOfLhs (Vector _ x) = nameOfLhs x nameOfLhs _ = error "tuple unsupported in type decl" withBindings :: BindingF (GenM ValueExpr) -> GenM ValueExpr -> GenM ValueExpr withBindings b1 genX = do b0 <- view binding let BindingF stmts0 = b1 typeDecls0 :: [(LExpr, TypeExpr)] typeDecls0 = concat $ flip map stmts0 $ \x -> case x of TypeDeclF t l -> [(l, t)] _ -> [] substs0 :: [(LExpr, GenM ValueExpr)] substs0 = concat $ flip map stmts0 $ \x -> case x of SubstF l r -> [(l, r)] _ -> [] typeDict :: M.Map IdentName TypeExpr typeDict = M.fromList [(nameOfLhs l, t) | (l,t)<- typeDecls0] let -- Let bindings enter scope one by one, not simultaneously graduallyBind :: [(LExpr, GenM ValueExpr)] -> GenM [(IdentName, ValueExpr)] graduallyBind [] = return [] graduallyBind ((l,genV): restOfBinds) = do v0 <- genV v <- case M.lookup (nameOfLhs l) typeDict of Nothing -> return v0 Just t -> castVal t v0 case v of (n :. _) -> do theGraph . ix n . A.annotation %= A.set (SourceName $ nameOfLhs l) theGraph . ix n . A.annotation %= A.set Manifest _ -> return () -- TODO: LHS grid pattern must be taken care of. b2s <- local (binding %~ M.insert (nameOfLhs l) v) $ graduallyBind restOfBinds return ((nameOfLhs l, v) : b2s) substs1 <- graduallyBind substs0 -- M.union prefers left-hand-side when duplicate keys are encountered local (binding %~ M.union (M.fromList substs1)) genX instance Generatable (Sum '[]) where gen _ = raiseErr $ failed "impossible happened: gen of Void" instance Generatable NodeValueF where gen (NodeValue t v) = return (NodeValue t v) instance Generatable FunValueF where gen (FunValue l r) = return (FunValue l r) instance (Generatable f, Generatable (Sum fs)) => Generatable (Sum (f ': fs)) where gen = gen +:: gen genRhs :: RXExpr -> GenM ValueExpr genRhs r = compilerFoldout gen r genMainFunction :: RExpr -> GenM () genMainFunction (Lambda l r) = do v <- insert (Load "input_value") (GridType (Vec [0]) (ElemType "double")) let (n :. _ ) = v theGraph . ix n . A.annotation %= A.set Manifest (n99 :. t99) <- genRhs $ Apply (FunValue l (subFix r)) (subFix v) theGraph . ix n99 . A.annotation %= A.set Manifest return () genMainFunction _ = raiseErr $ failed "Please specify a function for generation"