From c2b42d668d3042ac19c57fa405d1c59bd6e20bba Mon Sep 17 00:00:00 2001 From: ungaro Date: Sun, 18 Aug 2024 15:37:23 -0400 Subject: [PATCH 1/3] formatting changes --- compiler/passes/src/type_checking/mod.rs | 54 ++++++++++++++++++++++++ errors/src/emitter/mod.rs | 8 ++-- 2 files changed, 58 insertions(+), 4 deletions(-) diff --git a/compiler/passes/src/type_checking/mod.rs b/compiler/passes/src/type_checking/mod.rs index 6aad25b5cd..8a5046b023 100644 --- a/compiler/passes/src/type_checking/mod.rs +++ b/compiler/passes/src/type_checking/mod.rs @@ -40,8 +40,62 @@ impl<'a, N: Network> Pass for TypeChecker<'a, N> { type Output = Result<(SymbolTable, StructGraph, CallGraph)>; fn do_pass((ast, handler, st, tt, max_depth, await_checking): Self::Input) -> Self::Output { + // get program name without consuming AST + let program_name = &ast + .ast + .program_scopes + .keys() + .next() + .map(|s| s.to_string()) + .unwrap_or_else(|| "Unknown program".to_string()); + let mut visitor = TypeChecker::::new(st, tt, handler, max_depth, await_checking); visitor.visit_program(ast.as_repr()); + + // color codes for terminal + const RED: &str = "\x1b[31m"; + const YELLOW: &str = "\x1b[33m"; + const RESET: &str = "\x1b[0m"; + + // get error and warning counts from handler + let inner = handler.inner.borrow(); + let err_count = inner.err_count; + let warn_count = inner.warn_count; + + // if there is at least one error or warning, add two empty lines before report + if err_count + warn_count > 0 { + println!("\n"); + } + + // show warning counts + if warn_count > 0 { + println!( + "{}warning{}: {}.leo generated {} warning{}", + YELLOW, + RESET, + program_name, + warn_count, + if warn_count > 1 { "s" } else { "" } + ); + } + + //show error counts, if warnings emitted include them as well. + if err_count > 0 { + let error_message = format!( + "{}error{}: could not compile {}.leo due to {} previous error{}", + RED, + RESET, + program_name, + err_count, + if err_count > 1 { "s" } else { "" } + ); + if warn_count > 0 { + println!("{}; {} warning{} emitted", error_message, warn_count, if warn_count > 1 { "s" } else { "" }); + } else { + println!("{}", error_message); + } + } + handler.last_err().map_err(|e| *e)?; // Remove unused structs from the struct graph. diff --git a/errors/src/emitter/mod.rs b/errors/src/emitter/mod.rs index 0769b5e06c..17b127b057 100644 --- a/errors/src/emitter/mod.rs +++ b/errors/src/emitter/mod.rs @@ -136,11 +136,11 @@ impl Emitter for BufferEmitter { /// Contains the actual data for `Handler`. /// Modelled this way to afford an API using interior mutability. -struct HandlerInner { +pub struct HandlerInner { /// Number of errors emitted thus far. - err_count: usize, + pub err_count: usize, /// Number of warnings emitted thus far. - warn_count: usize, + pub warn_count: usize, /// The sink through which errors will be emitted. emitter: Box, } @@ -168,7 +168,7 @@ impl HandlerInner { pub struct Handler { /// The inner handler. /// `RefCell` is used here to avoid `&mut` all over the compiler. - inner: RefCell, + pub inner: RefCell, } impl Default for Handler { From 44a92896c109f9640f484d79ff53a96bf17e4f6a Mon Sep 17 00:00:00 2001 From: ungaro Date: Sun, 18 Aug 2024 15:46:39 -0400 Subject: [PATCH 2/3] remove unnecessary space --- compiler/passes/src/type_checking/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/passes/src/type_checking/mod.rs b/compiler/passes/src/type_checking/mod.rs index 8a5046b023..2a3ab72230 100644 --- a/compiler/passes/src/type_checking/mod.rs +++ b/compiler/passes/src/type_checking/mod.rs @@ -70,7 +70,7 @@ impl<'a, N: Network> Pass for TypeChecker<'a, N> { // show warning counts if warn_count > 0 { println!( - "{}warning{}: {}.leo generated {} warning{}", + "{}warning{}: {}.leo generated {} warning{}", YELLOW, RESET, program_name, From 6c0fbc45b300a74156c7576c9761b5bd62db4c19 Mon Sep 17 00:00:00 2001 From: ungaro Date: Mon, 26 Aug 2024 18:36:10 -0400 Subject: [PATCH 3/3] Move error reporting to compiler & fix comments capitalization and punctuation. --- compiler/compiler/src/compiler.rs | 77 ++++++++++++++++++++++-- compiler/passes/src/type_checking/mod.rs | 54 ----------------- 2 files changed, 72 insertions(+), 59 deletions(-) diff --git a/compiler/compiler/src/compiler.rs b/compiler/compiler/src/compiler.rs index 0651c41126..91f5af3b7a 100644 --- a/compiler/compiler/src/compiler.rs +++ b/compiler/compiler/src/compiler.rs @@ -155,18 +155,28 @@ impl<'a, N: Network> Compiler<'a, N> { /// Runs the type checker pass. pub fn type_checker_pass(&'a self, symbol_table: SymbolTable) -> Result<(SymbolTable, StructGraph, CallGraph)> { - let (symbol_table, struct_graph, call_graph) = TypeChecker::::do_pass(( + let type_check_result = TypeChecker::::do_pass(( &self.ast, self.handler, symbol_table, &self.type_table, self.compiler_options.build.conditional_block_max_depth, self.compiler_options.build.disable_conditional_branch_type_checking, - ))?; - if self.compiler_options.output.type_checked_symbol_table { - self.write_symbol_table_to_json("type_checked_symbol_table.json", &symbol_table)?; + )); + + // Always report errors and warnings, regardless of the result, + // because even in the Ok case, there might still be warnings. + self.report_errors_and_warnings(); + + match type_check_result { + Ok((symbol_table, struct_graph, call_graph)) => { + if self.compiler_options.output.type_checked_symbol_table { + self.write_symbol_table_to_json("type_checked_symbol_table.json", &symbol_table)?; + } + Ok((symbol_table, struct_graph, call_graph)) + } + Err(e) => Err(e), } - Ok((symbol_table, struct_graph, call_graph)) } /// Runs the loop unrolling pass. @@ -316,6 +326,63 @@ impl<'a, N: Network> Compiler<'a, N> { Ok(bytecode) } + /// Reports any errors and warnings found during type checking. + fn report_errors_and_warnings(&self) { + // Retrieve error and warning counts. + let inner = self.handler.inner.borrow(); + let err_count = inner.err_count; + let warn_count = inner.warn_count; + + // Color codes for terminal. + const RED: &str = "\x1b[31m"; + const YELLOW: &str = "\x1b[33m"; + const RESET: &str = "\x1b[0m"; + + // Get program name. + let program_name = &self + .ast + .ast + .program_scopes + .keys() + .next() + .map(|s| s.to_string()) + .unwrap_or_else(|| "Unknown program".to_string()); + + // Adds two empty lines before the report if there are any errors or warnings. + if err_count + warn_count > 0 { + println!("\n"); + } + + // Show warning counts. + if warn_count > 0 { + println!( + "{}warning{}: {}.leo generated {} warning{}", + YELLOW, + RESET, + program_name, + warn_count, + if warn_count > 1 { "s" } else { "" } + ); + } + + // Show error counts, if warnings emitted include them as well. + if err_count > 0 { + let error_message = format!( + "{}error{}: could not compile {}.leo due to {} previous error{}", + RED, + RESET, + program_name, + err_count, + if err_count > 1 { "s" } else { "" } + ); + if warn_count > 0 { + println!("{}; {} warning{} emitted", error_message, warn_count, if warn_count > 1 { "s" } else { "" }); + } else { + println!("{}", error_message); + } + } + } + /// Writes the AST to a JSON file. fn write_ast_to_json(&self, file_suffix: &str) -> Result<()> { // Remove `Span`s if they are not enabled. diff --git a/compiler/passes/src/type_checking/mod.rs b/compiler/passes/src/type_checking/mod.rs index 2a3ab72230..6aad25b5cd 100644 --- a/compiler/passes/src/type_checking/mod.rs +++ b/compiler/passes/src/type_checking/mod.rs @@ -40,62 +40,8 @@ impl<'a, N: Network> Pass for TypeChecker<'a, N> { type Output = Result<(SymbolTable, StructGraph, CallGraph)>; fn do_pass((ast, handler, st, tt, max_depth, await_checking): Self::Input) -> Self::Output { - // get program name without consuming AST - let program_name = &ast - .ast - .program_scopes - .keys() - .next() - .map(|s| s.to_string()) - .unwrap_or_else(|| "Unknown program".to_string()); - let mut visitor = TypeChecker::::new(st, tt, handler, max_depth, await_checking); visitor.visit_program(ast.as_repr()); - - // color codes for terminal - const RED: &str = "\x1b[31m"; - const YELLOW: &str = "\x1b[33m"; - const RESET: &str = "\x1b[0m"; - - // get error and warning counts from handler - let inner = handler.inner.borrow(); - let err_count = inner.err_count; - let warn_count = inner.warn_count; - - // if there is at least one error or warning, add two empty lines before report - if err_count + warn_count > 0 { - println!("\n"); - } - - // show warning counts - if warn_count > 0 { - println!( - "{}warning{}: {}.leo generated {} warning{}", - YELLOW, - RESET, - program_name, - warn_count, - if warn_count > 1 { "s" } else { "" } - ); - } - - //show error counts, if warnings emitted include them as well. - if err_count > 0 { - let error_message = format!( - "{}error{}: could not compile {}.leo due to {} previous error{}", - RED, - RESET, - program_name, - err_count, - if err_count > 1 { "s" } else { "" } - ); - if warn_count > 0 { - println!("{}; {} warning{} emitted", error_message, warn_count, if warn_count > 1 { "s" } else { "" }); - } else { - println!("{}", error_message); - } - } - handler.last_err().map_err(|e| *e)?; // Remove unused structs from the struct graph.