#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <stdarg.h>
#include <math.h>
#include <time.h>

#ifdef _WIN32
    #include <windows.h>
    #include <wininet.h>
    #define OS_WINDOWS 1
#else
    #include <sys/utsname.h>
    #include <sys/stat.h>
    #include <unistd.h>
    #define OS_WINDOWS 0
#endif

#define VERSION "B-5"
#define MAX_TOKENS 8192
#define MAX_VARS 512
#define MAX_LINE 8192
#define MAX_STRING 2048
#define MAX_ARRAY_SIZE 1024

typedef enum {
    TOKEN_EOF,
    TOKEN_IDENTIFIER,
    TOKEN_STRING,
    TOKEN_NUMBER,
    TOKEN_PRINT,
    TOKEN_VAR,
    TOKEN_IF,
    TOKEN_WHILE,
    TOKEN_FOR,
    TOKEN_FUNCTION,
    TOKEN_RETURN,
    TOKEN_ELSE,
    TOKEN_LPAREN,
    TOKEN_RPAREN,
    TOKEN_LBRACE,
    TOKEN_RBRACE,
    TOKEN_LBRACKET,
    TOKEN_RBRACKET,
    TOKEN_COMMA,
    TOKEN_SEMICOLON,
    TOKEN_ASSIGN,
    TOKEN_PLUS,
    TOKEN_MINUS,
    TOKEN_MULTIPLY,
    TOKEN_DIVIDE,
    TOKEN_EQUAL,
    TOKEN_NOT_EQUAL,
    TOKEN_GREATER,
    TOKEN_LESS,
    TOKEN_AND,
    TOKEN_OR,
    TOKEN_NOT,
    TOKEN_GREATER_EQUAL,
    TOKEN_LESS_EQUAL,
    TOKEN_MODULO,
    TOKEN_PLUS_ASSIGN,
    TOKEN_MINUS_ASSIGN,
    TOKEN_MULTIPLY_ASSIGN,
    TOKEN_DIVIDE_ASSIGN,
    TOKEN_MODULO_ASSIGN,
    TOKEN_INCREMENT,
    TOKEN_DECREMENT,
    TOKEN_COLON,
    TOKEN_DOT,
    TOKEN_ARROW,
    TOKEN_SWITCH,
    TOKEN_CASE,
    TOKEN_DEFAULT,
    TOKEN_BREAK,
    TOKEN_CONTINUE,
    TOKEN_DO,
    TOKEN_STRUCT,
    TOKEN_TYPEDEF,
    TOKEN_ENUM,
    TOKEN_GOTO,
    TOKEN_BIT_AND,
    TOKEN_BIT_OR,
    TOKEN_BIT_XOR,
    TOKEN_BIT_NOT,
    TOKEN_SHIFT_LEFT,
    TOKEN_SHIFT_RIGHT,
    TOKEN_NEW,
    TOKEN_DELETE,
    TOKEN_TRY,
    TOKEN_CATCH,
    TOKEN_THROW,
    TOKEN_ASTERISK,
    TOKEN_LABEL
} OraTokenType;

typedef struct {
    OraTokenType type;
    char value[MAX_STRING];
    int line;
} Token;

typedef enum {
    VAL_NUMBER,
    VAL_STRING,
    VAL_ARRAY,
    VAL_STRUCT,
    VAL_ENUM,
    VAL_POINTER
} ValueType;

typedef struct {
    ValueType type;
    double num_value;
    char str_value[MAX_STRING];
    double arr_value[MAX_ARRAY_SIZE];
    int arr_size;
    int struct_type;
    int pointer_target;
} Value;

typedef struct {
    char name[64];
    Value value;
} Variable;

typedef struct {
    char name[64];
    int param_count;
    char params[8][64];
    int body_start;
    int body_end;
} Function;

typedef struct {
    char name[64];
    char fields[16][64];
    int field_count;
} StructType;

typedef struct {
    char name[64];
    char values[16][64];
    int value_count;
} EnumType;

typedef struct {
    char name[64];
    int token_index;
} Label;

Token tokens[MAX_TOKENS];
int token_count = 0;
int current_token = 0;
Variable vars[MAX_VARS];
int var_count = 0;
Function funcs[MAX_VARS];
int func_count = 0;
StructType structs[MAX_VARS];
int struct_count = 0;
EnumType enums[MAX_VARS];
int enum_count = 0;
Label labels[MAX_VARS];
int label_count = 0;
int print_newline = 1;
int current_line = 1;
int in_for_loop_update = 0;
int in_repl = 0;
int loop_depth = 0;
int switch_active = 0;

int match(OraTokenType type);
Value* find_variable(const char* name);

static const struct {
    const char* name;
    OraTokenType type;
} keywords[] = {
    {"echo", TOKEN_PRINT},
    {"let", TOKEN_VAR},
    {"if", TOKEN_IF},
    {"else", TOKEN_ELSE},
    {"while", TOKEN_WHILE},
    {"for", TOKEN_FOR},
    {"proc", TOKEN_FUNCTION},
    {"return", TOKEN_RETURN},
    {"switch", TOKEN_SWITCH},
    {"case", TOKEN_CASE},
    {"default", TOKEN_DEFAULT},
    {"break", TOKEN_BREAK},
    {"continue", TOKEN_CONTINUE},
    {"do", TOKEN_DO},
    {"struct", TOKEN_STRUCT},
    {"typedef", TOKEN_TYPEDEF},
    {"enum", TOKEN_ENUM},
    {"goto", TOKEN_GOTO},
    {"new", TOKEN_NEW},
    {"delete", TOKEN_DELETE},
    {"try", TOKEN_TRY},
    {"catch", TOKEN_CATCH},
    {"throw", TOKEN_THROW},
    {NULL, TOKEN_EOF}
};

void error(const char* msg, ...) {
    va_list args;
    va_start(args, msg);
    fprintf(stderr, "[Error at line %d] ", current_line);
    vfprintf(stderr, msg, args);
    fprintf(stderr, "\n");
    va_end(args);
    if (in_repl) return;
    exit(1);
}

static const char* get_string_value() {
    if (match(TOKEN_STRING)) {
        return tokens[current_token - 1].value;
    } else if (match(TOKEN_IDENTIFIER)) {
        const char* name = tokens[current_token - 1].value;
        Value* v = find_variable(name);
        if (!v || v->type != VAL_STRING) {
            error("Expected string variable: %s", name);
        }
        return v->str_value;
    }
    error("Expected string");
    return "";
}

static void skip_whitespace_and_comments(const char** p) {
    while (**p) {
        if (**p == ' ' || **p == '\t' || **p == '\r') {
            (*p)++;
        } else if (**p == '\n') {
            (*p)++;
            current_line++;
        } else if (**p == '#' || (**p == '/' && *(*p+1) == '/')) {
            while (**p && **p != '\n') (*p)++;
        } else if (**p == '/' && *(*p+1) == '*') {
            (*p) += 2;
            while (**p && !(*(*p) == '*' && *(*p+1) == '/')) {
                if (**p == '\n') current_line++;
                (*p)++;
            }
            if (**p) (*p) += 2;
        } else {
            break;
        }
    }
}

static void add_token(OraTokenType type, const char* value) {
    if (token_count >= MAX_TOKENS) {
        error("Too many tokens (max %d)", MAX_TOKENS);
    }
    tokens[token_count].type = type;
    strncpy(tokens[token_count].value, value, MAX_STRING - 1);
    tokens[token_count].value[MAX_STRING - 1] = '\0';
    tokens[token_count].line = current_line;
    token_count++;
}

