about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--tvix/Cargo.lock12
-rw-r--r--tvix/Cargo.nix60
-rw-r--r--tvix/Cargo.toml1
-rw-r--r--tvix/cli/Cargo.toml10
-rw-r--r--tvix/cli/default.nix5
-rw-r--r--tvix/cli/src/main.rs (renamed from tvix/eval/src/main.rs)57
-rw-r--r--tvix/eval/Cargo.toml11
-rw-r--r--tvix/eval/src/eval.rs145
-rw-r--r--tvix/eval/src/lib.rs2
9 files changed, 105 insertions, 198 deletions
diff --git a/tvix/Cargo.lock b/tvix/Cargo.lock
index 4e2197a90c3f..7dcf6c78f87e 100644
--- a/tvix/Cargo.lock
+++ b/tvix/Cargo.lock
@@ -1488,11 +1488,20 @@ dependencies = [
 ]
 
 [[package]]
+name = "tvix-cli"
+version = "0.1.0"
+dependencies = [
+ "clap 3.2.23",
+ "dirs",
+ "rustyline",
+ "tvix-eval",
+]
+
+[[package]]
 name = "tvix-eval"
 version = "0.1.0"
 dependencies = [
  "backtrace-on-stack-overflow",
- "clap 3.2.23",
  "codemap",
  "codemap-diagnostic",
  "criterion",
@@ -1504,7 +1513,6 @@ dependencies = [
  "regex",
  "rnix",
  "rowan",
- "rustyline",
  "serde",
  "serde_json",
  "smol_str",
diff --git a/tvix/Cargo.nix b/tvix/Cargo.nix
index 075ca7219f4c..599da8108557 100644
--- a/tvix/Cargo.nix
+++ b/tvix/Cargo.nix
@@ -47,6 +47,16 @@ rec {
       # File a bug if you depend on any for non-debug work!
       debug = internal.debugCrate { inherit packageId; };
     };
+    "tvix-cli" = rec {
+      packageId = "tvix-cli";
+      build = internal.buildRustCrateWithFeatures {
+        packageId = "tvix-cli";
+      };
+
+      # Debug support which might change between releases.
+      # File a bug if you depend on any for non-debug work!
+      debug = internal.debugCrate { inherit packageId; };
+    };
     "tvix-eval" = rec {
       packageId = "tvix-eval";
       build = internal.buildRustCrateWithFeatures {
@@ -4176,13 +4186,39 @@ rec {
         ];
 
       };
-      "tvix-eval" = rec {
-        crateName = "tvix-eval";
+      "tvix-cli" = rec {
+        crateName = "tvix-cli";
         version = "0.1.0";
         edition = "2021";
         crateBin = [
-          { name = "tvix-eval"; path = "src/main.rs"; }
+          { name = "tvix-cli"; path = "src/main.rs"; }
         ];
+        src = lib.cleanSourceWith { filter = sourceFilter; src = ./cli; };
+        dependencies = [
+          {
+            name = "clap";
+            packageId = "clap 3.2.23";
+            features = [ "derive" "env" ];
+          }
+          {
+            name = "dirs";
+            packageId = "dirs";
+          }
+          {
+            name = "rustyline";
+            packageId = "rustyline";
+          }
+          {
+            name = "tvix-eval";
+            packageId = "tvix-eval";
+          }
+        ];
+
+      };
+      "tvix-eval" = rec {
+        crateName = "tvix-eval";
+        version = "0.1.0";
+        edition = "2021";
         src = lib.cleanSourceWith { filter = sourceFilter; src = ./eval; };
         libName = "tvix_eval";
         dependencies = [
@@ -4192,12 +4228,6 @@ rec {
             optional = true;
           }
           {
-            name = "clap";
-            packageId = "clap 3.2.23";
-            optional = true;
-            features = [ "derive" "env" ];
-          }
-          {
             name = "codemap";
             packageId = "codemap";
           }
@@ -4233,11 +4263,6 @@ rec {
             packageId = "rowan";
           }
           {
-            name = "rustyline";
-            packageId = "rustyline";
-            optional = true;
-          }
-          {
             name = "serde";
             packageId = "serde";
           }
@@ -4290,14 +4315,11 @@ rec {
           "arbitrary" = [ "proptest" "test-strategy" ];
           "backtrace-on-stack-overflow" = [ "dep:backtrace-on-stack-overflow" ];
           "backtrace_overflow" = [ "backtrace-on-stack-overflow" ];
-          "clap" = [ "dep:clap" ];
-          "default" = [ "repl" "impure" "arbitrary" "nix_tests" "backtrace_overflow" ];
+          "default" = [ "impure" "arbitrary" "nix_tests" "backtrace_overflow" ];
           "proptest" = [ "dep:proptest" ];
-          "repl" = [ "rustyline" "clap" ];
-          "rustyline" = [ "dep:rustyline" ];
           "test-strategy" = [ "dep:test-strategy" ];
         };
-        resolvedDefaultFeatures = [ "arbitrary" "backtrace-on-stack-overflow" "backtrace_overflow" "clap" "default" "impure" "nix_tests" "proptest" "repl" "rustyline" "test-strategy" ];
+        resolvedDefaultFeatures = [ "arbitrary" "backtrace-on-stack-overflow" "backtrace_overflow" "default" "impure" "nix_tests" "proptest" "test-strategy" ];
       };
       "tvix-eval-builtin-macros" = rec {
         crateName = "tvix-eval-builtin-macros";
diff --git a/tvix/Cargo.toml b/tvix/Cargo.toml
index 4cc70f9040a6..178802dd56ee 100644
--- a/tvix/Cargo.toml
+++ b/tvix/Cargo.toml
@@ -18,6 +18,7 @@
 [workspace]
 
 members = [
+  "cli",
   "eval",
   "eval/builtin-macros",
   "nix_cli",
diff --git a/tvix/cli/Cargo.toml b/tvix/cli/Cargo.toml
new file mode 100644
index 000000000000..605b2c80651d
--- /dev/null
+++ b/tvix/cli/Cargo.toml
@@ -0,0 +1,10 @@
+[package]
+name = "tvix-cli"
+version = "0.1.0"
+edition = "2021"
+
+[dependencies]
+tvix-eval = { path = "../eval" }
+rustyline = "10.0.0"
+clap = { version = "3.2.22", features = ["derive", "env"] }
+dirs = "4.0.0"
diff --git a/tvix/cli/default.nix b/tvix/cli/default.nix
new file mode 100644
index 000000000000..7cb91979fd62
--- /dev/null
+++ b/tvix/cli/default.nix
@@ -0,0 +1,5 @@
+{ depot, pkgs, lib, ... }:
+
+depot.tvix.crates.workspaceMembers.tvix-cli.build.override {
+  runTests = true;
+}
diff --git a/tvix/eval/src/main.rs b/tvix/cli/src/main.rs
index bef48d07a0c4..1c148cad3873 100644
--- a/tvix/eval/src/main.rs
+++ b/tvix/cli/src/main.rs
@@ -2,7 +2,7 @@ use std::{fs, path::PathBuf};
 
 use clap::Parser;
 use rustyline::{error::ReadlineError, Editor};
-use tvix_eval::Value;
+use tvix_eval::Value; //{Error, EvalWarning, Evaluation, Value};
 
 #[derive(Parser)]
 struct Args {
@@ -11,35 +11,57 @@ struct Args {
 
     #[clap(long, short = 'E')]
     expr: Option<String>,
+    // TODO: port these options here directly
+    // #[clap(flatten)]
+    // eval_options: tvix_eval::Options,
+}
+
+/// Interprets the given code snippet, printing out warnings, errors
+/// and the result itself. The return value indicates whether
+/// evaluation succeeded.
+fn interpret(code: &str, path: Option<PathBuf>) -> bool {
+    let mut eval = tvix_eval::Evaluation::new(code, path);
+    let result = eval.evaluate();
+
+    let source_map = eval.source_map();
+    for error in &result.errors {
+        error.fancy_format_stderr(&source_map);
+    }
+
+    for warning in &result.warnings {
+        warning.fancy_format_stderr(&source_map);
+    }
+
+    if let Some(value) = result.value.as_ref() {
+        println_result(value, /* TODO raw = */ false);
+    }
 
-    #[clap(flatten)]
-    eval_options: tvix_eval::Options,
+    // inform the caller about any errors
+    result.errors.is_empty()
 }
 
 fn main() {
     let args = Args::parse();
 
     if let Some(file) = args.script {
-        run_file(file, args.eval_options)
+        run_file(file /* TODO, args.eval_options*/)
     } else if let Some(expr) = args.expr {
-        let raw = args.eval_options.raw;
-        if let Ok(result) = tvix_eval::interpret(&expr, None, args.eval_options) {
-            println_result(&result, raw);
+        if !interpret(&expr, None) {
+            std::process::exit(1);
         }
     } else {
-        run_prompt(args.eval_options)
+        run_prompt(/* TODO args.eval_options */)
     }
 }
 
-fn run_file(mut path: PathBuf, eval_options: tvix_eval::Options) {
+fn run_file(mut path: PathBuf /* TODO: , eval_options: tvix_eval::Options */) {
     if path.is_dir() {
         path.push("default.nix");
     }
     let contents = fs::read_to_string(&path).expect("failed to read the input file");
-    let raw = eval_options.raw;
-    match tvix_eval::interpret(&contents, Some(path), eval_options) {
-        Ok(result) => println_result(&result, raw),
-        Err(err) => eprintln!("{}", err),
+
+    if !interpret(&contents, Some(path)) {
+        std::process::exit(1);
     }
 }
 
@@ -59,7 +81,7 @@ fn state_dir() -> Option<PathBuf> {
     path
 }
 
-fn run_prompt(eval_options: tvix_eval::Options) {
+fn run_prompt(/* TODO eval_options: tvix_eval::Options */) {
     let mut rl = Editor::<()>::new().expect("should be able to launch rustyline");
 
     let history_path = match state_dir() {
@@ -84,12 +106,7 @@ fn run_prompt(eval_options: tvix_eval::Options) {
                 }
 
                 rl.add_history_entry(&line);
-                match tvix_eval::interpret(&line, None, eval_options.clone()) {
-                    Ok(result) => {
-                        println!("=> {} :: {}", result, result.type_of());
-                    }
-                    Err(_) => { /* interpret takes care of error formatting */ }
-                }
+                interpret(&line, None);
             }
             Err(ReadlineError::Interrupted) | Err(ReadlineError::Eof) => break,
 
diff --git a/tvix/eval/Cargo.toml b/tvix/eval/Cargo.toml
index 1b24f6401343..e4282507d7ec 100644
--- a/tvix/eval/Cargo.toml
+++ b/tvix/eval/Cargo.toml
@@ -8,13 +8,8 @@ edition = "2021"
 [lib]
 name = "tvix_eval"
 
-[[bin]]
-name = "tvix-eval"
-required-features = [ "repl" ]
-
 [dependencies]
 smol_str = "0.1"
-rustyline = { version = "10.0.0", optional = true }
 dirs = "4.0.0"
 path-clean = "0.1"
 tabwriter = "1.2"
@@ -23,7 +18,6 @@ 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"] }
 serde = "1.0"
 serde_json = "1.0"
 regex = "1.6.0"
@@ -39,15 +33,12 @@ itertools = "0.10.3"
 tempdir = "0.3.7"
 
 [features]
-default = [ "repl", "impure", "arbitrary", "nix_tests", "backtrace_overflow" ]
+default = [ "impure", "arbitrary", "nix_tests", "backtrace_overflow" ]
 
 # Enables running the Nix language test suite from the original C++
 # Nix implementation (at version 2.3) against Tvix.
 nix_tests = []
 
-# Enables building the binary (tvix-eval REPL)
-repl = [ "rustyline", "clap" ]
-
 # Enables operations in the VM which depend on the ability to perform I/O
 impure = []
 
diff --git a/tvix/eval/src/eval.rs b/tvix/eval/src/eval.rs
deleted file mode 100644
index bfd827e2ca5b..000000000000
--- a/tvix/eval/src/eval.rs
+++ /dev/null
@@ -1,145 +0,0 @@
-use std::path::PathBuf;
-
-use crate::{
-    builtins::global_builtins,
-    errors::{Error, ErrorKind, EvalResult},
-    nix_search_path::NixSearchPath,
-    observer::{DisassemblingObserver, NoOpObserver, TracingObserver},
-    pretty_ast::pretty_print_expr,
-    value::Value,
-    SourceCode,
-};
-
-/// Runtime options for the Tvix interpreter
-#[derive(Debug, Clone, 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,
-
-    /// Print warnings
-    #[cfg_attr(
-        feature = "repl",
-        clap(long, env = "TVIX_WARNINGS", default_value = "true")
-    )]
-    warnings: bool,
-
-    /// A colon-separated list of directories to use to resolve `<...>`-style paths
-    #[cfg_attr(feature = "repl", clap(long, short = 'I', env = "NIX_PATH"))]
-    nix_search_path: Option<NixSearchPath>,
-
-    #[cfg_attr(feature = "repl", clap(long))]
-    pub raw: bool,
-}
-
-impl Options {
-    #[cfg(test)]
-    pub(crate) fn test_options() -> Options {
-        Options {
-            warnings: false,
-            ..Options::default()
-        }
-    }
-}
-
-pub fn interpret(code: &str, location: Option<PathBuf>, options: Options) -> EvalResult<Value> {
-    let source = SourceCode::new();
-    let file = source.add_file(
-        location
-            .as_ref()
-            .map(|p| p.to_string_lossy().to_string())
-            .unwrap_or_else(|| "[tvix-repl]".into()),
-        code.into(),
-    );
-
-    let parsed = rnix::ast::Root::parse(code);
-    let errors = parsed.errors();
-
-    if !errors.is_empty() {
-        let err = Error {
-            kind: ErrorKind::ParseErrors(errors.to_vec()),
-            span: file.span,
-        };
-        err.fancy_format_stderr(&source);
-        return Err(err);
-    }
-
-    // If we've reached this point, there are no errors.
-    let root_expr = parsed
-        .tree()
-        .expr()
-        .expect("expression should exist if no errors occured");
-
-    if options.display_ast {
-        println!("{}", pretty_print_expr(&root_expr));
-    }
-
-    let builtins = crate::compiler::prepare_globals(Box::new(global_builtins(source.clone())));
-    let result = if options.dump_bytecode {
-        crate::compiler::compile(
-            &root_expr,
-            location,
-            file.clone(),
-            builtins,
-            &mut DisassemblingObserver::new(source.clone(), std::io::stderr()),
-        )
-    } else {
-        crate::compiler::compile(
-            &root_expr,
-            location,
-            file.clone(),
-            builtins,
-            &mut NoOpObserver::default(),
-        )
-    }?;
-
-    if options.warnings {
-        for warning in result.warnings {
-            warning.fancy_format_stderr(&source);
-        }
-    }
-
-    for error in &result.errors {
-        error.fancy_format_stderr(&source);
-    }
-
-    if let Some(err) = result.errors.last() {
-        return Err(err.clone());
-    }
-
-    let result = if options.trace_runtime {
-        crate::vm::run_lambda(
-            options.nix_search_path.unwrap_or_default(),
-            &mut TracingObserver::new(std::io::stderr()),
-            result.lambda,
-        )
-    } else {
-        crate::vm::run_lambda(
-            options.nix_search_path.unwrap_or_default(),
-            &mut NoOpObserver::default(),
-            result.lambda,
-        )
-    };
-
-    if let Err(err) = &result {
-        err.fancy_format_stderr(&source);
-    }
-
-    result.map(|r| {
-        if options.warnings {
-            for warning in r.warnings {
-                warning.fancy_format_stderr(&source);
-            }
-        }
-        r.value
-    })
-}
diff --git a/tvix/eval/src/lib.rs b/tvix/eval/src/lib.rs
index 43a085108258..8697c752f392 100644
--- a/tvix/eval/src/lib.rs
+++ b/tvix/eval/src/lib.rs
@@ -16,7 +16,6 @@ mod builtins;
 mod chunk;
 mod compiler;
 mod errors;
-mod eval;
 pub mod observer;
 mod opcode;
 mod pretty_ast;
@@ -44,7 +43,6 @@ use std::sync::Arc;
 pub use crate::builtins::global_builtins;
 pub use crate::compiler::{compile, prepare_globals};
 pub use crate::errors::{Error, ErrorKind, EvalResult};
-pub use crate::eval::{interpret, Options};
 pub use crate::pretty_ast::pretty_print_expr;
 pub use crate::source::SourceCode;
 pub use crate::value::Value;