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.119 2001/02/05 19:30:48 grubba Exp $"); + RCSID("$Id: operators.c,v 1.120 2001/02/07 14:58:35 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:50:    break; \    default: \    for(i=1;i<args;i++) \    if(! ( FUN (sp-args+i-1, sp-args+i))) \    break; \    pop_n_elems(args); \    push_int(i==args); \    } \   }    + /*! @decl int(0..1) `!=(mixed arg1, mixed arg2, mixed ... extras) +  *! +  *! Inequality operator. +  *! +  *! Returns @tt{0@} (zero) if all the arguments are equal, and +  *! @tt{1@} otherwise. +  *! +  *! This is the inverse of @[`==()]. +  *! +  *! @seealso +  *! @[`==()] +  */ +    PMOD_EXPORT void f_ne(INT32 args)   {    f_eq(args);    o_not();   }    -  + /*! @decl int(0..1) `==(mixed arg1, mixed arg2, mixed ... extras) +  *! +  *! Equality operator. +  *! +  *! Returns @tt{1@} if all the arguments are equal, and +  *! @tt{0@} (zero) otherwise. +  *! +  *! @seealso +  *! @[`!=()] +  */   COMPARISON(f_eq,"`==", is_eq) -  +  + /*! @decl int(0..1) `<(mixed arg1, mixed arg2, mixed ... extras) +  *! +  *! Less than operator. +  *! +  *! Returns @tt{1@} if the arguments are strictly increasing, and +  *! @tt{0@} (zero) otherwise. +  *! +  *! @seealso +  *! @[`<=()], @[`>()], @[`>=()] +  */   COMPARISON(f_lt,"`<" , is_lt) -  +  + /*! @decl int(0..1) `<=(mixed arg1, mixed arg2, mixed ... extras) +  *! +  *! Less or equal operator. +  *! +  *! Returns @tt{1@} if the arguments are not strictly decreasing, and +  *! @tt{0@} (zero) otherwise. +  *! +  *! This is the inverse of @[`>()]. +  *! +  *! @seealso +  *! @[`<()], @[`>()], @[`>=()] +  */   COMPARISON(f_le,"`<=",!is_gt) -  +  + /*! @decl int(0..1) `>(mixed arg1, mixed arg2, mixed ... extras) +  *! +  *! Greater than operator. +  *! +  *! Returns @tt{1@} if the arguments are strictly decreasing, and +  *! @tt{0@} (zero) otherwise. +  *! +  *! @seealso +  *! @[`<()], @[`<=()], @[`>=()] +  */   COMPARISON(f_gt,"`>" , is_gt) -  +  + /*! @decl int(0..1) `>=(mixed arg1, mixed arg2, mixed ... extras) +  *! +  *! Greater or equal operator. +  *! +  *! Returns @tt{1@} if the arguments are not strictly increasing, and +  *! @tt{0@} (zero) otherwise. +  *! +  *! This is the inverse of @[`<()]. +  *! +  *! @seealso +  *! @[`<=()], @[`>()], @[`<()] +  */   COMPARISON(f_ge,"`>=",!is_lt)         #define CALL_OPERATOR(OP, args) \    if(!sp[-args].u.object->prog) \    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) \    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--; \    dmalloc_touch_svalue(sp);    -  + /*! @decl mixed `+(mixed arg1) +  *! @decl mixed `+(object arg1, mixed ... extras) +  *! @decl string `+(string arg1, string|int|float arg2) +  *! @decl string `+(int|float arg1, string arg2) +  *! @decl int `+(int arg1, int arg2) +  *! @decl float `+(float arg1, int|float arg2) +  *! @decl float `+(int|float arg1, float arg2) +  *! @decl array `+(array arg1, array arg2) +  *! @decl mapping `+(mapping arg1, mapping arg2) +  *! @decl multiset `+(multiset arg1, multiset arg2) +  *! @decl mixed `+(mixed arg1, mixed arg2, mixed ... extras) +  *! +  *! Addition operator. +  *! +  *! If there's only a single argument, that argument will be returned. +  *! +  *! If @[arg1] is an object and it has an @[lfun::`+()], +  *! that function will be called with the rest of the arguments, +  *! and the result returned. +  *! +  *! Otherwise if any of the other arguments is an object that has +  *! an @[lfun::``+()] the first such function fill be called +  *! with the arguments leading up to it, and @[`+()] be called recursively +  *! with the result and the rest of the srguments. +  *! +  *! If there are two arguments the result will be: +  *! @mixed @[arg1] +  *! @type string +  *! @[arg2] will be converted to a string, and the result the +  *! strings concatenated. +  *! @type int|float +  *! @mixed @[arg2] +  *! @type string +  *! @[arg1] will be converted to string, and the result the +  *! strings concatenated. +  *! @type int|float +  *! The result will be @code{@[arg1] + @[arg2]@}, and will +  *! be a float if either @[arg1] or @[arg2] is a float. +  *! @endmixed +  *! @type array +  *! The arrays will be concatenated. +  *! @type mapping +  *! The mappings will be joined. +  *! @type multiset +  *! The multisets will be added. +  *! @endmixed +  *! +  *! Otherwise if there are more than 2 arguments the result will be: +  *! @code{`+(`+(@[arg1], @[arg2]), @@@[extras])@} +  *! +  *! @note +  *! In Pike 7.0 and earlier the addition order was unspecified. +  *! +  *! If @[arg1] is @tt{UNDEFINED@} it will behave as the empty +  *! array/mapping/multiset if needed. This behaviour was new +  *! in Pike 7.0. +  *! +  *! @seealso +  *! @[`-()], @[lfun::`+()], @[lfun::``+()] +  */   PMOD_EXPORT 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)    {
pike.git/src/operators.c:833:       default:    {    int args = 2;    SIMPLE_BAD_ARG_ERROR("`-", 1,    "int|float|string|mapping|multiset|array|object");    }    }   }    + /*! @decl mixed `-(mixed arg1) +  *! @decl mixed `-(object arg1, mixed arg2) +  *! @decl mixed `-(mixed arg1, mixed arg2) +  *! @decl mapping `-(mapping arg1, array arg2) +  *! @decl mapping `-(mapping arg1, multiset arg2) +  *! @decl mapping `-(mapping arg1, mapping arg2) +  *! @decl array `-(array arg1, array arg2) +  *! @decl multiset `-(multiset arg1, multiset arg2) +  *! @decl float `-(float arg1, int|float arg2) +  *! @decl float `-(int arg1, float arg2) +  *! @decl int `-(int arg1, int arg2) +  *! @decl string `-(string arg1, string arg2) +  *! @decl mixed `-(mixed arg1, mixed arg2, mixed ... extras) +  *! +  *! Negation/subtraction operator. +  *! +  *! If there's only a single argument, that argument will be returned +  *! negated. If @[arg1] was an object, @code{@[arg1]::`-()@} will be called +  *! without arguments. +  *! +  *! If there are more than two arguments the result will be: +  *! @code{`-(`-(@[arg1], @[arg2]), @@@[extras])@}. +  *! +  *! If @[arg1] is an object that overloads @tt{`-()@}, that function will +  *! be called with @[arg2] as the single argument. +  *! +  *! If @[arg2] is an object that overloads @tt{``-()@}, that function will +  *! be called with @[arg1] as the single argument. +  *! +  *! Otherwise the result will be as follows: +  *! @mixed @[arg1] +  *! @type mapping +  *! @mixed @[arg2] +  *! @type array +  *! The result will be @[arg1] with all occurrances of +  *! @[arg2] removed. +  *! @type multiset +  *! @type mapping +  *! The result will be @[arg1] with all occurrences of +  *! @code{@[indices](@[arg2])@} removed. +  *! @endmixed +  *! @type array +  *! @type multiset +  *! The result will be the elements of @[arg1] that are not in @[arg2]. +  *! @type float +  *! @type int +  *! The result will be @code{@[arg1] - @[arg2]@}, and will be a float +  *! if either @[arg1] or @[arg2] is a float. +  *! @type string +  *! Result will be the string @[arg1] with all occurrances of the +  *! substring @[arg2] removed. +  *! @endmixed +  *! +  *! @note +  *! In Pike 7.0 and earlier the subtraction order was unspecified. +  *! +  *! @seealso +  *! @[`+()] +  */   PMOD_EXPORT void f_minus(INT32 args)   {    switch(args)    {    case 0: SIMPLE_TOO_FEW_ARGS_ERROR("`-", 1);    case 1: o_negate(); break;    case 2: o_subtract(); break;    default:    {    INT32 e;
pike.git/src/operators.c:1139:    case T_ARRAY:    case T_MAPPING:    r_speedup(args,func);    return;       default:    while(--args > 0) func();    }   }    + /*! @decl mixed `&(mixed arg1) +  *! @decl mixed `&(object arg1, mixed arg2) +  *! @decl mixed `&(mixed arg1, object arg2) +  *! @decl int `&(int arg1, int arg2) +  *! @decl array `&(array arg1, array arg2) +  *! @decl multiset `&(multiset arg1, multiset arg2) +  *! @decl mapping `&(mapping arg1, mapping arg2) +  *! @decl string `&(string arg1, string arg2) +  *! @decl type `&(type|program arg1, type|program arg2) +  *! @decl mapping `&(mapping arg1, array arg2) +  *! @decl mapping `&(array arg1, mapping arg2) +  *! @decl mapping `&(mapping arg1, multiset arg2) +  *! @decl mapping `&(multiset arg1, mapping arg2) +  *! @decl mixed `&(mixed arg1, mixed arg2, mixed ... extras) +  *! +  *! Bitwise and/intersection operator. +  *! +  *! If there's a single argument, that argument will be returned. +  *! +  *! If there are more than two arguments, the result will be: +  *! @code{`&(`&(@[arg1], @[arg2]), @@@[extras])@}. +  *! +  *! If @[arg1] is an object that has an @[lfun::`&()], that function +  *! will be called with @[arg2] as the single argument. +  *! +  *! If @[arg2] is an object that has an @[lfun::``&()], that function +  *! will be called with @[arg1] as the single argument. +  *! +  *! Otherwise the result will be: +  *! @mixed @[arg1] +  *! @type int +  *! The result will be the bitwise and of @[arg1] and @[arg2]. +  *! @type array +  *! @type multiset +  *! @type mapping +  *! The result will be the elements of @[arg1] and @[arg2] that +  *! occurr in both. +  *! @type type +  *! @type program +  *! The result will be the type intersection of @[arg1] and @[arg2]. +  *! @type string +  *! The result will be the string where the elements of @[arg1] +  *! and @[arg2] have been pairwise anded. +  *! @endmixed +  *! +  *! @seealso +  *! @[`|()], @[lfun::`&()], @[lfun::``&()] +  */   PMOD_EXPORT void f_and(INT32 args)   {    switch(args)    {    case 0: SIMPLE_TOO_FEW_ARGS_ERROR("`&", 1);    case 1: return;    case 2: o_and(); return;    default:    if(sp[-args].type == T_OBJECT)    {
pike.git/src/operators.c:1313:    return;    }       STRING_BITOP(|,"OR")       default:    PIKE_ERROR("`|", "Bitwise or on illegal type.\n", sp, 2);    }   }    + /*! @decl mixed `|(mixed arg1, mixed ... extras) +  *! +  *! Or operator. +  */   PMOD_EXPORT void f_or(INT32 args)   {    switch(args)    {    case 0: SIMPLE_TOO_FEW_ARGS_ERROR("`|", 1);    case 1: return;    case 2: o_or(); return;    default:    if(sp[-args].type==T_OBJECT)    {
pike.git/src/operators.c:1492:    return;    }       STRING_BITOP(^,"XOR")       default:    PIKE_ERROR("`^", "Bitwise XOR on illegal type.\n", sp, 2);    }   }    + /*! @decl mixed `^(mixed arg1, mixed ... extras) +  *! +  *! Xor operator. +  */   PMOD_EXPORT void f_xor(INT32 args)   {    switch(args)    {    case 0: SIMPLE_TOO_FEW_ARGS_ERROR("`^", 1);    case 1: return;    case 2: o_xor(); return;    default:    if(sp[-args].type==T_OBJECT)    {
pike.git/src/operators.c:1548:    return;       if(sp[-2].type != T_INT)    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;   }    + /*! @decl mixed `<<(mixed arg1, mixed arg2) +  *! +  *! Left shift operator. +  */   PMOD_EXPORT void f_lsh(INT32 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)
pike.git/src/operators.c:1593: Inside #if defined(AUTO_BIGNUM)
   sp--;    sp[-1].u.integer = 0;    return;    }   #endif /* AUTO_BIGNUM */       sp--;    sp[-1].u.integer = sp[-1].u.integer >> sp->u.integer;   }    + /*! @decl mixed `>>(mixed arg1, mixed arg2) +  *! +  *! Right shift operator. +  */   PMOD_EXPORT void f_rsh(INT32 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)
pike.git/src/operators.c:1799:       default:    do_lfun_multiply:    if(call_lfun(LFUN_MULTIPLY, LFUN_RMULTIPLY))    return;       PIKE_ERROR("`*", "Bad arguments.\n", sp, 2);    }   }    + /*! @decl mixed `*(mixed arg1, mixed ... extras) +  *! +  *! Multiplication operator. +  */   PMOD_EXPORT void f_multiply(INT32 args)   {    switch(args)    {    case 0: SIMPLE_TOO_FEW_ARGS_ERROR("`*", 1);    case 1: return;    case 2: o_multiply(); return;    default:    if(sp[-args].type==T_OBJECT)    {
pike.git/src/operators.c:2102:    tmp--;    sp[-1].u.integer=tmp;    return;    }       default:    PIKE_ERROR("`/", "Bad argument 1.\n", sp, 2);    }   }    + /*! @decl mixed `/(mixed arg1, mixed arg2, mixed ... extras) +  *! +  *! Division operator. +  */   PMOD_EXPORT void f_divide(INT32 args)   {    switch(args)    {    case 0:    case 1: SIMPLE_TOO_FEW_ARGS_ERROR("`/", 2);    case 2: o_divide(); break;    default:    {    INT32 e;
pike.git/src/operators.c:2240:    sp[-1].u.integer=-(-sp[-1].u.integer % -sp[0].u.integer);    }    }    return;       default:    PIKE_ERROR("`%", "Bad argument 1.\n", sp, 2);    }   }    + /*! @decl mixed `%(mixed arg1, mixed arg2) +  *! +  *! Modulo operator. +  */   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();   }      static int generate_mod(node *n)
pike.git/src/operators.c:2287:    }    break;       default:    free_svalue(sp-1);    sp[-1].type=T_INT;    sp[-1].u.integer=0;    }   }    + /*! @decl mixed `!(mixed arg) +  *! +  *! Negation operator. +  */   PMOD_EXPORT void f_not(INT32 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)
pike.git/src/operators.c:2379:    pop_n_elems(1);    push_string(end_shared_string(s));    break;    }       default:    PIKE_ERROR("`~", "Bad argument.\n", sp, 1);    }   }    + /*! @decl mixed `~(mixed arg) +  *! +  *! Complement operator. +  */   PMOD_EXPORT void f_compl(INT32 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)
pike.git/src/operators.c:2494:    free_array(sp[-1].u.array);    sp[-1].u.array=a;    break;    }       default:    PIKE_ERROR("`[]", "[ .. ] on non-scalar type.\n", sp, 3);    }   }    + /*! @decl mixed `[](mixed arg1, mixed arg2, mixed|void arg3) +  *! +  *! Index and range operator. +  */   PMOD_EXPORT void f_index(INT32 args)   {    switch(args)    {    case 0:    case 1:    PIKE_ERROR("`[]", "Too few arguments.\n", sp, args);    break;    case 2:    if(sp[-1].type==T_STRING) sp[-1].subtype=0;    o_index();    break;    case 3:    o_range();    break;    default:    PIKE_ERROR("`[]", "Too many arguments.\n", sp, args);    }   }    -  + /*! @decl mixed `->(mixed arg1, mixed arg2) +  *! +  *! Arrow index operator. +  */   PMOD_EXPORT void f_arrow(INT32 args)   {    switch(args)    {    case 0:    case 1:    PIKE_ERROR("`->", "Too few arguments.\n", sp, args);    break;    case 2:    if(sp[-1].type==T_STRING)    sp[-1].subtype=1;    o_index();    break;    default:    PIKE_ERROR("`->", "Too many arguments.\n", sp, args);    }   }    -  + /*! @decl mixed `[]=(mixed arg1, mixed arg2, mixed arg3) +  *! +  *! Index assign operator. +  */   PMOD_EXPORT void f_index_assign(INT32 args)   {    switch (args) {    case 0:    case 1:    case 2:    PIKE_ERROR("`[]=", "Too few arguments.\n", sp, args);    break;    case 3:    if(sp[-2].type==T_STRING) sp[-2].subtype=0;    assign_lvalue (sp-3, sp-1);    assign_svalue (sp-3, sp-1);    pop_n_elems (args-1);    break;    default:    PIKE_ERROR("`[]=", "Too many arguments.\n", sp, args);    }   }    -  + /*! @decl mixed `->=(mixed arg1, mixed arg2, mixed arg3) +  *! +  *! Arrow assign operator. +  */   PMOD_EXPORT void f_arrow_assign(INT32 args)   {    switch (args) {    case 0:    case 1:    case 2:    PIKE_ERROR("`->=", "Too few arguments.\n", sp, args);    break;    case 3:    if(sp[-2].type==T_STRING) sp[-2].subtype=1;    assign_lvalue (sp-3, sp-1);    assign_svalue (sp-3, sp-1);    pop_n_elems (args-1);    break;    default:    PIKE_ERROR("`->=", "Too many arguments.\n", sp, args);    }   }    -  + /*! @decl int sizeof(mixed arg) +  *! +  *! Sizeof operator. +  */   PMOD_EXPORT void f_sizeof(INT32 args)   {    INT32 tmp;    if(args<1)    PIKE_ERROR("sizeof", "Too few arguments.\n", sp, args);       tmp=pike_sizeof(sp-args);       pop_n_elems(args);    push_int(tmp);
pike.git/src/operators.c:2593:   {    node **arg;    if(count_args(CDR(n)) != 1) return 0;    if(do_docode(CDR(n),DO_NOT_COPY) != 1)    fatal("Count args was wrong in sizeof().\n");    emit0(F_SIZEOF);    return 1;   }      extern int generate_call_function(node *n); +  + /*! @class string_assignment +  */ +    struct program *string_assignment_program;      #undef THIS   #define THIS ((struct string_assignment_storage *)(CURRENT_STORAGE)) -  + /*! @decl int `[](int i, int j) +  *! +  *! String index operator. +  */   static void f_string_assignment_index(INT32 args)   {    INT_TYPE i;    get_all_args("string[]",args,"%i",&i);    if(i<0) i+=THIS->s->len;    if(i<0)    i+=THIS->s->len;    if(i<0 || i>=THIS->s->len)    Pike_error("Index %d is out of range 0 - %ld.\n",    i, PTRDIFF_T_TO_LONG(THIS->s->len - 1));    else    i=index_shared_string(THIS->s,i);    pop_n_elems(args);    push_int(i);   }    -  + /*! @decl int `[]=(int i, int j) +  *! +  *! String assign index operator. +  */   static void f_string_assignment_assign_index(INT32 args)   {    INT_TYPE i,j;    union anything *u;    get_all_args("string[]=",args,"%i%i",&i,&j);    if((u=get_pointer_if_this_type(THIS->lval, T_STRING)))    {    free_string(THIS->s);    if(i<0) i+=u->string->len;    if(i<0 || i>=u->string->len)
pike.git/src/operators.c:2656:    THIS->s=0;   }      static void exit_string_assignment_storage(struct object *o)   {    free_svalues(THIS->lval, 2, BIT_MIXED);    if(THIS->s)    free_string(THIS->s);   }    + /*! @endclass +  */ +    void init_operators(void)   {    /* function(string,int:int)|function(object,string:mixed)|function(array(0=mixed),int:0)|function(mapping(mixed:1=mixed),mixed:1)|function(multiset,mixed:int)|function(string,int,int:string)|function(array(2=mixed),int,int:array(2))|function(program:mixed) */    ADD_EFUN2("`[]",f_index,tOr7(tFunc(tStr tInt,tInt),tFunc(tObj tStr,tMix),tFunc(tArr(tSetvar(0,tMix)) tInt,tVar(0)),tFunc(tMap(tMix,tSetvar(1,tMix)) tMix,tVar(1)),tFunc(tMultiset tMix,tInt),tFunc(tStr tInt tInt,tStr),tOr(tFunc(tArr(tSetvar(2,tMix)) tInt tInt,tArr(tVar(2))),tFunc(tPrg,tMix))),OPT_TRY_OPTIMIZE,0,0);       /* 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) tStr,tMix)),OPT_TRY_OPTIMIZE,0,0);       ADD_EFUN("`[]=", f_index_assign,    tOr4(tFunc(tObj tStr tSetvar(0,tMix), tVar(0)),