pike.git / src / operators.c

version» Context lines:

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);