void tokenize(const char* source) {
    token_count = 0;
    current_line = 1;
    const char* p = source;

    while (1) {
        skip_whitespace_and_comments(&p);
        if (!*p) break;

        if (*p == '"') {
            p++;
            char buf[MAX_STRING];
            int i = 0;
            while (*p && *p != '"' && i < MAX_STRING - 1) {
                if (*p == '\\' && *(p+1)) {
                    p++;
                    switch (*p) {
                        case 'n': buf[i++] = '\n'; break;
                        case 't': buf[i++] = '\t'; break;
                        case 'r': buf[i++] = '\r'; break;
                        case '\\': buf[i++] = '\\'; break;
                        case '"': buf[i++] = '"'; break;
                        case '0': buf[i++] = '\0'; break;
                        default: buf[i++] = *p; break;
                    }
                } else {
                    buf[i++] = *p;
                }
                p++;
            }
            buf[i] = '\0';
            if (*p != '"') error("Unterminated string literal");
            p++;
            add_token(TOKEN_STRING, buf);
            continue;
        }

        if (*p == '\'') {
            p++;
            char buf[MAX_STRING];
            int i = 0;
            while (*p && *p != '\'' && i < MAX_STRING - 1) {
                if (*p == '\\' && *(p+1)) {
                    p++;
                    switch (*p) {
                        case 'n': buf[i++] = '\n'; break;
                        case 't': buf[i++] = '\t'; break;
                        case 'r': buf[i++] = '\r'; break;
                        case '\\': buf[i++] = '\\'; break;
                        case '\'': buf[i++] = '\''; break;
                        default: buf[i++] = *p; break;
                    }
                } else {
                    buf[i++] = *p;
                }
                p++;
            }
            buf[i] = '\0';
            if (*p != '\'') error("Unterminated string literal");
            p++;
            add_token(TOKEN_STRING, buf);
            continue;
        }

        if (isdigit(*p) || (*p == '.' && isdigit(*(p+1)))) {
            char buf[64];
            int i = 0;
            int dot_count = 0;
            while ((isdigit(*p) || (*p == '.' && dot_count < 1)) && i < 63) {
                if (*p == '.') dot_count++;
                buf[i++] = *p++;
            }
            buf[i] = '\0';
            add_token(TOKEN_NUMBER, buf);
            continue;
        }

        if (isalpha(*p) || *p == '_') {
            char buf[64];
            int i = 0;
            while ((isalnum(*p) || *p == '_') && i < 63) {
                buf[i++] = *p++;
            }
            buf[i] = '\0';

            int j;
            for (j = 0; keywords[j].name; j++) {
                if (strcmp(buf, keywords[j].name) == 0) {
                    add_token(keywords[j].type, buf);
                    break;
                }
            }
            if (!keywords[j].name) {
                if (*p == ':') {
                    strncpy(labels[label_count].name, buf, 63);
                    labels[label_count].token_index = token_count + 1;
                    label_count++;
                    add_token(TOKEN_LABEL, buf);
                    p++;
                } else {
                    add_token(TOKEN_IDENTIFIER, buf);
                }
            }
            continue;
        }

        if (*p == '=' && *(p+1) == '=') { add_token(TOKEN_EQUAL, "=="); p += 2; continue; }
        if (*p == '!' && *(p+1) == '=') { add_token(TOKEN_NOT_EQUAL, "!="); p += 2; continue; }
        if (*p == '&' && *(p+1) == '&') { add_token(TOKEN_AND, "&&"); p += 2; continue; }
        if (*p == '|' && *(p+1) == '|') { add_token(TOKEN_OR, "||"); p += 2; continue; }
        if (*p == '>' && *(p+1) == '=') { add_token(TOKEN_GREATER_EQUAL, ">="); p += 2; continue; }
        if (*p == '<' && *(p+1) == '=') { add_token(TOKEN_LESS_EQUAL, "<="); p += 2; continue; }
        if (*p == '+' && *(p+1) == '=') { add_token(TOKEN_PLUS_ASSIGN, "+="); p += 2; continue; }
        if (*p == '-' && *(p+1) == '=') { add_token(TOKEN_MINUS_ASSIGN, "-="); p += 2; continue; }
        if (*p == '*' && *(p+1) == '=') { add_token(TOKEN_MULTIPLY_ASSIGN, "*="); p += 2; continue; }
        if (*p == '/' && *(p+1) == '=') { add_token(TOKEN_DIVIDE_ASSIGN, "/="); p += 2; continue; }
        if (*p == '%' && *(p+1) == '=') { add_token(TOKEN_MODULO_ASSIGN, "%="); p += 2; continue; }
        if (*p == '+' && *(p+1) == '+') { add_token(TOKEN_INCREMENT, "++"); p += 2; continue; }
        if (*p == '-' && *(p+1) == '-') { add_token(TOKEN_DECREMENT, "--"); p += 2; continue; }
        if (*p == '-' && *(p+1) == '>') { add_token(TOKEN_ARROW, "->"); p += 2; continue; }
        if (*p == '<' && *(p+1) == '<') { add_token(TOKEN_SHIFT_LEFT, "<<"); p += 2; continue; }
        if (*p == '>' && *(p+1) == '>') { add_token(TOKEN_SHIFT_RIGHT, ">>"); p += 2; continue; }

        switch (*p) {
            case '&': add_token(TOKEN_BIT_AND, "&"); break;
            case '|': add_token(TOKEN_BIT_OR, "|"); break;
            case '^': add_token(TOKEN_BIT_XOR, "^"); break;
            case '~': add_token(TOKEN_BIT_NOT, "~"); break;
            case '(': add_token(TOKEN_LPAREN, "("); break;
            case ')': add_token(TOKEN_RPAREN, ")"); break;
            case '{': add_token(TOKEN_LBRACE, "{"); break;
            case '}': add_token(TOKEN_RBRACE, "}"); break;
            case '[': add_token(TOKEN_LBRACKET, "["); break;
            case ']': add_token(TOKEN_RBRACKET, "]"); break;
            case ',': add_token(TOKEN_COMMA, ","); break;
            case ';': add_token(TOKEN_SEMICOLON, ";"); break;
            case '=': add_token(TOKEN_ASSIGN, "="); break;
            case '>': add_token(TOKEN_GREATER, ">"); break;
            case '<': add_token(TOKEN_LESS, "<"); break;
            case '+': add_token(TOKEN_PLUS, "+"); break;
            case '-': add_token(TOKEN_MINUS, "-"); break;
            case '*': add_token(TOKEN_MULTIPLY, "*"); break;
            case '/': add_token(TOKEN_DIVIDE, "/"); break;
            case '%': add_token(TOKEN_MODULO, "%"); break;
            case '!': add_token(TOKEN_NOT, "!"); break;
            case ':': add_token(TOKEN_COLON, ":"); break;
            case '.': add_token(TOKEN_DOT, "."); break;
            default: error("Unknown character: '%c'", *p);
        }
        p++;
    }

    add_token(TOKEN_EOF, "");
}

Token peek() { return tokens[current_token]; }
Token advance() { return tokens[current_token++]; }

int match(OraTokenType type) {
    if (peek().type == type) {
        if (tokens[current_token].line > 0) {
            current_line = tokens[current_token].line;
        }
        advance();
        return 1;
    }
    return 0;
}

void consume(OraTokenType type, const char* msg) {
    if (!match(type)) {
        error("%s (got '%s')", msg, peek().value);
    }
}

double evaluate();
int execute_statement();
int update_oraset(const char* target_version);

Value* find_variable(const char* name) {
    for (int i = var_count - 1; i >= 0; i--) {
        if (strcmp(vars[i].name, name) == 0) {
            return &vars[i].value;
        }
    }
    return NULL;
}

int find_function(const char* name) {
    for (int i = func_count - 1; i >= 0; i--) {
        if (strcmp(funcs[i].name, name) == 0) {
            return i;
        }
    }
    return -1;
}

int find_struct(const char* name) {
    for (int i = struct_count - 1; i >= 0; i--) {
        if (strcmp(structs[i].name, name) == 0) {
            return i;
        }
    }
    return -1;
}

int find_enum(const char* name) {
    for (int i = enum_count - 1; i >= 0; i--) {
        if (strcmp(enums[i].name, name) == 0) {
            return i;
        }
    }
    return -1;
}

int find_label(const char* name) {
    for (int i = label_count - 1; i >= 0; i--) {
        if (strcmp(labels[i].name, name) == 0) {
            return i;
        }
    }
    return -1;
}

double parse_array_access(Value* arr, int index) {
    if (arr->type != VAL_ARRAY) {
        error("Cannot index non-array value");
    }
    if (index < 0 || index >= arr->arr_size) {
        error("Array index out of bounds: %d", index);
    }
    return arr->arr_value[index];
}

double parse_primary();

