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

Use a Juvix source file to define a package #2434

Merged
merged 15 commits into from
Oct 27, 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
4 changes: 2 additions & 2 deletions app/Commands/Dev/Core/Repl.hs
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@ module Commands.Dev.Core.Repl where

import Commands.Base
import Commands.Dev.Core.Repl.Options
import Evaluator
import Juvix.Compiler.Core.Data.InfoTable qualified as Core
import Juvix.Compiler.Core.Evaluator qualified as Core
import Juvix.Compiler.Core.Extra.Base qualified as Core
import Juvix.Compiler.Core.Info qualified as Info
import Juvix.Compiler.Core.Info.NoDisplayInfo qualified as Info
Expand Down Expand Up @@ -97,7 +97,7 @@ runRepl opts tab = do
where
replEval :: Bool -> Core.InfoTable -> Core.Node -> Sem r ()
replEval noIO tab' node = do
r <- doEval noIO defaultLoc tab' node
r <- Core.doEval noIO defaultLoc tab' node
case r of
Left err -> do
printJuvixError (JuvixError err)
Expand Down
4 changes: 4 additions & 0 deletions app/Commands/Repl.hs
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,8 @@ 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.Package.Loader.Error
import Juvix.Compiler.Pipeline.Package.Loader.EvalEff.IO
import Juvix.Compiler.Pipeline.Repl
import Juvix.Compiler.Pipeline.Run
import Juvix.Compiler.Pipeline.Setup (entrySetup)
Expand Down Expand Up @@ -154,6 +156,8 @@ loadDefaultPrelude = whenJustM defaultPreludeEntryPoint $ \e -> do
. runError @GitProcessError
. runGitProcess
. runError @DependencyError
. runError @PackageLoaderError
. runEvalFileEffIO
. runPathResolver root
$ entrySetup defaultDependenciesConfig
loadEntryPoint e
Expand Down
16 changes: 2 additions & 14 deletions app/Evaluator.hs
Original file line number Diff line number Diff line change
Expand Up @@ -23,25 +23,13 @@ data EvalOptions = EvalOptions

makeLenses ''EvalOptions

