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