double parse_call(const char* func_name) {
    consume(TOKEN_LPAREN, "Expected '(' after function name");
    
    if (strcmp(func_name, "abs") == 0) {
        double val = evaluate();
        consume(TOKEN_RPAREN, "Expected ')'");
        return fabs(val);
    } else if (strcmp(func_name, "sqrt") == 0) {
        double val = evaluate();
        consume(TOKEN_RPAREN, "Expected ')'");
        return sqrt(val);
    } else if (strcmp(func_name, "sin") == 0) {
        double val = evaluate();
        consume(TOKEN_RPAREN, "Expected ')'");
        return sin(val);
    } else if (strcmp(func_name, "cos") == 0) {
        double val = evaluate();
        consume(TOKEN_RPAREN, "Expected ')'");
        return cos(val);
    } else if (strcmp(func_name, "tan") == 0) {
        double val = evaluate();
        consume(TOKEN_RPAREN, "Expected ')'");
        return tan(val);
    } else if (strcmp(func_name, "random") == 0) {
        if (match(TOKEN_RPAREN)) {
            return (double)rand() / RAND_MAX;
        }
        double max = evaluate();
        consume(TOKEN_RPAREN, "Expected ')'");
        return fmod((double)rand(), max);
    } else if (strcmp(func_name, "size") == 0) {
        if (match(TOKEN_STRING)) {
            const char* str = tokens[current_token - 1].value;
            consume(TOKEN_RPAREN, "Expected ')'");
            return strlen(str);
        }
        error("Expected string argument for size()");
    } else if (strcmp(func_name, "to_num") == 0) {
        if (match(TOKEN_STRING)) {
            const char* str = tokens[current_token - 1].value;
            consume(TOKEN_RPAREN, "Expected ')'");
            return atof(str);
        }
        error("Expected string argument for to_num()");
    } else if (strcmp(func_name, "to_str") == 0) {
        double val = evaluate();
        consume(TOKEN_RPAREN, "Expected ')'");
        char buf[MAX_STRING];
        sprintf(buf, "%g", val);
        for (int i = 0; i < var_count; i++) {
            if (strcmp(vars[i].name, "__tmp_str_result") == 0) {
                strncpy(vars[i].value.str_value, buf, MAX_STRING - 1);
                vars[i].value.str_value[MAX_STRING - 1] = '\0';
                vars[i].value.type = VAL_STRING;
                return 0;
            }
        }
        strncpy(vars[var_count].name, "__tmp_str_result", 63);
        strncpy(vars[var_count].value.str_value, buf, MAX_STRING - 1);
        vars[var_count].value.str_value[MAX_STRING - 1] = '\0';
        vars[var_count].value.type = VAL_STRING;
        var_count++;
        return 0;
    } else if (strcmp(func_name, "input") == 0) {
        const char* prompt = "";
        if (match(TOKEN_STRING)) {
            prompt = tokens[current_token - 1].value;
        }
        consume(TOKEN_RPAREN, "Expected ')'");
        
        printf("%s", prompt);
        fflush(stdout);
        
        char input[MAX_STRING];
        if (fgets(input, MAX_STRING, stdin) == NULL) {
            error("Failed to read input");
        }
        
        input[strcspn(input, "\n")] = '\0';
        
        for (int i = 0; i < var_count; i++) {
            if (strcmp(vars[i].name, "__input_result") == 0) {
                strncpy(vars[i].value.str_value, input, MAX_STRING - 1);
                vars[i].value.str_value[MAX_STRING - 1] = '\0';
                vars[i].value.type = VAL_STRING;
                return 0;
            }
        }
        strncpy(vars[var_count].name, "__input_result", 63);
        strncpy(vars[var_count].value.str_value, input, MAX_STRING - 1);
        vars[var_count].value.str_value[MAX_STRING - 1] = '\0';
        vars[var_count].value.type = VAL_STRING;
        var_count++;
        return 0;
    } else if (strcmp(func_name, "int") == 0) {
        double val = evaluate();
        consume(TOKEN_RPAREN, "Expected ')'");
        return (int)val;
    } else if (strcmp(func_name, "float") == 0) {
        double val = evaluate();
        consume(TOKEN_RPAREN, "Expected ')'");
        return val;
    } else if (strcmp(func_name, "floor") == 0) {
        double val = evaluate();
        consume(TOKEN_RPAREN, "Expected ')'");
        return floor(val);
    } else if (strcmp(func_name, "ceil") == 0) {
        double val = evaluate();
        consume(TOKEN_RPAREN, "Expected ')'");
        return ceil(val);
    } else if (strcmp(func_name, "round") == 0) {
        double val = evaluate();
        consume(TOKEN_RPAREN, "Expected ')'");
        return round(val);
    } else if (strcmp(func_name, "pow") == 0) {
        double base = evaluate();
        consume(TOKEN_COMMA, "Expected ','");
        double exp = evaluate();
        consume(TOKEN_RPAREN, "Expected ')'");
        return pow(base, exp);
    } else if (strcmp(func_name, "log") == 0) {
        double val = evaluate();
        consume(TOKEN_RPAREN, "Expected ')'");
        return log(val);
    } else if (strcmp(func_name, "time") == 0) {
        consume(TOKEN_RPAREN, "Expected ')'");
        return (double)time(NULL);
    } else if (strcmp(func_name, "array") == 0) {
        int size = (int)evaluate();
        consume(TOKEN_RPAREN, "Expected ')'");
        for (int i = 0; i < var_count; i++) {
            if (strcmp(vars[i].name, "__tmp_arr_result") == 0) {
                vars[i].value.type = VAL_ARRAY;
                vars[i].value.arr_size = size;
                for (int j = 0; j < size; j++) {
                    vars[i].value.arr_value[j] = 0;
                }
                return 0;
            }
        }
        strncpy(vars[var_count].name, "__tmp_arr_result", 63);
        vars[var_count].value.type = VAL_ARRAY;
        vars[var_count].value.arr_size = size;
        for (int j = 0; j < size; j++) {
            vars[var_count].value.arr_value[j] = 0;
        }
        var_count++;
        return 0;
    } else if (strcmp(func_name, "arrlen") == 0) {
        consume(TOKEN_IDENTIFIER, "Expected array variable");
        const char* name = tokens[current_token - 1].value;
        Value* v = find_variable(name);
        if (!v || v->type != VAL_ARRAY) {
            error("'%s' is not an array", name);
        }
        consume(TOKEN_RPAREN, "Expected ')'");
        return v->arr_size;
    } else if (strcmp(func_name, "exit") == 0) {
        int code = (int)evaluate();
        consume(TOKEN_RPAREN, "Expected ')'");
        exit(code);
    } else if (strcmp(func_name, "assert") == 0) {
        double cond = evaluate();
        consume(TOKEN_COMMA, "Expected ','");
        if (match(TOKEN_STRING)) {
            const char* msg = tokens[current_token - 1].value;
            consume(TOKEN_RPAREN, "Expected ')'");
            if (cond == 0) {
                error("Assertion failed: %s", msg);
            }
        } else {
            consume(TOKEN_RPAREN, "Expected ')'");
            if (cond == 0) {
                error("Assertion failed");
            }
        }
        return 1;
    } else if (strcmp(func_name, "strcmp") == 0) {
        const char* str1 = get_string_value();
        consume(TOKEN_COMMA, "Expected ','");
        const char* str2 = get_string_value();
        consume(TOKEN_RPAREN, "Expected ')'");
        return strcmp(str1, str2);
    } else if (strcmp(func_name, "strcpy") == 0) {
        const char* src = get_string_value();
        consume(TOKEN_RPAREN, "Expected ')'");
        for (int i = 0; i < var_count; i++) {
            if (strcmp(vars[i].name, "__tmp_str_result") == 0) {
                strncpy(vars[i].value.str_value, src, MAX_STRING - 1);
                vars[i].value.str_value[MAX_STRING - 1] = '\0';
                vars[i].value.type = VAL_STRING;
                return 0;
            }
        }
        strncpy(vars[var_count].name, "__tmp_str_result", 63);
        strncpy(vars[var_count].value.str_value, src, MAX_STRING - 1);
        vars[var_count].value.str_value[MAX_STRING - 1] = '\0';
        vars[var_count].value.type = VAL_STRING;
        var_count++;
        return 0;
    } else if (strcmp(func_name, "strcat") == 0) {
        const char* str1 = get_string_value();
        consume(TOKEN_COMMA, "Expected ','");
        const char* str2 = get_string_value();
        consume(TOKEN_RPAREN, "Expected ')'");
        for (int i = 0; i < var_count; i++) {
            if (strcmp(vars[i].name, "__tmp_str_result") == 0) {
                strncpy(vars[i].value.str_value, str1, MAX_STRING - 1);
                strncat(vars[i].value.str_value, str2, MAX_STRING - strlen(vars[i].value.str_value) - 1);
                vars[i].value.type = VAL_STRING;
                return 0;
            }
        }
        strncpy(vars[var_count].name, "__tmp_str_result", 63);
        strncpy(vars[var_count].value.str_value, str1, MAX_STRING - 1);
        strncat(vars[var_count].value.str_value, str2, MAX_STRING - strlen(vars[var_count].value.str_value) - 1);
        vars[var_count].value.type = VAL_STRING;
        var_count++;
        return 0;
    } else if (strcmp(func_name, "sizeof") == 0) {
        consume(TOKEN_IDENTIFIER, "Expected variable name");
        const char* name = tokens[current_token - 1].value;
        consume(TOKEN_RPAREN, "Expected ')'");
        Value* v = find_variable(name);
        if (!v) error("Undefined variable: %s", name);
        if (v->type == VAL_STRING) {
            return strlen(v->str_value);
        } else if (v->type == VAL_ARRAY) {
            return v->arr_size;
        }
        return sizeof(double);
    } else if (strcmp(func_name, "malloc") == 0) {
        int size = (int)evaluate();
        consume(TOKEN_RPAREN, "Expected ')'");
        for (int i = 0; i < var_count; i++) {
            if (strcmp(vars[i].name, "__tmp_arr_result") == 0) {
                vars[i].value.type = VAL_ARRAY;
                vars[i].value.arr_size = size;
                for (int j = 0; j < size; j++) {
                    vars[i].value.arr_value[j] = 0;
                }
                return 0;
            }
        }
        strncpy(vars[var_count].name, "__tmp_arr_result", 63);
        vars[var_count].value.type = VAL_ARRAY;
        vars[var_count].value.arr_size = size;
        for (int j = 0; j < size; j++) {
            vars[var_count].value.arr_value[j] = 0;
        }
        var_count++;
        return 0;
    } else if (strcmp(func_name, "memcpy") == 0) {
        consume(TOKEN_IDENTIFIER, "Expected destination array");
        const char* dest_name = tokens[current_token - 1].value;
        consume(TOKEN_COMMA, "Expected ','");
        consume(TOKEN_IDENTIFIER, "Expected source array");
        const char* src_name = tokens[current_token - 1].value;
        consume(TOKEN_COMMA, "Expected ','");
        int count = (int)evaluate();
        consume(TOKEN_RPAREN, "Expected ')'");
        Value* dest = find_variable(dest_name);
        Value* src = find_variable(src_name);
        if (!dest || dest->type != VAL_ARRAY) error("Invalid destination array");
        if (!src || src->type != VAL_ARRAY) error("Invalid source array");
        for (int i = 0; i < count && i < dest->arr_size && i < src->arr_size; i++) {
            dest->arr_value[i] = src->arr_value[i];
        }
        return 0;
    } else if (strcmp(func_name, "memcmp") == 0) {
        consume(TOKEN_IDENTIFIER, "Expected first array");
        const char* name1 = tokens[current_token - 1].value;
        consume(TOKEN_COMMA, "Expected ','");
        consume(TOKEN_IDENTIFIER, "Expected second array");
        const char* name2 = tokens[current_token - 1].value;
        consume(TOKEN_COMMA, "Expected ','");
        int count = (int)evaluate();
        consume(TOKEN_RPAREN, "Expected ')'");
        Value* arr1 = find_variable(name1);
        Value* arr2 = find_variable(name2);
        if (!arr1 || arr1->type != VAL_ARRAY) error("Invalid first array");
        if (!arr2 || arr2->type != VAL_ARRAY) error("Invalid second array");
        for (int i = 0; i < count && i < arr1->arr_size && i < arr2->arr_size; i++) {
            if (arr1->arr_value[i] != arr2->arr_value[i]) {
                return arr1->arr_value[i] - arr2->arr_value[i];
            }
        }
        return 0;
    } else {
        int func_idx = find_function(func_name);
        if (func_idx >= 0) {
            int saved_var_count = var_count;
            for (int i = 0; i < funcs[func_idx].param_count; i++) {
                if (i > 0) consume(TOKEN_COMMA, "Expected ','");
                strncpy(vars[var_count].name, funcs[func_idx].params[i], 63);
                vars[var_count].value.num_value = evaluate();
                vars[var_count].value.type = VAL_NUMBER;
                var_count++;
            }
            consume(TOKEN_RPAREN, "Expected ')'");
            
            int saved_token = current_token;
            current_token = funcs[func_idx].body_start;
            while (current_token < funcs[func_idx].body_end && peek().type != TOKEN_EOF) {
                if (execute_statement() == 1) break;
            }
            current_token = saved_token;
            
            double result = 0;
            for (int i = var_count - 1; i >= 0; i--) {
                if (strcmp(vars[i].name, "__return_value") == 0) {
                    result = vars[i].value.num_value;
                    break;
                }
            }
            var_count = saved_var_count;
            return result;
        }
        error("Undefined function: %s", func_name);
    }
    return 0;
}

