From 1b89ad58b37799d1fcce495f7be9bf466aebc3b9 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Fredrik=20H=C3=BCbinette=20=28Hubbe=29?= <hubbe@hubbe.net>
Date: Fri, 10 Oct 1997 23:49:20 -0700
Subject: [PATCH] right-side operator overloading implemented

Rev: src/array.c:1.18
Rev: src/interpret.c:1.49
Rev: src/lex.c:1.28
Rev: src/modules/Gmp/mpz_glue.c:1.23
Rev: src/modules/Gmp/testsuite.in:1.7
Rev: src/operators.c:1.20
Rev: src/program.c:1.43
Rev: src/program.h:1.21
---
 src/array.c                  |   4 +-
 src/interpret.c              |  25 +----
 src/lex.c                    |  62 ++++++------
 src/modules/Gmp/mpz_glue.c   | 109 +++++++++++++++++++--
 src/modules/Gmp/testsuite.in |  67 ++++++++-----
 src/operators.c              | 179 +++++++++++++++++++++++++----------
 src/program.c                |  12 ++-
 src/program.h                |  14 ++-
 8 files changed, 333 insertions(+), 139 deletions(-)

diff --git a/src/array.c b/src/array.c
index e464921734..b672034307 100644
--- a/src/array.c
+++ b/src/array.c
@@ -966,7 +966,9 @@ int array_equal_p(struct array *a, struct array *b, struct processing *p)
    * the type fields didn't contain types that
    * really aren't in the array
    */
-  if(!(a->type_field & b->type_field)) return 0;
+  if(!(a->type_field & b->type_field) &&
+     !( (a->type_field | b->type_field) & BIT_OBJECT ))
+    return 0;
 
   curr.pointer_a = a;
   curr.pointer_b = b;
diff --git a/src/interpret.c b/src/interpret.c
index ce568bb5eb..1275db1b35 100644
--- a/src/interpret.c
+++ b/src/interpret.c
@@ -4,7 +4,7 @@
 ||| See the files COPYING and DISCLAIMER for more information.
 \*/
 #include "global.h"
-RCSID("$Id: interpret.c,v 1.48 1997/10/10 20:22:01 hubbe Exp $");
+RCSID("$Id: interpret.c,v 1.49 1997/10/11 06:48:23 hubbe Exp $");
 #include "interpret.h"
 #include "object.h"
 #include "program.h"
@@ -1164,27 +1164,8 @@ static void eval_instruction(unsigned char *pc)
       }
       break;
 
-      CASE(F_LSH);
-      if(sp[-2].type != T_INT)
-      {
-	o_lsh();
-      }else{
-	if(sp[-1].type != T_INT) error("Bad argument 2 to <<\n");
-	sp--;
-	sp[-1].u.integer = sp[-1].u.integer << sp->u.integer;
-      }
-      break;
-
-      CASE(F_RSH);
-      if(sp[-2].type != T_INT)
-      {
-	o_rsh();
-      }else{
-	if(sp[-1].type != T_INT) error("Bad argument 2 to >>\n");
-	sp--;
-	sp[-1].u.integer = sp[-1].u.integer >> sp->u.integer;
-      }
-      break;
+      CASE(F_LSH); o_lsh(); break;
+      CASE(F_RSH); o_rsh(); break;
 
       COMPARISMENT(F_EQ, is_eq(sp-2,sp-1));
       COMPARISMENT(F_NE,!is_eq(sp-2,sp-1));
diff --git a/src/lex.c b/src/lex.c
index 21b3ac82dd..b7f66b5e47 100644
--- a/src/lex.c
+++ b/src/lex.c
@@ -4,7 +4,7 @@
 ||| See the files COPYING and DISCLAIMER for more information.
 \*/
 #include "global.h"
-RCSID("$Id: lex.c,v 1.27 1997/09/08 01:03:24 hubbe Exp $");
+RCSID("$Id: lex.c,v 1.28 1997/10/11 06:48:23 hubbe Exp $");
 #include "language.h"
 #include "array.h"
 #include "lex.h"
