|
|
|
|
|
|
|
#include "global.h" |
#include <math.h> |
#include "interpret.h" |
#include "svalue.h" |
#include "multiset.h" |
#include "mapping.h" |
#include "array.h" |
#include "stralloc.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_security.h" |
|
#define sp Pike_sp |
|
#define OP_DIVISION_BY_ZERO_ERROR(FUNC) \ |
math_error(FUNC, sp-2, 2, 0, "Division by zero.\n") |
#define OP_MODULO_BY_ZERO_ERROR(FUNC) \ |
math_error(FUNC, sp-2, 2, 0, "Modulo by zero.\n") |
|
void index_no_free(struct svalue *to,struct svalue *what,struct svalue *ind) |
{ |
#ifdef PIKE_SECURITY |
if(what->type <= MAX_COMPLEX) |
if(!CHECK_DATA_SECURITY(what->u.array, SECURITY_BIT_INDEX)) |
Pike_error("Index permission denied.\n"); |
#endif |
|
switch(what->type) |
{ |
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, ind); |
break; |
|
case T_MULTISET: { |
int i=multiset_member(what->u.multiset, ind); |
to->type=T_INT; |
to->subtype=i ? 0 : NUMBER_UNDEFINED; |
to->u.integer=i; |
break; |
} |
|
case T_STRING: |
if(ind->type==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); |
to->type=T_INT; |
to->subtype=NUMBER_NUMBER; |
to->u.integer=i; |
break; |
}else{ |
if (ind->type == 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 (ind->type)); |
} |
|
case T_PROGRAM: |
program_index_no_free(to, what->u.program, ind); |
break; |
|
case T_FUNCTION: |
{ |
struct program *p = program_from_svalue(what); |
if (p) { |
program_index_no_free(to, p, ind); |
break; |
} |
} |
|
|
#ifdef AUTO_BIGNUM |
case T_INT: |
if (ind->type == T_STRING) { |
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; |
} |
|
|
#endif /* AUTO_BIGNUM */ |
|
default: |
if (ind->type == T_INT) |
Pike_error ("Cannot index %s with %"PRINTPIKEINT"d.\n", |
(what->type == T_INT && !what->u.integer)? |
"the NULL value":get_name_of_type(what->type), |
ind->u.integer); |
else if (ind->type == T_FLOAT) |
Pike_error ("Cannot index %s with %"PRINTPIKEFLOAT"g.\n", |
(what->type == T_INT && !what->u.integer)? |
"the NULL value":get_name_of_type(what->type), |
ind->u.float_number); |
else if (ind->type == T_STRING) |
Pike_error ("Cannot index %s with \"%S\".\n", |
(what->type == T_INT && !what->u.integer)? |
"the NULL value":get_name_of_type(what->type), |
ind->u.string); |
else |
Pike_error ("Cannot index %s with %s.\n", |
(what->type == T_INT && !what->u.integer)? |
"the NULL value":get_name_of_type(what->type), |
get_name_of_type (ind->type)); |
} |
} |
|
void o_index(void) |
{ |
struct svalue s; |
index_no_free(&s,sp-2,sp-1); |
pop_n_elems(2); |
*sp=s; |
dmalloc_touch_svalue(sp); |
sp++; |
dmalloc_touch_svalue(Pike_sp-1); |
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void o_cast_to_int(void) |
{ |
switch(sp[-1].type) |
{ |
case T_OBJECT: |
if(!sp[-1].u.object->prog) { |
|
pop_stack(); |
push_int (0); |
} |
|
else { |
{ |
struct object *o = sp[-1].u.object; |
struct pike_string *s; |
int f = FIND_LFUN(o->prog,LFUN_CAST); |
if(f == -1) |
Pike_error("No cast method in object.\n"); |
REF_MAKE_CONST_STRING(s, "int"); |
push_string(s); |
apply_low(o, f, 1); |
stack_pop_keep_top(); |
} |
|
if(sp[-1].type != PIKE_T_INT) |
{ |
if(sp[-1].type == T_OBJECT && sp[-1].u.object->prog) |
{ |
int f=FIND_LFUN(sp[-1].u.object->prog, LFUN__IS_TYPE); |
if( f != -1) |
{ |
struct pike_string *s; |
REF_MAKE_CONST_STRING(s, "int"); |
push_string(s); |
apply_low(sp[-2].u.object, f, 1); |
f=!UNSAFE_IS_ZERO(sp-1); |
pop_stack(); |
if(f) return; |
} |
} |
Pike_error("Cast failed, wanted int, got %s\n", |
get_name_of_type(sp[-1].type)); |
} |
} |
|
break; |
|
case T_FLOAT: |
{ |
int i=DO_NOT_WARN((int)(sp[-1].u.float_number)); |
#ifdef AUTO_BIGNUM |
if((i < 0 ? -i : i) < floor(fabs(sp[-1].u.float_number))) |
{ |
|
|
convert_stack_top_to_bignum(); |
return; |
|
|
|
|
} |
else |
#endif /* AUTO_BIGNUM */ |
{ |
sp[-1].type=T_INT; |
sp[-1].u.integer=i; |
} |
} |
break; |
|
case T_STRING: |
|
|
|
#ifdef AUTO_BIGNUM |
|
|
|
|
if( sp[-1].u.string->len < 10 && |
!sp[-1].u.string->size_shift ) |
{ |
int i=atoi(sp[-1].u.string->str); |
free_string(sp[-1].u.string); |
sp[-1].type=T_INT; |
sp[-1].u.integer=i; |
} |
else |
convert_stack_top_string_to_inumber(10); |
return; |
|
|
|
|
#else |
{ |
int i=STRTOL(sp[-1].u.string->str,0,10); |
free_string(sp[-1].u.string); |
sp[-1].type=T_INT; |
sp[-1].u.integer=i; |
} |
#endif /* AUTO_BIGNUM */ |
break; |
|
case PIKE_T_INT: |
break; |
|
default: |
Pike_error("Cannot cast %s to int.\n", get_name_of_type(sp[-1].type)); |
} |
} |
|
|
void o_cast_to_string(void) |
{ |
char buf[200]; |
switch(sp[-1].type) |
{ |
case PIKE_T_STRING: |
return; |
|
case T_OBJECT: |
if(!sp[-1].u.object->prog) { |
|
pop_stack(); |
push_constant_text("0"); |
} else { |
{ |
struct object *o = sp[-1].u.object; |
struct pike_string *s; |
int f = FIND_LFUN(o->prog,LFUN_CAST); |
if(f == -1) |
Pike_error("No cast method in object.\n"); |
push_constant_text("string"); |
apply_low(o, f, 1); |
stack_pop_keep_top(); |
} |
|
if(sp[-1].type != PIKE_T_STRING) |
{ |
if(sp[-1].type == T_OBJECT && sp[-1].u.object->prog) |
{ |
int f=FIND_LFUN(sp[-1].u.object->prog, LFUN__IS_TYPE); |
if( f != -1) |
{ |
struct pike_string *s; |
REF_MAKE_CONST_STRING(s, "string"); |
push_string(s); |
apply_low(sp[-2].u.object, f, 1); |
f=!UNSAFE_IS_ZERO(sp-1); |
pop_stack(); |
if(f) return; |
} |
} |
Pike_error("Cast failed, wanted string, got %s\n", |
get_name_of_type(sp[-1].type)); |
} |
} |
return; |
|
case T_INT: |
sprintf(buf, "%"PRINTPIKEINT"d", sp[-1].u.integer); |
break; |
|
case T_ARRAY: |
{ |
int i; |
struct array *a = sp[-1].u.array; |
struct pike_string *s; |
int shift = 0; |
|
for(i = a->size; i--; ) { |
unsigned INT32 val; |
if (a->item[i].type != T_INT) { |
Pike_error("cast: Item %d is not an integer.\n", i); |
} |
val = (unsigned INT32)a->item[i].u.integer; |
if (val > 0xff) { |
shift = 1; |
if (val > 0xffff) { |
shift = 2; |
while(i--) |
if (a->item[i].type != T_INT) |
Pike_error("cast: Item %d is not an integer.\n", i); |
break; |
} |
while(i--) { |
if (a->item[i].type != T_INT) { |
Pike_error("cast: Item %d is not an integer.\n", i); |
} |
val = (unsigned INT32)a->item[i].u.integer; |
if (val > 0xffff) { |
shift = 2; |
while(i--) |
if (a->item[i].type != T_INT) |
Pike_error("cast: Item %d is not an integer.\n", i); |
break; |
} |
} |
break; |
} |
} |
s = begin_wide_shared_string(a->size, shift); |
switch(shift) { |
case 0: |
for(i = a->size; i--; ) { |
s->str[i] = a->item[i].u.integer; |
} |
break; |
case 1: |
{ |
p_wchar1 *str1 = STR1(s); |
for(i = a->size; i--; ) { |
str1[i] = a->item[i].u.integer; |
} |
} |
break; |
case 2: |
{ |
p_wchar2 *str2 = STR2(s); |
for(i = a->size; i--; ) { |
str2[i] = a->item[i].u.integer; |
} |
} |
break; |
default: |
free_string(end_shared_string(s)); |
Pike_fatal("cast: Bad shift: %d.\n", shift); |
break; |
} |
s = end_shared_string(s); |
pop_stack(); |
push_string(s); |
} |
return; |
|
case T_FLOAT: |
sprintf(buf, "%f", (double)sp[-1].u.float_number); |
break; |
|
default: |
Pike_error("Cannot cast %s to string.\n", get_name_of_type(sp[-1].type)); |
} |
|
sp[-1].type = PIKE_T_STRING; |
sp[-1].u.string = make_shared_string(buf); |
} |
|
void o_cast(struct pike_type *type, INT32 run_time_type) |
{ |
if(run_time_type != sp[-1].type) |
{ |
if(run_time_type == T_MIXED) |
return; |
|
if (sp[-1].type == T_OBJECT && !sp[-1].u.object->prog) { |
|
pop_stack(); |
push_int (0); |
} |
|
if(sp[-1].type == T_OBJECT) |
{ |
struct object *o = sp[-1].u.object; |
struct pike_string *s; |
int f = FIND_LFUN(o->prog,LFUN_CAST); |
if(f == -1) |
Pike_error("No cast method in object.\n"); |
push_string(describe_type(type)); |
apply_low(o, f, 1); |
stack_pop_keep_top(); |
}else |
|
switch(run_time_type) |
{ |
default: |
Pike_error("Cannot perform cast to that type.\n"); |
|
case T_MIXED: |
return; |
|
case T_MULTISET: |
switch(sp[-1].type) |
{ |
case T_ARRAY: |
{ |
extern void f_mkmultiset(INT32); |
f_mkmultiset(1); |
break; |
} |
|
default: |
Pike_error("Cannot cast %s to multiset.\n",get_name_of_type(sp[-1].type)); |
} |
break; |
|
case T_MAPPING: |
switch(sp[-1].type) |
{ |
case T_ARRAY: |
{ |
struct array *a=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 (ITEM(a)[i].type!=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(sp[-1].type)); |
} |
break; |
|
case T_ARRAY: |
switch(sp[-1].type) |
{ |
case T_MAPPING: |
{ |
struct array *a=mapping_to_array(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(sp[-1].type)); |
|
} |
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(sp[-1].type) |
{ |
case T_INT: |
f=(FLOAT_TYPE)(sp[-1].u.integer); |
break; |
|
case T_STRING: |
f = |
(FLOAT_TYPE)STRTOD_PCHARP(MKPCHARP(sp[-1].u.string->str, |
sp[-1].u.string->size_shift), |
0); |
free_string(sp[-1].u.string); |
break; |
|
default: |
Pike_error("Cannot cast %s to float.\n",get_name_of_type(sp[-1].type)); |
} |
|
sp[-1].type=T_FLOAT; |
sp[-1].u.float_number=f; |
break; |
} |
|
case T_OBJECT: |
switch(sp[-1].type) |
{ |
case T_STRING: { |
struct pike_string *file; |
INT32 lineno; |
if(Pike_fp->pc && |
(file = low_get_line(Pike_fp->pc, Pike_fp->context.prog, &lineno))) { |
push_string(file); |
}else{ |
push_int(0); |
} |
|
|
APPLY_MASTER("cast_to_object",2); |
return; |
} |
|
case T_FUNCTION: |
if (Pike_sp[-1].subtype == 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 { |
Pike_sp[-1].type = T_OBJECT; |
} |
break; |
|
default: |
Pike_error("Cannot cast %s to object.\n",get_name_of_type(sp[-1].type)); |
} |
break; |
|
case T_PROGRAM: |
switch(sp[-1].type) |
{ |
case T_STRING: { |
struct pike_string *file; |
INT32 lineno; |
if(Pike_fp->pc && |
(file = low_get_line(Pike_fp->pc, Pike_fp->context.prog, &lineno))) { |
push_string(file); |
}else{ |
push_int(0); |
} |
|
|
APPLY_MASTER("cast_to_program",2); |
return; |
} |
|
case T_FUNCTION: |
{ |
struct program *p=program_from_function(sp-1); |
if(p) |
{ |
add_ref(p); |
pop_stack(); |
push_program(p); |
}else{ |
pop_stack(); |
push_int(0); |
} |
} |
return; |
|
default: |
Pike_error("Cannot cast %s to a program.\n",get_name_of_type(sp[-1].type)); |
} |
} |
} |
|
if(run_time_type != sp[-1].type) |
{ |
if(sp[-1].type == T_OBJECT && sp[-1].u.object->prog) |
{ |
int f=FIND_LFUN(sp[-1].u.object->prog, LFUN__IS_TYPE); |
if( f != -1) |
{ |
push_text(get_name_of_type(run_time_type)); |
apply_low(sp[-2].u.object, f, 1); |
f=!UNSAFE_IS_ZERO(sp-1); |
pop_stack(); |
if(f) goto emulated_type_ok; |
} |
} |
Pike_error("Cast failed, wanted %s, got %s\n", |
get_name_of_type(run_time_type), |
get_name_of_type(sp[-1].type)); |
} |
|
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=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=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 << ITEM(a)[e].type; |
} |
a->type_field = types; |
#ifdef PIKE_DEBUG |
if(save_sp!=sp) |
Pike_fatal("o_cast left stack droppings.\n"); |
#endif |
} |
END_CYCLIC(); |
assign_svalue(sp-3,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=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=sp+1; |
#endif |
|
ptrdiff_t nodepos; |
if (multiset_indval (tmp)) |
Pike_error ("FIXME: Casting not implemented for multisets with values.\n"); |
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_2 (m, sp - 1, NULL, 0); |
pop_stack(); |
} while ((nodepos = multiset_next (tmp, nodepos)) >= 0); |
UNSET_ONERROR (uwp); |
sub_msnode_ref (tmp); |
} |
|
#ifdef PIKE_DEBUG |
if(save_sp!=sp) |
Pike_fatal("o_cast left stack droppings.\n"); |
#endif |
} |
END_CYCLIC(); |
assign_svalue(sp-3,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=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=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,sp-2,sp-1); |
pop_n_elems(2); |
} |
#ifdef PIKE_DEBUG |
if(save_sp!=sp) |
Pike_fatal("o_cast left stack droppings.\n"); |
#endif |
} |
END_CYCLIC(); |
assign_svalue(sp-4,sp-1); |
pop_stack(); |
} |
pop_n_elems(2); |
} |
} |
} |
|
PMOD_EXPORT void f_cast(void) |
{ |
#ifdef PIKE_DEBUG |
struct svalue *save_sp=sp; |
if(sp[-2].type != T_TYPE) |
Pike_fatal("Cast expression destroyed stack or left droppings! (Type:%d)\n", |
sp[-2].type); |
#endif |
o_cast(sp[-2].u.type, |
compile_type_to_runtime_type(sp[-2].u.type)); |
#ifdef PIKE_DEBUG |
if(save_sp != sp) |
Pike_fatal("Internal error: o_cast() left droppings on stack.\n"); |
#endif |
free_svalue(sp-2); |
sp[-2]=sp[-1]; |
sp--; |
dmalloc_touch_svalue(sp); |
} |
|
#define COMPARISON(ID,NAME,FUN) \ |
PMOD_EXPORT void ID(INT32 args) \ |
{ \ |
int i; \ |
switch(args) \ |
{ \ |
case 0: case 1: \ |
SIMPLE_TOO_FEW_ARGS_ERROR(NAME, 2); \ |
case 2: \ |
i=FUN (sp-2,sp-1); \ |
pop_n_elems(2); \ |
push_int(i); \ |
break; \ |
default: \ |
for(i=1;i<args;i++) \ |
if(! ( FUN (sp-args+i-1, sp-args+i))) \ |
break; \ |
pop_n_elems(args); \ |
push_int(i==args); \ |
} \ |
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
PMOD_EXPORT void f_ne(INT32 args) |
{ |
f_eq(args); |
o_not(); |
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
COMPARISON(f_eq,"`==", is_eq) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
COMPARISON(f_lt,"`<" , is_lt) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
COMPARISON(f_le,"`<=",!is_gt) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
COMPARISON(f_gt,"`>" , is_gt) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
COMPARISON(f_ge,"`>=",!is_lt) |
|
|
#define CALL_OPERATOR(OP, args) do { \ |
struct object *o_ = sp[-args].u.object; \ |
int i; \ |
if(!o_->prog) \ |
bad_arg_error(lfun_names[OP], sp-args, args, 1, "object", sp-args, \ |
"Called in destructed object.\n"); \ |
if((i = FIND_LFUN(o_->prog,OP)) == -1) \ |
bad_arg_error(lfun_names[OP], sp-args, args, 1, "object", sp-args, \ |
"Operator not in object.\n"); \ |
apply_low(o_, i, args-1); \ |
stack_pop_keep_top(); \ |
} while (0) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
PMOD_EXPORT void f_add(INT32 args) |
{ |
INT_TYPE e,size; |
TYPE_FIELD types; |
|
tail_recurse: |
types=0; |
for(e=-args;e<0;e++) types|=1<<sp[e].type; |
|
switch(types) |
{ |
default: |
if(!args) |
{ |
SIMPLE_TOO_FEW_ARGS_ERROR("`+", 1); |
}else{ |
if(types & BIT_OBJECT) |
{ |
if (args == 1) |
return; |
|
if(sp[-args].type == T_OBJECT && sp[-args].u.object->prog) |
{ |
|
int i; |
if(sp[-args].u.object->refs==1 && |
(i = FIND_LFUN(sp[-args].u.object->prog,LFUN_ADD_EQ)) != -1) |
{ |
apply_low(sp[-args].u.object, i, args-1); |
stack_pop_keep_top(); |
return; |
} |
if((i = FIND_LFUN(sp[-args].u.object->prog,LFUN_ADD)) != -1) |
{ |
apply_low(sp[-args].u.object, i, args-1); |
free_svalue(sp-2); |
sp[-2]=sp[-1]; |
sp--; |
dmalloc_touch_svalue(sp); |
return; |
} |
} |
|
for(e=1;e<args;e++) |
{ |
int i; |
if(sp[e-args].type == T_OBJECT && |
sp[e-args].u.object->prog && |
(i = FIND_LFUN(sp[e-args].u.object->prog,LFUN_RADD)) != -1) |
{ |
|
if (e == args-1) { |
|
struct object *o = Pike_sp[-1].u.object; |
ONERROR err; |
Pike_sp--; |
SET_ONERROR(err, do_free_object, o); |
apply_low(o, i, e); |
CALL_AND_UNSET_ONERROR(err); |
return; |
} 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 (Pike_sp[-args].type != T_OBJECT || |
!Pike_sp[-args].u.object->prog || |
FIND_LFUN(Pike_sp[-args].u.object->prog, LFUN_RADD) != i) { |
Pike_fatal("`+() Lost track of object.\n"); |
} |
#endif /* PIKE_DEBUG */ |
apply_low(Pike_sp[-args].u.object, i, e); |
args -= e; |
|
assign_svalue(Pike_sp-(args+1), Pike_sp-1); |
pop_stack(); |
goto tail_recurse; |
} |
} |
} |
} |
} |
|
switch(sp[-args].type) |
{ |
case T_PROGRAM: |
case T_FUNCTION: |
SIMPLE_BAD_ARG_ERROR("`+", 1, |
"string|object|int|float|array|mapping|multiset"); |
} |
bad_arg_error("`+", sp-args, args, 1, |
"string|object|int|float|array|mapping|multiset", sp-args, |
"Incompatible types\n"); |
return; |
|
case BIT_STRING: |
{ |
struct pike_string *r; |
PCHARP buf; |
ptrdiff_t tmp; |
int max_shift=0; |
|
if(args==1) return; |
|
size=0; |
for(e=-args;e<0;e++) |
{ |
size+=sp[e].u.string->len; |
if(sp[e].u.string->size_shift > max_shift) |
max_shift=sp[e].u.string->size_shift; |
} |
|
if(size == sp[-args].u.string->len) |
{ |
pop_n_elems(args-1); |
return; |
} |
|
tmp=sp[-args].u.string->len; |
r=new_realloc_shared_string(sp[-args].u.string,size,max_shift); |
sp[-args].type=T_INT; |
buf=MKPCHARP_STR_OFF(r,tmp); |
for(e=-args+1;e<0;e++) |
{ |
pike_string_cpy(buf,sp[e].u.string); |
INC_PCHARP(buf,sp[e].u.string->len); |
} |
sp[-args].u.string=low_end_shared_string(r); |
sp[-args].type=T_STRING; |
for(e=-args+1;e<0;e++) free_string(sp[e].u.string); |
sp-=args-1; |
|
break; |
} |
|
case BIT_STRING | BIT_INT: |
case BIT_STRING | BIT_FLOAT: |
case BIT_STRING | BIT_FLOAT | BIT_INT: |
{ |
struct pike_string *r; |
PCHARP buf; |
char buffer[50]; |
int max_shift=0; |
|
if ((sp[-args].type != T_STRING) && (sp[1-args].type != T_STRING)) { |
struct svalue *save_sp = sp; |
|
|
for (e=-args; e < 0; e++) { |
if (save_sp[e].type == T_STRING) |
break; |
*(sp++) = save_sp[e]; |
dmalloc_touch_svalue(Pike_sp-1); |
} |
|
f_add(args+e); |
dmalloc_touch_svalue(Pike_sp-1); |
save_sp[--e] = *(--sp); |
#ifdef PIKE_DEBUG |
if (sp != save_sp) { |
Pike_fatal("f_add(): Lost track of stack %p != %p\n", sp, save_sp); |
} |
#endif /* PIKE_DEBUG */ |
|
f_add(-e); |
#ifdef PIKE_DEBUG |
if (sp != save_sp + 1 + e) { |
Pike_fatal("f_add(): Lost track of stack (2) %p != %p\n", |
sp, save_sp + 1 + e); |
} |
#endif /* PIKE_DEBUG */ |
|
save_sp[-args] = sp[-1]; |
sp = save_sp + 1 - args; |
return; |
} else { |
e = -args; |
} |
|
|
size=0; |
for(e=-args;e<0;e++) |
{ |
switch(sp[e].type) |
{ |
case T_STRING: |
size+=sp[e].u.string->len; |
if(sp[e].u.string->size_shift > max_shift) |
max_shift=sp[e].u.string->size_shift; |
break; |
|
case T_INT: |
size+=14; |
break; |
|
case T_FLOAT: |
size+=22; |
break; |
} |
} |
|
r=begin_wide_shared_string(size,max_shift); |
buf=MKPCHARP_STR(r); |
size=0; |
|
for(e=-args;e<0;e++) |
{ |
switch(sp[e].type) |
{ |
case T_STRING: |
pike_string_cpy(buf,sp[e].u.string); |
INC_PCHARP(buf,sp[e].u.string->len); |
break; |
|
case T_INT: |
sprintf(buffer,"%"PRINTPIKEINT"d",sp[e].u.integer); |
goto append_buffer; |
|
case T_FLOAT: |
sprintf(buffer,"%"PRINTPIKEFLOAT"f",sp[e].u.float_number); |
append_buffer: |
switch(max_shift) |
{ |
case 0: |
convert_0_to_0((p_wchar0 *)buf.ptr,buffer,strlen(buffer)); |
break; |
|
case 1: |
convert_0_to_1((p_wchar1 *)buf.ptr,(p_wchar0 *)buffer, |
strlen(buffer)); |
break; |
|
case 2: |
convert_0_to_2((p_wchar2 *)buf.ptr,(p_wchar0 *)buffer, |
strlen(buffer)); |
break; |
|
} |
INC_PCHARP(buf,strlen(buffer)); |
} |
} |
r = realloc_unlinked_string(r, SUBTRACT_PCHARP(buf, MKPCHARP_STR(r))); |
r = low_end_shared_string(r); |
pop_n_elems(args); |
push_string(r); |
break; |
} |
|
case BIT_INT: |
#ifdef AUTO_BIGNUM |
size = 0; |
for(e = -args; e < 0; e++) |
{ |
if(INT_TYPE_ADD_OVERFLOW(sp[e].u.integer, size)) |
{ |
convert_svalue_to_bignum(sp-args); |
f_add(args); |
return; |
} |
else |
{ |
size += sp[e].u.integer; |
} |
} |
sp-=args; |
push_int(size); |
#else |
size=0; |
for(e=-args; e<0; e++) size+=sp[e].u.integer; |
sp-=args-1; |
sp[-1].u.integer=size; |
#endif /* AUTO_BIGNUM */ |
break; |
|
case BIT_FLOAT: |
{ |
FLOAT_ARG_TYPE sum; |
sum=0.0; |
for(e=-args; e<0; e++) sum+=sp[e].u.float_number; |
sp-=args-1; |
sp[-1].u.float_number=sum; |
break; |
} |
|
case BIT_FLOAT|BIT_INT: |
{ |
FLOAT_ARG_TYPE sum; |
sum=0.0; |
for(e=-args; e<0; e++) |
{ |
if(sp[e].type==T_FLOAT) |
{ |
sum+=sp[e].u.float_number; |
}else{ |
sum+=(FLOAT_ARG_TYPE)sp[e].u.integer; |
} |
} |
sp-=args-1; |
sp[-1].type=T_FLOAT; |
sp[-1].u.float_number=sum; |
break; |
} |
|
#define ADD_WITH_UNDEFINED(TYPE, T_TYPEID, ADD_FUNC, PUSH_FUNC) do { \ |
int e; \ |
if (sp[-args].type == T_INT) { \ |
if(IS_UNDEFINED(sp-args)) \ |
{ \ |
struct TYPE *x; \ |
\ |
for(e=1;e<args;e++) \ |
if(sp[e-args].type != T_TYPEID) \ |
SIMPLE_ARG_TYPE_ERROR("`+", e+1, #TYPE); \ |
\ |
x = ADD_FUNC(sp-args+1,args-1); \ |
pop_n_elems(args); \ |
PUSH_FUNC(x); \ |
return; \ |
} \ |
\ |
for(e=1;e<args;e++) \ |
if (sp[e-args].type != T_INT) \ |
SIMPLE_ARG_TYPE_ERROR("`+", e+1, "int"); \ |
} \ |
\ |
else { \ |
for(e=1;e<args;e++) \ |
if (sp[e-args].type != T_TYPEID) \ |
SIMPLE_ARG_TYPE_ERROR("`+", e+1, #TYPE); \ |
} \ |
\ |
DO_IF_DEBUG (Pike_fatal ("Shouldn't be reached.\n")); \ |
} while (0) |
|
#define ADD(TYPE, ADD_FUNC, PUSH_FUNC) do { \ |
struct TYPE *x = ADD_FUNC (sp - args, args); \ |
pop_n_elems (args); \ |
PUSH_FUNC (x); \ |
return; \ |
} while (0) |
|
case BIT_ARRAY|BIT_INT: |
ADD_WITH_UNDEFINED (array, T_ARRAY, add_arrays, push_array); |
|
case BIT_ARRAY: |
ADD (array, add_arrays, push_array); |
|
case BIT_MAPPING|BIT_INT: |
ADD_WITH_UNDEFINED (mapping, T_MAPPING, add_mappings, push_mapping); |
|
case BIT_MAPPING: |
ADD (mapping, add_mappings, push_mapping); |
|
case BIT_MULTISET|BIT_INT: |
ADD_WITH_UNDEFINED (multiset, T_MULTISET, add_multisets, push_multiset); |
|
case BIT_MULTISET: |
ADD (multiset, add_multisets, push_multiset); |
|
#undef ADD_WITH_UNDEFINED |
#undef ADD |
} |
} |
|
static int generate_sum(node *n) |
{ |
node **first_arg, **second_arg, **third_arg; |
int num_args; |
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) && |
pike_types_le(second_arg[0]->type, int_type_string)) |
{ |
emit0(F_ADD_INTS); |
} |
else |
{ |
emit0(F_ADD); |
} |
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); |
if (third_arg[0]->type == float_type_string) { |
do_docode(*third_arg, 0); |
emit0(F_ADD_FLOATS); |
return 1; |
} |
} |
else if(first_arg[0]->type && second_arg[0]->type && |
pike_types_le(first_arg[0]->type, int_type_string) && |
pike_types_le(second_arg[0]->type, int_type_string)) |
{ |
do_docode(*first_arg, 0); |
do_docode(*second_arg, 0); |
emit0(F_ADD_INTS); |
if (third_arg[0]->type && |
pike_types_le(third_arg[0]->type, int_type_string)) { |
do_docode(*third_arg, 0); |
emit0(F_ADD_INTS); |
return 1; |
} |
} |
else |
{ |
return 0; |
} |
do_docode(*third_arg, 0); |
emit0(F_ADD); |
|
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(node_is_false(*first_arg) && !node_may_overload(*second_arg,LFUN_EQ)) |
{ |
ret=*second_arg; |
ADD_NODE_REF(*second_arg); |
return mkopernode("`!",ret,0); |
} |
|
if(node_is_false(*second_arg) && !node_may_overload(*first_arg,LFUN_EQ)) |
{ |
ret=*first_arg; |
ADD_NODE_REF(*first_arg); |
return mkopernode("`!",ret,0); |
} |
|
if (((*second_arg)->token == F_CONSTANT) && |
((*second_arg)->u.sval.type == 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) && |
(CAR (low)->u.sval.type == T_INT) && |
(!(CAR (low)->u.sval.u.integer)))) && |
(high->token == F_RANGE_OPEN || |
(high->token == F_RANGE_FROM_BEG && |
(CAR (high)->token == F_CONSTANT) && |
(CAR (high)->u.sval.type == 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, "`=="); |
TMP_OPT(f_lt, "`>="); |
TMP_OPT(f_gt, "`<="); |
TMP_OPT(f_le, "`>"); |
TMP_OPT(f_ge, "`<"); |
#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) && |
(CAR(search_args)->type == string_type_string) && |
CDR(search_args) && |
(CDR(search_args)->type == string_type_string)) { |
|
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 (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; |
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)->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; |
} |
} |
} |
return 0; |
} |
|
|
static int generate_comparison(node *n) |
{ |
if(count_args(CDR(n))==2) |
{ |
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"); |
return 1; |
} |
return 0; |
} |
|
static int float_promote(void) |
{ |
if(sp[-2].type==T_INT && sp[-1].type==T_FLOAT) |
{ |
sp[-2].u.float_number=(FLOAT_TYPE)sp[-2].u.integer; |
sp[-2].type=T_FLOAT; |
return 1; |
} |
else if(sp[-1].type==T_INT && sp[-2].type==T_FLOAT) |
{ |
sp[-1].u.float_number=(FLOAT_TYPE)sp[-1].u.integer; |
sp[-1].type=T_FLOAT; |
return 1; |
} |
|
#ifdef AUTO_BIGNUM |
if(is_bignum_object_in_svalue(sp-2) && sp[-1].type==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(sp-1) && sp[-2].type==T_FLOAT) |
{ |
ref_push_type_value(float_type_string); |
stack_swap(); |
f_cast(); |
return 1; |
} |
#endif |
return 0; |
} |
|
static int call_lfun(int left, int right) |
{ |
int i; |
if(sp[-2].type == T_OBJECT && |
sp[-2].u.object->prog && |
(i = FIND_LFUN(sp[-2].u.object->prog,left)) != -1) |
{ |
apply_low(sp[-2].u.object, i, 1); |
free_svalue(sp-2); |
sp[-2]=sp[-1]; |
sp--; |
dmalloc_touch_svalue(sp); |
return 1; |
} |
|
if(sp[-1].type == T_OBJECT && |
sp[-1].u.object->prog && |
(i = FIND_LFUN(sp[-1].u.object->prog,right)) != -1) |
{ |
push_svalue(sp-2); |
apply_low(sp[-2].u.object, i, 1); |
free_svalue(sp-3); |
sp[-3]=sp[-1]; |
sp--; |
dmalloc_touch_svalue(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 (sp[-2].type != sp[-1].type && !float_promote()) |
{ |
if(call_lfun(LFUN_SUBTRACT, LFUN_RSUBTRACT)) |
return; |
|
if (sp[-2].type==T_MAPPING) |
switch (sp[-1].type) |
{ |
case T_ARRAY: |
{ |
struct mapping *m; |
|
m=merge_mapping_array_unordered(sp[-2].u.mapping, |
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 (sp[-1].u.multiset); |
struct array *ind = multiset_indices (sp[-1].u.multiset); |
pop_stack(); |
push_array (ind); |
if (got_cmp_less) |
m=merge_mapping_array_unordered(sp[-2].u.mapping, |
sp[-1].u.array, |
PIKE_ARRAY_OP_SUB); |
else |
m=merge_mapping_array_ordered(sp[-2].u.mapping, |
sp[-1].u.array, |
PIKE_ARRAY_OP_SUB); |
pop_n_elems(2); |
push_mapping(m); |
return; |
} |
} |
|
bad_arg_error("`-", sp-2, 2, 2, get_name_of_type(sp[-2].type), |
sp-1, "Subtract on different types.\n"); |
} |
|
switch(sp[-2].type) |
{ |
case T_OBJECT: |
CALL_OPERATOR(LFUN_SUBTRACT,2); |
break; |
|
case T_ARRAY: |
{ |
struct array *a; |
|
check_array_for_destruct(sp[-2].u.array); |
check_array_for_destruct(sp[-1].u.array); |
a = subtract_arrays(sp[-2].u.array, sp[-1].u.array); |
pop_n_elems(2); |
push_array(a); |
return; |
} |
|
case T_MAPPING: |
{ |
struct mapping *m; |
m=merge_mappings(sp[-2].u.mapping, 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(sp[-2].u.multiset, sp[-1].u.multiset, PIKE_ARRAY_OP_SUB); |
pop_n_elems(2); |
push_multiset(l); |
return; |
} |
|
case T_FLOAT: |
sp--; |
sp[-1].u.float_number -= sp[0].u.float_number; |
return; |
|
case T_INT: |
#ifdef AUTO_BIGNUM |
if(INT_TYPE_SUB_OVERFLOW(sp[-2].u.integer, sp[-1].u.integer)) |
{ |
convert_stack_top_to_bignum(); |
f_minus(2); |
return; |
} |
#endif /* AUTO_BIGNUM */ |
sp--; |
sp[-1].u.integer -= sp[0].u.integer; |
return; |
|
case T_STRING: |
{ |
struct pike_string *s,*ret; |
s=make_shared_string(""); |
ret=string_replace(sp[-2].u.string,sp[-1].u.string,s); |
free_string(sp[-2].u.string); |
free_string(sp[-1].u.string); |
free_string(s); |
sp[-2].u.string=ret; |
sp--; |
return; |
} |
|
|
|
default: |
{ |
int args = 2; |
SIMPLE_BAD_ARG_ERROR("`-", 1, |
"int|float|string|mapping|multiset|array|object"); |
} |
} |
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
PMOD_EXPORT void f_minus(INT32 args) |
{ |
switch(args) |
{ |
case 0: SIMPLE_TOO_FEW_ARGS_ERROR("`-", 1); |
case 1: o_negate(); break; |
case 2: o_subtract(); break; |
default: |
{ |
INT32 e; |
struct svalue *s=sp-args; |
push_svalue(s); |
for(e=1;e<args;e++) |
{ |
push_svalue(s+e); |
o_subtract(); |
} |
assign_svalue(s,sp-1); |
pop_n_elems(sp-s-1); |
} |
} |
} |
|
static int generate_minus(node *n) |
{ |
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); |
return 1; |
} |
return 0; |
} |
|
PMOD_EXPORT void o_and(void) |
{ |
if(sp[-1].type != sp[-2].type) |
{ |
if(call_lfun(LFUN_AND, LFUN_RAND)) |
return; |
else if (((sp[-1].type == T_TYPE) || (sp[-1].type == T_PROGRAM) || |
(sp[-1].type == T_FUNCTION)) && |
((sp[-2].type == T_TYPE) || (sp[-2].type == T_PROGRAM) || |
(sp[-2].type == T_FUNCTION))) |
{ |
if (sp[-2].type != T_TYPE) |
{ |
struct program *p = program_from_svalue(sp - 2); |
if (!p) { |
int args = 2; |
SIMPLE_BAD_ARG_ERROR("`&", 1, "type"); |
} |
type_stack_mark(); |
push_object_type(0, p->id); |
free_svalue(sp - 2); |
sp[-2].u.type = pop_unfinished_type(); |
sp[-2].type = T_TYPE; |
} |
if (sp[-1].type != T_TYPE) |
{ |
struct program *p = program_from_svalue(sp - 1); |
if (!p) |
{ |
int args = 2; |
SIMPLE_BAD_ARG_ERROR("`&", 2, "type"); |
} |
type_stack_mark(); |
push_object_type(0, p->id); |
free_svalue(sp - 1); |
sp[-1].u.type = pop_unfinished_type(); |
sp[-1].type = T_TYPE; |
} |
} |
else if (sp[-2].type==T_MAPPING) |
switch (sp[-1].type) |
{ |
case T_ARRAY: |
{ |
struct mapping *m; |
|
m=merge_mapping_array_unordered(sp[-2].u.mapping, |
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 (sp[-1].u.multiset); |
struct array *ind = multiset_indices (sp[-1].u.multiset); |
pop_stack(); |
push_array (ind); |
if (got_cmp_less) |
m=merge_mapping_array_unordered(sp[-2].u.mapping, |
sp[-1].u.array, |
PIKE_ARRAY_OP_AND); |
else |
m=merge_mapping_array_ordered(sp[-2].u.mapping, |
sp[-1].u.array, |
PIKE_ARRAY_OP_AND); |
pop_n_elems(2); |
push_mapping(m); |
return; |
} |
default: |
{ |
int args = 2; |
SIMPLE_BAD_ARG_ERROR("`&", 2, "mapping"); |
} |
} |
else |
{ |
int args = 2; |
SIMPLE_BAD_ARG_ERROR("`&", 2, get_name_of_type(sp[-2].type)); |
} |
} |
|
switch(sp[-2].type) |
{ |
case T_OBJECT: |
CALL_OPERATOR(LFUN_AND,2); |
break; |
|
case T_INT: |
sp--; |
sp[-1].u.integer &= sp[0].u.integer; |
break; |
|
case T_MAPPING: |
{ |
struct mapping *m; |
m=merge_mappings(sp[-2].u.mapping, 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(sp[-2].u.multiset, 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(sp[-2].u.array, sp[-1].u.array); |
pop_n_elems(2); |
push_array(a); |
return; |
} |
|
case T_TYPE: |
{ |
struct pike_type *t; |
t = and_pike_types(sp[-2].u.type, sp[-1].u.type); |
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(sp - 2); |
if (!p) { |
int args = 2; |
SIMPLE_BAD_ARG_ERROR("`&", 1, "type"); |
} |
type_stack_mark(); |
push_object_type(0, p->id); |
a = pop_unfinished_type(); |
|
p = program_from_svalue(sp - 1); |
if (!p) { |
int args = 2; |
SIMPLE_BAD_ARG_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 = sp[-2].u.string->len; \ |
if (len != sp[-1].u.string->len) \ |
PIKE_ERROR("`" #OP, "Bitwise "STROP \ |
" on strings of different lengths.\n", sp, 2); \ |
if(!sp[-2].u.string->size_shift && !sp[-1].u.string->size_shift) \ |
{ \ |
s = begin_shared_string(len); \ |
for (i=0; i<len; i++) \ |
s->str[i] = sp[-2].u.string->str[i] OP sp[-1].u.string->str[i]; \ |
}else{ \ |
s = begin_wide_shared_string(len, \ |
MAXIMUM(sp[-2].u.string->size_shift, \ |
sp[-1].u.string->size_shift)); \ |
for (i=0; i<len; i++) \ |
low_set_index(s,i,index_shared_string(sp[-2].u.string,i) OP \ |
index_shared_string(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", 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=*--sp; |
SET_ONERROR(err,do_free_svalue,&tmp); |
r_speedup(args>>1,func); |
UNSET_ONERROR(err); |
sp++[0]=tmp; |
func(); |
} |
} |
static void speedup(INT32 args, void (*func)(void)) |
{ |
switch(sp[-args].type) |
{ |
|
|
|
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_TOO_FEW_ARGS_ERROR("`&", 1); |
case 1: return; |
case 2: o_and(); return; |
default: |
if(sp[-args].type == T_OBJECT) |
{ |
CALL_OPERATOR(LFUN_AND, args); |
}else{ |
speedup(args, o_and); |
} |
} |
} |
|
static int generate_and(node *n) |
{ |
switch(count_args(CDR(n))) |
{ |
case 1: |
do_docode(CDR(n),0); |
return 1; |
|
case 2: |
do_docode(CDR(n),0); |
emit0(F_AND); |
return 1; |
|
default: |
return 0; |
} |
} |
|
PMOD_EXPORT void o_or(void) |
{ |
if(sp[-1].type != sp[-2].type) |
{ |
if(call_lfun(LFUN_OR, LFUN_ROR)) { |
return; |
} else if (((sp[-1].type == T_TYPE) || (sp[-1].type == T_PROGRAM) || |
(sp[-1].type == T_FUNCTION)) && |
((sp[-2].type == T_TYPE) || (sp[-2].type == T_PROGRAM) || |
(sp[-2].type == T_FUNCTION))) { |
if (sp[-2].type != T_TYPE) { |
struct program *p = program_from_svalue(sp - 2); |
if (!p) { |
int args = 2; |
SIMPLE_BAD_ARG_ERROR("`|", 1, "type"); |
} |
type_stack_mark(); |
push_object_type(0, p->id); |
free_svalue(sp - 2); |
sp[-2].u.type = pop_unfinished_type(); |
sp[-2].type = T_TYPE; |
} |
if (sp[-1].type != T_TYPE) { |
struct program *p = program_from_svalue(sp - 1); |
if (!p) { |
int args = 2; |
SIMPLE_BAD_ARG_ERROR("`|", 2, "type"); |
} |
type_stack_mark(); |
push_object_type(0, p->id); |
free_svalue(sp - 1); |
sp[-1].u.type = pop_unfinished_type(); |
sp[-1].type = T_TYPE; |
} |
} else { |
int args = 2; |
SIMPLE_BAD_ARG_ERROR("`|", 2, get_name_of_type(sp[-2].type)); |
} |
} |
|
switch(sp[-2].type) |
{ |
case T_OBJECT: |
CALL_OPERATOR(LFUN_OR,2); |
break; |
|
case T_INT: |
sp--; |
sp[-1].u.integer |= sp[0].u.integer; |
break; |
|
case T_MAPPING: |
{ |
struct mapping *m; |
m=merge_mappings(sp[-2].u.mapping, 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(sp[-2].u.multiset, sp[-1].u.multiset, PIKE_ARRAY_OP_OR_LEFT); |
pop_n_elems(2); |
push_multiset(l); |
return; |
} |
|
case T_ARRAY: |
{ |
struct array *a; |
a=merge_array_with_order(sp[-2].u.array, 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(sp[-2].u.type, 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(sp - 2); |
if (!p) { |
int args = 2; |
SIMPLE_BAD_ARG_ERROR("`|", 1, "type"); |
} |
type_stack_mark(); |
push_object_type(0, p->id); |
a = pop_unfinished_type(); |
|
p = program_from_svalue(sp - 1); |
if (!p) { |
int args = 2; |
SIMPLE_BAD_ARG_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", sp, 2); |
} |
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
PMOD_EXPORT void f_or(INT32 args) |
{ |
switch(args) |
{ |
case 0: SIMPLE_TOO_FEW_ARGS_ERROR("`|", 1); |
case 1: return; |
case 2: o_or(); return; |
default: |
if(sp[-args].type==T_OBJECT) |
{ |
CALL_OPERATOR(LFUN_OR, args); |
} else { |
speedup(args, o_or); |
} |
} |
} |
|
static int generate_or(node *n) |
{ |
switch(count_args(CDR(n))) |
{ |
case 1: |
do_docode(CDR(n),0); |
return 1; |
|
case 2: |
do_docode(CDR(n),0); |
emit0(F_OR); |
return 1; |
|
default: |
return 0; |
} |
} |
|
|
PMOD_EXPORT void o_xor(void) |
{ |
if(sp[-1].type != sp[-2].type) |
{ |
if(call_lfun(LFUN_XOR, LFUN_RXOR)) { |
return; |
} else if (((sp[-1].type == T_TYPE) || (sp[-1].type == T_PROGRAM) || |
(sp[-1].type == T_FUNCTION)) && |
((sp[-2].type == T_TYPE) || (sp[-2].type == T_PROGRAM) || |
(sp[-2].type == T_FUNCTION))) { |
if (sp[-2].type != T_TYPE) { |
struct program *p = program_from_svalue(sp - 2); |
if (!p) { |
int args = 2; |
SIMPLE_BAD_ARG_ERROR("`^", 1, "type"); |
} |
type_stack_mark(); |
push_object_type(0, p->id); |
free_svalue(sp - 2); |
sp[-2].u.type = pop_unfinished_type(); |
sp[-2].type = T_TYPE; |
} |
if (sp[-1].type != T_TYPE) { |
struct program *p = program_from_svalue(sp - 1); |
if (!p) { |
int args = 2; |
SIMPLE_BAD_ARG_ERROR("`^", 2, "type"); |
} |
type_stack_mark(); |
push_object_type(0, p->id); |
free_svalue(sp - 1); |
sp[-1].u.type = pop_unfinished_type(); |
sp[-1].type = T_TYPE; |
} |
} else { |
int args = 2; |
SIMPLE_BAD_ARG_ERROR("`^", 2, get_name_of_type(sp[-2].type)); |
} |
} |
|
switch(sp[-2].type) |
{ |
case T_OBJECT: |
CALL_OPERATOR(LFUN_XOR,2); |
break; |
|
case T_INT: |
sp--; |
sp[-1].u.integer ^= sp[0].u.integer; |
break; |
|
case T_MAPPING: |
{ |
struct mapping *m; |
m=merge_mappings(sp[-2].u.mapping, 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(sp[-2].u.multiset, 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(sp[-2].u.array, 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(sp - 1); |
if (!p) { |
int args = 2; |
SIMPLE_BAD_ARG_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(sp - 1); |
if (!p) { |
int args = 2; |
stack_swap(); |
SIMPLE_BAD_ARG_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, sp[-2].u.type); |
copy_pike_type(b, 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", sp, 2); |
} |
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
PMOD_EXPORT void f_xor(INT32 args) |
{ |
switch(args) |
{ |
case 0: SIMPLE_TOO_FEW_ARGS_ERROR("`^", 1); |
case 1: return; |
case 2: o_xor(); return; |
default: |
if(sp[-args].type==T_OBJECT) |
{ |
CALL_OPERATOR(LFUN_XOR, args); |
} else { |
speedup(args, o_xor); |
} |
} |
} |
|
static int generate_xor(node *n) |
{ |
switch(count_args(CDR(n))) |
{ |
case 1: |
do_docode(CDR(n),0); |
return 1; |
|
case 2: |
do_docode(CDR(n),0); |
emit0(F_XOR); |
return 1; |
|
default: |
return 0; |
} |
} |
|
PMOD_EXPORT void o_lsh(void) |
{ |
#ifdef AUTO_BIGNUM |
if ((sp[-1].type == T_INT) && (sp[-2].type == T_INT) && |
INT_TYPE_LSH_OVERFLOW(sp[-2].u.integer, sp[-1].u.integer)) |
convert_stack_top_to_bignum(); |
#endif /* AUTO_BIGNUM */ |
|
if(sp[-1].type != T_INT || sp[-2].type != T_INT) |
{ |
int args = 2; |
if(call_lfun(LFUN_LSH, LFUN_RLSH)) |
return; |
|
if(sp[-2].type != T_INT) |
SIMPLE_BAD_ARG_ERROR("`<<", 1, "int|object"); |
SIMPLE_BAD_ARG_ERROR("`<<", 2, "int(0..)|object"); |
} |
#ifndef AUTO_BIGNUM |
if (sp[-1].u.integer > 31) { |
sp--; |
sp[-1].u.integer = 0; |
return; |
} |
#endif /* !AUTO_BIGNUM */ |
if (sp[-1].u.integer < 0) { |
int args = 2; |
SIMPLE_BAD_ARG_ERROR("`<<", 2, "int(0..)|object"); |
} |
sp--; |
sp[-1].u.integer = sp[-1].u.integer << sp->u.integer; |
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
PMOD_EXPORT void f_lsh(INT32 args) |
{ |
if(args != 2) { |
|
SIMPLE_TOO_FEW_ARGS_ERROR("`<<", 2); |
} |
o_lsh(); |
} |
|
static int generate_lsh(node *n) |
{ |
if(count_args(CDR(n))==2) |
{ |
do_docode(CDR(n),DO_NOT_COPY_TOPLEVEL); |
emit0(F_LSH); |
return 1; |
} |
return 0; |
} |
|
PMOD_EXPORT void o_rsh(void) |
{ |
if(sp[-2].type != T_INT || sp[-1].type != T_INT) |
{ |
int args = 2; |
if(call_lfun(LFUN_RSH, LFUN_RRSH)) |
return; |
if(sp[-2].type != T_INT) |
SIMPLE_BAD_ARG_ERROR("`>>", 1, "int|object"); |
SIMPLE_BAD_ARG_ERROR("`>>", 2, "int(0..)|object"); |
} |
|
if (sp[-1].u.integer < 0) { |
int args = 2; |
SIMPLE_BAD_ARG_ERROR("`>>", 2, "int(0..)|object"); |
} |
|
if( |
#ifdef AUTO_BIGNUM |
(INT_TYPE_RSH_OVERFLOW(sp[-2].u.integer, sp[-1].u.integer)) |
#else /* !AUTO_BIGNUM */ |
(sp[-1].u.integer > 31) |
#endif /* AUTO_BIGNUM */ |
) |
{ |
sp--; |
if (sp[-1].u.integer < 0) { |
sp[-1].u.integer = -1; |
} else { |
sp[-1].u.integer = 0; |
} |
return; |
} |
|
sp--; |
sp[-1].u.integer = sp[-1].u.integer >> sp->u.integer; |
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
PMOD_EXPORT void f_rsh(INT32 args) |
{ |
if(args != 2) { |
|
SIMPLE_TOO_FEW_ARGS_ERROR("`>>", 2); |
} |
o_rsh(); |
} |
|
static int generate_rsh(node *n) |
{ |
if(count_args(CDR(n))==2) |
{ |
do_docode(CDR(n),DO_NOT_COPY); |
emit0(F_RSH); |
return 1; |
} |
return 0; |
} |
|
|
#define TWO_TYPES(X,Y) (((X)<<8)|(Y)) |
PMOD_EXPORT void o_multiply(void) |
{ |
int args = 2; |
switch(TWO_TYPES(sp[-2].type,sp[-1].type)) |
{ |
case TWO_TYPES(T_ARRAY, T_INT): |
{ |
struct array *ret; |
struct svalue *pos; |
INT32 e; |
if(sp[-1].u.integer < 0) |
SIMPLE_BAD_ARG_ERROR("`*", 2, "int(0..)"); |
ret=allocate_array(sp[-2].u.array->size * sp[-1].u.integer); |
pos=ret->item; |
for(e=0;e<sp[-1].u.integer;e++,pos+=sp[-2].u.array->size) |
assign_svalues_no_free(pos, |
sp[-2].u.array->item, |
sp[-2].u.array->size, |
sp[-2].u.array->type_field); |
ret->type_field=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(sp[-1].u.float_number < 0) |
SIMPLE_BAD_ARG_ERROR("`*", 2, "float(0..)"); |
|
src = sp[-2].u.array; |
delta = src->size; |
asize = (ptrdiff_t)floor(delta * 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(sp[-1].u.float_number < 0) |
SIMPLE_BAD_ARG_ERROR("`*", 2, "float(0..)"); |
src = sp[-2].u.string; |
len = (ptrdiff_t)floor(src->len * 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(sp[-1].u.integer < 0) |
SIMPLE_BAD_ARG_ERROR("`*", 2, "int(0..)"); |
ret=begin_wide_shared_string(sp[-2].u.string->len * sp[-1].u.integer, |
sp[-2].u.string->size_shift); |
pos=ret->str; |
len=sp[-2].u.string->len << sp[-2].u.string->size_shift; |
for(e=0;e<sp[-1].u.integer;e++,pos+=len) |
MEMCPY(pos,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(sp[-2].u.array,sp[-1].u.string); |
free_string(sp[-1].u.string); |
free_array(sp[-2].u.array); |
sp[-2].type=T_STRING; |
sp[-2].u.string=ret; |
sp--; |
return; |
} |
|
case TWO_TYPES(T_ARRAY,T_ARRAY): |
{ |
struct array *ret; |
ret=implode_array(sp[-2].u.array, sp[-1].u.array); |
pop_n_elems(2); |
push_array(ret); |
return; |
} |
|
case TWO_TYPES(T_FLOAT,T_FLOAT): |
sp--; |
sp[-1].u.float_number *= sp[0].u.float_number; |
return; |
|
case TWO_TYPES(T_FLOAT,T_INT): |
sp--; |
sp[-1].u.float_number *= (FLOAT_TYPE)sp[0].u.integer; |
return; |
|
case TWO_TYPES(T_INT,T_FLOAT): |
sp--; |
sp[-1].u.float_number= |
(FLOAT_TYPE) sp[-1].u.integer * sp[0].u.float_number; |
sp[-1].type=T_FLOAT; |
return; |
|
case TWO_TYPES(T_INT,T_INT): |
#ifdef AUTO_BIGNUM |
if(INT_TYPE_MUL_OVERFLOW(sp[-2].u.integer, sp[-1].u.integer)) |
{ |
convert_stack_top_to_bignum(); |
goto do_lfun_multiply; |
} |
#endif /* AUTO_BIGNUM */ |
sp--; |
sp[-1].u.integer *= sp[0].u.integer; |
return; |
|
default: |
do_lfun_multiply: |
if(call_lfun(LFUN_MULTIPLY, LFUN_RMULTIPLY)) |
return; |
|
PIKE_ERROR("`*", "Bad arguments.\n", sp, 2); |
} |
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
PMOD_EXPORT void f_multiply(INT32 args) |
{ |
switch(args) |
{ |
case 0: SIMPLE_TOO_FEW_ARGS_ERROR("`*", 1); |
case 1: return; |
case 2: o_multiply(); return; |
default: |
if(sp[-args].type==T_OBJECT) |
{ |
CALL_OPERATOR(LFUN_MULTIPLY, args); |
} else { |
INT32 i = -args, j = -1; |
|
while(i < j) { |
struct svalue tmp = sp[i]; |
sp[i++] = sp[j]; |
sp[j--] = tmp; |
} |
while(--args > 0) { |
|
stack_swap(); |
o_multiply(); |
} |
} |
} |
} |
|
static int generate_multiply(node *n) |
{ |
switch(count_args(CDR(n))) |
{ |
case 1: |
do_docode(CDR(n),0); |
return 1; |
|
case 2: |
do_docode(CDR(n),0); |
emit0(F_MULTIPLY); |
return 1; |
|
default: |
return 0; |
} |
} |
|
PMOD_EXPORT void o_divide(void) |
{ |
if(sp[-2].type!=sp[-1].type && !float_promote()) |
{ |
if(call_lfun(LFUN_DIVIDE, LFUN_RDIVIDE)) |
return; |
|
switch(TWO_TYPES(sp[-2].type,sp[-1].type)) |
{ |
case TWO_TYPES(T_STRING,T_INT): |
{ |
struct array *a; |
INT_TYPE len; |
ptrdiff_t size,e,pos=0; |
|
len=sp[-1].u.integer; |
if(!len) |
OP_DIVISION_BY_ZERO_ERROR("`/"); |
|
if(len<0) |
{ |
len=-len; |
size=sp[-2].u.string->len / len; |
pos+=sp[-2].u.string->len % len; |
}else{ |
size=sp[-2].u.string->len / len; |
} |
a=allocate_array(size); |
for(e=0;e<size;e++) |
{ |
a->item[e].u.string=string_slice(sp[-2].u.string, pos,len); |
a->item[e].type=T_STRING; |
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=sp[-1].u.float_number; |
if(len==0.0) |
OP_DIVISION_BY_ZERO_ERROR("`/"); |
|
if(len<0) |
{ |
len=-len; |
size=(ptrdiff_t)ceil( ((double)sp[-2].u.string->len) / len); |
a=allocate_array(size); |
|
for(last=sp[-2].u.string->len,e=0;e<size-1;e++) |
{ |
pos=sp[-2].u.string->len - (ptrdiff_t)((e+1)*len+0.5); |
a->item[size-1-e].u.string=string_slice(sp[-2].u.string, |
pos, |
last-pos); |
a->item[size-1-e].type=T_STRING; |
last=pos; |
} |
pos=0; |
a->item[0].u.string=string_slice(sp[-2].u.string, |
pos, |
last-pos); |
a->item[0].type=T_STRING; |
}else{ |
size=(ptrdiff_t)ceil( ((double)sp[-2].u.string->len) / len); |
a=allocate_array(size); |
|
for(last=0,e=0;e<size-1;e++) |
{ |
pos = DO_NOT_WARN((ptrdiff_t)((e+1)*len+0.5)); |
a->item[e].u.string=string_slice(sp[-2].u.string, |
last, |
pos-last); |
a->item[e].type=T_STRING; |
last=pos; |
} |
pos=sp[-2].u.string->len; |
a->item[e].u.string=string_slice(sp[-2].u.string, |
last, |
pos-last); |
a->item[e].type=T_STRING; |
} |
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=sp[-1].u.integer; |
if(!len) |
OP_DIVISION_BY_ZERO_ERROR("`/"); |
|
if(len<0) |
{ |
len = -len; |
pos = sp[-2].u.array->size % len; |
}else{ |
pos = 0; |
} |
size = sp[-2].u.array->size / len; |
|
a=allocate_array(size); |
for(e=0;e<size;e++) |
{ |
a->item[e].u.array=friendly_slice_array(sp[-2].u.array, |
pos, |
pos+len); |
pos+=len; |
a->item[e].type=T_ARRAY; |
} |
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=sp[-1].u.float_number; |
if(len==0.0) |
OP_DIVISION_BY_ZERO_ERROR("`/"); |
|
if(len<0) |
{ |
len=-len; |
size = (ptrdiff_t)ceil( ((double)sp[-2].u.array->size) / len); |
a=allocate_array(size); |
|
for(last=sp[-2].u.array->size,e=0;e<size-1;e++) |
{ |
pos=sp[-2].u.array->size - (ptrdiff_t)((e+1)*len+0.5); |
a->item[size-1-e].u.array=friendly_slice_array(sp[-2].u.array, |
pos, |
last); |
a->item[size-1-e].type=T_ARRAY; |
last=pos; |
} |
a->item[0].u.array=slice_array(sp[-2].u.array, |
0, |
last); |
a->item[0].type=T_ARRAY; |
}else{ |
size = (ptrdiff_t)ceil( ((double)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); |
a->item[e].u.array=friendly_slice_array(sp[-2].u.array, |
last, |
pos); |
a->item[e].type=T_ARRAY; |
last=pos; |
} |
a->item[e].u.array=slice_array(sp[-2].u.array, |
last, |
sp[-2].u.array->size); |
a->item[e].type=T_ARRAY; |
} |
a->type_field=BIT_ARRAY; |
pop_n_elems(2); |
push_array(a); |
return; |
} |
} |
|
PIKE_ERROR("`/", "Division on different types.\n", sp, 2); |
} |
|
switch(sp[-2].type) |
{ |
case T_OBJECT: |
do_lfun_division: |
CALL_OPERATOR(LFUN_DIVIDE,2); |
break; |
|
case T_STRING: |
{ |
struct array *ret; |
ret=explode(sp[-2].u.string,sp[-1].u.string); |
free_string(sp[-2].u.string); |
free_string(sp[-1].u.string); |
sp[-2].type=T_ARRAY; |
sp[-2].u.array=ret; |
sp--; |
return; |
} |
|
case T_ARRAY: |
{ |
struct array *ret=explode_array(sp[-2].u.array, sp[-1].u.array); |
pop_n_elems(2); |
push_array(ret); |
return; |
} |
|
case T_FLOAT: |
if(sp[-1].u.float_number == 0.0) |
OP_DIVISION_BY_ZERO_ERROR("`/"); |
sp--; |
sp[-1].u.float_number /= sp[0].u.float_number; |
return; |
|
case T_INT: |
{ |
INT_TYPE tmp; |
|
if (sp[-1].u.integer == 0) |
OP_DIVISION_BY_ZERO_ERROR("`/"); |
|
if(INT_TYPE_DIV_OVERFLOW(sp[-2].u.integer, sp[-1].u.integer)) |
{ |
#ifdef AUTO_BIGNUM |
stack_swap(); |
convert_stack_top_to_bignum(); |
stack_swap(); |
goto do_lfun_division; |
#else |
|
some CPU:s), thus we return what MININT*-1 returns: MININT. */ |
tmp = sp[-2].u.integer; |
#endif /* AUTO_BIGNUM */ |
} |
else |
tmp = sp[-2].u.integer/sp[-1].u.integer; |
sp--; |
|
|
|
if((sp[-1].u.integer<0) != (sp[0].u.integer<0)) |
if(tmp*sp[0].u.integer!=sp[-1].u.integer) |
tmp--; |
sp[-1].u.integer=tmp; |
return; |
} |
|
default: |
PIKE_ERROR("`/", "Bad argument 1.\n", sp, 2); |
} |
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
PMOD_EXPORT void f_divide(INT32 args) |
{ |
switch(args) |
{ |
case 0: |
case 1: SIMPLE_TOO_FEW_ARGS_ERROR("`/", 2); |
case 2: o_divide(); break; |
default: |
{ |
INT32 e; |
struct svalue *s=sp-args; |
push_svalue(s); |
for(e=1;e<args;e++) |
{ |
push_svalue(s+e); |
o_divide(); |
} |
assign_svalue(s,sp-1); |
pop_n_elems(sp-s-1); |
} |
} |
} |
|
static int generate_divide(node *n) |
{ |
if(count_args(CDR(n))==2) |
{ |
do_docode(CDR(n),DO_NOT_COPY_TOPLEVEL); |
emit0(F_DIVIDE); |
return 1; |
} |
return 0; |
} |
|
PMOD_EXPORT void o_mod(void) |
{ |
if(sp[-2].type != sp[-1].type && !float_promote()) |
{ |
if(call_lfun(LFUN_MOD, LFUN_RMOD)) |
return; |
|
switch(TWO_TYPES(sp[-2].type,sp[-1].type)) |
{ |
case TWO_TYPES(T_STRING,T_INT): |
{ |
struct pike_string *s=sp[-2].u.string; |
ptrdiff_t tmp,base; |
|
if(!sp[-1].u.integer) |
OP_MODULO_BY_ZERO_ERROR("`%"); |
|
if(sp[-1].u.integer<0) |
{ |
tmp=s->len % -sp[-1].u.integer; |
base=0; |
}else{ |
tmp=s->len % 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=sp[-2].u.array; |
ptrdiff_t tmp,base; |
if(!sp[-1].u.integer) |
OP_MODULO_BY_ZERO_ERROR("`%"); |
|
if(sp[-1].u.integer<0) |
{ |
tmp=a->size % -sp[-1].u.integer; |
base=0; |
}else{ |
tmp=a->size % 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", sp, 2); |
} |
|
switch(sp[-2].type) |
{ |
case T_OBJECT: |
CALL_OPERATOR(LFUN_MOD,2); |
break; |
|
case T_FLOAT: |
{ |
FLOAT_TYPE foo; |
if(sp[-1].u.float_number == 0.0) |
OP_MODULO_BY_ZERO_ERROR("`%"); |
sp--; |
foo = DO_NOT_WARN((FLOAT_TYPE)(sp[-1].u.float_number / |
sp[0].u.float_number)); |
foo = DO_NOT_WARN((FLOAT_TYPE)(sp[-1].u.float_number - |
sp[0].u.float_number * floor(foo))); |
sp[-1].u.float_number=foo; |
return; |
} |
case T_INT: |
if (sp[-1].u.integer == 0) |
OP_MODULO_BY_ZERO_ERROR("`%"); |
sp--; |
if(sp[-1].u.integer>=0) |
{ |
if(sp[0].u.integer>=0) |
{ |
sp[-1].u.integer %= sp[0].u.integer; |
}else{ |
sp[-1].u.integer=((sp[-1].u.integer+~sp[0].u.integer)%-sp[0].u.integer)-~sp[0].u.integer; |
} |
}else{ |
if(sp[0].u.integer>=0) |
{ |
sp[-1].u.integer=sp[0].u.integer+~((~sp[-1].u.integer) % sp[0].u.integer); |
}else{ |
sp[-1].u.integer=-(-sp[-1].u.integer % -sp[0].u.integer); |
} |
} |
return; |
|
default: |
PIKE_ERROR("`%", "Bad argument 1.\n", sp, 2); |
} |
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
PMOD_EXPORT void f_mod(INT32 args) |
{ |
if(args != 2) { |
|
SIMPLE_TOO_FEW_ARGS_ERROR("`%", 2); |
} |
o_mod(); |
} |
|
static int generate_mod(node *n) |
{ |
if(count_args(CDR(n))==2) |
{ |
do_docode(CDR(n),DO_NOT_COPY_TOPLEVEL); |
emit0(F_MOD); |
return 1; |
} |
return 0; |
} |
|
PMOD_EXPORT void o_not(void) |
{ |
switch(sp[-1].type) |
{ |
case T_INT: |
sp[-1].u.integer = !sp[-1].u.integer; |
break; |
|
case T_FUNCTION: |
case T_OBJECT: |
if(UNSAFE_IS_ZERO(sp-1)) |
{ |
pop_stack(); |
push_int(1); |
}else{ |
pop_stack(); |
push_int(0); |
} |
break; |
|
default: |
free_svalue(sp-1); |
sp[-1].type=T_INT; |
sp[-1].u.integer=0; |
} |
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
PMOD_EXPORT void f_not(INT32 args) |
{ |
if(args != 1) { |
|
SIMPLE_TOO_FEW_ARGS_ERROR("`!", 1); |
} |
o_not(); |
} |
|
static int generate_not(node *n) |
{ |
if(count_args(CDR(n))==1) |
{ |
do_docode(CDR(n),DO_NOT_COPY); |
emit0(F_NOT); |
return 1; |
} |
return 0; |
} |
|
PMOD_EXPORT void o_compl(void) |
{ |
switch(sp[-1].type) |
{ |
case T_OBJECT: |
CALL_OPERATOR(LFUN_COMPL,1); |
break; |
|
case T_INT: |
sp[-1].u.integer = ~ sp[-1].u.integer; |
break; |
|
case T_FLOAT: |
sp[-1].u.float_number = -1.0 - sp[-1].u.float_number; |
break; |
|
case T_TYPE: |
type_stack_mark(); |
if (sp[-1].u.type->type == T_NOT) { |
push_finished_type(sp[-1].u.type->car); |
} else { |
push_finished_type(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(sp - 1); |
if (!p) { |
PIKE_ERROR("`~", "Bad argument.\n", 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(sp[-1].u.string->size_shift) { |
bad_arg_error("`~", sp-1, 1, 1, "string(0)", sp-1, |
"Expected 8-bit string.\n"); |
} |
|
len = sp[-1].u.string->len; |
s = begin_shared_string(len); |
for (i=0; i<len; i++) |
s->str[i] = ~ sp[-1].u.string->str[i]; |
pop_n_elems(1); |
push_string(end_shared_string(s)); |
break; |
} |
|
default: |
PIKE_ERROR("`~", "Bad argument.\n", sp, 1); |
} |
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
PMOD_EXPORT void f_compl(INT32 args) |
{ |
if(args != 1) { |
|
SIMPLE_TOO_FEW_ARGS_ERROR("`~", 1); |
} |
o_compl(); |
} |
|
static int generate_compl(node *n) |
{ |
if(count_args(CDR(n))==1) |
{ |
do_docode(CDR(n),DO_NOT_COPY); |
emit0(F_COMPL); |
return 1; |
} |
return 0; |
} |
|
PMOD_EXPORT void o_negate(void) |
{ |
switch(sp[-1].type) |
{ |
case T_OBJECT: |
do_lfun_negate: |
CALL_OPERATOR(LFUN_SUBTRACT,1); |
break; |
|
case T_FLOAT: |
sp[-1].u.float_number=-sp[-1].u.float_number; |
return; |
|
case T_INT: |
#ifdef AUTO_BIGNUM |
if(INT_TYPE_NEG_OVERFLOW(sp[-1].u.integer)) |
{ |
convert_stack_top_to_bignum(); |
goto do_lfun_negate; |
} |
#endif /* AUTO_BIGNUM */ |
sp[-1].u.integer = - sp[-1].u.integer; |
return; |
|
default: |
PIKE_ERROR("`-", "Bad argument to unary minus.\n", 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 (ind->type == T_STRING) |
len = ind->u.string->len; |
else { |
#ifdef PIKE_DEBUG |
if (!ind || ind->type != 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) low = len - 1 - low; |
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) high = len - high; |
else high++; |
if (high < from) to = from; |
else if (high > len) to = len; |
else to = high; |
} |
|
if (ind->type == 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, --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 (sp++, low); |
break; |
case RANGE_LOW_OPEN: |
push_int (0); |
break; |
default: |
push_svalue (&end_pos); |
move_svalue (sp++, 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 (sp++, high); |
break; |
case RANGE_HIGH_OPEN: |
push_int (MAX_INT_TYPE); |
break; |
default: |
push_svalue (&end_pos); |
move_svalue (sp++, 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 |
} |
} |
|
PMOD_EXPORT void o_range2 (int bound_types) |
|
|
{ |
struct svalue *ind, *low, *high; |
|
high = bound_types & RANGE_HIGH_OPEN ? sp : sp - 1; |
low = bound_types & RANGE_LOW_OPEN ? high : high - 1; |
ind = low - 1; |
|
switch (ind->type) { |
case T_OBJECT: { |
struct object *o = ind->u.object; |
int f; |
if (!o->prog) |
bad_arg_error (range_func_name (bound_types), |
ind, sp - ind, 1, "object", ind, |
"Cannot call `[..] in destructed object.\n"); |
|
if ((f = FIND_LFUN (o->prog, LFUN_RANGE)) != -1) { |
struct svalue h; |
if (!(bound_types & RANGE_HIGH_OPEN)) { |
move_svalue (&h, high); |
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 (sp++, &h); |
push_int (INDEX_FROM_BEG); |
} |
else if (bound_types & RANGE_HIGH_OPEN) { |
push_int (0); |
push_int (OPEN_BOUND); |
} |
else { |
move_svalue (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), |
ind, sp - ind, 1, "object", ind, |
"Object got neither `[..] nor `[].\n"); |
case 2: |
bad_arg_error (range_func_name (bound_types), |
ind, sp - ind, 1, "object", ind, |
"Object got no `[..] and there is no _sizeof to " |
"translate the from-the-end index to use `[].\n"); |
case 3: |
bad_arg_error (range_func_name (bound_types), |
ind, 3, 1, "object", ind, |
"Cannot call `[..] in destructed object.\n"); |
default: |
free_svalue (ind); |
move_svalue (ind, sp - 1); |
|
sp = ind + 1; |
} |
|
break; |
} |
|
case T_STRING: |
case T_ARRAY: { |
INT_TYPE l, h; |
if (!(bound_types & RANGE_LOW_OPEN)) { |
if (low->type != T_INT) |
bad_arg_error (range_func_name (bound_types), |
ind, sp - ind, 2, "int", low, |
"Bad lower bound. Expected int, got %s.\n", |
get_name_of_type (low->type)); |
l = low->u.integer; |
} |
if (!(bound_types & RANGE_HIGH_OPEN)) { |
if (high->type != T_INT) |
bad_arg_error (range_func_name (bound_types), |
ind, sp - ind, high - ind + 1, "int", high, |
"Bad upper bound. Expected int, got %s.\n", |
get_name_of_type (high->type)); |
h = high->u.integer; |
} |
|
|
sp = ind + 1; |
|
string_or_array_range (bound_types, ind, l, h); |
break; |
} |
|
default: |
bad_arg_error (range_func_name (bound_types), |
ind, sp - ind, 1, "string|array|object", ind, |
"Cannot use [..] on a %s. Expected string, array or object.\n", |
get_name_of_type (ind->type)); |
} |
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
PMOD_EXPORT void f_range(INT32 args) |
{ |
struct svalue *ind; |
if (args != 5) |
SIMPLE_WRONG_NUM_ARGS_ERROR ("predef::`[..]", 5); |
ind = sp - 5; |
|
#define CALC_BOUND_TYPES(bound_types) do { \ |
if (ind[2].type != 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 (ind[4].type != 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 (ind->type) { |
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, 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"); |
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"); |
case 3: |
SIMPLE_ARG_ERROR ("predef::`[..]", 1, |
"Cannot call `[..] in destructed object.\n"); |
default: |
free_svalue (ind); |
move_svalue (ind, sp - 1); |
|
|
sp = ind + 1; |
} |
} |
|
break; |
} |
|
case T_STRING: |
case T_ARRAY: { |
INT_TYPE l, h; |
int bound_types; |
CALC_BOUND_TYPES (bound_types); |
|
if (!(bound_types & RANGE_LOW_OPEN)) { |
if (ind[1].type != T_INT) |
SIMPLE_ARG_TYPE_ERROR ("predef::`[..]", 2, "int"); |
l = ind[1].u.integer; |
} |
if (!(bound_types & RANGE_HIGH_OPEN)) { |
if (ind[3].type != 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"); |
} |
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
PMOD_EXPORT void f_index(INT32 args) |
{ |
switch(args) |
{ |
case 2: |
if(sp[-1].type==T_STRING) sp[-1].subtype=0; |
o_index(); |
break; |
case 3: |
move_svalue (sp, sp - 1); |
sp += 2; |
sp[-3].type = sp[-1].type = T_INT; |
sp[-3].subtype = sp[-1].subtype = NUMBER_NUMBER; |
sp[-3].u.integer = sp[-1].u.integer = INDEX_FROM_BEG; |
f_range (5); |
break; |
default: |
SIMPLE_WRONG_NUM_ARGS_ERROR ("predef::`[]", args); |
break; |
} |
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
PMOD_EXPORT void f_arrow(INT32 args) |
{ |
switch(args) |
{ |
case 0: |
case 1: |
PIKE_ERROR("`->", "Too few arguments.\n", sp, args); |
break; |
case 2: |
if(sp[-1].type==T_STRING) |
sp[-1].subtype=1; |
o_index(); |
break; |
default: |
PIKE_ERROR("`->", "Too many arguments.\n", sp, args); |
} |
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
PMOD_EXPORT void f_index_assign(INT32 args) |
{ |
switch (args) { |
case 0: |
case 1: |
case 2: |
PIKE_ERROR("`[]=", "Too few arguments.\n", sp, args); |
break; |
case 3: |
if(sp[-2].type==T_STRING) sp[-2].subtype=0; |
assign_lvalue (sp-3, sp-1); |
assign_svalue (sp-3, sp-1); |
pop_n_elems (args-1); |
break; |
default: |
PIKE_ERROR("`[]=", "Too many arguments.\n", sp, args); |
} |
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
PMOD_EXPORT void f_arrow_assign(INT32 args) |
{ |
switch (args) { |
case 0: |
case 1: |
case 2: |
PIKE_ERROR("`->=", "Too few arguments.\n", sp, args); |
break; |
case 3: |
if(sp[-2].type==T_STRING) sp[-2].subtype=1; |
assign_lvalue (sp-3, sp-1); |
assign_svalue (sp-3, sp-1); |
pop_n_elems (args-1); |
break; |
default: |
PIKE_ERROR("`->=", "Too many arguments.\n", sp, args); |
} |
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
PMOD_EXPORT void f_sizeof(INT32 args) |
{ |
INT32 tmp; |
if(args<1) |
PIKE_ERROR("sizeof", "Too few arguments.\n", sp, args); |
|
tmp=pike_sizeof(sp-args); |
|
pop_n_elems(args); |
push_int(tmp); |
} |
|
static node *optimize_sizeof(node *n) |
{ |
if (CDR(n) && (CDR(n)->token == F_APPLY) && |
(CADR(n)) && (CADR(n)->token == F_CONSTANT) && |
(CADR(n)->u.sval.type == T_FUNCTION) && |
(CADR(n)->u.sval.subtype == FUNCTION_BUILTIN)) { |
extern struct program *string_split_iterator_program; |
|
if ((CADR(n)->u.sval.u.efun->function == f_divide) && |
CDDR(n) && (CDDR(n)->token == F_ARG_LIST) && |
CADDR(n) && (CADDR(n)->type == string_type_string) && |
CDDDR(n) && (CDDDR(n)->token == F_CONSTANT) && |
(CDDDR(n)->u.sval.type == T_STRING) && |
(CDDDR(n)->u.sval.u.string->len == 1)) { |
p_wchar2 split = index_shared_string(CDDDR(n)->u.sval.u.string, 0); |
|
|
ADD_NODE_REF2(CADDR(n), |
return mkefuncallnode("sizeof", |
mkapplynode(mkprgnode(string_split_iterator_program), |
mknode(F_ARG_LIST, CADDR(n), |
mkintnode(split)))); |
); |
} |
if ((CADR(n)->u.sval.u.efun->function == f_minus) && |
CDDR(n) && (CDDR(n)->token == F_ARG_LIST) && |
CADDR(n) && (CADDR(n)->token == F_APPLY) && |
CAADDR(n) && (CAADDR(n)->token == F_CONSTANT) && |
(CAADDR(n)->u.sval.type == T_FUNCTION) && |
(CAADDR(n)->u.sval.subtype == FUNCTION_BUILTIN) && |
(CAADDR(n)->u.sval.u.efun->function == f_divide) && |
CDADDR(n) && (CDADDR(n)->token == F_ARG_LIST) && |
CADADDR(n) && (CADADDR(n)->type == string_type_string) && |
CDDADDR(n) && (CDDADDR(n)->token == F_CONSTANT) && |
(CDDADDR(n)->u.sval.type == T_STRING) && |
(CDDADDR(n)->u.sval.u.string->len == 1) && |
CDDDR(n)) { |
|
if (((CDDDR(n)->token == F_CONSTANT) && |
(CDDDR(n)->u.sval.type == T_ARRAY) && |
(CDDDR(n)->u.sval.u.array->size == 1) && |
(CDDDR(n)->u.sval.u.array->item[0].type == T_STRING) && |
(CDDDR(n)->u.sval.u.array->item[0].u.string->len == 0)) || |
((CDDDR(n)->token == F_APPLY) && |
CADDDR(n) && (CADDDR(n)->token == F_CONSTANT) && |
(CADDDR(n)->u.sval.type == T_FUNCTION) && |
(CADDDR(n)->u.sval.subtype == FUNCTION_BUILTIN) && |
(CADDDR(n)->u.sval.u.efun->function == f_allocate) && |
CDDDDR(n) && (CDDDDR(n)->token == F_ARG_LIST) && |
CADDDDR(n) && (CADDDDR(n)->token == F_CONSTANT) && |
(CADDDDR(n)->u.sval.type == T_INT) && |
(CADDDDR(n)->u.sval.u.integer == 1) && |
CDDDDDR(n) && (CDDDDDR(n)->token == F_CONSTANT) && |
(CDDDDDR(n)->u.sval.type == T_STRING) && |
(CDDDDDR(n)->u.sval.u.string->len == 0))) { |
|
p_wchar2 split = index_shared_string(CDDADDR(n)->u.sval.u.string, 0); |
ADD_NODE_REF2(CADADDR(n), |
return mkefuncallnode("sizeof", |
mkapplynode(mkprgnode(string_split_iterator_program), |
mknode(F_ARG_LIST, CADADDR(n), |
mknode(F_ARG_LIST, |
mkintnode(split), |
mkintnode(1))))); |
); |
} |
} |
} |
return NULL; |
} |
|
static int generate_sizeof(node *n) |
{ |
if(count_args(CDR(n)) != 1) return 0; |
if(do_docode(CDR(n),DO_NOT_COPY) != 1) |
Pike_fatal("Count args was wrong in sizeof().\n"); |
emit0(F_SIZEOF); |
return 1; |
} |
|
extern int generate_call_function(node *n); |
|
|
|
|
struct program *string_assignment_program; |
|
#undef THIS |
#define THIS ((struct string_assignment_storage *)(CURRENT_STORAGE)) |
|
*! |
*! String index operator. |
*/ |
static void f_string_assignment_index(INT32 args) |
{ |
ptrdiff_t len = THIS->s->len; |
INT_TYPE i, p; |
get_all_args("string[]",args,"%i",&p); |
i = p < 0 ? p + len : p; |
if(i<0 || i>=len) |
Pike_error("Index %"PRINTPIKEINT"d is out of string range " |
"%"PRINTPTRDIFFT"d..%"PRINTPTRDIFFT"d.\n", |
p, -len, len - 1); |
else |
i=index_shared_string(THIS->s,i); |
pop_n_elems(args); |
push_int(i); |
} |
|
|
|
|
|
static void f_string_assignment_assign_index(INT32 args) |
{ |
INT_TYPE p, i, j; |
union anything *u; |
ptrdiff_t len; |
|
get_all_args("string[]=",args,"%i%i",&p,&j); |
|
if((u=get_pointer_if_this_type(THIS->lval, T_STRING))) |
{ |
len = u->string->len; |
i = p < 0 ? p + len : p; |
if(i<0 || i>=len) |
Pike_error("Index %"PRINTPIKEINT"d is out of string range " |
"%"PRINTPTRDIFFT"d..%"PRINTPTRDIFFT"d.\n", |
p, -len, len - 1); |
free_string(THIS->s); |
u->string=modify_shared_string(u->string,i,j); |
copy_shared_string(THIS->s, u->string); |
} |
|
else{ |
lvalue_to_svalue_no_free(sp,THIS->lval); |
sp++; |
dmalloc_touch_svalue(Pike_sp-1); |
if(sp[-1].type != T_STRING) Pike_error("string[]= failed.\n"); |
len = sp[-1].u.string->len; |
i = p < 0 ? p + len : p; |
if(i<0 || i>=len) |
Pike_error("Index %"PRINTPIKEINT"d is out of string range " |
"%"PRINTPTRDIFFT"d..%"PRINTPTRDIFFT"d.\n", |
p, -len, len - 1); |
sp[-1].u.string=modify_shared_string(sp[-1].u.string,i,j); |
assign_lvalue(THIS->lval, sp-1); |
pop_stack(); |
} |
|
pop_n_elems(args); |
push_int(j); |
} |
|
|
static void init_string_assignment_storage(struct object *o) |
{ |
THIS->lval[0].type=T_INT; |
THIS->lval[1].type=T_INT; |
THIS->s=0; |
} |
|
static void exit_string_assignment_storage(struct object *o) |
{ |
free_svalues(THIS->lval, 2, BIT_MIXED); |
if(THIS->s) |
free_string(THIS->s); |
} |
|
|
|
|
void init_operators(void) |
{ |
ADD_EFUN ("`[..]", f_range, |
tOr3(tFunc(tStr tInt tRangeBound tInt tRangeBound, tStr), |
tFunc(tArr(tSetvar(0,tMix)) tInt tRangeBound tInt tRangeBound, tArr(tVar(0))), |
tFunc(tObj tMix tRangeBound tMix tRangeBound, tMix)), |
OPT_TRY_OPTIMIZE); |
|
ADD_INT_CONSTANT ("INDEX_FROM_BEG", INDEX_FROM_BEG, 0); |
ADD_INT_CONSTANT ("INDEX_FROM_END", INDEX_FROM_END, 0); |
ADD_INT_CONSTANT ("OPEN_BOUND", OPEN_BOUND, 0); |
|
ADD_EFUN ("`[]", f_index, |
tOr9(tFunc(tObj tMix tOr(tVoid,tMix), tMix), |
tFunc(tInt tString, tFunction), |
tFunc(tStr tInt, tInt), |
tFunc(tArr(tSetvar(0,tMix)) tMix, tVar(0)), |
tFunc(tMap(tMix,tSetvar(1,tMix)) tMix, tVar(1)), |
tFunc(tMultiset tMix, tInt01), |
tFunc(tPrg(tObj) tString, tMix), |
tFunc(tStr tInt tInt, tStr), |
tFunc(tArr(tSetvar(2,tMix)) tInt tInt, tArr(tVar(2)))), |
OPT_TRY_OPTIMIZE); |
|
|
ADD_EFUN2("`->",f_arrow,tOr(tFunc(tArr(tOr4(tObj,tMapping,tMultiset,tArray)) tStr,tArr(tMix)),tFunc(tOr4(tObj,tMapping,tMultiset,tPrg(tObj)) tStr,tMix)),OPT_TRY_OPTIMIZE,0,0); |
|
ADD_EFUN("`[]=", f_index_assign, |
tOr4(tFunc(tObj tStr tSetvar(0,tMix), tVar(0)), |
tFunc(tArr(tSetvar(1,tMix)) tInt tVar(1), tVar(1)), |
tFunc(tMap(tSetvar(2,tMix), tSetvar(3,tMix)) tVar(2) tVar(3), tVar(3)), |
tFunc(tSet(tSetvar(4,tMix)) tVar(4) tSetvar(5,tMix), tVar(5))), |
OPT_SIDE_EFFECT|OPT_TRY_OPTIMIZE); |
|
ADD_EFUN("`->=", f_arrow_assign, |
tOr3(tFunc(tArr(tOr4(tArray,tObj,tMultiset,tMapping)) tStr tSetvar(0,tMix), tVar(0)), |
tFunc(tOr(tObj, tMultiset) tStr tSetvar(1,tMix), tVar(1)), |
tFunc(tMap(tMix, tSetvar(2,tMix)) tStr tVar(2), tVar(2))), |
OPT_SIDE_EFFECT|OPT_TRY_OPTIMIZE); |
|
|
ADD_EFUN2("`==",f_eq, |
tOr5(tFuncV(tOr(tInt,tFloat) tOr(tInt,tFloat), |
tOr(tInt,tFloat),tInt01), |
tFuncV(tSetvar(0,tOr4(tString,tMapping,tMultiset,tArray)) |
tVar(0), tVar(0),tInt01), |
tFuncV(tOr3(tObj,tPrg(tObj),tFunction) tMix,tMix,tInt01), |
tFuncV(tMix tOr3(tObj,tPrg(tObj),tFunction),tMix,tInt01), |
tFuncV(tType(tMix) tType(tMix), |
tOr3(tPrg(tObj),tFunction,tType(tMix)),tInt01)), |
OPT_WEAK_TYPE|OPT_TRY_OPTIMIZE,optimize_eq,generate_comparison); |
|
ADD_EFUN2("`!=",f_ne, |
tOr5(tFuncV(tOr(tInt,tFloat) tOr(tInt,tFloat), |
tOr(tInt,tFloat),tInt01), |
tFuncV(tSetvar(0,tOr4(tString,tMapping,tMultiset,tArray)) |
tVar(0), tVar(0),tInt01), |
tFuncV(tOr3(tObj,tPrg(tObj),tFunction) tMix,tMix,tInt01), |
tFuncV(tMix tOr3(tObj,tPrg(tObj),tFunction),tMix,tInt01), |
tFuncV(tType(tMix) tType(tMix), |
tOr3(tPrg(tObj),tFunction,tType(tMix)),tInt01)), |
OPT_WEAK_TYPE|OPT_TRY_OPTIMIZE,0,generate_comparison); |
|
ADD_EFUN2("`!",f_not,tFuncV(tMix,tVoid,tInt01), |
OPT_TRY_OPTIMIZE,optimize_not,generate_not); |
|
#define CMP_TYPE "!function(!(object|mixed)...:mixed)&function(mixed...:int(0..1))|function(int|float...:int(0..1))|function(string...:int(0..1))|function(type|program,type|program,type|program...:int(0..1))" |
add_efun2("`<", f_lt,CMP_TYPE,OPT_TRY_OPTIMIZE,0,generate_comparison); |
add_efun2("`<=",f_le,CMP_TYPE,OPT_TRY_OPTIMIZE,0,generate_comparison); |
add_efun2("`>", f_gt,CMP_TYPE,OPT_TRY_OPTIMIZE,0,generate_comparison); |
add_efun2("`>=",f_ge,CMP_TYPE,OPT_TRY_OPTIMIZE,0,generate_comparison); |
|
ADD_EFUN2("`+",f_add, |
tOr7(tIfnot(tFuncV(tNone,tNot(tOr(tObj,tMix)),tMix),tFunction), |
tFuncV(tInt,tInt,tInt), |
tIfnot(tFuncV(tNone, tNot(tFlt), tMix), |
tFuncV(tOr(tInt,tFlt),tOr(tInt,tFlt),tFlt)), |
tIfnot(tFuncV(tNone, tNot(tStr), tMix), |
tFuncV(tOr3(tStr,tInt,tFlt), |
tOr3(tStr,tInt,tFlt),tStr)), |
tFuncV(tSetvar(0,tArray),tSetvar(1,tArray), |
tOr(tVar(0),tVar(1))), |
tFuncV(tSetvar(0,tMapping),tSetvar(1,tMapping), |
tOr(tVar(0),tVar(1))), |
tFuncV(tSetvar(0,tMultiset),tSetvar(1,tMultiset), |
tOr(tVar(0),tVar(1)))), |
OPT_TRY_OPTIMIZE,optimize_binary,generate_sum); |
|
ADD_EFUN2("`-",f_minus, |
tOr7(tIfnot(tFuncV(tNone,tNot(tOr(tObj,tMix)),tMix),tFunction), |
tFuncV(tInt,tInt,tInt), |
tIfnot(tFuncV(tNone,tNot(tFlt),tMix), |
tFuncV(tOr(tInt,tFlt),tOr(tInt,tFlt),tFlt)), |
tFuncV(tArr(tSetvar(0,tMix)),tArray,tArr(tVar(0))), |
tFuncV(tMap(tSetvar(1,tMix),tSetvar(2,tMix)), |
tOr3(tMapping,tArray,tMultiset), |
tMap(tVar(1),tVar(2))), |
tFunc(tSet(tSetvar(3,tMix)) tMultiset,tSet(tVar(3))), |
tFuncV(tStr,tStr,tStr)), |
OPT_TRY_OPTIMIZE,0,generate_minus); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#define F_AND_TYPE(Z) \ |
tOr(tFunc(tSetvar(0,Z),tVar(0)), \ |
tIfnot(tFunc(Z,tMix), \ |
tFuncV(tSetvar(1,Z),tSetvar(2,Z), \ |
tOr(tVar(1),tVar(2))))) |
|
|
ADD_EFUN2("`&",f_and, |
tOr4( |
tFunc(tSetvar(0,tMix),tVar(0)), |
|
tOr(tFuncV(tMix tObj,tMix,tMix), |
tFuncV(tObj tMix,tMix,tMix)), |
|
tOr6( F_AND_TYPE(tInt), |
F_AND_TYPE(tArray), |
F_AND_TYPE(tMapping), |
F_AND_TYPE(tMultiset), |
F_AND_TYPE(tString), |
F_AND_TYPE(tOr(tType(tMix),tPrg(tObj))) ), |
|
tIfnot(tFuncV(tNone, tNot(tMapping), tMix), |
tFuncV(tNone, |
tOr3(tArray,tMultiset,tSetvar(4,tMapping)), |
tVar(4)) ) |
), |
|
OPT_TRY_OPTIMIZE,optimize_binary,generate_and); |
|
#define LOG_TYPE \ |
tOr7(tOr(tFuncV(tMix tObj,tMix,tMix), \ |
tFuncV(tObj,tMix,tMix)), \ |
tFuncV(tInt,tInt,tInt), \ |
tFuncV(tSetvar(1,tMapping),tSetvar(2,tMapping),tOr(tVar(1),tVar(2))), \ |
tFuncV(tSetvar(3,tMultiset),tSetvar(4,tMultiset),tOr(tVar(3),tVar(4))), \ |
tFuncV(tSetvar(5,tArray),tSetvar(6,tArray),tOr(tVar(5),tVar(6))), \ |
tFuncV(tString,tString,tString), \ |
tFuncV(tOr(tType(tMix),tPrg(tObj)),tOr(tType(tMix),tPrg(tObj)),tType(tMix))) |
|
ADD_EFUN2("`|",f_or,LOG_TYPE,OPT_TRY_OPTIMIZE,optimize_binary,generate_or); |
|
ADD_EFUN2("`^",f_xor,LOG_TYPE,OPT_TRY_OPTIMIZE,optimize_binary,generate_xor); |
|
#define SHIFT_TYPE \ |
tOr(tAnd(tNot(tFuncV(tNone, tNot(tObj), tMix)), \ |
tOr(tFunc(tMix tObj,tMix), \ |
tFunc(tObj tMix,tMix))), \ |
tFunc(tInt tInt,tInt)) |
|
ADD_EFUN2("`<<", f_lsh, SHIFT_TYPE, OPT_TRY_OPTIMIZE, |
may_have_side_effects, generate_lsh); |
ADD_EFUN2("`>>", f_rsh, SHIFT_TYPE, OPT_TRY_OPTIMIZE, |
may_have_side_effects, generate_rsh); |
|
|
|
|
|
|
|
|
|
|
|
ADD_EFUN2("`*", f_multiply, |
tOr9(tIfnot(tFuncV(tNone,tNot(tOr(tObj,tMix)),tMix),tFunction), |
tFunc(tArr(tArr(tSetvar(1,tMix))) |
tArr(tSetvar(1,tMix)),tArr(tVar(1))), |
tFuncV(tInt,tInt,tInt), |
tIfnot(tFuncV(tNone,tNot(tFlt),tMix), |
tFuncV(tOr(tFlt,tInt),tOr(tFlt,tInt),tFlt)), |
tFunc(tArr(tStr) tStr,tStr), |
tFunc(tArr(tSetvar(0,tMix)) tInt,tArr(tVar(0))), |
tFunc(tArr(tSetvar(0,tMix)) tFlt,tArr(tVar(0))), |
tFunc(tStr tInt,tStr), |
tFunc(tStr tFlt,tStr)), |
OPT_TRY_OPTIMIZE,optimize_binary,generate_multiply); |
|
|
|
|
|
|
ADD_EFUN2("`/", f_divide, |
tOr5(tIfnot(tFuncV(tNone,tNot(tOr(tObj,tMix)),tMix),tFunction), |
tFuncV(tInt, tInt, tInt), |
tIfnot(tFuncV(tNone, tNot(tFlt), tMix), |
tFuncV(tOr(tFlt,tInt),tOr(tFlt,tInt),tFlt)), |
tFuncV(tArr(tSetvar(0,tMix)), |
tOr3(tArray,tInt,tFlt), |
tArr(tArr(tVar(0)))), |
tFuncV(tStr,tOr3(tStr,tInt,tFlt),tArr(tStr))), |
OPT_TRY_OPTIMIZE,0,generate_divide); |
|
|
|
|
|
|
|
ADD_EFUN2("`%", f_mod, |
tOr6(tFunc(tMix tObj,tMix), |
tFunc(tObj tMix,tMix), |
tFunc(tInt tInt,tInt), |
tFunc(tStr tInt,tStr), |
tFunc(tArr(tSetvar(0,tMix)) tInt,tArr(tVar(0))), |
tIfnot(tFuncV(tNone, tNot(tFlt), tMix), |
tFunc(tOr(tInt,tFlt) tOr(tInt,tFlt),tFlt))), |
OPT_TRY_OPTIMIZE,0,generate_mod); |
|
|
ADD_EFUN2("`~",f_compl, |
tOr6(tFunc(tObj,tMix), |
tFunc(tInt,tInt), |
tFunc(tFlt,tFlt), |
tFunc(tStr,tStr), |
tFunc(tType(tSetvar(0, tMix)), tType(tNot(tVar(0)))), |
tFunc(tPrg(tObj), tType(tMix))), |
OPT_TRY_OPTIMIZE,0,generate_compl); |
|
ADD_EFUN2("sizeof", f_sizeof, |
tFunc(tOr5(tStr,tMultiset,tArray,tMapping,tObj),tInt), |
OPT_TRY_OPTIMIZE, optimize_sizeof, generate_sizeof); |
|
|
ADD_EFUN2("`()",f_call_function,tFuncV(tMix,tMix,tMix),OPT_SIDE_EFFECT | OPT_EXTERNAL_DEPEND,0,generate_call_function); |
|
|
|
ADD_EFUN2("call_function",f_call_function,tFuncV(tMix,tMix,tMix),OPT_SIDE_EFFECT | OPT_EXTERNAL_DEPEND,0,generate_call_function); |
|
|
start_new_program(); |
ADD_STORAGE(struct string_assignment_storage); |
|
ADD_FUNCTION2("`[]", f_string_assignment_index, tFunc(tInt,tInt), 0, |
OPT_EXTERNAL_DEPEND); |
|
ADD_FUNCTION2("`[]=", f_string_assignment_assign_index, |
tFunc(tInt tInt,tInt), 0, OPT_SIDE_EFFECT); |
set_init_callback(init_string_assignment_storage); |
set_exit_callback(exit_string_assignment_storage); |
string_assignment_program=end_program(); |
} |
|
|
void exit_operators(void) |
{ |
if(string_assignment_program) |
{ |
free_program(string_assignment_program); |
string_assignment_program=0; |
} |
} |
|
void o_breakpoint(void) |
{ |
|
} |
|
|