1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
|
use clap::Parser;
use mimalloc::MiMalloc;
use std::rc::Rc;
use std::{fs, path::PathBuf};
use tvix_cli::args::Args;
use tvix_cli::repl::Repl;
use tvix_cli::{init_io_handle, interpret, AllowIncomplete};
use tvix_eval::observer::DisassemblingObserver;
use tvix_eval::EvalMode;
use tvix_glue::tvix_store_io::TvixStoreIO;
#[global_allocator]
static GLOBAL: MiMalloc = MiMalloc;
/// Interpret the given code snippet, but only run the Tvix compiler
/// on it and return errors and warnings.
fn lint(code: &str, path: Option<PathBuf>, args: &Args) -> bool {
let mut eval_builder = tvix_eval::Evaluation::builder_impure();
if args.strict {
eval_builder = eval_builder.mode(EvalMode::Strict);
}
let source_map = eval_builder.source_map().clone();
let mut compiler_observer = DisassemblingObserver::new(source_map.clone(), std::io::stderr());
if args.dump_bytecode {
eval_builder.set_compiler_observer(Some(&mut compiler_observer));
}
if args.trace_runtime {
eprintln!("warning: --trace-runtime has no effect with --compile-only!");
}
let eval = eval_builder.build();
let result = eval.compile_only(code, path);
if args.display_ast {
if let Some(ref expr) = result.expr {
eprintln!("AST: {}", tvix_eval::pretty_print_expr(expr));
}
}
for error in &result.errors {
error.fancy_format_stderr();
}
for warning in &result.warnings {
warning.fancy_format_stderr(&source_map);
}
// inform the caller about any errors
result.errors.is_empty()
}
fn main() {
let args = Args::parse();
tvix_tracing::TracingBuilder::default()
.enable_progressbar()
.build()
.expect("unable to set up tracing subscriber");
let tokio_runtime = tokio::runtime::Runtime::new().expect("failed to setup tokio runtime");
let io_handle = init_io_handle(&tokio_runtime, &args);
if let Some(file) = &args.script {
run_file(io_handle, file.clone(), &args)
} else if let Some(expr) = &args.expr {
if !interpret(
io_handle,
expr,
None,
&args,
false,
AllowIncomplete::RequireComplete,
None, // TODO(aspen): Pass in --arg/--argstr here
None,
None,
)
.unwrap()
.finalize()
{
std::process::exit(1);
}
} else {
let mut repl = Repl::new(io_handle, &args);
repl.run()
}
}
fn run_file(io_handle: Rc<TvixStoreIO>, mut path: PathBuf, args: &Args) {
if path.is_dir() {
path.push("default.nix");
}
let contents = fs::read_to_string(&path).expect("failed to read the input file");
let success = if args.compile_only {
lint(&contents, Some(path), args)
} else {
interpret(
io_handle,
&contents,
Some(path),
args,
false,
AllowIncomplete::RequireComplete,
None,
None,
None,
)
.unwrap()
.finalize()
};
if !success {
std::process::exit(1);
}
}
|