#include #include #include #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, ""); } 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); }