Rework tracing arguments to --keep-traces & --trace-level

This allows for a more fine-grained control over how the traces are showed. Now users can instrument the compiler to preserve only their user-defined traces, or the only the compiler, or all, or none. We also want to add another trace level on top of that: 'compact' to only show line numbers; which will work for both user-defined and/or compiler-generated traces.
This commit is contained in:
KtorZ 2024-01-17 17:23:34 +01:00
parent 86146ae7f4
commit d27ea98a8f
No known key found for this signature in database
GPG Key ID: 33173CB6F77F4277
12 changed files with 145 additions and 73 deletions

View File

@ -1360,25 +1360,50 @@ pub enum TraceKind {
#[derive(Debug, Clone, Copy, PartialEq, Eq)] #[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum Tracing { pub enum Tracing {
NoTraces, UserDefined(TraceLevel),
KeepTraces, CompilerGenerated(TraceLevel),
All(TraceLevel),
} }
impl From<bool> for Tracing { #[derive(Debug, Clone, Copy, PartialEq, Eq)]
fn from(keep: bool) -> Self { pub enum TraceLevel {
if keep { Silent, // No traces
Tracing::KeepTraces // Compact, // Line numbers only
Verbose, // Full verbose traces as provided by the user or the compiler
}
impl Tracing {
pub fn silent() -> Self {
Tracing::All(TraceLevel::Silent)
}
/// Get the tracing level based on the context we're in.
pub fn trace_level(&self, is_code_gen: bool) -> TraceLevel {
match self {
Tracing::UserDefined(lvl) => {
if is_code_gen {
TraceLevel::Silent
} else { } else {
Tracing::NoTraces *lvl
}
}
Tracing::CompilerGenerated(lvl) => {
if is_code_gen {
*lvl
} else {
TraceLevel::Silent
}
}
Tracing::All(lvl) => *lvl,
} }
} }
} }
impl From<Tracing> for bool { impl Display for TraceLevel {
fn from(value: Tracing) -> Self { fn fmt(&self, f: &mut std::fmt::Formatter) -> std::result::Result<(), std::fmt::Error> {
match value { match self {
Tracing::NoTraces => false, TraceLevel::Silent => f.write_str("silent"),
Tracing::KeepTraces => true, TraceLevel::Verbose => f.write_str("verbose"),
} }
} }
} }

View File

