pike.git
/
src
/
operators.c
version
»
Context lines:
10
20
40
80
file
none
3
pike.git/src/operators.c:1:
/* || This file is part of Pike. For copyright information see COPYRIGHT. || Pike is distributed under GPL, LGPL and MPL. See the file COPYING || for more information.
-
|| $Id$
+
*/ #include "global.h" #include <math.h> #include "interpret.h" #include "svalue.h" #include "multiset.h" #include "mapping.h" #include "array.h" #include "stralloc.h"
pike.git/src/operators.c:23:
#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") /* The destructive multiset merge code is broken.
pike.git/src/operators.c:53:
/* It utilizes that log10(256) ~= 2.4 < 5/2. */ /* One extra char for the sign and one for the \0 terminator. */ #define MAX_INT_SPRINTF_LEN (2 + (SIZEOF_INT_TYPE * 5 + 1) / 2) /* Enough to hold a Pike float or int in textform */ #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;
pike.git/src/operators.c:111:
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;
-
#ifdef AUTO_BIGNUM
+
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; } /* FALL_THROUGH */
-
#endif /* AUTO_BIGNUM */
+
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",
pike.git/src/operators.c:159:
"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))); } }
-
void o_index(void)
+
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); }
pike.git/src/operators.c:225:
case T_OBJECT: if(!sp[-1].u.object->prog) { /* Casting a destructed object should be like casting a zero. */ pop_stack(); push_int (0); } else { { struct object *o = sp[-1].u.object;
-
struct pike_string *s;
+
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
_
MAKE
_
CONST_STRING
(
s, "
int
");
-
push
_string
(s
);
+
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) {
-
struct pike
_
string *s;
-
REF
_
MAKE_CONST_STRING
(
s, "
int
");
-
push
_string
(s
);
+
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:
+
case T_FLOAT:
{
+
FLOAT_TYPE f = sp[-1].u.float_number;
+
if ( #ifdef HAVE_ISINF
-
isinf(
sp[-1].u.float_number
) ||
+
isinf(
f
) ||
#endif #ifdef HAVE_ISNAN
-
isnan(
sp[-1].u.float_number
) ||
+
isnan(
f
) ||
#endif
-
0)
{
+
0)
Pike_error("Can't cast infinites or NaN to int.\n");
-
} else {
-
int
i=DO_NOT_WARN
((
int)(sp[-1].u.float_number));
-
#ifdef
AUTO
_
BIGNUM
-
if((i
<
0 ? -i : i) < floor(fabs(sp[-1].u.float
_
number
))
)
-
{
-
/* Note: This includes the case when i = 0x80000000, i.e.
-
the absolute value is not computable. */
+
+
if
(
UNLIKELY
(
f
> MAX
_
INT_TYPE
||
f
<
MIN
_
INT_TYPE
)) {
convert_stack_top_to_bignum();
-
return; /* FIXME: OK to return? Cast tests below indicates
-
we have to do this
,
at least for now... /Noring */
-
/* Yes
,
it is ok to return
,
it is actually an optimization :
)
-
* /Hubbe
-
*/
+
}
else
{
+
SET_SVAL(sp[-1],
T_INT
,
NUMBER_NUMBER
,
integer
,
f
)
;
}
-
else
-
#endif /* AUTO_BIGNUM */
-
{
-
SET_SVAL(sp[-1], T_INT, NUMBER_NUMBER, integer, i);
-
}
-
}
+
break;
-
+
}
case T_STRING:
-
/* This can be here independently of AUTO_BIGNUM. Besides,
-
we really want to reduce the number of number parsers
-
around here. :) /Noring */
-
#ifdef AUTO_BIGNUM
+
/* The generic function is rather slow, so I added this * code for benchmark purposes. :-) /per */ if( (sp[-1].u.string->len >= 10) || sp[-1].u.string->size_shift ) convert_stack_top_string_to_inumber(10); else
-
#endif /* AUTO_BIGNUM */
+
{
-
INT_TYPE i =
STRTOL
(sp[-1].u.string->str, 0, 10);
+
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])));
-
+
break;
} } /* Special case for casting to string. */ PMOD_EXPORT void o_cast_to_string(void) {
-
char
buf[MAX
_
NUM_BUF]
;
+
struct
pike
_
string *s
;
+
switch(TYPEOF(sp[-1])) { case T_OBJECT: if(!sp[-1].u.object->prog) { /* Casting a destructed object should be like casting a zero. */ 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");
-
push_
constant_text
(
"
string
"
);
+
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) {
-
struct pike
_
string *s;
-
REF
_
MAKE_CONST_STRING
(
s, "
string
");
-
push
_string
(s
);
+
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;
-
struct pike_string *s;
+
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); }
pike.git/src/operators.c:398:
case 1: if ((unsigned INT32) val <= 0xffff) break; shift = 2; /* FALL THROUGH */ 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",
+
Pike_error ("Item %d is too large: %"PRINTPIKEINT"x.\n",
i, val); #endif break; } } s = begin_wide_shared_string(a->size, shift); switch(shift) {
-
default:
-
#ifdef PIKE_DEBUG
-
Pike_fatal("cast: Bad shift: %d.\n", shift);
-
break;
+
case 0:
-
#endif
+
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; }
pike.git/src/operators.c:434:
break; case 2: { p_wchar2 *str2 = STR2(s); for(i = a->size; i--; ) { str2[i] = (p_wchar2) a->item[i].u.integer; } } break; }
-
s = end_shared_string(s);
+
pop_stack();
-
push_string(s);
+
push_string(
end_shared_string(
s)
)
;
} return; default: Pike_error("Cannot cast %s to string.\n", get_name_of_type(TYPEOF(sp[-1])));
-
+
break;
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:
-
sprintf(
buf
,
"%"PRINTPIKEINT"d",
sp[-1].u.integer);
+
{
+
INT_TYPE org;
+
char
buf
[MAX_INT_SPRINTF_LEN];
+
char *b = buf+sizeof buf-1;
+
unsigned INT_TYPE i;
+
org =
sp[-1].u.integer
;
+
*b-- = '\0';
+
i = org;
+
+
if( org < 0
)
+
i = -i
;
+
+
goto jin; /* C as a macro assembler :-) */
+
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,
make_shared_string(buf
)
)
;
+
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) { /* Casting a destructed object should be like casting a zero. */ 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(f == -1)
{
+
if (run_time_type != T_PROGRAM) {
Pike_error("No cast method in object.\n");
-
push_
string
(
describe
_type(type));
+
}
+
f_object_program(1);
+
return;
+
}
+
push_
static_text
(
get
_
name_of_
type(type
->type
));
apply_low(o, f, 1);
-
+
+
if (run_time_type == T_PROGRAM) {
+
if (IS_UNDEFINED(Pike_sp-1)) {
+
pop_stack();
+
f_object_program(1);
+
return;
+
}
+
}
+
stack_pop_keep_top();
-
}else
+
-
+
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");
-
+
break;
-
case T_MIXED:
-
return;
-
+
case T_MULTISET: switch(TYPEOF(sp[-1])) { case T_ARRAY: { extern void f_mkmultiset(INT32); f_mkmultiset(1); break; }
pike.git/src/operators.c:561:
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;
pike.git/src/operators.c:605:
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;
-
INT32
lineno;
+
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); } /* FIXME: Ought to allow compile_handler to override. */ APPLY_MASTER("cast_to_object",2); return;
pike.git/src/operators.c:643:
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;
-
INT32
lineno;
+
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); } /* FIXME: Ought to allow compile_handler to override. */ APPLY_MASTER("cast_to_program",2); return;
pike.git/src/operators.c:671:
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])) {
-
if
(TYPEOF(sp[-1])
==
T_OBJECT
&&
sp[-1].u.object->prog)
+
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));
+
push_
static_
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:
+
/* Check that the function actually is a program. */
+
if ((run_time_type == T_PROGRAM) &&
+
program_from_function(sp-1)) {
+
return; /* No need for further post-processing. */
+
}
+
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)
pike.git/src/operators.c:775:
if((m=(struct multiset *)BEGIN_CYCLIC(tmp,0))) { ref_push_multiset(m); }else{ #ifdef PIKE_DEBUG struct svalue *save_sp=sp+1; #endif ptrdiff_t nodepos;
-
if (multiset_indval (tmp))
-
Pike_error ("FIXME: Casting not implemented for multisets with values.\n");
+
push_multiset (m = allocate_multiset (multiset_sizeof (tmp), multiset_get_flags (tmp), multiset_get_cmp_less (tmp))); SET_CYCLIC_RET(m); if ((nodepos = multiset_first (tmp)) >= 0) { ONERROR uwp; SET_ONERROR (uwp, do_sub_msnode_ref, tmp); do { push_multiset_index (tmp, nodepos); o_cast(itype, run_time_itype);
-
multiset_insert
_2
(m, sp - 1
, NULL, 0
);
+
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
pike.git/src/operators.c:905:
return !s->u.integer; case PIKE_T_FUNCTION: if (SUBTYPEOF(*s) == FUNCTION_BUILTIN) return 0; /* FALL_THROUGH */ 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) {
-
if
(type->type
==
PIKE_T_INT
) {
+
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;
-
}
-
if (type->type ==
PIKE_T_FLOAT
)
return 1;
-
if
(type->type ==
PIKE_T_STRING
) {
+
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;
-
}
-
switch(type->type) {
+
case PIKE_T_OBJECT: { struct program *p; /* Common cases. */ 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); }
pike.git/src/operators.c:992:
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) { /* FIXME: Add code here. */ return 1; } } if ((lfun = FIND_LFUN(s->u.object->prog, LFUN__IS_TYPE)) != -1) { int ret;
-
push_text(get_name_of_type(type->type));
+
push_
static_
text(get_name_of_type(type->type));
apply_low(s->u.object, lfun, 1); ret = !UNSAFE_IS_ZERO(Pike_sp-1); pop_stack(); return ret; } return 0; } if ((TYPEOF(*s) == PIKE_T_FUNCTION) && (type->type == PIKE_T_PROGRAM)) { /* FIXME: Add code here. */ return 1;
pike.git/src/operators.c:1021:
void o_check_soft_cast(struct svalue *s, struct pike_type *type) { if (!low_check_soft_cast(s, type)) { /* Note: get_type_from_svalue() doesn't return a fully specified type * for array, mapping and multiset, so we perform a more lenient * check for them. */ struct pike_type *sval_type = get_type_of_svalue(s); struct pike_string *t1;
-
struct
pike_
string
*t2
;
+
struct
string
_
builder
s
;
char *fname = "__soft-cast";
-
+
ONERROR tmp0;
ONERROR tmp1;
-
ONERROR tmp2;
+
-
+
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) { /* Look up the function-name */ 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);
-
t2 = describe_type(sval_type);
-
SET_ONERROR(tmp2, do_free_string, t2);
-
+
free_type(sval_type); bad_arg_error(NULL, Pike_sp-1, 1, 1, t1->str, Pike_sp-1,
-
"%s(): Soft cast failed.
Expected
%
s, got %s\n
",
-
fname,
t1->str, t2->str
);
-
/* NOT_REACHED */
-
UNSET_ONERROR(
tmp2
);
-
UNSET_ONERROR(
tmp1
)
;
-
free_string(t2
);
-
free_string(t1);
+
"%s(): Soft cast failed.
\n
%
S
",
+
fname,
s.s
);
+
+
UNREACHABLE(CALL
_
AND_
UNSET_ONERROR(
tmp1
)
)
;
+
UNREACHABLE(CALL_AND_
UNSET_ONERROR(
tmp0
));
} } #define COMPARISON(ID,NAME,FUN) \ PMOD_EXPORT void ID(INT32 args) \ { \ int i; \ switch(args) \ { \ case 0: case 1: \
pike.git/src/operators.c:1131:
*! *! Otherwise, if the arguments are of different types, the test is *! unsuccessful. Function pointers to programs are automatically *! converted to program pointers if necessary, though. *! *! Otherwise the test depends on the type of the arguments: *! @mixed *! @type int *! Successful iff the two integers are numerically equal. *! @type float
-
*! Successful iff the two floats are numerically equal
or if
-
*!
both
are
NaN.
+
*! Successful iff the two floats are numerically equal
and
+
*!
not
NaN.
*! @type string *! Successful iff the two strings are identical, character for *! character. (Since all strings are kept unique, this is *! actually a test whether the arguments point to the same *! string, and it therefore run in constant time.) *! @type array|mapping|multiset|object|function|program|type *! Successful iff the two arguments point to the same instance. *! @endmixed *! *! @returns
pike.git/src/operators.c:1434:
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) { /* The first argument is an object. */ 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();
pike.git/src/operators.c:1496:
"Incompatible types\n"); return; /* compiler hint */ 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);
+
+
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;
+
int max_shift=0
, len
;
if ((TYPEOF(sp[-args]) != T_STRING) && (TYPEOF(sp[1-args]) != T_STRING)) { struct svalue *save_sp = sp; /* We need to perform a normal addition first. */ for (e=-args; e < 0; e++) { if (TYPEOF(save_sp[e]) == T_STRING) break; *(sp++) = save_sp[e]; dmalloc_touch_svalue(Pike_sp-1);
pike.git/src/operators.c:1630:
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,
strlen(buffer
)
)
;
+
convert_0_to_0((p_wchar0 *)buf.ptr,buffer,
len
);
break; case 1:
-
convert_0_to_1((p_wchar1 *)buf.ptr,(p_wchar0 *)buffer,
-
strlen(buffer
)
)
;
+
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,
-
strlen(buffer
)
)
;
+
convert_0_to_2((p_wchar2 *)buf.ptr,(p_wchar0 *)buffer,
len
);
break;
-
+
}
-
INC_PCHARP(buf,
strlen(buffer
)
)
;
+
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:
-
#ifdef
AUTO_BIGNUM
+
{
+
int of = 0;
size = 0; for(e = -args; e < 0; e++) {
-
if(INT_TYPE_ADD_OVERFLOW(sp[e].u.integer, size))
+
if
(
DO_
INT_TYPE_ADD_OVERFLOW(
size,
sp[e].u.integer,
&
size))
{ convert_svalue_to_bignum(sp-args); f_add(args); return; }
-
else
-
{
-
size += sp[e].u.integer;
+
}
-
}
+
sp-=args; push_int(size);
-
#else
-
size=0;
-
for(e=-args; e<0; e++) size+=sp[e].u.integer;
-
sp-=args-1;
-
SET_SVAL(sp[-1], PIKE_T_INT, NUMBER_NUMBER, integer, size);
-
#endif /* AUTO_BIGNUM */
+
break;
-
+
}
case BIT_FLOAT: if (args > 2) { /* Attempt to minimize the accumulated summation error * by adding the smallest (absolute) values first. * * Large accumulated errors can occur eg when the number * of values to add is of the same order as the largest * number representable by the mantissa alone. ie when * the sum differs by an order of magnitude from a * typical term. */ /* Heapify */ for(e = args>>1; e--;) { float_heap_sift_down(Pike_sp-args, e, args); } while (args > 2) { /* Pop the smallest element from the heap. */ FLOAT_ARG_TYPE top = Pike_sp[-args].u.float_number;
-
Pike_sp[-args] =
*(
-
-
Pike_sp
)
;
+
Pike_sp[-args] =
Pike_sp[
-
1];
+
Pike_sp
--
;
args--; float_heap_sift_down(Pike_sp-args, 0, args); /* And add it to the second smallest. */ 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--;
pike.git/src/operators.c:1789:
#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);
+
break;
case BIT_ARRAY: ADD (array, add_arrays, push_array);
-
+
break;
case BIT_MAPPING|BIT_INT: ADD_WITH_UNDEFINED (mapping, T_MAPPING, add_mappings, push_mapping);
-
+
break;
case BIT_MAPPING: ADD (mapping, add_mappings, push_mapping);
-
+
break;
case BIT_MULTISET|BIT_INT: ADD_WITH_UNDEFINED (multiset, T_MULTISET, add_multisets, push_multiset);
-
+
break;
case BIT_MULTISET: ADD (multiset, add_multisets, push_multiset);
-
+
break;
#undef ADD_WITH_UNDEFINED #undef ADD } } static int generate_sum(node *n) { struct compilation *c = THIS_COMPILATION; node **first_arg, **second_arg, **third_arg;
pike.git/src/operators.c:1908:
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 0
-
/* Disabled these - boolean falsehood is not the same thing as
-
* equality with the integer 0. */
-
-
if(node_is_false(*first_arg) && !node_may_overload(*second_arg,LFUN_EQ))
-
{
-
ret=*second_arg;
-
ADD_NODE_REF(*second_arg);
-
return mkopernode("`!",ret,0);
-
}
-
-
if(node_is_false(*second_arg) && !node_may_overload(*first_arg,LFUN_EQ))
-
{
-
ret=*first_arg;
-
ADD_NODE_REF(*first_arg);
-
return mkopernode("`!",ret,0);
-
}
-
#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)))) &&
pike.git/src/operators.c:2180:
{ 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; }
-
#ifdef AUTO_BIGNUM
+
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; }
-
#endif
+
return 0; } static int call_lfun(int left, int right) { struct object *o; struct program *p; int i; if(TYPEOF(sp[-2]) == T_OBJECT &&
pike.git/src/operators.c:2336:
push_multiset(l); return; } case T_FLOAT: sp--; sp[-1].u.float_number -= sp[0].u.float_number; return; case T_INT:
-
#ifdef AUTO_BIGNUM
+
if(INT_TYPE_SUB_OVERFLOW(sp[-2].u.integer, sp[-1].u.integer)) { convert_stack_top_to_bignum(); f_minus(2); return; }
-
#endif /* AUTO_BIGNUM */
+
sp--; 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);
pike.git/src/operators.c:3357:
modify_stack_depth(-1); return 1; default: return 0; } } PMOD_EXPORT void o_lsh(void) {
-
#ifdef
AUTO_BIGNUM
-
if ((TYPEOF(sp[-
1
]) == T_
INT
)
&&
(TYPEOF(sp[-
2
]) == T_INT)
&&
-
INT_TYPE_LSH_OVERFLOW(sp[-2].u.integer, sp[-1].u.integer))
+
int args = 2;
+
if ((TYPEOF(sp[-
2
]) == T_
OBJECT
)
||
+
(TYPEOF(sp[-
1
]) == T_
OBJECT))
+
goto call_lfun;
+
+
if ((TYPEOF(sp[-1]) != T_
INT)
|| (sp[-1].u.integer < 0)) {
+
SIMPLE_BAD_ARG_ERROR("`<<",
2,
"int(0..)|object");
+
}
+
+
switch(TYPEOF(sp[-2])) {
+
case T_
INT
:
+
if (!INT
_TYPE_LSH_OVERFLOW(sp[-2].u.integer, sp[-1].u.integer))
+
break;
convert_stack_top_to_bignum();
-
#endif /* AUTO_BIGNUM */
+
-
if(TYPEOF(sp[-1])
!=
T
_
INT
||
TYPEOF(sp[-2])
!=
T_
INT)
-
{
-
int args = 2;
+
/* FALL
_
THROUGH
*/
+
+
case
T_
OBJECT:
+
call_lfun:
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("`<<", 1, "int|
float|
object");
SIMPLE_BAD_ARG_ERROR("`<<", 2, "int(0..)|object");
-
}
-
#ifndef
AUTO_BIGNUM
-
if
(sp[-1].u.integer > 31) {
+
break;
+
+
case
T_FLOAT:
sp--;
-
SET
_
SVAL
(sp[-1]
, T
_
INT
,
NUMBER_NUMBER,
integer
, 0
);
+
sp[-1].u.float
_
number = ldexp
(sp[-1]
.u.float
_
number
,
sp->u.
integer);
return;
-
+
+
default:
+
SIMPLE_BAD_ARG_ERROR("`<<", 1, "int|float|object");
+
break;
}
-
#endif /* !AUTO_BIGNUM */
-
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); }
-
/*! @decl int `<<(int arg1, int arg2)
-
*! @decl mixed `<<(object arg1, int|object arg2)
+
/*! @decl int `<<(int arg1, int
(0..)
arg2)
+
*! @decl mixed `<<(object arg1, int
(0..)
|object arg2)
*! @decl mixed `<<(int arg1, object arg2)
-
+
*! @decl mixed `<<(float arg1, int(0..) arg2)
*! *! Left shift. *! *! Every expression with the @expr{<<@} operator becomes a call to *! this function, i.e. @expr{a<<b@} is the same as *! @expr{predef::`<<(a,b)@}. *! *! If @[arg1] is an object that implements @[lfun::`<<()], that *! function will be called with @[arg2] as the single argument. *! *! If @[arg2] is an object that implements @[lfun::``<<()], that *! function will be called with @[arg1] as the single argument. *!
-
+
*! If @[arg1] is a float and @[arg2] is a non-negative integer,
+
*! @[arg1] will be multiplied by @expr{1<<@[arg2]@}.
+
*!
*! Otherwise @[arg1] will be shifted @[arg2] bits left. *! *! @seealso *! @[`>>()] */ PMOD_EXPORT void f_lsh(INT32 args) { if(args != 2) { /* FIXME: Not appropriate if too many args. */ SIMPLE_TOO_FEW_ARGS_ERROR("`<<", 2);
pike.git/src/operators.c:3434:
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 ((TYPEOF(sp[-2]) == T_OBJECT) || (TYPEOF(sp[-1]) == T_OBJECT))
+
{
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;
+
if (
(TYPEOF(
sp[-1]
) != T_INT) || (sp[-1]
.u.integer < 0)
)
{
SIMPLE_BAD_ARG_ERROR("`>>", 2, "int(0..)|object"); }
-
if(
-
#ifdef AUTO_BIGNUM
-
(INT_TYPE_RSH_OVERFLOW(sp[-2].u.integer, sp[-1].u.integer))
-
#else /* !AUTO_BIGNUM */
-
(sp[-1].u.integer > 31)
-
#endif /* AUTO_BIGNUM */
-
)
-
{
+
sp--;
-
+
switch(TYPEOF(sp[-1])) {
+
case T_INT:
+
if( INT_TYPE_RSH_OVERFLOW(sp[-1].u.integer, sp->u.integer) )
+
{
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; }
-
+
break;
+
case T_FLOAT:
+
sp[-1].u.float_number = ldexp(sp[-1].u.float_number, -sp->u.integer);
+
return;
+
default:
+
SIMPLE_BAD_ARG_ERROR("`>>", 1, "int|float|object");
+
break;
+
}
-
sp--;
+
SET_SVAL(sp[-1], T_INT, NUMBER_NUMBER, integer, sp[-1].u.integer >> sp->u.integer); }
-
/*! @decl int `>>(int arg1, int arg2)
-
*! @decl mixed `>>(object arg1, int|object arg2)
+
/*! @decl int `>>(int arg1, int
(0..)
arg2)
+
*! @decl mixed `>>(object arg1, int
(0..)
|object arg2)
*! @decl mixed `>>(int arg1, object arg2)
-
+
*! @decl float `>>(float arg1, int(0..) arg2)
*! *! Right shift. *! *! Every expression with the @expr{>>@} operator becomes a call to *! this function, i.e. @expr{a>>b@} is the same as *! @expr{predef::`>>(a,b)@}. *! *! If @[arg1] is an object that implements @[lfun::`>>()], that *! function will be called with @[arg2] as the single argument. *! *! If @[arg2] is an object that implements @[lfun::``>>()], that *! function will be called with @[arg1] as the single argument. *!
-
+
*! If @[arg1] is a float and @[arg2] is a non-negative integer,
+
*! @[arg1] will be divided by @expr{1<<@[arg2]@}.
+
*!
*! Otherwise @[arg1] will be shifted @[arg2] bits right. *! *! @seealso *! @[`<<()] */ PMOD_EXPORT void f_rsh(INT32 args) { if(args != 2) { /* FIXME: Not appropriate if too many args. */ SIMPLE_TOO_FEW_ARGS_ERROR("`>>", 2);
pike.git/src/operators.c:3601:
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);
+
memcpy
(pos, src->str, delta);
pos += delta; len -= delta; while (len > delta) {
-
MEMCPY
(pos, ret->str, delta);
+
memcpy
(pos, ret->str, delta);
pos += delta; len -= delta; delta <<= 1; } if (len) {
-
MEMCPY
(pos, ret->str, len);
+
memcpy
(pos, ret->str, len);
} } else if (len) {
-
MEMCPY
(pos, src->str, 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);
+
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);
pike.git/src/operators.c:3679:
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):
-
#ifdef AUTO_BIGNUM
-
if(INT_TYPE_MUL_OVERFLOW(sp[-2].u.integer, sp[-1].u.integer))
+
{
-
+
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; }
-
#endif /* AUTO_BIGNUM */
+
sp--;
-
SET_SVAL(sp[-1], T_INT, NUMBER_NUMBER, integer,
-
sp[-1].u.integer * sp[0].u.integer
);
+
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); } } /*! @decl mixed `*(mixed arg1)
pike.git/src/operators.c:3877:
} 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)
)
;
+
pos = (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);
pike.git/src/operators.c:4027:
case T_INT: { INT_TYPE tmp; if (sp[-1].u.integer == 0) OP_DIVISION_BY_ZERO_ERROR("`/"); if(INT_TYPE_DIV_OVERFLOW(sp[-2].u.integer, sp[-1].u.integer)) {
-
#ifdef AUTO_BIGNUM
+
stack_swap(); convert_stack_top_to_bignum(); stack_swap(); goto do_lfun_division;
-
#else
-
/* It's not possible to do MININT/-1 (it gives FPU exception on
-
some CPU:s), thus we return what MININT*-1 returns: MININT. */
-
tmp = sp[-2].u.integer;
-
#endif /* AUTO_BIGNUM */
+
} else tmp = sp[-2].u.integer/sp[-1].u.integer; sp--; /* What is this trying to solve? /Noring */ /* It fixes rounding towards negative infinity. /mast */ if((sp[-1].u.integer<0) != (sp[0].u.integer<0)) if(tmp*sp[0].u.integer!=sp[-1].u.integer) tmp--;
pike.git/src/operators.c:4164:
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;
pike.git/src/operators.c:4230:
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))
)
;
+
foo = (FLOAT_TYPE)(sp[-1].u.float_number / sp[0].u.float_number);
+
foo = (FLOAT_TYPE)(sp[-1].u.float_number -
+
sp[0].u.float_number * floor(foo));
sp[-1].u.float_number=foo; return; } case T_INT:
-
if
(
sp[-1].u.integer == 0)
+
{
+
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("`%");
-
sp--;
-
if(
sp[-1].u.integer
>=0)
+
if(
a
>=0)
{
-
if(
sp[0].u.integer
>=0)
+
if(
b
>=0)
{
-
sp[-1].u.integer
%
=
sp[0].u.integer
;
+
res
=
a % b
;
}else{
-
sp[-1].u.integer
=((
sp[-1].u.integer+
~
sp[0].u.integer
)%-
sp[0].u.integer
)-~
sp[0].u.integer
;
+
/* res
=
((
a+
~
b
)%-
b
)-~
b */
+
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(
sp[0].u.integer
>=0)
+
if(
b
>=0)
{
-
sp[-1].u.integer
=
sp[0].u.integer+
~((~
sp[-1].u.integer
) %
sp[0].u.integer
);
+
/* res
=
b+
~((~
a
) %
b
)
*/
+
of = DO_INT_TYPE_MOD_OVERFLOW(~a, b, &res)
+
|| DO_INT_TYPE_ADD_OVERFLOW(b, ~res, &res)
;
}else{
-
sp[
-
1].u.integer
=-(-
sp[-1].u.integer
% -
sp[0].u.integer
);
+
/* a % b and a %
-
b are equivalent, if overflow does not
+
* happen
+
* res
=
-(-
a
% -
b
)
= a % b
;
*/
+
of = DO_INT_TYPE_MOD_OVERFLOW(a, b, &res);
} }
-
SET_SVAL
_SUBTYPE
(sp[-1], NUMBER_NUMBER);
+
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); } } /*! @decl mixed `%(object arg1, mixed arg2) *! @decl mixed `%(mixed arg1, object arg2) *! @decl string `%(string arg1, int arg2) *! @decl array `%(array arg1, int arg2) *! @decl float `%(float arg1, float|int arg2)
pike.git/src/operators.c:4303:
*! @type int|float *! The result will be *! @expr{@[arg1] - @[arg2]*@[floor](@[arg1]/@[arg2])@}. *! The result will be a float if either @[arg1] or @[arg2] is *! a float, and an int otherwise. *! @endmixed *! *! For numbers, this means that *! @ol *! @item
-
*!
a
%
b
always has the same sign as
b
(typically
b
is positive;
-
*! array size, rsa modulo, etc, and
a
varies a lot more than
b
).
+
*!
@expr{a
%
b@}
always has the same sign as
@expr{b@}
+
*!
(typically
@expr{b@}
is positive;
+
*! array size, rsa modulo, etc, and
@expr{a@}
varies a
+
*!
lot more than
@expr{b@}
).
*! @item
-
*! The function
f
(x) = x %
n
behaves in a sane way;
as x increases,
-
*!
f
(x) cycles through the values
0
,1, ..., n-1, 0, .... Nothing
+
*! The function
@expr{f
(x) = x %
n@}
behaves in a sane way;
+
*!
as @expr{x@} increases, @expr{f
(x)
@}
cycles through the
+
*!
values
@expr{0
,1, ..., n-1, 0, ...
@}
. Nothing
*! strange happens when you cross zero. *! @item
-
*! The % operator implements the binary "mod" operation,
as defined
-
*! by Donald Knuth (see the Art of Computer Programming,
1.2.4). It
-
*! should be noted that Pike treats %-by-0 as an error
rather than
-
*! returning 0, though.
+
*! The
@expr{
%
@}
operator implements the binary "mod" operation,
+
*!
as defined
by Donald Knuth (see the Art of Computer Programming,
+
*!
1.2.4). It should be noted that Pike treats %-by-0 as an error
+
*!
rather than
returning 0, though.
*! @item
-
*! / and % are compatible, so that
a
= b*(a/b) + a%
b
for all
a
and
b
.
+
*!
@expr{
/
@}
and
@expr{
%
@}
are compatible, so that
+
*!
@expr{a
=
=
b*
@[floor]
(a/b) + a%
b@}
for all
@expr{a@}
and
@expr{b@}
.
*! @endol *! @seealso
-
*! @[`/]
+
*! @[`/]
, @[floor()]
*/ PMOD_EXPORT void f_mod(INT32 args) { if(args != 2) { /* FIXME: Not appropriate when too many args. */ SIMPLE_TOO_FEW_ARGS_ERROR("`%", 2); } o_mod(); }
pike.git/src/operators.c:4554:
case T_OBJECT: do_lfun_negate: CALL_OPERATOR(LFUN_SUBTRACT,1); break; case T_FLOAT: sp[-1].u.float_number=-sp[-1].u.float_number; return; case T_INT:
-
#ifdef AUTO_BIGNUM
+
if(INT_TYPE_NEG_OVERFLOW(sp[-1].u.integer)) { convert_stack_top_to_bignum(); goto do_lfun_negate; }
-
#endif /* AUTO_BIGNUM */
+
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,
pike.git/src/operators.c:4795:
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");
+
break;
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");
-
+
break;
case 3: bad_arg_error (range_func_name (bound_types), ind, 3, 1, "object", ind, "Cannot call `[..] in destructed object.\n");
-
+
break;
default: free_svalue (ind); move_svalue (ind, sp - 1); /* low and high have lost their refs in call_old_range_lfun. */ sp = ind + 1;
-
+
break;
} break; } case T_STRING: case T_ARRAY: { INT_TYPE l=0, h=0; if (!(bound_types & RANGE_LOW_OPEN)) { if (TYPEOF(*low) != T_INT)
pike.git/src/operators.c:4925:
*! @type object *! If the object implements @[lfun::`[..]], that function is *! called with the four remaining arguments. *! *! As a compatibility measure, if the object does not implement *! @[lfun::`[..]] but @[lfun::`[]] then the latter is called *! with the bounds transformed to normal from-the-beginning *! indices in array-like fashion: *! *! @dl
-
*! @item
@{`
[..] (a, i, Pike.INDEX_FROM_BEG, j, Pike.INDEX_FROM_BEG)@}
+
*! @item
@expr{`
[..] (a, i, Pike.INDEX_FROM_BEG, j, Pike.INDEX_FROM_BEG)@}
*! Calls @expr{a->`[] (i, j)@}
-
*! @item
@{`
[..] (a, i, Pike.INDEX_FROM_BEG, j, Pike.INDEX_FROM_END)@}
+
*! @item
@expr{`
[..] (a, i, Pike.INDEX_FROM_BEG, j, Pike.INDEX_FROM_END)@}
*! Calls @expr{a->`[] (i, a->_sizeof()-1-j)@}
-
*! @item
@{`
[..] (a, i, Pike.INDEX_FROM_BEG, 0, Pike.OPEN_BOUND)@}
+
*! @item
@expr{`
[..] (a, i, Pike.INDEX_FROM_BEG, 0, Pike.OPEN_BOUND)@}
*! Calls @expr{a->`[] (i, @[Int.NATIVE_MAX])@}
-
*! @item
@{`
[..] (a, i, Pike.INDEX_FROM_END, j, Pike.INDEX_FROM_BEG)@}
+
*! @item
@expr{`
[..] (a, i, Pike.INDEX_FROM_END, j, Pike.INDEX_FROM_BEG)@}
*! Calls @expr{a->`[] (a->_sizeof()-1-i, j)@}
-
*! @item
@{`
[..] (a, i, Pike.INDEX_FROM_END, j, Pike.INDEX_FROM_END)@}
+
*! @item
@expr{`
[..] (a, i, Pike.INDEX_FROM_END, j, Pike.INDEX_FROM_END)@}
*! Calls @expr{a->`[] (a->_sizeof()-1-i, a->_sizeof()-1-j)@}, *! except that @expr{a->_sizeof()@} is called only once.
-
*! @item
@{`
[..] (a, i, Pike.INDEX_FROM_END, 0, Pike.OPEN_BOUND)@}
+
*! @item
@expr{`
[..] (a, i, Pike.INDEX_FROM_END, 0, Pike.OPEN_BOUND)@}
*! Calls @expr{a->`[] (a->_sizeof()-1-i, @[Int.NATIVE_MAX])@}
-
*! @item
@{`
[..] (a, 0, Pike.OPEN_BOUND, j, Pike.INDEX_FROM_BEG)@}
+
*! @item
@expr{`
[..] (a, 0, Pike.OPEN_BOUND, j, Pike.INDEX_FROM_BEG)@}
*! Calls @expr{a->`[] (0, j)@}
-
*! @item
@{`
[..] (a, 0, Pike.OPEN_BOUND, j, Pike.INDEX_FROM_END)@}
+
*! @item
@expr{`
[..] (a, 0, Pike.OPEN_BOUND, j, Pike.INDEX_FROM_END)@}
*! Calls @expr{a->`[] (0, a->_sizeof()-1-j)@}
-
*! @item
@{`
[..] (a, 0, Pike.OPEN_BOUND, 0, Pike.OPEN_BOUND)@}
+
*! @item
@expr{`
[..] (a, 0, Pike.OPEN_BOUND, 0, Pike.OPEN_BOUND)@}
*! Calls @expr{a->`[] (0, @[Int.NATIVE_MAX])@} *! @enddl *! *! Note that @[Int.NATIVE_MAX] might be replaced with an even *! larger integer in the future. *! @endmixed *! *! @seealso *! @[lfun::`[..]], @[`[]] */
pike.git/src/operators.c:5003:
stack_pop_keep_top(); } else { int bound_types; CALC_BOUND_TYPES (bound_types); switch (call_old_range_lfun (bound_types, o, ind + 1, ind + 3)) { case 1: SIMPLE_ARG_ERROR ("predef::`[..]", 1, "Object got neither `[..] nor `[].\n");
+
break;
case 2: SIMPLE_ARG_ERROR ("predef::`[..]", 1, "Object got no `[..] and there is no _sizeof to " "translate the from-the-end index to use `[].\n");
-
+
break;
case 3: SIMPLE_ARG_ERROR ("predef::`[..]", 1, "Cannot call `[..] in destructed object.\n");
-
+
break;
default: free_svalue (ind); move_svalue (ind, sp - 1); /* The bound types are simple integers and the bounds * themselves have lost their refs in call_old_range_lfun. */ sp = ind + 1;
-
+
break;
} } break; } case T_STRING: case T_ARRAY: { INT_TYPE l=0, h=0; int bound_types;
pike.git/src/operators.c:5463:
} 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");
+
if( pike_types_le( my_get_arg(&CDR(n), 0)[0]->type, string_type_string ) )
+
emit0(F_SIZEOF_STRING);
+
/* else if( pike_types_le( my_get_arg(&CDR(n), 0)[0]->type, array_type_string ) ) */
+
/* emit0(F_SIZEOF_ARRAY); */
+
else
emit0(F_SIZEOF); return 1; } extern int generate_call_function(node *n);
-
+
/*! @decl void _Static_assert(int constant_expression, string constant_message)
+
*!
+
*! Perform a compile-time assertion check.
+
*!
+
*! If @[constant_expression] is false, a compiler error message
+
*! containing @[constant_message] will be generated.
+
*!
+
*! @note
+
*! Note that the function call compiles to the null statement,
+
*! and thus does not affect the run-time.
+
*!
+
*! @seealso
+
*! @[cpp::static_assert]
+
*/
+
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;
+
}
+
/*! @class string_assignment */ struct program *string_assignment_program; #undef THIS #define THIS ((struct string_assignment_storage *)(CURRENT_STORAGE)) /*! @decl int `[](int i) *! *! String index operator.
pike.git/src/operators.c:5549:
sp[-1].u.string=modify_shared_string(sp[-1].u.string,i,j); assign_lvalue(THIS->lval, sp-1); pop_stack(); } pop_n_elems(args); push_int(j); }
-
static void init_string_assignment_storage(struct object *o)
+
static void init_string_assignment_storage(struct object *
UNUSED(
o)
)
{ SET_SVAL(THIS->lval[0], T_INT, PIKE_T_FREE, integer, 0); SET_SVAL(THIS->lval[1], T_INT, PIKE_T_FREE, integer, 0); THIS->s = NULL; }
-
static void exit_string_assignment_storage(struct object *o)
+
static void exit_string_assignment_storage(struct object *
UNUSED(
o)
)
{ free_svalues(THIS->lval, 2, BIT_MIXED); if(THIS->s) free_string(THIS->s); } /*! @endclass */ void init_operators(void)
pike.git/src/operators.c:5581:
tFunc(tObj tMix tRangeBound tMix tRangeBound, tMix)), OPT_TRY_OPTIMIZE); ADD_INT_CONSTANT ("INDEX_FROM_BEG", INDEX_FROM_BEG, 0); ADD_INT_CONSTANT ("INDEX_FROM_END", INDEX_FROM_END, 0); ADD_INT_CONSTANT ("OPEN_BOUND", OPEN_BOUND, 0); ADD_EFUN ("`[]", f_index, tOr9(tFunc(tObj tMix tOr(tVoid,tMix), tMix), tFunc(tInt tString, tFunction),
-
tFunc(
tStr
tInt,
tInt
),
+
tFunc(
tNStr(tSetvar(0,tInt))
tInt,
tVar(0
)
)
,
tFunc(tArr(tSetvar(0,tMix)) tMix, tVar(0)), tFunc(tMap(tMix,tSetvar(1,tMix)) tMix, tVar(1)), tFunc(tMultiset tMix, tInt01), tFunc(tPrg(tObj) tString, tMix), tFunc(tStr tInt tInt, tStr), tFunc(tArr(tSetvar(2,tMix)) tInt tInt, tArr(tVar(2)))), OPT_TRY_OPTIMIZE); /* function(array(object|mapping|multiset|array),string:array(mixed))|function(object|mapping|multiset|program,string:mixed) */ ADD_EFUN2("`->",f_arrow,tOr(tFunc(tArr(tOr4(tObj,tMapping,tMultiset,tArray)) tStr,tArr(tMix)),tFunc(tOr4(tObj,tMapping,tMultiset,tPrg(tObj)) tStr,tMix)),OPT_TRY_OPTIMIZE,0,0);
pike.git/src/operators.c:5608:
OPT_SIDE_EFFECT|OPT_TRY_OPTIMIZE); ADD_EFUN("`->=", f_arrow_assign, tOr3(tFunc(tArr(tOr4(tArray,tObj,tMultiset,tMapping)) tStr tSetvar(0,tMix), tVar(0)), tFunc(tOr(tObj, tMultiset) tStr tSetvar(1,tMix), tVar(1)), tFunc(tMap(tMix, tSetvar(2,tMix)) tStr tVar(2), tVar(2))), OPT_SIDE_EFFECT|OPT_TRY_OPTIMIZE); /* function(mixed...:int) */ ADD_EFUN2("`==",f_eq,
-
tOr5
(tFuncV(tOr(tInt,tFloat) tOr(tInt,tFloat),
+
tOr6
(tFuncV(tOr(tInt,tFloat) tOr(tInt,tFloat),
tOr(tInt,tFloat),tInt01), tFuncV(tSetvar(0,tOr4(tString,tMapping,tMultiset,tArray)) tVar(0), tVar(0),tInt01), tFuncV(tOr3(tObj,tPrg(tObj),tFunction) tMix,tMix,tInt01), tFuncV(tMix tOr3(tObj,tPrg(tObj),tFunction),tMix,tInt01), tFuncV(tType(tMix) tType(tMix),
-
tOr3(tPrg(tObj),tFunction,tType(tMix)),tInt01)),
+
tOr3(tPrg(tObj),tFunction,tType(tMix)),tInt01)
,
+
tFuncV(tSetvar(0,tOr4(tString,tMapping,tMultiset,tArray
)
)
,
+
tNot(tVar(0)),tInt0)),
OPT_WEAK_TYPE|OPT_TRY_OPTIMIZE,optimize_eq,generate_comparison); /* function(mixed...:int) */ ADD_EFUN2("`!=",f_ne,
-
tOr5
(tFuncV(tOr(tInt,tFloat) tOr(tInt,tFloat),
+
tOr6
(tFuncV(tOr(tInt,tFloat) tOr(tInt,tFloat),
tOr(tInt,tFloat),tInt01), tFuncV(tSetvar(0,tOr4(tString,tMapping,tMultiset,tArray)) tVar(0), tVar(0),tInt01), tFuncV(tOr3(tObj,tPrg(tObj),tFunction) tMix,tMix,tInt01), tFuncV(tMix tOr3(tObj,tPrg(tObj),tFunction),tMix,tInt01), tFuncV(tType(tMix) tType(tMix),
-
tOr3(tPrg(tObj),tFunction,tType(tMix)),tInt01)),
+
tOr3(tPrg(tObj),tFunction,tType(tMix)),tInt01)
,
+
tFuncV(tSetvar(0,tOr4(tString,tMapping,tMultiset,tArray
)
)
,
+
tNot(tVar(0)),tInt1)),
OPT_WEAK_TYPE|OPT_TRY_OPTIMIZE,0,generate_comparison); /* function(mixed:int) */ ADD_EFUN2("`!",f_not,tFuncV(tMix,tVoid,tInt01), OPT_TRY_OPTIMIZE,optimize_not,generate_not); #define CMP_TYPE "!function(!(object|mixed)...:mixed)&function(mixed...:int(0..1))|function(int|float...:int(0..1))|function(string...:int(0..1))|function(type|program,type|program,type|program...:int(0..1))" add_efun2("`<", f_lt,CMP_TYPE,OPT_TRY_OPTIMIZE,0,generate_comparison); add_efun2("`<=",f_le,CMP_TYPE,OPT_TRY_OPTIMIZE,0,generate_comparison); add_efun2("`>", f_gt,CMP_TYPE,OPT_TRY_OPTIMIZE,0,generate_comparison); add_efun2("`>=",f_ge,CMP_TYPE,OPT_TRY_OPTIMIZE,0,generate_comparison); ADD_EFUN2("`+",f_add, tOr7(tIfnot(tFuncV(tNone,tNot(tOr(tObj,tMix)),tMix), tFuncV(tNone,tMix,tMix)), tFuncV(tInt,tInt,tInt), tIfnot(tFuncV(tNone, tNot(tFlt), tMix), tFuncV(tOr(tInt,tFlt),tOr(tInt,tFlt),tFlt)), tIfnot(tFuncV(tNone, tNot(tStr), tMix),
-
tFuncV(tOr3(tStr,tInt,tFlt),
-
tOr3(tStr,tInt,tFlt),
tStr
)),
+
tFuncV(tOr3(
tSetvar(0,
tStr
)
,tInt,tFlt),
+
tOr3(
tSetvar(1,
tStr
)
,tInt,tFlt),
tOr(tVar(0
)
,tVar(1
)
)))
,
tFuncV(tSetvar(0,tArray),tSetvar(1,tArray), tOr(tVar(0),tVar(1))), tFuncV(tSetvar(0,tMapping),tSetvar(1,tMapping), tOr(tVar(0),tVar(1))), tFuncV(tSetvar(0,tMultiset),tSetvar(1,tMultiset), tOr(tVar(0),tVar(1)))), OPT_TRY_OPTIMIZE,optimize_binary,generate_sum); ADD_EFUN2("`-",f_minus, tOr7(tIfnot(tFuncV(tNone,tNot(tOr(tObj,tMix)),tMix), tFuncV(tNone,tMix,tMix)), tFuncV(tInt,tInt,tInt), tIfnot(tFuncV(tNone,tNot(tFlt),tMix), tFuncV(tOr(tInt,tFlt),tOr(tInt,tFlt),tFlt)), tFuncV(tArr(tSetvar(0,tMix)),tArray,tArr(tVar(0))), tFuncV(tMap(tSetvar(1,tMix),tSetvar(2,tMix)), tOr3(tMapping,tArray,tMultiset), tMap(tVar(1),tVar(2))), tFunc(tSet(tSetvar(3,tMix)) tMultiset,tSet(tVar(3))),
-
tFuncV(
tStr
,tStr,tStr)),
+
tFuncV(
tSetvar(0,
tStr
)
,tStr,
tVar(0
))
)
,
OPT_TRY_OPTIMIZE,0,generate_minus); /* object & mixed -> mixed mixed & object -> mixed int & int -> int array & array -> array multiset & multiset -> multiset
pike.git/src/operators.c:5733:
tFuncV(tSetvar(3,tMultiset),tSetvar(4,tMultiset),tOr(tVar(3),tVar(4))), \ tFuncV(tSetvar(5,tArray),tSetvar(6,tArray),tOr(tVar(5),tVar(6))), \ tFuncV(tString,tString,tString), \ tFuncV(tOr(tType(tMix),tPrg(tObj)),tOr(tType(tMix),tPrg(tObj)),tType(tMix))) ADD_EFUN2("`|",f_or,LOG_TYPE,OPT_TRY_OPTIMIZE,optimize_binary,generate_or); ADD_EFUN2("`^",f_xor,LOG_TYPE,OPT_TRY_OPTIMIZE,optimize_binary,generate_xor); #define SHIFT_TYPE \
-
tOr
(
tAnd
(
tNot(
tFuncV(tNone, tNot(tObj), tMix)
)
, \
-
tOr(tFunc(tMix tObj,tMix),
\
+
tOr3
(
tIfnot
(tFuncV(tNone, tNot(tObj), tMix),
\
+
tOr(tFunc(tMix tObj,tMix), \
tFunc(tObj tMix,tMix))), \
-
tFunc(
tInt
tInt
,
tInt
))
+
tOr3(
tFunc(
tInt1Plus
tIntPos
,
tIntPos
)
, \
+
tFunc(tInt0 tIntPos, tInt0
)
, \
+
tFunc(tIntMinus tIntPos, tIntNeg)), \
+
tIfnot(tFuncV(tNot(tFloat), tNot(tIntPos), tMix), \
+
tFunc(tAnd(tFloat, tNot(tInt0)) tIntPos, tFloat)))
ADD_EFUN2("`<<", f_lsh, SHIFT_TYPE, OPT_TRY_OPTIMIZE, may_have_side_effects, generate_lsh); ADD_EFUN2("`>>", f_rsh, SHIFT_TYPE, OPT_TRY_OPTIMIZE, may_have_side_effects, generate_rsh); /* !function(!object...:mixed)&function(mixed...:mixed)|" "function(array(array(1=mixed)),array(1=mixed):array(1))|" "function(int...:int)|" "!function(int...:mixed)&function(float|int...:float)|"
pike.git/src/operators.c:5792:
tFuncV(tStr,tOr3(tStr,tInt,tFlt),tArr(tStr))), OPT_TRY_OPTIMIZE,0,generate_divide); /* function(mixed,object:mixed)|" "function(object,mixed:mixed)|" "function(int,int:int)|" "function(string,int:string)|" "function(array(0=mixed),int:array(0))|" "!function(int,int:mixed)&function(int|float,int|float:float) */ ADD_EFUN2("`%", f_mod,
-
tOr6
(tFunc(tMix tObj,tMix),
+
tOr7
(tFunc(tMix tObj,tMix),
tFunc(tObj tMix,tMix),
-
tFunc(tInt
tInt
,tInt),
+
tFunc(tInt
tIntPos, tIntPos),
+
tFunc(
tInt
tIntNeg
,
tIntNeg
),
tFunc(tStr tInt,tStr), tFunc(tArr(tSetvar(0,tMix)) tInt,tArr(tVar(0))), tIfnot(tFuncV(tNone, tNot(tFlt), tMix), tFunc(tOr(tInt,tFlt) tOr(tInt,tFlt),tFlt))), OPT_TRY_OPTIMIZE,0,generate_mod); /* function(object:mixed)|function(int:int)|function(float:float)|function(string:string) */ ADD_EFUN2("`~",f_compl,
-
tOr6
(tFunc(tObj,tMix),
-
tFunc(
tInt
,
tInt
),
+
tOr7
(tFunc(tObj,tMix),
+
tFunc(
tIntPos
,
tIntMinus
),
+
tFunc(tIntMinus,tIntPos),
tFunc(tFlt,tFlt), tFunc(tStr,tStr), tFunc(tType(tSetvar(0, tMix)), tType(tNot(tVar(0)))), tFunc(tPrg(tObj), tType(tMix))), OPT_TRY_OPTIMIZE,0,generate_compl);
-
/* function(string|multiset|array|mapping|object:int) */
+
/* function(string|multiset|array|mapping|object:int
(0..
)
)
*/
ADD_EFUN2("sizeof", f_sizeof,
-
tFunc(tOr5(tStr,tMultiset,tArray,tMapping,tObj),
tInt
),
+
tFunc(tOr5(tStr,tMultiset,tArray,tMapping,tObj),
tIntPos
),
OPT_TRY_OPTIMIZE, optimize_sizeof, generate_sizeof);
-
+
ADD_EFUN2("strlen", f_sizeof,
+
tFunc(tStr,tIntPos), OPT_TRY_OPTIMIZE, optimize_sizeof,
+
generate_sizeof);
+
/* function(mixed,mixed ...:mixed) */ ADD_EFUN2("`()",f_call_function,tFuncV(tMix,tMix,tMix),OPT_SIDE_EFFECT | OPT_EXTERNAL_DEPEND,0,generate_call_function); /* This one should be removed */ /* function(mixed,mixed ...:mixed) */ ADD_EFUN2("call_function",f_call_function,tFuncV(tMix,tMix,tMix),OPT_SIDE_EFFECT | OPT_EXTERNAL_DEPEND,0,generate_call_function);
-
+
/* From the 201x C standard */
+
ADD_EFUN2("_Static_assert", NULL,
+
tFunc(tInt tStr, tVoid), OPT_TRY_OPTIMIZE,
+
NULL, generate__Static_assert);
start_new_program(); ADD_STORAGE(struct string_assignment_storage); /* function(int:int) */ ADD_FUNCTION2("`[]", f_string_assignment_index, tFunc(tInt,tInt), 0, OPT_EXTERNAL_DEPEND); /* function(int,int:int) */ ADD_FUNCTION2("`[]=", f_string_assignment_assign_index, tFunc(tInt tInt,tInt), 0, OPT_SIDE_EFFECT); set_init_callback(init_string_assignment_storage);