← index
MXVM/modules/std/std.cpp
Source: MXVM/modules/std/std.cpp
#include "mx_std.h"
#include "mxvm/mxvm.hpp"
#include <algorithm>
#include <cctype>
#include <cmath>
#include <cstdlib>
#include <ctime>
#include <iostream>
#include <string>

extern "C" void mxvm_std_abs(mxvm::Program *program, std::vector<mxvm::Operand> &operand) {
    if (operand.size() != 1) {
        throw mx::Exception("abs requires 1 argument (value).");
    }

    int64_t value = program->isVariable(operand[0].op) ? program->getVariable(operand[0].op).var_value.int_value : operand[0].op_value;

    int64_t result = std::abs(value);
    program->vars["%rax"].type = mxvm::VarType::VAR_INTEGER;
    program->vars["%rax"].var_value.type = mxvm::VarType::VAR_INTEGER;
    program->vars["%rax"].var_value.int_value = result;
}

extern "C" void mxvm_std_fabs(mxvm::Program *program, std::vector<mxvm::Operand> &operand) {
    if (operand.size() != 1) {
        throw mx::Exception("fabs requires 1 argument (value).");
    }

    if (!program->isVariable(operand[0].op)) {
        throw mx::Exception("fabs argument must be a variable.");
    }

    mxvm::Variable &var = program->getVariable(operand[0].op);
    double value = (var.type == mxvm::VarType::VAR_FLOAT) ? var.var_value.float_value : static_cast<double>(var.var_value.int_value);

    double result = std::fabs(value);
    program->vars["%rax"].type = mxvm::VarType::VAR_FLOAT;
    program->vars["%rax"].var_value.type = mxvm::VarType::VAR_FLOAT;
    program->vars["%rax"].var_value.float_value = result;
}

extern "C" void mxvm_std_sqrt(mxvm::Program *program, std::vector<mxvm::Operand> &operand) {
    if (operand.size() != 1) {
        throw mx::Exception("sqrt requires 1 argument (value).");
    }

    if (!program->isVariable(operand[0].op)) {
        throw mx::Exception("sqrt argument must be a variable.");
    }

    mxvm::Variable &var = program->getVariable(operand[0].op);
    double value = (var.type == mxvm::VarType::VAR_FLOAT) ? var.var_value.float_value : static_cast<double>(var.var_value.int_value);

    double result = std::sqrt(value);
    program->vars["%rax"].type = mxvm::VarType::VAR_FLOAT;
    program->vars["%rax"].var_value.type = mxvm::VarType::VAR_FLOAT;
    program->vars["%rax"].var_value.float_value = result;
}

extern "C" void mxvm_std_pow(mxvm::Program *program, std::vector<mxvm::Operand> &operand) {
    if (operand.size() != 2) {
        throw mx::Exception("pow requires 2 arguments (base, exponent).");
    }

    double base, exponent;

    if (program->isVariable(operand[0].op)) {
        mxvm::Variable &var = program->getVariable(operand[0].op);
        base = (var.type == mxvm::VarType::VAR_FLOAT) ? var.var_value.float_value : static_cast<double>(var.var_value.int_value);
    } else {
        base = static_cast<double>(operand[0].op_value);
    }

    if (program->isVariable(operand[1].op)) {
        mxvm::Variable &var = program->getVariable(operand[1].op);
        exponent = (var.type == mxvm::VarType::VAR_FLOAT) ? var.var_value.float_value : static_cast<double>(var.var_value.int_value);
    } else {
        exponent = static_cast<double>(operand[1].op_value);
    }

    double result = std::pow(base, exponent);
    program->vars["%rax"].type = mxvm::VarType::VAR_FLOAT;
    program->vars["%rax"].var_value.type = mxvm::VarType::VAR_FLOAT;
    program->vars["%rax"].var_value.float_value = result;
}

extern "C" void mxvm_std_sin(mxvm::Program *program, std::vector<mxvm::Operand> &operand) {
    if (operand.size() != 1) {
        throw mx::Exception("sin requires 1 argument (angle).");
    }

    if (!program->isVariable(operand[0].op)) {
        throw mx::Exception("sin argument must be a variable.");
    }

    mxvm::Variable &var = program->getVariable(operand[0].op);
    double value = (var.type == mxvm::VarType::VAR_FLOAT) ? var.var_value.float_value : static_cast<double>(var.var_value.int_value);

    double result = std::sin(value);
    program->vars["%rax"].type = mxvm::VarType::VAR_FLOAT;
    program->vars["%rax"].var_value.type = mxvm::VarType::VAR_FLOAT;
    program->vars["%rax"].var_value.float_value = result;
}

extern "C" void mxvm_std_cos(mxvm::Program *program, std::vector<mxvm::Operand> &operand) {
    if (operand.size() != 1) {
        throw mx::Exception("cos requires 1 argument (angle).");
    }

    if (!program->isVariable(operand[0].op)) {
        throw mx::Exception("cos argument must be a variable.");
    }

    mxvm::Variable &var = program->getVariable(operand[0].op);
    double value = (var.type == mxvm::VarType::VAR_FLOAT) ? var.var_value.float_value : static_cast<double>(var.var_value.int_value);

    double result = std::cos(value);
    program->vars["%rax"].type = mxvm::VarType::VAR_FLOAT;
    program->vars["%rax"].var_value.type = mxvm::VarType::VAR_FLOAT;
    program->vars["%rax"].var_value.float_value = result;
}

