Skip to content

Instantly share code, notes, and snippets.

@ArnaudValensi
Last active June 5, 2023 10:06
Show Gist options
  • Save ArnaudValensi/9f0077bad262b96408e3dae47866f82d to your computer and use it in GitHub Desktop.
Save ArnaudValensi/9f0077bad262b96408e3dae47866f82d to your computer and use it in GitHub Desktop.
Jai panic and assert with pretty stack trace
/*
██████████ █████
░░███░░░░███ ░░███
░███ ░░███ ██████ ░███████ █████ ████ ███████
░███ ░███ ███░░███ ░███░░███░░███ ░███ ███░░███
░███ ░███░███████ ░███ ░███ ░███ ░███ ░███ ░███
░███ ███ ░███░░░ ░███ ░███ ░███ ░███ ░███ ░███
██████████ ░░██████ ████████ ░░████████░░███████
░░░░░░░░░░ ░░░░░░ ░░░░░░░░ ░░░░░░░░ ░░░░░███
███ ░███
░░██████
░░░░░░
*/
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);
}
@ArnaudValensi
Copy link
Author

Assert

image

Panic

image

Stacktrace

The print_stack_trace_with_code function can be use independently.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment