math_ast.h
| Line | Branch | Exec | Source |
|---|---|---|---|
| 1 | #include <memory> | ||
| 2 | #include <variant> | ||
| 3 | #include <vector> | ||
| 4 | #include <unordered_map> | ||
| 5 | #include "libstr.h" | ||
| 6 | #include "asar_math.h" | ||
| 7 | #include "assembleblock.h" | ||
| 8 | |||
| 9 | using owned_node = std::unique_ptr<math_ast_node>; | ||
| 10 | |||
| 11 | enum class math_binop_type { | ||
| 12 | pow, // ** | ||
| 13 | mul, // * | ||
| 14 | div, // / | ||
| 15 | mod, // % | ||
| 16 | add, // + | ||
| 17 | sub, // - | ||
| 18 | shift_left, // << | ||
| 19 | shift_right, // >> | ||
| 20 | bit_and, // & | ||
| 21 | bit_or, // | | ||
| 22 | bit_xor, // ^ | ||
| 23 | logical_and, // && | ||
| 24 | logical_or, // || | ||
| 25 | comp_ge, // >= | ||
| 26 | comp_le, // <= | ||
| 27 | comp_gt, // > | ||
| 28 | comp_lt, // < | ||
| 29 | comp_eq, // == | ||
| 30 | comp_ne, // != | ||
| 31 | }; | ||
| 32 | |||
| 33 | math_val evaluate_binop(math_val lhs, math_val rhs, math_binop_type type); | ||
| 34 | |||
| 35 | class math_ast_binop : public math_ast_node { | ||
| 36 | public: | ||
| 37 | owned_node m_left, m_right; | ||
| 38 | math_binop_type m_type; | ||
| 39 | 5097 | math_ast_binop(owned_node left_in, owned_node right_in, math_binop_type type_in) | |
| 40 | 5097 | : m_left(std::move(left_in)), m_right(std::move(right_in)), m_type(type_in) {} | |
| 41 | |||
| 42 | math_val evaluate(const eval_context &ctx) const; | ||
| 43 | int has_label() const; | ||
| 44 | int get_len(bool could_be_bank_ex) const; | ||
| 45 | }; | ||
| 46 | |||
| 47 | enum class math_unop_type { | ||
| 48 | neg, | ||
| 49 | bit_not, | ||
| 50 | bank_extract, | ||
| 51 | }; | ||
| 52 | |||
| 53 | class math_ast_unop : public math_ast_node { | ||
| 54 | public: | ||
| 55 | owned_node m_arg; | ||
| 56 | math_unop_type m_type; | ||
| 57 | 66 | math_ast_unop(owned_node arg_in, math_unop_type type_in) | |
| 58 | 66 | : m_arg(std::move(arg_in)), m_type(type_in) {} | |
| 59 | math_val evaluate(const eval_context &ctx) const; | ||
| 60 | int has_label() const; | ||
| 61 | int get_len(bool could_be_bank_ex) const; | ||
| 62 | }; | ||
| 63 | |||
| 64 | class math_ast_ternary_cond : public math_ast_node { | ||
| 65 | owned_node m_cond, m_true, m_false; | ||
| 66 | public: | ||
| 67 | 8 | math_ast_ternary_cond(owned_node cond_in, owned_node true_in, owned_node false_in) | |
| 68 | 8 | : m_cond(std::move(cond_in)), m_true(std::move(true_in)), m_false(std::move(false_in)) {} | |
| 69 | |||
| 70 | math_val evaluate(const eval_context& ctx) const; | ||
| 71 | int has_label() const; | ||
| 72 | int get_len(bool could_be_bank_ex) const; | ||
| 73 | }; | ||
| 74 | |||
| 75 | class math_ast_literal : public math_ast_node { | ||
| 76 | math_val m_value; | ||
| 77 | int m_len; | ||
| 78 | public: | ||
| 79 | 18342 | math_ast_literal(math_val value, int len=0) : m_value(value), m_len(len) {} | |
| 80 | 16468 | math_val evaluate(const eval_context& ctx) const { return m_value; } | |
| 81 | 13449 | int has_label() const { return 0; } | |
| 82 | 2472 | int get_len(bool could_be_bank_ex) const { return m_len; } | |
| 83 | friend int math_ast_binop::get_len(bool) const; | ||
| 84 | }; | ||
| 85 | |||
| 86 | class math_ast_label : public math_ast_node { | ||
| 87 | string m_labelname; | ||
| 88 | // current namespace when this label was referenced | ||
| 89 | string m_cur_ns; | ||
| 90 | public: | ||
| 91 | // this should be the output of labelname() already | ||
| 92 | 1254 | math_ast_label(string labelname) | |
| 93 | 2508 | : m_labelname(labelname) | |
| 94 | // this is initialized with the global ns | ||
| 95 | 1885 | , m_cur_ns(ns) {} | |
| 96 | math_val evaluate(const eval_context &ctx) const; | ||
| 97 | int has_label() const; | ||
| 98 | int get_len(bool could_be_bank_ex) const; | ||
| 99 | }; | ||
| 100 | |||
| 101 | |||
| 102 | class math_builtin_function { | ||
| 103 | using call_t = math_val(*)(const std::vector<math_val>& args); | ||
| 104 | using haslabel_t = int(*)(); | ||
| 105 | using getlen_t = int(*)(const std::vector<owned_node>& args, bool could_be_bank_ex); | ||
| 106 | 462 | static int default_has_label() { | |
| 107 | 462 | return 0; | |
| 108 | } | ||
| 109 | 66 | static int default_get_len(const std::vector<owned_node>& args, bool could_be_bank_ex) { | |
| 110 | 66 | int res = 0; | |
| 111 | 132 | for(auto& v : args) { | |
| 112 | 66 | res = std::max(res, v->get_len(false)); | |
| 113 | } | ||
| 114 | 66 | return res; | |
| 115 | } | ||
| 116 | call_t m_call; | ||
| 117 | haslabel_t m_haslabel; | ||
| 118 | getlen_t m_getlen; | ||
| 119 | public: | ||
| 120 | 414 | math_builtin_function(call_t c, haslabel_t l = default_has_label, getlen_t gl = default_get_len) | |
| 121 | 414 | : m_call(c), m_haslabel(l), m_getlen(gl) {} | |
| 122 | 6 | math_builtin_function(call_t c, getlen_t gl) | |
| 123 | 6 | : m_call(c), m_haslabel(default_has_label), m_getlen(gl) {} | |
| 124 | 887 | math_val call(const std::vector<math_val>& args) const { | |
| 125 | 887 | return m_call(args); | |
| 126 | } | ||
| 127 | 486 | int has_label() const { | |
| 128 | 486 | return m_haslabel(); | |
| 129 | } | ||
| 130 | 90 | int get_len(const std::vector<owned_node>& args, bool could_be_bank_ex) const { | |
| 131 | 90 | return m_getlen(args, could_be_bank_ex); | |
| 132 | } | ||
| 133 | }; | ||
| 134 | |||
| 135 | class math_user_function { | ||
| 136 | size_t m_arg_count; | ||
| 137 | owned_node m_func_body; | ||
| 138 | public: | ||
| 139 | 48 | math_user_function(owned_node body, size_t arg_count) | |
| 140 | 48 | : m_arg_count(arg_count), m_func_body(std::move(body)) {} | |
| 141 | math_val call(const std::vector<math_val> &args) const; | ||
| 142 | int has_label() const; | ||
| 143 | int get_len(const std::vector<owned_node> &args, bool could_be_bank_ex) const; | ||
| 144 | }; | ||
| 145 | |||
| 146 | class math_function_ref { | ||
| 147 | public: | ||
| 148 | std::variant<const math_builtin_function*, const math_user_function*> inner; | ||
| 149 | 967 | math_function_ref(const math_builtin_function& fn) : inner(&fn) {} | |
| 150 | 30 | math_function_ref(const math_user_function& fn) : inner(&fn) {} | |
| 151 | 913 | math_val call(const std::vector<math_val>& args) const { | |
| 152 | 2266 | return std::visit([&](auto& i) { return i->call(args); }, inner); | |
| 153 | } | ||
| 154 | 486 | int has_label() const { | |
| 155 | 972 | return std::visit([&](auto& i) { return i->has_label(); }, inner); | |
| 156 | } | ||
| 157 | 96 | int get_len(const std::vector<owned_node>& args, bool could_be_bank_ex) const { | |
| 158 | 192 | return std::visit([&](auto& i) { return i->get_len(args, could_be_bank_ex); }, inner); | |
| 159 | } | ||
| 160 | }; | ||
| 161 | |||
| 162 | extern std::unordered_map<string, math_user_function> user_functions; | ||
| 163 | extern const std::unordered_map<string, math_builtin_function> builtin_functions; | ||
| 164 | |||
| 165 | class math_ast_function_call : public math_ast_node { | ||
| 166 | std::vector<owned_node> m_arguments; | ||
| 167 | math_function_ref m_func; | ||
| 168 | static math_function_ref lookup_fname(string const &function_name); | ||
| 169 | |||
| 170 | public: | ||
| 171 | 997 | math_ast_function_call(std::vector<owned_node> args, string function_name) | |
| 172 | 1498 | : m_arguments(std::move(args)) | |
| 173 | 1994 | , m_func(lookup_fname(function_name)) {} | |
| 174 | math_val evaluate(const eval_context &ctx) const; | ||
| 175 | int has_label() const; | ||
| 176 | int get_len(bool could_be_bank_ex) const; | ||
| 177 | }; | ||
| 178 | |||
| 179 | // only for use inside user function definitions | ||
| 180 | class math_ast_function_argument : public math_ast_node { | ||
| 181 | size_t m_arg_idx; | ||
| 182 | public: | ||
| 183 | 54 | math_ast_function_argument(size_t arg_idx) : m_arg_idx(arg_idx) {} | |
| 184 | |||
| 185 | 34 | math_val evaluate(const eval_context& ctx) const { | |
| 186 | 34 | return ctx.userfunc_params[m_arg_idx]; | |
| 187 | } | ||
| 188 | |||
| 189 | // if a function is called with a label as an argument, that gets checked by | ||
| 190 | // the function call node, not here | ||
| 191 | ✗ | int has_label() const { return 0; } | |
| 192 | // i don't think these should ever have their len gotten? | ||
| 193 | ✗ | int get_len(bool could_be_bank_ex) const { return 0; } | |
| 194 | }; | ||
| 195 |