feat(tvix/eval): add observer configuration to public API

With this change, it should be possible to have both existing
use-cases (CLI & Tvixbolt) use the same API.

Change-Id: I2195264f08cc892177b559a28660dc5f98e48e41
Reviewed-on: https://cl.tvl.fyi/c/depot/+/7545
Autosubmit: tazjin <tazjin@tvl.su>
Tested-by: BuildkiteCI
Reviewed-by: grfn <grfn@gws.fyi>
This commit is contained in:
Vincent Ambo 2022-12-09 12:58:58 +03:00 committed by tazjin
parent 9bc1e6ef05
commit 59e695a9d9

View file

@ -44,6 +44,7 @@ use std::sync::Arc;
pub use crate::builtins::global_builtins;
pub use crate::compiler::{compile, prepare_globals};
pub use crate::errors::{Error, ErrorKind, EvalResult};
use crate::observer::{CompilerObserver, RuntimeObserver};
pub use crate::pretty_ast::pretty_print_expr;
pub use crate::source::SourceCode;
pub use crate::value::Value;
@ -69,10 +70,9 @@ pub(crate) fn unwrap_or_clone_rc<T: Clone>(rc: Rc<T>) -> T {
///
/// Public fields are intended to be set by the caller. Setting all
/// fields is optional.
#[derive(Clone)]
pub struct Evaluation<'a> {
pub struct Evaluation<'code, 'co, 'ro> {
/// The Nix source code to be evaluated.
code: &'a str,
code: &'code str,
/// Optional location of the source code (i.e. path to the file it was read
/// from). Used for error reporting, and for resolving relative paths in
@ -91,6 +91,14 @@ pub struct Evaluation<'a> {
/// (optional) Nix search path, e.g. the value of `NIX_PATH` used
/// for resolving items on the search path (such as `<nixpkgs>`).
pub nix_path: Option<String>,
/// (optional) compiler observer for reporting on compilation
/// details, like the emitted bytecode.
pub compiler_observer: Option<&'co mut dyn CompilerObserver>,
/// (optional) runtime observer, for reporting on execution steps
/// of Nix code.
pub runtime_observer: Option<&'ro mut dyn RuntimeObserver>,
}
/// Result of evaluating a piece of Nix code. If evaluation succeeded, a value
@ -109,11 +117,11 @@ pub struct EvaluationResult {
pub warnings: Vec<EvalWarning>,
}
impl<'a> Evaluation<'a> {
impl<'code, 'co, 'ro> Evaluation<'code, 'co, 'ro> {
/// Initialise an `Evaluation` for the given Nix source code snippet, and
/// an optional code location.
/// reporting the location of errors in the code.
pub fn new(code: &'a str, location: Option<PathBuf>) -> Self {
pub fn new(code: &'code str, location: Option<PathBuf>) -> Self {
let source_map = SourceCode::new();
let location_str = location
@ -130,6 +138,8 @@ impl<'a> Evaluation<'a> {
file,
expr: None,
nix_path: None,
compiler_observer: None,
runtime_observer: None,
}
}
@ -163,12 +173,15 @@ impl<'a> Evaluation<'a> {
let builtins =
crate::compiler::prepare_globals(Box::new(global_builtins(self.source_map())));
let mut noop_observer = observer::NoOpObserver::default();
let compiler_observer = self.compiler_observer.take().unwrap_or(&mut noop_observer);
let compiler_result = match compiler::compile(
self.expr.as_ref().unwrap(),
self.location.take(),
self.file.clone(),
builtins,
&mut observer::NoOpObserver::default(), // TODO: compilation observer
compiler_observer,
) {
Ok(result) => result,
Err(err) => {
@ -202,11 +215,8 @@ impl<'a> Evaluation<'a> {
})
.unwrap_or_else(|| Default::default());
let vm_result = run_lambda(
nix_path,
&mut observer::NoOpObserver::default(), // TODO: runtime observer
compiler_result.lambda,
);
let runtime_observer = self.runtime_observer.take().unwrap_or(&mut noop_observer);
let vm_result = run_lambda(nix_path, runtime_observer, compiler_result.lambda);
match vm_result {
Ok(mut runtime_result) => {