extern "C" void mxvm_std_tan(mxvm::Program *program, std::vector<mxvm::Operand> &operand) {
    if (operand.size() != 1) {
        throw mx::Exception("tan requires 1 argument (angle).");
    }

    if (!program->isVariable(operand[0].op)) {
        throw mx::Exception("tan argument must be a variable.");
    }

    mxvm::Variable &var = program->getVariable(operand[0].op);
    double value = (var.type == mxvm::VarType::VAR_FLOAT) ? var.var_value.float_value : static_cast<double>(var.var_value.int_value);

    double result = std::tan(value);
    program->vars["%rax"].type = mxvm::VarType::VAR_FLOAT;
    program->vars["%rax"].var_value.type = mxvm::VarType::VAR_FLOAT;
    program->vars["%rax"].var_value.float_value = result;
}

extern "C" void mxvm_std_floor(mxvm::Program *program, std::vector<mxvm::Operand> &operand) {
    if (operand.size() != 1) {
        throw mx::Exception("floor requires 1 argument (value).");
    }

    if (!program->isVariable(operand[0].op)) {
        throw mx::Exception("floor argument must be a variable.");
    }

    mxvm::Variable &var = program->getVariable(operand[0].op);
    double value = (var.type == mxvm::VarType::VAR_FLOAT) ? var.var_value.float_value : static_cast<double>(var.var_value.int_value);

    double result = std::floor(value);
    program->vars["%rax"].type = mxvm::VarType::VAR_FLOAT;
    program->vars["%rax"].var_value.type = mxvm::VarType::VAR_FLOAT;
    program->vars["%rax"].var_value.float_value = result;
}

extern "C" void mxvm_std_ceil(mxvm::Program *program, std::vector<mxvm::Operand> &operand) {
    if (operand.size() != 1) {
        throw mx::Exception("ceil requires 1 argument (value).");
    }

    if (!program->isVariable(operand[0].op)) {
        throw mx::Exception("ceil argument must be a variable.");
    }

    mxvm::Variable &var = program->getVariable(operand[0].op);
    double value = (var.type == mxvm::VarType::VAR_FLOAT) ? var.var_value.float_value : static_cast<double>(var.var_value.int_value);

    double result = std::ceil(value);
    program->vars["%rax"].type = mxvm::VarType::VAR_FLOAT;
    program->vars["%rax"].var_value.type = mxvm::VarType::VAR_FLOAT;
    program->vars["%rax"].var_value.float_value = result;
}

// Random number functions
extern "C" void mxvm_std_rand(mxvm::Program *program, std::vector<mxvm::Operand> &operand) {
    int64_t result = std::rand();
    program->vars["%rax"].type = mxvm::VarType::VAR_INTEGER;
    program->vars["%rax"].var_value.type = mxvm::VarType::VAR_INTEGER;
    program->vars["%rax"].var_value.int_value = result;
}

extern "C" void mxvm_std_srand(mxvm::Program *program, std::vector<mxvm::Operand> &operand) {
    if (operand.size() != 1) {
        throw mx::Exception("srand requires 1 argument (seed).");
    }

    int64_t seed = program->isVariable(operand[0].op) ? program->getVariable(operand[0].op).var_value.int_value : operand[0].op_value;

    std::srand(static_cast<unsigned int>(seed));
}

// Memory functions
extern "C" void mxvm_std_malloc(mxvm::Program *program, std::vector<mxvm::Operand> &operand) {
    if (operand.size() != 1) {
        throw mx::Exception("malloc requires 1 argument (size).");
    }

    int64_t size = program->isVariable(operand[0].op) ? program->getVariable(operand[0].op).var_value.int_value : operand[0].op_value;

    void *result = std::malloc(static_cast<size_t>(size));
    program->vars["%rax"].type = mxvm::VarType::VAR_POINTER;
    program->vars["%rax"].var_value.type = mxvm::VarType::VAR_POINTER;
    program->vars["%rax"].var_value.ptr_value = result;
    program->vars["%rax"].var_value.owns = true;
    program->vars["%rax"].var_value.ptr_size = static_cast<uint64_t>(size);
    program->vars["%rax"].var_value.ptr_count = 1;
}

extern "C" void mxvm_std_calloc(mxvm::Program *program, std::vector<mxvm::Operand> &operand) {
    if (operand.size() != 2) {
        throw mx::Exception("calloc requires 2 arguments (count, size).");
    }

    int64_t count = program->isVariable(operand[0].op) ? program->getVariable(operand[0].op).var_value.int_value : operand[0].op_value;
    int64_t size = program->isVariable(operand[1].op) ? program->getVariable(operand[1].op).var_value.int_value : operand[1].op_value;

    void *result = std::calloc(static_cast<size_t>(count), static_cast<size_t>(size));
    program->vars["%rax"].type = mxvm::VarType::VAR_POINTER;
    program->vars["%rax"].var_value.type = mxvm::VarType::VAR_POINTER;
    program->vars["%rax"].var_value.ptr_value = result;
    program->vars["%rax"].var_value.owns = true;
    program->vars["%rax"].var_value.ptr_size = static_cast<uint64_t>(size);
    program->vars["%rax"].var_value.ptr_count = static_cast<uint64_t>(count);
}

