202 lines
7.7 KiB
C
Raw Normal View History

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "types.h"
#include "error.h"
extern Token tokens[];
extern int tk_idx;
extern int pc;
extern CallStack call_stack;
void push_call_frame(const char *function_name, const char *filename, int line, int is_native) {
if (call_stack.depth >= MAX_CALL_STACK) {
return;
}
CallStackFrame *frame = &call_stack.frames[call_stack.depth];
frame->function_name = function_name;
frame->filename = filename;
frame->line = line;
frame->is_native = is_native;
call_stack.depth++;
}
void pop_call_frame() {
if (call_stack.depth > 0) {
call_stack.depth--;
}
}
void print_stacktrace() {
if (call_stack.depth == 0) {
return;
}
fprintf(stderr, "\n");
fprintf(stderr, "╔════════════════════════════════════════════════════════════════╗\n");
fprintf(stderr, "║ STACK TRACE ║\n");
fprintf(stderr, "╚════════════════════════════════════════════════════════════════╝\n");
int frames_to_show = call_stack.depth;
if (frames_to_show > 10) {
frames_to_show = 10;
}
for (int i = call_stack.depth - 1; i >= call_stack.depth - frames_to_show; i--) {
if (i < 0) break;
CallStackFrame *frame = &call_stack.frames[i];
const char *type_marker = frame->is_native ? "[native]" : "[script]";
fprintf(stderr, " %s ", type_marker);
if (frame->function_name) {
fprintf(stderr, "%s()", frame->function_name);
} else {
fprintf(stderr, "<anonymous>");
}
if (frame->filename && frame->line > 0) {
fprintf(stderr, "\n at %s:%d", frame->filename, frame->line);
} else if (frame->filename) {
fprintf(stderr, "\n at %s", frame->filename);
}
fprintf(stderr, "\n");
}
if (call_stack.depth > 10) {
fprintf(stderr, " ... %d more frames\n", call_stack.depth - 10);
}
fprintf(stderr, "\n");
}
static const char* get_error_tip(const char *error_type, const char *message) {
if (strstr(message, "index out of bounds") || strstr(message, "Token index")) {
return "Check array bounds and ensure index is within valid range";
}
if (strstr(message, "Too many")) {
return "Consider breaking down into smaller components or increasing limits";
}
if (strstr(message, "Stack overflow")) {
return "Reduce recursion depth or local variable usage";
}
if (strstr(message, "Undefined variable")) {
return "Ensure variable is declared before use with: int varname;";
}
if (strstr(message, "Unknown function")) {
return "Check function name spelling and ensure it's defined before calling";
}
if (strstr(message, "Unexpected token")) {
return "Check for missing semicolons, braces, or parentheses";
}
if (strstr(message, "division by zero") || strstr(message, "divide by zero")) {
return "Add a check: if (divisor != 0) before division";
}
if (strstr(message, "Null pointer")) {
return "Check if pointer is null before dereferencing: if (ptr != null)";
}
if (strstr(message, "Memory")) {
return "Reduce memory usage or check for memory leaks";
}
if (strstr(message, "Unknown class") || strstr(message, "Unknown field") ||
strstr(message, "Unknown method")) {
return "Verify class/field/method name and ensure class is defined";
}
return "Review the code at the error location and check for typos";
}
static void print_code_context(int token_index) {
if (token_index < 0 || token_index >= tk_idx) {
return;
}
Token *error_token = &tokens[token_index];
if (!error_token->filename || error_token->line <= 0) {
return;
}
fprintf(stderr, "\n");
fprintf(stderr, "╔════════════════════════════════════════════════════════════════╗\n");
fprintf(stderr, "║ CODE CONTEXT ║\n");
fprintf(stderr, "╚════════════════════════════════════════════════════════════════╝\n");
int start_token = token_index - 3;
int end_token = token_index + 3;
if (start_token < 0) start_token = 0;
if (end_token >= tk_idx) end_token = tk_idx - 1;
for (int i = start_token; i <= end_token && i < tk_idx; i++) {
if (i < 0) continue;
Token *t = &tokens[i];
const char *marker = (i == token_index) ? ">>> " : " ";
fprintf(stderr, "%s", marker);
if (t->type >= 32 && t->type < 127) {
fprintf(stderr, "'%c' ", t->type);
} else if (t->type == Num) {
fprintf(stderr, "%ld ", t->val);
} else if (t->type == Id && t->text) {
fprintf(stderr, "%.*s ", (int)t->val, t->text);
} else if (t->type == Str && t->text) {
fprintf(stderr, "\"%s\" ", t->text);
} else {
fprintf(stderr, "[token:%d] ", t->type);
}
if (i == token_index) {
fprintf(stderr, "<-- ERROR HERE");
}
fprintf(stderr, "\n");
}
fprintf(stderr, "\n");
}
void error_with_context(const char *error_type, const char *message, const char *tip) {
fprintf(stderr, "\n");
fprintf(stderr, "╔════════════════════════════════════════════════════════════════╗\n");
fprintf(stderr, "║ RUNTIME ERROR ║\n");
fprintf(stderr, "╚════════════════════════════════════════════════════════════════╝\n");
fprintf(stderr, "\n");
fprintf(stderr, " Error Type: %s\n", error_type ? error_type : "General Error");
fprintf(stderr, " Message: %s\n", message);
if (pc >= 0 && pc < tk_idx) {
Token *current_token = &tokens[pc];
if (current_token->filename) {
fprintf(stderr, " Location: %s", current_token->filename);
if (current_token->line > 0) {
fprintf(stderr, ":%d", current_token->line);
if (current_token->column > 0) {
fprintf(stderr, ":%d", current_token->column);
}
}
fprintf(stderr, "\n");
}
}
fprintf(stderr, "\n");
const char *actual_tip = tip ? tip : get_error_tip(error_type, message);
if (actual_tip) {
fprintf(stderr, "╔════════════════════════════════════════════════════════════════╗\n");
fprintf(stderr, "║ TIP ║\n");
fprintf(stderr, "╚════════════════════════════════════════════════════════════════╝\n");
fprintf(stderr, " 💡 %s\n", actual_tip);
}
print_code_context(pc);
print_stacktrace();
exit(1);
}