double parse_primary() {
    if (match(TOKEN_NUMBER)) {
        return atof(tokens[current_token - 1].value);
    }
    if (match(TOKEN_STRING)) {
        error("Cannot use string directly in expression");
    }
    if (match(TOKEN_IDENTIFIER)) {
        const char* name = tokens[current_token - 1].value;
        if (peek().type == TOKEN_LPAREN) {
            return parse_call(name);
        }
        if (peek().type == TOKEN_LBRACKET) {
            Value* v = find_variable(name);
            if (!v) error("Undefined variable: %s", name);
            advance();
            int index = (int)evaluate();
            consume(TOKEN_RBRACKET, "Expected ']'");
            return parse_array_access(v, index);
        }
        if (peek().type == TOKEN_DOT) {
            Value* v = find_variable(name);
            if (!v) error("Undefined variable: %s", name);
            if (v->type != VAL_STRUCT) {
                error("Cannot access field of non-struct variable");
            }
            advance();
            consume(TOKEN_IDENTIFIER, "Expected field name");
            const char* field_name = tokens[current_token - 1].value;
            int struct_idx = v->struct_type;
            for (int i = 0; i < structs[struct_idx].field_count; i++) {
                if (strcmp(structs[struct_idx].fields[i], field_name) == 0) {
                    return (double)i;
                }
            }
            error("Undefined field: %s", field_name);
        }
        Value* v = find_variable(name);
        if (!v) error("Undefined variable: %s", name);
        if (v->type == VAL_STRING) {
            error("Cannot use string variable in numeric expression");
        }
        return v->num_value;
    }
    if (match(TOKEN_LPAREN)) {
        double val = evaluate();
        consume(TOKEN_RPAREN, "Expected ')'");
        return val;
    }
    error("Expected expression (got '%s')", peek().value);
    return 0;
}

double parse_unary() {
    if (match(TOKEN_NOT)) {
        return parse_unary() == 0 ? 1 : 0;
    }
    if (match(TOKEN_MINUS)) {
        return -parse_unary();
    }
    if (match(TOKEN_PLUS)) {
        return parse_unary();
    }
    if (match(TOKEN_BIT_NOT)) {
        return ~(int)parse_unary();
    }
    return parse_primary();
}

double parse_factor() {
    double left = parse_unary();
    while (match(TOKEN_MULTIPLY) || match(TOKEN_DIVIDE) || match(TOKEN_MODULO)) {
        OraTokenType op = tokens[current_token - 1].type;
        double right = parse_unary();
        if (op == TOKEN_MULTIPLY) left *= right;
        else if (op == TOKEN_DIVIDE) {
            if (right == 0) error("Division by zero");
            left /= right;
        } else {
            if (right == 0) error("Modulo by zero");
            left = fmod(left, right);
        }
    }
    return left;
}

double parse_term() {
    double left = parse_factor();
    while (match(TOKEN_PLUS) || match(TOKEN_MINUS)) {
        OraTokenType op = tokens[current_token - 1].type;
        double right = parse_factor();
        if (op == TOKEN_PLUS) left += right;
        else left -= right;
    }
    return left;
}

double parse_shift() {
    double left = parse_term();
    while (match(TOKEN_SHIFT_LEFT) || match(TOKEN_SHIFT_RIGHT)) {
        OraTokenType op = tokens[current_token - 1].type;
        double right = parse_term();
        if (op == TOKEN_SHIFT_LEFT) left = (int)left << (int)right;
        else left = (int)left >> (int)right;
    }
    return left;
}

double parse_bit_and() {
    double left = parse_shift();
    while (match(TOKEN_BIT_AND)) {
        double right = parse_shift();
        left = (int)left & (int)right;
    }
    return left;
}

double parse_bit_xor() {
    double left = parse_bit_and();
    while (match(TOKEN_BIT_XOR)) {
        double right = parse_bit_and();
        left = (int)left ^ (int)right;
    }
    return left;
}

double parse_bit_or() {
    double left = parse_bit_xor();
    while (match(TOKEN_BIT_OR)) {
        double right = parse_bit_xor();
        left = (int)left | (int)right;
    }
    return left;
}

double parse_comparison() {
    double left = parse_bit_or();
    while (1) {
        if (match(TOKEN_EQUAL)) {
            double right = parse_bit_or();
            left = (left == right) ? 1 : 0;
        } else if (match(TOKEN_NOT_EQUAL)) {
            double right = parse_bit_or();
            left = (left != right) ? 1 : 0;
        } else if (match(TOKEN_GREATER)) {
            double right = parse_bit_or();
            left = (left > right) ? 1 : 0;
        } else if (match(TOKEN_LESS)) {
            double right = parse_bit_or();
            left = (left < right) ? 1 : 0;
        } else if (match(TOKEN_GREATER_EQUAL)) {
            double right = parse_bit_or();
            left = (left >= right) ? 1 : 0;
        } else if (match(TOKEN_LESS_EQUAL)) {
            double right = parse_bit_or();
            left = (left <= right) ? 1 : 0;
        } else {
            break;
        }
    }
    return left;
}

double parse_logic_and() {
    double left = parse_comparison();
    while (match(TOKEN_AND)) {
        double right = parse_comparison();
        left = (left != 0 && right != 0) ? 1 : 0;
    }
    return left;
}

double parse_logic_or() {
    double left = parse_logic_and();
    while (match(TOKEN_OR)) {
        double right = parse_logic_and();
        left = (left != 0 || right != 0) ? 1 : 0;
    }
    return left;
}

double evaluate() {
    return parse_logic_or();
}

void execute_print() {
    consume(TOKEN_LPAREN, "Expected '(' after print");
    int first = 1;
    int newline = print_newline;

    while (!match(TOKEN_RPAREN)) {
        if (!first) consume(TOKEN_COMMA, "Expected ',' between arguments");

        if (match(TOKEN_STRING)) {
            const char* str = tokens[current_token - 1].value;
            if (strcmp(str, "nel") == 0) {
                newline = 0;
                first = 0;
                continue;
            }
            if (!first) printf(" ");
            printf("%s", str);
        } else if (match(TOKEN_NUMBER)) {
            if (!first) printf(" ");
            printf("%s", tokens[current_token - 1].value);
        } else if (match(TOKEN_BIT_NOT) || match(TOKEN_MINUS) || match(TOKEN_PLUS) || match(TOKEN_NOT)) {
            current_token--;
            double val = evaluate();
            if (!first) printf(" ");
            printf("%g", val);
        } else if (match(TOKEN_IDENTIFIER)) {
            const char* name = tokens[current_token - 1].value;
            if (peek().type == TOKEN_PLUS || peek().type == TOKEN_MINUS || 
                peek().type == TOKEN_MULTIPLY || peek().type == TOKEN_DIVIDE ||
                peek().type == TOKEN_MODULO || peek().type == TOKEN_BIT_AND ||
                peek().type == TOKEN_BIT_OR || peek().type == TOKEN_BIT_XOR ||
                peek().type == TOKEN_SHIFT_LEFT || peek().type == TOKEN_SHIFT_RIGHT) {
                current_token--;
                double val = evaluate();
                if (!first) printf(" ");
                printf("%g", val);
            } else if (peek().type == TOKEN_BIT_NOT) {
                current_token--;
                double val = evaluate();
                if (!first) printf(" ");
                printf("%g", val);
            } else if (peek().type == TOKEN_LBRACKET) {
                Value* v = find_variable(name);
                if (!v) error("Undefined variable: %s", name);
                advance();
                int index = (int)evaluate();
                consume(TOKEN_RBRACKET, "Expected ']'");
                if (!first) printf(" ");
                printf("%g", parse_array_access(v, index));
            } else if (peek().type == TOKEN_LPAREN) {
                int func_idx = find_function(name);
                if (func_idx >= 0) {
                    consume(TOKEN_LPAREN, "Expected '('");
                    int saved_var_count = var_count;
                    for (int i = 0; i < funcs[func_idx].param_count; i++) {
                        if (i > 0) consume(TOKEN_COMMA, "Expected ','");
                        strncpy(vars[var_count].name, funcs[func_idx].params[i], 63);
                        vars[var_count].value.num_value = evaluate();
                        vars[var_count].value.type = VAL_NUMBER;
                        var_count++;
                    }
                    consume(TOKEN_RPAREN, "Expected ')'");
                    
                    int saved_token = current_token;
                    current_token = funcs[func_idx].body_start;
                    while (current_token < funcs[func_idx].body_end && peek().type != TOKEN_EOF) {
                        execute_statement();
                    }
                    current_token = saved_token;
                    var_count = saved_var_count;
                    
                    for (int i = var_count - 1; i >= 0; i--) {
                        if (strcmp(vars[i].name, "__return_value") == 0) {
                            if (!first) printf(" ");
                            printf("%g", vars[i].value.num_value);
                            break;
                        }
                    }
                } else {
                    if (!first) printf(" ");
                    printf("%g", parse_call(name));
                }
            } else {
                int found = 0;
                for (int i = 0; i < var_count; i++) {
                    if (strcmp(vars[i].name, name) == 0) {
                        if (!first) printf(" ");
                        if (vars[i].value.type == VAL_STRING) {
                            printf("%s", vars[i].value.str_value);
                        } else if (vars[i].value.type == VAL_ARRAY) {
                            printf("[");
                            for (int j = 0; j < vars[i].value.arr_size; j++) {
                                if (j > 0) printf(", ");
                                printf("%g", vars[i].value.arr_value[j]);
                            }
                            printf("]");
                        } else {
                            printf("%g", vars[i].value.num_value);
                        }
                        found = 1;
                        break;
                    }
                }
                if (!found) error("Undefined variable: %s", name);
            }
        } else {
            error("Unexpected token in print: '%s'", peek().value);
        }
        first = 0;
    }

    if (newline) {
        printf("\n");
    }
    fflush(stdout);
}

