131 lines
4.4 KiB
C++
131 lines
4.4 KiB
C++
#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"
|
|
#include "../modules/concat/concat.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::Concat:
|
|
return modules::concat(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("");
|
|
}
|
|
}
|