extern "C" void mxvm_std_release(mxvm::Program *program, std::vector<mxvm::Operand> &operand) {
    if (operand.size() != 1) {
        throw mx::Exception("free requires 1 argument (pointer).");
    }

    if (!program->isVariable(operand[0].op)) {
        throw mx::Exception("free argument must be a variable.");
    }

    mxvm::Variable &var = program->getVariable(operand[0].op);
    if (var.type != mxvm::VarType::VAR_POINTER) {
        throw mx::Exception("free argument must be a pointer variable.");
    }

    std::free(var.var_value.ptr_value);
    var.var_value.ptr_value = nullptr;
}

// Character functions
extern "C" void mxvm_std_toupper(mxvm::Program *program, std::vector<mxvm::Operand> &operand) {
    if (operand.size() != 1) {
        throw mx::Exception("toupper requires 1 argument (character).");
    }

    int64_t ch = program->isVariable(operand[0].op) ? program->getVariable(operand[0].op).var_value.int_value : operand[0].op_value;

    int64_t result = std::toupper(static_cast<int>(ch));
    program->vars["%rax"].type = mxvm::VarType::VAR_INTEGER;
    program->vars["%rax"].var_value.type = mxvm::VarType::VAR_INTEGER;
    program->vars["%rax"].var_value.int_value = result;
}

extern "C" void mxvm_std_tolower(mxvm::Program *program, std::vector<mxvm::Operand> &operand) {
    if (operand.size() != 1) {
        throw mx::Exception("tolower requires 1 argument (character).");
    }

    int64_t ch = program->isVariable(operand[0].op) ? program->getVariable(operand[0].op).var_value.int_value : operand[0].op_value;

    int64_t result = std::tolower(static_cast<int>(ch));
    program->vars["%rax"].type = mxvm::VarType::VAR_INTEGER;
    program->vars["%rax"].var_value.type = mxvm::VarType::VAR_INTEGER;
    program->vars["%rax"].var_value.int_value = result;
}

extern "C" void mxvm_std_isalpha(mxvm::Program *program, std::vector<mxvm::Operand> &operand) {
    if (operand.size() != 1) {
        throw mx::Exception("isalpha requires 1 argument (character).");
    }

    int64_t ch = program->isVariable(operand[0].op) ? program->getVariable(operand[0].op).var_value.int_value : operand[0].op_value;

    int64_t result = std::isalpha(static_cast<int>(ch)) ? 1 : 0;
    program->vars["%rax"].type = mxvm::VarType::VAR_INTEGER;
    program->vars["%rax"].var_value.type = mxvm::VarType::VAR_INTEGER;
    program->vars["%rax"].var_value.int_value = result;
}

extern "C" void mxvm_std_isdigit(mxvm::Program *program, std::vector<mxvm::Operand> &operand) {
    if (operand.size() != 1) {
        throw mx::Exception("isdigit requires 1 argument (character).");
    }

    int64_t ch = program->isVariable(operand[0].op) ? program->getVariable(operand[0].op).var_value.int_value : operand[0].op_value;

    int64_t result = std::isdigit(static_cast<int>(ch)) ? 1 : 0;
    program->vars["%rax"].type = mxvm::VarType::VAR_INTEGER;
    program->vars["%rax"].var_value.type = mxvm::VarType::VAR_INTEGER;
    program->vars["%rax"].var_value.int_value = result;
}

extern "C" void mxvm_std_isspace(mxvm::Program *program, std::vector<mxvm::Operand> &operand) {
    if (operand.size() != 1) {
        throw mx::Exception("isspace requires 1 argument (character).");
    }

    int64_t ch = program->isVariable(operand[0].op) ? program->getVariable(operand[0].op).var_value.int_value : operand[0].op_value;

    int64_t result = std::isspace(static_cast<int>(ch)) ? 1 : 0;
    program->vars["%rax"].type = mxvm::VarType::VAR_INTEGER;
    program->vars["%rax"].var_value.type = mxvm::VarType::VAR_INTEGER;
    program->vars["%rax"].var_value.int_value = result;
}

// String conversion functions
extern "C" void mxvm_std_atoi(mxvm::Program *program, std::vector<mxvm::Operand> &operand) {
    if (operand.size() != 1) {
        throw mx::Exception("atoi requires 1 argument (string).");
    }

    if (!program->isVariable(operand[0].op)) {
        throw mx::Exception("atoi argument must be a variable.");
    }

    mxvm::Variable &var = program->getVariable(operand[0].op);
    const char *str = nullptr;

    if (var.type == mxvm::VarType::VAR_STRING) {
        str = var.var_value.str_value.c_str();
    } else if (var.type == mxvm::VarType::VAR_POINTER) {
        str = reinterpret_cast<const char *>(var.var_value.ptr_value);
    } else {
        throw mx::Exception("atoi argument must be a string or pointer variable.");
    }

    int64_t result = std::atoi(str);
    program->vars["%rax"].type = mxvm::VarType::VAR_INTEGER;
    program->vars["%rax"].var_value.type = mxvm::VarType::VAR_INTEGER;
    program->vars["%rax"].var_value.int_value = result;
}

