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