|
|
- #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;
- }
- }
|