extern "C" void mxvm_std_atof(mxvm::Program *program, std::vector<mxvm::Operand> &operand) {
    if (operand.size() != 1) {
        throw mx::Exception("atof requires 1 argument (string).");
    }

    if (!program->isVariable(operand[0].op)) {
        throw mx::Exception("atof argument must be a variable.");
    }

    mxvm::Variable &var = program->getVariable(operand[0].op);
    const char *str = nullptr;

    if (var.type == mxvm::VarType::VAR_STRING) {
        str = var.var_value.str_value.c_str();
    } else if (var.type == mxvm::VarType::VAR_POINTER) {
        str = reinterpret_cast<const char *>(var.var_value.ptr_value);
    } else {
        throw mx::Exception("atof argument must be a string or pointer variable.");
    }

    double result = std::atof(str);
    program->vars["%rax"].type = mxvm::VarType::VAR_FLOAT;
    program->vars["%rax"].var_value.type = mxvm::VarType::VAR_FLOAT;
    program->vars["%rax"].var_value.float_value = result;
}

// Utility functions
extern "C" void mxvm_std_exit(mxvm::Program *program, std::vector<mxvm::Operand> &operand) {
    int64_t exit_code = 0;
    if (!operand.empty()) {
        exit_code = program->isVariable(operand[0].op) ? program->getVariable(operand[0].op).var_value.int_value : operand[0].op_value;
    }

    std::exit(static_cast<int>(exit_code));
}

extern "C" void mxvm_std_system(mxvm::Program *program, std::vector<mxvm::Operand> &operand) {
    if (operand.size() != 1) {
        throw mx::Exception("system requires 1 argument (command).");
    }

    if (!program->isVariable(operand[0].op)) {
        throw mx::Exception("system argument must be a variable.");
    }

    mxvm::Variable &var = program->getVariable(operand[0].op);
    const char *command = nullptr;

    if (var.type == mxvm::VarType::VAR_STRING) {
        command = var.var_value.str_value.c_str();
    } else if (var.type == mxvm::VarType::VAR_POINTER) {
        command = reinterpret_cast<const char *>(var.var_value.ptr_value);
    } else {
        throw mx::Exception("system argument must be a string or pointer variable.");
    }

    int64_t result = std::system(command);
    program->vars["%rax"].type = mxvm::VarType::VAR_INTEGER;
    program->vars["%rax"].var_value.type = mxvm::VarType::VAR_INTEGER;
    program->vars["%rax"].var_value.int_value = result;
}

// ...existing code...

extern "C" void mxvm_std_memcpy(mxvm::Program *program, std::vector<mxvm::Operand> &operand) {
    if (operand.size() != 3) {
        throw mx::Exception("memcpy requires 3 arguments (dest, src, size).");
    }

    if (!program->isVariable(operand[0].op) || !program->isVariable(operand[1].op)) {
        throw mx::Exception("memcpy dest and src must be pointer variables.");
    }

    mxvm::Variable &dest = program->getVariable(operand[0].op);
    mxvm::Variable &src = program->getVariable(operand[1].op);

    if (dest.type != mxvm::VarType::VAR_POINTER || src.type != mxvm::VarType::VAR_POINTER) {
        throw mx::Exception("memcpy dest and src must be pointer variables.");
    }

    mxvm::except_assert("memcpy: dest pointer is null", dest.var_value.ptr_value != nullptr);
    mxvm::except_assert("memcpy: src pointer is null", src.var_value.ptr_value != nullptr);

    size_t n = 0;
    if (program->isVariable(operand[2].op)) {
        mxvm::Variable &size_var = program->getVariable(operand[2].op);
        n = static_cast<size_t>(size_var.var_value.int_value);
    } else {
        n = static_cast<size_t>(operand[2].op_value);
    }

    if (n > 0) {
        memcpy(dest.var_value.ptr_value, src.var_value.ptr_value, n);
    }

    // Return dest pointer in %rax
    program->vars["%rax"].type = mxvm::VarType::VAR_POINTER;
    program->vars["%rax"].var_value.type = mxvm::VarType::VAR_POINTER;
    program->vars["%rax"].var_value.ptr_value = dest.var_value.ptr_value;
}

extern "C" void mxvm_std_memcmp(mxvm::Program *program, std::vector<mxvm::Operand> &operand) {
    if (operand.size() != 3) {
        throw mx::Exception("memcmp requires 3 arguments (ptr1, ptr2, size).");
    }

    if (!program->isVariable(operand[0].op) || !program->isVariable(operand[1].op)) {
        throw mx::Exception("memcmp ptr1 and ptr2 must be pointer variables.");
    }

    mxvm::Variable &ptr1 = program->getVariable(operand[0].op);
    mxvm::Variable &ptr2 = program->getVariable(operand[1].op);

    if (ptr1.type != mxvm::VarType::VAR_POINTER || ptr2.type != mxvm::VarType::VAR_POINTER) {
        throw mx::Exception("memcmp ptr1 and ptr2 must be pointer variables.");
    }

    mxvm::except_assert("memcmp: ptr1 is null", ptr1.var_value.ptr_value != nullptr);
    mxvm::except_assert("memcmp: ptr2 is null", ptr2.var_value.ptr_value != nullptr);

    size_t n = 0;
    if (program->isVariable(operand[2].op)) {
        mxvm::Variable &size_var = program->getVariable(operand[2].op);
        n = static_cast<size_t>(size_var.var_value.int_value);
    } else {
        n = static_cast<size_t>(operand[2].op_value);
    }

    int result = 0;
    if (n > 0) {
        result = memcmp(ptr1.var_value.ptr_value, ptr2.var_value.ptr_value, n);
    }

    program->vars["%rax"].type = mxvm::VarType::VAR_INTEGER;
    program->vars["%rax"].var_value.type = mxvm::VarType::VAR_INTEGER;
    program->vars["%rax"].var_value.int_value = static_cast<int64_t>(result);
}

