2025-11-24 01:59:54 +01:00
|
|
|
#include <stdio.h>
|
|
|
|
|
#include <stdlib.h>
|
|
|
|
|
#include <string.h>
|
2025-11-24 08:55:17 +01:00
|
|
|
#include <pthread.h>
|
2025-11-24 01:59:54 +01:00
|
|
|
#include "types.h"
|
|
|
|
|
#include "error.h"
|
|
|
|
|
|
|
|
|
|
extern Token tokens[];
|
|
|
|
|
extern int tk_idx;
|
|
|
|
|
extern int pc;
|
|
|
|
|
extern CallStack call_stack;
|
2025-11-24 08:55:17 +01:00
|
|
|
extern pthread_rwlock_t tokens_rwlock;
|
2025-11-24 01:59:54 +01:00
|
|
|
|
|
|
|
|
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) {
|
2025-11-24 08:55:17 +01:00
|
|
|
if (pthread_rwlock_tryrdlock(&tokens_rwlock) != 0) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2025-11-24 01:59:54 +01:00
|
|
|
if (token_index < 0 || token_index >= tk_idx) {
|
2025-11-24 08:55:17 +01:00
|
|
|
pthread_rwlock_unlock(&tokens_rwlock);
|
2025-11-24 01:59:54 +01:00
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Token *error_token = &tokens[token_index];
|
|
|
|
|
if (!error_token->filename || error_token->line <= 0) {
|
2025-11-24 08:55:17 +01:00
|
|
|
pthread_rwlock_unlock(&tokens_rwlock);
|
2025-11-24 01:59:54 +01:00
|
|
|
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");
|
2025-11-24 08:55:17 +01:00
|
|
|
pthread_rwlock_unlock(&tokens_rwlock);
|
2025-11-24 01:59:54 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
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);
|
|
|
|
|
}
|