pike.git / src / operators.c

version» Context lines:

pike.git/src/operators.c:1:   /*\   ||| This file a part of Pike, and is copyright by Fredrik Hubinette   ||| Pike is distributed as GPL (General Public License)   ||| See the files COPYING and DISCLAIMER for more information.   \*/ + /**/   #include "global.h"   #include <math.h> - RCSID("$Id: operators.c,v 1.51 1999/03/12 22:22:55 per Exp $"); + RCSID("$Id: operators.c,v 1.52 1999/03/26 23:40:57 grubba Exp $");   #include "interpret.h"   #include "svalue.h"   #include "multiset.h"   #include "mapping.h"   #include "array.h"   #include "stralloc.h"   #include "opcodes.h"   #include "operators.h"   #include "language.h"   #include "pike_memory.h"
pike.git/src/operators.c:20:   #include "docode.h"   #include "constants.h"   #include "peep.h"   #include "lex.h"   #include "program.h"   #include "object.h"   #include "pike_types.h"   #include "module_support.h"   #include "pike_macros.h"    + #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") +    #define COMPARISON(ID,NAME,FUN) \   void ID(INT32 args) \   { \    int i; \    switch(args) \    { \    case 0: case 1: \ -  PIKE_ERROR(NAME, "Too few arguments\n", sp, args); \ +  SIMPLE_TOO_FEW_ARGS_ERROR(NAME, 2); \    case 2: \    i=FUN (sp-2,sp-1); \    pop_n_elems(2); \    push_int(i); \    break; \    default: \    for(i=1;i<args;i++) \    if(! ( FUN (sp-args+i-1, sp-args+i))) \    break; \    pop_n_elems(args); \
pike.git/src/operators.c:57:      COMPARISON(f_eq,"`==", is_eq)   COMPARISON(f_lt,"`<" , is_lt)   COMPARISON(f_le,"`<=",!is_gt)   COMPARISON(f_gt,"`>" , is_gt)   COMPARISON(f_ge,"`>=",!is_lt)         #define CALL_OPERATOR(OP, args) \    if(!sp[-args].u.object->prog) \ -  PIKE_ERROR(lfun_names[OP], "Called in destructed object.\n", sp, args); \ +  bad_arg_error(lfun_names[OP], sp-args, args, 1, "object", sp-args, \ +  "Called in destructed object.\n"); \    if(FIND_LFUN(sp[-args].u.object->prog,OP) == -1) \ -  PIKE_ERROR(lfun_names[OP], "Operator not in object.\n", sp, args); \ +  bad_arg_error(lfun_names[OP], sp-args, args, 1, "object", sp-args, \ +  "Operator not in object.\n"); \    apply_lfun(sp[-args].u.object, OP, args-1); \    free_svalue(sp-2); \    sp[-2]=sp[-1]; \    sp--;      void f_add(INT32 args)   {    INT_TYPE e,size;    TYPE_FIELD types;       types=0;    for(e=-args;e<0;e++) types|=1<<sp[e].type;       switch(types)    {    default:    if(!args)    { -  PIKE_ERROR("`+", "Too few arguments\n", sp, args); +  SIMPLE_TOO_FEW_ARGS_ERROR("`+", 1);    }else{    if(types & BIT_OBJECT)    {    if(sp[-args].type == T_OBJECT && sp[-args].u.object->prog)    {    if(sp[-args].u.object->refs==1 &&    FIND_LFUN(sp[-args].u.object->prog,LFUN_ADD_EQ) != -1)    {    apply_lfun(sp[-args].u.object, LFUN_ADD_EQ, args-1);    pop_stack();
pike.git/src/operators.c:132:    return;    }    }    }    }       switch(sp[-args].type)    {    case T_PROGRAM:    case T_FUNCTION: -  PIKE_ERROR("`+", "Bad argument 1\n", sp, args); +  SIMPLE_BAD_ARG_ERROR("`+", 1, +  "string|object|int|float|array|mapping|multiset");    } -  PIKE_ERROR("`+", "Incompatible types\n", sp, args); +  bad_arg_error("`+", sp-args, args, 1, +  "string|object|int|float|array|mapping|multiset", sp-args, +  "Incompatible types\n");    return; /* compiler hint */       case BIT_STRING:    {    struct pike_string *r;    PCHARP buf;    INT32 tmp;    int max_shift=0;       if(args==1) return;
pike.git/src/operators.c:291:       case BIT_ARRAY|BIT_INT:    {    if(IS_UNDEFINED(sp-args))    {    int e;    struct array *a;       for(e=1;e<args;e++)    if(sp[e-args].type != T_ARRAY) -  error("`+: trying to add integers and arrays.\n"); +  SIMPLE_BAD_ARG_ERROR("`+", e+1, "array");       a=add_arrays(sp-args+1,args-1);    pop_n_elems(args);    push_array(a);    return;    } -  error("`+: trying to add integers and arrays.\n"); +  if (sp[-args].type == T_INT) { +  int e; +  for(e=1;e<args;e++) +  if (sp[e-args].type != T_INT) +  SIMPLE_BAD_ARG_ERROR("`+", e+1, "int"); +  } else { +  int e; +  for(e=0;e<args;e++) +  if (sp[e-args].type != T_ARRAY) +  SIMPLE_BAD_ARG_ERROR("`+", e+1, "array");    } -  +  /* Probably not reached, but... */ +  bad_arg_error("`+", sp-args, args, 1, "array", sp-args, +  "trying to add integers and arrays.\n"); +  }       case BIT_ARRAY:    {    struct array *a;    a=add_arrays(sp-args,args);    pop_n_elems(args);    push_array(a);    break;    }       case BIT_MAPPING|BIT_INT:    {    if(IS_UNDEFINED(sp-args))    {    int e;    struct mapping *a;       for(e=1;e<args;e++)    if(sp[e-args].type != T_MAPPING) -  error("`+: trying to add integers and mappings.\n"); +  SIMPLE_BAD_ARG_ERROR("`+", e+1, "mapping");       a=add_mappings(sp-args+1,args-1);    pop_n_elems(args);    push_mapping(a);    return;    } -  error("`+: trying to add integers and mappings.\n"); +  if (sp[-args].type == T_INT) { +  int e; +  for(e=1;e<args;e++) +  if (sp[e-args].type != T_INT) +  SIMPLE_BAD_ARG_ERROR("`+", e+1, "int"); +  } else { +  int e; +  for(e=0;e<args;e++) +  if (sp[e-args].type != T_MAPPING) +  SIMPLE_BAD_ARG_ERROR("`+", e+1, "mapping");    } -  +  /* Probably not reached, but... */ +  bad_arg_error("`+", sp-args, args, 1, "mapping", sp-args, +  "Trying to add integers and mappings.\n"); +  }       case BIT_MAPPING:    {    struct mapping *m;       m = add_mappings(sp - args, args);    pop_n_elems(args);    push_mapping(m);    break;    }
pike.git/src/operators.c:565:       return 0;   }      void o_subtract(void)   {    if (sp[-2].type != sp[-1].type && !float_promote())    {    if(call_lfun(LFUN_SUBTRACT, LFUN_RSUBTRACT))    return; -  PIKE_ERROR("`-", "Subtract on different types.\n", sp, 2); +  bad_arg_error("`-", sp-2, 2, 2, type_name[sp[-2].type], +  sp-1, "Subtract on different types.\n");    }       switch(sp[-2].type)    {    case T_OBJECT:    CALL_OPERATOR(LFUN_SUBTRACT,2);    break;       case T_ARRAY:    {
pike.git/src/operators.c:628:    ret=string_replace(sp[-2].u.string,sp[-1].u.string,s);    free_string(sp[-2].u.string);    free_string(sp[-1].u.string);    free_string(s);    sp[-2].u.string=ret;    sp--;    return;    }       default: -  PIKE_ERROR("`-", "Bad argument 1.\n", sp, 2); +  { +  int args = 2; +  SIMPLE_BAD_ARG_ERROR("`-", 1, +  "int|float|string|mapping|multiset|array|object");    }    } -  + }      void f_minus(INT32 args)   {    switch(args)    { -  case 0: PIKE_ERROR("`-", "Too few arguments.\n", sp, 0); +  case 0: SIMPLE_TOO_FEW_ARGS_ERROR("`-", 1);    case 1: o_negate(); break;    case 2: o_subtract(); break;    default:    {    INT32 e;    struct svalue *s=sp-args;    push_svalue(s);    for(e=1;e<args;e++)    {    push_svalue(s+e);
pike.git/src/operators.c:678:    }    return 0;   }      void o_and(void)   {    if(sp[-1].type != sp[-2].type)    {    if(call_lfun(LFUN_AND, LFUN_RAND))    return; -  -  PIKE_ERROR("`&", "Bitwise and on different types.\n", sp, 2); +  { +  int args = 2; +  SIMPLE_BAD_ARG_ERROR("`&", 2, type_name[sp[-2].type]);    } -  +  }       switch(sp[-2].type)    {    case T_OBJECT:    CALL_OPERATOR(LFUN_AND,2);    break;       case T_INT:    sp--;    sp[-1].u.integer &= sp[0].u.integer;
pike.git/src/operators.c:822:       default:    while(--args > 0) func();    }   }      void f_and(INT32 args)   {    switch(args)    { -  case 0: PIKE_ERROR("`&", "Too few arguments.\n", sp, 0); +  case 0: SIMPLE_TOO_FEW_ARGS_ERROR("`&", 1);    case 1: return;    case 2: o_and(); return;    default:    if(sp[-args].type == T_OBJECT)    {    CALL_OPERATOR(LFUN_AND, args);    }else{    speedup(args, o_and);    }    }
pike.git/src/operators.c:860:    }   }      void o_or(void)   {    if(sp[-1].type != sp[-2].type)    {    if(call_lfun(LFUN_OR, LFUN_ROR))    return;    -  PIKE_ERROR("`|", "Bitwise or on different types.\n", sp, 2); +  { +  int args = 2; +  SIMPLE_BAD_ARG_ERROR("`|", 2, type_name[sp[-2].type]);    } -  +  }       switch(sp[-2].type)    {    case T_OBJECT:    CALL_OPERATOR(LFUN_OR,2);    break;       case T_INT:    sp--;    sp[-1].u.integer |= sp[0].u.integer;
pike.git/src/operators.c:912:       default:    PIKE_ERROR("`|", "Bitwise or on illegal type.\n", sp, 2);    }   }      void f_or(INT32 args)   {    switch(args)    { -  case 0: PIKE_ERROR("`|", "Too few arguments.\n", sp, 0); +  case 0: SIMPLE_TOO_FEW_ARGS_ERROR("`|", 1);    case 1: return;    case 2: o_or(); return;    default:    if(sp[-args].type==T_OBJECT)    {    CALL_OPERATOR(LFUN_OR, args);    } else {    speedup(args, o_or);    }    }
pike.git/src/operators.c:950:    }   }         void o_xor(void)   {    if(sp[-1].type != sp[-2].type)    {    if(call_lfun(LFUN_XOR, LFUN_RXOR))    return; -  PIKE_ERROR("`^", "Bitwise XOR on different types.\n", sp, 2); +  { +  int args = 2; +  SIMPLE_BAD_ARG_ERROR("`^", 2, type_name[sp[-2].type]);    } -  +  }       switch(sp[-2].type)    {    case T_OBJECT:    CALL_OPERATOR(LFUN_XOR,2);    break;       case T_INT:    sp--;    sp[-1].u.integer ^= sp[0].u.integer;
pike.git/src/operators.c:1002:       default:    PIKE_ERROR("`^", "Bitwise XOR on illegal type.\n", sp, 2);    }   }      void f_xor(INT32 args)   {    switch(args)    { -  case 0: PIKE_ERROR("`^", "Too few arguments.\n", sp, 0); +  case 0: SIMPLE_TOO_FEW_ARGS_ERROR("`^", 1);    case 1: return;    case 2: o_xor(); return;    default:    if(sp[-args].type==T_OBJECT)    {    CALL_OPERATOR(LFUN_XOR, args);    } else {    speedup(args, o_xor);    }    }
pike.git/src/operators.c:1037:       default:    return 0;    }   }      void o_lsh(void)   {    if(sp[-1].type != T_INT || sp[-2].type != T_INT)    { +  int args = 2;    if(call_lfun(LFUN_LSH, LFUN_RLSH))    return;       if(sp[-2].type != T_INT) -  PIKE_ERROR("`<<", "Bad argument 1.\n", sp, 2); -  PIKE_ERROR("`<<", "Bad argument 2.\n", sp, 2); +  SIMPLE_BAD_ARG_ERROR("`<<", 1, "int|object"); +  SIMPLE_BAD_ARG_ERROR("`<<", 2, "int|object");    }    sp--;    sp[-1].u.integer = sp[-1].u.integer << sp->u.integer;   }      void f_lsh(INT32 args)   { -  if(args != 2) -  PIKE_ERROR("`<<", "Bad number of args.\n", sp, args); +  if(args != 2) { +  /* FIXME: Not appropriate if too many args. */ +  SIMPLE_TOO_FEW_ARGS_ERROR("`<<", 2); +  }    o_lsh();   }      static int generate_lsh(node *n)   {    if(count_args(CDR(n))==2)    {    do_docode(CDR(n),DO_NOT_COPY);    emit2(F_LSH);    return 1;    }    return 0;   }      void o_rsh(void)   {    if(sp[-2].type != T_INT || sp[-1].type != T_INT)    { -  +  int args = 2;    if(call_lfun(LFUN_RSH, LFUN_RRSH))    return;    if(sp[-2].type != T_INT) -  PIKE_ERROR("`>>", "Bad argument 1.\n", sp, 2); -  PIKE_ERROR("`>>", "Bad argument 2.\n", sp, 2); +  SIMPLE_BAD_ARG_ERROR("`>>", 1, "int|object"); +  SIMPLE_BAD_ARG_ERROR("`>>", 2, "int|object");    }    sp--;    sp[-1].u.integer = sp[-1].u.integer >> sp->u.integer;   }      void f_rsh(INT32 args)   { -  if(args != 2) -  PIKE_ERROR("`>>", "Bad number of args.\n", sp, args); +  if(args != 2) { +  /* FIXME: Not appropriate if too many args. */ +  SIMPLE_TOO_FEW_ARGS_ERROR("`>>", 2); +  }    o_rsh();   }      static int generate_rsh(node *n)   {    if(count_args(CDR(n))==2)    {    do_docode(CDR(n),DO_NOT_COPY);    emit2(F_RSH);    return 1;    }    return 0;   }         #define TWO_TYPES(X,Y) (((X)<<8)|(Y))   void o_multiply(void)   { -  +  int args = 2;    switch(TWO_TYPES(sp[-2].type,sp[-1].type))    {    case TWO_TYPES(T_ARRAY, T_INT):    {    struct array *ret;    struct svalue *pos;    INT32 e;    if(sp[-1].u.integer < 0) -  PIKE_ERROR("`*", "Cannot multiply array by negative number.\n", sp, 2); +  SIMPLE_BAD_ARG_ERROR("`*", 2, "int(0..)");    ret=allocate_array(sp[-2].u.array->size * sp[-1].u.integer);    pos=ret->item;    for(e=0;e<sp[-1].u.integer;e++,pos+=sp[-2].u.array->size)    assign_svalues_no_free(pos,    sp[-2].u.array->item,    sp[-2].u.array->size,    sp[-2].u.array->type_field);    ret->type_field=sp[-2].u.array->type_field;    pop_n_elems(2);    push_array(ret);    return;    }    case TWO_TYPES(T_STRING, T_INT):    {    struct pike_string *ret;    char *pos;    INT32 e,len;    if(sp[-1].u.integer < 0) -  PIKE_ERROR("`*", "Cannot multiply string by negative number.\n", sp, 2); +  SIMPLE_BAD_ARG_ERROR("`*", 2, "int(0..)");    ret=begin_wide_shared_string(sp[-2].u.string->len * sp[-1].u.integer,    sp[-2].u.string->size_shift);    pos=ret->str;    len=sp[-2].u.string->len << sp[-2].u.string->size_shift;    for(e=0;e<sp[-1].u.integer;e++,pos+=len)    MEMCPY(pos,sp[-2].u.string->str,len);    pop_n_elems(2);    push_string(low_end_shared_string(ret));    return;    }
pike.git/src/operators.c:1196:    return;       PIKE_ERROR("`*", "Bad arguments.\n", sp, 2);    }   }      void f_multiply(INT32 args)   {    switch(args)    { -  case 0: PIKE_ERROR("`*", "Too few arguments.\n", sp, 0); +  case 0: SIMPLE_TOO_FEW_ARGS_ERROR("`*", 1);    case 1: return;    case 2: o_multiply(); return;    default:    if(sp[-args].type==T_OBJECT)    {    CALL_OPERATOR(LFUN_MULTIPLY, args);    } else {    while(--args > 0) o_multiply();    }    }
pike.git/src/operators.c:1243:       switch(TWO_TYPES(sp[-2].type,sp[-1].type))    {    case TWO_TYPES(T_STRING,T_INT):    {    struct array *a;    INT32 size,e,len,pos=0;       len=sp[-1].u.integer;    if(!len) -  PIKE_ERROR("`/", "Division by zero.\n", sp, 2); +  OP_DIVISION_BY_ZERO_ERROR("`/");       if(len<0)    {    len=-len;    size=sp[-2].u.string->len / len;    pos+=sp[-2].u.string->len % len;    }else{    size=sp[-2].u.string->len / len;    }    a=allocate_array(size);
pike.git/src/operators.c:1274:    }       case TWO_TYPES(T_STRING,T_FLOAT):    {    struct array *a;    INT32 last,pos,e,size;    double len;       len=sp[-1].u.float_number;    if(len==0.0) -  PIKE_ERROR("`/", "Division by zero.\n", sp, 2); +  OP_DIVISION_BY_ZERO_ERROR("`/");       if(len<0)    {    len=-len;    size=(INT32)ceil( ((double)sp[-2].u.string->len) / len);    a=allocate_array(size);       for(last=sp[-2].u.string->len,e=0;e<size-1;e++)    {    pos=sp[-2].u.string->len - (INT32)((e+1)*len);
pike.git/src/operators.c:1329:    }          case TWO_TYPES(T_ARRAY, T_INT):    {    struct array *a;    INT32 size,e,len,pos;       len=sp[-1].u.integer;    if(!len) -  PIKE_ERROR("`/", "Division by zero.\n", sp, 2); +  OP_DIVISION_BY_ZERO_ERROR("`/");       if(len<0)    {    len = -len;    pos = sp[-2].u.array->size % len;    }else{    pos = 0;    }    size = sp[-2].u.array->size / len;   
pike.git/src/operators.c:1363:    }       case TWO_TYPES(T_ARRAY,T_FLOAT):    {    struct array *a;    INT32 last,pos,e,size;    double len;       len=sp[-1].u.float_number;    if(len==0.0) -  PIKE_ERROR("`/", "Division by zero.\n", sp, 2); +  OP_DIVISION_BY_ZERO_ERROR("`/");       if(len<0)    {    len=-len;    size=(INT32)ceil( ((double)sp[-2].u.array->size) / len);    a=allocate_array(size);       for(last=sp[-2].u.array->size,e=0;e<size-1;e++)    {    pos=sp[-2].u.array->size - (INT32)((e+1)*len);
pike.git/src/operators.c:1440:    case T_ARRAY:    {    struct array *ret=explode_array(sp[-2].u.array, sp[-1].u.array);    pop_n_elems(2);    push_array(ret);    return;    }       case T_FLOAT:    if(sp[-1].u.float_number == 0.0) -  PIKE_ERROR("`/", "Division by zero.\n", sp, 2); +  OP_DIVISION_BY_ZERO_ERROR("`/");    sp--;    sp[-1].u.float_number /= sp[0].u.float_number;    return;       case T_INT:    {    INT32 tmp;    if (sp[-1].u.integer == 0) -  PIKE_ERROR("`/", "Division by zero\n", sp, 2); +  OP_DIVISION_BY_ZERO_ERROR("`/");    sp--;       tmp=sp[-1].u.integer/sp[0].u.integer;       if((sp[-1].u.integer<0) != (sp[0].u.integer<0))    if(tmp*sp[0].u.integer!=sp[-1].u.integer)    tmp--;       sp[-1].u.integer=tmp;    return;
pike.git/src/operators.c:1472:    default:    PIKE_ERROR("`/", "Bad argument 1.\n", sp, 2);    }   }      void f_divide(INT32 args)   {    switch(args)    {    case 0: -  case 1: PIKE_ERROR("`/", "Too few arguments to `/\n", sp, args); +  case 1: SIMPLE_TOO_FEW_ARGS_ERROR("`/", 2);    case 2: o_divide(); break;    default:    {    INT32 e;    struct svalue *s=sp-args;    push_svalue(s);    for(e=1;e<args;e++)    {    push_svalue(s+e);    o_divide();
pike.git/src/operators.c:1515:    if(call_lfun(LFUN_MOD, LFUN_RMOD))    return;       switch(TWO_TYPES(sp[-2].type,sp[-1].type))    {    case TWO_TYPES(T_STRING,T_INT):    {    struct pike_string *s=sp[-2].u.string;    INT32 tmp,base;    if(!sp[-1].u.integer) -  PIKE_ERROR("`%", "Modulo by zero.\n", sp, 2); +  OP_MODULO_BY_ZERO_ERROR("`%");       tmp=sp[-1].u.integer;    if(tmp<0)    {    tmp=s->len % -tmp;    base=0;    }else{    tmp=s->len % tmp;    base=s->len - tmp;    }
pike.git/src/operators.c:1538:    push_string(s);    return;    }          case TWO_TYPES(T_ARRAY,T_INT):    {    struct array *a=sp[-2].u.array;    INT32 tmp,base;    if(!sp[-1].u.integer) -  PIKE_ERROR("`%", "Modulo by zero.\n", sp, 2); +  OP_MODULO_BY_ZERO_ERROR("`%");       tmp=sp[-1].u.integer;    if(tmp<0)    {    tmp=a->size % -tmp;    base=0;    }else{    tmp=a->size % tmp;    base=a->size - tmp;    }
pike.git/src/operators.c:1570:    switch(sp[-2].type)    {    case T_OBJECT:    CALL_OPERATOR(LFUN_MOD,2);    break;       case T_FLOAT:    {    FLOAT_TYPE foo;    if(sp[-1].u.float_number == 0.0) -  PIKE_ERROR("`%", "Modulo by zero.\n", sp, 2); +  OP_MODULO_BY_ZERO_ERROR("`%");    sp--;    foo=sp[-1].u.float_number / sp[0].u.float_number;    foo=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) PIKE_ERROR("`%", "Modulo by zero.\n", sp, 2); +  if (sp[-1].u.integer == 0) +  OP_MODULO_BY_ZERO_ERROR("`%");    sp--;    if(sp[-1].u.integer>=0)    {    if(sp[0].u.integer>=0)    {    sp[-1].u.integer %= sp[0].u.integer;    }else{    sp[-1].u.integer=((sp[-1].u.integer+~sp[0].u.integer)%-sp[0].u.integer)-~sp[0].u.integer;    }    }else{
pike.git/src/operators.c:1605:    }    return;       default:    PIKE_ERROR("`%", "Bad argument 1.\n", sp, 2);    }   }      void f_mod(INT32 args)   { -  if(args != 2) -  PIKE_ERROR("`%", "Bad number of args\n", sp, args); +  if(args != 2) { +  /* FIXME: Not appropriate when too many args. */ +  SIMPLE_TOO_FEW_ARGS_ERROR("`%", 2); +  }    o_mod();   }      static int generate_mod(node *n)   {    if(count_args(CDR(n))==2)    {    do_docode(CDR(n),DO_NOT_COPY);    emit2(F_MOD);    return 1;
pike.git/src/operators.c:1650:       default:    free_svalue(sp-1);    sp[-1].type=T_INT;    sp[-1].u.integer=0;    }   }      void f_not(INT32 args)   { -  if(args != 1) PIKE_ERROR("`!", "Bad number of args.\n", sp, args); +  if(args != 1) { +  /* FIXME: Not appropriate with too many args. */ +  SIMPLE_TOO_FEW_ARGS_ERROR("`!", 1); +  }    o_not();   }      static int generate_not(node *n)   {    if(count_args(CDR(n))==1)    {    do_docode(CDR(n),DO_NOT_COPY);    emit2(F_NOT);    return 1;
pike.git/src/operators.c:1686:       case T_FLOAT:    sp[-1].u.float_number = -1.0 - sp[-1].u.float_number;    break;       case T_STRING:    {    struct pike_string *s;    INT32 len, i;    -  if(sp[-1].u.string->size_shift) -  error("`~ cannot handle wide strings.\n"); +  if(sp[-1].u.string->size_shift) { +  bad_arg_error("`~", sp-1, 1, 1, "string(0)", sp-1, +  "Expected 8-bit string.\n"); +  }       len = sp[-1].u.string->len;    s = begin_shared_string(len);    for (i=0; i<len; i++)    s->str[i] = ~ sp[-1].u.string->str[i];    pop_n_elems(1);    push_string(end_shared_string(s));    break;    }       default:    PIKE_ERROR("`~", "Bad argument.\n", sp, 1);    }   }      void f_compl(INT32 args)   { -  if(args != 1) PIKE_ERROR("`~", "Bad number of args.\n", sp, args); +  if(args != 1) { +  /* FIXME: Not appropriate with too many args. */ +  SIMPLE_TOO_FEW_ARGS_ERROR("`~", 1); +  }    o_compl();   }      static int generate_compl(node *n)   {    if(count_args(CDR(n))==1)    {    do_docode(CDR(n),DO_NOT_COPY);    emit2(F_COMPL);    return 1;