extern "C" void mxvm_std_memmove(mxvm::Program *program, std::vector<mxvm::Operand> &operand) {
    if (operand.size() != 3) {
        throw mx::Exception("memmove requires 3 arguments (dest, src, size).");
    }

    if (!program->isVariable(operand[0].op) || !program->isVariable(operand[1].op)) {
        throw mx::Exception("memmove dest and src must be pointer variables.");
    }

    mxvm::Variable &dest = program->getVariable(operand[0].op);
    mxvm::Variable &src = program->getVariable(operand[1].op);

    if (dest.type != mxvm::VarType::VAR_POINTER || src.type != mxvm::VarType::VAR_POINTER) {
        throw mx::Exception("memmove dest and src must be pointer variables.");
    }

    mxvm::except_assert("memmove: dest pointer is null", dest.var_value.ptr_value != nullptr);
    mxvm::except_assert("memmove: src pointer is null", src.var_value.ptr_value != nullptr);

    size_t n = 0;
    if (program->isVariable(operand[2].op)) {
        mxvm::Variable &size_var = program->getVariable(operand[2].op);
        n = static_cast<size_t>(size_var.var_value.int_value);
    } else {
        n = static_cast<size_t>(operand[2].op_value);
    }

    if (n > 0) {
        memmove(dest.var_value.ptr_value, src.var_value.ptr_value, n);
    }

    // Return dest pointer in %rax
    program->vars["%rax"].type = mxvm::VarType::VAR_POINTER;
    program->vars["%rax"].var_value.type = mxvm::VarType::VAR_POINTER;
    program->vars["%rax"].var_value.ptr_value = dest.var_value.ptr_value;
}

extern "C" void mxvm_std_memset(mxvm::Program *program, std::vector<mxvm::Operand> &operand) {
    if (operand.size() != 3) {
        throw mx::Exception("memset requires 3 arguments (dest, value, size).");
    }

    if (!program->isVariable(operand[0].op)) {
        throw mx::Exception("memset dest must be a pointer variable.");
    }

    mxvm::Variable &dest = program->getVariable(operand[0].op);

    if (dest.type != mxvm::VarType::VAR_POINTER) {
        throw mx::Exception("memset dest must be a pointer variable.");
    }

    mxvm::except_assert("memset: dest pointer is null", dest.var_value.ptr_value != nullptr);

    int value = 0;
    if (program->isVariable(operand[1].op)) {
        mxvm::Variable &val_var = program->getVariable(operand[1].op);
        value = static_cast<int>(val_var.var_value.int_value);
    } else {
        value = static_cast<int>(operand[1].op_value);
    }

    size_t n = 0;
    if (program->isVariable(operand[2].op)) {
        mxvm::Variable &size_var = program->getVariable(operand[2].op);
        n = static_cast<size_t>(size_var.var_value.int_value);
    } else {
        n = static_cast<size_t>(operand[2].op_value);
    }

    if (n > 0) {
        memset(dest.var_value.ptr_value, value, n);
    }

    program->vars["%rax"].type = mxvm::VarType::VAR_POINTER;
    program->vars["%rax"].var_value.type = mxvm::VarType::VAR_POINTER;
    program->vars["%rax"].var_value.ptr_value = dest.var_value.ptr_value;
}

extern "C" void mxvm_std_exp(mxvm::Program *program, std::vector<mxvm::Operand> &operand) {
    if (operand.size() != 1)
        throw mx::Exception("exp requires 1 argument.");
    double v = program->isVariable(operand[0].op) ? (program->getVariable(operand[0].op).type == mxvm::VarType::VAR_FLOAT ? program->getVariable(operand[0].op).var_value.float_value : (double)program->getVariable(operand[0].op).var_value.int_value)
                                                  : (double)operand[0].op_value;
    double r = std::exp(v);
    program->vars["%rax"].type = mxvm::VarType::VAR_FLOAT;
    program->vars["%rax"].var_value.type = mxvm::VarType::VAR_FLOAT;
    program->vars["%rax"].var_value.float_value = r;
}

extern "C" void mxvm_std_exp2(mxvm::Program *program, std::vector<mxvm::Operand> &operand) {
    if (operand.size() != 1)
        throw mx::Exception("exp2 requires 1 argument.");
    double v = program->isVariable(operand[0].op) ? (program->getVariable(operand[0].op).type == mxvm::VarType::VAR_FLOAT ? program->getVariable(operand[0].op).var_value.float_value : (double)program->getVariable(operand[0].op).var_value.int_value)
                                                  : (double)operand[0].op_value;
    double r = std::exp2(v);
    program->vars["%rax"].type = mxvm::VarType::VAR_FLOAT;
    program->vars["%rax"].var_value.type = mxvm::VarType::VAR_FLOAT;
    program->vars["%rax"].var_value.float_value = r;
}

extern "C" void mxvm_std_log(mxvm::Program *program, std::vector<mxvm::Operand> &operand) {
    if (operand.size() != 1)
        throw mx::Exception("log requires 1 argument.");
    double v = program->isVariable(operand[0].op) ? (program->getVariable(operand[0].op).type == mxvm::VarType::VAR_FLOAT ? program->getVariable(operand[0].op).var_value.float_value : (double)program->getVariable(operand[0].op).var_value.int_value)
                                                  : (double)operand[0].op_value;
    double r = std::log(v);
    program->vars["%rax"].type = mxvm::VarType::VAR_FLOAT;
    program->vars["%rax"].var_value.type = mxvm::VarType::VAR_FLOAT;
    program->vars["%rax"].var_value.float_value = r;
}

