|
|
|
|
|
|
#include "global.h" |
#include "interpret.h" |
#include "svalue.h" |
#include "multiset.h" |
#include "mapping.h" |
#include "array.h" |
#include "stralloc.h" |
#include "pike_float.h" |
#include "opcodes.h" |
#include "operators.h" |
#include "pike_memory.h" |
#include "pike_error.h" |
#include "docode.h" |
#include "constants.h" |
#include "peep.h" |
#include "lex.h" |
#include "program.h" |
#include "object.h" |
#include "pike_types.h" |
#include "module_support.h" |
#include "pike_macros.h" |
#include "bignum.h" |
#include "builtin_functions.h" |
#include "cyclic.h" |
#include "pike_compiler.h" |
|
#define OP_DIVISION_BY_ZERO_ERROR(FUNC) \ |
math_error(FUNC, 2, 0, "Division by zero.\n") |
#define OP_MODULO_BY_ZERO_ERROR(FUNC) \ |
math_error(FUNC, 2, 0, "Modulo by zero.\n") |
|
|
|
|
#define MAX_INT_SPRINTF_LEN (2 + (SIZEOF_INT_TYPE * 5 + 1) / 2) |
|
|
|
#define MAX_NUM_BUF (MAXIMUM(MAX_INT_SPRINTF_LEN,MAX_FLOAT_SPRINTF_LEN)) |
|
static int has_lfun(enum LFUN lfun, int arg); |
static int call_lfun(enum LFUN left, enum LFUN right); |
static int call_lhs_lfun(enum LFUN lfun, int arg); |
|
void index_no_free(struct svalue *to,struct svalue *what,struct svalue *ind) |
{ |
switch(TYPEOF(*what)) |
{ |
case T_ARRAY: |
simple_array_index_no_free(to,what->u.array,ind); |
break; |
|
case T_MAPPING: |
mapping_index_no_free(to,what->u.mapping,ind); |
break; |
|
case T_OBJECT: |
object_index_no_free(to, what->u.object, SUBTYPEOF(*what), ind); |
break; |
|
case T_MULTISET: { |
int i=multiset_member(what->u.multiset, ind); |
SET_SVAL(*to, T_INT, i ? NUMBER_NUMBER : NUMBER_UNDEFINED, integer, i); |
break; |
} |
|
case T_STRING: |
if(TYPEOF(*ind) == T_INT) |
{ |
ptrdiff_t len = what->u.string->len; |
INT_TYPE p = ind->u.integer; |
INT_TYPE i = p < 0 ? p + len : p; |
if(i<0 || i>=len) |
{ |
if(len == 0) |
Pike_error("Attempt to index the empty string with %"PRINTPIKEINT"d.\n", i); |
else |
Pike_error("Index %"PRINTPIKEINT"d is out of string range " |
"%"PRINTPTRDIFFT"d..%"PRINTPTRDIFFT"d.\n", |
i, -len, len - 1); |
} else |
i=index_shared_string(what->u.string,i); |
SET_SVAL(*to, T_INT, NUMBER_NUMBER, integer, i); |
break; |
}else{ |
if (TYPEOF(*ind) == T_STRING) |
Pike_error ("Expected integer as string index, got \"%S\".\n", |
ind->u.string); |
else |
Pike_error ("Expected integer as string index, got %s.\n", |
get_name_of_type (TYPEOF(*ind))); |
} |
|
case T_FUNCTION: |
case T_PROGRAM: |
if (program_index_no_free(to, what, ind)) break; |
goto index_error; |
|
case T_INT: |
if (TYPEOF(*ind) == T_STRING && !IS_UNDEFINED (what)) { |
INT_TYPE val = what->u.integer; |
|
convert_svalue_to_bignum(what); |
index_no_free(to, what, ind); |
if(IS_UNDEFINED(to)) { |
if (val) { |
Pike_error("Indexing the integer %"PRINTPIKEINT"d " |
"with unknown method \"%S\".\n", |
val, ind->u.string); |
} else { |
Pike_error("Indexing the NULL value with \"%S\".\n", |
ind->u.string); |
} |
} |
break; |
} |
|
|
|
default: |
index_error: |
if (TYPEOF(*ind) == T_INT) |
Pike_error ("Cannot index %s with %"PRINTPIKEINT"d.\n", |
(TYPEOF(*what) == T_INT && !what->u.integer)? |
"the NULL value":get_name_of_type(TYPEOF(*what)), |
ind->u.integer); |
else if (TYPEOF(*ind) == T_FLOAT) |
Pike_error ("Cannot index %s with %"PRINTPIKEFLOAT"e.\n", |
(TYPEOF(*what) == T_INT && !what->u.integer)? |
"the NULL value":get_name_of_type(TYPEOF(*what)), |
ind->u.float_number); |
else if (TYPEOF(*ind) == T_STRING) |
Pike_error ("Cannot index %s with \"%S\".\n", |
(TYPEOF(*what) == T_INT && !what->u.integer)? |
"the NULL value":get_name_of_type(TYPEOF(*what)), |
ind->u.string); |
else |
Pike_error ("Cannot index %s with %s.\n", |
(TYPEOF(*what) == T_INT && !what->u.integer)? |
"the NULL value":get_name_of_type(TYPEOF(*what)), |
get_name_of_type (TYPEOF(*ind))); |
} |
} |
|
PMOD_EXPORT void o_index(void) |
{ |
struct svalue s; |
index_no_free(&s,Pike_sp-2,Pike_sp-1); |
pop_n_elems(2); |
*Pike_sp=s; |
dmalloc_touch_svalue(Pike_sp); |
Pike_sp++; |
dmalloc_touch_svalue(Pike_sp-1); |
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
PMOD_EXPORT void o_cast_to_int(void) |
{ |
switch(TYPEOF(Pike_sp[-1])) |
{ |
case T_OBJECT: |
if(!Pike_sp[-1].u.object->prog) { |
|
pop_stack(); |
push_int (0); |
} |
else |
{ |
if( Pike_sp[-1].u.object->prog == bignum_program ) |
return; |
|
ref_push_string(literal_int_string); |
if(!call_lhs_lfun(LFUN_CAST,2)) |
Pike_error("No cast method in object <2>.\n"); |
stack_pop_keep_top(); |
|
if(TYPEOF(Pike_sp[-1]) != PIKE_T_INT) |
{ |
if(TYPEOF(Pike_sp[-1]) == T_OBJECT) |
{ |
struct object *o = Pike_sp[-1].u.object; |
if( o->prog == bignum_program ) |
return; |
else if( o->prog ) |
{ |
ref_push_string(literal_int_string); |
if( call_lhs_lfun(LFUN__IS_TYPE,2) ) |
if( !UNSAFE_IS_ZERO(Pike_sp-1) ) |
{ |
pop_stack(); |
return; |
} |
pop_stack(); |
} |
} |
Pike_error("Cast failed, wanted int, got %s\n", |
get_name_of_type(TYPEOF(Pike_sp[-1]))); |
} |
else if(SUBTYPEOF(Pike_sp[-1]) == NUMBER_UNDEFINED) |
Pike_error("Cannot cast this object to int.\n"); |
} |
break; |
|
case T_FLOAT: { |
FLOAT_TYPE f = Pike_sp[-1].u.float_number; |
|
if ( PIKE_ISINF(f) || PIKE_ISNAN(f) ) |
Pike_error("Can't cast infinites or NaN to int.\n"); |
|
|
if (UNLIKELY(f > MAX_INT_TYPE || f < MIN_INT_TYPE)) { |
convert_stack_top_to_bignum(); |
} else { |
SET_SVAL(Pike_sp[-1], T_INT, NUMBER_NUMBER, integer, f); |
} |
break; |
} |
|
case T_STRING: |
|
|
|
if( (Pike_sp[-1].u.string->len >= 10) || Pike_sp[-1].u.string->size_shift ) |
convert_stack_top_string_to_inumber(10); |
else |
{ |
INT_TYPE i = strtol(Pike_sp[-1].u.string->str, 0, 10); |
free_string(Pike_sp[-1].u.string); |
SET_SVAL(Pike_sp[-1], T_INT, NUMBER_NUMBER, integer, i); |
} |
break; |
|
case PIKE_T_INT: |
break; |
|
default: |
Pike_error("Cannot cast %s to int.\n", get_name_of_type(TYPEOF(Pike_sp[-1]))); |
break; |
} |
} |
|
|
PMOD_EXPORT void o_cast_to_string(void) |
{ |
struct pike_string *s; |
|
switch(TYPEOF(Pike_sp[-1])) |
{ |
case T_OBJECT: |
if(!Pike_sp[-1].u.object->prog) { |
|
pop_stack(); |
push_constant_text("0"); |
} else |
{ |
ref_push_string(literal_string_string); |
if(!call_lhs_lfun(LFUN_CAST,2)) |
Pike_error("No cast method in object.\n"); |
stack_pop_keep_top(); |
|
if(TYPEOF(Pike_sp[-1]) != PIKE_T_STRING) |
{ |
if(TYPEOF(Pike_sp[-1])==PIKE_T_INT && SUBTYPEOF(Pike_sp[-1])==NUMBER_UNDEFINED) |
Pike_error("Cannot cast this object to string.\n"); |
if(TYPEOF(Pike_sp[-1]) == T_OBJECT && Pike_sp[-1].u.object->prog) |
{ |
ref_push_string(literal_string_string); |
if( call_lhs_lfun( LFUN__IS_TYPE,2 ) ) |
if( !UNSAFE_IS_ZERO(Pike_sp-1) ) |
{ |
pop_stack(); |
return; |
} |
pop_stack(); |
} |
Pike_error("Cast failed, wanted string, got %s\n", |
get_name_of_type(TYPEOF(Pike_sp[-1]))); |
} |
} |
return; |
|
case T_ARRAY: |
{ |
int i, alen; |
struct array *a = Pike_sp[-1].u.array; |
int shift = 0; |
alen = a->size; |
|
for(i = 0; i<alen; i++) { |
INT_TYPE val; |
if (TYPEOF(a->item[i]) != T_INT) { |
Pike_error( |
"Can only cast array(int) to string, item %d is not an integer: %O\n", |
i, a->item + i); |
} |
val = a->item[i].u.integer; |
switch (shift) { |
case 0: |
if ((unsigned INT32) val <= 0xff) |
break; |
shift = 1; |
|
|
case 1: |
if ((unsigned INT32) val <= 0xffff) |
break; |
shift = 2; |
|
|
case 2: |
#if SIZEOF_INT_TYPE > 4 |
if (val < MIN_INT32 || val > MAX_INT32) |
Pike_error ("Item %d is too large: %"PRINTPIKEINT"x.\n", |
i, val); |
#endif |
break; |
} |
} |
|
s = begin_wide_shared_string(a->size, shift); |
switch(shift) { |
case 0: |
for(i = a->size; i--; ) { |
s->str[i] = (p_wchar0) a->item[i].u.integer; |
} |
break; |
case 1: |
{ |
p_wchar1 *str1 = STR1(s); |
for(i = a->size; i--; ) { |
str1[i] = (p_wchar1) a->item[i].u.integer; |
} |
} |
break; |
case 2: |
{ |
p_wchar2 *str2 = STR2(s); |
for(i = a->size; i--; ) { |
str2[i] = (p_wchar2) a->item[i].u.integer; |
} |
} |
break; |
} |
pop_stack(); |
push_string(end_shared_string(s)); |
} |
return; |
|
default: |
Pike_error("Cannot cast %s to string.\n", get_name_of_type(TYPEOF(Pike_sp[-1]))); |
break; |
|
case PIKE_T_STRING: |
return; |
|
case T_FLOAT: |
{ |
char buf[MAX_FLOAT_SPRINTF_LEN+1]; |
format_pike_float (buf, Pike_sp[-1].u.float_number); |
s = make_shared_string(buf); |
break; |
} |
|
case T_INT: |
{ |
INT_TYPE org; |
char buf[MAX_INT_SPRINTF_LEN]; |
char *b = buf+sizeof buf-1; |
unsigned INT_TYPE i; |
org = Pike_sp[-1].u.integer; |
*b-- = '\0'; |
i = org; |
|
if( org < 0 ) |
i = -i; |
|
goto jin; |
do |
{ |
i /= 10; |
jin: *b-- = '0'+(i%10); |
} |
while( i >= 10 ); |
|
if( org < 0 ) |
*b = '-'; |
else |
b++; |
s = make_shared_string(b); |
} |
break; |
} |
|
SET_SVAL(Pike_sp[-1], PIKE_T_STRING, 0, string, s); |
} |
|
PMOD_EXPORT void o_cast(struct pike_type *type, INT32 run_time_type) |
{ |
if(run_time_type != TYPEOF(Pike_sp[-1])) |
{ |
if(run_time_type == T_MIXED) |
return; |
|
if (TYPEOF(Pike_sp[-1]) == T_OBJECT && !Pike_sp[-1].u.object->prog) { |
|
pop_stack(); |
push_int (0); |
} |
|
if(TYPEOF(Pike_sp[-1]) == T_OBJECT) |
{ |
struct object *o = Pike_sp[-1].u.object; |
int f = FIND_LFUN(o->prog->inherits[SUBTYPEOF(Pike_sp[-1])].prog, LFUN_CAST); |
if(f == -1) { |
if (run_time_type == T_MAPPING) { |
stack_dup(); |
f_indices(1); |
stack_swap(); |
f_values(1); |
f_mkmapping(2); |
goto emulated_type_ok; |
} |
if (run_time_type != T_PROGRAM) { |
Pike_error("No cast method in object.\n"); |
} |
f_object_program(1); |
return; |
} |
push_static_text(get_name_of_type(type->type)); |
apply_low(o, f, 1); |
|
if (run_time_type == T_PROGRAM) { |
if (IS_UNDEFINED(Pike_sp-1)) { |
pop_stack(); |
f_object_program(1); |
return; |
} |
} |
|
stack_pop_keep_top(); |
|
if(TYPEOF(Pike_sp[-1]) == T_INT && |
SUBTYPEOF(Pike_sp[-1]) == NUMBER_UNDEFINED) |
Pike_error("Cannot cast this object to %s.\n", |
get_name_of_type(type->type)); |
|
} else |
|
switch(run_time_type) |
{ |
default: |
Pike_error("Cannot perform cast to that type.\n"); |
break; |
|
case T_MULTISET: |
switch(TYPEOF(Pike_sp[-1])) |
{ |
case T_ARRAY: |
{ |
f_mkmultiset(1); |
break; |
} |
|
default: |
Pike_error("Cannot cast %s to multiset.\n", |
get_name_of_type(TYPEOF(Pike_sp[-1]))); |
} |
break; |
|
case T_MAPPING: |
switch(TYPEOF(Pike_sp[-1])) |
{ |
case T_ARRAY: |
{ |
struct array *a=Pike_sp[-1].u.array; |
struct array *b; |
struct mapping *m; |
INT32 i; |
m=allocate_mapping(a->size); |
push_mapping(m); |
for (i=0; i<a->size; i++) |
{ |
if (TYPEOF(ITEM(a)[i]) != T_ARRAY) |
Pike_error("Cast array to mapping: " |
"element %d is not an array\n", i); |
b=ITEM(a)[i].u.array; |
if (b->size!=2) |
Pike_error("Cast array to mapping: " |
"element %d is not an array of size 2\n", i); |
mapping_insert(m,ITEM(b)+0,ITEM(b)+1); |
} |
stack_swap(); |
pop_n_elems(1); |
break; |
} |
|
default: |
Pike_error("Cannot cast %s to mapping.\n", |
get_name_of_type(TYPEOF(Pike_sp[-1]))); |
} |
break; |
|
case T_ARRAY: |
switch(TYPEOF(Pike_sp[-1])) |
{ |
case T_MAPPING: |
{ |
struct array *a=mapping_to_array(Pike_sp[-1].u.mapping); |
pop_stack(); |
push_array(a); |
break; |
} |
|
case T_STRING: |
f_values(1); |
break; |
|
case T_MULTISET: |
f_indices(1); |
break; |
|
default: |
Pike_error("Cannot cast %s to array.\n", |
get_name_of_type(TYPEOF(Pike_sp[-1]))); |
} |
break; |
|
case T_INT: |
o_cast_to_int(); |
return; |
|
case T_STRING: |
o_cast_to_string(); |
return; |
|
case T_FLOAT: |
{ |
FLOAT_TYPE f = 0.0; |
|
switch(TYPEOF(Pike_sp[-1])) |
{ |
case T_INT: |
f=(FLOAT_TYPE)(Pike_sp[-1].u.integer); |
break; |
|
case T_STRING: |
#if SIZEOF_FLOAT_TYPE > SIZEOF_DOUBLE |
f = |
(FLOAT_TYPE)STRTOLD_PCHARP(MKPCHARP(Pike_sp[-1].u.string->str, |
Pike_sp[-1].u.string->size_shift), |
0); |
#else |
f = |
(FLOAT_TYPE)STRTOD_PCHARP(MKPCHARP(Pike_sp[-1].u.string->str, |
Pike_sp[-1].u.string->size_shift), |
0); |
#endif |
free_string(Pike_sp[-1].u.string); |
break; |
|
default: |
Pike_error("Cannot cast %s to float.\n", |
get_name_of_type(TYPEOF(Pike_sp[-1]))); |
} |
|
SET_SVAL(Pike_sp[-1], T_FLOAT, 0, float_number, f); |
break; |
} |
|
case T_OBJECT: |
{ |
struct program *p = program_from_type(type); |
if (p) { |
struct svalue s; |
SET_SVAL(s, T_PROGRAM, 0, program, p); |
apply_svalue(&s, 1); |
return; |
} |
} |
switch(TYPEOF(Pike_sp[-1])) |
{ |
case T_STRING: { |
struct pike_string *file; |
INT_TYPE lineno; |
if(Pike_fp->pc && |
(file = low_get_line(Pike_fp->pc, Pike_fp->context->prog, |
&lineno, NULL))) { |
push_string(file); |
}else{ |
push_int(0); |
} |
|
|
APPLY_MASTER("cast_to_object",2); |
return; |
} |
|
case T_FUNCTION: |
if (SUBTYPEOF(Pike_sp[-1]) == FUNCTION_BUILTIN) { |
Pike_error("Cannot cast builtin functions to object.\n"); |
} else if (Pike_sp[-1].u.object->prog == pike_trampoline_program) { |
ref_push_object(((struct pike_trampoline *) |
(Pike_sp[-1].u.object->storage))-> |
frame->current_object); |
stack_pop_keep_top(); |
} else { |
SET_SVAL_TYPE(Pike_sp[-1], T_OBJECT); |
SET_SVAL_SUBTYPE(Pike_sp[-1], 0); |
} |
break; |
|
default: |
Pike_error("Cannot cast %s to object.\n", |
get_name_of_type(TYPEOF(Pike_sp[-1]))); |
} |
break; |
|
case T_PROGRAM: |
switch(TYPEOF(Pike_sp[-1])) |
{ |
case T_STRING: { |
struct pike_string *file; |
INT_TYPE lineno; |
if(Pike_fp->pc && |
(file = low_get_line(Pike_fp->pc, Pike_fp->context->prog, |
&lineno, NULL))) { |
push_string(file); |
}else{ |
push_int(0); |
} |
|
|
APPLY_MASTER("cast_to_program",2); |
return; |
} |
|
case T_FUNCTION: |
{ |
struct program *p=program_from_function(Pike_sp-1); |
if(p) |
{ |
add_ref(p); |
pop_stack(); |
push_program(p); |
}else{ |
pop_stack(); |
push_int(0); |
} |
} |
return; |
|
case PIKE_T_TYPE: |
{ |
struct pike_type *t = Pike_sp[-1].u.type; |
struct program *p = program_from_type(t); |
pop_stack(); |
if (p) { |
ref_push_program(p); |
} else { |
push_int(0); |
} |
return; |
} |
|
default: |
Pike_error("Cannot cast %s to a program.\n", |
get_name_of_type(TYPEOF(Pike_sp[-1]))); |
} |
} |
} |
|
if(run_time_type != TYPEOF(Pike_sp[-1])) |
{ |
switch(TYPEOF(Pike_sp[-1])) { |
case T_OBJECT: |
if(Pike_sp[-1].u.object->prog) |
{ |
struct object *o = Pike_sp[-1].u.object; |
int f = FIND_LFUN(o->prog->inherits[SUBTYPEOF(Pike_sp[-1])].prog, |
LFUN__IS_TYPE); |
if( f != -1) |
{ |
push_static_text(get_name_of_type(run_time_type)); |
apply_low(o, f, 1); |
f=!UNSAFE_IS_ZERO(Pike_sp-1); |
pop_stack(); |
if(f) goto emulated_type_ok; |
} |
} |
break; |
case T_FUNCTION: |
|
if ((run_time_type == T_PROGRAM) && |
program_from_function(Pike_sp-1)) { |
return; |
} |
break; |
} |
Pike_error("Cast failed, wanted %s, got %s\n", |
get_name_of_type(run_time_type), |
get_name_of_type(TYPEOF(Pike_sp[-1]))); |
} |
|
emulated_type_ok: |
|
if (!type) return; |
|
switch(run_time_type) |
{ |
case T_ARRAY: |
{ |
struct pike_type *itype; |
INT32 run_time_itype; |
|
push_type_value(itype = index_type(type, int_type_string, 0)); |
run_time_itype = compile_type_to_runtime_type(itype); |
|
if(run_time_itype != T_MIXED) |
{ |
struct array *a; |
struct array *tmp=Pike_sp[-2].u.array; |
DECLARE_CYCLIC(); |
|
if((a=(struct array *)BEGIN_CYCLIC(tmp,0))) |
{ |
ref_push_array(a); |
}else{ |
INT32 e; |
TYPE_FIELD types = 0; |
#ifdef PIKE_DEBUG |
struct svalue *save_sp=Pike_sp+1; |
#endif |
push_array(a=allocate_array(tmp->size)); |
SET_CYCLIC_RET(a); |
|
for(e=0;e<a->size;e++) |
{ |
push_svalue(tmp->item+e); |
o_cast(itype, run_time_itype); |
stack_pop_to_no_free (ITEM(a) + e); |
types |= 1 << TYPEOF(ITEM(a)[e]); |
} |
a->type_field = types; |
#ifdef PIKE_DEBUG |
if(save_sp!=Pike_sp) |
Pike_fatal("o_cast left stack droppings.\n"); |
#endif |
} |
END_CYCLIC(); |
assign_svalue(Pike_sp-3,Pike_sp-1); |
pop_stack(); |
} |
pop_stack(); |
} |
break; |
|
case T_MULTISET: |
{ |
struct pike_type *itype; |
INT32 run_time_itype; |
|
push_type_value(itype = key_type(type, 0)); |
run_time_itype = compile_type_to_runtime_type(itype); |
|
if(run_time_itype != T_MIXED) |
{ |
struct multiset *m; |
struct multiset *tmp=Pike_sp[-2].u.multiset; |
DECLARE_CYCLIC(); |
|
if((m=(struct multiset *)BEGIN_CYCLIC(tmp,0))) |
{ |
ref_push_multiset(m); |
}else{ |
#ifdef PIKE_DEBUG |
struct svalue *save_sp=Pike_sp+1; |
#endif |
|
ptrdiff_t nodepos; |
push_multiset (m = allocate_multiset (multiset_sizeof (tmp), |
multiset_get_flags (tmp), |
multiset_get_cmp_less (tmp))); |
|
SET_CYCLIC_RET(m); |
|
if ((nodepos = multiset_first (tmp)) >= 0) { |
ONERROR uwp; |
SET_ONERROR (uwp, do_sub_msnode_ref, tmp); |
do { |
push_multiset_index (tmp, nodepos); |
o_cast(itype, run_time_itype); |
multiset_insert (m, Pike_sp - 1); |
pop_stack(); |
} while ((nodepos = multiset_next (tmp, nodepos)) >= 0); |
UNSET_ONERROR (uwp); |
sub_msnode_ref (tmp); |
} |
|
#ifdef PIKE_DEBUG |
if(save_sp!=Pike_sp) |
Pike_fatal("o_cast left stack droppings.\n"); |
#endif |
} |
END_CYCLIC(); |
assign_svalue(Pike_sp-3,Pike_sp-1); |
pop_stack(); |
} |
pop_stack(); |
} |
break; |
|
case T_MAPPING: |
{ |
struct pike_type *itype, *vtype; |
INT32 run_time_itype; |
INT32 run_time_vtype; |
|
push_type_value(itype = key_type(type, 0)); |
run_time_itype = compile_type_to_runtime_type(itype); |
|
push_type_value(vtype = index_type(type, mixed_type_string, 0)); |
run_time_vtype = compile_type_to_runtime_type(vtype); |
|
if(run_time_itype != T_MIXED || |
run_time_vtype != T_MIXED) |
{ |
struct mapping *m; |
struct mapping *tmp=Pike_sp[-3].u.mapping; |
DECLARE_CYCLIC(); |
|
if((m=(struct mapping *)BEGIN_CYCLIC(tmp,0))) |
{ |
ref_push_mapping(m); |
}else{ |
INT32 e; |
struct keypair *k; |
struct mapping_data *md; |
#ifdef PIKE_DEBUG |
struct svalue *save_sp=Pike_sp+1; |
#endif |
push_mapping(m=allocate_mapping(m_sizeof(tmp))); |
|
SET_CYCLIC_RET(m); |
|
md = tmp->data; |
NEW_MAPPING_LOOP(md) |
{ |
push_svalue(& k->ind); |
o_cast(itype, run_time_itype); |
push_svalue(& k->val); |
o_cast(vtype, run_time_vtype); |
mapping_insert(m,Pike_sp-2,Pike_sp-1); |
pop_n_elems(2); |
} |
#ifdef PIKE_DEBUG |
if(save_sp!=Pike_sp) |
Pike_fatal("o_cast left stack droppings.\n"); |
#endif |
} |
END_CYCLIC(); |
assign_svalue(Pike_sp-4,Pike_sp-1); |
pop_stack(); |
} |
pop_n_elems(2); |
} |
} |
} |
|
PMOD_EXPORT void f_cast(void) |
{ |
#ifdef PIKE_DEBUG |
struct svalue *save_sp=Pike_sp; |
if(TYPEOF(Pike_sp[-2]) != T_TYPE) |
Pike_fatal("Cast expression destroyed stack or left droppings! (Type:%d)\n", |
TYPEOF(Pike_sp[-2])); |
#endif |
o_cast(Pike_sp[-2].u.type, |
compile_type_to_runtime_type(Pike_sp[-2].u.type)); |
#ifdef PIKE_DEBUG |
if(save_sp != Pike_sp) |
Pike_fatal("Internal error: o_cast() left droppings on stack.\n"); |
#endif |
free_svalue(Pike_sp-2); |
Pike_sp[-2]=Pike_sp[-1]; |
Pike_sp--; |
dmalloc_touch_svalue(Pike_sp); |
} |
|
|
|
|
|
|
|
|
static void f___cast(INT32 args) |
{ |
DECLARE_CYCLIC(); |
|
if (args != 2) { |
SIMPLE_WRONG_NUM_ARGS_ERROR("__cast", 2); |
} |
|
if (BEGIN_CYCLIC(Pike_sp[-1].u.refs, Pike_sp[2].u.refs)) { |
END_CYCLIC(); |
pop_n_elems(args); |
push_undefined(); |
return; |
} |
|
SET_CYCLIC_RET(1); |
|
if (TYPEOF(Pike_sp[-1]) == PIKE_T_STRING) { |
struct pike_string *type_name = Pike_sp[-1].u.string; |
if ((type_name->len >= 3) && (type_name->size_shift == eightbit)) { |
|
|
|
|
|
|
|
|
|
|
|
|
switch(type_name->str[0]) { |
case 'a': |
if (type_name == literal_array_string) { |
pop_stack(); |
ref_push_type_value(array_type_string); |
} |
break; |
case 'f': |
if (type_name == literal_float_string) { |
pop_stack(); |
ref_push_type_value(float_type_string); |
} |
break; |
case 'i': |
if (type_name == literal_int_string) { |
pop_stack(); |
ref_push_type_value(int_type_string); |
} |
break; |
case 'm': |
if (type_name == literal_mapping_string) { |
pop_stack(); |
ref_push_type_value(mapping_type_string); |
} |
if (type_name == literal_multiset_string) { |
pop_stack(); |
ref_push_type_value(multiset_type_string); |
} |
break; |
case 'o': |
if (type_name == literal_object_string) { |
pop_stack(); |
ref_push_type_value(object_type_string); |
} |
break; |
case 'p': |
if (type_name == literal_program_string) { |
pop_stack(); |
ref_push_type_value(program_type_string); |
} |
break; |
case 's': |
if (type_name == literal_string_string) { |
pop_stack(); |
ref_push_type_value(string_type_string); |
} |
break; |
} |
} |
} |
|
if (TYPEOF(Pike_sp[-1]) != PIKE_T_TYPE) { |
END_CYCLIC(); |
bad_arg_error("__cast", args, 2, "string|type", Pike_sp - 2, |
"Expected type or type name.\n"); |
} |
|
stack_swap(); |
f_cast(); |
|
END_CYCLIC(); |
} |
|
|
int low_check_soft_cast(struct svalue *s, struct pike_type *type) |
{ |
loop: |
switch(type->type) { |
case T_MIXED: return 1; |
case T_ZERO: |
switch(TYPEOF(*s)) { |
case PIKE_T_INT: |
return !s->u.integer; |
case PIKE_T_FUNCTION: |
if (SUBTYPEOF(*s) == FUNCTION_BUILTIN) return 0; |
|
case PIKE_T_OBJECT: |
return !s->u.object->prog; |
} |
return 0; |
case T_ASSIGN: |
case PIKE_T_NAME: |
type = type->cdr; |
goto loop; |
case PIKE_T_ATTRIBUTE: |
{ |
int ret; |
if (!low_check_soft_cast(s, type->cdr)) return 0; |
push_svalue(s); |
ref_push_string((struct pike_string *)type->car); |
SAFE_MAYBE_APPLY_MASTER("handle_attribute", 2); |
ret = !SAFE_IS_ZERO(Pike_sp-1) || IS_UNDEFINED(Pike_sp-1); |
pop_stack(); |
return ret; |
} |
case T_AND: |
if (!low_check_soft_cast(s, type->car)) return 0; |
type = type->cdr; |
goto loop; |
case T_OR: |
if (low_check_soft_cast(s, type->car)) return 1; |
type = type->cdr; |
goto loop; |
case T_NOT: |
return !low_check_soft_cast(s, type->car); |
} |
if ((TYPEOF(*s) == PIKE_T_INT) && !s->u.integer) return 1; |
if (TYPEOF(*s) == type->type) { |
switch(type->type) { |
case PIKE_T_INT: |
if (((((INT32)CAR_TO_INT(type)) != MIN_INT32) && |
(s->u.integer < (INT32)CAR_TO_INT(type))) || |
((((INT32)CDR_TO_INT(type)) != MAX_INT32) && |
(s->u.integer > (INT32)CDR_TO_INT(type)))) { |
return 0; |
} |
return 1; |
case PIKE_T_FLOAT: |
return 1; |
case PIKE_T_STRING: |
if ((8<<s->u.string->size_shift) > CAR_TO_INT(type)) { |
return 0; |
} |
return 1; |
case PIKE_T_OBJECT: |
{ |
struct program *p; |
|
if (!type->cdr) return 1; |
if (s->u.object->prog->id == CDR_TO_INT(type)) return 1; |
p = id_to_program(CDR_TO_INT(type)); |
if (!p) return 1; |
return implements(s->u.object->prog, p); |
} |
case PIKE_T_PROGRAM: |
{ |
struct program *p; |
|
if (!type->car->cdr) return 1; |
if (s->u.program->id == CDR_TO_INT(type->car)) return 1; |
p = id_to_program(CDR_TO_INT(type->car)); |
if (!p) return 1; |
return implements(s->u.program, p); |
} |
case PIKE_T_ARRAY: |
{ |
struct array *a = s->u.array; |
int i; |
for (i = a->size; i--;) { |
if (!low_check_soft_cast(a->item + i, type->car)) return 0; |
} |
} |
break; |
case PIKE_T_MULTISET: |
|
break; |
case PIKE_T_MAPPING: |
|
break; |
case PIKE_T_FUNCTION: |
|
break; |
case PIKE_T_TYPE: |
|
break; |
} |
return 1; |
} |
if (TYPEOF(*s) == PIKE_T_OBJECT) { |
int lfun; |
if (!s->u.object->prog) return 0; |
if (type->type == PIKE_T_FUNCTION) { |
if ((lfun = FIND_LFUN(s->u.object->prog, LFUN_CALL)) != -1) { |
|
return 1; |
} |
} |
if ((lfun = FIND_LFUN(s->u.object->prog, LFUN__IS_TYPE)) != -1) { |
int ret; |
push_static_text(get_name_of_type(type->type)); |
apply_low(s->u.object, lfun, 1); |
ret = !UNSAFE_IS_ZERO(Pike_sp-1); |
pop_stack(); |
return ret; |
} |
return 0; |
} |
if ((TYPEOF(*s) == PIKE_T_FUNCTION) && (type->type == PIKE_T_PROGRAM)) { |
|
return 1; |
} |
if ((TYPEOF(*s) == PIKE_T_FUNCTION) && (type->type == T_MANY)) { |
|
return 1; |
} |
|
return 0; |
} |
|
void o_check_soft_cast(struct svalue *s, struct pike_type *type) |
{ |
if (!low_check_soft_cast(s, type)) { |
|
|
|
|
struct pike_type *sval_type = get_type_of_svalue(s); |
struct pike_string *t1; |
struct string_builder s; |
char *fname = "__soft-cast"; |
ONERROR tmp0; |
ONERROR tmp1; |
|
init_string_builder(&s, 0); |
|
SET_ONERROR(tmp0, free_string_builder, &s); |
|
string_builder_explain_nonmatching_types(&s, type, sval_type); |
|
if (Pike_fp->current_program) { |
|
struct pike_string *name = |
ID_FROM_INT(Pike_fp->current_program, Pike_fp->fun)->name; |
if ((!name->size_shift) && (name->len < 100)) |
fname = name->str; |
} |
|
t1 = describe_type(type); |
SET_ONERROR(tmp1, do_free_string, t1); |
|
free_type(sval_type); |
|
bad_arg_error(NULL, -1, 1, t1->str, Pike_sp-1, |
"%s(): Soft cast failed.\n%S", |
fname, s.s); |
|
UNREACHABLE(CALL_AND_UNSET_ONERROR(tmp1)); |
UNREACHABLE(CALL_AND_UNSET_ONERROR(tmp0)); |
} |
} |
|
#define COMPARISON(ID,NAME,FUN) \ |
PMOD_EXPORT void ID(INT32 args) \ |
{ \ |
int i; \ |
switch(args) \ |
{ \ |
case 0: case 1: \ |
SIMPLE_WRONG_NUM_ARGS_ERROR(NAME, 2); \ |
case 2: \ |
i=FUN (Pike_sp-2,Pike_sp-1); \ |
pop_n_elems(2); \ |
push_int(i); \ |
break; \ |
default: \ |
for(i=1;i<args;i++) \ |
if(! ( FUN (Pike_sp-args+i-1, Pike_sp-args+i))) \ |
break; \ |
pop_n_elems(args); \ |
push_int(i==args); \ |
} \ |
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
PMOD_EXPORT void f_ne(INT32 args) |
{ |
f_eq(args); |
|
Pike_sp[-1].u.integer = !Pike_sp[-1].u.integer; |
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
COMPARISON(f_eq,"`==", is_eq) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
COMPARISON(f_lt,"`<" , is_lt) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
COMPARISON(f_le,"`<=",is_le) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
COMPARISON(f_gt,"`>" , is_gt) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
COMPARISON(f_ge,"`>=",is_ge) |
|
|
|
|
|
|
|
|
|
PMOD_EXPORT INT32 low_rop(struct object *o, int i, INT32 e, INT32 args) |
{ |
if (e == args-1) { |
|
ONERROR err; |
Pike_sp--; |
SET_ONERROR(err, do_free_object, o); |
apply_low(o, i, e); |
CALL_AND_UNSET_ONERROR(err); |
return args - e; |
} else { |
|
|
struct svalue *tmp; |
if (e*2 < args) { |
tmp = xalloc(e*sizeof(struct svalue)); |
memcpy(tmp, Pike_sp-args, e*sizeof(struct svalue)); |
memmove(Pike_sp-args, (Pike_sp-args)+e, |
(args-e)*sizeof(struct svalue)); |
memcpy(Pike_sp-e, tmp, e*sizeof(struct svalue)); |
} else { |
tmp = xalloc((args-e)*sizeof(struct svalue)); |
memcpy(tmp, (Pike_sp-args)+e, (args-e)*sizeof(struct svalue)); |
memmove(Pike_sp-e, Pike_sp-args, e*sizeof(struct svalue)); |
memcpy(Pike_sp-args, tmp, (args-e)*sizeof(struct svalue)); |
} |
free(tmp); |
|
|
|
|
|
|
|
|
|
|
#ifdef PIKE_DEBUG |
if (TYPEOF(Pike_sp[-args]) != T_OBJECT || |
Pike_sp[-args].u.object != o || |
!o->prog) { |
Pike_fatal("low_rop() Lost track of object.\n"); |
} |
#endif /* PIKE_DEBUG */ |
apply_low(o, i, e); |
args -= e; |
|
assign_svalue(Pike_sp-(args+1), Pike_sp-1); |
pop_stack(); |
return args; |
} |
} |
|
static void add_strings(INT32 args) |
{ |
struct pike_string *r; |
PCHARP buf; |
ptrdiff_t tmp; |
int max_shift=0; |
ptrdiff_t size=0,e; |
int num=0; |
|
for(e=-args;e<0;e++) |
{ |
if(Pike_sp[e].u.string->len != 0) num++; |
size += Pike_sp[e].u.string->len; |
if(Pike_sp[e].u.string->size_shift > max_shift) |
max_shift=Pike_sp[e].u.string->size_shift; |
} |
|
|
if(num == 0) |
{ |
pop_n_elems(args-1); |
return; |
} |
|
|
if(num == 1) |
{ |
for(e=-args;e<0;e++) |
{ |
if( Pike_sp[e].u.string->len ) |
{ |
if( e != -args ) |
{ |
r = Pike_sp[e].u.string; |
Pike_sp[e].u.string = Pike_sp[-args].u.string; |
Pike_sp[-args].u.string = r; |
} |
} |
} |
pop_n_elems(args-1); |
return; |
} |
|
tmp=Pike_sp[-args].u.string->len; |
r=new_realloc_shared_string(Pike_sp[-args].u.string,size,max_shift); |
mark_free_svalue (Pike_sp - args); |
buf=MKPCHARP_STR_OFF(r,tmp); |
for(e=-args+1;e<0;e++) |
{ |
if( Pike_sp[e].u.string->len ) |
{ |
update_flags_for_add( r, Pike_sp[e].u.string ); |
pike_string_cpy(buf,Pike_sp[e].u.string); |
INC_PCHARP(buf,Pike_sp[e].u.string->len); |
} |
free_string(Pike_sp[e].u.string); |
} |
Pike_sp -= args-1; |
SET_SVAL(Pike_sp[-1], T_STRING, 0, string, low_end_shared_string(r)); |
} |
|
static int pair_add() |
{ |
if(TYPEOF(Pike_sp[-1]) == PIKE_T_OBJECT || |
TYPEOF(Pike_sp[-2]) == PIKE_T_OBJECT) |
{ |
if(TYPEOF(Pike_sp[-2]) == PIKE_T_OBJECT && |
|
Pike_sp[-2].u.object->refs == 2 && |
call_lhs_lfun(LFUN_ADD_EQ,2)) |
return 1; |
if(call_lfun(LFUN_ADD, LFUN_RADD)) |
return !IS_UNDEFINED(Pike_sp-1); |
} |
|
if (TYPEOF(Pike_sp[-2]) != TYPEOF(Pike_sp[-1])) |
{ |
if(IS_UNDEFINED(Pike_sp-2)) |
{ |
stack_swap(); |
pop_stack(); |
return 1; |
} |
|
if(IS_UNDEFINED(Pike_sp-1)) |
{ |
pop_stack(); |
return 1; |
} |
|
|
if( TYPEOF(Pike_sp[-2]) == PIKE_T_STRING ) |
o_cast_to_string(); |
else if( TYPEOF(Pike_sp[-1]) == PIKE_T_STRING ) |
{ |
stack_swap(); |
o_cast_to_string(); |
stack_swap(); |
} |
else if( TYPEOF(Pike_sp[-2]) == PIKE_T_FLOAT ) |
{ |
if( TYPEOF(Pike_sp[-1]) == PIKE_T_INT ) |
{ |
Pike_sp[-1].u.float_number = Pike_sp[-1].u.integer; |
TYPEOF(Pike_sp[-1]) = PIKE_T_FLOAT; |
} |
} |
else if( TYPEOF(Pike_sp[-1]) == PIKE_T_FLOAT ) |
{ |
if( TYPEOF(Pike_sp[-2]) == PIKE_T_INT ) |
{ |
Pike_sp[-2].u.float_number = Pike_sp[-2].u.integer; |
TYPEOF(Pike_sp[-2]) = PIKE_T_FLOAT; |
} |
} |
|
if (TYPEOF(Pike_sp[-2]) != TYPEOF(Pike_sp[-1])) |
return 0; |
} |
|
|
switch(TYPEOF(Pike_sp[-1])) |
{ |
|
|
|
|
|
case PIKE_T_INT: |
{ |
INT_TYPE res; |
if (DO_INT_TYPE_ADD_OVERFLOW(Pike_sp[-2].u.integer, Pike_sp[-1].u.integer, &res)) |
{ |
convert_svalue_to_bignum(Pike_sp-2); |
if (LIKELY(call_lfun(LFUN_ADD,LFUN_RADD))) { |
return 1; |
} |
Pike_fatal("Failed to call `+() in bignum.\n"); |
} |
Pike_sp[-2].u.integer = res; |
Pike_sp--; |
} |
return 1; |
case PIKE_T_FLOAT: |
Pike_sp[-2].u.float_number += Pike_sp[-1].u.float_number; |
Pike_sp--; |
return 1; |
case PIKE_T_STRING: |
Pike_sp[-2].u.string = add_and_free_shared_strings(Pike_sp[-2].u.string, |
Pike_sp[-1].u.string); |
Pike_sp--; |
return 1; |
|
case PIKE_T_ARRAY: |
push_array( add_arrays(Pike_sp-2,2) ); |
stack_swap(); pop_stack(); |
stack_swap(); pop_stack(); |
return 1; |
case PIKE_T_MAPPING: |
push_mapping( add_mappings(Pike_sp-2,2) ); |
stack_swap(); pop_stack(); |
stack_swap(); pop_stack(); |
return 1; |
case PIKE_T_MULTISET: |
push_multiset( add_multisets(Pike_sp-2,2) ); |
stack_swap(); pop_stack(); |
stack_swap(); pop_stack(); |
return 1; |
case PIKE_T_OBJECT: |
return call_lfun(LFUN_ADD,LFUN_RADD); |
} |
return 0; |
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
PMOD_EXPORT void f_add(INT32 args) |
{ |
INT_TYPE e; |
TYPE_FIELD types=0; |
|
if(!args) |
SIMPLE_WRONG_NUM_ARGS_ERROR("`+", 1); |
|
if (args == 1) return; |
|
for(e=-args;e<0;e++) types |= 1<<TYPEOF(Pike_sp[e]); |
|
switch(types) |
{ |
default: |
pairwise_add: |
{ |
struct svalue *s=Pike_sp-args; |
push_svalue(s); |
for(e=1;e<args;e++) |
{ |
push_svalue(s+e); |
if(!pair_add()) |
{ |
Pike_error("Addition on unsupported types: %s + %s\nm", |
get_name_of_type(TYPEOF(*(s+e))), |
get_name_of_type(TYPEOF(*s))); |
} |
} |
assign_svalue(s,Pike_sp-1); |
pop_n_elems(Pike_sp-s-1); |
return; |
} |
|
case BIT_STRING: |
add_strings(args); |
return; |
|
case BIT_STRING | BIT_INT: |
case BIT_STRING | BIT_FLOAT: |
case BIT_STRING | BIT_FLOAT | BIT_INT: |
if ((TYPEOF(Pike_sp[-args]) != T_STRING) && (TYPEOF(Pike_sp[1-args]) != T_STRING)) |
{ |
|
goto pairwise_add; |
} |
for(e=-args;e<0;e++) |
{ |
if( TYPEOF(Pike_sp[e]) != PIKE_T_STRING ) |
{ |
*Pike_sp = Pike_sp[e]; |
Pike_sp++; |
o_cast_to_string(); |
Pike_sp[e-1] = Pike_sp[-1]; |
Pike_sp--; |
} |
} |
add_strings(args); |
return; |
|
case BIT_INT: |
{ |
INT_TYPE size = Pike_sp[-args].u.integer; |
for(e = -args+1; e < 0; e++) |
{ |
if (DO_INT_TYPE_ADD_OVERFLOW(size, Pike_sp[e].u.integer, &size)) |
{ |
convert_svalue_to_bignum(Pike_sp-args); |
f_add(args); |
return; |
} |
} |
Pike_sp-=args; |
push_int(size); |
break; |
} |
|
case BIT_FLOAT: |
{ |
FLOAT_ARG_TYPE res = Pike_sp[-args].u.float_number; |
for(e=args-1; e>0; e-- ) |
res += Pike_sp[-e].u.float_number; |
Pike_sp -= args-1; |
Pike_sp[-1].u.float_number = res; |
} |
break; |
|
case BIT_FLOAT|BIT_INT: |
{ |
FLOAT_ARG_TYPE res = 0.0; |
int i; |
for(i=0; i<args; i++) |
if (TYPEOF(Pike_sp[i-args]) == T_FLOAT) |
res += Pike_sp[i-args].u.float_number; |
else |
res += (FLOAT_ARG_TYPE)Pike_sp[i-args].u.integer; |
Pike_sp-=args; |
push_float(res); |
return; |
} |
|
#define ADD(TYPE, ADD_FUNC, PUSH_FUNC) do { \ |
struct TYPE *x = ADD_FUNC (Pike_sp - args, args); \ |
pop_n_elems (args); \ |
PUSH_FUNC (x); \ |
return; \ |
} while (0) |
|
#define REMOVE_UNDEFINED(TYPE) \ |
do { \ |
int to = -args, i=-args; \ |
for(; i<0; i++) \ |
{ \ |
if(TYPEOF(Pike_sp[i]) == PIKE_T_INT) \ |
{ \ |
if(!IS_UNDEFINED(Pike_sp+i)) \ |
SIMPLE_ARG_TYPE_ERROR("`+", args+i, #TYPE); \ |
} \ |
else if(to!=i) \ |
Pike_sp[to++] = Pike_sp[i]; \ |
else to++; \ |
} \ |
for(i=to; i<0; i++) \ |
TYPEOF(Pike_sp[i])=PIKE_T_INT; \ |
Pike_sp += to; \ |
args += to; \ |
} while(0); |
|
case BIT_ARRAY|BIT_INT: |
REMOVE_UNDEFINED (array); |
|
case BIT_ARRAY: |
ADD (array, add_arrays, push_array); |
break; |
|
case BIT_MAPPING|BIT_INT: |
REMOVE_UNDEFINED (mapping); |
|
case BIT_MAPPING: |
ADD (mapping, add_mappings, push_mapping); |
break; |
|
case BIT_MULTISET|BIT_INT: |
REMOVE_UNDEFINED (multiset); |
|
case BIT_MULTISET: |
ADD (multiset, add_multisets, push_multiset); |
break; |
|
#undef REMOVE_UNDEFINED |
#undef ADD |
} |
} |
|
static int generate_sum(node *n) |
{ |
struct compilation *c = THIS_COMPILATION; |
node **first_arg, **second_arg, **third_arg; |
switch(count_args(CDR(n))) |
{ |
case 0: return 0; |
|
case 1: |
do_docode(CDR(n),0); |
return 1; |
|
case 2: |
first_arg=my_get_arg(&_CDR(n), 0); |
second_arg=my_get_arg(&_CDR(n), 1); |
|
do_docode(CDR(n),DO_NOT_COPY_TOPLEVEL); |
if(first_arg[0]->type == float_type_string && |
second_arg[0]->type == float_type_string) |
{ |
emit0(F_ADD_FLOATS); |
} |
else if(first_arg[0]->type && second_arg[0]->type && |
pike_types_le(first_arg[0]->type, int_type_string, 0, 0) && |
pike_types_le(second_arg[0]->type, int_type_string, 0, 0)) |
{ |
emit0(F_ADD_INTS); |
} |
else |
{ |
emit0(F_ADD); |
} |
modify_stack_depth(-1); |
return 1; |
|
case 3: |
first_arg = my_get_arg(&_CDR(n), 0); |
second_arg = my_get_arg(&_CDR(n), 1); |
third_arg = my_get_arg(&_CDR(n), 2); |
|
if(first_arg[0]->type == float_type_string && |
second_arg[0]->type == float_type_string) |
{ |
do_docode(*first_arg, 0); |
do_docode(*second_arg, 0); |
emit0(F_ADD_FLOATS); |
modify_stack_depth(-1); |
if (third_arg[0]->type == float_type_string) { |
do_docode(*third_arg, 0); |
emit0(F_ADD_FLOATS); |
modify_stack_depth(-1); |
return 1; |
} |
} |
else if(first_arg[0]->type && second_arg[0]->type && |
pike_types_le(first_arg[0]->type, int_type_string, 0, 0) && |
pike_types_le(second_arg[0]->type, int_type_string, 0, 0)) |
{ |
do_docode(*first_arg, 0); |
do_docode(*second_arg, 0); |
emit0(F_ADD_INTS); |
modify_stack_depth(-1); |
if (third_arg[0]->type && |
pike_types_le(third_arg[0]->type, int_type_string, 0, 0)) { |
do_docode(*third_arg, 0); |
emit0(F_ADD_INTS); |
modify_stack_depth(-1); |
return 1; |
} |
} |
else |
{ |
return 0; |
} |
do_docode(*third_arg, 0); |
emit0(F_ADD); |
modify_stack_depth(-1); |
|
return 1; |
|
default: |
return 0; |
} |
} |
|
static node *optimize_eq(node *n) |
{ |
node **first_arg, **second_arg, *ret; |
if(count_args(CDR(n))==2) |
{ |
first_arg=my_get_arg(&_CDR(n), 0); |
second_arg=my_get_arg(&_CDR(n), 1); |
|
#ifdef PIKE_DEBUG |
if(!first_arg || !second_arg) |
Pike_fatal("Couldn't find argument!\n"); |
#endif |
|
if (((*second_arg)->token == F_CONSTANT) && |
(TYPEOF((*second_arg)->u.sval) == T_STRING) && |
((*first_arg)->token == F_RANGE)) { |
node *low = CADR (*first_arg), *high = CDDR (*first_arg); |
INT_TYPE c; |
if ((low->token == F_RANGE_OPEN || |
(low->token == F_RANGE_FROM_BEG && |
(CAR (low)->token == F_CONSTANT) && |
(TYPEOF(CAR (low)->u.sval) == T_INT) && |
(!(CAR (low)->u.sval.u.integer)))) && |
(high->token == F_RANGE_OPEN || |
(high->token == F_RANGE_FROM_BEG && |
(CAR (high)->token == F_CONSTANT) && |
(TYPEOF(CAR (high)->u.sval) == T_INT) && |
(c = CAR (high)->u.sval.u.integer, 1)))) { |
|
|
|
if (high->token == F_RANGE_OPEN || |
(*second_arg)->u.sval.u.string->len <= c) { |
|
|
|
|
|
ADD_NODE_REF2(CAR(*first_arg), |
ADD_NODE_REF2(*second_arg, |
ret = mkopernode("`==", CAR(*first_arg), *second_arg); |
)); |
return ret; |
} else if ((*second_arg)->u.sval.u.string->len == c+1) { |
|
|
|
|
ADD_NODE_REF2(CAR(*first_arg), |
ADD_NODE_REF2(*second_arg, |
ret = mkopernode("has_prefix", CAR(*first_arg), *second_arg); |
)); |
return ret; |
} else { |
|
|
|
|
|
ADD_NODE_REF2(CAR(*first_arg), |
ret = mknode(F_COMMA_EXPR, CAR(*first_arg), mkintnode(0)); |
); |
return ret; |
} |
} |
} |
} |
return 0; |
} |
|
static node *optimize_not(node *n) |
{ |
node **first_arg, **more_args; |
|
if(count_args(CDR(n))==1) |
{ |
first_arg=my_get_arg(&_CDR(n), 0); |
#ifdef PIKE_DEBUG |
if(!first_arg) |
Pike_fatal("Couldn't find argument!\n"); |
#endif |
if(node_is_true(*first_arg)) return mkintnode(0); |
if(node_is_false(*first_arg)) return mkintnode(1); |
|
#define TMP_OPT(X,Y) do { \ |
if((more_args=is_call_to(*first_arg, X))) \ |
{ \ |
node *tmp=*more_args; \ |
if(count_args(*more_args) > 2) return 0; \ |
ADD_NODE_REF(*more_args); \ |
return mkopernode(Y,tmp,0); \ |
} } while(0) |
|
TMP_OPT(f_eq, "`!="); |
TMP_OPT(f_ne, "`=="); |
#if 0 |
|
TMP_OPT(f_lt, "`>="); |
TMP_OPT(f_gt, "`<="); |
TMP_OPT(f_le, "`>"); |
TMP_OPT(f_ge, "`<"); |
#endif |
#undef TMP_OPT |
if((more_args = is_call_to(*first_arg, f_search)) && |
(count_args(*more_args) == 2)) { |
node *search_args = *more_args; |
if ((search_args->token == F_ARG_LIST) && |
CAR(search_args) && |
pike_types_le(CAR(search_args)->type, string_type_string, 0, 0) && |
CDR(search_args) && |
pike_types_le(CDR(search_args)->type, string_type_string, 0, 0)) { |
|
ADD_NODE_REF(*more_args); |
return mkefuncallnode("has_prefix", search_args); |
} |
} |
} |
|
return 0; |
} |
|
static node *may_have_side_effects(node *n) |
{ |
node **arg; |
int argno; |
for (argno = 0; (arg = my_get_arg(&_CDR(n), argno)); argno++) { |
if (((*arg)->type != zero_type_string) && |
match_types(object_type_string, (*arg)->type)) { |
n->node_info |= OPT_SIDE_EFFECT; |
n->tree_info |= OPT_SIDE_EFFECT; |
return NULL; |
} |
} |
return NULL; |
} |
|
static node *optimize_binary(node *n) |
{ |
node **first_arg, **second_arg, *ret; |
int args; |
|
if((args = count_args(CDR(n)))==2) |
{ |
first_arg=my_get_arg(&_CDR(n), 0); |
second_arg=my_get_arg(&_CDR(n), 1); |
|
#ifdef PIKE_DEBUG |
if(!first_arg || !second_arg) |
Pike_fatal("Couldn't find argument!\n"); |
#endif |
|
if((*second_arg)->type == (*first_arg)->type && |
compile_type_to_runtime_type((*second_arg)->type) != T_MIXED) |
{ |
if((*first_arg)->token == F_APPLY && |
CAR(*first_arg)->token == F_CONSTANT && |
is_eq(& CAR(*first_arg)->u.sval, & CAR(n)->u.sval)) |
{ |
|
ADD_NODE_REF2(CAR(n), |
ADD_NODE_REF2(CDR(*first_arg), |
ADD_NODE_REF2(*second_arg, |
ret = mknode(F_APPLY, |
CAR(n), |
mknode(F_ARG_LIST, |
CDR(*first_arg), |
*second_arg)) |
))); |
return ret; |
} |
|
if((*second_arg)->token == F_APPLY && |
CAR(*second_arg)->token == F_CONSTANT && |
is_eq(& CAR(*second_arg)->u.sval, & CAR(n)->u.sval)) |
{ |
|
ADD_NODE_REF2(CAR(n), |
ADD_NODE_REF2(*first_arg, |
ADD_NODE_REF2(CDR(*second_arg), |
ret = mknode(F_APPLY, |
CAR(n), |
mknode(F_ARG_LIST, |
*first_arg, |
CDR(*second_arg))) |
))); |
return ret; |
} |
} |
} |
#if 0 /* Does not work for multiplication. */ |
|
if (n->type && (n->type->type == T_STRING) && |
CAR_TO_INT(n->type) == 32 && (args > 0)) { |
int str_width = 6; |
while (args--) { |
struct pike_type *t; |
node **arg = my_get_arg(&_CDR(n), args); |
if (!arg || !(t = (*arg)->type)) continue; |
if (t->type == T_STRING) { |
int w = CAR_TO_INT(t); |
if (w > str_width) str_width = w; |
} |
} |
if (str_width != 32) { |
type_stack_mark(); |
push_int_type(0, (1<<str_width)-1); |
push_unlimited_array_type(T_STRING); |
free_type(n->type); |
n->type = pop_unfinished_type(); |
} |
} |
#endif /* 0 */ |
return 0; |
} |
|
|
static int generate_comparison(node *n) |
{ |
if(count_args(CDR(n))==2) |
{ |
struct compilation *c = THIS_COMPILATION; |
if(do_docode(CDR(n),DO_NOT_COPY) != 2) |
Pike_fatal("Count args was wrong in generate_comparison.\n"); |
|
if(CAR(n)->u.sval.u.efun->function == f_eq) |
emit0(F_EQ); |
else if(CAR(n)->u.sval.u.efun->function == f_ne) |
emit0(F_NE); |
else if(CAR(n)->u.sval.u.efun->function == f_lt) |
emit0(F_LT); |
else if(CAR(n)->u.sval.u.efun->function == f_le) |
emit0(F_LE); |
else if(CAR(n)->u.sval.u.efun->function == f_gt) |
emit0(F_GT); |
else if(CAR(n)->u.sval.u.efun->function == f_ge) |
emit0(F_GE); |
else |
Pike_fatal("Couldn't generate comparison!\n" |
"efun->function: %p\n" |
"f_eq: %p\n" |
"f_ne: %p\n" |
"f_lt: %p\n" |
"f_le: %p\n" |
"f_gt: %p\n" |
"f_ge: %p\n", |
CAR(n)->u.sval.u.efun->function, |
f_eq, f_ne, f_lt, f_le, f_gt, f_ge); |
modify_stack_depth(-1); |
return 1; |
} |
return 0; |
} |
|
static int float_promote(void) |
{ |
if(TYPEOF(Pike_sp[-2]) == T_INT && TYPEOF(Pike_sp[-1]) == T_FLOAT) |
{ |
SET_SVAL(Pike_sp[-2], T_FLOAT, 0, float_number, (FLOAT_TYPE)Pike_sp[-2].u.integer); |
return 1; |
} |
else if(TYPEOF(Pike_sp[-1]) == T_INT && TYPEOF(Pike_sp[-2]) == T_FLOAT) |
{ |
SET_SVAL(Pike_sp[-1], T_FLOAT, 0, float_number, (FLOAT_TYPE)Pike_sp[-1].u.integer); |
return 1; |
} |
|
if(is_bignum_object_in_svalue(Pike_sp-2) && TYPEOF(Pike_sp[-1]) == T_FLOAT) |
{ |
stack_swap(); |
ref_push_type_value(float_type_string); |
stack_swap(); |
f_cast(); |
stack_swap(); |
return 1; |
} |
else if(is_bignum_object_in_svalue(Pike_sp-1) && TYPEOF(Pike_sp[-2]) == T_FLOAT) |
{ |
ref_push_type_value(float_type_string); |
stack_swap(); |
f_cast(); |
return 1; |
} |
|
return 0; |
} |
|
static int has_lfun(enum LFUN lfun, int arg) |
{ |
struct program *p; |
|
if(TYPEOF(Pike_sp[-arg]) == T_OBJECT && (p = Pike_sp[-arg].u.object->prog)) |
return FIND_LFUN(p->inherits[SUBTYPEOF(Pike_sp[-arg])].prog, lfun); |
return -1; |
} |
|
static int call_lhs_lfun( enum LFUN lfun, int arg ) |
{ |
int i = has_lfun(lfun,arg); |
|
if(i != -1) |
{ |
apply_low(Pike_sp[-arg].u.object, i, arg-1); |
return 1; |
} |
return 0; |
} |
|
static int call_lfun(enum LFUN left, enum LFUN right) |
{ |
struct object *o; |
struct program *p; |
int i; |
|
if(TYPEOF(Pike_sp[-2]) == T_OBJECT && |
(p = (o = Pike_sp[-2].u.object)->prog) && |
(i = FIND_LFUN(p->inherits[SUBTYPEOF(Pike_sp[-2])].prog, left)) != -1) |
{ |
apply_low(o, i, 1); |
free_svalue(Pike_sp-2); |
Pike_sp[-2]=Pike_sp[-1]; |
Pike_sp--; |
dmalloc_touch_svalue(Pike_sp); |
return 1; |
} |
|
if(TYPEOF(Pike_sp[-1]) == T_OBJECT && |
(p = (o = Pike_sp[-1].u.object)->prog) && |
(i = FIND_LFUN(p->inherits[SUBTYPEOF(Pike_sp[-1])].prog, right)) != -1) |
{ |
push_svalue(Pike_sp-2); |
apply_low(o, i, 1); |
free_svalue(Pike_sp-3); |
Pike_sp[-3]=Pike_sp[-1]; |
Pike_sp--; |
dmalloc_touch_svalue(Pike_sp); |
pop_stack(); |
return 1; |
} |
|
return 0; |
} |
|
struct mapping *merge_mapping_array_ordered(struct mapping *a, |
struct array *b, INT32 op); |
struct mapping *merge_mapping_array_unordered(struct mapping *a, |
struct array *b, INT32 op); |
|
PMOD_EXPORT void o_subtract(void) |
{ |
if (TYPEOF(Pike_sp[-2]) != TYPEOF(Pike_sp[-1]) && !float_promote()) |
{ |
if(call_lfun(LFUN_SUBTRACT, LFUN_RSUBTRACT)) |
return; |
|
if (TYPEOF(Pike_sp[-2]) == T_MAPPING) |
switch (TYPEOF(Pike_sp[-1])) |
{ |
case T_ARRAY: |
{ |
struct mapping *m; |
|
m=merge_mapping_array_unordered(Pike_sp[-2].u.mapping, |
Pike_sp[-1].u.array, |
PIKE_ARRAY_OP_SUB); |
pop_n_elems(2); |
push_mapping(m); |
return; |
} |
case T_MULTISET: |
{ |
struct mapping *m; |
|
int got_cmp_less = !!multiset_get_cmp_less (Pike_sp[-1].u.multiset); |
struct array *ind = multiset_indices (Pike_sp[-1].u.multiset); |
pop_stack(); |
push_array (ind); |
if (got_cmp_less) |
m=merge_mapping_array_unordered(Pike_sp[-2].u.mapping, |
Pike_sp[-1].u.array, |
PIKE_ARRAY_OP_SUB); |
else |
m=merge_mapping_array_ordered(Pike_sp[-2].u.mapping, |
Pike_sp[-1].u.array, |
PIKE_ARRAY_OP_SUB); |
pop_n_elems(2); |
push_mapping(m); |
return; |
} |
} |
|
bad_arg_error("`-", 2, 2, get_name_of_type(TYPEOF(Pike_sp[-2])), |
Pike_sp-1, "Subtract on different types.\n"); |
} |
|
switch(TYPEOF(Pike_sp[-2])) |
{ |
case T_OBJECT: |
if(!call_lfun(LFUN_SUBTRACT, LFUN_RSUBTRACT)) |
PIKE_ERROR("`-", "Subtract on objects without `- operator.\n", Pike_sp, 2); |
return; |
|
case T_ARRAY: |
{ |
struct array *a; |
|
check_array_for_destruct(Pike_sp[-2].u.array); |
check_array_for_destruct(Pike_sp[-1].u.array); |
a = subtract_arrays(Pike_sp[-2].u.array, Pike_sp[-1].u.array); |
pop_n_elems(2); |
push_array(a); |
return; |
} |
|
case T_MAPPING: |
{ |
struct mapping *m; |
m=merge_mappings(Pike_sp[-2].u.mapping, Pike_sp[-1].u.mapping,PIKE_ARRAY_OP_SUB); |
pop_n_elems(2); |
push_mapping(m); |
return; |
} |
|
case T_MULTISET: |
{ |
struct multiset *l; |
l=merge_multisets(Pike_sp[-2].u.multiset, Pike_sp[-1].u.multiset, |
PIKE_ARRAY_OP_SUB); |
pop_n_elems(2); |
push_multiset(l); |
return; |
} |
|
case T_FLOAT: |
Pike_sp--; |
Pike_sp[-1].u.float_number -= Pike_sp[0].u.float_number; |
return; |
|
case T_INT: |
if(INT_TYPE_SUB_OVERFLOW(Pike_sp[-2].u.integer, Pike_sp[-1].u.integer)) |
{ |
convert_stack_top_to_bignum(); |
if (LIKELY(call_lfun(LFUN_SUBTRACT, LFUN_RSUBTRACT))) { |
return; |
} |
Pike_fatal("Failed to call `-() in bignum.\n"); |
} |
Pike_sp--; |
SET_SVAL(Pike_sp[-1], PIKE_T_INT, NUMBER_NUMBER, integer, |
Pike_sp[-1].u.integer - Pike_sp[0].u.integer); |
return; |
|
case T_STRING: |
{ |
struct pike_string *s,*ret; |
s=make_shared_string(""); |
ret=string_replace(Pike_sp[-2].u.string,Pike_sp[-1].u.string,s); |
free_string(Pike_sp[-2].u.string); |
free_string(Pike_sp[-1].u.string); |
free_string(s); |
Pike_sp[-2].u.string=ret; |
Pike_sp--; |
return; |
} |
|
case T_TYPE: |
{ |
struct pike_type *t = type_binop(PT_BINOP_MINUS, |
Pike_sp[-2].u.type, Pike_sp[-1].u.type, |
0, 0, 0); |
pop_n_elems(2); |
if (t) { |
push_type_value(t); |
} else { |
push_undefined(); |
} |
return; |
} |
|
default: |
{ |
int args = 2; |
SIMPLE_ARG_TYPE_ERROR("`-", 1, |
"int|float|string|mapping|multiset|array|object"); |
} |
} |
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
PMOD_EXPORT void f_minus(INT32 args) |
{ |
switch(args) |
{ |
case 0: SIMPLE_WRONG_NUM_ARGS_ERROR("`-", 1); |
case 1: o_negate(); break; |
case 2: o_subtract(); break; |
default: |
{ |
INT32 e; |
TYPE_FIELD types = 0; |
struct svalue *s=Pike_sp-args; |
|
for(e=-args;e<0;e++) types |= 1<<TYPEOF(Pike_sp[e]); |
|
if ((types | BIT_INT | BIT_FLOAT) == (BIT_INT | BIT_FLOAT)) { |
INT32 carry = 0; |
if (types == BIT_INT) { |
f_add(args-1); |
o_subtract(); |
break; |
} |
|
for(e = 1; e < args; e++) { |
if (TYPEOF(s[e]) == PIKE_T_INT) { |
INT_TYPE val = s[e].u.integer; |
if (val >= -0x7fffffff) { |
s[e].u.integer = -val; |
} else { |
|
s[e].u.integer = ~val; |
carry++; |
} |
} else { |
s[e].u.float_number = -s[e].u.float_number; |
} |
} |
if (carry) { |
push_int(carry); |
args++; |
} |
f_add(args); |
break; |
} |
|
push_svalue(s); |
for(e=1;e<args;e++) |
{ |
push_svalue(s+e); |
o_subtract(); |
} |
assign_svalue(s,Pike_sp-1); |
pop_n_elems(Pike_sp-s-1); |
} |
} |
} |
|
static int generate_minus(node *n) |
{ |
struct compilation *c = THIS_COMPILATION; |
switch(count_args(CDR(n))) |
{ |
case 1: |
do_docode(CDR(n),DO_NOT_COPY); |
emit0(F_NEGATE); |
return 1; |
|
case 2: |
do_docode(CDR(n),DO_NOT_COPY_TOPLEVEL); |
emit0(F_SUBTRACT); |
modify_stack_depth(-1); |
return 1; |
} |
return 0; |
} |
|
PMOD_EXPORT void o_and(void) |
{ |
if(UNLIKELY(TYPEOF(Pike_sp[-1]) != TYPEOF(Pike_sp[-2]))) |
{ |
if(call_lfun(LFUN_AND, LFUN_RAND)) |
return; |
else if (((TYPEOF(Pike_sp[-1]) == T_TYPE) || (TYPEOF(Pike_sp[-1]) == T_PROGRAM) || |
(TYPEOF(Pike_sp[-1]) == T_FUNCTION)) && |
((TYPEOF(Pike_sp[-2]) == T_TYPE) || (TYPEOF(Pike_sp[-2]) == T_PROGRAM) || |
(TYPEOF(Pike_sp[-2]) == T_FUNCTION))) |
{ |
if (TYPEOF(Pike_sp[-2]) != T_TYPE) |
{ |
struct program *p = program_from_svalue(Pike_sp - 2); |
if (!p) { |
int args = 2; |
SIMPLE_ARG_TYPE_ERROR("`&", 1, "type"); |
} |
type_stack_mark(); |
push_object_type(0, p->id); |
free_svalue(Pike_sp - 2); |
SET_SVAL(Pike_sp[-2], T_TYPE, 0, type, pop_unfinished_type()); |
} |
if (TYPEOF(Pike_sp[-1]) != T_TYPE) |
{ |
struct program *p = program_from_svalue(Pike_sp - 1); |
if (!p) |
{ |
int args = 2; |
SIMPLE_ARG_TYPE_ERROR("`&", 2, "type"); |
} |
type_stack_mark(); |
push_object_type(0, p->id); |
free_svalue(Pike_sp - 1); |
SET_SVAL(Pike_sp[-1], T_TYPE, 0, type, pop_unfinished_type()); |
} |
} |
else if (TYPEOF(Pike_sp[-2]) == T_MAPPING) |
switch (TYPEOF(Pike_sp[-1])) |
{ |
case T_ARRAY: |
{ |
struct mapping *m; |
|
m=merge_mapping_array_unordered(Pike_sp[-2].u.mapping, |
Pike_sp[-1].u.array, |
PIKE_ARRAY_OP_AND); |
pop_n_elems(2); |
push_mapping(m); |
return; |
} |
case T_MULTISET: |
{ |
struct mapping *m; |
|
int got_cmp_less = !!multiset_get_cmp_less (Pike_sp[-1].u.multiset); |
struct array *ind = multiset_indices (Pike_sp[-1].u.multiset); |
pop_stack(); |
push_array (ind); |
if (got_cmp_less) |
m=merge_mapping_array_unordered(Pike_sp[-2].u.mapping, |
Pike_sp[-1].u.array, |
PIKE_ARRAY_OP_AND); |
else |
m=merge_mapping_array_ordered(Pike_sp[-2].u.mapping, |
Pike_sp[-1].u.array, |
PIKE_ARRAY_OP_AND); |
pop_n_elems(2); |
push_mapping(m); |
return; |
} |
default: |
{ |
int args = 2; |
SIMPLE_ARG_TYPE_ERROR("`&", 2, "mapping"); |
} |
} |
else |
{ |
int args = 2; |
SIMPLE_ARG_TYPE_ERROR("`&", 2, get_name_of_type(TYPEOF(Pike_sp[-2]))); |
} |
} |
|
switch(TYPEOF(Pike_sp[-2])) |
{ |
case T_OBJECT: |
if(!call_lfun(LFUN_AND,LFUN_RAND)) |
PIKE_ERROR("`&", "Bitwise and on objects without `& operator.\n", Pike_sp, 2); |
return; |
|
case T_INT: |
Pike_sp--; |
SET_SVAL(Pike_sp[-1], PIKE_T_INT, NUMBER_NUMBER, integer, |
Pike_sp[-1].u.integer & Pike_sp[0].u.integer); |
return; |
|
case T_MAPPING: |
{ |
struct mapping *m; |
m=merge_mappings(Pike_sp[-2].u.mapping, Pike_sp[-1].u.mapping, PIKE_ARRAY_OP_AND); |
pop_n_elems(2); |
push_mapping(m); |
return; |
} |
|
case T_MULTISET: |
{ |
struct multiset *l; |
l=merge_multisets(Pike_sp[-2].u.multiset, Pike_sp[-1].u.multiset, |
PIKE_ARRAY_OP_AND); |
pop_n_elems(2); |
push_multiset(l); |
return; |
} |
|
case T_ARRAY: |
{ |
struct array *a; |
a=and_arrays(Pike_sp[-2].u.array, Pike_sp[-1].u.array); |
pop_n_elems(2); |
push_array(a); |
return; |
} |
|
case T_TYPE: |
{ |
struct pike_type *t; |
t = intersect_types(Pike_sp[-2].u.type, Pike_sp[-1].u.type, 0, 0, 0); |
pop_n_elems(2); |
push_type_value(t); |
return; |
} |
|
case T_FUNCTION: |
case T_PROGRAM: |
{ |
struct program *p; |
struct pike_type *a; |
struct pike_type *b; |
struct pike_type *t; |
|
p = program_from_svalue(Pike_sp - 2); |
if (!p) { |
int args = 2; |
SIMPLE_ARG_TYPE_ERROR("`&", 1, "type"); |
} |
type_stack_mark(); |
push_object_type(0, p->id); |
a = pop_unfinished_type(); |
|
p = program_from_svalue(Pike_sp - 1); |
if (!p) { |
int args = 2; |
SIMPLE_ARG_TYPE_ERROR("`&", 2, "type"); |
} |
type_stack_mark(); |
push_object_type(0, p->id); |
b = pop_unfinished_type(); |
|
t = and_pike_types(a, b); |
|
pop_n_elems(2); |
push_type_value(t); |
free_type(a); |
free_type(b); |
return; |
} |
|
#define STRING_BITOP(OP,STROP) \ |
case T_STRING: \ |
{ \ |
struct pike_string *s; \ |
ptrdiff_t len, i; \ |
\ |
len = Pike_sp[-2].u.string->len; \ |
if (len != Pike_sp[-1].u.string->len) \ |
PIKE_ERROR("`" #OP, "Bitwise "STROP \ |
" on strings of different lengths.\n", Pike_sp, 2); \ |
if(!Pike_sp[-2].u.string->size_shift && !Pike_sp[-1].u.string->size_shift) \ |
{ \ |
s = begin_shared_string(len); \ |
for (i=0; i<len; i++) \ |
s->str[i] = Pike_sp[-2].u.string->str[i] OP Pike_sp[-1].u.string->str[i]; \ |
}else{ \ |
s = begin_wide_shared_string(len, \ |
MAXIMUM(Pike_sp[-2].u.string->size_shift, \ |
Pike_sp[-1].u.string->size_shift)); \ |
for (i=0; i<len; i++) \ |
low_set_index(s,i,index_shared_string(Pike_sp[-2].u.string,i) OP \ |
index_shared_string(Pike_sp[-1].u.string,i)); \ |
} \ |
pop_n_elems(2); \ |
push_string(end_shared_string(s)); \ |
return; \ |
} |
|
STRING_BITOP(&,"AND") |
|
default: |
PIKE_ERROR("`&", "Bitwise AND on illegal type.\n", Pike_sp, 2); |
} |
} |
|
|
|
|
|
|
|
static void r_speedup(INT32 args, void (*func)(void)) |
{ |
struct svalue tmp; |
ONERROR err; |
|
switch(args) |
{ |
case 3: func(); |
case 2: func(); |
case 1: return; |
|
default: |
r_speedup((args+1)>>1,func); |
dmalloc_touch_svalue(Pike_sp-1); |
tmp=*--Pike_sp; |
SET_ONERROR(err,do_free_svalue,&tmp); |
r_speedup(args>>1,func); |
UNSET_ONERROR(err); |
Pike_sp++[0]=tmp; |
func(); |
} |
} |
static void speedup(INT32 args, void (*func)(void)) |
{ |
switch(TYPEOF(Pike_sp[-args])) |
{ |
|
|
|
case T_ARRAY: |
case T_MAPPING: |
r_speedup(args,func); |
return; |
|
default: |
while(--args > 0) func(); |
} |
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
PMOD_EXPORT void f_and(INT32 args) |
{ |
switch(args) |
{ |
case 0: SIMPLE_WRONG_NUM_ARGS_ERROR("`&", 1); |
case 1: return; |
case 2: o_and(); return; |
default: |
speedup(args, o_and); |
} |
} |
|
static int generate_and(node *n) |
{ |
struct compilation *c = THIS_COMPILATION; |
switch(count_args(CDR(n))) |
{ |
case 1: |
do_docode(CDR(n),0); |
return 1; |
|
case 2: |
do_docode(CDR(n),0); |
emit0(F_AND); |
modify_stack_depth(-1); |
return 1; |
|
default: |
return 0; |
} |
} |
|
PMOD_EXPORT void o_or(void) |
{ |
if(TYPEOF(Pike_sp[-1]) != TYPEOF(Pike_sp[-2])) |
{ |
if(call_lfun(LFUN_OR, LFUN_ROR)) { |
return; |
} else if (((TYPEOF(Pike_sp[-1]) == T_TYPE) || |
(TYPEOF(Pike_sp[-1]) == T_PROGRAM) || |
(TYPEOF(Pike_sp[-1]) == T_FUNCTION)) && |
((TYPEOF(Pike_sp[-2]) == T_TYPE) || |
(TYPEOF(Pike_sp[-2]) == T_PROGRAM) || |
(TYPEOF(Pike_sp[-2]) == T_FUNCTION))) { |
if (TYPEOF(Pike_sp[-2]) != T_TYPE) { |
struct program *p = program_from_svalue(Pike_sp - 2); |
if (!p) { |
int args = 2; |
SIMPLE_ARG_TYPE_ERROR("`|", 1, "type"); |
} |
type_stack_mark(); |
push_object_type(0, p->id); |
free_svalue(Pike_sp - 2); |
SET_SVAL(Pike_sp[-2], T_TYPE, 0, type, pop_unfinished_type()); |
} |
if (TYPEOF(Pike_sp[-1]) != T_TYPE) { |
struct program *p = program_from_svalue(Pike_sp - 1); |
if (!p) { |
int args = 2; |
SIMPLE_ARG_TYPE_ERROR("`|", 2, "type"); |
} |
type_stack_mark(); |
push_object_type(0, p->id); |
free_svalue(Pike_sp - 1); |
SET_SVAL(Pike_sp[-1], T_TYPE, 0, type, pop_unfinished_type()); |
} |
} else { |
int args = 2; |
|
if ((TYPEOF(Pike_sp[-1]) == PIKE_T_INT) && |
(SUBTYPEOF(Pike_sp[-1]) == NUMBER_UNDEFINED)) { |
if (TYPEOF(Pike_sp[-2]) == PIKE_T_MULTISET) { |
struct multiset *l = copy_multiset(Pike_sp[-2].u.multiset); |
pop_stack(); |
pop_stack(); |
push_multiset(l); |
return; |
} |
} else if ((TYPEOF(Pike_sp[-2]) == PIKE_T_INT) && |
(SUBTYPEOF(Pike_sp[-2]) == NUMBER_UNDEFINED)) { |
if (TYPEOF(Pike_sp[-1]) == PIKE_T_MULTISET) { |
struct multiset *l = copy_multiset(Pike_sp[-1].u.multiset); |
pop_stack(); |
pop_stack(); |
push_multiset(l); |
return; |
} |
} |
|
SIMPLE_ARG_TYPE_ERROR("`|", 2, get_name_of_type(TYPEOF(Pike_sp[-2]))); |
} |
} |
|
switch(TYPEOF(Pike_sp[-2])) |
{ |
case T_OBJECT: |
if(!call_lfun(LFUN_OR,LFUN_ROR)) |
PIKE_ERROR("`|", "Bitwise or on objects without `| operator.\n", Pike_sp, 2); |
return; |
|
case T_INT: |
Pike_sp--; |
SET_SVAL(Pike_sp[-1], T_INT, NUMBER_NUMBER, integer, |
Pike_sp[-1].u.integer | Pike_sp[0].u.integer); |
return; |
|
case T_MAPPING: |
{ |
struct mapping *m; |
m=merge_mappings(Pike_sp[-2].u.mapping, Pike_sp[-1].u.mapping, PIKE_ARRAY_OP_OR); |
pop_n_elems(2); |
push_mapping(m); |
return; |
} |
|
case T_MULTISET: |
{ |
struct multiset *l; |
l=merge_multisets(Pike_sp[-2].u.multiset, Pike_sp[-1].u.multiset, |
PIKE_ARRAY_OP_OR_LEFT); |
pop_n_elems(2); |
push_multiset(l); |
return; |
} |
|
case T_ARRAY: |
{ |
if (Pike_sp[-1].u.array->size == 1) { |
|
int i = array_search(Pike_sp[-2].u.array, Pike_sp[-1].u.array->item, 0); |
if (i == -1) { |
f_add(2); |
} else { |
pop_stack(); |
} |
} else if ((Pike_sp[-2].u.array == Pike_sp[-1].u.array) && |
(Pike_sp[-1].u.array->refs == 2)) { |
|
pop_stack(); |
} else { |
struct array *a; |
a=merge_array_with_order(Pike_sp[-2].u.array, Pike_sp[-1].u.array, |
PIKE_ARRAY_OP_OR_LEFT); |
pop_n_elems(2); |
push_array(a); |
} |
return; |
} |
|
case T_TYPE: |
{ |
struct pike_type *t; |
t = or_pike_types(Pike_sp[-2].u.type, Pike_sp[-1].u.type, 0); |
pop_n_elems(2); |
push_type_value(t); |
return; |
} |
|
case T_FUNCTION: |
case T_PROGRAM: |
{ |
struct program *p; |
struct pike_type *a; |
struct pike_type *b; |
struct pike_type *t; |
|
p = program_from_svalue(Pike_sp - 2); |
if (!p) { |
int args = 2; |
SIMPLE_ARG_TYPE_ERROR("`|", 1, "type"); |
} |
type_stack_mark(); |
push_object_type(0, p->id); |
a = pop_unfinished_type(); |
|
p = program_from_svalue(Pike_sp - 1); |
if (!p) { |
int args = 2; |
SIMPLE_ARG_TYPE_ERROR("`|", 2, "type"); |
} |
type_stack_mark(); |
push_object_type(0, p->id); |
b = pop_unfinished_type(); |
|
t = or_pike_types(a, b, 0); |
|
pop_n_elems(2); |
push_type_value(t); |
free_type(a); |
free_type(b); |
return; |
} |
|
STRING_BITOP(|,"OR") |
|
default: |
PIKE_ERROR("`|", "Bitwise OR on illegal type.\n", Pike_sp, 2); |
} |
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
PMOD_EXPORT void f_or(INT32 args) |
{ |
switch(args) |
{ |
case 0: SIMPLE_WRONG_NUM_ARGS_ERROR("`|", 1); |
case 1: return; |
case 2: o_or(); return; |
default: |
speedup(args, o_or); |
} |
} |
|
static int generate_or(node *n) |
{ |
struct compilation *c = THIS_COMPILATION; |
switch(count_args(CDR(n))) |
{ |
case 1: |
do_docode(CDR(n),0); |
return 1; |
|
case 2: |
do_docode(CDR(n),0); |
emit0(F_OR); |
modify_stack_depth(-1); |
return 1; |
|
default: |
return 0; |
} |
} |
|
|
PMOD_EXPORT void o_xor(void) |
{ |
if(TYPEOF(Pike_sp[-1]) != TYPEOF(Pike_sp[-2])) |
{ |
if(call_lfun(LFUN_XOR, LFUN_RXOR)) { |
return; |
} else if (((TYPEOF(Pike_sp[-1]) == T_TYPE) || |
(TYPEOF(Pike_sp[-1]) == T_PROGRAM) || |
(TYPEOF(Pike_sp[-1]) == T_FUNCTION)) && |
((TYPEOF(Pike_sp[-2]) == T_TYPE) || |
(TYPEOF(Pike_sp[-2]) == T_PROGRAM) || |
(TYPEOF(Pike_sp[-2]) == T_FUNCTION))) { |
if (TYPEOF(Pike_sp[-2]) != T_TYPE) { |
struct program *p = program_from_svalue(Pike_sp - 2); |
if (!p) { |
int args = 2; |
SIMPLE_ARG_TYPE_ERROR("`^", 1, "type"); |
} |
type_stack_mark(); |
push_object_type(0, p->id); |
free_svalue(Pike_sp - 2); |
SET_SVAL(Pike_sp[-2], T_TYPE, 0, type, pop_unfinished_type()); |
} |
if (TYPEOF(Pike_sp[-1]) != T_TYPE) { |
struct program *p = program_from_svalue(Pike_sp - 1); |
if (!p) { |
int args = 2; |
SIMPLE_ARG_TYPE_ERROR("`^", 2, "type"); |
} |
type_stack_mark(); |
push_object_type(0, p->id); |
free_svalue(Pike_sp - 1); |
SET_SVAL(Pike_sp[-1], T_TYPE, 0, type, pop_unfinished_type()); |
} |
} else { |
int args = 2; |
SIMPLE_ARG_TYPE_ERROR("`^", 2, get_name_of_type(TYPEOF(Pike_sp[-2]))); |
} |
} |
|
switch(TYPEOF(Pike_sp[-2])) |
{ |
case T_OBJECT: |
if(!call_lfun(LFUN_XOR,LFUN_RXOR)) |
PIKE_ERROR("`^", "Bitwise xor on objects without `^ operator.\n", Pike_sp, 2); |
return; |
|
case T_INT: |
Pike_sp--; |
SET_SVAL(Pike_sp[-1], T_INT, NUMBER_NUMBER, integer, |
Pike_sp[-1].u.integer ^ Pike_sp[0].u.integer); |
return; |
|
case T_MAPPING: |
{ |
struct mapping *m; |
m=merge_mappings(Pike_sp[-2].u.mapping, Pike_sp[-1].u.mapping, PIKE_ARRAY_OP_XOR); |
pop_n_elems(2); |
push_mapping(m); |
return; |
} |
|
case T_MULTISET: |
{ |
struct multiset *l; |
l=merge_multisets(Pike_sp[-2].u.multiset, Pike_sp[-1].u.multiset, |
PIKE_ARRAY_OP_XOR); |
pop_n_elems(2); |
push_multiset(l); |
return; |
} |
|
case T_ARRAY: |
{ |
struct array *a; |
a=merge_array_with_order(Pike_sp[-2].u.array, Pike_sp[-1].u.array, PIKE_ARRAY_OP_XOR); |
pop_n_elems(2); |
push_array(a); |
return; |
} |
|
case T_FUNCTION: |
case T_PROGRAM: |
{ |
struct program *p; |
|
p = program_from_svalue(Pike_sp - 1); |
if (!p) { |
int args = 2; |
SIMPLE_ARG_TYPE_ERROR("`^", 2, "type"); |
} |
type_stack_mark(); |
push_object_type(0, p->id); |
pop_stack(); |
push_type_value(pop_unfinished_type()); |
|
stack_swap(); |
|
p = program_from_svalue(Pike_sp - 1); |
if (!p) { |
int args = 2; |
stack_swap(); |
SIMPLE_ARG_TYPE_ERROR("`^", 1, "type"); |
} |
type_stack_mark(); |
push_object_type(0, p->id); |
pop_stack(); |
push_type_value(pop_unfinished_type()); |
} |
|
case T_TYPE: |
{ |
|
struct pike_type *a; |
struct pike_type *b; |
copy_pike_type(a, Pike_sp[-2].u.type); |
copy_pike_type(b, Pike_sp[-1].u.type); |
o_compl(); |
o_and(); |
push_type_value(a); |
o_compl(); |
push_type_value(b); |
o_and(); |
o_or(); |
return; |
} |
|
STRING_BITOP(^,"XOR") |
|
default: |
PIKE_ERROR("`^", "Bitwise XOR on illegal type.\n", Pike_sp, 2); |
} |
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
PMOD_EXPORT void f_xor(INT32 args) |
{ |
switch(args) |
{ |
case 0: SIMPLE_WRONG_NUM_ARGS_ERROR("`^", 1); |
case 1: return; |
case 2: o_xor(); return; |
default: |
speedup(args, o_xor); |
} |
} |
|
static int generate_xor(node *n) |
{ |
struct compilation *c = THIS_COMPILATION; |
switch(count_args(CDR(n))) |
{ |
case 1: |
do_docode(CDR(n),0); |
return 1; |
|
case 2: |
do_docode(CDR(n),0); |
emit0(F_XOR); |
modify_stack_depth(-1); |
return 1; |
|
default: |
return 0; |
} |
} |
|
PMOD_EXPORT void o_lsh(void) |
{ |
int args = 2; |
if ((TYPEOF(Pike_sp[-2]) == T_OBJECT) || |
(TYPEOF(Pike_sp[-1]) == T_OBJECT)) |
goto call_lfun; |
|
if ((TYPEOF(Pike_sp[-1]) != T_INT) || (Pike_sp[-1].u.integer < 0)) { |
SIMPLE_ARG_TYPE_ERROR("`<<", 2, "int(0..)|object"); |
} |
|
switch(TYPEOF(Pike_sp[-2])) { |
case T_INT: |
if (!INT_TYPE_LSH_OVERFLOW(Pike_sp[-2].u.integer, Pike_sp[-1].u.integer)) |
break; |
convert_stack_top_to_bignum(); |
|
|
|
case T_OBJECT: |
call_lfun: |
if(call_lfun(LFUN_LSH, LFUN_RLSH)) |
return; |
|
if(TYPEOF(Pike_sp[-2]) != T_INT) |
SIMPLE_ARG_TYPE_ERROR("`<<", 1, "int|float|object"); |
SIMPLE_ARG_TYPE_ERROR("`<<", 2, "int(0..)|object"); |
break; |
|
case T_FLOAT: |
Pike_sp--; |
Pike_sp[-1].u.float_number = ldexp(Pike_sp[-1].u.float_number, |
Pike_sp->u.integer); |
return; |
|
default: |
SIMPLE_ARG_TYPE_ERROR("`<<", 1, "int|float|object"); |
break; |
} |
|
Pike_sp--; |
SET_SVAL(Pike_sp[-1], T_INT, NUMBER_NUMBER, integer, |
Pike_sp[-1].u.integer << Pike_sp->u.integer); |
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
PMOD_EXPORT void f_lsh(INT32 args) |
{ |
if(args != 2) |
SIMPLE_WRONG_NUM_ARGS_ERROR("`<<", 2); |
o_lsh(); |
} |
|
static int generate_lsh(node *n) |
{ |
struct compilation *c = THIS_COMPILATION; |
if(count_args(CDR(n))==2) |
{ |
do_docode(CDR(n),DO_NOT_COPY_TOPLEVEL); |
emit0(F_LSH); |
modify_stack_depth(-1); |
return 1; |
} |
return 0; |
} |
|
PMOD_EXPORT void o_rsh(void) |
{ |
int args = 2; |
if ((TYPEOF(Pike_sp[-2]) == T_OBJECT) || (TYPEOF(Pike_sp[-1]) == T_OBJECT)) |
{ |
if(call_lfun(LFUN_RSH, LFUN_RRSH)) |
return; |
if(TYPEOF(Pike_sp[-2]) != T_INT) |
SIMPLE_ARG_TYPE_ERROR("`>>", 1, "int|object"); |
SIMPLE_ARG_TYPE_ERROR("`>>", 2, "int(0..)|object"); |
} |
|
if ((TYPEOF(Pike_sp[-1]) != T_INT) || (Pike_sp[-1].u.integer < 0)) { |
SIMPLE_ARG_TYPE_ERROR("`>>", 2, "int(0..)|object"); |
} |
|
Pike_sp--; |
switch(TYPEOF(Pike_sp[-1])) { |
case T_INT: |
if( INT_TYPE_RSH_OVERFLOW(Pike_sp[-1].u.integer, Pike_sp->u.integer) ) |
{ |
if (Pike_sp[-1].u.integer < 0) { |
SET_SVAL(Pike_sp[-1], T_INT, NUMBER_NUMBER, integer, -1); |
} else { |
SET_SVAL(Pike_sp[-1], T_INT, NUMBER_NUMBER, integer, 0); |
} |
return; |
} |
break; |
case T_FLOAT: |
Pike_sp[-1].u.float_number = ldexp(Pike_sp[-1].u.float_number, |
-Pike_sp->u.integer); |
return; |
default: |
SIMPLE_ARG_TYPE_ERROR("`>>", 1, "int|float|object"); |
break; |
} |
|
SET_SVAL(Pike_sp[-1], T_INT, NUMBER_NUMBER, integer, |
Pike_sp[-1].u.integer >> Pike_sp->u.integer); |
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
PMOD_EXPORT void f_rsh(INT32 args) |
{ |
if(args != 2) |
SIMPLE_WRONG_NUM_ARGS_ERROR("`>>", 2); |
o_rsh(); |
} |
|
static int generate_rsh(node *n) |
{ |
if(count_args(CDR(n))==2) |
{ |
struct compilation *c = THIS_COMPILATION; |
do_docode(CDR(n),DO_NOT_COPY); |
emit0(F_RSH); |
modify_stack_depth(-1); |
return 1; |
} |
return 0; |
} |
|
|
#define TWO_TYPES(X,Y) (((X)<<8)|(Y)) |
PMOD_EXPORT void o_multiply(void) |
{ |
int args = 2; |
switch(TWO_TYPES(TYPEOF(Pike_sp[-2]), TYPEOF(Pike_sp[-1]))) |
{ |
case TWO_TYPES(T_ARRAY, T_INT): |
{ |
struct array *ret; |
struct svalue *pos; |
INT32 e; |
if(Pike_sp[-1].u.integer < 0) |
SIMPLE_ARG_TYPE_ERROR("`*", 2, "int(0..)"); |
ret=allocate_array(Pike_sp[-2].u.array->size * Pike_sp[-1].u.integer); |
pos=ret->item; |
for(e=0;e<Pike_sp[-1].u.integer;e++,pos+=Pike_sp[-2].u.array->size) |
assign_svalues_no_free(pos, |
Pike_sp[-2].u.array->item, |
Pike_sp[-2].u.array->size, |
Pike_sp[-2].u.array->type_field); |
ret->type_field=Pike_sp[-2].u.array->type_field; |
pop_n_elems(2); |
push_array(ret); |
return; |
} |
|
case TWO_TYPES(T_ARRAY, T_FLOAT): |
{ |
struct array *src; |
struct array *ret; |
struct svalue *pos; |
ptrdiff_t asize, delta; |
if(Pike_sp[-1].u.float_number < 0) |
SIMPLE_ARG_TYPE_ERROR("`*", 2, "float(0..)"); |
|
src = Pike_sp[-2].u.array; |
delta = src->size; |
asize = (ptrdiff_t)floor(delta * Pike_sp[-1].u.float_number + 0.5); |
ret = allocate_array(asize); |
pos = ret->item; |
if (asize > delta) { |
ret->type_field = src->type_field; |
assign_svalues_no_free(pos, |
src->item, |
delta, |
src->type_field); |
pos += delta; |
asize -= delta; |
while (asize > delta) { |
assign_svalues_no_free(pos, ret->item, delta, ret->type_field); |
pos += delta; |
asize -= delta; |
delta <<= 1; |
} |
if (asize) { |
assign_svalues_no_free(pos, ret->item, asize, ret->type_field); |
} |
} else if (asize) { |
ret->type_field = |
assign_svalues_no_free(pos, |
src->item, |
asize, |
src->type_field); |
} |
pop_n_elems(2); |
push_array(ret); |
return; |
} |
|
case TWO_TYPES(T_STRING, T_FLOAT): |
{ |
struct pike_string *src; |
struct pike_string *ret; |
char *pos; |
ptrdiff_t len, delta; |
|
if(Pike_sp[-1].u.float_number < 0) |
SIMPLE_ARG_TYPE_ERROR("`*", 2, "float(0..)"); |
src = Pike_sp[-2].u.string; |
len = (ptrdiff_t)floor(src->len * Pike_sp[-1].u.float_number + 0.5); |
ret = begin_wide_shared_string(len, src->size_shift); |
len <<= src->size_shift; |
delta = src->len << src->size_shift; |
pos = ret->str; |
|
if (len > delta) { |
memcpy(pos, src->str, delta); |
pos += delta; |
len -= delta; |
while (len > delta) { |
memcpy(pos, ret->str, delta); |
pos += delta; |
len -= delta; |
delta <<= 1; |
} |
if (len) { |
memcpy(pos, ret->str, len); |
} |
} else if (len) { |
memcpy(pos, src->str, len); |
} |
pop_n_elems(2); |
push_string(low_end_shared_string(ret)); |
return; |
} |
|
|
case TWO_TYPES(T_STRING, T_INT): |
{ |
struct pike_string *ret; |
char *pos; |
INT_TYPE e; |
ptrdiff_t len; |
if(Pike_sp[-1].u.integer < 0) |
SIMPLE_ARG_TYPE_ERROR("`*", 2, "int(0..)"); |
ret=begin_wide_shared_string(Pike_sp[-2].u.string->len * Pike_sp[-1].u.integer, |
Pike_sp[-2].u.string->size_shift); |
pos=ret->str; |
len=Pike_sp[-2].u.string->len << Pike_sp[-2].u.string->size_shift; |
for(e=0;e<Pike_sp[-1].u.integer;e++,pos+=len) |
memcpy(pos,Pike_sp[-2].u.string->str,len); |
pop_n_elems(2); |
push_string(low_end_shared_string(ret)); |
return; |
} |
|
case TWO_TYPES(T_ARRAY,T_STRING): |
{ |
struct pike_string *ret; |
ret=implode(Pike_sp[-2].u.array,Pike_sp[-1].u.string); |
free_string(Pike_sp[-1].u.string); |
free_array(Pike_sp[-2].u.array); |
SET_SVAL(Pike_sp[-2], T_STRING, 0, string, ret); |
Pike_sp--; |
return; |
} |
|
case TWO_TYPES(T_ARRAY,T_ARRAY): |
{ |
struct array *ret; |
ret=implode_array(Pike_sp[-2].u.array, Pike_sp[-1].u.array); |
pop_n_elems(2); |
push_array(ret); |
return; |
} |
|
case TWO_TYPES(T_FLOAT,T_FLOAT): |
Pike_sp--; |
Pike_sp[-1].u.float_number *= Pike_sp[0].u.float_number; |
return; |
|
case TWO_TYPES(T_FLOAT,T_INT): |
Pike_sp--; |
Pike_sp[-1].u.float_number *= (FLOAT_TYPE)Pike_sp[0].u.integer; |
return; |
|
case TWO_TYPES(T_INT,T_FLOAT): |
Pike_sp--; |
Pike_sp[-1].u.float_number= |
(FLOAT_TYPE) Pike_sp[-1].u.integer * Pike_sp[0].u.float_number; |
SET_SVAL_TYPE(Pike_sp[-1], T_FLOAT); |
return; |
|
case TWO_TYPES(T_INT,T_INT): |
{ |
INT_TYPE res; |
|
if (DO_INT_TYPE_MUL_OVERFLOW(Pike_sp[-2].u.integer, Pike_sp[-1].u.integer, &res)) |
{ |
convert_stack_top_to_bignum(); |
goto do_lfun_multiply; |
} |
|
Pike_sp--; |
SET_SVAL(Pike_sp[-1], T_INT, NUMBER_NUMBER, integer, res); |
return; |
} |
default: |
do_lfun_multiply: |
if(!call_lfun(LFUN_MULTIPLY, LFUN_RMULTIPLY)) |
PIKE_ERROR("`*", "Multiplication on objects without `* operator.\n", Pike_sp, 2); |
return; |
} |
} |
|
|
|
|
|
|
|
|
|
|
PMOD_EXPORT void f_exponent(INT32 args) |
{ |
FLOAT_ARG_TYPE a, b; |
|
if(args != 2 ) |
SIMPLE_WRONG_NUM_ARGS_ERROR("`**",2); |
|
switch( TWO_TYPES(TYPEOF(Pike_sp[-2]), TYPEOF(Pike_sp[-1])) ) |
{ |
case TWO_TYPES(T_FLOAT,T_FLOAT): |
a = Pike_sp[-2].u.float_number; |
b = Pike_sp[-1].u.float_number; |
goto res_is_powf; |
|
case TWO_TYPES(T_FLOAT,T_INT): |
a = Pike_sp[-2].u.float_number; |
b = (FLOAT_ARG_TYPE)Pike_sp[-1].u.integer; |
goto res_is_powf; |
|
case TWO_TYPES(T_INT,T_FLOAT): |
a = (FLOAT_ARG_TYPE)Pike_sp[-2].u.integer; |
b = (FLOAT_ARG_TYPE)Pike_sp[-1].u.float_number; |
|
res_is_powf: |
{ |
Pike_sp-=2; |
#if SIZEOF_FLOAT_TYPE > SIZEOF_DOUBLE |
push_float( powl( a, b ) ); |
#else |
push_float( pow( a, b ) ); |
#endif |
return; |
} |
default: |
stack_swap(); |
convert_stack_top_to_bignum(); |
stack_swap(); |
|
|
case TWO_TYPES(T_OBJECT,T_INT): |
case TWO_TYPES(T_OBJECT,T_FLOAT): |
case TWO_TYPES(T_OBJECT,T_OBJECT): |
case TWO_TYPES(T_INT,T_OBJECT): |
case TWO_TYPES(T_FLOAT,T_OBJECT): |
if( !call_lfun( LFUN_POW, LFUN_RPOW ) ) |
{ |
if( TYPEOF(Pike_sp[-2]) != PIKE_T_OBJECT ) |
{ |
stack_swap(); |
convert_stack_top_to_bignum(); |
stack_swap(); |
if( call_lfun( LFUN_POW, LFUN_RPOW ) ) |
return; |
} |
Pike_error("Illegal argument 1 to `** (object missing implementation of `**).\n"); |
} |
return; |
} |
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
PMOD_EXPORT void f_multiply(INT32 args) |
{ |
switch(args) |
{ |
case 0: SIMPLE_WRONG_NUM_ARGS_ERROR("`*", 1); |
case 1: return; |
case 2: o_multiply(); return; |
default: |
{ |
INT32 i = -args, j = -1; |
|
while(i < j) { |
struct svalue tmp = Pike_sp[i]; |
Pike_sp[i++] = Pike_sp[j]; |
Pike_sp[j--] = tmp; |
} |
while(--args > 0) { |
|
stack_swap(); |
o_multiply(); |
} |
} |
} |
} |
|
static int generate_multiply(node *n) |
{ |
struct compilation *c = THIS_COMPILATION; |
switch(count_args(CDR(n))) |
{ |
case 1: |
do_docode(CDR(n),0); |
return 1; |
|
case 2: |
do_docode(CDR(n),0); |
emit0(F_MULTIPLY); |
modify_stack_depth(-1); |
return 1; |
|
default: |
return 0; |
} |
} |
|
PMOD_EXPORT void o_divide(void) |
{ |
if(TYPEOF(Pike_sp[-2]) != TYPEOF(Pike_sp[-1]) && !float_promote()) |
{ |
if(call_lfun(LFUN_DIVIDE, LFUN_RDIVIDE)) |
return; |
|
switch(TWO_TYPES(TYPEOF(Pike_sp[-2]), TYPEOF(Pike_sp[-1]))) |
{ |
case TWO_TYPES(T_STRING,T_INT): |
{ |
struct array *a; |
INT_TYPE len; |
ptrdiff_t size,e,pos=0; |
|
len=Pike_sp[-1].u.integer; |
if(!len) |
OP_DIVISION_BY_ZERO_ERROR("`/"); |
|
if(len<0) |
{ |
len=-len; |
size=Pike_sp[-2].u.string->len / len; |
pos+=Pike_sp[-2].u.string->len % len; |
}else{ |
size=Pike_sp[-2].u.string->len / len; |
} |
a=allocate_array(size); |
for(e=0;e<size;e++) |
{ |
SET_SVAL(a->item[e], T_STRING, 0, string, |
string_slice(Pike_sp[-2].u.string, pos,len)); |
pos+=len; |
} |
a->type_field=BIT_STRING; |
pop_n_elems(2); |
push_array(a); |
return; |
} |
|
case TWO_TYPES(T_STRING,T_FLOAT): |
{ |
struct array *a; |
ptrdiff_t size, pos, last, e; |
FLOAT_ARG_TYPE len; |
|
len=Pike_sp[-1].u.float_number; |
if(len==0.0) |
OP_DIVISION_BY_ZERO_ERROR("`/"); |
|
if(len<0) |
{ |
len=-len; |
size=(ptrdiff_t)ceil( ((double)Pike_sp[-2].u.string->len) / len); |
a=allocate_array(size); |
|
for(last=Pike_sp[-2].u.string->len,e=0;e<size-1;e++) |
{ |
pos=Pike_sp[-2].u.string->len - (ptrdiff_t)((e+1)*len+0.5); |
SET_SVAL(a->item[size-1-e], T_STRING, 0, string, |
string_slice(Pike_sp[-2].u.string, pos, last-pos)); |
last=pos; |
} |
pos=0; |
SET_SVAL(a->item[0], T_STRING, 0, string, |
string_slice(Pike_sp[-2].u.string, pos, last-pos)); |
}else{ |
size=(ptrdiff_t)ceil( ((double)Pike_sp[-2].u.string->len) / len); |
a=allocate_array(size); |
|
for(last=0,e=0;e<size-1;e++) |
{ |
pos = (ptrdiff_t)((e+1)*len+0.5); |
SET_SVAL(a->item[e], T_STRING, 0, string, |
string_slice(Pike_sp[-2].u.string, last, pos-last)); |
last=pos; |
} |
pos=Pike_sp[-2].u.string->len; |
SET_SVAL(a->item[e], T_STRING, 0, string, |
string_slice(Pike_sp[-2].u.string, last, pos-last)); |
} |
a->type_field=BIT_STRING; |
pop_n_elems(2); |
push_array(a); |
return; |
} |
|
|
case TWO_TYPES(T_ARRAY, T_INT): |
{ |
struct array *a; |
ptrdiff_t size,e,pos; |
|
INT_TYPE len=Pike_sp[-1].u.integer; |
if(!len) |
OP_DIVISION_BY_ZERO_ERROR("`/"); |
|
if (!Pike_sp[-2].u.array->size) { |
pop_n_elems (2); |
ref_push_array (&empty_array); |
return; |
} |
|
if(len<0) |
{ |
len = -len; |
pos = Pike_sp[-2].u.array->size % len; |
}else{ |
pos = 0; |
} |
size = Pike_sp[-2].u.array->size / len; |
|
a=allocate_array(size); |
for(e=0;e<size;e++) |
{ |
SET_SVAL(a->item[e], T_ARRAY, 0, array, |
friendly_slice_array(Pike_sp[-2].u.array, pos, pos+len)); |
pos+=len; |
} |
a->type_field=BIT_ARRAY; |
pop_n_elems(2); |
push_array(a); |
return; |
} |
|
case TWO_TYPES(T_ARRAY,T_FLOAT): |
{ |
struct array *a; |
ptrdiff_t last,pos,e,size; |
FLOAT_ARG_TYPE len; |
|
len=Pike_sp[-1].u.float_number; |
if(len==0.0) |
OP_DIVISION_BY_ZERO_ERROR("`/"); |
|
if (!Pike_sp[-2].u.array->size) { |
pop_n_elems (2); |
ref_push_array (&empty_array); |
return; |
} |
|
if(len<0) |
{ |
len=-len; |
size = (ptrdiff_t)ceil( ((double)Pike_sp[-2].u.array->size) / len); |
a=allocate_array(size); |
|
for(last=Pike_sp[-2].u.array->size,e=0;e<size-1;e++) |
{ |
pos=Pike_sp[-2].u.array->size - (ptrdiff_t)((e+1)*len+0.5); |
SET_SVAL(a->item[size-1-e], T_ARRAY, 0, array, |
friendly_slice_array(Pike_sp[-2].u.array, pos, last)); |
last=pos; |
} |
SET_SVAL(a->item[0], T_ARRAY, 0, array, |
slice_array(Pike_sp[-2].u.array, 0, last)); |
}else{ |
size = (ptrdiff_t)ceil( ((double)Pike_sp[-2].u.array->size) / len); |
a=allocate_array(size); |
|
for(last=0,e=0;e<size-1;e++) |
{ |
pos = (ptrdiff_t)((e+1)*len+0.5); |
SET_SVAL(a->item[e], T_ARRAY, 0, array, |
friendly_slice_array(Pike_sp[-2].u.array, last, pos)); |
last=pos; |
} |
SET_SVAL(a->item[e], T_ARRAY, 0, array, |
slice_array(Pike_sp[-2].u.array, last, Pike_sp[-2].u.array->size)); |
} |
a->type_field=BIT_ARRAY; |
pop_n_elems(2); |
push_array(a); |
return; |
} |
} |
|
PIKE_ERROR("`/", "Division on different types.\n", Pike_sp, 2); |
} |
|
switch(TYPEOF(Pike_sp[-2])) |
{ |
case T_OBJECT: |
if(!call_lfun(LFUN_DIVIDE,LFUN_RDIVIDE)) |
PIKE_ERROR("`/", "Division on objects without `/ operator.\n", Pike_sp, 2); |
return; |
|
case T_STRING: |
{ |
struct array *ret; |
ret=explode(Pike_sp[-2].u.string,Pike_sp[-1].u.string); |
free_string(Pike_sp[-2].u.string); |
free_string(Pike_sp[-1].u.string); |
SET_SVAL(Pike_sp[-2], T_ARRAY, 0, array, ret); |
Pike_sp--; |
return; |
} |
|
case T_ARRAY: |
{ |
struct array *ret=explode_array(Pike_sp[-2].u.array, Pike_sp[-1].u.array); |
pop_n_elems(2); |
push_array(ret); |
return; |
} |
|
case T_FLOAT: |
if(Pike_sp[-1].u.float_number == 0.0) |
OP_DIVISION_BY_ZERO_ERROR("`/"); |
Pike_sp--; |
Pike_sp[-1].u.float_number /= Pike_sp[0].u.float_number; |
return; |
|
case T_INT: |
{ |
INT_TYPE tmp; |
|
if (Pike_sp[-1].u.integer == 0) |
OP_DIVISION_BY_ZERO_ERROR("`/"); |
|
if(INT_TYPE_DIV_OVERFLOW(Pike_sp[-2].u.integer, Pike_sp[-1].u.integer)) |
{ |
stack_swap(); |
convert_stack_top_to_bignum(); |
stack_swap(); |
if (LIKELY(call_lfun(LFUN_DIVIDE,LFUN_RDIVIDE))) { |
return; |
} |
Pike_fatal("Failed to call `/() in bignum.\n"); |
} |
else |
tmp = Pike_sp[-2].u.integer/Pike_sp[-1].u.integer; |
Pike_sp--; |
|
|
|
if((Pike_sp[-1].u.integer<0) != (Pike_sp[0].u.integer<0)) |
if(tmp*Pike_sp[0].u.integer!=Pike_sp[-1].u.integer) |
tmp--; |
SET_SVAL(Pike_sp[-1], T_INT, NUMBER_NUMBER, integer, tmp); |
return; |
} |
|
default: |
PIKE_ERROR("`/", "Bad argument 1.\n", Pike_sp, 2); |
} |
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
PMOD_EXPORT void f_divide(INT32 args) |
{ |
switch(args) |
{ |
case 0: |
case 1: SIMPLE_WRONG_NUM_ARGS_ERROR("`/", 2); |
case 2: o_divide(); break; |
default: |
{ |
INT32 e; |
struct svalue *s=Pike_sp-args; |
push_svalue(s); |
for(e=1;e<args;e++) |
{ |
push_svalue(s+e); |
o_divide(); |
} |
assign_svalue(s,Pike_sp-1); |
pop_n_elems(Pike_sp-s-1); |
} |
} |
} |
|
static int generate_divide(node *n) |
{ |
if(count_args(CDR(n))==2) |
{ |
struct compilation *c = THIS_COMPILATION; |
do_docode(CDR(n),DO_NOT_COPY_TOPLEVEL); |
emit0(F_DIVIDE); |
modify_stack_depth(-1); |
return 1; |
} |
return 0; |
} |
|
PMOD_EXPORT void o_mod(void) |
{ |
if(TYPEOF(Pike_sp[-2]) != TYPEOF(Pike_sp[-1]) && !float_promote()) |
{ |
do_lfun_modulo: |
if(call_lfun(LFUN_MOD, LFUN_RMOD)) |
return; |
|
switch(TWO_TYPES(TYPEOF(Pike_sp[-2]), TYPEOF(Pike_sp[-1]))) |
{ |
case TWO_TYPES(T_STRING,T_INT): |
{ |
struct pike_string *s=Pike_sp[-2].u.string; |
ptrdiff_t tmp,base; |
|
if(!Pike_sp[-1].u.integer) |
OP_MODULO_BY_ZERO_ERROR("`%"); |
|
if(Pike_sp[-1].u.integer<0) |
{ |
tmp=s->len % -Pike_sp[-1].u.integer; |
base=0; |
}else{ |
tmp=s->len % Pike_sp[-1].u.integer; |
base=s->len - tmp; |
} |
s=string_slice(s, base, tmp); |
pop_n_elems(2); |
push_string(s); |
return; |
} |
|
|
case TWO_TYPES(T_ARRAY,T_INT): |
{ |
struct array *a=Pike_sp[-2].u.array; |
ptrdiff_t tmp,base; |
if(!Pike_sp[-1].u.integer) |
OP_MODULO_BY_ZERO_ERROR("`%"); |
|
if(Pike_sp[-1].u.integer<0) |
{ |
tmp=a->size % -Pike_sp[-1].u.integer; |
base=0; |
}else{ |
tmp=a->size % Pike_sp[-1].u.integer; |
base=a->size - tmp; |
} |
|
a=slice_array(a,base,base+tmp); |
pop_n_elems(2); |
push_array(a); |
return; |
} |
} |
|
PIKE_ERROR("`%", "Modulo on different types.\n", Pike_sp, 2); |
} |
|
switch(TYPEOF(Pike_sp[-2])) |
{ |
case T_OBJECT: |
if(!call_lfun(LFUN_MOD,LFUN_RMOD)) |
PIKE_ERROR("`%", "Modulo on objects without `% operator.\n", Pike_sp, 2); |
return; |
|
case T_FLOAT: |
{ |
FLOAT_TYPE foo; |
if(Pike_sp[-1].u.float_number == 0.0) |
OP_MODULO_BY_ZERO_ERROR("`%"); |
Pike_sp--; |
foo = (FLOAT_TYPE)(Pike_sp[-1].u.float_number / Pike_sp[0].u.float_number); |
foo = (FLOAT_TYPE)(Pike_sp[-1].u.float_number - |
Pike_sp[0].u.float_number * floor(foo)); |
Pike_sp[-1].u.float_number=foo; |
return; |
} |
case T_INT: |
{ |
int of = 0; |
INT_TYPE a = Pike_sp[-2].u.integer, |
b = Pike_sp[-1].u.integer; |
INT_TYPE res; |
if (b == 0) |
OP_MODULO_BY_ZERO_ERROR("`%"); |
if(a>=0) |
{ |
if(b>=0) |
{ |
res = a % b; |
}else{ |
|
of = DO_INT_TYPE_ADD_OVERFLOW(a, ~b, &res) |
|| DO_INT_TYPE_MOD_OVERFLOW(res, b, &res) |
|| DO_INT_TYPE_SUB_OVERFLOW(res, ~b, &res); |
} |
}else{ |
if(b>=0) |
{ |
|
of = DO_INT_TYPE_MOD_OVERFLOW(~a, b, &res) |
|| DO_INT_TYPE_ADD_OVERFLOW(b, ~res, &res); |
}else{ |
|
|
|
of = DO_INT_TYPE_MOD_OVERFLOW(a, b, &res); |
} |
} |
if (of) { |
stack_swap(); |
convert_stack_top_to_bignum(); |
stack_swap(); |
goto do_lfun_modulo; |
} |
Pike_sp--; |
SET_SVAL(Pike_sp[-1], T_INT, NUMBER_NUMBER, integer, res); |
return; |
} |
default: |
PIKE_ERROR("`%", "Bad argument 1.\n", Pike_sp, 2); |
} |
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
PMOD_EXPORT void f_mod(INT32 args) |
{ |
if(args != 2) |
SIMPLE_WRONG_NUM_ARGS_ERROR("`%", 2); |
o_mod(); |
} |
|
static int generate_mod(node *n) |
{ |
if(count_args(CDR(n))==2) |
{ |
struct compilation *c = THIS_COMPILATION; |
do_docode(CDR(n),DO_NOT_COPY_TOPLEVEL); |
emit0(F_MOD); |
modify_stack_depth(-1); |
return 1; |
} |
return 0; |
} |
|
PMOD_EXPORT void o_not(void) |
{ |
switch(TYPEOF(Pike_sp[-1])) |
{ |
case T_INT: |
SET_SVAL(Pike_sp[-1], T_INT, NUMBER_NUMBER, integer, !Pike_sp[-1].u.integer); |
break; |
|
case T_FUNCTION: |
case T_OBJECT: |
if(UNSAFE_IS_ZERO(Pike_sp-1)) |
{ |
pop_stack(); |
push_int(1); |
}else{ |
pop_stack(); |
push_int(0); |
} |
break; |
|
default: |
free_svalue(Pike_sp-1); |
SET_SVAL(Pike_sp[-1], T_INT, NUMBER_NUMBER, integer, 0); |
} |
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
PMOD_EXPORT void f_not(INT32 args) |
{ |
if(args != 1) |
SIMPLE_WRONG_NUM_ARGS_ERROR("`!", 1); |
o_not(); |
} |
|
static int generate_not(node *n) |
{ |
if(count_args(CDR(n))==1) |
{ |
struct compilation *c = THIS_COMPILATION; |
do_docode(CDR(n),DO_NOT_COPY); |
emit0(F_NOT); |
return 1; |
} |
return 0; |
} |
|
PMOD_EXPORT void o_compl(void) |
{ |
switch(TYPEOF(Pike_sp[-1])) |
{ |
case T_OBJECT: |
if(!call_lhs_lfun(LFUN_COMPL,1)) |
PIKE_ERROR("`~", "Complement on object without `~ operator.\n", Pike_sp, 1); |
stack_pop_keep_top(); |
break; |
|
case T_INT: |
SET_SVAL(Pike_sp[-1], T_INT, NUMBER_NUMBER, integer, ~Pike_sp[-1].u.integer); |
break; |
|
case T_FLOAT: |
Pike_sp[-1].u.float_number = (FLOAT_TYPE) -1.0 - Pike_sp[-1].u.float_number; |
break; |
|
case T_TYPE: |
type_stack_mark(); |
if (Pike_sp[-1].u.type->type == T_NOT) { |
push_finished_type(Pike_sp[-1].u.type->car); |
} else { |
push_finished_type(Pike_sp[-1].u.type); |
push_type(T_NOT); |
} |
pop_stack(); |
push_type_value(pop_unfinished_type()); |
break; |
|
case T_FUNCTION: |
case T_PROGRAM: |
{ |
|
struct program *p = program_from_svalue(Pike_sp - 1); |
if (!p) { |
PIKE_ERROR("`~", "Bad argument.\n", Pike_sp, 1); |
} |
type_stack_mark(); |
push_object_type(0, p->id); |
push_type(T_NOT); |
pop_stack(); |
push_type_value(pop_unfinished_type()); |
} |
break; |
|
case T_STRING: |
{ |
struct pike_string *s; |
ptrdiff_t len, i; |
|
if(Pike_sp[-1].u.string->size_shift) { |
bad_arg_error("`~", 1, 1, "string(0)", Pike_sp-1, |
"Expected 8-bit string.\n"); |
} |
|
len = Pike_sp[-1].u.string->len; |
s = begin_shared_string(len); |
for (i=0; i<len; i++) |
s->str[i] = ~ Pike_sp[-1].u.string->str[i]; |
pop_n_elems(1); |
push_string(end_shared_string(s)); |
break; |
} |
|
default: |
PIKE_ERROR("`~", "Bad argument.\n", Pike_sp, 1); |
} |
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
PMOD_EXPORT void f_compl(INT32 args) |
{ |
if(args != 1) |
SIMPLE_WRONG_NUM_ARGS_ERROR("`~", 1); |
o_compl(); |
} |
|
static int generate_compl(node *n) |
{ |
if(count_args(CDR(n))==1) |
{ |
struct compilation *c = THIS_COMPILATION; |
do_docode(CDR(n),DO_NOT_COPY); |
emit0(F_COMPL); |
return 1; |
} |
return 0; |
} |
|
PMOD_EXPORT void o_negate(void) |
{ |
switch(TYPEOF(Pike_sp[-1])) |
{ |
case T_OBJECT: |
do_lfun_negate: |
if(!call_lhs_lfun(LFUN_SUBTRACT,1)) |
PIKE_ERROR("`-", "Negate on object without `- operator.\n", Pike_sp, 1); |
stack_pop_keep_top(); |
break; |
|
case T_FLOAT: |
Pike_sp[-1].u.float_number=-Pike_sp[-1].u.float_number; |
return; |
|
case T_INT: |
if(INT_TYPE_NEG_OVERFLOW(Pike_sp[-1].u.integer)) |
{ |
convert_stack_top_to_bignum(); |
goto do_lfun_negate; |
} |
SET_SVAL(Pike_sp[-1], T_INT, NUMBER_NUMBER, integer, -Pike_sp[-1].u.integer); |
return; |
|
case T_TYPE: |
o_compl(); |
return; |
|
default: |
PIKE_ERROR("`-", "Bad argument to unary minus.\n", Pike_sp, 1); |
} |
} |
|
static void string_or_array_range (int bound_types, |
struct svalue *ind, |
INT_TYPE low, |
INT_TYPE high) |
|
|
{ |
INT32 from, to, len; |
|
if (TYPEOF(*ind) == T_STRING) |
len = ind->u.string->len; |
else { |
#ifdef PIKE_DEBUG |
if (!ind || TYPEOF(*ind) != T_ARRAY) Pike_fatal ("Invalid ind svalue.\n"); |
#endif |
len = ind->u.array->size; |
} |
|
if (bound_types & RANGE_LOW_OPEN) |
from = 0; |
else { |
if (bound_types & RANGE_LOW_FROM_END) { |
if (low >= len) from = 0; |
else if (low < 0) from = len; |
else from = len - 1 - low; |
} else { |
if (low < 0) from = 0; |
else if (low > len) from = len; |
else from = low; |
} |
} |
|
if (bound_types & RANGE_HIGH_OPEN) |
to = len; |
else { |
if (bound_types & RANGE_HIGH_FROM_END) { |
if (high > len - from) to = from; |
else if (high <= 0) to = len; |
else to = len - high; |
} else { |
if (high < from) to = from; |
else if (high >= len) to = len; |
else to = high + 1; |
} |
} |
|
if (TYPEOF(*ind) == T_STRING) { |
struct pike_string *s; |
if (from == 0 && to == len) return; |
|
s=string_slice(ind->u.string, from, to-from); |
free_string(ind->u.string); |
ind->u.string=s; |
} |
|
else { |
struct array *a; |
a = slice_array(ind->u.array, from, to); |
free_array(ind->u.array); |
ind->u.array=a; |
} |
} |
|
static int call_old_range_lfun (int bound_types, struct object *o, |
struct svalue *low, struct svalue *high) |
|
|
|
{ |
struct svalue end_pos; |
ONERROR uwp; |
int f; |
|
if ((f = FIND_LFUN (o->prog, LFUN_INDEX)) == -1) |
return 1; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (bound_types & (RANGE_LOW_FROM_END|RANGE_HIGH_FROM_END)) { |
int f2 = FIND_LFUN (o->prog, LFUN__SIZEOF); |
if (f2 == -1) |
return 2; |
apply_low (o, f2, 0); |
push_int (1); |
o_subtract(); |
move_svalue (&end_pos, --Pike_sp); |
SET_ONERROR (uwp, do_free_svalue, &end_pos); |
} |
|
switch (bound_types & (RANGE_LOW_FROM_BEG|RANGE_LOW_FROM_END|RANGE_LOW_OPEN)) { |
case RANGE_LOW_FROM_BEG: |
move_svalue (Pike_sp++, low); |
mark_free_svalue (low); |
break; |
case RANGE_LOW_OPEN: |
push_int (0); |
break; |
default: |
push_svalue (&end_pos); |
move_svalue (Pike_sp++, low); |
mark_free_svalue (low); |
o_subtract(); |
break; |
} |
|
switch (bound_types & (RANGE_HIGH_FROM_BEG|RANGE_HIGH_FROM_END|RANGE_HIGH_OPEN)) { |
case RANGE_HIGH_FROM_BEG: |
move_svalue (Pike_sp++, high); |
mark_free_svalue (high); |
break; |
case RANGE_HIGH_OPEN: |
push_int (MAX_INT_TYPE); |
break; |
default: |
push_svalue (&end_pos); |
move_svalue (Pike_sp++, high); |
mark_free_svalue (high); |
o_subtract(); |
break; |
} |
|
if (bound_types & (RANGE_LOW_FROM_END|RANGE_HIGH_FROM_END)) { |
UNSET_ONERROR (uwp); |
free_svalue (&end_pos); |
|
|
if (!o->prog) |
return 3; |
} |
|
apply_low (o, f, 2); |
return 0; |
} |
|
static const char *range_func_name (int bound_types) |
{ |
|
|
switch (bound_types) { |
case RANGE_LOW_FROM_BEG|RANGE_HIGH_FROM_BEG: return "arg1[arg2..arg3]"; |
case RANGE_LOW_FROM_BEG|RANGE_HIGH_FROM_END: return "arg1[arg2..<arg3]"; |
case RANGE_LOW_FROM_BEG|RANGE_HIGH_OPEN: return "arg1[arg2..]"; |
case RANGE_LOW_FROM_END|RANGE_HIGH_FROM_BEG: return "arg1[<arg2..arg3]"; |
case RANGE_LOW_FROM_END|RANGE_HIGH_FROM_END: return "arg1[<arg2..<arg3]"; |
case RANGE_LOW_FROM_END|RANGE_HIGH_OPEN: return "arg1[<arg2..]"; |
case RANGE_LOW_OPEN|RANGE_HIGH_FROM_BEG: return "arg1[..arg2]"; |
case RANGE_LOW_OPEN|RANGE_HIGH_FROM_END: return "arg1[..<arg2]"; |
case RANGE_LOW_OPEN|RANGE_HIGH_OPEN: return "arg1[..]"; |
#ifdef PIKE_DEBUG |
default: |
Pike_fatal ("Unexpected bound_types.\n"); |
#endif |
} |
UNREACHABLE(return "Unexpected bound_types"); |
} |
|
PMOD_EXPORT void o_range2 (int bound_types) |
|
|
{ |
struct svalue *ind, *low, *high; |
|
high = bound_types & RANGE_HIGH_OPEN ? Pike_sp : Pike_sp - 1; |
low = bound_types & RANGE_LOW_OPEN ? high : high - 1; |
ind = low - 1; |
|
switch (TYPEOF(*ind)) { |
case T_OBJECT: { |
struct object *o = ind->u.object; |
int f; |
if (!o->prog) |
bad_arg_error (range_func_name (bound_types), |
Pike_sp - ind, 1, "object", ind, |
"Cannot call `[..] in destructed object.\n"); |
|
if ((f = FIND_LFUN(o->prog->inherits[SUBTYPEOF(*ind)].prog, |
LFUN_RANGE)) != -1) { |
struct svalue h; |
if (!(bound_types & RANGE_HIGH_OPEN)) { |
move_svalue (&h, high); |
Pike_sp = high; |
} |
|
if (bound_types & RANGE_LOW_FROM_BEG) |
push_int (INDEX_FROM_BEG); |
else if (bound_types & RANGE_LOW_OPEN) { |
push_int (0); |
push_int (OPEN_BOUND); |
} |
else |
push_int (INDEX_FROM_END); |
|
if (bound_types & RANGE_HIGH_FROM_BEG) { |
move_svalue (Pike_sp++, &h); |
push_int (INDEX_FROM_BEG); |
} |
else if (bound_types & RANGE_HIGH_OPEN) { |
push_int (0); |
push_int (OPEN_BOUND); |
} |
else { |
move_svalue (Pike_sp++, &h); |
push_int (INDEX_FROM_END); |
} |
|
apply_low (o, f, 4); |
stack_pop_keep_top(); |
} |
|
else |
switch (call_old_range_lfun (bound_types, o, low, high)) { |
case 1: |
bad_arg_error (range_func_name (bound_types), |
Pike_sp - ind, 1, "object", ind, |
"Object got neither `[..] nor `[].\n"); |
break; |
case 2: |
bad_arg_error (range_func_name (bound_types), |
Pike_sp - ind, 1, "object", ind, |
"Object got no `[..] and there is no _sizeof to " |
"translate the from-the-end index to use `[].\n"); |
break; |
case 3: |
bad_arg_error (range_func_name (bound_types), |
3, 1, "object", ind, |
"Cannot call `[..] in destructed object.\n"); |
break; |
default: |
free_svalue (ind); |
move_svalue (ind, Pike_sp - 1); |
|
Pike_sp = ind + 1; |
break; |
} |
|
break; |
} |
|
case T_STRING: |
case T_ARRAY: { |
INT_TYPE l=0, h=0; |
if (!(bound_types & RANGE_LOW_OPEN)) { |
if (TYPEOF(*low) != T_INT) |
bad_arg_error (range_func_name (bound_types), |
Pike_sp - ind, 2, "int", low, |
"Bad lower bound. Expected int, got %s.\n", |
get_name_of_type (TYPEOF(*low))); |
l = low->u.integer; |
} |
if (!(bound_types & RANGE_HIGH_OPEN)) { |
if (TYPEOF(*high) != T_INT) |
bad_arg_error (range_func_name (bound_types), |
Pike_sp - ind, high - ind + 1, "int", high, |
"Bad upper bound. Expected int, got %s.\n", |
get_name_of_type (TYPEOF(*high))); |
h = high->u.integer; |
} |
|
|
Pike_sp = ind + 1; |
|
string_or_array_range (bound_types, ind, l, h); |
break; |
} |
|
default: |
bad_arg_error (range_func_name (bound_types), |
Pike_sp - ind, 1, "string|array|object", ind, |
"Cannot use [..] on a %s. Expected string, array or object.\n", |
get_name_of_type (TYPEOF(*ind))); |
} |
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
PMOD_EXPORT void f_range(INT32 args) |
{ |
struct svalue *ind; |
if (args != 5) |
SIMPLE_WRONG_NUM_ARGS_ERROR ("predef::`[..]", 5); |
ind = Pike_sp - 5; |
|
#define CALC_BOUND_TYPES(bound_types) do { \ |
if (TYPEOF(ind[2]) != T_INT) \ |
SIMPLE_ARG_TYPE_ERROR ("predef::`[..]", 3, "int"); \ |
switch (ind[2].u.integer) { \ |
case INDEX_FROM_BEG: bound_types = RANGE_LOW_FROM_BEG; break; \ |
case INDEX_FROM_END: bound_types = RANGE_LOW_FROM_END; break; \ |
case OPEN_BOUND: bound_types = RANGE_LOW_OPEN; break; \ |
default: \ |
SIMPLE_ARG_ERROR ("predef::`[..]", 3, "Unrecognized bound type."); \ |
} \ |
\ |
if (TYPEOF(ind[4]) != T_INT) \ |
SIMPLE_ARG_TYPE_ERROR ("predef::`[..]", 5, "int"); \ |
switch (ind[4].u.integer) { \ |
case INDEX_FROM_BEG: bound_types |= RANGE_HIGH_FROM_BEG; break; \ |
case INDEX_FROM_END: bound_types |= RANGE_HIGH_FROM_END; break; \ |
case OPEN_BOUND: bound_types |= RANGE_HIGH_OPEN; break; \ |
default: \ |
SIMPLE_ARG_ERROR ("predef::`[..]", 5, "Unrecognized bound type."); \ |
} \ |
} while (0) |
|
switch (TYPEOF(*ind)) { |
case T_OBJECT: { |
struct object *o = ind->u.object; |
int f; |
if (!o->prog) |
SIMPLE_ARG_ERROR ("predef::`[..]", 1, |
"Cannot call `[..] in destructed object.\n"); |
|
if ((f = FIND_LFUN(o->prog->inherits[SUBTYPEOF(*ind)].prog, |
LFUN_RANGE)) != -1) { |
apply_low (o, f, 4); |
stack_pop_keep_top(); |
} |
|
else { |
int bound_types; |
CALC_BOUND_TYPES (bound_types); |
switch (call_old_range_lfun (bound_types, o, ind + 1, ind + 3)) { |
case 1: |
SIMPLE_ARG_ERROR ("predef::`[..]", 1, |
"Object got neither `[..] nor `[].\n"); |
break; |
case 2: |
SIMPLE_ARG_ERROR ("predef::`[..]", 1, |
"Object got no `[..] and there is no _sizeof to " |
"translate the from-the-end index to use `[].\n"); |
break; |
case 3: |
SIMPLE_ARG_ERROR ("predef::`[..]", 1, |
"Cannot call `[..] in destructed object.\n"); |
break; |
default: |
free_svalue (ind); |
move_svalue (ind, Pike_sp - 1); |
|
|
Pike_sp = ind + 1; |
break; |
} |
} |
|
break; |
} |
|
case T_STRING: |
case T_ARRAY: { |
INT_TYPE l=0, h=0; |
int bound_types; |
CALC_BOUND_TYPES (bound_types); |
|
if (!(bound_types & RANGE_LOW_OPEN)) { |
if (TYPEOF(ind[1]) != T_INT) |
SIMPLE_ARG_TYPE_ERROR ("predef::`[..]", 2, "int"); |
l = ind[1].u.integer; |
} |
if (!(bound_types & RANGE_HIGH_OPEN)) { |
if (TYPEOF(ind[3]) != T_INT) |
SIMPLE_ARG_TYPE_ERROR ("predef::`[..]", 4, "int"); |
h = ind[3].u.integer; |
} |
|
pop_n_elems (4); |
string_or_array_range (bound_types, ind, l, h); |
break; |
} |
|
default: |
SIMPLE_ARG_TYPE_ERROR ("predef::`[..]", 1, "string|array|object"); |
} |
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|