@@ -1673,78 +1673,82 @@ static int do_lex2(int literal, YYSTYPE *yylval)
     case '`':
     {
       char *tmp;
+      int offset=2;
+      if(GOBBLE('`')) offset--;
+      if(GOBBLE('`')) offset--;
+      
       switch(GETC())
       {
-      case '+': tmp="`+"; break;
-      case '/': tmp="`/"; break;
-      case '%': tmp="`%"; break;
-      case '*': tmp="`*"; break;
-      case '&': tmp="`&"; break;
-      case '|': tmp="`|"; break;
-      case '^': tmp="`^"; break;
-      case '~': tmp="`~"; break;
+      case '+': tmp="```+"; break;
+      case '/': tmp="```/"; break;
+      case '%': tmp="```%"; break;
+      case '*': tmp="```*"; break;
+      case '&': tmp="```&"; break;
+      case '|': tmp="```|"; break;
+      case '^': tmp="```^"; break;
+      case '~': tmp="```~"; break;
       case '<':
-	if(GOBBLE('<')) { tmp="`<<"; break; }
-	if(GOBBLE('=')) { tmp="`<="; break; }
-	tmp="`<";
+	if(GOBBLE('<')) { tmp="```<<"; break; }
+	if(GOBBLE('=')) { tmp="```<="; break; }
+	tmp="```<";
 	break;
 
       case '>':
-	if(GOBBLE('>')) { tmp="`>>"; break; }
-	if(GOBBLE('=')) { tmp="`>="; break; }
-	tmp="`>";
+	if(GOBBLE('>')) { tmp="```>>"; break; }
+	if(GOBBLE('=')) { tmp="```>="; break; }
+	tmp="```>";
 	break;
 
       case '!':
-	if(GOBBLE('=')) { tmp="`!="; break; }
-	tmp="`!";
+	if(GOBBLE('=')) { tmp="```!="; break; }
+	tmp="```!";
 	break;
 
       case '=':
-	if(GOBBLE('=')) { tmp="`=="; break; }
-	tmp="`=";
+	if(GOBBLE('=')) { tmp="```=="; break; }
+	tmp="```=";
 	break;
 
       case '(':
 	if(GOBBLE(')')) 
 	{
-	  tmp="`()";
+	  tmp="```()";
 	  break;
 	}
 	yyerror("Illegal ` identifier.");
-	tmp="";
+	tmp="``";
 	break;
 	
       case '-':
 	if(GOBBLE('>'))
 	{
-	  tmp="`->";
-	  if(GOBBLE('=')) tmp="`->=";
+	  tmp="```->";
+	  if(GOBBLE('=')) tmp="```->=";
 	}else{
-	  tmp="`-";
+	  tmp="```-";
 	}
 	break;
 
       case '[':
 	if(GOBBLE(']'))
 	{
-	  tmp="`[]";
-	  if(GOBBLE('=')) tmp="`[]=";
+	  tmp="```[]";
+	  if(GOBBLE('=')) tmp="```[]=";
 	  break;
 	}
 
       default:
 	yyerror("Illegal ` identifier.");
-	tmp="";
+	tmp="``";
 	break;
 
       }
 
       if(literal)
       {
-	yylval->str=buf;
+	yylval->str=tmp+offset;
       }else{
-	yylval->string=make_shared_string(tmp);
+	yylval->string=make_shared_string(tmp+offset);
       }
       return F_IDENTIFIER;
     }
diff --git a/src/modules/Gmp/mpz_glue.c b/src/modules/Gmp/mpz_glue.c
index ee6b6b863f..016884973d 100644
--- a/src/modules/Gmp/mpz_glue.c
+++ b/src/modules/Gmp/mpz_glue.c
@@ -4,7 +4,7 @@
 ||| See the files COPYING and DISCLAIMER for more information.
 \*/
 #include "global.h"
-RCSID("$Id: mpz_glue.c,v 1.22 1997/09/07 15:04:08 nisse Exp $");
+RCSID("$Id: mpz_glue.c,v 1.23 1997/10/11 06:49:19 hubbe Exp $");
 #include "gmp_machine.h"
 
 #if !defined(HAVE_LIBGMP)
@@ -398,6 +398,24 @@ static void mpzmod_sub(INT32 args)
   push_object(res);
 }
 