void execute_var() {
    consume(TOKEN_IDENTIFIER, "Expected variable name");
    const char* name = tokens[current_token - 1].value;

    if (var_count >= MAX_VARS) {
        error("Too many variables (max %d)", MAX_VARS);
    }

    Variable* v = &vars[var_count];
    strncpy(v->name, name, 63);
    v->name[63] = '\0';
    var_count++;

    if (match(TOKEN_ASSIGN)) {
        if (match(TOKEN_STRING)) {
            strncpy(v->value.str_value, tokens[current_token - 1].value, MAX_STRING - 1);
            v->value.str_value[MAX_STRING - 1] = '\0';
            v->value.type = VAL_STRING;
            v->value.num_value = 0;
        } else if (match(TOKEN_LBRACKET)) {
            v->value.type = VAL_ARRAY;
            v->value.arr_size = 0;
            while (!match(TOKEN_RBRACKET)) {
                if (v->value.arr_size > 0) consume(TOKEN_COMMA, "Expected ',' between array elements");
                v->value.arr_value[v->value.arr_size++] = evaluate();
                if (v->value.arr_size >= MAX_ARRAY_SIZE) {
                    error("Array size exceeds maximum (%d)", MAX_ARRAY_SIZE);
                }
            }
        } else {
            v->value.num_value = evaluate();
            v->value.type = VAL_NUMBER;
            v->value.str_value[0] = '\0';
            for (int i = 0; i < var_count; i++) {
                if (strcmp(vars[i].name, "__tmp_arr_result") == 0) {
                    v->value.type = vars[i].value.type;
                    v->value.arr_size = vars[i].value.arr_size;
                    for (int j = 0; j < vars[i].value.arr_size; j++) {
                        v->value.arr_value[j] = vars[i].value.arr_value[j];
                    }
                    break;
                }
            }
        }
    } else {
        v->value.type = VAL_NUMBER;
        v->value.num_value = 0;
        v->value.str_value[0] = '\0';
    }
    if (!in_for_loop_update) {
        consume(TOKEN_SEMICOLON, "Expected ';' after variable declaration");
    }
}

static void skip_block() {
    int depth = 1;
    while (depth > 0 && peek().type != TOKEN_EOF) {
        Token t = advance();
        if (t.type == TOKEN_LBRACE) depth++;
        if (t.type == TOKEN_RBRACE) depth--;
    }
}

int execute_if() {
    consume(TOKEN_LPAREN, "Expected '(' after 'if'");
    double cond = evaluate();
    consume(TOKEN_RPAREN, "Expected ')' after condition");
    
    if (match(TOKEN_LBRACE)) {
        if (cond != 0) {
            while (!match(TOKEN_RBRACE) && peek().type != TOKEN_EOF) {
                int result = execute_statement();
                if (result == 2 || result == 3) {
                    return result;
                }
            }
        } else {
            skip_block();
        }
    } else {
        if (cond != 0) {
            int result = execute_statement();
            if (result == 2 || result == 3) {
                return result;
            }
        } else {
            while (peek().type != TOKEN_SEMICOLON && peek().type != TOKEN_EOF) {
                advance();
            }
            consume(TOKEN_SEMICOLON, "Expected ';'");
        }
    }
    
    if (match(TOKEN_ELSE)) {
        if (match(TOKEN_LBRACE)) {
            if (cond == 0) {
                while (!match(TOKEN_RBRACE) && peek().type != TOKEN_EOF) {
                    int result = execute_statement();
                    if (result == 2 || result == 3) {
                        return result;
                    }
                }
            } else {
                skip_block();
            }
        } else {
            if (cond == 0) {
                int result = execute_statement();
                if (result == 2 || result == 3) {
                    return result;
                }
            } else {
                while (peek().type != TOKEN_SEMICOLON && peek().type != TOKEN_EOF) {
                    advance();
                }
                consume(TOKEN_SEMICOLON, "Expected ';'");
            }
        }
    }
    return 0;
}

void execute_while() {
    consume(TOKEN_LPAREN, "Expected '(' after 'while'");
    
    int cond_start = current_token;
    evaluate();
    consume(TOKEN_RPAREN, "Expected ')' after condition");
    consume(TOKEN_LBRACE, "Expected '{' after while condition");

    int body_start = current_token;
    skip_block();
    int body_end = current_token;

    int saved_loop_depth = loop_depth;
    loop_depth++;

    while (1) {
        current_token = cond_start;
        current_line = tokens[cond_start].line;
        double cond = evaluate();
        
        if (cond == 0) {
            current_token = body_end;
            break;
        }

        current_token = body_start;
        while (current_token < body_end && peek().type != TOKEN_EOF && peek().type != TOKEN_RBRACE) {
            int result = execute_statement();
            if (result == 2) {
                break;
            }
            if (result == 3) {
                break;
            }
            if (result == 1) {
                loop_depth = saved_loop_depth;
                return;
            }
        }
    }

    loop_depth = saved_loop_depth;
}

void execute_for() {
    consume(TOKEN_LPAREN, "Expected '(' after 'for'");
    
    int init_start = current_token;
    while (peek().type != TOKEN_SEMICOLON && peek().type != TOKEN_EOF) {
        advance();
    }
    consume(TOKEN_SEMICOLON, "Expected ';'");
    
    int cond_start = current_token;
    while (peek().type != TOKEN_SEMICOLON && peek().type != TOKEN_EOF) {
        advance();
    }
    consume(TOKEN_SEMICOLON, "Expected ';'");
    
    int update_start = current_token;
    while (peek().type != TOKEN_RPAREN && peek().type != TOKEN_EOF) {
        advance();
    }
    consume(TOKEN_RPAREN, "Expected ')'");
    consume(TOKEN_LBRACE, "Expected '{'");
    
    int body_start = current_token;
    skip_block();
    int body_end = current_token;
    
    int saved_token = current_token;
    current_token = init_start;
    in_for_loop_update = 1;
    while (peek().type != TOKEN_SEMICOLON && peek().type != TOKEN_EOF) {
        execute_statement();
    }
    in_for_loop_update = 0;
    current_token = saved_token;
    
    int saved_loop_depth = loop_depth;
    loop_depth++;
    
    while (1) {
        double cond = 0;
        int temp_token = cond_start;
        current_token = cond_start;
        current_line = tokens[cond_start].line;
        
        int paren_count = 0;
        while (temp_token < token_count) {
            if (tokens[temp_token].type == TOKEN_LPAREN) paren_count++;
            if (tokens[temp_token].type == TOKEN_RPAREN) paren_count--;
            if (tokens[temp_token].type == TOKEN_SEMICOLON && paren_count == 0) break;
            temp_token++;
        }
        
        cond = evaluate();
        
        if (cond == 0) {
            break;
        }
        
        current_token = body_start;
        while (current_token < body_end && peek().type != TOKEN_EOF) {
            int result = execute_statement();
            if (result == 2) {
                loop_depth = saved_loop_depth;
                return;
            }
            if (result == 1) {
                loop_depth = saved_loop_depth;
                return;
            }
        }
        
        current_token = update_start;
        in_for_loop_update = 1;
        while (peek().type != TOKEN_RPAREN && peek().type != TOKEN_EOF) {
            execute_statement();
        }
        in_for_loop_update = 0;
    }
    
    loop_depth = saved_loop_depth;
}

extern int in_for_loop_update;

void execute_function() {
    consume(TOKEN_IDENTIFIER, "Expected function name");
    const char* name = tokens[current_token - 1].value;
    consume(TOKEN_LPAREN, "Expected '(' after function name");
    
    int func_idx = func_count;
    strncpy(funcs[func_idx].name, name, 63);
    funcs[func_idx].param_count = 0;
    
    while (!match(TOKEN_RPAREN)) {
        if (funcs[func_idx].param_count > 0) consume(TOKEN_COMMA, "Expected ','");
        consume(TOKEN_IDENTIFIER, "Expected parameter name");
        strncpy(funcs[func_idx].params[funcs[func_idx].param_count], 
                tokens[current_token - 1].value, 63);
        funcs[func_idx].param_count++;
        if (funcs[func_idx].param_count >= 8) {
            error("Too many parameters (max 8)");
        }
    }
    
    consume(TOKEN_LBRACE, "Expected '{'");
    funcs[func_idx].body_start = current_token;
    
    skip_block();
    funcs[func_idx].body_end = current_token;
    func_count++;
}

void execute_switch() {
    consume(TOKEN_LPAREN, "Expected '('");
    double switch_val = evaluate();
    consume(TOKEN_RPAREN, "Expected ')'");
    consume(TOKEN_LBRACE, "Expected '{'");
    
    int saved_switch_active = switch_active;
    switch_active = 1;
    
    int body_start = current_token;
    skip_block();
    int body_end = current_token;
    
    int saved_token = current_token;
    current_token = body_start;
    
    int should_execute = 0;
    while (current_token < body_end && peek().type != TOKEN_EOF) {
        if (match(TOKEN_CASE)) {
            double case_val = evaluate();
            consume(TOKEN_COLON, "Expected ':' after case");
            if (!should_execute && case_val == switch_val) {
                should_execute = 1;
            }
        } else if (match(TOKEN_DEFAULT)) {
            consume(TOKEN_COLON, "Expected ':' after default");
            if (!should_execute) {
                should_execute = 1;
            }
        } else {
            if (should_execute) {
                int result = execute_statement();
                if (result == 2) {
                    break;
                }
            } else {
                advance();
            }
        }
    }
    
    current_token = saved_token;
    switch_active = saved_switch_active;
}

