Last active
June 5, 2023 10:06
-
-
Save ArnaudValensi/9f0077bad262b96408e3dae47866f82d to your computer and use it in GitHub Desktop.
Jai panic and assert with pretty stack trace
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
██████████ █████ | |
░░███░░░░███ ░░███ | |
░███ ░░███ ██████ ░███████ █████ ████ ███████ | |
░███ ░███ ███░░███ ░███░░███░░███ ░███ ███░░███ | |
░███ ░███░███████ ░███ ░███ ░███ ░███ ░███ ░███ | |
░███ ███ ░███░░░ ░███ ░███ ░███ ░███ ░███ ░███ | |
██████████ ░░██████ ████████ ░░████████░░███████ | |
░░░░░░░░░░ ░░░░░░ ░░░░░░░░ ░░░░░░░░ ░░░░░███ | |
███ ░███ | |
░░██████ | |
░░░░░░ | |
*/ | |
panic :: (format_string: string, args: .. Any) { | |
builder: String_Builder; | |
append(*builder, "------------------------- PANIC -------------------------\n"); | |
print_to_builder(*builder, format_string, ..args); | |
append(*builder, "\n"); | |
s := builder_to_string(*builder); | |
write_string(s, to_standard_error = true); | |
print_stack_trace_with_code(context.stack_trace); | |
write_string("---------------------------------------------------------\n", to_standard_error = true); | |
debug_break(); | |
free_buffers(*builder); | |
} | |
// To replace the default assertion handling function, we have to register the new one in the | |
// context: | |
// | |
// ``` | |
// context.assertion_failed = assertion_failed; | |
// ``` | |
// | |
// Then we can just call the `assert` function anywhere: | |
// | |
// ``` | |
// assert(1 == 2); | |
// ``` | |
// | |
assertion_failed :: (loc: Source_Code_Location, message: string) { | |
write_string("-------------------- ASSERTION FAILED -------------------\n", to_standard_error = true); | |
// Only display the file and line when no stack trace is available. | |
if !context.stack_trace { | |
write_string("at: ", to_standard_error = true); | |
write_string(loc.fully_pathed_filename, to_standard_error = true); | |
write_string(":", to_standard_error = true); | |
write_nonnegative_number(xx loc.line_number, to_standard_error = true); | |
write_string("\n", to_standard_error = true); | |
} | |
if message { | |
write_string(message, to_standard_error = true); | |
write_string("\n", to_standard_error = true); | |
} | |
if context.stack_trace { | |
// Skip one frame. | |
print_stack_trace_with_code(context.stack_trace.next); | |
} else { | |
write_string("Exiting...\n", to_standard_error = true); | |
} | |
write_string("---------------------------------------------------------\n", to_standard_error = true); | |
__runtime_support_disable_stack_trace = true; | |
debug_break(); | |
} | |
// Note: if the function fails to display anonymous procedure, check the code of | |
// runtime_support_assertion_failed in Jai. | |
print_stack_trace_with_code :: (node: *Stack_Trace_Node, to_standard_error := true) { | |
set_console_color :: (builder: *String_Builder, color: Print_Color.Console_Color) { | |
print_to_builder(builder, "\e[%m", cast(int) color); | |
} | |
reset_console_color :: (builder: *String_Builder) { | |
append(builder, "\e[0m"); | |
} | |
indent :: (builder: *String_Builder, size: int) { | |
for 1..size append(builder, " "); | |
} | |
print_line_with_context :: (builder: *String_Builder, file: string, line: int, padding_size: int, context_size := 3) { | |
str, success := File.read_entire_file(file); | |
if !success return; | |
lines := split(str, "\n"); | |
focused_line := line - 1; | |
start := max(focused_line - context_size, 0); | |
end := min(lines.count - 1, focused_line + context_size); | |
for current_line: start..end { | |
indent(builder, padding_size); | |
if current_line == focused_line set_console_color(builder, .BLUE); | |
print_to_builder( | |
builder, | |
"% ", | |
formatInt(current_line + 1, minimum_digits=padding_size, padding=#char" ") | |
); | |
if current_line == focused_line { | |
append(builder, "> "); | |
} else { | |
append(builder, "| "); | |
} | |
print_to_builder(builder, "%\n", lines[current_line]); | |
if current_line == focused_line reset_console_color(builder); | |
} | |
} | |
builder: String_Builder; | |
init_string_builder(*builder); | |
stack_item_padding_size := tprint("%", node.call_depth - 1).count; | |
count := 0; | |
while node { | |
if node.info { | |
function := node.info.name; | |
file := node.info.location.fully_pathed_filename; | |
line := node.line_number; | |
print_to_builder( | |
*builder, | |
"%: ", | |
formatInt(count, minimum_digits=stack_item_padding_size, padding=#char" ") | |
); | |
set_console_color(*builder, .GREEN); | |
append(*builder, function); | |
reset_console_color(*builder); | |
append(*builder, "\n"); | |
indent(*builder, stack_item_padding_size + 2); | |
print_to_builder(*builder, "at %:%\n", file, line); | |
print_line_with_context(*builder, file, line, stack_item_padding_size + 4); | |
} | |
node = node.next; | |
count += 1; | |
} | |
s := builder_to_string(*builder); | |
write_string(s, to_standard_error = to_standard_error); | |
free_buffers(*builder); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Assert
Panic
Stacktrace
The print_stack_trace_with_code function can be use independently.