Jikka 5.4.0.0 → 5.5.0.0
raw patch · 59 files changed
+1291/−380 lines, 59 filesdep ~template-haskell
Dependency ranges changed: template-haskell
Files
- CHANGELOG.md +17/−1
- Jikka.cabal +13/−6
- README.md +10/−5
- app/doctests.hs +14/−0
- doctests.hs +0/−13
- src/Jikka/CPlusPlus/Convert/BundleRuntime.hs +18/−16
- src/Jikka/CPlusPlus/Format.hs +1/−3
- src/Jikka/Common/FileEmbed.hs +3/−1
- src/Jikka/Common/IOFormat.hs +27/−8
- src/Jikka/Core/Convert.hs +2/−0
- src/Jikka/Core/Convert/ANormal.hs +4/−3
- src/Jikka/Core/Convert/Alpha.hs +53/−23
- src/Jikka/Core/Convert/ArithmeticExpr.hs +9/−5
- src/Jikka/Core/Convert/Beta.hs +2/−4
- src/Jikka/Core/Convert/BubbleLet.hs +2/−2
- src/Jikka/Core/Convert/CloseAll.hs +5/−5
- src/Jikka/Core/Convert/CloseMin.hs +18/−11
- src/Jikka/Core/Convert/CloseSum.hs +5/−5
- src/Jikka/Core/Convert/ConstantFolding.hs +15/−14
- src/Jikka/Core/Convert/ConstantPropagation.hs +2/−2
- src/Jikka/Core/Convert/ConvexHullTrick.hs +6/−4
- src/Jikka/Core/Convert/CumulativeSum.hs +2/−4
- src/Jikka/Core/Convert/EqualitySolving.hs +14/−13
- src/Jikka/Core/Convert/Eta.hs +2/−2
- src/Jikka/Core/Convert/KubaruToMorau.hs +2/−2
- src/Jikka/Core/Convert/MakeScanl.hs +2/−2
- src/Jikka/Core/Convert/MatrixExponentiation.hs +3/−3
- src/Jikka/Core/Convert/PropagateMod.hs +6/−6
- src/Jikka/Core/Convert/RemoveUnusedVars.hs +2/−2
- src/Jikka/Core/Convert/SegmentTree.hs +2/−2
- src/Jikka/Core/Convert/ShortCutFusion.hs +9/−9
- src/Jikka/Core/Convert/SortAbs.hs +135/−0
- src/Jikka/Core/Convert/SpecializeFoldl.hs +2/−2
- src/Jikka/Core/Convert/TrivialLetElimination.hs +2/−2
- src/Jikka/Core/Convert/TypeInfer.hs +21/−6
- src/Jikka/Core/Convert/UnpackTuple.hs +2/−4
- src/Jikka/Core/Language/ArithmeticExpr.hs +30/−0
- src/Jikka/Core/Language/AssertedHint.hs +274/−0
- src/Jikka/Core/Language/Lint.hs +10/−0
- src/Jikka/Core/Language/NameCheck.hs +82/−0
- src/Jikka/Core/Language/QuasiRules.hs +14/−4
- src/Jikka/Core/Language/RewriteRules.hs +36/−15
- src/Jikka/Core/Language/TypeCheck.hs +1/−3
- src/Jikka/Core/Language/Util.hs +5/−0
- src/Jikka/Core/Parse/Happy.y +1/−1
- test/Jikka/CPlusPlus/FormatSpec.hs +2/−2
- test/Jikka/Core/Convert/ANormalSpec.hs +6/−6
- test/Jikka/Core/Convert/AlphaSpec.hs +4/−4
- test/Jikka/Core/Convert/BetaSpec.hs +2/−2
- test/Jikka/Core/Convert/CloseMinSpec.hs +74/−0
- test/Jikka/Core/Convert/ConvexHullTrickSpec.hs +1/−1
- test/Jikka/Core/Convert/CumulativeSumSpec.hs +6/−6
- test/Jikka/Core/Convert/SegmentTreeSpec.hs +8/−8
- test/Jikka/Core/Convert/ShortCutFusionSpec.hs +2/−2
- test/Jikka/Core/Convert/SortAbsSpec.hs +51/−0
- test/Jikka/Core/Convert/TypeInferSpec.hs +105/−94
- test/Jikka/Core/Convert/UnpackTupleSpec.hs +2/−2
- test/Jikka/Core/Language/AssertedHintSpec.hs +93/−0
- test/Jikka/Core/ParseSpec.hs +50/−40
CHANGELOG.md view
@@ -1,10 +1,26 @@ # Changelog for Jikka +## 2021-09-04: v5.5.0.0++Features:++- Now Jikka is available on Web: <https://kmyk.github.io/Jikka/playground/>+- Solve some formulae in the form of `∑ᵢ ∑ⱼ |aᵢ−aⱼ|` [#210](https://github.com/kmyk/Jikka/pull/210) by [@kmyk](https://github.com/kmyk)++Bug Fix:++- Fix a bug about `std::accumulate` ([#205](https://github.com/kmyk/Jikka/pull/205) by [@riantkb](https://github.com/riantkb)+ ## 2021-08-24: v5.4.0.0 -- More and more tests are added and some bugs are removed.+Features:+ - An online judge is published: <https://judge.kimiyuki.net/> - This judge contains example problems which Jikka can/will be able to solve.++Bug Fix:++- More and more tests are added and some bugs are removed. ## 2021-08-16: v5.3.0.0
Jikka.cabal view
@@ -5,7 +5,7 @@ -- see: https://github.com/sol/hpack name: Jikka-version: 5.4.0.0+version: 5.5.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@@ -84,6 +84,7 @@ Jikka.Core.Convert.RemoveUnusedVars Jikka.Core.Convert.SegmentTree Jikka.Core.Convert.ShortCutFusion+ Jikka.Core.Convert.SortAbs Jikka.Core.Convert.SpecializeFoldl Jikka.Core.Convert.TrivialLetElimination Jikka.Core.Convert.TypeInfer@@ -91,6 +92,7 @@ Jikka.Core.Evaluate Jikka.Core.Format Jikka.Core.Language.ArithmeticExpr+ Jikka.Core.Language.AssertedHint Jikka.Core.Language.Beta Jikka.Core.Language.BuiltinPatterns Jikka.Core.Language.Expr@@ -98,6 +100,7 @@ Jikka.Core.Language.LambdaPatterns Jikka.Core.Language.Lint Jikka.Core.Language.ModuloExpr+ Jikka.Core.Language.NameCheck Jikka.Core.Language.QuasiRules Jikka.Core.Language.RewriteRules Jikka.Core.Language.Runtime@@ -169,7 +172,7 @@ , deepseq >=1.4.4 && <1.5 , directory >=1.3.3 && <1.4 , mtl >=2.2.2 && <2.3- , template-haskell >=2.16.0 && <2.17+ , template-haskell >=2.15.0 && <2.17 , text >=1.2.3 && <1.3 , transformers >=0.5.6 && <0.6 , vector >=0.12.3 && <0.13@@ -193,7 +196,7 @@ , deepseq >=1.4.4 && <1.5 , directory >=1.3.3 && <1.4 , mtl >=2.2.2 && <2.3- , template-haskell >=2.16.0 && <2.17+ , template-haskell >=2.15.0 && <2.17 , text >=1.2.3 && <1.3 , transformers >=0.5.6 && <0.6 , vector >=0.12.3 && <0.13@@ -203,9 +206,10 @@ type: exitcode-stdio-1.0 main-is: doctests.hs other-modules:+ Main Paths_Jikka hs-source-dirs:- ./+ app ghc-options: -W -threaded -rtsopts -with-rtsopts=-N -optP-Wno-nonportable-include-path build-depends: Jikka@@ -217,7 +221,7 @@ , directory >=1.3.3 && <1.4 , doctest , mtl >=2.2.2 && <2.3- , template-haskell >=2.16.0 && <2.17+ , template-haskell >=2.15.0 && <2.17 , text >=1.2.3 && <1.3 , transformers >=0.5.6 && <0.6 , vector >=0.12.3 && <0.13@@ -234,6 +238,7 @@ Jikka.Core.Convert.AlphaSpec Jikka.Core.Convert.ANormalSpec Jikka.Core.Convert.BetaSpec+ Jikka.Core.Convert.CloseMinSpec Jikka.Core.Convert.CloseSumSpec Jikka.Core.Convert.ConstantFoldingSpec Jikka.Core.Convert.ConstantPropagationSpec@@ -247,6 +252,7 @@ Jikka.Core.Convert.RemoveUnusedVarsSpec Jikka.Core.Convert.SegmentTreeSpec Jikka.Core.Convert.ShortCutFusionSpec+ Jikka.Core.Convert.SortAbsSpec Jikka.Core.Convert.SpecializeFoldlSpec Jikka.Core.Convert.TrivialLetEliminationSpec Jikka.Core.Convert.TypeInferSpec@@ -254,6 +260,7 @@ Jikka.Core.EvaluateSpec Jikka.Core.FormatSpec Jikka.Core.Language.ArithmeticExprSpec+ Jikka.Core.Language.AssertedHintSpec Jikka.Core.Language.BetaSpec Jikka.Core.ParseSpec Jikka.CPlusPlus.Convert.FromCoreSpec@@ -296,7 +303,7 @@ , hspec , mtl >=2.2.2 && <2.3 , ormolu- , template-haskell >=2.16.0 && <2.17+ , template-haskell >=2.15.0 && <2.17 , text >=1.2.3 && <1.3 , transformers >=0.5.6 && <0.6 , vector >=0.12.3 && <0.13
README.md view
@@ -4,14 +4,18 @@ Jikka is an automated solver for problems of competitive programming. -In competitive programming, there are some problems which are solvable only with "repeating formula transformations", "pasting snippets of famous data structures", etc.-Jikka automatically solves such problems.-Jikka takes such problems as input in the form of a program of a very restricted subset of Python, optimizes the code to reduce the computational complexity, and outputs as an implementation in C++.+In competitive programming, there are some problems that can be solved just by _repeating formula transformations_ or by _pasting snippets of famous data structures_.+Jikka solves such problems automatically.+Jikka takes problems as input in the form of programs of a very restricted subset of Python, optimizes the codes to reduce their computational complexity, and converts them to implementations of C++ for output. / 競技プログラミングにおいて「ただ式変形をするだけで解ける」「ただデータ構造のライブラリを貼るだけで解ける」問題は実は少なくありません。-Jikka はそのような問題を自動で解きます。-そのような問題をとても制限された Python のサブセット言語のコードの形で入力として受け取り、計算量を落とすような最適化を行い、C++ の実装に変換して出力します。+Jikka はそのような問題を自動で解いてくれます。+Jikka は問題をとても制限された Python のサブセット言語のコードの形で入力として受け取り、計算量を落とすような最適化を行い、C++ の実装に変換して出力します。 +## Try on Web++Go <https://kmyk.github.io/Jikka/playground>.+ ## Usage ```console@@ -59,6 +63,7 @@ - A list of optimizations which Jikka does / Jikka が行なってくれる最適化の一覧 - [examples/](https://github.com/kmyk/Jikka/blob/master/examples) - [gallery](https://kmyk.github.io/Jikka/gallery)+ - [playground](https://kmyk.github.io/Jikka/playground) - [CHANGELOG.md](https://github.com/kmyk/Jikka/blob/master/CHANGELOG.md) For developpers:
+ app/doctests.hs view
@@ -0,0 +1,14 @@+import Test.DocTest++-- | The modules generated by alex and happy confuse doctest, so we need to avoid some modules which depend on them.+-- TODO: Resolve this issue.+--+-- > main = doctest ["-isrc", "src/Jikka/Main.hs"]+main :: IO ()+main =+ doctest+ [ "src/Jikka/Common/",+ "src/Jikka/Python/Convert/",+ "src/Jikka/Python/Language/",+ "src/Jikka/RestrictedPython/Language/"+ ]
− doctests.hs
@@ -1,13 +0,0 @@-import Test.DocTest---- | The modules generated by alex and happy confuse doctest, so we need to avoid some modules which depend on them.--- TODO: Resolve this issue.------ > main = doctest ["-isrc", "src/Jikka/Main.hs"]-main :: IO ()-main = doctest- [ "src/Jikka/Common/"- , "src/Jikka/Python/Convert/"- , "src/Jikka/Python/Language/"- , "src/Jikka/RestrictedPython/Language/"- ]
src/Jikka/CPlusPlus/Convert/BundleRuntime.hs view
@@ -37,18 +37,16 @@ #ifdef JIKKA_EMBED_RUNTIME embeddedRuntimeFiles :: [(FilePath, T.Text)] embeddedRuntimeFiles = $(embedDir "runtime/include")-#endif -{-# ANN readRuntimeFile ("HLint: ignore Redundant return" :: String) #-}-readRuntimeFile :: (MonadIO m, MonadError Error m) => FilePath -> m T.Text-readRuntimeFile path = do- return () -- Without this, Ormolu fails with "The GHC parser (in Haddock mode) failed: parse error on input `='"--#ifdef JIKKA_EMBED_RUNTIME+readRuntimeFile :: MonadError Error m => FilePath -> m T.Text+readRuntimeFile path = case lookup ("runtime/include/" ++ path) embeddedRuntimeFiles of Just file -> return file Nothing -> throwInternalError $ "failed to open file. It may need recompile the binary?: " ++ path+ #else+readRuntimeFile :: (MonadIO m, MonadError Error m) => FilePath -> m T.Text+readRuntimeFile path = do resolvedPath <- liftIO $ getDataFileName ("runtime/include/" ++ path) file <- liftIO $ tryIOError (T.readFile resolvedPath) case file of@@ -72,11 +70,11 @@ throwInternalErrorAt'' :: MonadError Error m => FilePath -> Integer -> String -> m a throwInternalErrorAt'' path lineno msg = wrapError' (path ++ " (line " ++ show lineno ++ ")") $ throwInternalError msg -runLine :: (MonadIO m, MonadError Error m, MonadState PreprocessorState m) => FilePath -> Integer -> T.Text -> m [T.Text]-runLine path lineno line+runLine :: (MonadError Error m, MonadState PreprocessorState m) => (FilePath -> m T.Text) -> FilePath -> Integer -> T.Text -> m [T.Text]+runLine readRuntimeFile path lineno line | "#include \"" `T.isPrefixOf` line = case T.splitOn "\"" line of ["#include ", path', ""] -> do- lines <- runFile (T.unpack path')+ lines <- runFile readRuntimeFile (T.unpack path') return (lines ++ [T.pack ("#line " ++ show (lineno + 1) ++ " \"" ++ path ++ "\"")]) _ -> throwInternalErrorAt'' path lineno "invalid #include \"...\"" | otherwise = do@@ -86,11 +84,11 @@ False : _ -> return [] [] -> throwInternalError "there are more #endif than #ifdef and #ifndef" -runLines :: (MonadIO m, MonadError Error m, MonadState PreprocessorState m) => FilePath -> Integer -> [T.Text] -> m [T.Text]-runLines path lineno lines = concat <$> zipWithM (runLine path) [lineno ..] lines+runLines :: (MonadError Error m, MonadState PreprocessorState m) => (FilePath -> m T.Text) -> FilePath -> Integer -> [T.Text] -> m [T.Text]+runLines readRuntimeFile path lineno lines = concat <$> zipWithM (runLine readRuntimeFile path) [lineno ..] lines -runFile :: (MonadIO m, MonadError Error m, MonadState PreprocessorState m) => FilePath -> m [T.Text]-runFile path = do+runFile :: (MonadError Error m, MonadState PreprocessorState m) => (FilePath -> m T.Text) -> FilePath -> m [T.Text]+runFile readRuntimeFile path = do file <- readRuntimeFile path let lines = T.lines file let macro = map (\c -> if isAlphaNum c then toUpper c else '_') path@@ -107,7 +105,7 @@ then return [] else do modify' (\s -> s {definedMacros = S.insert macro macros})- (T.pack ("#line 3 \"" ++ path ++ "\"") :) <$> runLines path 3 (drop 2 (init lines))+ (T.pack ("#line 3 \"" ++ path ++ "\"") :) <$> runLines readRuntimeFile path 3 (drop 2 (init lines)) removeConsecutiveLineDirectives :: [T.Text] -> [T.Text] removeConsecutiveLineDirectives = \case@@ -116,7 +114,11 @@ [] -> [] -- | `run` bundles runtime headers to C++ code like <https://github.com/online-judge-tools/verification-helper `oj-bundle` command>.+#ifdef JIKKA_EMBED_RUNTIME+run :: MonadError Error m => T.Text -> m T.Text+#else run :: (MonadIO m, MonadError Error m) => T.Text -> m T.Text+#endif run prog = wrapError' "Jikka.CPlusPlus.Convert.BundleRuntime" $ do- lines <- evalStateT (runLines "main.cpp" 1 (T.lines prog)) initialPreprocessorState+ lines <- evalStateT (runLines readRuntimeFile "main.cpp" 1 (T.lines prog)) initialPreprocessorState return $ T.unlines (removeConsecutiveLineDirectives lines)
src/Jikka/CPlusPlus/Format.hs view
@@ -196,9 +196,7 @@ formatLiteral :: Literal -> Code formatLiteral = \case LitInt32 n -> show n- LitInt64 n- | - (2 ^ 31) <= n && n < 2 ^ 31 -> show n- | otherwise -> show n ++ "ll"+ LitInt64 n -> show n ++ "ll" LitBool p -> if p then "true" else "false" LitChar c -> show c LitString s -> show s
src/Jikka/Common/FileEmbed.hs view
@@ -3,6 +3,7 @@ module Jikka.Common.FileEmbed where import Control.Monad+import Data.Char import qualified Data.Text as T import qualified Data.Text.IO as T import Language.Haskell.TH@@ -30,4 +31,5 @@ paths <- runIO $ listDirectoryRecursive path contents <- runIO $ mapM T.readFile paths :: Q [T.Text] mapM_ addDependentFile paths- [e|zip paths contents :: [(FilePath, T.Text)]|]+ let contents' = map (map ord . T.unpack) contents -- use [Int] instead of T.Text for scripts/erase_template_haskell.py+ [e|zip paths (map (T.pack . map chr) contents') :: [(FilePath, T.Text)]|]
src/Jikka/Common/IOFormat.hs view
@@ -1,5 +1,6 @@ {-# LANGUAGE FlexibleContexts #-} {-# LANGUAGE LambdaCase #-}+{-# LANGUAGE ScopedTypeVariables #-} module Jikka.Common.IOFormat where @@ -127,17 +128,33 @@ At e i -> second (++ [i]) <$> unpackSubscriptedVar e e -> throwInternalError $ "not a subscripted variable: " ++ formatFormatExpr e -makeReadValueIO :: (MonadError Error m, MonadIO m) => (value -> m Integer) -> (Integer -> value) -> (value -> m (V.Vector value)) -> (V.Vector value -> value) -> IOFormat -> m ([value], M.Map String value)+makeReadValueIO :: forall m value. (MonadError Error m, MonadIO m) => (value -> m Integer) -> (Integer -> value) -> (value -> m (V.Vector value)) -> (V.Vector value -> value) -> IOFormat -> m ([value], M.Map String value) makeReadValueIO toInt fromInt toList fromList format = wrapError' "Jikka.Common.IOFormat.makeReadValueIO" $ do- env <- liftIO $ newIORef M.empty- sizes <- liftIO $ newIORef M.empty- let lookup x = do+ env <- liftIO $ newIORef M.empty :: m (IORef (M.Map String value))+ sizes <- liftIO $ newIORef M.empty :: m (IORef (M.Map String Integer))+ let lookup :: String -> m value+ lookup x = do y <- M.lookup x <$> liftIO (readIORef env) case y of Nothing -> throwInternalError $ "undefined variable: " ++ x Just y -> return y- let go = \case+ let goEmpty :: FormatTree -> m ()+ goEmpty = \case Exp e -> do+ (x, _) <- unpackSubscriptedVar e+ y <- M.lookup x <$> liftIO (readIORef env)+ case y of+ Just _ -> return ()+ Nothing -> do+ let y = fromList V.empty+ liftIO $ modifyIORef' env (M.insert x y)+ Newline -> return ()+ Seq formats -> mapM_ goEmpty formats+ Loop _ _ body -> do+ goEmpty body+ let go :: FormatTree -> m ()+ go = \case+ Exp e -> do (x, indices) <- unpackSubscriptedVar e word <- liftIO $ hGetWord stdin n <- case readMaybe word of@@ -171,9 +188,11 @@ Len (Var xs) -> toInteger . V.length <$> (toList =<< lookup xs) _ -> throwInternalError $ "invalid loop size in input tree: " ++ formatFormatExpr n liftIO $ modifyIORef' sizes (M.insert i n)- forM_ [0 .. n -1] $ \i' -> do- liftIO $ modifyIORef' env (M.insert i (fromInt i'))- go body+ if n == 0+ then goEmpty body+ else forM_ [0 .. n -1] $ \i' -> do+ liftIO $ modifyIORef' env (M.insert i (fromInt i'))+ go body go (inputTree format) values <- mapM lookup (inputVariables format) env <- liftIO $ readIORef env
src/Jikka/Core/Convert.hs view
@@ -37,6 +37,7 @@ import qualified Jikka.Core.Convert.RemoveUnusedVars as RemoveUnusedVars import qualified Jikka.Core.Convert.SegmentTree as SegmentTree import qualified Jikka.Core.Convert.ShortCutFusion as ShortCutFusion+import qualified Jikka.Core.Convert.SortAbs as SortAbs import qualified Jikka.Core.Convert.SpecializeFoldl as SpecializeFoldl import qualified Jikka.Core.Convert.TrivialLetElimination as TrivialLetElimination import qualified Jikka.Core.Convert.TypeInfer as TypeInfer@@ -49,6 +50,7 @@ prog <- UnpackTuple.run prog prog <- MatrixExponentiation.run prog prog <- SpecializeFoldl.run prog+ prog <- SortAbs.run prog prog <- MakeScanl.run prog prog <- PropagateMod.run prog prog <- ConstantPropagation.run prog
src/Jikka/Core/Convert/ANormal.hs view
@@ -16,7 +16,6 @@ import Jikka.Common.Alpha (MonadAlpha) import Jikka.Common.Error-import qualified Jikka.Core.Convert.Alpha as Alpha (runProgram) import Jikka.Core.Language.Expr import Jikka.Core.Language.Lint import Jikka.Core.Language.TypeCheck@@ -107,7 +106,9 @@ -- > in z run :: (MonadAlpha m, MonadError Error m) => Program -> m Program run prog = wrapError' "Jikka.Core.Convert.ANormal" $ do- prog <- Alpha.runProgram prog+ precondition $ do+ lint prog prog <- runProgram prog- ensureWellTyped prog+ postcondition $ do+ lint prog return prog
src/Jikka/Core/Convert/Alpha.hs view
@@ -10,43 +10,66 @@ -- Maintainer : kimiyuki95@gmail.com -- Stability : experimental -- Portability : portable-module Jikka.Core.Convert.Alpha where+module Jikka.Core.Convert.Alpha+ ( run,+ runProgram,+ runToplevelExpr,+ runExpr,+ )+where +import Control.Monad.State.Strict import Jikka.Common.Alpha import Jikka.Common.Error import Jikka.Core.Language.Expr+import Jikka.Core.Language.Lint -rename :: MonadAlpha m => VarName -> m VarName+type UsedVars = [VarName]++type RenameMapping = [(VarName, VarName)]++rename :: (MonadState UsedVars m, MonadAlpha m) => VarName -> m VarName rename x = do- let base = takeWhile (/= '$') (unVarName x)- i <- nextCounter- return $ VarName (base ++ "$" ++ show i)+ used <- get+ y <-+ if x `notElem` used+ then return x+ else do+ let base = takeWhile (/= '$') (unVarName x)+ i <- nextCounter+ return $ VarName (base ++ "$" ++ show i)+ put $ y : used+ return y -runExpr :: (MonadAlpha m, MonadError Error m) => [(VarName, VarName)] -> Expr -> m Expr-runExpr env = \case+runExpr' :: (MonadState UsedVars m, MonadAlpha m, MonadError Error m) => RenameMapping -> Expr -> m Expr+runExpr' env = \case Var x -> case lookup x env of Nothing -> throwInternalError $ "undefined variable: " ++ unVarName x Just y -> return $ Var y Lit lit -> return $ Lit lit- App f e -> App <$> runExpr env f <*> runExpr env e+ App f e -> App <$> runExpr' env f <*> runExpr' env e Lam x t body -> do y <- rename x- body <- runExpr ((x, y) : env) body+ body <- runExpr' ((x, y) : env) body return $ Lam y t body Let x t e1 e2 -> do- e1 <- runExpr env e1+ e1 <- runExpr' env e1 y <- rename x- e2 <- runExpr ((x, y) : env) e2+ e2 <- runExpr' ((x, y) : env) e2 return $ Let y t e1 e2- Assert e1 e2 -> Assert <$> runExpr env e1 <*> runExpr env e2+ Assert e1 e2 -> Assert <$> runExpr' env e1 <*> runExpr' env e2 -runToplevelExpr :: (MonadAlpha m, MonadError Error m) => [(VarName, VarName)] -> ToplevelExpr -> m ToplevelExpr-runToplevelExpr env = \case- ResultExpr e -> ResultExpr <$> runExpr env e+runExpr :: (MonadAlpha m, MonadError Error m) => [(VarName, Type)] -> Expr -> m Expr+runExpr env e = wrapError' "Jikka.Core.Convert.Alpha.runExpr" $ do+ evalStateT (runExpr' (map (\(x, _) -> (x, x)) env) e) (map fst env)++runToplevelExpr' :: (MonadState UsedVars m, MonadAlpha m, MonadError Error m) => RenameMapping -> ToplevelExpr -> m ToplevelExpr+runToplevelExpr' env = \case+ ResultExpr e -> ResultExpr <$> runExpr' env e ToplevelLet x t e cont -> do y <- rename x- e <- runExpr env e- cont <- runToplevelExpr ((x, y) : env) cont+ e <- runExpr' env e+ cont <- runToplevelExpr' ((x, y) : env) cont return $ ToplevelLet y t e cont ToplevelLetRec f args ret body cont -> do g <- rename f@@ -55,13 +78,21 @@ return (x, y, t) let args1 = map (\(x, y, _) -> (x, y)) args let args2 = map (\(_, y, t) -> (y, t)) args- body <- runExpr (args1 ++ (f, g) : env) body- cont <- runToplevelExpr ((f, g) : env) cont+ body <- runExpr' (args1 ++ (f, g) : env) body+ cont <- runToplevelExpr' ((f, g) : env) cont return $ ToplevelLetRec g args2 ret body cont- ToplevelAssert e1 e2 -> ToplevelAssert <$> runExpr env e1 <*> runToplevelExpr env e2+ ToplevelAssert e1 e2 -> ToplevelAssert <$> runExpr' env e1 <*> runToplevelExpr' env e2 +runToplevelExpr :: (MonadAlpha m, MonadError Error m) => [(VarName, Type)] -> ToplevelExpr -> m ToplevelExpr+runToplevelExpr env e = wrapError' "Jikka.Core.Convert.Alpha.runToplevelExpr" $ do+ evalStateT (runToplevelExpr' (map (\(x, _) -> (x, x)) env) e) (map fst env)+ runProgram :: (MonadAlpha m, MonadError Error m) => Program -> m Program-runProgram = runToplevelExpr []+runProgram prog = wrapError' "Jikka.Core.Convert.Alpha.runProgram" $ do+ prog <- evalStateT (runToplevelExpr' [] prog) []+ postcondition $ do+ ensureAlphaConverted prog+ return prog -- | `run` renames variables in exprs to avoid name conflictions, even if the scopes of two variables are distinct. --@@ -81,5 +112,4 @@ -- > in x2 = x0 + y1 -- > x2 + y1 run :: (MonadAlpha m, MonadError Error m) => Program -> m Program-run prog = wrapError' "Jikka.Core.Convert.Alpha" $ do- runToplevelExpr [] prog+run = runProgram
src/Jikka/Core/Convert/ArithmeticExpr.hs view
@@ -10,6 +10,7 @@ -- Portability : portable module Jikka.Core.Convert.ArithmeticExpr ( run,+ runExpr, ) where @@ -20,15 +21,18 @@ import Jikka.Core.Language.TypeCheck import Jikka.Core.Language.Util -runExpr :: MonadError Error m => [(VarName, Type)] -> Expr -> m Expr-runExpr env e = do+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 +runExpr :: MonadError Error m => [(VarName, Type)] -> Expr -> m Expr+runExpr = mapSubExprM runExpr'+ runProgram :: MonadError Error m => Program -> m Program-runProgram = mapExprProgramM (mapSubExprM runExpr) -- Doesn't use RewriteRules because the rewriting may not terminate.+runProgram = mapExprProgramM (mapSubExprM runExpr') -- Doesn't use RewriteRules because the rewriting may not terminate. -- | `run` sorts arithmetical exprs. --@@ -44,8 +48,8 @@ run :: MonadError Error m => Program -> m Program run prog = wrapError' "Jikka.Core.Convert.ArithmeticExpr" $ do precondition $ do- ensureWellTyped prog+ lint prog prog <- runProgram prog postcondition $ do- ensureWellTyped prog+ lint prog return prog
src/Jikka/Core/Convert/Beta.hs view
@@ -19,7 +19,6 @@ import Jikka.Common.Alpha import Jikka.Common.Error-import qualified Jikka.Core.Convert.Alpha as Alpha import Jikka.Core.Language.Beta import Jikka.Core.Language.Expr import Jikka.Core.Language.Lint@@ -47,9 +46,8 @@ run :: (MonadAlpha m, MonadError Error m) => Program -> m Program run prog = wrapError' "Jikka.Core.Convert.Beta" $ do precondition $ do- ensureWellTyped prog- prog <- Alpha.run prog+ lint prog prog <- runProgram prog postcondition $ do- ensureWellTyped prog+ lint prog return prog
src/Jikka/Core/Convert/BubbleLet.hs view
@@ -55,8 +55,8 @@ run :: (MonadAlpha m, MonadError Error m) => Program -> m Program run prog = wrapError' "Jikka.Core.Convert.BubbleLet" $ do precondition $ do- ensureWellTyped prog+ lint prog prog <- runProgram prog postcondition $ do- ensureWellTyped prog+ lint prog return prog
src/Jikka/Core/Convert/CloseAll.hs view
@@ -28,7 +28,7 @@ import Jikka.Core.Language.QuasiRules import Jikka.Core.Language.RewriteRules -reduceAll :: MonadAlpha m => RewriteRule m+reduceAll :: (MonadAlpha m, MonadError Error m) => RewriteRule m reduceAll = mconcat [ -- list build functions@@ -42,7 +42,7 @@ [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+reduceAny :: (MonadAlpha m, MonadError Error m) => RewriteRule m reduceAny = mconcat [ -- list build functions@@ -57,7 +57,7 @@ [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+rule :: (MonadAlpha m, MonadError Error m) => RewriteRule m rule = mconcat [ reduceAll,@@ -113,8 +113,8 @@ run :: (MonadAlpha m, MonadError Error m) => Program -> m Program run prog = wrapError' "Jikka.Core.Convert.CloseAll" $ do precondition $ do- ensureWellTyped prog+ lint prog prog <- runProgram prog postcondition $ do- ensureWellTyped prog+ lint prog return prog
src/Jikka/Core/Convert/CloseMin.hs view
@@ -25,7 +25,7 @@ import Jikka.Common.Alpha import Jikka.Common.Error-import qualified Jikka.Core.Convert.Alpha as Alpha+import Jikka.Core.Language.AssertedHint import Jikka.Core.Language.BuiltinPatterns import Jikka.Core.Language.Expr import Jikka.Core.Language.FreeVars@@ -34,10 +34,14 @@ import Jikka.Core.Language.QuasiRules import Jikka.Core.Language.RewriteRules -reduceMin :: MonadAlpha m => RewriteRule m+reduceMin :: (MonadAlpha m, MonadError Error m) => RewriteRule m reduceMin = mconcat- [ -- list build functions+ [ -- reduce minimum-cons if non-nil+ pureRewriteRule "minimum/cons" $ \env -> \case+ Min1' t (Cons' _ x xs) | nullWithHints (assertedHints env) xs == Just False -> Just $ Min2' t x (Min1' t xs)+ _ -> Nothing,+ -- list build functions [r| "minimum/nil" minimum nil = bottom<"no minimum in empty list"> |], [r| "minimum/cons/cons" forall x y zs. minimum (cons x (cons y zs)) = min x (minimum (cons y zs)) |], [r| "minimum/range" forall n. minimum (range n) = 0 |],@@ -82,10 +86,14 @@ _ -> return Nothing ] -reduceMax :: MonadAlpha m => RewriteRule m+reduceMax :: (MonadAlpha m, MonadError Error m) => RewriteRule m reduceMax = mconcat- [ -- list build functions+ [ -- reduce maximum-cons if non-nil+ pureRewriteRule "maximum/cons" $ \env -> \case+ Max1' t (Cons' _ x xs) | nullWithHints (assertedHints env) xs == Just False -> Just $ Max2' t x (Max1' t xs)+ _ -> Nothing,+ -- list build functions [r| "maximum/nil" maximum nil = bottom<"no maximum in empty list"> |], [r| "maximum/cons/cons" forall x y zs. maximum (cons x (cons y zs)) = max x (maximum (cons y zs)) |], [r| "maximum/range" forall n. maximum (range n) = n - 1 |],@@ -131,7 +139,7 @@ ] -- | TODO: implement this-reduceArgMin :: Monad m => RewriteRule m+reduceArgMin :: (MonadAlpha m, MonadError Error m) => RewriteRule m reduceArgMin = simpleRewriteRule "reduceArgMin" $ \case -- list map functions ArgMin' t (Reversed' _ xs) -> Just $ Minus' (Minus' (Len' t xs) (ArgMin' t xs)) Lit1@@ -141,7 +149,7 @@ _ -> Nothing -- | TODO: implement this-reduceArgMax :: Monad m => RewriteRule m+reduceArgMax :: (MonadAlpha m, MonadError Error m) => RewriteRule m reduceArgMax = simpleRewriteRule "reduceArgMax" $ \case -- list map functions ArgMax' t (Reversed' _ xs) -> Just $ Minus' (Minus' (Len' t xs) (ArgMax' t xs)) Lit1@@ -150,7 +158,7 @@ ArgMax' _ (Map' t1 t2 (Lam x t (Plus' e1 e2)) xs) | x `isUnusedVar` e2 -> Just $ ArgMax' t2 (Map' t1 t2 (Lam x t e1) xs) _ -> Nothing -rule :: MonadAlpha m => RewriteRule m+rule :: (MonadAlpha m, MonadError Error m) => RewriteRule m rule = mconcat [ reduceMin,@@ -209,9 +217,8 @@ run :: (MonadAlpha m, MonadError Error m) => Program -> m Program run prog = wrapError' "Jikka.Core.Convert.CloseMin" $ do precondition $ do- ensureWellTyped prog+ lint prog prog <- runProgram prog- prog <- Alpha.run prog postcondition $ do- ensureWellTyped prog+ lint prog return prog
src/Jikka/Core/Convert/CloseSum.hs view
@@ -39,7 +39,7 @@ import Jikka.Core.Language.QuasiRules import Jikka.Core.Language.RewriteRules -reduceSum :: MonadAlpha m => RewriteRule m+reduceSum :: (MonadAlpha m, MonadError Error m) => RewriteRule m reduceSum = mconcat [ -- reduce list build functions@@ -87,7 +87,7 @@ -- | -- * This assumes that `ModFloor` is already propagated.-reduceModSum :: MonadAlpha m => RewriteRule m+reduceModSum :: (MonadAlpha m, MonadError Error m) => RewriteRule m reduceModSum = mconcat [ -- the corner case@@ -138,7 +138,7 @@ _ -> Nothing _ -> Nothing -rule :: MonadAlpha m => RewriteRule m+rule :: (MonadAlpha m, MonadError Error m) => RewriteRule m rule = mconcat [ reduceSum,@@ -204,8 +204,8 @@ run :: (MonadAlpha m, MonadError Error m) => Program -> m Program run prog = wrapError' "Jikka.Core.Convert.CloseSum" $ do precondition $ do- ensureWellTyped prog+ lint prog prog <- runProgram prog postcondition $ do- ensureWellTyped prog+ lint prog return prog
src/Jikka/Core/Convert/ConstantFolding.hs view
@@ -36,6 +36,7 @@ import Data.Bits import Data.Either+import Jikka.Common.Alpha import Jikka.Common.Error import Jikka.Core.Language.BuiltinPatterns import Jikka.Core.Language.Expr@@ -64,7 +65,7 @@ -- * `Abs` \(: \int \to \int\) -- * `Gcd` \(: \int \to \int \to \int\) -- * `Lcm` \(: \int \to \int \to \int\)-reduceConstArithmeticExpr :: Monad m => RewriteRule m+reduceConstArithmeticExpr :: (MonadAlpha m, MonadError Error m) => RewriteRule m reduceConstArithmeticExpr = let return' = Just . LitInt' in simpleRewriteRule "reduceConstArithmeticExpr" $ \case@@ -111,7 +112,7 @@ -- -- * `Min2` \(: \forall \alpha. \alpha \to \alpha \to \alpha\) (specialized to \(\alpha = \lbrace \bool, \int \rbrace\)) -- * `Max2` \(: \forall \alpha. \alpha \to \alpha \to \alpha\) (specialized to \(\alpha = \lbrace \bool, \int \rbrace\))-reduceConstMaxExpr :: Monad m => RewriteRule m+reduceConstMaxExpr :: (MonadAlpha m, MonadError Error m) => RewriteRule m reduceConstMaxExpr = simpleRewriteRule "reduceConstMaxExpr" $ \case Min2' _ (LitInt' a) (LitInt' b) -> Just . LitInt' $ min a b Min2' _ (LitBool' a) (LitBool' b) -> Just . LitBool' $ min a b@@ -127,7 +128,7 @@ -- * `And` \(: \bool \to \bool \to \bool\) -- * `Or` \(: \bool \to \bool \to \bool\) -- * `Implies` \(: \bool \to \bool \to \bool\)-reduceIdempotentBooleanExpr :: Monad m => RewriteRule m+reduceIdempotentBooleanExpr :: (MonadAlpha m, MonadError Error m) => RewriteRule m reduceIdempotentBooleanExpr = mconcat [ [r| "join/and" forall x. x && x = x|],@@ -145,7 +146,7 @@ -- * `And` \(: \bool \to \bool \to \bool\) -- * `Or` \(: \bool \to \bool \to \bool\) -- * `Implies` \(: \bool \to \bool \to \bool\)-reduceUnitBooleanExpr :: Monad m => RewriteRule m+reduceUnitBooleanExpr :: (MonadAlpha m, MonadError Error m) => RewriteRule m reduceUnitBooleanExpr = mconcat [ [r| "not/true" not true = false|],@@ -170,7 +171,7 @@ -- === Boolean functions -- -- * `If` \(: \forall \alpha. \bool \to \alpha \to \alpha \to \alpha\)-reduceConstBooleanExpr :: Monad m => RewriteRule m+reduceConstBooleanExpr :: (MonadAlpha m, MonadError Error m) => RewriteRule m reduceConstBooleanExpr = mconcat [ [r| "if/true" forall e1 e2. if true then e1 else e2 = e1|],@@ -188,7 +189,7 @@ -- * `BitXor` \(: \int \to \int \to \int\) -- * `BitLeftShift` \(: \int \to \int \to \int\) -- * `BitRightShift` \(: \int \to \int \to \int\)-reduceUnitBitExpr :: Monad m => RewriteRule m+reduceUnitBitExpr :: (MonadAlpha m, MonadError Error m) => RewriteRule m reduceUnitBitExpr = mconcat [ [r| "bitand/0" forall x. 0 & x = 0 |],@@ -220,7 +221,7 @@ -- * `BitXor` \(: \int \to \int \to \int\) -- * `BitLeftShift` \(: \int \to \int \to \int\) -- * `BitRightShift` \(: \int \to \int \to \int\)-reduceConstBitExpr :: Monad m => RewriteRule m+reduceConstBitExpr :: (MonadAlpha m, MonadError Error m) => RewriteRule m reduceConstBitExpr = let return' = Just . LitInt' in simpleRewriteRule "reduceConstBitExpr" $ \case@@ -243,7 +244,7 @@ -- * `GreaterEqual` \(: \forall \alpha. \alpha \to \alpha \to \bool\) (specialized to \(\alpha \in \lbrace \bool, \int \rbrace\)) -- * `Equal` \(: \forall \alpha. \alpha \to \alpha \to \bool\) (specialized to \(\alpha \in \lbrace \bool, \int \rbrace\)) -- * `NotEqual` \(: \forall \alpha. \alpha \to \alpha \to \bool\) (specialized to \(\alpha \in \lbrace \bool, \int \rbrace\))-reduceConstIntComparison :: Monad m => RewriteRule m+reduceConstIntComparison :: (MonadAlpha m, MonadError Error m) => RewriteRule m reduceConstIntComparison = simpleRewriteRule "comparison/const/int" $ (LitBool' <$>) . \case@@ -266,7 +267,7 @@ -- * `GreaterEqual` \(: \forall \alpha. \alpha \to \alpha \to \bool\) (specialized to \(\alpha \in \lbrace \bool, \int \rbrace\)) -- * `Equal` \(: \forall \alpha. \alpha \to \alpha \to \bool\) (specialized to \(\alpha \in \lbrace \bool, \int \rbrace\)) -- * `NotEqual` \(: \forall \alpha. \alpha \to \alpha \to \bool\) (specialized to \(\alpha \in \lbrace \bool, \int \rbrace\))-reduceUnitBooleanComparison :: Monad m => RewriteRule m+reduceUnitBooleanComparison :: (MonadAlpha m, MonadError Error m) => RewriteRule m reduceUnitBooleanComparison = mconcat [ -- TODO: implement lessthan and lessequal@@ -281,7 +282,7 @@ [r| "notequal/false'" forall x. x /= false = x |] ] -rule :: MonadError Error m => RewriteRule m+rule :: (MonadAlpha m, MonadError Error m) => RewriteRule m rule = mconcat [ reduceConstArithmeticExpr,@@ -295,7 +296,7 @@ reduceUnitBooleanComparison ] -runProgram :: MonadError Error m => Program -> m Program+runProgram :: (MonadAlpha m, MonadError Error m) => Program -> m Program runProgram = applyRewriteRuleProgram' rule -- | `run` folds constants in given programs.@@ -306,11 +307,11 @@ -- to the follwoing: -- -- > 3 x + 3-run :: MonadError Error m => Program -> m Program+run :: (MonadAlpha m, MonadError Error m) => Program -> m Program run prog = wrapError' "Jikka.Core.Convert.ConstantFolding" $ do precondition $ do- ensureWellTyped prog+ lint prog prog <- runProgram prog postcondition $ do- ensureWellTyped prog+ lint prog return prog
src/Jikka/Core/Convert/ConstantPropagation.hs view
@@ -70,8 +70,8 @@ run :: MonadError Error m => Program -> m Program run prog = wrapError' "Jikka.Core.Convert.ConstantPropagation" $ do precondition $ do- ensureWellTyped prog+ lint prog prog <- return $ run' prog postcondition $ do- ensureWellTyped prog+ lint prog return prog
src/Jikka/Core/Convert/ConvexHullTrick.hs view
@@ -28,6 +28,7 @@ import Control.Monad.Trans.Maybe import Jikka.Common.Alpha import Jikka.Common.Error+import qualified Jikka.Core.Convert.Alpha as Alpha import Jikka.Core.Language.ArithmeticExpr import Jikka.Core.Language.Beta import Jikka.Core.Language.BuiltinPatterns@@ -161,7 +162,7 @@ _ -> Nothing rule :: (MonadAlpha m, MonadError Error m) => RewriteRule m-rule = makeRewriteRule "Jikka.Core.Convert.ConvexHullTrick" $ \_ -> \case+rule = makeRewriteRule "Jikka.Core.Convert.ConvexHullTrick" $ \env -> \case -- build (fun f -> step(f)) base n Build' IntTy (Lam f _ step) base n -> runMaybeT $ do let ts = [ConvexHullTrickTy, ListTy IntTy]@@ -217,7 +218,8 @@ Let y ConvexHullTrickTy (ConvexHullTrickInsert' (Proj' ts 0 (Var x)) a b) $ uncurryApp (Tuple' ts) [Var y, Var f'] -- proj 1 (foldl step' base' (range (n - 1)))- return $ Proj' ts 1 (Foldl' IntTy (TupleTy ts) step' base' (Range1' n))+ let e = Proj' ts 1 (Foldl' IntTy (TupleTy ts) step' base' (Range1' n))+ lift $ Alpha.runExpr (typeEnv env) e _ -> return Nothing runProgram :: (MonadAlpha m, MonadError Error m) => Program -> m Program@@ -230,8 +232,8 @@ run :: (MonadAlpha m, MonadError Error m) => Program -> m Program run prog = wrapError' "Jikka.Core.Convert.ConvexHullTrick" $ do precondition $ do- ensureWellTyped prog+ lint prog prog <- runProgram prog postcondition $ do- ensureWellTyped prog+ lint prog return prog
src/Jikka/Core/Convert/CumulativeSum.hs view
@@ -20,7 +20,6 @@ import Data.Maybe import Jikka.Common.Alpha import Jikka.Common.Error-import qualified Jikka.Core.Convert.Alpha as Alpha import Jikka.Core.Language.ArithmeticExpr import Jikka.Core.Language.BuiltinPatterns import Jikka.Core.Language.Expr@@ -86,9 +85,8 @@ run :: (MonadAlpha m, MonadError Error m) => Program -> m Program run prog = wrapError' "Jikka.Core.Convert.CumulativeSum" $ do precondition $ do- ensureWellTyped prog- prog <- Alpha.run prog+ lint prog prog <- runProgram prog postcondition $ do- ensureWellTyped prog+ lint prog return prog
src/Jikka/Core/Convert/EqualitySolving.hs view
@@ -33,6 +33,7 @@ ) where +import Jikka.Common.Alpha import Jikka.Common.Error import Jikka.Core.Language.BuiltinPatterns import Jikka.Core.Language.Expr@@ -42,7 +43,7 @@ import Jikka.Core.Language.Util -- | `moveLiteralToRight` moves literals to lhs of `(==)` or `(/=)`, using symmetricity.-moveLiteralToRight :: Monad m => RewriteRule m+moveLiteralToRight :: (MonadAlpha m, MonadError Error m) => RewriteRule m moveLiteralToRight = mconcat [ simpleRewriteRule "equal/symmetricity/literal" $ \case@@ -54,7 +55,7 @@ ] -- | `convertGreaterToLess` erases `(>)` and `(>=)`.-convertGreaterToLess :: Monad m => RewriteRule m+convertGreaterToLess :: (MonadAlpha m, MonadError Error m) => RewriteRule m convertGreaterToLess = mconcat [ [r| "greaterthan->lessthan" forall x y. x > y = y < x |],@@ -62,7 +63,7 @@ ] -- | `reduceReflexivity` uses reflexivity.-reduceReflexivity :: Monad m => RewriteRule m+reduceReflexivity :: (MonadAlpha m, MonadError Error m) => RewriteRule m reduceReflexivity = mconcat [ [r| "lessthan/reflexivity" forall x. x == x = false |],@@ -72,7 +73,7 @@ ] -- | `makeRightZero` makes RHS of integer equality/inequality zero with subtracting RHS from both sides.-makeRightZero :: Monad m => RewriteRule m+makeRightZero :: (MonadAlpha m, MonadError Error m) => RewriteRule m makeRightZero = mconcat [ simpleRewriteRule "lessthan/right-zero" $ \case@@ -90,7 +91,7 @@ ] -- | `reduceIntInjective` removes injective functions from equalities of integers.-reduceIntInjective :: Monad m => RewriteRule m+reduceIntInjective :: (MonadAlpha m, MonadError Error m) => RewriteRule m reduceIntInjective = mconcat [ [r| "equal/negate" forall x y k. - x == 0 = x == 0 |],@@ -98,7 +99,7 @@ [r| "equal/fact'" forall x y. - fact x + fact y == 0 = x == y |] ] -reduceNot :: Monad m => RewriteRule m+reduceNot :: (MonadAlpha m, MonadError Error m) => RewriteRule m reduceNot = mconcat [ [r| "equal/not" forall x y. not x == y = x /= y |],@@ -107,7 +108,7 @@ [r| "notequal/not'" forall x y. x /= not y = x == y |] ] -reduceListCtor :: Monad m => RewriteRule m+reduceListCtor :: (MonadAlpha m, MonadError Error m) => RewriteRule m reduceListCtor = mconcat [ [r| "equal/nil/nil" forall x xs. nil == nil = true |],@@ -116,13 +117,13 @@ [r| "equal/cons/cons" forall x xs y ys. cons x xs == cons y ys = x == y && xs == ys |] ] -reduceListInjective :: Monad m => RewriteRule m+reduceListInjective :: (MonadAlpha m, MonadError Error m) => RewriteRule m reduceListInjective = mconcat [ [r| "equal/range/range" forall n1 n2. range n1 == range n2 = n1 == n2 |] ] -rule :: Monad m => RewriteRule m+rule :: (MonadAlpha m, MonadError Error m) => RewriteRule m rule = mconcat [ moveLiteralToRight,@@ -135,14 +136,14 @@ reduceListInjective ] -runProgram :: MonadError Error m => Program -> m Program+runProgram :: (MonadAlpha m, MonadError Error m) => Program -> m Program runProgram = applyRewriteRuleProgram' rule -run :: MonadError Error m => Program -> m Program+run :: (MonadAlpha m, MonadError Error m) => Program -> m Program run prog = wrapError' "Jikka.Core.Convert.EqualitySolving" $ do precondition $ do- ensureWellTyped prog+ lint prog prog <- runProgram prog postcondition $ do- ensureWellTyped prog+ lint prog return prog
src/Jikka/Core/Convert/Eta.hs view
@@ -76,8 +76,8 @@ run :: (MonadAlpha m, MonadError Error m) => Program -> m Program run prog = wrapError' "Jikka.Core.Convert.Eta" $ do precondition $ do- ensureWellTyped prog+ lint prog prog <- runProgram prog postcondition $ do- ensureWellTyped prog+ lint prog return prog
src/Jikka/Core/Convert/KubaruToMorau.hs view
@@ -107,8 +107,8 @@ run :: (MonadAlpha m, MonadError Error m) => Program -> m Program run prog = wrapError' "Jikka.Core.Convert.KubaruToMorau" $ do precondition $ do- ensureWellTyped prog+ lint prog prog <- runProgram prog postcondition $ do- ensureWellTyped prog+ lint prog return prog
src/Jikka/Core/Convert/MakeScanl.hs view
@@ -275,8 +275,8 @@ run :: (MonadAlpha m, MonadError Error m) => Program -> m Program run prog = wrapError' "Jikka.Core.Convert.MakeScanl" $ do precondition $ do- ensureWellTyped prog+ lint prog prog <- runProgram prog postcondition $ do- ensureWellTyped prog+ lint prog return prog
src/Jikka/Core/Convert/MatrixExponentiation.hs view
@@ -96,7 +96,7 @@ Iterate' (TupleTy ts) k (Lam x _ step) base | isVectorTy' ts -> do let n = genericLength ts let go n step base = MatAp' n n (MatPow' n step k) base- step <- toMatrix env x n step+ step <- toMatrix (typeEnv env) x n step case step of Nothing -> return Nothing Just (a, Nothing) -> return . Just $ go n (fromMatrix a) base@@ -134,8 +134,8 @@ run :: (MonadAlpha m, MonadError Error m) => Program -> m Program run prog = wrapError' "Jikka.Core.Convert.MatrixExponentiation" $ do precondition $ do- ensureWellTyped prog+ lint prog prog <- runProgram prog postcondition $ do- ensureWellTyped prog+ lint prog return prog
src/Jikka/Core/Convert/PropagateMod.hs view
@@ -135,10 +135,10 @@ e@(ModMult' _ _ _) -> return $ go0 e e@(ModInv' _ _) -> return $ go0 e e@(ModPow' _ _ _) -> return $ go0 e- ModMatAp' h w e1 e2 m | not (e1 `isModulo'` m) || not (e2 `isModulo'` m) -> go2 m (ModMatAp' h w) (putMatFloorMod env, e1) (putVecFloorMod env, e2)- ModMatAdd' h w e1 e2 m | not (e1 `isModulo'` m) || not (e2 `isModulo'` m) -> go2 m (ModMatAdd' h w) (putMatFloorMod env, e1) (putMatFloorMod env, e2)- ModMatMul' h n w e1 e2 m | not (e1 `isModulo'` m) || not (e2 `isModulo'` m) -> go2 m (ModMatMul' h n w) (putMatFloorMod env, e1) (putMatFloorMod env, e2)- ModMatPow' n e1 e2 m | not (e1 `isModulo'` m) -> go2 m (ModMatPow' n) (putMatFloorMod env, e1) (\_ e -> return e, e2)+ ModMatAp' h w e1 e2 m | not (e1 `isModulo'` m) || not (e2 `isModulo'` m) -> go2 m (ModMatAp' h w) (putMatFloorMod (typeEnv env), e1) (putVecFloorMod (typeEnv env), e2)+ ModMatAdd' h w e1 e2 m | not (e1 `isModulo'` m) || not (e2 `isModulo'` m) -> go2 m (ModMatAdd' h w) (putMatFloorMod (typeEnv env), e1) (putMatFloorMod (typeEnv env), e2)+ ModMatMul' h n w e1 e2 m | not (e1 `isModulo'` m) || not (e2 `isModulo'` m) -> go2 m (ModMatMul' h n w) (putMatFloorMod (typeEnv env), e1) (putMatFloorMod (typeEnv env), e2)+ ModMatPow' n e1 e2 m | not (e1 `isModulo'` m) -> go2 m (ModMatPow' n) (putMatFloorMod (typeEnv env), e1) (\_ e -> return e, e2) ModSum' e m | not (e `isModulo'` m) -> go1 m ModSum' (putMapFloorMod, e) ModProduct' e m | not (e `isModulo'` m) -> go1 m ModProduct' (putMapFloorMod, e) FloorMod' e m ->@@ -169,8 +169,8 @@ run :: (MonadAlpha m, MonadError Error m) => Program -> m Program run prog = wrapError' "Jikka.Core.Convert.PropagateMod" $ do precondition $ do- ensureWellTyped prog+ lint prog prog <- runProgram prog postcondition $ do- ensureWellTyped prog+ lint prog return prog
src/Jikka/Core/Convert/RemoveUnusedVars.hs view
@@ -62,8 +62,8 @@ run :: MonadError Error m => Program -> m Program run prog = wrapError' "Jikka.Core.Convert.RemoveUnusedVars" $ do precondition $ do- ensureWellTyped prog+ lint prog prog <- return $ run' prog postcondition $ do- ensureWellTyped prog+ lint prog return prog
src/Jikka/Core/Convert/SegmentTree.hs view
@@ -177,9 +177,9 @@ run :: (MonadAlpha m, MonadError Error m) => Program -> m Program run prog = wrapError' "Jikka.Core.Convert.SegmentTree" $ do precondition $ do- ensureWellTyped prog+ lint prog prog <- runProgram prog prog <- Alpha.run prog postcondition $ do- ensureWellTyped prog+ lint prog return prog
src/Jikka/Core/Convert/ShortCutFusion.hs view
@@ -47,14 +47,14 @@ -- * `Range2` is removed. -- * `Range3` is removed. -- * `Nil` and `Cons` are kept as is.-reduceBuild :: MonadAlpha m => RewriteRule m+reduceBuild :: (MonadAlpha m, MonadError Error m) => RewriteRule m reduceBuild = mconcat [ [r| "range2" forall l r. range2 l r = map (fun i -> l + i) (range (r - l)) |], [r| "range3" forall l r step. range3 l r step = map (fun i -> l + i * step) (range ((r - l) /^ step)) |] ] -reduceMapBuild :: MonadAlpha m => RewriteRule m+reduceMapBuild :: (MonadAlpha m, MonadError Error m) => RewriteRule m reduceMapBuild = mconcat [ [r| "sorted/nil" sorted nil = nil |],@@ -66,7 +66,7 @@ [r| "map/cons" forall f x xs. map f (cons x xs) = cons (f x) (map f xs) |] ] -reduceMap :: Monad m => RewriteRule m+reduceMap :: (MonadAlpha m, MonadError Error m) => RewriteRule m reduceMap = mconcat [ [r| "map/id" forall xs. map (fun x -> x) xs = xs |],@@ -79,7 +79,7 @@ -- * `Sort` and `Reversed` (functions to reorder) are lastly applied to lists -- * `Map` (functions to modify lists) -- * `Filter` (funcitons to reduce lengths) is firstly applied to lists-reduceMapMap :: MonadAlpha m => RewriteRule m+reduceMapMap :: (MonadAlpha m, MonadError Error m) => RewriteRule m reduceMapMap = mconcat [ [r| "map/map" forall f g xs. map g (map f xs) = map (fun x -> g (f x)) xs |],@@ -92,7 +92,7 @@ [r| "sorted/sorted" forall xs. sorted (sorted xs) = sorted xs |] ] -reduceFoldMap :: MonadAlpha m => RewriteRule m+reduceFoldMap :: (MonadAlpha m, MonadError Error m) => RewriteRule m reduceFoldMap = mconcat [ -- reduce `Reversed`@@ -117,7 +117,7 @@ Foldl' t1 t2 (Lam2 x2 _ x1 _ body) init xs | x1 `isUnusedVar` body -> Just $ Iterate' t2 (Len' t1 xs) (Lam x2 t2 body) init _ -> Nothing -reduceFoldBuild :: MonadAlpha m => RewriteRule m+reduceFoldBuild :: (MonadAlpha m, MonadError Error m) => RewriteRule m reduceFoldBuild = mconcat [ -- reduce `Foldl`@@ -141,7 +141,7 @@ [r| "len/build" forall f base n. len (build f base n) = len base + n |] ] -rule :: MonadAlpha m => RewriteRule m+rule :: (MonadAlpha m, MonadError Error m) => RewriteRule m rule = mconcat [ reduceFoldMap,@@ -197,8 +197,8 @@ run :: (MonadAlpha m, MonadError Error m) => Program -> m Program run prog = wrapError' "Jikka.Core.Convert.ShortCutFusion" $ do precondition $ do- ensureWellTyped prog+ lint prog prog <- runProgram prog postcondition $ do- ensureWellTyped prog+ lint prog return prog
+ src/Jikka/Core/Convert/SortAbs.hs view
@@ -0,0 +1,135 @@+{-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE LambdaCase #-}++-- |+-- Module : Jikka.Core.Convert.SortAbs+-- Description : remove abs with sorting. / sort によって abs を除去します。+-- Copyright : (c) Kimiyuki Onaka, 2021+-- License : Apache License 2.0+-- Maintainer : kimiyuki95@gmail.com+-- Stability : experimental+-- Portability : portable+--+-- \[+-- \newcommand\int{\mathbf{int}}+-- \newcommand\bool{\mathbf{bool}}+-- \newcommand\list{\mathbf{list}}+-- \]+module Jikka.Core.Convert.SortAbs+ ( run,++ -- * internal rules+ rule,+ )+where++import Control.Monad.Trans.Maybe+import Jikka.Common.Alpha+import Jikka.Common.Error+import qualified Jikka.Core.Convert.Alpha as Alpha+import Jikka.Core.Language.ArithmeticExpr+import Jikka.Core.Language.Beta+import Jikka.Core.Language.BuiltinPatterns+import Jikka.Core.Language.Expr+import Jikka.Core.Language.Lint+import Jikka.Core.Language.QuasiRules+import Jikka.Core.Language.RewriteRules+import Jikka.Core.Language.Util++-- | @replaceAbsDelta x y z e@ replaces \(\levert x - y \rvert\) in \(e\) with \(z\).+replaceAbsDelta :: VarName -> VarName -> VarName -> Expr -> Expr+replaceAbsDelta x y z e = mapSubExpr go [] e+ where+ go _ = \case+ Abs' e | isZeroArithmeticExpr (parseArithmeticExpr (Minus' e (Minus' (Var x) (Var y)))) -> Var z+ Abs' e | isZeroArithmeticExpr (parseArithmeticExpr (Minus' e (Minus' (Var y) (Var x)))) -> Var z+ e -> e++swapTwoVars :: MonadAlpha m => VarName -> VarName -> Expr -> m Expr+swapTwoVars x y e = do+ x' <- genVarName x+ y' <- genVarName y+ e <- substitute x (Var x') e+ e <- substitute y (Var y') e+ e <- substitute x' (Var y) e+ substitute y' (Var x) e++-- | TODO: accept more functions+isSymmetric :: MonadAlpha m => VarName -> VarName -> Expr -> m Bool+isSymmetric x y f = do+ g <- swapTwoVars x y f+ return $ parseArithmeticExpr g == parseArithmeticExpr f++rule :: (MonadAlpha m, MonadError Error m) => RewriteRule m+rule = makeRewriteRule "sum/sum/abs/symmetric" $ \env -> \case+ Sum' (Map' IntTy _ (Lam x _ (Sum' (Map' _ _ (Lam y _ f) xs'))) xs) | xs' == xs -> runMaybeT $ do+ delta <- lift genVarName'+ let f' = replaceAbsDelta x y delta f+ guard $ f' /= f -- f has |x - y|+ guard =<< lift (isSymmetric x y f') -- symmetric+ ys <- lift $ genVarName'' xs+ i <- lift genVarName'+ j <- lift genVarName'+ lt <- lift $ substitute delta (Minus' (Var x) (Var y)) f'+ eq <- lift $ substitute delta (LitInt' 0) f'+ gt <- lift $ substitute delta (Minus' (Var y) (Var x)) f'+ let ctx = Let y IntTy (At' IntTy (Var ys) (Var j))+ let lt' = Sum' (Map' IntTy IntTy (Lam j IntTy (ctx lt)) (Range1' (Var i)))+ let eq' = Let j IntTy (Var i) (ctx eq)+ let gt' = Sum' (Map' IntTy IntTy (Lam j IntTy (ctx gt)) (Range2' (Plus' (Var i) (LitInt' 1)) (Len' IntTy (Var ys))))+ let e =+ Let ys (ListTy IntTy) (Sorted' IntTy xs) $+ Sum'+ ( Map'+ IntTy+ IntTy+ ( Lam+ i+ IntTy+ ( Let+ x+ IntTy+ (At' IntTy (Var ys) (Var i))+ (Plus' (Plus' lt' eq') gt')+ )+ )+ (Range1' (Len' IntTy (Var ys)))+ )+ lift $ Alpha.runExpr (typeEnv env) e+ _ -> return Nothing++runProgram :: (MonadAlpha m, MonadError Error m) => Program -> m Program+runProgram = applyRewriteRuleProgram' rule++-- | `run` reduces \(\lvert \sum _ {a_i \in a} \sum _ {a_j \in a} f(a, a_i, a_j) \rvert\) to \(\mathbf{let}~ b = \mathrm{sort}(a) ~\mathbf{in}~ \sum \sum f'(a, a_i, a_j)\) when \(f\) contains \(\lvert a_i - a_j \rvert\) and \(f(a, a_i, a_j) = f(a, a_j, a_i)\) holds.+--+-- == Example+--+-- Before:+--+-- > sum (map (fun (a_i: int) ->+-- > sum (map (fun (a_j: int) ->+-- > abs (a_i - a_j)+-- > ) a)+-- > ) a)+--+-- After:+--+-- > let b = sort a+-- > in sum (map (fun (i: int) ->+-- > (sum (map (fun (b_j: int) ->+-- > b_i - b_j+-- > ) b[:i])+-- > + 0+-- > + sum (map (fun (b_j: int) ->+-- > b_j - b_i+-- > ) b[i + 1:]))+-- > ) (range (length b)))+run :: (MonadAlpha m, MonadError Error m) => Program -> m Program+run prog = wrapError' "Jikka.Core.Convert.SortAbs" $ do+ precondition $ do+ lint prog+ prog <- runProgram prog+ postcondition $ do+ lint prog+ return prog
src/Jikka/Core/Convert/SpecializeFoldl.hs view
@@ -131,8 +131,8 @@ run :: (MonadAlpha m, MonadError Error m) => Program -> m Program run prog = wrapError' "Jikka.Core.Convert.SpecializeFoldl" $ do precondition $ do- ensureWellTyped prog+ lint prog prog <- runProgram prog postcondition $ do- ensureWellTyped prog+ lint prog return prog
src/Jikka/Core/Convert/TrivialLetElimination.hs view
@@ -91,8 +91,8 @@ run :: MonadError Error m => Program -> m Program run prog = wrapError' "Jikka.Core.Convert.ConstantPropagation" $ do precondition $ do- ensureWellTyped prog+ lint prog prog <- return $ run' prog postcondition $ do- ensureWellTyped prog+ lint prog return prog
src/Jikka/Core/Convert/TypeInfer.hs view
@@ -39,7 +39,8 @@ import Jikka.Core.Language.Expr import Jikka.Core.Language.FreeVars import Jikka.Core.Language.Lint-import Jikka.Core.Language.TypeCheck (literalToType, typecheckExpr, typecheckProgram)+import Jikka.Core.Language.NameCheck (namecheckExpr)+import Jikka.Core.Language.TypeCheck (literalToType, typecheckExpr) import Jikka.Core.Language.Util data Hint@@ -151,6 +152,7 @@ -- | `Subst` is type substituion. It's a mapping from type variables to their actual types. newtype Subst = Subst {unSubst :: M.Map TypeName Type}+ deriving (Eq, Ord, Show, Read) subst :: Subst -> Type -> Type subst sigma = \case@@ -247,7 +249,9 @@ -- > in let x: int = 1 -- > in f(x + x) run :: (MonadAlpha m, MonadError Error m) => Program -> m Program-run prog = wrapError' "Jikka.Core.Convert.TypeInfer" $ do+run prog = wrapError' "Jikka.Core.Convert.TypeInfer.run" $ do+ precondition $ do+ ensureAlphaConverted prog eqns <- formularizeProgram prog let (eqns', assertions) = sortEquations eqns let eqns'' = mergeAssertions assertions@@ -255,24 +259,31 @@ let t0 = Just UnitTy prog <- substProgram t0 sigma prog postcondition $ do- typecheckProgram prog+ ensureAlphaConverted prog+ ensureWellTyped prog return prog runExpr :: (MonadAlpha m, MonadError Error m) => [(VarName, Type)] -> Expr -> m Expr-runExpr env e = wrapError' "Jikka.Core.Convert.TypeInfer" $ do+runExpr env e = wrapError' "Jikka.Core.Convert.TypeInfer.runExpr" $ do+ precondition $ do+ namecheckExpr env e eqns <- getDual <$> execWriterT (formularizeExpr e) let (eqns', assertions) = sortEquations eqns- let eqns'' = mergeAssertions assertions+ let eqns'' = mergeAssertions (env ++ assertions) sigma <- solveEquations (eqns' ++ eqns'') let t0 = Nothing -- don't use substDefault env <- return $ map (second (subst' t0 sigma)) env e <- substExpr t0 sigma env e postcondition $ do+ namecheckExpr env e typecheckExpr env e return e runRule :: (MonadAlpha m, MonadError Error m) => [(VarName, Type)] -> Expr -> Expr -> m ([(VarName, Type)], Expr, Expr)-runRule args e1 e2 = wrapError' "Jikka.Core.Convert.TypeInfer" $ do+runRule args e1 e2 = wrapError' "Jikka.Core.Convert.TypeInfer.runRule" $ do+ precondition $ do+ -- Underscores are allowed for names, so we don't use namecheckExpr here.+ return () eqns <- (getDual <$>) . execWriterT $ do t <- formularizeExpr e1 formularizeExpr' e2 t@@ -282,4 +293,8 @@ 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+ postcondition $ do+ -- Underscores are allowed for names, so we don't use namecheckExpr here.+ -- Type variables can remain, so we don't use typecheckExpr here.+ return () return (args, e1, e2)
src/Jikka/Core/Convert/UnpackTuple.hs view
@@ -19,7 +19,6 @@ import Jikka.Common.Alpha import Jikka.Common.Error-import qualified Jikka.Core.Convert.Alpha as Alpha import Jikka.Core.Language.Beta import Jikka.Core.Language.BuiltinPatterns import Jikka.Core.Language.Expr@@ -83,9 +82,8 @@ run :: (MonadAlpha m, MonadError Error m) => Program -> m Program run prog = wrapError' "Jikka.Core.Convert.UnpackTuple" $ do precondition $ do- ensureWellTyped prog- prog <- Alpha.run prog+ lint prog prog <- runProgram prog postcondition $ do- ensureWellTyped prog+ lint prog return prog
src/Jikka/Core/Language/ArithmeticExpr.hs view
@@ -12,14 +12,20 @@ plusArithmeticExpr, minusArithmeticExpr, multArithmeticExpr,+ incrArithmeticExpr,+ decrArithmeticExpr,+ sumArithmeticExpr, isZeroArithmeticExpr, isOneArithmeticExpr,+ isIntegerArithmeticExpr,+ integerFromArithmeticExpr, -- * Advanced functions unNPlusKPattern, makeVectorFromArithmeticExpr, makeAffineFunctionFromArithmeticExpr, splitConstantFactorArithmeticExpr,+ splitToSumArithmeticExpr, ) where @@ -143,6 +149,15 @@ multArithmeticExpr :: ArithmeticExpr -> ArithmeticExpr -> ArithmeticExpr multArithmeticExpr (ArithmeticExpr e1) (ArithmeticExpr e2) = ArithmeticExpr $ multSumExpr e1 e2 +incrArithmeticExpr :: ArithmeticExpr -> ArithmeticExpr+incrArithmeticExpr = plusArithmeticExpr (integerArithmeticExpr 1)++decrArithmeticExpr :: ArithmeticExpr -> ArithmeticExpr+decrArithmeticExpr = plusArithmeticExpr (integerArithmeticExpr (-1))++sumArithmeticExpr :: [ArithmeticExpr] -> ArithmeticExpr+sumArithmeticExpr = foldl plusArithmeticExpr (integerArithmeticExpr 0)+ parseSumExpr :: Expr -> SumExpr parseSumExpr = \case LitInt' n -> SumExpr {sumExprList = [], sumExprConst = n}@@ -242,6 +257,14 @@ isOneArithmeticExpr :: ArithmeticExpr -> Bool isOneArithmeticExpr e = normalizeArithmeticExpr e == integerArithmeticExpr 1 +isIntegerArithmeticExpr :: ArithmeticExpr -> Bool+isIntegerArithmeticExpr e = normalizeArithmeticExpr e == integerArithmeticExpr (sumExprConst (unArithmeticExpr e))++integerFromArithmeticExpr :: ArithmeticExpr -> Maybe Integer+integerFromArithmeticExpr e+ | isIntegerArithmeticExpr e = Just (sumExprConst (unArithmeticExpr e))+ | otherwise = Nothing+ -- | `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@@ -283,3 +306,10 @@ splitConstantFactorProductExpr :: ProductExpr -> (Integer, ProductExpr) splitConstantFactorProductExpr e = (productExprConst e, e {productExprConst = 1})++splitToSumArithmeticExpr :: ArithmeticExpr -> [ArithmeticExpr]+splitToSumArithmeticExpr e =+ let e' = unArithmeticExpr $ normalizeArithmeticExpr e+ es = map arithmeticalExprFromProductExpr (sumExprList e')+ k = if sumExprConst e' == 0 then [] else [integerArithmeticExpr (sumExprConst e')]+ in es ++ k
+ src/Jikka/Core/Language/AssertedHint.hs view
@@ -0,0 +1,274 @@+{-# LANGUAGE LambdaCase #-}+{-# LANGUAGE PatternSynonyms #-}+{-# LANGUAGE ViewPatterns #-}++module Jikka.Core.Language.AssertedHint+ ( AssertedHint (..),+ pattern EqualHint,+ parseHints,++ -- * Functions using hints+ lowerBoundWithHints,+ upperBoundWithHints,+ isZeroWithHints,+ nullWithHints,+ lengthWithHints,+ )+where++import Control.Monad+import Data.Semigroup+import Jikka.Core.Language.ArithmeticExpr+import Jikka.Core.Language.BuiltinPatterns+import Jikka.Core.Language.Expr++data AssertedHint+ = -- | @NotEqualHint n@ for a integer variable @x@ means @x /= n@+ NotEqualHint ArithmeticExpr+ | -- | @BoundHint l r@ for a integer variable @x@ means @l <= x < r@+ BoundHint (Maybe ArithmeticExpr) (Maybe ArithmeticExpr)+ | -- | @LengthHint t hint@ for a list variable @xs@ means @length xs@ satisfies @hint@+ LengthHint Type AssertedHint+ | -- | @AllHint t hint@ for a list variable @xs@ means that @x@ satisfies @hint@ for all @x@ in @xs@+ AllHint Type AssertedHint+ deriving (Eq, Ord, Show)++pattern EqualHint :: ArithmeticExpr -> AssertedHint+pattern EqualHint l <-+ (\case BoundHint (Just l) (Just r) | incrArithmeticExpr l == r -> Just l; _ -> Nothing -> Just l)+ where+ EqualHint l = BoundHint (Just l) (Just (incrArithmeticExpr l))++parseNilHint :: Expr -> [(VarName, AssertedHint)]+parseNilHint = \case+ -- Jikka.Core.Language.EqualitiySolving makes rhs nil+ Equal' _ (Var xs) (Nil' t) -> [(xs, LengthHint t (BoundHint (Just (integerArithmeticExpr 0)) (Just (integerArithmeticExpr 1))))]+ NotEqual' _ (Var xs) (Nil' t) -> [(xs, LengthHint t (BoundHint (Just (integerArithmeticExpr 1)) Nothing))]+ _ -> []++data Term+ = VarTerm VarName+ | LenTerm Type VarName+ | NegatedTerm Term+ deriving (Eq, Ord, Show, Read)++-- `decomposeArithmeticExpr` makes @a + b + c@ to @[(a, b + c), (b, a + c), (c, a + b)]@ in a convenient way, because Jikka.Core.Language.EqualitiySolving makes @a == b@ to @a - b == 0@.+decomposeArithmeticExpr :: Expr -> [(Term, ArithmeticExpr)]+decomposeArithmeticExpr e =+ let es = splitToSumArithmeticExpr $ parseArithmeticExpr e+ in (`concatMap` [0 .. length es - 1]) $ \i ->+ let e = es !! i+ e' = sumArithmeticExpr $ take i es ++ drop (i + 1) es+ in case formatArithmeticExpr e of+ Var x -> [(VarTerm x, e')]+ Negate' (Var x) -> [(NegatedTerm (VarTerm x), e')]+ Len' t (Var x) -> [(LenTerm t x, e')]+ Negate' (Len' t (Var x)) -> [(NegatedTerm (LenTerm t x), e')]+ _ -> []++parseBoundHint :: Expr -> [(VarName, AssertedHint)]+parseBoundHint = \case+ Equal' IntTy e (LitInt' 0) -> do+ (x, e) <- decomposeArithmeticExpr e+ case x of+ VarTerm x -> return (x, EqualHint (negateArithmeticExpr e))+ NegatedTerm (VarTerm x) -> return (x, EqualHint e)+ LenTerm t x -> return (x, LengthHint t (EqualHint (negateArithmeticExpr e)))+ NegatedTerm (LenTerm t x) -> return (x, LengthHint t (EqualHint e))+ _ -> []+ NotEqual' IntTy e (LitInt' 0) -> do+ (x, e) <- decomposeArithmeticExpr e+ case x of+ VarTerm x -> return (x, NotEqualHint (negateArithmeticExpr e))+ NegatedTerm (VarTerm x) -> return (x, NotEqualHint e)+ LenTerm t x | isZeroArithmeticExpr e -> return (x, LengthHint t (BoundHint (Just (integerArithmeticExpr 1)) Nothing))+ NegatedTerm (LenTerm t x) | isZeroArithmeticExpr e -> return (x, LengthHint t (BoundHint (Just (integerArithmeticExpr 1)) Nothing))+ _ -> []+ LessEqual' IntTy e (LitInt' 0) -> do+ (x, e) <- decomposeArithmeticExpr e+ case x of+ VarTerm x -> return (x, BoundHint Nothing (Just (incrArithmeticExpr (negateArithmeticExpr e))))+ NegatedTerm (VarTerm x) -> return (x, BoundHint (Just e) Nothing)+ LenTerm t x -> return (x, LengthHint t (BoundHint Nothing (Just (incrArithmeticExpr (negateArithmeticExpr e)))))+ NegatedTerm (LenTerm t x) -> return (x, LengthHint t (BoundHint (Just e) Nothing))+ _ -> []+ LessThan' IntTy e (LitInt' 0) -> do+ (x, e) <- decomposeArithmeticExpr e+ case x of+ VarTerm x -> return (x, BoundHint Nothing (Just (negateArithmeticExpr e)))+ NegatedTerm (VarTerm x) -> return (x, BoundHint (Just (incrArithmeticExpr e)) Nothing)+ LenTerm t x -> return (x, LengthHint t (BoundHint Nothing (Just (negateArithmeticExpr e))))+ NegatedTerm (LenTerm t x) -> return (x, LengthHint t (BoundHint (Just (incrArithmeticExpr e)) Nothing))+ _ -> []+ -- Jikka.Core.Language.EqualitiySolving makes rhs 0 and removes GreaterEqual and GreaterThan+ _ -> []++parseAndHint :: Expr -> [(VarName, AssertedHint)]+parseAndHint = \case+ And' e e' -> parseHints e ++ parseHints e'+ _ -> []++parseAllHint :: Expr -> [(VarName, AssertedHint)]+parseAllHint = \case+ All' (Map' t _ (Lam x _ pred) (Var xs)) -> do+ (x', hint) <- parseHints pred+ guard $ x' == x+ return (xs, AllHint t hint)+ _ -> []++parseHints :: Expr -> [(VarName, AssertedHint)]+parseHints e =+ concat+ [ parseNilHint e,+ parseBoundHint e,+ parseAndHint e,+ parseAllHint e+ ]++selectHints :: [(VarName, AssertedHint)] -> VarName -> [AssertedHint]+selectHints hints x = map snd (filter (\hint -> fst hint == x) hints)++maximum' :: Ord a => [Maybe a] -> Maybe a+maximum' = (getMax <$>) . mconcat . map (Max <$>)++minimum' :: Ord a => [Maybe a] -> Maybe a+minimum' = (getMin <$>) . mconcat . map (Min <$>)++lowerBoundWithHints :: [(VarName, AssertedHint)] -> Expr -> Maybe Integer+lowerBoundWithHints hints = \case+ LitInt' n -> Just n+ Negate' e -> do+ e <- upperBoundWithHints hints e+ return $ - (e - 1)+ Plus' e1 e2 -> do+ e1 <- lowerBoundWithHints hints e1+ e2 <- lowerBoundWithHints hints e2+ return $ e1 + e2+ Minus' e1 e2 -> do+ e1 <- lowerBoundWithHints hints e1+ e2 <- upperBoundWithHints hints e2+ return $ e1 - (e2 - 1)+ Mult' e1 e2 -> do+ e1 <- lowerBoundWithHints hints e1+ e2 <- lowerBoundWithHints hints e2+ guard $ e1 >= 0 && e2 >= 0+ return $ e1 * e2+ Var x ->+ let go :: AssertedHint -> Maybe Integer+ go = \case+ BoundHint (Just l) _ -> lowerBoundWithHints hints (formatArithmeticExpr l)+ _ -> Nothing+ in maximum' (map go (selectHints hints x))+ _ -> Nothing++upperBoundWithHints :: [(VarName, AssertedHint)] -> Expr -> Maybe Integer+upperBoundWithHints hints = \case+ LitInt' n -> Just (n + 1)+ Negate' e -> do+ e <- lowerBoundWithHints hints e+ return $ - e + 1+ Plus' e1 e2 -> do+ e1 <- upperBoundWithHints hints e1+ e2 <- upperBoundWithHints hints e2+ return $ e1 + e2 - 1+ Minus' e1 e2 -> do+ e1 <- upperBoundWithHints hints e1+ e2 <- lowerBoundWithHints hints e2+ return $ e1 - e2+ Mult' e1 e2 -> do+ l1 <- lowerBoundWithHints hints e1+ l2 <- lowerBoundWithHints hints e2+ r1 <- upperBoundWithHints hints e1+ r2 <- upperBoundWithHints hints e2+ guard $ l1 >= 0 && l2 >= 0+ return $ (r1 - 1) * (r2 - 1) + 1+ Var x ->+ let go :: AssertedHint -> Maybe Integer+ go = \case+ BoundHint _ (Just r) -> pred <$> upperBoundWithHints hints (formatArithmeticExpr r)+ _ -> Nothing+ in minimum' (map go (selectHints hints x))+ _ -> Nothing++isZeroWithHints :: [(VarName, AssertedHint)] -> Expr -> Maybe Bool+isZeroWithHints hints e =+ case (lowerBoundWithHints hints e, upperBoundWithHints hints e) of+ (Just 0, Just 1) -> Just True+ (Just l, _) | l >= 1 -> Just False+ (_, Just r) | r <= 0 -> Just False+ _ -> Nothing++integerWithHints :: [(VarName, AssertedHint)] -> Expr -> Maybe Integer+integerWithHints hints = \case+ LitInt' n -> Just n+ Negate' e -> do+ e <- integerWithHints hints e+ return $ - e+ Plus' e1 e2 -> do+ e1 <- integerWithHints hints e1+ e2 <- integerWithHints hints e2+ return $ e1 + e2+ Minus' e1 e2 -> do+ e1 <- integerWithHints hints e1+ e2 <- integerWithHints hints e2+ return $ e1 - e2+ Mult' e1 e2 -> do+ e1 <- integerWithHints hints e1+ e2 <- integerWithHints hints e2+ return $ e1 * e2+ e@(Var _) ->+ case (lowerBoundWithHints hints e, upperBoundWithHints hints e) of+ (Just l, Just r) | l + 1 == r -> Just l+ _ -> Nothing+ _ -> Nothing++nullWithHints :: [(VarName, AssertedHint)] -> Expr -> Maybe Bool+nullWithHints hints = \case+ Nil' _ -> Just True+ Cons' _ _ _ -> Just False+ Range1' n -> isZeroWithHints hints n+ Var xs -> do+ let go :: AssertedHint -> Maybe Integer+ go = \case+ LengthHint _ (BoundHint (Just l) _) -> lowerBoundWithHints hints (formatArithmeticExpr l)+ _ -> Nothing+ l <- maximum' (map go (selectHints hints xs))+ if l >= 1+ then Just False+ else do+ let go :: AssertedHint -> Maybe Integer+ go = \case+ LengthHint _ (NotEqualHint n) -> integerWithHints hints (formatArithmeticExpr n)+ _ -> Nothing+ let ns = map go (selectHints hints xs)+ if Just 0 `elem` ns+ then Just False+ else do+ let go :: AssertedHint -> Maybe Integer+ go = \case+ LengthHint _ (BoundHint _ (Just r)) -> pred <$> upperBoundWithHints hints (formatArithmeticExpr r)+ _ -> Nothing+ r <- minimum' (map go (selectHints hints xs))+ if r <= 1+ then Just True+ else Nothing+ _ -> Nothing++lengthWithHints :: [(VarName, AssertedHint)] -> Expr -> Maybe Integer+lengthWithHints hints = \case+ Nil' _ -> Just 0+ Cons' _ _ xs -> do+ n <- lengthWithHints hints xs+ return $ n + 1+ Range1' e -> case (lowerBoundWithHints hints e, upperBoundWithHints hints e) of+ (Just l, Just r) | l + 1 == r -> Just l+ _ -> Nothing+ Var xs -> do+ let go :: AssertedHint -> Maybe Integer+ go = \case+ LengthHint _ (BoundHint (Just l) _) -> lowerBoundWithHints hints (formatArithmeticExpr l)+ _ -> Nothing+ let minimum' :: Ord a => [Maybe a] -> Maybe a+ minimum' = (getMin <$>) . mconcat . map (Min <$>)+ minimum' (map go (selectHints hints xs))+ _ -> Nothing
src/Jikka/Core/Language/Lint.hs view
@@ -14,6 +14,7 @@ import Jikka.Common.Error import Jikka.Core.Language.Expr+import Jikka.Core.Language.NameCheck import Jikka.Core.Language.TypeCheck precondition :: MonadError Error m => m a -> m a@@ -31,3 +32,12 @@ ensureWellTyped prog = wrapError' "Jikka.Core.Language.Lint.ensureWellTyped" $ do _ <- typecheckProgram prog return ()++ensureAlphaConverted :: MonadError Error m => Program -> m ()+ensureAlphaConverted prog = wrapError' "Jikka.Core.Language.Lint.ensureAlphaConverted" $ do+ namecheckProgram prog++lint :: MonadError Error m => Program -> m ()+lint prog = do+ ensureAlphaConverted prog+ ensureWellTyped prog
+ src/Jikka/Core/Language/NameCheck.hs view
@@ -0,0 +1,82 @@+{-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE LambdaCase #-}++-- |+-- Module : Jikka.Core.Language.RewriteRules+-- Description : checks that there are no name conflicts. / 名前衝突がないか検査します。+-- Copyright : (c) Kimiyuki Onaka, 2021+-- License : Apache License 2.0+-- Maintainer : kimiyuki95@gmail.com+-- Stability : experimental+-- Portability : portable+module Jikka.Core.Language.NameCheck+ ( namecheckProgram,+ namecheckToplevelExpr,+ namecheckExpr,+ )+where++import Control.Monad.State.Strict+import Jikka.Common.Error+import Jikka.Core.Format (formatType)+import Jikka.Core.Language.Expr+import Jikka.Core.Language.Util++define :: (MonadState [(VarName, Type)] m, MonadError Error m) => VarName -> Type -> m ()+define x t = do+ env <- get+ case lookup x env of+ Just t' -> throwInternalError $ "name conflict: " ++ unVarName x ++ ": " ++ formatType t ++ " and " ++ unVarName x ++ ": " ++ formatType t'+ Nothing -> put $ (x, t) : env++namecheckExpr' :: (MonadState [(VarName, Type)] m, MonadError Error m) => Expr -> m ()+namecheckExpr' = \case+ Var x -> do+ env <- get+ case lookup x env of+ Nothing -> throwInternalError $ "undefined variable: " ++ unVarName x+ Just _ -> return ()+ Lit _ -> return ()+ App f e -> do+ namecheckExpr' f+ namecheckExpr' e+ Lam x t e -> do+ define x t+ namecheckExpr' e+ Let x t e1 e2 -> do+ namecheckExpr' e1+ define x t+ namecheckExpr' e2+ Assert e1 e2 -> do+ namecheckExpr' e1+ namecheckExpr' e2++namecheckExpr :: MonadError Error m => [(VarName, Type)] -> Expr -> m ()+namecheckExpr env e = wrapError' "Jikka.Core.Language.NameCheck.namecheckExpr" $ do+ evalStateT (namecheckExpr' e) env++namecheckToplevelExpr' :: (MonadState [(VarName, Type)] m, MonadError Error m) => ToplevelExpr -> m ()+namecheckToplevelExpr' = \case+ ResultExpr e -> namecheckExpr' e+ ToplevelLet x t e cont -> do+ namecheckExpr' e+ define x t+ namecheckToplevelExpr' cont+ ToplevelLetRec f args ret body cont -> do+ let t = curryFunTy (map snd args) ret+ define f t+ forM_ args $ \(x, t) -> do+ define x t+ namecheckExpr' body+ namecheckToplevelExpr' cont+ ToplevelAssert e1 e2 -> do+ namecheckExpr' e1+ namecheckToplevelExpr' e2++namecheckToplevelExpr :: MonadError Error m => [(VarName, Type)] -> ToplevelExpr -> m ()+namecheckToplevelExpr env e = wrapError' "Jikka.Core.Language.NameCheck.namecheckToplevelExpr" $ do+ evalStateT (namecheckToplevelExpr' e) env++namecheckProgram :: MonadError Error m => Program -> m ()+namecheckProgram prog = wrapError' "Jikka.Core.Language.NameCheck.namecheckProgram" $ do+ evalStateT (namecheckToplevelExpr' prog) []
src/Jikka/Core/Language/QuasiRules.hs view
@@ -9,6 +9,7 @@ -- * Things which `r` uses. module Jikka.Core.Language.Expr,+ alphaExpr, makeRewriteRule, genVarName', )@@ -17,8 +18,10 @@ import Control.Arrow import Control.Monad.State.Strict import Data.Data+import Jikka.Common.Alpha import Jikka.Common.Error import Jikka.Common.Format.Error+import qualified Jikka.Core.Convert.Alpha as Alpha import qualified Jikka.Core.Convert.TypeInfer as TypeInfer import Jikka.Core.Language.Expr import Jikka.Core.Language.RewriteRules@@ -255,6 +258,9 @@ e <- lift [e|Assert $(pure e1) $(pure e2)|] return (stmts1 ++ stmts2, e) +alphaExpr :: (MonadAlpha m, MonadError Error m) => [(VarName, Type)] -> Expr -> m Expr+alphaExpr = Alpha.runExpr+ ruleExp :: String -> Q Exp ruleExp s = do (name, args, e1, e2) <- liftError $ parseRule s@@ -274,11 +280,15 @@ supressUnusedMatchesWarnings' <- forM (typeVars env) $ \(_, y) -> do NoBindS <$> [e|return $(pure (VarE y))|] ((stmts, exp), _) <- runStateT (toExpE e2) env- exp' <- [e|return (Just $(pure exp))|]- let stmts' = supressUnusedMatchesWarnings ++ supressUnusedMatchesWarnings' ++ stmts ++ [NoBindS exp']+ nop <- [e|return ()|]+ exp' <- [e|return $(pure exp)|] [e|- makeRewriteRule $(pure (LitE (StringL name))) $ \_ e -> case e of- $(pure pat) -> $(pure (DoE stmts'))+ makeRewriteRule $(pure (LitE (StringL name))) $ \env e -> case e of+ $(pure pat) -> do+ $(pure (DoE (supressUnusedMatchesWarnings ++ [NoBindS nop])))+ $(pure (DoE (supressUnusedMatchesWarnings' ++ [NoBindS nop])))+ e <- $(pure (DoE (stmts ++ [NoBindS exp'])))+ Just <$> alphaExpr (typeEnv env) e _ -> return Nothing |]
src/Jikka/Core/Language/RewriteRules.hs view
@@ -12,6 +12,7 @@ -- Portability : portable module Jikka.Core.Language.RewriteRules ( RewriteRule,+ RewriteEnvironment (..), -- * Construct Rules makeRewriteRule,@@ -20,6 +21,8 @@ traceRewriteRule, -- * Apply Rules+ emptyRewriteEnvironment,+ makeRewriteEnvironmentFromTypeEnv, applyRewriteRule, applyRewriteRuleToplevelExpr, applyRewriteRuleProgram,@@ -32,11 +35,21 @@ import Debug.Trace import Jikka.Common.Error import Jikka.Core.Format (formatExpr)+import Jikka.Core.Language.AssertedHint import Jikka.Core.Language.Expr import Jikka.Core.Language.Util (curryFunTy) +data RewriteEnvironment = RewriteEnvironment+ { typeEnv :: [(VarName, Type)],+ assertedHints :: [(VarName, AssertedHint)]+ }+ deriving (Eq, Ord, Show)++putTypeEnv :: (VarName, Type) -> RewriteEnvironment -> RewriteEnvironment+putTypeEnv (x, t) env = env {typeEnv = (x, t) : typeEnv env}+ data RewriteRule m- = RewriteRule ([(VarName, Type)] -> Expr -> m (Maybe Expr))+ = RewriteRule (RewriteEnvironment -> Expr -> m (Maybe Expr)) | NamedRule String (RewriteRule m) | EmptyRule | AltRule (RewriteRule m) (RewriteRule m)@@ -48,7 +61,7 @@ instance Monad m => Monoid (RewriteRule m) where mempty = EmptyRule -applyRewriteRuleToRootExpr :: MonadError Error m => RewriteRule m -> [(VarName, Type)] -> Expr -> StateT Integer m (Maybe Expr)+applyRewriteRuleToRootExpr :: MonadError Error m => RewriteRule m -> RewriteEnvironment -> Expr -> StateT Integer m (Maybe Expr) applyRewriteRuleToRootExpr f env e = go "(anonymous)" False f where go :: MonadError Error m => String -> Bool -> RewriteRule m -> StateT Integer m (Maybe Expr)@@ -75,10 +88,10 @@ Nothing -> go ruleName dumpTrace g TraceRule f -> go ruleName True f -makeRewriteRule :: Monad m => String -> ([(VarName, Type)] -> Expr -> m (Maybe Expr)) -> RewriteRule m+makeRewriteRule :: Monad m => String -> (RewriteEnvironment -> Expr -> m (Maybe Expr)) -> RewriteRule m makeRewriteRule name f = NamedRule name (RewriteRule f) -pureRewriteRule :: Monad m => String -> ([(VarName, Type)] -> Expr -> Maybe Expr) -> RewriteRule m+pureRewriteRule :: Monad m => String -> (RewriteEnvironment -> Expr -> Maybe Expr) -> RewriteRule m pureRewriteRule name f = NamedRule name (RewriteRule (\env e -> return (f env e))) simpleRewriteRule :: Monad m => String -> (Expr -> Maybe Expr) -> RewriteRule m@@ -93,10 +106,10 @@ -- -- * This function is idempotent. -- * This function doesn't terminate when a given rewrite rule doesn't terminate.-applyRewriteRule :: MonadError Error m => RewriteRule m -> [(VarName, Type)] -> Expr -> m (Maybe Expr)+applyRewriteRule :: MonadError Error m => RewriteRule m -> RewriteEnvironment -> Expr -> m (Maybe Expr) applyRewriteRule f env e = evalStateT (applyRewriteRule' f env e) 0 -applyRewriteRule' :: (MonadError Error m) => RewriteRule m -> [(VarName, Type)] -> Expr -> StateT Integer m (Maybe Expr)+applyRewriteRule' :: (MonadError Error m) => RewriteRule m -> RewriteEnvironment -> Expr -> StateT Integer m (Maybe Expr) applyRewriteRule' = applyRewriteRulePreOrder coalesceMaybes :: a -> Maybe a -> b -> Maybe b -> Maybe (a, b)@@ -105,7 +118,7 @@ coalesceMaybes _ (Just a) b Nothing = Just (a, b) coalesceMaybes _ (Just a) _ (Just b) = Just (a, b) -applyRewriteRuleToImmediateSubExprs :: MonadError Error m => RewriteRule m -> [(VarName, Type)] -> Expr -> StateT Integer m (Maybe Expr)+applyRewriteRuleToImmediateSubExprs :: MonadError Error m => RewriteRule m -> RewriteEnvironment -> Expr -> StateT Integer m (Maybe Expr) applyRewriteRuleToImmediateSubExprs f env = \case Var _ -> return Nothing Lit _ -> return Nothing@@ -113,13 +126,14 @@ e1' <- applyRewriteRuleToRootExpr f env e1 e2' <- applyRewriteRuleToRootExpr f env e2 return $ fmap (uncurry App) (coalesceMaybes e1 e1' e2 e2')- Lam x t body -> (Lam x t <$>) <$> applyRewriteRuleToRootExpr f ((x, t) : env) body+ Lam x t body -> (Lam x t <$>) <$> applyRewriteRuleToRootExpr f (putTypeEnv (x, t) env) body Let x t e1 e2 -> do e1' <- applyRewriteRuleToRootExpr f env e1- e2' <- applyRewriteRuleToRootExpr f ((x, t) : env) e2+ e2' <- applyRewriteRuleToRootExpr f (putTypeEnv (x, t) env) e2 return $ fmap (uncurry (Let x t)) (coalesceMaybes e1 e1' e2 e2') Assert e1 e2 -> do e1' <- applyRewriteRuleToRootExpr f env e1+ env <- return $ env {assertedHints = parseHints (fromMaybe e1 e1') ++ assertedHints env} e2' <- applyRewriteRuleToRootExpr f env e2 return $ fmap (uncurry Assert) (coalesceMaybes e1 e1' e2 e2') @@ -130,7 +144,7 @@ put s return a -applyRewriteRulePreOrder :: forall m. MonadError Error m => RewriteRule m -> [(VarName, Type)] -> Expr -> StateT Integer m (Maybe Expr)+applyRewriteRulePreOrder :: forall m. MonadError Error m => RewriteRule m -> RewriteEnvironment -> Expr -> StateT Integer m (Maybe Expr) applyRewriteRulePreOrder f env e = do e' <- applyRewriteRuleToRootExpr f env e case e' of@@ -150,25 +164,32 @@ e'' <- applyRewriteRulePreOrder f env e' return . Just $ fromMaybe e' e'' -applyRewriteRuleToplevelExpr :: MonadError Error m => RewriteRule m -> [(VarName, Type)] -> ToplevelExpr -> StateT Integer m (Maybe ToplevelExpr)+applyRewriteRuleToplevelExpr :: MonadError Error m => RewriteRule m -> RewriteEnvironment -> ToplevelExpr -> StateT Integer m (Maybe ToplevelExpr) applyRewriteRuleToplevelExpr f env = \case ResultExpr e -> (ResultExpr <$>) <$> applyRewriteRule' f env e ToplevelLet y t e cont -> do e' <- applyRewriteRule' f env e- cont' <- applyRewriteRuleToplevelExpr f ((y, t) : env) cont+ cont' <- applyRewriteRuleToplevelExpr f (putTypeEnv (y, t) env) cont return $ fmap (uncurry (ToplevelLet y t)) (coalesceMaybes e e' cont cont') ToplevelLetRec g args ret body cont -> do- let env' = (g, curryFunTy (map snd args) ret) : env- body' <- applyRewriteRule' f (reverse args ++ env') body+ let env' = putTypeEnv (g, curryFunTy (map snd args) ret) env+ body' <- applyRewriteRule' f (foldr putTypeEnv env' args) body cont' <- applyRewriteRuleToplevelExpr f env' cont return $ fmap (uncurry (ToplevelLetRec g args ret)) (coalesceMaybes body body' cont cont') ToplevelAssert e1 e2 -> do e1' <- applyRewriteRule' f env e1+ env <- return $ env {assertedHints = parseHints (fromMaybe e1 e1') ++ assertedHints env} e2' <- applyRewriteRuleToplevelExpr f env e2 return $ fmap (uncurry ToplevelAssert) (coalesceMaybes e1 e1' e2 e2') +emptyRewriteEnvironment :: RewriteEnvironment+emptyRewriteEnvironment = RewriteEnvironment {typeEnv = [], assertedHints = []}++makeRewriteEnvironmentFromTypeEnv :: [(VarName, Type)] -> RewriteEnvironment+makeRewriteEnvironmentFromTypeEnv env = RewriteEnvironment {typeEnv = env, assertedHints = []}+ applyRewriteRuleProgram :: MonadError Error m => RewriteRule m -> Program -> m (Maybe Program)-applyRewriteRuleProgram f prog = evalStateT (applyRewriteRuleToplevelExpr f [] prog) 0+applyRewriteRuleProgram f prog = evalStateT (applyRewriteRuleToplevelExpr f emptyRewriteEnvironment prog) 0 applyRewriteRuleProgram' :: MonadError Error m => RewriteRule m -> Program -> m Program applyRewriteRuleProgram' f prog = fromMaybe prog <$> applyRewriteRuleProgram f prog
src/Jikka/Core/Language/TypeCheck.hs view
@@ -199,9 +199,7 @@ throwInternalError $ "assigned type is not correct: context = (let " ++ unVarName x ++ ": " ++ formatType t ++ " = " ++ formatExpr e ++ " in ...), expected type = " ++ formatType t ++ ", actual type = " ++ formatType t' typecheckToplevelExpr ((x, t) : env) cont ToplevelLetRec f args ret body cont -> do- let t = case args of- [] -> ret- _ -> curryFunTy (map snd args) ret+ let t = curryFunTy (map snd args) ret ret' <- typecheckExpr (reverse args ++ (f, t) : env) body when (ret' /= ret) $ do throwInternalError $ "returned type is not correct: context = (let rec " ++ unVarName f ++ " " ++ unwords (map (\(x, t) -> unVarName x ++ ": " ++ formatType t) args) ++ ": " ++ formatType ret ++ " = " ++ formatExpr body ++ " in ...), expected type = " ++ formatType ret ++ ", actual type = " ++ formatType ret'
src/Jikka/Core/Language/Util.hs view
@@ -30,6 +30,11 @@ genVarName' :: MonadAlpha m => m VarName genVarName' = genVarName (VarName "_") +genVarName'' :: MonadAlpha m => Expr -> m VarName+genVarName'' = \case+ Var x -> genVarName x+ _ -> genVarName'+ mapSubTypesM :: Monad m => (Type -> m Type) -> Type -> m Type mapSubTypesM f = go where
src/Jikka/Core/Parse/Happy.y view
@@ -592,7 +592,7 @@ runExpr :: (MonadAlpha m, MonadError Error m) => [WithLoc L.Token] -> m Expr runExpr tokens = wrapError' "Jikka.Core.Parse.Happy.runExpr" $ do e <- liftEither $ runExpr_ tokens- mapTypeExprM replaceUnderscoresT e+ e <- mapTypeExprM replaceUnderscoresT e mapSubExprM replaceUnderscoresE [] e runProgram :: (MonadAlpha m, MonadError Error m) => [WithLoc L.Token] -> m Program
test/Jikka/CPlusPlus/FormatSpec.hs view
@@ -35,7 +35,7 @@ ] let formatted = [ "int64_t solve(int32_t n) {",- " int64_t x = 0;",+ " int64_t x = 0ll;", " for (int32_t i = 0; i < n; ++ i) {", " x += int64_t(i);", " }",@@ -65,7 +65,7 @@ ] let formatted = [ "int64_t solve(int32_t n, std::vector<int64_t> h) {",- " int64_t x = 0;",+ " int64_t x = 0ll;", " for (int32_t i = 2; i < n; ++ i) {", " x += h[i - 2];", " }",
test/Jikka/Core/Convert/ANormalSpec.hs view
@@ -22,12 +22,12 @@ ResultExpr $ Plus' (Let "x" IntTy Lit1 (Var "x"))- (App (Lam "x" IntTy (Var "x")) Lit1)+ (App (Lam "y" IntTy (Var "y")) Lit1) let expected = ResultExpr $- Let "x$0" IntTy Lit1 $- Let "$3" (Fun1STy IntTy) (Lam "x$1" IntTy (Var "x$1")) $- Let "$2" (Fun1STy IntTy) (Var "$3") $- Let "$4" IntTy (App (Var "$2") Lit1) $- Plus' (Var "x$0") (Var "$4")+ Let "x" IntTy Lit1 $+ Let "$1" (Fun1STy IntTy) (Lam "y" IntTy (Var "y")) $+ Let "$0" (Fun1STy IntTy) (Var "$1") $+ Let "$2" IntTy (App (Var "$0") Lit1) $+ Plus' (Var "x") (Var "$2") run' prog `shouldBe` Right expected
test/Jikka/Core/Convert/AlphaSpec.hs view
@@ -34,14 +34,14 @@ let expected = ResultExpr ( Let- "x$0"+ "x" IntTy Lit0 ( Let- "x$1"+ "x$0" IntTy- (Plus' (Var "x$0") Lit1)- (Var "x$1")+ (Plus' (Var "x") Lit1)+ (Var "x$0") ) ) run' prog `shouldBe` Right expected
test/Jikka/Core/Convert/BetaSpec.hs view
@@ -31,8 +31,8 @@ let expected = ResultExpr ( Lam- "a$0"+ "a" IntTy- (Plus' (Var "a$0") (Var "a$0"))+ (Plus' (Var "a") (Var "a")) ) run' prog `shouldBe` Right expected
+ test/Jikka/Core/Convert/CloseMinSpec.hs view
@@ -0,0 +1,74 @@+{-# LANGUAGE OverloadedStrings #-}++module Jikka.Core.Convert.CloseMinSpec (spec) where++import Jikka.Common.Alpha+import Jikka.Common.Error+import Jikka.Core.Convert.CloseMin (rule)+import qualified Jikka.Core.Convert.TypeInfer as TypeInfer+import Jikka.Core.Format (formatProgram)+import Jikka.Core.Language.Expr+import Jikka.Core.Language.RewriteRules+import Jikka.Core.Parse (parseProgram)+import Test.Hspec++run' :: Program -> Either Error Program+run' = flip evalAlphaT 0 . applyRewriteRuleProgram' rule++parseProgram' :: [String] -> Program+parseProgram' = fromSuccess . flip evalAlphaT 100 . (TypeInfer.run <=< parseProgram . unlines)++spec :: Spec+spec = describe "run" $ do+ it "works" $ do+ let prog =+ parseProgram'+ [ "fun xs ->",+ " minimum (map (fun x -> 3 + x) xs)"+ ]+ let expected =+ parseProgram'+ [ "fun xs ->",+ " 3 + minimum (map (fun x -> x) xs)"+ ]+ (formatProgram <$> run' prog) `shouldBe` Right (formatProgram expected)+ it "reduces minimum-cons if non-nil" $ do+ let prog =+ parseProgram'+ [ "fun xs ->",+ " assert xs /= nil",+ " in minimum (cons 0 xs)"+ ]+ let expected =+ parseProgram'+ [ "fun xs ->",+ " assert xs /= nil",+ " in min 0 (minimum xs)"+ ]+ (formatProgram <$> run' prog) `shouldBe` Right (formatProgram expected)+ it "reduces maximum-cons if non-nil" $ do+ let prog =+ parseProgram'+ [ "fun xs ->",+ " assert 3 - len xs <= 0", -- Jikka.Core.Language.AssertedHint assumes exprs are converted with Jikka.Core.Convert.EqualitySolving.+ " in maximum (cons 0 xs)"+ ]+ let expected =+ parseProgram'+ [ "fun xs ->",+ " assert 3 - len xs <= 0",+ " in max 0 (maximum xs)"+ ]+ (formatProgram <$> run' prog) `shouldBe` Right (formatProgram expected)+ it "doesn't reduce minimum-cons if it may be nil" $ do+ let prog =+ parseProgram'+ [ "fun xs ->",+ " minimum (cons 0 xs)"+ ]+ let expected =+ parseProgram'+ [ "fun xs ->",+ " minimum (cons 0 xs)"+ ]+ (formatProgram <$> run' prog) `shouldBe` Right (formatProgram expected)
test/Jikka/Core/Convert/ConvexHullTrickSpec.hs view
@@ -86,7 +86,7 @@ ] let base = unlines- [ "let ys$2: int list = snoc nil ((let ys: int list = nil in e ys - c[0]) + c[0])",+ [ "let ys$2: int list = snoc nil ((let ys$7: int list = nil in e ys$7 - 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)"
test/Jikka/Core/Convert/CumulativeSumSpec.hs view
@@ -33,11 +33,11 @@ ] let expected = parseProgram'- [ "let rec f$0: int =",- " let a$1: int list = range 1000",- " in let n$2: int = 500",- " in let $4 = scanl (+) 0 a$1",- " in $4[n$2]",- "in f$0"+ [ "let rec f: int =",+ " let a: int list = range 1000",+ " in let n: int = 500",+ " in let $0 = scanl (+) 0 a",+ " in $0[n]",+ "in f" ] (formatProgram <$> run' prog) `shouldBe` Right (formatProgram expected)
test/Jikka/Core/Convert/SegmentTreeSpec.hs view
@@ -34,13 +34,13 @@ ] let expected = parseProgram'- [ "let a1$3: int list = range 1000",- "in let rec f$4 (k$5: int): int list =",- " let a2$6 = a1$3",- " in (foldl (fun a2$7 i$8 ->",- " let $9 = 0 + segtree_getrange<int_plus> a2$7.1 0 (i$8 + 100)",- " in (a2$7.0[i$8 + 10 <- $9], segtree_setpoint<int_plus> a2$7.1 (i$8 + 10) $9)",- " ) (a2$6, segtree_init<int_plus> a2$6) (range k$5)).0",- "in f$4 100"+ [ "let a1: int list = range 1000",+ "in let rec f (k: int): int list =",+ " let a2$2 = a1",+ " in (foldl (fun a2$0 i ->",+ " let $1 = 0 + segtree_getrange<int_plus> a2$0.1 0 (i + 100)",+ " in (a2$0.0[i + 10 <- $1], segtree_setpoint<int_plus> a2$0.1 (i + 10) $1)",+ " ) (a2$2, segtree_init<int_plus> a2$2) (range k)).0",+ "in f 100" ] (formatProgram <$> run' prog) `shouldBe` Right (formatProgram expected)
test/Jikka/Core/Convert/ShortCutFusionSpec.hs view
@@ -23,8 +23,8 @@ LitInt' 100 run' prog `shouldBe` Right expected it "squashes foldl-map combination" $ do- let g = Lam2 "a" IntTy "i" IntTy (Plus' (Var "a") (Var "i"))- let f = Lam "j" IntTy (Plus' (Var "j") Lit1)+ let g = Lam2 "a$4" IntTy "i$5" IntTy (Plus' (Var "a$4") (Var "i$5"))+ let f = Lam "j$6" IntTy (Plus' (Var "j$6") Lit1) let prog = ResultExpr $ Foldl' IntTy IntTy g Lit0 $
+ test/Jikka/Core/Convert/SortAbsSpec.hs view
@@ -0,0 +1,51 @@+{-# LANGUAGE OverloadedStrings #-}++module Jikka.Core.Convert.SortAbsSpec (spec) where++import Jikka.Common.Alpha+import Jikka.Common.Error+import Jikka.Core.Convert.SortAbs (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 . run++parseProgram' :: [String] -> Program+parseProgram' = fromSuccess . flip evalAlphaT 100 . (TypeInfer.run <=< parseProgram . unlines)++spec :: Spec+spec = describe "run" $ do+ it "works about sum" $ do+ let prog =+ parseProgram'+ [ "fun (a: int list) ->",+ " sum (map (fun (a_i: int) ->",+ " sum (map (fun (a_j: int) ->",+ " abs (a_i - a_j)",+ " ) a)",+ " ) a)"+ ]+ let expected =+ parseProgram'+ [ "fun (a: int list) ->",+ " let a$3 = sorted a",+ " in sum (map (fun ($4: int) ->",+ " let a_i = a$3[$4] in",+ " sum (map (fun ($5: int) ->",+ " let a_j = a$3[$5]",+ " in a_i - a_j",+ " ) (range $4))",+ " + (let $6 = $4",+ " in let a_j$7 = a$3[$6]",+ " in 0)",+ " + sum (map (fun ($8: int) ->",+ " let a_j$9 = a$3[$8]",+ " in a_j$9 - a_i",+ " ) (range2 ($4 + 1) (len a$3)))",+ " ) (range (len a$3)))"+ ]+ (formatProgram <$> run' prog) `shouldBe` Right (formatProgram expected)
test/Jikka/Core/Convert/TypeInferSpec.hs view
@@ -7,7 +7,7 @@ import Jikka.Common.Alpha import Jikka.Common.Error-import Jikka.Core.Convert.TypeInfer (run)+import Jikka.Core.Convert.TypeInfer (run, runExpr) import Jikka.Core.Language.BuiltinPatterns import Jikka.Core.Language.Expr import Test.Hspec@@ -15,97 +15,108 @@ run' :: Program -> Either Error Program run' = flip evalAlphaT 0 . run +runExpr' :: [(VarName, Type)] -> Expr -> Either Error Expr+runExpr' env = flip evalAlphaT 0 . runExpr env+ spec :: Spec-spec = describe "run" $ do- it "works" $ do- let prog =- ResultExpr- ( Let- "x"- (VarTy "t1")- Lit0- ( Let- "y"- (VarTy "t2")- (Plus' (Var "x") Lit1)- (Var "y")- )- )- let expected =- ResultExpr- ( Let- "x"- IntTy- Lit0- ( Let- "y"- IntTy- (Plus' (Var "x") Lit1)- (Var "y")- )- )- run' prog `shouldBe` Right expected- it "works on let-rec" $ do- let prog =- ToplevelLetRec- "f"- [("x", VarTy "t1")]- (VarTy "t2")- (Var "x")- (ResultExpr (App (Var "f") Lit0))- let expected =- ToplevelLetRec- "f"- [("x", IntTy)]- IntTy- (Var "x")- (ResultExpr (App (Var "f") Lit0))- run' prog `shouldBe` Right expected- it "replaces undetermined types with 0-tuples" $ do- let prog =- ToplevelLetRec- "f"- [("x", VarTy "t1")]- (VarTy "t2")- (Var "x")- (ResultExpr Lit0)- let expected =- ToplevelLetRec- "f"- [("x", TupleTy [])]- (TupleTy [])- (Var "x")- (ResultExpr Lit0)- run' prog `shouldBe` Right expected- it "works on builtin functions" $ do- let prog =- ToplevelLetRec- "solve"- [("n", IntTy)]- IntTy- ( If'- (VarTy "$0")- (Equal' IntTy (Var "n") Lit0)- Lit1- ( Mult'- (Var "n")- (App (Var "solve") (Minus' (Var "n") Lit1))- )- )- (ResultExpr (Var "solve"))- let expected =- ToplevelLetRec- "solve"- [("n", IntTy)]- IntTy- ( If'- IntTy- (Equal' IntTy (Var "n") Lit0)- Lit1- ( Mult'- (Var "n")- (App (Var "solve") (Minus' (Var "n") Lit1))- )- )- (ResultExpr (Var "solve"))- run' prog `shouldBe` Right expected+spec = do+ describe "run" $ do+ it "works" $ do+ let prog =+ ResultExpr+ ( Let+ "x"+ (VarTy "t1")+ Lit0+ ( Let+ "y"+ (VarTy "t2")+ (Plus' (Var "x") Lit1)+ (Var "y")+ )+ )+ let expected =+ ResultExpr+ ( Let+ "x"+ IntTy+ Lit0+ ( Let+ "y"+ IntTy+ (Plus' (Var "x") Lit1)+ (Var "y")+ )+ )+ run' prog `shouldBe` Right expected+ it "works on let-rec" $ do+ let prog =+ ToplevelLetRec+ "f"+ [("x", VarTy "t1")]+ (VarTy "t2")+ (Var "x")+ (ResultExpr (App (Var "f") Lit0))+ let expected =+ ToplevelLetRec+ "f"+ [("x", IntTy)]+ IntTy+ (Var "x")+ (ResultExpr (App (Var "f") Lit0))+ run' prog `shouldBe` Right expected+ it "replaces undetermined types with 0-tuples" $ do+ let prog =+ ToplevelLetRec+ "f"+ [("x", VarTy "t1")]+ (VarTy "t2")+ (Var "x")+ (ResultExpr Lit0)+ let expected =+ ToplevelLetRec+ "f"+ [("x", TupleTy [])]+ (TupleTy [])+ (Var "x")+ (ResultExpr Lit0)+ run' prog `shouldBe` Right expected+ it "works on builtin functions" $ do+ let prog =+ ToplevelLetRec+ "solve"+ [("n", IntTy)]+ IntTy+ ( If'+ (VarTy "$0")+ (Equal' IntTy (Var "n") Lit0)+ Lit1+ ( Mult'+ (Var "n")+ (App (Var "solve") (Minus' (Var "n") Lit1))+ )+ )+ (ResultExpr (Var "solve"))+ let expected =+ ToplevelLetRec+ "solve"+ [("n", IntTy)]+ IntTy+ ( If'+ IntTy+ (Equal' IntTy (Var "n") Lit0)+ Lit1+ ( Mult'+ (Var "n")+ (App (Var "solve") (Minus' (Var "n") Lit1))+ )+ )+ (ResultExpr (Var "solve"))+ run' prog `shouldBe` Right expected++ describe "runExpr" $ do+ it "works" $ do+ let e = Equal' (VarTy "t1") (Var "xs") (Nil' (VarTy "t2"))+ let env = [("xs", ListTy IntTy)]+ let expected = Equal' (ListTy IntTy) (Var "xs") (Nil' IntTy)+ runExpr' env e `shouldBe` Right expected
test/Jikka/Core/Convert/UnpackTupleSpec.hs view
@@ -25,7 +25,7 @@ App (Lam "x" (TupleTy ts) (Plus' (Proj' ts 0 (Var "x")) (Proj' ts 1 (Var "x")))) (uncurryApp (Tuple' ts) [LitInt' 0, LitInt' 1]) let expected = ResultExpr $- App2 (Lam2 "x$1" IntTy "x$2" IntTy (Plus' (Var "x$1") (Var "x$2"))) (LitInt' 0) (LitInt' 1)+ App2 (Lam2 "x$0" IntTy "x$1" IntTy (Plus' (Var "x$0") (Var "x$1"))) (LitInt' 0) (LitInt' 1) run' prog `shouldBe` Right expected it "works on foldl" $ do let prog =@@ -33,5 +33,5 @@ Foldl' IntTy (TupleTy [IntTy]) (Lam2 "x" (TupleTy [IntTy]) "y" IntTy (uncurryApp (Tuple' [IntTy]) [Plus' (Proj' [IntTy] 0 (Var "x")) (Var "y")])) (uncurryApp (Tuple' [IntTy]) [LitInt' 0]) (Range1' (LitInt' 10)) let expected = ResultExpr $- uncurryApp (Tuple' [IntTy]) [Foldl' IntTy IntTy (Lam2 "x$0" IntTy "y$1" IntTy (Plus' (Var "x$0") (Var "y$1"))) (LitInt' 0) (Range1' (LitInt' 10))]+ uncurryApp (Tuple' [IntTy]) [Foldl' IntTy IntTy (Lam2 "x" IntTy "y" IntTy (Plus' (Var "x") (Var "y"))) (LitInt' 0) (Range1' (LitInt' 10))] run' prog `shouldBe` Right expected
+ test/Jikka/Core/Language/AssertedHintSpec.hs view
@@ -0,0 +1,93 @@+{-# LANGUAGE OverloadedStrings #-}++module Jikka.Core.Language.AssertedHintSpec (spec) where++import Data.Maybe+import Jikka.Common.Alpha+import Jikka.Common.Error+import qualified Jikka.Core.Convert.ArithmeticExpr as ArithmeticExpr+import qualified Jikka.Core.Convert.EqualitySolving as EqualitySolving+import qualified Jikka.Core.Convert.TypeInfer as TypeInfer+import Jikka.Core.Language.ArithmeticExpr+import Jikka.Core.Language.AssertedHint+import Jikka.Core.Language.Expr+import Jikka.Core.Language.RewriteRules+import Jikka.Core.Parse (parseExpr)+import Test.Hspec++parseExpr' :: [(VarName, Type)] -> String -> Expr+parseExpr' env e = fromSuccess . flip evalAlphaT 100 $ do+ e <- parseExpr e+ e <- TypeInfer.runExpr env e+ e <- fromMaybe e <$> applyRewriteRule EqualitySolving.rule (makeRewriteEnvironmentFromTypeEnv env) e+ ArithmeticExpr.runExpr env e++spec :: Spec+spec = do+ describe "parseHints" $ do+ it "works on n == 3" $ do+ let e = parseExpr' [("n", IntTy)] "n == 3"+ let expected =+ [ ("n", EqualHint (integerArithmeticExpr 3))+ ]+ parseHints e `shouldBe` expected+ it "works on length xs == 3" $ do+ let e = parseExpr' [("xs", ListTy IntTy)] "len xs == 3"+ let expected =+ [ ("xs", LengthHint IntTy (EqualHint (integerArithmeticExpr 3)))+ ]+ parseHints e `shouldBe` expected+ it "works on length xs >= 3" $ do+ let e = parseExpr' [("xs", ListTy IntTy)] "len xs >= 3"+ let expected =+ [ ("xs", LengthHint IntTy (BoundHint (Just (integerArithmeticExpr 3)) Nothing))+ ]+ parseHints e `shouldBe` expected+ it "works on xs /= nil" $ do+ let e = parseExpr' [("xs", ListTy IntTy)] "xs /= nil"+ let expected =+ [ ("xs", LengthHint IntTy (BoundHint (Just (integerArithmeticExpr 1)) Nothing))+ ]+ parseHints e `shouldBe` expected+ it "works on length 0 <= xs - 3" $ do+ let e = parseExpr' [("xs", ListTy IntTy)] "0 <= len xs - 3"+ let expected =+ [ ("xs", LengthHint IntTy (BoundHint (Just (integerArithmeticExpr 3)) Nothing))+ ]+ parseHints e `shouldBe` expected++ describe "lowerBoundWithHints" $ do+ it "works on length n == 3" $ do+ let hints = [("n", EqualHint (integerArithmeticExpr 3))]+ let e = Var "n"+ let expected = Just 3+ lowerBoundWithHints hints e `shouldBe` expected++ describe "upperBoundWithHints" $ do+ it "works on length n == 3" $ do+ let hints = [("n", EqualHint (integerArithmeticExpr 3))]+ let e = Var "n"+ let expected = Just 4+ upperBoundWithHints hints e `shouldBe` expected++ describe "nullWithHints" $ do+ it "works on length xs >= 3" $ do+ let hints = [("xs", LengthHint IntTy (BoundHint (Just (integerArithmeticExpr 3)) Nothing))]+ let e = Var "xs"+ let expected = Just False+ nullWithHints hints e `shouldBe` expected+ it "works on length xs == 0" $ do+ let hints = [("xs", LengthHint IntTy (EqualHint (integerArithmeticExpr 0)))]+ let e = Var "xs"+ let expected = Just True+ nullWithHints hints e `shouldBe` expected+ it "works on length xs == 1" $ do+ let hints = [("xs", LengthHint IntTy (EqualHint (integerArithmeticExpr 1)))]+ let e = Var "xs"+ let expected = Just False+ nullWithHints hints e `shouldBe` expected+ it "works on length xs < 3" $ do+ let hints = [("xs", LengthHint IntTy (BoundHint Nothing (Just (integerArithmeticExpr 3))))]+ let e = Var "xs"+ let expected = Nothing+ nullWithHints hints e `shouldBe` expected
test/Jikka/Core/ParseSpec.hs view
@@ -16,45 +16,55 @@ run' :: String -> Either Error Program run' prog = evalAlphaT (run "<data>" (T.pack prog)) 100 +parseExpr' :: String -> Either Error Expr+parseExpr' e = evalAlphaT (parseExpr e) 100+ spec :: Spec-spec = describe "run" $ do- it "works" $ do- let prog =- 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",- "in",+spec = do+ describe "run" $ do+ it "works" $ do+ let prog =+ 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",+ "in",+ "solve$0"+ ]+ let expected =+ ToplevelLetRec "solve$0"- ]- let expected =- ToplevelLetRec- "solve$0"- [("n$1", IntTy)]- IntTy- ( Let- "xs$2"- (ListTy IntTy)- ( Map'- (VarTy "$100")- (VarTy "$101")- ( Lam- "i$3"- IntTy- (Mult' (Var "i$3") (Var "i$3"))- )- (Range1' (Var "n$1"))- )- (Sum' (Var "xs$2"))- )- (ResultExpr (Var "solve$0"))- run' prog `shouldBe` Right expected- it "inserts new type variables" $ do- let prog = "a[0 <- b][0]"- let expected =- ResultExpr- (At' (VarTy "$100") (SetAt' (VarTy "$101") (Var "a") (LitInt' 0) (Var "b")) (LitInt' 0))- run' prog `shouldBe` Right expected+ [("n$1", IntTy)]+ IntTy+ ( Let+ "xs$2"+ (ListTy IntTy)+ ( Map'+ (VarTy "$100")+ (VarTy "$101")+ ( Lam+ "i$3"+ IntTy+ (Mult' (Var "i$3") (Var "i$3"))+ )+ (Range1' (Var "n$1"))+ )+ (Sum' (Var "xs$2"))+ )+ (ResultExpr (Var "solve$0"))+ run' prog `shouldBe` Right expected+ it "inserts new type variables" $ do+ let prog = "a[0 <- b][0]"+ let expected =+ ResultExpr+ (At' (VarTy "$100") (SetAt' (VarTy "$101") (Var "a") (LitInt' 0) (Var "b")) (LitInt' 0))+ run' prog `shouldBe` Right expected++ describe "parseExpr" $ do+ it "works" $ do+ let e = "n == 3"+ let expected = Equal' (VarTy "$100") (Var "n") (LitInt' 3)+ parseExpr' e `shouldBe` Right expected