void execute_do_while() {
    consume(TOKEN_LBRACE, "Expected '{'");
    
    int body_start = current_token;
    skip_block();
    int body_end = current_token;
    
    consume(TOKEN_WHILE, "Expected 'while'");
    consume(TOKEN_LPAREN, "Expected '('");
    
    int cond_start = current_token;
    evaluate();
    consume(TOKEN_RPAREN, "Expected ')'");
    consume(TOKEN_SEMICOLON, "Expected ';'");
    
    int saved_loop_depth = loop_depth;
    loop_depth++;
    
    current_token = body_start;
    while (current_token < body_end && peek().type != TOKEN_EOF && peek().type != TOKEN_RBRACE) {
        int result = execute_statement();
        if (result == 2) {
            break;
        }
        if (result == 3) {
            break;
        }
        if (result == 1) {
            loop_depth = saved_loop_depth;
            return;
        }
    }
    
    while (1) {
        current_token = cond_start;
        current_line = tokens[cond_start].line;
        double cond = evaluate();
        
        if (cond == 0) {
            break;
        }
        
        current_token = body_start;
        while (current_token < body_end && peek().type != TOKEN_EOF && peek().type != TOKEN_RBRACE) {
            int result = execute_statement();
            if (result == 2) {
                break;
            }
            if (result == 3) {
                break;
            }
            if (result == 1) {
                loop_depth = saved_loop_depth;
                return;
            }
        }
    }
    
    loop_depth = saved_loop_depth;
}

void execute_struct() {
    consume(TOKEN_IDENTIFIER, "Expected struct name");
    const char* name = tokens[current_token - 1].value;
    consume(TOKEN_LBRACE, "Expected '{'");
    
    int struct_idx = struct_count;
    strncpy(structs[struct_idx].name, name, 63);
    structs[struct_idx].field_count = 0;
    
    while (peek().type != TOKEN_RBRACE && peek().type != TOKEN_EOF) {
        if (peek().type == TOKEN_SEMICOLON) {
            advance();
            continue;
        }
        consume(TOKEN_IDENTIFIER, "Expected field name");
        strncpy(structs[struct_idx].fields[structs[struct_idx].field_count], 
                tokens[current_token - 1].value, 63);
        structs[struct_idx].field_count++;
        if (structs[struct_idx].field_count >= 16) {
            error("Too many fields in struct (max 16)");
        }
        if (peek().type == TOKEN_SEMICOLON) {
            advance();
        }
    }
    
    consume(TOKEN_RBRACE, "Expected '}'");
    struct_count++;
    if (match(TOKEN_SEMICOLON)) {
    }
}

void execute_enum() {
    consume(TOKEN_IDENTIFIER, "Expected enum name");
    const char* name = tokens[current_token - 1].value;
    consume(TOKEN_LBRACE, "Expected '{'");
    
    int enum_idx = enum_count;
    strncpy(enums[enum_idx].name, name, 63);
    enums[enum_idx].value_count = 0;
    
    while (peek().type != TOKEN_RBRACE && peek().type != TOKEN_EOF) {
        consume(TOKEN_IDENTIFIER, "Expected enum value");
        strncpy(enums[enum_idx].values[enums[enum_idx].value_count], 
                tokens[current_token - 1].value, 63);
        enums[enum_idx].value_count++;
        if (enums[enum_idx].value_count >= 16) {
            error("Too many values in enum (max 16)");
        }
        if (match(TOKEN_COMMA)) {
            continue;
        }
        break;
    }
    
    consume(TOKEN_RBRACE, "Expected '}'");
    enum_count++;
    if (match(TOKEN_SEMICOLON)) {
    }
}

void execute_typedef() {
    consume(TOKEN_IDENTIFIER, "Expected original type");
    const char* orig_type = tokens[current_token - 1].value;
    consume(TOKEN_IDENTIFIER, "Expected new type name");
    const char* new_name = tokens[current_token - 1].value;
    consume(TOKEN_SEMICOLON, "Expected ';'");
    
    int struct_idx = find_struct(orig_type);
    if (struct_idx >= 0) {
        strncpy(structs[struct_count].name, new_name, 63);
        structs[struct_count].field_count = structs[struct_idx].field_count;
        for (int i = 0; i < structs[struct_idx].field_count; i++) {
            strncpy(structs[struct_count].fields[i], structs[struct_idx].fields[i], 63);
        }
        struct_count++;
    } else {
        int enum_idx = find_enum(orig_type);
        if (enum_idx >= 0) {
            strncpy(enums[enum_count].name, new_name, 63);
            enums[enum_count].value_count = enums[enum_idx].value_count;
            for (int i = 0; i < enums[enum_idx].value_count; i++) {
                strncpy(enums[enum_count].values[i], enums[enum_idx].values[i], 63);
            }
            enum_count++;
        }
    }
}

void execute_goto() {
    consume(TOKEN_IDENTIFIER, "Expected label name");
    const char* name = tokens[current_token - 1].value;
    consume(TOKEN_SEMICOLON, "Expected ';'");
    
    int label_idx = find_label(name);
    if (label_idx < 0) {
        error("Undefined label: %s", name);
    }
    current_token = labels[label_idx].token_index;
}

void execute_new() {
    consume(TOKEN_IDENTIFIER, "Expected type name");
    const char* type_name = tokens[current_token - 1].value;
    consume(TOKEN_SEMICOLON, "Expected ';'");
    
    int struct_idx = find_struct(type_name);
    if (struct_idx >= 0) {
        strncpy(vars[var_count].name, "__tmp_struct_result", 63);
        vars[var_count].value.type = VAL_STRUCT;
        vars[var_count].value.struct_type = struct_idx;
        var_count++;
    }
}

void execute_delete() {
    consume(TOKEN_IDENTIFIER, "Expected variable name");
    const char* name = tokens[current_token - 1].value;
    consume(TOKEN_SEMICOLON, "Expected ';'");
    
    for (int i = 0; i < var_count; i++) {
        if (strcmp(vars[i].name, name) == 0) {
            for (int j = i; j < var_count - 1; j++) {
                vars[j] = vars[j + 1];
            }
            var_count--;
            return;
        }
    }
    error("Undefined variable: %s", name);
}

void execute_try_catch() {
    consume(TOKEN_LBRACE, "Expected '{'");
    
    int try_start = current_token;
    skip_block();
    int try_end = current_token;
    
    consume(TOKEN_CATCH, "Expected 'catch'");
    consume(TOKEN_LPAREN, "Expected '('");
    consume(TOKEN_IDENTIFIER, "Expected exception variable name");
    const char* exc_name = tokens[current_token - 1].value;
    consume(TOKEN_RPAREN, "Expected ')'");
    consume(TOKEN_LBRACE, "Expected '{'");
    
    int catch_start = current_token;
    skip_block();
    int catch_end = current_token;
    
    int saved_var_count = var_count;
    
    current_token = try_start;
    while (current_token < try_end && peek().type != TOKEN_EOF && peek().type != TOKEN_RBRACE) {
        int result = execute_statement();
        if (result == 1) {
            var_count = saved_var_count;
            return;
        }
    }
    
    var_count = saved_var_count;
}

void execute_throw() {
    evaluate();
    consume(TOKEN_SEMICOLON, "Expected ';'");
}

void execute_return() {
    if (peek().type == TOKEN_SEMICOLON || peek().type == TOKEN_RBRACE) {
        consume(TOKEN_SEMICOLON, "Expected ';' after return");
        return;
    }
    double val = evaluate();
    consume(TOKEN_SEMICOLON, "Expected ';' after return");
    for (int i = var_count - 1; i >= 0; i--) {
        if (strcmp(vars[i].name, "__return_value") == 0) {
            vars[i].value.num_value = val;
            vars[i].value.type = VAL_NUMBER;
            return;
        }
    }
    strncpy(vars[var_count].name, "__return_value", 63);
    vars[var_count].value.num_value = val;
    vars[var_count].value.type = VAL_NUMBER;
    var_count++;
}

