diff --git a/src/errors/root.zig b/src/errors/root.zig index e157813..0d7046d 100644 --- a/src/errors/root.zig +++ b/src/errors/root.zig @@ -22,13 +22,22 @@ pub const ErrorData = struct { /// 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, alloc: std.mem.Allocator) ![]u8 { + pub fn get_error_str(self: *@This(), source_code: []const u8, filename: []const u8, alloc: std.mem.Allocator) ![]u8 { const faulty_line = get_line(source_code, self.start_position); const error_message = try std.fmt.allocPrint(alloc, \\Error: {s} - \\{s} - , .{ self.reason, faulty_line }); + \\[{s}:{d}:{d}] + \\ + \\ {d} | {s} + , .{ + self.reason, + filename, + faulty_line.line_number, + faulty_line.column_number, + faulty_line.line_number, + faulty_line.line, + }); return error_message; } @@ -44,7 +53,16 @@ pub const ErrorData = struct { } }; -fn get_line(input: []const u8, at: usize) []const u8 { +const LineInfo = struct { + line: []const u8, + /// 1 based + line_number: usize, + /// 1 based + column_number: usize, +}; + +fn get_line(input: []const u8, at: usize) LineInfo { + var line_number: usize = 1; var line_start: usize = 0; var line_end: usize = 0; var current_pos: usize = 0; @@ -54,9 +72,13 @@ fn get_line(input: []const u8, at: usize) []const u8 { while (current_pos < cap and current_pos < at) : (current_pos += 1) { if (input[current_pos] == '\n' and current_pos + 1 < cap) { line_start = current_pos + 1; + line_number += 1; } } + // compute the column number + const column_number: usize = current_pos - line_start + 1; + // search the end pos of the line while (current_pos < cap) : (current_pos += 1) { // EOF is EOL @@ -71,7 +93,11 @@ fn get_line(input: []const u8, at: usize) []const u8 { } } - return input[line_start..line_end]; + return .{ + .line = input[line_start..line_end], + .line_number = line_number, + .column_number = column_number, + }; } test { @@ -83,7 +109,9 @@ test "should get a single line" { const at = 4; const output = get_line(input, at); - try std.testing.expectEqualStrings("print(hello)", output); + try std.testing.expectEqualStrings("print(hello)", output.line); + try std.testing.expectEqual(1, output.line_number); + try std.testing.expectEqual(5, output.column_number); } test "should get line from 2 lines (1)" { @@ -91,7 +119,9 @@ test "should get line from 2 lines (1)" { const at = 4; const output = get_line(input, at); - try std.testing.expectEqualStrings("print(hello)", output); + try std.testing.expectEqualStrings("print(hello)", output.line); + try std.testing.expectEqual(1, output.line_number); + try std.testing.expectEqual(5, output.column_number); } test "should get line from 2 lines (2)" { @@ -99,7 +129,9 @@ test "should get line from 2 lines (2)" { const at = 15; const output = get_line(input, at); - try std.testing.expectEqualStrings("print(bye)", output); + try std.testing.expectEqualStrings("print(bye)", output.line); + try std.testing.expectEqual(2, output.line_number); + try std.testing.expectEqual(3, output.column_number); } test "should get line from 2 lines (3)" { @@ -107,7 +139,9 @@ test "should get line from 2 lines (3)" { const at = 15; const output = get_line(input, at); - try std.testing.expectEqualStrings("print(sure?)", output); + try std.testing.expectEqualStrings("print(sure?)", output.line); + try std.testing.expectEqual(2, output.line_number); + try std.testing.expectEqual(3, output.column_number); } test "should gen error message" { @@ -118,11 +152,13 @@ test "should gen error message" { .start_position = 6, .end_position = 9, }; - const out = try err.get_error_str(source, std.testing.allocator); + const out = try err.get_error_str(source, "repl", std.testing.allocator); defer std.testing.allocator.free(out); try std.testing.expectEqualStrings( \\Error: Invalid identifier - \\print(ehh) + \\[repl:1:7] + \\ + \\ 1 | print(ehh) , out); }