#include "executor.h" #include "../defs/defs.h" #include "../data/data.h" #include "../error/error.h" #include "../vars/vars.h" #include "../modules/println/println.h" #include "../modules/print/print.h" #include "../modules/math/math.h" #include "../modules/let/let.h" #include "../modules/exit/exit.h" #include "../modules/if/if.h" #include "../modules/while/while.h" #include "../modules/compare/compare.h" #include "../modules/input/input.h" #include "../modules/function/function.h" Value execute(Instruction inst) { // Special cases that need to manage their own argument evaluation if (inst.instruction == InstructionType::Let) { return modules::let(inst.args); } if (inst.instruction == InstructionType::If) { return modules::ifs(inst.args); } if (inst.instruction == InstructionType::While) { return modules::whiles(inst.args); } if (inst.instruction == InstructionType::Function) { return modules::fndef(inst.args); } // For all other instructions, evaluate the arguments first size_t i = 0; while (i < inst.args.size()) { bool evaluated = false; if (inst.args[i].valtype == ValueType::Processed) { if (inst.args[i].processed) { inst.args[i] = execute(*inst.args[i].processed); evaluated = true; } } else if (inst.args[i].valtype == ValueType::Variable) { inst.args[i] = data::getValue(inst.args[i].varName.key); evaluated = true; } if (!evaluated) { i++; } } // Then, execute the instruction with the evaluated arguments switch (inst.instruction) { case InstructionType::Print: return modules::print(inst.args); break; case InstructionType::Println: return modules::println(inst.args); break; case InstructionType::Math: return modules::math(inst.args); break; case InstructionType::Compare: return modules::compare(inst.args); break; case InstructionType::Input: return modules::input(inst.args); break; case InstructionType::Exit: return modules::exit(inst.args); break; case InstructionType::Variable: { if (!inst.args.empty()) { const std::string& name = inst.args[0].real; if (data::functions.count(name)) { const auto& func = data::functions.at(name); if (func.arg_names.size() != inst.args.size() - 1) { error("Function " + name + " expects " + std::to_string(func.arg_names.size()) + " arguments, but got " + std::to_string(inst.args.size() - 1)); return Value(); } data::pushScope(); for (size_t i = 0; i < func.arg_names.size(); ++i) { Value arg_val = inst.args[i+1]; data::scopes.back()[func.arg_names[i]] = arg_val; } Value return_val; for (const auto& body_inst : func.body) { return_val = execute(body_inst); if (return_val.is_return) { break; } } data::popScope(); return_val.is_return = false; return return_val; } } if (inst.args.size() > 2 && inst.args[1].valtype == ValueType::Real && inst.args[1].real == "=") { return varmod(inst.args); } else { error("Unknown instruction or variable"); return Value(""); } break; } case InstructionType::Return: { if (inst.args.empty()) { Value val; val.is_return = true; return val; } Value return_val = inst.args[0]; return_val.is_return = true; return return_val; } default: // Note: 'If' and 'Let' are already handled. error("Unknown instruction"); return Value(""); } }