From 19116dcbd00a9bbf9b0dd8ae32433a1c104755c5 Mon Sep 17 00:00:00 2001 From: augustin64 Date: Thu, 4 Jan 2024 19:31:48 +0100 Subject: [PATCH 1/3] Pretty print stack trace --- src/errors.cpp | 24 +++++++++++++++++++----- src/include/errors.h | 5 +++++ src/include/utils.h | 5 +++++ src/main.cpp | 7 +------ src/utils.cpp | 10 ++++++++++ 5 files changed, 40 insertions(+), 11 deletions(-) diff --git a/src/errors.cpp b/src/errors.cpp index 0503704..53308b9 100644 --- a/src/errors.cpp +++ b/src/errors.cpp @@ -1,8 +1,10 @@ #include #include +#include #include using namespace std; +#include "include/utils.h" #include "include/errors.h" #include "include/colors.h" #include "include/tokenize.h" @@ -60,14 +62,26 @@ void print_error_position(vector history, CodePosition pos) { if (pos.column == -1 || pos.line == -1) return; - cout << endl; - string line = history[pos.line]; - - printf(BOLD "%4d " RESET , pos.line+1); - cout << line << endl; + cout << endl << BOLD + << setw(4) << setfill(' ') + << pos.line+1 << " " RESET + << history[pos.line] << endl; for (int i=0; i < pos.column + 5; i++) cout << " "; cout << BOLD RED "^--" RESET << endl; +} + +void print_error_stack_trace(vector history, const RuntimeError& error) { + cout << "\n" BOLD "Traceback" RESET " (most recent call last)" << endl; + for (StackTraceEntry e : error.trace) { + cout << BOLD << setw(4) << setfill(' ') + << get<1>(e).line+1 << RESET BLUE + << setw(16) << setfill(' ') + << get<0>(e) << RESET << "\t" + << trim(history[get<1>(e).line]) << endl; + } + + cout << BOLD RED "Runtime Error: " RESET << error.get_message() << endl; } \ No newline at end of file diff --git a/src/include/errors.h b/src/include/errors.h index 408bc5a..4e27a0c 100644 --- a/src/include/errors.h +++ b/src/include/errors.h @@ -115,4 +115,9 @@ public: */ void print_error_position(vector history, CodePosition pos); +/** + * Display the stack trace associated with an error +*/ +void print_error_stack_trace(vector history, const RuntimeError& error); + #endif \ No newline at end of file diff --git a/src/include/utils.h b/src/include/utils.h index 6e9a1f3..be847ed 100644 --- a/src/include/utils.h +++ b/src/include/utils.h @@ -39,4 +39,9 @@ string _debug_get_type_type_name(TypeType type); */ bool equal_types(Type type1, Type type2); +/** + * Trim a string (remove whitespaces before and after) +*/ +string trim(const string& str); + #endif \ No newline at end of file diff --git a/src/main.cpp b/src/main.cpp index a8fc983..780ef16 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -119,12 +119,7 @@ int main(int argc, char* argv[]) { cout << BOLD RED "Type Error: " RESET << e.get_message() << endl; } catch (const RuntimeError& e) { - print_error_position(input, e.pos); - cout << BOLD RED "Runtime Error: " RESET << e.get_message() << endl; - - for (StackTraceEntry e : e.trace) { - cout << get<0>(e) << " " << (get<1>(e).line + 1) << endl; - } + print_error_stack_trace(input, e); } cout << endl; } diff --git a/src/utils.cpp b/src/utils.cpp index a169ef2..022154d 100644 --- a/src/utils.cpp +++ b/src/utils.cpp @@ -111,4 +111,14 @@ bool equal_types(Type type1, Type type2) { return false; break; } +} + +string trim(const string& str) { + size_t first = str.find_first_not_of(" \t\n\r"); + size_t last = str.find_last_not_of(" \t\n\r"); + + if (first == string::npos || last == string::npos) + return ""; // or handle empty string + + return str.substr(first, last - first + 1); } \ No newline at end of file From ac191716d9114f0c0aab977f0af821af87a557b7 Mon Sep 17 00:00:00 2001 From: augustin64 Date: Thu, 4 Jan 2024 19:39:31 +0100 Subject: [PATCH 2/3] Add column number --- src/errors.cpp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/errors.cpp b/src/errors.cpp index 53308b9..ca5fc82 100644 --- a/src/errors.cpp +++ b/src/errors.cpp @@ -76,10 +76,11 @@ void print_error_position(vector history, CodePosition pos) { void print_error_stack_trace(vector history, const RuntimeError& error) { cout << "\n" BOLD "Traceback" RESET " (most recent call last)" << endl; for (StackTraceEntry e : error.trace) { - cout << BOLD << setw(4) << setfill(' ') - << get<1>(e).line+1 << RESET BLUE + cout << BOLD << setw(8) << setfill(' ') + << to_string(get<1>(e).line+1) + ":" + to_string(get<1>(e).column+1) + << RESET BLUE << setw(16) << setfill(' ') - << get<0>(e) << RESET << "\t" + << get<0>(e) << RESET << " \t" << trim(history[get<1>(e).line]) << endl; } From 6a646ecec7b4848ba9e576ade71ef13ab42687fd Mon Sep 17 00:00:00 2001 From: augustin64 Date: Thu, 4 Jan 2024 21:22:35 +0100 Subject: [PATCH 3/3] Add incomplete type error --- src/analysis.cpp | 24 ++++++++++++++++++++++++ src/errors.cpp | 1 + src/include/errors.h | 1 + test/functions.cpp | 12 ++++++++++++ test/variables.cpp | 6 ++++++ 5 files changed, 44 insertions(+) diff --git a/src/analysis.cpp b/src/analysis.cpp index a367361..25fba58 100644 --- a/src/analysis.cpp +++ b/src/analysis.cpp @@ -214,6 +214,9 @@ AnalysisResult analyze(Node &ast, Memory &memory) { throw TypeError(ErrorType::AlreadyDeclaredIdentifier, token.pos, identifier); Type type = try_string_to_type(type_string, type_token.pos); + if (type.type == TypeType::Void) + throw TypeError(ErrorType::IncompleteType, token.pos, {}); + memory.declare(identifier, type); return {}; @@ -229,6 +232,9 @@ AnalysisResult analyze(Node &ast, Memory &memory) { throw TypeError(ErrorType::AlreadyDeclaredIdentifier, token.pos, identifier); Type type = try_string_to_type(type_string, type_token.pos); + if (type.type == TypeType::Void) + throw TypeError(ErrorType::IncompleteType, token.pos, {}); + memory.declare(identifier, type); get_cast(type, analyze(node.children[2], memory), get_node_pos(node)); @@ -295,6 +301,15 @@ AnalysisResult analyze(Node &ast, Memory &memory) { } } + for (int i=1; i < (int)prototype.size(); i++) { + if (get<0>(prototype.at(i)).type == TypeType::Void) { + InnerNode args_node = get(node.children[2]); + InnerNode declaration_node = get(args_node.children[i-1]); + CodePosition type_pos = get_node_pos(declaration_node.children[0]); + throw TypeError(ErrorType::IncompleteType, type_pos, {}); + } + } + memory.declare(function_name, type); return {}; @@ -335,6 +350,15 @@ AnalysisResult analyze(Node &ast, Memory &memory) { } } + for (int i=1; i < (int)prototype.size(); i++) { + if (get<0>(prototype.at(i)).type == TypeType::Void) { + InnerNode args_node = get(node.children[2]); + InnerNode declaration_node = get(args_node.children[i-1]); + CodePosition type_pos = get_node_pos(declaration_node.children[0]); + throw TypeError(ErrorType::IncompleteType, type_pos, {}); + } + } + memory.declare(function_name, type); memory.update(function_name, node.children[3]); diff --git a/src/errors.cpp b/src/errors.cpp index ca5fc82..1a991fa 100644 --- a/src/errors.cpp +++ b/src/errors.cpp @@ -46,6 +46,7 @@ string UserError::get_message(void) const { case ErrorType::IncompatibleDefinition: return "Declaration of '"+get(this->data)+"' is incompatible with previous prototype"; case ErrorType::UnexpectedArgumentCount: return "Expected "+to_string(get(this->data))+" arguments to function call"; case ErrorType::IncompatibleReturnValue: return "Return value type does not match the function type"; + case ErrorType::IncompleteType: return "Incomplete type is not allowed"; // Runtime case ErrorType::UnknownIdentifier: return "Unknown identifier '"+get(this->data)+"'"; diff --git a/src/include/errors.h b/src/include/errors.h index 4e27a0c..4f9f2ae 100644 --- a/src/include/errors.h +++ b/src/include/errors.h @@ -45,6 +45,7 @@ enum class ErrorType { IncompatibleDefinition, // function declaration incompatible with prototype UnexpectedArgumentCount, IncompatibleReturnValue, + IncompleteType, // void x // Runtime UnknownIdentifier, diff --git a/test/functions.cpp b/test/functions.cpp index 5c42735..567af3f 100644 --- a/test/functions.cpp +++ b/test/functions.cpp @@ -98,5 +98,17 @@ int main() { true ); + _TEST_ASSERT( + _TEST_IS_EXCEPTION(execute("int f(int x, void y);"), ErrorType::IncompleteType), + "Argument void (prototype)", + true + ); + + _TEST_ASSERT( + _TEST_IS_EXCEPTION(execute("int f(int x, void y) { return x+2; };"), ErrorType::IncompleteType), + "Argument void (déclaration)", + true + ); + return 0; } \ No newline at end of file diff --git a/test/variables.cpp b/test/variables.cpp index b55ccdc..6938560 100644 --- a/test/variables.cpp +++ b/test/variables.cpp @@ -35,6 +35,12 @@ int main() { true ); + _TEST_ASSERT( + _TEST_IS_EXCEPTION(execute("void x;"), ErrorType::IncompleteType), + "Type void", + true + ); + _TEST_ASSERT( _TEST_NO_EXCEPTION(holds_alternative(execute("int x; { int x; }"))), "Identifieur déjà défini dans une autre scope",