Introduce 'compact' trace level verbosity

For now, it only shows the span start. We'll change that in the next commit to show a line number and a column.
This commit is contained in:
KtorZ 2024-01-18 11:43:07 +01:00
parent 627c6b576e
commit e67d5863a1
No known key found for this signature in database
GPG Key ID: 33173CB6F77F4277
6 changed files with 251 additions and 201 deletions

View File

@ -1367,8 +1367,8 @@ pub enum Tracing {
#[derive(Debug, Clone, Copy, PartialEq, Eq)] #[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum TraceLevel { pub enum TraceLevel {
Silent, // No traces Silent, // No traces
// Compact, // Line numbers only Compact, // Line numbers only
Verbose, // Full verbose traces as provided by the user or the compiler Verbose, // Full verbose traces as provided by the user or the compiler
} }
@ -1403,6 +1403,7 @@ impl Display for TraceLevel {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::result::Result<(), std::fmt::Error> { fn fmt(&self, f: &mut std::fmt::Formatter) -> std::result::Result<(), std::fmt::Error> {
match self { match self {
TraceLevel::Silent => f.write_str("silent"), TraceLevel::Silent => f.write_str("silent"),
TraceLevel::Compact => f.write_str("compact"),
TraceLevel::Verbose => f.write_str("verbose"), TraceLevel::Verbose => f.write_str("verbose"),
} }
} }

View File

@ -468,22 +468,32 @@ impl<'a> CodeGenerator<'a> {
let air_value = self.build(value, module_name); let air_value = self.build(value, module_name);
let msg = get_src_code_by_span(module_name, location, &self.module_src);
let msg_func_name = msg.split_whitespace().join("");
self.special_functions.insert_new_function(
msg_func_name.clone(),
Term::string(msg),
string(),
);
// TODO
let msg_func = match self.tracing { let msg_func = match self.tracing {
TraceLevel::Verbose if kind.is_expect() => { TraceLevel::Silent => None,
Some(self.special_functions.use_function_msg(msg_func_name)) TraceLevel::Verbose | TraceLevel::Compact => {
if kind.is_expect() {
let msg = match self.tracing {
TraceLevel::Silent => unreachable!("excluded from pattern guards"),
// TODO: line number & col
TraceLevel::Compact => format!("{}", location.start),
TraceLevel::Verbose => {
get_src_code_by_span(module_name, location, &self.module_src)
}
};
let msg_func_name = msg.split_whitespace().join("");
self.special_functions.insert_new_function(
msg_func_name.clone(),
Term::string(msg),
string(),
);
Some(self.special_functions.use_function_msg(msg_func_name))
} else {
None
}
} }
_ => None,
}; };
self.assignment( self.assignment(
@ -1589,9 +1599,9 @@ impl<'a> CodeGenerator<'a> {
// mutate code_gen_funcs and defined_data_types in this if branch // mutate code_gen_funcs and defined_data_types in this if branch
if function.is_none() && defined_data_types.get(&data_type_name).is_none() { if function.is_none() && defined_data_types.get(&data_type_name).is_none() {
let (msg_term, error_term) = match self.tracing { let (msg_term, error_term) = match self.tracing {
TraceLevel::Verbose => { TraceLevel::Silent => (None, AirTree::error(tipo.clone(), false)),
TraceLevel::Compact | TraceLevel::Verbose => {
let msg = AirMsg::LocalVar("__param_msg".to_string()); let msg = AirMsg::LocalVar("__param_msg".to_string());
( (
Some(msg.clone()), Some(msg.clone()),
AirTree::trace( AirTree::trace(
@ -1601,7 +1611,6 @@ impl<'a> CodeGenerator<'a> {
), ),
) )
} }
TraceLevel::Silent => (None, AirTree::error(tipo.clone(), false)),
}; };
defined_data_types.insert(data_type_name.clone(), 1); defined_data_types.insert(data_type_name.clone(), 1);
@ -1721,14 +1730,14 @@ impl<'a> CodeGenerator<'a> {
} }
let code_gen_func = match self.tracing { let code_gen_func = match self.tracing {
TraceLevel::Verbose => CodeGenFunction::Function {
body: func_body,
params: vec!["__param_0".to_string(), "__param_msg".to_string()],
},
TraceLevel::Silent => CodeGenFunction::Function { TraceLevel::Silent => CodeGenFunction::Function {
body: func_body, body: func_body,
params: vec!["__param_0".to_string()], params: vec!["__param_0".to_string()],
}, },
TraceLevel::Compact | TraceLevel::Verbose => CodeGenFunction::Function {
body: func_body,
params: vec!["__param_0".to_string(), "__param_msg".to_string()],
},
}; };
self.code_gen_functions self.code_gen_functions
@ -1741,7 +1750,7 @@ impl<'a> CodeGenerator<'a> {
let args = match self.tracing { let args = match self.tracing {
TraceLevel::Silent => vec![value], TraceLevel::Silent => vec![value],
TraceLevel::Verbose => vec![ TraceLevel::Compact | TraceLevel::Verbose => vec![
value, value,
msg_func msg_func
.expect("should be unreachable: no msg func with tracing enabled.") .expect("should be unreachable: no msg func with tracing enabled.")
@ -2750,25 +2759,29 @@ impl<'a> CodeGenerator<'a> {
let actual_type = convert_opaque_type(&arg.tipo, &self.data_types); let actual_type = convert_opaque_type(&arg.tipo, &self.data_types);
let msg = src_code
.get(arg_span.start..arg_span.end)
.expect("Out of bounds span")
.to_string();
let msg_func_name = msg.split_whitespace().join("");
self.special_functions.insert_new_function(
msg_func_name.to_string(),
Term::string(msg),
string(),
);
// TODO
let msg_func = match self.tracing { let msg_func = match self.tracing {
TraceLevel::Verbose => { TraceLevel::Silent => None,
TraceLevel::Compact | TraceLevel::Verbose => {
let msg = match self.tracing {
TraceLevel::Silent => unreachable!("excluded from pattern guards"),
// TODO: Show line number + column
TraceLevel::Compact => format!("{}", arg_span.start),
TraceLevel::Verbose => src_code
.get(arg_span.start..arg_span.end)
.expect("Out of bounds span")
.to_string(),
};
let msg_func_name = msg.split_whitespace().join("");
self.special_functions.insert_new_function(
msg_func_name.to_string(),
Term::string(msg),
string(),
);
Some(self.special_functions.use_function_msg(msg_func_name)) Some(self.special_functions.use_function_msg(msg_func_name))
} }
_ => None,
}; };
let assign = self.assignment( let assign = self.assignment(
@ -3724,14 +3737,16 @@ impl<'a> CodeGenerator<'a> {
fn gen_uplc(&mut self, ir: Air, arg_stack: &mut Vec<Term<Name>>) -> Option<Term<Name>> { fn gen_uplc(&mut self, ir: Air, arg_stack: &mut Vec<Term<Name>>) -> Option<Term<Name>> {
// Going to mark the changes made to code gen after air tree implementation // Going to mark the changes made to code gen after air tree implementation
// TODO
let error_term = match self.tracing { let error_term = match self.tracing {
TraceLevel::Verbose if air_holds_msg(&ir) => { TraceLevel::Silent => Term::Error,
let msg = arg_stack.pop().unwrap(); TraceLevel::Compact | TraceLevel::Verbose => {
if air_holds_msg(&ir) {
Term::Error.delayed_trace(msg) let msg = arg_stack.pop().unwrap();
Term::Error.delayed_trace(msg)
} else {
Term::Error
}
} }
_ => Term::Error,
}; };
match ir { match ir {

View File

@ -1639,39 +1639,50 @@ pub fn wrap_as_multi_validator(
) )
.lambda("__second_arg") .lambda("__second_arg")
.lambda("__first_arg"), .lambda("__first_arg"),
TraceLevel::Verbose => { TraceLevel::Verbose | TraceLevel::Compact => {
let trace_string = format!( let trace_string = match trace {
"Incorrect redeemer type for validator {}. TraceLevel::Verbose => format!(
Double check you have wrapped the redeemer type as specified in your plutus.json", "Incorrect redeemer type for validator {}.
spend_name Double check you have wrapped the redeemer type as specified in your plutus.json",
); spend_name
),
TraceLevel::Compact => "RX".to_string(),
TraceLevel::Silent => unreachable!("Filtered-out from the pattern guards."),
};
let error_term = Term::Error.delayed_trace(Term::var("__incorrect_second_arg_type")); let error_term = Term::Error.delayed_trace(Term::var("__incorrect_second_arg_type"));
let then_term = mint
.apply(Term::var("__first_arg"))
.apply(Term::var("__second_arg"));
let else_term = spend.apply(Term::var("__first_arg")).apply(
Term::head_list()
.apply(Term::var(CONSTR_FIELDS_EXPOSER).apply(Term::var("__second_arg"))),
);
Term::var("__second_arg") Term::var("__second_arg")
.delayed_choose_data( .delayed_choose_data(
Term::equals_integer() Term::equals_integer()
.apply(Term::integer(0.into())) .apply(Term::integer(0.into()))
.apply(Term::var(CONSTR_INDEX_EXPOSER).apply(Term::var("__second_arg"))) .apply(Term::var(CONSTR_INDEX_EXPOSER).apply(Term::var("__second_arg")))
.delayed_if_then_else( .delayed_if_then_else(
mint.apply(Term::var("__first_arg")) if trace == TraceLevel::Verbose {
.apply(Term::var("__second_arg")) then_term.delayed_trace(Term::string(format!(
.delayed_trace(Term::string(format!(
"Running 2 arg validator {}", "Running 2 arg validator {}",
mint_name mint_name
))), )))
spend } else {
.apply(Term::var("__first_arg")) then_term
.apply( },
Term::head_list().apply( if trace == TraceLevel::Verbose {
Term::var(CONSTR_FIELDS_EXPOSER) else_term.delayed_trace(Term::string(format!(
.apply(Term::var("__second_arg")),
),
)
.delayed_trace(Term::string(format!(
"Running 3 arg validator {}", "Running 3 arg validator {}",
spend_name spend_name
))), )))
} else {
else_term
},
), ),
error_term.clone(), error_term.clone(),
error_term.clone(), error_term.clone(),
@ -1725,6 +1736,9 @@ pub fn wrap_validator_condition(air_tree: AirTree, trace: TraceLevel) -> AirTree
let success_branch = vec![(air_tree, AirTree::void())]; let success_branch = vec![(air_tree, AirTree::void())];
let otherwise = match trace { let otherwise = match trace {
TraceLevel::Silent => AirTree::error(void(), true), TraceLevel::Silent => AirTree::error(void(), true),
TraceLevel::Compact => {
AirTree::trace(AirTree::string("VX"), void(), AirTree::error(void(), true))
}
TraceLevel::Verbose => AirTree::trace( TraceLevel::Verbose => AirTree::trace(
AirTree::string("Validator returned false"), AirTree::string("Validator returned false"),
void(), void(),

View File

@ -421,15 +421,23 @@ impl<'a, 'b> ExprTyper<'a, 'b> {
}, },
}; };
let text = TypedExpr::String { let text = match self.tracing.trace_level(false) {
location, TraceLevel::Verbose => Some(TypedExpr::String {
tipo: string(), location,
value: format!( tipo: string(),
"{} ? False", value: format!(
format::Formatter::new() "{} ? False",
.expr(&value, false) format::Formatter::new()
.to_pretty_string(999) .expr(&value, false)
), .to_pretty_string(999)
),
}),
TraceLevel::Compact => Some(TypedExpr::String {
location,
tipo: string(),
value: format!("{}", location.start),
}),
TraceLevel::Silent => None,
}; };
let typed_value = self.infer(value)?; let typed_value = self.infer(value)?;
@ -438,7 +446,7 @@ impl<'a, 'b> ExprTyper<'a, 'b> {
match self.tracing.trace_level(false) { match self.tracing.trace_level(false) {
TraceLevel::Silent => Ok(typed_value), TraceLevel::Silent => Ok(typed_value),
TraceLevel::Verbose => Ok(TypedExpr::If { TraceLevel::Verbose | TraceLevel::Compact => Ok(TypedExpr::If {
location, location,
branches: vec1::vec1![IfBranch { branches: vec1::vec1![IfBranch {
condition: typed_value, condition: typed_value,
@ -448,7 +456,7 @@ impl<'a, 'b> ExprTyper<'a, 'b> {
final_else: Box::new(TypedExpr::Trace { final_else: Box::new(TypedExpr::Trace {
location, location,
tipo: bool(), tipo: bool(),
text: Box::new(text), text: Box::new(text.expect("TraceLevel::Silent excluded from pattern-guard")),
then: Box::new(var_false), then: Box::new(var_false),
}), }),
tipo: bool(), tipo: bool(),
@ -1819,6 +1827,17 @@ impl<'a, 'b> ExprTyper<'a, 'b> {
match self.tracing.trace_level(false) { match self.tracing.trace_level(false) {
TraceLevel::Silent => Ok(then), TraceLevel::Silent => Ok(then),
// TODO: use line numbers & cols
TraceLevel::Compact => Ok(TypedExpr::Trace {
location,
tipo,
then: Box::new(then),
text: Box::new(TypedExpr::String {
location,
tipo: string(),
value: format!("{}", location.start),
}),
}),
TraceLevel::Verbose => Ok(TypedExpr::Trace { TraceLevel::Verbose => Ok(TypedExpr::Trace {
location, location,
tipo, tipo,

View File

@ -1,6 +1,6 @@
use pretty_assertions::assert_eq; use pretty_assertions::assert_eq;
use aiken_lang::ast::{Definition, Function, TypedFunction, TypedValidator}; use aiken_lang::ast::{Definition, Function, TraceLevel, Tracing, TypedFunction, TypedValidator};
use uplc::{ use uplc::{
ast::{Constant, Data, DeBruijn, Name, Program, Term, Type}, ast::{Constant, Data, DeBruijn, Name, Program, Term, Type},
builder::{CONSTR_FIELDS_EXPOSER, CONSTR_INDEX_EXPOSER}, builder::{CONSTR_FIELDS_EXPOSER, CONSTR_INDEX_EXPOSER},
@ -26,7 +26,7 @@ fn assert_uplc(source_code: &str, expected: Term<Name>, should_fail: bool) {
&project.functions, &project.functions,
&project.data_types, &project.data_types,
&project.module_types, &project.module_types,
true, Tracing::All(TraceLevel::Verbose),
); );
let Some(checked_module) = modules.values().next() else { let Some(checked_module) = modules.values().next() else {

View File

@ -86,8 +86,9 @@ pub fn keep_traces_parser(
#[allow(clippy::type_complexity)] #[allow(clippy::type_complexity)]
pub fn trace_level_parser() -> MapValueParser<PossibleValuesParser, fn(String) -> TraceLevel> { pub fn trace_level_parser() -> MapValueParser<PossibleValuesParser, fn(String) -> TraceLevel> {
PossibleValuesParser::new(["silent", "verbose"]).map(|s| match s.as_str() { PossibleValuesParser::new(["silent", "compact", "verbose"]).map(|s| match s.as_str() {
"silent" => TraceLevel::Silent, "silent" => TraceLevel::Silent,
"compact" => TraceLevel::Compact,
"verbose" => TraceLevel::Verbose, "verbose" => TraceLevel::Verbose,
_ => unreachable!(), _ => unreachable!(),
}) })