about summary refs log tree commit diff
path: root/tvix
diff options
context:
space:
mode:
Diffstat (limited to 'tvix')
-rw-r--r--tvix/eval/Cargo.lock108
-rw-r--r--tvix/eval/Cargo.toml3
-rw-r--r--tvix/eval/benches/eval.rs14
-rw-r--r--tvix/eval/src/eval.rs25
-rw-r--r--tvix/eval/src/lib.rs2
-rw-r--r--tvix/eval/src/main.rs33
-rw-r--r--tvix/eval/src/tests/mod.rs6
-rw-r--r--tvix/eval/tests/nix_oracle.rs4
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);
 }