|
|
|
|
|
|
#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 "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_security.h" |
#include "pike_compiler.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") |
|
|
|
|
|
|
|
#undef PIKE_MERGE_DESTR_A |
#define PIKE_MERGE_DESTR_A 0 |
|
|
|
|
#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)) |
|
void index_no_free(struct svalue *to,struct svalue *what,struct svalue *ind) |
{ |
#ifdef PIKE_SECURITY |
if(TYPEOF(*what) <= MAX_COMPLEX) |
if(!CHECK_DATA_SECURITY(what->u.array, SECURITY_BIT_INDEX)) |
Pike_error("Index permission denied.\n"); |
#endif |
|
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,sp-2,sp-1); |
pop_n_elems(2); |
*sp=s; |
dmalloc_touch_svalue(sp); |
sp++; |
dmalloc_touch_svalue(Pike_sp-1); |
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
PMOD_EXPORT void o_cast_to_int(void) |
{ |
switch(TYPEOF(sp[-1])) |
{ |
case T_OBJECT: |
if(!sp[-1].u.object->prog) { |
|
pop_stack(); |
push_int (0); |
} |
|
else { |
{ |
struct object *o = sp[-1].u.object; |
struct program *p = o->prog->inherits[SUBTYPEOF(sp[-1])].prog; |
int f = FIND_LFUN(p, LFUN_CAST); |
if(f == -1) |
Pike_error("No cast method in object.\n"); |
ref_push_string(literal_int_string); |
apply_low(o, f, 1); |
stack_pop_keep_top(); |
} |
|
if(TYPEOF(sp[-1]) != PIKE_T_INT) |
{ |
if(TYPEOF(sp[-1]) == T_OBJECT && sp[-1].u.object->prog) |
{ |
struct object *o = sp[-1].u.object; |
int f = FIND_LFUN(o->prog->inherits[SUBTYPEOF(sp[-1])].prog, |
LFUN__IS_TYPE); |
if( f != -1) |
{ |
ref_push_string(literal_int_string); |
apply_low(o, 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(TYPEOF(sp[-1]))); |
} |
else if(SUBTYPEOF(sp[-1]) == NUMBER_UNDEFINED) |
Pike_error("Cannot cast this object to int.\n"); |
} |
|
break; |
|
case T_FLOAT: |
if ( |
#ifdef HAVE_ISINF |
isinf(sp[-1].u.float_number) || |
#endif |
#ifdef HAVE_ISNAN |
isnan(sp[-1].u.float_number) || |
#endif |
0) { |
Pike_error("Can't cast infinites or NaN to int.\n"); |
} else { |
int i=DO_NOT_WARN((int)(sp[-1].u.float_number)); |
if((i < 0 ? -i : i) < floor(fabs(sp[-1].u.float_number))) |
{ |
|
|
convert_stack_top_to_bignum(); |
return; |
|
|
|
|
} |
else |
{ |
SET_SVAL(sp[-1], T_INT, NUMBER_NUMBER, integer, i); |
} |
} |
break; |
|
case T_STRING: |
|
|
|
if( (sp[-1].u.string->len >= 10) || sp[-1].u.string->size_shift ) |
convert_stack_top_string_to_inumber(10); |
else |
{ |
INT_TYPE i = STRTOL(sp[-1].u.string->str, 0, 10); |
free_string(sp[-1].u.string); |
SET_SVAL(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(sp[-1]))); |
} |
} |
|
|
PMOD_EXPORT void o_cast_to_string(void) |
{ |
struct pike_string *s; |
|
switch(TYPEOF(sp[-1])) |
{ |
case T_OBJECT: |
if(!sp[-1].u.object->prog) { |
|
pop_stack(); |
push_constant_text("0"); |
} else { |
{ |
struct object *o = sp[-1].u.object; |
int f = FIND_LFUN(o->prog->inherits[SUBTYPEOF(sp[-1])].prog, LFUN_CAST); |
if(f == -1) |
Pike_error("No cast method in object.\n"); |
ref_push_string(literal_string_string); |
apply_low(o, f, 1); |
stack_pop_keep_top(); |
} |
|
if(TYPEOF(sp[-1]) != PIKE_T_STRING) |
{ |
if(TYPEOF(sp[-1])==PIKE_T_INT && SUBTYPEOF(sp[-1])==NUMBER_UNDEFINED) |
Pike_error("Cannot cast this object to string.\n"); |
if(TYPEOF(sp[-1]) == T_OBJECT && sp[-1].u.object->prog) |
{ |
struct object *o = sp[-1].u.object; |
int f = FIND_LFUN(o->prog->inherits[SUBTYPEOF(sp[-1])].prog, |
LFUN__IS_TYPE); |
if( f != -1) |
{ |
ref_push_string(literal_string_string); |
apply_low(o, 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(TYPEOF(sp[-1]))); |
} |
} |
return; |
|
case T_ARRAY: |
{ |
int i, alen; |
struct array *a = 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 ("cast: 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(sp[-1]))); |
|
case PIKE_T_STRING: |
return; |
|
case T_FLOAT: |
{ |
char buf[MAX_FLOAT_SPRINTF_LEN+1]; |
format_pike_float (buf, sp[-1].u.float_number); |
s = make_shared_string(buf); |
break; |
} |
|
case T_INT: |
{ |
INT_TYPE org; |
char buf[MAX_INT_SPRINTF_LEN]; |
register char*b = buf+sizeof buf-1; |
register unsigned INT_TYPE i; |
org = 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(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(sp[-1])) |
{ |
if(run_time_type == T_MIXED) |
return; |
|
if (TYPEOF(sp[-1]) == T_OBJECT && !sp[-1].u.object->prog) { |
|
pop_stack(); |
push_int (0); |
} |
|
if(TYPEOF(sp[-1]) == T_OBJECT) |
{ |
struct object *o = sp[-1].u.object; |
int f = FIND_LFUN(o->prog->inherits[SUBTYPEOF(sp[-1])].prog, LFUN_CAST); |
if(f == -1) { |
if (run_time_type != T_PROGRAM) { |
Pike_error("No cast method in object.\n"); |
} |
f_object_program(1); |
return; |
} |
push_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(sp[-1]) == T_INT && |
SUBTYPEOF(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"); |
|
case T_MIXED: |
return; |
|
case T_MULTISET: |
switch(TYPEOF(sp[-1])) |
{ |
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(TYPEOF(sp[-1]))); |
} |
break; |
|
case T_MAPPING: |
switch(TYPEOF(sp[-1])) |
{ |
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 (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(sp[-1]))); |
} |
break; |
|
case T_ARRAY: |
switch(TYPEOF(sp[-1])) |
{ |
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(TYPEOF(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(sp[-1])) |
{ |
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(TYPEOF(sp[-1]))); |
} |
|
SET_SVAL(sp[-1], T_FLOAT, 0, float_number, f); |
break; |
} |
|
case T_OBJECT: |
switch(TYPEOF(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))) { |
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(sp[-1]))); |
} |
break; |
|
case T_PROGRAM: |
switch(TYPEOF(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))) { |
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; |
|
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(sp[-1]))); |
} |
} |
} |
|
if(run_time_type != TYPEOF(sp[-1])) |
{ |
switch(TYPEOF(sp[-1])) { |
case T_OBJECT: |
if(sp[-1].u.object->prog) |
{ |
struct object *o = sp[-1].u.object; |
int f = FIND_LFUN(o->prog->inherits[SUBTYPEOF(sp[-1])].prog, |
LFUN__IS_TYPE); |
if( f != -1) |
{ |
push_text(get_name_of_type(run_time_type)); |
apply_low(o, f, 1); |
f=!UNSAFE_IS_ZERO(sp-1); |
pop_stack(); |
if(f) goto emulated_type_ok; |
} |
} |
break; |
case T_FUNCTION: |
|
if ((run_time_type == T_PROGRAM) && |
program_from_function(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(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=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 << TYPEOF(ITEM(a)[e]); |
} |
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 (m, sp - 1); |
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(TYPEOF(sp[-2]) != T_TYPE) |
Pike_fatal("Cast expression destroyed stack or left droppings! (Type:%d)\n", |
TYPEOF(sp[-2])); |
#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); |
} |
|
|
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: |
case PIKE_T_ATTRIBUTE: |
type = type->cdr; |
goto loop; |
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_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, Pike_sp-1, 1, 1, t1->str, Pike_sp-1, |
"%s(): Soft cast failed.\n%S", |
fname, s.s); |
|
CALL_AND_UNSET_ONERROR(tmp1); |
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_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_le) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
COMPARISON(f_gt,"`>" , is_gt) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
COMPARISON(f_ge,"`>=",is_ge) |
|
|
#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->inherits[SUBTYPEOF(sp[-args])].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 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 float_heap_sift_down(struct svalue *svalues, int root, int nelems) |
{ |
FLOAT_ARG_TYPE val = svalues[root].u.float_number; |
FLOAT_ARG_TYPE abs_val = fabs(val); |
int child; |
|
while ((child = ((root<<1) +1)) < nelems) { |
int swap = root; |
FLOAT_ARG_TYPE s_abs_val; |
if ((s_abs_val = fabs(svalues[child].u.float_number)) < abs_val) { |
swap = child; |
} else { |
s_abs_val = abs_val; |
} |
child++; |
if ((child < nelems) && |
(fabs(svalues[child].u.float_number) < s_abs_val)) { |
swap = child; |
} |
if (swap == root) break; |
svalues[root] = svalues[swap]; |
root = swap; |
} |
svalues[root].u.float_number = val; |
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
PMOD_EXPORT void f_add(INT32 args) |
{ |
INT_TYPE e,size; |
TYPE_FIELD types; |
|
tail_recurse: |
if (args == 1) return; |
|
types=0; |
for(e=-args;e<0;e++) types |= 1<<TYPEOF(sp[e]); |
|
switch(types) |
{ |
default: |
if(!args) |
{ |
SIMPLE_TOO_FEW_ARGS_ERROR("`+", 1); |
}else{ |
if(types & BIT_OBJECT) |
{ |
struct object *o; |
struct program *p; |
int i; |
|
if (args == 1) |
return; |
|
if(TYPEOF(sp[-args]) == T_OBJECT && sp[-args].u.object->prog) |
{ |
|
o = sp[-args].u.object; |
p = o->prog->inherits[SUBTYPEOF(sp[-args])].prog; |
if(o->refs==1 && |
(i = FIND_LFUN(p, LFUN_ADD_EQ)) != -1) |
{ |
apply_low(o, i, args-1); |
stack_pop_keep_top(); |
return; |
} |
if((i = FIND_LFUN(p, LFUN_ADD)) != -1) |
{ |
apply_low(o, i, args-1); |
free_svalue(sp-2); |
sp[-2]=sp[-1]; |
sp--; |
dmalloc_touch_svalue(sp); |
return; |
} |
} |
|
for(e=1;e<args;e++) |
{ |
if(TYPEOF(sp[e-args]) == T_OBJECT && |
(p = (o = sp[e-args].u.object)->prog) && |
(i = FIND_LFUN(p->inherits[SUBTYPEOF(sp[e-args])].prog, |
LFUN_RADD)) != -1) |
{ |
|
if ((args = low_rop(o, i, e, args)) > 1) { |
goto tail_recurse; |
} |
return; |
} |
} |
} |
} |
|
switch(TYPEOF(sp[-args])) |
{ |
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; |
} |
else if(args == 2 && (size == sp[-1].u.string->len)) |
{ |
stack_swap(); |
pop_stack(); |
return; |
} |
|
tmp=sp[-args].u.string->len; |
r=new_realloc_shared_string(sp[-args].u.string,size,max_shift); |
mark_free_svalue (sp - args); |
buf=MKPCHARP_STR_OFF(r,tmp); |
for(e=-args+1;e<0;e++) |
{ |
if( sp[e].u.string->len ) |
{ |
update_flags_for_add( r, sp[e].u.string ); |
pike_string_cpy(buf,sp[e].u.string); |
INC_PCHARP(buf,sp[e].u.string->len); |
} |
} |
SET_SVAL(sp[-args], T_STRING, 0, string, low_end_shared_string(r)); |
|
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[MAX_NUM_BUF]; |
int max_shift=0, len; |
|
if ((TYPEOF(sp[-args]) != T_STRING) && (TYPEOF(sp[1-args]) != T_STRING)) { |
struct svalue *save_sp = sp; |
|
|
for (e=-args; e < 0; e++) { |
if (TYPEOF(save_sp[e]) == 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(TYPEOF(sp[e])) |
{ |
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 += MAX_INT_SPRINTF_LEN; |
break; |
|
case T_FLOAT: |
size += MAX_FLOAT_SPRINTF_LEN; |
break; |
} |
} |
|
r=begin_wide_shared_string(size,max_shift); |
buf=MKPCHARP_STR(r); |
size=0; |
|
for(e=-args;e<0;e++) |
{ |
switch(TYPEOF(sp[e])) |
{ |
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); |
#ifdef PIKE_DEBUG |
if (strlen (buffer) > MAX_INT_SPRINTF_LEN) |
Pike_fatal ("Formatted integer %s is %"PRINTSIZET"u, " |
"longer than assumed max %"PRINTSIZET"u.\n", |
buffer, strlen (buffer), MAX_INT_SPRINTF_LEN); |
#endif |
goto append_buffer; |
|
case T_FLOAT: |
sprintf(buffer,"%.*"PRINTPIKEFLOAT"g", |
PIKEFLOAT_DIG, sp[e].u.float_number); |
|
if (!strchr (buffer, '.') && !strchr (buffer, 'e')) |
strcat (buffer, ".0"); |
#ifdef PIKE_DEBUG |
if (strlen (buffer) > MAX_FLOAT_SPRINTF_LEN) |
Pike_fatal ("Formatted float %s is %"PRINTSIZET"u, " |
"longer than assumed max %"PRINTSIZET"u.\n", |
buffer, strlen (buffer), MAX_FLOAT_SPRINTF_LEN); |
#endif |
|
append_buffer: |
len = strlen(buffer); |
switch(max_shift) |
{ |
case 0: |
convert_0_to_0((p_wchar0 *)buf.ptr,buffer,len); |
break; |
|
case 1: |
convert_0_to_1((p_wchar1 *)buf.ptr,(p_wchar0 *)buffer,len); |
break; |
|
case 2: |
convert_0_to_2((p_wchar2 *)buf.ptr,(p_wchar0 *)buffer,len); |
break; |
} |
INC_PCHARP(buf,len); |
} |
} |
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: |
{ |
int of = 0; |
size = 0; |
for(e = -args; e < 0; e++) |
{ |
if (DO_INT_TYPE_ADD_OVERFLOW(size, sp[e].u.integer, &size)) |
{ |
convert_svalue_to_bignum(sp-args); |
f_add(args); |
return; |
} |
} |
sp-=args; |
push_int(size); |
break; |
|
} |
case BIT_FLOAT: |
if (args > 2) { |
|
|
|
|
|
|
|
|
|
|
for(e = args>>1; e--;) { |
float_heap_sift_down(Pike_sp-args, e, args); |
} |
while (args > 2) { |
|
FLOAT_ARG_TYPE top = Pike_sp[-args].u.float_number; |
Pike_sp[-args] = Pike_sp[-1]; |
Pike_sp--; |
args--; |
float_heap_sift_down(Pike_sp-args, 0, args); |
|
|
Pike_sp[-args].u.float_number += top; |
float_heap_sift_down(Pike_sp-args, 0, args); |
} |
} |
sp[-2].u.float_number += sp[-1].u.float_number; |
sp--; |
break; |
|
case BIT_FLOAT|BIT_INT: |
{ |
|
|
|
|
int i = args-1; |
e = 0; |
while (e < i) { |
for(;e < i; i--) { |
if (TYPEOF(sp[i-args]) == T_FLOAT) break; |
} |
for(;e < i; e++) { |
if (TYPEOF(sp[e-args]) == T_INT) break; |
} |
if (e < i) { |
|
struct svalue sval = sp[e-args]; |
sp[e-args] = sp[i-args]; |
sp[i-args] = sval; |
} |
} |
if (TYPEOF(sp[e-args]) == T_FLOAT) e++; |
|
if (args - e > 1) { |
f_add(args-e); |
} |
args = e+1; |
o_cast(float_type_string, PIKE_T_FLOAT); |
|
|
goto tail_recurse; |
} |
|
#define ADD_WITH_UNDEFINED(TYPE, T_TYPEID, ADD_FUNC, PUSH_FUNC) do { \ |
int e; \ |
if (TYPEOF(sp[-args]) == T_INT) { \ |
if(IS_UNDEFINED(sp-args)) \ |
{ \ |
struct TYPE *x; \ |
\ |
for(e=1;e<args;e++) \ |
if(TYPEOF(sp[e-args]) != 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 (TYPEOF(sp[e-args]) != T_INT) \ |
SIMPLE_ARG_TYPE_ERROR("`+", e+1, "int"); \ |
} \ |
\ |
else { \ |
for(e=1;e<args;e++) \ |
if (TYPEOF(sp[e-args]) != T_TYPEID) \ |
SIMPLE_ARG_TYPE_ERROR("`+", e+1, #TYPE); \ |
} \ |
\ |
DO_IF_DEBUG (Pike_fatal ("Shouldn't be reached.\n")); \ |
break; \ |
} 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) |
{ |
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) && |
pike_types_le(second_arg[0]->type, int_type_string)) |
{ |
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) && |
pike_types_le(second_arg[0]->type, int_type_string)) |
{ |
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)) { |
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) && |
CDR(search_args) && |
pike_types_le(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 (((*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_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(sp[-2]) == T_INT && TYPEOF(sp[-1]) == T_FLOAT) |
{ |
SET_SVAL(sp[-2], T_FLOAT, 0, float_number, (FLOAT_TYPE)sp[-2].u.integer); |
return 1; |
} |
else if(TYPEOF(sp[-1]) == T_INT && TYPEOF(sp[-2]) == T_FLOAT) |
{ |
SET_SVAL(sp[-1], T_FLOAT, 0, float_number, (FLOAT_TYPE)sp[-1].u.integer); |
return 1; |
} |
|
if(is_bignum_object_in_svalue(sp-2) && TYPEOF(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(sp-1) && TYPEOF(sp[-2]) == T_FLOAT) |
{ |
ref_push_type_value(float_type_string); |
stack_swap(); |
f_cast(); |
return 1; |
} |
|
return 0; |
} |
|
static int call_lfun(int left, int right) |
{ |
struct object *o; |
struct program *p; |
int i; |
|
if(TYPEOF(sp[-2]) == T_OBJECT && |
(p = (o = sp[-2].u.object)->prog) && |
(i = FIND_LFUN(p->inherits[SUBTYPEOF(sp[-2])].prog, left)) != -1) |
{ |
apply_low(o, i, 1); |
free_svalue(sp-2); |
sp[-2]=sp[-1]; |
sp--; |
dmalloc_touch_svalue(sp); |
return 1; |
} |
|
if(TYPEOF(sp[-1]) == T_OBJECT && |
(p = (o = sp[-1].u.object)->prog) && |
(i = FIND_LFUN(p->inherits[SUBTYPEOF(sp[-1])].prog, right)) != -1) |
{ |
push_svalue(sp-2); |
apply_low(o, 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 (TYPEOF(sp[-2]) != TYPEOF(sp[-1]) && !float_promote()) |
{ |
if(call_lfun(LFUN_SUBTRACT, LFUN_RSUBTRACT)) |
return; |
|
if (TYPEOF(sp[-2]) == T_MAPPING) |
switch (TYPEOF(sp[-1])) |
{ |
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(TYPEOF(sp[-2])), |
sp-1, "Subtract on different types.\n"); |
} |
|
switch(TYPEOF(sp[-2])) |
{ |
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; |
if (sp[-2].u.multiset->refs == 1) { |
l=merge_multisets(sp[-2].u.multiset, sp[-1].u.multiset, |
PIKE_ARRAY_OP_SUB | PIKE_MERGE_DESTR_A); |
} else { |
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: |
if(INT_TYPE_SUB_OVERFLOW(sp[-2].u.integer, sp[-1].u.integer)) |
{ |
convert_stack_top_to_bignum(); |
f_minus(2); |
return; |
} |
sp--; |
SET_SVAL(sp[-1], PIKE_T_INT, NUMBER_NUMBER, integer, |
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; |
TYPE_FIELD types = 0; |
struct svalue *s=sp-args; |
|
for(e=-args;e<0;e++) types |= 1<<TYPEOF(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,sp-1); |
pop_n_elems(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(TYPEOF(sp[-1]) != TYPEOF(sp[-2])) |
{ |
if(call_lfun(LFUN_AND, LFUN_RAND)) |
return; |
else if (((TYPEOF(sp[-1]) == T_TYPE) || (TYPEOF(sp[-1]) == T_PROGRAM) || |
(TYPEOF(sp[-1]) == T_FUNCTION)) && |
((TYPEOF(sp[-2]) == T_TYPE) || (TYPEOF(sp[-2]) == T_PROGRAM) || |
(TYPEOF(sp[-2]) == T_FUNCTION))) |
{ |
if (TYPEOF(sp[-2]) != 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); |
SET_SVAL(sp[-2], T_TYPE, 0, type, pop_unfinished_type()); |
} |
if (TYPEOF(sp[-1]) != 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); |
SET_SVAL(sp[-1], T_TYPE, 0, type, pop_unfinished_type()); |
} |
} |
else if (TYPEOF(sp[-2]) == T_MAPPING) |
switch (TYPEOF(sp[-1])) |
{ |
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(TYPEOF(sp[-2]))); |
} |
} |
|
switch(TYPEOF(sp[-2])) |
{ |
case T_OBJECT: |
CALL_OPERATOR(LFUN_AND,2); |
break; |
|
case T_INT: |
sp--; |
SET_SVAL(sp[-1], PIKE_T_INT, NUMBER_NUMBER, integer, |
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; |
if (sp[-2].u.multiset->refs == 1) { |
l=merge_multisets(sp[-2].u.multiset, sp[-1].u.multiset, |
PIKE_ARRAY_OP_AND | PIKE_MERGE_DESTR_A); |
} else { |
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(TYPEOF(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_TOO_FEW_ARGS_ERROR("`&", 1); |
case 1: return; |
case 2: o_and(); return; |
default: |
if(TYPEOF(sp[-args]) == T_OBJECT) |
{ |
CALL_OPERATOR(LFUN_AND, args); |
}else{ |
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(sp[-1]) != TYPEOF(sp[-2])) |
{ |
if(call_lfun(LFUN_OR, LFUN_ROR)) { |
return; |
} else if (((TYPEOF(sp[-1]) == T_TYPE) || (TYPEOF(sp[-1]) == T_PROGRAM) || |
(TYPEOF(sp[-1]) == T_FUNCTION)) && |
((TYPEOF(sp[-2]) == T_TYPE) || (TYPEOF(sp[-2]) == T_PROGRAM) || |
(TYPEOF(sp[-2]) == T_FUNCTION))) { |
if (TYPEOF(sp[-2]) != 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); |
SET_SVAL(sp[-2], T_TYPE, 0, type, pop_unfinished_type()); |
} |
if (TYPEOF(sp[-1]) != 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); |
SET_SVAL(sp[-1], T_TYPE, 0, type, pop_unfinished_type()); |
} |
} else { |
int args = 2; |
SIMPLE_BAD_ARG_ERROR("`|", 2, get_name_of_type(TYPEOF(sp[-2]))); |
} |
} |
|
switch(TYPEOF(sp[-2])) |
{ |
case T_OBJECT: |
CALL_OPERATOR(LFUN_OR,2); |
break; |
|
case T_INT: |
sp--; |
SET_SVAL(sp[-1], T_INT, NUMBER_NUMBER, integer, |
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; |
if (sp[-2].u.multiset->refs == 1) { |
l=merge_multisets(sp[-2].u.multiset, sp[-1].u.multiset, |
PIKE_ARRAY_OP_OR_LEFT | PIKE_MERGE_DESTR_A); |
} else { |
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: |
{ |
if (sp[-1].u.array->size == 1) { |
|
int i = array_search(sp[-2].u.array, sp[-1].u.array->item, 0); |
if (i == -1) { |
f_add(2); |
} else { |
pop_stack(); |
} |
} else if ((sp[-2].u.array == sp[-1].u.array) && |
(sp[-1].u.array->refs == 2)) { |
|
pop_stack(); |
} else { |
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(TYPEOF(sp[-args]) == T_OBJECT) |
{ |
CALL_OPERATOR(LFUN_OR, args); |
} else { |
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(sp[-1]) != TYPEOF(sp[-2])) |
{ |
if(call_lfun(LFUN_XOR, LFUN_RXOR)) { |
return; |
} else if (((TYPEOF(sp[-1]) == T_TYPE) || (TYPEOF(sp[-1]) == T_PROGRAM) || |
(TYPEOF(sp[-1]) == T_FUNCTION)) && |
((TYPEOF(sp[-2]) == T_TYPE) || (TYPEOF(sp[-2]) == T_PROGRAM) || |
(TYPEOF(sp[-2]) == T_FUNCTION))) { |
if (TYPEOF(sp[-2]) != 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); |
SET_SVAL(sp[-2], T_TYPE, 0, type, pop_unfinished_type()); |
} |
if (TYPEOF(sp[-1]) != 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); |
SET_SVAL(sp[-1], T_TYPE, 0, type, pop_unfinished_type()); |
} |
} else { |
int args = 2; |
SIMPLE_BAD_ARG_ERROR("`^", 2, get_name_of_type(TYPEOF(sp[-2]))); |
} |
} |
|
switch(TYPEOF(sp[-2])) |
{ |
case T_OBJECT: |
CALL_OPERATOR(LFUN_XOR,2); |
break; |
|
case T_INT: |
sp--; |
SET_SVAL(sp[-1], T_INT, NUMBER_NUMBER, integer, |
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; |
if (sp[-2].u.multiset->refs == 1) { |
l=merge_multisets(sp[-2].u.multiset, sp[-1].u.multiset, |
PIKE_ARRAY_OP_XOR | PIKE_MERGE_DESTR_A); |
} else { |
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(TYPEOF(sp[-args]) == T_OBJECT) |
{ |
CALL_OPERATOR(LFUN_XOR, args); |
} else { |
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) |
{ |
if ((TYPEOF(sp[-1]) == T_INT) && (TYPEOF(sp[-2]) == T_INT) && |
INT_TYPE_LSH_OVERFLOW(sp[-2].u.integer, sp[-1].u.integer)) |
convert_stack_top_to_bignum(); |
|
if(TYPEOF(sp[-1]) != T_INT || TYPEOF(sp[-2]) != T_INT) |
{ |
int args = 2; |
if(call_lfun(LFUN_LSH, LFUN_RLSH)) |
return; |
|
if(TYPEOF(sp[-2]) != 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"); |
} |
sp--; |
SET_SVAL(sp[-1], T_INT, NUMBER_NUMBER, 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) |
{ |
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) |
{ |
if(TYPEOF(sp[-2]) != T_INT || TYPEOF(sp[-1]) != T_INT) |
{ |
int args = 2; |
if(call_lfun(LFUN_RSH, LFUN_RRSH)) |
return; |
if(TYPEOF(sp[-2]) != 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( INT_TYPE_RSH_OVERFLOW(sp[-2].u.integer, sp[-1].u.integer) ) |
{ |
sp--; |
if (sp[-1].u.integer < 0) { |
SET_SVAL(sp[-1], T_INT, NUMBER_NUMBER, integer, -1); |
} else { |
SET_SVAL(sp[-1], T_INT, NUMBER_NUMBER, integer, 0); |
} |
return; |
} |
|
sp--; |
SET_SVAL(sp[-1], T_INT, NUMBER_NUMBER, 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) |
{ |
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(sp[-2]), TYPEOF(sp[-1]))) |
{ |
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); |
SET_SVAL(sp[-2], T_STRING, 0, 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; |
SET_SVAL_TYPE(sp[-1], T_FLOAT); |
return; |
|
case TWO_TYPES(T_INT,T_INT): |
{ |
INT_TYPE res; |
|
if (DO_INT_TYPE_MUL_OVERFLOW(sp[-2].u.integer, sp[-1].u.integer, &res)) |
{ |
convert_stack_top_to_bignum(); |
goto do_lfun_multiply; |
} |
|
sp--; |
SET_SVAL(sp[-1], T_INT, NUMBER_NUMBER, integer, res); |
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(TYPEOF(sp[-args]) == 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) |
{ |
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(sp[-2]) != TYPEOF(sp[-1]) && !float_promote()) |
{ |
if(call_lfun(LFUN_DIVIDE, LFUN_RDIVIDE)) |
return; |
|
switch(TWO_TYPES(TYPEOF(sp[-2]), TYPEOF(sp[-1]))) |
{ |
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++) |
{ |
SET_SVAL(a->item[e], T_STRING, 0, string, |
string_slice(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=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); |
SET_SVAL(a->item[size-1-e], T_STRING, 0, string, |
string_slice(sp[-2].u.string, pos, last-pos)); |
last=pos; |
} |
pos=0; |
SET_SVAL(a->item[0], T_STRING, 0, string, |
string_slice(sp[-2].u.string, pos, last-pos)); |
}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)); |
SET_SVAL(a->item[e], T_STRING, 0, string, |
string_slice(sp[-2].u.string, last, pos-last)); |
last=pos; |
} |
pos=sp[-2].u.string->len; |
SET_SVAL(a->item[e], T_STRING, 0, string, |
string_slice(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=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 = 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++) |
{ |
SET_SVAL(a->item[e], T_ARRAY, 0, array, |
friendly_slice_array(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=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)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); |
SET_SVAL(a->item[size-1-e], T_ARRAY, 0, array, |
friendly_slice_array(sp[-2].u.array, pos, last)); |
last=pos; |
} |
SET_SVAL(a->item[0], T_ARRAY, 0, array, |
slice_array(sp[-2].u.array, 0, last)); |
}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); |
SET_SVAL(a->item[e], T_ARRAY, 0, array, |
friendly_slice_array(sp[-2].u.array, last, pos)); |
last=pos; |
} |
SET_SVAL(a->item[e], T_ARRAY, 0, array, |
slice_array(sp[-2].u.array, last, 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", sp, 2); |
} |
|
switch(TYPEOF(sp[-2])) |
{ |
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); |
SET_SVAL(sp[-2], T_ARRAY, 0, 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)) |
{ |
stack_swap(); |
convert_stack_top_to_bignum(); |
stack_swap(); |
goto do_lfun_division; |
} |
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--; |
SET_SVAL(sp[-1], T_INT, NUMBER_NUMBER, 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) |
{ |
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(sp[-2]) != TYPEOF(sp[-1]) && !float_promote()) |
{ |
do_lfun_modulo: |
if(call_lfun(LFUN_MOD, LFUN_RMOD)) |
return; |
|
switch(TWO_TYPES(TYPEOF(sp[-2]), TYPEOF(sp[-1]))) |
{ |
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(TYPEOF(sp[-2])) |
{ |
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: |
{ |
int of = 0; |
INT_TYPE a = sp[-2].u.integer, |
b = 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; |
} |
sp--; |
SET_SVAL(sp[-1], T_INT, NUMBER_NUMBER, integer, res); |
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) |
{ |
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(sp[-1])) |
{ |
case T_INT: |
SET_SVAL(sp[-1], T_INT, NUMBER_NUMBER, 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); |
SET_SVAL(sp[-1], T_INT, NUMBER_NUMBER, 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) |
{ |
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(sp[-1])) |
{ |
case T_OBJECT: |
CALL_OPERATOR(LFUN_COMPL,1); |
break; |
|
case T_INT: |
SET_SVAL(sp[-1], T_INT, NUMBER_NUMBER, integer, ~sp[-1].u.integer); |
break; |
|
case T_FLOAT: |
sp[-1].u.float_number = (FLOAT_TYPE) -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) |
{ |
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(sp[-1])) |
{ |
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: |
if(INT_TYPE_NEG_OVERFLOW(sp[-1].u.integer)) |
{ |
convert_stack_top_to_bignum(); |
goto do_lfun_negate; |
} |
SET_SVAL(sp[-1], T_INT, NUMBER_NUMBER, 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 (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, --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); |
mark_free_svalue (low); |
break; |
case RANGE_LOW_OPEN: |
push_int (0); |
break; |
default: |
push_svalue (&end_pos); |
move_svalue (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 (sp++, high); |
mark_free_svalue (high); |
break; |
case RANGE_HIGH_OPEN: |
push_int (MAX_INT_TYPE); |
break; |
default: |
push_svalue (&end_pos); |
move_svalue (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 |
} |
return "Unexpected bound_types"; |
} |
|
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 (TYPEOF(*ind)) { |
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->inherits[SUBTYPEOF(*ind)].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=0, h=0; |
if (!(bound_types & RANGE_LOW_OPEN)) { |
if (TYPEOF(*low) != 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 (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), |
ind, 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; |
} |
|
|
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 (TYPEOF(*ind))); |
} |
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
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 (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"); |
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=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"); |
} |
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
PMOD_EXPORT void f_index(INT32 args) |
{ |
switch(args) |
{ |
case 2: |
if(TYPEOF(sp[-1]) == T_STRING) SET_SVAL_SUBTYPE(sp[-1], 0); |
o_index(); |
break; |
case 3: |
move_svalue (sp, sp - 1); |
sp += 2; |
SET_SVAL(sp[-1], T_INT, NUMBER_NUMBER, integer, INDEX_FROM_BEG); |
sp[-3] = sp[-1]; |
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(TYPEOF(sp[-1]) == T_STRING) |
SET_SVAL_SUBTYPE(sp[-1], 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(TYPEOF(sp[-2]) == T_STRING) SET_SVAL_SUBTYPE(sp[-2], 0); |
assign_lvalue (sp-3, sp-1); |
stack_pop_n_elems_keep_top (2); |
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(TYPEOF(sp[-2]) == T_STRING) SET_SVAL_SUBTYPE(sp[-2], 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) && |
(TYPEOF(CADR(n)->u.sval) == T_FUNCTION) && |
(SUBTYPEOF(CADR(n)->u.sval) == 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) && pike_types_le(CADDR(n)->type, string_type_string) && |
CDDDR(n) && (CDDDR(n)->token == F_CONSTANT) && |
(TYPEOF(CDDDR(n)->u.sval) == 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) && |
(TYPEOF(CAADDR(n)->u.sval) == T_FUNCTION) && |
(SUBTYPEOF(CAADDR(n)->u.sval) == FUNCTION_BUILTIN) && |
(CAADDR(n)->u.sval.u.efun->function == f_divide) && |
CDADDR(n) && (CDADDR(n)->token == F_ARG_LIST) && |
CADADDR(n) && pike_types_le(CADADDR(n)->type, string_type_string) && |
CDDADDR(n) && (CDDADDR(n)->token == F_CONSTANT) && |
(TYPEOF(CDDADDR(n)->u.sval) == T_STRING) && |
(CDDADDR(n)->u.sval.u.string->len == 1) && |
CDDDR(n)) { |
|
if (((CDDDR(n)->token == F_CONSTANT) && |
(TYPEOF(CDDDR(n)->u.sval) == T_ARRAY) && |
(CDDDR(n)->u.sval.u.array->size == 1) && |
(TYPEOF(CDDDR(n)->u.sval.u.array->item[0]) == 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) && |
(TYPEOF(CADDDR(n)->u.sval) == T_FUNCTION) && |
(SUBTYPEOF(CADDDR(n)->u.sval) == 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) && |
(TYPEOF(CADDDDR(n)->u.sval) == T_INT) && |
(CADDDDR(n)->u.sval.u.integer == 1) && |
CDDDDDR(n) && (CDDDDDR(n)->token == F_CONSTANT) && |
(TYPEOF(CDDDDDR(n)->u.sval) == 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) |
{ |
struct compilation *c = THIS_COMPILATION; |
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); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static int generate__Static_assert(node *n) |
{ |
struct compilation *c = THIS_COMPILATION; |
ptrdiff_t tmp; |
node **expr = my_get_arg(&_CDR(n), 0); |
node **msg = my_get_arg(&_CDR(n), 1); |
if(!expr || !msg || count_args(CDR(n)) != 2) { |
yyerror("Bad number of arguments to _Static_assert()."); |
return 1; |
} |
tmp = eval_low(*msg, 0); |
if (tmp < 1) { |
yyerror("Argument 2 to _Static_assert() is not constant."); |
return 1; |
} |
if (tmp > 1) pop_n_elems(tmp-1); |
if (TYPEOF(Pike_sp[-1]) != T_STRING) { |
yyerror("Bad argument 2 to _Static_assert(), expected string."); |
return 1; |
} |
tmp = eval_low(*expr, 0); |
if (tmp < 1) { |
pop_stack(); |
yyerror("Argument 1 to _Static_assert is not constant."); |
return 1; |
} |
if (tmp > 1) pop_n_elems(tmp-1); |
if (SAFE_IS_ZERO(Pike_sp-1)) { |
my_yyerror("Assertion failed: %S", Pike_sp[-2].u.string); |
} |
pop_n_elems(2); |
return 1; |
} |
|
|
|
|
struct program *string_assignment_program; |
|
#undef THIS |
|