doEval ::
forall r.
(Members '[Embed IO] r) =>
Bool ->
Interval ->
Core.InfoTable ->
Core.Node ->
Sem r (Either Core.CoreError Core.Node)
doEval noIO loc tab node
| noIO = embed $ Core.catchEvalError loc (Core.eval stderr (tab ^. Core.identContext) [] node)
| otherwise = embed $ Core.catchEvalErrorIO loc (Core.evalIO (tab ^. Core.identContext) [] node)

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

evalAndPrint ::
forall r a.
Expand All @@ -52,7 +40,7 @@ evalAndPrint ::
Sem r ()
evalAndPrint opts tab node = do
loc <- defaultLoc
r <- doEval (project opts ^. evalNoIO) loc tab node
r <- Core.doEval (project opts ^. evalNoIO) loc tab node
case r of
Left err -> exitJuvixError (JuvixError err)
Right node'
Expand Down
51 changes: 36 additions & 15 deletions include/package/PackageDescription.juvix
Original file line number Diff line number Diff line change
Expand Up @@ -2,22 +2,29 @@ module PackageDescription;

import Stdlib.Prelude open;

--- A ;Package; defines the configuration for a Juvix package
type Package :=
mkPackage {
-- The name of the package
name : String;
-- The version for the package
version : SemVer;
-- The dependencies of this package
dependencies : List Dependency;
-- A path to the Main module for this package
main : Maybe String;
-- A path to a directory where Juvix should output intermediate build products
buildDir : Maybe String
};

mkPackageDefault (name : String)
{version : SemVer := mkVersion 0 0 0}
{dependencies : List Dependency := []}
{main : Maybe String := nothing}
{buildDir : Maybe String := nothing} : Package :=
--- Construct a ;Package; with useful default arguments.
defaultPackage {name : String := "my-project"} {version : SemVer := defaultVersion} {dependencies : List
Dependency := [defaultStdlib]} {main : Maybe
String := nothing} {buildDir : Maybe String := nothing}
: Package :=
mkPackage name version dependencies main buildDir;

--- A ;SemVer; defines a version that conforms to the Semantic Versioning specification.
type SemVer :=
mkSemVer {
major : Nat;
Expand All @@ -27,25 +34,39 @@ type SemVer :=
meta : Maybe String
};

mkVersion (major : Nat)
(minor : Nat)
(patch : Nat)
{release : Maybe String := nothing}
{meta : Maybe String := nothing} : SemVer :=
--- Construct a ;SemVer; with useful default arguments.
mkVersion (major minor patch : Nat) {release : Maybe
String := nothing} {meta : Maybe String := nothing}
: SemVer :=
mkSemVer
(major := major;
minor := minor;
patch := patch;
release := release;
meta := meta);

--- The default version used in `defaultPackage`.
defaultVersion : SemVer := mkVersion 0 0 0;

--- A ;Dependency; defines a Juvix package dependency.
type Dependency :=
| pathDependency {path : String}
| gitDependency {
url : String;
| --- A filesystem path to another Juvix Package.
path {path : String}
| --- A ;git; repository containing a Juvix package at its root
git {
-- A name for this dependency
name : String;
-- The URL to the git repository
url : String;
-- The git ref to checkout
ref : String
};
}
| --- The ;defaultStdlib; that is bundled with the Juvix compiler.
defaultStdlib;

--- Constructs a GitHub dependency.
github (org repo ref : String) : Dependency :=
gitDependency ("https://github.com/" ++str org ++str "/" ++str repo) (org ++str "_" ++str repo) ref;
git
(org ++str "_" ++str repo)
("https://github.com/" ++str org ++str "/" ++str repo)
ref;
2 changes: 1 addition & 1 deletion src/Juvix/Compiler/Concrete/Translation.hs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ module Juvix.Compiler.Concrete.Translation where
import Juvix.Compiler.Concrete.Data.Highlight.Input (HighlightBuilder)
import Juvix.Compiler.Concrete.Language
import Juvix.Compiler.Concrete.Translation.FromParsed qualified as Scoper
import Juvix.Compiler.Concrete.Translation.FromParsed.Analysis.PathResolver
import Juvix.Compiler.Concrete.Translation.FromParsed.Analysis.PathResolver.Base
import Juvix.Compiler.Concrete.Translation.FromSource qualified as Parser
import Juvix.Compiler.Pipeline.EntryPoint
import Juvix.Prelude
Expand Down
2 changes: 1 addition & 1 deletion src/Juvix/Compiler/Concrete/Translation/FromParsed.hs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ where

import Juvix.Compiler.Concrete.Data.Highlight.Input
import Juvix.Compiler.Concrete.Language
import Juvix.Compiler.Concrete.Translation.FromParsed.Analysis.PathResolver
import Juvix.Compiler.Concrete.Translation.FromParsed.Analysis.PathResolver.Base
import Juvix.Compiler.Concrete.Translation.FromParsed.Analysis.Scoping
import Juvix.Compiler.Concrete.Translation.FromParsed.Analysis.Scoping.Data.Context
import Juvix.Compiler.Concrete.Translation.FromSource qualified as Parser
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,14 +23,15 @@ import Juvix.Compiler.Concrete.Translation.FromParsed.Analysis.PathResolver.Path
import Juvix.Compiler.Pipeline.EntryPoint
import Juvix.Compiler.Pipeline.Lockfile
import Juvix.Compiler.Pipeline.Package
import Juvix.Compiler.Pipeline.Package.Loader.EvalEff
import Juvix.Data.Effect.Git
import Juvix.Extra.Paths
import Juvix.Extra.Stdlib (ensureStdlib)
import Juvix.Prelude

mkPackage ::
forall r.
(Members '[Files, Error JuvixError, Reader ResolverEnv, GitClone] r) =>
(Members '[Files, Error JuvixError, Reader ResolverEnv, GitClone, EvalFileEff] r) =>
Maybe EntryPoint ->
Path Abs Dir ->
Sem r Package
Expand Down Expand Up @@ -162,7 +163,7 @@ resolveDependency i = case i ^. packageDepdendencyInfoDependency of

registerDependencies' ::
forall r.
(Members '[Reader EntryPoint, State ResolverState, Reader ResolverEnv, Files, Error JuvixError, Error DependencyError, GitClone] r) =>
(Members '[Reader EntryPoint, State ResolverState, Reader ResolverEnv, Files, Error JuvixError, Error DependencyError, GitClone, EvalFileEff] r) =>
DependenciesConfig ->
Sem r ()
registerDependencies' conf = do
Expand All @@ -186,7 +187,7 @@ registerDependencies' conf = do

addRootDependency ::
forall r.
(Members '[State ResolverState, Reader ResolverEnv, Files, Error JuvixError, Error DependencyError, GitClone] r) =>
(Members '[State ResolverState, Reader ResolverEnv, Files, Error JuvixError, Error DependencyError, GitClone, EvalFileEff] r) =>
DependenciesConfig ->
EntryPoint ->
Path Abs Dir ->
Expand All @@ -207,7 +208,7 @@ addRootDependency conf e root = do

addDependency ::
forall r.
(Members '[State ResolverState, Reader ResolverEnv, Files, Error JuvixError, Error DependencyError, GitClone] r) =>
(Members '[State ResolverState, Reader ResolverEnv, Files, Error JuvixError, Error DependencyError, GitClone, EvalFileEff] r) =>
Maybe EntryPoint ->
PackageDependencyInfo ->
Sem r LockfileDependency
Expand All @@ -224,7 +225,7 @@ addDependency me d = do

addDependency' ::
forall r.
(Members '[State ResolverState, Reader ResolverEnv, Files, Error JuvixError, Error DependencyError, GitClone] r) =>
(Members '[State ResolverState, Reader ResolverEnv, Files, Error JuvixError, Error DependencyError, GitClone, EvalFileEff] r) =>
Package ->
Maybe EntryPoint ->
ResolvedDependency ->
Expand Down Expand Up @@ -319,7 +320,7 @@ expectedPath' actualPath m = do

re ::
forall r a.
(Members '[Reader EntryPoint, Files, Error JuvixError, Error DependencyError, GitClone] r) =>
(Members '[Reader EntryPoint, Files, Error JuvixError, Error DependencyError, GitClone, EvalFileEff] r) =>
Sem (PathResolver ': r) a ->
Sem (Reader ResolverEnv ': State ResolverState ': r) a
re = reinterpret2H helper
Expand All @@ -342,13 +343,13 @@ re = reinterpret2H helper
Right (r, _) -> r
raise (evalPathResolver' st' root' (a' x'))

evalPathResolver' :: (Members '[Reader EntryPoint, Files, Error JuvixError, Error DependencyError, GitClone] r) => ResolverState -> Path Abs Dir -> Sem (PathResolver ': r) a -> Sem r a
evalPathResolver' :: (Members '[Reader EntryPoint, Files, Error JuvixError, Error DependencyError, GitClone, EvalFileEff] r) => ResolverState -> Path Abs Dir -> Sem (PathResolver ': r) a -> Sem r a
evalPathResolver' st root = fmap snd . runPathResolver' st root

runPathResolver :: (Members '[Reader EntryPoint, Files, Error JuvixError, Error DependencyError, GitClone] r) => Path Abs Dir -> Sem (PathResolver ': r) a -> Sem r (ResolverState, a)
runPathResolver :: (Members '[Reader EntryPoint, Files, Error JuvixError, Error DependencyError, GitClone, EvalFileEff] r) => Path Abs Dir -> Sem (PathResolver ': r) a -> Sem r (ResolverState, a)
runPathResolver = runPathResolver' iniResolverState

runPathResolver' :: (Members '[Reader EntryPoint, Files, Error JuvixError, Error DependencyError, GitClone] r) => ResolverState -> Path Abs Dir -> Sem (PathResolver ': r) a -> Sem r (ResolverState, a)
runPathResolver' :: (Members '[Reader EntryPoint, Files, Error JuvixError, Error DependencyError, GitClone, EvalFileEff] r) => ResolverState -> Path Abs Dir -> Sem (PathResolver ': r) a -> Sem r (ResolverState, a)
runPathResolver' st root x = do
e <- ask
let _envSingleFile :: Maybe (Path Abs File)
Expand All @@ -364,15 +365,15 @@ runPathResolver' st root x = do
}
runState st (runReader env (re x))

runPathResolverPipe' :: (Members '[Files, Reader EntryPoint, Error DependencyError, GitClone, Error JuvixError] r) => ResolverState -> Sem (PathResolver ': r) a -> Sem r (ResolverState, a)
runPathResolverPipe' :: (Members '[Files, Reader EntryPoint, Error DependencyError, GitClone, Error JuvixError, EvalFileEff] r) => ResolverState -> Sem (PathResolver ': r) a -> Sem r (ResolverState, a)
runPathResolverPipe' iniState a = do
r <- asks (^. entryPointResolverRoot)
runPathResolver' iniState r a

runPathResolverPipe :: (Members '[Files, Reader EntryPoint, Error DependencyError, GitClone, Error JuvixError] r) => Sem (PathResolver ': r) a -> Sem r (ResolverState, a)
runPathResolverPipe :: (Members '[Files, Reader EntryPoint, Error DependencyError, GitClone, Error JuvixError, EvalFileEff] r) => Sem (PathResolver ': r) a -> Sem r (ResolverState, a)
runPathResolverPipe a = do
r <- asks (^. entryPointResolverRoot)
runPathResolver r a

evalPathResolverPipe :: (Members '[Files, Reader EntryPoint, Error DependencyError, GitClone, Error JuvixError] r) => Sem (PathResolver ': r) a -> Sem r a
evalPathResolverPipe :: (Members '[Files, Reader EntryPoint, Error DependencyError, GitClone, Error JuvixError, EvalFileEff] r) => Sem (PathResolver ': r) a -> Sem r a
evalPathResolverPipe = fmap snd . runPathResolverPipe
Original file line number Diff line number Diff line change
Expand Up @@ -93,12 +93,14 @@ instance PrettyCodeAnn MissingLockfileDependency where
data PathResolverError
= ErrDependencyConflict DependencyConflict
| ErrMissingModule MissingModule
| ErrPackageInvalidImport PackageInvalidImport
deriving stock (Show)

instance PrettyCodeAnn PathResolverError where
ppCodeAnn = \case
ErrDependencyConflict e -> ppCodeAnn e
ErrMissingModule e -> ppCodeAnn e
ErrPackageInvalidImport e -> ppCodeAnn e

data DependencyConflict = DependencyConflict
{ _conflictPackages :: NonEmpty PackageInfo,
Expand Down Expand Up @@ -151,3 +153,15 @@ instance PrettyCodeAnn MissingModule where
where
deps :: [Dependency]
deps = _missingInfo ^. packagePackage . packageDependencies

newtype PackageInvalidImport = PackageInvalidImport
{_packageInvalidImport :: TopModulePath}
deriving stock (Show)

instance PrettyCodeAnn PackageInvalidImport where
ppCodeAnn PackageInvalidImport {..} =
"The module"
<+> pcode _packageInvalidImport
<+> "cannot be imported by the Package file."
<> line
<> "Package files may only import modules from the Juvix standard library or from the PackageDescription module."
3 changes: 2 additions & 1 deletion src/Juvix/Compiler/Concrete/Translation/FromSource.hs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,8 @@ import Juvix.Compiler.Concrete.Data.ParsedInfoTableBuilder
import Juvix.Compiler.Concrete.Extra (takeWhile1P)
import Juvix.Compiler.Concrete.Extra qualified as P
import Juvix.Compiler.Concrete.Language
import Juvix.Compiler.Concrete.Translation.FromParsed.Analysis.PathResolver
import Juvix.Compiler.Concrete.Translation.FromParsed.Analysis.PathResolver.Base
import Juvix.Compiler.Concrete.Translation.FromParsed.Analysis.PathResolver.Error
import Juvix.Compiler.Concrete.Translation.FromSource.Data.Context
import Juvix.Compiler.Concrete.Translation.FromSource.Lexer hiding
( symbol,
Expand Down
12 changes: 12 additions & 0 deletions src/Juvix/Compiler/Core/Evaluator.hs
Original file line number Diff line number Diff line change
Expand Up @@ -399,6 +399,18 @@ hEvalIO = hEvalIO' defaultEvalOptions
evalIO :: IdentContext -> Env -> Node -> IO Node
evalIO = hEvalIO stderr stdin stdout

doEval ::
forall r.
(Members '[Embed IO] r) =>
Bool ->
Interval ->
InfoTable ->
Node ->
Sem r (Either CoreError Node)
doEval noIO loc tab node
| noIO = embed $ catchEvalError loc (eval stderr (tab ^. identContext) [] node)
| otherwise = embed $ catchEvalErrorIO loc (evalIO (tab ^. identContext) [] node)

-- | Catch EvalError and convert it to CoreError. Needs a default location in case
-- no location is available in EvalError.
catchEvalError :: Location -> a -> IO (Either CoreError a)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ convertNode nonRecSyms tab = umap go
&& _builtinAppOp /= OpTrace
&& _builtinAppOp /= OpSeq
&& all isNonRecValue _builtinAppArgs ->
doEval node
doEval' node
NApp {}
| Info.isClosed node ->
case h of
Expand All @@ -29,7 +29,7 @@ convertNode nonRecSyms tab = umap go
&& length tyargs == ii ^. identifierArgsNum
&& isZeroOrderType tab tgt'
&& all isNonRecValue args ->
doEval node
doEval' node
where
ii = lookupIdentifierInfo tab _identSymbol
evalAllowed = maybe True (^. pragmaEval) (ii ^. identifierPragmas . pragmasEval)
Expand All @@ -53,8 +53,8 @@ convertNode nonRecSyms tab = umap go
in isNonRecValue h && all isType' args
_ -> isType' node

doEval :: Node -> Node
doEval = removeClosures . geval opts stderr (tab ^. identContext) []
doEval' :: Node -> Node
doEval' = removeClosures . geval opts stderr (tab ^. identContext) []
where
opts =
defaultEvalOptions
Expand Down
Loading