Skip to content

Commit

Permalink
Move repl runTransformations and doEval to src target
Browse files Browse the repository at this point in the history
  • Loading branch information
paulcadman committed Feb 12, 2024
1 parent 04ef67e commit ff4db7e
Show file tree
Hide file tree
Showing 6 changed files with 151 additions and 60 deletions.
53 changes: 1 addition & 52 deletions app/Commands/Repl.hs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@ import Control.Monad.State.Strict qualified as State
import Control.Monad.Trans.Class (lift)
import Control.Monad.Trans.Reader (mapReaderT)
import Data.String.Interpolate (i, __i)
import Evaluator
import HaskelineJB
import Juvix.Compiler.Concrete.Data.Scope (scopePath)
import Juvix.Compiler.Concrete.Data.Scope qualified as Scoped
Expand All @@ -25,8 +24,6 @@ import Juvix.Compiler.Core.Extra.Value
import Juvix.Compiler.Core.Info qualified as Info
import Juvix.Compiler.Core.Info.NoDisplayInfo qualified as Info
import Juvix.Compiler.Core.Pretty qualified as Core
import Juvix.Compiler.Core.Transformation qualified as Core
import Juvix.Compiler.Core.Transformation.DisambiguateNames (disambiguateNames)
import Juvix.Compiler.Internal.Language qualified as Internal
import Juvix.Compiler.Internal.Pretty qualified as Internal
import Juvix.Compiler.Pipeline.Repl
Expand Down Expand Up @@ -190,7 +187,7 @@ replCommand opts input_ = catchAll $ do
doEvalIO' :: Artifacts -> Core.Node -> IO (Either JuvixError Core.Node)
doEvalIO' artif' n =
mapLeft (JuvixError @Core.CoreError)
<$> doEvalIO False replDefaultLoc (Core.computeCombinedInfoTable $ artif' ^. artifactCoreModule) n
<$> Core.doEvalIO False replDefaultLoc (Core.computeCombinedInfoTable $ artif' ^. artifactCoreModule) n

compileString :: Repl (Maybe Core.Node)
compileString = do
Expand Down Expand Up @@ -605,51 +602,3 @@ renderOut = render'

renderOutLn :: (P.HasAnsiBackend a, P.HasTextBackend a) => a -> Repl ()
renderOutLn t = renderOut t >> replNewline

runTransformations ::
forall r.
(Members '[State Artifacts, Error JuvixError, Reader EntryPoint] r) =>
Bool ->
[Core.TransformationId] ->
Core.Node ->
Sem r Core.Node
runTransformations shouldDisambiguate ts n = runCoreInfoTableBuilderArtifacts $ do
sym <- addNode n
applyTransforms shouldDisambiguate ts
getNode sym
where
addNode :: Core.Node -> Sem (Core.InfoTableBuilder ': r) Core.Symbol
addNode node = do
sym <- Core.freshSymbol
Core.registerIdentNode sym node
-- `n` will get filtered out by the transformations unless it has a
-- corresponding entry in `infoIdentifiers`
md <- Core.getModule
let name = Core.freshIdentName md "_repl"
idenInfo =
Core.IdentifierInfo
{ _identifierName = name,
_identifierSymbol = sym,
_identifierLocation = Nothing,
_identifierArgsNum = 0,
_identifierType = Core.mkDynamic',
_identifierIsExported = False,
_identifierBuiltin = Nothing,
_identifierPragmas = mempty,
_identifierArgNames = []
}
Core.registerIdent name idenInfo
return sym

applyTransforms :: Bool -> [Core.TransformationId] -> Sem (Core.InfoTableBuilder ': r) ()
applyTransforms shouldDisambiguate' ts' = do
md <- Core.getModule
md' <- mapReader Core.fromEntryPoint $ Core.applyTransformations ts' md
let md'' =
if
| shouldDisambiguate' -> disambiguateNames md'
| otherwise -> md'
Core.setModule md''

getNode :: Core.Symbol -> Sem (Core.InfoTableBuilder ': r) Core.Node
getNode sym = fromMaybe impossible . flip Core.lookupIdentifierNode' sym <$> Core.getModule
8 changes: 0 additions & 8 deletions app/Evaluator.hs
Original file line number Diff line number Diff line change
Expand Up @@ -19,14 +19,6 @@ data EvalOptions = EvalOptions

makeLenses ''EvalOptions

doEvalIO ::
Bool ->
Interval ->
Core.InfoTable ->
Core.Node ->
IO (Either Core.CoreError Core.Node)
doEvalIO noIO i tab node = runM (Core.doEval noIO i tab node)

evalAndPrint ::
forall r a.
(Members '[Embed IO, App] r, CanonicalProjection a EvalOptions, CanonicalProjection a Core.Options) =>
Expand Down
8 changes: 8 additions & 0 deletions src/Juvix/Compiler/Core/Evaluator.hs
Original file line number Diff line number Diff line change
Expand Up @@ -404,6 +404,14 @@ doEval noIO loc tab node
| noIO = catchEvalError loc (eval stderr (tab ^. identContext) [] node)
| otherwise = liftIO (catchEvalErrorIO loc (evalIO (tab ^. identContext) [] node))

doEvalIO ::
Bool ->
Interval ->
InfoTable ->
Node ->
IO (Either CoreError Node)
doEvalIO noIO i tab node = runM (doEval noIO i tab node)

-- | Catch EvalError and convert it to CoreError. Needs a default location in case
-- no location is available in EvalError.
catchEvalError :: (MonadIO m) => Location -> a -> m (Either CoreError a)
Expand Down
50 changes: 50 additions & 0 deletions src/Juvix/Compiler/Pipeline/Repl.hs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ import Juvix.Compiler.Concrete.Translation.FromParsed qualified as Scoper
import Juvix.Compiler.Concrete.Translation.FromSource qualified as Parser
import Juvix.Compiler.Concrete.Translation.FromSource.ParserResultBuilder (runParserResultBuilder)
import Juvix.Compiler.Core qualified as Core
import Juvix.Compiler.Core.Transformation qualified as Core
import Juvix.Compiler.Core.Transformation.DisambiguateNames (disambiguateNames)
import Juvix.Compiler.Internal qualified as Internal
import Juvix.Compiler.Internal.Translation.FromInternal.Analysis.Termination.Checker
import Juvix.Compiler.Pipeline.Artifacts
Expand Down Expand Up @@ -167,3 +169,51 @@ compileReplInputIO fp txt = do
Parser.ReplExpression e -> ReplPipelineResultNode <$> compileExpression e
Parser.ReplImport i -> registerImport i $> ReplPipelineResultImport (i ^. importModulePath)
Parser.ReplOpenImport i -> return (ReplPipelineResultOpen (i ^. openModuleName))

runTransformations ::
forall r.
(Members '[State Artifacts, Error JuvixError, Reader EntryPoint] r) =>
Bool ->
[Core.TransformationId] ->
Core.Node ->
Sem r Core.Node
runTransformations shouldDisambiguate ts n = runCoreInfoTableBuilderArtifacts $ do
sym <- addNode n
applyTransforms shouldDisambiguate ts
getNode sym
where
addNode :: Core.Node -> Sem (Core.InfoTableBuilder ': r) Core.Symbol
addNode node = do
sym <- Core.freshSymbol
Core.registerIdentNode sym node
-- `n` will get filtered out by the transformations unless it has a
-- corresponding entry in `infoIdentifiers`
md <- Core.getModule
let name = Core.freshIdentName md "_repl"
idenInfo =
Core.IdentifierInfo
{ _identifierName = name,
_identifierSymbol = sym,
_identifierLocation = Nothing,
_identifierArgsNum = 0,
_identifierType = Core.mkDynamic',
_identifierIsExported = False,
_identifierBuiltin = Nothing,
_identifierPragmas = mempty,
_identifierArgNames = []
}
Core.registerIdent name idenInfo
return sym

applyTransforms :: Bool -> [Core.TransformationId] -> Sem (Core.InfoTableBuilder ': r) ()
applyTransforms shouldDisambiguate' ts' = do
md <- Core.getModule
md' <- mapReader Core.fromEntryPoint $ Core.applyTransformations ts' md
let md'' =
if
| shouldDisambiguate' -> disambiguateNames md'
| otherwise -> md'
Core.setModule md''

getNode :: Core.Symbol -> Sem (Core.InfoTableBuilder ': r) Core.Node
getNode sym = fromMaybe impossible . flip Core.lookupIdentifierNode' sym <$> Core.getModule
7 changes: 7 additions & 0 deletions test/Repl.hs
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
module Repl where

import Base
import Repl.Positive qualified as P

allTests :: TestTree
allTests = testGroup "Juvix REPL tests" [P.allTests]
85 changes: 85 additions & 0 deletions test/Repl/Positive.hs
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
module Repl.Positive where

import Base
import Juvix.Data.Effect.TaggedLock
import Juvix.Extra.Stdlib
import Juvix.Compiler.Pipeline.Root
import Juvix.Compiler.Core qualified as Core
import Juvix.Compiler.Pipeline.Repl
import Juvix.Extra.Paths qualified as P

runTaggedLockIO' :: Sem '[TaggedLock, Files, Embed IO, Resource, Final IO] a -> IO a
runTaggedLockIO' = runFinal
. resourceToIOFinal
. embedToFinal @IO
. runFilesIO
. runTaggedLock LockModePermissive

loadPrelude :: Path Abs Dir -> IO (Artifacts, EntryPoint)
loadPrelude rootDir = runTaggedLockIO' $ do
runReader rootDir writeStdlib
pkg <- readPackageRootIO root
let ep = defaultEntryPoint pkg root (rootDir <//> preludePath)
artif <- embed (runReplPipelineIO ep)
return (artif, ep)

where
root :: Root
root = Root {_rootRootDir=rootDir,
_rootPackageType=LocalPackage,
_rootInvokeDir=rootDir,
_rootBuildDir=DefaultBuildDir}

data TestCtx = TestCtx {
_testCtxRootDir :: Path Abs Dir,
_testCtxEntryPoint :: EntryPoint,
_testCtxArtifacts :: Artifacts
}

makeLenses ''TestCtx

assertNodeEqual :: Core.Node -> Core.Node -> Assertion
assertNodeEqual n1 n2 = undefined

replSetup :: IO TestCtx
replSetup = do
_testCtxRootDir <- do
sysTemp <- getTempDir
createTempDir sysTemp "repl"
(_testCtxArtifacts, _testCtxEntryPoint) <- loadPrelude _testCtxRootDir
return TestCtx {..}

replTeardown :: TestCtx -> IO ()
replTeardown = removeDirRecur . (^. testCtxRootDir)

replTest :: IO TestCtx -> IO ()
replTest getTestCtx = do
ctx <- getTestCtx
(_, res) <- compileReplInputIO' ctx "1 + 1"
case res of
Left err -> assertFailure "err"
Right Nothing -> assertFailure "nothing"
Right n -> assertBool "expected equal" (n == (Just (Core.mkConstant' (Core.ConstInteger 2))))


allTests :: TestTree
allTests = withResource
replSetup
replTeardown
(\getTestCtx -> testGroup "REPL positive tests"
(map (\f -> f getTestCtx ) [testCase "repl test" . replTest]))

compileReplInputIO' :: TestCtx -> Text -> IO (Artifacts, (Either JuvixError (Maybe Core.Node)))
compileReplInputIO' ctx txt =
runM
. runState (ctx ^. testCtxArtifacts)
. runReader (ctx ^. testCtxEntryPoint)
$ do
r <- compileReplInputIO P.replPath txt
return (extractNode <$> r)
where
extractNode :: ReplPipelineResult -> Maybe Core.Node
extractNode = \case
ReplPipelineResultNode n -> Just n
ReplPipelineResultImport {} -> Nothing
ReplPipelineResultOpen {} -> Nothing

0 comments on commit ff4db7e

Please sign in to comment.