pike.git / src / operators.c

version» Context lines:

pike.git/src/operators.c:13:   #include "stralloc.h"   #include "opcodes.h"   #include "operators.h"   #include "language.h"   #include "memory.h"   #include "error.h"   #include "docode.h"   #include "add_efun.h"   #include "peep.h"   #include "lex.h" + #include "program.h" + #include "object.h"      #define COMPARISON(ID,NAME,EXPR) \   void ID(INT32 args) \   { \    int i; \    if(args > 2) \    pop_n_elems(args-2); \    else if(args < 2) \    error("Too few arguments to %s\n",NAME); \    i=EXPR; \    pop_n_elems(2); \ -  sp->type=T_INT; \ -  sp->u.integer=i; \ -  sp++; \ +  push_int(i); \   }      COMPARISON(f_eq,"`==", is_eq(sp-2,sp-1))   COMPARISON(f_ne,"`!=",!is_eq(sp-2,sp-1))   COMPARISON(f_lt,"`<" , is_lt(sp-2,sp-1))   COMPARISON(f_le,"`<=",!is_gt(sp-2,sp-1))   COMPARISON(f_gt,"`>" , is_gt(sp-2,sp-1))   COMPARISON(f_ge,"`>=",!is_lt(sp-2,sp-1))       -  + #define CALL_OPERATOR(OP, args) \ +  if(!sp[-args].u.object->prog) \ +  error("Operator %s called in destructed object.\n",lfun_names[OP]); \ +  if(sp[-args].u.object->prog->lfuns[OP] == -1) \ +  error("No operator %s in object.\n",lfun_names[OP]); \ +  apply_lfun(sp[-args].u.object, OP, args-1); \ +  free_svalue(sp-2); \ +  sp[-2]=sp[-1]; \ +  sp--; +  +    void f_add(INT32 args)   {    INT32 e,size;    TYPE_FIELD types;       types=0;    for(e=-args;e<0;e++) types|=1<<sp[e].type;       switch(types)    {    default:    if(args)    {    switch(sp[-args].type)    {    case T_OBJECT: -  +  CALL_OPERATOR(LFUN_ADD,args); +  return; +     case T_PROGRAM:    case T_FUNCTION:    error("Bad argument 1 to summation\n");    }    }    error("Incompatible types to sum() or +\n");    return; /* compiler hint */       case BIT_STRING:    {
pike.git/src/operators.c:331:    {    sp[-1].u.float_number=(FLOAT_TYPE)sp[-1].u.integer;    sp[-1].type=T_FLOAT;    }       return sp[-2].type == sp[-1].type;   }      void o_subtract()   { -  if (sp[-2].type != sp[-1].type && !float_promote()) +  if (sp[-2].type != sp[-1].type && +  !float_promote() && +  sp[-2].type != T_OBJECT)    error("Subtract on different types.\n");    -  switch(sp[-1].type) +  switch(sp[-2].type)    { -  +  case T_OBJECT: +  CALL_OPERATOR(LFUN_SUBTRACT,2); +  break; +     case T_ARRAY:    {    struct array *a;       check_array_for_destruct(sp[-2].u.array);    check_array_for_destruct(sp[-1].u.array);    a = subtract_arrays(sp[-2].u.array, sp[-1].u.array);    pop_n_elems(2);    push_array(a);    return;
pike.git/src/operators.c:424:    case 2:    do_docode(CDR(n),DO_NOT_COPY);    emit2(F_SUBTRACT);    return 1;    }    return 0;   }      void o_and()   { -  if(sp[-1].type != sp[-2].type) +  if(sp[-1].type != sp[-2].type && +  sp[-2].type != T_OBJECT)    error("Bitwise and on different types.\n");       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;    break;       case T_MAPPING:    {    struct mapping *m;    m=merge_mappings(sp[-2].u.mapping, sp[-1].u.mapping, OP_AND);    pop_n_elems(2);
pike.git/src/operators.c:472:    }   }      void f_and(INT32 args)   {    switch(args)    {    case 0: error("Too few arguments to `&\n");    case 1: return;    case 2: o_and(); return; -  default: while(--args > 0) o_and(); +  default: +  if(sp[-args].type == T_OBJECT) +  { +  CALL_OPERATOR(LFUN_AND, args); +  }else{ +  while(--args > 0) o_and();    }    } -  + }      static int generate_and(node *n)   {    switch(count_args(CDR(n)))    {    case 1:    do_docode(CDR(n),0);    return 1;       case 2:
pike.git/src/operators.c:496:    emit2(F_AND);    return 1;       default:    return 0;    }   }      void o_or()   { -  if(sp[-1].type != sp[-2].type) +  if(sp[-1].type != sp[-2].type && +  sp[-2].type != T_OBJECT)    error("Bitwise or on different types.\n");       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;    break;       case T_MAPPING:    {    struct mapping *m;    m=merge_mappings(sp[-2].u.mapping, sp[-1].u.mapping, OP_OR);    pop_n_elems(2);
pike.git/src/operators.c:545:    }   }      void f_or(INT32 args)   {    switch(args)    {    case 0: error("Too few arguments to `|\n");    case 1: return;    case 2: o_or(); return; -  default: while(--args > 0) o_or(); +  default: +  if(sp[-args].type==T_OBJECT) +  { +  CALL_OPERATOR(LFUN_OR, args); +  } else { +  while(--args > 0) o_or();    }    } -  + }      static int generate_or(node *n)   {    switch(count_args(CDR(n)))    {    case 1:    do_docode(CDR(n),0);    return 1;       case 2:
pike.git/src/operators.c:570:    return 1;       default:    return 0;    }   }         void o_xor()   { -  if(sp[-1].type != sp[-2].type) +  if(sp[-1].type != sp[-2].type && +  sp[-2].type != T_OBJECT)    error("Bitwise xor on different types.\n");       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;    break;       case T_MAPPING:    {    struct mapping *m;    m=merge_mappings(sp[-2].u.mapping, sp[-1].u.mapping, OP_XOR);    pop_n_elems(2);
pike.git/src/operators.c:618:    }   }      void f_xor(INT32 args)   {    switch(args)    {    case 0: error("Too few arguments to `^\n");    case 1: return;    case 2: o_xor(); return; -  default: while(--args > 0) o_xor(); +  default: +  if(sp[-args].type==T_OBJECT) +  { +  CALL_OPERATOR(LFUN_XOR, args); +  } else { +  while(--args > 0) o_xor();    }    } -  + }      static int generate_xor(node *n)   {    switch(count_args(CDR(n)))    {    case 1:    do_docode(CDR(n),0);    return 1;       case 2:
pike.git/src/operators.c:642:    emit2(F_XOR);    return 1;       default:    return 0;    }   }      void o_lsh()   { -  if(sp[-2].type != T_INT) error("Bad argument 1 to <<\n"); +  if(sp[-2].type != T_INT) +  { +  if(sp[-2].type == T_OBJECT) +  { +  CALL_OPERATOR(LFUN_LSH,2); +  return; +  } +  +  error("Bad argument 1 to <<\n"); +  }    if(sp[-1].type != T_INT) error("Bad argument 2 to <<\n");    sp--;    sp[-1].u.integer = sp[-1].u.integer << sp->u.integer;   }      void f_lsh(INT32 args)   {    if(args != 2)    error("Bad number of args to `<<\n");    o_lsh();
pike.git/src/operators.c:668:    {    do_docode(CDR(n),DO_NOT_COPY);    emit2(F_LSH);    return 1;    }    return 0;   }      void o_rsh()   { -  if(sp[-2].type != T_INT) error("Bad argument 1 to >>\n"); +  if(sp[-2].type != T_INT) +  { +  if(sp[-2].type == T_OBJECT) +  { +  CALL_OPERATOR(LFUN_RSH,2); +  return; +  } +  error("Bad argument 1 to >>\n"); +  }    if(sp[-1].type != T_INT) error("Bad argument 2 to >>\n");    sp--;    sp[-1].u.integer = sp[-1].u.integer >> sp->u.integer;   }      void f_rsh(INT32 args)   {    if(args != 2)    error("Bad number of args to `>>\n");    o_rsh();
pike.git/src/operators.c:733:    (FLOAT_TYPE) sp[-1].u.integer * (FLOAT_TYPE)sp[0].u.float_number;    sp[-1].type=T_FLOAT;    return;       case TWO_TYPES(T_INT,T_INT):    sp--;    sp[-1].u.integer *= sp[0].u.integer;    return;       default: +  if(sp[-2].type == T_OBJECT) +  { +  CALL_OPERATOR(LFUN_MULTIPLY,2); +  return; +  } +     error("Bad arguments to multiply.\n");    }   }      void f_multiply(INT32 args)   {    switch(args)    {    case 0: error("Too few arguments to `*\n");    case 1: return;    case 2: o_multiply(); return; -  default: while(--args > 0) o_multiply(); +  default: +  if(sp[-args].type==T_OBJECT) +  { +  CALL_OPERATOR(LFUN_MULTIPLY, args); +  } else { +  while(--args > 0) o_multiply();    }    } -  + }      static int generate_multiply(node *n)   {    switch(count_args(CDR(n)))    {    case 1:    do_docode(CDR(n),0);    return 1;       case 2:
pike.git/src/operators.c:768:    emit2(F_MULTIPLY);    return 1;       default:    return 0;    }   }      void o_divide()   { -  if(sp[-2].type!=sp[-1].type && !float_promote()) +  if(sp[-2].type!=sp[-1].type && +  !float_promote() && +  sp[-2].type != T_OBJECT)    error("Division on different types.\n");       switch(sp[-2].type)    { -  +  case T_OBJECT: +  CALL_OPERATOR(LFUN_DIVIDE,2); +  break; +     case T_STRING:    {    struct array *ret;    ret=explode(sp[-2].u.string,sp[-1].u.string);    free_string(sp[-2].u.string);    free_string(sp[-1].u.string);    sp[-2].type=T_ARRAY;    sp[-2].u.array=ret;    sp--;    return;
pike.git/src/operators.c:824:    {    do_docode(CDR(n),DO_NOT_COPY);    emit2(F_DIVIDE);    return 1;    }    return 0;   }      void o_mod()   { -  if(sp[-2].type != sp[-1].type && !float_promote()) +  if(sp[-2].type != sp[-1].type && +  !float_promote() && +  sp[-2].type != T_OBJECT)    error("Modulo on different types.\n");    -  switch(sp[-1].type) +  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)    error("Modulo by zero.\n");    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;
pike.git/src/operators.c:871:    {    do_docode(CDR(n),DO_NOT_COPY);    emit2(F_MOD);    return 1;    }    return 0;   }      void o_not()   { -  if(sp[-1].type==T_INT) +  switch(sp[-1].type)    { -  +  case T_INT:    sp[-1].u.integer = !sp[-1].u.integer; -  +  break; +  +  case T_FUNCTION: +  case T_OBJECT: +  if(IS_ZERO(sp-1)) +  { +  pop_stack(); +  push_int(1);    }else{    pop_stack(); -  sp->type=T_INT; -  sp->u.integer=0; -  sp++; +  push_int(0);    } -  +  break; +  +  default: +  free_svalue(sp-1); +  sp[-1].type=T_INT; +  sp[-1].u.integer=0;    } -  + }      void f_not(INT32 args)   {    if(args != 1) error("Bad number of args to `!\n");    o_not();   }      static int generate_not(node *n)   {    if(count_args(CDR(n))==1)
pike.git/src/operators.c:903:    emit2(F_NOT);    return 1;    }    return 0;   }      void o_compl()   {    switch(sp[-1].type)    { +  case T_OBJECT: +  CALL_OPERATOR(LFUN_COMPL,1); +  break; +     case T_INT:    sp[-1].u.integer = ~ sp[-1].u.integer;    break;       case T_FLOAT:    sp[-1].u.float_number = -1.0 - sp[-1].u.float_number;    break;       default:    error("Bad argument to ~\n");
pike.git/src/operators.c:937:    emit2(F_COMPL);    return 1;    }    return 0;   }      void o_negate()   {    switch(sp[-1].type)    { +  case T_OBJECT: +  CALL_OPERATOR(LFUN_SUBTRACT,1); +  break; +     case T_FLOAT:    sp[-1].u.float_number=-sp[-1].u.float_number;    return;       case T_INT:    sp[-1].u.integer = - sp[-1].u.integer;    return;       default:    error("Bad argument to unary minus\n");
pike.git/src/operators.c:1009:       default:    error("[ .. ] can only be done on strings and arrays.\n");    }   }      void init_operators()   {    add_efun2("`==",f_eq,"function(mixed,mixed:int)",OPT_TRY_OPTIMIZE,0,generate_comparison);    add_efun2("`!=",f_ne,"function(mixed,mixed:int)",OPT_TRY_OPTIMIZE,0,generate_comparison); -  add_efun2("`<", f_lt,"function(int|float,int|float:int)|function(string,string:int)",OPT_TRY_OPTIMIZE,0,generate_comparison); -  add_efun2("`<=",f_le,"function(int|float,int|float:int)|function(string,string:int)",OPT_TRY_OPTIMIZE,0,generate_comparison); -  add_efun2("`>", f_gt,"function(int|float,int|float:int)|function(string,string:int)",OPT_TRY_OPTIMIZE,0,generate_comparison); -  add_efun2("`>=",f_ge,"function(int|float,int|float:int)|function(string,string:int)",OPT_TRY_OPTIMIZE,0,generate_comparison); +  add_efun2("`!",f_not,"function(mixed:int)",OPT_TRY_OPTIMIZE,0,generate_not);    -  add_efun2("`+",f_add,"function(int...:int)|!function(int...:mixed)&function(int|float...:float)|!function(int|float...:mixed)&function(string|int|float...:string)|function(array...:array)|function(mapping...:mapping)|function(list...:list)",OPT_TRY_OPTIMIZE,optimize_binary,generate_sum); + #define CMP_TYPE "function(object,mixed:int)|function(mixed,object:int)|function(int|float,int|float:int)|function(string,string:int)" +  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_minus,"function(int:int)|function(float:float)|function(array,array:array)|function(mapping,mapping:mapping)|function(list,list:list)|function(float|int,float:float)|function(float,int:float)|function(int,int:int)|function(string,string:string)",OPT_TRY_OPTIMIZE,0,generate_minus); +  add_efun2("`+",f_add,"function(object,mixed...:mixed)|function(int...:int)|!function(int...:mixed)&function(int|float...:float)|!function(int|float...:mixed)&function(string|int|float...:string)|function(array...:array)|function(mapping...:mapping)|function(list...:list)",OPT_TRY_OPTIMIZE,optimize_binary,generate_sum);    -  add_efun2("`&",f_and,"function(int...:int)|function(mapping...:mapping)|function(list...:list)|function(array...:array)",OPT_TRY_OPTIMIZE,optimize_binary,generate_and); +  add_efun2("`-",f_minus,"function(object,mixed...:mixed)|function(int:int)|function(float:float)|function(array,array:array)|function(mapping,mapping:mapping)|function(list,list:list)|function(float|int,float:float)|function(float,int:float)|function(int,int:int)|function(string,string:string)",OPT_TRY_OPTIMIZE,0,generate_minus);    -  add_efun2("`|",f_or,"function(int...:int)|function(mapping...:mapping)|function(list...:list)|function(array...:array)",OPT_TRY_OPTIMIZE,optimize_binary,generate_or); + #define LOG_TYPE "function(object,mixed...:mixed)|function(int...:int)|function(mapping...:mapping)|function(list...:list)|function(array...:array)"    -  add_efun2("`^",f_xor,"function(int...:int)|function(mapping...:mapping)|function(list...:list)|function(array...:array)",OPT_TRY_OPTIMIZE,optimize_binary,generate_xor); +  add_efun2("`&",f_and,LOG_TYPE,OPT_TRY_OPTIMIZE,optimize_binary,generate_and);    -  add_efun2("`<<",f_lsh,"function(int,int:int)",OPT_TRY_OPTIMIZE,0,generate_lsh); -  add_efun2("`>>",f_rsh,"function(int,int:int)",OPT_TRY_OPTIMIZE,0,generate_rsh); +  add_efun2("`|",f_or,LOG_TYPE,OPT_TRY_OPTIMIZE,optimize_binary,generate_or);    -  add_efun2("`*",f_multiply,"function(int...:int)|!function(int...:mixed)&function(float|int...:float)|function(string*,string:string)",OPT_TRY_OPTIMIZE,optimize_binary,generate_multiply); +  add_efun2("`^",f_xor,LOG_TYPE,OPT_TRY_OPTIMIZE,optimize_binary,generate_xor);    -  add_efun2("`/",f_divide,"function(int,int:int)|function(float|int,float:float)|function(float,int:float)|function(string,string:string*)",OPT_TRY_OPTIMIZE,0,generate_divide); +     -  add_efun2("`%",f_mod,"function(int,int:int)|!function(int,int:mixed)&function(int|float,int|float:float)",OPT_TRY_OPTIMIZE,0,generate_mod); + #define SHIFT_TYPE "function(object,mixed:mixed)|function(int,int:int)"    -  add_efun2("`!",f_not,"function(mixed:int)",OPT_TRY_OPTIMIZE,0,generate_not); -  add_efun2("`~",f_compl,"function(int:int)|function(float:float)",OPT_TRY_OPTIMIZE,0,generate_compl); +  add_efun2("`<<",f_lsh,SHIFT_TYPE,OPT_TRY_OPTIMIZE,0,generate_lsh); +  add_efun2("`>>",f_rsh,SHIFT_TYPE,OPT_TRY_OPTIMIZE,0,generate_rsh); +  +  add_efun2("`*",f_multiply,"function(object,mixed...:mixed)|function(int...:int)|!function(int...:mixed)&function(float|int...:float)|function(string*,string:string)",OPT_TRY_OPTIMIZE,optimize_binary,generate_multiply); +  +  add_efun2("`/",f_divide,"function(object,mixed:mixed)|function(int,int:int)|function(float|int,float:float)|function(float,int:float)|function(string,string:string*)",OPT_TRY_OPTIMIZE,0,generate_divide); +  +  add_efun2("`%",f_mod,"function(object,mixed:mixed)|function(int,int:int)|!function(int,int:mixed)&function(int|float,int|float:float)",OPT_TRY_OPTIMIZE,0,generate_mod); +  +  add_efun2("`~",f_compl,"function(object:mixed)|function(int:int)|function(float:float)",OPT_TRY_OPTIMIZE,0,generate_compl);   }