Turn evaluation hints into strings earlier, to make project's Error thread-safe.

This commit is contained in:
KtorZ 2023-11-24 09:44:02 +01:00
parent d04094560b
commit 1ca81ec133
No known key found for this signature in database
GPG Key ID: 33173CB6F77F4277
3 changed files with 58 additions and 37 deletions

View File

@ -1,9 +1,6 @@
use crate::{ use crate::{blueprint::error as blueprint, deps::manifest::Package, package_name::PackageName};
blueprint::error as blueprint, deps::manifest::Package, package_name::PackageName, pretty,
script::EvalHint,
};
use aiken_lang::{ use aiken_lang::{
ast::{self, BinOp, Span}, ast::{self, Span},
error::ExtraData, error::ExtraData,
parser::error::ParseError, parser::error::ParseError,
tipo, tipo,
@ -18,7 +15,6 @@ use std::{
ops::Deref, ops::Deref,
path::{Path, PathBuf}, path::{Path, PathBuf},
}; };
use uplc::machine::cost_model::ExBudget;
use zip::result::ZipError; use zip::result::ZipError;
#[allow(dead_code)] #[allow(dead_code)]
@ -97,7 +93,7 @@ pub enum Error {
path: PathBuf, path: PathBuf,
verbose: bool, verbose: bool,
src: String, src: String,
evaluation_hint: Option<EvalHint>, evaluation_hint: Option<String>,
}, },
#[error( #[error(
@ -313,33 +309,9 @@ impl Diagnostic for Error {
Error::MissingManifest { .. } => Some(Box::new("Try running `aiken new <REPOSITORY/PROJECT>` to initialise a project with an example manifest.")), Error::MissingManifest { .. } => Some(Box::new("Try running `aiken new <REPOSITORY/PROJECT>` to initialise a project with an example manifest.")),
Error::TomlLoading { .. } => None, Error::TomlLoading { .. } => None,
Error::Format { .. } => None, Error::Format { .. } => None,
Error::TestFailure { evaluation_hint, .. } =>{ Error::TestFailure { evaluation_hint, .. } => match evaluation_hint {
match evaluation_hint {
None => None, None => None,
Some(hint) => { Some(hint) => Some(Box::new(hint.to_string()))
let budget = ExBudget { mem: i64::MAX, cpu: i64::MAX, };
let left = pretty::boxed("left", &match hint.left.clone().eval(budget).result() {
Ok(term) => format!("{term}"),
Err(err) => format!("{err}"),
});
let right = pretty::boxed("right", &match hint.right.clone().eval(budget).result() {
Ok(term) => format!("{term}"),
Err(err) => format!("{err}"),
});
let msg = match hint.bin_op {
BinOp::And => Some(format!("{left}\n\nand\n\n{right}\n\nshould both be true.")),
BinOp::Or => Some(format!("{left}\n\nor\n\n{right}\n\nshould be true.")),
BinOp::Eq => Some(format!("{left}\n\nshould be equal to\n\n{right}")),
BinOp::NotEq => Some(format!("{left}\n\nshould not be equal to\n\n{right}")),
BinOp::LtInt => Some(format!("{left}\n\nshould be lower than\n\n{right}")),
BinOp::LtEqInt => Some(format!("{left}\n\nshould be lower than or equal to\n\n{right}")),
BinOp::GtEqInt => Some(format!("{left}\n\nshould be greater than\n\n{right}")),
BinOp::GtInt => Some(format!("{left}\n\nshould be greater than or equal to\n\n{right}")),
_ => None
}?;
Some(Box::new(msg))
}
}
}, },
Error::Http(_) => None, Error::Http(_) => None,
Error::ZipExtract(_) => None, Error::ZipExtract(_) => None,

View File

@ -329,7 +329,11 @@ where
Some(Error::TestFailure { Some(Error::TestFailure {
name: e.script.name.clone(), name: e.script.name.clone(),
path: e.script.input_path.clone(), path: e.script.input_path.clone(),
evaluation_hint: e.script.evaluation_hint.clone(), evaluation_hint: e
.script
.evaluation_hint
.as_ref()
.map(|hint| hint.to_string()),
src: e.script.program.to_pretty(), src: e.script.program.to_pretty(),
verbose, verbose,
}) })

View File

@ -1,6 +1,9 @@
use crate::{ExBudget, Term}; use crate::{pretty, ExBudget, Term};
use aiken_lang::ast::BinOp; use aiken_lang::ast::BinOp;
use std::path::PathBuf; use std::{
fmt::{self, Display},
path::PathBuf,
};
use uplc::ast::{NamedDeBruijn, Program}; use uplc::ast::{NamedDeBruijn, Program};
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
@ -42,6 +45,48 @@ pub struct EvalHint {
pub right: Program<NamedDeBruijn>, pub right: Program<NamedDeBruijn>,
} }
impl Display for EvalHint {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let unlimited_budget = ExBudget {
mem: i64::MAX,
cpu: i64::MAX,
};
let left = pretty::boxed(
"left",
&match self.left.clone().eval(unlimited_budget).result() {
Ok(term) => format!("{term}"),
Err(err) => format!("{err}"),
},
);
let right = pretty::boxed(
"right",
&match self.right.clone().eval(unlimited_budget).result() {
Ok(term) => format!("{term}"),
Err(err) => format!("{err}"),
},
);
let msg = match self.bin_op {
BinOp::And => Some(format!("{left}\n\nand\n\n{right}\n\nshould both be true.")),
BinOp::Or => Some(format!("{left}\n\nor\n\n{right}\n\nshould be true.")),
BinOp::Eq => Some(format!("{left}\n\nshould be equal to\n\n{right}")),
BinOp::NotEq => Some(format!("{left}\n\nshould not be equal to\n\n{right}")),
BinOp::LtInt => Some(format!("{left}\n\nshould be lower than\n\n{right}")),
BinOp::LtEqInt => Some(format!(
"{left}\n\nshould be lower than or equal to\n\n{right}"
)),
BinOp::GtEqInt => Some(format!("{left}\n\nshould be greater than\n\n{right}")),
BinOp::GtInt => Some(format!(
"{left}\n\nshould be greater than or equal to\n\n{right}"
)),
_ => None,
}
.ok_or(fmt::Error::default())?;
f.write_str(&msg)
}
}
#[derive(Debug)] #[derive(Debug)]
pub struct EvalInfo { pub struct EvalInfo {
pub success: bool, pub success: bool,