Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
tree: 8a0aaf9e72
Fetching contributors…

Cannot retrieve contributors at this time

1448 lines (1052 sloc) 38.34 kb
/*
Copyright (C) 2001-2007, The Perl Foundation.
$Id$
=head1 NAME
src/pmc/scalar.pmc - Scalar Abstract Superclass
=head1 DESCRIPTION
These are the vtable functions for the scalar base PMC class
=head2 Methods
=over 4
=cut
*/
#include "parrot/parrot.h"
/* XXX This should be declared in a .h file somewhere */
extern PMC *
Parrot_BigInt_bitwise_shl_int(PARROT_INTERP, PMC *pmc, INTVAL value, PMC *dest);
static PMC *
bitwise_left_shift_internal(PARROT_INTERP, PMC *self,
PMC *dest, INTVAL shift_amount)
{
/* This handles both left and right shifts; the sign of shift_amount
controls the direction, shifting left if positive and right if negative.
If we get an error (which can only happen for left shifts) and
PARROT_ERRORS_OVERFLOW_FLAG is set, then we throw an error, else the
destination is promoted to a BigInt before shifting. If dest == self,
then the shift is done in place. */
const INTVAL base = VTABLE_get_integer(interp, self);
INTVAL result = 0;
int overflow_p = 0;
/* Compute the shift. */
if (shift_amount >= 8*INTVAL_SIZE) {
/* Extreme left shift; no need to do an integer shift first. */
overflow_p = 1;
}
else if (shift_amount >= 0) {
/* Left shift. */
result = base << shift_amount;
overflow_p = (result >> shift_amount) != base;
}
else if (shift_amount > -8*INTVAL_SIZE) {
/* Right shift. By definition, this can never overflow. */
result = base >> -shift_amount;
}
else {
/* Extreme right shift. */
result = 0;
}
/* Store the result. */
if (! overflow_p) {
if (!dest)
dest = pmc_new(interp, self->vtable->base_type);
VTABLE_set_integer_native(interp, dest, result);
}
else if (PARROT_ERRORS_test(interp, PARROT_ERRORS_OVERFLOW_FLAG)) {
real_exception(interp, NULL, ERR_OVERFLOW, "Integer overflow");
}
else {
/* Overflow; must promote dest to BigInt, and do a BigInt shift. */
if (dest)
VTABLE_morph(interp, dest, enum_class_BigInt);
else {
/* Arguably, we should throw an error here if dest == self and self
* is not a numeric type. However, that would require a firmer
* definition of "numeric type."
*/
dest = pmc_new(interp, enum_class_BigInt);
}
VTABLE_set_integer_native(interp, dest, base);
Parrot_BigInt_bitwise_shl_int(interp, dest, shift_amount, dest);
}
return dest;
}
pmclass scalar abstract noinit {
/*
=item C<void morph(INTVAL type)>
Morphs the scalar to the specified type.
=cut
*/
void morph(INTVAL type) {
if (SELF->vtable->base_type == type)
return;
pmc_reuse(INTERP, SELF, type, 0);
}
/*
=item C<void assign_pmc(PMC *value)>
Sets the PMC C<*value>, calling the appropriate C<set_*> method
according to the type of C<*value>.
=cut
*/
void assign_pmc(PMC *value) {
STRING * const s_int = CONST_STRING(INTERP, "Integer");
STRING *s_num;
STRING *s_str;
if (SELF->vtable->base_type == enum_class_Boolean) {
/* doesn't morph */
DYNSELF.morph(value->vtable->base_type);
}
if (value->vtable->base_type == enum_class_Undef ||
value->vtable->base_type == enum_class_Undef) {
DYNSELF.morph(value->vtable->base_type);
return;
}
if (VTABLE_isa(INTERP, value, s_int)) {
const INTVAL v = VTABLE_get_integer(INTERP, value);
DYNSELF.set_integer_native(v);
return;
}
s_num = CONST_STRING(INTERP, "Float");
if (VTABLE_isa(INTERP, value, s_num)) {
const FLOATVAL v = VTABLE_get_number(INTERP, value);
DYNSELF.set_number_native(v);
return;
}
s_str = CONST_STRING(INTERP, "String");
if (VTABLE_isa(INTERP, value, s_str)) {
STRING * const v = VTABLE_get_string(INTERP, value);
DYNSELF.set_string_native(v);
return;
}
DYNSELF.morph(enum_class_Ref);
DYNSELF.set_pmc(value);
}
/*
=item C<PMC *clone()>
Creates and returns a clone of the scalar.
=cut
*/
PMC *clone() {
PMC * const dest = pmc_new(INTERP, SELF->vtable->base_type);
memcpy(&PMC_union(dest), &PMC_union(SELF), sizeof (UnionVal));
return dest;
}
/*
=back
=head1 Mathematical Methods
=over 4
=item C<PMC *subtract(PMC *value, PMC *dest)>
=cut
*/
/*
=item C<void add(PMC *value, PMC *dest)>
=item C<void add_int(INTVAL value, PMC *dest)>
=item C<void add_float(FLOATVAL value, PMC *dest)>
Adds C<value> to the number and returns the result in C<*dest>.
If C<dest> is NULL it's created.
=item C<void i_add(PMC *value)>
=item C<void i_add(INTVAL value)>
=item C<void i_add(FLOATVAL value)>
Adds C<value> to C<SELF> inplace.
=cut
*/
PMC *add(PMC *value, PMC *dest) {
MMD_Complex: {
const FLOATVAL a = DYNSELF.get_number();
if (dest)
VTABLE_morph(INTERP, dest, value->vtable->base_type);
else
dest = pmc_new(INTERP, value->vtable->base_type);
VTABLE_set_number_native(INTERP, dest,
a + VTABLE_get_number_keyed_int(INTERP, value, 0));
VTABLE_set_number_keyed_int(INTERP, dest, 1,
VTABLE_get_number_keyed_int(INTERP, value, 1));
return dest;
}
MMD_DEFAULT: {
if (!dest)
dest = pmc_new(INTERP, SELF->vtable->base_type);
VTABLE_set_number_native(INTERP, dest,
DYNSELF.get_number() + VTABLE_get_number(INTERP, value));
return dest;
}
}
PMC *add_int(INTVAL value, PMC *dest) {
if (!dest)
dest = pmc_new(INTERP, SELF->vtable->base_type);
VTABLE_set_number_native(INTERP, dest,
DYNSELF.get_number() + (FLOATVAL)value);
return dest;
}
PMC *add_float(FLOATVAL value, PMC *dest) {
if (!dest)
dest = pmc_new(INTERP, SELF->vtable->base_type);
VTABLE_set_number_native(INTERP, dest,
DYNSELF.get_number() + value);
return dest;
}
void i_add(PMC *value) {
MMD_Complex: {
const FLOATVAL a = DYNSELF.get_number();
VTABLE_morph(INTERP, SELF, value->vtable->base_type);
VTABLE_set_number_native(INTERP, SELF,
a + VTABLE_get_number_keyed_int(INTERP, value, 0));
VTABLE_set_number_keyed_int(INTERP, SELF, 1,
VTABLE_get_number_keyed_int(INTERP, value, 1));
}
MMD_DEFAULT: {
VTABLE_set_number_native(INTERP, SELF,
DYNSELF.get_number() + VTABLE_get_number(INTERP, value));
}
}
void i_add_int(INTVAL value) {
VTABLE_set_number_native(INTERP, SELF,
DYNSELF.get_number() + (FLOATVAL)value);
}
void i_add_float(FLOATVAL value) {
VTABLE_set_number_native(INTERP, SELF,
DYNSELF.get_number() + value);
}
/*
=item C<PMC *subtract(PMC *value, PMC *dest)>
=item C<PMC *subtract_int(INTVAL value, PMC *dest)>
=item C<PMC *subtract_float(FLOATVAL value, PMC *dest)>
Subtracts C<value> from the number and returns the result in C<*dest>.
If C<dest> doesn't exist a new C<Float> is created.
=item C<void i_subtract(PMC *value)>
=item C<void i_subtract_int(INTVAL value)>
=item C<void i_subtract_float(FLOATVAL value)>
Subtracts C<value> from C<SELF> inplace.
=cut
*/
PMC *subtract(PMC *value, PMC *dest) {
MMD_Complex: {
const FLOATVAL a = DYNSELF.get_number();
if (dest)
VTABLE_morph(INTERP, dest, value->vtable->base_type);
else
dest = pmc_new(INTERP, value->vtable->base_type);
VTABLE_set_number_native(INTERP, dest,
a - VTABLE_get_number_keyed_int(INTERP, value, 0));
VTABLE_set_number_keyed_int(INTERP, dest, 1,
-VTABLE_get_number_keyed_int(INTERP, value, 1));
return dest;
}
MMD_DEFAULT: {
if (!dest)
dest = pmc_new(INTERP, SELF->vtable->base_type);
VTABLE_set_number_native(INTERP, dest,
DYNSELF.get_number() - VTABLE_get_number(INTERP, value));
return dest;
}
}
PMC *subtract_int(INTVAL value, PMC *dest) {
if (!dest)
dest = pmc_new(INTERP, SELF->vtable->base_type);
VTABLE_set_number_native(INTERP, dest,
DYNSELF.get_number() - (FLOATVAL)value);
return dest;
}
PMC *subtract_float(FLOATVAL value, PMC *dest) {
if (!dest)
dest = pmc_new(INTERP, SELF->vtable->base_type);
VTABLE_set_number_native(INTERP, dest,
DYNSELF.get_number() - value);
return dest;
}
void i_subtract(PMC *value) {
MMD_Complex: {
const FLOATVAL a = DYNSELF.get_number();
VTABLE_morph(INTERP, SELF, value->vtable->base_type);
VTABLE_set_number_native(INTERP, SELF,
a - VTABLE_get_number_keyed_int(INTERP, value, 0));
VTABLE_set_number_keyed_int(INTERP, SELF, 1,
-VTABLE_get_number_keyed_int(INTERP, value, 1));
}
MMD_DEFAULT: {
VTABLE_set_number_native(INTERP, SELF,
DYNSELF.get_number() - VTABLE_get_number(INTERP, value));
}
}
void i_subtract_int(INTVAL value) {
VTABLE_set_number_native(INTERP, SELF,
DYNSELF.get_number() - (FLOATVAL)value);
}
void i_subtract_float(FLOATVAL value) {
VTABLE_set_number_native(INTERP, SELF,
DYNSELF.get_number() - value);
}
/*
=item C<PMC *multiply(PMC *value, PMC *dest)>
=item C<PMC *multiply_int(INTVAL value, PMC *dest)>
=item C<PMC *multiply_float(FLOATVAL value, PMC *dest)>
Multiplies the number by C<value> and returns the result in C<*dest>.
=cut
*/
PMC *multiply(PMC *value, PMC *dest) {
MMD_Complex: {
real_exception(INTERP, NULL, E_NotImplementedError,
"TODO mul<Float, Complex>");
}
MMD_DEFAULT: {
if (!dest)
dest = pmc_new(INTERP, SELF->vtable->base_type);
VTABLE_set_number_native(INTERP, dest,
DYNSELF.get_number() * VTABLE_get_number(INTERP, value));
return dest;
}
}
PMC *multiply_int(INTVAL value, PMC *dest) {
if (!dest)
dest = pmc_new(INTERP, SELF->vtable->base_type);
VTABLE_set_number_native(INTERP, dest,
DYNSELF.get_number() * value);
return dest;
}
PMC *multiply_float(FLOATVAL value, PMC *dest) {
if (!dest)
dest = pmc_new(INTERP, SELF->vtable->base_type);
VTABLE_set_number_native(INTERP, dest,
DYNSELF.get_number() * value);
return dest;
}
void i_multiply(PMC *value) {
MMD_Complex: {
real_exception(INTERP, NULL, E_NotImplementedError,
"TODO i_mul<Float, Complex>");
}
MMD_DEFAULT: {
VTABLE_set_number_native(INTERP, SELF,
DYNSELF.get_number() * VTABLE_get_number(INTERP, value));
}
}
void i_multiply_int(INTVAL value) {
VTABLE_set_number_native(INTERP, SELF,
DYNSELF.get_number() * (FLOATVAL)value);
}
void i_multiply_float(FLOATVAL value) {
VTABLE_set_number_native(INTERP, SELF,
DYNSELF.get_number() * value);
}
/*
=item C<PMC *divide(PMC *value, PMC *dest)>
=item C<PMC *divide_int(INTVAL value, PMC *dest)>
=item C<PMC *divide_float(FLOATVAL value, PMC *dest)>
Divides the number by C<value> and returns the result in C<*dest>.
=item C<void i_divide(PMC *value)>
=item C<void i_divide_int(INTVAL value)>
=item C<void i_divide_float(FLOATVAL value)>
Divides C<SELF> by C<value> inplace.
=cut
*/
PMC *divide(PMC *value, PMC *dest) {
FLOATVAL d = VTABLE_get_number(INTERP, value);
if (FLOAT_IS_ZERO(d))
real_exception(INTERP, NULL, E_ZeroDivisionError,
"float division by zero");
if (!dest)
dest = pmc_new(INTERP, SELF->vtable->base_type);
VTABLE_set_number_native(INTERP, dest, DYNSELF.get_number() / d);
return dest;
}
PMC *divide_int(INTVAL value, PMC *dest) {
if (value == 0)
real_exception(INTERP, NULL, E_ZeroDivisionError,
"float division by zero");
if (!dest)
dest = pmc_new(INTERP, SELF->vtable->base_type);
VTABLE_set_number_native(INTERP, dest, DYNSELF.get_number() / value);
return dest;
}
PMC *divide_float(FLOATVAL value, PMC *dest) {
if (FLOAT_IS_ZERO(value))
real_exception(INTERP, NULL, E_ZeroDivisionError,
"float division by zero");
if (!dest)
dest = pmc_new(INTERP, SELF->vtable->base_type);
VTABLE_set_number_native(INTERP, dest, DYNSELF.get_number() / value);
return dest;
}
void i_divide(PMC *value) {
FLOATVAL d = VTABLE_get_number(INTERP, value);
if (FLOAT_IS_ZERO(d))
real_exception(INTERP, NULL, E_ZeroDivisionError,
"float division by zero");
VTABLE_set_number_native(INTERP, SELF, DYNSELF.get_number() / d);
}
void i_divide_int(INTVAL value) {
if (value == 0)
real_exception(INTERP, NULL, E_ZeroDivisionError,
"float division by zero");
VTABLE_set_number_native(INTERP, SELF, DYNSELF.get_number() / value);
}
void i_divide_float(FLOATVAL value) {
if (FLOAT_IS_ZERO(value))
real_exception(INTERP, NULL, E_ZeroDivisionError,
"float division by zero");
VTABLE_set_number_native(INTERP, SELF, DYNSELF.get_number() / value);
}
/*
=item C<PMC *floor_divide(PMC *value, PMC *dest)>
=item C<PMC *floor_divide_int(INTVAL value, PMC *dest)>
=item C<PMC *floor_divide_float(FLOATVAL value, PMC *dest)>
Divides the number by C<value> and returns the result in C<*dest>.
=item C<void i_floor_divide(PMC *value)>
=item C<void i_floor_divide_int(INTVAL value)>
=item C<void i_floor_divide_float(FLOATVAL value)>
Divides C<SELF> by C<value> inplace.
=cut
*/
PMC *floor_divide(PMC *value, PMC *dest) {
FLOATVAL d = VTABLE_get_number(INTERP, value);
if (FLOAT_IS_ZERO(d))
real_exception(INTERP, NULL, E_ZeroDivisionError,
"float division by zero");
if (!dest)
dest = pmc_new(INTERP, SELF->vtable->base_type);
VTABLE_set_number_native(INTERP, dest,
floor(DYNSELF.get_number() / d));
return dest;
}
PMC *floor_divide_int(INTVAL value, PMC *dest) {
if (value == 0)
real_exception(INTERP, NULL, E_ZeroDivisionError,
"float division by zero");
if (!dest)
dest = pmc_new(INTERP, SELF->vtable->base_type);
VTABLE_set_number_native(INTERP, dest,
floor(DYNSELF.get_number() / value));
return dest;
}
PMC *floor_divide_float(FLOATVAL value, PMC *dest) {
if (FLOAT_IS_ZERO(value))
real_exception(INTERP, NULL, E_ZeroDivisionError,
"float division by zero");
if (!dest)
dest = pmc_new(INTERP, SELF->vtable->base_type);
VTABLE_set_number_native(INTERP, dest,
floor(DYNSELF.get_number() / value));
return dest;
}
void i_floor_divide(PMC *value) {
FLOATVAL d = VTABLE_get_number(INTERP, value);
if (FLOAT_IS_ZERO(d))
real_exception(INTERP, NULL, E_ZeroDivisionError,
"float division by zero");
VTABLE_set_number_native(INTERP, SELF,
floor(DYNSELF.get_number() / d));
}
void i_floor_divide_int(INTVAL value) {
if (value == 0)
real_exception(INTERP, NULL, E_ZeroDivisionError,
"float division by zero");
VTABLE_set_number_native(INTERP, SELF,
floor(DYNSELF.get_number() / value));
}
void i_floor_divide_float(FLOATVAL value) {
if (FLOAT_IS_ZERO(value))
real_exception(INTERP, NULL, E_ZeroDivisionError,
"float division by zero");
VTABLE_set_number_native(INTERP, SELF,
floor(DYNSELF.get_number() / value));
}
/*
=item C<PMC *cmodulus(PMC *value, PMC *dest)>
=item C<PMC *cmodulus(INTVAL value, PMC *dest)>
=item C<PMC *cmodulus(FLOATVAL value, PMC *dest)>
Calculates the value of the number C-style C<mod> C<value> and returns
the result in C<dest>.
=item C<void i_cmodulus(PMC *value)>
=item C<void i_cmodulus(INTVAL value)>
=item C<void i_cmodulus(FLOATVAL value)>
Calculates the value of the number C-style C<mod> C<value> and returns
the result in C<dest>.
=cut
*/
PMC *cmodulus(PMC *value, PMC *dest) {
FLOATVAL d = VTABLE_get_number(INTERP, value);
if (FLOAT_IS_ZERO(d))
real_exception(INTERP, NULL, E_ZeroDivisionError,
"float cmodulus by zero");
if (!dest)
dest = pmc_new(INTERP, SELF->vtable->base_type);
VTABLE_set_number_native(INTERP, dest,
fmod(DYNSELF.get_number(), d));
return dest;
}
PMC *cmodulus_float(FLOATVAL value, PMC *dest) {
if (value == 0.0)
real_exception(INTERP, NULL, E_ZeroDivisionError,
"float cmodulus by zero");
if (!dest)
dest = pmc_new(INTERP, SELF->vtable->base_type);
VTABLE_set_number_native(INTERP, dest,
fmod(DYNSELF.get_number(), value));
return dest;
}
PMC *cmodulus_float(FLOATVAL value, PMC *dest) {
if (FLOAT_IS_ZERO(value))
real_exception(INTERP, NULL, E_ZeroDivisionError,
"float cmodulus by zero");
if (!dest)
dest = pmc_new(INTERP, SELF->vtable->base_type);
VTABLE_set_number_native(INTERP, dest,
fmod(DYNSELF.get_number(), value));
return dest;
}
void i_cmodulus(PMC *value) {
FLOATVAL d = VTABLE_get_number(INTERP, value);
if (FLOAT_IS_ZERO(d))
real_exception(INTERP, NULL, E_ZeroDivisionError,
"float cmodulus by zero");
VTABLE_set_number_native(INTERP, SELF,
fmod(DYNSELF.get_number() , d));
}
void i_cmodulus_int(INTVAL value) {
if (value == 0)
real_exception(INTERP, NULL, E_ZeroDivisionError,
"float cmodulus by zero");
VTABLE_set_number_native(INTERP, SELF,
fmod(DYNSELF.get_number() , value));
}
void i_cmodulus_float(FLOATVAL value) {
if (FLOAT_IS_ZERO(value))
real_exception(INTERP, NULL, E_ZeroDivisionError,
"float cmodulus by zero");
VTABLE_set_number_native(INTERP, SELF,
fmod(DYNSELF.get_number() , value));
}
/*
=item C<PMC *modulus(PMC *value, PMC *dest)>
=item C<PMC *modulus(INTVAL value, PMC *dest)>
=item C<PMC *modulus(FLOATVAL value, PMC *dest)>
Calculates the value of corrected C<mod> C<value> and returns
the result in C<dest>. See also ops/math.ops.
=item C<void i_modulus(PMC *value)>
=item C<void i_modulus(INTVAL value)>
=item C<void i_modulus(FLOATVAL value)>
Calculates modulus inplace
=cut
*/
PMC *modulus(PMC *value, PMC *dest) {
FLOATVAL d = VTABLE_get_number(INTERP, value);
if (FLOAT_IS_ZERO(d))
real_exception(INTERP, NULL, E_ZeroDivisionError,
"float modulus by zero");
if (!dest)
dest = pmc_new(INTERP, SELF->vtable->base_type);
VTABLE_set_number_native(INTERP, dest,
floatval_mod(DYNSELF.get_number(), d));
return dest;
}
PMC *modulus_int(INTVAL value, PMC *dest) {
if (value == 0)
real_exception(INTERP, NULL, E_ZeroDivisionError,
"float modulus by zero");
if (!dest)
dest = pmc_new(INTERP, SELF->vtable->base_type);
VTABLE_set_number_native(INTERP, dest,
floatval_mod(DYNSELF.get_number(), value));
return dest;
}
PMC *modulus_float(FLOATVAL value, PMC *dest) {
if (FLOAT_IS_ZERO(value))
real_exception(INTERP, NULL, E_ZeroDivisionError,
"float modulus by zero");
if (!dest)
dest = pmc_new(INTERP, SELF->vtable->base_type);
VTABLE_set_number_native(INTERP, dest,
floatval_mod(DYNSELF.get_number(), value));
return dest;
}
void i_modulus(PMC *value) {
FLOATVAL d = VTABLE_get_number(INTERP, value);
if (FLOAT_IS_ZERO(d))
real_exception(INTERP, NULL, E_ZeroDivisionError,
"float modulus by zero");
VTABLE_set_number_native(INTERP, SELF,
floatval_mod(DYNSELF.get_number() , d));
}
void i_modulus_int(INTVAL value) {
if (value == 0)
real_exception(INTERP, NULL, E_ZeroDivisionError,
"float modulus by zero");
VTABLE_set_number_native(INTERP, SELF,
floatval_mod(DYNSELF.get_number() , value));
}
void i_modulus_float(FLOATVAL value) {
if (FLOAT_IS_ZERO(value))
real_exception(INTERP, NULL, E_ZeroDivisionError,
"float modulus by zero");
VTABLE_set_number_native(INTERP, SELF,
floatval_mod(DYNSELF.get_number() , value));
}
/*
=item C<PMC *pow(PMC *value, PMC *dest)>
=item C<PMC *pow_int(INTVAL value, PMC *dest)>
=item C<PMC *pow_float(FLOATVAL value, PMC *dest)>
Calculates C<SELF pow value> and returns
the result in C<dest>. See also ops/math.ops.
=item C<void i_pow(PMC *value)>
=item C<void i_pow_int(INTVAL value)>
=item C<void i_pow_float(FLOATVAL value)>
Calculates pow inplace
=cut
*/
PMC *pow(PMC *value, PMC *dest) {
const FLOATVAL d = VTABLE_get_number(INTERP, value);
if (!dest)
dest = pmc_new(INTERP, SELF->vtable->base_type);
VTABLE_set_number_native(INTERP, dest,
pow(DYNSELF.get_number(), d));
return dest;
}
PMC *pow_int(INTVAL value, PMC *dest) {
if (!dest)
dest = pmc_new(INTERP, SELF->vtable->base_type);
VTABLE_set_number_native(INTERP, dest,
pow(DYNSELF.get_number(), value));
return dest;
}
PMC *pow_float(FLOATVAL value, PMC *dest) {
if (!dest)
dest = pmc_new(INTERP, SELF->vtable->base_type);
VTABLE_set_number_native(INTERP, dest,
pow(DYNSELF.get_number(), value));
return dest;
}
void i_pow(PMC *value) {
const FLOATVAL d = VTABLE_get_number(INTERP, value);
VTABLE_set_number_native(INTERP, SELF,
pow(DYNSELF.get_number(), d));
}
void i_pow_int(INTVAL value) {
VTABLE_set_number_native(INTERP, SELF,
pow(DYNSELF.get_number(), value));
}
void i_pow_float(FLOATVAL value) {
VTABLE_set_number_native(INTERP, SELF,
pow(DYNSELF.get_number(), value));
}
/*
=item C<PMC *neg(PMC *dest)>
=item C<void i_neg()>
Set C<dest> to the negated value of C<SELF>.
=cut
*/
PMC *neg(PMC *dest) {
const INTVAL a = -DYNSELF.get_integer();
if (!dest)
dest = pmc_new(INTERP, SELF->vtable->base_type);
VTABLE_set_integer_native(INTERP, dest, a);
return dest;
}
void i_neg() {
VTABLE_set_integer_native(INTERP, SELF, -DYNSELF.get_integer());
}
/*
=back
=head2 Bitwise Methods
=over 4
=item C<PMC *bitwise_or(PMC *value, PMC *dest)>
=item C<PMC *bitwise_or_int(INTVAL value, PMC *dest)>
Returns in C<*dest> the bitwise C<OR> of the scalar and C<value>.
=item C<void i_bitwise_or(PMC *value)>
=item C<void i_bitwise_or_int(INTVAL value)>
Inplace bitwise or.
=cut
*/
PMC *bitwise_or(PMC *value, PMC *dest) {
const INTVAL result = DYNSELF.get_integer() | VTABLE_get_integer(INTERP, value);
if (!dest)
dest = pmc_new(INTERP, SELF->vtable->base_type);
VTABLE_set_integer_native(INTERP, dest, result);
return dest;
}
PMC *bitwise_or_int(INTVAL value, PMC *dest) {
const INTVAL result = DYNSELF.get_integer() | value;
if (!dest)
dest = pmc_new(INTERP, SELF->vtable->base_type);
VTABLE_set_integer_native(INTERP, dest, result);
return dest;
}
void i_bitwise_or(PMC *value) {
const INTVAL result = DYNSELF.get_integer() | VTABLE_get_integer(INTERP, value);
DYNSELF.set_integer_native(result);
}
void i_bitwise_or_int(INTVAL value) {
const INTVAL result = DYNSELF.get_integer() | value;
DYNSELF.set_integer_native(result);
}
/*
=item C<PMC *bitwise_and(PMC *value, PMC *dest)>
=item C<PMC *bitwise_and_int(INTVAL value, PMC *dest)>
Returns in C<*dest> the bitwise C<AND> of the scalar and C<value>.
=item C<void i_bitwise_and(PMC *value)>
=item C<void i_bitwise_and_int(INTVAL value)>
Inplace bitwise and.
=cut
*/
PMC *bitwise_and(PMC *value, PMC *dest) {
const INTVAL result = DYNSELF.get_integer() & VTABLE_get_integer(INTERP, value);
if (!dest)
dest = pmc_new(INTERP, SELF->vtable->base_type);
VTABLE_set_integer_native(INTERP, dest, result);
return dest;
}
PMC *bitwise_and_int(INTVAL value, PMC *dest) {
const INTVAL result = DYNSELF.get_integer() & value;
if (!dest)
dest = pmc_new(INTERP, SELF->vtable->base_type);
VTABLE_set_integer_native(INTERP, dest, result);
return dest;
}
void i_bitwise_and(PMC *value) {
const INTVAL result = DYNSELF.get_integer() & VTABLE_get_integer(INTERP, value);
DYNSELF.set_integer_native(result);
}
void i_bitwise_and_int(INTVAL value) {
const INTVAL result = DYNSELF.get_integer() & value;
DYNSELF.set_integer_native(result);
}
/*
=item C<void bitwise_xor(PMC *value, PMC *dest)>
=item C<void bitwise_xor_int(INTVAL value, PMC *dest)>
Returns in C<*dest> the bitwise C<XOR> of the scalar and C<*value>.
=item C<void i_bitwise_xor(PMC *value)>
=item C<void i_bitwise_xor_int(INTVAL value)>
Inplace bitwise and.
=cut
*/
PMC *bitwise_xor(PMC *value, PMC *dest) {
const INTVAL result = DYNSELF.get_integer() ^ VTABLE_get_integer(INTERP, value);
if (!dest)
dest = pmc_new(INTERP, SELF->vtable->base_type);
VTABLE_set_integer_native(INTERP, dest, result);
return dest;
}
PMC *bitwise_xor_int(INTVAL value, PMC *dest) {
const INTVAL result = DYNSELF.get_integer() ^ value;
if (!dest)
dest = pmc_new(INTERP, SELF->vtable->base_type);
VTABLE_set_integer_native(INTERP, dest, result);
return dest;
}
void i_bitwise_xor(PMC *value) {
const INTVAL result = DYNSELF.get_integer() ^ VTABLE_get_integer(INTERP, value);
DYNSELF.set_integer_native(result);
}
void i_bitwise_xor_int(INTVAL value) {
const INTVAL result = DYNSELF.get_integer() ^ value;
DYNSELF.set_integer_native(result);
}
/*
=item C<PMC *bitwise_not(PMC *dest)>
=item C<void i_bitwise_not()>
Returns in C<*dest> the bitwise negation of the scalar and C<value>.
=cut
*/
PMC *bitwise_not(PMC *dest) {
const INTVAL a = ~DYNSELF.get_integer();
if (!dest)
dest = pmc_new(INTERP, SELF->vtable->base_type);
VTABLE_set_integer_native(INTERP, dest, a);
return dest;
}
void i_bitwise_not() {
VTABLE_set_integer_native(INTERP, SELF, ~DYNSELF.get_integer());
}
/*
=item C<PMC *bitwise_shr(PMC *value, PMC *dest)>
=item C<PMC *bitwise_shr_int(INTVAL value, PMC *dest)>
Returns in C<*dest> the arithmetic shift right of the scalar by C<value>.
A negative C<value> shifts left.
The destination may become a C<BigInt> as a result (but only if the shift amount
is less than zero).
=item C<void i_bitwise_shr(PMC *value)>
=item C<void i_bitwise_shr_int(INTVAL value)>
Inplace shift right. A negative C<value> shifts left.
SELF may become a C<BigInt> as a result (but only if the shift amount is less
than zero).
=cut
*/
PMC *bitwise_shr(PMC *value, PMC *dest) {
return bitwise_left_shift_internal(INTERP, SELF, dest,
-VTABLE_get_integer(INTERP, value));
}
PMC *bitwise_shr_int(INTVAL value, PMC *dest) {
return bitwise_left_shift_internal(INTERP, SELF, dest, -value);
}
void i_bitwise_shr(PMC *value) {
bitwise_left_shift_internal(INTERP, SELF, SELF,
-VTABLE_get_integer(INTERP, value));
}
void i_bitwise_shr_int(INTVAL value) {
bitwise_left_shift_internal(INTERP, SELF, SELF, -value);
}
/*
=item C<PMC *bitwise_lsr(PMC *value, PMC *dest)>
=item C<PMC *bitwise_lsr_int(INTVAL value, PMC *dest)>
Returns in C<*dest> the logical shift right of the scalar by C<*value>.
=item C<void i_bitwise_lsr(PMC *value)>
=item C<void i_bitwise_lsr_int(INTVAL value)>
Inplace shift right.
=cut
*/
PMC *bitwise_lsr(PMC *value, PMC *dest) {
const INTVAL result = (UINTVAL)DYNSELF.get_integer() >>
VTABLE_get_integer(INTERP, value);
if (!dest)
dest = pmc_new(INTERP, SELF->vtable->base_type);
VTABLE_set_integer_native(INTERP, dest, result);
return dest;
}
PMC *bitwise_lsr_int(INTVAL value, PMC *dest) {
const INTVAL result = (UINTVAL)DYNSELF.get_integer() >> value;
if (!dest)
dest = pmc_new(INTERP, SELF->vtable->base_type);
VTABLE_set_integer_native(INTERP, dest, result);
return dest;
}
void i_bitwise_lsr(PMC *value) {
const INTVAL result = (UINTVAL)DYNSELF.get_integer() >>
VTABLE_get_integer(INTERP, value);
DYNSELF.set_integer_native(result);
}
void i_bitwise_lsr_int(INTVAL value) {
const INTVAL result = (UINTVAL)DYNSELF.get_integer() >> value;
DYNSELF.set_integer_native(result);
}
/*
=item C<PMC *bitwise_shl(PMC *value, PMC *dest)>
=item C<PMC *bitwise_shl_int(INTVAL value, PMC *dest)>
Returns in C<*dest> the shift left of the scalar by C<*value>. A negative
C<value> shifts right. The destination may become a C<BigInt> as a result.
=item C<void i_bitwise_shl(PMC *value)>
=item C<void i_bitwise_shl_int(INTVAL value)>
Inplace shift left. A negative C<value> shifts right. SELF may become a
C<BigInt> as a result.
=cut
*/
PMC *bitwise_shl(PMC *value, PMC *dest) {
return bitwise_left_shift_internal(INTERP, SELF, dest,
VTABLE_get_integer(INTERP, value));
}
PMC *bitwise_shl_int(INTVAL value, PMC *dest) {
return bitwise_left_shift_internal(INTERP, SELF, dest, value);
}
void i_bitwise_shl(PMC *value) {
bitwise_left_shift_internal(INTERP, SELF, SELF,
VTABLE_get_integer(INTERP, value));
}
void i_bitwise_shl_int(INTVAL value) {
bitwise_left_shift_internal(INTERP, SELF, SELF, value);
}
/*
=back
=head2 String Methods
=over 4
=item C<PMC *concatenate(PMC *value, PMC *dest)>
=item C<PMC *concatenate_str(STRING *value, PMC *dest)>
Returns in C<*dest> the result of concatenating the scalar and C<*value>.
=item C<void concatenate(PMC *value)>
=item C<void concatenate_str(STRING *value)>
Concatenate the string C<value> in place.
=cut
*/
PMC *concatenate(PMC *value, PMC *dest) {
STRING * const s = string_concat(INTERP,
DYNSELF.get_string(),
VTABLE_get_string(INTERP, value), 0);
if (!dest)
dest = pmc_new(INTERP, SELF->vtable->base_type);
VTABLE_set_string_native(INTERP, dest, s);
return dest;
}
PMC *concatenate_str(STRING *value, PMC *dest) {
STRING * const s = string_concat(INTERP,
DYNSELF.get_string(), value, 0);
if (!dest)
dest = pmc_new(INTERP, SELF->vtable->base_type);
VTABLE_set_string_native(INTERP, dest, s);
return dest;
}
void i_concatenate(PMC *value) {
STRING * const s = DYNSELF.get_string();
STRING * const v = VTABLE_get_string(INTERP, value);
DYNSELF.set_string_native(string_append(INTERP, s, v));
}
void i_concatenate_str(STRING *value) {
STRING * const s = DYNSELF.get_string();
DYNSELF.set_string_native(string_append(INTERP, s, value));
}
/*
=item C<PMC *repeat(PMC *value, PMC *dest)>
=item C<PMC *repeat_int(INTVAL value, PMC *dest)>
Returns in C<*dest> the result of repeating the scalar C<value> times.
=item C<void i_repeat(PMC *value)>
=item C<void i_repeat_int(INTVAL value)>
Repeat the string C<SELF> in place C<value> times.
=cut
*/
PMC *repeat(PMC *value, PMC *dest) {
STRING * const s = DYNSELF.get_string();
const UINTVAL n = (UINTVAL)VTABLE_get_integer(INTERP, value);
if (!dest)
dest = pmc_new(INTERP, SELF->vtable->base_type);
VTABLE_set_string_native(INTERP, dest,
string_repeat(INTERP, s, n, NULL));
return dest;
}
PMC *repeat_int(INTVAL value, PMC *dest) {
STRING * const s = DYNSELF.get_string();
const UINTVAL n = value;
if (!dest)
dest = pmc_new(INTERP, SELF->vtable->base_type);
VTABLE_set_string_native(INTERP, dest,
string_repeat(INTERP, s, n, NULL));
return dest;
}
void i_repeat(PMC *value) {
STRING * const s = DYNSELF.get_string();
const UINTVAL n = (UINTVAL)VTABLE_get_integer(INTERP, value);
DYNSELF.set_string_native(string_repeat(INTERP, s, n, NULL));
}
void i_repeat_int(INTVAL value) {
STRING * const s = DYNSELF.get_string();
const UINTVAL n = value;
DYNSELF.set_string_native(string_repeat(INTERP, s, n, NULL));
}
/*
=back
=head2 Compare Methods
=over 4
=item C<INTVAL cmp_num(PMC *value)>
Returns the result of comparing the floating-point values of the scalar
and C<*value>.
=cut
*/
INTVAL cmp_num(PMC *value) {
/* XXX - Floating-point precision errors possible? */
FLOATVAL diff = VTABLE_get_number(INTERP, value) -
DYNSELF.get_number();
return FLOAT_IS_ZERO(diff) ? 0 : diff < 0.0 ? -1 : 1;
}
/*
=item C<INTVAL cmp_string(PMC *value)>
Returns the result of comparing the string values of the scalar and
C<*value>.
=cut
*/
INTVAL cmp_string(PMC *value) {
return string_compare(INTERP, DYNSELF.get_string(),
VTABLE_get_string(INTERP, value));
}
/*
=back
=head2 Logical Methods
=over 4
=item C<PMC *logical_or(PMC *value, PMC *dest)>
Returns the result of the logical C<OR> of C<SELF> and C<value>, i.e. returns
C<SELF> it is true or C<value>: C<dest> is alway ignored.
=cut
*/
PMC *logical_or(PMC *value, PMC *dest) {
if (DYNSELF.get_bool()) {
return SELF;
}
return value;
}
/*
=item C< PMC *logical_and(PMC *value, PMC *dest)>
Returns the result of the logical C<AND> of C<SELF> and C<value>, i.e.
returns C<value> if C<SELF> is true else C<SELF>. C<dest> is always ignored.
=cut
*/
PMC *logical_and(PMC *value, PMC *dest) {
if (DYNSELF.get_bool()) {
return value;
}
return SELF;
}
/*
=item C<PMC *logical_xor(PMC *value, PMC *dest)>
Returns the result of the logical C<XOR> of C<SELF> and C<*value>.
=cut
*/
PMC *logical_xor(PMC *value, PMC *dest) {
const INTVAL my_bool = DYNSELF.get_bool();
const INTVAL value_bool = VTABLE_get_bool(INTERP, value);
if (my_bool && ! value_bool) {
return SELF;
}
else if (value_bool && ! my_bool) {
return value;
}
dest = pmc_new(INTERP, SELF->vtable->base_type);
VTABLE_set_bool(INTERP, dest, 0);
return dest;
}
/*
=item C<PMC *logical_not(PMC *dest)>
=item C<void i_logical_not()>
Returns in C<*dest> the result of the logical negation of the scalar and
C<*value>.
=cut
*/
PMC *logical_not(PMC *dest) {
const INTVAL a = ! DYNSELF.get_bool();
if (!dest)
dest = pmc_new(INTERP, SELF->vtable->base_type);
VTABLE_set_bool(INTERP, dest, a);
return dest;
}
void i_logical_not() {
VTABLE_set_bool(INTERP, SELF, ! DYNSELF.get_bool());
}
/*
=item C<INTVAL defined()>
Always returns true.
=cut
*/
INTVAL defined() {
return 1;
}
/*
=item C<STRING *substr_str(INTVAL offset, INTVAL length)>
Returns the substring of length C<length> of the scalar starting at
C<offset>.
=cut
*/
STRING *substr_str(INTVAL offset, INTVAL length) {
return string_substr(INTERP, VTABLE_get_string(INTERP,SELF),
offset, length, NULL, 0);
}
/*
=item C<void share_ro()>
Sets this PMC as shared and read-only.
=cut
*/
PMC *share_ro() {
PMC *ret;
PMC * const _true = pmc_new(INTERP, enum_class_Integer);
VTABLE_set_integer_native(INTERP, _true, 1);
ret = pt_shared_fixup(INTERP, SELF);
/* first set readonly */
VTABLE_setprop(INTERP, ret, const_string(INTERP, "_ro"), _true);
/* now share; we add a PMC_EXT so we can identify the owning interp */
add_pmc_sync(INTERP, ret);
PObj_is_PMC_shared_SET(ret);
/* XXX FIXME workaround lack of metadata sharing*/
PMC_metadata(SELF) = NULL;
return ret;
}
}
/*
=back
=cut
*/
/*
* Local variables:
* c-file-style: "parrot"
* End:
* vim: expandtab shiftwidth=4:
*/
Jump to Line
Something went wrong with that request. Please try again.