extern "C" void mxvm_std_log10(mxvm::Program *program, std::vector<mxvm::Operand> &operand) {
    if (operand.size() != 1)
        throw mx::Exception("log10 requires 1 argument.");
    double v = program->isVariable(operand[0].op) ? (program->getVariable(operand[0].op).type == mxvm::VarType::VAR_FLOAT ? program->getVariable(operand[0].op).var_value.float_value : (double)program->getVariable(operand[0].op).var_value.int_value)
                                                  : (double)operand[0].op_value;
    double r = std::log10(v);
    program->vars["%rax"].type = mxvm::VarType::VAR_FLOAT;
    program->vars["%rax"].var_value.type = mxvm::VarType::VAR_FLOAT;
    program->vars["%rax"].var_value.float_value = r;
}

extern "C" void mxvm_std_log2(mxvm::Program *program, std::vector<mxvm::Operand> &operand) {
    if (operand.size() != 1)
        throw mx::Exception("log2 requires 1 argument.");
    double v = program->isVariable(operand[0].op) ? (program->getVariable(operand[0].op).type == mxvm::VarType::VAR_FLOAT ? program->getVariable(operand[0].op).var_value.float_value : (double)program->getVariable(operand[0].op).var_value.int_value)
                                                  : (double)operand[0].op_value;
    double r = std::log2(v);
    program->vars["%rax"].type = mxvm::VarType::VAR_FLOAT;
    program->vars["%rax"].var_value.type = mxvm::VarType::VAR_FLOAT;
    program->vars["%rax"].var_value.float_value = r;
}

extern "C" void mxvm_std_fmod(mxvm::Program *program, std::vector<mxvm::Operand> &operand) {
    if (operand.size() != 2)
        throw mx::Exception("fmod requires 2 arguments (x, y).");
    double x = program->isVariable(operand[0].op) ? (program->getVariable(operand[0].op).type == mxvm::VarType::VAR_FLOAT ? program->getVariable(operand[0].op).var_value.float_value : (double)program->getVariable(operand[0].op).var_value.int_value)
                                                  : (double)operand[0].op_value;
    double y = program->isVariable(operand[1].op) ? (program->getVariable(operand[1].op).type == mxvm::VarType::VAR_FLOAT ? program->getVariable(operand[1].op).var_value.float_value : (double)program->getVariable(operand[1].op).var_value.int_value)
                                                  : (double)operand[1].op_value;
    double r = std::fmod(x, y);
    program->vars["%rax"].type = mxvm::VarType::VAR_FLOAT;
    program->vars["%rax"].var_value.type = mxvm::VarType::VAR_FLOAT;
    program->vars["%rax"].var_value.float_value = r;
}

extern "C" void mxvm_std_atan2(mxvm::Program *program, std::vector<mxvm::Operand> &operand) {
    if (operand.size() != 2)
        throw mx::Exception("atan2 requires 2 arguments (y, x).");
    double y = program->isVariable(operand[0].op) ? (program->getVariable(operand[0].op).type == mxvm::VarType::VAR_FLOAT ? program->getVariable(operand[0].op).var_value.float_value : (double)program->getVariable(operand[0].op).var_value.int_value)
                                                  : (double)operand[0].op_value;
    double x = program->isVariable(operand[1].op) ? (program->getVariable(operand[1].op).type == mxvm::VarType::VAR_FLOAT ? program->getVariable(operand[1].op).var_value.float_value : (double)program->getVariable(operand[1].op).var_value.int_value)
                                                  : (double)operand[1].op_value;
    double r = std::atan2(y, x);
    program->vars["%rax"].type = mxvm::VarType::VAR_FLOAT;
    program->vars["%rax"].var_value.type = mxvm::VarType::VAR_FLOAT;
    program->vars["%rax"].var_value.float_value = r;
}

extern "C" void mxvm_std_asin(mxvm::Program *program, std::vector<mxvm::Operand> &operand) {
    if (operand.size() != 1)
        throw mx::Exception("asin requires 1 argument.");
    double v = program->isVariable(operand[0].op) ? (program->getVariable(operand[0].op).type == mxvm::VarType::VAR_FLOAT ? program->getVariable(operand[0].op).var_value.float_value : (double)program->getVariable(operand[0].op).var_value.int_value)
                                                  : (double)operand[0].op_value;
    double r = std::asin(v);
    program->vars["%rax"].type = mxvm::VarType::VAR_FLOAT;
    program->vars["%rax"].var_value.type = mxvm::VarType::VAR_FLOAT;
    program->vars["%rax"].var_value.float_value = r;
}

extern "C" void mxvm_std_acos(mxvm::Program *program, std::vector<mxvm::Operand> &operand) {
    if (operand.size() != 1)
        throw mx::Exception("acos requires 1 argument.");
    double v = program->isVariable(operand[0].op) ? (program->getVariable(operand[0].op).type == mxvm::VarType::VAR_FLOAT ? program->getVariable(operand[0].op).var_value.float_value : (double)program->getVariable(operand[0].op).var_value.int_value)
                                                  : (double)operand[0].op_value;
    double r = std::acos(v);
    program->vars["%rax"].type = mxvm::VarType::VAR_FLOAT;
    program->vars["%rax"].var_value.type = mxvm::VarType::VAR_FLOAT;
    program->vars["%rax"].var_value.float_value = r;
}