@ -1,5 +1,5 @@
use crate::{ use crate::{
ast::{Definition, ModuleKind, Tracing, TypedModule, UntypedModule}, ast::{Definition, ModuleKind, TraceLevel, Tracing, TypedModule, UntypedModule},
builtins, builtins,
expr::TypedExpr, expr::TypedExpr,
parser, parser,
@ -31,7 +31,7 @@ fn check_module(
kind, kind,
"test/project", "test/project",
&module_types, &module_types,
Tracing::KeepTraces, Tracing::All(TraceLevel::Verbose),
&mut warnings, &mut warnings,
); );

View File

@ -5,9 +5,9 @@ use crate::{
ast::{ ast::{
Annotation, Arg, ArgName, AssignmentKind, BinOp, Bls12_381Point, ByteArrayFormatPreference, Annotation, Arg, ArgName, AssignmentKind, BinOp, Bls12_381Point, ByteArrayFormatPreference,
CallArg, ClauseGuard, Constant, Curve, IfBranch, LogicalOpChainKind, RecordUpdateSpread, CallArg, ClauseGuard, Constant, Curve, IfBranch, LogicalOpChainKind, RecordUpdateSpread,
Span, TraceKind, Tracing, TypedArg, TypedCallArg, TypedClause, TypedClauseGuard, Span, TraceKind, TraceLevel, Tracing, TypedArg, TypedCallArg, TypedClause,
TypedIfBranch, TypedPattern, TypedRecordUpdateArg, UnOp, UntypedArg, UntypedClause, TypedClauseGuard, TypedIfBranch, TypedPattern, TypedRecordUpdateArg, UnOp, UntypedArg,
UntypedClauseGuard, UntypedIfBranch, UntypedPattern, UntypedRecordUpdateArg, UntypedClause, UntypedClauseGuard, UntypedIfBranch, UntypedPattern, UntypedRecordUpdateArg,
}, },
builtins::{bool, byte_array, function, g1_element, g2_element, int, list, string, tuple}, builtins::{bool, byte_array, function, g1_element, g2_element, int, list, string, tuple},
expr::{FnStyle, TypedExpr, UntypedExpr}, expr::{FnStyle, TypedExpr, UntypedExpr},
@ -436,9 +436,9 @@ impl<'a, 'b> ExprTyper<'a, 'b> {
self.unify(bool(), typed_value.tipo(), typed_value.location(), false)?; self.unify(bool(), typed_value.tipo(), typed_value.location(), false)?;
match self.tracing { match self.tracing.trace_level(false) {
Tracing::NoTraces => Ok(typed_value), TraceLevel::Silent => Ok(typed_value),
Tracing::KeepTraces => Ok(TypedExpr::If { TraceLevel::Verbose => Ok(TypedExpr::If {
location, location,
branches: vec1::vec1![IfBranch { branches: vec1::vec1![IfBranch {
condition: typed_value, condition: typed_value,
@ -1817,9 +1817,9 @@ impl<'a, 'b> ExprTyper<'a, 'b> {
}) })
} }
match self.tracing { match self.tracing.trace_level(false) {
Tracing::NoTraces => Ok(then), TraceLevel::Silent => Ok(then),
Tracing::KeepTraces => Ok(TypedExpr::Trace { TraceLevel::Verbose => Ok(TypedExpr::Trace {
location, location,
tipo, tipo,
then: Box::new(then), then: Box::new(then),

View File

@ -32,14 +32,9 @@ impl LspProject {
pub fn compile(&mut self) -> Result<(), Vec<ProjectError>> { pub fn compile(&mut self) -> Result<(), Vec<ProjectError>> {
let checkpoint = self.project.checkpoint(); let checkpoint = self.project.checkpoint();
let result = self.project.check( let result = self
true, .project
None, .check(true, None, false, false, Tracing::silent());
false,
false,
Tracing::NoTraces,
Tracing::NoTraces,
);
self.project.restore(checkpoint); self.project.restore(checkpoint);

View File

@ -22,7 +22,10 @@ use crate::blueprint::{
Blueprint, Blueprint,
}; };
use aiken_lang::{ use aiken_lang::{
ast::{Definition, Function, ModuleKind, Tracing, TypedDataType, TypedFunction, Validator}, ast::{
Definition, Function, ModuleKind, TraceLevel, Tracing, TypedDataType, TypedFunction,
Validator,
},
builtins, builtins,
gen_uplc::builder::{DataTypeKey, FunctionAccessKey}, gen_uplc::builder::{DataTypeKey, FunctionAccessKey},
tipo::TypeInfo, tipo::TypeInfo,
@ -151,16 +154,10 @@ where
self.defined_modules = checkpoint.defined_modules; self.defined_modules = checkpoint.defined_modules;
} }
pub fn build( pub fn build(&mut self, uplc: bool, tracing: Tracing) -> Result<(), Vec<Error>> {
&mut self,
uplc: bool,
tracing: Tracing,
code_gen_tracing: Tracing,
) -> Result<(), Vec<Error>> {
let options = Options { let options = Options {
code_gen_mode: CodeGenMode::Build(uplc), code_gen_mode: CodeGenMode::Build(uplc),
tracing, tracing,
code_gen_tracing,
}; };
self.compile(options) self.compile(options)
@ -182,7 +179,7 @@ where
let parsed_modules = self.parse_sources(self.config.name.clone())?; let parsed_modules = self.parse_sources(self.config.name.clone())?;
self.type_check(parsed_modules, Tracing::NoTraces, false)?; self.type_check(parsed_modules, Tracing::silent(), false)?;
self.event_listener.handle_event(Event::GeneratingDocFiles { self.event_listener.handle_event(Event::GeneratingDocFiles {
output_path: destination.clone(), output_path: destination.clone(),
@ -216,11 +213,9 @@ where
verbose: bool, verbose: bool,
exact_match: bool, exact_match: bool,
tracing: Tracing, tracing: Tracing,
code_gen_tracing: Tracing,
) -> Result<(), Vec<Error>> { ) -> Result<(), Vec<Error>> {
let options = Options { let options = Options {
tracing, tracing,
code_gen_tracing,
code_gen_mode: if skip_tests { code_gen_mode: if skip_tests {
CodeGenMode::NoOp CodeGenMode::NoOp
} else { } else {
@ -290,7 +285,10 @@ where
&self.functions, &self.functions,
&self.data_types, &self.data_types,
&self.module_types, &self.module_types,
options.code_gen_tracing.into(), match options.tracing.trace_level(true) {
TraceLevel::Silent => false,
TraceLevel::Verbose => true,
},
); );
let blueprint = Blueprint::new(&self.config, &self.checked_modules, &mut generator) let blueprint = Blueprint::new(&self.config, &self.checked_modules, &mut generator)
@ -323,7 +321,10 @@ where
verbose, verbose,
match_tests, match_tests,
exact_match, exact_match,
options.code_gen_tracing.into(), match options.tracing.trace_level(true) {
TraceLevel::Silent => false,
TraceLevel::Verbose => true,
},
)?; )?;
if !tests.is_empty() { if !tests.is_empty() {
@ -530,7 +531,7 @@ where
let parsed_modules = self.parse_sources(package.name)?; let parsed_modules = self.parse_sources(package.name)?;
self.type_check(parsed_modules, Tracing::NoTraces, true)?; self.type_check(parsed_modules, Tracing::silent(), true)?;
} }
Ok(()) Ok(())

View File

@ -3,7 +3,6 @@ use aiken_lang::ast::Tracing;
pub struct Options { pub struct Options {
pub code_gen_mode: CodeGenMode, pub code_gen_mode: CodeGenMode,
pub tracing: Tracing, pub tracing: Tracing,
pub code_gen_tracing: Tracing,
} }
pub enum CodeGenMode { pub enum CodeGenMode {

View File

@ -2,7 +2,7 @@ use std::collections::HashMap;
use std::path::PathBuf; use std::path::PathBuf;
use aiken_lang::{ use aiken_lang::{
ast::{ModuleKind, Tracing, TypedDataType, TypedFunction}, ast::{ModuleKind, TraceLevel, Tracing, TypedDataType, TypedFunction},
gen_uplc::builder::{DataTypeKey, FunctionAccessKey}, gen_uplc::builder::{DataTypeKey, FunctionAccessKey},
parser, parser,
tipo::TypeInfo, tipo::TypeInfo,
@ -81,7 +81,7 @@ impl TestProject {
module.kind, module.kind,
&self.package.to_string(), &self.package.to_string(),
&self.module_types, &self.module_types,
Tracing::KeepTraces, Tracing::All(TraceLevel::Verbose),
&mut warnings, &mut warnings,
) )
.expect("Failed to type-check module"); .expect("Failed to type-check module");

View File

@ -36,7 +36,7 @@ pub fn exec(
) -> miette::Result<()> { ) -> miette::Result<()> {
with_project(directory.as_deref(), false, |p| { with_project(directory.as_deref(), false, |p| {
if rebuild { if rebuild {
p.build(false, Tracing::NoTraces, Tracing::NoTraces)?; p.build(false, Tracing::silent())?;
} }
let title = module.as_ref().map(|m| { let title = module.as_ref().map(|m| {

View File

@ -31,7 +31,7 @@ pub fn exec(
) -> miette::Result<()> { ) -> miette::Result<()> {
with_project(directory.as_deref(), false, |p| { with_project(directory.as_deref(), false, |p| {
if rebuild { if rebuild {
p.build(false, Tracing::NoTraces, Tracing::NoTraces)?; p.build(false, Tracing::silent())?;
} }
let title = module.as_ref().map(|m| { let title = module.as_ref().map(|m| {

View File

@ -31,7 +31,7 @@ pub fn exec(
) -> miette::Result<()> { ) -> miette::Result<()> {
with_project(directory.as_deref(), false, |p| { with_project(directory.as_deref(), false, |p| {
if rebuild { if rebuild {
p.build(false, Tracing::NoTraces, Tracing::NoTraces)?; p.build(false, Tracing::silent())?;
} }
let title = module.as_ref().map(|m| { let title = module.as_ref().map(|m| {

View File

@ -1,4 +1,7 @@
use aiken_lang::ast::{TraceLevel, Tracing};
use aiken_project::watch::{self, watch_project, with_project}; use aiken_project::watch::{self, watch_project, with_project};
use clap::builder::MapValueParser;
use clap::builder::{PossibleValuesParser, TypedValueParser};
use std::{path::PathBuf, process}; use std::{path::PathBuf, process};
#[derive(clap::Args)] #[derive(clap::Args)]
@ -19,13 +22,18 @@ pub struct Args {
#[clap(short, long)] #[clap(short, long)]
uplc: bool, uplc: bool,
/// Do not remove traces when generating code /// Do not remove traces when generating code.
#[clap(short, long)] #[clap(short, long, value_parser=keep_traces_parser(), default_missing_value="all")]
keep_traces: bool, keep_traces: Option<fn(TraceLevel) -> Tracing>,
/// Add code gen traces when generating code /// Choose the level of tracing
#[clap(short, long)] /// - silent: disable traces altogether
code_gen_traces: bool, /// - compact: only culprit line numbers are shown on failures
/// - verbose: enable full verbose traces as provided by the user or the compiler
///
///
#[clap(short, long, value_parser=trace_level_parser(), default_value_t=TraceLevel::Verbose, verbatim_doc_comment)]
trace_level: TraceLevel,
} }
pub fn exec( pub fn exec(
@ -35,18 +43,52 @@ pub fn exec(
watch, watch,
uplc, uplc,
keep_traces, keep_traces,
code_gen_traces, trace_level,
}: Args, }: Args,
) -> miette::Result<()> { ) -> miette::Result<()> {
let result = if watch { let result = if watch {
watch_project(directory.as_deref(), watch::default_filter, 500, |p| { watch_project(directory.as_deref(), watch::default_filter, 500, |p| {
p.build(uplc, keep_traces.into(), code_gen_traces.into()) p.build(
uplc,
match keep_traces {
Some(keep_traces) => keep_traces(trace_level),
None => Tracing::All(trace_level),
},
)
}) })
} else { } else {
with_project(directory.as_deref(), deny, |p| { with_project(directory.as_deref(), deny, |p| {
p.build(uplc, keep_traces.into(), code_gen_traces.into()) p.build(
uplc,
match keep_traces {
Some(keep_traces) => keep_traces(trace_level),
None => Tracing::All(trace_level),
},
)
}) })
}; };
result.map_err(|_| process::exit(1)) result.map_err(|_| process::exit(1))
} }
#[allow(clippy::type_complexity)]
pub fn keep_traces_parser(
) -> MapValueParser<PossibleValuesParser, fn(String) -> fn(TraceLevel) -> Tracing> {
PossibleValuesParser::new(["user-defined", "compiler-generated", "all"]).map(
|s: String| match s.as_str() {
"user-defined" => Tracing::UserDefined,
"compiler-generated" => Tracing::CompilerGenerated,
"all" => Tracing::All,
_ => unreachable!(),
},
)
}
#[allow(clippy::type_complexity)]
pub fn trace_level_parser() -> MapValueParser<PossibleValuesParser, fn(String) -> TraceLevel> {
PossibleValuesParser::new(["silent", "verbose"]).map(|s| match s.as_str() {
"silent" => TraceLevel::Silent,
"verbose" => TraceLevel::Verbose,
_ => unreachable!(),
})
}

View File

@ -1,3 +1,5 @@
use super::build::{keep_traces_parser, trace_level_parser};
use aiken_lang::ast::{TraceLevel, Tracing};
use aiken_project::watch::{self, watch_project, with_project}; use aiken_project::watch::{self, watch_project, with_project};
use std::{path::PathBuf, process}; use std::{path::PathBuf, process};
@ -34,13 +36,17 @@ pub struct Args {
#[clap(short, long)] #[clap(short, long)]
exact_match: bool, exact_match: bool,
/// Remove traces when generating code (including tests) /// Do not remove traces when generating code
#[clap(long)] #[clap(short, long, value_parser=keep_traces_parser(), default_missing_value="all")]
no_traces: bool, keep_traces: Option<fn(TraceLevel) -> Tracing>,
/// Remove code gen traces when generating code (including tests) /// Choose the level of tracing
#[clap(long)] /// - silent: disable traces altogether
no_code_gen_traces: bool, /// - compact: only culprit line numbers are shown on failures
/// - verbose: enable full verbose traces as provided by the user or the compiler
/// [optional]
#[clap(short, long, value_parser=trace_level_parser(), default_value_t=TraceLevel::Verbose, verbatim_doc_comment)]
trace_level: TraceLevel,
} }
pub fn exec( pub fn exec(
@ -51,9 +57,9 @@ pub fn exec(
debug, debug,
match_tests, match_tests,
exact_match, exact_match,
no_traces,
no_code_gen_traces,
watch, watch,
keep_traces,
trace_level,
}: Args, }: Args,
) -> miette::Result<()> { ) -> miette::Result<()> {
let result = if watch { let result = if watch {
@ -63,8 +69,10 @@ pub fn exec(
match_tests.clone(), match_tests.clone(),
debug, debug,
exact_match, exact_match,
(!no_traces).into(), match keep_traces {
(!no_code_gen_traces).into(), Some(keep_traces) => keep_traces(trace_level),
None => Tracing::All(trace_level),
},
) )
}) })
} else { } else {
@ -74,8 +82,10 @@ pub fn exec(
match_tests.clone(), match_tests.clone(),
debug, debug,
exact_match, exact_match,
(!no_traces).into(), match keep_traces {
(!no_code_gen_traces).into(), Some(keep_traces) => keep_traces(trace_level),
None => Tracing::All(trace_level),
},
) )
}) })
}; };