Nelze vybrat více než 25 témat Téma musí začínat písmenem nebo číslem, může obsahovat pomlčky („-“) a může být dlouhé až 35 znaků.
 

221 řádky
11 KiB

#include <ranges>
#include "UserScript/interpreter.h"
namespace scripting {
// Replace with constexpr vector & find ?
static const std::map<ast::operator_t, ByteCodeInterpreter::operator_t> mappings = {
{ast::operator_t::logical_not, ByteCodeInterpreter::operator_t::logical_not},
{ast::operator_t::binary_not, ByteCodeInterpreter::operator_t::binary_not},
{ast::operator_t::divide, ByteCodeInterpreter::operator_t::divide},
{ast::operator_t::modulo, ByteCodeInterpreter::operator_t::modulo},
{ast::operator_t::multiply, ByteCodeInterpreter::operator_t::multiply},
{ast::operator_t::subtract, ByteCodeInterpreter::operator_t::subtract},
{ast::operator_t::add, ByteCodeInterpreter::operator_t::add},
{ast::operator_t::bitshift_left, ByteCodeInterpreter::operator_t::bitshift_left},
{ast::operator_t::bitshift_right, ByteCodeInterpreter::operator_t::bitshift_right},
{ast::operator_t::rotate_left, ByteCodeInterpreter::operator_t::rotate_left},
{ast::operator_t::rotate_right, ByteCodeInterpreter::operator_t::rotate_right},
{ast::operator_t::less_than, ByteCodeInterpreter::operator_t::less_than},
{ast::operator_t::greater_than, ByteCodeInterpreter::operator_t::greater_than},
{ast::operator_t::less_or_equal_than, ByteCodeInterpreter::operator_t::less_or_equal_than},
{ast::operator_t::greater_or_equal_than, ByteCodeInterpreter::operator_t::greater_or_equal_than},
{ast::operator_t::equals, ByteCodeInterpreter::operator_t::equals},
{ast::operator_t::different, ByteCodeInterpreter::operator_t::different},
{ast::operator_t::binary_and, ByteCodeInterpreter::operator_t::binary_and},
{ast::operator_t::binary_or, ByteCodeInterpreter::operator_t::binary_or},
{ast::operator_t::binary_xor, ByteCodeInterpreter::operator_t::binary_xor},
{ast::operator_t::logical_and, ByteCodeInterpreter::operator_t::logical_and},
{ast::operator_t::logical_or, ByteCodeInterpreter::operator_t::logical_or},
};
/// GENERATION HANDLERS DECLARATIONS
template<typename T>
void handle(std::vector<ByteCodeInterpreter::operand> &, std::vector<script_error> &, T &);
template<>
void handle<ast::block>(std::vector<ByteCodeInterpreter::operand> &ctx, std::vector<script_error> &errors,
ast::block &block);
template<>
void
handle<ast::command_expression>(std::vector<ByteCodeInterpreter::operand> &ctx, std::vector<script_error> &errors,
ast::command_expression &cmd);
template<>
void handle<ast::binary_algebraic_expression>(std::vector<ByteCodeInterpreter::operand> &ctx,
std::vector<script_error> &errors,
ast::binary_algebraic_expression &cmd);
template<>
void handle<ast::unary_algebraic_expression>(std::vector<ByteCodeInterpreter::operand> &ctx,
std::vector<script_error> &errors,
ast::unary_algebraic_expression &cmd);
template<>
void
handle<ast::paren_expression>(std::vector<ByteCodeInterpreter::operand> &ctx, std::vector<script_error> &errors,
ast::paren_expression &cmd);
template<>
void handle<ast::conditional>(std::vector<ByteCodeInterpreter::operand> &ctx, std::vector<script_error> &errors,
ast::conditional &cmd);
template<>
void handle<ast::while_loop>(std::vector<ByteCodeInterpreter::operand> &ctx, std::vector<script_error> &errors,
ast::while_loop &cmd);
template<>
void handle<ast::expression>(std::vector<ByteCodeInterpreter::operand> &ctx, std::vector<script_error> &errors,
ast::expression &cmd);
template<>
void
handle<ast::variable_expression>(std::vector<ByteCodeInterpreter::operand> &ctx, std::vector<script_error> &errors,
ast::variable_expression &cmd);
template<>
void handle<ast::literal_int_expression>(std::vector<ByteCodeInterpreter::operand> &ctx,
std::vector<script_error> &errors, ast::literal_int_expression &cmd);
template<>
void handle<ast::literal_string_expression>(std::vector<ByteCodeInterpreter::operand> &ctx,
std::vector<script_error> &errors, ast::literal_string_expression &cmd);
/// GENERATION HANDLERS DEFINITIONS
template<>
void handle<ast::block>(std::vector<ByteCodeInterpreter::operand> &ctx, std::vector<script_error> &errors,
ast::block &block) {
for (auto &elem: block.contents) {
std::visit([&](auto &v) { handle(ctx, errors, *v); }, elem.contents);
ctx.push_back(ByteCodeInterpreter::operand{.element = ByteCodeInterpreter::operator_t::INTERNAL_stack_cls});
}
}
template<>
void
handle<ast::command_expression>(std::vector<ByteCodeInterpreter::operand> &ctx, std::vector<script_error> &errors,
ast::command_expression &cmd) {
for (auto& argument : std::ranges::reverse_view(cmd.arguments)) {
std::visit([&](auto &v) { handle(ctx, errors, *v); }, argument->contents);
}
ctx.push_back(
ByteCodeInterpreter::operand{.element = ByteCodeInterpreter::function_tag{.name = cmd.name.value, .arity = cmd.arguments.size()}, .location = cmd.location});
}
template<>
void
handle<ast::paren_expression>(std::vector<ByteCodeInterpreter::operand> &ctx, std::vector<script_error> &errors,
ast::paren_expression &expr) {
std::visit([&](auto &v) { handle(ctx, errors, *v); }, expr.content);
}
template<>
void handle<ast::expression>(std::vector<ByteCodeInterpreter::operand> &ctx, std::vector<script_error> &errors,
ast::expression &expr) {
std::visit([&](auto &v) { handle(ctx, errors, *v); }, expr.contents);
}
template<>
void handle<ast::binary_algebraic_expression>(std::vector<ByteCodeInterpreter::operand> &ctx,
std::vector<script_error> &errors,
ast::binary_algebraic_expression &expr) {
handle(ctx, errors, *expr.lhs);
handle(ctx, errors, *expr.rhs);
ctx.push_back(ByteCodeInterpreter::operand{.element = mappings.at(expr.op), .location = expr.location});
}
template<>
void handle<ast::unary_algebraic_expression>(std::vector<ByteCodeInterpreter::operand> &ctx,
std::vector<script_error> &errors,
ast::unary_algebraic_expression &expr) {
handle(ctx, errors, *expr.content);
ctx.push_back(ByteCodeInterpreter::operand{.element = mappings.at(expr.op), .location = expr.location});
}
template<>
void
handle<ast::variable_expression>(std::vector<ByteCodeInterpreter::operand> &ctx, std::vector<script_error> &errors,
ast::variable_expression &expr) {
ctx.push_back(ByteCodeInterpreter::operand{
ByteCodeInterpreter::variable_tag{.name = expr.name.value, .location = expr.location}});
}
template<>
void handle<ast::literal_int_expression>(std::vector<ByteCodeInterpreter::operand> &ctx,
std::vector<script_error> &errors, ast::literal_int_expression &expr) {
ctx.push_back(ByteCodeInterpreter::operand{script_value{expr.value}});
}
template<>
void handle<ast::literal_string_expression>(std::vector<ByteCodeInterpreter::operand> &ctx,
std::vector<script_error> &errors,
ast::literal_string_expression &expr) {
ctx.push_back(ByteCodeInterpreter::operand{script_value{expr.value}});
}
template<>
void handle<ast::conditional>(std::vector<ByteCodeInterpreter::operand> &ctx, std::vector<script_error> &errors,
ast::conditional &cond) {
/// some basic documentation (from before the reference stability bug but things are the same):
/// https://app.excalidraw.com/s/hxPegpAmTX/2c8KKzinqeg
std::visit([&](auto &v) { handle(ctx, errors, *v); }, cond.condition->contents);
ctx.push_back(ByteCodeInterpreter::operand{.element = script_value{}, .location = cond.location});
/// As you can see, being smart is dumb, be a fucking monkey that comes from the 70s and use 70s technology:tm: to your advantage
/// More seriously, WTF (?) we do this because we used to have a bug with unreliable references to these locations, which makes sense since we
/// don't have reference stability
auto else_side_idx = ctx.size() - 1;
ctx.push_back(
ByteCodeInterpreter::operand{.element = ByteCodeInterpreter::operator_t::INTERNAL_jump_if, .location = cond.location});
handle(ctx, errors, *cond.on_condition);
if (cond.otherwise) {
ctx.push_back(ByteCodeInterpreter::operand{.element = script_value{}, .location = cond.location});
auto end_side_idx = ctx.size() - 1;
ctx.push_back(
ByteCodeInterpreter::operand{.element = ByteCodeInterpreter::operator_t::INTERNAL_jump, .location = cond.location});
ctx[else_side_idx].element = static_cast<int32_t>(ctx.size()) - 1;
ctx[else_side_idx].location = cond.location;
handle(ctx, errors, *cond.otherwise);
ctx[end_side_idx].element = static_cast<int32_t>(ctx.size()) - 1;
ctx[end_side_idx].location = cond.location;
} else {
ctx[else_side_idx].element = static_cast<int32_t>(ctx.size()) - 1;
ctx[else_side_idx].location = cond.location;
}
}
template<>
void handle<ast::while_loop>(std::vector<ByteCodeInterpreter::operand> &ctx, std::vector<script_error> &errors,
ast::while_loop &cond) {
auto beforewhile_side_idx = static_cast<int32_t>(ctx.size()) - 1;
std::visit([&](auto &v) { handle(ctx, errors, *v); }, cond.condition->contents);
ctx.push_back(ByteCodeInterpreter::operand{.element = script_value{}, .location = cond.location});
auto endwhile_side_idx = ctx.size() - 1;
ctx.push_back(
ByteCodeInterpreter::operand{.element = ByteCodeInterpreter::operator_t::INTERNAL_jump_if, .location = cond.location});
handle(ctx, errors, *cond.on_condition);
ctx.push_back(
ByteCodeInterpreter::operand{.element = script_value{beforewhile_side_idx}, .location = cond.location});
ctx.push_back(
ByteCodeInterpreter::operand{.element = ByteCodeInterpreter::operator_t::INTERNAL_jump, .location = cond.location});
ctx[endwhile_side_idx].element = static_cast<int32_t>(ctx.size()) - 1;
ctx[endwhile_side_idx].location = cond.location;
}
std::vector<ByteCodeInterpreter::operand>
ByteCodeInterpreter::generate(std::vector<script_error> &errors, ast::block &tree, bool loop) {
std::vector<operand> code;
handle(code, errors, tree);
if (loop) {
// Here we have to deal with the quirks of jumping before the increments happens again
code.push_back(ByteCodeInterpreter::operand{.element = script_value{-1}, .location = tree.location});
code.push_back(
ByteCodeInterpreter::operand{.element = ByteCodeInterpreter::operator_t::INTERNAL_jump, .location = tree.location});
}
return code;
}
}