extern "C" void mxvm_std_atan(mxvm::Program *program, std::vector<mxvm::Operand> &operand) {
    if (operand.size() != 1)
        throw mx::Exception("atan requires 1 argument.");
    double v = program->isVariable(operand[0].op) ? (program->getVariable(operand[0].op).type == mxvm::VarType::VAR_FLOAT ? program->getVariable(operand[0].op).var_value.float_value : (double)program->getVariable(operand[0].op).var_value.int_value)
                                                  : (double)operand[0].op_value;
    double r = std::atan(v);
    program->vars["%rax"].type = mxvm::VarType::VAR_FLOAT;
    program->vars["%rax"].var_value.type = mxvm::VarType::VAR_FLOAT;
    program->vars["%rax"].var_value.float_value = r;
}

extern "C" void mxvm_std_sinh(mxvm::Program *program, std::vector<mxvm::Operand> &operand) {
    if (operand.size() != 1)
        throw mx::Exception("sinh requires 1 argument.");
    double v = program->isVariable(operand[0].op) ? (program->getVariable(operand[0].op).type == mxvm::VarType::VAR_FLOAT ? program->getVariable(operand[0].op).var_value.float_value : (double)program->getVariable(operand[0].op).var_value.int_value)
                                                  : (double)operand[0].op_value;
    double r = std::sinh(v);
    program->vars["%rax"].type = mxvm::VarType::VAR_FLOAT;
    program->vars["%rax"].var_value.type = mxvm::VarType::VAR_FLOAT;
    program->vars["%rax"].var_value.float_value = r;
}

extern "C" void mxvm_std_cosh(mxvm::Program *program, std::vector<mxvm::Operand> &operand) {
    if (operand.size() != 1)
        throw mx::Exception("cosh requires 1 argument.");
    double v = program->isVariable(operand[0].op) ? (program->getVariable(operand[0].op).type == mxvm::VarType::VAR_FLOAT ? program->getVariable(operand[0].op).var_value.float_value : (double)program->getVariable(operand[0].op).var_value.int_value)
                                                  : (double)operand[0].op_value;
    double r = std::cosh(v);
    program->vars["%rax"].type = mxvm::VarType::VAR_FLOAT;
    program->vars["%rax"].var_value.type = mxvm::VarType::VAR_FLOAT;
    program->vars["%rax"].var_value.float_value = r;
}

extern "C" void mxvm_std_tanh(mxvm::Program *program, std::vector<mxvm::Operand> &operand) {
    if (operand.size() != 1)
        throw mx::Exception("tanh requires 1 argument.");
    double v = program->isVariable(operand[0].op) ? (program->getVariable(operand[0].op).type == mxvm::VarType::VAR_FLOAT ? program->getVariable(operand[0].op).var_value.float_value : (double)program->getVariable(operand[0].op).var_value.int_value)
                                                  : (double)operand[0].op_value;
    double r = std::tanh(v);
    program->vars["%rax"].type = mxvm::VarType::VAR_FLOAT;
    program->vars["%rax"].var_value.type = mxvm::VarType::VAR_FLOAT;
    program->vars["%rax"].var_value.float_value = r;
}

extern "C" void mxvm_std_hypot(mxvm::Program *program, std::vector<mxvm::Operand> &operand) {
    if (operand.size() != 2)
        throw mx::Exception("hypot requires 2 arguments (x, y).");
    double x = program->isVariable(operand[0].op) ? (program->getVariable(operand[0].op).type == mxvm::VarType::VAR_FLOAT ? program->getVariable(operand[0].op).var_value.float_value : (double)program->getVariable(operand[0].op).var_value.int_value)
                                                  : (double)operand[0].op_value;
    double y = program->isVariable(operand[1].op) ? (program->getVariable(operand[1].op).type == mxvm::VarType::VAR_FLOAT ? program->getVariable(operand[1].op).var_value.float_value : (double)program->getVariable(operand[1].op).var_value.int_value)
                                                  : (double)operand[1].op_value;
    double r = std::hypot(x, y);
    program->vars["%rax"].type = mxvm::VarType::VAR_FLOAT;
    program->vars["%rax"].var_value.type = mxvm::VarType::VAR_FLOAT;
    program->vars["%rax"].var_value.float_value = r;
}

extern "C" void mxvm_std_round(mxvm::Program *program, std::vector<mxvm::Operand> &operand) {
    if (operand.size() != 1)
        throw mx::Exception("round requires 1 argument.");
    double v = program->isVariable(operand[0].op) ? (program->getVariable(operand[0].op).type == mxvm::VarType::VAR_FLOAT ? program->getVariable(operand[0].op).var_value.float_value : (double)program->getVariable(operand[0].op).var_value.int_value)
                                                  : (double)operand[0].op_value;
    double r = std::round(v);
    program->vars["%rax"].type = mxvm::VarType::VAR_FLOAT;
    program->vars["%rax"].var_value.type = mxvm::VarType::VAR_FLOAT;
    program->vars["%rax"].var_value.float_value = r;
}

