Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support module imports in Juvix REPL #2029

Merged
merged 19 commits into from
May 8, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
48 changes: 33 additions & 15 deletions app/Commands/Repl.hs
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ 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
import Juvix.Compiler.Pipeline.Setup (entrySetup)
import Juvix.Data.Error.GenericError qualified as Error
import Juvix.Extra.Paths
Expand Down Expand Up @@ -157,20 +158,26 @@ runCommand opts = do
evalRes <- compileThenEval ctx' input
case evalRes of
Left err -> printError err
Right n
Right (Just n)
| Info.member Info.kNoDisplayInfo (Core.getInfo n) -> return ()
Right n
Right (Just n)
| opts ^. replPrintValues ->
renderOut (Core.ppOut opts (toValue tab n))
| otherwise ->
renderOut (Core.ppOut opts n)
Right Nothing -> return ()
Nothing -> noFileLoadedMsg
where
defaultLoc :: Interval
defaultLoc = singletonInterval (mkInitialLoc replPath)

compileThenEval :: ReplContext -> String -> Repl (Either JuvixError Core.Node)
compileThenEval ctx s = bindEither compileString eval
compileThenEval :: ReplContext -> String -> Repl (Either JuvixError (Maybe Core.Node))
compileThenEval ctx s = do
mn <- compileString
case mn of
Left err -> return (Left err)
Right Nothing -> return (Right Nothing)
Right (Just n) -> fmap Just <$> eval n
where
artif :: Artifacts
artif = ctx ^. replContextArtifacts
Expand All @@ -195,21 +202,22 @@ runCommand opts = do
mapLeft (JuvixError @Core.CoreError)
<$> doEvalIO False defaultLoc (artif' ^. artifactCoreTable) n

compileString :: Repl (Either JuvixError Core.Node)
compileString = liftIO $ compileExpressionIO' ctx (strip (pack s))

bindEither :: (Monad m) => m (Either e a) -> (a -> m (Either e b)) -> m (Either e b)
bindEither x f = join <$> (x >>= mapM f)
compileString :: Repl (Either JuvixError (Maybe Core.Node))
compileString = do
(artifacts, res) <- liftIO $ compileReplInputIO' ctx (strip (pack s))
State.modify (over (replStateContext . _Just) (set replContextArtifacts artifacts))
return res

core :: String -> Repl ()
core input = Repline.dontCrash $ do
ctx <- State.gets (^. replStateContext)
case ctx of
Just ctx' -> do
compileRes <- liftIO (compileExpressionIO' ctx' (strip (pack input)))
compileRes <- snd <$> liftIO (compileReplInputIO' ctx' (strip (pack input)))
case compileRes of
Left err -> printError err
Right n -> renderOut (Core.ppOut opts n)
Right (Just n) -> renderOut (Core.ppOut opts n)
Right Nothing -> return ()
Nothing -> noFileLoadedMsg

inferType :: String -> Repl ()
Expand Down Expand Up @@ -337,13 +345,23 @@ inferExpressionIO' :: ReplContext -> Text -> IO (Either JuvixError Internal.Expr
inferExpressionIO' ctx txt =
runM
. evalState (ctx ^. replContextArtifacts)
. runReader (ctx ^. replContextEntryPoint)
$ inferExpressionIO replPath txt

compileExpressionIO' :: ReplContext -> Text -> IO (Either JuvixError Core.Node)
compileExpressionIO' ctx txt =
compileReplInputIO' :: ReplContext -> Text -> IO (Artifacts, (Either JuvixError (Maybe Core.Node)))
compileReplInputIO' ctx txt =
runM
. evalState (ctx ^. replContextArtifacts)
$ compileExpressionIO replPath txt
. runState (ctx ^. replContextArtifacts)
. runReader (ctx ^. replContextEntryPoint)
$ do
r <- compileReplInputIO replPath txt
return (extractNode <$> r)
where
extractNode :: ReplPipelineResult -> Maybe Core.Node
extractNode = \case
ReplPipelineResultNode n -> Just n
ReplPipelineResultImport {} -> Nothing
ReplPipelineResultOpenImport {} -> Nothing

render' :: (P.HasAnsiBackend a, P.HasTextBackend a) => a -> Repl ()
render' t = do
Expand Down
3 changes: 3 additions & 0 deletions src/Juvix/Compiler/Abstract/Data/InfoTableBuilder.hs
Original file line number Diff line number Diff line change
Expand Up @@ -64,5 +64,8 @@ toState = reinterpret $ \case
runInfoTableBuilder :: Sem (InfoTableBuilder ': r) a -> Sem r (InfoTable, a)
runInfoTableBuilder = runState emptyInfoTable . toState

runInfoTableBuilder' :: InfoTable -> Sem (InfoTableBuilder ': r) a -> Sem r (InfoTable, a)
runInfoTableBuilder' t = runState t . toState

ignoreInfoTableBuilder :: Sem (InfoTableBuilder ': r) a -> Sem r a
ignoreInfoTableBuilder = fmap snd . runInfoTableBuilder
49 changes: 34 additions & 15 deletions src/Juvix/Compiler/Abstract/Translation/FromConcrete.hs
Original file line number Diff line number Diff line change
Expand Up @@ -17,21 +17,16 @@ import Juvix.Compiler.Concrete.Translation.FromParsed.Analysis.Scoping.Error
import Juvix.Data.NameKind
import Juvix.Prelude

newtype ModulesCache = ModulesCache
{_cachedModules :: HashMap S.NameId Abstract.TopModule}

makeLenses ''ModulesCache

unsupported :: Text -> a
unsupported msg = error $ msg <> "Scoped to Abstract: not yet supported"

fromConcrete :: (Members '[Error JuvixError, Builtins, NameIdGen] r) => Scoper.ScoperResult -> Sem r AbstractResult
fromConcrete _resultScoper =
mapError (JuvixError @ScoperError) $ do
(_resultTable, _resultModules) <-
(_resultTable, (_resultModulesCache, _resultModules)) <-
runInfoTableBuilder $
runReader @Pragmas mempty $
evalState (ModulesCache mempty) $
runState (ModulesCache mempty) $
mapM goTopModule ms
let _resultExports = _resultScoper ^. Scoper.resultExports
return AbstractResult {..}
Expand All @@ -41,6 +36,18 @@ fromConcrete _resultScoper =
fromConcreteExpression :: (Members '[Error JuvixError, NameIdGen] r) => Scoper.Expression -> Sem r Abstract.Expression
fromConcreteExpression = mapError (JuvixError @ScoperError) . ignoreInfoTableBuilder . runReader @Pragmas mempty . goExpression

fromConcreteImport ::
Members '[Error JuvixError, NameIdGen, Builtins, InfoTableBuilder, State ModulesCache] r =>
Scoper.Import 'Scoped ->
Sem r Abstract.TopModule
fromConcreteImport = mapError (JuvixError @ScoperError) . runReader @Pragmas mempty . goImport

fromConcreteOpenImport ::
Members '[Error JuvixError, NameIdGen, Builtins, InfoTableBuilder, State ModulesCache] r =>
Scoper.OpenModule 'Scoped ->
Sem r (Maybe Abstract.TopModule)
fromConcreteOpenImport = mapError (JuvixError @ScoperError) . runReader @Pragmas mempty . goOpenModule'

goTopModule ::
(Members '[InfoTableBuilder, Error ScoperError, Builtins, NameIdGen, Reader Pragmas, State ModulesCache] r) =>
Module 'Scoped 'ModuleTop ->
Expand Down Expand Up @@ -146,6 +153,13 @@ goModuleBody ss' = do
sigs :: [Indexed (TypeSignature 'Scoped)]
sigs = [Indexed i t | (Indexed i (StatementTypeSignature t)) <- ss]

goImport ::
forall r.
(Members '[InfoTableBuilder, Error ScoperError, Builtins, NameIdGen, State ModulesCache, Reader Pragmas] r) =>
Import 'Scoped ->
Sem r Abstract.TopModule
goImport t = goModule (t ^. importModule . moduleRefModule)

goStatement ::
forall r.
(Members '[InfoTableBuilder, Error ScoperError, Builtins, NameIdGen, Reader Pragmas, State ModulesCache] r) =>
Expand All @@ -154,28 +168,33 @@ goStatement ::
goStatement (Indexed idx s) =
fmap (Indexed idx) <$> case s of
StatementAxiom d -> Just . Abstract.StatementAxiom <$> goAxiom d
StatementImport t -> Just . Abstract.StatementImport <$> goModule (t ^. importModule . moduleRefModule)
StatementImport t -> Just . Abstract.StatementImport <$> goImport t
StatementOperator {} -> return Nothing
StatementOpenModule o -> goOpenModule o
StatementInductive i -> Just . Abstract.StatementInductive <$> goInductive i
StatementModule f -> Just . Abstract.StatementLocalModule <$> goLocalModule f
StatementTypeSignature {} -> return Nothing
StatementFunctionClause {} -> return Nothing

goOpenModule ::
goOpenModule' ::
forall r.
(Members '[InfoTableBuilder, Error ScoperError, Builtins, NameIdGen, Reader Pragmas, State ModulesCache] r) =>
(Members '[InfoTableBuilder, Error ScoperError, Builtins, NameIdGen, State ModulesCache, Reader Pragmas] r) =>
OpenModule 'Scoped ->
Sem r (Maybe Abstract.Statement)
goOpenModule o
Sem r (Maybe Abstract.TopModule)
goOpenModule' o
| isJust (o ^. openModuleImportKw) =
case o ^. openModuleName of
ModuleRef' (SModuleTop :&: m) ->
Just . Abstract.StatementImport
<$> goModule (m ^. moduleRefModule)
ModuleRef' (SModuleTop :&: m) -> Just <$> goModule (m ^. moduleRefModule)
_ -> impossible
| otherwise = return Nothing

goOpenModule ::
forall r.
(Members '[InfoTableBuilder, Error ScoperError, Builtins, NameIdGen, Reader Pragmas, State ModulesCache] r) =>
OpenModule 'Scoped ->
Sem r (Maybe Abstract.Statement)
goOpenModule o = fmap Abstract.StatementImport <$> goOpenModule' o

goLetFunctionDef ::
(Members '[InfoTableBuilder, Reader Pragmas, Error ScoperError] r) =>
TypeSignature 'Scoped ->
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,19 +6,26 @@ where

import Juvix.Compiler.Abstract.Data.InfoTable
import Juvix.Compiler.Abstract.Language
import Juvix.Compiler.Abstract.Language qualified as Abstract
import Juvix.Compiler.Concrete.Data.ScopedName qualified as S
import Juvix.Compiler.Concrete.Translation.FromParsed qualified as Concrete
import Juvix.Compiler.Concrete.Translation.FromSource qualified as Concrete
import Juvix.Compiler.Pipeline.EntryPoint qualified as E
import Juvix.Prelude

newtype ModulesCache = ModulesCache
{_cachedModules :: HashMap S.NameId Abstract.TopModule}

data AbstractResult = AbstractResult
{ _resultScoper :: Concrete.ScoperResult,
_resultTable :: InfoTable,
_resultModules :: NonEmpty TopModule,
_resultExports :: HashSet NameId
_resultExports :: HashSet NameId,
_resultModulesCache :: ModulesCache
}

makeLenses ''AbstractResult
makeLenses ''ModulesCache

abstractResultEntryPoint :: Lens' AbstractResult E.EntryPoint
abstractResultEntryPoint = resultScoper . Concrete.resultParserResult . Concrete.resultEntry
28 changes: 9 additions & 19 deletions src/Juvix/Compiler/Concrete/Data/ParsedInfoTableBuilder.hs
Original file line number Diff line number Diff line change
@@ -1,18 +1,4 @@
module Juvix.Compiler.Concrete.Data.ParsedInfoTableBuilder
( InfoTableBuilder,
registerLiteral,
registerDelimiter,
registerKeyword,
registerJudocText,
registerPragmas,
registerSpaceSpan,
registerModule,
moduleVisited,
visitModule,
runParserInfoTableBuilder,
module Juvix.Compiler.Concrete.Data.ParsedInfoTable,
)
where
module Juvix.Compiler.Concrete.Data.ParsedInfoTableBuilder where

import Data.HashMap.Strict qualified as HashMap
import Data.HashSet qualified as HashSet
Expand Down Expand Up @@ -108,10 +94,9 @@ build st =
registerItem' :: Members '[State BuilderState] r => ParsedItem -> Sem r ()
registerItem' i = modify' (over stateItems (i :))

runParserInfoTableBuilder :: Sem (InfoTableBuilder ': r) a -> Sem r (InfoTable, a)
runParserInfoTableBuilder =
fmap (first build)
. runState iniState
runParserInfoTableBuilder' :: BuilderState -> Sem (InfoTableBuilder ': r) a -> Sem r (BuilderState, a)
runParserInfoTableBuilder' s =
runState s
. reinterpret
( \case
ModuleVisited i -> HashSet.member i <$> gets (^. stateVisited)
Expand All @@ -129,3 +114,8 @@ runParserInfoTableBuilder =
_parsedTag = ParsedTagComment
}
)

runParserInfoTableBuilder :: Sem (InfoTableBuilder ': r) a -> Sem r (BuilderState, InfoTable, a)
runParserInfoTableBuilder m = do
(builderState, x) <- runParserInfoTableBuilder' iniState m
return (builderState, build builderState, x)
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@ import Data.List.NonEmpty qualified as NonEmpty
import Juvix.Compiler.Concrete.Data.InfoTableBuilder
import Juvix.Compiler.Concrete.Data.Name qualified as N
import Juvix.Compiler.Concrete.Data.Scope
import Juvix.Compiler.Concrete.Data.Scope qualified as S
import Juvix.Compiler.Concrete.Data.ScopedName qualified as S
import Juvix.Compiler.Concrete.Extra qualified as P
import Juvix.Compiler.Concrete.Language
Expand Down Expand Up @@ -58,25 +57,24 @@ scopeCheck pr modules =
_resultScoperTable = st,
_resultModules = ms,
_resultExports = exp,
_resultScope = scoperSt ^. scoperScope
_resultScope = scoperSt ^. scoperScope,
_resultScoperState = scoperSt
}

scopeCheckExpression ::
forall r.
(Members '[Error JuvixError, NameIdGen] r) =>
(Members '[Error JuvixError, NameIdGen, State Scope] r) =>
InfoTable ->
S.Scope ->
ExpressionAtoms 'Parsed ->
Sem r Expression
scopeCheckExpression tab scope as = mapError (JuvixError @ScoperError) $ do
scopeCheckExpression tab as = mapError (JuvixError @ScoperError) $ do
snd
<$> runInfoTableBuilder
tab
( runReader iniScopeParameters $
evalState iniScoperState $
evalState scope $
withLocalScope $
checkParseExpressionAtoms as
withLocalScope $
checkParseExpressionAtoms as
)
where
iniScopeParameters :: ScopeParameters
Expand All @@ -92,6 +90,20 @@ checkParseExpressionAtoms' ::
Sem r Expression
checkParseExpressionAtoms' = checkExpressionAtoms >=> parseExpressionAtoms

scopeCheckImport ::
forall r.
Members '[Error JuvixError, InfoTableBuilder, NameIdGen, State Scope, Reader ScopeParameters, State ScoperState] r =>
Import 'Parsed ->
Sem r (Import 'Scoped)
scopeCheckImport i = mapError (JuvixError @ScoperError) $ checkImport i

scopeCheckOpenModule ::
forall r.
Members '[Error JuvixError, InfoTableBuilder, NameIdGen, State Scope, Reader ScopeParameters, State ScoperState] r =>
OpenModule 'Parsed ->
Sem r (OpenModule 'Scoped)
scopeCheckOpenModule i = mapError (JuvixError @ScoperError) $ checkOpenModule i

freshVariable :: Members '[NameIdGen, State ScoperFixities, State Scope, State ScoperState] r => Symbol -> Sem r S.Symbol
freshVariable = freshSymbol S.KNameLocal

Expand Down Expand Up @@ -316,7 +328,7 @@ lookInExport sym remaining e = case remaining of
-- modules due to nesting.
lookupQualifiedSymbol ::
forall r.
Members '[State Scope, State ScoperState] r =>
Members '[State Scope] r =>
([Symbol], Symbol) ->
Sem r [SymbolEntry]
lookupQualifiedSymbol (path, sym) = do
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,8 @@ data ScoperResult = ScoperResult
_resultScoperTable :: InfoTable,
_resultModules :: NonEmpty (Module 'Scoped 'ModuleTop),
_resultExports :: HashSet NameId,
_resultScope :: HashMap TopModulePath Scope
_resultScope :: HashMap TopModulePath Scope,
_resultScoperState :: ScoperState
}

makeLenses ''ScoperResult
Expand Down
Loading