You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

190 lines
4.6 KiB

  1. #pragma once
  2. #include <stack>
  3. #include <map>
  4. #include "UserScript.h"
  5. #include "UserScript/parser.h"
  6. namespace scripting {
  7. class ByteCodeInterpreter final : public UserScript {
  8. std::map<std::string, script_value> variables;
  9. std::map<std::string, function> functions;
  10. std::vector<argument> execution_stack;
  11. public:
  12. struct function_tag {
  13. std::string name;
  14. size_t arity;
  15. std::shared_ptr<const code_location> location;
  16. };
  17. struct variable_tag {
  18. std::string name;
  19. std::shared_ptr<const code_location> location;
  20. };
  21. enum class operator_t : uint8_t {
  22. logical_not,
  23. binary_not,
  24. unary_plus,
  25. unary_minus,
  26. divide,
  27. modulo,
  28. multiply,
  29. subtract,
  30. add,
  31. bitshift_left,
  32. bitshift_right,
  33. rotate_left,
  34. rotate_right,
  35. less_than,
  36. greater_than,
  37. less_or_equal_than,
  38. greater_or_equal_than,
  39. equals,
  40. different,
  41. binary_and,
  42. binary_or,
  43. binary_xor,
  44. logical_and,
  45. logical_or,
  46. INTERNAL_jump,
  47. INTERNAL_jump_if,
  48. INTERNAL_stack_cls,
  49. };
  50. struct operand {
  51. std::variant<script_value, function_tag, variable_tag, operator_t> element;
  52. std::shared_ptr<const code_location> location;
  53. };
  54. std::optional<std::reference_wrapper<script_value>> getValue(const std::string &name) {
  55. if (auto var = variables.find(name); var != variables.end()) {
  56. return var->second;
  57. } else {
  58. return std::nullopt;
  59. }
  60. }
  61. bool setValue(const std::string &name, script_value value) {
  62. if (auto var = variables.find(name); var != variables.end()) {
  63. var->second = value;
  64. return true;
  65. } else {
  66. variables.emplace(std::make_pair(name, value));
  67. return false;
  68. }
  69. }
  70. std::vector<operand> bytecode;
  71. size_t instruction_ptr;
  72. script_value resolve(const std::string &name) final {
  73. auto it = variables.find(name);
  74. if (it == variables.end()) {
  75. return script_value{};
  76. }
  77. return (*it).second;
  78. }
  79. script_value resolve_and_pop() {
  80. if (execution_stack.empty()) return script_value{};
  81. auto value = std::move(execution_stack.back());
  82. auto resolved = std::visit([&](auto v) -> script_value {
  83. if constexpr (std::is_same_v<script_variable, decltype(v)>) {
  84. auto it = variables.find(v.name);
  85. if (it == variables.end()) {
  86. return script_value{};
  87. }
  88. return (*it).second;
  89. } else {
  90. return v;
  91. }
  92. }, value);
  93. execution_stack.pop_back();
  94. return resolved;
  95. }
  96. void big_f_ing_switch(operand &op, std::optional<script_error> &error);
  97. std::vector<ByteCodeInterpreter::operand>
  98. generate(std::vector<script_error> &errors, ast::block &tree, bool loop = true);
  99. void registerFunction(std::string name, function fn) final {
  100. functions.insert_or_assign(name, std::move(fn));
  101. }
  102. void clear_variables() final {
  103. variables.clear();
  104. }
  105. int32_t op_count() final {
  106. return bytecode.size();
  107. }
  108. int32_t var_count() final {
  109. return variables.size();
  110. }
  111. void var_clear() final {
  112. variables.clear();
  113. }
  114. std::optional<script_value> var_by_idx(int32_t idx) final {
  115. if(idx >= var_count() || idx < 0) return std::nullopt;
  116. for(auto& val : variables) {
  117. if(not idx--) {
  118. return val.second;
  119. }
  120. }
  121. return std::nullopt;
  122. }
  123. std::optional<script_value> varname_by_idx(int32_t idx) final {
  124. if(idx >= var_count() || idx < 0) return std::nullopt;
  125. for(auto& val : variables) {
  126. if(not idx--) {
  127. return val.first;
  128. }
  129. }
  130. return std::nullopt;
  131. }
  132. std::variant<script_value, std::vector<script_error>> executeAtOnce(std::string code) final {
  133. std::vector<script_error> errors;
  134. auto lexed = ast::lex(code, errors);
  135. auto parsed = ast::parse(lexed, errors);
  136. if (not errors.empty()) return errors;
  137. bytecode = generate(errors, parsed, false);
  138. if (not errors.empty()) return errors;
  139. std::optional<script_error> maybe_error;
  140. instruction_ptr = 0;
  141. while (instruction_ptr < bytecode.size()) {
  142. step(maybe_error);
  143. if (maybe_error) return std::vector<script_error>({maybe_error.value()});
  144. }
  145. auto v = resolve_and_pop();
  146. execution_stack.clear();
  147. return v;
  148. }
  149. std::vector<script_error> prepare(std::string code, bool repeating) final {
  150. std::vector<script_error> errors;
  151. auto lexed = ast::lex(code, errors);
  152. auto parsed = ast::parse(lexed, errors);
  153. if (errors.empty()) {
  154. bytecode = generate(errors, parsed, repeating);
  155. }
  156. return errors;
  157. }
  158. std::optional<script_error> stepOnce() final {
  159. std::optional<script_error> error;
  160. while (not step(error));
  161. return error;
  162. }
  163. bool step(std::optional<script_error> &error);
  164. ~ByteCodeInterpreter() final {}
  165. };
  166. }