Skip to content

Commit bb5f116

Browse files
committed
bigint variant of the nqp radix op.
1 parent 302cc17 commit bb5f116

File tree

1 file changed

+96
-0
lines changed

1 file changed

+96
-0
lines changed

src/ops/nqp_bigint.ops

Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -219,3 +219,99 @@ inline op nqp_bigint_bnot(out PMC, in PMC) :base_cor {
219219
mp_add_d(a, 1, b);
220220
mp_neg(b, b);
221221
}
222+
223+
224+
/*
225+
226+
=item nqp_bigint_radix(out, radix, str, pos, flag, type)
227+
228+
Convert string $3 into a number starting at offset $4 and using radix $2.
229+
The result of the conversion returns an object of type $6, which is either
230+
a bigint or some type that boxes one.
231+
232+
The $5 flags is a bitmask that modifies the parse and/or result:
233+
0x01: negate the result (useful if you've already parsed a minus)
234+
0x02: parse a leading +/- and negate the result on -
235+
0x04: parse trailing zeroes but do not include in result
236+
(for parsing values after a decimal point)
237+
238+
=cut
239+
240+
*/
241+
242+
inline op nqp_radix(out PMC, in INT, in STR, in INT, in INT, in PMC) :base_core {
243+
PMC *out;
244+
INTVAL radix = $2;
245+
STRING *str = $3;
246+
INTVAL zpos = $4;
247+
INTVAL flags = $5;
248+
INTVAL chars = Parrot_str_length(interp, str);
249+
int neg = 0;
250+
INTVAL ch;
251+
mp_int zvalue;
252+
mp_int zbase;
253+
PMC *value_obj;
254+
mp_int *value;
255+
PMC *base_obj;
256+
mp_int *base;
257+
PMC *pos_obj;
258+
INTVAL pos = -1;
259+
260+
if (radix > 36) {
261+
Parrot_ex_throw_from_c_args(interp, NULL, EXCEPTION_INVALID_OPERATION,
262+
"Cannot convert radix of %d (max 36)", radix);
263+
}
264+
265+
mp_init(&zvalue);
266+
mp_init(&zbase);
267+
mp_set_int(&zbase, 1);
268+
269+
value_obj = REPR($6)->allocate(interp, STABLE($6));
270+
REPR(value_obj)->initialize(interp, STABLE(value_obj), OBJECT_BODY(value_obj));
271+
value = get_bigint(interp, value_obj);
272+
273+
base_obj = REPR($6)->allocate(interp, STABLE($6));
274+
REPR(base_obj)->initialize(interp, STABLE(base_obj), OBJECT_BODY(base_obj));
275+
base = get_bigint(interp, base_obj);
276+
mp_set_int(base, 1);
277+
278+
ch = (zpos < chars) ? STRING_ord(interp, str, zpos) : 0;
279+
if ((flags & 0x02) && (ch == '+' || ch == '-')) {
280+
neg = (ch == '-');
281+
zpos++;
282+
ch = (zpos < chars) ? STRING_ord(interp, str, zpos) : 0;
283+
}
284+
while (zpos < chars) {
285+
if (ch >= '0' && ch <= '9') ch = ch - '0';
286+
else if (ch >= 'a' && ch <= 'z') ch = ch - 'a' + 10;
287+
else if (ch >= 'A' && ch <= 'Z') ch = ch - 'A' + 10;
288+
else break;
289+
if (ch >= radix) break;
290+
mp_mul_d(&zvalue, radix, &zvalue);
291+
mp_add_d(&zvalue, ch, &zvalue);
292+
mp_mul_d(&zbase, radix, &zbase);
293+
zpos++; pos = zpos;
294+
if (ch != 0 || !(flags & 0x04)) { mp_copy(&zvalue, value); mp_copy(&zbase, base); }
295+
if (zpos >= chars) break;
296+
ch = STRING_ord(interp, str, zpos);
297+
if (ch != '_') continue;
298+
zpos++;
299+
if (zpos >= chars) break;
300+
ch = STRING_ord(interp, str, zpos);
301+
}
302+
303+
mp_clear(&zvalue);
304+
mp_clear(&zbase);
305+
306+
pos_obj = REPR($6)->allocate(interp, STABLE($6));
307+
REPR(pos_obj)->initialize(interp, STABLE(pos_obj), OBJECT_BODY(pos_obj));
308+
REPR(pos_obj)->set_int(interp, STABLE(pos_obj), OBJECT_BODY(pos_obj), pos);
309+
310+
if (neg || flags & 0x01) { mp_neg(value, value); }
311+
out = pmc_new(interp, enum_class_FixedPMCArray);
312+
VTABLE_set_integer_native(interp, out, 3);
313+
VTABLE_set_pmc_keyed_int(interp, out, 0, value_obj);
314+
VTABLE_set_pmc_keyed_int(interp, out, 1, base_obj);
315+
VTABLE_set_pmc_keyed_int(interp, out, 2, pos_obj);
316+
$1 = out;
317+
}

0 commit comments

Comments
 (0)