From d27ea98a8ffe47396bc0c788410da553aba9a368 Mon Sep 17 00:00:00 2001 From: KtorZ Date: Wed, 17 Jan 2024 17:23:34 +0100 Subject: [PATCH] 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. --- crates/aiken-lang/src/ast.rs | 51 +++++++++++++----- crates/aiken-lang/src/tests/check.rs | 4 +- crates/aiken-lang/src/tipo/expr.rs | 18 +++---- crates/aiken-lsp/src/server/lsp_project.rs | 11 ++-- crates/aiken-project/src/lib.rs | 29 ++++++----- crates/aiken-project/src/options.rs | 1 - crates/aiken-project/src/tests/mod.rs | 4 +- crates/aiken/src/cmd/blueprint/address.rs | 2 +- crates/aiken/src/cmd/blueprint/hash.rs | 2 +- crates/aiken/src/cmd/blueprint/policy.rs | 2 +- crates/aiken/src/cmd/build.rs | 60 ++++++++++++++++++---- crates/aiken/src/cmd/check.rs | 34 +++++++----- 12 files changed, 145 insertions(+), 73 deletions(-) diff --git a/crates/aiken-lang/src/ast.rs b/crates/aiken-lang/src/ast.rs index 34ce3793..a16e0bf1 100644 --- a/crates/aiken-lang/src/ast.rs +++ b/crates/aiken-lang/src/ast.rs @@ -1360,25 +1360,50 @@ pub enum TraceKind { #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub enum Tracing { - NoTraces, - KeepTraces, + UserDefined(TraceLevel), + CompilerGenerated(TraceLevel), + All(TraceLevel), } -impl From for Tracing { - fn from(keep: bool) -> Self { - if keep { - Tracing::KeepTraces - } else { - Tracing::NoTraces +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub enum TraceLevel { + Silent, // No traces + // 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 { + *lvl + } + } + Tracing::CompilerGenerated(lvl) => { + if is_code_gen { + *lvl + } else { + TraceLevel::Silent + } + } + Tracing::All(lvl) => *lvl, } } } -impl From for bool { - fn from(value: Tracing) -> Self { - match value { - Tracing::NoTraces => false, - Tracing::KeepTraces => true, +impl Display for TraceLevel { + fn fmt(&self, f: &mut std::fmt::Formatter) -> std::result::Result<(), std::fmt::Error> { + match self { + TraceLevel::Silent => f.write_str("silent"), + TraceLevel::Verbose => f.write_str("verbose"), } } } diff --git a/crates/aiken-lang/src/tests/check.rs b/crates/aiken-lang/src/tests/check.rs index 1163b02f..d7bc8eb7 100644 --- a/crates/aiken-lang/src/tests/check.rs +++ b/crates/aiken-lang/src/tests/check.rs @@ -1,5 +1,5 @@ use crate::{ - ast::{Definition, ModuleKind, Tracing, TypedModule, UntypedModule}, + ast::{Definition, ModuleKind, TraceLevel, Tracing, TypedModule, UntypedModule}, builtins, expr::TypedExpr, parser, @@ -31,7 +31,7 @@ fn check_module( kind, "test/project", &module_types, - Tracing::KeepTraces, + Tracing::All(TraceLevel::Verbose), &mut warnings, ); diff --git a/crates/aiken-lang/src/tipo/expr.rs b/crates/aiken-lang/src/tipo/expr.rs index 2c642ae4..83ee53fd 100644 --- a/crates/aiken-lang/src/tipo/expr.rs +++ b/crates/aiken-lang/src/tipo/expr.rs @@ -5,9 +5,9 @@ use crate::{ ast::{ Annotation, Arg, ArgName, AssignmentKind, BinOp, Bls12_381Point, ByteArrayFormatPreference, CallArg, ClauseGuard, Constant, Curve, IfBranch, LogicalOpChainKind, RecordUpdateSpread, - Span, TraceKind, Tracing, TypedArg, TypedCallArg, TypedClause, TypedClauseGuard, - TypedIfBranch, TypedPattern, TypedRecordUpdateArg, UnOp, UntypedArg, UntypedClause, - UntypedClauseGuard, UntypedIfBranch, UntypedPattern, UntypedRecordUpdateArg, + Span, TraceKind, TraceLevel, Tracing, TypedArg, TypedCallArg, TypedClause, + TypedClauseGuard, TypedIfBranch, TypedPattern, TypedRecordUpdateArg, UnOp, UntypedArg, + UntypedClause, UntypedClauseGuard, UntypedIfBranch, UntypedPattern, UntypedRecordUpdateArg, }, builtins::{bool, byte_array, function, g1_element, g2_element, int, list, string, tuple}, expr::{FnStyle, TypedExpr, UntypedExpr}, @@ -436,9 +436,9 @@ impl<'a, 'b> ExprTyper<'a, 'b> { self.unify(bool(), typed_value.tipo(), typed_value.location(), false)?; - match self.tracing { - Tracing::NoTraces => Ok(typed_value), - Tracing::KeepTraces => Ok(TypedExpr::If { + match self.tracing.trace_level(false) { + TraceLevel::Silent => Ok(typed_value), + TraceLevel::Verbose => Ok(TypedExpr::If { location, branches: vec1::vec1![IfBranch { condition: typed_value, @@ -1817,9 +1817,9 @@ impl<'a, 'b> ExprTyper<'a, 'b> { }) } - match self.tracing { - Tracing::NoTraces => Ok(then), - Tracing::KeepTraces => Ok(TypedExpr::Trace { + match self.tracing.trace_level(false) { + TraceLevel::Silent => Ok(then), + TraceLevel::Verbose => Ok(TypedExpr::Trace { location, tipo, then: Box::new(then), diff --git a/crates/aiken-lsp/src/server/lsp_project.rs b/crates/aiken-lsp/src/server/lsp_project.rs index 4c40367a..b2c8ac70 100644 --- a/crates/aiken-lsp/src/server/lsp_project.rs +++ b/crates/aiken-lsp/src/server/lsp_project.rs @@ -32,14 +32,9 @@ impl LspProject { pub fn compile(&mut self) -> Result<(), Vec> { let checkpoint = self.project.checkpoint(); - let result = self.project.check( - true, - None, - false, - false, - Tracing::NoTraces, - Tracing::NoTraces, - ); + let result = self + .project + .check(true, None, false, false, Tracing::silent()); self.project.restore(checkpoint); diff --git a/crates/aiken-project/src/lib.rs b/crates/aiken-project/src/lib.rs index 1ac2a935..2647c8fb 100644 --- a/crates/aiken-project/src/lib.rs +++ b/crates/aiken-project/src/lib.rs @@ -22,7 +22,10 @@ use crate::blueprint::{ Blueprint, }; use aiken_lang::{ - ast::{Definition, Function, ModuleKind, Tracing, TypedDataType, TypedFunction, Validator}, + ast::{ + Definition, Function, ModuleKind, TraceLevel, Tracing, TypedDataType, TypedFunction, + Validator, + }, builtins, gen_uplc::builder::{DataTypeKey, FunctionAccessKey}, tipo::TypeInfo, @@ -151,16 +154,10 @@ where self.defined_modules = checkpoint.defined_modules; } - pub fn build( - &mut self, - uplc: bool, - tracing: Tracing, - code_gen_tracing: Tracing, - ) -> Result<(), Vec> { + pub fn build(&mut self, uplc: bool, tracing: Tracing) -> Result<(), Vec> { let options = Options { code_gen_mode: CodeGenMode::Build(uplc), tracing, - code_gen_tracing, }; self.compile(options) @@ -182,7 +179,7 @@ where 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 { output_path: destination.clone(), @@ -216,11 +213,9 @@ where verbose: bool, exact_match: bool, tracing: Tracing, - code_gen_tracing: Tracing, ) -> Result<(), Vec> { let options = Options { tracing, - code_gen_tracing, code_gen_mode: if skip_tests { CodeGenMode::NoOp } else { @@ -290,7 +285,10 @@ where &self.functions, &self.data_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) @@ -323,7 +321,10 @@ where verbose, match_tests, exact_match, - options.code_gen_tracing.into(), + match options.tracing.trace_level(true) { + TraceLevel::Silent => false, + TraceLevel::Verbose => true, + }, )?; if !tests.is_empty() { @@ -530,7 +531,7 @@ where 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(()) diff --git a/crates/aiken-project/src/options.rs b/crates/aiken-project/src/options.rs index 2d147604..2da0d13d 100644 --- a/crates/aiken-project/src/options.rs +++ b/crates/aiken-project/src/options.rs @@ -3,7 +3,6 @@ use aiken_lang::ast::Tracing; pub struct Options { pub code_gen_mode: CodeGenMode, pub tracing: Tracing, - pub code_gen_tracing: Tracing, } pub enum CodeGenMode { diff --git a/crates/aiken-project/src/tests/mod.rs b/crates/aiken-project/src/tests/mod.rs index 0c2ed35f..bd5eb1e7 100644 --- a/crates/aiken-project/src/tests/mod.rs +++ b/crates/aiken-project/src/tests/mod.rs @@ -2,7 +2,7 @@ use std::collections::HashMap; use std::path::PathBuf; use aiken_lang::{ - ast::{ModuleKind, Tracing, TypedDataType, TypedFunction}, + ast::{ModuleKind, TraceLevel, Tracing, TypedDataType, TypedFunction}, gen_uplc::builder::{DataTypeKey, FunctionAccessKey}, parser, tipo::TypeInfo, @@ -81,7 +81,7 @@ impl TestProject { module.kind, &self.package.to_string(), &self.module_types, - Tracing::KeepTraces, + Tracing::All(TraceLevel::Verbose), &mut warnings, ) .expect("Failed to type-check module"); diff --git a/crates/aiken/src/cmd/blueprint/address.rs b/crates/aiken/src/cmd/blueprint/address.rs index 18889e8f..1d83b69d 100644 --- a/crates/aiken/src/cmd/blueprint/address.rs +++ b/crates/aiken/src/cmd/blueprint/address.rs @@ -36,7 +36,7 @@ pub fn exec( ) -> miette::Result<()> { with_project(directory.as_deref(), false, |p| { if rebuild { - p.build(false, Tracing::NoTraces, Tracing::NoTraces)?; + p.build(false, Tracing::silent())?; } let title = module.as_ref().map(|m| { diff --git a/crates/aiken/src/cmd/blueprint/hash.rs b/crates/aiken/src/cmd/blueprint/hash.rs index 4dbf10f7..effe5e7f 100644 --- a/crates/aiken/src/cmd/blueprint/hash.rs +++ b/crates/aiken/src/cmd/blueprint/hash.rs @@ -31,7 +31,7 @@ pub fn exec( ) -> miette::Result<()> { with_project(directory.as_deref(), false, |p| { if rebuild { - p.build(false, Tracing::NoTraces, Tracing::NoTraces)?; + p.build(false, Tracing::silent())?; } let title = module.as_ref().map(|m| { diff --git a/crates/aiken/src/cmd/blueprint/policy.rs b/crates/aiken/src/cmd/blueprint/policy.rs index 1d7fc536..80c90d4c 100644 --- a/crates/aiken/src/cmd/blueprint/policy.rs +++ b/crates/aiken/src/cmd/blueprint/policy.rs @@ -31,7 +31,7 @@ pub fn exec( ) -> miette::Result<()> { with_project(directory.as_deref(), false, |p| { if rebuild { - p.build(false, Tracing::NoTraces, Tracing::NoTraces)?; + p.build(false, Tracing::silent())?; } let title = module.as_ref().map(|m| { diff --git a/crates/aiken/src/cmd/build.rs b/crates/aiken/src/cmd/build.rs index 2ac1e44d..f9da1a6a 100644 --- a/crates/aiken/src/cmd/build.rs +++ b/crates/aiken/src/cmd/build.rs @@ -1,4 +1,7 @@ +use aiken_lang::ast::{TraceLevel, Tracing}; use aiken_project::watch::{self, watch_project, with_project}; +use clap::builder::MapValueParser; +use clap::builder::{PossibleValuesParser, TypedValueParser}; use std::{path::PathBuf, process}; #[derive(clap::Args)] @@ -19,13 +22,18 @@ pub struct Args { #[clap(short, long)] uplc: bool, - /// Do not remove traces when generating code - #[clap(short, long)] - keep_traces: bool, + /// Do not remove traces when generating code. + #[clap(short, long, value_parser=keep_traces_parser(), default_missing_value="all")] + keep_traces: Option Tracing>, - /// Add code gen traces when generating code - #[clap(short, long)] - code_gen_traces: bool, + /// Choose the level of tracing + /// - silent: disable traces altogether + /// - 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( @@ -35,18 +43,52 @@ pub fn exec( watch, uplc, keep_traces, - code_gen_traces, + trace_level, }: Args, ) -> miette::Result<()> { let result = if watch { 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 { 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)) } + +#[allow(clippy::type_complexity)] +pub fn keep_traces_parser( +) -> MapValueParser 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 TraceLevel> { + PossibleValuesParser::new(["silent", "verbose"]).map(|s| match s.as_str() { + "silent" => TraceLevel::Silent, + "verbose" => TraceLevel::Verbose, + _ => unreachable!(), + }) +} diff --git a/crates/aiken/src/cmd/check.rs b/crates/aiken/src/cmd/check.rs index 2b1f21ca..c0628b20 100644 --- a/crates/aiken/src/cmd/check.rs +++ b/crates/aiken/src/cmd/check.rs @@ -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 std::{path::PathBuf, process}; @@ -34,13 +36,17 @@ pub struct Args { #[clap(short, long)] exact_match: bool, - /// Remove traces when generating code (including tests) - #[clap(long)] - no_traces: bool, + /// Do not remove traces when generating code + #[clap(short, long, value_parser=keep_traces_parser(), default_missing_value="all")] + keep_traces: Option Tracing>, - /// Remove code gen traces when generating code (including tests) - #[clap(long)] - no_code_gen_traces: bool, + /// Choose the level of tracing + /// - silent: disable traces altogether + /// - 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( @@ -51,9 +57,9 @@ pub fn exec( debug, match_tests, exact_match, - no_traces, - no_code_gen_traces, watch, + keep_traces, + trace_level, }: Args, ) -> miette::Result<()> { let result = if watch { @@ -63,8 +69,10 @@ pub fn exec( match_tests.clone(), debug, exact_match, - (!no_traces).into(), - (!no_code_gen_traces).into(), + match keep_traces { + Some(keep_traces) => keep_traces(trace_level), + None => Tracing::All(trace_level), + }, ) }) } else { @@ -74,8 +82,10 @@ pub fn exec( match_tests.clone(), debug, exact_match, - (!no_traces).into(), - (!no_code_gen_traces).into(), + match keep_traces { + Some(keep_traces) => keep_traces(trace_level), + None => Tracing::All(trace_level), + }, ) }) };