feat(tvix/repl): Allow binding variables at the top-level
Allow binding variables at the REPL's toplevel in the same way the Nix
REPL does, using the syntax <ident> = <expr>. This fully, strictly
evaluates the value and sets it in the repl's "env", which gets passed
in at the toplevel when evaluating expressions.
The laziness behavior differs from Nix's, but I think this is good:
❯ nix repl
Welcome to Nix version 2.3.18. Type :? for help.
nix-repl> x = builtins.trace "x" 1
nix-repl> x
trace: x
1
nix-repl> x
1
vs tvix:
tvix-repl> x = builtins.trace "x" 1
trace: "x" :: string
tvix-repl> x
=> 1 :: int
tvix-repl> x
=> 1 :: int
Bug: https://b.tvl.fyi/issues/371
Change-Id: Ieb2d626b7195fa87be638c9a4dae2eee45eb9ab1
Reviewed-on: https://cl.tvl.fyi/c/depot/+/11954
Reviewed-by: flokli <flokli@flokli.de>
Tested-by: BuildkiteCI
Autosubmit: aspen <root@gws.fyi>
This commit is contained in:
parent
ac3d717944
commit
fc63594631
6 changed files with 157 additions and 16 deletions
|
|
@ -1,10 +1,13 @@
|
|||
use std::path::PathBuf;
|
||||
use std::rc::Rc;
|
||||
use std::{collections::HashMap, path::PathBuf};
|
||||
|
||||
use rustyline::{error::ReadlineError, Editor};
|
||||
use smol_str::SmolStr;
|
||||
use tvix_eval::Value;
|
||||
use tvix_glue::tvix_store_io::TvixStoreIO;
|
||||
|
||||
use crate::{interpret, AllowIncomplete, Args, IncompleteInput};
|
||||
use crate::evaluate;
|
||||
use crate::{assignment::Assignment, interpret, AllowIncomplete, Args, IncompleteInput};
|
||||
|
||||
fn state_dir() -> Option<PathBuf> {
|
||||
let mut path = dirs::data_dir();
|
||||
|
|
@ -17,6 +20,7 @@ fn state_dir() -> Option<PathBuf> {
|
|||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub enum ReplCommand<'a> {
|
||||
Expr(&'a str),
|
||||
Assign(Assignment<'a>),
|
||||
Explain(&'a str),
|
||||
Print(&'a str),
|
||||
Quit,
|
||||
|
|
@ -29,11 +33,12 @@ Welcome to the Tvix REPL!
|
|||
|
||||
The following commands are supported:
|
||||
|
||||
<expr> Evaluate a Nix language expression and print the result, along with its inferred type
|
||||
:d <expr> Evaluate a Nix language expression and print a detailed description of the result
|
||||
:p <expr> Evaluate a Nix language expression and print the result recursively
|
||||
:q Exit the REPL
|
||||
:?, :h Display this help text
|
||||
<expr> Evaluate a Nix language expression and print the result, along with its inferred type
|
||||
<x> = <expr> Bind the result of an expression to a variable
|
||||
:d <expr> Evaluate a Nix language expression and print a detailed description of the result
|
||||
:p <expr> Evaluate a Nix language expression and print the result recursively
|
||||
:q Exit the REPL
|
||||
:?, :h Display this help text
|
||||
";
|
||||
|
||||
pub fn parse(input: &'a str) -> Self {
|
||||
|
|
@ -52,6 +57,10 @@ The following commands are supported:
|
|||
}
|
||||
}
|
||||
|
||||
if let Some(assignment) = Assignment::parse(input) {
|
||||
return Self::Assign(assignment);
|
||||
}
|
||||
|
||||
Self::Expr(input)
|
||||
}
|
||||
}
|
||||
|
|
@ -61,6 +70,8 @@ pub struct Repl {
|
|||
/// In-progress multiline input, when the input so far doesn't parse as a complete expression
|
||||
multiline_input: Option<String>,
|
||||
rl: Editor<()>,
|
||||
/// Local variables defined at the top-level in the repl
|
||||
env: HashMap<SmolStr, Value>,
|
||||
}
|
||||
|
||||
impl Repl {
|
||||
|
|
@ -69,6 +80,7 @@ impl Repl {
|
|||
Self {
|
||||
multiline_input: None,
|
||||
rl,
|
||||
env: HashMap::new(),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -125,7 +137,25 @@ impl Repl {
|
|||
args,
|
||||
false,
|
||||
AllowIncomplete::Allow,
|
||||
Some(&self.env),
|
||||
),
|
||||
ReplCommand::Assign(Assignment { ident, value }) => {
|
||||
match evaluate(
|
||||
Rc::clone(&io_handle),
|
||||
&value.to_string(), /* FIXME: don't re-parse */
|
||||
None,
|
||||
args,
|
||||
AllowIncomplete::Allow,
|
||||
Some(&self.env),
|
||||
) {
|
||||
Ok(Some(value)) => {
|
||||
self.env.insert(ident.into(), value);
|
||||
Ok(true)
|
||||
}
|
||||
Ok(None) => Ok(true),
|
||||
Err(incomplete) => Err(incomplete),
|
||||
}
|
||||
}
|
||||
ReplCommand::Explain(input) => interpret(
|
||||
Rc::clone(&io_handle),
|
||||
input,
|
||||
|
|
@ -133,6 +163,7 @@ impl Repl {
|
|||
args,
|
||||
true,
|
||||
AllowIncomplete::Allow,
|
||||
Some(&self.env),
|
||||
),
|
||||
ReplCommand::Print(input) => interpret(
|
||||
Rc::clone(&io_handle),
|
||||
|
|
@ -144,6 +175,7 @@ impl Repl {
|
|||
},
|
||||
false,
|
||||
AllowIncomplete::Allow,
|
||||
Some(&self.env),
|
||||
),
|
||||
};
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue