-
Notifications
You must be signed in to change notification settings - Fork 57
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
This PR adds an parser, pretty printer, evaluator, repl and quasi-quoter for Nock terms. ## Parser / Pretty Printer The parser and pretty printer handle both standard Nock terms and 'pretty' Nock terms (where op codes and paths can be named). Standard and pretty Nock forms can be mixed in the same term. For example instead of `[0 2]` you can write `[@ L]`. See https://github.com/anoma/juvix/blob/a6028b0d92e2dff02329ab7f441bf48ccdeb3eb3/src/Juvix/Compiler/Nockma/Language.hs#L79 for the correspondence between pretty Nock and Nock operators. In pretty Nock, paths are represented as strings of `L` (for head) and `R` (for tail) instead of the number encoding in standard nock. The character `S` is used to refer to the whole subject, i.e it is sugar for `1` in standard Nock. See https://github.com/anoma/juvix/blob/a6028b0d92e2dff02329ab7f441bf48ccdeb3eb3/src/Juvix/Compiler/Nockma/Language.hs#L177 for the correspondence between pretty Nock path and standard Nock position. ## Quasi-quoter A quasi-quoter is added so Nock terms can be included in the source, e.g `[nock| [@ LL] |]`. ## REPL Launch the repl with `juvix dev nockma repl`. A Nock `[subject formula]` cell is input as `subject / formula` , e.g: ``` nockma> [1 0] / [@ L] 1 ``` The subject can be set using `:set-stack`. ``` nockma> :set-stack [1 0] nockma> [@ L] 1 ``` The subject can be viewed using `:get-stack`. ``` nockma> :set-stack [1 0] nockma> :get-stack [1 0] ``` You can assign a Nock term to a variable and use it in another expression: ``` nockma> r := [@ L] nockma> [1 0] / r 1 ``` A list of assignments can be read from a file: ``` $ cat stack.nock r := [@ L] $ juvix dev nockma repl nockma> :load stack.nock nockma> [1 0] / r 1 ``` * Closes #2557 --------- Co-authored-by: Jan Mas Rovira <[email protected]> Co-authored-by: Lukasz Czajka <[email protected]>
- Loading branch information
1 parent
8e5f45f
commit a9995b8
Showing
40 changed files
with
1,890 additions
and
15 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
module Commands.Dev.Nockma where | ||
|
||
import Commands.Base | ||
import Commands.Dev.Nockma.Options | ||
import Commands.Dev.Nockma.Repl as Repl | ||
|
||
runCommand :: forall r. (Members '[Embed IO, App] r) => NockmaCommand -> Sem r () | ||
runCommand = \case | ||
NockmaRepl opts -> Repl.runCommand opts |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
module Commands.Dev.Nockma.Options where | ||
|
||
import Commands.Dev.Nockma.Repl.Options | ||
import CommonOptions | ||
|
||
data NockmaCommand | ||
= NockmaRepl NockmaReplOptions | ||
deriving stock (Data) | ||
|
||
parseNockmaCommand :: Parser NockmaCommand | ||
parseNockmaCommand = hsubparser commandRepl | ||
where | ||
commandRepl :: Mod CommandFields NockmaCommand | ||
commandRepl = command "repl" replInfo | ||
|
||
replInfo :: ParserInfo NockmaCommand | ||
replInfo = | ||
info | ||
(NockmaRepl <$> parseNockmaReplOptions) | ||
(progDesc "Run the nockma repl") |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,177 @@ | ||
{-# LANGUAGE QuasiQuotes #-} | ||
|
||
module Commands.Dev.Nockma.Repl where | ||
|
||
import Commands.Base hiding (Atom) | ||
import Commands.Dev.Nockma.Repl.Options | ||
import Control.Exception (throwIO) | ||
import Control.Monad.State.Strict qualified as State | ||
import Data.String.Interpolate (__i) | ||
import Juvix.Compiler.Nockma.Evaluator (NockEvalError, evalRepl, fromReplTerm, programAssignments) | ||
import Juvix.Compiler.Nockma.Language | ||
import Juvix.Compiler.Nockma.Pretty (ppPrint) | ||
import Juvix.Compiler.Nockma.Translation.FromSource (parseProgramFile, parseReplStatement, parseReplText, parseText) | ||
import Juvix.Parser.Error | ||
import Juvix.Prelude.Pretty | ||
import System.Console.Haskeline | ||
import System.Console.Repline qualified as Repline | ||
import Prelude (read) | ||
|
||
type ReplS = State.StateT ReplState IO | ||
|
||
data ReplState = ReplState | ||
{ _replStateProgram :: Maybe (Program Natural), | ||
_replStateStack :: Maybe (Term Natural), | ||
_replStateLoadedFile :: Maybe (FilePath) | ||
} | ||
|
||
type Repl a = Repline.HaskelineT ReplS a | ||
|
||
makeLenses ''ReplState | ||
|
||
printHelpTxt :: Repl () | ||
printHelpTxt = liftIO $ putStrLn helpTxt | ||
where | ||
helpTxt :: Text = | ||
[__i| | ||
EXPRESSION Evaluate a Nockma expression in the context of the current stack | ||
STACK_EXPRESSION / EXPRESSION Evaluate a Nockma EXPRESSION in the context of STACK_EXPRESSION | ||
:load FILE Load a file containing Nockma assignments | ||
:reload Reload the current file | ||
:help Print help text and describe options | ||
:set-stack EXPRESSION Set the current stack | ||
:get-stack Print the current stack | ||
:dir NATURAL Convert a natural number representing a position into a sequence of L and Rs. S means the empty sequence | ||
:quit Exit the REPL | ||
|] | ||
|
||
quit :: String -> Repl () | ||
quit _ = liftIO (throwIO Interrupt) | ||
|
||
printStack :: String -> Repl () | ||
printStack _ = Repline.dontCrash $ do | ||
stack <- getStack | ||
case stack of | ||
Nothing -> noStackErr | ||
Just s -> liftIO (putStrLn (ppPrint s)) | ||
|
||
noStackErr :: a | ||
noStackErr = error "no stack is set. Use :set-stack <TERM> to set a stack." | ||
|
||
setStack :: String -> Repl () | ||
setStack s = Repline.dontCrash $ do | ||
newStack <- readReplTerm s | ||
State.modify (set replStateStack (Just newStack)) | ||
|
||
loadFile :: String -> Repl () | ||
loadFile s = Repline.dontCrash $ do | ||
State.modify (set replStateLoadedFile (Just s)) | ||
prog <- readProgram s | ||
State.modify (set replStateProgram (Just prog)) | ||
|
||
reloadFile :: Repl () | ||
reloadFile = Repline.dontCrash $ do | ||
fp <- State.gets (^. replStateLoadedFile) | ||
case fp of | ||
Nothing -> error "no file loaded" | ||
Just f -> do | ||
prog <- readProgram f | ||
State.modify (set replStateProgram (Just prog)) | ||
|
||
options :: [(String, String -> Repl ())] | ||
options = | ||
[ ("quit", quit), | ||
("get-stack", printStack), | ||
("set-stack", setStack), | ||
("load", loadFile), | ||
("reload", const reloadFile), | ||
("dir", direction') | ||
] | ||
|
||
banner :: Repline.MultiLine -> Repl String | ||
banner = \case | ||
Repline.MultiLine -> return "... " | ||
Repline.SingleLine -> return "nockma> " | ||
|
||
getStack :: Repl (Maybe (Term Natural)) | ||
getStack = State.gets (^. replStateStack) | ||
|
||
getProgram :: Repl (Maybe (Program Natural)) | ||
getProgram = State.gets (^. replStateProgram) | ||
|
||
readProgram :: FilePath -> Repl (Program Natural) | ||
readProgram s = fromMegaParsecError <$> parseProgramFile s | ||
|
||
fromMegaParsecError :: Either MegaparsecError a -> a | ||
fromMegaParsecError = \case | ||
Left e -> error (prettyText e) | ||
Right a -> a | ||
|
||
direction' :: String -> Repl () | ||
direction' s = Repline.dontCrash $ do | ||
let n = read s :: Natural | ||
p = run (runFailDefault (error "invalid position") (decodePath (EncodedPath n))) | ||
liftIO (putStrLn (ppPrint p)) | ||
|
||
readTerm :: String -> Repl (Term Natural) | ||
readTerm s = return (fromMegaParsecError (parseText (strip (pack s)))) | ||
|
||
readReplTerm :: String -> Repl (Term Natural) | ||
readReplTerm s = do | ||
mprog <- getProgram | ||
let t = run $ runError @NockEvalError (fromReplTerm (programAssignments mprog) (fromMegaParsecError (parseReplText (strip (pack s))))) | ||
case t of | ||
Left e -> error (show e) | ||
Right tv -> return tv | ||
|
||
readStatement :: String -> Repl (ReplStatement Natural) | ||
readStatement s = return (fromMegaParsecError (parseReplStatement (strip (pack s)))) | ||
|
||
evalStatement :: ReplStatement Natural -> Repl () | ||
evalStatement = \case | ||
ReplStatementAssignment as -> do | ||
prog <- fromMaybe (Program []) <$> getProgram | ||
let p' = over programStatements (++ [StatementAssignment as]) prog | ||
State.modify (set replStateProgram (Just p')) | ||
ReplStatementExpression t -> do | ||
s <- getStack | ||
prog <- getProgram | ||
let et = | ||
run | ||
. runError @(ErrNockNatural Natural) | ||
. runError @NockEvalError | ||
$ evalRepl prog s t | ||
case et of | ||
Left e -> error (show e) | ||
Right ev -> case ev of | ||
Left e -> error (show e) | ||
Right res -> liftIO (putStrLn (ppPrint res)) | ||
|
||
replCommand :: String -> Repl () | ||
replCommand input = Repline.dontCrash $ do | ||
readStatement input >>= evalStatement | ||
|
||
replAction :: ReplS () | ||
replAction = | ||
Repline.evalReplOpts | ||
Repline.ReplOpts | ||
{ prefix = Just ':', | ||
command = replCommand, | ||
initialiser = return (), | ||
finaliser = return Repline.Exit, | ||
multilineCommand = Just "multiline", | ||
tabComplete = Repline.Word (\_ -> return []), | ||
options, | ||
banner | ||
} | ||
|
||
runCommand :: forall r. (Members '[Embed IO, App] r) => NockmaReplOptions -> Sem r () | ||
runCommand _ = embed . (`State.evalStateT` iniState) $ replAction | ||
where | ||
iniState :: ReplState | ||
iniState = | ||
ReplState | ||
{ _replStateStack = Nothing, | ||
_replStateProgram = Nothing, | ||
_replStateLoadedFile = Nothing | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
module Commands.Dev.Nockma.Repl.Options where | ||
|
||
import CommonOptions | ||
|
||
newtype NockmaReplOptions = NockmaReplOptions | ||
{ _nockmaReplOptionsStackFile :: Maybe (AppPath File) | ||
} | ||
deriving stock (Data) | ||
|
||
parseNockmaReplOptions :: Parser NockmaReplOptions | ||
parseNockmaReplOptions = do | ||
_nockmaReplOptionsStackFile <- optional (parseInputFile FileExtNock) | ||
pure NockmaReplOptions {..} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.