extern "C" void mxvm_std_trunc(mxvm::Program *program, std::vector<mxvm::Operand> &operand) {
    if (operand.size() != 1)
        throw mx::Exception("trunc requires 1 argument.");
    double v = program->isVariable(operand[0].op) ? (program->getVariable(operand[0].op).type == mxvm::VarType::VAR_FLOAT ? program->getVariable(operand[0].op).var_value.float_value : (double)program->getVariable(operand[0].op).var_value.int_value)
                                                  : (double)operand[0].op_value;
    double r = std::trunc(v);
    program->vars["%rax"].type = mxvm::VarType::VAR_FLOAT;
    program->vars["%rax"].var_value.type = mxvm::VarType::VAR_FLOAT;
    program->vars["%rax"].var_value.float_value = r;
}

extern "C" void mxvm_std_argc(mxvm::Program *program, std::vector<mxvm::Operand> &operand) {
    (void)operand;
    int v = argc();
    program->vars["%rax"].type = mxvm::VarType::VAR_INTEGER;
    program->vars["%rax"].var_value.type = mxvm::VarType::VAR_INTEGER;
    program->vars["%rax"].var_value.int_value = (int64_t)v;
}

extern "C" void mxvm_std_argv(mxvm::Program *program, std::vector<mxvm::Operand> &operand) {
    if (operand.size() != 1) {
        throw mx::Exception("argv(index) requires 1 argument");
    }

    int idx = 0;
    if (operand[0].type == mxvm::OperandType::OP_CONSTANT) {
        idx = (int)operand[0].op_value;
    } else if (program->isVariable(operand[0].op)) {
        mxvm::Variable &v = program->getVariable(operand[0].op);
        if (v.type != mxvm::VarType::VAR_INTEGER) {
            throw mx::Exception("argv index must be an integer");
        }
        idx = (int)v.var_value.int_value;
    } else {
        throw mx::Exception("argv argument must be an index constant or integer variable");
    }

    const char *s = argv(idx);
    program->vars["%rax"].type = mxvm::VarType::VAR_POINTER;
    program->vars["%rax"].var_value.type = mxvm::VarType::VAR_POINTER;
    program->vars["%rax"].var_value.ptr_value = (void *)s; /* may be NULL */
}

extern "C" void mxvm_std_free_program_args(mxvm::Program *program, std::vector<mxvm::Operand> &operand) {
    free_program_args();
}

extern "C" void mxvm_std_set_program_args(mxvm::Program *program, std::vector<mxvm::Operand> &operand) {
    if (operand.size() != 2) {
        throw mx::Exception("set_program_args requires 2 arguments (argc, argv)");
    }

    if (!program->isVariable(operand[0].op) || !program->isVariable(operand[1].op)) {
        throw mx::Exception("set_program_args arguments must be variables");
    }

    mxvm::Variable &argc_var = program->getVariable(operand[0].op);
    mxvm::Variable &argv_var = program->getVariable(operand[1].op);

    if (argc_var.type != mxvm::VarType::VAR_INTEGER) {
        throw mx::Exception("set_program_args first argument (argc) must be an integer");
    }

    if (argv_var.type != mxvm::VarType::VAR_POINTER) {
        throw mx::Exception("set_program_args second argument (argv) must be a pointer");
    }

    int argc = (int)argc_var.var_value.int_value;
    const char **argv = (const char **)argv_var.var_value.ptr_value;

    if (argv == nullptr && argc > 0) {
        throw mx::Exception("set_program_args: argv pointer is null but argc > 0");
    }

    set_program_args(argc, argv);
}

extern "C" void mxvm_std_float_to_int(mxvm::Program *program, std::vector<mxvm::Operand> &operand) {
    if (operand.size() != 1) {
        throw mx::Exception("float_to_int requires 1 argument (float value).");
    }

    double value = 0.0;
    if (program->isVariable(operand[0].op)) {
        mxvm::Variable &var = program->getVariable(operand[0].op);
        if (var.type == mxvm::VarType::VAR_FLOAT) {
            value = var.var_value.float_value;
        } else if (var.type == mxvm::VarType::VAR_INTEGER) {
            value = static_cast<double>(var.var_value.int_value);
        } else {
            throw mx::Exception("float_to_int argument must be a float or integer variable.");
        }
    } else {
        value = static_cast<double>(operand[0].op_value);
    }

    int64_t result = static_cast<int64_t>(value);
    program->vars["%rax"].type = mxvm::VarType::VAR_INTEGER;
    program->vars["%rax"].var_value.type = mxvm::VarType::VAR_INTEGER;
    program->vars["%rax"].var_value.int_value = result;
}

extern "C" void mxvm_std_int_to_float(mxvm::Program *program, std::vector<mxvm::Operand> &operand) {
    if (operand.size() != 1) {
        throw mx::Exception("int_to_float requires 1 argument (integer value).");
    }

    int64_t value = 0;
    if (program->isVariable(operand[0].op)) {
        mxvm::Variable &var = program->getVariable(operand[0].op);
        if (var.type == mxvm::VarType::VAR_INTEGER) {
            value = var.var_value.int_value;
        } else if (var.type == mxvm::VarType::VAR_FLOAT) {
            value = static_cast<int64_t>(var.var_value.float_value);
        } else {
            throw mx::Exception("int_to_float argument must be an integer or float variable.");
        }
    } else {
        value = operand[0].op_value;
    }

    double result = static_cast<double>(value);
    program->vars["%rax"].type = mxvm::VarType::VAR_FLOAT;
    program->vars["%rax"].var_value.type = mxvm::VarType::VAR_FLOAT;
    program->vars["%rax"].var_value.float_value = result;
}