From a371b10180a71361fa4588448d95460951d48e78 Mon Sep 17 00:00:00 2001 From: Fernando Araoz Date: Sat, 28 Dec 2024 07:23:38 -0500 Subject: [PATCH] fix: memory leaks on error handling --- src/01_lexic/number.zig | 5 +++++ src/01_lexic/root.zig | 1 + src/01_lexic/token.zig | 1 + src/errors/root.zig | 9 +++++++++ 4 files changed, 16 insertions(+) diff --git a/src/01_lexic/number.zig b/src/01_lexic/number.zig index 6f988e0..c52d5a6 100644 --- a/src/01_lexic/number.zig +++ b/src/01_lexic/number.zig @@ -67,6 +67,7 @@ fn prefixed( if (end_position >= cap or !validator(input[end_position])) { // populate error information try err.init("Incomplete number", start, end_position, alloc); + try err.add_label("Expected a valid digit after the '" ++ [_]u8{prefix} ++ "'", start, end_position); // throw error return LexError.Incomplete; @@ -303,6 +304,7 @@ test "shouldnt parse incomplete hex number" { defer std.testing.allocator.destroy(errdata); const result = lex(input, input.len, 0, errdata, std.testing.allocator) catch |err| { try std.testing.expect(err == token.LexError.Incomplete); + defer errdata.deinit(); return; }; @@ -322,6 +324,7 @@ test "shouldnt parse incomplete hex number 2" { defer std.testing.allocator.destroy(errdata); const result = lex(input, input.len, 0, errdata, std.testing.allocator) catch |err| { try std.testing.expect(err == token.LexError.Incomplete); + defer errdata.deinit(); return; }; @@ -365,6 +368,7 @@ test "shouldnt parse incomplete octal number" { defer std.testing.allocator.destroy(errdata); const result = lex(input, input.len, 0, errdata, std.testing.allocator) catch |err| { try std.testing.expect(err == token.LexError.Incomplete); + defer errdata.deinit(); return; }; @@ -396,6 +400,7 @@ test "shouldnt parse incomplete binary number" { defer std.testing.allocator.destroy(errdata); const result = lex(input, input.len, 0, errdata, std.testing.allocator) catch |err| { try std.testing.expect(err == token.LexError.Incomplete); + defer errdata.deinit(); return; }; diff --git a/src/01_lexic/root.zig b/src/01_lexic/root.zig index 28d282b..8018b7a 100644 --- a/src/01_lexic/root.zig +++ b/src/01_lexic/root.zig @@ -214,6 +214,7 @@ test "should handle recoverable errors" { const input = "322 0b 644"; var error_list = std.ArrayList(errors.ErrorData).init(std.testing.allocator); defer error_list.deinit(); + defer for (error_list.items) |*err| err.deinit(); const arrl = try tokenize(input, std.testing.allocator, &error_list); defer arrl.deinit(); diff --git a/src/01_lexic/token.zig b/src/01_lexic/token.zig index bf1aae1..73d0cca 100644 --- a/src/01_lexic/token.zig +++ b/src/01_lexic/token.zig @@ -41,6 +41,7 @@ pub const LexError = error{ IncompleteScientificNumber, IncompleteString, CRLF, + OutOfMemory, }; /// Contains the lexed token and the next position diff --git a/src/errors/root.zig b/src/errors/root.zig index 0e6907e..08b2252 100644 --- a/src/errors/root.zig +++ b/src/errors/root.zig @@ -10,6 +10,7 @@ pub const ErrorLabel = struct { /// and pretty prints them. pub const ErrorData = struct { reason: []const u8, + help: ?[]const u8, start_position: usize, end_position: usize, labels: std.ArrayList(ErrorLabel), @@ -27,6 +28,7 @@ pub const ErrorData = struct { .start_position = start_position, .end_position = end_position, .labels = std.ArrayList(ErrorLabel).init(alloc), + .help = null, .alloc = alloc, }; } @@ -39,6 +41,11 @@ pub const ErrorData = struct { }); } + /// Sets the help message of this error. + pub fn set_help(self: *@This(), help: []const u8) void { + self.help = help; + } + /// Generates an error string. `alloc` is used to create the string, /// the caller should call `free` on the returning slice. pub fn get_error_str(self: *@This(), source_code: []const u8, filename: []const u8, alloc: std.mem.Allocator) ![]u8 { @@ -238,6 +245,7 @@ test "should gen error message" { const source = "print(ehh)"; var err = ErrorData{ .reason = "Invalid identifier", + .help = null, .start_position = 6, .end_position = 9, .labels = std.ArrayList(ErrorLabel).init(std.testing.allocator), @@ -256,6 +264,7 @@ test "should gen error message with label (1)" { const source = "print(ehh)"; var err = ErrorData{ .reason = "Invalid identifier", + .help = null, .start_position = 6, .end_position = 9, .labels = std.ArrayList(ErrorLabel).init(std.testing.allocator),