int execute_statement() {
    Token t = peek();

    switch (t.type) {
        case TOKEN_PRINT:
            advance();
            execute_print();
            consume(TOKEN_SEMICOLON, "Expected ';' after print");
            return 0;

        case TOKEN_VAR:
            advance();
            execute_var();
            return 0;

        case TOKEN_IF:
            advance();
            return execute_if();

        case TOKEN_WHILE:
            advance();
            execute_while();
            return 0;

        case TOKEN_FOR:
            advance();
            execute_for();
            return 0;

        case TOKEN_FUNCTION:
            advance();
            execute_function();
            return 0;

        case TOKEN_SWITCH:
            advance();
            execute_switch();
            return 0;

        case TOKEN_DO:
            advance();
            execute_do_while();
            return 0;

        case TOKEN_BREAK:
            advance();
            consume(TOKEN_SEMICOLON, "Expected ';' after break");
            if (loop_depth == 0 && !switch_active) {
                error("break outside loop or switch");
            }
            return 2;

        case TOKEN_CONTINUE:
            advance();
            consume(TOKEN_SEMICOLON, "Expected ';' after continue");
            if (loop_depth == 0) {
                error("continue outside loop");
            }
            return 3;

        case TOKEN_RETURN:
            advance();
            execute_return();
            return 1;

        case TOKEN_STRUCT:
            advance();
            execute_struct();
            return 0;

        case TOKEN_ENUM:
            advance();
            execute_enum();
            return 0;

        case TOKEN_TYPEDEF:
            advance();
            execute_typedef();
            return 0;

        case TOKEN_GOTO:
            advance();
            execute_goto();
            return 0;

        case TOKEN_NEW:
            advance();
            execute_new();
            return 0;

        case TOKEN_DELETE:
            advance();
            execute_delete();
            return 0;

        case TOKEN_TRY:
            advance();
            execute_try_catch();
            return 0;

        case TOKEN_THROW:
            advance();
            execute_throw();
            return 0;

        case TOKEN_LABEL:
            advance();
            return 0;

        case TOKEN_IDENTIFIER: {
            advance();
            if (match(TOKEN_ASSIGN)) {
                const char* name = tokens[current_token - 2].value;
                for (int i = 0; i < var_count; i++) {
                    if (strcmp(vars[i].name, name) == 0) {
                        if (match(TOKEN_STRING)) {
                            strncpy(vars[i].value.str_value, tokens[current_token - 1].value, MAX_STRING - 1);
                            vars[i].value.str_value[MAX_STRING - 1] = '\0';
                            vars[i].value.type = VAL_STRING;
                        } else if (match(TOKEN_LBRACKET)) {
                            vars[i].value.type = VAL_ARRAY;
                            vars[i].value.arr_size = 0;
                            while (!match(TOKEN_RBRACKET)) {
                                if (vars[i].value.arr_size > 0) consume(TOKEN_COMMA, "Expected ','");
                                vars[i].value.arr_value[vars[i].value.arr_size++] = evaluate();
                            }
                        } else {
                            vars[i].value.num_value = evaluate();
                            vars[i].value.type = VAL_NUMBER;
                        }
                        if (!in_for_loop_update) {
                        consume(TOKEN_SEMICOLON, "Expected ';' after assignment");
                    }
                    return 0;
                }
            }
            error("Undefined variable: %s", name);
        } else if (match(TOKEN_PLUS_ASSIGN)) {
                const char* name = tokens[current_token - 2].value;
                for (int i = 0; i < var_count; i++) {
                    if (strcmp(vars[i].name, name) == 0) {
                        if (vars[i].value.type == VAL_STRING) {
                            const char* str = tokens[current_token].value;
                            strncat(vars[i].value.str_value, str, MAX_STRING - strlen(vars[i].value.str_value) - 1);
                        } else {
                            vars[i].value.num_value += evaluate();
                        }
                        if (!in_for_loop_update) {
                            consume(TOKEN_SEMICOLON, "Expected ';' after assignment");
                        }
                        return 0;
                    }
                }
                error("Undefined variable: %s", name);
            } else if (match(TOKEN_MINUS_ASSIGN)) {
                const char* name = tokens[current_token - 2].value;
                for (int i = 0; i < var_count; i++) {
                    if (strcmp(vars[i].name, name) == 0) {
                        vars[i].value.num_value -= evaluate();
                        if (!in_for_loop_update) {
                            consume(TOKEN_SEMICOLON, "Expected ';' after assignment");
                        }
                        return 0;
                    }
                }
                error("Undefined variable: %s", name);
            } else if (match(TOKEN_MULTIPLY_ASSIGN)) {
                const char* name = tokens[current_token - 2].value;
                for (int i = 0; i < var_count; i++) {
                    if (strcmp(vars[i].name, name) == 0) {
                        vars[i].value.num_value *= evaluate();
                        if (!in_for_loop_update) {
                            consume(TOKEN_SEMICOLON, "Expected ';' after assignment");
                        }
                        return 0;
                    }
                }
                error("Undefined variable: %s", name);
            } else if (match(TOKEN_DIVIDE_ASSIGN)) {
                const char* name = tokens[current_token - 2].value;
                for (int i = 0; i < var_count; i++) {
                    if (strcmp(vars[i].name, name) == 0) {
                        double right = evaluate();
                        if (right == 0) error("Division by zero");
                        vars[i].value.num_value /= right;
                        if (!in_for_loop_update) {
                            consume(TOKEN_SEMICOLON, "Expected ';' after assignment");
                        }
                        return 0;
                    }
                }
                error("Undefined variable: %s", name);
            } else if (match(TOKEN_MODULO_ASSIGN)) {
                const char* name = tokens[current_token - 2].value;
                for (int i = 0; i < var_count; i++) {
                    if (strcmp(vars[i].name, name) == 0) {
                        double right = evaluate();
                        if (right == 0) error("Modulo by zero");
                        vars[i].value.num_value = fmod(vars[i].value.num_value, right);
                        if (!in_for_loop_update) {
                            consume(TOKEN_SEMICOLON, "Expected ';' after assignment");
                        }
                        return 0;
                    }
                }
                error("Undefined variable: %s", name);
            } else if (match(TOKEN_INCREMENT)) {
                const char* name = tokens[current_token - 2].value;
                for (int i = 0; i < var_count; i++) {
                    if (strcmp(vars[i].name, name) == 0) {
                        vars[i].value.num_value++;
                        if (!in_for_loop_update) {
                            consume(TOKEN_SEMICOLON, "Expected ';' after increment");
                        }
                        return 0;
                    }
                }
                error("Undefined variable: %s", name);
            } else if (match(TOKEN_DECREMENT)) {
                const char* name = tokens[current_token - 2].value;
                for (int i = 0; i < var_count; i++) {
                    if (strcmp(vars[i].name, name) == 0) {
                        vars[i].value.num_value--;
                        if (!in_for_loop_update) {
                            consume(TOKEN_SEMICOLON, "Expected ';' after decrement");
                        }
                        return 0;
                    }
                }
                error("Undefined variable: %s", name);
            } else if (peek().type == TOKEN_LBRACKET) {
                const char* name = tokens[current_token - 1].value;
                for (int i = 0; i < var_count; i++) {
                    if (strcmp(vars[i].name, name) == 0) {
                        advance();
                        int index = (int)evaluate();
                        consume(TOKEN_RBRACKET, "Expected ']'");
                        if (match(TOKEN_ASSIGN)) {
                            vars[i].value.arr_value[index] = evaluate();
                            if (!in_for_loop_update) {
                                consume(TOKEN_SEMICOLON, "Expected ';'");
                            }
                        } else {
                            printf("%g\n", vars[i].value.arr_value[index]);
                        }
                        return 0;
                    }
                }
                error("Undefined variable: %s", name);
            } else if (peek().type == TOKEN_LPAREN) {
                const char* name = tokens[current_token - 1].value;
                int func_idx = find_function(name);
                if (func_idx >= 0) {
                    consume(TOKEN_LPAREN, "Expected '('");
                    int saved_var_count = var_count;
                    for (int i = 0; i < funcs[func_idx].param_count; i++) {
                        if (i > 0) consume(TOKEN_COMMA, "Expected ','");
                        strncpy(vars[var_count].name, funcs[func_idx].params[i], 63);
                        vars[var_count].value.num_value = evaluate();
                        vars[var_count].value.type = VAL_NUMBER;
                        var_count++;
                    }
                    consume(TOKEN_RPAREN, "Expected ')'");
                    consume(TOKEN_SEMICOLON, "Expected ';'");
                    
                    int saved_token = current_token;
                    current_token = funcs[func_idx].body_start;
                    while (current_token < funcs[func_idx].body_end && peek().type != TOKEN_EOF) {
                        if (execute_statement() == 1) break;
                    }
                    current_token = saved_token;
                    var_count = saved_var_count;
                    return 0;
                }
                
                parse_call(name);
                consume(TOKEN_SEMICOLON, "Expected ';'");
                return 0;
            }
            error("Unexpected identifier: %s", tokens[current_token - 1].value);
            return 0;
        }

        case TOKEN_EOF:
            break;

        default:
            error("Unexpected token: %s", t.value);
    }
    return 0;
}

void parse_config(const char* source) {
    print_newline = 1;
    const char* p = source;

    while (*p) {
        if (*p == ' ' || *p == '\t' || *p == '\r') {
            p++;
            continue;
        }
        if (*p == '\n') break;
        if (*p == '#') {
            while (*p && *p != '\n') p++;
            continue;
        }
        if (*p == 's' && *(p+1) == 'g' && *(p+2) == '<') {
            p += 3;
            while (*p && *p != '>') {
                if (strncmp(p, "nel", 3) == 0) {
                    print_newline = 0;
                    break;
                }
                p++;
            }
            break;
        }
        break;
    }
}

char* strip_config(const char* source) {
    const char* p = source;

    while (*p) {
        if (*p == ' ' || *p == '\t' || *p == '\r') {
            p++;
            continue;
        }
        if (*p == '\n') {
            return strdup(source);
        }
        if (*p == '#') {
            while (*p && *p != '\n') p++;
            if (*p == '\n') p++;
            continue;
        }
        if (*p == 's' && *(p+1) == 'g' && *(p+2) == '<') {
            const char* start = p;
            while (*p && *p != '\n') p++;
            if (*p == '\n') p++;

            size_t prefix_len = start - source;
            size_t suffix_len = strlen(p);
            char* result = malloc(prefix_len + suffix_len + 1);
            if (!result) error("Out of memory");

            memcpy(result, source, prefix_len);
            memcpy(result + prefix_len, p, suffix_len + 1);
            return result;
        }
        return strdup(source);
    }
    return strdup(source);
}

void run(const char* source) {
    static int rand_seeded = 0;
    if (!rand_seeded) {
        srand(time(NULL));
        rand_seeded = 1;
    }
    
    parse_config(source);
    char* clean_source = strip_config(source);
    tokenize(clean_source);
    current_token = 0;

    while (peek().type != TOKEN_EOF) {
        execute_statement();
    }

    free(clean_source);
}

void run_file(const char* path) {
    FILE* f = fopen(path, "r");
    if (!f) {
        error("Cannot open file: %s", path);
    }

    fseek(f, 0, SEEK_END);
    long size = ftell(f);
    if (size < 0) {
        fclose(f);
        error("Cannot read file: %s", path);
    }
    fseek(f, 0, SEEK_SET);

    char* source = malloc(size + 1);
    if (!source) {
        fclose(f);
        error("Out of memory");
    }

    size_t read = fread(source, 1, size, f);
    fclose(f);
    source[read] = '\0';

    run(source);
    free(source);
}

void run_repl() {
    in_repl = 1;
    printf("Oraset B-5 REPL\n");
    printf("Type 'exit' or 'quit' to exit.\n");
    printf("> ");
    
    char line[MAX_LINE];
    while (fgets(line, MAX_LINE, stdin)) {
        line[strcspn(line, "\n")] = '\0';
        
        if (strcmp(line, "exit") == 0 || strcmp(line, "quit") == 0) {
            break;
        }
        if (strcmp(line, "") == 0) {
            printf("> ");
            continue;
        }
        
        char* source = malloc(strlen(line) + 2);
        strcpy(source, line);
        strcat(source, "\n");
        
        static int rand_seeded = 0;
        if (!rand_seeded) {
            srand(time(NULL));
            rand_seeded = 1;
        }
        
        parse_config(source);
        char* clean_source = strip_config(source);
        tokenize(clean_source);
        current_token = 0;
        
        while (peek().type != TOKEN_EOF) {
            execute_statement();
        }
        
        free(clean_source);
        free(source);
        printf("> ");
    }
    
    printf("\n");
    in_repl = 0;
}

