From 8b689708532ac46f21fddcc761c399fc0a594931 Mon Sep 17 00:00:00 2001 From: Jan Mas Rovira <janmasrovira@gmail.com> Date: Tue, 6 Sep 2022 12:28:39 +0200 Subject: [PATCH 1/7] add core read command --- app/App.hs | 18 ++++- app/Commands/Dev/Core.hs | 70 ++++++++++++++----- app/Main.hs | 67 +++++++++--------- .../Analysis/Scoping/Data/Context.hs | 2 +- .../Compiler/Core/Data/TransformationId.hs | 4 ++ .../Core/Data/TransformationId/Parser.hs | 31 ++++++++ src/Juvix/Compiler/Core/Pretty/Base.hs | 46 ++++++++---- src/Juvix/Compiler/Core/Pretty/Options.hs | 10 ++- src/Juvix/Compiler/Core/Transformation.hs | 10 +++ .../Core/Transformation/LambdaLifting.hs | 10 ++- .../Analysis/ArityChecking/Data/Context.hs | 2 +- .../Analysis/TypeChecking/Data/Context.hs | 2 +- src/Juvix/Compiler/Pipeline/EntryPoint.hs | 2 +- src/Juvix/Prelude/Base.hs | 2 +- src/Juvix/Prelude/Lens.hs | 4 +- src/Juvix/Prelude/Trace.hs | 11 ++- test/Core.hs | 6 +- test/Core/Transformation.hs | 7 ++ test/Core/Transformation/Base.hs | 39 +++++++++++ test/Core/Transformation/Lifting.hs | 33 +++++++++ test/Reachability/Positive.hs | 2 +- test/Scope/Positive.hs | 10 +-- test/Termination/Positive.hs | 4 +- test/TypeCheck/Positive.hs | 4 +- 24 files changed, 304 insertions(+), 92 deletions(-) create mode 100644 src/Juvix/Compiler/Core/Data/TransformationId.hs create mode 100644 src/Juvix/Compiler/Core/Data/TransformationId/Parser.hs create mode 100644 test/Core/Transformation.hs create mode 100644 test/Core/Transformation/Base.hs create mode 100644 test/Core/Transformation/Lifting.hs diff --git a/app/App.hs b/app/App.hs index 5ad70380f2..16f7aa14d1 100644 --- a/app/App.hs +++ b/app/App.hs @@ -9,7 +9,7 @@ import Juvix.Prelude.Pretty hiding (Doc) import System.Console.ANSI qualified as Ansi data App m a where - ExitMsg :: ExitCode -> Text -> App m () + ExitMsg :: ExitCode -> Text -> App m a ExitJuvixError :: JuvixError -> App m a PrintJuvixError :: JuvixError -> App m () ReadGlobalOptions :: App m GlobalOptions @@ -53,8 +53,20 @@ runPipeline p = do newline :: Member App r => Sem r () newline = say "" -printSuccessExit :: Member App r => Text -> Sem r () +printSuccessExit :: Member App r => Text -> Sem r a printSuccessExit = exitMsg ExitSuccess -printFailureExit :: Member App r => Text -> Sem r () +printFailureExit :: Member App r => Text -> Sem r a printFailureExit = exitMsg (ExitFailure 1) + +getRight :: (Members '[App] r, AppError e) => Either e a -> Sem r a +getRight = either appError return + +instance AppError Text where + appError = printFailureExit + +instance AppError JuvixError where + appError = exitJuvixError + +class AppError e where + appError :: Members '[App] r => e -> Sem r a diff --git a/app/Commands/Dev/Core.hs b/app/Commands/Dev/Core.hs index e907b0c3ac..358736265e 100644 --- a/app/Commands/Dev/Core.hs +++ b/app/Commands/Dev/Core.hs @@ -1,29 +1,42 @@ module Commands.Dev.Core where +import Juvix.Compiler.Core.Data.TransformationId.Parser import Juvix.Prelude hiding (Doc) import Options.Applicative data CoreCommand = Repl CoreReplOptions | Eval CoreEvalOptions + | Read CoreReadOptions newtype CoreReplOptions = CoreReplOptions { _coreReplShowDeBruijn :: Bool } -data CoreEvalOptions = CoreEvalOptions - { _coreEvalShowDeBruijn :: Bool, - _coreEvalNoIO :: Bool +newtype CoreEvalOptions = CoreEvalOptions + { _coreEvalNoIO :: Bool + } + +data CoreReadOptions = CoreReadOptions + { _coreReadTransformations :: [TransformationId], + _coreReadShowDeBruijn :: Bool } makeLenses ''CoreReplOptions makeLenses ''CoreEvalOptions +makeLenses ''CoreReadOptions defaultCoreEvalOptions :: CoreEvalOptions defaultCoreEvalOptions = CoreEvalOptions - { _coreEvalShowDeBruijn = False, - _coreEvalNoIO = False + { _coreEvalNoIO = False + } + +defaultCoreReadOptions :: CoreReadOptions +defaultCoreReadOptions = + CoreReadOptions + { _coreReadTransformations = mempty, + _coreReadShowDeBruijn = False } parseCoreCommand :: Parser CoreCommand @@ -31,7 +44,8 @@ parseCoreCommand = hsubparser $ mconcat [ commandRepl, - commandEval + commandEval, + commandRead ] where commandRepl :: Mod CommandFields CoreCommand @@ -40,6 +54,9 @@ parseCoreCommand = commandEval :: Mod CommandFields CoreCommand commandEval = command "eval" evalInfo + commandRead :: Mod CommandFields CoreCommand + commandRead = command "read" readInfo + replInfo :: ParserInfo CoreCommand replInfo = info @@ -52,13 +69,31 @@ parseCoreCommand = (Eval <$> parseCoreEvalOptions) (progDesc "Evaluate a JuvixCore file and pretty print the result") + readInfo :: ParserInfo CoreCommand + readInfo = + info + (Read <$> parseCoreReadOptions) + (progDesc "Read a JuvixCore file, transform it, and pretty print it") + +parseCoreReadOptions :: Parser CoreReadOptions +parseCoreReadOptions = do + _coreReadShowDeBruijn <- deBruijnOpt + _coreReadTransformations <- + option + (eitherReader parseTransf) + ( long "transforms" + <> short 't' + <> value mempty + <> metavar "[Transform]" + <> help "comma sep list of transformations. Available: lifting" + ) + pure CoreReadOptions {..} + where + parseTransf :: String -> Either String [TransformationId] + parseTransf = mapLeft unpack . parseTransformations . pack + parseCoreEvalOptions :: Parser CoreEvalOptions parseCoreEvalOptions = do - _coreEvalShowDeBruijn <- - switch - ( long "show-de-bruijn" - <> help "Show variable de Bruijn indices" - ) _coreEvalNoIO <- switch ( long "no-io" @@ -66,11 +101,14 @@ parseCoreEvalOptions = do ) pure CoreEvalOptions {..} +deBruijnOpt :: Parser Bool +deBruijnOpt = + switch + ( long "show-de-bruijn" + <> help "Show variable de Bruijn indices" + ) + parseCoreReplOptions :: Parser CoreReplOptions parseCoreReplOptions = do - _coreReplShowDeBruijn <- - switch - ( long "show-de-bruijn" - <> help "Show variable de Bruijn indices" - ) + _coreReplShowDeBruijn <- deBruijnOpt pure CoreReplOptions {..} diff --git a/app/Main.hs b/app/Main.hs index fce1020abc..7cf950afbd 100644 --- a/app/Main.hs +++ b/app/Main.hs @@ -5,7 +5,6 @@ import CLI import Commands.Dev.Termination as Termination import Commands.Init qualified as Init import Control.Exception qualified as IO -import Control.Monad.Extra import Data.ByteString qualified as ByteString import Data.HashMap.Strict qualified as HashMap import Data.Yaml @@ -29,6 +28,7 @@ import Juvix.Compiler.Core.Info qualified as Info import Juvix.Compiler.Core.Info.NoDisplayInfo qualified as Info import Juvix.Compiler.Core.Language qualified as Core import Juvix.Compiler.Core.Pretty qualified as Core +import Juvix.Compiler.Core.Transformation qualified as Core import Juvix.Compiler.Core.Translation.FromSource qualified as Core import Juvix.Compiler.Internal.Pretty qualified as Internal import Juvix.Compiler.Internal.Translation.FromAbstract qualified as Internal @@ -39,7 +39,7 @@ import Juvix.Compiler.Pipeline import Juvix.Extra.Paths qualified as Paths import Juvix.Extra.Process import Juvix.Extra.Version (runDisplayVersion) -import Juvix.Prelude hiding (Doc) +import Juvix.Prelude import Juvix.Prelude.Pretty hiding (Doc) import Options.Applicative import System.Environment (getProgName) @@ -252,28 +252,30 @@ runCommand cmdWithOpts = do printSuccessExit (n <> " Terminates with order " <> show (toList k)) _ -> impossible -runCoreCommand :: Members '[Embed IO, App] r => GlobalOptions -> CoreCommand -> Sem r () +runCoreCommand :: forall r. Members '[Embed IO, App] r => GlobalOptions -> CoreCommand -> Sem r () runCoreCommand globalOpts = \case Repl opts -> do embed showReplWelcome runRepl opts Core.emptyInfoTable - Eval opts -> - case globalOpts ^. globalInputFiles of - [] -> printFailureExit "Provide a JuvixCore file to run this command\nUse --help to see all the options" - files -> mapM_ (evalFile opts) files + Eval opts -> getFile >>= evalFile opts + Read opts -> getFile >>= runRead opts where - genericOpts :: GenericOptions - genericOpts = genericFromGlobalOptions globalOpts + getFile :: Sem r FilePath + getFile = case globalOpts ^? globalInputFiles . _head of + Nothing -> printFailureExit "Provide a JuvixCore file to run this command\nUse --help to see all the options" + Just f -> return f - docOpts :: Bool -> Core.Options - docOpts showDeBruijn = set Core.optShowNameIds (genericOpts ^. showNameIds) (set Core.optShowDeBruijnIndices showDeBruijn Core.defaultOptions) + runRead :: CoreReadOptions -> FilePath -> Sem r () + runRead opts f = do + s' <- embed (readFile f) + tab <- getRight (fst <$> mapLeft JuvixError (Core.runParser "" f Core.emptyInfoTable s')) + let tab' = Core.applyTransformations (opts ^. coreReadTransformations) tab + renderStdOut (Core.ppOut docOpts tab') + where + docOpts :: Core.Options + docOpts = set Core.optShowDeBruijnIndices (opts ^. coreReadShowDeBruijn) Core.defaultOptions - runRepl :: - forall r. - Members '[Embed IO, App] r => - CoreReplOptions -> - Core.InfoTable -> - Sem r () + runRepl :: CoreReplOptions -> Core.InfoTable -> Sem r () runRepl opts tab = do embed (putStr "> ") embed (hFlush stdout) @@ -291,7 +293,7 @@ runCoreCommand globalOpts = \case printJuvixError (JuvixError err) runRepl opts tab Right (tab', Just node) -> do - renderStdOut (Core.ppOut (docOpts (opts ^. coreReplShowDeBruijn)) node) + renderStdOut (Core.ppOut docOpts node) embed (putStrLn "") runRepl opts tab' Right (tab', Nothing) -> @@ -311,10 +313,9 @@ runCoreCommand globalOpts = \case Left err -> do printJuvixError (JuvixError err) runRepl opts tab - Right (tab', Just node) -> - replEval False tab' node - Right (tab', Nothing) -> - runRepl opts tab' + Right (tab', mnode) -> case mnode of + Nothing -> runRepl opts tab' + Just node -> replEval False tab' node ":r" -> runRepl opts Core.emptyInfoTable _ -> @@ -327,8 +328,8 @@ runCoreCommand globalOpts = \case Right (tab', Nothing) -> runRepl opts tab' where - defaultLoc = singletonInterval (mkLoc "stdin" 0 (M.initialPos "stdin")) - + docOpts :: Core.Options + docOpts = set Core.optShowDeBruijnIndices (opts ^. coreReplShowDeBruijn) Core.defaultOptions replEval :: Bool -> Core.InfoTable -> Core.Node -> Sem r () replEval noIO tab' node = do r <- doEval noIO defaultLoc tab' node @@ -337,12 +338,13 @@ runCoreCommand globalOpts = \case printJuvixError (JuvixError err) runRepl opts tab' Right node' - | Info.member Info.kNoDisplayInfo (Core.getInfo node') -> + | Info.member Info.kNoDisplayInfo (Core.getInfo node') -> runRepl opts tab' + | otherwise -> do + renderStdOut (Core.ppOut docOpts node') + embed (putStrLn "") runRepl opts tab' - Right node' -> do - renderStdOut (Core.ppOut (docOpts (opts ^. coreReplShowDeBruijn)) node') - embed (putStrLn "") - runRepl opts tab' + where + defaultLoc = singletonInterval (mkLoc "stdin" 0 (M.initialPos "stdin")) showReplWelcome :: IO () showReplWelcome = do @@ -367,7 +369,7 @@ runCoreCommand globalOpts = \case putStrLn ":h Display this help message." putStrLn "" - evalFile :: Members '[Embed IO, App] r => CoreEvalOptions -> FilePath -> Sem r () + evalFile :: CoreEvalOptions -> FilePath -> Sem r () evalFile opts f = do s <- embed (readFile f) case Core.runParser "" f Core.emptyInfoTable s of @@ -380,14 +382,15 @@ runCoreCommand globalOpts = \case | Info.member Info.kNoDisplayInfo (Core.getInfo node') -> return () Right node' -> do - renderStdOut (Core.ppOut (docOpts (opts ^. coreEvalShowDeBruijn)) node') + renderStdOut (Core.ppOut docOpts node') embed (putStrLn "") Right (_, Nothing) -> return () where + docOpts :: Core.Options + docOpts = Core.defaultOptions defaultLoc = singletonInterval (mkLoc f 0 (M.initialPos f)) doEval :: - Members '[Embed IO, App] r => Bool -> Interval -> Core.InfoTable -> diff --git a/src/Juvix/Compiler/Concrete/Translation/FromParsed/Analysis/Scoping/Data/Context.hs b/src/Juvix/Compiler/Concrete/Translation/FromParsed/Analysis/Scoping/Data/Context.hs index b1e89a4fbb..83dbccc750 100644 --- a/src/Juvix/Compiler/Concrete/Translation/FromParsed/Analysis/Scoping/Data/Context.hs +++ b/src/Juvix/Compiler/Concrete/Translation/FromParsed/Analysis/Scoping/Data/Context.hs @@ -17,4 +17,4 @@ data ScoperResult = ScoperResult makeLenses ''ScoperResult mainModule :: Lens' ScoperResult (Module 'Scoped 'ModuleTop) -mainModule = resultModules . _head +mainModule = resultModules . _head1 diff --git a/src/Juvix/Compiler/Core/Data/TransformationId.hs b/src/Juvix/Compiler/Core/Data/TransformationId.hs new file mode 100644 index 0000000000..cd7402e2d7 --- /dev/null +++ b/src/Juvix/Compiler/Core/Data/TransformationId.hs @@ -0,0 +1,4 @@ +module Juvix.Compiler.Core.Data.TransformationId where + +data TransformationId + = LambdaLifting diff --git a/src/Juvix/Compiler/Core/Data/TransformationId/Parser.hs b/src/Juvix/Compiler/Core/Data/TransformationId/Parser.hs new file mode 100644 index 0000000000..dac7d81b62 --- /dev/null +++ b/src/Juvix/Compiler/Core/Data/TransformationId/Parser.hs @@ -0,0 +1,31 @@ +module Juvix.Compiler.Core.Data.TransformationId.Parser (parseTransformations, TransformationId (..)) where + +import Juvix.Compiler.Core.Data.TransformationId +import Juvix.Prelude +import Juvix.Prelude.Pretty hiding (comma) +import Text.Megaparsec +import Text.Megaparsec.Char qualified as L +import Text.Megaparsec.Char.Lexer qualified as L + +parseTransformations :: Text -> Either Text [TransformationId] +parseTransformations t = case runParser transformations "<input>" t of + Left (err :: ParseErrorBundle Text Void) -> Left (prettyText (errorBundlePretty err)) + Right r -> return r + +transformations :: MonadParsec e Text m => m [TransformationId] +transformations = do + L.hspace + sepEndBy transformation comma <* eof + +lexeme :: MonadParsec e Text m => m a -> m a +lexeme = L.lexeme L.hspace + +comma :: MonadParsec e Text m => m () +comma = symbol "," + +symbol :: MonadParsec e Text m => Text -> m () +symbol = void . lexeme . chunk + +transformation :: MonadParsec e Text m => m TransformationId +transformation = + symbol "lifting" $> LambdaLifting diff --git a/src/Juvix/Compiler/Core/Pretty/Base.hs b/src/Juvix/Compiler/Core/Pretty/Base.hs index a1d15949e3..cedd6bfbbd 100644 --- a/src/Juvix/Compiler/Core/Pretty/Base.hs +++ b/src/Juvix/Compiler/Core/Pretty/Base.hs @@ -5,10 +5,11 @@ module Juvix.Compiler.Core.Pretty.Base ) where -import Data.List qualified as List +import Data.HashMap.Strict qualified as HashMap +import Juvix.Compiler.Core.Data.InfoTable import Juvix.Compiler.Core.Extra import Juvix.Compiler.Core.Info qualified as Info -import Juvix.Compiler.Core.Info.BinderInfo as BinderInfo +import Juvix.Compiler.Core.Info.BinderInfo import Juvix.Compiler.Core.Info.BranchInfo as BranchInfo import Juvix.Compiler.Core.Info.NameInfo as NameInfo import Juvix.Compiler.Core.Language @@ -63,6 +64,23 @@ instance PrettyCode Tag where BuiltinTag tag -> ppCode tag UserTag tag -> return $ kwUnnamedConstr <> pretty tag +instance PrettyCode InfoTable where + ppCode :: forall r. Member (Reader Options) r => InfoTable -> Sem r (Doc Ann) + ppCode tbl = do + ctx' <- ppContext (tbl ^. identContext) + return ("-- IdentContext" <> line <> ctx' <> line) + where + ppContext :: IdentContext -> Sem r (Doc Ann) + ppContext ctx = do + defs <- mapM (uncurry ppDef) (HashMap.toList ctx) + return (vsep defs) + where + ppDef :: Symbol -> Node -> Sem r (Doc Ann) + ppDef s n = do + sym' <- maybe (return (pretty s)) ppCode (tbl ^? infoIdentifiers . at s . _Just . identifierName) + body' <- ppCode n + return (kwDef <+> sym' <+> kwAssign <+> body') + instance PrettyCode Node where ppCode :: forall r. Member (Reader Options) r => Node -> Sem r (Doc Ann) ppCode node = case node of @@ -124,17 +142,16 @@ instance PrettyCode Node where ns <- mapM getName (getInfoBinders n _letRecInfo) vs <- mapM ppCode _letRecValues b' <- ppCode _letRecBody - if - | length ns == 1 -> - return $ kwLetRec <+> List.head ns <+> kwAssign <+> head vs <+> kwIn <+> b' - | otherwise -> - let bss = - indent' $ - align $ - concatWith (\a b -> a <> kwSemicolon <> line <> b) $ - zipWithExact (\name val -> name <+> kwAssign <+> val) ns (toList vs) - nss = enclose kwSquareL kwSquareR (concatWith (<+>) ns) - in return $ kwLetRec <> nss <> line <> bss <> line <> kwIn <> line <> b' + case listToMaybe ns of + Just hns -> return $ kwLetRec <+> hns <+> kwAssign <+> head vs <+> kwIn <+> b' + Nothing -> + let bss = + indent' $ + align $ + concatWith (\a b -> a <> kwSemicolon <> line <> b) $ + zipWithExact (\name val -> name <+> kwAssign <+> val) ns (toList vs) + nss = enclose kwSquareL kwSquareR (concatWith (<+>) ns) + in return $ kwLetRec <> nss <> line <> bss <> line <> kwIn <> line <> b' where getName :: Info -> Sem r (Doc Ann) getName i = @@ -282,6 +299,9 @@ kwDefault = keyword Str.underscore kwPi :: Doc Ann kwPi = keyword Str.pi_ +kwDef :: Doc Ann +kwDef = keyword Str.def + kwTrace :: Doc Ann kwTrace = keyword Str.trace_ diff --git a/src/Juvix/Compiler/Core/Pretty/Options.hs b/src/Juvix/Compiler/Core/Pretty/Options.hs index 51967f113e..63c7242e4d 100644 --- a/src/Juvix/Compiler/Core/Pretty/Options.hs +++ b/src/Juvix/Compiler/Core/Pretty/Options.hs @@ -8,6 +8,8 @@ data Options = Options _optShowDeBruijnIndices :: Bool } +makeLenses ''Options + defaultOptions :: Options defaultOptions = Options @@ -16,7 +18,13 @@ defaultOptions = _optShowDeBruijnIndices = False } -makeLenses ''Options +traceOptions :: Options +traceOptions = + Options + { _optIndent = 2, + _optShowNameIds = False, + _optShowDeBruijnIndices = True + } fromGenericOptions :: GenericOptions -> Options fromGenericOptions GenericOptions {..} = set optShowNameIds _showNameIds defaultOptions diff --git a/src/Juvix/Compiler/Core/Transformation.hs b/src/Juvix/Compiler/Core/Transformation.hs index 0da169b0b2..69fb993abf 100644 --- a/src/Juvix/Compiler/Core/Transformation.hs +++ b/src/Juvix/Compiler/Core/Transformation.hs @@ -1,10 +1,20 @@ module Juvix.Compiler.Core.Transformation ( module Juvix.Compiler.Core.Transformation.Base, + module Juvix.Compiler.Core.Transformation, module Juvix.Compiler.Core.Transformation.Eta, module Juvix.Compiler.Core.Transformation.LambdaLifting, + module Juvix.Compiler.Core.Data.TransformationId, ) where +import Juvix.Compiler.Core.Data.TransformationId import Juvix.Compiler.Core.Transformation.Base import Juvix.Compiler.Core.Transformation.Eta import Juvix.Compiler.Core.Transformation.LambdaLifting + +applyTransformations :: [TransformationId] -> InfoTable -> InfoTable +applyTransformations ts tbl = foldl' (flip appTrans) tbl ts + where + appTrans :: TransformationId -> InfoTable -> InfoTable + appTrans = \case + LambdaLifting -> lambdaLifting diff --git a/src/Juvix/Compiler/Core/Transformation/LambdaLifting.hs b/src/Juvix/Compiler/Core/Transformation/LambdaLifting.hs index 21592a1a5a..eec594f133 100644 --- a/src/Juvix/Compiler/Core/Transformation/LambdaLifting.hs +++ b/src/Juvix/Compiler/Core/Transformation/LambdaLifting.hs @@ -4,13 +4,11 @@ module Juvix.Compiler.Core.Transformation.LambdaLifting ) where -import Juvix.Compiler.Core.Data.InfoTableBuilder +import Juvix.Compiler.Core.Pretty import Juvix.Compiler.Core.Transformation.Base -lambdaLiftNode :: Member InfoTableBuilder r => Node -> Sem r Node -lambdaLiftNode _ = do - void freshSymbol - error "not yet implemented" +lambdaLiftNode :: Node -> Sem r Node +lambdaLiftNode = return -lambdaLifting :: Transformation +lambdaLifting :: InfoTable -> InfoTable lambdaLifting = run . mapT' lambdaLiftNode diff --git a/src/Juvix/Compiler/Internal/Translation/FromInternal/Analysis/ArityChecking/Data/Context.hs b/src/Juvix/Compiler/Internal/Translation/FromInternal/Analysis/ArityChecking/Data/Context.hs index e4246435e1..559708e66c 100644 --- a/src/Juvix/Compiler/Internal/Translation/FromInternal/Analysis/ArityChecking/Data/Context.hs +++ b/src/Juvix/Compiler/Internal/Translation/FromInternal/Analysis/ArityChecking/Data/Context.hs @@ -13,7 +13,7 @@ data InternalArityResult = InternalArityResult makeLenses ''InternalArityResult mainModule :: Lens' InternalArityResult Module -mainModule = resultModules . _head +mainModule = resultModules . _head1 internalArityResultEntryPoint :: Lens' InternalArityResult E.EntryPoint internalArityResultEntryPoint = resultInternalResult . M.microJuvixResultEntryPoint diff --git a/src/Juvix/Compiler/Internal/Translation/FromInternal/Analysis/TypeChecking/Data/Context.hs b/src/Juvix/Compiler/Internal/Translation/FromInternal/Analysis/TypeChecking/Data/Context.hs index 471f3a1b0d..1e0b55e8a1 100644 --- a/src/Juvix/Compiler/Internal/Translation/FromInternal/Analysis/TypeChecking/Data/Context.hs +++ b/src/Juvix/Compiler/Internal/Translation/FromInternal/Analysis/TypeChecking/Data/Context.hs @@ -25,7 +25,7 @@ data InternalTypedResult = InternalTypedResult makeLenses ''InternalTypedResult mainModule :: Lens' InternalTypedResult Module -mainModule = resultModules . _head +mainModule = resultModules . _head1 internalTypedResultEntryPoint :: Lens' InternalTypedResult E.EntryPoint internalTypedResultEntryPoint = resultInternalArityResult . Arity.internalArityResultEntryPoint diff --git a/src/Juvix/Compiler/Pipeline/EntryPoint.hs b/src/Juvix/Compiler/Pipeline/EntryPoint.hs index 71bda99383..075c28c202 100644 --- a/src/Juvix/Compiler/Pipeline/EntryPoint.hs +++ b/src/Juvix/Compiler/Pipeline/EntryPoint.hs @@ -36,4 +36,4 @@ defaultEntryPoint mainFile = makeLenses ''EntryPoint mainModulePath :: Lens' EntryPoint FilePath -mainModulePath = entryPointModulePaths . _head +mainModulePath = entryPointModulePaths . _head1 diff --git a/src/Juvix/Prelude/Base.hs b/src/Juvix/Prelude/Base.hs index 3ddb789433..ce0163a566 100644 --- a/src/Juvix/Prelude/Base.hs +++ b/src/Juvix/Prelude/Base.hs @@ -132,7 +132,7 @@ import GHC.Num import GHC.Real import GHC.Stack.Types import Language.Haskell.TH.Syntax (Lift) -import Lens.Micro.Platform hiding (both, _head) +import Lens.Micro.Platform hiding (both) import Polysemy import Polysemy.Embed import Polysemy.Error hiding (fromEither) diff --git a/src/Juvix/Prelude/Lens.hs b/src/Juvix/Prelude/Lens.hs index 9dcacb7954..bd8561d78e 100644 --- a/src/Juvix/Prelude/Lens.hs +++ b/src/Juvix/Prelude/Lens.hs @@ -3,5 +3,5 @@ module Juvix.Prelude.Lens where import Juvix.Prelude.Base -- | points to the first element of a non-empty list. -_head :: Lens' (NonEmpty a) a -_head = singular each +_head1 :: Lens' (NonEmpty a) a +_head1 = singular each diff --git a/src/Juvix/Prelude/Trace.hs b/src/Juvix/Prelude/Trace.hs index 01b7d565f1..a0938b8e89 100644 --- a/src/Juvix/Prelude/Trace.hs +++ b/src/Juvix/Prelude/Trace.hs @@ -1,6 +1,11 @@ -module Juvix.Prelude.Trace where +module Juvix.Prelude.Trace + ( module Juvix.Prelude.Trace, + module Debug.Trace, + ) +where import Data.Text qualified as Text +import Debug.Trace hiding (trace, traceM, traceShow) import Debug.Trace qualified as T import GHC.IO (unsafePerformIO) import Juvix.Prelude.Base @@ -20,6 +25,10 @@ trace :: Text -> a -> a trace = traceLabel "" {-# WARNING trace "Using trace" #-} +traceM :: Applicative f => Text -> f () +traceM t = traceLabel "" t (pure ()) +{-# WARNING traceM "Using traceM" #-} + traceShow :: Show b => b -> b traceShow b = traceLabel "" (pack . show $ b) b {-# WARNING traceShow "Using traceShow" #-} diff --git a/test/Core.hs b/test/Core.hs index 52a22ed4b5..6d6c26ea04 100644 --- a/test/Core.hs +++ b/test/Core.hs @@ -1,8 +1,8 @@ module Core where import Base -import Core.Negative qualified as N -import Core.Positive qualified as P +import Core.Eval qualified as Eval +import Core.Transformation qualified as Transformation allTests :: TestTree -allTests = testGroup "JuvixCore tests" [P.allTests, N.allTests] +allTests = testGroup "JuvixCore tests" [Eval.allTests, Transformation.allTests] diff --git a/test/Core/Transformation.hs b/test/Core/Transformation.hs new file mode 100644 index 0000000000..8d20dddcfa --- /dev/null +++ b/test/Core/Transformation.hs @@ -0,0 +1,7 @@ +module Core.Transformation where + +import Base +import Core.Transformation.Lifting qualified as Lifting + +allTests :: TestTree +allTests = testGroup "JuvixCore transformations" [Lifting.allTests] diff --git a/test/Core/Transformation/Base.hs b/test/Core/Transformation/Base.hs new file mode 100644 index 0000000000..1d68ef0b25 --- /dev/null +++ b/test/Core/Transformation/Base.hs @@ -0,0 +1,39 @@ +module Core.Transformation.Base where + +import Base +import Juvix.Compiler.Core.Data.InfoTable +import Juvix.Compiler.Core.Pretty +import Juvix.Compiler.Core.Transformation +import Juvix.Compiler.Core.Translation.FromSource +import Prettyprinter.Render.Text qualified as Text + +data Test = Test + { _testName :: String, + _testCoreFile :: FilePath, + _testExpectedFile :: FilePath, + _testTransformations :: [TransformationId] + } + +fromTest :: Test -> TestTree +fromTest = mkTest . toTestDescr + +troot :: FilePath +troot = "tests/Core/positive/" + +toTestDescr :: Test -> TestDescr +toTestDescr t@Test {..} = + TestDescr + { _testName, + _testRoot = troot, + _testAssertion = Single (coreTransAssertion t) + } + +coreTransAssertion :: Test -> Assertion +coreTransAssertion Test {..} = do + r <- applyTransformations [LambdaLifting] <$> parseFile _testCoreFile + expected <- readFile _testExpectedFile + let actualOutput = Text.renderStrict (toTextStream (ppOutDefault r)) + assertEqDiff ("Check: EVAL output = " <> _testExpectedFile) actualOutput expected + +parseFile :: FilePath -> IO InfoTable +parseFile f = fst <$> fromRightIO show (runParser "" f emptyInfoTable <$> readFile f) diff --git a/test/Core/Transformation/Lifting.hs b/test/Core/Transformation/Lifting.hs new file mode 100644 index 0000000000..8708eb4aef --- /dev/null +++ b/test/Core/Transformation/Lifting.hs @@ -0,0 +1,33 @@ +module Core.Transformation.Lifting (allTests) where + +import Base +import Core.Transformation.Base +import Juvix.Compiler.Core.Transformation + +allTests :: TestTree +allTests = testGroup "Lambda lifting" tests + +pipe :: [TransformationId] +pipe = [LambdaLifting] + +dir :: FilePath +dir = "lambda-lifting" + +liftTest :: String -> FilePath -> FilePath -> TestTree +liftTest _testName _testCoreFile _testExpectedFile = + fromTest + Test + { _testTransformations = pipe, + _testCoreFile = dir </> _testCoreFile, + _testName, + _testExpectedFile = dir </> _testExpectedFile + } + +tests :: [TestTree] +tests = + [ liftTest + ("Lambda lifting without let rec " <> i) + ("test" <> i <> ".jvc") + ("test" <> i <> ".out") + | i <- map show [1 :: Int .. 3] + ] diff --git a/test/Reachability/Positive.hs b/test/Reachability/Positive.hs index 51d175ca72..373fbf903f 100644 --- a/test/Reachability/Positive.hs +++ b/test/Reachability/Positive.hs @@ -36,7 +36,7 @@ testDescr PosTest {..} = } step "Pipeline up to reachability" - p :: Micro.InternalTypedResult <- runIO' (upToInternalReachability entryPoint) + p :: Micro.InternalTypedResult <- runIO (upToInternalReachability entryPoint) step "Check reachability results" let names = concatMap getNames (p ^. Micro.resultModules) diff --git a/test/Scope/Positive.hs b/test/Scope/Positive.hs index 89f0f14e67..549dafffb2 100644 --- a/test/Scope/Positive.hs +++ b/test/Scope/Positive.hs @@ -49,13 +49,13 @@ testDescr PosTest {..} = | otherwise = HashMap.union fs stdlibMap step "Parsing" - p :: Parser.ParserResult <- runIO' (upToParsing entryPoint) + p :: Parser.ParserResult <- runIO (upToParsing entryPoint) let p2 = head (p ^. Parser.resultModules) step "Scoping" s :: Scoper.ScoperResult <- - runIO' + runIO ( do void (entrySetup entryPoint) Concrete.fromParsed p @@ -78,18 +78,18 @@ testDescr PosTest {..} = step "Parsing pretty scoped" let fs2 = unionStdlib (HashMap.singleton entryFile scopedPretty) p' :: Parser.ParserResult <- - (runM . runErrorIO' @JuvixError . runNameIdGen . runFilesPure fs2) + (runM . runErrorIO @JuvixError . runNameIdGen . runFilesPure fs2) (upToParsing entryPoint) step "Parsing pretty parsed" let fs3 = unionStdlib (HashMap.singleton entryFile parsedPretty) parsedPretty' :: Parser.ParserResult <- - (runM . runErrorIO' @JuvixError . runNameIdGen . runFilesPure fs3) + (runM . runErrorIO @JuvixError . runNameIdGen . runFilesPure fs3) (upToParsing entryPoint) step "Scoping the scoped" s' :: Scoper.ScoperResult <- - (runM . runErrorIO' @JuvixError . runNameIdGen . runFilesPure fs) + (runM . runErrorIO @JuvixError . runNameIdGen . runFilesPure fs) (upToScoping entryPoint) step "Checks" diff --git a/test/Termination/Positive.hs b/test/Termination/Positive.hs index 1ffa1183d4..22de643edf 100644 --- a/test/Termination/Positive.hs +++ b/test/Termination/Positive.hs @@ -21,7 +21,7 @@ testDescr PosTest {..} = _testRoot = tRoot, _testAssertion = Single $ do let entryPoint = (defaultEntryPoint _file) {_entryPointNoStdlib = True} - (void . runIO') (upToInternal entryPoint) + (void . runIO) (upToInternal entryPoint) } -------------------------------------------------------------------------------- @@ -45,7 +45,7 @@ testDescrFlag N.NegTest {..} = _entryPointNoStdlib = True } - (void . runIO') (upToInternal entryPoint) + (void . runIO) (upToInternal entryPoint) } -------------------------------------------------------------------------------- diff --git a/test/TypeCheck/Positive.hs b/test/TypeCheck/Positive.hs index e5e5ed01e3..535522abaa 100644 --- a/test/TypeCheck/Positive.hs +++ b/test/TypeCheck/Positive.hs @@ -21,7 +21,7 @@ testDescr PosTest {..} = _testRoot = tRoot, _testAssertion = Single $ do let entryPoint = defaultEntryPoint _file - (void . runIO') (upToInternalTyped entryPoint) + (void . runIO) (upToInternalTyped entryPoint) } -------------------------------------------------------------------------------- @@ -43,7 +43,7 @@ testNoPositivityFlag N.NegTest {..} = { _entryPointNoPositivity = True } - (void . runIO') (upToInternal entryPoint) + (void . runIO) (upToInternal entryPoint) } negPositivityTests :: [N.NegTest] From 827eb30524ca2f7b68505705e23b59913749c029 Mon Sep 17 00:00:00 2001 From: Jan Mas Rovira <janmasrovira@gmail.com> Date: Tue, 6 Sep 2022 12:36:23 +0200 Subject: [PATCH 2/7] format --- src/Juvix/Compiler/Core/Pretty/Base.hs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Juvix/Compiler/Core/Pretty/Base.hs b/src/Juvix/Compiler/Core/Pretty/Base.hs index cedd6bfbbd..2a828fe5c6 100644 --- a/src/Juvix/Compiler/Core/Pretty/Base.hs +++ b/src/Juvix/Compiler/Core/Pretty/Base.hs @@ -151,7 +151,7 @@ instance PrettyCode Node where concatWith (\a b -> a <> kwSemicolon <> line <> b) $ zipWithExact (\name val -> name <+> kwAssign <+> val) ns (toList vs) nss = enclose kwSquareL kwSquareR (concatWith (<+>) ns) - in return $ kwLetRec <> nss <> line <> bss <> line <> kwIn <> line <> b' + in return $ kwLetRec <> nss <> line <> bss <> line <> kwIn <> line <> b' where getName :: Info -> Sem r (Doc Ann) getName i = From d0a786e9e58eced72738541d97fececa63e3a845 Mon Sep 17 00:00:00 2001 From: Jan Mas Rovira <janmasrovira@gmail.com> Date: Tue, 6 Sep 2022 12:46:39 +0200 Subject: [PATCH 3/7] recover core eval tests --- test/Core/Eval.hs | 8 ++ test/Core/Eval/Base.hs | 82 +++++++++++++ test/Core/Eval/Negative.hs | 68 +++++++++++ test/Core/Eval/Positive.hs | 228 +++++++++++++++++++++++++++++++++++++ 4 files changed, 386 insertions(+) create mode 100644 test/Core/Eval.hs create mode 100644 test/Core/Eval/Base.hs create mode 100644 test/Core/Eval/Negative.hs create mode 100644 test/Core/Eval/Positive.hs diff --git a/test/Core/Eval.hs b/test/Core/Eval.hs new file mode 100644 index 0000000000..3d4ac85da4 --- /dev/null +++ b/test/Core/Eval.hs @@ -0,0 +1,8 @@ +module Core.Eval where + +import Base +import Core.Eval.Negative qualified as EvalN +import Core.Eval.Positive qualified as EvalP + +allTests :: TestTree +allTests = testGroup "JuvixCore eval" [EvalP.allTests, EvalN.allTests] diff --git a/test/Core/Eval/Base.hs b/test/Core/Eval/Base.hs new file mode 100644 index 0000000000..69f1a79a60 --- /dev/null +++ b/test/Core/Eval/Base.hs @@ -0,0 +1,82 @@ +module Core.Eval.Base where + +import Base +import Data.Text.IO qualified as TIO +import Juvix.Compiler.Core.Data.InfoTable +import Juvix.Compiler.Core.Error +import Juvix.Compiler.Core.Evaluator +import Juvix.Compiler.Core.Extra +import Juvix.Compiler.Core.Info qualified as Info +import Juvix.Compiler.Core.Info.NoDisplayInfo +import Juvix.Compiler.Core.Language +import Juvix.Compiler.Core.Pretty +import Juvix.Compiler.Core.Translation.FromSource +import System.IO.Extra (withTempDir) +import Text.Megaparsec.Pos qualified as M + +coreEvalAssertion :: FilePath -> FilePath -> (String -> IO ()) -> Assertion +coreEvalAssertion mainFile expectedFile step = do + step "Parse" + r <- parseFile mainFile + case r of + Left err -> assertFailure (show (pretty err)) + Right (_, Nothing) -> do + step "Compare expected and actual program output" + expected <- TIO.readFile expectedFile + assertEqDiff ("Check: EVAL output = " <> expectedFile) "" expected + Right (tab, Just node) -> do + withTempDir + ( \dirPath -> do + let outputFile = dirPath </> "out.out" + hout <- openFile outputFile WriteMode + step "Evaluate" + r' <- doEval mainFile hout tab node + case r' of + Left err -> do + hClose hout + assertFailure (show (pretty err)) + Right value -> do + unless + (Info.member kNoDisplayInfo (getInfo value)) + (hPutStrLn hout (ppPrint value)) + hClose hout + actualOutput <- TIO.readFile outputFile + step "Compare expected and actual program output" + expected <- TIO.readFile expectedFile + assertEqDiff ("Check: EVAL output = " <> expectedFile) actualOutput expected + ) + +coreEvalErrorAssertion :: FilePath -> (String -> IO ()) -> Assertion +coreEvalErrorAssertion mainFile step = do + step "Parse" + r <- parseFile mainFile + case r of + Left _ -> assertBool "" True + Right (_, Nothing) -> assertFailure "no error" + Right (tab, Just node) -> do + withTempDir + ( \dirPath -> do + let outputFile = dirPath </> "out.out" + hout <- openFile outputFile WriteMode + step "Evaluate" + r' <- doEval mainFile hout tab node + case r' of + Left _ -> assertBool "" True + Right _ -> assertFailure "no error" + ) + +parseFile :: FilePath -> IO (Either ParserError (InfoTable, Maybe Node)) +parseFile f = do + s <- readFile f + return $ runParser "" f emptyInfoTable s + +doEval :: + FilePath -> + Handle -> + InfoTable -> + Node -> + IO (Either CoreError Node) +doEval f hout tab node = + catchEvalErrorIO defaultLoc (hEvalIO stdin hout (tab ^. identContext) [] node) + where + defaultLoc = singletonInterval (mkLoc f 0 (M.initialPos f)) diff --git a/test/Core/Eval/Negative.hs b/test/Core/Eval/Negative.hs new file mode 100644 index 0000000000..28b3d87ed0 --- /dev/null +++ b/test/Core/Eval/Negative.hs @@ -0,0 +1,68 @@ +module Core.Eval.Negative where + +import Base +import Core.Eval.Base + +data NegTest = NegTest + { _name :: String, + _relDir :: FilePath, + _file :: FilePath + } + +root :: FilePath +root = "tests/Core/negative" + +testDescr :: NegTest -> TestDescr +testDescr NegTest {..} = + let tRoot = root </> _relDir + in TestDescr + { _testName = _name, + _testRoot = tRoot, + _testAssertion = Steps $ coreEvalErrorAssertion _file + } + +allTests :: TestTree +allTests = + testGroup + "JuvixCore negative tests" + (map (mkTest . testDescr) tests) + +tests :: [NegTest] +tests = + [ NegTest + "Division by zero" + "." + "test001.jvc", + NegTest + "Arithmetic operations on non-numbers" + "." + "test002.jvc", + NegTest + "Matching on non-data" + "." + "test003.jvc", + NegTest + "If on non-boolean" + "." + "test004.jvc", + NegTest + "No matching case branch" + "." + "test005.jvc", + NegTest + "Invalid application" + "." + "test006.jvc", + NegTest + "Invalid builtin application" + "." + "test007.jvc", + NegTest + "Undefined symbol" + "." + "test008.jvc", + NegTest + "Erroneous Church numerals" + "." + "test009.jvc" + ] diff --git a/test/Core/Eval/Positive.hs b/test/Core/Eval/Positive.hs new file mode 100644 index 0000000000..ebf8c54e91 --- /dev/null +++ b/test/Core/Eval/Positive.hs @@ -0,0 +1,228 @@ +module Core.Eval.Positive where + +import Base +import Core.Eval.Base + +data PosTest = PosTest + { _name :: String, + _relDir :: FilePath, + _file :: FilePath, + _expectedFile :: FilePath + } + +root :: FilePath +root = "tests/Core/positive" + +testDescr :: PosTest -> TestDescr +testDescr PosTest {..} = + let tRoot = root </> _relDir + in TestDescr + { _testName = _name, + _testRoot = tRoot, + _testAssertion = Steps $ coreEvalAssertion _file _expectedFile + } + +allTests :: TestTree +allTests = + testGroup + "JuvixCore positive tests" + (map (mkTest . testDescr) tests) + +tests :: [PosTest] +tests = + [ PosTest + "Arithmetic operators" + "." + "test001.jvc" + "out/test001.out", + PosTest + "Arithmetic operators inside lambdas" + "." + "test002.jvc" + "out/test002.out", + PosTest + "Empty program with comments" + "." + "test003.jvc" + "out/test003.out", + PosTest + "IO builtins" + "." + "test004.jvc" + "out/test004.out", + PosTest + "Higher-order functions" + "." + "test005.jvc" + "out/test005.out", + PosTest + "If-then-else" + "." + "test006.jvc" + "out/test006.out", + PosTest + "Case" + "." + "test007.jvc" + "out/test007.out", + PosTest + "Recursion" + "." + "test008.jvc" + "out/test008.out", + PosTest + "Tail recursion" + "." + "test009.jvc" + "out/test009.out", + PosTest + "Let" + "." + "test010.jvc" + "out/test010.out", + PosTest + "Tail recursion: Fibonacci numbers in linear time" + "." + "test011.jvc" + "out/test011.out", + PosTest + "Trees" + "." + "test012.jvc" + "out/test012.out", + PosTest + "Functions returning functions with variable capture" + "." + "test013.jvc" + "out/test013.out", + PosTest + "Arithmetic" + "." + "test014.jvc" + "out/test014.out", + PosTest + "Local functions with free variables" + "." + "test015.jvc" + "out/test015.out", + PosTest + "Recursion through higher-order functions" + "." + "test016.jvc" + "out/test016.out", + PosTest + "Tail recursion through higher-order functions" + "." + "test017.jvc" + "out/test017.out", + PosTest + "Higher-order functions and recursion" + "." + "test018.jvc" + "out/test018.out", + PosTest + "Self-application" + "." + "test019.jvc" + "out/test019.out", + PosTest + "Recursive functions: McCarthy's 91 function, subtraction by increments" + "." + "test020.jvc" + "out/test020.out", + PosTest + "Higher-order recursive functions" + "." + "test021.jvc" + "out/test021.out", + PosTest + "Fast exponentiation" + "." + "test022.jvc" + "out/test022.out", + PosTest + "Lists" + "." + "test023.jvc" + "out/test023.out", + PosTest + "Structural equality" + "." + "test024.jvc" + "out/test024.out", + PosTest + "Mutual recursion" + "." + "test025.jvc" + "out/test025.out", + PosTest + "Nested 'case', 'let' and 'if' with variable capture" + "." + "test026.jvc" + "out/test026.out", + PosTest + "Euclid's algorithm" + "." + "test027.jvc" + "out/test027.out", + PosTest + "Functional queues" + "." + "test028.jvc" + "out/test028.out", + PosTest + "Church numerals" + "." + "test029.jvc" + "out/test029.out", + PosTest + "Streams without memoization" + "." + "test030.jvc" + "out/test030.out", + PosTest + "Ackermann function" + "." + "test031.jvc" + "out/test031.out", + PosTest + "Ackermann function (higher-order definition)" + "." + "test032.jvc" + "out/test032.out", + PosTest + "Nested lists" + "." + "test033.jvc" + "out/test033.out", + {- PosTest + "Evaluation order" + "." + "test034.jvc" + "out/test034.out", -} + PosTest + "Merge sort" + "." + "test035.jvc" + "out/test035.out", + PosTest + "Big numbers" + "." + "test036.jvc" + "out/test036.out", + PosTest + "Global variables" + "." + "test037.jvc" + "out/test037.out", + PosTest + "Global variables and forward declarations" + "." + "test038.jvc" + "out/test038.out", + PosTest + "Eta-expansion of builtins and constructors" + "." + "test039.jvc" + "out/test039.out" + ] From 0a0df7bc87bb2301c26e437400957de2ef494ed9 Mon Sep 17 00:00:00 2001 From: Jan Mas Rovira <janmasrovira@gmail.com> Date: Tue, 6 Sep 2022 12:53:32 +0200 Subject: [PATCH 4/7] reset tests --- test/Core/Transformation/Lifting.hs | 26 +------------------------- test/Reachability/Positive.hs | 2 +- test/Scope/Positive.hs | 10 +++++----- test/Termination/Positive.hs | 4 ++-- test/TypeCheck/Positive.hs | 4 ++-- 5 files changed, 11 insertions(+), 35 deletions(-) diff --git a/test/Core/Transformation/Lifting.hs b/test/Core/Transformation/Lifting.hs index 8708eb4aef..b6d41efe31 100644 --- a/test/Core/Transformation/Lifting.hs +++ b/test/Core/Transformation/Lifting.hs @@ -1,33 +1,9 @@ module Core.Transformation.Lifting (allTests) where import Base -import Core.Transformation.Base -import Juvix.Compiler.Core.Transformation allTests :: TestTree allTests = testGroup "Lambda lifting" tests -pipe :: [TransformationId] -pipe = [LambdaLifting] - -dir :: FilePath -dir = "lambda-lifting" - -liftTest :: String -> FilePath -> FilePath -> TestTree -liftTest _testName _testCoreFile _testExpectedFile = - fromTest - Test - { _testTransformations = pipe, - _testCoreFile = dir </> _testCoreFile, - _testName, - _testExpectedFile = dir </> _testExpectedFile - } - tests :: [TestTree] -tests = - [ liftTest - ("Lambda lifting without let rec " <> i) - ("test" <> i <> ".jvc") - ("test" <> i <> ".out") - | i <- map show [1 :: Int .. 3] - ] +tests = [] diff --git a/test/Reachability/Positive.hs b/test/Reachability/Positive.hs index 373fbf903f..51d175ca72 100644 --- a/test/Reachability/Positive.hs +++ b/test/Reachability/Positive.hs @@ -36,7 +36,7 @@ testDescr PosTest {..} = } step "Pipeline up to reachability" - p :: Micro.InternalTypedResult <- runIO (upToInternalReachability entryPoint) + p :: Micro.InternalTypedResult <- runIO' (upToInternalReachability entryPoint) step "Check reachability results" let names = concatMap getNames (p ^. Micro.resultModules) diff --git a/test/Scope/Positive.hs b/test/Scope/Positive.hs index 549dafffb2..89f0f14e67 100644 --- a/test/Scope/Positive.hs +++ b/test/Scope/Positive.hs @@ -49,13 +49,13 @@ testDescr PosTest {..} = | otherwise = HashMap.union fs stdlibMap step "Parsing" - p :: Parser.ParserResult <- runIO (upToParsing entryPoint) + p :: Parser.ParserResult <- runIO' (upToParsing entryPoint) let p2 = head (p ^. Parser.resultModules) step "Scoping" s :: Scoper.ScoperResult <- - runIO + runIO' ( do void (entrySetup entryPoint) Concrete.fromParsed p @@ -78,18 +78,18 @@ testDescr PosTest {..} = step "Parsing pretty scoped" let fs2 = unionStdlib (HashMap.singleton entryFile scopedPretty) p' :: Parser.ParserResult <- - (runM . runErrorIO @JuvixError . runNameIdGen . runFilesPure fs2) + (runM . runErrorIO' @JuvixError . runNameIdGen . runFilesPure fs2) (upToParsing entryPoint) step "Parsing pretty parsed" let fs3 = unionStdlib (HashMap.singleton entryFile parsedPretty) parsedPretty' :: Parser.ParserResult <- - (runM . runErrorIO @JuvixError . runNameIdGen . runFilesPure fs3) + (runM . runErrorIO' @JuvixError . runNameIdGen . runFilesPure fs3) (upToParsing entryPoint) step "Scoping the scoped" s' :: Scoper.ScoperResult <- - (runM . runErrorIO @JuvixError . runNameIdGen . runFilesPure fs) + (runM . runErrorIO' @JuvixError . runNameIdGen . runFilesPure fs) (upToScoping entryPoint) step "Checks" diff --git a/test/Termination/Positive.hs b/test/Termination/Positive.hs index 22de643edf..1ffa1183d4 100644 --- a/test/Termination/Positive.hs +++ b/test/Termination/Positive.hs @@ -21,7 +21,7 @@ testDescr PosTest {..} = _testRoot = tRoot, _testAssertion = Single $ do let entryPoint = (defaultEntryPoint _file) {_entryPointNoStdlib = True} - (void . runIO) (upToInternal entryPoint) + (void . runIO') (upToInternal entryPoint) } -------------------------------------------------------------------------------- @@ -45,7 +45,7 @@ testDescrFlag N.NegTest {..} = _entryPointNoStdlib = True } - (void . runIO) (upToInternal entryPoint) + (void . runIO') (upToInternal entryPoint) } -------------------------------------------------------------------------------- diff --git a/test/TypeCheck/Positive.hs b/test/TypeCheck/Positive.hs index 535522abaa..e5e5ed01e3 100644 --- a/test/TypeCheck/Positive.hs +++ b/test/TypeCheck/Positive.hs @@ -21,7 +21,7 @@ testDescr PosTest {..} = _testRoot = tRoot, _testAssertion = Single $ do let entryPoint = defaultEntryPoint _file - (void . runIO) (upToInternalTyped entryPoint) + (void . runIO') (upToInternalTyped entryPoint) } -------------------------------------------------------------------------------- @@ -43,7 +43,7 @@ testNoPositivityFlag N.NegTest {..} = { _entryPointNoPositivity = True } - (void . runIO) (upToInternal entryPoint) + (void . runIO') (upToInternal entryPoint) } negPositivityTests :: [N.NegTest] From 6b10f7c9b2cb6aadde61598da23336b1e0a168e4 Mon Sep 17 00:00:00 2001 From: Jan Mas Rovira <janmasrovira@gmail.com> Date: Tue, 6 Sep 2022 13:18:51 +0200 Subject: [PATCH 5/7] remove old files --- test/Core/Base.hs | 82 --------------- test/Core/Negative.hs | 72 ------------- test/Core/Positive.hs | 233 ------------------------------------------ 3 files changed, 387 deletions(-) delete mode 100644 test/Core/Base.hs delete mode 100644 test/Core/Negative.hs delete mode 100644 test/Core/Positive.hs diff --git a/test/Core/Base.hs b/test/Core/Base.hs deleted file mode 100644 index afd23810c3..0000000000 --- a/test/Core/Base.hs +++ /dev/null @@ -1,82 +0,0 @@ -module Core.Base where - -import Base -import Data.Text.IO qualified as TIO -import Juvix.Compiler.Core.Data.InfoTable -import Juvix.Compiler.Core.Error -import Juvix.Compiler.Core.Evaluator -import Juvix.Compiler.Core.Extra -import Juvix.Compiler.Core.Info qualified as Info -import Juvix.Compiler.Core.Info.NoDisplayInfo -import Juvix.Compiler.Core.Language -import Juvix.Compiler.Core.Pretty -import Juvix.Compiler.Core.Translation.FromSource -import System.IO.Extra (withTempDir) -import Text.Megaparsec.Pos qualified as M - -coreEvalAssertion :: FilePath -> FilePath -> (String -> IO ()) -> Assertion -coreEvalAssertion mainFile expectedFile step = do - step "Parse" - r <- parseFile mainFile - case r of - Left err -> assertFailure (show (pretty err)) - Right (_, Nothing) -> do - step "Compare expected and actual program output" - expected <- TIO.readFile expectedFile - assertEqDiff ("Check: EVAL output = " <> expectedFile) "" expected - Right (tab, Just node) -> do - withTempDir - ( \dirPath -> do - let outputFile = dirPath </> "out.out" - hout <- openFile outputFile WriteMode - step "Evaluate" - r' <- doEval mainFile hout tab node - case r' of - Left err -> do - hClose hout - assertFailure (show (pretty err)) - Right value -> do - unless - (Info.member kNoDisplayInfo (getInfo value)) - (hPutStrLn hout (ppPrint value)) - hClose hout - actualOutput <- TIO.readFile outputFile - step "Compare expected and actual program output" - expected <- TIO.readFile expectedFile - assertEqDiff ("Check: EVAL output = " <> expectedFile) actualOutput expected - ) - -coreEvalErrorAssertion :: FilePath -> (String -> IO ()) -> Assertion -coreEvalErrorAssertion mainFile step = do - step "Parse" - r <- parseFile mainFile - case r of - Left _ -> assertBool "" True - Right (_, Nothing) -> assertFailure "no error" - Right (tab, Just node) -> do - withTempDir - ( \dirPath -> do - let outputFile = dirPath </> "out.out" - hout <- openFile outputFile WriteMode - step "Evaluate" - r' <- doEval mainFile hout tab node - case r' of - Left _ -> assertBool "" True - Right _ -> assertFailure "no error" - ) - -parseFile :: FilePath -> IO (Either ParserError (InfoTable, Maybe Node)) -parseFile f = do - s <- readFile f - return $ runParser "" f emptyInfoTable s - -doEval :: - FilePath -> - Handle -> - InfoTable -> - Node -> - IO (Either CoreError Node) -doEval f hout tab node = - catchEvalErrorIO defaultLoc (hEvalIO stdin hout (tab ^. identContext) [] node) - where - defaultLoc = singletonInterval (mkLoc f 0 (M.initialPos f)) diff --git a/test/Core/Negative.hs b/test/Core/Negative.hs deleted file mode 100644 index 219725adb2..0000000000 --- a/test/Core/Negative.hs +++ /dev/null @@ -1,72 +0,0 @@ -module Core.Negative where - -import Base -import Core.Base - -data NegTest = NegTest - { _name :: String, - _relDir :: FilePath, - _file :: FilePath - } - -root :: FilePath -root = "tests/Core/negative" - -testDescr :: NegTest -> TestDescr -testDescr NegTest {..} = - let tRoot = root </> _relDir - in TestDescr - { _testName = _name, - _testRoot = tRoot, - _testAssertion = Steps $ coreEvalErrorAssertion _file - } - -allTests :: TestTree -allTests = - testGroup - "JuvixCore negative tests" - (map (mkTest . testDescr) tests) - -tests :: [NegTest] -tests = - [ NegTest - "Division by zero" - "." - "test001.jvc", - NegTest - "Arithmetic operations on non-numbers" - "." - "test002.jvc", - NegTest - "Matching on non-data" - "." - "test003.jvc", - NegTest - "If on non-boolean" - "." - "test004.jvc", - NegTest - "No matching case branch" - "." - "test005.jvc", - NegTest - "Invalid application" - "." - "test006.jvc", - NegTest - "Invalid builtin application" - "." - "test007.jvc", - NegTest - "Undefined symbol" - "." - "test008.jvc", - NegTest - "Erroneous Church numerals" - "." - "test009.jvc", - NegTest - "Empty letrec" - "." - "test010.jvc" - ] diff --git a/test/Core/Positive.hs b/test/Core/Positive.hs deleted file mode 100644 index dda2582349..0000000000 --- a/test/Core/Positive.hs +++ /dev/null @@ -1,233 +0,0 @@ -module Core.Positive where - -import Base -import Core.Base - -data PosTest = PosTest - { _name :: String, - _relDir :: FilePath, - _file :: FilePath, - _expectedFile :: FilePath - } - -root :: FilePath -root = "tests/Core/positive" - -testDescr :: PosTest -> TestDescr -testDescr PosTest {..} = - let tRoot = root </> _relDir - in TestDescr - { _testName = _name, - _testRoot = tRoot, - _testAssertion = Steps $ coreEvalAssertion _file _expectedFile - } - -allTests :: TestTree -allTests = - testGroup - "JuvixCore positive tests" - (map (mkTest . testDescr) tests) - -tests :: [PosTest] -tests = - [ PosTest - "Arithmetic operators" - "." - "test001.jvc" - "out/test001.out", - PosTest - "Arithmetic operators inside lambdas" - "." - "test002.jvc" - "out/test002.out", - PosTest - "Empty program with comments" - "." - "test003.jvc" - "out/test003.out", - PosTest - "IO builtins" - "." - "test004.jvc" - "out/test004.out", - PosTest - "Higher-order functions" - "." - "test005.jvc" - "out/test005.out", - PosTest - "If-then-else" - "." - "test006.jvc" - "out/test006.out", - PosTest - "Case" - "." - "test007.jvc" - "out/test007.out", - PosTest - "Recursion" - "." - "test008.jvc" - "out/test008.out", - PosTest - "Tail recursion" - "." - "test009.jvc" - "out/test009.out", - PosTest - "Let" - "." - "test010.jvc" - "out/test010.out", - PosTest - "Tail recursion: Fibonacci numbers in linear time" - "." - "test011.jvc" - "out/test011.out", - PosTest - "Trees" - "." - "test012.jvc" - "out/test012.out", - PosTest - "Functions returning functions with variable capture" - "." - "test013.jvc" - "out/test013.out", - PosTest - "Arithmetic" - "." - "test014.jvc" - "out/test014.out", - PosTest - "Local functions with free variables" - "." - "test015.jvc" - "out/test015.out", - PosTest - "Recursion through higher-order functions" - "." - "test016.jvc" - "out/test016.out", - PosTest - "Tail recursion through higher-order functions" - "." - "test017.jvc" - "out/test017.out", - PosTest - "Higher-order functions and recursion" - "." - "test018.jvc" - "out/test018.out", - PosTest - "Self-application" - "." - "test019.jvc" - "out/test019.out", - PosTest - "Recursive functions: McCarthy's 91 function, subtraction by increments" - "." - "test020.jvc" - "out/test020.out", - PosTest - "Higher-order recursive functions" - "." - "test021.jvc" - "out/test021.out", - PosTest - "Fast exponentiation" - "." - "test022.jvc" - "out/test022.out", - PosTest - "Lists" - "." - "test023.jvc" - "out/test023.out", - PosTest - "Structural equality" - "." - "test024.jvc" - "out/test024.out", - PosTest - "Mutual recursion" - "." - "test025.jvc" - "out/test025.out", - PosTest - "Nested 'case', 'let' and 'if' with variable capture" - "." - "test026.jvc" - "out/test026.out", - PosTest - "Euclid's algorithm" - "." - "test027.jvc" - "out/test027.out", - PosTest - "Functional queues" - "." - "test028.jvc" - "out/test028.out", - PosTest - "Church numerals" - "." - "test029.jvc" - "out/test029.out", - PosTest - "Streams without memoization" - "." - "test030.jvc" - "out/test030.out", - PosTest - "Ackermann function" - "." - "test031.jvc" - "out/test031.out", - PosTest - "Ackermann function (higher-order definition)" - "." - "test032.jvc" - "out/test032.out", - PosTest - "Nested lists" - "." - "test033.jvc" - "out/test033.out", - {- PosTest - "Evaluation order" - "." - "test034.jvc" - "out/test034.out", -} - PosTest - "Merge sort" - "." - "test035.jvc" - "out/test035.out", - PosTest - "Big numbers" - "." - "test036.jvc" - "out/test036.out", - PosTest - "Global variables" - "." - "test037.jvc" - "out/test037.out", - PosTest - "Global variables and forward declarations" - "." - "test038.jvc" - "out/test038.out", - PosTest - "Eta-expansion of builtins and constructors" - "." - "test039.jvc" - "out/test039.out", - PosTest - "Letrec" - "." - "test040.jvc" - "out/test040.out" - ] From 8c62a0de03582e05a088f6d58638df618c834ce9 Mon Sep 17 00:00:00 2001 From: Jan Mas Rovira <janmasrovira@gmail.com> Date: Tue, 6 Sep 2022 13:22:15 +0200 Subject: [PATCH 6/7] fix tests --- test/Core/Eval/Negative.hs | 6 +++++- test/Core/Eval/Positive.hs | 7 ++++++- 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/test/Core/Eval/Negative.hs b/test/Core/Eval/Negative.hs index 28b3d87ed0..6fcb414bbc 100644 --- a/test/Core/Eval/Negative.hs +++ b/test/Core/Eval/Negative.hs @@ -64,5 +64,9 @@ tests = NegTest "Erroneous Church numerals" "." - "test009.jvc" + "test009.jvc", + NegTest + "Empty letrec" + "." + "test010.jvc" ] diff --git a/test/Core/Eval/Positive.hs b/test/Core/Eval/Positive.hs index ebf8c54e91..8d6f1aad21 100644 --- a/test/Core/Eval/Positive.hs +++ b/test/Core/Eval/Positive.hs @@ -224,5 +224,10 @@ tests = "Eta-expansion of builtins and constructors" "." "test039.jvc" - "out/test039.out" + "out/test039.out", + PosTest + "LetRec" + "." + "test040.jvc" + "out/test040.out" ] From 8efcca761a8589ad65819b4ccd904b4cf2bf6f00 Mon Sep 17 00:00:00 2001 From: Jan Mas Rovira <janmasrovira@gmail.com> Date: Tue, 6 Sep 2022 14:55:40 +0200 Subject: [PATCH 7/7] remove unused import --- src/Juvix/Compiler/Core/Transformation/LambdaLifting.hs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/Juvix/Compiler/Core/Transformation/LambdaLifting.hs b/src/Juvix/Compiler/Core/Transformation/LambdaLifting.hs index eec594f133..bf2c9386a8 100644 --- a/src/Juvix/Compiler/Core/Transformation/LambdaLifting.hs +++ b/src/Juvix/Compiler/Core/Transformation/LambdaLifting.hs @@ -4,7 +4,6 @@ module Juvix.Compiler.Core.Transformation.LambdaLifting ) where -import Juvix.Compiler.Core.Pretty import Juvix.Compiler.Core.Transformation.Base lambdaLiftNode :: Node -> Sem r Node