Skip to content

Commit

Permalink
Add juvix dev anoma prove
Browse files Browse the repository at this point in the history
This is similar to `juvix dev nockma run`. The difference is that the
mamaged client is used and it outputs the result as a jammed file.
  • Loading branch information
paulcadman committed Nov 22, 2024
1 parent 669474f commit 5c3449b
Show file tree
Hide file tree
Showing 10 changed files with 142 additions and 59 deletions.
40 changes: 33 additions & 7 deletions app/Commands/Dev/Anoma.hs
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,40 @@ module Commands.Dev.Anoma
)
where

import Anoma.Client.Config
import Anoma.Effect.Base
import Commands.Base
import Commands.Dev.Anoma.Client
import Commands.Dev.Anoma.Options
import Commands.Dev.Anoma.Prove qualified as Prove
import Commands.Dev.Anoma.Prove.Options
import Commands.Dev.Anoma.Start qualified as Start
import Commands.Dev.Anoma.Status qualified as Status
import Commands.Dev.Anoma.Stop qualified as Stop
import Juvix.Data.CodeAnn
import Juvix.Data.Yaml qualified as Y

runCommand :: (Members AppEffects r) => AnomaCommand -> Sem r ()
runCommand = \case
AnomaCommandStart opts -> Start.runCommand opts
AnomaCommandStatus -> Status.runCommand
AnomaCommandStop -> Stop.runCommand
runCommand :: forall r. (Members AppEffects r) => AnomaCommand -> Sem r ()
runCommand =
runAppError @SimpleError . \case
AnomaCommandStart opts -> Start.runCommand opts
AnomaCommandStatus -> checkRunning >>= renderStdOutLn . ppCodeAnn
AnomaCommandStop -> checkRunning >>= stopClient >> removeConfig
AnomaCommandProve opts -> do
host <- getHostConfig (opts ^. proveClientInfo)
runAnomaWithClient host (Prove.runCommand opts)
where
checkRunning :: (Members (Error SimpleError ': AppEffects) x) => Sem x ClientConfig
checkRunning = fromMaybeM (logInfo "The Anoma client is not running" >> exitFailure) checkClientRunning

getHostConfig :: (Members (Error SimpleError ': AppEffects) x) => Maybe (AppPath File) -> Sem x AnomaClientInfo
getHostConfig = \case
Just p -> fromAppFile p >>= readClientInfo
Nothing -> (^. clientConfigHost) <$> checkRunning

readClientInfo :: (Members '[Files, Error SimpleError] x) => Path Abs File -> Sem x AnomaClientInfo
readClientInfo fp = do
let pathName = pack (toFilePath fp)
unlessM (fileExists' fp) (throw (SimpleError (mkAnsiText ("Config file: " <> pathName <> " does not exist"))))
bs <- readFileBS' fp
case Y.decodeEither bs of
Left err -> throw (SimpleError (mkAnsiText (Y.prettyPrintParseException err <> "\n" <> toFilePath fp)))
Right a -> return a
25 changes: 25 additions & 0 deletions app/Commands/Dev/Anoma/Base.hs
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
module Commands.Dev.Anoma.Base where

import Anoma.Effect
import Commands.Base hiding (Atom)
import Juvix.Compiler.Nockma.Pretty
import Juvix.Compiler.Nockma.Translation.FromSource qualified as Nockma

-- | Calls Anoma.Protobuf.NockService.Prove
runNock :: forall r. (Members '[Error SimpleError, Anoma] r, Members AppEffects r) => AppPath File -> Maybe (AppPath File) -> Sem r RunNockmaResult
runNock programFile margsFile = do
afile <- fromAppPathFile programFile
argsFile <- mapM fromAppPathFile margsFile
parsedArgs <- runAppError @JuvixError (mapM Nockma.cueJammedFileOrPretty argsFile)
parsedTerm <- runAppError @JuvixError (Nockma.cueJammedFileOrPretty afile)
case parsedTerm of
TermAtom {} -> exitFailMsg "Expected nockma input to be a cell"
t@(TermCell {}) -> go t (maybe [] unfoldList parsedArgs)
where
go :: Term Natural -> [Term Natural] -> Sem r RunNockmaResult
go t args =
runNockma
RunNockmaInput
{ _runNockmaProgram = t,
_runNockmaArgs = args
}
14 changes: 13 additions & 1 deletion app/Commands/Dev/Anoma/Options.hs
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
module Commands.Dev.Anoma.Options where

import Commands.Dev.Anoma.Prove.Options
import Commands.Dev.Anoma.Start.Options
import CommonOptions

data AnomaCommand
= AnomaCommandStart StartOptions
| AnomaCommandStatus
| AnomaCommandStop
| AnomaCommandProve ProveOptions
deriving stock (Data)

parseAnomaCommand :: Parser AnomaCommand
Expand All @@ -15,7 +17,8 @@ parseAnomaCommand =
( mconcat
[ commandStart,
commandStatus,
commandStop
commandStop,
commandProve
]
)
where
Expand Down Expand Up @@ -45,3 +48,12 @@ parseAnomaCommand =
info
(pure AnomaCommandStop)
(progDesc "Stop the Anoma client")

commandProve :: Mod CommandFields AnomaCommand
commandProve = command "prove" runInfo
where
runInfo :: ParserInfo AnomaCommand
runInfo =
info
(AnomaCommandProve <$> parseProveOptions)
(progDesc "Submit an Anoma program to Anoma.Protobuf.NockService.Prove")
27 changes: 27 additions & 0 deletions app/Commands/Dev/Anoma/Prove.hs
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
module Commands.Dev.Anoma.Prove where

import Anoma.Effect.Base
import Anoma.Effect.RunNockma
import Commands.Base
import Commands.Dev.Anoma.Base
import Commands.Dev.Anoma.Prove.Options
import Juvix.Compiler.Nockma.Encoding.Jam qualified as Encoding
import Juvix.Compiler.Nockma.Pretty hiding (Path)

runCommand :: forall r. (Members (Anoma ': Error SimpleError ': AppEffects) r) => ProveOptions -> Sem r ()
runCommand opts = do
res <- runNock (opts ^. proveFile) (opts ^. proveArgs)
let traces = res ^. runNockmaTraces
forM_ traces (renderStdOutLn . ppPrint)
let provedCode = Encoding.jamToByteString (res ^. runNockmaResult)
outputFile <- getOutputFile (opts ^. proveOutputFile)
writeFileBS outputFile provedCode
where
getOutputFile :: (Member App x) => Maybe (AppPath File) -> Sem x (Path Abs File)
getOutputFile = \case
Just out -> fromAppFile out
Nothing -> do
invokeDir <- askInvokeDir
programFilePath <- fromAppFile (opts ^. proveFile)
let baseOutputFile = invokeDir <//> filename programFilePath
return (replaceExtensions' (".proved" :| [".nockma"]) baseOutputFile)
21 changes: 21 additions & 0 deletions app/Commands/Dev/Anoma/Prove/Options.hs
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
module Commands.Dev.Anoma.Prove.Options where

import CommonOptions

data ProveOptions = ProveOptions
{ _proveFile :: AppPath File,
_proveArgs :: Maybe (AppPath File),
_proveClientInfo :: Maybe (AppPath File),
_proveOutputFile :: Maybe (AppPath File)
}
deriving stock (Data)

makeLenses ''ProveOptions

parseProveOptions :: Parser ProveOptions
parseProveOptions = do
_proveFile <- parseInputFile FileExtNockma
_proveArgs <- optional anomaArgsOpt
_proveClientInfo <- optional anomaClientConfigOpt
_proveOutputFile <- optional parseGenericOutputFile
pure ProveOptions {..}
12 changes: 0 additions & 12 deletions app/Commands/Dev/Anoma/Status.hs

This file was deleted.

12 changes: 0 additions & 12 deletions app/Commands/Dev/Anoma/Stop.hs

This file was deleted.

31 changes: 8 additions & 23 deletions app/Commands/Dev/Nockma/Run/Anoma.hs
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@ module Commands.Dev.Nockma.Run.Anoma where

import Anoma.Effect
import Commands.Base hiding (Atom)
import Commands.Dev.Anoma.Base
import Juvix.Compiler.Nockma.Pretty
import Juvix.Compiler.Nockma.Translation.FromSource qualified as Nockma

data RunCommandArgs = RunCommandArgs
{ _runCommandArgsFile :: Maybe (AppPath File),
Expand All @@ -14,25 +14,10 @@ makeLenses ''RunCommandArgs

runInAnoma :: forall r. (Members '[Error SimpleError, Anoma] r, Members AppEffects r) => RunCommandArgs -> Sem r ()
runInAnoma runArgs = do
afile <- fromAppPathFile (runArgs ^. runCommandProgramFile)
argsFile <- mapM fromAppPathFile (runArgs ^. runCommandArgsFile)
parsedArgs <- runAppError @JuvixError (mapM Nockma.cueJammedFileOrPretty argsFile)
parsedTerm <- runAppError @JuvixError (Nockma.cueJammedFileOrPretty afile)
case parsedTerm of
TermAtom {} -> exitFailMsg "Expected nockma input to be a cell"
t@(TermCell {}) -> go t (maybe [] unfoldList parsedArgs)
where
go :: Term Natural -> [Term Natural] -> Sem r ()
go t args = do
res <-
runNockma
RunNockmaInput
{ _runNockmaProgram = t,
_runNockmaArgs = args
}
let traces = res ^. runNockmaTraces
renderStdOutLn (annotate AnnImportant $ "Traces (" <> show (length traces) <> "):")
forM_ traces $ \tr ->
renderStdOutLn (ppPrint tr)
renderStdOutLn (annotate AnnImportant "Result:")
renderStdOutLn (ppPrint (res ^. runNockmaResult))
res <- runNock (runArgs ^. runCommandProgramFile) (runArgs ^. runCommandArgsFile)
let traces = res ^. runNockmaTraces
renderStdOutLn (annotate AnnImportant $ "Traces (" <> show (length traces) <> "):")
forM_ traces $ \tr ->
renderStdOutLn (ppPrint tr)
renderStdOutLn (annotate AnnImportant "Result:")
renderStdOutLn (ppPrint (res ^. runNockmaResult))
13 changes: 13 additions & 0 deletions app/CommonOptions.hs
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,19 @@ anomaArgsOpt = do
)
pure AppPath {_pathIsInput = True, ..}

anomaClientConfigOpt :: Parser (AppPath File)
anomaClientConfigOpt = do
_pathPath <-
option
somePreFileOpt
( long "config"
<> short 'c'
<> metavar "CONFIG_FILE"
<> help "A path to a Anoma client configuration file"
<> action "file"
)
pure AppPath {_pathIsInput = True, ..}

parseNumThreads :: Parser NumThreads
parseNumThreads = do
option
Expand Down
6 changes: 2 additions & 4 deletions src/Anoma/Client/Config.hs
Original file line number Diff line number Diff line change
Expand Up @@ -30,10 +30,8 @@ $( deriveJSON

instance PrettyCodeAnn ClientConfig where
ppCodeAnn c =
"Anoma client info:"
<> line
-- The output of YAML encoding has a trailing newline
<> pretty (T.dropWhileEnd (== '\n') (decodeUtf8 (Y.encode c)))
-- The output of YAML encoding has a trailing newline
pretty (T.dropWhileEnd (== '\n') (decodeUtf8 (Y.encode c)))

configPath :: (Member Files r) => Sem r (Path Abs File)
configPath = (<//> clientConfigPath) <$> globalAnomaClient
Expand Down

0 comments on commit 5c3449b

Please sign in to comment.