Você não pode selecionar mais de 25 tópicos Os tópicos devem começar com uma letra ou um número, podem incluir traços ('-') e podem ter até 35 caracteres.

220 linhas
11 KiB

  1. #include <ranges>
  2. #include "UserScript/interpreter.h"
  3. namespace scripting {
  4. // Replace with constexpr vector & find ?
  5. static const std::map<ast::operator_t, ByteCodeInterpreter::operator_t> mappings = {
  6. {ast::operator_t::logical_not, ByteCodeInterpreter::operator_t::logical_not},
  7. {ast::operator_t::binary_not, ByteCodeInterpreter::operator_t::binary_not},
  8. {ast::operator_t::divide, ByteCodeInterpreter::operator_t::divide},
  9. {ast::operator_t::modulo, ByteCodeInterpreter::operator_t::modulo},
  10. {ast::operator_t::multiply, ByteCodeInterpreter::operator_t::multiply},
  11. {ast::operator_t::subtract, ByteCodeInterpreter::operator_t::subtract},
  12. {ast::operator_t::add, ByteCodeInterpreter::operator_t::add},
  13. {ast::operator_t::bitshift_left, ByteCodeInterpreter::operator_t::bitshift_left},
  14. {ast::operator_t::bitshift_right, ByteCodeInterpreter::operator_t::bitshift_right},
  15. {ast::operator_t::rotate_left, ByteCodeInterpreter::operator_t::rotate_left},
  16. {ast::operator_t::rotate_right, ByteCodeInterpreter::operator_t::rotate_right},
  17. {ast::operator_t::less_than, ByteCodeInterpreter::operator_t::less_than},
  18. {ast::operator_t::greater_than, ByteCodeInterpreter::operator_t::greater_than},
  19. {ast::operator_t::less_or_equal_than, ByteCodeInterpreter::operator_t::less_or_equal_than},
  20. {ast::operator_t::greater_or_equal_than, ByteCodeInterpreter::operator_t::greater_or_equal_than},
  21. {ast::operator_t::equals, ByteCodeInterpreter::operator_t::equals},
  22. {ast::operator_t::different, ByteCodeInterpreter::operator_t::different},
  23. {ast::operator_t::binary_and, ByteCodeInterpreter::operator_t::binary_and},
  24. {ast::operator_t::binary_or, ByteCodeInterpreter::operator_t::binary_or},
  25. {ast::operator_t::binary_xor, ByteCodeInterpreter::operator_t::binary_xor},
  26. {ast::operator_t::logical_and, ByteCodeInterpreter::operator_t::logical_and},
  27. {ast::operator_t::logical_or, ByteCodeInterpreter::operator_t::logical_or},
  28. };
  29. /// GENERATION HANDLERS DECLARATIONS
  30. template<typename T>
  31. void handle(std::vector<ByteCodeInterpreter::operand> &, std::vector<script_error> &, T &);
  32. template<>
  33. void handle<ast::block>(std::vector<ByteCodeInterpreter::operand> &ctx, std::vector<script_error> &errors,
  34. ast::block &block);
  35. template<>
  36. void
  37. handle<ast::command_expression>(std::vector<ByteCodeInterpreter::operand> &ctx, std::vector<script_error> &errors,
  38. ast::command_expression &cmd);
  39. template<>
  40. void handle<ast::binary_algebraic_expression>(std::vector<ByteCodeInterpreter::operand> &ctx,
  41. std::vector<script_error> &errors,
  42. ast::binary_algebraic_expression &cmd);
  43. template<>
  44. void handle<ast::unary_algebraic_expression>(std::vector<ByteCodeInterpreter::operand> &ctx,
  45. std::vector<script_error> &errors,
  46. ast::unary_algebraic_expression &cmd);
  47. template<>
  48. void
  49. handle<ast::paren_expression>(std::vector<ByteCodeInterpreter::operand> &ctx, std::vector<script_error> &errors,
  50. ast::paren_expression &cmd);
  51. template<>
  52. void handle<ast::conditional>(std::vector<ByteCodeInterpreter::operand> &ctx, std::vector<script_error> &errors,
  53. ast::conditional &cmd);
  54. template<>
  55. void handle<ast::while_loop>(std::vector<ByteCodeInterpreter::operand> &ctx, std::vector<script_error> &errors,
  56. ast::while_loop &cmd);
  57. template<>
  58. void handle<ast::expression>(std::vector<ByteCodeInterpreter::operand> &ctx, std::vector<script_error> &errors,
  59. ast::expression &cmd);
  60. template<>
  61. void
  62. handle<ast::variable_expression>(std::vector<ByteCodeInterpreter::operand> &ctx, std::vector<script_error> &errors,
  63. ast::variable_expression &cmd);
  64. template<>
  65. void handle<ast::literal_int_expression>(std::vector<ByteCodeInterpreter::operand> &ctx,
  66. std::vector<script_error> &errors, ast::literal_int_expression &cmd);
  67. template<>
  68. void handle<ast::literal_string_expression>(std::vector<ByteCodeInterpreter::operand> &ctx,
  69. std::vector<script_error> &errors, ast::literal_string_expression &cmd);
  70. /// GENERATION HANDLERS DEFINITIONS
  71. template<>
  72. void handle<ast::block>(std::vector<ByteCodeInterpreter::operand> &ctx, std::vector<script_error> &errors,
  73. ast::block &block) {
  74. for (auto &elem: block.contents) {
  75. std::visit([&](auto &v) { handle(ctx, errors, *v); }, elem.contents);
  76. ctx.push_back(ByteCodeInterpreter::operand{.element = ByteCodeInterpreter::operator_t::INTERNAL_stack_cls});
  77. }
  78. }
  79. template<>
  80. void
  81. handle<ast::command_expression>(std::vector<ByteCodeInterpreter::operand> &ctx, std::vector<script_error> &errors,
  82. ast::command_expression &cmd) {
  83. for (auto& argument : std::ranges::reverse_view(cmd.arguments)) {
  84. std::visit([&](auto &v) { handle(ctx, errors, *v); }, argument->contents);
  85. }
  86. ctx.push_back(
  87. ByteCodeInterpreter::operand{.element = ByteCodeInterpreter::function_tag{.name = cmd.name.value, .arity = cmd.arguments.size()}, .location = cmd.location});
  88. }
  89. template<>
  90. void
  91. handle<ast::paren_expression>(std::vector<ByteCodeInterpreter::operand> &ctx, std::vector<script_error> &errors,
  92. ast::paren_expression &expr) {
  93. std::visit([&](auto &v) { handle(ctx, errors, *v); }, expr.content);
  94. }
  95. template<>
  96. void handle<ast::expression>(std::vector<ByteCodeInterpreter::operand> &ctx, std::vector<script_error> &errors,
  97. ast::expression &expr) {
  98. std::visit([&](auto &v) { handle(ctx, errors, *v); }, expr.contents);
  99. }
  100. template<>
  101. void handle<ast::binary_algebraic_expression>(std::vector<ByteCodeInterpreter::operand> &ctx,
  102. std::vector<script_error> &errors,
  103. ast::binary_algebraic_expression &expr) {
  104. handle(ctx, errors, *expr.lhs);
  105. handle(ctx, errors, *expr.rhs);
  106. ctx.push_back(ByteCodeInterpreter::operand{.element = mappings.at(expr.op), .location = expr.location});
  107. }
  108. template<>
  109. void handle<ast::unary_algebraic_expression>(std::vector<ByteCodeInterpreter::operand> &ctx,
  110. std::vector<script_error> &errors,
  111. ast::unary_algebraic_expression &expr) {
  112. handle(ctx, errors, *expr.content);
  113. ctx.push_back(ByteCodeInterpreter::operand{.element = mappings.at(expr.op), .location = expr.location});
  114. }
  115. template<>
  116. void
  117. handle<ast::variable_expression>(std::vector<ByteCodeInterpreter::operand> &ctx, std::vector<script_error> &errors,
  118. ast::variable_expression &expr) {
  119. ctx.push_back(ByteCodeInterpreter::operand{
  120. ByteCodeInterpreter::variable_tag{.name = expr.name.value, .location = expr.location}});
  121. }
  122. template<>
  123. void handle<ast::literal_int_expression>(std::vector<ByteCodeInterpreter::operand> &ctx,
  124. std::vector<script_error> &errors, ast::literal_int_expression &expr) {
  125. ctx.push_back(ByteCodeInterpreter::operand{script_value{expr.value}});
  126. }
  127. template<>
  128. void handle<ast::literal_string_expression>(std::vector<ByteCodeInterpreter::operand> &ctx,
  129. std::vector<script_error> &errors,
  130. ast::literal_string_expression &expr) {
  131. ctx.push_back(ByteCodeInterpreter::operand{script_value{expr.value}});
  132. }
  133. template<>
  134. void handle<ast::conditional>(std::vector<ByteCodeInterpreter::operand> &ctx, std::vector<script_error> &errors,
  135. ast::conditional &cond) {
  136. /// some basic documentation (from before the reference stability bug but things are the same):
  137. /// https://app.excalidraw.com/s/hxPegpAmTX/2c8KKzinqeg
  138. std::visit([&](auto &v) { handle(ctx, errors, *v); }, cond.condition->contents);
  139. ctx.push_back(ByteCodeInterpreter::operand{.element = script_value{}, .location = cond.location});
  140. /// 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
  141. /// More seriously, WTF (?) we do this because we used to have a bug with unreliable references to these locations, which makes sense since we
  142. /// don't have reference stability
  143. auto else_side_idx = ctx.size() - 1;
  144. ctx.push_back(
  145. ByteCodeInterpreter::operand{.element = ByteCodeInterpreter::operator_t::INTERNAL_jump_if, .location = cond.location});
  146. handle(ctx, errors, *cond.on_condition);
  147. if (cond.otherwise) {
  148. ctx.push_back(ByteCodeInterpreter::operand{.element = script_value{}, .location = cond.location});
  149. auto end_side_idx = ctx.size() - 1;
  150. ctx.push_back(
  151. ByteCodeInterpreter::operand{.element = ByteCodeInterpreter::operator_t::INTERNAL_jump, .location = cond.location});
  152. ctx[else_side_idx].element = static_cast<int32_t>(ctx.size()) - 1;
  153. ctx[else_side_idx].location = cond.location;
  154. handle(ctx, errors, *cond.otherwise);
  155. ctx[end_side_idx].element = static_cast<int32_t>(ctx.size()) - 1;
  156. ctx[end_side_idx].location = cond.location;
  157. } else {
  158. ctx[else_side_idx].element = static_cast<int32_t>(ctx.size()) - 1;
  159. ctx[else_side_idx].location = cond.location;
  160. }
  161. }
  162. template<>
  163. void handle<ast::while_loop>(std::vector<ByteCodeInterpreter::operand> &ctx, std::vector<script_error> &errors,
  164. ast::while_loop &cond) {
  165. auto beforewhile_side_idx = static_cast<int32_t>(ctx.size()) - 1;
  166. std::visit([&](auto &v) { handle(ctx, errors, *v); }, cond.condition->contents);
  167. ctx.push_back(ByteCodeInterpreter::operand{.element = script_value{}, .location = cond.location});
  168. auto endwhile_side_idx = ctx.size() - 1;
  169. ctx.push_back(
  170. ByteCodeInterpreter::operand{.element = ByteCodeInterpreter::operator_t::INTERNAL_jump_if, .location = cond.location});
  171. handle(ctx, errors, *cond.on_condition);
  172. ctx.push_back(
  173. ByteCodeInterpreter::operand{.element = script_value{beforewhile_side_idx}, .location = cond.location});
  174. ctx.push_back(
  175. ByteCodeInterpreter::operand{.element = ByteCodeInterpreter::operator_t::INTERNAL_jump, .location = cond.location});
  176. ctx[endwhile_side_idx].element = static_cast<int32_t>(ctx.size()) - 1;
  177. ctx[endwhile_side_idx].location = cond.location;
  178. }
  179. std::vector<ByteCodeInterpreter::operand>
  180. ByteCodeInterpreter::generate(std::vector<script_error> &errors, ast::block &tree, bool loop) {
  181. std::vector<operand> code;
  182. handle(code, errors, tree);
  183. if (loop) {
  184. // Here we have to deal with the quirks of jumping before the increments happens again
  185. code.push_back(ByteCodeInterpreter::operand{.element = script_value{-1}, .location = tree.location});
  186. code.push_back(
  187. ByteCodeInterpreter::operand{.element = ByteCodeInterpreter::operator_t::INTERNAL_jump, .location = tree.location});
  188. }
  189. return code;
  190. }
  191. }