#define VERSION_URL "https://oraset.parlz.com/download/version.txt"
#define DOWNLOAD_BASE "https://oraset.parlz.com/download"

static char* http_get(const char* url) {
#ifdef _WIN32
    HINTERNET hInternet = InternetOpenA("Oraset", INTERNET_OPEN_TYPE_DIRECT, NULL, NULL, 0);
    if (!hInternet) return NULL;
    
    HINTERNET hUrl = InternetOpenUrlA(hInternet, url, NULL, 0, INTERNET_FLAG_RELOAD, 0);
    if (!hUrl) {
        InternetCloseHandle(hInternet);
        return NULL;
    }
    
    char* buffer = malloc(4096);
    if (!buffer) {
        InternetCloseHandle(hUrl);
        InternetCloseHandle(hInternet);
        return NULL;
    }
    
    DWORD total_read = 0;
    DWORD bytes_read;
    char temp[1024];
    
    while (InternetReadFile(hUrl, temp, sizeof(temp), &bytes_read) && bytes_read > 0) {
        if (total_read + bytes_read >= 4095) {
            char* new_buf = realloc(buffer, total_read + bytes_read + 4096);
            if (!new_buf) {
                free(buffer);
                InternetCloseHandle(hUrl);
                InternetCloseHandle(hInternet);
                return NULL;
            }
            buffer = new_buf;
        }
        memcpy(buffer + total_read, temp, bytes_read);
        total_read += bytes_read;
    }
    buffer[total_read] = '\0';
    
    InternetCloseHandle(hUrl);
    InternetCloseHandle(hInternet);
    return buffer;
#else
    char cmd[512];
    snprintf(cmd, sizeof(cmd), "curl -s \"%s\" 2>/dev/null", url);
    FILE* fp = popen(cmd, "r");
    if (!fp) return NULL;
    
    char* buffer = malloc(4096);
    if (!buffer) {
        pclose(fp);
        return NULL;
    }
    
    size_t total_read = 0;
    size_t bytes_read;
    char temp[1024];
    
    while ((bytes_read = fread(temp, 1, sizeof(temp), fp)) > 0) {
        if (total_read + bytes_read >= 4095) {
            char* new_buf = realloc(buffer, total_read + bytes_read + 4096);
            if (!new_buf) {
                free(buffer);
                pclose(fp);
                return NULL;
            }
            buffer = new_buf;
        }
        memcpy(buffer + total_read, temp, bytes_read);
        total_read += bytes_read;
    }
    buffer[total_read] = '\0';
    pclose(fp);
    return buffer;
#endif
}

static int download_file(const char* url, const char* dest_path) {
#ifdef _WIN32
    HINTERNET hInternet = InternetOpenA("Oraset", INTERNET_OPEN_TYPE_DIRECT, NULL, NULL, 0);
    if (!hInternet) return -1;
    
    HINTERNET hUrl = InternetOpenUrlA(hInternet, url, NULL, 0, INTERNET_FLAG_RELOAD, 0);
    if (!hUrl) {
        InternetCloseHandle(hInternet);
        return -1;
    }
    
    FILE* fp = fopen(dest_path, "wb");
    if (!fp) {
        InternetCloseHandle(hUrl);
        InternetCloseHandle(hInternet);
        return -1;
    }
    
    char temp[4096];
    DWORD bytes_read;
    
    while (InternetReadFile(hUrl, temp, sizeof(temp), &bytes_read) && bytes_read > 0) {
        fwrite(temp, 1, bytes_read, fp);
    }
    
    fclose(fp);
    InternetCloseHandle(hUrl);
    InternetCloseHandle(hInternet);
    return 0;
#else
    char cmd[1024];
    snprintf(cmd, sizeof(cmd), "curl -L -o \"%s\" \"%s\" 2>/dev/null", dest_path, url);
    return system(cmd);
#endif
}

static void get_system_info(char* os, char* ext) {
#ifdef _WIN32
    strcpy(os, "windows");
    strcpy(ext, ".exe");
#elif defined(__APPLE__)
    strcpy(os, "macos");
    strcpy(ext, ".pkg");
#elif defined(__linux__)
    strcpy(os, "linux");
    strcpy(ext, ".tar.gz");
#else
    strcpy(os, "unknown");
    strcpy(ext, ".tar.gz");
#endif
}

static int compare_versions(const char* v1, const char* v2) {
    int major1 = 0, minor1 = 0, patch1 = 0, major2 = 0, minor2 = 0, patch2 = 0;
    char suffix1[64] = "", suffix2[64] = "";
    
    sscanf(v1, "%d.%d.%d-%63s", &major1, &minor1, &patch1, suffix1);
    sscanf(v2, "%d.%d.%d-%63s", &major2, &minor2, &patch2, suffix2);
    
    if (major1 != major2) return major1 - major2;
    if (minor1 != minor2) return minor1 - minor2;
    if (patch1 != patch2) return patch1 - patch2;
    
    int s1 = (strstr(suffix1, "Release") || strlen(suffix1) == 0) ? 3 : 
             (strstr(suffix1, "Beta") ? 2 : 1);
    int s2 = (strstr(suffix2, "Release") || strlen(suffix2) == 0) ? 3 : 
             (strstr(suffix2, "Beta") ? 2 : 1);
    return s1 - s2;
}

static void trim_newline(char* str) {
    int len = strlen(str);
    while (len > 0 && (str[len-1] == '\n' || str[len-1] == '\r')) {
        str[--len] = '\0';
    }
}

int update_oraset(const char* target_version) {
    printf("Checking for updates...\n");
    
    char* version_info = http_get(VERSION_URL);
    if (!version_info) {
        fprintf(stderr, "Error: Cannot fetch version information.\n");
        fprintf(stderr, "Please check your internet connection.\n");
        return 1;
    }
    
    trim_newline(version_info);
    char latest_version[128];
    strncpy(latest_version, version_info, sizeof(latest_version) - 1);
    free(version_info);
    
    printf("Current version: %s\n", VERSION);
    printf("Latest version: %s\n", latest_version);
    
    const char* version_to_install = target_version ? target_version : latest_version;
    
    if (target_version) {
        printf("Target version specified: %s\n", version_to_install);
    }
    
    char os[32], ext[16];
    get_system_info(os, ext);
    printf("Detected OS: %s\n", os);
    
    char download_url[512];
    char filename[128];
    
    if (strcmp(os, "windows") == 0) {
        snprintf(filename, sizeof(filename), "Oraset-B5%s", ext);
        snprintf(download_url, sizeof(download_url), "%s/exe/%s", DOWNLOAD_BASE, filename);
    } else if (strcmp(os, "macos") == 0) {
        snprintf(filename, sizeof(filename), "Oraset-B5%s", ext);
        snprintf(download_url, sizeof(download_url), "%s/pkg/%s", DOWNLOAD_BASE, filename);
    } else {
        snprintf(filename, sizeof(filename), "Oraset-B5%s", ext);
        snprintf(download_url, sizeof(download_url), "%s/deb/%s", DOWNLOAD_BASE, filename);
    }
    
    printf("Downloading: %s\n", download_url);
    
    char temp_path[512];
#ifdef _WIN32
    char temp_dir[MAX_PATH];
    GetTempPathA(MAX_PATH, temp_dir);
    snprintf(temp_path, sizeof(temp_path), "%s%s", temp_dir, filename);
#else
    snprintf(temp_path, sizeof(temp_path), "/tmp/%s", filename);
#endif
    
    if (download_file(download_url, temp_path) != 0) {
        fprintf(stderr, "Error: Failed to download update.\n");
        return 1;
    }
    
    printf("Downloaded to: %s\n", temp_path);
    
#ifdef _WIN32
    printf("Please run the installer: %s\n", temp_path);
#else
    if (strcmp(os, "macos") == 0) {
        printf("Installing package...\n");
        char cmd[1024];
        snprintf(cmd, sizeof(cmd), "sudo installer -pkg \"%s\" -target /", temp_path);
        system(cmd);
    } else if (strcmp(os, "linux") == 0) {
        printf("Extracting...\n");
        char cmd[1024];
        snprintf(cmd, sizeof(cmd), "cd /tmp && tar -xzf \"%s\" && sudo cp oraset /usr/local/bin/", temp_path);
        system(cmd);
    }
    printf("Installation complete!\n");
#endif
    
    return 0;
}

int main(int argc, char** argv) {
    if (argc == 1) {
        printf("Oraset B-5\n");
        printf("Usage: oraset [options] <script>\n");
        printf("Options:\n");
        printf("  -v, --version   Show version information\n");
        printf("  -u [version]    Update to latest or specified version\n");
        printf("  -i, --interactive  Enter interactive REPL mode\n");
        printf("  <script.ora>    Run an Oraset script file\n");
        return 0;
    }

    if (argc == 2) {
        if (strcmp(argv[1], "-v") == 0 || strcmp(argv[1], "--version") == 0) {
            printf("Oraset B-5\n");
            printf("A simple interpreted programming language\n");
            return 0;
        }
        if (strcmp(argv[1], "-u") == 0) {
            return update_oraset(NULL);
        }
        if (strcmp(argv[1], "-i") == 0 || strcmp(argv[1], "--interactive") == 0) {
            run_repl();
            return 0;
        }
        run_file(argv[1]);
        return 0;
    }

    if (argc >= 3 && strcmp(argv[1], "-u") == 0) {
        return update_oraset(argv[2]);
    }

    printf("Oraset B-5\n");
    printf("Usage: oraset [options] <script>\n");
    printf("Options:\n");
    printf("  -v, --version   Show version information\n");
    printf("  -u [version]    Update to latest or specified version\n");
    printf("  -i, --interactive  Enter interactive REPL mode\n");
    printf("  <script.ora>    Run an Oraset script file\n");
    return 1;
}