/home/travis/build/MoarVM/MoarVM/src/core/coerce.c
Line | Count | Source (jump to first uncovered line) |
1 | | #include "moar.h" |
2 | | |
3 | | #if defined(_MSC_VER) |
4 | | #define strtoll _strtoi64 |
5 | | #define snprintf _snprintf |
6 | | #endif |
7 | | |
8 | | /* Special return structure for boolification handling. */ |
9 | | typedef struct { |
10 | | MVMuint8 *true_addr; |
11 | | MVMuint8 *false_addr; |
12 | | MVMuint8 flip; |
13 | | MVMRegister res_reg; |
14 | | } BoolMethReturnData; |
15 | | |
16 | 680k | MVMint64 MVM_coerce_istrue_s(MVMThreadContext *tc, MVMString *str) { |
17 | 676k | return str == NULL || !IS_CONCRETE(str) || MVM_string_graphs_nocheck(tc, str) == 0 ? 0 : 1; |
18 | 680k | } |
19 | | |
20 | | /* Tries to do the boolification. It may be that a method call is needed. In |
21 | | * this case, a return hook is set up to handle doing the right thing. The |
22 | | * result register to put the result in should be indicated in res_reg, or |
23 | | * alternatively the true/false addresses to set the PC to should be set. |
24 | | * In the register case, expects that the current PC is already at the |
25 | | * next instruction before this is called. */ |
26 | | static void boolify_return(MVMThreadContext *tc, void *sr_data); |
27 | | static void flip_return(MVMThreadContext *tc, void *sr_data); |
28 | | void MVM_coerce_istrue(MVMThreadContext *tc, MVMObject *obj, MVMRegister *res_reg, |
29 | 5.98M | MVMuint8 *true_addr, MVMuint8 *false_addr, MVMuint8 flip) { |
30 | 5.98M | MVMint64 result = 0; |
31 | 5.98M | if (!MVM_is_null(tc, obj)) { |
32 | 5.98M | MVMBoolificationSpec *bs = obj->st->boolification_spec; |
33 | 5.95M | switch (bs == NULL ? MVM_BOOL_MODE_NOT_TYPE_OBJECT : bs->mode) { |
34 | 86.6k | case MVM_BOOL_MODE_CALL_METHOD: { |
35 | 86.6k | MVMObject *code = MVM_frame_find_invokee(tc, bs->method, NULL); |
36 | 86.6k | MVMCallsite *inv_arg_callsite = MVM_callsite_get_common(tc, MVM_CALLSITE_ID_INV_ARG); |
37 | 86.6k | if (res_reg) { |
38 | 38.1k | /* We need to do the invocation, and set this register |
39 | 38.1k | * the result. Then we just do the call. For the flip |
40 | 38.1k | * case, just set up special return handler to flip |
41 | 38.1k | * the register. */ |
42 | 38.1k | MVM_args_setup_thunk(tc, res_reg, MVM_RETURN_INT, inv_arg_callsite); |
43 | 38.1k | tc->cur_frame->args[0].o = obj; |
44 | 38.1k | if (flip) { |
45 | 25.5k | tc->cur_frame->special_return = flip_return; |
46 | 25.5k | tc->cur_frame->special_return_data = res_reg; |
47 | 25.5k | } |
48 | 38.1k | STABLE(code)->invoke(tc, code, inv_arg_callsite, tc->cur_frame->args); |
49 | 38.1k | } |
50 | 48.4k | else { |
51 | 48.4k | /* Need to set up special return hook. */ |
52 | 48.4k | BoolMethReturnData *data = MVM_malloc(sizeof(BoolMethReturnData)); |
53 | 48.4k | data->true_addr = true_addr; |
54 | 48.4k | data->false_addr = false_addr; |
55 | 48.4k | data->flip = flip; |
56 | 48.4k | tc->cur_frame->special_return = boolify_return; |
57 | 48.4k | tc->cur_frame->special_return_data = data; |
58 | 48.4k | MVM_args_setup_thunk(tc, &data->res_reg, MVM_RETURN_INT, inv_arg_callsite); |
59 | 48.4k | tc->cur_frame->args[0].o = obj; |
60 | 48.4k | STABLE(code)->invoke(tc, code, inv_arg_callsite, tc->cur_frame->args); |
61 | 48.4k | } |
62 | 86.6k | return; |
63 | 86.6k | } |
64 | 742k | case MVM_BOOL_MODE_UNBOX_INT: |
65 | 742k | result = !IS_CONCRETE(obj) || REPR(obj)->box_funcs.get_int(tc, STABLE(obj), obj, OBJECT_BODY(obj)) == 0 ? 0 : 1; |
66 | 742k | break; |
67 | 465 | case MVM_BOOL_MODE_UNBOX_NUM: |
68 | 465 | result = !IS_CONCRETE(obj) || REPR(obj)->box_funcs.get_num(tc, STABLE(obj), obj, OBJECT_BODY(obj)) == 0.0 ? 0 : 1; |
69 | 465 | break; |
70 | 140k | case MVM_BOOL_MODE_UNBOX_STR_NOT_EMPTY: { |
71 | 140k | MVMString *str; |
72 | 140k | if (!IS_CONCRETE(obj)) { |
73 | 0 | result = 0; |
74 | 0 | break; |
75 | 0 | } |
76 | 140k | str = REPR(obj)->box_funcs.get_str(tc, STABLE(obj), obj, OBJECT_BODY(obj)); |
77 | 140k | result = MVM_coerce_istrue_s(tc, str); |
78 | 140k | break; |
79 | 140k | } |
80 | 3 | case MVM_BOOL_MODE_UNBOX_STR_NOT_EMPTY_OR_ZERO: { |
81 | 3 | MVMString *str; |
82 | 3 | MVMint64 chars; |
83 | 3 | if (!IS_CONCRETE(obj)) { |
84 | 0 | result = 0; |
85 | 0 | break; |
86 | 0 | } |
87 | 3 | str = REPR(obj)->box_funcs.get_str(tc, STABLE(obj), obj, OBJECT_BODY(obj)); |
88 | 3 | |
89 | 3 | if (str == NULL || !IS_CONCRETE(str)) { |
90 | 0 | result = 0; |
91 | 0 | break; |
92 | 0 | } |
93 | 3 | |
94 | 3 | chars = MVM_string_graphs_nocheck(tc, str); |
95 | 3 | |
96 | 3 | result = chars == 0 || |
97 | 2 | (chars == 1 && MVM_string_get_grapheme_at_nocheck(tc, str, 0) == 48) |
98 | 2 | ? 0 : 1; |
99 | 3 | break; |
100 | 3 | } |
101 | 1.74M | case MVM_BOOL_MODE_NOT_TYPE_OBJECT: |
102 | 1.74M | result = !IS_CONCRETE(obj) ? 0 : 1; |
103 | 1.74M | break; |
104 | 2 | case MVM_BOOL_MODE_BIGINT: |
105 | 2 | result = IS_CONCRETE(obj) ? MVM_bigint_bool(tc, obj) : 0; |
106 | 2 | break; |
107 | 1.61M | case MVM_BOOL_MODE_ITER: |
108 | 1.61M | result = IS_CONCRETE(obj) ? MVM_iter_istrue(tc, (MVMIter *)obj) : 0; |
109 | 1.61M | break; |
110 | 1.65M | case MVM_BOOL_MODE_HAS_ELEMS: |
111 | 1.65M | result = IS_CONCRETE(obj) ? MVM_repr_elems(tc, obj) != 0 : 0; |
112 | 1.65M | break; |
113 | 0 | default: |
114 | 0 | MVM_exception_throw_adhoc(tc, "Invalid boolification spec mode used"); |
115 | 5.98M | } |
116 | 5.98M | } |
117 | 5.98M | |
118 | 5.89M | if (flip) |
119 | 4.26M | result = result ? 0 : 1; |
120 | 5.89M | |
121 | 5.89M | if (res_reg) { |
122 | 2.77M | res_reg->i64 = result; |
123 | 2.77M | } |
124 | 3.12M | else { |
125 | 3.12M | if (result) |
126 | 1.69M | *(tc->interp_cur_op) = true_addr; |
127 | 3.12M | else |
128 | 1.42M | *(tc->interp_cur_op) = false_addr; |
129 | 3.12M | } |
130 | 5.89M | } |
131 | | |
132 | | /* Callback after running boolification method. */ |
133 | 48.4k | static void boolify_return(MVMThreadContext *tc, void *sr_data) { |
134 | 48.4k | BoolMethReturnData *data = (BoolMethReturnData *)sr_data; |
135 | 48.4k | MVMint64 result = data->res_reg.i64; |
136 | 48.4k | if (data->flip) |
137 | 41.3k | result = result ? 0 : 1; |
138 | 48.4k | if (result) |
139 | 19.4k | *(tc->interp_cur_op) = data->true_addr; |
140 | 48.4k | else |
141 | 29.0k | *(tc->interp_cur_op) = data->false_addr; |
142 | 48.4k | MVM_free(data); |
143 | 48.4k | } |
144 | | |
145 | | /* Callback to flip result. */ |
146 | 25.5k | static void flip_return(MVMThreadContext *tc, void *sr_data) { |
147 | 25.5k | MVMRegister *r = (MVMRegister *)sr_data; |
148 | 15.2k | r->i64 = r->i64 ? 0 : 1; |
149 | 25.5k | } |
150 | | |
151 | 344k | MVMString * MVM_coerce_i_s(MVMThreadContext *tc, MVMint64 i) { |
152 | 344k | char buffer[64]; |
153 | 344k | int len; |
154 | 344k | |
155 | 344k | /* See if we can hit the cache. */ |
156 | 343k | int cache = i >= 0 && i < MVM_INT_TO_STR_CACHE_SIZE; |
157 | 344k | if (cache) { |
158 | 271k | MVMString *cached = tc->instance->int_to_str_cache[i]; |
159 | 271k | if (cached) |
160 | 266k | return cached; |
161 | 271k | } |
162 | 344k | |
163 | 344k | /* Otherwise, need to do the work; cache it if in range. */ |
164 | 77.9k | len = snprintf(buffer, 64, "%lld", (long long int)i); |
165 | 77.9k | if (len >= 0) { |
166 | 77.9k | MVMString *result = MVM_string_ascii_decode(tc, tc->instance->VMString, buffer, len); |
167 | 77.9k | if (cache) |
168 | 4.72k | tc->instance->int_to_str_cache[i] = result; |
169 | 77.9k | return result; |
170 | 77.9k | } |
171 | 0 | else { |
172 | 0 | MVM_exception_throw_adhoc(tc, "Could not stringify integer"); |
173 | 0 | } |
174 | 77.9k | } |
175 | | |
176 | 20.4k | MVMString * MVM_coerce_n_s(MVMThreadContext *tc, MVMnum64 n) { |
177 | 20.4k | if (n == MVM_num_posinf(tc)) { |
178 | 0 | return MVM_string_ascii_decode_nt(tc, tc->instance->VMString, "Inf"); |
179 | 0 | } |
180 | 20.4k | else if (n == MVM_num_neginf(tc)) { |
181 | 0 | return MVM_string_ascii_decode_nt(tc, tc->instance->VMString, "-Inf"); |
182 | 0 | } |
183 | 20.4k | else if (n != n) { |
184 | 0 | return MVM_string_ascii_decode_nt(tc, tc->instance->VMString, "NaN"); |
185 | 0 | } |
186 | 20.4k | else { |
187 | 20.4k | char buf[64]; |
188 | 20.4k | int i; |
189 | 20.4k | if (snprintf(buf, 64, "%.15g", n) < 0) |
190 | 0 | MVM_exception_throw_adhoc(tc, "Could not stringify number"); |
191 | 20.4k | if (strstr(buf, ".")) { |
192 | 434 | MVMint64 is_not_scientific = !strstr(buf, "e"); |
193 | 434 | i = strlen(buf); |
194 | 434 | while (i > 1 && ((buf[--i] == '0' && is_not_scientific) || buf[i] == ' ')) |
195 | 0 | buf[i] = '\0'; |
196 | 434 | if (buf[i] == '.') |
197 | 0 | buf[i] = '\0'; |
198 | 434 | } |
199 | 20.4k | return MVM_string_ascii_decode(tc, tc->instance->VMString, buf, strlen(buf)); |
200 | 20.4k | } |
201 | 20.4k | } |
202 | | |
203 | 1.88M | void MVM_coerce_smart_stringify(MVMThreadContext *tc, MVMObject *obj, MVMRegister *res_reg) { |
204 | 1.88M | MVMObject *strmeth; |
205 | 1.88M | const MVMStorageSpec *ss; |
206 | 1.88M | |
207 | 1.88M | /* Handle null case. */ |
208 | 1.88M | if (MVM_is_null(tc, obj)) { |
209 | 2 | res_reg->s = tc->instance->str_consts.empty; |
210 | 2 | return; |
211 | 2 | } |
212 | 1.88M | |
213 | 1.88M | /* If it can unbox as a string, that wins right off. */ |
214 | 1.88M | ss = REPR(obj)->get_storage_spec(tc, STABLE(obj)); |
215 | 1.88M | if (ss->can_box & MVM_STORAGE_SPEC_CAN_BOX_STR && IS_CONCRETE(obj)) { |
216 | 1.37M | res_reg->s = REPR(obj)->box_funcs.get_str(tc, STABLE(obj), obj, OBJECT_BODY(obj)); |
217 | 1.37M | return; |
218 | 1.37M | } |
219 | 1.88M | |
220 | 1.88M | /* Check if there is a Str method. */ |
221 | 514k | MVMROOT(tc, obj, { |
222 | 514k | strmeth = MVM_6model_find_method_cache_only(tc, obj, |
223 | 514k | tc->instance->str_consts.Str); |
224 | 514k | }); |
225 | 514k | |
226 | 514k | if (!MVM_is_null(tc, strmeth)) { |
227 | 125k | /* We need to do the invocation; just set it up with our result reg as |
228 | 125k | * the one for the call. */ |
229 | 125k | MVMObject *code = MVM_frame_find_invokee(tc, strmeth, NULL); |
230 | 125k | MVMCallsite *inv_arg_callsite = MVM_callsite_get_common(tc, MVM_CALLSITE_ID_INV_ARG); |
231 | 125k | |
232 | 125k | MVM_args_setup_thunk(tc, res_reg, MVM_RETURN_STR, inv_arg_callsite); |
233 | 125k | tc->cur_frame->args[0].o = obj; |
234 | 125k | STABLE(code)->invoke(tc, code, inv_arg_callsite, tc->cur_frame->args); |
235 | 125k | return; |
236 | 125k | } |
237 | 514k | |
238 | 514k | /* Otherwise, guess something appropriate. */ |
239 | 389k | if (!IS_CONCRETE(obj)) |
240 | 38.1k | res_reg->s = tc->instance->str_consts.empty; |
241 | 351k | else { |
242 | 351k | if (REPR(obj)->ID == MVM_REPR_ID_MVMException) |
243 | 61 | res_reg->s = ((MVMException *)obj)->body.message; |
244 | 351k | else if (ss->can_box & MVM_STORAGE_SPEC_CAN_BOX_INT) |
245 | 330k | res_reg->s = MVM_coerce_i_s(tc, REPR(obj)->box_funcs.get_int(tc, STABLE(obj), obj, OBJECT_BODY(obj))); |
246 | 20.3k | else if (ss->can_box & MVM_STORAGE_SPEC_CAN_BOX_NUM) |
247 | 20.3k | res_reg->s = MVM_coerce_n_s(tc, REPR(obj)->box_funcs.get_num(tc, STABLE(obj), obj, OBJECT_BODY(obj))); |
248 | 20.3k | else |
249 | 0 | MVM_exception_throw_adhoc(tc, "cannot stringify this"); |
250 | 351k | } |
251 | 389k | } |
252 | | |
253 | 1.84k | MVMint64 MVM_coerce_s_i(MVMThreadContext *tc, MVMString *s) { |
254 | 1.84k | char *enc = MVM_string_ascii_encode(tc, s, NULL, 0); |
255 | 1.84k | MVMint64 i = strtoll(enc, NULL, 10); |
256 | 1.84k | MVM_free(enc); |
257 | 1.84k | return i; |
258 | 1.84k | } |
259 | | |
260 | 2.20k | MVMnum64 MVM_coerce_s_n(MVMThreadContext *tc, MVMString *s) { |
261 | 2.20k | char *enc = MVM_string_ascii_encode(tc, s, NULL, 0); |
262 | 2.20k | MVMnum64 n; |
263 | 2.20k | if (strcmp(enc, "NaN") == 0) |
264 | 0 | n = MVM_num_nan(tc); |
265 | 2.20k | else if (strcmp(enc, "Inf") == 0) |
266 | 0 | n = MVM_num_posinf(tc); |
267 | 2.20k | else if (strcmp(enc, "+Inf") == 0) |
268 | 0 | n = MVM_num_posinf(tc); |
269 | 2.20k | else if (strcmp(enc, "-Inf") == 0) |
270 | 0 | n = MVM_num_neginf(tc); |
271 | 2.20k | else |
272 | 2.20k | n = atof(enc); |
273 | 2.20k | MVM_free(enc); |
274 | 2.20k | return n; |
275 | 2.20k | } |
276 | | |
277 | 4.21M | void MVM_coerce_smart_numify(MVMThreadContext *tc, MVMObject *obj, MVMRegister *res_reg) { |
278 | 4.21M | MVMObject *nummeth; |
279 | 4.21M | |
280 | 4.21M | /* Handle null case. */ |
281 | 4.21M | if (MVM_is_null(tc, obj)) { |
282 | 0 | res_reg->n64 = 0.0; |
283 | 0 | return; |
284 | 0 | } |
285 | 4.21M | |
286 | 4.21M | /* Check if there is a Num method. */ |
287 | 4.21M | MVMROOT(tc, obj, { |
288 | 4.21M | nummeth = MVM_6model_find_method_cache_only(tc, obj, |
289 | 4.21M | tc->instance->str_consts.Num); |
290 | 4.21M | }); |
291 | 4.21M | |
292 | 4.21M | if (!MVM_is_null(tc, nummeth)) { |
293 | 533 | /* We need to do the invocation; just set it up with our result reg as |
294 | 533 | * the one for the call. */ |
295 | 533 | MVMObject *code = MVM_frame_find_invokee(tc, nummeth, NULL); |
296 | 533 | MVMCallsite *inv_arg_callsite = MVM_callsite_get_common(tc, MVM_CALLSITE_ID_INV_ARG); |
297 | 533 | |
298 | 533 | MVM_args_setup_thunk(tc, res_reg, MVM_RETURN_NUM, inv_arg_callsite); |
299 | 533 | tc->cur_frame->args[0].o = obj; |
300 | 533 | STABLE(code)->invoke(tc, code, inv_arg_callsite, tc->cur_frame->args); |
301 | 533 | return; |
302 | 533 | } |
303 | 4.21M | |
304 | 4.21M | /* Otherwise, guess something appropriate. */ |
305 | 4.21M | if (!IS_CONCRETE(obj)) { |
306 | 2.73k | res_reg->n64 = 0.0; |
307 | 2.73k | } |
308 | 4.20M | else { |
309 | 4.20M | const MVMStorageSpec *ss = REPR(obj)->get_storage_spec(tc, STABLE(obj)); |
310 | 4.20M | if (ss->can_box & MVM_STORAGE_SPEC_CAN_BOX_INT) |
311 | 2.78M | res_reg->n64 = (MVMnum64)REPR(obj)->box_funcs.get_int(tc, STABLE(obj), obj, OBJECT_BODY(obj)); |
312 | 1.42M | else if (ss->can_box & MVM_STORAGE_SPEC_CAN_BOX_NUM) |
313 | 1.16M | res_reg->n64 = REPR(obj)->box_funcs.get_num(tc, STABLE(obj), obj, OBJECT_BODY(obj)); |
314 | 259k | else if (ss->can_box & MVM_STORAGE_SPEC_CAN_BOX_STR) |
315 | 2.19k | res_reg->n64 = MVM_coerce_s_n(tc, REPR(obj)->box_funcs.get_str(tc, STABLE(obj), obj, OBJECT_BODY(obj))); |
316 | 257k | else if (REPR(obj)->ID == MVM_REPR_ID_VMArray) |
317 | 250k | res_reg->n64 = (MVMnum64)REPR(obj)->elems(tc, STABLE(obj), obj, OBJECT_BODY(obj)); |
318 | 6.46k | else if (REPR(obj)->ID == MVM_REPR_ID_MVMHash) |
319 | 6.46k | res_reg->n64 = (MVMnum64)REPR(obj)->elems(tc, STABLE(obj), obj, OBJECT_BODY(obj)); |
320 | 6.46k | else |
321 | 0 | MVM_exception_throw_adhoc(tc, "cannot numify this"); |
322 | 4.20M | } |
323 | 4.21M | } |
324 | | |
325 | 608k | MVMint64 MVM_coerce_simple_intify(MVMThreadContext *tc, MVMObject *obj) { |
326 | 608k | /* Handle null and non-concrete case. */ |
327 | 608k | if (MVM_is_null(tc, obj) || !IS_CONCRETE(obj)) { |
328 | 0 | return 0; |
329 | 0 | } |
330 | 608k | |
331 | 608k | /* Otherwise, guess something appropriate. */ |
332 | 608k | else { |
333 | 608k | const MVMStorageSpec *ss = REPR(obj)->get_storage_spec(tc, STABLE(obj)); |
334 | 608k | if (ss->can_box & MVM_STORAGE_SPEC_CAN_BOX_INT) |
335 | 540k | return REPR(obj)->box_funcs.get_int(tc, STABLE(obj), obj, OBJECT_BODY(obj)); |
336 | 68.0k | else if (ss->can_box & MVM_STORAGE_SPEC_CAN_BOX_NUM) |
337 | 68.0k | return (MVMint64)REPR(obj)->box_funcs.get_num(tc, STABLE(obj), obj, OBJECT_BODY(obj)); |
338 | 0 | else if (ss->can_box & MVM_STORAGE_SPEC_CAN_BOX_STR) |
339 | 0 | return MVM_coerce_s_i(tc, REPR(obj)->box_funcs.get_str(tc, STABLE(obj), obj, OBJECT_BODY(obj))); |
340 | 0 | else if (REPR(obj)->ID == MVM_REPR_ID_VMArray) |
341 | 0 | return REPR(obj)->elems(tc, STABLE(obj), obj, OBJECT_BODY(obj)); |
342 | 0 | else if (REPR(obj)->ID == MVM_REPR_ID_MVMHash) |
343 | 0 | return REPR(obj)->elems(tc, STABLE(obj), obj, OBJECT_BODY(obj)); |
344 | 0 | else |
345 | 0 | MVM_exception_throw_adhoc(tc, "cannot intify this"); |
346 | 608k | } |
347 | 608k | } |
348 | | |
349 | | /* concatenating with "" ensures that only literal strings are accepted as argument. */ |
350 | | #define STR_WITH_LEN(str) ("" str ""), (sizeof(str) - 1) |
351 | | |
352 | 5.39k | MVMObject * MVM_radix(MVMThreadContext *tc, MVMint64 radix, MVMString *str, MVMint64 offset, MVMint64 flag) { |
353 | 5.39k | MVMObject *result; |
354 | 5.39k | MVMint64 zvalue = 0; |
355 | 5.39k | MVMint64 zbase = 1; |
356 | 5.39k | MVMint64 chars = MVM_string_graphs(tc, str); |
357 | 5.39k | MVMint64 value = zvalue; |
358 | 5.39k | MVMint64 base = zbase; |
359 | 5.39k | MVMint64 pos = -1; |
360 | 5.39k | MVMuint16 neg = 0; |
361 | 5.39k | MVMint64 ch; |
362 | 5.39k | |
363 | 5.39k | if (radix > 36) { |
364 | 0 | MVM_exception_throw_adhoc(tc, "Cannot convert radix of %"PRId64" (max 36)", radix); |
365 | 0 | } |
366 | 5.39k | |
367 | 5.31k | ch = (offset < chars) ? MVM_string_get_grapheme_at_nocheck(tc, str, offset) : 0; |
368 | 5.39k | if ((flag & 0x02) && (ch == '+' || ch == '-')) { |
369 | 4 | neg = (ch == '-'); |
370 | 4 | offset++; |
371 | 4 | ch = (offset < chars) ? MVM_string_get_grapheme_at_nocheck(tc, str, offset) : 0; |
372 | 4 | } |
373 | 5.39k | |
374 | 7.88k | while (offset < chars) { |
375 | 7.80k | if (ch >= '0' && ch <= '9') ch = ch - '0'; /* fast-path for ASCII 0..9 */ |
376 | 208 | else if (ch >= 'a' && ch <= 'z') ch = ch - 'a' + 10; |
377 | 17 | else if (ch >= 'A' && ch <= 'Z') ch = ch - 'A' + 10; |
378 | 12 | else if (ch >= 0xFF21 && ch <= 0xFF3A) ch = ch - 0xFF21 + 10; /* uppercase fullwidth */ |
379 | 12 | else if (ch >= 0xFF41 && ch <= 0xFF5A) ch = ch - 0xFF41 + 10; /* lowercase fullwidth */ |
380 | 12 | else if (ch > 0 && MVM_unicode_codepoint_get_property_int(tc, ch, MVM_UNICODE_PROPERTY_NUMERIC_TYPE) |
381 | 12 | == MVM_UNICODE_PVALUE_Numeric_Type_DECIMAL) { |
382 | 0 | /* as of Unicode 9.0.0, characters with the 'de' Numeric Type (and are |
383 | 0 | * thus also of General Category Nd, since 4.0.0) are contiguous |
384 | 0 | * sequences of 10 chars whose Numeric Values ascend from 0 through 9. |
385 | 0 | */ |
386 | 0 |
|
387 | 0 | /* the string returned for NUMERIC_VALUE_NUMERATOR contains an integer |
388 | 0 | * value. We can use numerator because they all are from 0-9 and have |
389 | 0 | * denominator of 1 */ |
390 | 0 | ch = fast_atoi(MVM_unicode_codepoint_get_property_cstr(tc, ch, MVM_UNICODE_PROPERTY_NUMERIC_VALUE_NUMERATOR)); |
391 | 0 | } |
392 | 12 | else break; |
393 | 7.79k | if (ch >= radix) break; |
394 | 7.71k | zvalue = zvalue * radix + ch; |
395 | 7.71k | zbase = zbase * radix; |
396 | 7.71k | offset++; pos = offset; |
397 | 7.71k | if (ch != 0 || !(flag & 0x04)) { value=zvalue; base=zbase; } |
398 | 7.71k | if (offset >= chars) break; |
399 | 2.49k | ch = MVM_string_get_grapheme_at_nocheck(tc, str, offset); |
400 | 2.49k | if (ch != '_') continue; |
401 | 3 | offset++; |
402 | 3 | if (offset >= chars) break; |
403 | 3 | ch = MVM_string_get_grapheme_at_nocheck(tc, str, offset); |
404 | 3 | } |
405 | 5.39k | |
406 | 5.39k | if (neg || flag & 0x01) { value = -value; } |
407 | 5.39k | |
408 | 5.39k | /* initialize the object */ |
409 | 5.39k | result = MVM_repr_alloc_init(tc, MVM_hll_current(tc)->slurpy_array_type); |
410 | 5.39k | MVMROOT(tc, result, { |
411 | 5.39k | MVMObject *box_type = MVM_hll_current(tc)->int_box_type; |
412 | 5.39k | MVMROOT(tc, box_type, { |
413 | 5.39k | MVMObject *boxed = MVM_repr_box_int(tc, box_type, value); |
414 | 5.39k | MVM_repr_push_o(tc, result, boxed); |
415 | 5.39k | boxed = MVM_repr_box_int(tc, box_type, base); |
416 | 5.39k | MVM_repr_push_o(tc, result, boxed); |
417 | 5.39k | boxed = MVM_repr_box_int(tc, box_type, pos); |
418 | 5.39k | MVM_repr_push_o(tc, result, boxed); |
419 | 5.39k | }); |
420 | 5.39k | }); |
421 | 5.39k | |
422 | 5.39k | return result; |
423 | 5.39k | } |
424 | | |
425 | | |
426 | | void MVM_box_int(MVMThreadContext *tc, MVMint64 value, MVMObject *type, |
427 | 2.69M | MVMRegister * dst) { |
428 | 2.69M | MVMObject *box = MVM_intcache_get(tc, type, value); |
429 | 2.69M | if (box == 0) { |
430 | 441k | box = REPR(type)->allocate(tc, STABLE(type)); |
431 | 441k | if (REPR(box)->initialize) |
432 | 366 | REPR(box)->initialize(tc, STABLE(box), box, OBJECT_BODY(box)); |
433 | 441k | REPR(box)->box_funcs.set_int(tc, STABLE(box), box, |
434 | 441k | OBJECT_BODY(box), value); |
435 | 441k | } |
436 | 2.69M | dst->o = box; |
437 | 2.69M | } |
438 | | |
439 | | void MVM_box_num(MVMThreadContext *tc, MVMnum64 value, MVMObject *type, |
440 | 194k | MVMRegister * dst) { |
441 | 194k | MVMObject *box = REPR(type)->allocate(tc, STABLE(type)); |
442 | 194k | if (REPR(box)->initialize) |
443 | 4 | REPR(box)->initialize(tc, STABLE(box), box, OBJECT_BODY(box)); |
444 | 194k | REPR(box)->box_funcs.set_num(tc, STABLE(box), box, |
445 | 194k | OBJECT_BODY(box), value); |
446 | 194k | dst->o = box; |
447 | 194k | |
448 | 194k | } |
449 | | |
450 | | void MVM_box_str(MVMThreadContext *tc, MVMString *value, MVMObject *type, |
451 | 1.49M | MVMRegister * dst) { |
452 | 1.49M | MVMObject *box; |
453 | 1.49M | MVMROOT(tc, value, { |
454 | 1.49M | box = REPR(type)->allocate(tc, STABLE(type)); |
455 | 1.49M | if (REPR(box)->initialize) |
456 | 1.49M | REPR(box)->initialize(tc, STABLE(box), box, OBJECT_BODY(box)); |
457 | 1.49M | REPR(box)->box_funcs.set_str(tc, STABLE(box), box, |
458 | 1.49M | OBJECT_BODY(box), value); |
459 | 1.49M | dst->o = box; |
460 | 1.49M | }); |
461 | 1.49M | } |
462 | | |
463 | | void MVM_box_uint(MVMThreadContext *tc, MVMuint64 value, MVMObject *type, |
464 | 0 | MVMRegister * dst) { |
465 | 0 | MVMObject *box = REPR(type)->allocate(tc, STABLE(type)); |
466 | 0 | if (REPR(box)->initialize) |
467 | 0 | REPR(box)->initialize(tc, STABLE(box), box, OBJECT_BODY(box)); |
468 | 0 | REPR(box)->box_funcs.set_uint(tc, STABLE(box), box, OBJECT_BODY(box), value); |
469 | 0 | dst->o = box; |
470 | 0 | } |