+static void mpzmod_rsub(INT32 args)
+{
+  INT32 e;
+  struct object *res;
+  MP_INT *a;
+  
+  if(args!=1)
+    error("Gmp.mpz->``- called with more or less than one argument.\n");
+  
+  a=get_mpz(sp-1,1);
+  
+  res = clone_object(mpzmod_program, 0);
+
+  mpz_sub(OBTOMPZ(res), a, THIS);
+  pop_n_elems(args);
+  push_object(res);
+}
+
 static void mpzmod_div(INT32 args)
 {
   INT32 e;
@@ -416,6 +434,24 @@ static void mpzmod_div(INT32 args)
   push_object(res);
 }
 
+static void mpzmod_rdiv(INT32 args)
+{
+  MP_INT *a;
+  struct object *res;
+  if(!mpz_sgn(THIS))
+    error("Division by zero.\n");
+
+  if(args!=1)
+    error("Gmp.mpz->``/() called with more than one argument.\n");
+
+  a=get_mpz(sp-1,1);
+  
+  res=clone_object(mpzmod_program,0);
+  mpz_fdiv_q(OBTOMPZ(res), a, THIS);
+  pop_n_elems(args);
+  push_object(res);
+}
+
 static void mpzmod_mod(INT32 args)
 {
   INT32 e;
@@ -434,6 +470,25 @@ static void mpzmod_mod(INT32 args)
   push_object(res);
 }
 
