Jikka 5.2.0.0 → 5.3.0.0
raw patch · 46 files changed
+1411/−1137 lines, 46 files
Files
- CHANGELOG.md +4/−0
- Jikka.cabal +6/−4
- README.md +3/−0
- src/Jikka/CPlusPlus/Convert.hs +4/−2
- src/Jikka/CPlusPlus/Convert/FromCore.hs +249/−346
- src/Jikka/CPlusPlus/Convert/InlineSetAt.hs +59/−0
- src/Jikka/CPlusPlus/Convert/MoveSemantics.hs +44/−15
- src/Jikka/CPlusPlus/Convert/OptimizeRange.hs +1/−1
- src/Jikka/CPlusPlus/Convert/UseInitialization.hs +1/−1
- src/Jikka/CPlusPlus/Format.hs +1/−0
- src/Jikka/CPlusPlus/Language/Expr.hs +2/−0
- src/Jikka/CPlusPlus/Language/Util.hs +55/−19
- src/Jikka/Common/Error.hs +6/−0
- src/Jikka/Common/Matrix.hs +2/−2
- src/Jikka/Core/Convert.hs +2/−2
- src/Jikka/Core/Convert/ArithmeticExpr.hs +51/−0
- src/Jikka/Core/Convert/ArithmeticalExpr.hs +0/−51
- src/Jikka/Core/Convert/CloseAll.hs +7/−7
- src/Jikka/Core/Convert/ConstantFolding.hs +5/−5
- src/Jikka/Core/Convert/ConvexHullTrick.hs +34/−33
- src/Jikka/Core/Convert/CumulativeSum.hs +5/−5
- src/Jikka/Core/Convert/KubaruToMorau.hs +5/−5
- src/Jikka/Core/Convert/MakeScanl.hs +7/−7
- src/Jikka/Core/Convert/MatrixExponentiation.hs +12/−12
- src/Jikka/Core/Convert/RemoveUnusedVars.hs +2/−2
- src/Jikka/Core/Convert/ShortCutFusion.hs +3/−3
- src/Jikka/Core/Convert/TypeInfer.hs +35/−19
- src/Jikka/Core/Evaluate.hs +1/−1
- src/Jikka/Core/Format.hs +55/−52
- src/Jikka/Core/Language/ArithmeticExpr.hs +282/−0
- src/Jikka/Core/Language/ArithmeticalExpr.hs +0/−277
- src/Jikka/Core/Language/Expr.hs +4/−2
- src/Jikka/Core/Language/TypeCheck.hs +5/−2
- src/Jikka/Core/Language/Util.hs +21/−26
- src/Jikka/Core/Parse/Alex.x +3/−8
- src/Jikka/Core/Parse/Happy.y +54/−55
- src/Jikka/Core/Parse/Token.hs +1/−6
- src/Jikka/Main.hs +11/−4
- src/Jikka/Main/Subcommand/Convert.hs +52/−32
- test/Jikka/CPlusPlus/Convert/MoveSemanticsSpec.hs +127/−3
- test/Jikka/Core/Convert/ConvexHullTrickSpec.hs +105/−0
- test/Jikka/Core/Convert/MatrixExponentiationSpec.hs +28/−60
- test/Jikka/Core/FormatSpec.hs +4/−5
- test/Jikka/Core/Language/ArithmeticExprSpec.hs +29/−0
- test/Jikka/Core/Language/ArithmeticalExprSpec.hs +0/−29
- test/Jikka/RestrictedPython/Convert/ToCoreSpec.hs +24/−34
CHANGELOG.md view
@@ -1,5 +1,9 @@ # Changelog for Jikka +## 2021-08-16: v5.3.0.0++Many bugs are removed.+ ## 2021-08-07: v5.2.0.0 Now we are fixing many bugs to use Jikka during contests!
Jikka.cabal view
@@ -5,7 +5,7 @@ -- see: https://github.com/sol/hpack name: Jikka-version: 5.2.0.0+version: 5.3.0.0 synopsis: A transpiler from Python to C++ for competitive programming description: Please see the README on GitHub at <https://github.com/kmyk/Jikka> category: Compilers/Interpreters@@ -65,7 +65,7 @@ Jikka.Core.Convert Jikka.Core.Convert.Alpha Jikka.Core.Convert.ANormal- Jikka.Core.Convert.ArithmeticalExpr+ Jikka.Core.Convert.ArithmeticExpr Jikka.Core.Convert.Beta Jikka.Core.Convert.BubbleLet Jikka.Core.Convert.CloseAll@@ -91,7 +91,7 @@ Jikka.Core.Convert.UnpackTuple Jikka.Core.Evaluate Jikka.Core.Format- Jikka.Core.Language.ArithmeticalExpr+ Jikka.Core.Language.ArithmeticExpr Jikka.Core.Language.Beta Jikka.Core.Language.BuiltinPatterns Jikka.Core.Language.Expr@@ -112,6 +112,7 @@ Jikka.CPlusPlus.Convert.AddMain Jikka.CPlusPlus.Convert.BundleRuntime Jikka.CPlusPlus.Convert.FromCore+ Jikka.CPlusPlus.Convert.InlineSetAt Jikka.CPlusPlus.Convert.MoveSemantics Jikka.CPlusPlus.Convert.OptimizeRange Jikka.CPlusPlus.Convert.UnpackTuples@@ -236,6 +237,7 @@ Jikka.Core.Convert.CloseSumSpec Jikka.Core.Convert.ConstantFoldingSpec Jikka.Core.Convert.ConstantPropagationSpec+ Jikka.Core.Convert.ConvexHullTrickSpec Jikka.Core.Convert.EtaSpec Jikka.Core.Convert.MakeScanlSpec Jikka.Core.Convert.MatrixExponentiationSpec@@ -248,7 +250,7 @@ Jikka.Core.Convert.UnpackTupleSpec Jikka.Core.EvaluateSpec Jikka.Core.FormatSpec- Jikka.Core.Language.ArithmeticalExprSpec+ Jikka.Core.Language.ArithmeticExprSpec Jikka.Core.Language.BetaSpec Jikka.Core.ParseSpec Jikka.CPlusPlus.Convert.FromCoreSpec
README.md view
@@ -73,6 +73,9 @@ - 実装方針について - [docs/internal.ja.md](https://github.com/kmyk/Jikka/blob/master/docs/internal.ja.md) (Japanese) - 具体的な処理の流れについて+- [docs/core.md](https://github.com/kmyk/Jikka/blob/master/docs/core.md)+ - [docs/core.ja.md](https://github.com/kmyk/Jikka/blob/master/docs/core.ja.md) (Japanese)+ - core 言語の説明 - [Haddock](https://hackage.haskell.org/package/Jikka) - [Haddock (master)](https://kmyk.github.io/Jikka/haddock)
src/Jikka/CPlusPlus/Convert.hs view
@@ -7,6 +7,7 @@ import qualified Jikka.CPlusPlus.Convert.AddMain as AddMain import qualified Jikka.CPlusPlus.Convert.FromCore as FromCore+import qualified Jikka.CPlusPlus.Convert.InlineSetAt as InlineSetAt import qualified Jikka.CPlusPlus.Convert.MoveSemantics as MoveSemantics import qualified Jikka.CPlusPlus.Convert.OptimizeRange as OptimizeRange import qualified Jikka.CPlusPlus.Convert.UnpackTuples as UnpackTuples@@ -17,7 +18,7 @@ import Jikka.Common.IOFormat import qualified Jikka.Core.Language.Expr as X -run :: (MonadAlpha m, MonadError Error m) => X.Program -> IOFormat -> m Y.Program+run :: (MonadAlpha m, MonadError Error m) => X.Program -> Maybe IOFormat -> m Y.Program run prog format = do prog <- FromCore.run prog let go prog = do@@ -26,6 +27,7 @@ OptimizeRange.run prog prog <- go prog prog <- go prog+ prog <- InlineSetAt.run prog prog <- go prog- prog <- AddMain.run prog format+ prog <- maybe (return prog) (AddMain.run prog) format UseInitialization.run prog
src/Jikka/CPlusPlus/Convert/FromCore.hs view
@@ -1,4 +1,5 @@ {-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE FlexibleInstances #-} {-# LANGUAGE LambdaCase #-} {-# LANGUAGE OverloadedStrings #-} @@ -17,6 +18,7 @@ ) where +import Control.Monad.Writer.Strict import qualified Jikka.CPlusPlus.Language.Expr as Y import qualified Jikka.CPlusPlus.Language.Util as Y import Jikka.Common.Alpha@@ -24,6 +26,7 @@ import qualified Jikka.Core.Format as X (formatBuiltinIsolated, formatType) import qualified Jikka.Core.Language.BuiltinPatterns as X import qualified Jikka.Core.Language.Expr as X+import qualified Jikka.Core.Language.LambdaPatterns as X import qualified Jikka.Core.Language.TypeCheck as X import qualified Jikka.Core.Language.Util as X @@ -43,6 +46,20 @@ Just y -> return y Nothing -> throwInternalError $ "undefined variable: " ++ X.unVarName x +class Monad m => MonadStatements m where+ useStatement :: Y.Statement -> m ()++instance Monad m => MonadStatements (WriterT (Dual [Y.Statement]) m) where+ useStatement stmt = tell $ Dual [stmt]++useStatements :: MonadStatements m => [Y.Statement] -> m ()+useStatements = mapM_ useStatement++runStatementsT :: Monad m => WriterT (Dual [Y.Statement]) m a -> m ([Y.Statement], a)+runStatementsT f = do+ (a, stmts) <- runWriterT f+ return (reverse (getDual stmts), a)+ -------------------------------------------------------------------------------- -- run @@ -74,7 +91,7 @@ runLiteral :: (MonadAlpha m, MonadError Error m) => Env -> X.Literal -> m Y.Expr runLiteral env = \case X.LitBuiltin builtin ts -> do- (stmts, e) <- runAppBuiltin env builtin ts []+ (stmts, e) <- runStatementsT $ runAppBuiltin env builtin ts [] case stmts of [] -> return e _ -> throwInternalError "now builtin values don't use statements"@@ -101,89 +118,146 @@ X.Proj _ -> return 1 builtin -> length . fst . X.uncurryFunTy <$> X.builtinToType builtin ts -runAppBuiltin :: (MonadAlpha m, MonadError Error m) => Env -> X.Builtin -> [X.Type] -> [X.Expr] -> m ([Y.Statement], Y.Expr)+runIterate :: (MonadStatements m, MonadAlpha m, MonadError Error m) => Env -> X.Type -> X.Expr -> X.Expr -> X.Expr -> m Y.Expr+runIterate env t n f x = do+ t <- runType t+ n <- runExpr env n+ x <- runExpr env x+ y <- Y.newFreshName Y.LocalNameKind+ i <- Y.newFreshName Y.LoopCounterNameKind+ (stmtsF, body, f) <- runExprFunction env f (Y.Var y)+ useStatement $ Y.Declare t y (Y.DeclareCopy x)+ useStatements stmtsF+ useStatement $ Y.repStatement i (Y.cast Y.TyInt32 n) (body ++ [Y.assignSimple y f])+ return $ Y.Var y++runIf :: (MonadStatements m, MonadAlpha m, MonadError Error m) => Env -> X.Type -> X.Expr -> X.Expr -> X.Expr -> m Y.Expr+runIf env t e1 e2 e3 = do+ e1' <- runExpr env e1+ (stmts2, e2') <- runStatementsT $ runExpr env e2+ (stmts3, e3') <- runStatementsT $ runExpr env e3+ case (stmts2, stmts3) of+ ([], [])+ | X.isConstantTimeExpr e2 && X.isConstantTimeExpr e3 ->+ return $ Y.Cond e1' e2' e3'+ _ -> do+ t <- runType t+ phi <- Y.newFreshName Y.LocalNameKind+ let assign = Y.Assign . Y.AssignExpr Y.SimpleAssign (Y.LeftVar phi)+ useStatement $ Y.Declare t phi Y.DeclareDefault+ useStatement $ Y.If e1' (stmts2 ++ [assign e2']) (Just (stmts3 ++ [assign e3']))+ return $ Y.Var phi++runFoldl :: (MonadStatements m, MonadAlpha m, MonadError Error m) => Env -> X.Type -> X.Type -> X.Expr -> X.Expr -> X.Expr -> m Y.Expr+runFoldl env t1 t2 f init xs = do+ init <- runExpr env init+ xs <- runExpr env xs+ t1 <- runType t1+ t2 <- runType t2+ y <- Y.newFreshName Y.LocalNameKind+ x <- Y.newFreshName Y.LocalNameKind+ (stmtsF, body, f) <- runExprFunction2 env f (Y.Var y) (Y.Var x)+ useStatement $ Y.Declare t2 y (Y.DeclareCopy init)+ useStatements stmtsF+ useStatement $ Y.ForEach t1 x xs (body ++ [Y.assignSimple y f])+ return $ Y.Var y++runMap :: (MonadStatements m, MonadAlpha m, MonadError Error m) => Env -> X.Type -> X.Type -> X.Expr -> X.Expr -> m Y.Expr+runMap env _ t2 f xs = do+ ys <- Y.newFreshName Y.LocalNameKind+ t2 <- runType t2+ case (f, xs) of+ -- optimize @map (const e) xs@+ (X.LamConst _ e, xs) -> do+ xs <- runExpr env xs+ e <- runExpr env e+ useStatement $ Y.Declare (Y.TyVector t2) ys (Y.DeclareCopy (Y.vecCtor t2 [Y.size xs, e]))+ return $ Y.Var ys+ -- other cases+ _ -> do+ xs <- runExpr env xs+ i <- Y.newFreshName Y.LoopCounterNameKind+ (stmtsF, body, f) <- runExprFunction env f (Y.at xs (Y.Var i))+ useStatement $ Y.Declare (Y.TyVector t2) ys (Y.DeclareCopy (Y.vecCtor t2 [Y.size xs]))+ useStatements stmtsF+ useStatement $ Y.repStatement i (Y.cast Y.TyInt32 (Y.size xs)) (body ++ [Y.assignAt ys (Y.Var i) f])+ return $ Y.Var ys++runAppBuiltin :: (MonadStatements m, MonadAlpha m, MonadError Error m) => Env -> X.Builtin -> [X.Type] -> [X.Expr] -> m Y.Expr runAppBuiltin env f ts args = wrapError' ("converting builtin " ++ X.formatBuiltinIsolated f ts) $ do- let go0T f = case ts of+ let go0T :: (MonadAlpha m, MonadError Error m, MonadStatements m) => m Y.Expr -> m Y.Expr+ go0T f = case ts of [] -> f _ -> throwInternalError $ "expected 0 type arguments, got " ++ show (length ts)- let go1T' f = case ts of+ let go1T' :: (MonadAlpha m, MonadError Error m, MonadStatements m) => (X.Type -> m Y.Expr) -> m Y.Expr+ go1T' f = case ts of [t1] -> f t1 _ -> throwInternalError $ "expected 1 type argument, got " ++ show (length ts)- let go1T f = go1T' $ f <=< runType+ let go1T :: (MonadAlpha m, MonadError Error m, MonadStatements m) => (Y.Type -> m Y.Expr) -> m Y.Expr+ go1T f = go1T' $ f <=< runType let go2T' f = case ts of [t1, t2] -> f t1 t2 _ -> throwInternalError $ "expected 2 type arguments, got " ++ show (length ts)- let go0E f = case args of+ let go0E :: (MonadAlpha m, MonadError Error m, MonadStatements m) => m Y.Expr -> m Y.Expr+ go0E f = case args of [] -> f _ -> throwInternalError $ "expected 0 type arguments, got " ++ show (length args)- let go1E' f = case args of+ let go1E' :: (MonadAlpha m, MonadError Error m, MonadStatements m) => (X.Expr -> m Y.Expr) -> m Y.Expr+ go1E' f = case args of [e1] -> f e1 _ -> throwInternalError $ "expected 1 type argument, got " ++ show (length args)- let go1E f = go1E' $ \e1 -> do- (stmts1, e1) <- runExpr env e1- (stmts, e) <- f e1- return (stmts1 ++ stmts, e)+ let go1E :: (MonadAlpha m, MonadError Error m, MonadStatements m) => (Y.Expr -> m Y.Expr) -> m Y.Expr+ go1E f = go1E' $ f <=< runExpr env let go2E' f = case args of [e1, e2] -> f e1 e2 _ -> throwInternalError $ "expected 2 type arguments, got " ++ show (length args)- let go2E f = go2E' $ \e1 e2 -> do- (stmts1, e1) <- runExpr env e1- (stmts2, e2) <- runExpr env e2- (stmts, e) <- f e1 e2- return (stmts1 ++ stmts2 ++ stmts, e)+ let go2E f = go2E' $ \e1 e2 -> join $ f <$> runExpr env e1 <*> runExpr env e2 let go3E' f = case args of [e1, e2, e3] -> f e1 e2 e3 _ -> throwInternalError $ "expected 2 type arguments, got " ++ show (length args)- let go3E f = go3E' $ \e1 e2 e3 -> do- (stmts1, e1) <- runExpr env e1- (stmts2, e2) <- runExpr env e2- (stmts3, e3) <- runExpr env e3- (stmts, e) <- f e1 e2 e3- return (stmts1 ++ stmts2 ++ stmts3 ++ stmts, e)- let goP f = return ([], f)- let go00 f = go0T $ go0E $ goP f- let go01' :: (MonadAlpha m, MonadError Error m) => (Y.Expr -> m ([Y.Statement], Y.Expr)) -> m ([Y.Statement], Y.Expr)+ let go3E f = go3E' $ \e1 e2 e3 -> join $ f <$> runExpr env e1 <*> runExpr env e2 <*> runExpr env e3+ let go00 f = go0T $ go0E $ return f+ let go01' :: (MonadAlpha m, MonadError Error m, MonadStatements m) => (Y.Expr -> m Y.Expr) -> m Y.Expr go01' f = go0T $ go1E f- let go01 :: (MonadAlpha m, MonadError Error m) => (Y.Expr -> Y.Expr) -> m ([Y.Statement], Y.Expr)- go01 f = go0T $ go1E $ \e1 -> goP $ f e1- let go11' :: (MonadAlpha m, MonadError Error m) => (Y.Type -> Y.Expr -> m ([Y.Statement], Y.Expr)) -> m ([Y.Statement], Y.Expr)+ let go01 :: (MonadAlpha m, MonadError Error m, MonadStatements m) => (Y.Expr -> Y.Expr) -> m Y.Expr+ go01 f = go0T $ go1E $ \e1 -> return $ f e1+ let go11' :: (MonadAlpha m, MonadError Error m, MonadStatements m) => (Y.Type -> Y.Expr -> m Y.Expr) -> m Y.Expr go11' f = go1T $ \t1 -> go1E $ \e1 -> f t1 e1- let go11 :: (MonadAlpha m, MonadError Error m) => (Y.Type -> Y.Expr -> Y.Expr) -> m ([Y.Statement], Y.Expr)- go11 f = go1T $ \t1 -> go1E $ \e1 -> goP $ f t1 e1- let go02' :: (MonadAlpha m, MonadError Error m) => (Y.Expr -> Y.Expr -> m ([Y.Statement], Y.Expr)) -> m ([Y.Statement], Y.Expr)+ let go11 :: (MonadAlpha m, MonadError Error m, MonadStatements m) => (Y.Type -> Y.Expr -> Y.Expr) -> m Y.Expr+ go11 f = go1T $ \t1 -> go1E $ \e1 -> return $ f t1 e1+ let go02' :: (MonadAlpha m, MonadError Error m, MonadStatements m) => (Y.Expr -> Y.Expr -> m Y.Expr) -> m Y.Expr go02' f = go0T $ go2E f- let go02 :: (MonadAlpha m, MonadError Error m) => (Y.Expr -> Y.Expr -> Y.Expr) -> m ([Y.Statement], Y.Expr)- go02 f = go0T $ go2E $ \e1 e2 -> goP $ f e1 e2- let go12'' :: (MonadAlpha m, MonadError Error m) => (X.Type -> X.Expr -> X.Expr -> m ([Y.Statement], Y.Expr)) -> m ([Y.Statement], Y.Expr)+ let go02 :: (MonadAlpha m, MonadError Error m, MonadStatements m) => (Y.Expr -> Y.Expr -> Y.Expr) -> m Y.Expr+ go02 f = go0T $ go2E $ \e1 e2 -> return $ f e1 e2+ let go12'' :: (MonadAlpha m, MonadError Error m, MonadStatements m) => (X.Type -> X.Expr -> X.Expr -> m Y.Expr) -> m Y.Expr go12'' f = go1T' $ \t1 -> go2E' $ \e1 e2 -> f t1 e1 e2- let go12' :: (MonadAlpha m, MonadError Error m) => (Y.Type -> Y.Expr -> Y.Expr -> m ([Y.Statement], Y.Expr)) -> m ([Y.Statement], Y.Expr)+ let go12' :: (MonadAlpha m, MonadError Error m, MonadStatements m) => (Y.Type -> Y.Expr -> Y.Expr -> m Y.Expr) -> m Y.Expr go12' f = go1T $ \t1 -> go2E $ \e1 e2 -> f t1 e1 e2- let go12 :: (MonadAlpha m, MonadError Error m) => (Y.Type -> Y.Expr -> Y.Expr -> Y.Expr) -> m ([Y.Statement], Y.Expr)- go12 f = go1T $ \t1 -> go2E $ \e1 e2 -> goP $ f t1 e1 e2- let go22'' :: (MonadAlpha m, MonadError Error m) => (X.Type -> X.Type -> X.Expr -> X.Expr -> m ([Y.Statement], Y.Expr)) -> m ([Y.Statement], Y.Expr)+ let go12 :: (MonadAlpha m, MonadError Error m, MonadStatements m) => (Y.Type -> Y.Expr -> Y.Expr -> Y.Expr) -> m Y.Expr+ go12 f = go1T $ \t1 -> go2E $ \e1 e2 -> return $ f t1 e1 e2+ let go22'' :: (MonadAlpha m, MonadError Error m, MonadStatements m) => (X.Type -> X.Type -> X.Expr -> X.Expr -> m Y.Expr) -> m Y.Expr go22'' f = go2T' $ \t1 t2 -> go2E' $ \e1 e2 -> f t1 t2 e1 e2- let go03' :: (MonadAlpha m, MonadError Error m) => (Y.Expr -> Y.Expr -> Y.Expr -> m ([Y.Statement], Y.Expr)) -> m ([Y.Statement], Y.Expr)+ let go03' :: (MonadAlpha m, MonadError Error m, MonadStatements m) => (Y.Expr -> Y.Expr -> Y.Expr -> m Y.Expr) -> m Y.Expr go03' f = go0T $ go3E f- let go03 f = go0T $ go3E $ \e1 e2 e3 -> goP $ f e1 e2 e3- let go13'' :: (MonadAlpha m, MonadError Error m) => (X.Type -> X.Expr -> X.Expr -> X.Expr -> m ([Y.Statement], Y.Expr)) -> m ([Y.Statement], Y.Expr)+ let go03 f = go0T $ go3E $ \e1 e2 e3 -> return $ f e1 e2 e3+ let go13'' :: (MonadAlpha m, MonadError Error m, MonadStatements m) => (X.Type -> X.Expr -> X.Expr -> X.Expr -> m Y.Expr) -> m Y.Expr go13'' f = go1T' $ \t1 -> go3E' $ \e1 e2 e3 -> f t1 e1 e2 e3- let go13' :: (MonadAlpha m, MonadError Error m) => (Y.Type -> Y.Expr -> Y.Expr -> Y.Expr -> m ([Y.Statement], Y.Expr)) -> m ([Y.Statement], Y.Expr)- go13' f = go1T $ \t1 -> go3E $ \e1 e2 e3 -> f t1 e1 e2 e3- let go23'' :: (MonadAlpha m, MonadError Error m) => (X.Type -> X.Type -> X.Expr -> X.Expr -> X.Expr -> m ([Y.Statement], Y.Expr)) -> m ([Y.Statement], Y.Expr)+ let go13 :: (MonadAlpha m, MonadError Error m, MonadStatements m) => (Y.Type -> Y.Expr -> Y.Expr -> Y.Expr -> Y.Expr) -> m Y.Expr+ go13 f = go1T $ \t1 -> go3E $ \e1 e2 e3 -> return $ f t1 e1 e2 e3+ let go23'' :: (MonadAlpha m, MonadError Error m, MonadStatements m) => (X.Type -> X.Type -> X.Expr -> X.Expr -> X.Expr -> m Y.Expr) -> m Y.Expr go23'' f = go2T' $ \t1 t2 -> go3E' $ \e1 e2 e3 -> f t1 t2 e1 e2 e3- let goN1 :: (MonadAlpha m, MonadError Error m) => ([Y.Type] -> Y.Expr -> Y.Expr) -> m ([Y.Statement], Y.Expr)+ let goN1 :: (MonadAlpha m, MonadError Error m, MonadStatements m) => ([Y.Type] -> Y.Expr -> Y.Expr) -> m Y.Expr goN1 f = case args of [e1] -> do ts <- mapM runType ts- (stmts1, e1) <- runExpr env e1- return (stmts1, f ts e1)+ e1 <- runExpr env e1+ return $ f ts e1 _ -> throwInternalError $ "expected 1 argument, got " ++ show (length args)- let goNN :: (MonadAlpha m, MonadError Error m) => ([Y.Type] -> [Y.Expr] -> Y.Expr) -> m ([Y.Statement], Y.Expr)+ let goNN :: (MonadAlpha m, MonadError Error m, MonadStatements m) => ([Y.Type] -> [Y.Expr] -> Y.Expr) -> m Y.Expr goNN f = do ts <- mapM runType ts args <- mapM (runExpr env) args- let e = f ts (map snd args)- return (concatMap fst args, e)+ return $ f ts args case f of -- arithmetical functions X.Negate -> go01 $ \e -> Y.UnOp Y.Negate e@@ -201,42 +275,13 @@ X.Lcm -> go02 $ \e1 e2 -> Y.Call (Y.Function "std::lcm" []) [e1, e2] X.Min2 -> go12 $ \t e1 e2 -> Y.Call (Y.Function "std::min" [t]) [e1, e2] X.Max2 -> go12 $ \t e1 e2 -> Y.Call (Y.Function "std::max" [t]) [e1, e2]- X.Iterate -> go13'' $ \t n f x -> do- t <- runType t- (stmtsN, n) <- runExpr env n- (stmtsX, x) <- runExpr env x- y <- Y.newFreshName Y.LocalNameKind- i <- Y.newFreshName Y.LoopCounterNameKind- (stmtsF, body, f) <- runExprFunction env f (Y.Var y)- return- ( stmtsN ++ stmtsX- ++ [Y.Declare t y (Y.DeclareCopy x)]- ++ stmtsF- ++ [ Y.repStatement- i- (Y.cast Y.TyInt32 n)- (body ++ [Y.assignSimple y f])- ],- Y.Var y- )+ X.Iterate -> go13'' $ runIterate env -- logical functions X.Not -> go01 $ \e -> Y.UnOp Y.Not e X.And -> go02 $ \e1 e2 -> Y.BinOp Y.And e1 e2 X.Or -> go02 $ \e1 e2 -> Y.BinOp Y.Or e1 e2 X.Implies -> go02 $ \e1 e2 -> Y.BinOp Y.Or (Y.UnOp Y.Not e1) e2- X.If -> go13'' $ \t e1 e2 e3 -> do- (stmts1, e1') <- runExpr env e1- (stmts2, e2') <- runExpr env e2- (stmts3, e3') <- runExpr env e3- case (stmts2, stmts3) of- ([], [])- | X.isConstantTimeExpr e2 && X.isConstantTimeExpr e3 ->- return (stmts1, Y.Cond e1' e2' e3')- _ -> do- t <- runType t- phi <- Y.newFreshName Y.LocalNameKind- let assign = Y.Assign . Y.AssignExpr Y.SimpleAssign (Y.LeftVar phi)- return ([Y.Declare t phi Y.DeclareDefault] ++ stmts1 ++ [Y.If e1' (stmts2 ++ [assign e2']) (Just (stmts3 ++ [assign e3']))], Y.Var phi)+ X.If -> go13'' $ runIf env -- bitwise functions X.BitNot -> go01 $ \e -> Y.UnOp Y.BitNot e X.BitAnd -> go02 $ \e1 e2 -> Y.BinOp Y.BitAnd e1 e2@@ -245,14 +290,14 @@ X.BitLeftShift -> go02 $ \e1 e2 -> Y.BinOp Y.BitLeftShift e1 e2 X.BitRightShift -> go02 $ \e1 e2 -> Y.BinOp Y.BitRightShift e1 e2 -- matrix functions- X.MatAp h w -> go02 $ \f x -> Y.Call (Y.Function "jikka::mat::ap" [Y.TyIntValue (fromIntegral h), Y.TyIntValue (fromIntegral w)]) [f, x]- X.MatZero n -> go00 $ Y.Call (Y.Function "jikka::mat::zero" [Y.TyIntValue (fromIntegral n)]) []- X.MatOne n -> go00 $ Y.Call (Y.Function "jikka::mat::one" [Y.TyIntValue (fromIntegral n)]) []- X.MatAdd h w -> go02 $ \f g -> Y.Call (Y.Function "jikka::mat::add" [Y.TyIntValue (fromIntegral h), Y.TyIntValue (fromIntegral w)]) [f, g]- X.MatMul h n w -> go02 $ \f g -> Y.Call (Y.Function "jikka::mat::mul" [Y.TyIntValue (fromIntegral h), Y.TyIntValue (fromIntegral n), Y.TyIntValue (fromIntegral w)]) [f, g]- X.MatPow n -> go02 $ \f k -> Y.Call (Y.Function "jikka::mat::pow" [Y.TyIntValue (fromIntegral n)]) [f, k]- X.VecFloorMod n -> go02 $ \x m -> Y.Call (Y.Function "jikka::modmat::floormod" [Y.TyIntValue (fromIntegral n)]) [x, m]- X.MatFloorMod h w -> go02 $ \f m -> Y.Call (Y.Function "jikka::modmat::floormod" [Y.TyIntValue (fromIntegral h), Y.TyIntValue (fromIntegral w)]) [f, m]+ X.MatAp h w -> go02 $ \f x -> Y.Call (Y.Function "jikka::mat::ap" [Y.TyIntValue h, Y.TyIntValue w]) [f, x]+ X.MatZero h w -> go00 $ Y.Call (Y.Function "jikka::mat::zero" [Y.TyIntValue h, Y.TyIntValue w]) []+ X.MatOne n -> go00 $ Y.Call (Y.Function "jikka::mat::one" [Y.TyIntValue n]) []+ X.MatAdd h w -> go02 $ \f g -> Y.Call (Y.Function "jikka::mat::add" [Y.TyIntValue h, Y.TyIntValue w]) [f, g]+ X.MatMul h n w -> go02 $ \f g -> Y.Call (Y.Function "jikka::mat::mul" [Y.TyIntValue h, Y.TyIntValue n, Y.TyIntValue w]) [f, g]+ X.MatPow n -> go02 $ \f k -> Y.Call (Y.Function "jikka::mat::pow" [Y.TyIntValue n]) [f, k]+ X.VecFloorMod n -> go02 $ \x m -> Y.Call (Y.Function "jikka::modmat::floormod" [Y.TyIntValue n]) [x, m]+ X.MatFloorMod h w -> go02 $ \f m -> Y.Call (Y.Function "jikka::modmat::floormod" [Y.TyIntValue h, Y.TyIntValue w]) [f, m] -- modular functions X.ModNegate -> go02 $ \e1 e2 -> Y.Call (Y.Function "jikka::mod::negate" []) [e1, e2] X.ModPlus -> go03 $ \e1 e2 e3 -> Y.Call (Y.Function "jikka::mod::plus" []) [e1, e2, e3]@@ -260,295 +305,140 @@ X.ModMult -> go03 $ \e1 e2 e3 -> Y.Call (Y.Function "jikka::mod::mult" []) [e1, e2, e3] X.ModInv -> go02 $ \e1 e2 -> Y.Call (Y.Function "jikka::mod::inv" []) [e1, e2] X.ModPow -> go03 $ \e1 e2 e3 -> Y.Call (Y.Function "jikka::mod::pow" []) [e1, e2, e3]- X.ModMatAp h w -> go03 $ \f x m -> Y.Call (Y.Function "jikka::modmat::ap" [Y.TyIntValue (fromIntegral h), Y.TyIntValue (fromIntegral w)]) [f, x, m]- X.ModMatAdd h w -> go03 $ \f g m -> Y.Call (Y.Function "jikka::modmat::add" [Y.TyIntValue (fromIntegral h), Y.TyIntValue (fromIntegral w)]) [f, g, m]- X.ModMatMul h n w -> go03 $ \f g m -> Y.Call (Y.Function "jikka::modmat::mul" [Y.TyIntValue (fromIntegral h), Y.TyIntValue (fromIntegral n), Y.TyIntValue (fromIntegral w)]) [f, g, m]- X.ModMatPow n -> go03 $ \f k m -> Y.Call (Y.Function "jikka::modmat::pow" [Y.TyIntValue (fromIntegral n)]) [f, k, m]+ X.ModMatAp h w -> go03 $ \f x m -> Y.Call (Y.Function "jikka::modmat::ap" [Y.TyIntValue h, Y.TyIntValue w]) [f, x, m]+ X.ModMatAdd h w -> go03 $ \f g m -> Y.Call (Y.Function "jikka::modmat::add" [Y.TyIntValue h, Y.TyIntValue w]) [f, g, m]+ X.ModMatMul h n w -> go03 $ \f g m -> Y.Call (Y.Function "jikka::modmat::mul" [Y.TyIntValue h, Y.TyIntValue n, Y.TyIntValue w]) [f, g, m]+ X.ModMatPow n -> go03 $ \f k m -> Y.Call (Y.Function "jikka::modmat::pow" [Y.TyIntValue n]) [f, k, m] -- list functions X.Cons -> go12' $ \t x xs -> do ys <- Y.newFreshName Y.LocalNameKind- return- ( [ Y.Declare (Y.TyVector t) ys Y.DeclareDefault,- Y.callMethod' (Y.Var ys) "push_back" [x],- Y.callMethod' (Y.Var ys) "insert" [Y.end (Y.Var ys), Y.begin xs, Y.end xs]- ],- Y.Var ys- )+ useStatement $ Y.Declare (Y.TyVector t) ys Y.DeclareDefault+ useStatement $ Y.callMethod' (Y.Var ys) "push_back" [x]+ useStatement $ Y.callMethod' (Y.Var ys) "insert" [Y.end (Y.Var ys), Y.begin xs, Y.end xs]+ return $ Y.Var ys X.Snoc -> go12' $ \t xs x -> do ys <- Y.newFreshName Y.LocalNameKind- return- ( [ Y.Declare (Y.TyVector t) ys (Y.DeclareCopy xs),- Y.callMethod' (Y.Var ys) "push_back" [x]- ],- Y.Var ys- )- X.Foldl -> go23'' $ \t1 t2 f init xs -> do- (stmtsInit, init) <- runExpr env init- (stmtsXs, xs) <- runExpr env xs- t1 <- runType t1- t2 <- runType t2- y <- Y.newFreshName Y.LocalNameKind- x <- Y.newFreshName Y.LocalNameKind- (stmtsF, body, f) <- runExprFunction2 env f (Y.Var y) (Y.Var x)- return- ( stmtsInit ++ stmtsXs- ++ [Y.Declare t2 y (Y.DeclareCopy init)]- ++ stmtsF- ++ [ Y.ForEach- t1- x- xs- (body ++ [Y.assignSimple y f])- ],- Y.Var y- )+ useStatement $ Y.Declare (Y.TyVector t) ys (Y.DeclareCopy xs)+ useStatement $ Y.callMethod' (Y.Var ys) "push_back" [x]+ return $ Y.Var ys+ X.Foldl -> go23'' $ runFoldl env X.Scanl -> go23'' $ \_ t2 f init xs -> do- (stmtsInit, init) <- runExpr env init- (stmtsXs, xs) <- runExpr env xs+ init <- runExpr env init+ xs <- runExpr env xs t2 <- runType t2 ys <- Y.newFreshName Y.LocalNameKind i <- Y.newFreshName Y.LoopCounterNameKind (stmtsF, body, f) <- runExprFunction2 env f (Y.at (Y.Var ys) (Y.Var i)) (Y.at xs (Y.Var i))- return- ( stmtsInit ++ stmtsXs- ++ [ Y.Declare (Y.TyVector t2) ys (Y.DeclareCopy (Y.vecCtor t2 [Y.incrExpr (Y.size xs)])),- Y.assignAt ys (Y.litInt32 0) init- ]- ++ stmtsF- ++ [ Y.repStatement- i- (Y.cast Y.TyInt32 (Y.size xs))- (body ++ [Y.assignAt ys (Y.incrExpr (Y.Var i)) f])- ],- Y.Var ys- )+ useStatement $ Y.Declare (Y.TyVector t2) ys (Y.DeclareCopy (Y.vecCtor t2 [Y.incrExpr (Y.size xs)]))+ useStatement $ Y.assignAt ys (Y.litInt32 0) init+ useStatements stmtsF+ useStatement $ Y.repStatement i (Y.cast Y.TyInt32 (Y.size xs)) (body ++ [Y.assignAt ys (Y.incrExpr (Y.Var i)) f])+ return $ Y.Var ys X.Build -> go13'' $ \t f xs n -> do- (stmtsInit, xs) <- runExpr env xs- (stmtsXs, n) <- runExpr env n+ xs <- runExpr env xs+ n <- runExpr env n t <- runType t ys <- Y.newFreshName Y.LocalNameKind i <- Y.newFreshName Y.LoopCounterNameKind (stmtsF, body, f) <- runExprFunction env f (Y.Var ys)- return- ( stmtsInit ++ stmtsXs- ++ [ Y.Declare (Y.TyVector t) ys (Y.DeclareCopy xs)- ]- ++ stmtsF- ++ [ Y.repStatement- i- (Y.cast Y.TyInt32 n)- (body ++ [Y.callMethod' (Y.Var ys) "push_back" [f]])- ],- Y.Var ys- )+ useStatement $ Y.Declare (Y.TyVector t) ys (Y.DeclareCopy xs)+ useStatements stmtsF+ useStatement $ Y.repStatement i (Y.cast Y.TyInt32 n) (body ++ [Y.callMethod' (Y.Var ys) "push_back" [f]])+ return $ Y.Var ys X.Len -> go11 $ \_ e -> Y.cast Y.TyInt64 (Y.size e)- X.Map -> go22'' $ \_ t2 f xs -> do- ys <- Y.newFreshName Y.LocalNameKind- t2 <- runType t2- stmts <- case (f, xs) of- (X.Lam _ _ (X.Lit lit), X.Range1' n) -> do- (stmtsN, n) <- runExpr env n- lit <- runLiteral env lit- return $- stmtsN- ++ [Y.Declare (Y.TyVector t2) ys (Y.DeclareCopy (Y.vecCtor t2 [n, lit]))]- _ -> do- (stmtsXs, xs) <- runExpr env xs- i <- Y.newFreshName Y.LoopCounterNameKind- (stmtsF, body, f) <- runExprFunction env f (Y.at xs (Y.Var i))- return $- stmtsXs- ++ [Y.Declare (Y.TyVector t2) ys (Y.DeclareCopy (Y.vecCtor t2 [Y.size xs]))]- ++ stmtsF- ++ [ Y.repStatement- i- (Y.cast Y.TyInt32 (Y.size xs))- (body ++ [Y.assignAt ys (Y.Var i) f])- ]- return (stmts, Y.Var ys)+ X.Map -> go22'' $ runMap env X.Filter -> go12'' $ \t f xs -> do- (stmtsXs, xs) <- runExpr env xs+ xs <- runExpr env xs t <- runType t ys <- Y.newFreshName Y.LocalNameKind x <- Y.newFreshName Y.LocalNameKind (stmtsF, body, f) <- runExprFunction env f (Y.Var x)- return- ( stmtsXs- ++ [Y.Declare (Y.TyVector t) ys Y.DeclareDefault]- ++ stmtsF- ++ [ Y.ForEach- t- x- xs- ( body- ++ [ Y.If- f- [Y.callMethod' (Y.Var ys) "push_back" [Y.Var x]]- Nothing- ]- )- ],- Y.Var ys- )+ useStatement $ Y.Declare (Y.TyVector t) ys Y.DeclareDefault+ useStatements stmtsF+ useStatement $ Y.ForEach t x xs (body ++ [Y.If f [Y.callMethod' (Y.Var ys) "push_back" [Y.Var x]] Nothing])+ return $ Y.Var ys X.At -> go12 $ \_ e1 e2 -> Y.at e1 e2- X.SetAt -> go13' $ \t xs i x -> do- ys <- Y.newFreshName Y.LocalNameKind- return- ( [ Y.Declare (Y.TyVector t) ys (Y.DeclareCopy xs),- Y.assignAt ys i x- ],- Y.Var ys- )+ X.SetAt -> go13 $ \t xs i x -> Y.Call (Y.SetAt t) [xs, i, x] X.Elem -> go12' $ \_ xs x -> do y <- Y.newFreshName Y.LocalNameKind- return- ( [ Y.Declare Y.TyBool y (Y.DeclareCopy (Y.BinOp Y.NotEqual (Y.callFunction "std::find" [] [Y.begin xs, Y.end xs, x]) (Y.end xs)))- ],- Y.Var y- )+ useStatement $ Y.Declare Y.TyBool y (Y.DeclareCopy (Y.BinOp Y.NotEqual (Y.callFunction "std::find" [] [Y.begin xs, Y.end xs, x]) (Y.end xs)))+ return $ Y.Var y X.Sum -> go01' $ \xs -> do y <- Y.newFreshName Y.LocalNameKind- return- ( [ Y.Declare Y.TyInt64 y (Y.DeclareCopy (Y.callFunction "std::accumulate" [] [Y.begin xs, Y.end xs, Y.litInt64 0]))- ],- Y.Var y- )+ useStatement $ Y.Declare Y.TyInt64 y (Y.DeclareCopy (Y.callFunction "std::accumulate" [] [Y.begin xs, Y.end xs, Y.litInt64 0]))+ return $ Y.Var y X.ModSum -> go02' $ \xs m -> do y <- Y.newFreshName Y.LocalNameKind x <- Y.newFreshName Y.LocalNameKind- return- ( [ Y.Declare Y.TyInt64 y (Y.DeclareCopy (Y.litInt64 0)),- Y.ForEach- Y.TyInt64- x- xs- [Y.Assign (Y.AssignExpr Y.AddAssign (Y.LeftVar y) (Y.callFunction "jikka::floormod" [] [Y.Var x, m]))]- ],- Y.callFunction "jikka::floormod" [] [Y.Var y, m]- )+ useStatement $ Y.Declare Y.TyInt64 y (Y.DeclareCopy (Y.litInt64 0))+ useStatement $ Y.ForEach Y.TyInt64 x xs [Y.Assign (Y.AssignExpr Y.AddAssign (Y.LeftVar y) (Y.callFunction "jikka::floormod" [] [Y.Var x, m]))]+ return $ Y.callFunction "jikka::floormod" [] [Y.Var y, m] X.Product -> go01' $ \xs -> do y <- Y.newFreshName Y.LocalNameKind x <- Y.newFreshName Y.LocalNameKind- return- ( [ Y.Declare Y.TyInt64 y (Y.DeclareCopy (Y.litInt64 1)),- Y.ForEach- Y.TyInt64- x- xs- [Y.Assign (Y.AssignExpr Y.MulAssign (Y.LeftVar y) (Y.Var x))]- ],- Y.Var y- )+ useStatement $ Y.Declare Y.TyInt64 y (Y.DeclareCopy (Y.litInt64 1))+ useStatement $ Y.ForEach Y.TyInt64 x xs [Y.Assign (Y.AssignExpr Y.MulAssign (Y.LeftVar y) (Y.Var x))]+ return $ Y.Var y X.ModProduct -> go02' $ \xs m -> do y <- Y.newFreshName Y.LocalNameKind x <- Y.newFreshName Y.LocalNameKind- return- ( [ Y.Declare Y.TyInt64 y (Y.DeclareCopy (Y.litInt64 1)),- Y.ForEach- Y.TyInt64- x- xs- [Y.Assign (Y.AssignExpr Y.SimpleAssign (Y.LeftVar y) (Y.callFunction "jikka::mod::mult" [] [Y.Var y, Y.Var x, m]))]- ],- Y.Var y- )+ useStatement $ Y.Declare Y.TyInt64 y (Y.DeclareCopy (Y.litInt64 1))+ useStatement $ Y.ForEach Y.TyInt64 x xs [Y.Assign (Y.AssignExpr Y.SimpleAssign (Y.LeftVar y) (Y.callFunction "jikka::mod::mult" [] [Y.Var y, Y.Var x, m]))]+ return $ Y.Var y X.Min1 -> go11' $ \t xs -> do y <- Y.newFreshName Y.LocalNameKind- return- ( [ Y.Declare t y (Y.DeclareCopy (Y.UnOp Y.Deref (Y.callFunction "std::min_element" [] [Y.begin xs, Y.end xs])))- ],- Y.Var y- )+ useStatement $ Y.Declare t y (Y.DeclareCopy (Y.UnOp Y.Deref (Y.callFunction "std::min_element" [] [Y.begin xs, Y.end xs])))+ return $ Y.Var y X.Max1 -> go11' $ \t xs -> do y <- Y.newFreshName Y.LocalNameKind- return- ( [ Y.Declare t y (Y.DeclareCopy (Y.UnOp Y.Deref (Y.callFunction "std::max_element" [] [Y.begin xs, Y.end xs])))- ],- Y.Var y- )+ useStatement $ Y.Declare t y (Y.DeclareCopy (Y.UnOp Y.Deref (Y.callFunction "std::max_element" [] [Y.begin xs, Y.end xs])))+ return $ Y.Var y X.ArgMin -> go11' $ \t xs -> do y <- Y.newFreshName Y.LocalNameKind- return- ( [ Y.Declare t y (Y.DeclareCopy (Y.BinOp Y.Sub (Y.callFunction "std::min_element" [] [Y.begin xs, Y.end xs]) (Y.begin xs)))- ],- Y.Var y- )+ useStatement $ Y.Declare t y (Y.DeclareCopy (Y.BinOp Y.Sub (Y.callFunction "std::min_element" [] [Y.begin xs, Y.end xs]) (Y.begin xs)))+ return $ Y.Var y X.ArgMax -> go11' $ \t xs -> do y <- Y.newFreshName Y.LocalNameKind- return- ( [ Y.Declare t y (Y.DeclareCopy (Y.BinOp Y.Sub (Y.callFunction "std::max_element" [] [Y.begin xs, Y.end xs]) (Y.begin xs)))- ],- Y.Var y- )+ useStatement $ Y.Declare t y (Y.DeclareCopy (Y.BinOp Y.Sub (Y.callFunction "std::max_element" [] [Y.begin xs, Y.end xs]) (Y.begin xs)))+ return $ Y.Var y X.Gcd1 -> go11' $ \t xs -> do y <- Y.newFreshName Y.LocalNameKind- return- ( [ Y.Declare t y (Y.DeclareCopy (Y.UnOp Y.Deref (Y.callFunction "std::accumulate" [] [Y.begin xs, Y.end xs, Y.litInt64 0, Y.Lam [(Y.TyAuto, Y.VarName "a"), (Y.TyAuto, Y.VarName "b")] Y.TyAuto [Y.Return $ Y.callFunction "std::gcd" [] [Y.Var $ Y.VarName "a", Y.Var $ Y.VarName "b"]]])))- ],- Y.Var y- )+ useStatement $ Y.Declare t y (Y.DeclareCopy (Y.UnOp Y.Deref (Y.callFunction "std::accumulate" [] [Y.begin xs, Y.end xs, Y.litInt64 0, Y.Lam [(Y.TyAuto, Y.VarName "a"), (Y.TyAuto, Y.VarName "b")] Y.TyAuto [Y.Return $ Y.callFunction "std::gcd" [] [Y.Var $ Y.VarName "a", Y.Var $ Y.VarName "b"]]])))+ return $ Y.Var y X.Lcm1 -> go11' $ \t xs -> do y <- Y.newFreshName Y.LocalNameKind- return- ( [ Y.Declare t y (Y.DeclareCopy (Y.UnOp Y.Deref (Y.callFunction "std::accumulate" [] [Y.begin xs, Y.end xs, Y.litInt64 1, Y.Lam [(Y.TyAuto, Y.VarName "a"), (Y.TyAuto, Y.VarName "b")] Y.TyAuto [Y.Return $ Y.callFunction "std::lcm" [] [Y.Var $ Y.VarName "a", Y.Var $ Y.VarName "b"]]])))- ],- Y.Var y- )+ useStatement $ Y.Declare t y (Y.DeclareCopy (Y.UnOp Y.Deref (Y.callFunction "std::accumulate" [] [Y.begin xs, Y.end xs, Y.litInt64 1, Y.Lam [(Y.TyAuto, Y.VarName "a"), (Y.TyAuto, Y.VarName "b")] Y.TyAuto [Y.Return $ Y.callFunction "std::lcm" [] [Y.Var $ Y.VarName "a", Y.Var $ Y.VarName "b"]]])))+ return $ Y.Var y X.All -> go01' $ \xs -> do y <- Y.newFreshName Y.LocalNameKind- return- ( [ Y.Declare Y.TyBool y (Y.DeclareCopy (Y.BinOp Y.Equal (Y.callFunction "std::find" [] [Y.begin xs, Y.end xs, Y.Lit (Y.LitBool False)]) (Y.end xs)))- ],- Y.Var y- )+ useStatement $ Y.Declare Y.TyBool y (Y.DeclareCopy (Y.BinOp Y.Equal (Y.callFunction "std::find" [] [Y.begin xs, Y.end xs, Y.Lit (Y.LitBool False)]) (Y.end xs)))+ return $ Y.Var y X.Any -> go01' $ \xs -> do y <- Y.newFreshName Y.LocalNameKind- return- ( [ Y.Declare Y.TyBool y (Y.DeclareCopy (Y.BinOp Y.NotEqual (Y.callFunction "std::find" [] [Y.begin xs, Y.end xs, Y.Lit (Y.LitBool True)]) (Y.end xs)))- ],- Y.Var y- )+ useStatement $ Y.Declare Y.TyBool y (Y.DeclareCopy (Y.BinOp Y.NotEqual (Y.callFunction "std::find" [] [Y.begin xs, Y.end xs, Y.Lit (Y.LitBool True)]) (Y.end xs)))+ return $ Y.Var y X.Sorted -> go11' $ \t xs -> do ys <- Y.newFreshName Y.LocalNameKind- return- ( [ Y.Declare (Y.TyVector t) ys (Y.DeclareCopy xs),- Y.callFunction' "std::sort" [] [Y.begin (Y.Var ys), Y.end (Y.Var ys)]- ],- Y.Var ys- )+ useStatement $ Y.Declare (Y.TyVector t) ys (Y.DeclareCopy xs)+ useStatement $ Y.callFunction' "std::sort" [] [Y.begin (Y.Var ys), Y.end (Y.Var ys)]+ return $ Y.Var ys X.Reversed -> go11' $ \t xs -> do ys <- Y.newFreshName Y.LocalNameKind- return- ( [ Y.Declare (Y.TyVector t) ys (Y.DeclareCopy xs),- Y.callFunction' "std::reverse" [] [Y.begin (Y.Var ys), Y.end (Y.Var ys)]- ],- Y.Var ys- )+ useStatement $ Y.Declare (Y.TyVector t) ys (Y.DeclareCopy xs)+ useStatement $ Y.callFunction' "std::reverse" [] [Y.begin (Y.Var ys), Y.end (Y.Var ys)]+ return $ Y.Var ys X.Range1 -> go01 $ \n -> Y.Call Y.Range [n] X.Range2 -> go02' $ \from to -> do ys <- Y.newFreshName Y.LocalNameKind- return- ( [ Y.Declare (Y.TyVector Y.TyInt64) ys (Y.DeclareCopy (Y.vecCtor Y.TyInt64 [Y.BinOp Y.Sub to from])),- Y.callFunction' "std::iota" [] [Y.begin (Y.Var ys), Y.end (Y.Var ys), from]- ],- Y.Var ys- )+ useStatement $ Y.Declare (Y.TyVector Y.TyInt64) ys (Y.DeclareCopy (Y.vecCtor Y.TyInt64 [Y.BinOp Y.Sub to from]))+ useStatement $ Y.callFunction' "std::iota" [] [Y.begin (Y.Var ys), Y.end (Y.Var ys), from]+ return $ Y.Var ys X.Range3 -> go03' $ \from to step -> do ys <- Y.newFreshName Y.LocalNameKind i <- Y.newFreshName Y.LoopCounterNameKind- return- ( [ Y.Declare (Y.TyVector Y.TyInt64) ys Y.DeclareDefault,- Y.For- Y.TyInt32- i- from- (Y.BinOp Y.LessThan (Y.Var i) to)- (Y.AssignExpr Y.AddAssign (Y.LeftVar i) step)- [ Y.callMethod' (Y.Var ys) "push_back" [Y.Var i]- ]- ],- Y.Var ys- )+ useStatement $ Y.Declare (Y.TyVector Y.TyInt64) ys Y.DeclareDefault+ useStatement $ Y.For Y.TyInt32 i from (Y.BinOp Y.LessThan (Y.Var i) to) (Y.AssignExpr Y.AddAssign (Y.LeftVar i) step) [Y.callMethod' (Y.Var ys) "push_back" [Y.Var i]]+ return $ Y.Var ys -- tuple functions X.Tuple -> goNN $ \ts es -> if Y.shouldBeArray ts@@ -556,7 +446,7 @@ else Y.Call (Y.StdTuple ts) es X.Proj n -> goN1 $ \ts e -> if Y.shouldBeArray ts- then Y.at e (Y.Lit (Y.LitInt32 (fromIntegral n)))+ then Y.at e (Y.Lit (Y.LitInt32 n)) else Y.Call (Y.StdGet (toInteger n)) [e] -- comparison X.LessThan -> go12 $ \_ e1 e2 -> Y.BinOp Y.LessThan e1 e2@@ -582,12 +472,12 @@ runExprFunction env f e = case f of X.Lam x t body -> do y <- renameVarName' Y.LocalArgumentNameKind x- (stmts, body) <- runExpr ((x, t, y) : env) body+ (stmts, body) <- runStatementsT $ runExpr ((x, t, y) : env) body let stmts' = map (Y.replaceStatement y e) stmts let body' = Y.replaceExpr y e body return ([], stmts', body') f -> do- (stmts, f) <- runExpr env f+ (stmts, f) <- runStatementsT $ runExpr env f return (stmts, [], Y.CallExpr f [e]) runExprFunction2 :: (MonadAlpha m, MonadError Error m) => Env -> X.Expr -> Y.Expr -> Y.Expr -> m ([Y.Statement], [Y.Statement], Y.Expr)@@ -595,22 +485,36 @@ X.Lam2 x1 t1 x2 t2 body -> do y1 <- renameVarName' Y.LocalArgumentNameKind x1 y2 <- renameVarName' Y.LocalArgumentNameKind x2- (stmts, body) <- runExpr ((x2, t2, y2) : (x1, t1, y1) : env) body+ (stmts, body) <- runStatementsT $ runExpr ((x2, t2, y2) : (x1, t1, y1) : env) body let stmts' = map (Y.replaceStatement y2 e2 . Y.replaceStatement y1 e1) stmts let body' = Y.replaceExpr y2 e2 $ Y.replaceExpr y1 e1 body return ([], stmts', body') f -> do- (stmts, f) <- runExpr env f+ (stmts, f) <- runStatementsT $ runExpr env f return (stmts, [], Y.CallExpr (Y.CallExpr f [e1]) [e2]) -runExpr :: (MonadAlpha m, MonadError Error m) => Env -> X.Expr -> m ([Y.Statement], Y.Expr)+runAssert :: (MonadStatements m, MonadAlpha m, MonadError Error m) => Env -> X.Expr -> m ()+runAssert env = \case+ -- optimize @assert all(...)@+ X.All' (X.Map' t _ f xs) -> do+ t <- runType t+ y <- Y.newFreshName Y.LocalNameKind+ xs <- runExpr env xs+ (stmtsF, body, e) <- runExprFunction env f (Y.Var y)+ useStatements stmtsF+ useStatement $ Y.ForEach t y xs (body ++ [Y.Assert e])+ -- other cases+ e -> do+ e <- runExpr env e+ useStatement $ Y.Assert e++runExpr :: (MonadStatements m, MonadAlpha m, MonadError Error m) => Env -> X.Expr -> m Y.Expr runExpr env = \case X.Var x -> do y <- lookupVarName env x- return ([], Y.Var y)+ return $ Y.Var y X.Lit lit -> do- lit <- runLiteral env lit- return ([], lit)+ runLiteral env lit e@(X.App _ _) -> do let (f, args) = X.curryApp e case f of@@ -623,40 +527,39 @@ ret <- runType ret xs <- replicateM (arity - length args) X.genVarName' ys <- mapM (renameVarName' Y.LocalArgumentNameKind) xs- (stmts, e) <- runAppBuiltin env builtin bts (args ++ map X.Var xs)+ e <- runAppBuiltin env builtin bts (args ++ map X.Var xs) let (_, e') = foldr (\(t, y) (ret, e) -> (Y.TyFunction ret [t], Y.Lam [(t, y)] ret [Y.Return e])) (ret, e) (zip (drop (length args) ts) ys)- return (stmts, e')+ return e' else if length args == arity then do runAppBuiltin env builtin bts args else do- (stmts, e) <- runAppBuiltin env builtin bts (take arity args)- args <- mapM (runExpr env) (drop arity args)- return (concatMap fst args ++ stmts, Y.CallExpr e (map snd args))+ args' <- mapM (runExpr env) (drop arity args)+ e <- runAppBuiltin env builtin bts (take arity args)+ return $ Y.CallExpr e args' _ -> do+ f <- runExpr env f args <- mapM (runExpr env) args- (stmts, f) <- runExpr env f- return (stmts ++ concatMap fst args, Y.CallExpr f (map snd args))+ return $ Y.CallExpr f args e@(X.Lam _ _ _) -> do let (args, body) = X.uncurryLam e ys <- mapM (renameVarName' Y.LocalArgumentNameKind . fst) args let env' = reverse (zipWith (\(x, t) y -> (x, t, y)) args ys) ++ env ret <- runType =<< typecheckExpr env' body- (stmts, body) <- runExpr env' body+ (stmts, body) <- runStatementsT $ runExpr env' body ts <- mapM (runType . snd) args let (_, [Y.Return e]) = foldr (\(t, y) (ret, body) -> (Y.TyFunction ret [t], [Y.Return (Y.Lam [(t, y)] ret body)])) (ret, stmts ++ [Y.Return body]) (zip ts ys)- return ([], e)+ return e X.Let x t e1 e2 -> do y <- renameVarName' Y.LocalNameKind x t' <- runType t- (stmts1, e1) <- runExpr env e1- (stmts2, e2) <- runExpr ((x, t, y) : env) e2- return (stmts1 ++ Y.Declare t' y (Y.DeclareCopy e1) : stmts2, e2)+ e1 <- runExpr env e1+ useStatement $ Y.Declare t' y (Y.DeclareCopy e1)+ runExpr ((x, t, y) : env) e2 X.Assert e1 e2 -> do- (stmts1, e1) <- runExpr env e1- (stmts2, e2) <- runExpr env e2- return (stmts1 ++ Y.Assert e1 : stmts2, e2)+ runAssert env e1+ runExpr env e2 runToplevelFunDef :: (MonadAlpha m, MonadError Error m) => Env -> Y.VarName -> [(X.VarName, X.Type)] -> X.Type -> X.Expr -> m [Y.ToplevelStatement] runToplevelFunDef env f args ret body = do@@ -664,7 +567,7 @@ args <- forM args $ \(x, t) -> do y <- renameVarName' Y.ArgumentNameKind x return (x, t, y)- (stmts, result) <- runExpr (reverse args ++ env) body+ (stmts, result) <- runStatementsT $ runExpr (reverse args ++ env) body args <- forM args $ \(_, t, y) -> do t <- runType t return (t, y)@@ -673,7 +576,7 @@ runToplevelVarDef :: (MonadAlpha m, MonadError Error m) => Env -> Y.VarName -> X.Type -> X.Expr -> m [Y.ToplevelStatement] runToplevelVarDef env x t e = do t <- runType t- (stmts, e) <- runExpr env e+ (stmts, e) <- runStatementsT $ runExpr env e case stmts of [] -> return [Y.VarDef t x e] _ -> return [Y.VarDef t x (Y.CallExpr (Y.Lam [] t (stmts ++ [Y.Return e])) [])]@@ -691,7 +594,7 @@ args <- forM args $ \(x, t) -> do y <- renameVarName' Y.ArgumentNameKind x return (x, t, y)- (stmts, e) <- runExpr (reverse args ++ env) body+ (stmts, e) <- runStatementsT $ runExpr (reverse args ++ env) body let body = stmts ++ [Y.Return e] args' <- forM args $ \(_, t, y) -> do t <- runType t@@ -702,7 +605,7 @@ t <- runType t y <- Y.newFreshName Y.ArgumentNameKind return (t, y)- (stmts, e) <- runExpr env e+ (stmts, e) <- runStatementsT $ runExpr env e let body = stmts ++ [Y.Return (Y.CallExpr e (map (Y.Var . snd) args))] return (args, body) ret <- runType ret@@ -734,7 +637,7 @@ cont <- runToplevelExpr ((f, t, g) : env) cont return $ stmt ++ cont X.ToplevelAssert e cont -> do- (stmts, e) <- runExpr env e+ (stmts, e) <- runStatementsT $ runExpr env e let stmt = Y.StaticAssert (Y.CallExpr (Y.Lam [] Y.TyBool (stmts ++ [Y.Return e])) []) "" cont <- runToplevelExpr env cont return $ stmt : cont
+ src/Jikka/CPlusPlus/Convert/InlineSetAt.hs view
@@ -0,0 +1,59 @@+{-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE LambdaCase #-}++-- |+-- Module : Jikka.CPlusPlus.Convert.InlineSetAt+-- Description : does inline expansion of @set_at@ function. / @set_at@ 関数を inline 展開します。+-- Copyright : (c) Kimiyuki Onaka, 2020+-- License : Apache License 2.0+-- Maintainer : kimiyuki95@gmail.com+-- Stability : experimental+-- Portability : portable+module Jikka.CPlusPlus.Convert.InlineSetAt+ ( run,+ )+where++import Control.Monad.Writer.Strict+import Jikka.CPlusPlus.Language.Expr+import Jikka.CPlusPlus.Language.Util+import Jikka.Common.Alpha+import Jikka.Common.Error++runExpr :: (MonadAlpha m, MonadWriter [Statement] m) => Expr -> m Expr+runExpr = \case+ Call (SetAt t) [xs, i, x] -> do+ y <- case xs of+ Var (VarName xs) -> renameVarName LocalNameKind xs+ _ -> newFreshName LocalNameKind+ tell+ [ Declare (TyVector t) y (DeclareCopy xs),+ Assign (AssignExpr SimpleAssign (LeftAt (LeftVar y) i) x)+ ]+ return (Var y)+ e -> return e++runStatement :: MonadAlpha m => Statement -> m [Statement]+runStatement stmt = do+ (stmt, decls) <- runWriterT (mapDirectExprStatementM (mapSubExprM runExpr) stmt)+ return $ decls ++ [stmt]++runProgram :: MonadAlpha m => Program -> m Program+runProgram = mapExprStatementProgramM return runStatement++-- | `run` does inline expansion of @jikka::set_at<T>(...)@ function.+--+-- == Examples+--+-- Before:+--+-- > func(jikka::set_at<T>(xs, i, x));+--+-- After:+--+-- > vector<int> ys = xs;+-- > ys[i] = x;+-- > func(ys);+run :: (MonadAlpha m, MonadError Error m) => Program -> m Program+run prog = wrapError' "Jikka.CPlusPlus.Convert.InlineSetAt" $ do+ runProgram prog
src/Jikka/CPlusPlus/Convert/MoveSemantics.hs view
@@ -51,21 +51,38 @@ AssignIncr e -> AssignIncr <$> runLeftExpr e AssignDecr e -> AssignDecr <$> runLeftExpr e -isMovableTo :: VarName -> VarName -> [[Statement]] -> Bool-isMovableTo x y cont- | x `S.notMember` readList' (analyzeStatements (concat cont)) = True+data CopyType+ = SimpleCopy+ | UpdatedCopy+ deriving (Eq, Ord, Show, Read, Enum, Bounded)++-- | @isMovableTo x y env cont@ checkes whether @x@ is movable to @y@ instead of copying, under a context @env@ and @cont@.+-- @x@ is already replaced by the mapping of @env@, but @y@ and @cont@ are not yet.+isMovableTo :: VarName -> VarName -> CopyType -> M.Map VarName VarName -> [[Statement]] -> Bool+isMovableTo x y0 typ env cont+ | x `S.notMember` readList' (analyzeStatements' (concat cont)) = True -- @x@ is movable if @x@ is not used after the current position | otherwise = let go = \case [] -> False- (Assign (AssignExpr SimpleAssign (LeftVar x') (Var y')) : cont')- | x' == x && y' == y ->- let ReadWriteList _ ws' = analyzeStatements cont'- ReadWriteList rs ws = analyzeStatements (concat (tail cont))+ (Assign (AssignExpr SimpleAssign (LeftVar x') (Var _)) : cont')+ | x' == x -> -- re-assignment to @x@+ let ReadWriteList _ ws' = analyzeStatements' cont'+ ReadWriteList rs ws = analyzeStatements' (concat (tail cont)) in y `S.notMember` S.unions [ws', rs, ws] (stmt : cont) ->- let ReadWriteList rs ws = analyzeStatement stmt- in x `S.notMember` S.unions [rs, ws] && go cont- in go (head cont)+ let ReadWriteList rs ws = analyzeStatement' stmt+ rws = if typ == SimpleCopy then ws else S.union rs ws -- Reading @x@ is okay when it's a copy without updating.+ in x `S.notMember` rws && go cont -- @x@ is used+ in go (head cont) -- @x@ is movable if @x@ is unused until a next re-assignment+ where+ y :: VarName+ y = fromMaybe y0 (M.lookup y0 env)+ applyEnv :: ReadWriteList -> ReadWriteList+ applyEnv (ReadWriteList rs ws) =+ let f = S.map (\x -> fromMaybe x (M.lookup x env))+ in ReadWriteList (f rs) (f ws)+ analyzeStatements' = applyEnv . analyzeStatements+ analyzeStatement' = applyEnv . analyzeStatement runStatement :: MonadState (M.Map VarName VarName) m => Statement -> [[Statement]] -> m [Statement] runStatement stmt cont = case stmt of@@ -98,17 +115,22 @@ DeclareDefault -> return DeclareDefault DeclareCopy e -> DeclareCopy <$> runExpr e DeclareInitialize es -> DeclareInitialize <$> mapM runExpr es+ env <- get case init of- DeclareCopy (Var x) | (x `isMovableTo` y) cont -> do+ DeclareCopy (Var x) | (x `isMovableTo` y) SimpleCopy env cont -> do modify' (M.insert y x) return []+ DeclareCopy (Call (SetAt _) [Var x, i, xi])+ | (x `isMovableTo` y) UpdatedCopy env cont -> do+ modify' (M.insert y x)+ return [Assign (AssignExpr SimpleAssign (LeftAt (LeftVar x) i) xi)] DeclareCopy (Call ConvexHullTrickCtor []) -> return [Declare t y DeclareDefault] DeclareCopy (Call ConvexHullTrickCopyAddLine [Var x, a, b])- | (x `isMovableTo` y) cont -> do+ | (x `isMovableTo` y) UpdatedCopy env cont -> do modify' (M.insert y x) return [callMethod' (Var x) "add_line" [a, b]] DeclareCopy (Call (SegmentTreeCopySetPoint _) [Var x, i, a])- | (x `isMovableTo` y) cont -> do+ | (x `isMovableTo` y) UpdatedCopy env cont -> do modify' (M.insert y x) return [callMethod' (Var x) "set" [i, a]] _ -> do@@ -118,17 +140,24 @@ return [DeclareDestructure xs e] Assign e -> do e <- runAssignExpr e+ env <- get case e of AssignExpr SimpleAssign (LeftVar y) (Var x) | x == y -> return []+ AssignExpr SimpleAssign (LeftVar y) (Call (SetAt _) [Var x, i, xi])+ | x == y -> return [Assign (AssignExpr SimpleAssign (LeftAt (LeftVar x) i) xi)]+ | (x `isMovableTo` y) UpdatedCopy env cont -> do+ modify' (M.insert y x)+ return [Assign (AssignExpr SimpleAssign (LeftAt (LeftVar x) i) xi)]+ | otherwise -> return [Assign e] AssignExpr SimpleAssign (LeftVar y) (Call ConvexHullTrickCopyAddLine [Var x, a, b]) | x == y -> return [callMethod' (Var x) "add_line" [a, b]]- | (x `isMovableTo` y) cont -> do+ | (x `isMovableTo` y) UpdatedCopy env cont -> do modify' (M.insert y x) return [callMethod' (Var x) "add_line" [a, b]] | otherwise -> return [Assign e] AssignExpr SimpleAssign (LeftVar y) (Call (SegmentTreeCopySetPoint _) [Var x, i, a]) | x == y -> return [callMethod' (Var x) "set" [i, a]]- | (x `isMovableTo` y) cont -> do+ | (x `isMovableTo` y) UpdatedCopy env cont -> do modify' (M.insert y x) return [callMethod' (Var x) "set" [i, a]] | otherwise -> return [Assign e]
src/Jikka/CPlusPlus/Convert/OptimizeRange.hs view
@@ -30,7 +30,7 @@ stmt -> return stmt runProgram :: Monad m => Program -> m Program-runProgram = mapExprStatementProgramM runExpr runStatement+runProgram = mapExprStatementProgramM runExpr (((: []) <$>) . runStatement) -- | `run` replaces superfluous copying. --
src/Jikka/CPlusPlus/Convert/UseInitialization.hs view
@@ -30,7 +30,7 @@ stmt -> stmt runProgram :: Program -> Program-runProgram = mapExprStatementProgram id runStatement+runProgram = mapExprStatementProgram id ((: []) . runStatement) -- | `run` unpack tuples. --
src/Jikka/CPlusPlus/Format.hs view
@@ -239,6 +239,7 @@ e2' = formatExpr' ParenPrec e2 in (e1' ++ "[" ++ e2' ++ "]", FunCallPrec) _ -> error $ "Jikka.CPlusPlus.Language.Format.formatExpr: wrong number of arguments for subscription: " ++ show (length args)+ SetAt t -> call $ "jikka::set_at<" ++ formatType t ++ ">" Cast t -> call $ formatType t StdTuple ts -> call $ "std::tuple<" ++ intercalate ", " (map formatType ts) ++ ">" StdGet n -> call $ "std::get<" ++ show n ++ ">"
src/Jikka/CPlusPlus/Language/Expr.hs view
@@ -78,6 +78,8 @@ Method FunName | -- | subscription @e1[e2]@ At+ | -- | updated array @auto tmp = e1; tmp[e2] = e3; return tmp;@+ SetAt Type | -- | cast @(T)e@ Cast Type | -- | functio @std::tuple\<T1, T2, ...\>(e1, e2, ...)@
src/Jikka/CPlusPlus/Language/Util.hs view
@@ -4,7 +4,7 @@ module Jikka.CPlusPlus.Language.Util where import Control.Monad.Identity-import Data.Char (isAlphaNum)+import Data.Char (isAlphaNum, isNumber) import qualified Data.Set as S import Jikka.CPlusPlus.Language.Expr import Jikka.Common.Alpha@@ -39,7 +39,8 @@ renameVarName :: MonadAlpha m => NameKind -> String -> m VarName renameVarName kind hint = do i <- nextCounter- let prefix = case takeWhile (\c -> isAlphaNum c || c == '_') hint of+ let f = reverse . dropWhile (\c -> isNumber c || c == '_') . reverse . takeWhile (\c -> isAlphaNum c || c == '_')+ let prefix = case f hint of "" -> fromNameKind kind hint' -> hint' ++ "_" return (VarName (prefix ++ show i))@@ -147,7 +148,7 @@ end :: Expr -> Expr end e = Call (Method "end") [e] -mapExprStatementExprM :: Monad m => (Expr -> m Expr) -> (Statement -> m Statement) -> Expr -> m Expr+mapExprStatementExprM :: Monad m => (Expr -> m Expr) -> (Statement -> m [Statement]) -> Expr -> m Expr mapExprStatementExprM f g = go where go = \case@@ -156,33 +157,34 @@ UnOp op e -> f . UnOp op =<< go e BinOp op e1 e2 -> f =<< (BinOp op <$> go e1 <*> go e2) Cond e1 e2 e3 -> f =<< (Cond <$> go e1 <*> go e2 <*> go e3)- Lam args ret body -> f . Lam args ret =<< mapM (mapExprStatementStatementM f g) body+ Lam args ret body -> f . Lam args ret . concat =<< mapM (mapExprStatementStatementM f g) body Call g args -> f . Call g =<< mapM go args CallExpr g args -> f =<< (CallExpr <$> go g <*> mapM go args) -mapExprStatementLeftExprM :: Monad m => (Expr -> m Expr) -> (Statement -> m Statement) -> LeftExpr -> m LeftExpr+mapExprStatementLeftExprM :: Monad m => (Expr -> m Expr) -> (Statement -> m [Statement]) -> LeftExpr -> m LeftExpr mapExprStatementLeftExprM f g = \case LeftVar x -> return $ LeftVar x LeftAt e1 e2 -> LeftAt <$> mapExprStatementLeftExprM f g e1 <*> mapExprStatementExprM f g e2 LeftGet n e -> LeftGet n <$> mapExprStatementLeftExprM f g e -mapExprStatementAssignExprM :: Monad m => (Expr -> m Expr) -> (Statement -> m Statement) -> AssignExpr -> m AssignExpr+mapExprStatementAssignExprM :: Monad m => (Expr -> m Expr) -> (Statement -> m [Statement]) -> AssignExpr -> m AssignExpr mapExprStatementAssignExprM f g = \case AssignExpr op e1 e2 -> AssignExpr op <$> mapExprStatementLeftExprM f g e1 <*> mapExprStatementExprM f g e2 AssignIncr e -> AssignIncr <$> mapExprStatementLeftExprM f g e AssignDecr e -> AssignDecr <$> mapExprStatementLeftExprM f g e -mapExprStatementStatementM :: Monad m => (Expr -> m Expr) -> (Statement -> m Statement) -> Statement -> m Statement+mapExprStatementStatementM :: Monad m => (Expr -> m Expr) -> (Statement -> m [Statement]) -> Statement -> m [Statement] mapExprStatementStatementM f g = go where- go' = mapExprStatementExprM f g+ go' e = mapExprStatementExprM f g e+ go'' body = concat <$> mapM go body go = \case ExprStatement e -> g . ExprStatement =<< go' e- Block stmts -> g . Block =<< mapM go stmts- If e body1 body2 -> g =<< (If <$> go' e <*> mapM go body1 <*> traverse (mapM go) body2)- For t x init pred incr body -> g =<< (For t x <$> go' init <*> go' pred <*> mapExprStatementAssignExprM f g incr <*> mapM go body)- ForEach t x e body -> g =<< (ForEach t x <$> go' e <*> mapM go body)- While e body -> g =<< (While <$> go' e <*> mapM go body)+ Block stmts -> g . Block =<< go'' stmts+ If e body1 body2 -> g =<< (If <$> go' e <*> go'' body1 <*> traverse go'' body2)+ For t x init pred incr body -> g =<< (For t x <$> go' init <*> go' pred <*> mapExprStatementAssignExprM f g incr <*> go'' body)+ ForEach t x e body -> g =<< (ForEach t x <$> go' e <*> go'' body)+ While e body -> g =<< (While <$> go' e <*> go'' body) Declare t x init -> do init <- case init of DeclareDefault -> return DeclareDefault@@ -194,27 +196,61 @@ Assert e -> g . Assert =<< go' e Return e -> g . Return =<< go' e -mapExprStatementToplevelStatementM :: Monad m => (Expr -> m Expr) -> (Statement -> m Statement) -> ToplevelStatement -> m ToplevelStatement+mapExprStatementToplevelStatementM :: Monad m => (Expr -> m Expr) -> (Statement -> m [Statement]) -> ToplevelStatement -> m ToplevelStatement mapExprStatementToplevelStatementM f g = \case VarDef t x e -> VarDef t x <$> mapExprStatementExprM f g e- FunDef ret h args body -> FunDef ret h args <$> mapM (mapExprStatementStatementM f g) body+ FunDef ret h args body -> FunDef ret h args <$> (concat <$> mapM (mapExprStatementStatementM f g) body) StaticAssert e msg -> StaticAssert <$> mapExprStatementExprM f g e <*> pure msg -mapExprStatementProgramM :: Monad m => (Expr -> m Expr) -> (Statement -> m Statement) -> Program -> m Program+mapExprStatementProgramM :: Monad m => (Expr -> m Expr) -> (Statement -> m [Statement]) -> Program -> m Program mapExprStatementProgramM f g (Program decls) = Program <$> mapM (mapExprStatementToplevelStatementM f g) decls -mapExprStatementProgram :: (Expr -> Expr) -> (Statement -> Statement) -> Program -> Program+mapExprStatementProgram :: (Expr -> Expr) -> (Statement -> [Statement]) -> Program -> Program mapExprStatementProgram f g = runIdentity . mapExprStatementProgramM (return . f) (return . g) +mapSubExprM :: Monad m => (Expr -> m Expr) -> Expr -> m Expr+mapSubExprM f e = mapExprStatementExprM f (return . (: [])) e++-- | `mapDirectExprStatementM` replaces exprs which are direct children of a given statement.+mapDirectExprStatementM :: Monad m => (Expr -> m Expr) -> Statement -> m Statement+mapDirectExprStatementM f = \case+ ExprStatement e -> ExprStatement <$> f e+ Block stmts -> return $ Block stmts+ If e body1 body2 -> If <$> f e <*> pure body1 <*> pure body2+ For t x init pred incr body -> For t x <$> f init <*> f pred <*> mapDirectExprAssignExprM f incr <*> pure body+ ForEach t x e body -> ForEach t x <$> f e <*> pure body+ While e body -> While <$> f e <*> pure body+ Declare t x init ->+ Declare t x <$> case init of+ DeclareDefault -> return DeclareDefault+ DeclareCopy e -> DeclareCopy <$> f e+ DeclareInitialize es -> DeclareInitialize <$> mapM f es+ DeclareDestructure xs e -> DeclareDestructure xs <$> f e+ Assign e -> Assign <$> mapDirectExprAssignExprM f e+ Assert e -> Assert <$> f e+ Return e -> Return <$> f e++mapDirectExprAssignExprM :: Monad m => (Expr -> m Expr) -> AssignExpr -> m AssignExpr+mapDirectExprAssignExprM f = \case+ AssignExpr op e1 e2 -> AssignExpr op <$> mapDirectExprLeftExprM f e1 <*> f e2+ AssignIncr e -> AssignIncr <$> mapDirectExprLeftExprM f e+ AssignDecr e -> AssignDecr <$> mapDirectExprLeftExprM f e++mapDirectExprLeftExprM :: Monad m => (Expr -> m Expr) -> LeftExpr -> m LeftExpr+mapDirectExprLeftExprM f = \case+ LeftVar x -> pure $ LeftVar x+ LeftAt e1 e2 -> LeftAt <$> mapDirectExprLeftExprM f e1 <*> f e2+ LeftGet i e -> LeftGet i <$> mapDirectExprLeftExprM f e+ replaceExpr :: VarName -> Expr -> Expr -> Expr-replaceExpr x e = runIdentity . mapExprStatementExprM go return+replaceExpr x e = runIdentity . mapExprStatementExprM go (return . (: [])) where go = \case Var y | y == x -> return e e' -> return e' replaceStatement :: VarName -> Expr -> Statement -> Statement-replaceStatement x e = runIdentity . mapExprStatementStatementM go return+replaceStatement x e = head . runIdentity . mapExprStatementStatementM go (return . (: [])) where go = \case Var y | y == x -> return e
src/Jikka/Common/Error.hs view
@@ -23,6 +23,7 @@ wrapAt', maybeToError, eitherToError,+ fromSuccess, -- * utilities to report multiple errors catchError',@@ -149,6 +150,11 @@ eitherToError :: MonadError a m => Either a b -> m b eitherToError = liftEither++fromSuccess :: Either Error a -> a+fromSuccess f = case f of+ Left err -> error $ "Jikka.Common.Error.fromSuccess: unexpected failure: " ++ show err+ Right y -> y -- | `catchError'` is the inverse of `liftError`. catchError' :: MonadError e m => m a -> m (Either e a)
src/Jikka/Common/Matrix.hs view
@@ -58,8 +58,8 @@ Nothing -> error "Jikka.Common.Matrix.makeMatrix': the input is not a matrix" Just a -> a -matzero :: Num a => Int -> Matrix a-matzero n = Matrix $ V.replicate n (V.replicate n 0)+matzero :: Num a => Int -> Int -> Matrix a+matzero h w = Matrix $ V.replicate h (V.replicate w 0) matone :: Num a => Int -> Matrix a matone n = Matrix $ V.generate n (\y -> V.generate n (\x -> if y == x then 1 else 0))
src/Jikka/Core/Convert.hs view
@@ -18,7 +18,7 @@ import Jikka.Common.Alpha import Jikka.Common.Error import qualified Jikka.Core.Convert.Alpha as Alpha-import qualified Jikka.Core.Convert.ArithmeticalExpr as ArithmeticalExpr+import qualified Jikka.Core.Convert.ArithmeticExpr as ArithmeticExpr import qualified Jikka.Core.Convert.Beta as Beta import qualified Jikka.Core.Convert.BubbleLet as BubbleLet import qualified Jikka.Core.Convert.CloseAll as CloseAll@@ -63,7 +63,7 @@ prog <- CumulativeSum.run prog prog <- SegmentTree.run prog prog <- BubbleLet.run prog- prog <- ArithmeticalExpr.run prog+ prog <- ArithmeticExpr.run prog prog <- ConvexHullTrick.run prog prog <- StrengthReduction.run prog Eta.run prog
+ src/Jikka/Core/Convert/ArithmeticExpr.hs view
@@ -0,0 +1,51 @@+{-# LANGUAGE FlexibleContexts #-}++-- |+-- Module : Jikka.Core.Convert.ArithmeticExpr+-- Description : sorts arithmetical exprs. / 算術式を整理します。+-- Copyright : (c) Kimiyuki Onaka, 2021+-- License : Apache License 2.0+-- Maintainer : kimiyuki95@gmail.com+-- Stability : experimental+-- Portability : portable+module Jikka.Core.Convert.ArithmeticExpr+ ( run,+ )+where++import Jikka.Common.Error+import Jikka.Core.Language.ArithmeticExpr+import Jikka.Core.Language.Expr+import Jikka.Core.Language.Lint+import Jikka.Core.Language.TypeCheck+import Jikka.Core.Language.Util++runExpr :: MonadError Error m => [(VarName, Type)] -> Expr -> m Expr+runExpr env e = do+ t <- typecheckExpr env e+ if t == IntTy+ then return . formatArithmeticExpr $ parseArithmeticExpr e+ else return e++runProgram :: MonadError Error m => Program -> m Program+runProgram = mapExprProgramM (mapSubExprM runExpr) -- Doesn't use RewriteRules because the rewriting may not terminate.++-- | `run` sorts arithmetical exprs.+--+-- == Examples+--+-- Before:+--+-- > 1 + a * 1 + b - b+--+-- After:+--+-- > a + 1+run :: MonadError Error m => Program -> m Program+run prog = wrapError' "Jikka.Core.Convert.ArithmeticExpr" $ do+ precondition $ do+ ensureWellTyped prog+ prog <- runProgram prog+ postcondition $ do+ ensureWellTyped prog+ return prog
− src/Jikka/Core/Convert/ArithmeticalExpr.hs
@@ -1,51 +0,0 @@-{-# LANGUAGE FlexibleContexts #-}---- |--- Module : Jikka.Core.Convert.ArithmeticalExpr--- Description : sorts arithmetical exprs. / 算術式を整理します。--- Copyright : (c) Kimiyuki Onaka, 2021--- License : Apache License 2.0--- Maintainer : kimiyuki95@gmail.com--- Stability : experimental--- Portability : portable-module Jikka.Core.Convert.ArithmeticalExpr- ( run,- )-where--import Jikka.Common.Error-import Jikka.Core.Language.ArithmeticalExpr-import Jikka.Core.Language.Expr-import Jikka.Core.Language.Lint-import Jikka.Core.Language.TypeCheck-import Jikka.Core.Language.Util--runExpr :: MonadError Error m => [(VarName, Type)] -> Expr -> m Expr-runExpr env e = do- t <- typecheckExpr env e- if t == IntTy- then return . formatArithmeticalExpr $ parseArithmeticalExpr e- else return e--runProgram :: MonadError Error m => Program -> m Program-runProgram = mapExprProgramM runExpr -- Doesn't use RewriteRules because the rewriting may not terminate.---- | `run` sorts arithmetical exprs.------ == Examples------ Before:------ > 1 + a * 1 + b - b------ After:------ > a + 1-run :: MonadError Error m => Program -> m Program-run prog = wrapError' "Jikka.Core.Convert.ArithmeticalExpr" $ do- precondition $ do- ensureWellTyped prog- prog <- runProgram prog- postcondition $ do- ensureWellTyped prog- return prog
src/Jikka/Core/Convert/CloseAll.hs view
@@ -34,13 +34,13 @@ mconcat [ -- list build functions [r| "all/nil" all nil = true |],- [r| "all/cons" forall x xs. all (cons x xs) = x and all xs |],+ [r| "all/cons" forall x xs. all (cons x xs) = x && all xs |], -- list map functions [r| "all/reversed" forall xs. all (reversed xs) = all xs |], [r| "all/sorted" forall xs. all (sorted xs) = all xs |],- [r| "all/filter" forall f xs. all (filter f xs) = all (map (fun x -> f x implies x) xs) |],+ [r| "all/filter" forall f xs. all (filter f xs) = all (map (fun x -> implies (f x) x) xs) |], [r| "all/map/not" forall e xs. all (map (fun x -> not e) xs) = not (any (map (fun x -> e) xs)) |],- [r| "all/map/and" forall e1 e2 xs. all (map (fun x -> e1 and e2) xs) = all (map (fun x -> e1) xs) and all (map (fun x -> e2) xs) |]+ [r| "all/map/and" forall e1 e2 xs. all (map (fun x -> e1 && e2) xs) = all (map (fun x -> e1) xs) && all (map (fun x -> e2) xs) |] ] reduceAny :: MonadAlpha m => RewriteRule m@@ -48,14 +48,14 @@ mconcat [ -- list build functions [r| "any/nil" any nil = false |],- [r| "any/cons" forall x xs. any (cons x xs) = x or any xs |],+ [r| "any/cons" forall x xs. any (cons x xs) = x || any xs |], -- list map functions [r| "any/reversed" forall xs. any (reversed xs) = any xs |], [r| "any/sorted" forall xs. any (sorted xs) = any xs |],- [r| "any/filter" forall f xs. any (filter f xs) = any (map (fun x -> f x and x) xs) |],+ [r| "any/filter" forall f xs. any (filter f xs) = any (map (fun x -> f x && x) xs) |], [r| "any/map/not" forall e xs. any (map (fun x -> not e) xs) = not (all (map (fun x -> e) xs)) |],- [r| "any/map/or" forall e1 e2 xs. any (map (fun x -> e1 or e2) xs) = any (map (fun x -> e1) xs) or any (map (fun x -> e2) xs) |],- [r| "any/map/implies" forall e1 e2 xs. any (map (fun x -> e1 implies e2) xs) = any (map (fun x -> not e1) xs) or any (map (fun x -> e2) xs) |]+ [r| "any/map/or" forall e1 e2 xs. any (map (fun x -> e1 || e2) xs) = any (map (fun x -> e1) xs) || any (map (fun x -> e2) xs) |],+ [r| "any/map/implies" forall e1 e2 xs. any (map (fun x -> implies e1 e2) xs) = any (map (fun x -> not e1) xs) || any (map (fun x -> e2) xs) |] ] rule :: MonadAlpha m => RewriteRule m
src/Jikka/Core/Convert/ConstantFolding.hs view
@@ -20,7 +20,7 @@ -- * internal rules rule,- reduceConstArithmeticalExpr,+ reduceConstArithmeticExpr, reduceConstMaxExpr, reduceConstBooleanExpr, reduceConstBitExpr,@@ -57,10 +57,10 @@ -- * `Abs` \(: \int \to \int\) -- * `Gcd` \(: \int \to \int \to \int\) -- * `Lcm` \(: \int \to \int \to \int\)-reduceConstArithmeticalExpr :: Monad m => RewriteRule m-reduceConstArithmeticalExpr =+reduceConstArithmeticExpr :: Monad m => RewriteRule m+reduceConstArithmeticExpr = let return' = Just . LitInt'- in simpleRewriteRule "reduceConstArithmeticalExpr" $ \case+ in simpleRewriteRule "reduceConstArithmeticExpr" $ \case Negate' (LitInt' a) -> return' $ - a Plus' a (LitInt' 0) -> Just a Plus' (LitInt' 0) b -> Just b@@ -209,7 +209,7 @@ rule :: MonadError Error m => RewriteRule m rule = mconcat- [ reduceConstArithmeticalExpr,+ [ reduceConstArithmeticExpr, reduceConstMaxExpr, reduceConstBooleanExpr, reduceConstBitExpr,
src/Jikka/Core/Convert/ConvexHullTrick.hs view
@@ -28,7 +28,7 @@ import Control.Monad.Trans.Maybe import Jikka.Common.Alpha import Jikka.Common.Error-import Jikka.Core.Language.ArithmeticalExpr+import Jikka.Core.Language.ArithmeticExpr import Jikka.Core.Language.Beta import Jikka.Core.Language.BuiltinPatterns import Jikka.Core.Language.Expr@@ -38,22 +38,22 @@ import Jikka.Core.Language.Util -- | This is something commutative because only one kind of @c@ is allowed.-plusPair :: (ArithmeticalExpr, ArithmeticalExpr) -> (ArithmeticalExpr, ArithmeticalExpr) -> Maybe (ArithmeticalExpr, ArithmeticalExpr)-plusPair (a1, c1) (a2, _) | isZeroArithmeticalExpr a2 = Just (a1, c1)-plusPair (a1, c1) (_, c2) | isZeroArithmeticalExpr c2 = Just (a1, c1)-plusPair (a1, _) (a2, c2) | isZeroArithmeticalExpr a1 = Just (a2, c2)-plusPair (_, c1) (a2, c2) | isZeroArithmeticalExpr c1 = Just (a2, c2)+plusPair :: (ArithmeticExpr, ArithmeticExpr) -> (ArithmeticExpr, ArithmeticExpr) -> Maybe (ArithmeticExpr, ArithmeticExpr)+plusPair (a1, c1) (a2, _) | isZeroArithmeticExpr a2 = Just (a1, c1)+plusPair (a1, c1) (_, c2) | isZeroArithmeticExpr c2 = Just (a1, c1)+plusPair (a1, _) (a2, c2) | isZeroArithmeticExpr a1 = Just (a2, c2)+plusPair (_, c1) (a2, c2) | isZeroArithmeticExpr c1 = Just (a2, c2) plusPair (a1, c1) (a2, c2) =- let (k1, c1') = splitConstantFactorArithmeticalExpr c1- (k2, c2') = splitConstantFactorArithmeticalExpr c2- a1' = multArithmeticalExpr (integerArithmeticalExpr k1) a1- a2' = multArithmeticalExpr (integerArithmeticalExpr k2) a2+ let (k1, c1') = splitConstantFactorArithmeticExpr c1+ (k2, c2') = splitConstantFactorArithmeticExpr c2+ a1' = multArithmeticExpr (integerArithmeticExpr k1) a1+ a2' = multArithmeticExpr (integerArithmeticExpr k2) a2 in if c1' == c2'- then Just (plusArithmeticalExpr a1' a2', c1')+ then Just (plusArithmeticExpr a1' a2', c1') else Nothing -sumPairs :: [(ArithmeticalExpr, ArithmeticalExpr)] -> Maybe (ArithmeticalExpr, ArithmeticalExpr)-sumPairs = foldr (\e1 e2 -> plusPair e1 =<< e2) (Just (integerArithmeticalExpr 1, integerArithmeticalExpr 0))+sumPairs :: [(ArithmeticExpr, ArithmeticExpr)] -> Maybe (ArithmeticExpr, ArithmeticExpr)+sumPairs = foldr (\e1 e2 -> plusPair e1 =<< e2) (Just (integerArithmeticExpr 1, integerArithmeticExpr 0)) -- | `parseLinearFunctionBody'` parses the body of a linear function which can be decomposed to convex hull trick. -- @parseLinearFunctionBody' f i j e@ finds a 4-tuple @a, b, c, d@ where @e = a(f[j], j) c(f[< i], i) + b(f[j], j) + d(f[< i], i)@.@@ -63,56 +63,56 @@ parseLinearFunctionBody' f i j e = result <$> go e where result (a, c, b, d) =- let (k, a') = splitConstantFactorArithmeticalExpr a- c' = multArithmeticalExpr (integerArithmeticalExpr k) c- in (formatArithmeticalExpr a', formatArithmeticalExpr c', formatArithmeticalExpr b, formatArithmeticalExpr d)+ let (k, a') = splitConstantFactorArithmeticExpr a+ c' = multArithmeticExpr (integerArithmeticExpr k) c+ in (formatArithmeticExpr a', formatArithmeticExpr c', formatArithmeticExpr b, formatArithmeticExpr d) go = \case Negate' e -> do (a, c, b, d) <- go e- return (a, negateArithmeticalExpr c, negateArithmeticalExpr b, negateArithmeticalExpr d)+ return (a, negateArithmeticExpr c, negateArithmeticExpr b, negateArithmeticExpr d) Plus' e1 e2 -> do (a1, c1, b1, d1) <- go e1 (a2, c2, b2, d2) <- go e2 (a, c) <- plusPair (a1, c1) (a2, c2)- return (a, c, plusArithmeticalExpr b1 b2, plusArithmeticalExpr d1 d2)+ return (a, c, plusArithmeticExpr b1 b2, plusArithmeticExpr d1 d2) Minus' e1 e2 -> do (a1, c1, b1, d1) <- go e1 (a2, c2, b2, d2) <- go e2- (a, c) <- plusPair (a1, c1) (negateArithmeticalExpr a2, c2)- return (a, c, minusArithmeticalExpr b1 b2, minusArithmeticalExpr d1 d2)+ (a, c) <- plusPair (a1, c1) (negateArithmeticExpr a2, c2)+ return (a, c, minusArithmeticExpr b1 b2, minusArithmeticExpr d1 d2) Mult' e1 e2 -> do (a1, c1, b1, d1) <- go e1 (a2, c2, b2, d2) <- go e2 (a, c) <- sumPairs- [ (multArithmeticalExpr a1 a2, multArithmeticalExpr c1 c2),- (multArithmeticalExpr b2 a1, c1),- (multArithmeticalExpr b1 a2, c2),- (a1, multArithmeticalExpr c1 d2),- (a2, multArithmeticalExpr c2 d1),+ [ (multArithmeticExpr a1 a2, multArithmeticExpr c1 c2),+ (multArithmeticExpr b2 a1, c1),+ (multArithmeticExpr b1 a2, c2),+ (a1, multArithmeticExpr c1 d2),+ (a2, multArithmeticExpr c2 d1), (b2, d1), (b1, d2) ]- return (a, c, multArithmeticalExpr b1 b2, multArithmeticalExpr d1 d2)+ return (a, c, multArithmeticExpr b1 b2, multArithmeticExpr d1 d2) e | f `isUnusedVar` e && j `isUnusedVar` e -> -- NOTE: Put constants to @d@ and simplify @a, b@- return (integerArithmeticalExpr 1, integerArithmeticalExpr 0, integerArithmeticalExpr 0, parseArithmeticalExpr e)+ return (integerArithmeticExpr 1, integerArithmeticExpr 0, integerArithmeticExpr 0, parseArithmeticExpr e) e | f `isUnusedVar` e && i `isUnusedVar` e ->- return (integerArithmeticalExpr 1, integerArithmeticalExpr 0, parseArithmeticalExpr e, integerArithmeticalExpr 0)- e@(At' _ (Var f') index) | f' == f -> case unNPlusKPattern (parseArithmeticalExpr index) of+ return (integerArithmeticExpr 1, integerArithmeticExpr 0, parseArithmeticExpr e, integerArithmeticExpr 0)+ e@(At' _ (Var f') index) | f' == f -> case unNPlusKPattern (parseArithmeticExpr index) of Just (i', k) | i' == i && k < 0 -> do- return (integerArithmeticalExpr 1, integerArithmeticalExpr 0, integerArithmeticalExpr 0, parseArithmeticalExpr e)+ return (integerArithmeticExpr 1, integerArithmeticExpr 0, integerArithmeticExpr 0, parseArithmeticExpr e) Just (j', 0) | j' == j -> do- return (integerArithmeticalExpr 1, integerArithmeticalExpr 0, parseArithmeticalExpr e, integerArithmeticalExpr 0)+ return (integerArithmeticExpr 1, integerArithmeticExpr 0, parseArithmeticExpr e, integerArithmeticExpr 0) _ -> Nothing _ -> Nothing parseLinearFunctionBody :: MonadAlpha m => VarName -> VarName -> Integer -> Expr -> m (Maybe (Expr, Expr, Expr, Expr, Expr, Maybe Expr)) parseLinearFunctionBody f i k = runMaybeT . go where- goMin e j step size = case unNPlusKPattern (parseArithmeticalExpr size) of+ goMin e j step size = case unNPlusKPattern (parseArithmeticExpr size) of Just (i', k') | i' == i && k' == k -> do (a, b, c, d) <- hoistMaybe $ parseLinearFunctionBody' f i j step -- raname @j@ to @i@@@ -175,7 +175,8 @@ (Just e, 0) -> do e0 <- lift $ substitute i (LitInt' 0) e d0 <- lift $ substitute i (LitInt' 0) d- let base' = Let f (ListTy IntTy) base $ Snoc' IntTy base (Plus' (Mult' sign e0) d0)+ let e0' = Let f (ListTy IntTy) base e0+ let base' = Snoc' IntTy base (Plus' (Mult' sign e0') d0) c <- lift $ substitute i (Plus' (Var i) (LitInt' 1)) c d <- lift $ substitute i (Plus' (Var i) (LitInt' 1)) d e <- lift $ substitute i (Plus' (Var i) (LitInt' 1)) e
src/Jikka/Core/Convert/CumulativeSum.hs view
@@ -21,7 +21,7 @@ import Jikka.Common.Alpha import Jikka.Common.Error import qualified Jikka.Core.Convert.Alpha as Alpha-import Jikka.Core.Language.ArithmeticalExpr+import Jikka.Core.Language.ArithmeticExpr import Jikka.Core.Language.BuiltinPatterns import Jikka.Core.Language.Expr import Jikka.Core.Language.FreeVars@@ -41,13 +41,13 @@ rule :: MonadAlpha m => RewriteRule m rule = makeRewriteRule "Jikka.Core.Convert.CumulativeSum" $ \_ -> \case Sum' (Map' _ _ (Lam x _ (At' _ a index)) (Range1' n)) | x `isUnusedVar` a -> do- case makeAffineFunctionFromArithmeticalExpr x (parseArithmeticalExpr index) of- Just (coeff, shift) | isOneArithmeticalExpr coeff -> do+ case makeAffineFunctionFromArithmeticExpr x (parseArithmeticExpr index) of+ Just (coeff, shift) | isOneArithmeticExpr coeff -> do b <- genVarName' let e =- if isZeroArithmeticalExpr shift+ if isZeroArithmeticExpr shift then At' IntTy (Var b) n- else Minus' (At' IntTy (Var b) (Plus' n (formatArithmeticalExpr shift))) (At' IntTy (Var b) (formatArithmeticalExpr shift))+ else Minus' (At' IntTy (Var b) (Plus' n (formatArithmeticExpr shift))) (At' IntTy (Var b) (formatArithmeticExpr shift)) return . Just $ Let b (ListTy IntTy) (Scanl' IntTy IntTy (Builtin Plus) Lit0 a) e _ -> return Nothing
src/Jikka/Core/Convert/KubaruToMorau.hs view
@@ -21,7 +21,7 @@ import Control.Monad.Trans.Maybe import Jikka.Common.Alpha import Jikka.Common.Error-import Jikka.Core.Language.ArithmeticalExpr+import Jikka.Core.Language.ArithmeticExpr import Jikka.Core.Language.Beta import Jikka.Core.Language.BuiltinPatterns import Jikka.Core.Language.Expr@@ -40,8 +40,8 @@ | otherwise -> return $ Var x Lit lit -> return $ Lit lit At' _ (Var c') index | c' == c -> case () of- () | parseArithmeticalExpr index == parseArithmeticalExpr (Var i) -> return $ Var x- () | parseArithmeticalExpr index == parseArithmeticalExpr (Var k) -> return $ Var y+ () | parseArithmeticExpr index == parseArithmeticExpr (Var i) -> return $ Var x+ () | parseArithmeticExpr index == parseArithmeticExpr (Var k) -> return $ Var y () | otherwise -> hoistMaybe Nothing App e1 e2 -> App <$> go e1 <*> go e2 Let x t e1 e2@@ -60,9 +60,9 @@ Foldl' IntTy (ListTy t2) (Lam2 b _ i _ (Foldl' IntTy (ListTy t2') (Lam2 c _ j _ (SetAt' _ (Var c') index step)) (Var b') (Range1' m))) a (Range1' n) | t2' == t2 && b' == b && c == c' && b `isUnusedVar` m && b `isUnusedVar` index && b `isUnusedVar` step && c `isUnusedVar` index -> runMaybeT $ do -- m(i) = n - i - 1- guard $ parseArithmeticalExpr m == parseArithmeticalExpr (Minus' (Minus' n (Var i)) (LitInt' 1))+ guard $ parseArithmeticExpr m == parseArithmeticExpr (Minus' (Minus' n (Var i)) (LitInt' 1)) -- index(i, j) = i + j + 1- guard $ parseArithmeticalExpr index == parseArithmeticalExpr (Plus' (Var i) (Plus' (Var j) (LitInt' 1)))+ guard $ parseArithmeticExpr index == parseArithmeticExpr (Plus' (Var i) (Plus' (Var j) (LitInt' 1))) x <- lift genVarName' y <- lift genVarName' k <- lift genVarName'
src/Jikka/Core/Convert/MakeScanl.hs view
@@ -35,7 +35,7 @@ import qualified Data.Map as M import Jikka.Common.Alpha import Jikka.Common.Error-import Jikka.Core.Language.ArithmeticalExpr+import Jikka.Core.Language.ArithmeticExpr import Jikka.Core.Language.Beta import Jikka.Core.Language.BuiltinPatterns import Jikka.Core.Language.Expr@@ -66,7 +66,7 @@ else Nothing let go :: Expr -> Maybe Expr go = \case- At' _ (Var a') i' | a' == a -> case unNPlusKPattern (parseArithmeticalExpr i') of+ At' _ (Var a') i' | a' == a -> case unNPlusKPattern (parseArithmeticExpr i') of Just (i', k) | i' == i -> proj k _ -> Nothing Var x -> if x == a then Nothing else Just (Var x)@@ -90,7 +90,7 @@ else Nothing let go :: Expr -> Maybe Expr go = \case- At' _ (Var a') i' | a' == a -> case unNPlusKPattern (parseArithmeticalExpr i') of+ At' _ (Var a') i' | a' == a -> case unNPlusKPattern (parseArithmeticExpr i') of Just (i', k) | i' == i -> proj k _ -> Nothing Var x -> if x == a then Nothing else Just (Var x)@@ -112,7 +112,7 @@ -- foldl (fun a i -> setat a index(i) step(a, i)) base indices Foldl' _ (ListTy t2) (Lam2 a _ i _ (SetAt' _ (Var a') index step)) base indices | a' == a && a `isUnusedVar` index -> runMaybeT $ do -- index(i) = i + k- k <- hoistMaybe $ case unNPlusKPattern (parseArithmeticalExpr index) of+ k <- hoistMaybe $ case unNPlusKPattern (parseArithmeticExpr index) of Just (i', k) | i' == i -> Just k _ -> Nothing -- indices = range n@@ -184,12 +184,12 @@ -- (i, k) in env menas a[i + k] is accessible but a[i + k + 1] is not. go :: M.Map VarName Integer -> Expr -> Bool go env = \case- At' _ (Var a') i | a' == a -> case unNPlusKPattern (parseArithmeticalExpr i) of+ At' _ (Var a') i | a' == a -> case unNPlusKPattern (parseArithmeticExpr i) of Just (i, k) -> case M.lookup i env of Just limit -> k <= limit Nothing -> False _ -> False- Map' _ _ (Lam j _ body) (Range1' n) | j /= a -> case unNPlusKPattern (parseArithmeticalExpr n) of+ Map' _ _ (Lam j _ body) (Range1' n) | j /= a -> case unNPlusKPattern (parseArithmeticExpr n) of Just (i, k) -> case M.lookup i env of Just limit -> go (M.insert j (limit - k + 1) env) body Nothing -> go env body && go env n@@ -206,7 +206,7 @@ -- foldl (fun a i -> setat a index(i) step(a, i)) base indices Foldl' _ (ListTy t2) (Lam2 a _ i _ (SetAt' _ (Var a') index step)) base indices | a' == a && a `isUnusedVar` index -> runMaybeT $ do -- index(i) = i + k- k <- hoistMaybe $ case unNPlusKPattern (parseArithmeticalExpr index) of+ k <- hoistMaybe $ case unNPlusKPattern (parseArithmeticExpr index) of Just (i', k) | i' == i -> Just k _ -> Nothing -- indices = range n
src/Jikka/Core/Convert/MatrixExponentiation.hs view
@@ -21,7 +21,7 @@ import Jikka.Common.Alpha import Jikka.Common.Error import Jikka.Common.Matrix-import Jikka.Core.Language.ArithmeticalExpr+import Jikka.Core.Language.ArithmeticExpr import Jikka.Core.Language.BuiltinPatterns import Jikka.Core.Language.Expr import Jikka.Core.Language.FreeVars@@ -31,29 +31,29 @@ toLinearExpression :: VarName -> Expr -> Maybe (Maybe Expr, Maybe Expr) toLinearExpression x e = do- (a, b) <- makeVectorFromArithmeticalExpr (V.singleton x) (parseArithmeticalExpr e)+ (a, b) <- makeVectorFromArithmeticExpr (V.singleton x) (parseArithmeticExpr e) case V.toList a of [a] ->- let a' = if isOneArithmeticalExpr a then Nothing else Just (formatArithmeticalExpr a)- b' = if isZeroArithmeticalExpr b then Nothing else Just (formatArithmeticalExpr b)+ let a' = if isOneArithmeticExpr a then Nothing else Just (formatArithmeticExpr a)+ b' = if isZeroArithmeticExpr b then Nothing else Just (formatArithmeticExpr b) in Just (a', b') _ -> error $ "Jikka.Core.Convert.MatrixExponentiation.toLinearExpression: size mismtach: " ++ show (V.length a) -fromMatrix :: Matrix ArithmeticalExpr -> Expr+fromMatrix :: Matrix ArithmeticExpr -> Expr fromMatrix f = let (h, w) = matsize f- go row = uncurryApp (Tuple' (replicate w IntTy)) (map formatArithmeticalExpr (V.toList row))+ go row = uncurryApp (Tuple' (replicate w IntTy)) (map formatArithmeticExpr (V.toList row)) in uncurryApp (Tuple' (replicate h (TupleTy (replicate w IntTy)))) (map go (V.toList (unMatrix f))) -fromAffineMatrix :: Matrix ArithmeticalExpr -> V.Vector ArithmeticalExpr -> Expr+fromAffineMatrix :: Matrix ArithmeticExpr -> V.Vector ArithmeticExpr -> Expr fromAffineMatrix a b | fst (matsize a) /= V.length b = error $ "Jikka.Core.Convert.MatrixExponentiation.fromAffineMatrix: size mismtach: " ++ show (matsize a) ++ " and " ++ show (V.length b) fromAffineMatrix a b = let (h, w) = matsize a- go row c = uncurryApp (Tuple' (replicate (w + 1) IntTy)) (map formatArithmeticalExpr (V.toList row ++ [c]))+ go row c = uncurryApp (Tuple' (replicate (w + 1) IntTy)) (map formatArithmeticExpr (V.toList row ++ [c])) bottom = uncurryApp (Tuple' (replicate (w + 1) IntTy)) (replicate w (LitInt' 0) ++ [LitInt' 1]) in uncurryApp (Tuple' (replicate (h + 1) (TupleTy (replicate (w + 1) IntTy)))) (V.toList (V.zipWith go (unMatrix a) b) ++ [bottom]) -toMatrix :: MonadAlpha m => [(VarName, Type)] -> VarName -> Integer -> Expr -> m (Maybe (Matrix ArithmeticalExpr, Maybe (V.Vector ArithmeticalExpr)))+toMatrix :: MonadAlpha m => [(VarName, Type)] -> VarName -> Integer -> Expr -> m (Maybe (Matrix ArithmeticExpr, Maybe (V.Vector ArithmeticExpr))) toMatrix env x n step = case curryApp step of (Tuple' _, es) -> runMaybeT $ do@@ -62,11 +62,11 @@ Proj' _ i (Var x') | x' == x -> Var (xs V.! fromInteger i) _ -> e rows <- MaybeT . return . forM es $ \e -> do- let e' = mapExpr unpackTuple env e+ let e' = mapSubExpr unpackTuple env e guard $ x `isUnusedVar` e'- makeVectorFromArithmeticalExpr xs (parseArithmeticalExpr e')+ makeVectorFromArithmeticExpr xs (parseArithmeticExpr e') a <- MaybeT . return $ makeMatrix (V.fromList (map fst rows))- let b = if all (isZeroArithmeticalExpr . snd) rows then Nothing else Just (V.fromList (map snd rows))+ let b = if all (isZeroArithmeticExpr . snd) rows then Nothing else Just (V.fromList (map snd rows)) return (a, b) _ -> return Nothing
src/Jikka/Core/Convert/RemoveUnusedVars.hs view
@@ -24,7 +24,7 @@ import Jikka.Core.Language.Util runExpr :: [(VarName, Type)] -> Expr -> Expr-runExpr _ = mapExpr go []+runExpr _ = mapSubExpr go [] where go _ = \case Let x _ _ e2 | x `isUnusedVar` e2 -> e2@@ -40,7 +40,7 @@ e -> e run' :: Program -> Program-run' = mapToplevelExprProgram runToplevelExpr . mapExprProgram runExpr+run' = mapToplevelExprProgram runToplevelExpr . mapExprProgram (mapSubExpr runExpr) -- | `run` removes unused variables in given programs. --
src/Jikka/Core/Convert/ShortCutFusion.hs view
@@ -85,7 +85,7 @@ mconcat [ [r| "map/map" forall f g xs. map g (map f xs) = map (fun x -> g (f x)) xs |], [r| "map/reversed" forall f xs. map f (reversed xs) = reversed (map f xs) |],- [r| "filter/filter" forall f g xs. filter g (filter f xs) = filter (fun x -> f x and g x) xs |],+ [r| "filter/filter" forall f g xs. filter g (filter f xs) = filter (fun x -> f x && g x) xs |], [r| "filter/sorted" forall f xs. filter f (sorted xs) = sorted (filter f xs) |], [r| "filter/reversed" forall f xs. filter f (reversed xs) = reversed (filter f xs) |], [r| "reversed/reversed" forall xs. reversed (reversed xs) = xs |],@@ -136,8 +136,8 @@ [r| "at/range" forall n i. (range n)[i] = i |], -- reduce `Elem` [r| "elem/nil" forall y. elem y nil = false |],- [r| "elem/cons" forall y x xs. elem y (cons x xs) = y == x or elem y xs |],- [r| "elem/range" forall i n. elem i (range n) = 0 <= i and i < n |],+ [r| "elem/cons" forall y x xs. elem y (cons x xs) = y == x || elem y xs |],+ [r| "elem/range" forall i n. elem i (range n) = 0 <= i && i < n |], -- others [r| "len/build" forall f base n. len (build f base n) = len base + n |] ]
src/Jikka/Core/Convert/TypeInfer.hs view
@@ -21,6 +21,7 @@ mergeAssertions, Subst (..), subst,+ substDefault, solveEquations, substProgram, )@@ -34,6 +35,7 @@ import Jikka.Common.Alpha import Jikka.Common.Error import Jikka.Core.Format (formatType)+import Jikka.Core.Language.BuiltinPatterns import Jikka.Core.Language.Expr import Jikka.Core.Language.FreeVars import Jikka.Core.Language.Lint@@ -59,7 +61,9 @@ t <- genType formularizeVarName x t return t- Lit lit -> literalToType lit+ Lit lit -> case lit of+ LitBuiltin (Proj _) [] -> genType -- Proj may have a empty list.+ _ -> literalToType lit App f e -> do ret <- genType t <- formularizeExpr e@@ -166,26 +170,36 @@ solveEquations eqns = wrapError' "failed to solve type equations" $ do execStateT (mapM_ (uncurry unifyType) eqns) (Subst M.empty) --- | `substUnit` replaces all undetermined type variables with the unit type.-substUnit :: Type -> Type-substUnit = \case+-- | `substDefault` replaces all undetermined type variables with the given default type.+substDefault :: Type -> Type -> Type+substDefault t0 = \case VarTy _ -> TupleTy [] IntTy -> IntTy BoolTy -> BoolTy- ListTy t -> ListTy (substUnit t)- TupleTy ts -> TupleTy (map substUnit ts)- FunTy t ret -> FunTy (substUnit t) (substUnit ret)+ ListTy t -> ListTy (substDefault t0 t)+ TupleTy ts -> TupleTy (map (substDefault t0) ts)+ FunTy t ret -> FunTy (substDefault t0 t) (substDefault t0 ret) DataStructureTy ds -> DataStructureTy ds -subst' :: Subst -> Type -> Type-subst' sigma = substUnit . subst sigma+subst' :: Maybe Type -> Subst -> Type -> Type+subst' t0 sigma = maybe id substDefault t0 . subst sigma -substProgram :: Subst -> Program -> Program-substProgram sigma = mapTypeProgram (subst' sigma)+fixProj :: MonadError Error m => [(VarName, Type)] -> Expr -> m Expr+fixProj env = \case+ Proj' [] i e -> do+ -- fix Proj with a empty list+ t <- typecheckExpr env e+ case t of+ TupleTy ts -> return $ Proj' ts i e+ _ -> throwInternalError $ "type of argument of proj must be a tuple: " ++ formatType t+ e -> return e -substExpr :: Subst -> Expr -> Expr-substExpr sigma = mapTypeExpr (subst' sigma)+substProgram :: MonadError Error m => Maybe Type -> Subst -> Program -> m Program+substProgram t0 sigma = mapExprProgramM (mapSubExprM fixProj) . mapTypeProgram (subst' t0 sigma) +substExpr :: MonadError Error m => Maybe Type -> Subst -> [(VarName, Type)] -> Expr -> m Expr+substExpr t0 sigma env = mapSubExprM fixProj env . mapTypeExpr (subst' t0 sigma)+ -- | `run` does type inference. -- -- * This assumes that program has no name conflicts.@@ -207,7 +221,8 @@ let (eqns', assertions) = sortEquations eqns let eqns'' = mergeAssertions assertions sigma <- solveEquations (eqns' ++ eqns'')- prog <- return $ substProgram sigma prog+ let t0 = Just UnitTy+ prog <- substProgram t0 sigma prog postcondition $ do typecheckProgram prog return prog@@ -218,8 +233,9 @@ let (eqns', assertions) = sortEquations eqns let eqns'' = mergeAssertions assertions sigma <- solveEquations (eqns' ++ eqns'')- env <- return $ map (second (subst' sigma)) env- e <- return $ substExpr sigma e+ let t0 = Nothing -- don't use substDefault+ env <- return $ map (second (subst' t0 sigma)) env+ e <- substExpr t0 sigma env e postcondition $ do typecheckExpr env e return e@@ -232,7 +248,7 @@ let (eqns', assertions) = sortEquations eqns let eqns'' = mergeAssertions assertions sigma <- solveEquations (eqns' ++ eqns'')- args <- return $ map (second (subst sigma)) args -- don't use substUnit- e1 <- return $ mapTypeExpr (subst sigma) e1 -- don't use substUnit- e2 <- return $ mapTypeExpr (subst sigma) e2 -- don't use substUnit+ args <- return $ map (second (subst sigma)) args -- don't use substDefault+ e1 <- return $ mapTypeExpr (subst sigma) e1 -- don't use substDefault+ e2 <- return $ mapTypeExpr (subst sigma) e2 -- don't use substDefault return (args, e1, e2)
src/Jikka/Core/Evaluate.hs view
@@ -187,7 +187,7 @@ BitRightShift -> go2 valueToInt valueToInt ValInt $ \a b -> a `shift` fromInteger (- b) -- matrix functions MatAp _ _ -> go2' valueToMatrix valueToVector valueFromVector matap'- MatZero n -> go0 valueFromMatrix (matzero (fromInteger n))+ MatZero h w -> go0 valueFromMatrix (matzero (fromInteger h) (fromInteger w)) MatOne n -> go0 valueFromMatrix (matone (fromInteger n)) MatAdd _ _ -> go2' valueToMatrix valueToMatrix valueFromMatrix matadd' MatMul _ _ _ -> go2' valueToMatrix valueToMatrix valueFromMatrix matmul'
src/Jikka/Core/Format.hs view
@@ -114,7 +114,7 @@ ListTy t -> (resolvePrec funCallPrec (formatType' t) ++ " list", funCallPrec) TupleTy ts -> case ts of [] -> ("unit", identPrec)- [t] -> (resolvePrec (pred multPrec) (formatType' t) ++ ",", multPrec)+ [t] -> (resolvePrec funCallPrec (formatType' t) ++ " one_tuple", funCallPrec) _ -> (intercalate " * " (map (resolvePrec (pred multPrec) . formatType') ts), multPrec) FunTy t1 t2 -> (resolvePrecLeft impliesPrec RightToLeft (formatType' t1) ++ " -> " ++ resolvePrecRight impliesPrec RightToLeft (formatType' t2), impliesPrec)@@ -125,16 +125,16 @@ formatDataStructure :: DataStructure -> String formatDataStructure = \case- ConvexHullTrick -> "convex-hull-trick"- SegmentTree semigrp -> "segment-tree<" ++ formatSemigroup semigrp ++ ">"+ ConvexHullTrick -> "convex_hull_trick"+ SegmentTree semigrp -> "segment_tree<" ++ formatSemigroup semigrp ++ ">" formatSemigroup :: Semigroup' -> String formatSemigroup = \case- SemigroupIntPlus -> "int.plus"- SemigroupIntMin -> "int.min"- SemigroupIntMax -> "int.max"- SemigroupIntGcd -> "int.gcd"- SemigroupIntLcm -> "int.lcm"+ SemigroupIntPlus -> "int_plus"+ SemigroupIntMin -> "int_min"+ SemigroupIntMax -> "int_max"+ SemigroupIntGcd -> "int_gcd"+ SemigroupIntLcm -> "int_lcm" data Builtin' = Fun String@@ -147,6 +147,9 @@ | If' deriving (Eq, Ord, Show, Read) +funMat :: String -> [Integer] -> Builtin'+funMat f args = Fun $ intercalate "@" (f : map show args)+ analyzeBuiltin :: Builtin -> Builtin' analyzeBuiltin = \case -- arithmetical functions@@ -163,13 +166,13 @@ Abs -> Fun "abs" Gcd -> Fun "gcd" Lcm -> Fun "lcm"- Min2 -> InfixOp "<?" appendPrec LeftToRight- Max2 -> InfixOp ">?" appendPrec LeftToRight+ Min2 -> Fun "min"+ Max2 -> Fun "max" -- logical functions- Not -> PrefixOp "not"- And -> InfixOp "and" andPrec RightToLeft- Or -> InfixOp "or" orPrec RightToLeft- Implies -> InfixOp "implies" impliesPrec RightToLeft+ Not -> Fun "not"+ And -> InfixOp "&&" andPrec RightToLeft+ Or -> InfixOp "||" orPrec RightToLeft+ Implies -> Fun "implies" If -> If' -- bitwise functions BitNot -> PrefixOp "~"@@ -179,14 +182,14 @@ BitLeftShift -> InfixOp "<<" powerPrec LeftToRight BitRightShift -> InfixOp ">>" powerPrec LeftToRight -- matrix functions- MatAp _ _ -> Fun "matap"- MatZero _ -> Fun "matzero"- MatOne _ -> Fun "matone"- MatAdd _ _ -> Fun "matadd"- MatMul _ _ _ -> Fun "matmul"- MatPow _ -> Fun "matpow"- VecFloorMod _ -> Fun "vecfloormod"- MatFloorMod _ _ -> Fun "matfloormod"+ MatAp h w -> funMat "matap" [h, w]+ MatZero h w -> funMat "matzero" [h, w]+ MatOne n -> funMat "matone" [n]+ MatAdd h w -> funMat "matadd" [h, w]+ MatMul h n w -> funMat "matmul" [h, n, w]+ MatPow n -> funMat "matpow" [n]+ VecFloorMod n -> funMat "vecfloormod" [n]+ MatFloorMod h w -> funMat "matfloormod" [h, w] -- modular functions ModNegate -> Fun "modnegate" ModPlus -> Fun "modplus"@@ -194,10 +197,10 @@ ModMult -> Fun "modmult" ModInv -> Fun "modinv" ModPow -> Fun "modpow"- ModMatAp _ _ -> Fun "modmatap"- ModMatAdd _ _ -> Fun "modmatadd"- ModMatMul _ _ _ -> Fun "modmatmul"- ModMatPow _ -> Fun "modmatpow"+ ModMatAp h w -> funMat "modmatap" [h, w]+ ModMatAdd h w -> funMat "modmatadd" [h, w]+ ModMatMul h n w -> funMat "modmatmul" [h, n, w]+ ModMatPow n -> funMat "modmatpow" [n] -- list functions Cons -> Fun "cons" Snoc -> Fun "snoc"@@ -215,12 +218,12 @@ Product -> Fun "product" ModSum -> Fun "modsum" ModProduct -> Fun "modproduct"- Min1 -> Fun "min"- Max1 -> Fun "max"+ Min1 -> Fun "minimum"+ Max1 -> Fun "maximum" ArgMin -> Fun "argmin" ArgMax -> Fun "argmax"- Gcd1 -> Fun "gcd"- Lcm1 -> Fun "lcm"+ Gcd1 -> Fun "gcds"+ Lcm1 -> Fun "lcms" All -> Fun "all" Any -> Fun "any" Sorted -> Fun "sort"@@ -244,22 +247,22 @@ Permute -> Fun "permute" MultiChoose -> Fun "multichoose" -- data structures- ConvexHullTrickInit -> Fun "cht.init"- ConvexHullTrickGetMin -> Fun "cht.getmin"- ConvexHullTrickInsert -> Fun "cht.insert"- SegmentTreeInitList _ -> Fun "segtree.initlist"- SegmentTreeGetRange _ -> Fun "segtree.getrange"- SegmentTreeSetPoint _ -> Fun "segtree.setpoint"+ ConvexHullTrickInit -> Fun "cht_init"+ ConvexHullTrickGetMin -> Fun "cht_getmin"+ ConvexHullTrickInsert -> Fun "cht_insert"+ SegmentTreeInitList _ -> Fun "segtree_initlist"+ SegmentTreeGetRange _ -> Fun "segtree_getrange"+ SegmentTreeSetPoint _ -> Fun "segtree_setpoint" formatTemplate :: [Type] -> String-formatTemplate = \case- [] -> ""- ts -> "<" ++ intercalate ", " (map formatType ts) ++ ">"+formatTemplate ts = concatMap (('@' :) . formatType) ts formatFunCall :: (String, Prec) -> [Expr] -> (String, Prec)-formatFunCall f = \case- [] -> f- args -> (resolvePrec funCallPrec f ++ "(" ++ intercalate ", " (map (resolvePrec commaPrec . formatExpr') args) ++ ")", funCallPrec)+formatFunCall f [] = f+formatFunCall f args =+ let f' = resolvePrecLeft funCallPrec LeftToRight f+ args' = map (resolvePrecRight funCallPrec LeftToRight . formatExpr') args+ in (unwords (f' : args'), funCallPrec) formatBuiltinIsolated' :: Builtin' -> [Type] -> String formatBuiltinIsolated' builtin ts = case builtin of@@ -275,30 +278,30 @@ formatBuiltinIsolated :: Builtin -> [Type] -> String formatBuiltinIsolated builtin ts = formatBuiltinIsolated' (analyzeBuiltin builtin) ts -formatBuiltin' :: Builtin' -> [Type] -> [Expr] -> (String, Prec)-formatBuiltin' builtin ts args = case (builtin, ts, args) of+formatBuiltin' :: Builtin -> [Type] -> [Expr] -> (String, Prec)+formatBuiltin' builtin ts args = case (analyzeBuiltin builtin, ts, args) of (Fun "map", _, [Lam x IntTy e, Range1' n]) | x `isUnusedVar` e -> formatFunCall ("replicate", identPrec) [n, e] (Fun name, _, _) -> formatFunCall (name, identPrec) args (PrefixOp op, _, e1 : args) -> formatFunCall (op ++ " " ++ resolvePrec unaryPrec (formatExpr' e1), unaryPrec) args (InfixOp op prec assoc, _, e1 : e2 : args) -> formatFunCall (resolvePrecLeft prec assoc (formatExpr' e1) ++ " " ++ op ++ " " ++ resolvePrecRight prec assoc (formatExpr' e2), prec) args (At', _, e1 : e2 : args) -> formatFunCall (resolvePrec identPrec (formatExpr' e1) ++ "[" ++ resolvePrec parenPrec (formatExpr' e2) ++ "]", identPrec) args- (SetAt', _, e1 : e2 : e3 : args) -> formatFunCall (resolvePrec identPrec (formatExpr' e1) ++ "[" ++ resolvePrec parenPrec (formatExpr' e2) ++ " := " ++ resolvePrec parenPrec (formatExpr' e3) ++ "]", identPrec) args+ (SetAt', _, e1 : e2 : e3 : args) -> formatFunCall (resolvePrec identPrec (formatExpr' e1) ++ "[" ++ resolvePrec parenPrec (formatExpr' e2) ++ " <- " ++ resolvePrec parenPrec (formatExpr' e3) ++ "]", identPrec) args (Tuple', [_], e : args) -> formatFunCall (paren (resolvePrec commaPrec (formatExpr' e) ++ ","), identPrec) args (Tuple', _, args) | length args >= length ts -> formatFunCall (paren (intercalate ", " (map (resolvePrec commaPrec . formatExpr') (take (length ts) args))), identPrec) (drop (length ts) args) (Proj' n, _, e : args) -> formatFunCall (resolvePrec identPrec (formatExpr' e) ++ "." ++ show n, identPrec) args (If', _, e1 : e2 : e3 : args) -> formatFunCall ("if" ++ " " ++ resolvePrec parenPrec (formatExpr' e1) ++ " then " ++ resolvePrec parenPrec (formatExpr' e2) ++ " else " ++ resolvePrec lambdaPrec (formatExpr' e3), lambdaPrec) args- _ -> formatFunCall (formatBuiltinIsolated' builtin ts, identPrec) args+ _ -> formatFunCall (formatBuiltinIsolated' (analyzeBuiltin builtin) ts, identPrec) args formatBuiltin :: Builtin -> [Type] -> [Expr] -> String-formatBuiltin f ts args = resolvePrec parenPrec (formatBuiltin' (analyzeBuiltin f) ts args)+formatBuiltin f ts args = resolvePrec parenPrec (formatBuiltin' f ts args) formatLiteral :: Literal -> String formatLiteral = \case LitBuiltin builtin ts -> formatBuiltinIsolated builtin ts LitInt n -> show n LitBool p -> map toLower $ show p- LitNil t -> "nil" ++ formatTemplate [t]- LitBottom t _ -> "bottom" ++ formatTemplate [t]+ LitNil _ -> "nil"+ LitBottom _ msg -> "bottom<" ++ show msg ++ ">" formatFormalArgs :: [(VarName, Type)] -> String formatFormalArgs args = unwords $ map (\(x, t) -> paren (unVarName x ++ ": " ++ formatType t)) args@@ -311,15 +314,15 @@ let (f, args) = curryApp e in case f of Var x -> formatFunCall (unVarName x, identPrec) args- Lit (LitBuiltin builtin ts) -> (formatBuiltin builtin ts args, identPrec)+ Lit (LitBuiltin builtin ts) -> formatBuiltin' builtin ts args _ -> formatFunCall (formatExpr' f) args LamId _ -> ("id", identPrec) LamConst _ e -> formatFunCall ("const", identPrec) [e] e@(Lam _ _ _) -> let (args, body) = uncurryLam e in ("fun " ++ formatFormalArgs args ++ " ->\n" ++ indent ++ "\n" ++ resolvePrec parenPrec (formatExpr' body) ++ "\n" ++ dedent ++ "\n", lambdaPrec)- Let x t e1 e2 -> ("let " ++ unVarName x ++ ": " ++ formatType t ++ " =\n" ++ indent ++ "\n" ++ resolvePrec parenPrec (formatExpr' e1) ++ "\n" ++ dedent ++ "\nin " ++ resolvePrec lambdaPrec (formatExpr' e2), lambdaPrec)- Assert e1 e2 -> ("assert " ++ resolvePrec parenPrec (formatExpr' e1) ++ " in " ++ resolvePrec lambdaPrec (formatExpr' e2), lambdaPrec)+ Let x t e1 e2 -> ("let " ++ unVarName x ++ ": " ++ formatType t ++ " = " ++ resolvePrec parenPrec (formatExpr' e1) ++ "\nin " ++ resolvePrec lambdaPrec (formatExpr' e2), lambdaPrec)+ Assert e1 e2 -> ("assert " ++ resolvePrec parenPrec (formatExpr' e1) ++ " in\n" ++ resolvePrec lambdaPrec (formatExpr' e2), lambdaPrec) formatExpr :: Expr -> String formatExpr = unlines . makeIndentFromMarkers 4 . lines . resolvePrec parenPrec . formatExpr'
+ src/Jikka/Core/Language/ArithmeticExpr.hs view
@@ -0,0 +1,282 @@+{-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE LambdaCase #-}+{-# LANGUAGE TupleSections #-}++module Jikka.Core.Language.ArithmeticExpr+ ( -- * Basic functions+ ArithmeticExpr,+ parseArithmeticExpr,+ formatArithmeticExpr,+ integerArithmeticExpr,+ negateArithmeticExpr,+ plusArithmeticExpr,+ minusArithmeticExpr,+ multArithmeticExpr,+ isZeroArithmeticExpr,+ isOneArithmeticExpr,++ -- * Advanced functions+ unNPlusKPattern,+ makeVectorFromArithmeticExpr,+ makeAffineFunctionFromArithmeticExpr,+ splitConstantFactorArithmeticExpr,+ )+where++import Control.Arrow+import Control.Monad+import Control.Monad.ST+import Control.Monad.Trans+import Control.Monad.Trans.Maybe+import Data.List (findIndices, groupBy, sort, sortBy)+import Data.STRef+import qualified Data.Vector as V+import qualified Data.Vector.Mutable as MV+import Jikka.Core.Language.BuiltinPatterns+import Jikka.Core.Language.Expr+import Jikka.Core.Language.FreeVars++data ProductExpr = ProductExpr+ { productExprConst :: Integer,+ productExprList :: [Expr]+ }+ deriving (Eq, Ord, Show, Read)++data SumExpr = SumExpr+ { sumExprList :: [ProductExpr],+ sumExprConst :: Integer+ }+ deriving (Eq, Ord, Show, Read)++newtype ArithmeticExpr = ArithmeticExpr {unArithmeticExpr :: SumExpr}+ deriving (Show)++instance Eq ArithmeticExpr where+ e1 == e2 = unArithmeticExpr (normalizeArithmeticExpr e1) == unArithmeticExpr (normalizeArithmeticExpr e2)++instance Ord ArithmeticExpr where+ e1 `compare` e2 = unArithmeticExpr (normalizeArithmeticExpr e1) `compare` unArithmeticExpr (normalizeArithmeticExpr e2)++integerProductExpr :: Integer -> ProductExpr+integerProductExpr n =+ ProductExpr+ { productExprConst = n,+ productExprList = []+ }++negateProductExpr :: ProductExpr -> ProductExpr+negateProductExpr e = e {productExprConst = negate (productExprConst e)}++multProductExpr :: ProductExpr -> ProductExpr -> ProductExpr+multProductExpr e1 e2 =+ ProductExpr+ { productExprConst = productExprConst e1 * productExprConst e2,+ productExprList = productExprList e1 ++ productExprList e2+ }++iterateN :: Integer -> (a -> a) -> a -> a+iterateN n _ _ | n < 0 = error $ "iterateN: negative number: " ++ show n+iterateN 0 _ x = x+iterateN n f x = iterateN (n - 1) f (f x)++parseProductExpr :: Expr -> ProductExpr+parseProductExpr = \case+ LitInt' n -> ProductExpr {productExprConst = n, productExprList = []}+ Negate' e -> negateProductExpr (parseProductExpr e)+ Mult' e1 e2 -> multProductExpr (parseProductExpr e1) (parseProductExpr e2)+ Pow' e1 (LitInt' k) | 0 <= k && k < 10 -> iterateN k (multProductExpr (parseProductExpr e1)) (integerProductExpr 1)+ e -> ProductExpr {productExprConst = 1, productExprList = [e]}++sumExprFromProductExpr :: ProductExpr -> SumExpr+sumExprFromProductExpr e =+ SumExpr+ { sumExprList = [e],+ sumExprConst = 0+ }++arithmeticalExprFromProductExpr :: ProductExpr -> ArithmeticExpr+arithmeticalExprFromProductExpr = ArithmeticExpr . sumExprFromProductExpr++integerSumExpr :: Integer -> SumExpr+integerSumExpr n =+ SumExpr+ { sumExprConst = n,+ sumExprList = []+ }++integerArithmeticExpr :: Integer -> ArithmeticExpr+integerArithmeticExpr = ArithmeticExpr . integerSumExpr++negateSumExpr :: SumExpr -> SumExpr+negateSumExpr e =+ SumExpr+ { sumExprList = map negateProductExpr (sumExprList e),+ sumExprConst = negate (sumExprConst e)+ }++plusSumExpr :: SumExpr -> SumExpr -> SumExpr+plusSumExpr e1 e2 =+ SumExpr+ { sumExprList = sumExprList e1 ++ sumExprList e2,+ sumExprConst = sumExprConst e1 + sumExprConst e2+ }++multSumExpr :: SumExpr -> SumExpr -> SumExpr+multSumExpr e1 e2 =+ SumExpr+ { sumExprList =+ let es1 = parseProductExpr (LitInt' (sumExprConst e1)) : sumExprList e1+ es2 = parseProductExpr (LitInt' (sumExprConst e2)) : sumExprList e2+ in tail $ map (uncurry multProductExpr) ((,) <$> es1 <*> es2),+ sumExprConst = sumExprConst e1 * sumExprConst e2+ }++negateArithmeticExpr :: ArithmeticExpr -> ArithmeticExpr+negateArithmeticExpr (ArithmeticExpr e) = ArithmeticExpr $ negateSumExpr e++plusArithmeticExpr :: ArithmeticExpr -> ArithmeticExpr -> ArithmeticExpr+plusArithmeticExpr (ArithmeticExpr e1) (ArithmeticExpr e2) = ArithmeticExpr $ plusSumExpr e1 e2++minusArithmeticExpr :: ArithmeticExpr -> ArithmeticExpr -> ArithmeticExpr+minusArithmeticExpr (ArithmeticExpr e1) (ArithmeticExpr e2) = ArithmeticExpr $ plusSumExpr e1 (negateSumExpr e2)++multArithmeticExpr :: ArithmeticExpr -> ArithmeticExpr -> ArithmeticExpr+multArithmeticExpr (ArithmeticExpr e1) (ArithmeticExpr e2) = ArithmeticExpr $ multSumExpr e1 e2++parseSumExpr :: Expr -> SumExpr+parseSumExpr = \case+ LitInt' n -> SumExpr {sumExprList = [], sumExprConst = n}+ Negate' e -> negateSumExpr (parseSumExpr e)+ Plus' e1 e2 -> plusSumExpr (parseSumExpr e1) (parseSumExpr e2)+ Minus' e1 e2 -> plusSumExpr (parseSumExpr e1) (negateSumExpr (parseSumExpr e2))+ Mult' e1 e2 -> multSumExpr (parseSumExpr e1) (parseSumExpr e2)+ e -> sumExprFromProductExpr (parseProductExpr e)++-- | `parseArithmeticExpr` converts a given expr to a normal form \(\sum_i \prod_j e _ {i,j})\).+-- This assumes given exprs have the type \(\mathbf{int}\).+parseArithmeticExpr :: Expr -> ArithmeticExpr+parseArithmeticExpr = ArithmeticExpr . parseSumExpr++formatProductExpr :: ProductExpr -> Expr+formatProductExpr e =+ let k = LitInt' (productExprConst e)+ k' e' = case productExprConst e of+ 0 -> LitInt' 0+ 1 -> e'+ -1 -> Negate' e'+ _ -> Mult' e' k+ in case productExprList e of+ [] -> k+ eHead : esTail -> k' (foldl Mult' eHead esTail)++formatSumExpr :: SumExpr -> Expr+formatSumExpr e = case sumExprList e of+ [] -> LitInt' (sumExprConst e)+ eHead : esTail ->+ let op e'+ | productExprConst e' > 0 = Plus'+ | productExprConst e' < 0 = Minus'+ | otherwise = const+ go e1 e2 = op e2 e1 (formatProductExpr (e2 {productExprConst = abs (productExprConst e2)}))+ k' e'+ | sumExprConst e > 0 = Plus' e' (LitInt' (sumExprConst e))+ | sumExprConst e < 0 = Minus' e' (LitInt' (abs (sumExprConst e)))+ | otherwise = e'+ in k' (foldl go (formatProductExpr eHead) esTail)++formatArithmeticExpr :: ArithmeticExpr -> Expr+formatArithmeticExpr = formatSumExpr . unArithmeticExpr . normalizeArithmeticExpr++normalizeProductExpr :: ProductExpr -> ProductExpr+normalizeProductExpr e =+ let es =+ if productExprConst e == 0+ then []+ else sort (productExprList e)+ in e {productExprList = es}++normalizeSumExpr :: SumExpr -> SumExpr+normalizeSumExpr e =+ let cmp e1 e2 = productExprList e1 `compare` productExprList e2+ cmp' e1 e2 = cmp e1 e2 == EQ+ es = sortBy cmp (map normalizeProductExpr (sumExprList e))+ es' = groupBy cmp' es+ es'' = map (\group -> ProductExpr {productExprConst = sum (map productExprConst group), productExprList = productExprList (head group)}) es'+ es''' = filter (\e -> productExprConst e /= 0 && not (null (productExprList e))) es''+ k = sum (map (\e -> if null (productExprList e) then productExprConst e else 0) es'')+ in SumExpr+ { sumExprList = es''',+ sumExprConst = sumExprConst e + k+ }++normalizeArithmeticExpr :: ArithmeticExpr -> ArithmeticExpr+normalizeArithmeticExpr = ArithmeticExpr . normalizeSumExpr . unArithmeticExpr++-- | `makeVectorFromArithmeticExpr` makes a vector \(f\) and a expr \(c\) from a given vector of variables \(x_0, x_1, \dots, x _ {n - 1}\) and a given expr \(e\) s.t. \(f\) and \(c\) don't have \(x_0, x_1, \dots, x _ {n - 1}\) as free variables and \(e = c + f \cdot (x_0, x_1, \dots, x _ {n - 1})\) holds.+-- This assumes given variables and exprs have the type \(\mathbf{int}\).+--+-- * The returned exprs are normalized with `normalizeArithmeticExpr`.+makeVectorFromArithmeticExpr :: V.Vector VarName -> ArithmeticExpr -> Maybe (V.Vector ArithmeticExpr, ArithmeticExpr)+makeVectorFromArithmeticExpr xs es = runST $ do+ runMaybeT $ do+ f <- lift $ MV.replicate (V.length xs) (integerArithmeticExpr 0)+ c <- lift $ newSTRef (integerArithmeticExpr (sumExprConst (unArithmeticExpr es)))+ forM_ (sumExprList (unArithmeticExpr es)) $ \e -> do+ let indices = V.imap (\i x -> map (i,) (findIndices (x `isFreeVar`) (productExprList e))) xs+ case concat (V.toList indices) of+ [] -> lift $ modifySTRef c (plusArithmeticExpr (arithmeticalExprFromProductExpr e))+ [(i, j)] -> do+ let e' = e {productExprList = take j (productExprList e) ++ drop (j + 1) (productExprList e)}+ lift $ MV.modify f (plusArithmeticExpr (arithmeticalExprFromProductExpr e')) i+ _ -> MaybeT $ return Nothing+ f <- V.freeze f+ c <- lift $ readSTRef c+ return (V.map normalizeArithmeticExpr f, normalizeArithmeticExpr c)++isZeroArithmeticExpr :: ArithmeticExpr -> Bool+isZeroArithmeticExpr e = normalizeArithmeticExpr e == integerArithmeticExpr 0++isOneArithmeticExpr :: ArithmeticExpr -> Bool+isOneArithmeticExpr e = normalizeArithmeticExpr e == integerArithmeticExpr 1++-- | `unNPlusKPattern` recognizes a pattern of \(x + k\) for a variable \(x\) and an integer constant \(k \in \mathbb{Z}\).+unNPlusKPattern :: ArithmeticExpr -> Maybe (VarName, Integer)+unNPlusKPattern e = case normalizeArithmeticExpr e of+ ArithmeticExpr+ SumExpr+ { sumExprList =+ [ ProductExpr+ { productExprConst = 1,+ productExprList = [Var x]+ }+ ],+ sumExprConst = k+ } -> Just (x, k)+ _ -> Nothing++-- | `makeAffineFunctionFromArithmeticExpr` is a specialized version of `makeVectorFromArithmeticExpr`.+-- This function returns \(a, b\) for a given variable \(x\) and a given expr \(e = a x + b\) where \(a, b\) which doesn't use \(x\) free.+makeAffineFunctionFromArithmeticExpr :: VarName -> ArithmeticExpr -> Maybe (ArithmeticExpr, ArithmeticExpr)+makeAffineFunctionFromArithmeticExpr x es = first V.head <$> makeVectorFromArithmeticExpr (V.singleton x) es++-- | `splitConstantFactorArithmeticExpr` finds \(k\) and \(e'\) for given \(e\) s.t. \(e = k e'\).+splitConstantFactorArithmeticExpr :: ArithmeticExpr -> (Integer, ArithmeticExpr)+splitConstantFactorArithmeticExpr e =+ let e' = unArithmeticExpr $ normalizeArithmeticExpr e+ in case (sumExprConst e', sumExprList e') of+ (0, []) -> (0, integerArithmeticExpr 0)+ (k, []) -> (k, integerArithmeticExpr 1)+ (0, [e]) -> second arithmeticalExprFromProductExpr $ splitConstantFactorProductExpr e+ (k, es) ->+ let kes = map splitConstantFactorProductExpr es+ d = foldl gcd k (map fst kes)+ in ( d,+ ArithmeticExpr+ SumExpr+ { sumExprConst = k `div` d,+ sumExprList = map (\(k, e) -> e {productExprConst = (k * productExprConst e) `div` d}) kes+ }+ )++splitConstantFactorProductExpr :: ProductExpr -> (Integer, ProductExpr)+splitConstantFactorProductExpr e = (productExprConst e, e {productExprConst = 1})
− src/Jikka/Core/Language/ArithmeticalExpr.hs
@@ -1,277 +0,0 @@-{-# LANGUAGE FlexibleContexts #-}-{-# LANGUAGE LambdaCase #-}-{-# LANGUAGE TupleSections #-}--module Jikka.Core.Language.ArithmeticalExpr- ( -- * Basic functions- ArithmeticalExpr,- parseArithmeticalExpr,- formatArithmeticalExpr,- integerArithmeticalExpr,- negateArithmeticalExpr,- plusArithmeticalExpr,- minusArithmeticalExpr,- multArithmeticalExpr,- isZeroArithmeticalExpr,- isOneArithmeticalExpr,-- -- * Advanced functions- unNPlusKPattern,- makeVectorFromArithmeticalExpr,- makeAffineFunctionFromArithmeticalExpr,- splitConstantFactorArithmeticalExpr,- )-where--import Control.Arrow-import Control.Monad-import Control.Monad.ST-import Control.Monad.Trans-import Control.Monad.Trans.Maybe-import Data.List (findIndices, groupBy, sort, sortBy)-import Data.STRef-import qualified Data.Vector as V-import qualified Data.Vector.Mutable as MV-import Jikka.Core.Language.BuiltinPatterns-import Jikka.Core.Language.Expr-import Jikka.Core.Language.FreeVars--data ProductExpr = ProductExpr- { productExprConst :: Integer,- productExprList :: [Expr]- }- deriving (Eq, Ord, Show, Read)--data SumExpr = SumExpr- { sumExprList :: [ProductExpr],- sumExprConst :: Integer- }- deriving (Eq, Ord, Show, Read)--newtype ArithmeticalExpr = ArithmeticalExpr {unArithmeticalExpr :: SumExpr}- deriving (Show)--instance Eq ArithmeticalExpr where- e1 == e2 = unArithmeticalExpr (normalizeArithmeticalExpr e1) == unArithmeticalExpr (normalizeArithmeticalExpr e2)--instance Ord ArithmeticalExpr where- e1 `compare` e2 = unArithmeticalExpr (normalizeArithmeticalExpr e1) `compare` unArithmeticalExpr (normalizeArithmeticalExpr e2)--integerProductExpr :: Integer -> ProductExpr-integerProductExpr n =- ProductExpr- { productExprConst = n,- productExprList = []- }--negateProductExpr :: ProductExpr -> ProductExpr-negateProductExpr e = e {productExprConst = negate (productExprConst e)}--multProductExpr :: ProductExpr -> ProductExpr -> ProductExpr-multProductExpr e1 e2 =- ProductExpr- { productExprConst = productExprConst e1 * productExprConst e2,- productExprList = productExprList e1 ++ productExprList e2- }--parseProductExpr :: Expr -> ProductExpr-parseProductExpr = \case- LitInt' n -> ProductExpr {productExprConst = n, productExprList = []}- Negate' e -> negateProductExpr (parseProductExpr e)- Mult' e1 e2 -> multProductExpr (parseProductExpr e1) (parseProductExpr e2)- Pow' e1 (LitInt' k) | 0 <= k && k < 10 -> iterate (multProductExpr (parseProductExpr e1)) (integerProductExpr 1) !! fromInteger k- e -> ProductExpr {productExprConst = 1, productExprList = [e]}--sumExprFromProductExpr :: ProductExpr -> SumExpr-sumExprFromProductExpr e =- SumExpr- { sumExprList = [e],- sumExprConst = 0- }--arithmeticalExprFromProductExpr :: ProductExpr -> ArithmeticalExpr-arithmeticalExprFromProductExpr = ArithmeticalExpr . sumExprFromProductExpr--integerSumExpr :: Integer -> SumExpr-integerSumExpr n =- SumExpr- { sumExprConst = n,- sumExprList = []- }--integerArithmeticalExpr :: Integer -> ArithmeticalExpr-integerArithmeticalExpr = ArithmeticalExpr . integerSumExpr--negateSumExpr :: SumExpr -> SumExpr-negateSumExpr e =- SumExpr- { sumExprList = map negateProductExpr (sumExprList e),- sumExprConst = negate (sumExprConst e)- }--plusSumExpr :: SumExpr -> SumExpr -> SumExpr-plusSumExpr e1 e2 =- SumExpr- { sumExprList = sumExprList e1 ++ sumExprList e2,- sumExprConst = sumExprConst e1 + sumExprConst e2- }--multSumExpr :: SumExpr -> SumExpr -> SumExpr-multSumExpr e1 e2 =- SumExpr- { sumExprList =- let es1 = parseProductExpr (LitInt' (sumExprConst e1)) : sumExprList e1- es2 = parseProductExpr (LitInt' (sumExprConst e2)) : sumExprList e2- in tail $ map (uncurry multProductExpr) ((,) <$> es1 <*> es2),- sumExprConst = sumExprConst e1 * sumExprConst e2- }--negateArithmeticalExpr :: ArithmeticalExpr -> ArithmeticalExpr-negateArithmeticalExpr (ArithmeticalExpr e) = ArithmeticalExpr $ negateSumExpr e--plusArithmeticalExpr :: ArithmeticalExpr -> ArithmeticalExpr -> ArithmeticalExpr-plusArithmeticalExpr (ArithmeticalExpr e1) (ArithmeticalExpr e2) = ArithmeticalExpr $ plusSumExpr e1 e2--minusArithmeticalExpr :: ArithmeticalExpr -> ArithmeticalExpr -> ArithmeticalExpr-minusArithmeticalExpr (ArithmeticalExpr e1) (ArithmeticalExpr e2) = ArithmeticalExpr $ plusSumExpr e1 (negateSumExpr e2)--multArithmeticalExpr :: ArithmeticalExpr -> ArithmeticalExpr -> ArithmeticalExpr-multArithmeticalExpr (ArithmeticalExpr e1) (ArithmeticalExpr e2) = ArithmeticalExpr $ multSumExpr e1 e2--parseSumExpr :: Expr -> SumExpr-parseSumExpr = \case- LitInt' n -> SumExpr {sumExprList = [], sumExprConst = n}- Negate' e -> negateSumExpr (parseSumExpr e)- Plus' e1 e2 -> plusSumExpr (parseSumExpr e1) (parseSumExpr e2)- Minus' e1 e2 -> plusSumExpr (parseSumExpr e1) (negateSumExpr (parseSumExpr e2))- Mult' e1 e2 -> multSumExpr (parseSumExpr e1) (parseSumExpr e2)- e -> sumExprFromProductExpr (parseProductExpr e)---- | `parseArithmeticalExpr` converts a given expr to a normal form \(\sum_i \prod_j e _ {i,j})\).--- This assumes given exprs have the type \(\mathbf{int}\).-parseArithmeticalExpr :: Expr -> ArithmeticalExpr-parseArithmeticalExpr = ArithmeticalExpr . parseSumExpr--formatProductExpr :: ProductExpr -> Expr-formatProductExpr e =- let k = LitInt' (productExprConst e)- k' e' = case productExprConst e of- 0 -> LitInt' 0- 1 -> e'- -1 -> Negate' e'- _ -> Mult' e' k- in case productExprList e of- [] -> k- eHead : esTail -> k' (foldl Mult' eHead esTail)--formatSumExpr :: SumExpr -> Expr-formatSumExpr e = case sumExprList e of- [] -> LitInt' (sumExprConst e)- eHead : esTail ->- let op e'- | productExprConst e' > 0 = Plus'- | productExprConst e' < 0 = Minus'- | otherwise = const- go e1 e2 = op e2 e1 (formatProductExpr (e2 {productExprConst = abs (productExprConst e2)}))- k' e'- | sumExprConst e > 0 = Plus' e' (LitInt' (sumExprConst e))- | sumExprConst e < 0 = Minus' e' (LitInt' (abs (sumExprConst e)))- | otherwise = e'- in k' (foldl go (formatProductExpr eHead) esTail)--formatArithmeticalExpr :: ArithmeticalExpr -> Expr-formatArithmeticalExpr = formatSumExpr . unArithmeticalExpr . normalizeArithmeticalExpr--normalizeProductExpr :: ProductExpr -> ProductExpr-normalizeProductExpr e =- let es =- if productExprConst e == 0- then []- else sort (productExprList e)- in e {productExprList = es}--normalizeSumExpr :: SumExpr -> SumExpr-normalizeSumExpr e =- let cmp e1 e2 = productExprList e1 `compare` productExprList e2- cmp' e1 e2 = cmp e1 e2 == EQ- es = sortBy cmp (map normalizeProductExpr (sumExprList e))- es' = groupBy cmp' es- es'' = map (\group -> ProductExpr {productExprConst = sum (map productExprConst group), productExprList = productExprList (head group)}) es'- es''' = filter (\e -> productExprConst e /= 0 && not (null (productExprList e))) es''- k = sum (map (\e -> if null (productExprList e) then productExprConst e else 0) es'')- in SumExpr- { sumExprList = es''',- sumExprConst = sumExprConst e + k- }--normalizeArithmeticalExpr :: ArithmeticalExpr -> ArithmeticalExpr-normalizeArithmeticalExpr = ArithmeticalExpr . normalizeSumExpr . unArithmeticalExpr---- | `makeVectorFromArithmeticalExpr` makes a vector \(f\) and a expr \(c\) from a given vector of variables \(x_0, x_1, \dots, x _ {n - 1}\) and a given expr \(e\) s.t. \(f\) and \(c\) don't have \(x_0, x_1, \dots, x _ {n - 1}\) as free variables and \(e = c + f \cdot (x_0, x_1, \dots, x _ {n - 1})\) holds.--- This assumes given variables and exprs have the type \(\mathbf{int}\).------ * The returned exprs are normalized with `normalizeArithmeticalExpr`.-makeVectorFromArithmeticalExpr :: V.Vector VarName -> ArithmeticalExpr -> Maybe (V.Vector ArithmeticalExpr, ArithmeticalExpr)-makeVectorFromArithmeticalExpr xs es = runST $ do- runMaybeT $ do- f <- lift $ MV.replicate (V.length xs) (integerArithmeticalExpr 0)- c <- lift $ newSTRef (integerArithmeticalExpr (sumExprConst (unArithmeticalExpr es)))- forM_ (sumExprList (unArithmeticalExpr es)) $ \e -> do- let indices = V.imap (\i x -> map (i,) (findIndices (x `isFreeVar`) (productExprList e))) xs- case concat (V.toList indices) of- [] -> lift $ modifySTRef c (plusArithmeticalExpr (arithmeticalExprFromProductExpr e))- [(i, j)] -> do- let e' = e {productExprList = take j (productExprList e) ++ drop (j + 1) (productExprList e)}- lift $ MV.modify f (plusArithmeticalExpr (arithmeticalExprFromProductExpr e')) i- _ -> MaybeT $ return Nothing- f <- V.freeze f- c <- lift $ readSTRef c- return (V.map normalizeArithmeticalExpr f, normalizeArithmeticalExpr c)--isZeroArithmeticalExpr :: ArithmeticalExpr -> Bool-isZeroArithmeticalExpr e = normalizeArithmeticalExpr e == integerArithmeticalExpr 0--isOneArithmeticalExpr :: ArithmeticalExpr -> Bool-isOneArithmeticalExpr e = normalizeArithmeticalExpr e == integerArithmeticalExpr 1---- | `unNPlusKPattern` recognizes a pattern of \(x + k\) for a variable \(x\) and an integer constant \(k \in \mathbb{Z}\).-unNPlusKPattern :: ArithmeticalExpr -> Maybe (VarName, Integer)-unNPlusKPattern e = case normalizeArithmeticalExpr e of- ArithmeticalExpr- SumExpr- { sumExprList =- [ ProductExpr- { productExprConst = 1,- productExprList = [Var x]- }- ],- sumExprConst = k- } -> Just (x, k)- _ -> Nothing---- | `makeAffineFunctionFromArithmeticalExpr` is a specialized version of `makeVectorFromArithmeticalExpr`.--- This function returns \(a, b\) for a given variable \(x\) and a given expr \(e = a x + b\) where \(a, b\) which doesn't use \(x\) free.-makeAffineFunctionFromArithmeticalExpr :: VarName -> ArithmeticalExpr -> Maybe (ArithmeticalExpr, ArithmeticalExpr)-makeAffineFunctionFromArithmeticalExpr x es = first V.head <$> makeVectorFromArithmeticalExpr (V.singleton x) es---- | `splitConstantFactorArithmeticalExpr` finds \(k\) and \(e'\) for given \(e\) s.t. \(e = k e'\).-splitConstantFactorArithmeticalExpr :: ArithmeticalExpr -> (Integer, ArithmeticalExpr)-splitConstantFactorArithmeticalExpr e =- let e' = unArithmeticalExpr $ normalizeArithmeticalExpr e- in case (sumExprConst e', sumExprList e') of- (0, []) -> (0, integerArithmeticalExpr 0)- (k, []) -> (k, integerArithmeticalExpr 1)- (0, [e]) -> second arithmeticalExprFromProductExpr $ splitConstantFactorProductExpr e- (k, es) ->- let kes = map splitConstantFactorProductExpr es- d = foldl gcd k (map fst kes)- in ( d,- ArithmeticalExpr- SumExpr- { sumExprConst = k `div` d,- sumExprList = map (\(k, e) -> e {productExprConst = (k * productExprConst e) `div` d}) kes- }- )--splitConstantFactorProductExpr :: ProductExpr -> (Integer, ProductExpr)-splitConstantFactorProductExpr e = (productExprConst e, e {productExprConst = 1})
src/Jikka/Core/Language/Expr.hs view
@@ -136,8 +136,8 @@ -- | matrix application \(: \int^{H \times W} \to \int^W \to \int^H\) MatAp Integer Integer- | -- | zero matrix \(: \to \int^{n \times n}\)- MatZero Integer+ | -- | zero matrix \(: \to \int^{h \times w}\)+ MatZero Integer Integer | -- | unit matrix \(: \to \int^{n \times n}\) MatOne Integer | -- | matrix addition \(: \int^{H \times W} \to \int^{H \times W} \to \int^{H \times W}\)@@ -235,6 +235,8 @@ -- | \(: \forall \alpha_0 \alpha_1 \dots \alpha _ {n - 1}. \alpha_0 \to \dots \to \alpha _ {n - 1} \to \alpha_0 \times \dots \times \alpha _ {n - 1}\) Tuple | -- | \(: \forall \alpha_0 \alpha_1 \dots \alpha _ {n - 1}. \alpha_0 \times \dots \times \alpha _ {n - 1} \to \alpha_i\)+ --+ -- `Jikka.Core.Parse` may make broken `Proj` with its list of type arguments is empty. This is fixed by `Jikka.Core.Convert.TypeInfer` module. Proj Integer | -- comparison
src/Jikka/Core/Language/TypeCheck.hs view
@@ -58,7 +58,7 @@ BitRightShift -> go0 $ Fun2STy IntTy -- matrix functions MatAp h w -> go0 $ Fun2Ty (matrixTy h w) (vectorTy w) (vectorTy h)- MatZero n -> go0 $ matrixTy n n+ MatZero h w -> go0 $ matrixTy h w MatOne n -> go0 $ matrixTy n n MatAdd h w -> go0 $ Fun2Ty (matrixTy h w) (matrixTy h w) (matrixTy h w) MatMul h n w -> go0 $ Fun2Ty (matrixTy h n) (matrixTy n w) (matrixTy h w)@@ -107,7 +107,10 @@ Range3 -> go0 $ Fun3Ty IntTy IntTy IntTy (ListTy IntTy) -- tuple functions Tuple -> return $ curryFunTy ts (TupleTy ts)- Proj n -> return $ FunTy (TupleTy ts) (ts !! fromInteger n)+ Proj n ->+ if 0 <= n && n < toInteger (length ts)+ then return $ FunTy (TupleTy ts) (ts !! fromInteger n)+ else throwTypeError $ "projection index is out of range: type = " ++ formatType (TupleTy ts) ++ ", index = " ++ show n -- comparison LessThan -> go1 $ \t -> Fun2Ty t t BoolTy LessEqual -> go1 $ \t -> Fun2Ty t t BoolTy
src/Jikka/Core/Language/Util.hs view
@@ -77,11 +77,11 @@ mapTypeProgram :: (Type -> Type) -> Program -> Program mapTypeProgram f prog = runIdentity (mapTypeProgramM (return . f) prog) --- | `mapExprM'` substitutes exprs using given two functions, which are called in pre-order and post-order.-mapExprM' :: Monad m => ([(VarName, Type)] -> Expr -> m Expr) -> ([(VarName, Type)] -> Expr -> m Expr) -> [(VarName, Type)] -> Expr -> m Expr-mapExprM' pre post env e = do+-- | `mapSubExprM'` substitutes exprs using given two functions, which are called in pre-order and post-order.+mapSubExprM' :: Monad m => ([(VarName, Type)] -> Expr -> m Expr) -> ([(VarName, Type)] -> Expr -> m Expr) -> [(VarName, Type)] -> Expr -> m Expr+mapSubExprM' pre post env e = do e <- pre env e- let go = mapExprM' pre post+ let go = mapSubExprM' pre post e <- case e of Var y -> return $ Var y Lit lit -> return $ Lit lit@@ -105,37 +105,32 @@ ToplevelAssert e <$> mapToplevelExprM' pre post env cont post env e -mapExprToplevelExprM' :: Monad m => ([(VarName, Type)] -> Expr -> m Expr) -> ([(VarName, Type)] -> Expr -> m Expr) -> [(VarName, Type)] -> ToplevelExpr -> m ToplevelExpr-mapExprToplevelExprM' pre post env = mapToplevelExprM' pre' (\_ e -> return e) env+mapExprToplevelExprM :: Monad m => ([(VarName, Type)] -> Expr -> m Expr) -> [(VarName, Type)] -> ToplevelExpr -> m ToplevelExpr+mapExprToplevelExprM f env = mapToplevelExprM' pre' (\_ e -> return e) env where- go = mapExprM' pre post pre' env = \case- ResultExpr e -> ResultExpr <$> go env e- ToplevelLet y t e cont -> ToplevelLet y t <$> go env e <*> pure cont+ ResultExpr e -> ResultExpr <$> f env e+ ToplevelLet y t e cont -> ToplevelLet y t <$> f env e <*> pure cont ToplevelLetRec g args ret body cont -> let env' = (g, foldr (FunTy . snd) ret args) : env- in ToplevelLetRec g args ret <$> go (reverse args ++ env') body <*> pure cont- ToplevelAssert e cont -> ToplevelAssert <$> go env e <*> pure cont--mapExprProgramM' :: Monad m => ([(VarName, Type)] -> Expr -> m Expr) -> ([(VarName, Type)] -> Expr -> m Expr) -> Program -> m Program-mapExprProgramM' pre post = mapExprToplevelExprM' pre post []---- | `mapExprM` is a wrapper of `mapExprM'`. This function works in post-order.-mapExprM :: Monad m => ([(VarName, Type)] -> Expr -> m Expr) -> [(VarName, Type)] -> Expr -> m Expr-mapExprM f = mapExprM' (\_ e -> return e) f--mapExprToplevelExprM :: Monad m => ([(VarName, Type)] -> Expr -> m Expr) -> [(VarName, Type)] -> ToplevelExpr -> m ToplevelExpr-mapExprToplevelExprM f = mapExprToplevelExprM' (\_ e -> return e) f+ in ToplevelLetRec g args ret <$> f (reverse args ++ env') body <*> pure cont+ ToplevelAssert e cont -> ToplevelAssert <$> f env e <*> pure cont mapExprProgramM :: Monad m => ([(VarName, Type)] -> Expr -> m Expr) -> Program -> m Program-mapExprProgramM f = mapExprProgramM' (\_ e -> return e) f+mapExprProgramM f = mapExprToplevelExprM f [] -mapExpr :: ([(VarName, Type)] -> Expr -> Expr) -> [(VarName, Type)] -> Expr -> Expr-mapExpr f env e = runIdentity $ mapExprM (\env e -> return $ f env e) env e+-- | `mapSubExprM` is a wrapper of `mapSubExprM'`. This function works in post-order.+mapSubExprM :: Monad m => ([(VarName, Type)] -> Expr -> m Expr) -> [(VarName, Type)] -> Expr -> m Expr+mapSubExprM f = mapSubExprM' (\_ e -> return e) f +mapSubExpr :: ([(VarName, Type)] -> Expr -> Expr) -> [(VarName, Type)] -> Expr -> Expr+mapSubExpr f env e = runIdentity $ mapSubExprM (\env e -> return $ f env e) env e+ mapExprToplevelExpr :: ([(VarName, Type)] -> Expr -> Expr) -> [(VarName, Type)] -> ToplevelExpr -> ToplevelExpr mapExprToplevelExpr f env e = runIdentity $ mapExprToplevelExprM (\env e -> return $ f env e) env e +-- | @mapExprProgram f prog@ applies @f@ to each root exprs in @prog@.+-- This doesn't run into sub-exprs. For example, @toplevel-let x = (e1 + e2) in ...@ becomes @toplevel-let x = (f (e1 + e2)) in ...@, instead of @toplevel-let x = (f (f e1 + f e2)) in ...@ mapExprProgram :: ([(VarName, Type)] -> Expr -> Expr) -> Program -> Program mapExprProgram f prog = runIdentity $ mapExprProgramM (\env e -> return $ f env e) prog @@ -150,7 +145,7 @@ mapToplevelExprProgram f prog = runIdentity $ mapToplevelExprProgramM (\env e -> return $ f env e) prog listSubExprs :: Expr -> [Expr]-listSubExprs e = getDual . execWriter $ mapExprM go [] e+listSubExprs e = getDual . execWriter $ mapSubExprM go [] e where go _ e = do tell $ Dual [e]@@ -236,7 +231,7 @@ BitRightShift -> True -- matrix functions MatAp _ _ -> True- MatZero _ -> True+ MatZero _ _ -> True MatOne _ -> True MatAdd _ _ -> True MatMul _ _ _ -> True
src/Jikka/Core/Parse/Alex.x view
@@ -93,10 +93,8 @@ "**" { tok (Operator Pow) } -- boolean operators- "and" { tok (Operator And) }- "or" { tok (Operator Or) }- "not" { tok (Operator Not) }- "implies" { tok (Operator Implies) }+ "&&" { tok (Operator And) }+ "||" { tok (Operator Or) } -- bit operators "~" { tok (Operator BitNot) }@@ -106,10 +104,6 @@ "<<" { tok (Operator BitLShift) } ">>" { tok (Operator BitRShift) } - -- min max operators- "<?" { tok (Operator Min) }- ">?" { tok (Operator Max) }- -- comparators ">" { tok (Operator GreaterThan) } "<" { tok (Operator LessThan) }@@ -121,6 +115,7 @@ -- identifier $alpha ($alnum | "_") * { tok' Ident } $alpha ($alnum | "_") * "$" $digit + { tok' Ident }+ "$" $digit + { tok' Ident } -- catch error . { skip' }
src/Jikka/Core/Parse/Happy.y view
@@ -28,6 +28,7 @@ import Jikka.Common.Location import Jikka.Core.Language.BuiltinPatterns import Jikka.Core.Language.Expr+import Jikka.Core.Language.TypeCheck import Jikka.Core.Language.Util import qualified Jikka.Core.Parse.Token as L }@@ -79,6 +80,7 @@ "bool" { WithLoc _ (L.Ident "bool") } "list" { WithLoc _ (L.Ident "list") } "unit" { WithLoc _ (L.Ident "unit") }+ "one_tuple" { WithLoc _ (L.Ident "one_tuple") } "convex_hull_trick" { WithLoc _ (L.Ident "convex_hull_trick") } "segment_tree" { WithLoc _ (L.Ident "segment_tree") } "int_plus" { WithLoc _ (L.Ident "int_plus") }@@ -90,6 +92,10 @@ "abs" { WithLoc _ (L.Ident "abs") } "gcd" { WithLoc _ (L.Ident "gcd") } "lcm" { WithLoc _ (L.Ident "lcm") }+ "max" { WithLoc _ (L.Ident "max") }+ "min" { WithLoc _ (L.Ident "min") }+ "not" { WithLoc _ (L.Ident "not") }+ "implies" { WithLoc _ (L.Ident "implies") } "iterate" { WithLoc _ (L.Ident "iterate") } "matap" { WithLoc _ (L.Ident "matap") } "matzero" { WithLoc _ (L.Ident "matzero") }@@ -122,10 +128,12 @@ "product" { WithLoc _ (L.Ident "product") } "modsum" { WithLoc _ (L.Ident "modsum") } "modproduct" { WithLoc _ (L.Ident "modproduct") }- "min" { WithLoc _ (L.Ident "min") }- "max" { WithLoc _ (L.Ident "max") }+ "minimum" { WithLoc _ (L.Ident "minimum") }+ "maximum" { WithLoc _ (L.Ident "maximum") } "argmin" { WithLoc _ (L.Ident "argmin") } "argmax" { WithLoc _ (L.Ident "argmax") }+ "gcds" { WithLoc _ (L.Ident "gcds") }+ "lcms" { WithLoc _ (L.Ident "lcms") } "all" { WithLoc _ (L.Ident "all") } "any" { WithLoc _ (L.Ident "any") } "sorted" { WithLoc _ (L.Ident "sorted") }@@ -158,10 +166,8 @@ "**" { WithLoc _ (L.Operator L.Pow) } -- boolean operators- "and" { WithLoc _ (L.Operator L.And) }- "or" { WithLoc _ (L.Operator L.Or) }- "not" { WithLoc _ (L.Operator L.Not) }- "implies" { WithLoc _ (L.Operator L.Implies) }+ "&&" { WithLoc _ (L.Operator L.And) }+ "||" { WithLoc _ (L.Operator L.Or) } -- bit operators "~" { WithLoc _ (L.Operator L.BitNot) }@@ -171,10 +177,6 @@ "<<" { WithLoc _ (L.Operator L.BitLShift) } ">>" { WithLoc _ (L.Operator L.BitRShift) } - -- min max operators- "<?" { WithLoc _ (L.Operator L.Min) }- ">?" { WithLoc _ (L.Operator L.Max) }- -- comparators ">" { WithLoc _ (L.Operator L.GreaterThan) } "<" { WithLoc _ (L.Operator L.LessThan) }@@ -232,6 +234,7 @@ | "bool" { BoolTy } | atom_type "list" { ListTy $1 } | "unit" { TupleTy [] }+ | atom_type "one_tuple" { TupleTy [$1] } | datastructure { DataStructureTy $1 } | "(" type ")" { $2 } @@ -291,26 +294,32 @@ : "abs" { (Abs, []) } | "gcd" { (Gcd, []) } | "lcm" { (Lcm, []) }+ | "min" { (Min2, [underscoreTy]) }+ | "min" "@" atom_type { (Min2, [$3]) }+ | "max" { (Max2, [underscoreTy]) }+ | "max" "@" atom_type { (Max2, [$3]) }+ | "not" { (Not, []) }+ | "implies" { (Implies, []) } | "iterate" { (Iterate, [underscoreTy]) } | "iterate" "@" atom_type { (Iterate, [$3]) }- | "matap" integer integer { (MatAp $2 $3, []) }- | "matzero" integer { (MatZero $2, []) }- | "matone" integer { (MatOne $2, []) }- | "matadd" integer integer { (MatAdd $2 $3, []) }- | "matmul" integer integer integer { (MatMul $2 $3 $4, []) }- | "matpow" integer { (MatPow $2, []) }- | "vecfloormod" integer { (VecFloorMod $2, []) }- | "matfloormod" integer integer { (MatFloorMod $2 $3, []) }+ | "matap" "@" integer "@" integer { (MatAp $3 $5, []) }+ | "matzero" "@" integer "@" integer { (MatZero $3 $5, []) }+ | "matone" "@" integer { (MatOne $3, []) }+ | "matadd" "@" integer "@" integer { (MatAdd $3 $5, []) }+ | "matmul" "@" integer "@" integer "@" integer { (MatMul $3 $5 $7, []) }+ | "matpow" "@" integer { (MatPow $3, []) }+ | "vecfloormod" "@" integer { (VecFloorMod $3, []) }+ | "matfloormod" "@" integer "@" integer { (MatFloorMod $3 $5, []) } | "modnegate" { (ModNegate, []) } | "modplus" { (ModPlus, []) } | "modminus" { (ModMinus, []) } | "modmult" { (ModMult, []) } | "modinv" { (ModInv, []) } | "modpow" { (ModPow, []) }- | "modmatap" integer integer { (ModMatAp $2 $3, []) }- | "modmatadd" integer integer { (ModMatAdd $2 $3, []) }- | "modmatmul" integer integer integer { (ModMatMul $2 $3 $4, []) }- | "modmatpow" integer { (ModMatPow $2, []) }+ | "modmatap" "@" integer "@" integer { (ModMatAp $3 $5, []) }+ | "modmatadd" "@" integer "@" integer { (ModMatAdd $3 $5, []) }+ | "modmatmul" "@" integer "@" integer "@" integer { (ModMatMul $3 $5 $7, []) }+ | "modmatpow" "@" integer { (ModMatPow $3, []) } | "cons" { (Cons, [underscoreTy]) } | "cons" "@" atom_type { (Cons, [$3]) } | "snoc" { (Snoc, [underscoreTy]) }@@ -333,14 +342,16 @@ | "product" { (Product, []) } | "modsum" { (ModSum, []) } | "modproduct" { (ModProduct, []) }- | "min" { (Min1, [underscoreTy]) }- | "min" "@" atom_type { (Min1, [$3]) }- | "max" { (Max1, [underscoreTy]) }- | "max" "@" atom_type { (Max1, [$3]) }+ | "minimum" { (Min1, [underscoreTy]) }+ | "minimum" "@" atom_type { (Min1, [$3]) }+ | "maximum" { (Max1, [underscoreTy]) }+ | "maximum" "@" atom_type { (Max1, [$3]) } | "argmin" { (ArgMin, [underscoreTy]) } | "argmin" "@" atom_type { (ArgMin, [$3]) } | "argmax" { (ArgMax, [underscoreTy]) } | "argmax" "@" atom_type { (ArgMax, [$3]) }+ | "gcds" { (Gcd1, []) }+ | "lcms" { (Lcm1, []) } | "all" { (All, []) } | "any" { (Any, []) } | "sorted" { (Sorted, [underscoreTy]) }@@ -372,7 +383,7 @@ | primary "[" expression "]" "@" atom_type { At' $6 $1 $3 } | primary "[" expression "<-" expression "]" { SetAt' underscoreTy $1 $3 $5 } | primary "[" expression "<-" expression "]" "@" atom_type { SetAt' $8 $1 $3 $5 }- -- | primary "." integer {% makeProj $1 $3 underscoreTy }+ | primary "." integer {% makeProj $1 $3 underscoreTy } | primary "." integer "@" atom_type {% makeProj $1 $3 $5 } -- Function applications@@ -422,19 +433,11 @@ : xor_expr { $1 } | or_expr "|" xor_expr { BitOr' $1 $3 } --- Min and max operations-min_expr :: { Expr }- : or_expr { $1 }- | min_expr "<?" or_expr { Min2' underscoreTy $1 $3 }- | min_expr "<?" "@" atom_type or_expr { Min2' $4 $1 $5 }- | min_expr ">?" or_expr { Max2' underscoreTy $1 $3 }- | min_expr ">?" "@" atom_type or_expr { Max2' $4 $1 $5 }- -- Comparisons comparison :: { Expr }- : min_expr { $1 }- | comparison comp_operator min_expr { $2 underscoreTy $1 $3 }- | comparison comp_operator "@" atom_type min_expr { $2 $4 $1 $5 }+ : or_expr { $1 }+ | comparison comp_operator or_expr { $2 underscoreTy $1 $3 }+ | comparison comp_operator "@" atom_type or_expr { $2 $4 $1 $5 } comp_operator :: { Type -> Expr -> Expr -> Expr } : "==" { Equal' } | "/=" { NotEqual' }@@ -444,20 +447,12 @@ | ">=" { GreaterEqual' } -- Boolean operations-not_test :: { Expr }- : comparison { $1 }- | "not" not_test { Not' $2 } and_test :: { Expr }- : not_test { $1 }- | and_test "and" not_test { And' $1 $3 }+ : comparison { $1 }+ | and_test "&&" comparison { And' $1 $3 } or_test :: { Expr } : and_test { $1 }- | or_test "or" and_test { Or' $1 $3 }---- Implication operation-implies_test :: { Expr }- : or_test { $1 }- | or_test "implies" implies_test { Implies' $1 $3 }+ | or_test "||" and_test { Or' $1 $3 } -- Conditional expressions conditional_expression :: { Expr }@@ -477,7 +472,7 @@ : "assert" expression "->" expression { Assert $2 $4 } expression_nolet :: { Expr }- : implies_test { $1 }+ : or_test { $1 } | conditional_expression { $1 } | lambda_expr { $1 } | assert_expr { $1 }@@ -503,8 +498,9 @@ makeProj :: MonadError Error m => Expr -> Integer -> Type -> m Expr makeProj e n t = case t of+ t | t == underscoreTy -> return $ Proj' [] n e -- A projection from the empty tuple is fixed in Jikka.Core.Convert.TypeInfer. TupleTy ts -> return $ Proj' ts n e- _ -> throwSyntaxError "Jikka.Core.Parse.Happy.makeTuple: wrong type annotation for proj"+ _ -> throwSyntaxError "Jikka.Core.Parse.Happy.makeTuple: wrong type annotation for a tuple projection" replaceUnderscoresT :: MonadAlpha m => Type -> m Type replaceUnderscoresT = mapSubTypesM go where@@ -512,10 +508,13 @@ VarTy (TypeName "_") -> genType t -> return t -replaceUnderscoresE :: MonadAlpha m => [(VarName, Type)] -> Expr -> m Expr-replaceUnderscoresE env = mapExprM go env where+replaceUnderscoresE :: (MonadAlpha m, MonadError Error m) => [(VarName, Type)] -> Expr -> m Expr+replaceUnderscoresE env = mapSubExprM go env where go _ = \case Var (VarName "_") -> Var <$> genVarName'+ e@(Proj' [] i (Var x)) -> case lookup x env of+ Just (TupleTy ts) -> return $ Proj' ts i (Var x) -- Fix types of projections if it's easily possible.+ _ -> return e -- Some cases are impossible. You need to use Jikka.Core.Convert.TypeInfer. e -> return e happyErrorExpList :: MonadError Error m => ([WithLoc L.Token], [String]) -> m a@@ -555,11 +554,11 @@ runExpr tokens = wrapError' "Jikka.Core.Parse.Happy.runExpr" $ do e <- liftEither $ runExpr_ tokens mapTypeExprM replaceUnderscoresT e- mapExprM replaceUnderscoresE [] e+ mapSubExprM replaceUnderscoresE [] e runProgram :: (MonadAlpha m, MonadError Error m) => [WithLoc L.Token] -> m Program runProgram tokens = wrapError' "Jikka.Core.Parse.Happy.runProgram" $ do prog <- liftEither $ runProgram_ tokens prog <- mapTypeProgramM replaceUnderscoresT prog- mapExprProgramM replaceUnderscoresE prog+ mapExprProgramM (mapSubExprM replaceUnderscoresE) prog }
src/Jikka/Core/Parse/Token.hs view
@@ -21,10 +21,8 @@ | CeilMod | Pow | -- boolean operators- Not- | And+ And | Or- | Implies | -- bit operators BitNot | BitAnd@@ -32,9 +30,6 @@ | BitXor | BitLShift | BitRShift- | -- min max operators- Min- | Max | -- comparators DoubleEqual | NotEqual
src/Jikka/Main.hs view
@@ -30,6 +30,7 @@ = Help | Verbose | Version+ | Source String | Target String | BundleRuntimeHeaders Bool | EmbedOriginalCode Bool@@ -37,6 +38,7 @@ data Options = Options { verbose :: Bool,+ source :: Target, target :: Maybe Target, bundleRuntimeHeaders :: Bool, embedOriginalCode :: Bool@@ -47,6 +49,7 @@ defaultOptions = Options { verbose = False,+ source = PythonTarget, target = Nothing, bundleRuntimeHeaders = True, embedOriginalCode = True@@ -60,6 +63,7 @@ [ Option ['h', '?'] ["help"] (NoArg Help) "", Option ['v'] ["verbose"] (NoArg Verbose) "", Option [] ["version"] (NoArg Version) "",+ Option [] ["source"] (ReqArg Source "SOURCE") "\"python\" or \"core\"", Option [] ["target"] (ReqArg Target "TARGET") "\"python\", \"rpython\", \"core\" or \"cxx\"", Option [] ["bundle-runtime-headers"] (NoArg (BundleRuntimeHeaders True)) "bundles C++ runtime headers", Option [] ["no-bundle-runtime-headers"] (NoArg (BundleRuntimeHeaders False)) "",@@ -108,6 +112,9 @@ Help -> throwCommandLineError "parseFlags is not called when --help is specified" Version -> throwCommandLineError "parseFlags is not called when --version is specified" Verbose -> go (opts {verbose = True}) flags+ Source source -> do+ source <- parseTarget source+ go (opts {source = source}) flags Target target -> do target <- parseTarget target go (opts {target = Just target}) flags@@ -119,19 +126,19 @@ "convert" -> do input <- liftIO $ T.readFile path let target' = fromMaybe CPlusPlusTarget (target opts)- output <- liftEither $ Convert.run target' path input+ output <- liftEither $ Convert.run (source opts) target' path input output <- if target' == CPlusPlusTarget && bundleRuntimeHeaders opts then BundleRuntime.run output else return output output <- return $- if embedOriginalCode opts+ if target' == CPlusPlusTarget && embedOriginalCode opts then let headers = ["// This C++ code is transpiled using Jikka transpiler v" <> T.pack (showVersion version) <> " https://github.com/kmyk/Jikka", "// The original Python code:"] in T.unlines (headers ++ map ("// " <>) (T.lines input)) <> output else output liftIO $ T.putStr output- "debug" -> Debug.run path- "execute" -> Execute.run (fromMaybe CoreTarget (target opts)) path+ "debug" -> Debug.run path -- TODO: make this subcommand convenient+ "execute" -> Execute.run (fromMaybe CoreTarget (target opts)) path -- TODO: use source _ -> throwCommandLineError $ "undefined subcommand: " ++ show subcmd
src/Jikka/Main/Subcommand/Convert.hs view
@@ -1,3 +1,4 @@+{-# LANGUAGE FlexibleContexts #-} {-# LANGUAGE LambdaCase #-} -- |@@ -13,49 +14,68 @@ import Data.Text (Text, pack) import qualified Jikka.CPlusPlus.Convert as FromCore import qualified Jikka.CPlusPlus.Format as FormatCPlusPlus+import qualified Jikka.CPlusPlus.Language.Expr as CPlusPlus import Jikka.Common.Alpha import Jikka.Common.Error import qualified Jikka.Core.Convert as Convert import qualified Jikka.Core.Format as FormatCore+import qualified Jikka.Core.Language.Expr as Core+import qualified Jikka.Core.Parse as ParseCore import Jikka.Main.Target import qualified Jikka.Python.Convert.ToRestrictedPython as ToRestrictedPython+import qualified Jikka.Python.Language.Expr as Python import qualified Jikka.Python.Parse as ParsePython import qualified Jikka.RestrictedPython.Convert as ToCore import qualified Jikka.RestrictedPython.Format as FormatRestrictedPython+import qualified Jikka.RestrictedPython.Language.Expr as RestrictedPython -runPython :: FilePath -> Text -> Either Error Text-runPython path input = flip evalAlphaT 0 $ do- prog <- ParsePython.run path input- return . pack $ show prog -- TODO+data Program+ = PythonProgram Python.Program+ | RestrictedPythonProgram RestrictedPython.Program+ | CoreProgram Core.Program+ | CPlusPlusProgram CPlusPlus.Program+ deriving (Eq, Ord, Read, Show) -runRestrictedPython :: FilePath -> Text -> Either Error Text-runRestrictedPython path input = flip evalAlphaT 0 $ do- prog <- ParsePython.run path input- prog <- ToRestrictedPython.run prog- (prog, _) <- ToCore.run' prog- FormatRestrictedPython.run prog+parseProgram :: (MonadAlpha m, MonadError Error m) => Target -> FilePath -> Text -> m Program+parseProgram source path input = case source of+ PythonTarget -> PythonProgram <$> ParsePython.run path input+ RestrictedPythonTarget -> throwCommandLineError "cannot convert from restricted Python"+ CoreTarget -> CoreProgram <$> ParseCore.run path input+ CPlusPlusTarget -> throwCommandLineError "cannot convert from C++" -runCore :: FilePath -> Text -> Either Error Text-runCore path input = flip evalAlphaT 0 $ do- prog <- ParsePython.run path input- prog <- ToRestrictedPython.run prog- (prog, _) <- ToCore.run prog- prog <- Convert.run prog- FormatCore.run prog+convertProgram :: (MonadAlpha m, MonadError Error m) => Program -> Target -> m Program+convertProgram prog target = case (prog, target) of+ (PythonProgram _, PythonTarget) -> return prog+ (RestrictedPythonProgram _, RestrictedPythonTarget) -> return prog+ (CoreProgram prog, CoreTarget) -> CoreProgram <$> Convert.run prog -- optimize+ (CPlusPlusProgram _, CPlusPlusTarget) -> return prog+ (RestrictedPythonProgram _, PythonTarget) -> throwCommandLineError "cannot convert from restricted Python to Python"+ (CoreProgram _, PythonTarget) -> throwCommandLineError "cannot convert from core to Python"+ (CoreProgram _, RestrictedPythonTarget) -> throwCommandLineError "cannot convert from core to restricted Python"+ (PythonProgram prog, _) -> do+ prog <- ToRestrictedPython.run prog+ convertProgram (RestrictedPythonProgram prog) target+ (RestrictedPythonProgram prog, CoreTarget) -> do+ (prog, _) <- ToCore.run prog+ CoreProgram <$> Convert.run prog+ (RestrictedPythonProgram prog, CPlusPlusTarget) -> do+ (prog, format) <- ToCore.run prog+ prog <- Convert.run prog+ CPlusPlusProgram <$> FromCore.run prog (Just format)+ (CoreProgram prog, CPlusPlusTarget) -> do+ prog <- Convert.run prog+ CPlusPlusProgram <$> FromCore.run prog Nothing+ (CPlusPlusProgram _, _) -> throwCommandLineError "cannot convert from C++" -runCPlusPlus :: FilePath -> Text -> Either Error Text-runCPlusPlus path input = flip evalAlphaT 0 $ do- prog <- ParsePython.run path input- prog <- ToRestrictedPython.run prog- (prog, format) <- ToCore.run prog- prog <- Convert.run prog- resetAlphaT 0 -- to make generated C++ code cleaner- prog <- FromCore.run prog format- FormatCPlusPlus.run prog+formatProgram :: (MonadAlpha m, MonadError Error m) => Program -> m Text+formatProgram = \case+ PythonProgram prog -> return . pack $ show prog -- TODO+ RestrictedPythonProgram prog -> FormatRestrictedPython.run prog+ CoreProgram prog -> FormatCore.run prog+ CPlusPlusProgram prog -> FormatCPlusPlus.run prog -run :: Target -> FilePath -> Text -> Either Error Text-run = \case- PythonTarget -> runPython- RestrictedPythonTarget -> runRestrictedPython- CoreTarget -> runCore- CPlusPlusTarget -> runCPlusPlus+run :: Target -> Target -> FilePath -> Text -> Either Error Text+run source target path input = flip evalAlphaT 0 $ do+ prog <- parseProgram source path input+ prog <- convertProgram prog target+ formatProgram prog
test/Jikka/CPlusPlus/Convert/MoveSemanticsSpec.hs view
@@ -22,6 +22,34 @@ [ FunDef TyInt32 "func"+ [(TyInt32, "a")]+ [ Declare TyInt32 "b" (DeclareCopy (Var "a")),+ Assign (AssignExpr AddAssign (LeftVar "b") (Lit (LitInt32 10))),+ Declare TyInt32 "c" (DeclareCopy (Var "b")),+ Assign (AssignExpr AddAssign (LeftVar "b") (Lit (LitInt32 10))),+ Return (BinOp Add (Var "b") (Var "c"))+ ]+ ]+ let expected =+ Program+ [ FunDef+ TyInt32+ "func"+ [(TyInt32, "a")]+ [ Assign (AssignExpr AddAssign (LeftVar "a") (Lit (LitInt32 10))),+ Declare TyInt32 "c" (DeclareCopy (Var "a")),+ Assign (AssignExpr AddAssign (LeftVar "a") (Lit (LitInt32 10))),+ Return (BinOp Add (Var "a") (Var "c"))+ ]+ ]+ run' prog `shouldBe` Right expected++ it "recognizes push_back" $ do+ let prog =+ Program+ [ FunDef+ TyInt32+ "func" [(TyVector TyInt32, "a")] [ Declare (TyVector TyInt32) "b" (DeclareCopy (Var "a")), ExprStatement (Call (Method "push_back") [Var "b", Lit (LitInt32 10)]),@@ -42,7 +70,103 @@ Return (BinOp Add (Call MethodSize [Var "a"]) (Call MethodSize [Var "c"])) ] ]- -- TODO: fix the bug https://github.com/kmyk/Jikka/issues/154 and enable this check+ run' prog `shouldBe` Right expected++ it "don't move if it is used in the next loop iteration" $ do+ let prog =+ Program+ [ FunDef+ TyInt32+ "func"+ [(TyInt32, "a")]+ [ For+ TyInt32+ "i"+ (Lit (LitInt32 0))+ (BinOp LessThan (Var "i") (Lit (LitInt32 10)))+ (AssignIncr (LeftVar "i"))+ [ Declare TyInt32 "b" (DeclareCopy (Var "a")),+ Assign (AssignExpr AddAssign (LeftVar "b") (Lit (LitInt32 10)))+ ],+ Return (Var "a")+ ]+ ]+ let expected = prog+ run' prog `shouldBe` Right expected++ it "allows to write back" $ do+ let prog =+ Program+ [ FunDef+ TyInt32+ "func"+ [(TyInt32, "a")]+ [ Declare TyInt32 "b" (DeclareCopy (Var "a")),+ Assign (AssignExpr AddAssign (LeftVar "b") (Lit (LitInt32 10))),+ Assign (AssignExpr SimpleAssign (LeftVar "a") (Var "b")),+ Return (Var "a")+ ]+ ]+ let expected =+ Program+ [ FunDef+ TyInt32+ "func"+ [(TyInt32, "a")]+ [ Assign (AssignExpr AddAssign (LeftVar "a") (Lit (LitInt32 10))),+ Return (Var "a")+ ]+ ]+ run' prog `shouldBe` Right expected++ it "recognizes set_at" $ do+ let prog =+ Program+ [ FunDef+ (TyVector TyInt32)+ "func"+ [(TyVector TyInt32, "a")]+ [ Declare (TyVector TyInt32) "b" (DeclareCopy (Var "a")),+ Assign (AssignExpr AddAssign (LeftAt (LeftVar "b") (Lit (LitInt32 0))) (Call At [Var "a", Lit (LitInt32 1)])),+ Assign (AssignExpr SimpleAssign (LeftVar "a") (Var "b")),+ Return (Var "a")+ ]+ ]+ let expected =+ Program+ [ FunDef+ (TyVector TyInt32)+ "func"+ [(TyVector TyInt32, "a")]+ [ Assign (AssignExpr AddAssign (LeftAt (LeftVar "a") (Lit (LitInt32 0))) (Call At [Var "a", Lit (LitInt32 1)])),+ Return (Var "a")+ ]+ ]+ run' prog `shouldBe` Right expected++ it "TODO: allows to write back and reads after it" $ do+ let prog =+ Program+ [ FunDef+ TyInt32+ "func"+ [(TyInt32, "a")]+ [ Declare TyInt32 "b" (DeclareCopy (Var "a")),+ Assign (AssignExpr AddAssign (LeftVar "b") (Lit (LitInt32 10))),+ Assign (AssignExpr AddAssign (LeftVar "a") (Var "b")),+ Return (BinOp Add (Var "a") (Var "b"))+ ]+ ]+ let expected =+ Program+ [ FunDef+ TyInt32+ "func"+ [(TyInt32, "a")]+ [ Assign (AssignExpr AddAssign (LeftVar "a") (Lit (LitInt32 10))),+ Return (BinOp Add (Var "a") (Var "a"))+ ]+ ]+ -- TODO: fix this -- run' prog `shouldBe` Right expected- run' prog `shouldBe` run' prog -- supress warnings- expected `shouldBe` expected -- supress warnings+ run' prog `shouldNotBe` Right expected
+ test/Jikka/Core/Convert/ConvexHullTrickSpec.hs view
@@ -0,0 +1,105 @@+{-# LANGUAGE OverloadedStrings #-}++module Jikka.Core.Convert.ConvexHullTrickSpec+ ( spec,+ )+where++import Jikka.Common.Alpha+import Jikka.Common.Error+import qualified Jikka.Core.Convert.ConstantFolding as ConstantFolding+import Jikka.Core.Convert.ConvexHullTrick (run)+import qualified Jikka.Core.Convert.TypeInfer as TypeInfer+import Jikka.Core.Format (formatProgram)+import Jikka.Core.Language.Expr+import Jikka.Core.Parse (parseProgram)+import Test.Hspec++run' :: Program -> Either Error Program+run' = flip evalAlphaT 0 . (ConstantFolding.run <=< run)++parseProgram' :: [String] -> Program+parseProgram' = fromSuccess . flip evalAlphaT 100 . (TypeInfer.run <=< parseProgram . unlines)++spec :: Spec+spec = describe "run" $ do+ it "works on morau-style min" $ do+ let prog =+ parseProgram'+ [ "let k: int = 1000",+ "in let a: int list = range k",+ "in let b: int list = range k",+ "in let c: int list = range k",+ "in let e: int = 1234",+ "in let xs: int list = range k",+ "in build (fun ys ->",+ " minimum (map (fun j -> a[j] * xs[len ys] + b[j] + c[len ys]) (range (len ys)))",+ ") (snoc nil e) k"+ ]+ let step =+ unlines+ [ "fun ($4: convex_hull_trick * int list) ($0: int) ->",+ " let ys: int list = $4.1",+ " in let ys$6: int list = snoc ys (cht_getmin $4.0 xs[$0 + 1] + c[$0 + 1])",+ " in let $5: convex_hull_trick = cht_insert $4.0 a[$0 + 1] b[$0 + 1]",+ " in ($5, ys$6)"+ ]+ let base =+ unlines+ [ "let ys$2: int list = (snoc nil e)",+ "in (foldl (fun ($1: convex_hull_trick) ($3: int) ->",+ " cht_insert $1 a[$3] b[$3]",+ ") cht_init (range 1), ys$2)"+ ]+ let expected =+ parseProgram'+ [ "let k: int = 1000",+ "in let a: int list = range k",+ "in let b: int list = range k",+ "in let c: int list = range k",+ "in let e: int = 1234",+ "in let xs: int list = range k",+ "in (foldl (" ++ step ++ ") (" ++ base ++ ") (range k)).1",+ ""+ ]+ (formatProgram <$> run' prog) `shouldBe` Right (formatProgram expected)+ it "works on morau-style min-snoc" $ do+ let prog =+ parseProgram'+ [ "let k: int = 1000",+ "in let a: int list = range k",+ "in let b: int list = range k",+ "in let c: int list = range k",+ "in let e: int list -> int = fun f -> len f + 1234",+ "in let xs: int list = range k",+ "in build (fun ys ->",+ " minimum (snoc (map (fun j -> a[j] * xs[len ys] + b[j] + c[len ys]) (range (len ys))) (e ys))",+ ") nil k"+ ]+ let step =+ unlines+ [ "fun ($4: convex_hull_trick * int list) ($0: int) ->",+ " let ys: int list = $4.1",+ " in let ys$6: int list = snoc ys (min (e ys - c[$0 + 1]) (cht_getmin $4.0 xs[$0 + 1]) + c[$0 + 1])",+ " in let $5: convex_hull_trick = cht_insert $4.0 a[$0 + 1] b[$0 + 1]",+ " in ($5, ys$6)"+ ]+ let base =+ unlines+ [ "let ys$2: int list = snoc nil ((let ys: int list = nil in e ys - c[0]) + c[0])",+ "in (foldl (fun ($1: convex_hull_trick) ($3: int) ->",+ " cht_insert $1 a[$3] b[$3]",+ ") cht_init (range 1), ys$2)"+ ]+ let expected =+ parseProgram'+ [ "let k: int = 1000",+ "in let a: int list = range k",+ "in let b: int list = range k",+ "in let c: int list = range k",+ "in let e: int list -> int = fun f -> len f + 1234",+ "in let xs: int list = range k",+ "in (foldl (" ++ step ++ ") (" ++ base ++ ") (range (k - 1))).1",+ ""+ ]+ (formatProgram <$> run' prog) `shouldBe` Right (formatProgram expected)
test/Jikka/Core/Convert/MatrixExponentiationSpec.hs view
@@ -8,77 +8,45 @@ import Jikka.Common.Alpha import Jikka.Common.Error import Jikka.Core.Convert.MatrixExponentiation (run)-import Jikka.Core.Language.BuiltinPatterns+import qualified Jikka.Core.Convert.TypeInfer as TypeInfer+import Jikka.Core.Format (formatProgram) import Jikka.Core.Language.Expr-import Jikka.Core.Language.Util+import Jikka.Core.Parse (parseProgram) import Test.Hspec run' :: Program -> Either Error Program run' = flip evalAlphaT 0 . run +parseProgram' :: [String] -> Program+parseProgram' = fromSuccess . flip evalAlphaT 100 . (TypeInfer.run <=< parseProgram . unlines)+ spec :: Spec spec = describe "run" $ do it "works about matrices" $ do- let ts2 = [IntTy, IntTy]- let ts22 = [TupleTy ts2, TupleTy ts2]- let proj i = Proj' ts2 i (Var "xs")- let mkTuple ts = uncurryApp (Tuple' ts)- let letConst = Let "c" IntTy (LitInt' 10)- let k = LitInt' 100- let base = mkTuple ts2 [LitInt' 12, LitInt' 34] let prog =- ResultExpr- ( letConst- ( Iterate'- (TupleTy ts2)- k- ( Lam- "xs"- (TupleTy ts2)- (mkTuple ts2 [Plus' (proj 0) (Mult' (Var "c") (proj 1)), proj 0])- )- base- )- )+ parseProgram'+ [ "let c: int = 10",+ "in let k: int = 1000",+ "in iterate k (fun x -> (x.0 + c * x.1, x.0)) (12, 34)"+ ] let expected =- ResultExpr- ( letConst- ( MatAp'- 2- 2- ( MatPow'- 2- (mkTuple ts22 [mkTuple ts2 [Lit1, Var "c"], mkTuple ts2 [Lit1, Lit0]])- k- )- base- )- )- run' prog `shouldBe` Right expected+ parseProgram'+ [ "let c: int = 10",+ "in let k: int = 1000",+ "in matap@2@2 (matpow@2 ((1, c), (1, 0)) k) (12, 34)"+ ]+ (formatProgram <$> run' prog) `shouldBe` Right (formatProgram expected) it "works about integers" $ do- let letConst = Let "c" IntTy (LitInt' 10)- let k = LitInt' 100- let base = LitInt' 1234 let prog =- ResultExpr- ( letConst- ( Iterate'- IntTy- k- ( Lam- "x"- IntTy- (Plus' (Mult' (Var "c") (Var "x")) (LitInt' 2))- )- base- )- )+ parseProgram'+ [ "let c: int = 10",+ "in let k: int = 1000",+ "in iterate k (fun x -> c * x + 2) 1234"+ ] let expected =- ResultExpr- ( letConst- ( Plus'- (Mult' (Pow' (Var "c") k) base)- (Mult' (FloorDiv' (Minus' (Pow' (Var "c") k) (LitInt' 1)) (Minus' (Var "c") (LitInt' 1))) (LitInt' 2))- )- )- run' prog `shouldBe` Right expected+ parseProgram'+ [ "let c: int = 10",+ "in let k: int = 1000",+ "in c ** k * 1234 + (c ** k - 1) / (c - 1) * 2"+ ]+ (formatProgram <$> run' prog) `shouldBe` Right (formatProgram expected)
test/Jikka/Core/FormatSpec.hs view
@@ -37,11 +37,10 @@ let expected = unlines [ "let rec solve$0 (n$1: int): int =",- " let xs$2: int list =",- " map((fun (i$3: int) ->",- " i$3 * i$3",- " ), range(n$1))",- " in sum(xs$2)",+ " let xs$2: int list = map (fun (i$3: int) ->",+ " i$3 * i$3",+ " ) (range n$1)",+ " in sum xs$2", "in", "solve$0" ]
+ test/Jikka/Core/Language/ArithmeticExprSpec.hs view
@@ -0,0 +1,29 @@+{-# LANGUAGE OverloadedStrings #-}++module Jikka.Core.Language.ArithmeticExprSpec+ ( spec,+ )+where++import qualified Data.Vector as V+import Jikka.Core.Language.ArithmeticExpr+import Jikka.Core.Language.BuiltinPatterns+import Jikka.Core.Language.Expr+import Test.Hspec++spec :: Spec+spec = do+ describe "makeVectorFromArithmeticExpr" $ do+ it "works" $ do+ let xs = V.fromList ["x", "y"]+ let e =+ parseArithmeticExpr+ (Plus' (Var "x") (Plus' (Mult' (LitInt' 3) (Var "y")) (Minus' (Var "x") (LitInt' 10))))+ let f = V.fromList [parseArithmeticExpr (LitInt' 2), parseArithmeticExpr (LitInt' 3)]+ let c = parseArithmeticExpr (LitInt' (-10))+ makeVectorFromArithmeticExpr xs e `shouldBe` Just (f, c)+ describe "normalizeArithmeticExpr" $ do+ it "works" $ do+ let e = Plus' (LitInt' 2) (Plus' (Var "a") (LitInt' (-2)))+ let expected = Var "a"+ (formatArithmeticExpr . parseArithmeticExpr) e `shouldBe` expected
− test/Jikka/Core/Language/ArithmeticalExprSpec.hs
@@ -1,29 +0,0 @@-{-# LANGUAGE OverloadedStrings #-}--module Jikka.Core.Language.ArithmeticalExprSpec- ( spec,- )-where--import qualified Data.Vector as V-import Jikka.Core.Language.ArithmeticalExpr-import Jikka.Core.Language.BuiltinPatterns-import Jikka.Core.Language.Expr-import Test.Hspec--spec :: Spec-spec = do- describe "makeVectorFromArithmeticalExpr" $ do- it "works" $ do- let xs = V.fromList ["x", "y"]- let e =- parseArithmeticalExpr- (Plus' (Var "x") (Plus' (Mult' (LitInt' 3) (Var "y")) (Minus' (Var "x") (LitInt' 10))))- let f = V.fromList [parseArithmeticalExpr (LitInt' 2), parseArithmeticalExpr (LitInt' 3)]- let c = parseArithmeticalExpr (LitInt' (-10))- makeVectorFromArithmeticalExpr xs e `shouldBe` Just (f, c)- describe "normalizeArithmeticalExpr" $ do- it "works" $ do- let e = Plus' (LitInt' 2) (Plus' (Var "a") (LitInt' (-2)))- let expected = Var "a"- (formatArithmeticalExpr . parseArithmeticalExpr) e `shouldBe` expected
test/Jikka/RestrictedPython/Convert/ToCoreSpec.hs view
@@ -7,6 +7,7 @@ import qualified Jikka.Core.Format as Y (formatProgram) import qualified Jikka.Core.Language.BuiltinPatterns as Y import qualified Jikka.Core.Language.Expr as Y+import qualified Jikka.Core.Parse as Y (parseProgram) import Jikka.RestrictedPython.Convert.ToCore (run) import qualified Jikka.RestrictedPython.Language.Expr as X import qualified Jikka.RestrictedPython.Language.WithoutLoc as X@@ -15,6 +16,9 @@ run' :: X.Program -> Either Error Y.Program run' = flip evalAlphaT 0 . run +parseProgram :: [String] -> Y.Program+parseProgram = fromSuccess . flip evalAlphaT 100 . Y.parseProgram . unlines+ spec :: Spec spec = describe "run" $ do it "works" $ do@@ -66,37 +70,27 @@ ] ] let expected =- unlines+ parseProgram [ "let rec solve (n: int): int =",- " let a: $0 =",- " 0",- " in let b: $1 =",- " 1",+ " let a: $0 = 0",+ " in let b: $1 = 1", " in let $4: $5 * $6 =",- " foldl((fun ($4: $5 * $6) ($3: $2) ->",- " let b: $5 =",- " $4.0",- " in let a: $6 =",- " $4.1",- " in let i: $7 =",- " $3",- " in let c: $8 =",- " a + b",- " in let a: $9 =",- " b",- " in let b: $10 =",- " c",+ " foldl (fun ($4: $5 * $6) ($3: $2) ->",+ " let b: $5 = $4.0",+ " in let a: $6 = $4.1",+ " in let i: $7 = $3",+ " in let c: $8 = a + b",+ " in let a: $9 = b",+ " in let b: $10 = c", " in (b, a)",- " ), (b, a), range(n))",- " in let b: $5 =",- " $4.0",- " in let a: $6 =",- " $4.1",+ " ) (b, a) (range n)",+ " in let b: $5 = $4.0",+ " in let a: $6 = $4.1", " in a", "in", "solve" ]- (Y.formatProgram <$> run' prog) `shouldBe` Right expected+ (Y.formatProgram <$> run' prog) `shouldBe` Right (Y.formatProgram expected) it "converts if-statements correctly" $ do let prog = [ X.ToplevelFunctionDef@@ -113,18 +107,14 @@ ] ] let expected =- unlines+ parseProgram [ "let rec solve : int =",- " let $2: $1, =",- " if true then let x: $3 =",- " 1",- " in (x,) else let x: $5 =",- " 0",- " in (x,)",- " in let x: $1 =",- " $2.0",+ " let $2: $1 one_tuple = if true",+ " then let x: $3 = 1 in (x,)",+ " else let x: $5 = 0 in (x,)",+ " in let x: $1 = $2.0", " in x", "in", "solve" ]- (Y.formatProgram <$> run' prog) `shouldBe` Right expected+ (Y.formatProgram <$> run' prog) `shouldBe` Right (Y.formatProgram expected)