asar coverage - build #324


src/asar/
File: src/asar/math_parse.cpp
Date: 2025-11-02 06:43:51
Lines:
215/228
94.3%
Functions:
10/10
100.0%
Branches:
537/830
64.7%

Line Branch Exec Source
1 #include "asar.h"
2 #include "assembleblock.h"
3 #include "asar_math.h"
4 #include "table.h"
5 #include "unicode.h"
6 #include <cmath>
7
8 #include "math_ast.h"
9
10
11 bool foundlabel;
12 // WARNING: this flag is only correctly set in pass 0, as forward labels are
13 // always non-static but we don't know when we hit forward-labels past pass 0
14 bool foundlabel_static;
15 // only set in pass 0
16 bool forwardlabel;
17
18
19 std::unordered_map<string, math_user_function> user_functions;
20
21 // we don't need this struct to be exported
22 namespace {
23 // data necessary for parsing an expression, which might be an user function declaration
24 struct parse_context {
25 const char*& str;
26 // this map is empty unless declaring a function,
27 // in which case it maps argument name to argument index
28 const std::unordered_map<string, size_t> function_arg_names;
29 // these are methods to allow easier access to `str`
30 owned_node parse_atom();
31 owned_node parse_unops();
32 owned_node parse_binops(int depth = 0);
33 owned_node parse();
34 };
35 }
36
37
38 static const long hextable[] = {
39 -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
40 -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
41 -1,-1, 0,1,2,3,4,5,6,7,8,9,-1,-1,-1,-1,-1,-1,-1,10,11,12,13,14,15,-1,
42 -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
43 -1,-1,10,11,12,13,14,15,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
44 -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
45 -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
46 -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
47 -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
48 -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
49 -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1
50 };
51
52 // "atom" = literal, parenthesized expression, or label reference
53 20685 owned_node parse_context::parse_atom() {
54
4/4
✓ Branch 0 taken 3197 times.
✓ Branch 1 taken 7075 times.
✓ Branch 2 taken 3284 times.
✓ Branch 3 taken 7129 times.
20685 if(*str == '$') {
55
2/8
✗ Branch 0 not taken.
✓ Branch 1 taken 3197 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 3284 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
6481 if (!is_xdigit(*++str)) throw_err_block(2, err_invalid_hex_value);
56 6481 const char* start = str;
57 6481 int64_t ret = 0; // todo error on overflow?
58
4/4
✓ Branch 0 taken 10397 times.
✓ Branch 1 taken 3197 times.
✓ Branch 2 taken 10733 times.
✓ Branch 3 taken 3284 times.
27611 while (hextable[0 + *str] >= 0) {
59
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 10733 times.
21130 ret = (ret << 4) | hextable[0 + *str++];
60 }
61 6481 int len = str - start;
62 6481 int len_bytes = (len+1)/2;
63
2/3
✓ Branch 0 taken 3197 times.
✓ Branch 1 taken 3284 times.
✗ Branch 2 not taken.
6481 return std::make_unique<math_ast_literal>(ret, len_bytes);
64 }
65
14/14
✓ Branch 0 taken 6003 times.
✓ Branch 1 taken 1072 times.
✓ Branch 2 taken 5820 times.
✓ Branch 3 taken 6233 times.
✓ Branch 4 taken 1086 times.
✓ Branch 5 taken 5813 times.
✓ Branch 6 taken 1262 times.
✓ Branch 7 taken 5813 times.
✓ Branch 8 taken 5867 times.
✓ Branch 9 taken 183 times.
✓ Branch 10 taken 7 times.
✓ Branch 11 taken 5860 times.
✓ Branch 12 taken 1269 times.
✓ Branch 13 taken 5860 times.
14204 if (is_ualpha(*str) || *str=='.' || *str=='?') {
66 2531 const char * start=str;
67
15/15
✓ Branch 0 taken 1901 times.
✓ Branch 1 taken 8024 times.
✓ Branch 2 taken 1269 times.
✓ Branch 3 taken 632 times.
✓ Branch 4 taken 7 times.
✓ Branch 5 taken 1262 times.
✓ Branch 6 taken 8663 times.
✓ Branch 7 taken 3170 times.
✓ Branch 8 taken 8055 times.
✓ Branch 9 taken 1276 times.
✓ Branch 10 taken 632 times.
✓ Branch 11 taken 7 times.
✓ Branch 12 taken 1269 times.
✓ Branch 13 taken 8694 times.
✓ Branch 14 taken 1269 times.
19888 while (is_ualnum(*str) || *str == '.' || *str == '?') str++;
68 2531 int len=(int)(str-start);
69
4/4
✓ Branch 0 taken 40 times.
✓ Branch 1 taken 1262 times.
✓ Branch 2 taken 40 times.
✓ Branch 3 taken 1269 times.
2611 while (*str==' ') str++;
70
4/4
✓ Branch 0 taken 475 times.
✓ Branch 1 taken 787 times.
✓ Branch 2 taken 480 times.
✓ Branch 3 taken 789 times.
2531 if (*str=='(') {
71 955 str++;
72 955 string func_name;
73
1/2
✓ Branch 0 taken 955 times.
✗ Branch 1 not taken.
955 func_name.assign(start, len);
74 955 std::vector<owned_node> arguments;
75
4/4
✓ Branch 0 taken 597 times.
✓ Branch 1 taken 475 times.
✓ Branch 2 taken 602 times.
✓ Branch 3 taken 480 times.
3109 while(*str != ')') {
76
4/4
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 597 times.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 602 times.
1201 while (*str==' ') str++;
77
4/7
✓ Branch 0 taken 597 times.
✓ Branch 1 taken 602 times.
✓ Branch 2 taken 597 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 602 times.
✗ Branch 6 not taken.
1199 arguments.emplace_back(parse_binops());
78 // is "invalid number" good here?
79
5/11
✓ Branch 0 taken 455 times.
✓ Branch 1 taken 142 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 915 times.
✓ Branch 4 taken 142 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✓ Branch 8 taken 460 times.
✗ Branch 9 not taken.
✗ Branch 10 not taken.
1199 if(*str != ',' && *str != ')') throw_err_block(2, err_invalid_number);
80
4/4
✓ Branch 0 taken 142 times.
✓ Branch 1 taken 455 times.
✓ Branch 2 taken 142 times.
✓ Branch 3 taken 460 times.
1199 if(*str == ',') str++;
81 }
82 955 str++;
83 // ternary is basically just a function called "?"
84
2/2
✓ Branch 0 taken 8 times.
✓ Branch 1 taken 947 times.
955 if(func_name == "?") {
85
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 8 times.
8 if(arguments.size() != 3) {
86 throw_err_block(2, err_argument_count, 3, (int)arguments.size());
87 }
88
2/4
✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 4 times.
✗ Branch 3 not taken.
28 return std::make_unique<math_ast_ternary_cond>(
89 8 std::move(arguments[0]),
90 8 std::move(arguments[1]),
91 16 std::move(arguments[2]));
92 }
93
2/4
✓ Branch 0 taken 471 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 476 times.
✗ Branch 3 not taken.
947 return std::make_unique<math_ast_function_call>(std::move(arguments), std::move(func_name));
94 955 } else {
95
2/3
✓ Branch 0 taken 787 times.
✓ Branch 1 taken 789 times.
✗ Branch 2 not taken.
1576 string name_part(start, len);
96
2/2
✓ Branch 0 taken 352 times.
✓ Branch 1 taken 1224 times.
1576 if(name_part == "...") {
97 // a tiny bit ugly, but whatever
98
4/8
✓ Branch 0 taken 176 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 352 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 352 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 176 times.
✗ Branch 7 not taken.
352 return std::make_unique<math_ast_literal>(math_val::make_identifier(name_part));
99 }
100
4/4
✓ Branch 0 taken 27 times.
✓ Branch 1 taken 584 times.
✓ Branch 2 taken 27 times.
✓ Branch 3 taken 586 times.
1224 if(!function_arg_names.empty()) {
101
2/4
✓ Branch 0 taken 27 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 27 times.
✗ Branch 3 not taken.
54 auto it = function_arg_names.find(name_part);
102
2/4
✓ Branch 0 taken 27 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 27 times.
✗ Branch 3 not taken.
54 if(it != function_arg_names.end()) {
103
2/4
✓ Branch 0 taken 27 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 27 times.
✗ Branch 3 not taken.
54 return std::make_unique<math_ast_function_argument>(it->second);
104 }
105 }
106
2/3
✓ Branch 0 taken 584 times.
✓ Branch 1 taken 586 times.
✗ Branch 2 not taken.
1170 string name = labelname(&start);
107 1170 str = start;
108
4/4
✓ Branch 0 taken 25 times.
✓ Branch 1 taken 559 times.
✓ Branch 2 taken 25 times.
✓ Branch 3 taken 561 times.
1170 if(*str == '[') {
109 // struct array indexing
110 50 str++;
111
2/3
✓ Branch 0 taken 25 times.
✓ Branch 1 taken 25 times.
✗ Branch 2 not taken.
50 auto index = parse_binops();
112
2/6
✗ Branch 0 not taken.
✓ Branch 1 taken 25 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 25 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
50 if(*str != ']') throw_err_block(2, err_invalid_label_missing_closer);
113 50 str++;
114
2/3
✓ Branch 0 taken 25 times.
✓ Branch 1 taken 25 times.
✗ Branch 2 not taken.
50 string subname = name;
115
4/4
✓ Branch 0 taken 24 times.
✓ Branch 1 taken 1 times.
✓ Branch 2 taken 24 times.
✓ Branch 3 taken 1 times.
50 if(*str == '.') {
116 // this part used to be in labelname... not sure where it really belongs....
117
10/10
✓ Branch 0 taken 48 times.
✓ Branch 1 taken 96 times.
✓ Branch 2 taken 24 times.
✓ Branch 3 taken 72 times.
✓ Branch 4 taken 216 times.
✓ Branch 5 taken 24 times.
✓ Branch 6 taken 24 times.
✓ Branch 7 taken 24 times.
✓ Branch 8 taken 120 times.
✓ Branch 9 taken 24 times.
288 while (is_ualnum(*str) || *str == '.') {
118
2/4
✓ Branch 0 taken 120 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 120 times.
✗ Branch 3 not taken.
240 subname += *(str++);
119 }
120 }
121 // when doing base[index].sub:
122 // result = (base_addr + index*object_size(base)) + sub_offset
123 // = sub_addr + index*object_size(base)
124 // so we build a math node that represents this calculation
125
2/3
✓ Branch 0 taken 25 times.
✓ Branch 1 taken 25 times.
✗ Branch 2 not taken.
50 auto node_sub = std::make_unique<math_ast_label>(subname);
126
2/3
✓ Branch 0 taken 25 times.
✓ Branch 1 taken 25 times.
✗ Branch 2 not taken.
50 auto node_base = std::make_unique<math_ast_label>(name);
127 50 std::vector<owned_node> arg_list;
128
2/3
✓ Branch 0 taken 25 times.
✓ Branch 1 taken 25 times.
✗ Branch 2 not taken.
50 arg_list.emplace_back(std::move(node_base));
129
2/4
✓ Branch 0 taken 25 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 25 times.
✗ Branch 3 not taken.
50 auto node_objsize = std::make_unique<math_ast_function_call>(std::move(arg_list), "objectsize");
130
2/4
✓ Branch 0 taken 25 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 25 times.
✗ Branch 3 not taken.
50 auto node_mul = std::make_unique<math_ast_binop>(std::move(node_objsize), std::move(index), math_binop_type::mul);
131
2/4
✓ Branch 0 taken 25 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 25 times.
✗ Branch 3 not taken.
50 auto node_add = std::make_unique<math_ast_binop>(std::move(node_mul), std::move(node_sub), math_binop_type::add);
132 50 return node_add;
133 50 } else {
134
2/4
✓ Branch 0 taken 559 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 561 times.
✗ Branch 3 not taken.
1120 return std::make_unique<math_ast_label>(std::move(name));
135 }
136 1576 }
137 }
138
4/4
✓ Branch 0 taken 76 times.
✓ Branch 1 taken 5737 times.
✓ Branch 2 taken 76 times.
✓ Branch 3 taken 5784 times.
11673 if(*str == '(') {
139 152 str++;
140
2/3
✓ Branch 0 taken 76 times.
✓ Branch 1 taken 76 times.
✗ Branch 2 not taken.
152 auto res = parse_binops();
141
2/6
✗ Branch 0 not taken.
✓ Branch 1 taken 76 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 76 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
152 if(*str != ')') throw_err_block(2, err_mismatched_parentheses);
142 152 str++;
143 152 return res;
144 152 }
145
4/4
✓ Branch 0 taken 10 times.
✓ Branch 1 taken 5727 times.
✓ Branch 2 taken 10 times.
✓ Branch 3 taken 5774 times.
11521 if(*str == '%') {
146
2/8
✗ Branch 0 not taken.
✓ Branch 1 taken 10 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 10 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
20 if (str[1] != '0' && str[1] != '1') throw_err_block(2, err_invalid_binary_value);
147 20 const char* start = str+1;
148
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 10 times.
20 uint64_t res = strtoull(str+1, const_cast<char**>(&str), 2);
149 20 int len = str - start;
150
2/4
✓ Branch 0 taken 10 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 10 times.
✗ Branch 3 not taken.
20 return std::make_unique<math_ast_literal>((int64_t)res, (len+7)/8);
151 }
152
4/4
✓ Branch 0 taken 112 times.
✓ Branch 1 taken 5615 times.
✓ Branch 2 taken 112 times.
✓ Branch 3 taken 5662 times.
11501 if (*str=='\'') {
153
2/7
✗ Branch 0 not taken.
✓ Branch 1 taken 112 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 112 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
224 if (!str[1]) throw_err_block(2, err_invalid_character);
154 112 int orig_val;
155 224 str++;
156
2/4
✓ Branch 0 taken 112 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 112 times.
✗ Branch 3 not taken.
224 str += utf8_val(&orig_val, str);
157
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 224 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
224 if (orig_val == -1) throw_err_block(0, err_invalid_utf8);
158
2/6
✗ Branch 0 not taken.
✓ Branch 1 taken 112 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 112 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
224 if (*str != '\'') throw_err_block(2, err_invalid_character);
159
2/4
✓ Branch 0 taken 112 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 112 times.
✗ Branch 3 not taken.
224 int64_t rval=thetable.get_val(orig_val);
160
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 224 times.
224 if (rval == -1)
161 {
162 // RPG Hacker: Should be fine to not check return value of codepoint_to_utf8() here, because
163 // our error cases above already made sure that orig_val contains valid data at this point.
164 string u8_str;
165 codepoint_to_utf8(&u8_str, orig_val);
166 throw_err_block(2, err_undefined_char, u8_str.data());
167 }
168 224 str++;
169
2/4
✓ Branch 0 taken 112 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 112 times.
✗ Branch 3 not taken.
224 return std::make_unique<math_ast_literal>(rval, 1);
170 }
171
4/4
✓ Branch 0 taken 5451 times.
✓ Branch 1 taken 164 times.
✓ Branch 2 taken 5492 times.
✓ Branch 3 taken 170 times.
11277 if (is_digit(*str)) {
172 10943 const char* end = str;
173 10943 bool is_float = false;
174
8/8
✓ Branch 0 taken 5491 times.
✓ Branch 1 taken 12584 times.
✓ Branch 2 taken 7155 times.
✓ Branch 3 taken 5451 times.
✓ Branch 4 taken 7132 times.
✓ Branch 5 taken 10943 times.
✓ Branch 6 taken 7155 times.
✓ Branch 7 taken 5492 times.
25190 while (is_digit(*end) || *end == '.') {
175
3/3
✓ Branch 0 taken 40 times.
✓ Branch 1 taken 7092 times.
✓ Branch 2 taken 7115 times.
14247 if(*end == '.') is_float = true;
176 14247 end++;
177 }
178 10943 string number;
179
2/4
✓ Branch 0 taken 5451 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 5492 times.
✗ Branch 3 not taken.
10943 number.assign(str, (int)(end - str));
180 10943 str = end;
181
2/2
✓ Branch 0 taken 80 times.
✓ Branch 1 taken 10863 times.
10943 if(is_float) {
182
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 40 times.
80 double res = std::atof(number);
183
2/3
✓ Branch 0 taken 40 times.
✓ Branch 1 taken 40 times.
✗ Branch 2 not taken.
80 return std::make_unique<math_ast_literal>(res);
184 } else {
185
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 5452 times.
10863 int64_t res = strtoll(number, nullptr, 10);
186
5/5
✓ Branch 0 taken 5405 times.
✓ Branch 1 taken 5452 times.
✓ Branch 2 taken 43 times.
✓ Branch 3 taken 5410 times.
✓ Branch 4 taken 5404 times.
10863 int len = (res >= 0x10000) ? 3 : (res >= 0x100) ? 2 : 1;
187
2/3
✓ Branch 0 taken 5411 times.
✓ Branch 1 taken 5452 times.
✗ Branch 2 not taken.
10863 return std::make_unique<math_ast_literal>(res, len);
188 }
189 10943 }
190
4/4
✓ Branch 0 taken 158 times.
✓ Branch 1 taken 6 times.
✓ Branch 2 taken 164 times.
✓ Branch 3 taken 6 times.
334 if(*str == '"') {
191 322 const char * strpos = str + 1;
192
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 164 times.
322 str = strchr(strpos, '"');
193
2/7
✗ Branch 0 not taken.
✓ Branch 1 taken 158 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 164 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
322 if(!str) throw_err_block(2, err_mismatched_quotes);
194
2/4
✓ Branch 0 taken 158 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 164 times.
✗ Branch 3 not taken.
322 string output(strpos, str - strpos);
195
5/6
✓ Branch 0 taken 162 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 172 times.
✓ Branch 3 taken 158 times.
✓ Branch 4 taken 4 times.
✓ Branch 5 taken 164 times.
330 while(str && str[1] == '"') {
196 // we hit an escaped quote
197
1/2
✓ Branch 0 taken 8 times.
✗ Branch 1 not taken.
8 output += '"';
198 8 strpos = str+2;
199
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
8 str = strchr(strpos, '"');
200
2/7
✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 4 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
8 if(!str) throw_err_block(2, err_mismatched_quotes);
201
2/4
✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 4 times.
✗ Branch 3 not taken.
8 output.append(strpos, 0, str - strpos);
202 }
203 322 str++;
204
4/4
✓ Branch 0 taken 12 times.
✓ Branch 1 taken 158 times.
✓ Branch 2 taken 12 times.
✓ Branch 3 taken 164 times.
346 while (*str==' ') str++; //eat space
205
2/4
✓ Branch 0 taken 158 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 164 times.
✗ Branch 3 not taken.
322 return std::make_unique<math_ast_literal>(std::move(output));
206 322 }
207 12 throw_err_block(2, err_invalid_number);
208 }
209
210 20751 owned_node parse_context::parse_unops() {
211
4/4
✓ Branch 0 taken 1259 times.
✓ Branch 1 taken 10305 times.
✓ Branch 2 taken 1259 times.
✓ Branch 3 taken 10446 times.
23269 while(*str == ' ') str++;
212 // optimize for the common case
213 // TODO how much of an optimization is this really?
214
4/4
✓ Branch 0 taken 3197 times.
✓ Branch 1 taken 7108 times.
✓ Branch 2 taken 3284 times.
✓ Branch 3 taken 7162 times.
20751 if(*str == '$') return parse_atom();
215
216
4/4
✓ Branch 0 taken 20 times.
✓ Branch 1 taken 7088 times.
✓ Branch 2 taken 20 times.
✓ Branch 3 taken 7142 times.
14270 if(*str == '-') {
217 40 str++;
218
4/7
✓ Branch 0 taken 20 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 20 times.
✓ Branch 3 taken 20 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 20 times.
✗ Branch 6 not taken.
40 return std::make_unique<math_ast_unop>(parse_unops(), math_unop_type::neg);
219
4/4
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 7084 times.
✓ Branch 2 taken 4 times.
✓ Branch 3 taken 7138 times.
14230 } else if(*str == '~') {
220 8 str++;
221
4/7
✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 4 times.
✓ Branch 3 taken 4 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 4 times.
✗ Branch 6 not taken.
8 return std::make_unique<math_ast_unop>(parse_unops(), math_unop_type::bit_not);
222
7/7
✓ Branch 0 taken 15 times.
✓ Branch 1 taken 7069 times.
✓ Branch 2 taken 9 times.
✓ Branch 3 taken 21 times.
✓ Branch 4 taken 7123 times.
✓ Branch 5 taken 9 times.
✓ Branch 6 taken 6 times.
14222 } else if(*str == '<' && str[1] == ':') {
223 18 str += 2;
224
4/7
✓ Branch 0 taken 9 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 9 times.
✓ Branch 3 taken 9 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 9 times.
✗ Branch 6 not taken.
18 return std::make_unique<math_ast_unop>(parse_unops(), math_unop_type::bank_extract);
225
2/4
✗ Branch 0 not taken.
✓ Branch 1 taken 7075 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 7129 times.
14204 } else if(*str == '+') {
226 str++;
227 return parse_unops();
228 }
229 14204 else return parse_atom();
230 }
231
232 20719 owned_node parse_context::parse_binops(int depth) {
233 20719 const char* posneglabel = str;
234
2/3
✓ Branch 0 taken 10286 times.
✓ Branch 1 taken 10433 times.
✗ Branch 2 not taken.
20719 string posnegname = posneglabelname(&posneglabel, false);
235
4/4
✓ Branch 0 taken 68 times.
✓ Branch 1 taken 20651 times.
✓ Branch 2 taken 34 times.
✓ Branch 3 taken 20685 times.
20787 if (posnegname.length() > 0 &&
236
5/6
✓ Branch 0 taken 17 times.
✓ Branch 1 taken 31 times.
✓ Branch 2 taken 20 times.
✓ Branch 3 taken 17 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 17 times.
68 (*posneglabel == '\0' || *posneglabel == ')')) {
237 34 str = posneglabel;
238
2/3
✓ Branch 0 taken 14 times.
✓ Branch 1 taken 20 times.
✗ Branch 2 not taken.
34 return std::make_unique<math_ast_label>(posnegname);
239 }
240
241
2/3
✓ Branch 0 taken 10272 times.
✓ Branch 1 taken 10413 times.
✗ Branch 2 not taken.
20685 recurseblock rec;
242
243
3/3
✓ Branch 0 taken 10266 times.
✓ Branch 1 taken 10413 times.
✓ Branch 2 taken 6 times.
20685 owned_node left = parse_unops();
244 20673 owned_node right;
245
4/4
✓ Branch 0 taken 1225 times.
✓ Branch 1 taken 10266 times.
✓ Branch 2 taken 1225 times.
✓ Branch 3 taken 10407 times.
23123 while(*str == ' ') str++;
246
14/14
✓ Branch 0 taken 3238 times.
✓ Branch 1 taken 9525 times.
✓ Branch 2 taken 2695 times.
✓ Branch 3 taken 3790 times.
✓ Branch 4 taken 12213 times.
✓ Branch 5 taken 142 times.
✓ Branch 6 taken 2528 times.
✓ Branch 7 taken 25 times.
✓ Branch 8 taken 2698 times.
✓ Branch 9 taken 549 times.
✓ Branch 10 taken 2556 times.
✓ Branch 11 taken 142 times.
✓ Branch 12 taken 2531 times.
✓ Branch 13 taken 25 times.
25670 while (*str && *str != ')' && *str != ','&& *str != ']') {
247
2/4
✗ Branch 0 not taken.
✓ Branch 1 taken 2528 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 2531 times.
5059 while(*str == ' ') str++;
248 // TODO can we make this macro a bit nicer???
249 #define oper(name, thisdepth, contents) \
250 if (!strncmp(str, name, strlen(name))) \
251 { \
252 if (depth<=thisdepth) \
253 { \
254 str += strlen(name); \
255 right = parse_binops(thisdepth+1); \
256 left = std::make_unique<math_ast_binop>(std::move(left), std::move(right), contents); \
257 continue; \
258 } \
259 else return left; \
260 }
261
9/14
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 2522 times.
✓ Branch 2 taken 6 times.
✓ Branch 3 taken 2531 times.
✓ Branch 4 taken 12 times.
✓ Branch 5 taken 2525 times.
✓ Branch 6 taken 12 times.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
✓ Branch 10 taken 6 times.
✗ Branch 11 not taken.
✓ Branch 12 taken 6 times.
✗ Branch 13 not taken.
5059 oper("**", 6, math_binop_type::pow);
262
9/13
✓ Branch 0 taken 18 times.
✓ Branch 1 taken 2504 times.
✓ Branch 2 taken 18 times.
✓ Branch 3 taken 18 times.
✓ Branch 4 taken 2525 times.
✓ Branch 5 taken 18 times.
✓ Branch 6 taken 18 times.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✓ Branch 9 taken 18 times.
✗ Branch 10 not taken.
✓ Branch 11 taken 18 times.
✗ Branch 12 not taken.
5047 oper("*", 5, math_binop_type::mul);
263
9/13
✓ Branch 0 taken 14 times.
✓ Branch 1 taken 2490 times.
✓ Branch 2 taken 14 times.
✓ Branch 3 taken 14 times.
✓ Branch 4 taken 2507 times.
✓ Branch 5 taken 14 times.
✓ Branch 6 taken 14 times.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✓ Branch 9 taken 14 times.
✗ Branch 10 not taken.
✓ Branch 11 taken 14 times.
✗ Branch 12 not taken.
5011 oper("/", 5, math_binop_type::div);
264
9/13
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 2489 times.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 1 times.
✓ Branch 4 taken 2493 times.
✓ Branch 5 taken 1 times.
✓ Branch 6 taken 1 times.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✓ Branch 9 taken 1 times.
✗ Branch 10 not taken.
✓ Branch 11 taken 1 times.
✗ Branch 12 not taken.
4983 oper("%", 5, math_binop_type::mod);
265
9/13
✓ Branch 0 taken 981 times.
✓ Branch 1 taken 1508 times.
✓ Branch 2 taken 971 times.
✓ Branch 3 taken 994 times.
✓ Branch 4 taken 2479 times.
✓ Branch 5 taken 974 times.
✓ Branch 6 taken 981 times.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✓ Branch 9 taken 974 times.
✗ Branch 10 not taken.
✓ Branch 11 taken 974 times.
✗ Branch 12 not taken.
4981 oper("+", 4, math_binop_type::add);
266
9/13
✓ Branch 0 taken 267 times.
✓ Branch 1 taken 1241 times.
✓ Branch 2 taken 267 times.
✓ Branch 3 taken 267 times.
✓ Branch 4 taken 1508 times.
✓ Branch 5 taken 267 times.
✓ Branch 6 taken 267 times.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✓ Branch 9 taken 267 times.
✗ Branch 10 not taken.
✓ Branch 11 taken 267 times.
✗ Branch 12 not taken.
3016 oper("-", 4, math_binop_type::sub);
267
9/14
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 1240 times.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 1241 times.
✓ Branch 4 taken 2 times.
✓ Branch 5 taken 1240 times.
✓ Branch 6 taken 2 times.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
✓ Branch 10 taken 1 times.
✗ Branch 11 not taken.
✓ Branch 12 taken 1 times.
✗ Branch 13 not taken.
2482 oper("<<", 3, math_binop_type::shift_left);
268
9/14
✓ Branch 0 taken 10 times.
✓ Branch 1 taken 1230 times.
✓ Branch 2 taken 10 times.
✓ Branch 3 taken 1240 times.
✓ Branch 4 taken 20 times.
✓ Branch 5 taken 1230 times.
✓ Branch 6 taken 20 times.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
✓ Branch 10 taken 10 times.
✗ Branch 11 not taken.
✓ Branch 12 taken 10 times.
✗ Branch 13 not taken.
2480 oper(">>", 3, math_binop_type::shift_right);
269
270 //these two needed checked early to avoid bitwise from eating a operator
271
10/14
✓ Branch 0 taken 13 times.
✓ Branch 1 taken 1217 times.
✓ Branch 2 taken 7 times.
✓ Branch 3 taken 1236 times.
✓ Branch 4 taken 20 times.
✓ Branch 5 taken 1217 times.
✓ Branch 6 taken 14 times.
✓ Branch 7 taken 6 times.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
✓ Branch 10 taken 7 times.
✗ Branch 11 not taken.
✓ Branch 12 taken 7 times.
✗ Branch 13 not taken.
2460 oper("&&", 0, math_binop_type::logical_and);
272
10/14
✓ Branch 0 taken 7 times.
✓ Branch 1 taken 1210 times.
✓ Branch 2 taken 4 times.
✓ Branch 3 taken 1220 times.
✓ Branch 4 taken 11 times.
✓ Branch 5 taken 1210 times.
✓ Branch 6 taken 8 times.
✓ Branch 7 taken 3 times.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
✓ Branch 10 taken 4 times.
✗ Branch 11 not taken.
✓ Branch 12 taken 4 times.
✗ Branch 13 not taken.
2434 oper("||", 0, math_binop_type::logical_or);
273
2/13
✗ Branch 0 not taken.
✓ Branch 1 taken 1210 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 1210 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
✗ Branch 10 not taken.
✗ Branch 11 not taken.
✗ Branch 12 not taken.
2420 oper("&", 2, math_binop_type::bit_and);
274
9/13
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 1207 times.
✓ Branch 2 taken 3 times.
✓ Branch 3 taken 3 times.
✓ Branch 4 taken 1210 times.
✓ Branch 5 taken 3 times.
✓ Branch 6 taken 3 times.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✓ Branch 9 taken 3 times.
✗ Branch 10 not taken.
✓ Branch 11 taken 3 times.
✗ Branch 12 not taken.
2420 oper("|", 2,math_binop_type::bit_or);
275
2/13
✗ Branch 0 not taken.
✓ Branch 1 taken 1207 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 1207 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
✗ Branch 10 not taken.
✗ Branch 11 not taken.
✗ Branch 12 not taken.
2414 oper("^", 2, math_binop_type::bit_xor);
276
277
9/14
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 1203 times.
✓ Branch 2 taken 4 times.
✓ Branch 3 taken 1207 times.
✓ Branch 4 taken 8 times.
✓ Branch 5 taken 1203 times.
✓ Branch 6 taken 8 times.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
✓ Branch 10 taken 4 times.
✗ Branch 11 not taken.
✓ Branch 12 taken 4 times.
✗ Branch 13 not taken.
2414 oper(">=", 1, math_binop_type::comp_ge);
278
9/14
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 1202 times.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 1203 times.
✓ Branch 4 taken 2 times.
✓ Branch 5 taken 1202 times.
✓ Branch 6 taken 2 times.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
✓ Branch 10 taken 1 times.
✗ Branch 11 not taken.
✓ Branch 12 taken 1 times.
✗ Branch 13 not taken.
2406 oper("<=", 1, math_binop_type::comp_le);
279
9/13
✓ Branch 0 taken 70 times.
✓ Branch 1 taken 1132 times.
✓ Branch 2 taken 70 times.
✓ Branch 3 taken 70 times.
✓ Branch 4 taken 1202 times.
✓ Branch 5 taken 70 times.
✓ Branch 6 taken 70 times.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✓ Branch 9 taken 70 times.
✗ Branch 10 not taken.
✓ Branch 11 taken 70 times.
✗ Branch 12 not taken.
2404 oper(">", 1, math_binop_type::comp_gt);
280
9/13
✓ Branch 0 taken 898 times.
✓ Branch 1 taken 234 times.
✓ Branch 2 taken 898 times.
✓ Branch 3 taken 898 times.
✓ Branch 4 taken 1132 times.
✓ Branch 5 taken 898 times.
✓ Branch 6 taken 898 times.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✓ Branch 9 taken 898 times.
✗ Branch 10 not taken.
✓ Branch 11 taken 898 times.
✗ Branch 12 not taken.
2264 oper("<", 1, math_binop_type::comp_lt);
281
10/14
✓ Branch 0 taken 209 times.
✓ Branch 1 taken 25 times.
✓ Branch 2 taken 207 times.
✓ Branch 3 taken 236 times.
✓ Branch 4 taken 416 times.
✓ Branch 5 taken 25 times.
✓ Branch 6 taken 414 times.
✓ Branch 7 taken 2 times.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
✓ Branch 10 taken 207 times.
✗ Branch 11 not taken.
✓ Branch 12 taken 207 times.
✗ Branch 13 not taken.
468 oper("==", 1, math_binop_type::comp_eq);
282
10/14
✓ Branch 0 taken 17 times.
✓ Branch 1 taken 8 times.
✓ Branch 2 taken 15 times.
✓ Branch 3 taken 27 times.
✓ Branch 4 taken 32 times.
✓ Branch 5 taken 8 times.
✓ Branch 6 taken 30 times.
✓ Branch 7 taken 2 times.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
✓ Branch 10 taken 15 times.
✗ Branch 11 not taken.
✓ Branch 12 taken 15 times.
✗ Branch 13 not taken.
50 oper("!=", 1, math_binop_type::comp_ne);
283
1/2
✓ Branch 0 taken 16 times.
✗ Branch 1 not taken.
16 throw_err_block(2, err_unknown_operator);
284 #undef oper
285 }
286 20611 return left;
287 20779 }
288
289 14321 owned_node parse_context::parse() {
290 14321 auto res = parse_binops();
291
2/4
✗ Branch 0 not taken.
✓ Branch 1 taken 7077 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 7216 times.
14293 if(*str) {
292 if(*str == ',') throw_err_block(2, err_invalid_input);
293 else throw_err_block(2, err_mismatched_parentheses);
294 }
295 14293 return res;
296 }
297
298 48 void createuserfunc(const char * name, const char * arguments, const char * content) {
299
19/38
✓ Branch 0 taken 24 times.
✓ Branch 1 taken 24 times.
✓ Branch 2 taken 24 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 24 times.
✓ Branch 5 taken 24 times.
✓ Branch 6 taken 24 times.
✓ Branch 7 taken 24 times.
✓ Branch 8 taken 24 times.
✗ Branch 9 not taken.
✗ Branch 10 not taken.
✓ Branch 11 taken 48 times.
✓ Branch 12 taken 24 times.
✗ Branch 13 not taken.
✓ Branch 14 taken 24 times.
✓ Branch 15 taken 24 times.
✗ Branch 16 not taken.
✓ Branch 17 taken 24 times.
✓ Branch 18 taken 24 times.
✓ Branch 19 taken 24 times.
✗ Branch 20 not taken.
✗ Branch 21 not taken.
✓ Branch 22 taken 24 times.
✗ Branch 23 not taken.
✓ Branch 24 taken 24 times.
✗ Branch 25 not taken.
✓ Branch 26 taken 24 times.
✗ Branch 27 not taken.
✗ Branch 28 not taken.
✓ Branch 29 taken 24 times.
✗ Branch 30 not taken.
✗ Branch 31 not taken.
✗ Branch 32 not taken.
✗ Branch 33 not taken.
✗ Branch 34 not taken.
✗ Branch 35 not taken.
✗ Branch 36 not taken.
✗ Branch 37 not taken.
48 if(user_functions.count(name) != 0 || builtin_functions.count(name) != 0) {
300 throw_err_block(0, err_function_redefined, name);
301 }
302
2/3
✓ Branch 0 taken 24 times.
✓ Branch 1 taken 24 times.
✗ Branch 2 not taken.
48 string arguments_buf = arguments;
303 // TODO: if we want to be more lenient with spaces in the `function`
304 // command, then we need to handle spaces inside `arguments_buf`
305 24 int numargs;
306
2/3
✓ Branch 0 taken 24 times.
✓ Branch 1 taken 24 times.
✗ Branch 2 not taken.
48 autoptr<char**> spl = split(arguments_buf.raw(), ',', &numargs);
307 48 size_t arg_count = numargs;
308
16/21
✓ Branch 0 taken 30 times.
✓ Branch 1 taken 18 times.
✓ Branch 2 taken 15 times.
✓ Branch 3 taken 15 times.
✓ Branch 4 taken 6 times.
✓ Branch 5 taken 9 times.
✓ Branch 6 taken 15 times.
✓ Branch 7 taken 9 times.
✓ Branch 8 taken 12 times.
✓ Branch 9 taken 27 times.
✓ Branch 10 taken 15 times.
✓ Branch 11 taken 9 times.
✗ Branch 12 not taken.
✓ Branch 13 taken 15 times.
✓ Branch 14 taken 9 times.
✓ Branch 15 taken 6 times.
✓ Branch 16 taken 18 times.
✗ Branch 17 not taken.
✗ Branch 18 not taken.
✗ Branch 19 not taken.
✗ Branch 20 not taken.
48 if(numargs == 1 && spl[0] == string{""}) {
309 12 arg_count = 0;
310 }
311 48 std::unordered_map<string, size_t> arg_indices;
312
3/3
✓ Branch 0 taken 27 times.
✓ Branch 1 taken 51 times.
✓ Branch 2 taken 24 times.
102 for(size_t i = 0; i < arg_count; i++) {
313
2/4
✓ Branch 0 taken 27 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 27 times.
✗ Branch 3 not taken.
54 string argname = spl[i];
314
2/4
✓ Branch 0 taken 54 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 54 times.
54 if(arg_indices.count(argname)) {
315 throw_err_block(0, err_duplicate_param_name, argname.data(), name);
316 }
317
2/4
✓ Branch 0 taken 54 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 54 times.
54 if(!confirmname(argname)) {
318 throw_err_block(0, err_invalid_param_name, argname.data());
319 }
320
2/3
✓ Branch 0 taken 27 times.
✓ Branch 1 taken 27 times.
✗ Branch 2 not taken.
54 arg_indices.emplace(std::move(argname), i);
321 54 }
322
323
2/3
✓ Branch 0 taken 24 times.
✓ Branch 1 taken 24 times.
✗ Branch 2 not taken.
48 parse_context ctx{ content, arg_indices };
324
2/3
✓ Branch 0 taken 24 times.
✓ Branch 1 taken 24 times.
✗ Branch 2 not taken.
48 auto parsed = ctx.parse();
325 48 math_user_function userfunc = { std::move(parsed), arg_count };
326
2/3
✓ Branch 0 taken 24 times.
✓ Branch 1 taken 24 times.
✗ Branch 2 not taken.
48 user_functions.emplace(name, std::move(userfunc));
327 72 }
328
329 14273 owned_node parse_math_expr(const char * str) {
330 14273 parse_context parse_ctx { str, {}};
331
3/3
✓ Branch 0 taken 7053 times.
✓ Branch 1 taken 7206 times.
✓ Branch 2 taken 14 times.
28518 return parse_ctx.parse();
332 14273 }
333
334 956 int64_t getnum(const char * str) {
335
2/3
✓ Branch 0 taken 478 times.
✓ Branch 1 taken 478 times.
✗ Branch 2 not taken.
956 owned_node parsed = parse_math_expr(str);
336
2/4
✓ Branch 0 taken 478 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 478 times.
✗ Branch 3 not taken.
956 int haslabel = parsed->has_label();
337 956 foundlabel = haslabel > 0;
338 956 foundlabel_static = haslabel < 2;
339 956 forwardlabel = haslabel == 7;
340
2/4
✓ Branch 0 taken 478 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 478 times.
✗ Branch 3 not taken.
1912 math_val rval = parsed->evaluate();
341
1/2
✓ Branch 0 taken 956 times.
✗ Branch 1 not taken.
1912 return rval.get_integer();
342 1912 }
343
344 414 int getlen(const char * orgstr, bool optimizebankextraction) {
345
2/3
✓ Branch 0 taken 207 times.
✓ Branch 1 taken 207 times.
✗ Branch 2 not taken.
414 owned_node parsed = parse_math_expr(orgstr);
346
2/4
✓ Branch 0 taken 207 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 207 times.
✗ Branch 3 not taken.
414 int letgen = parsed->get_len(optimizebankextraction);
347 414 return letgen;
348 414 }
349
350 850 void initmathcore()
351 {
352 850 user_functions.clear();
353 850 }
354
355 840 void deinitmathcore()
356 {
357 //not needed
358 840 }
359