Line | Branch | Exec | Source |
---|---|---|---|
1 | #include <stdlib.h> | ||
2 | #include <string.h> | ||
3 | #include <math.h> | ||
4 | #include "gwion_util.h" | ||
5 | #include "gwion_ast.h" | ||
6 | #include "gwion_env.h" | ||
7 | #include "vm.h" | ||
8 | #include "instr.h" | ||
9 | #include "gwion.h" | ||
10 | #include "object.h" | ||
11 | #include "operator.h" | ||
12 | #include "import.h" | ||
13 | #include "emit.h" | ||
14 | #include "specialid.h" | ||
15 | #include "gwi.h" | ||
16 | #include "gack.h" | ||
17 | #include "array.h" | ||
18 | |||
19 | #define describe_string_logical(name, action) \ | ||
20 | static INSTR(String_##name) { \ | ||
21 | POP_REG(shred, SZ_INT); \ | ||
22 | const M_Object lhs = *(M_Object *)REG(-SZ_INT); \ | ||
23 | const M_Object rhs = *(M_Object *)REG(0); \ | ||
24 | *(m_int *)REG(-SZ_INT) = action; \ | ||
25 | } | ||
26 | 6 | describe_string_logical(eq, (!strcmp(STRING(lhs), STRING(rhs)))) | |
27 | 2 | describe_string_logical(neq, (strcmp(STRING(lhs), STRING(rhs)))) | |
28 | |||
29 | 20 | static inline uint is_const_str(const Exp exp) { | |
30 |
1/2✓ Branch 0 taken 20 times.
✗ Branch 1 not taken.
|
40 | return exp->exp_type == ae_exp_primary && |
31 |
2/2✓ Branch 0 taken 7 times.
✓ Branch 1 taken 13 times.
|
20 | exp->d.prim.prim_type == ae_prim_str; |
32 | } | ||
33 | |||
34 | #define opck_str(name, __exp__) \ | ||
35 | OP_CHECK(opck_string_##name) { \ | ||
36 | Exp_Binary *bin = (Exp_Binary *)data; \ | ||
37 | if (!is_const_str(bin->lhs) || !is_const_str(bin->rhs)) \ | ||
38 | return env->gwion->type[et_bool]; \ | ||
39 | const int ret = __exp__; \ | ||
40 | free_exp(env->gwion->mp, bin->lhs); \ | ||
41 | free_exp(env->gwion->mp, bin->rhs); \ | ||
42 | const Exp e = exp_self(bin); \ | ||
43 | e->exp_type = ae_exp_primary; \ | ||
44 | e->d.prim.prim_type = ae_prim_num; \ | ||
45 | e->d.prim.d.num = ret; \ | ||
46 | return env->gwion->type[et_bool]; \ | ||
47 | } | ||
48 | |||
49 |
4/4✓ Branch 1 taken 4 times.
✓ Branch 2 taken 10 times.
✓ Branch 4 taken 1 times.
✓ Branch 5 taken 3 times.
|
14 | opck_str(eq, !strcmp(bin->lhs->d.prim.d.string.data, bin->rhs->d.prim.d.string.data)) |
50 |
1/4✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
|
2 | opck_str(neq, strcmp(bin->lhs->d.prim.d.string.data, bin->rhs->d.prim.d.string.data)) |
51 | |||
52 | 9 | static CTOR(string_ctor) { | |
53 | 9 | STRING(o) = _mp_calloc(shred->info->mp, 1); | |
54 | 9 | } | |
55 | |||
56 | 121 | static DTOR(string_dtor) { free_mstr(shred->info->mp, STRING(o)); } | |
57 | |||
58 | 2 | ID_CHECK(check_filepp) { | |
59 | 2 | ((Exp_Primary *)prim)->prim_type = ae_prim_str; | |
60 | 2 | ((Exp_Primary *)prim)->d.string.data = env->name; | |
61 | 2 | ((Exp_Primary *)prim)->value = global_string(env, prim->d.string.data, prim_pos(prim)); | |
62 | 2 | return prim->value->type; | |
63 | } | ||
64 | |||
65 | 45 | ID_CHECK(check_funcpp) { | |
66 | 45 | ((Exp_Primary *)prim)->prim_type = ae_prim_str; | |
67 | 134 | ((Exp_Primary *)prim)->d.string.data = env->func ? env->func->name | |
68 |
2/2✓ Branch 0 taken 44 times.
✓ Branch 1 taken 1 times.
|
46 | : env->class_def ? env->class_def->name |
69 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
|
1 | : env->name; |
70 | // handle delim? | ||
71 | 45 | ((Exp_Primary *)prim)->value = global_string(env, prim->d.string.data, prim_pos(prim)); | |
72 | 45 | return prim->value->type; | |
73 | } | ||
74 | |||
75 | ✗ | ID_CHECK(check_linepp) { | |
76 | ✗ | ((Exp_Primary *)prim)->prim_type = ae_prim_num; | |
77 | ✗ | ((Exp_Primary *)prim)->d.num = prim_pos(prim).first.line; | |
78 | ✗ | return env->gwion->type[et_int]; | |
79 | } | ||
80 | |||
81 | 784 | static GACK(gack_string) { | |
82 | 784 | const M_Object obj = *(M_Object *)VALUE; | |
83 |
1/2✓ Branch 0 taken 784 times.
✗ Branch 1 not taken.
|
784 | INTERP_PRINTF("%s", obj ? STRING(obj) : "(null string)"); |
84 | 784 | } | |
85 | |||
86 | 5 | static inline m_bool bounds(const m_str str, const m_int i) { | |
87 |
2/2✓ Branch 0 taken 1 times.
✓ Branch 1 taken 4 times.
|
5 | CHECK_BB(i); |
88 |
1/2✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
|
4 | return (m_uint)i <= strlen(str) ? GW_OK : GW_ERROR; |
89 | } | ||
90 | |||
91 | 3 | static INSTR(StringSlice) { | |
92 | 3 | shred->reg -= SZ_INT * 2; | |
93 | 3 | const M_Object obj = *(M_Object *)REG(-SZ_INT); | |
94 | 3 | m_str str = STRING(obj); | |
95 | 3 | const m_int start = *(m_uint *)REG(0); | |
96 | 3 | const size_t strsz = strlen(str); | |
97 | 3 | m_int end = *(m_uint *)REG(SZ_INT); | |
98 |
2/2✓ Branch 0 taken 2 times.
✓ Branch 1 taken 1 times.
|
3 | if (end < 0) end = strsz + end - 1; |
99 |
3/4✓ Branch 1 taken 2 times.
✓ Branch 2 taken 1 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 2 times.
|
3 | if (bounds(str, start) < 0 || bounds(str, end) < 0) { |
100 | 1 | handle(shred, "OutOfBoundsStringSlice"); | |
101 | 1 | return; | |
102 | } | ||
103 |
1/2✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
|
2 | const m_int op = start < end ? 1 : -1; |
104 |
1/2✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
|
2 | const m_uint sz = (op > 0 ? end - start : start - end) + 1; |
105 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
|
2 | if(sz >= SIZE_MAX/SZ_INT) { |
106 | ✗ | handle(shred, "SliceTooBig"); | |
107 | ✗ | return; | |
108 | } | ||
109 | 2 | char c[sz + 1]; | |
110 |
2/2✓ Branch 0 taken 10 times.
✓ Branch 1 taken 2 times.
|
12 | for (m_int i = start, j = 0; j < (m_int)sz; i += op, ++j) c[j] = str[i]; |
111 | 2 | c[sz] = '\0'; | |
112 | 2 | *(M_Object *)REG(-SZ_INT) = new_string(shred->info->vm->gwion, c); | |
113 | } | ||
114 | |||
115 | 1 | static MFUN(string_len) { *(m_uint *)RETURN = strlen(STRING(o)); } | |
116 | |||
117 | 1 | static MFUN(string_upper) { | |
118 | 1 | char c[strlen(STRING(o)) + 1]; | |
119 | 1 | strcpy(c, STRING(o)); | |
120 |
2/2✓ Branch 0 taken 11 times.
✓ Branch 1 taken 1 times.
|
12 | for (m_uint i = 0; i < strlen(c); i++) |
121 |
3/4✓ Branch 0 taken 9 times.
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 9 times.
✗ Branch 3 not taken.
|
11 | if (c[i] >= 'a' && c[i] <= 'z') c[i] += 'A' - 'a'; |
122 | 1 | *(M_Object *)RETURN = new_string(shred->info->vm->gwion, c); | |
123 | 1 | } | |
124 | |||
125 | 1 | static MFUN(string_lower) { | |
126 | 1 | char c[strlen(STRING(o)) + 1]; | |
127 | 1 | strcpy(c, STRING(o)); | |
128 |
2/2✓ Branch 0 taken 11 times.
✓ Branch 1 taken 1 times.
|
12 | for (m_uint i = 0; i < strlen(c); i++) |
129 |
4/4✓ Branch 0 taken 10 times.
✓ Branch 1 taken 1 times.
✓ Branch 2 taken 2 times.
✓ Branch 3 taken 8 times.
|
11 | if (c[i] >= 'A' && c[i] <= 'Z') c[i] -= 'A' - 'a'; |
130 | 1 | *(M_Object *)RETURN = new_string(shred->info->vm->gwion, c); | |
131 | 1 | } | |
132 | |||
133 | 2 | static MFUN(string_ltrim) { | |
134 | 2 | m_uint i = 0; | |
135 | 2 | const m_str str = STRING(o); | |
136 |
2/2✓ Branch 0 taken 2 times.
✓ Branch 1 taken 2 times.
|
4 | while (str[i] == ' ') i++; |
137 | 2 | char c[strlen(str) - i + 1]; | |
138 | 2 | strcpy(c, STRING(o) + i); | |
139 | 2 | *(M_Object *)RETURN = new_string(shred->info->vm->gwion, c); | |
140 | 2 | } | |
141 | |||
142 | 2 | static MFUN(string_rtrim) { | |
143 | 2 | const m_str str = STRING(o); | |
144 | 2 | const size_t sz = strlen(str); | |
145 |
2/2✓ Branch 0 taken 1 times.
✓ Branch 1 taken 1 times.
|
2 | if (sz) { |
146 | 1 | m_uint len = strlen(str) - 1; | |
147 |
2/2✓ Branch 0 taken 2 times.
✓ Branch 1 taken 1 times.
|
3 | while (str[len] == ' ') len--; |
148 | 1 | char c[len + 2]; | |
149 | 1 | strncpy(c, str, len + 1); | |
150 | 1 | c[len + 1] = '\0'; | |
151 | 1 | *(M_Object *)RETURN = new_string(shred->info->vm->gwion, c); | |
152 | } else { | ||
153 | 1 | ++o->ref; | |
154 | 1 | *(M_Object *)RETURN = o; | |
155 | } | ||
156 | 2 | } | |
157 | |||
158 | 2 | static MFUN(string_trim) { | |
159 | 2 | const m_str str = STRING(o); | |
160 | 2 | m_int i, start = 0, end = 0, len = 0; | |
161 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
|
2 | while (str[len] != '\0') len++; |
162 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
|
2 | for (i = 0; i < len; i++) { |
163 | ✗ | if (str[i] == ' ') | |
164 | ✗ | start++; | |
165 | else | ||
166 | ✗ | break; | |
167 | } | ||
168 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
|
2 | for (i = len - 1; i >= 0; i--) { |
169 | ✗ | if (str[i] == ' ') | |
170 | ✗ | end++; | |
171 | else | ||
172 | ✗ | break; | |
173 | } | ||
174 |
1/2✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
|
2 | if (len - start - end <= 0) { |
175 | 2 | xfun_handle(shred, "InvalidStringTrimRequest"); | |
176 | 2 | return; | |
177 | } | ||
178 | ✗ | char c[len - start - end + 1]; | |
179 | ✗ | for (i = start; i < len - end; i++) c[i - start] = str[i]; | |
180 | ✗ | c[len - start - end] = '\0'; | |
181 | ✗ | *(M_Object *)RETURN = new_string(shred->info->vm->gwion, c); | |
182 | } | ||
183 | |||
184 | ✗ | static MFUN(string_insert) { | |
185 | ✗ | char str[strlen(STRING(o)) + 1]; | |
186 | ✗ | strcpy(str, STRING(o)); | |
187 | ✗ | m_int i, len_insert = 0, index = *(m_int *)MEM(SZ_INT); | |
188 | ✗ | const M_Object arg = *(M_Object *)MEM(SZ_INT * 2); | |
189 | ✗ | char insert[strlen(STRING(arg)) + 1]; | |
190 | ✗ | strcpy(insert, STRING(arg)); | |
191 | ✗ | const m_uint len = strlen(str); | |
192 | ✗ | len_insert = strlen(insert); | |
193 | ✗ | char c[len + len_insert + 1]; | |
194 | ✗ | for (i = 0; i < index; i++) c[i] = str[i]; | |
195 | ✗ | for (i = 0; i < len_insert; i++) c[i + index] = insert[i]; | |
196 | ✗ | for (i = index; i < (m_int)len; i++) c[i + len_insert] = str[i]; | |
197 | ✗ | c[len + len_insert] = '\0'; | |
198 | ✗ | *(M_Object *)RETURN = new_string(shred->info->vm->gwion, c); | |
199 | ; | ||
200 | } | ||
201 | |||
202 | ✗ | static MFUN(string_replace) { | |
203 | ✗ | char str[strlen(STRING(o)) + 1]; | |
204 | ✗ | strcpy(str, STRING(o)); | |
205 | ✗ | m_int i, len_insert = 0, index = *(m_int *)MEM(SZ_INT); | |
206 | ✗ | const M_Object arg = *(M_Object *)MEM(SZ_INT * 2); | |
207 | ✗ | if (!arg) { | |
208 | ✗ | *(M_Object *)RETURN = o; | |
209 | ✗ | return; | |
210 | } | ||
211 | ✗ | char insert[strlen(STRING(arg)) + 1]; | |
212 | ✗ | strcpy(insert, STRING(arg)); | |
213 | ✗ | const m_uint len = strlen(str); | |
214 | ✗ | len_insert = strlen(insert); | |
215 | ✗ | if (index >= (m_int)len || index < 0 || (index + len_insert + 1) <= 0) { | |
216 | ✗ | xfun_handle(shred, "InvalidStringReplace"); | |
217 | ✗ | return; | |
218 | } | ||
219 | ✗ | char c[index + len_insert + 1]; | |
220 | ✗ | for (i = 0; i < index; i++) c[i] = str[i]; | |
221 | ✗ | for (i = 0; i < len_insert; i++) c[i + index] = insert[i]; | |
222 | ✗ | c[index + len_insert] = '\0'; | |
223 | ✗ | *(M_Object *)RETURN = new_string(shred->info->vm->gwion, c); | |
224 | ; | ||
225 | } | ||
226 | |||
227 | 1 | static MFUN(string_replaceN) { | |
228 | 1 | char str[strlen(STRING(o)) + 1]; | |
229 | 1 | strcpy(str, STRING(o)); | |
230 | 1 | m_int i, index = *(m_int *)MEM(SZ_INT); | |
231 | 1 | const M_Object arg = *(M_Object *)MEM(SZ_INT * 3); | |
232 | 1 | const m_int _len = *(m_int *)MEM(SZ_INT * 2); | |
233 |
2/4✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
|
1 | if (!arg || index > (m_int)strlen(STRING(o)) || |
234 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
|
1 | _len > (m_int)strlen(STRING(arg))) { |
235 | ✗ | xfun_handle(shred, "InvalidStringReplace"); | |
236 | ✗ | return; | |
237 | } | ||
238 | 1 | char insert[strlen(STRING(arg)) + 1]; | |
239 | 1 | const m_uint len = strlen(str); | |
240 | // memset(insert, 0, len + 1); | ||
241 | 1 | strcpy(insert, STRING(arg)); | |
242 | 1 | str[len] = '\0'; | |
243 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
|
1 | if (index > (m_int)len) index = len - 1; |
244 | 1 | char c[len + _len]; | |
245 | 1 | memset(c, 0, len + _len); | |
246 |
2/2✓ Branch 0 taken 2 times.
✓ Branch 1 taken 1 times.
|
3 | for (i = 0; i < index; i++) c[i] = str[i]; |
247 |
2/2✓ Branch 0 taken 3 times.
✓ Branch 1 taken 1 times.
|
4 | for (i = 0; i < _len; i++) c[i + index] = insert[i]; |
248 |
2/2✓ Branch 0 taken 2 times.
✓ Branch 1 taken 1 times.
|
3 | for (i = index + _len; i < (m_int)len; i++) c[i] = str[i]; |
249 | 1 | c[len + _len - 1] = '\0'; | |
250 | 1 | *(M_Object *)RETURN = new_string(shred->info->vm->gwion, c); | |
251 | ; | ||
252 | } | ||
253 | |||
254 | 3 | static MFUN(string_find) { | |
255 | 3 | const m_str base = STRING(o); | |
256 | 3 | char c = *(m_int *)MEM(SZ_INT); | |
257 | 3 | char * str = strchr(base, c); | |
258 |
2/2✓ Branch 0 taken 1 times.
✓ Branch 1 taken 2 times.
|
3 | *(m_uint *)RETURN = str ? str - base : -1; |
259 | 3 | } | |
260 | |||
261 | 4 | static MFUN(string_findStart) { | |
262 | 4 | const m_str base = STRING(o); | |
263 | 4 | const size_t sz = strlen(base); | |
264 | 4 | const int pos = *(m_int *)MEM(SZ_INT * 2); | |
265 |
4/4✓ Branch 0 taken 3 times.
✓ Branch 1 taken 1 times.
✓ Branch 2 taken 2 times.
✓ Branch 3 taken 1 times.
|
4 | if (pos >= 0 && (size_t)pos < sz) { |
266 | 2 | const char arg = *(m_int *)MEM(SZ_INT); | |
267 | 2 | char * str = strchr(base + pos, arg); | |
268 |
2/2✓ Branch 0 taken 1 times.
✓ Branch 1 taken 1 times.
|
2 | *(m_uint *)RETURN = str ? str - pos - base : -1; |
269 | } else | ||
270 | 2 | *(m_uint *)RETURN = -1; | |
271 | 4 | } | |
272 | |||
273 | 3 | static MFUN(string_findStr) { | |
274 | 3 | const m_str base = STRING(o); | |
275 | 3 | const size_t sz = strlen(base); | |
276 | 3 | const M_Object obj = *(M_Object *)MEM(SZ_INT); | |
277 |
2/2✓ Branch 0 taken 2 times.
✓ Branch 1 taken 1 times.
|
3 | if (sz) { |
278 | 2 | const m_str arg = STRING(obj); | |
279 | 2 | const m_str str = strstr(base, arg); | |
280 |
2/2✓ Branch 0 taken 1 times.
✓ Branch 1 taken 1 times.
|
2 | *(m_uint *)RETURN = str ? str - base : -1; |
281 | } else | ||
282 | 1 | *(m_uint *)RETURN = -1; | |
283 | 3 | } | |
284 | |||
285 | 4 | static MFUN(string_findStrStart) { | |
286 | 4 | const m_str base = STRING(o); | |
287 | 4 | const size_t sz = strlen(base); | |
288 | 4 | const int pos = *(m_int *)MEM(SZ_INT * 2); | |
289 | 4 | const M_Object obj = *(M_Object *)MEM(SZ_INT); | |
290 |
4/4✓ Branch 0 taken 3 times.
✓ Branch 1 taken 1 times.
✓ Branch 2 taken 2 times.
✓ Branch 3 taken 1 times.
|
4 | if (pos >= 0 && (size_t)pos < sz) { |
291 | 2 | const m_str arg = STRING(obj); | |
292 | 2 | const m_str str = strstr(base + pos, arg); | |
293 |
2/2✓ Branch 0 taken 1 times.
✓ Branch 1 taken 1 times.
|
2 | *(m_uint *)RETURN = str ? str - pos - base : -1; |
294 | } else | ||
295 | 2 | *(m_uint *)RETURN = -1; | |
296 | 4 | } | |
297 | |||
298 | ✗ | static MFUN(string_rfind) { | |
299 | ✗ | const m_str base = STRING(o); | |
300 | ✗ | char c = *(m_int *)MEM(SZ_INT); | |
301 | ✗ | char * str = strrchr(base, c); | |
302 | ✗ | *(m_uint *)RETURN = str ? str - base : -1; | |
303 | } | ||
304 | |||
305 | ✗ | static MFUN(string_rfindStart) { | |
306 | ✗ | const m_str base = STRING(o); | |
307 | ✗ | const size_t sz = strlen(base); | |
308 | ✗ | const int pos = *(m_int *)MEM(SZ_INT); | |
309 | ✗ | if (pos >= 0 && (size_t)pos < sz) { | |
310 | ✗ | const char arg = *(m_int *)MEM(SZ_INT * 2); | |
311 | ✗ | char * str = strrchr(base + pos, arg); | |
312 | ✗ | *(m_uint *)RETURN = str ? str - pos - base : -1; | |
313 | } else | ||
314 | ✗ | *(m_uint *)RETURN = -1; | |
315 | } | ||
316 | |||
317 | 3 | static MFUN(string_rfindStr) { | |
318 | 3 | const m_str base = STRING(o); | |
319 | 3 | const size_t sz = strlen(base); | |
320 | 3 | const M_Object obj = *(M_Object *)MEM(SZ_INT); | |
321 |
2/2✓ Branch 0 taken 2 times.
✓ Branch 1 taken 1 times.
|
3 | if (sz) { |
322 | 2 | const m_str arg = STRING(obj); | |
323 | 2 | m_str tmp = base, str = NULL; | |
324 |
2/2✓ Branch 0 taken 1 times.
✓ Branch 1 taken 2 times.
|
3 | while ((tmp = strstr(tmp, arg))) str = tmp++; |
325 |
2/2✓ Branch 0 taken 1 times.
✓ Branch 1 taken 1 times.
|
2 | *(m_uint *)RETURN = str ? str - base : -1; |
326 | } else | ||
327 | 1 | *(m_uint *)RETURN = -1; | |
328 | 3 | } | |
329 | |||
330 | 4 | static MFUN(string_rfindStrStart) { | |
331 | 4 | const m_str base = STRING(o); | |
332 | 4 | const size_t sz = strlen(base); | |
333 | 4 | const m_int pos = *(m_int *)MEM(SZ_INT * 2); | |
334 | 4 | const M_Object obj = *(M_Object *)MEM(SZ_INT); | |
335 |
4/4✓ Branch 0 taken 3 times.
✓ Branch 1 taken 1 times.
✓ Branch 2 taken 2 times.
✓ Branch 3 taken 1 times.
|
4 | if (sz && (size_t)pos < sz) { |
336 | 2 | const m_str arg = STRING(obj); | |
337 | 2 | m_str tmp = base + pos, str = NULL; | |
338 |
2/2✓ Branch 0 taken 1 times.
✓ Branch 1 taken 2 times.
|
3 | while ((tmp = strstr(tmp, arg))) str = tmp++; |
339 |
2/2✓ Branch 0 taken 1 times.
✓ Branch 1 taken 1 times.
|
2 | *(m_uint *)RETURN = str ? str - pos - base : -1; |
340 | } else | ||
341 | 2 | *(m_uint *)RETURN = -1; | |
342 | 4 | } | |
343 | |||
344 | 1 | static MFUN(string_erase) { | |
345 | 1 | const m_str str = STRING(o); | |
346 | 1 | const m_int _start = *(m_int *)MEM(SZ_INT); | |
347 | 1 | const m_int rem = *(m_int *)MEM(SZ_INT * 2); | |
348 | 1 | const m_int len = strlen(str); | |
349 | 1 | const m_int size = len - rem + 1; | |
350 |
1/2✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
|
1 | const m_int start = _start >= 0 ? _start : len - _start; |
351 |
1/4✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
|
1 | if (start >= len || size <= 0) { |
352 | 1 | xfun_handle(shred, "InvalidStringErase"); | |
353 | 1 | return; | |
354 | } | ||
355 | ✗ | char c[size]; | |
356 | ✗ | c[size - 1] = '\0'; | |
357 | ✗ | for (m_int i = 0; i < start; i++) c[i] = str[i]; | |
358 | ✗ | for (m_int i = start + rem; i < len; i++) c[i - rem] = str[i]; | |
359 | ✗ | STRING(o) = s_name(insert_symbol(shred->info->vm->gwion->st, c)); | |
360 | } | ||
361 | |||
362 | ✗ | static MFUN(string_save) { | |
363 | ✗ | const m_str path = STRING(*(M_Object*)MEM(SZ_INT)); | |
364 | ✗ | FILE *f = fopen(path, "w"); | |
365 | ✗ | if(!f) { | |
366 | ✗ | xfun_handle(shred, "StringLoadException"); | |
367 | ✗ | return; | |
368 | } | ||
369 | ✗ | const m_str str = STRING(o); | |
370 | ✗ | fprintf(f, "%s", str); | |
371 | ✗ | fclose(f); | |
372 | } | ||
373 | |||
374 | ✗ | static SFUN(string_load) { | |
375 | ✗ | const m_str path = STRING(*(M_Object*)MEM(0)); | |
376 | ✗ | FILE *f = fopen(path, "r"); | |
377 | ✗ | if(!f) { | |
378 | ✗ | xfun_handle(shred, "StringLoadException"); | |
379 | ✗ | return; | |
380 | } | ||
381 | ✗ | fseek(f, 0, SEEK_END); | |
382 | ✗ | const size_t sz = ftell(f); | |
383 | ✗ | char c[sz + 1]; | |
384 | ✗ | rewind(f); | |
385 | ✗ | (void)fread(c, 1, sz, f); | |
386 | ✗ | fclose(f); | |
387 | ✗ | *(M_Object*)RETURN = new_string(shred->info->vm->gwion, c); | |
388 | } | ||
389 | |||
390 | ✗ | static MFUN(string_atoi) { | |
391 | ✗ | const M_Object obj = *(M_Object*)MEM(0); | |
392 | ✗ | const m_str str = STRING(obj); | |
393 | ✗ | *(m_int*)RETURN = atoi(str); | |
394 | } | ||
395 | |||
396 | ✗ | static MFUN(string_atof) { | |
397 | ✗ | const M_Object obj = *(M_Object*)MEM(0); | |
398 | ✗ | const m_str str = STRING(obj); | |
399 | ✗ | *(m_float*)RETURN = (m_float)atof(str); | |
400 | } | ||
401 | #include <errno.h> | ||
402 | ✗ | static MFUN(string_atoi2) { | |
403 | ✗ | const M_Object obj = *(M_Object*)MEM(0); | |
404 | ✗ | const m_str str = STRING(obj); | |
405 | ✗ | char *endptr = NULL; | |
406 | ✗ | if(!(*(m_int*)RETURN = strtol(str, &endptr, 10))) { | |
407 | ✗ | if(errno == EINVAL) { | |
408 | ✗ | xfun_handle(shred, "ErrorInvalidValue"); | |
409 | ✗ | return; | |
410 | } | ||
411 | ✗ | if(errno == ERANGE) { | |
412 | ✗ | xfun_handle(shred, "ValueOutOfRange"); | |
413 | ✗ | return; | |
414 | } | ||
415 | } | ||
416 | ✗ | **(m_uint**)MEM(SZ_INT) = endptr - str; | |
417 | } | ||
418 | |||
419 | ANN Type check_array_access(const Env env, const Array_Sub array); | ||
420 | |||
421 | 2 | static OP_CHECK(opck_string_access) { | |
422 | 2 | const Array_Sub array = (Array_Sub)data; | |
423 | 2 | const Exp exp = array->exp; | |
424 |
1/2✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
|
2 | if(!exp->next) |
425 | 2 | return env->gwion->type[et_char]; | |
426 | ✗ | struct Array_Sub_ next = { exp->next, env->gwion->type[et_char], array->depth - 1 }; | |
427 | ✗ | return check_array_access(env, &next); | |
428 | } | ||
429 | |||
430 | 1 | static INSTR(string_at) { | |
431 | 1 | POP_REG(shred, SZ_INT); | |
432 | 1 | const m_str str = STRING(*(M_Object*)REG(-SZ_INT)); | |
433 | 1 | const m_int i = *(m_int *)REG(0); | |
434 | 1 | const m_uint len = strlen(str); | |
435 |
2/4✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 1 times.
|
1 | if (i < 0 || (m_uint)i >= len) { |
436 | ✗ | handle(shred, "invalid string access"); | |
437 | ✗ | return; | |
438 | } else | ||
439 | 1 | *(m_int *)REG(-SZ_INT) = str[i]; | |
440 | } | ||
441 | |||
442 | 1 | static INSTR(string_at_set) { | |
443 | 1 | POP_REG(shred, SZ_INT); | |
444 | 1 | const m_str str = STRING((*(M_Object*)REG(-SZ_INT))); | |
445 | 1 | const m_int i = *(m_int *)REG(0); | |
446 | 1 | const m_uint len = strlen(str); | |
447 |
2/4✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 1 times.
|
1 | if (i < 0 || (m_uint)i >= len) { |
448 | ✗ | handle(shred, "StringAccessException"); | |
449 | ✗ | return; | |
450 | } | ||
451 | 1 | const m_int c = *(m_int*)REG(-SZ_INT*2); | |
452 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
|
1 | if(c == '\0') { |
453 | ✗ | handle(shred, "StringAccessException"); | |
454 | ✗ | return; | |
455 | } | ||
456 | 1 | *(char**)REG(-SZ_INT) = str + i; | |
457 | 1 | memcpy(REG(-SZ_INT*2 + 1), str + i + 1, SZ_INT - 1); | |
458 | } | ||
459 | |||
460 | |||
461 | 2 | static OP_EMIT(opem_string_access) { | |
462 | 2 | struct ArrayAccessInfo *info = (struct ArrayAccessInfo*)data; | |
463 | 2 | const Exp exp = info->array.exp; | |
464 | 2 | const Exp next = exp->next; | |
465 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
|
2 | CHECK_BB(emit_exp(emit, exp)); |
466 | 2 | exp->next = next; | |
467 |
2/2✓ Branch 0 taken 1 times.
✓ Branch 1 taken 1 times.
|
2 | emit_add_instr(emit, !info->is_var ? string_at : string_at_set); |
468 | 2 | return GW_OK; | |
469 | } | ||
470 | |||
471 | 638 | GWION_IMPORT(string) { | |
472 | 638 | const Type t_string = gwi_class_ini(gwi, "string", NULL); | |
473 | 638 | gwi->gwion->type[et_string] = t_string; // use func | |
474 | 638 | gwi_class_xtor(gwi, string_ctor, string_dtor); | |
475 | 638 | GWI_BB(gwi_gack(gwi, t_string, gack_string)) | |
476 | 638 | t_string->nspc->offset += SZ_INT; | |
477 | |||
478 | 638 | gwi_func_ini(gwi, "int", "size"); | |
479 | 638 | GWI_BB(gwi_func_end(gwi, string_len, ae_flag_none)) | |
480 | |||
481 | 638 | gwi_func_ini(gwi, "string", "upper"); | |
482 | 638 | GWI_BB(gwi_func_end(gwi, string_upper, ae_flag_none)) | |
483 | |||
484 | 638 | gwi_func_ini(gwi, "string", "lower"); | |
485 | 638 | GWI_BB(gwi_func_end(gwi, string_lower, ae_flag_none)) | |
486 | |||
487 | 638 | gwi_func_ini(gwi, "string", "ltrim"); | |
488 | 638 | GWI_BB(gwi_func_end(gwi, string_ltrim, ae_flag_none)) | |
489 | |||
490 | 638 | gwi_func_ini(gwi, "string", "rtrim"); | |
491 | 638 | GWI_BB(gwi_func_end(gwi, string_rtrim, ae_flag_none)) | |
492 | |||
493 | 638 | gwi_func_ini(gwi, "string", "trim"); | |
494 | 638 | GWI_BB(gwi_func_end(gwi, string_trim, ae_flag_none)) | |
495 | |||
496 | 638 | gwi_func_ini(gwi, "string", "insert"); | |
497 | 638 | gwi_func_arg(gwi, "int", "pos"); | |
498 | 638 | gwi_func_arg(gwi, "string", "str"); | |
499 | 638 | GWI_BB(gwi_func_end(gwi, string_insert, ae_flag_none)) | |
500 | |||
501 | 638 | gwi_func_ini(gwi, "string", "replace"); | |
502 | 638 | gwi_func_arg(gwi, "int", "pos"); | |
503 | 638 | gwi_func_arg(gwi, "string", "str"); | |
504 | 638 | GWI_BB(gwi_func_end(gwi, string_replace, ae_flag_none)) | |
505 | |||
506 | 638 | gwi_func_ini(gwi, "string", "replace"); | |
507 | 638 | gwi_func_arg(gwi, "int", "pos"); | |
508 | 638 | gwi_func_arg(gwi, "int", "n"); | |
509 | 638 | gwi_func_arg(gwi, "string", "str"); | |
510 | 638 | GWI_BB(gwi_func_end(gwi, string_replaceN, ae_flag_none)) | |
511 | |||
512 | 638 | gwi_func_ini(gwi, "int", "find"); | |
513 | 638 | gwi_func_arg(gwi, "char", "c"); | |
514 | 638 | GWI_BB(gwi_func_end(gwi, string_find, ae_flag_none)) | |
515 | |||
516 | 638 | gwi_func_ini(gwi, "int", "find"); | |
517 | 638 | gwi_func_arg(gwi, "char", "c"); | |
518 | 638 | gwi_func_arg(gwi, "int", "pos"); | |
519 | 638 | GWI_BB(gwi_func_end(gwi, string_findStart, ae_flag_none)) | |
520 | |||
521 | 638 | gwi_func_ini(gwi, "int", "find"); | |
522 | 638 | gwi_func_arg(gwi, "string", "str"); | |
523 | 638 | GWI_BB(gwi_func_end(gwi, string_findStr, ae_flag_none)) | |
524 | |||
525 | 638 | gwi_func_ini(gwi, "int", "find"); | |
526 | 638 | gwi_func_arg(gwi, "string", "str"); | |
527 | 638 | gwi_func_arg(gwi, "int", "pos"); | |
528 | 638 | GWI_BB(gwi_func_end(gwi, string_findStrStart, ae_flag_none)) | |
529 | |||
530 | 638 | gwi_func_ini(gwi, "int", "rfind"); | |
531 | 638 | gwi_func_arg(gwi, "char", "c"); | |
532 | 638 | GWI_BB(gwi_func_end(gwi, string_rfind, ae_flag_none)) | |
533 | |||
534 | 638 | gwi_func_ini(gwi, "int", "rfind"); | |
535 | 638 | gwi_func_arg(gwi, "char", "c"); | |
536 | 638 | gwi_func_arg(gwi, "int", "pos"); | |
537 | 638 | GWI_BB(gwi_func_end(gwi, string_rfindStart, ae_flag_none)) | |
538 | |||
539 | 638 | gwi_func_ini(gwi, "int", "rfind"); | |
540 | 638 | gwi_func_arg(gwi, "string", "str"); | |
541 | 638 | GWI_BB(gwi_func_end(gwi, string_rfindStr, ae_flag_none)) | |
542 | |||
543 | 638 | gwi_func_ini(gwi, "int", "rfind"); | |
544 | 638 | gwi_func_arg(gwi, "string", "str"); | |
545 | 638 | gwi_func_arg(gwi, "int", "pos"); | |
546 | 638 | GWI_BB(gwi_func_end(gwi, string_rfindStrStart, ae_flag_none)) | |
547 | |||
548 | 638 | gwi_func_ini(gwi, "void", "erase"); | |
549 | 638 | gwi_func_arg(gwi, "int", "start"); | |
550 | 638 | gwi_func_arg(gwi, "int", "length"); | |
551 | 638 | GWI_BB(gwi_func_end(gwi, string_erase, ae_flag_none)) | |
552 | |||
553 | 638 | gwi_func_ini(gwi, "void", "save"); | |
554 | 638 | gwi_func_arg(gwi, "string", "path"); | |
555 | 638 | GWI_BB(gwi_func_end(gwi, string_save, ae_flag_none)) | |
556 | |||
557 | 638 | gwi_func_ini(gwi, "string", "load"); | |
558 | 638 | gwi_func_arg(gwi, "string", "path"); | |
559 | 638 | GWI_BB(gwi_func_end(gwi, string_load, ae_flag_static)) | |
560 | |||
561 | 638 | gwi_func_ini(gwi, "int", "atoi"); | |
562 | 638 | GWI_BB(gwi_func_end(gwi, string_atoi, ae_flag_none)) | |
563 | |||
564 | 638 | gwi_func_ini(gwi, "int", "atoi2"); | |
565 | 638 | gwi_func_arg(gwi, "&int", "offset"); | |
566 | 638 | GWI_BB(gwi_func_end(gwi, string_atoi2, ae_flag_none)) | |
567 | |||
568 | 638 | gwi_func_ini(gwi, "float", "atof"); | |
569 | 638 | GWI_BB(gwi_func_end(gwi, string_atof, ae_flag_none)) | |
570 | |||
571 | 638 | GWI_BB(gwi_class_end(gwi)) | |
572 | |||
573 | 638 | GWI_BB(gwi_oper_ini(gwi, "int", "string", NULL)) | |
574 | 638 | GWI_BB(gwi_oper_add(gwi, opck_string_access)) | |
575 | 638 | GWI_BB(gwi_oper_emi(gwi, opem_string_access)) | |
576 | 638 | GWI_BB(gwi_oper_end(gwi, "[]", NULL)) | |
577 | |||
578 | 638 | GWI_BB(gwi_oper_ini(gwi, "string", "string", "bool")) | |
579 | 638 | GWI_BB(gwi_oper_add(gwi, opck_string_eq)) | |
580 | 638 | GWI_BB(gwi_oper_end(gwi, "==", String_eq)) | |
581 | 638 | GWI_BB(gwi_oper_add(gwi, opck_string_neq)) | |
582 | 638 | GWI_BB(gwi_oper_end(gwi, "!=", String_neq)) | |
583 | |||
584 | 638 | GWI_BB(gwi_oper_ini(gwi, "int", "string", "string")) | |
585 | 638 | GWI_BB(gwi_oper_end(gwi, "[:]", StringSlice)) | |
586 | |||
587 | 638 | struct SpecialId_ file_spid = { | |
588 | .ck = check_filepp, .is_const = 1}; | ||
589 | 638 | gwi_specialid(gwi, "__file__", &file_spid); | |
590 | 638 | struct SpecialId_ func_spid = { | |
591 | .ck = check_funcpp, .is_const = 1}; | ||
592 | 638 | gwi_specialid(gwi, "__func__", &func_spid); | |
593 | 638 | struct SpecialId_ line_spid = { | |
594 | .ck = check_linepp, .is_const = 1}; | ||
595 | 638 | gwi_specialid(gwi, "__line__", &line_spid); | |
596 | 638 | return GW_OK; | |
597 | } | ||
598 |