+static void mpzmod_rmod(INT32 args)
+{
+  MP_INT *a;
+  struct object *res;
+  if(!mpz_sgn(THIS))
+    error("Modulo by zero.\n");
+
+  if(args!=1)
+    error("Gmp.mpz->``%%() called with more than one argument.\n");
+
+  a=get_mpz(sp-1,1);
+  
+  res=clone_object(mpzmod_program,0);
+  mpz_fdiv_r(OBTOMPZ(res), a, THIS);
+  pop_n_elems(args);
+  push_object(res);
+}
+
+
 static void mpzmod_gcdext(INT32 args)
 {
   struct object *g, *s, *t;
@@ -631,9 +686,8 @@ static void mpzmod_lsh(INT32 args)
 {
   struct object *res;
   if (args != 1)
-    error("Wrong number of arguments to Gmp.mpz->rsh.\n");
-  push_string(int_type_string);
-  int_type_string->refs++;
+    error("Wrong number of arguments to Gmp.mpz->`<<.\n");
+  ref_push_string(int_type_string);
   f_cast();
   if(sp[-1].u.integer < 0)
     error("mpz->lsh on negative number.\n");
@@ -647,9 +701,8 @@ static void mpzmod_rsh(INT32 args)
 {
   struct object *res;
   if (args != 1)
-    error("Wrong number of arguments to Gmp.mpz->rsh.\n");
-  push_string(int_type_string);
-  int_type_string->refs++;
+    error("Wrong number of arguments to Gmp.mpz->`>>.\n");
+  ref_push_string(int_type_string);
   f_cast();
   if (sp[-1].u.integer < 0)
     error("Gmp.mpz->rsh: Shift count must be positive.\n");
@@ -659,6 +712,39 @@ static void mpzmod_rsh(INT32 args)
   push_object(res);
 }
 
+static void mpzmod_rlsh(INT32 args)
+{
+  struct object *res;
+  INT32 i;
+  if (args != 1)
+    error("Wrong number of arguments to Gmp.mpz->``<<.\n");
+  get_mpz(sp-1,1);
+  i=mpz_get_si(THIS);
+  if(i < 0)
+    error("mpz->``<< on negative number.\n");
+
+  res = clone_object(mpzmod_program, 0);
+  mpz_mul_2exp(OBTOMPZ(res), OBTOMPZ(sp[-1].u.object), i);
+  pop_n_elems(args);
+  push_object(res);
+}
+
+static void mpzmod_rrsh(INT32 args)
+{
+  struct object *res;
+  INT32 i;
+  if (args != 1)
+    error("Wrong number of arguments to Gmp.mpz->``>>.\n");
+  get_mpz(sp-1,1);
+  i=mpz_get_si(THIS);
+  if(i < 0)
+    error("mpz->``>> on negative number.\n");
+  res = clone_object(mpzmod_program, 0);
+  mpz_fdiv_q_2exp(OBTOMPZ(res), OBTOMPZ(sp[-1].u.object), i);
+  pop_n_elems(args);
+  push_object(res);
+}
+
 static void mpzmod_powm(INT32 args)
 {
   struct object *res;
@@ -759,17 +845,26 @@ void pike_module_init(void)
 #define MPZ_BINOP_TYPE ("function(" MPZ_ARG_TYPE "...:object)")
 
   add_function("`+",mpzmod_add,MPZ_BINOP_TYPE,0);
+  add_function("``+",mpzmod_add,MPZ_BINOP_TYPE,0);
   add_function("`-",mpzmod_sub,MPZ_BINOP_TYPE,0);
+  add_function("``-",mpzmod_rsub,MPZ_BINOP_TYPE,0);
   add_function("`*",mpzmod_mul,MPZ_BINOP_TYPE,0);
+  add_function("``*",mpzmod_mul,MPZ_BINOP_TYPE,0);
   add_function("`/",mpzmod_div,MPZ_BINOP_TYPE,0);
+  add_function("``/",mpzmod_rdiv,MPZ_BINOP_TYPE,0);
   add_function("`%",mpzmod_mod,MPZ_BINOP_TYPE,0);
+  add_function("``%",mpzmod_rmod,MPZ_BINOP_TYPE,0);
   add_function("`&",mpzmod_and,MPZ_BINOP_TYPE,0);
+  add_function("``&",mpzmod_and,MPZ_BINOP_TYPE,0);
   add_function("`|",mpzmod_or,MPZ_BINOP_TYPE,0);
+  add_function("``|",mpzmod_or,MPZ_BINOP_TYPE,0);
   add_function("`~",mpzmod_compl,"function(:object)",0);
 
 #define MPZ_SHIFT_TYPE "function(int|float|object:object)"
   add_function("`<<",mpzmod_lsh,MPZ_SHIFT_TYPE,0);
   add_function("`>>",mpzmod_rsh,MPZ_SHIFT_TYPE,0);
+  add_function("``<<",mpzmod_rlsh,MPZ_SHIFT_TYPE,0);
+  add_function("``>>",mpzmod_rrsh,MPZ_SHIFT_TYPE,0);
 
 #define MPZ_CMPOP_TYPE ("function(" MPZ_ARG_TYPE ":int)")
 
diff --git a/src/modules/Gmp/testsuite.in b/src/modules/Gmp/testsuite.in
index dd277e5bc5..6c8c34e3d3 100644
--- a/src/modules/Gmp/testsuite.in
+++ b/src/modules/Gmp/testsuite.in
@@ -15,18 +15,27 @@ cond( [[ master()->resolv("Gmp")->mpz ]],
   test_eq(Gmp.mpz("17") != "foo", 1)
   test_true(catch(Gmp.mpz("17") < "foo"))
 
-  test_eq(clone(Gmp.mpz,99)+1,100)
-  test_eq(clone(Gmp.mpz,100)*10,1000)
-  test_eq(clone(Gmp.mpz,"100")*10.0,1000)
-  test_eq(clone(Gmp.mpz,100.0)*clone(Gmp.mpz,3),300)
-  test_eq(clone(Gmp.mpz,100.0)/4,25)
-  test_eq(clone(Gmp.mpz,42)%10,2)
-  test_eq(clone(Gmp.mpz,10)<<1,20)
-  test_eq(clone(Gmp.mpz,10)>>1,5)
-  test_eq(clone(Gmp.mpz,66)+11,77)
-  test_eq(clone(Gmp.mpz,66)-11,55)
-  test_eq(clone(Gmp.mpz,17)&18,16)
-  test_eq(clone(Gmp.mpz,17)|7,23)
+  define([[test_binop]],[[
+    test_eq(Gmp.mpz($1) $2 $3, $4)
+    test_eq(Gmp.mpz($1) $2 $3.0, $4)
+    test_eq(Gmp.mpz($1) $2 Gmp.mpz($3), $4)
+    test_eq($1 $2 Gmp.mpz($3), $4)
+    test_eq($1.0 $2 Gmp.mpz($3), $4)
+    test_eq($1.0 $2 Gmp.mpz($3), $4)
+    test_eq($1 $2 $3,Gmp.mpz($4))
+  ]])
+
+  test_binop(99,+,1,100)
+  test_binop(100,*,10,1000)
+  test_binop(100,/,4,25)
+  test_binop(103,/,4,25)
+  test_binop(10,<<,1,20)
+  test_binop(10,>>,1,5)
+  test_binop(66,+,11,77)
+  test_binop(66,-,11,55)
+  test_binop(17,|,7,23)
+  test_binop(17,&,18,16)
+
   test_eq(-clone(Gmp.mpz,17),-17)
   test_eq((~clone(Gmp.mpz,17)) & 255,238)
   test_true(stringp((string)clone(Gmp.mpz,17)))
@@ -56,19 +65,25 @@ cond( [[ master()->resolv("Gmp")->mpz ]],
   mpz_test_type2(1,2)
   mpz_test_type2(-2,1)
 
-  mpz_test_true(catch(Gmp.mpz("abcd", 47)))
-  mpz_test_true(catch(Gmp.mpz(-17)->digits(256)))
-  mpz_test_eq(Gmp.mpz(4711)->size(2), 13)
-  mpz_test_true(catch(Gmp.mpz(17) + 18 + "19"))
-  mpz_test_true(catch(Gmp.mpz(17) - 18 - "19"))
-  mpz_test_true(catch(Gmp.mpz(17) / 0))
-  mpz_test_true(catch(Gmp.mpz(49) % 0))
-  mpz_test_eq(Gmp.mpz(0)->pow(0), 1)
-  mpz_test_true(equal(Gmp.mpz(13)->gcdext(19), ({1, 3, -2})))
-  mpz_test_eq(Gmp.mpz(17)->invert(4711), 2217)
-  mpz_test_true(catch(Gmp.mpz(4711)->invert(0)))
-  mpz_test_true(catch(Gmp.mpz(7)->invert(4711)))
-  mpz_test_true(catch(Gmp.mpz(2)->powm(47, 0)))
-  
+  test_true(catch(Gmp.mpz("abcd", 47)))
+  test_true(catch(Gmp.mpz(-17)->digits(256)))
+  test_eq(Gmp.mpz(4711)->size(2), 13)
+  test_true(catch(Gmp.mpz(17) + 18 + "19"))
+  test_true(catch(Gmp.mpz(17) - 18 - "19"))
+  test_true(catch(Gmp.mpz(17) / 0))
+  test_true(catch(Gmp.mpz(49) % 0))
+  test_eq(Gmp.mpz(0)->pow(0), 1)
+  test_true(equal(Gmp.mpz(13)->gcdext(19), ({1, 3, -2})))
+  test_eq(Gmp.mpz(17)->invert(4711), 2217)
+  test_true(catch(Gmp.mpz(4711)->invert(0)))
+  test_true(catch(Gmp.mpz(7)->invert(4711)))
+  test_true(catch(Gmp.mpz(2)->powm(47, 0)))
+  test_any([[object o=Gmp.mpz(1); o++; return o;]],2)
+  test_any([[object o=Gmp.mpz(1); return o++;]],1)
+  test_any([[object o=Gmp.mpz(1); return ++o;]],2)
+  test_any([[object o=Gmp.mpz(1); o++;o++;o++;o++;o++;o++;o++;o++;o++; return o]],10)
+  test_any([[object o=Gmp.mpz(2); o--; return o;]],1)
+  test_any([[object o=Gmp.mpz(2); return --o;]],1)
+  test_any([[object o=Gmp.mpz(2); return o--;]],2)
 ]]);
 
diff --git a/src/operators.c b/src/operators.c
index 4ee7cf33da..75f4dc8a4b 100644
--- a/src/operators.c
+++ b/src/operators.c
@@ -5,7 +5,7 @@
 \*/
 #include <math.h>
 #include "global.h"
-RCSID("$Id: operators.c,v 1.19 1997/10/10 20:19:58 hubbe Exp $");
+RCSID("$Id: operators.c,v 1.20 1997/10/11 06:48:24 hubbe Exp $");
 #include "interpret.h"
 #include "svalue.h"
 #include "multiset.h"
@@ -68,18 +68,55 @@ void f_add(INT32 args)
   switch(types)
   {
   default:
-    if(args)
+    if(!args)
     {
-      switch(sp[-args].type)
+      error("Too few arguments to `+()\n");
+    }else{
+      if(types & BIT_OBJECT)
       {
-      case T_OBJECT:
-	CALL_OPERATOR(LFUN_ADD,args);
-	return;
+	if(sp[-args].type == T_OBJECT &&
+	  sp[-args].u.object->prog &&
+	  sp[-args].u.object->prog->lfuns[LFUN_ADD] != -1)
+	{
+	  apply_lfun(sp[-args].u.object, LFUN_ADD, args-1);
+	  free_svalue(sp-2);
+	  sp[-2]=sp[-1];
+	  sp--;
+	  return;
+	}
+	for(e=1;e<args;e++)
+	{
+	  if(sp[e-args].type == T_OBJECT &&
+	     sp[e-args].u.object->prog &&
+	     sp[e-args].u.object->prog->lfuns[LFUN_RADD] != -1)
+	  {
+	    struct svalue *tmp=sp+e-args;
+	    check_stack(e);
+	    assign_svalues_no_free(sp, sp-args, e, -1);
+	    sp+=e;
+	    apply_lfun(tmp->u.object, LFUN_RADD, e);
+	    if(args - e > 2)
+	    {
+	      assign_svalue(tmp, sp-1);
+	      pop_stack();
+	      f_add(args - e);
+	      assign_svalue(sp-e-1,sp-1);
+	      pop_n_elems(e);
+	    }else{
+	      assign_svalue(sp-args-1,sp-1);
+	      pop_n_elems(args);
+	    }
+	    return;
+	  }
+	}
+      }
+    }
 
+    switch(sp[-args].type)
+    {
       case T_PROGRAM:
       case T_FUNCTION:
 	error("Bad argument 1 to summation\n");
-      }
     }
     error("Incompatible types to sum() or +\n");
     return; /* compiler hint */
@@ -335,27 +372,58 @@ static int generate_comparison(node *n)
 
 static int float_promote(void)
 {
-  if(sp[-2].type==T_INT)
+  if(sp[-2].type==T_INT && sp[-1].type==T_FLOAT)
   {
     sp[-2].u.float_number=(FLOAT_TYPE)sp[-2].u.integer;
     sp[-2].type=T_FLOAT;
+    return 1;
   }
-
-  if(sp[-1].type==T_INT)
+  else if(sp[-1].type==T_INT && sp[-2].type==T_FLOAT)
   {
     sp[-1].u.float_number=(FLOAT_TYPE)sp[-1].u.integer;
     sp[-1].type=T_FLOAT;
+    return 1;
+  }
+  return 0;
+}
+
+static int call_lfun(int left, int right)
+{
+  if(sp[-2].type == T_OBJECT &&
+     sp[-2].u.object->prog &&
+     sp[-2].u.object->prog->lfuns[left] != -1)
+  {
+    apply_lfun(sp[-2].u.object, left, 1);
+    free_svalue(sp-2);
+    sp[-2]=sp[-1];
+    sp--;
+    return 1;
   }
 
-  return sp[-2].type == sp[-1].type;
+  if(sp[-1].type == T_OBJECT &&
+     sp[-1].u.object->prog &&
+     sp[-1].u.object->prog->lfuns[right] != -1)
+  {
+    push_svalue(sp-2);
+    apply_lfun(sp[-2].u.object, right, 1);
+    free_svalue(sp-3);
+    sp[-3]=sp[-1];
+    sp--;
+    pop_stack();
+    return 1;
+  }
+
+  return 0;
 }
 
 void o_subtract(void)
 {
-  if (sp[-2].type != sp[-1].type &&
-      !float_promote() &&
-      sp[-2].type != T_OBJECT)
+  if (sp[-2].type != sp[-1].type && !float_promote())
+  {
+    if(call_lfun(LFUN_SUBTRACT, LFUN_RSUBTRACT))
+      return;
     error("Subtract on different types.\n");
+  }
 
   switch(sp[-2].type)
   {
@@ -451,9 +519,13 @@ static int generate_minus(node *n)
 
 void o_and(void)
 {
-  if(sp[-1].type != sp[-2].type &&
-     sp[-2].type != T_OBJECT)
+  if(sp[-1].type != sp[-2].type)
+  {
+    if(call_lfun(LFUN_AND, LFUN_RAND))
+      return;
+
     error("Bitwise and on different types.\n");
+  }
 
   switch(sp[-2].type)
   {
@@ -587,9 +659,13 @@ static int generate_and(node *n)
 
 void o_or(void)
 {
-  if(sp[-1].type != sp[-2].type &&
-     sp[-2].type != T_OBJECT)
+  if(sp[-1].type != sp[-2].type)
+  {
+    if(call_lfun(LFUN_OR, LFUN_ROR))
+      return;
+
     error("Bitwise or on different types.\n");
+  }
 
   switch(sp[-2].type)
   {
@@ -688,9 +764,12 @@ static int generate_or(node *n)
 
 void o_xor(void)
 {
-  if(sp[-1].type != sp[-2].type &&
-     sp[-2].type != T_OBJECT)
+  if(sp[-1].type != sp[-2].type)
+  {
+    if(call_lfun(LFUN_XOR, LFUN_RXOR))
+      return;
     error("Bitwise xor on different types.\n");
+  }
 
   switch(sp[-2].type)
   {
@@ -788,17 +867,15 @@ static int generate_xor(node *n)
 
 void o_lsh(void)
 {
-  if(sp[-2].type != T_INT)
+  if(sp[-1].type != T_INT || sp[-2].type != T_INT)
   {
-    if(sp[-2].type == T_OBJECT)
-    {
-      CALL_OPERATOR(LFUN_LSH,2);
+    if(call_lfun(LFUN_LSH, LFUN_RLSH))
       return;
-    }
 
-    error("Bad argument 1 to <<\n");
+    if(sp[-2].type != T_INT)
+      error("Bad argument 1 to <<\n");
+    error("Bad argument 2 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;
 }
@@ -823,16 +900,14 @@ static int generate_lsh(node *n)
 
 void o_rsh(void)
 {
-  if(sp[-2].type != T_INT)
+  if(sp[-2].type != T_INT || sp[-1].type != T_INT)
   {
-    if(sp[-2].type == T_OBJECT)
-    {
-      CALL_OPERATOR(LFUN_RSH,2);
+    if(call_lfun(LFUN_RSH, LFUN_RRSH))
       return;
-    }
-    error("Bad argument 1 to >>\n");
+    if(sp[-2].type != T_INT)
+      error("Bad argument 1 to >>\n");
+    error("Bad argument 2 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;
 }
@@ -905,11 +980,8 @@ void o_multiply(void)
     return;
 
   default:
-    if(sp[-2].type == T_OBJECT)
-    {
-      CALL_OPERATOR(LFUN_MULTIPLY,2);
+    if(call_lfun(LFUN_MULTIPLY, LFUN_RMULTIPLY))
       return;
-    }
 
     error("Bad arguments to multiply.\n");
   }
@@ -952,10 +1024,12 @@ static int generate_multiply(node *n)
 
 void o_divide(void)
 {
-  if(sp[-2].type!=sp[-1].type &&
-     !float_promote() &&
-     sp[-2].type != T_OBJECT)
+  if(sp[-2].type!=sp[-1].type && !float_promote())
+  {
+    if(call_lfun(LFUN_DIVIDE, LFUN_RDIVIDE))
+      return;
     error("Division on different types.\n");
+  }
 
   switch(sp[-2].type)
   {
@@ -1030,10 +1104,13 @@ static int generate_divide(node *n)
 
 void o_mod(void)
 {
-  if(sp[-2].type != sp[-1].type &&
-     !float_promote() &&
-     sp[-2].type != T_OBJECT)
+  if(sp[-2].type != sp[-1].type && !float_promote())
+  {
+    if(call_lfun(LFUN_MOD, LFUN_RMOD))
+      return;
+
     error("Modulo on different types.\n");
+  }
 
   switch(sp[-2].type)
   {
@@ -1357,11 +1434,11 @@ void init_operators(void)
   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,"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(multiset...:multiset)",OPT_TRY_OPTIMIZE,optimize_binary,generate_sum);
+  add_efun2("`+",f_add,"!function(!object...:mixed)&function(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(multiset...:multiset)",OPT_TRY_OPTIMIZE,optimize_binary,generate_sum);
 
-  add_efun2("`-",f_minus,"function(object,mixed...:mixed)|function(int:int)|function(float:float)|function(array,array:array)|function(mapping,mapping:mapping)|function(multiset,multiset:multiset)|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_minus,"!function(!object...:mixed)&function(mixed...:mixed)|function(int:int)|function(float:float)|function(array,array:array)|function(mapping,mapping:mapping)|function(multiset,multiset:multiset)|function(float|int,float:float)|function(float,int:float)|function(int,int:int)|function(string,string:string)",OPT_TRY_OPTIMIZE,0,generate_minus);
 
-#define LOG_TYPE "function(object,mixed...:mixed)|function(int...:int)|function(mapping...:mapping)|function(multiset...:multiset)|function(array...:array)|function(string...:string)"
+#define LOG_TYPE "function(mixed,object...:mixed)|function(object,mixed...:mixed)|function(int...:int)|function(mapping...:mapping)|function(multiset...:multiset)|function(array...:array)|function(string...:string)"
 
   add_efun2("`&",f_and,LOG_TYPE,OPT_TRY_OPTIMIZE,optimize_binary,generate_and);
 
@@ -1370,16 +1447,16 @@ void init_operators(void)
   add_efun2("`^",f_xor,LOG_TYPE,OPT_TRY_OPTIMIZE,optimize_binary,generate_xor);
 
 
-#define SHIFT_TYPE "function(object,mixed:mixed)|function(int,int:int)"
+#define SHIFT_TYPE "function(object,mixed:mixed)|function(mixed,object:mixed)|function(int,int:int)"
 
   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(array(array),array:array)|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_multiply,"!function(!object...:mixed)&function(mixed...:mixed)|function(array(array),array:array)|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(array,array:array(array))|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_divide,"function(mixed,object:mixed)|function(array,array:array(array))|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_mod,"function(mixed,object:mixed)|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)|function(string:string)",OPT_TRY_OPTIMIZE,0,generate_compl);
   add_efun2("sizeof", f_sizeof, "function(string|multiset|array|mapping|object:int)",0,0,generate_sizeof);
diff --git a/src/program.c b/src/program.c
index d985970bc0..416c531607 100644
--- a/src/program.c
+++ b/src/program.c
@@ -4,7 +4,7 @@
 ||| See the files COPYING and DISCLAIMER for more information.
 \*/
 #include "global.h"
-RCSID("$Id: program.c,v 1.42 1997/09/22 01:01:18 hubbe Exp $");
+RCSID("$Id: program.c,v 1.43 1997/10/11 06:48:25 hubbe Exp $");
 #include "program.h"
 #include "object.h"
 #include "dynamic_buffer.h"
@@ -78,6 +78,16 @@ char *lfun_names[] = {
   "_indices",
   "_values",
   "`()",
+  "``+",
+  "``-",
+  "``&",
+  "``|",
+  "``^",
+  "``<<",
+  "``>>",
+  "``*",
+  "``/",
+  "``%",
 };
 
 struct program *first_program = 0;
diff --git a/src/program.h b/src/program.h
index 243ccde548..7fd0708b2a 100644
--- a/src/program.h
+++ b/src/program.h
@@ -37,8 +37,18 @@
 #define LFUN__INDICES 25
 #define LFUN__VALUES 26
 #define LFUN_CALL 27
-
-#define NUM_LFUNS 28
+#define LFUN_RADD 28
+#define LFUN_RSUBTRACT 29
+#define LFUN_RAND 30
+#define LFUN_ROR 31
+#define LFUN_RXOR 32
+#define LFUN_RLSH 33
+#define LFUN_RRSH 34
+#define LFUN_RMULTIPLY 35
+#define LFUN_RDIVIDE 36
+#define LFUN_RMOD 37
+
+#define NUM_LFUNS 38
 
 extern char *lfun_names[];
 
-- 
GitLab