diff options
-rw-r--r-- | tvix/eval/Cargo.lock | 108 | ||||
-rw-r--r-- | tvix/eval/Cargo.toml | 3 | ||||
-rw-r--r-- | tvix/eval/benches/eval.rs | 14 | ||||
-rw-r--r-- | tvix/eval/src/eval.rs | 25 | ||||
-rw-r--r-- | tvix/eval/src/lib.rs | 2 | ||||
-rw-r--r-- | tvix/eval/src/main.rs | 33 | ||||
-rw-r--r-- | tvix/eval/src/tests/mod.rs | 6 | ||||
-rw-r--r-- | tvix/eval/tests/nix_oracle.rs | 4 |
8 files changed, 167 insertions, 28 deletions
diff --git a/tvix/eval/Cargo.lock b/tvix/eval/Cargo.lock index 2804e7f1298f..71c6525b0a41 100644 --- a/tvix/eval/Cargo.lock +++ b/tvix/eval/Cargo.lock @@ -74,11 +74,50 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a0610544180c38b88101fecf2dd634b174a62eef6946f84dfc6a7127512b381c" dependencies = [ "bitflags", - "textwrap", + "textwrap 0.11.0", "unicode-width", ] [[package]] +name = "clap" +version = "3.2.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "86447ad904c7fb335a790c9d7fe3d0d971dc523b8ccd1561a520de9a85302750" +dependencies = [ + "atty", + "bitflags", + "clap_derive", + "clap_lex", + "indexmap", + "once_cell", + "strsim", + "termcolor", + "textwrap 0.15.1", +] + +[[package]] +name = "clap_derive" +version = "3.2.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ea0c8bce528c4be4da13ea6fead8965e95b6073585a2f05204bd8f4119f82a65" +dependencies = [ + "heck", + "proc-macro-error", + "proc-macro2 1.0.43", + "quote 1.0.21", + "syn 1.0.99", +] + +[[package]] +name = "clap_lex" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2850f2f5a82cbf437dd5af4d49848fbdfc27c157c3d010345776f952765261c5" +dependencies = [ + "os_str_bytes", +] + +[[package]] name = "clipboard-win" version = "4.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -120,7 +159,7 @@ checksum = "b01d6de93b2b6c65e17c634a26653a29d107b3c98c607c765bf38d041531cd8f" dependencies = [ "atty", "cast", - "clap", + "clap 2.34.0", "criterion-plot", "csv", "itertools", @@ -371,6 +410,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" [[package]] +name = "heck" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2540771e65fc8cb83cd6e8a237f70c319bd5c29f78ed1084ba5d50eeac86f7f9" + +[[package]] name = "hermit-abi" version = "0.1.19" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -380,6 +425,16 @@ dependencies = [ ] [[package]] +name = "indexmap" +version = "1.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "10a35a97730320ffe8e2d410b5d3b69279b98d2c14bdb8b70ea89ecf7888d41e" +dependencies = [ + "autocfg", + "hashbrown", +] + +[[package]] name = "instant" version = "0.1.12" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -518,6 +573,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0ab1bc2a289d34bd04a330323ac98a1b4bc82c9d9fcb1e66b63caa84da26b575" [[package]] +name = "os_str_bytes" +version = "6.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ff7415e9ae3fff1225851df9e0d9e4e5479f947619774677a63572e55e80eff" + +[[package]] name = "output_vt100" version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -579,6 +640,30 @@ dependencies = [ ] [[package]] +name = "proc-macro-error" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c" +dependencies = [ + "proc-macro-error-attr", + "proc-macro2 1.0.43", + "quote 1.0.21", + "syn 1.0.99", + "version_check", +] + +[[package]] +name = "proc-macro-error-attr" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869" +dependencies = [ + "proc-macro2 1.0.43", + "quote 1.0.21", + "version_check", +] + +[[package]] name = "proc-macro2" version = "0.4.30" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -943,6 +1028,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9e08d8363704e6c71fc928674353e6b7c23dcea9d82d7012c8faf2a3a025f8d0" [[package]] +name = "strsim" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" + +[[package]] name = "structmeta" version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -1069,6 +1160,12 @@ dependencies = [ ] [[package]] +name = "textwrap" +version = "0.15.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "949517c0cf1bf4ee812e2e07e08ab448e3ae0d23472aee8a06c985f0c8815b16" + +[[package]] name = "thiserror" version = "1.0.35" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -1102,6 +1199,7 @@ dependencies = [ name = "tvix-eval" version = "0.1.0" dependencies = [ + "clap 3.2.22", "codemap", "codemap-diagnostic", "criterion", @@ -1151,6 +1249,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "936e4b492acfd135421d8dca4b1aa80a7bfc26e702ef3af710e0752684df5372" [[package]] +name = "version_check" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" + +[[package]] name = "walkdir" version = "2.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" diff --git a/tvix/eval/Cargo.toml b/tvix/eval/Cargo.toml index 1c56f3171645..bf34159656aa 100644 --- a/tvix/eval/Cargo.toml +++ b/tvix/eval/Cargo.toml @@ -23,6 +23,7 @@ codemap = "0.1.3" codemap-diagnostic = "0.1.1" proptest = { version = "1.0.0", default_features = false, features = ["std", "alloc", "break-dead-code", "tempfile"], optional = true } test-strategy = { version = "0.2.1", optional = true } +clap = { version = "3.2.22", optional = true, features = ["derive", "env"] } # rnix has not been released in a while (as of 2022-09-18), we will # use it from git. @@ -45,7 +46,7 @@ default = [ "repl", "arbitrary" ] nix_tests = [] # Enables building the binary (tvix-eval REPL) -repl = [ "dep:rustyline" ] +repl = [ "dep:rustyline", "dep:clap" ] # Enables Arbitrary impls for internal types (required to run tests) arbitrary = [ "proptest", "test-strategy" ] diff --git a/tvix/eval/benches/eval.rs b/tvix/eval/benches/eval.rs index 9be381e0f803..3e4da75936d0 100644 --- a/tvix/eval/benches/eval.rs +++ b/tvix/eval/benches/eval.rs @@ -3,12 +3,20 @@ use itertools::Itertools; use tvix_eval::interpret; fn eval_literals(c: &mut Criterion) { - c.bench_function("int", |b| b.iter(|| black_box(interpret("42", None)))); + c.bench_function("int", |b| { + b.iter(|| black_box(interpret("42", None, Default::default()))) + }); } fn eval_merge_attrs(c: &mut Criterion) { c.bench_function("merge small attrs", |b| { - b.iter(|| black_box(interpret("{ a = 1; b = 2; } // { c = 3; }", None))) + b.iter(|| { + black_box(interpret( + "{ a = 1; b = 2; } // { c = 3; }", + None, + Default::default(), + )) + }) }); c.bench_function("merge large attrs with small attrs", |b| { @@ -17,7 +25,7 @@ fn eval_merge_attrs(c: &mut Criterion) { (0..10000).map(|n| format!("a{n} = {n};")).join(" ") ); let expr = format!("{large_attrs} // {{ c = 3; }}"); - b.iter(move || black_box(interpret(&expr, None))) + b.iter(move || black_box(interpret(&expr, None, Default::default()))) }); } diff --git a/tvix/eval/src/eval.rs b/tvix/eval/src/eval.rs index 6510ef0afb2b..21591802a443 100644 --- a/tvix/eval/src/eval.rs +++ b/tvix/eval/src/eval.rs @@ -7,7 +7,24 @@ use crate::{ value::Value, }; -pub fn interpret(code: &str, location: Option<PathBuf>) -> EvalResult<Value> { +/// Runtime options for the Tvix interpreter +#[derive(Debug, Clone, Copy, Default)] +#[cfg_attr(feature = "repl", derive(clap::Parser))] +pub struct Options { + /// Dump the raw AST to stdout before interpreting + #[cfg_attr(feature = "repl", clap(long, env = "TVIX_DISPLAY_AST"))] + display_ast: bool, + + /// Dump the bytecode to stdout before evaluating + #[cfg_attr(feature = "repl", clap(long, env = "TVIX_DUMP_BYTECODE"))] + dump_bytecode: bool, + + /// Trace the runtime of the VM + #[cfg_attr(feature = "repl", clap(long, env = "TVIX_TRACE_RUNTIME"))] + trace_runtime: bool, +} + +pub fn interpret(code: &str, location: Option<PathBuf>, options: Options) -> EvalResult<Value> { let mut codemap = codemap::CodeMap::new(); let file = codemap.add_file( location @@ -37,11 +54,11 @@ pub fn interpret(code: &str, location: Option<PathBuf>) -> EvalResult<Value> { .expr() .expect("expression should exist if no errors occured"); - if std::env::var("TVIX_DISPLAY_AST").is_ok() { + if options.display_ast { println!("{:?}", root_expr); } - let result = if std::env::var("TVIX_DUMP_BYTECODE").is_ok() { + let result = if options.dump_bytecode { crate::compiler::compile( root_expr, location, @@ -76,7 +93,7 @@ pub fn interpret(code: &str, location: Option<PathBuf>) -> EvalResult<Value> { return Err(err.clone()); } - if std::env::var("TVIX_TRACE_RUNTIME").is_ok() { + if options.trace_runtime { crate::vm::run_lambda(&mut TracingObserver::new(std::io::stderr()), result.lambda) } else { crate::vm::run_lambda(&mut NoOpObserver::default(), result.lambda) diff --git a/tvix/eval/src/lib.rs b/tvix/eval/src/lib.rs index 1c3fea3d5b9f..d7255af14e68 100644 --- a/tvix/eval/src/lib.rs +++ b/tvix/eval/src/lib.rs @@ -21,6 +21,6 @@ mod tests; pub use crate::builtins::global_builtins; pub use crate::compiler::compile; pub use crate::errors::EvalResult; -pub use crate::eval::interpret; +pub use crate::eval::{interpret, Options}; pub use crate::value::Value; pub use crate::vm::run_lambda; diff --git a/tvix/eval/src/main.rs b/tvix/eval/src/main.rs index 177d4f2ec8e6..351554c2d538 100644 --- a/tvix/eval/src/main.rs +++ b/tvix/eval/src/main.rs @@ -1,30 +1,35 @@ use std::{ - env, fs, + fs, path::{Path, PathBuf}, - process, }; +use clap::Parser; use rustyline::{error::ReadlineError, Editor}; +#[derive(Parser)] +struct Args { + /// Path to a script to evaluate + script: Option<PathBuf>, + + #[clap(flatten)] + eval_options: tvix_eval::Options, +} + fn main() { - let mut args = env::args(); - if args.len() > 2 { - println!("Usage: tvix-eval [script]"); - process::exit(1); - } + let args = Args::parse(); - if let Some(file) = args.nth(1) { - run_file(&file); + if let Some(file) = &args.script { + run_file(file, args.eval_options) } else { - run_prompt(); + run_prompt(args.eval_options) } } -fn run_file(file: &str) { +fn run_file(file: &Path, eval_options: tvix_eval::Options) { let contents = fs::read_to_string(file).expect("failed to read the input file"); let path = Path::new(file).to_owned(); - match tvix_eval::interpret(&contents, Some(path)) { + match tvix_eval::interpret(&contents, Some(path), eval_options) { Ok(result) => println!("=> {} :: {}", result, result.type_of()), Err(err) => eprintln!("{}", err), } @@ -38,7 +43,7 @@ fn state_dir() -> Option<PathBuf> { path } -fn run_prompt() { +fn run_prompt(eval_options: tvix_eval::Options) { let mut rl = Editor::<()>::new().expect("should be able to launch rustyline"); let history_path = match state_dir() { @@ -63,7 +68,7 @@ fn run_prompt() { } rl.add_history_entry(&line); - match tvix_eval::interpret(&line, None) { + match tvix_eval::interpret(&line, None, eval_options) { Ok(result) => { println!("=> {} :: {}", result, result.type_of()); } diff --git a/tvix/eval/src/tests/mod.rs b/tvix/eval/src/tests/mod.rs index ec9ee0d1c9ea..49ca35973e56 100644 --- a/tvix/eval/src/tests/mod.rs +++ b/tvix/eval/src/tests/mod.rs @@ -12,7 +12,8 @@ fn eval_okay_test(code_path: &str) { let code = std::fs::read_to_string(code_path).expect("should be able to read test code"); let exp = std::fs::read_to_string(exp_path).expect("should be able to read test expectation"); - let result = interpret(&code, None).expect("evaluation of eval-okay test should succeed"); + let result = interpret(&code, None, Default::default()) + .expect("evaluation of eval-okay test should succeed"); let result_str = format!("{}", result); assert_eq!( @@ -28,7 +29,8 @@ fn eval_okay_test(code_path: &str) { fn identity(code_path: &str) { let code = std::fs::read_to_string(code_path).expect("should be able to read test code"); - let result = interpret(&code, None).expect("evaluation of identity test should succeed"); + let result = interpret(&code, None, Default::default()) + .expect("evaluation of identity test should succeed"); let result_str = format!("{}", result); assert_eq!( diff --git a/tvix/eval/tests/nix_oracle.rs b/tvix/eval/tests/nix_oracle.rs index 1091d6adf0ee..61f2be674e27 100644 --- a/tvix/eval/tests/nix_oracle.rs +++ b/tvix/eval/tests/nix_oracle.rs @@ -40,7 +40,9 @@ fn nix_eval(expr: &str) -> String { #[track_caller] fn compare_eval(expr: &str) { let nix_result = nix_eval(expr); - let tvix_result = tvix_eval::interpret(expr, None).unwrap().to_string(); + let tvix_result = tvix_eval::interpret(expr, None, Default::default()) + .unwrap() + .to_string(); assert_eq!(nix_result.trim(), tvix_result); } |