Tcl Source Code

Artifact [62500ef3bb]
Login

Artifact 62500ef3bb3571297944d55cfdea14e755359c6f:

Attachment "tip174.patch" to ticket [1578137fff] added by pspjuth 2006-12-07 21:22:06.
diff -ru ../tcl-20061206/generic/tclBasic.c ./generic/tclBasic.c
--- ../tcl-20061206/generic/tclBasic.c	2006-12-06 08:02:56.000000000 +0100
+++ ./generic/tclBasic.c	2006-12-07 14:32:13.000000000 +0100
@@ -271,30 +271,30 @@
  */
 
 static const CmdInfo mathOpCmds[] = {
-    { "::tcl::mathop::~",  TclInvertOpCmd, TclCompileInvertOpCmd, 1 },
-    { "::tcl::mathop::!",  TclNotOpCmd,	   TclCompileNotOpCmd,	  1 },
-    { "::tcl::mathop::+",  TclAddOpCmd,	   TclCompileAddOpCmd,	  1 },
-    { "::tcl::mathop::*",  TclMulOpCmd,	   TclCompileMulOpCmd,	  1 },
-    { "::tcl::mathop::&",  TclAndOpCmd,	   TclCompileAndOpCmd,	  1 },
-    { "::tcl::mathop::|",  TclOrOpCmd,	   TclCompileOrOpCmd,	  1 },
-    { "::tcl::mathop::^",  TclXorOpCmd,	   TclCompileXorOpCmd,	  1 },
-    { "::tcl::mathop::**", TclPowOpCmd,	   TclCompilePowOpCmd,	  1 },
-    { "::tcl::mathop::<<", TclLshiftOpCmd, TclCompileLshiftOpCmd, 1 },
-    { "::tcl::mathop::>>", TclRshiftOpCmd, TclCompileRshiftOpCmd, 1 },
-    { "::tcl::mathop::%",  TclModOpCmd,	   TclCompileModOpCmd,	  1 },
-    { "::tcl::mathop::!=", TclNeqOpCmd,	   TclCompileNeqOpCmd,	  1 },
-    { "::tcl::mathop::ne", TclStrneqOpCmd, TclCompileStrneqOpCmd, 1 },
-    { "::tcl::mathop::in", TclInOpCmd,	   TclCompileInOpCmd,	  1 },
-    { "::tcl::mathop::ni", TclNiOpCmd,	   TclCompileNiOpCmd,	  1 },
-    { "::tcl::mathop::-",  TclMinusOpCmd,  TclCompileMinusOpCmd,  1 },
-    { "::tcl::mathop::/",  TclDivOpCmd,	   TclCompileDivOpCmd,	  1 },
-    { "::tcl::mathop::<",  TclLessOpCmd,   TclCompileLessOpCmd,	  1 },
-    { "::tcl::mathop::<=", TclLeqOpCmd,	   TclCompileLeqOpCmd,	  1 },
-    { "::tcl::mathop::>",  TclGreaterOpCmd,TclCompileGreaterOpCmd,1 },
-    { "::tcl::mathop::>=", TclGeqOpCmd,	   TclCompileGeqOpCmd,	  1 },
-    { "::tcl::mathop::==", TclEqOpCmd,	   TclCompileEqOpCmd,	  1 },
-    { "::tcl::mathop::eq", TclStreqOpCmd,  TclCompileStreqOpCmd,  1 },
-    { NULL,		   NULL,	   NULL,		  0 }
+    { "~",  TclInvertOpCmd,  TclCompileInvertOpCmd,   1 },
+    { "!",  TclNotOpCmd,     TclCompileNotOpCmd,      1 },
+    { "+",  TclAddOpCmd,     TclCompileAddOpCmd,      1 },
+    { "*",  TclMulOpCmd,     TclCompileMulOpCmd,      1 },
+    { "&",  TclAndOpCmd,     TclCompileAndOpCmd,      1 },
+    { "|",  TclOrOpCmd,	     TclCompileOrOpCmd,	      1 },
+    { "^",  TclXorOpCmd,     TclCompileXorOpCmd,      1 },
+    { "**", TclPowOpCmd,     TclCompilePowOpCmd,      1 },
+    { "<<", TclLshiftOpCmd,  TclCompileLshiftOpCmd,   1 },
+    { ">>", TclRshiftOpCmd,  TclCompileRshiftOpCmd,   1 },
+    { "%",  TclModOpCmd,     TclCompileModOpCmd,      1 },
+    { "!=", TclNeqOpCmd,     TclCompileNeqOpCmd,      1 },
+    { "ne", TclStrneqOpCmd,  TclCompileStrneqOpCmd,   1 },
+    { "in", TclInOpCmd,	     TclCompileInOpCmd,	      1 },
+    { "ni", TclNiOpCmd,	     TclCompileNiOpCmd,	      1 },
+    { "-",  TclMinusOpCmd,   TclCompileMinusOpCmd,    1 },
+    { "/",  TclDivOpCmd,     TclCompileDivOpCmd,      1 },
+    { "<",  TclLessOpCmd,    TclCompileLessOpCmd,     1 },
+    { "<=", TclLeqOpCmd,     TclCompileLeqOpCmd,      1 },
+    { ">",  TclGreaterOpCmd, TclCompileGreaterOpCmd,  1 },
+    { ">=", TclGeqOpCmd,     TclCompileGeqOpCmd,      1 },
+    { "==", TclEqOpCmd,	     TclCompileEqOpCmd,	      1 },
+    { "eq", TclStreqOpCmd,   TclCompileStreqOpCmd,    1 },
+    { NULL, NULL,	     NULL,		      0 }
 };
 
 /*
@@ -324,7 +324,7 @@
     const BuiltinFuncDef *builtinFuncPtr;
     const CmdInfo *cmdInfoPtr;
     const CmdInfo2 *cmdInfo2Ptr;
-    Tcl_Namespace *mathfuncNSPtr;
+    Tcl_Namespace *mathfuncNSPtr, *mathopNSPtr;
     union {
 	char c[sizeof(short)];
 	short s;
@@ -626,17 +626,22 @@
      * Register the mathematical "operator" commands. [TIP #174]
      */
 
-    if (Tcl_CreateNamespace(interp, "::tcl::mathop", NULL, NULL) == NULL) {
+    mathopNSPtr = Tcl_CreateNamespace(interp, "::tcl::mathop", NULL, NULL);
+#define MATH_OP_PREFIX_LEN 15 /* == strlen("::tcl::mathop::") */
+    if (mathopNSPtr == NULL) {
 	Tcl_Panic("can't create math operator namespace");
     }
+    strcpy(mathFuncName, "::tcl::mathop::");
     for (cmdInfoPtr=mathOpCmds ; cmdInfoPtr->name!=NULL ; cmdInfoPtr++) {
-	cmdPtr = (Command *) Tcl_CreateObjCommand(interp, cmdInfoPtr->name,
+	strcpy(mathFuncName + MATH_OP_PREFIX_LEN, cmdInfoPtr->name);
+	cmdPtr = (Command *) Tcl_CreateObjCommand(interp, mathFuncName,
 		cmdInfoPtr->objProc, NULL, NULL);
 	if (cmdPtr == NULL) {
 	    Tcl_Panic("failed to create math operator %s", cmdInfoPtr->name);
 	} else if (cmdInfoPtr->compileProc != NULL) {
 	    cmdPtr->compileProc = cmdInfoPtr->compileProc;
 	}
+	Tcl_Export(interp, mathopNSPtr, cmdInfoPtr->name, 0);
     }
 
     /*
diff -ru ../tcl-20061206/generic/tclCmdMZ.c ./generic/tclCmdMZ.c
--- ../tcl-20061206/generic/tclCmdMZ.c	2006-11-29 08:02:49.000000000 +0100
+++ ./generic/tclCmdMZ.c	2006-12-07 14:32:58.000000000 +0100
@@ -1166,9 +1166,7 @@
 	 * INST_EQ/INST_NEQ/INST_LT/...).
 	 */
 
-	int i, match, length, nocase = 0, reqlength = -1;
-	typedef int (*strCmpFn_t)(const char *, const char *, unsigned int);
-	strCmpFn_t strCmpFn;
+	int i, match, nocase = 0, reqlength = -1;
 
 	if (objc < 4 || objc > 7) {
 	str_cmp_args:
@@ -1205,87 +1203,13 @@
 
 	objv += objc-2;
 
-	if ((reqlength == 0) || (objv[0] == objv[1])) {
-	    /*
-	     * Always match at 0 chars of if it is the same obj.
-	     */
-
-	    Tcl_SetObjResult(interp,
-		    Tcl_NewBooleanObj((enum options) index == STR_EQUAL));
-	    break;
-	} else if (!nocase && objv[0]->typePtr == &tclByteArrayType &&
-		objv[1]->typePtr == &tclByteArrayType) {
-	    /*
-	     * Use binary versions of comparisons since that won't cause undue
-	     * type conversions and it is much faster. Only do this if we're
-	     * case-sensitive (which is all that really makes sense with byte
-	     * arrays anyway, and we have no memcasecmp() for some
-	     * reason... :^)
-	     */
-
-	    string1 = (char *) Tcl_GetByteArrayFromObj(objv[0], &length1);
-	    string2 = (char *) Tcl_GetByteArrayFromObj(objv[1], &length2);
-	    strCmpFn = (strCmpFn_t) memcmp;
-	} else if ((objv[0]->typePtr == &tclStringType)
-		&& (objv[1]->typePtr == &tclStringType)) {
-	    /*
-	     * Do a unicode-specific comparison if both of the args are of
-	     * String type. In benchmark testing this proved the most
-	     * efficient check between the unicode and string comparison
-	     * operations.
-	     */
-
-	    string1 = (char *) Tcl_GetUnicodeFromObj(objv[0], &length1);
-	    string2 = (char *) Tcl_GetUnicodeFromObj(objv[1], &length2);
-	    strCmpFn = (strCmpFn_t)
-		    (nocase ? Tcl_UniCharNcasecmp : Tcl_UniCharNcmp);
-	} else {
-	    /*
-	     * As a catch-all we will work with UTF-8. We cannot use memcmp()
-	     * as that is unsafe with any string containing NULL (\xC0\x80 in
-	     * Tcl's utf rep). We can use the more efficient TclpUtfNcmp2 if
-	     * we are case-sensitive and no specific length was requested.
-	     */
-
-	    string1 = (char *) Tcl_GetStringFromObj(objv[0], &length1);
-	    string2 = (char *) Tcl_GetStringFromObj(objv[1], &length2);
-	    if ((reqlength < 0) && !nocase) {
-		strCmpFn = (strCmpFn_t) TclpUtfNcmp2;
-	    } else {
-		length1 = Tcl_NumUtfChars(string1, length1);
-		length2 = Tcl_NumUtfChars(string2, length2);
-		strCmpFn = (strCmpFn_t)
-			(nocase ? Tcl_UtfNcasecmp : Tcl_UtfNcmp);
-	    }
-	}
-
-	if (((enum options) index == STR_EQUAL)
-		&& (reqlength < 0) && (length1 != length2)) {
-	    match = 1; /* this will be reversed below */
-	} else {
-	    length = (length1 < length2) ? length1 : length2;
-	    if (reqlength > 0 && reqlength < length) {
-		length = reqlength;
-	    } else if (reqlength < 0) {
-		/*
-		 * The requested length is negative, so we ignore it by
-		 * setting it to length + 1 so we correct the match var.
-		 */
-
-		reqlength = length + 1;
-	    }
-
-	    match = strCmpFn(string1, string2, (unsigned) length);
-	    if ((match == 0) && (reqlength > length)) {
-		match = length1 - length2;
-	    }
-	}
+	match = TclStrCompare(objv[0], objv[1], nocase, reqlength,
+		(enum options) index == STR_EQUAL);
 
 	if ((enum options) index == STR_EQUAL) {
 	    Tcl_SetObjResult(interp, Tcl_NewBooleanObj(match ? 0 : 1));
 	} else {
-	    Tcl_SetObjResult(interp, Tcl_NewIntObj(
-		    (match > 0) ? 1 : (match < 0) ? -1 : 0));
+	    Tcl_SetObjResult(interp, Tcl_NewIntObj(match));
 	}
 	break;
     }
diff -ru ../tcl-20061206/generic/tclCompCmds.c ./generic/tclCompCmds.c
--- ../tcl-20061206/generic/tclCompCmds.c	2006-12-07 12:59:13.000000000 +0100
+++ ./generic/tclCompCmds.c	2006-12-07 14:29:01.000000000 +0100
@@ -138,6 +138,12 @@
 static int		CompileAssociativeBinaryOpCmd(Tcl_Interp *interp,
 			    Tcl_Parse *parsePtr, CONST char *identity,
 			    unsigned char instruction, CompileEnv *envPtr);
+static int		CompileCompOpCmd(Tcl_Interp *interp,
+			    Tcl_Parse *parsePtr, unsigned char instruction,
+			    CompileEnv *envPtr);
+static int		CompileStrictlyBinaryOpCmd(Tcl_Interp *interp,
+			    Tcl_Parse *parsePtr, unsigned char instruction,
+			    CompileEnv *envPtr);
 static int		CompileUnaryOpCmd(Tcl_Interp *interp,
 			    Tcl_Parse *parsePtr, unsigned char instruction,
 			    CompileEnv *envPtr);
@@ -4658,6 +4664,12 @@
     if (parsePtr->numWords == 1) {
 	PushLiteral(envPtr, identity, -1);
 	return TCL_OK;
+    } else if (parsePtr->numWords == 2) {
+	/*
+	 * Defer single argument to runtime for content checking.
+	 */
+
+	return TCL_ERROR;
     }
     for (words=1 ; words<parsePtr->numWords ; words++) {
 	tokenPtr = TokenAfter(tokenPtr);
@@ -4705,6 +4717,88 @@
 /*
  *----------------------------------------------------------------------
  *
+ * CompileCompOpCmd --
+ *
+ *	Helper to compile comparison math operators
+ *
+ * Results:
+ * 	Returns TCL_OK for a successful compile. Returns TCL_ERROR to defer
+ * 	evaluation to runtime.
+ *
+ * Side effects:
+ *	Instructions are added to envPtr to execute the command at
+ *	runtime.
+ *
+ *----------------------------------------------------------------------
+ */
+
+static int
+CompileCompOpCmd(
+    Tcl_Interp *interp,		/* Used for error reporting. */
+    Tcl_Parse *parsePtr,	/* Points to a parse structure for the command
+				 * created by Tcl_ParseCommand. */
+    unsigned char instruction,  /* BC instruction for operator */
+    CompileEnv *envPtr)		/* Holds resulting instructions. */
+{
+    Tcl_Token *tokenPtr;
+    DefineLineInformation; /* TIP #280 */
+
+    if (parsePtr->numWords < 3) {
+	/* 
+	 * Zero or one argument is always true.
+	 * Discard single argument.
+	 */
+
+        if (parsePtr->numWords == 2) {
+            tokenPtr = TokenAfter(parsePtr->tokenPtr);
+            CompileWord(envPtr, tokenPtr, interp, 1);
+            TclEmitOpcode(INST_POP, envPtr);
+        }
+        PushLiteral(envPtr, "1", 1);
+        return TCL_OK;
+    } else if (parsePtr->numWords == 3) {
+	/*
+	 * Two arguments is just like a binary operator.
+	 */
+
+	return CompileAssociativeBinaryOpCmd(interp, parsePtr,
+		NULL, instruction, envPtr);
+    } else if (envPtr->procPtr == NULL) {
+	/*
+	 * No local variable space, which is needed for >= 3 args!
+	 */
+
+	return TCL_ERROR;
+    } else {
+	int tmpIndex = TclFindCompiledLocal(NULL, 0, 1, VAR_SCALAR,
+		envPtr->procPtr);
+	int words;
+
+	tokenPtr = TokenAfter(parsePtr->tokenPtr);
+	CompileWord(envPtr, tokenPtr, interp, 1);
+	tokenPtr = TokenAfter(tokenPtr);
+	CompileWord(envPtr, tokenPtr, interp, 2);
+	TclEmitInstInt4(INST_STORE_SCALAR4, tmpIndex, envPtr);
+	TclEmitOpcode(instruction, envPtr);
+	for (words=3 ; words<parsePtr->numWords ;) {
+	    TclEmitInstInt4(INST_LOAD_SCALAR4, tmpIndex, envPtr);
+	    tokenPtr = TokenAfter(tokenPtr);
+	    CompileWord(envPtr, tokenPtr, interp, words);
+	    if (++words < parsePtr->numWords) {
+		TclEmitInstInt4(INST_STORE_SCALAR4, tmpIndex, envPtr);
+	    }
+	    TclEmitOpcode(instruction, envPtr);
+	}
+	for (; words>3 ; words--) {
+	    TclEmitOpcode(INST_BITAND, envPtr);
+	}
+    }
+    return TCL_OK;
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
  * TclCompile*OpCmd --
  *
  *	Procedures called to compile the corresponding
@@ -4823,8 +4917,6 @@
  * in reverse order and apply a different sequence of instructions.
  * For N arguments, we apply N-2 INST_ADDs, then one INST_SUB.
  * Note that this does the right thing for N=2, a single INST_SUB.
- * When N=1, we can add a phony leading "0" argument and get the
- * right result from the same algorithm as well.
  */
 
 int
@@ -4841,7 +4933,10 @@
 	return TCL_ERROR;
     }
     if (parsePtr->numWords == 2) {
-	PushLiteral(envPtr, "0", -1);
+	tokenPtr = TokenAfter(tokenPtr);
+	CompileWord(envPtr, tokenPtr, interp, 1);
+	TclEmitOpcode(INST_UMINUS, envPtr);
+	return TCL_OK;
     }
     for (words=1 ; words<parsePtr->numWords ; words++) {
 	tokenPtr = TokenAfter(tokenPtr);
@@ -4875,6 +4970,12 @@
 	CompileWord(envPtr, tokenPtr, interp,1);
 	TclEmitOpcode(INST_DIV, envPtr);
 	return TCL_OK;
+    } else if (parsePtr->numWords > 3) {
+	/*
+	 * Defer more than two args to runtime to get correct behaviour.
+	 */
+
+	return TCL_ERROR;
     }
     tokenPtr = TokenAfter(parsePtr->tokenPtr);
     CompileWord(envPtr, tokenPtr, interp,1);
@@ -4956,48 +5057,7 @@
     Tcl_Parse *parsePtr,
     CompileEnv *envPtr)
 {
-    Tcl_Token *tokenPtr;
-    DefineLineInformation; /* TIP #280 */
-
-    if (parsePtr->numWords < 3) {
-	PushLiteral(envPtr, "1", 1);
-    } else if (parsePtr->numWords == 3) {
-	tokenPtr = TokenAfter(parsePtr->tokenPtr);
-	CompileWord(envPtr, tokenPtr, interp,1);
-	tokenPtr = TokenAfter(tokenPtr);
-	CompileWord(envPtr, tokenPtr, interp,2);
-	TclEmitOpcode(INST_LT, envPtr);
-    } else if (envPtr->procPtr == NULL) {
-	/*
-	 * No local variable space!
-	 */
-
-	return TCL_ERROR;
-    } else {
-	int tmpIndex = TclFindCompiledLocal(NULL, 0, 1, VAR_SCALAR,
-		envPtr->procPtr);
-	int words;
-
-	tokenPtr = TokenAfter(parsePtr->tokenPtr);
-	CompileWord(envPtr, tokenPtr, interp,1);
-	tokenPtr = TokenAfter(tokenPtr);
-	CompileWord(envPtr, tokenPtr, interp,2);
-	TclEmitInstInt4(INST_STORE_SCALAR4, tmpIndex, envPtr);
-	TclEmitOpcode(INST_LT, envPtr);
-	for (words=3 ; words<parsePtr->numWords ;) {
-	    TclEmitInstInt4(INST_LOAD_SCALAR4, tmpIndex, envPtr);
-	    tokenPtr = TokenAfter(tokenPtr);
-	    CompileWord(envPtr, tokenPtr, interp, words);
-	    if (++words < parsePtr->numWords) {
-		TclEmitInstInt4(INST_STORE_SCALAR4, tmpIndex, envPtr);
-	    }
-	    TclEmitOpcode(INST_LT, envPtr);
-	}
-	for (; words>3 ; words--) {
-	    TclEmitOpcode(INST_BITAND, envPtr);
-	}
-    }
-    return TCL_OK;
+    return CompileCompOpCmd(interp, parsePtr, INST_LT, envPtr);
 }
 
 int
@@ -5006,48 +5066,7 @@
     Tcl_Parse *parsePtr,
     CompileEnv *envPtr)
 {
-    Tcl_Token *tokenPtr;
-    DefineLineInformation; /* TIP #280 */
-
-    if (parsePtr->numWords < 3) {
-	PushLiteral(envPtr, "1", 1);
-    } else if (parsePtr->numWords == 3) {
-	tokenPtr = TokenAfter(parsePtr->tokenPtr);
-	CompileWord(envPtr, tokenPtr, interp,1);
-	tokenPtr = TokenAfter(tokenPtr);
-	CompileWord(envPtr, tokenPtr, interp,2);
-	TclEmitOpcode(INST_LE, envPtr);
-    } else if (envPtr->procPtr == NULL) {
-	/*
-	 * No local variable space!
-	 */
-
-	return TCL_ERROR;
-    } else {
-	int tmpIndex = TclFindCompiledLocal(NULL, 0, 1, VAR_SCALAR,
-		envPtr->procPtr);
-	int words;
-
-	tokenPtr = TokenAfter(parsePtr->tokenPtr);
-	CompileWord(envPtr, tokenPtr, interp,1);
-	tokenPtr = TokenAfter(tokenPtr);
-	CompileWord(envPtr, tokenPtr, interp,2);
-	TclEmitInstInt4(INST_STORE_SCALAR4, tmpIndex, envPtr);
-	TclEmitOpcode(INST_LE, envPtr);
-	for (words=3 ; words<parsePtr->numWords ;) {
-	    TclEmitInstInt4(INST_LOAD_SCALAR4, tmpIndex, envPtr);
-	    tokenPtr = TokenAfter(tokenPtr);
-	    CompileWord(envPtr, tokenPtr, interp,words);
-	    if (++words < parsePtr->numWords) {
-		TclEmitInstInt4(INST_STORE_SCALAR4, tmpIndex, envPtr);
-	    }
-	    TclEmitOpcode(INST_LE, envPtr);
-	}
-	for (; words>3 ; words--) {
-	    TclEmitOpcode(INST_BITAND, envPtr);
-	}
-    }
-    return TCL_OK;
+    return CompileCompOpCmd(interp, parsePtr, INST_LE, envPtr);
 }
 
 int
@@ -5056,48 +5075,7 @@
     Tcl_Parse *parsePtr,
     CompileEnv *envPtr)
 {
-    Tcl_Token *tokenPtr;
-    DefineLineInformation; /* TIP #280 */
-
-    if (parsePtr->numWords < 3) {
-	PushLiteral(envPtr, "1", 1);
-    } else if (parsePtr->numWords == 3) {
-	tokenPtr = TokenAfter(parsePtr->tokenPtr);
-	CompileWord(envPtr, tokenPtr, interp,1);
-	tokenPtr = TokenAfter(tokenPtr);
-	CompileWord(envPtr, tokenPtr, interp,2);
-	TclEmitOpcode(INST_GT, envPtr);
-    } else if (envPtr->procPtr == NULL) {
-	/*
-	 * No local variable space!
-	 */
-
-	return TCL_ERROR;
-    } else {
-	int tmpIndex = TclFindCompiledLocal(NULL, 0, 1, VAR_SCALAR,
-		envPtr->procPtr);
-	int words;
-
-	tokenPtr = TokenAfter(parsePtr->tokenPtr);
-	CompileWord(envPtr, tokenPtr, interp,1);
-	tokenPtr = TokenAfter(tokenPtr);
-	CompileWord(envPtr, tokenPtr, interp,2);
-	TclEmitInstInt4(INST_STORE_SCALAR4, tmpIndex, envPtr);
-	TclEmitOpcode(INST_GT, envPtr);
-	for (words=3 ; words<parsePtr->numWords ;) {
-	    TclEmitInstInt4(INST_LOAD_SCALAR4, tmpIndex, envPtr);
-	    tokenPtr = TokenAfter(tokenPtr);
-	    CompileWord(envPtr, tokenPtr, interp,words);
-	    if (++words < parsePtr->numWords) {
-		TclEmitInstInt4(INST_STORE_SCALAR4, tmpIndex, envPtr);
-	    }
-	    TclEmitOpcode(INST_GT, envPtr);
-	}
-	for (; words>3 ; words--) {
-	    TclEmitOpcode(INST_BITAND, envPtr);
-	}
-    }
-    return TCL_OK;
+    return CompileCompOpCmd(interp, parsePtr, INST_GT, envPtr);
 }
 
 int
@@ -5106,48 +5084,7 @@
     Tcl_Parse *parsePtr,
     CompileEnv *envPtr)
 {
-    Tcl_Token *tokenPtr;
-    DefineLineInformation; /* TIP #280 */
-
-    if (parsePtr->numWords < 3) {
-	PushLiteral(envPtr, "1", 1);
-    } else if (parsePtr->numWords == 3) {
-	tokenPtr = TokenAfter(parsePtr->tokenPtr);
-	CompileWord(envPtr, tokenPtr, interp,1);
-	tokenPtr = TokenAfter(tokenPtr);
-	CompileWord(envPtr, tokenPtr, interp,2);
-	TclEmitOpcode(INST_GE, envPtr);
-    } else if (envPtr->procPtr == NULL) {
-	/*
-	 * No local variable space!
-	 */
-
-	return TCL_ERROR;
-    } else {
-	int tmpIndex = TclFindCompiledLocal(NULL, 0, 1, VAR_SCALAR,
-		envPtr->procPtr);
-	int words;
-
-	tokenPtr = TokenAfter(parsePtr->tokenPtr);
-	CompileWord(envPtr, tokenPtr, interp,1);
-	tokenPtr = TokenAfter(tokenPtr);
-	CompileWord(envPtr, tokenPtr, interp,2);
-	TclEmitInstInt4(INST_STORE_SCALAR4, tmpIndex, envPtr);
-	TclEmitOpcode(INST_GE, envPtr);
-	for (words=3 ; words<parsePtr->numWords ;) {
-	    TclEmitInstInt4(INST_LOAD_SCALAR4, tmpIndex, envPtr);
-	    tokenPtr = TokenAfter(tokenPtr);
-	    CompileWord(envPtr, tokenPtr, interp, words);
-	    if (++words < parsePtr->numWords) {
-		TclEmitInstInt4(INST_STORE_SCALAR4, tmpIndex, envPtr);
-	    }
-	    TclEmitOpcode(INST_GE, envPtr);
-	}
-	for (; words>3 ; words--) {
-	    TclEmitOpcode(INST_BITAND, envPtr);
-	}
-    }
-    return TCL_OK;
+    return CompileCompOpCmd(interp, parsePtr, INST_GE, envPtr);
 }
 
 int
@@ -5156,48 +5093,7 @@
     Tcl_Parse *parsePtr,
     CompileEnv *envPtr)
 {
-    Tcl_Token *tokenPtr;
-    DefineLineInformation; /* TIP #280 */
-
-    if (parsePtr->numWords < 3) {
-	PushLiteral(envPtr, "1", 1);
-    } else if (parsePtr->numWords == 3) {
-	tokenPtr = TokenAfter(parsePtr->tokenPtr);
-	CompileWord(envPtr, tokenPtr, interp,1);
-	tokenPtr = TokenAfter(tokenPtr);
-	CompileWord(envPtr, tokenPtr, interp,2);
-	TclEmitOpcode(INST_EQ, envPtr);
-    } else if (envPtr->procPtr == NULL) {
-	/*
-	 * No local variable space!
-	 */
-
-	return TCL_ERROR;
-    } else {
-	int tmpIndex = TclFindCompiledLocal(NULL, 0, 1, VAR_SCALAR,
-		envPtr->procPtr);
-	int words;
-
-	tokenPtr = TokenAfter(parsePtr->tokenPtr);
-	CompileWord(envPtr, tokenPtr, interp,1);
-	tokenPtr = TokenAfter(tokenPtr);
-	CompileWord(envPtr, tokenPtr, interp,2);
-	TclEmitInstInt4(INST_STORE_SCALAR4, tmpIndex, envPtr);
-	TclEmitOpcode(INST_EQ, envPtr);
-	for (words=3 ; words<parsePtr->numWords ;) {
-	    TclEmitInstInt4(INST_LOAD_SCALAR4, tmpIndex, envPtr);
-	    tokenPtr = TokenAfter(tokenPtr);
-	    CompileWord(envPtr, tokenPtr, interp, words);
-	    if (++words < parsePtr->numWords) {
-		TclEmitInstInt4(INST_STORE_SCALAR4, tmpIndex, envPtr);
-	    }
-	    TclEmitOpcode(INST_EQ, envPtr);
-	}
-	for (; words>3 ; words--) {
-	    TclEmitOpcode(INST_BITAND, envPtr);
-	}
-    }
-    return TCL_OK;
+    return CompileCompOpCmd(interp, parsePtr, INST_EQ, envPtr);
 }
 
 int
@@ -5206,48 +5102,7 @@
     Tcl_Parse *parsePtr,
     CompileEnv *envPtr)
 {
-    Tcl_Token *tokenPtr;
-    DefineLineInformation; /* TIP #280 */
-
-    if (parsePtr->numWords < 3) {
-	PushLiteral(envPtr, "1", 1);
-    } else if (parsePtr->numWords == 3) {
-	tokenPtr = TokenAfter(parsePtr->tokenPtr);
-	CompileWord(envPtr, tokenPtr, interp,1);
-	tokenPtr = TokenAfter(tokenPtr);
-	CompileWord(envPtr, tokenPtr, interp,2);
-	TclEmitOpcode(INST_STR_EQ, envPtr);
-    } else if (envPtr->procPtr == NULL) {
-	/*
-	 * No local variable space!
-	 */
-
-	return TCL_ERROR;
-    } else {
-	int tmpIndex = TclFindCompiledLocal(NULL, 0, 1, VAR_SCALAR,
-		envPtr->procPtr);
-	int words;
-
-	tokenPtr = TokenAfter(parsePtr->tokenPtr);
-	CompileWord(envPtr, tokenPtr, interp,1);
-	tokenPtr = TokenAfter(tokenPtr);
-	CompileWord(envPtr, tokenPtr, interp,2);
-	TclEmitInstInt4(INST_STORE_SCALAR4, tmpIndex, envPtr);
-	TclEmitOpcode(INST_STR_EQ, envPtr);
-	for (words=3 ; words<parsePtr->numWords ;) {
-	    TclEmitInstInt4(INST_LOAD_SCALAR4, tmpIndex, envPtr);
-	    tokenPtr = TokenAfter(tokenPtr);
-	    CompileWord(envPtr, tokenPtr, interp, words);
-	    if (++words < parsePtr->numWords) {
-		TclEmitInstInt4(INST_STORE_SCALAR4, tmpIndex, envPtr);
-	    }
-	    TclEmitOpcode(INST_STR_EQ, envPtr);
-	}
-	for (; words>3 ; words--) {
-	    TclEmitOpcode(INST_BITAND, envPtr);
-	}
-    }
-    return TCL_OK;
+    return CompileCompOpCmd(interp, parsePtr, INST_STR_EQ, envPtr);
 }
 
 /*
diff -ru ../tcl-20061206/generic/tclExecute.c ./generic/tclExecute.c
--- ../tcl-20061206/generic/tclExecute.c	2006-12-02 08:03:11.000000000 +0100
+++ ./generic/tclExecute.c	2006-12-07 13:26:44.000000000 +0100
@@ -3145,36 +3145,10 @@
 	value2Ptr = *tosPtr;
 	valuePtr = *(tosPtr - 1);
 
-	if (valuePtr == value2Ptr) {
-	    /*
-	     * On the off-chance that the objects are the same, we don't
-	     * really have to think hard about equality.
-	     */
-
-	    iResult = (*pc == INST_STR_EQ);
-	} else {
-	    char *s1, *s2;
-	    int s1len, s2len;
-
-	    s1 = Tcl_GetStringFromObj(valuePtr, &s1len);
-	    s2 = Tcl_GetStringFromObj(value2Ptr, &s2len);
-	    if (s1len == s2len) {
-		/*
-		 * We only need to check (in)equality when we have equal
-		 * length strings.
-		 */
-
-		if (*pc == INST_STR_NEQ) {
-		    iResult = (strcmp(s1, s2) != 0);
-		} else {
-		    /* INST_STR_EQ */
-		    iResult = (strcmp(s1, s2) == 0);
-		}
-	    } else {
-		iResult = (*pc == INST_STR_NEQ);
-	    }
+	iResult = TclStrCompare(valuePtr, value2Ptr, 0, -1, 1);
+	if (*pc == INST_STR_EQ) {
+	    iResult = !iResult;
 	}
-
 	TRACE(("%.20s %.20s => %d\n", O2S(valuePtr), O2S(value2Ptr), iResult));
 
 	/*
@@ -3203,69 +3177,14 @@
 	 * String compare
 	 */
 
-	CONST char *s1, *s2;
-	int s1len, s2len, iResult;
+	int iResult;
 	Tcl_Obj *valuePtr, *value2Ptr;
 
     stringCompare:
 	value2Ptr = *tosPtr;
 	valuePtr = *(tosPtr - 1);
 
-	/*
-	 * The comparison function should compare up to the minimum byte
-	 * length only.
-	 */
-
-	if (valuePtr == value2Ptr) {
-	    /*
-	     * In the pure equality case, set lengths too for the checks below
-	     * (or we could goto beyond it).
-	     */
-
-	    iResult = s1len = s2len = 0;
-	} else if ((valuePtr->typePtr == &tclByteArrayType)
-		&& (value2Ptr->typePtr == &tclByteArrayType)) {
-	    s1 = (char *) Tcl_GetByteArrayFromObj(valuePtr, &s1len);
-	    s2 = (char *) Tcl_GetByteArrayFromObj(value2Ptr, &s2len);
-	    iResult = memcmp(s1, s2,
-		    (size_t) ((s1len < s2len) ? s1len : s2len));
-	} else if (((valuePtr->typePtr == &tclStringType)
-		&& (value2Ptr->typePtr == &tclStringType))) {
-	    /*
-	     * Do a unicode-specific comparison if both of the args are of
-	     * String type. If the char length == byte length, we can do a
-	     * memcmp. In benchmark testing this proved the most efficient
-	     * check between the unicode and string comparison operations.
-	     */
-
-	    s1len = Tcl_GetCharLength(valuePtr);
-	    s2len = Tcl_GetCharLength(value2Ptr);
-	    if ((s1len == valuePtr->length) && (s2len == value2Ptr->length)) {
-		iResult = memcmp(valuePtr->bytes, value2Ptr->bytes,
-			(unsigned) ((s1len < s2len) ? s1len : s2len));
-	    } else {
-		iResult = TclUniCharNcmp(Tcl_GetUnicode(valuePtr),
-			Tcl_GetUnicode(value2Ptr),
-			(unsigned) ((s1len < s2len) ? s1len : s2len));
-	    }
-	} else {
-	    /*
-	     * We can't do a simple memcmp in order to handle the special Tcl
-	     * \xC0\x80 null encoding for utf-8.
-	     */
-	    s1 = Tcl_GetStringFromObj(valuePtr, &s1len);
-	    s2 = Tcl_GetStringFromObj(value2Ptr, &s2len);
-	    iResult = TclpUtfNcmp2(s1, s2,
-		    (size_t) ((s1len < s2len) ? s1len : s2len));
-	}
-
-	/*
-	 * Make sure only -1,0,1 is returned
-	 * TODO: consider peephole opt.
-	 */
-	if (iResult == 0) {
-	    iResult = s1len - s2len;
-	}
+	iResult = TclStrCompare(valuePtr, value2Ptr, 0, -1, 0);
 
 	if (*pc != INST_STR_CMP) {
 	    /* Take care of the opcodes that goto'ed into here */
@@ -3942,7 +3861,12 @@
 
 	if (*pc == INST_LSHIFT) {
 	    /* Large left shifts create integer overflow */
-	    result = Tcl_GetIntFromObj(NULL, value2Ptr, &shift);
+	    if ((type2 != TCL_NUMBER_LONG) ||
+		    (*((const long *)ptr2) > (long) INT_MAX)) {
+		result = TCL_ERROR;
+	    } else {
+		result = Tcl_GetIntFromObj(NULL, value2Ptr, &shift);
+	    }
 	    if (result != TCL_OK) {
 		/*
 		 * Technically, we could hold the value (1 << (INT_MAX+1)) in
@@ -4117,115 +4041,13 @@
 
 	if ((type1 == TCL_NUMBER_BIG) || (type2 == TCL_NUMBER_BIG)) {
 	    mp_int big1, big2, bigResult;
-	    mp_int *First, *Second;
-	    int numPos;
 
 	    Tcl_TakeBignumFromObj(NULL, valuePtr, &big1);
 	    Tcl_TakeBignumFromObj(NULL, value2Ptr, &big2);
 
-	    /*
-	     * Count how many positive arguments we have. If only one of the
-	     * arguments is negative, store it in 'Second'.
-	     */
-
-	    if (mp_cmp_d(&big1, 0) != MP_LT) {
-		numPos = 1 + (mp_cmp_d(&big2, 0) != MP_LT);
-		First  = &big1;
-		Second = &big2;
-	    } else {
-		First  = &big2;
-		Second = &big1;
-		numPos = (mp_cmp_d(First, 0) != MP_LT);
-	    }
 	    mp_init(&bigResult);
 
-	    switch (*pc) {
-	    case INST_BITAND:
-		switch (numPos) {
-		case 2:
-		    /* Both arguments positive, base case */
-		    mp_and(First, Second, &bigResult);
-		    break;
-		case 1:
-		    /* First is positive; Second negative
-		     * P & N = P & ~~N = P&~(-N-1) = P & (P ^ (-N-1)) */
-		    mp_neg(Second, Second);
-		    mp_sub_d(Second, 1, Second);
-		    mp_xor(First, Second, &bigResult);
-		    mp_and(First, &bigResult, &bigResult);
-		    break;
-		case 0:
-		    /* Both arguments negative
-		     * a & b = ~ (~a | ~b) = -(-a-1|-b-1)-1 */
-		    mp_neg(First, First);
-		    mp_sub_d(First, 1, First);
-		    mp_neg(Second, Second);
-		    mp_sub_d(Second, 1, Second);
-		    mp_or(First, Second, &bigResult);
-		    mp_neg(&bigResult, &bigResult);
-		    mp_sub_d(&bigResult, 1, &bigResult);
-		    break;
-		}
-		break;
-
-	    case INST_BITOR:
-		switch (numPos) {
-		case 2:
-		    /* Both arguments positive, base case */
-		    mp_or(First, Second, &bigResult);
-		    break;
-		case 1:
-		    /* First is positive; Second negative
-		     * N|P = ~(~N&~P) = ~((-N-1)&~P) = -((-N-1)&((-N-1)^P))-1 */
-		    mp_neg(Second, Second);
-		    mp_sub_d(Second, 1, Second);
-		    mp_xor(First, Second, &bigResult);
-		    mp_and(Second, &bigResult, &bigResult);
-		    mp_neg(&bigResult, &bigResult);
-		    mp_sub_d(&bigResult, 1, &bigResult);
-		    break;
-		case 0:
-		    /* Both arguments negative
-		     * a | b = ~ (~a & ~b) = -(-a-1&-b-1)-1 */
-		    mp_neg(First, First);
-		    mp_sub_d(First, 1, First);
-		    mp_neg(Second, Second);
-		    mp_sub_d(Second, 1, Second);
-		    mp_and(First, Second, &bigResult);
-		    mp_neg(&bigResult, &bigResult);
-		    mp_sub_d(&bigResult, 1, &bigResult);
-		    break;
-		}
-		break;
-
-	    case INST_BITXOR:
-		switch (numPos) {
-		case 2:
-		    /* Both arguments positive, base case */
-		    mp_xor(First, Second, &bigResult);
-		    break;
-		case 1:
-		    /* First is positive; Second negative
-		     * P^N = ~(P^~N) = -(P^(-N-1))-1
-		     */
-		    mp_neg(Second, Second);
-		    mp_sub_d(Second, 1, Second);
-		    mp_xor(First, Second, &bigResult);
-		    mp_neg(&bigResult, &bigResult);
-		    mp_sub_d(&bigResult, 1, &bigResult);
-		    break;
-		case 0:
-		    /* Both arguments negative
-		     * a ^ b = (~a ^ ~b) = (-a-1^-b-1) */
-		    mp_neg(First, First);
-		    mp_sub_d(First, 1, First);
-		    mp_neg(Second, Second);
-		    mp_sub_d(Second, 1, Second);
-		    mp_xor(First, Second, &bigResult);
-		    break;
-		}
-		break;
-	    }
+            TclBitWiseBignumOp(*pc, &big1, &big2, &bigResult);
 
 	    mp_clear(&big1);
 	    mp_clear(&big2);
@@ -4786,6 +4608,7 @@
 	    if (type2 == TCL_NUMBER_BIG) {
 		Tcl_SetObjResult(interp,
 			Tcl_NewStringObj("exponent too large", -1));
+		result = TCL_ERROR;
 		goto checkForCatch;
 	    }
 	    /* TODO: Perform those computations that fit in native types */
@@ -4821,7 +4644,7 @@
 		{
 		    /* Must check for overflow */
 		    if (((w1 < 0) && (w2 > 0) && (wResult > 0))
-			    || ((w1 > 0) && (w2 < 0) && (wResult < 0))) {
+			    || ((w1 >= 0) && (w2 < 0) && (wResult < 0))) {
 			goto overflow;
 		    }
 		}
@@ -4906,6 +4729,7 @@
 			    Tcl_NewStringObj("exponent too large", -1));
 		    mp_clear(&big1);
 		    mp_clear(&big2);
+		    result = TCL_ERROR;
 		    goto checkForCatch;
 		}
 		mp_expt_d(&big1, big2.dp[0], &bigResult);
@@ -6368,6 +6192,169 @@
     Tcl_SetObjResult(interp, Tcl_ObjPrintf(
 	    "can't use %s as operand of \"%s\"", description, operator));
 }
+/*
+ *----------------------------------------------------------------------
+ *
+ * TclIllegalExprOperandType --
+ *
+ *	Exported version of IllegalExprOperandType.
+ *      Bytecode argument is provided by value instead of by pointer.
+ *
+ * Results:
+ *	None.
+ *
+ * Side effects:
+ *	An error message is appended to the interp result.
+ *
+ *----------------------------------------------------------------------
+ */
+
+void
+TclIllegalExprOperandType(
+    Tcl_Interp *interp,		/* Interpreter to which error information
+				 * pertains. */
+    unsigned char op,		/* The instruction where the illegal
+				 * type was found. */
+    Tcl_Obj *opndPtr)		/* Points to the operand holding the value
+				 * with the illegal type. */
+{
+    IllegalExprOperandType(interp, &op, opndPtr);
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * TclBitWiseBignumOp --
+ *
+ *	Perform a bitwise operation on bignums.
+ *
+ * Results:
+ *	Result of operation.
+ *
+ * Side effects:
+ *	None.
+ *
+ *----------------------------------------------------------------------
+ */
+
+void
+TclBitWiseBignumOp (
+    unsigned char op,
+    mp_int *big1,
+    mp_int *big2,
+    mp_int *result)
+{
+    mp_int bigResult;
+    mp_int *First, *Second;
+    int numPos;
+
+    /*
+     * Count how many positive arguments we have. If only one of the
+     * arguments is negative, store it in 'Second'.
+     */
+
+    if (mp_cmp_d(big1, 0) != MP_LT) {
+        numPos = 1 + (mp_cmp_d(big2, 0) != MP_LT);
+        First  = big1;
+        Second = big2;
+    } else {
+        First  = big2;
+        Second = big1;
+        numPos = (mp_cmp_d(First, 0) != MP_LT);
+    }
+    mp_init(&bigResult);
+
+    switch (op) {
+    case INST_BITAND:
+        switch (numPos) {
+        case 2:
+            /* Both arguments positive, base case */
+            mp_and(First, Second, &bigResult);
+            break;
+        case 1:
+            /* First is positive; Second negative
+             * P & N = P & ~~N = P&~(-N-1) = P & (P ^ (-N-1)) */
+            mp_neg(Second, Second);
+            mp_sub_d(Second, 1, Second);
+            mp_xor(First, Second, &bigResult);
+            mp_and(First, &bigResult, &bigResult);
+            break;
+        case 0:
+            /* Both arguments negative
+             * a & b = ~ (~a | ~b) = -(-a-1|-b-1)-1 */
+            mp_neg(First, First);
+            mp_sub_d(First, 1, First);
+            mp_neg(Second, Second);
+            mp_sub_d(Second, 1, Second);
+            mp_or(First, Second, &bigResult);
+            mp_neg(&bigResult, &bigResult);
+            mp_sub_d(&bigResult, 1, &bigResult);
+            break;
+        }
+        break;
+
+    case INST_BITOR:
+        switch (numPos) {
+        case 2:
+            /* Both arguments positive, base case */
+            mp_or(First, Second, &bigResult);
+            break;
+        case 1:
+            /* First is positive; Second negative
+             * N|P = ~(~N&~P) = ~((-N-1)&~P) = -((-N-1)&((-N-1)^P))-1 */
+            mp_neg(Second, Second);
+            mp_sub_d(Second, 1, Second);
+            mp_xor(First, Second, &bigResult);
+            mp_and(Second, &bigResult, &bigResult);
+            mp_neg(&bigResult, &bigResult);
+            mp_sub_d(&bigResult, 1, &bigResult);
+            break;
+        case 0:
+            /* Both arguments negative
+             * a | b = ~ (~a & ~b) = -(-a-1&-b-1)-1 */
+            mp_neg(First, First);
+            mp_sub_d(First, 1, First);
+            mp_neg(Second, Second);
+            mp_sub_d(Second, 1, Second);
+            mp_and(First, Second, &bigResult);
+            mp_neg(&bigResult, &bigResult);
+            mp_sub_d(&bigResult, 1, &bigResult);
+            break;
+        }
+        break;
+
+    case INST_BITXOR:
+        switch (numPos) {
+        case 2:
+            /* Both arguments positive, base case */
+            mp_xor(First, Second, &bigResult);
+            break;
+        case 1:
+            /* First is positive; Second negative
+             * P^N = ~(P^~N) = -(P^(-N-1))-1
+             */
+            mp_neg(Second, Second);
+            mp_sub_d(Second, 1, Second);
+            mp_xor(First, Second, &bigResult);
+            mp_neg(&bigResult, &bigResult);
+            mp_sub_d(&bigResult, 1, &bigResult);
+            break;
+        case 0:
+            /* Both arguments negative
+             * a ^ b = (~a ^ ~b) = (-a-1^-b-1) */
+            mp_neg(First, First);
+            mp_sub_d(First, 1, First);
+            mp_neg(Second, Second);
+            mp_sub_d(Second, 1, Second);
+            mp_xor(First, Second, &bigResult);
+            break;
+        }
+        break;
+    }
+
+    mp_exch(result, &bigResult);
+    mp_clear(&bigResult);
+}
 
 /*
  *----------------------------------------------------------------------
diff -ru ../tcl-20061206/generic/tclInt.h ./generic/tclInt.h
--- ../tcl-20061206/generic/tclInt.h	2006-12-02 08:03:13.000000000 +0100
+++ ./generic/tclInt.h	2006-12-05 13:21:35.000000000 +0100
@@ -2207,6 +2207,8 @@
 MODULE_SCOPE int	TclArraySet(Tcl_Interp *interp,
 			    Tcl_Obj *arrayNameObj, Tcl_Obj *arrayElemObj);
 MODULE_SCOPE double	TclBignumToDouble(mp_int *bignum);
+MODULE_SCOPE void	TclBitWiseBignumOp (unsigned char op, mp_int *big1,
+			    mp_int *big2, mp_int *result);
 MODULE_SCOPE double	TclCeil(mp_int *a);
 MODULE_SCOPE int	TclCheckBadOctal(Tcl_Interp *interp,CONST char *value);
 MODULE_SCOPE int	TclChanCreateObjCmd(ClientData clientData,
@@ -2272,6 +2274,8 @@
 MODULE_SCOPE int	TclGlob(Tcl_Interp *interp, char *pattern,
 			    Tcl_Obj *unquotedPrefix, int globFlags,
 			    Tcl_GlobTypeData *types);
+MODULE_SCOPE void	TclIllegalExprOperandType(Tcl_Interp *interp,
+			    unsigned char op, Tcl_Obj *opndPtr);
 MODULE_SCOPE int	TclIncrObj(Tcl_Interp *interp, Tcl_Obj *valuePtr,
 			    Tcl_Obj *incrPtr);
 MODULE_SCOPE Tcl_Obj *	TclIncrObjVar2(Tcl_Interp *interp, Tcl_Obj *part1Ptr,
@@ -2408,6 +2412,8 @@
 MODULE_SCOPE void	TclSignalExitThread(Tcl_ThreadId id, int result);
 MODULE_SCOPE int	TclSubstTokens(Tcl_Interp *interp, Tcl_Token *tokenPtr,
 			    int count, int *tokensLeftPtr, int line);
+MODULE_SCOPE int	TclStrCompare(Tcl_Obj *obj1Ptr,	Tcl_Obj *obj2Ptr,
+			    int nocase, int reqlength, int equal);
 MODULE_SCOPE void	TclTransferResult(Tcl_Interp *sourceInterp, int result,
 			    Tcl_Interp *targetInterp);
 MODULE_SCOPE Tcl_Obj *	TclpNativeToNormalized(ClientData clientData);
diff -ru ../tcl-20061206/generic/tclMathOp.c ./generic/tclMathOp.c
--- ../tcl-20061206/generic/tclMathOp.c	2006-12-02 08:03:13.000000000 +0100
+++ ./generic/tclMathOp.c	2006-12-06 16:36:53.000000000 +0100
@@ -50,9 +50,9 @@
  */
 
 static Tcl_Obj *	CombineIntFloat(Tcl_Interp *interp, Tcl_Obj *valuePtr,
-			    int opcode, Tcl_Obj *value2Ptr);
+			    unsigned char opcode, Tcl_Obj *value2Ptr);
 static Tcl_Obj *	CombineIntOnly(Tcl_Interp *interp, Tcl_Obj *valuePtr,
-			    int opcode, Tcl_Obj *value2Ptr);
+			    unsigned char opcode, Tcl_Obj *value2Ptr);
 static int		CompareNumbers(Tcl_Interp *interp, Tcl_Obj *numObj1,
 			    Tcl_Obj *numObj2, int *resultPtr);
 
@@ -80,22 +80,21 @@
 CombineIntFloat(
     Tcl_Interp *interp,		/* Place to write error messages. */
     Tcl_Obj *valuePtr,		/* First value to combine. */
-    int opcode,			/* Operation to use to combine the
+    unsigned char opcode,	/* Operation to use to combine the
 				 * values. Must be one of INST_ADD, INST_SUB,
 				 * INST_MULT, INST_DIV or INST_EXPON. */
     Tcl_Obj *value2Ptr)		/* Second value to combine. */
 {
     ClientData ptr1, ptr2;
     int type1, type2;
-    Tcl_Obj *errPtr;
 
     if ((TclGetNumberFromObj(NULL, valuePtr, &ptr1, &type1) != TCL_OK)
 #ifndef ACCEPT_NAN
 	    || (type1 == TCL_NUMBER_NAN)
 #endif
 	    ) {
-	errPtr = valuePtr;
-	goto illegalOperand;
+	TclIllegalExprOperandType(interp, opcode, valuePtr);
+	return NULL;
     }
 
 #ifdef ACCEPT_NAN
@@ -110,8 +109,8 @@
 	    || (type2 == TCL_NUMBER_NAN)
 #endif
 	    ) {
-	errPtr = value2Ptr;
-	goto illegalOperand;
+	TclIllegalExprOperandType(interp, opcode, value2Ptr);
+	return NULL;
     }
 
 #ifdef ACCEPT_NAN
@@ -331,7 +330,7 @@
 	    {
 		/* Must check for overflow */
 		if (((w1 < 0) && (w2 > 0) && (wResult > 0))
-			|| ((w1 > 0) && (w2 < 0) && (wResult < 0))) {
+			|| ((w1 >= 0) && (w2 < 0) && (wResult < 0))) {
 		    goto overflow;
 		}
 	    }
@@ -421,44 +420,6 @@
 	return valuePtr;
     }
 
-    {
-	const char *description, *operator;
-
-    illegalOperand:
-	switch (opcode) {
-	case INST_ADD:	 operator = "+";  break;
-	case INST_SUB:	 operator = "-";  break;
-	case INST_MULT:	 operator = "*";  break;
-	case INST_DIV:	 operator = "/";  break;
-	case INST_EXPON: operator = "**"; break;
-	default:
-	    operator = "???";
-	}
-
-	if (TclGetNumberFromObj(NULL, errPtr, &ptr1, &type1) != TCL_OK) {
-	    int numBytes;
-	    CONST char *bytes = Tcl_GetStringFromObj(errPtr, &numBytes);
-	    if (numBytes == 0) {
-		description = "empty string";
-	    } else if (TclCheckBadOctal(NULL, bytes)) {
-		description = "invalid octal number";
-	    } else {
-		description = "non-numeric string";
-	    }
-	} else if (type1 == TCL_NUMBER_NAN) {
-	    description = "non-numeric floating-point value";
-	} else if (type1 == TCL_NUMBER_DOUBLE) {
-	    description = "floating-point value";
-	} else {
-	    /* TODO: No caller needs this.  Eliminate? */
-	    description = "(big) integer";
-	}
-
-	Tcl_SetObjResult(interp, Tcl_ObjPrintf(
-		"can't use %s as operand of \"%s\"", description, operator));
-	return NULL;
-    }
-
   divideByZero:
     Tcl_SetObjResult(interp, Tcl_NewStringObj("divide by zero", -1));
     Tcl_SetErrorCode(interp, "ARITH", "DIVZERO", "divide by zero", NULL);
@@ -496,137 +457,34 @@
 CombineIntOnly(
     Tcl_Interp *interp,		/* Place to write error messages. */
     Tcl_Obj *valuePtr,		/* First value to combine. */
-    int opcode,			/* Operation to use to combine the
+    unsigned char opcode,	/* Operation to use to combine the
 				 * values. Must be one of INST_BITAND,
 				 * INST_BITOR or INST_BITXOR. */
     Tcl_Obj *value2Ptr)		/* Second value to combine. */
 {
     ClientData ptr1, ptr2;
     int type1, type2;
-    Tcl_Obj *errPtr;
 
     if ((TclGetNumberFromObj(NULL, valuePtr, &ptr1, &type1) != TCL_OK)
 	    || (type1 == TCL_NUMBER_NAN) || (type1 == TCL_NUMBER_DOUBLE)) {
-	errPtr = valuePtr;
-	goto illegalOperand;
+	TclIllegalExprOperandType(interp, opcode, valuePtr);
+	return NULL;
     }
     if ((TclGetNumberFromObj(NULL, value2Ptr, &ptr2, &type2) != TCL_OK)
 	    || (type2 == TCL_NUMBER_NAN) || (type2 == TCL_NUMBER_DOUBLE)) {
-	errPtr = value2Ptr;
-	goto illegalOperand;
+	TclIllegalExprOperandType(interp, opcode, value2Ptr);
+	return NULL;
     }
 
     if ((type1 == TCL_NUMBER_BIG) || (type2 == TCL_NUMBER_BIG)) {
 	mp_int big1, big2, bigResult;
-	mp_int *First, *Second;
-	int numPos;
-
 
 	Tcl_TakeBignumFromObj(NULL, valuePtr, &big1);
 	Tcl_TakeBignumFromObj(NULL, value2Ptr, &big2);
 
-	/*
-	 * Count how many positive arguments we have. If only one of the
-	 * arguments is negative, store it in 'Second'.
-	 */
-
-	if (mp_cmp_d(&big1, 0) != MP_LT) {
-	    numPos = 1 + (mp_cmp_d(&big2, 0) != MP_LT);
-	    First  = &big1;
-	    Second = &big2;
-	} else {
-	    First  = &big2;
-	    Second = &big1;
-	    numPos = (mp_cmp_d(First, 0) != MP_LT);
-	}
 	mp_init(&bigResult);
 
-	switch (opcode) {
-	case INST_BITAND:
-	    switch (numPos) {
-	    case 2:
-		/* Both arguments positive, base case */
-		mp_and(First, Second, &bigResult);
-		break;
-	    case 1:
-		/* First is positive; Second negative
-		 * P & N = P & ~~N = P&~(-N-1) = P & (P ^ (-N-1)) */
-		mp_neg(Second, Second);
-		mp_sub_d(Second, 1, Second);
-		mp_xor(First, Second, &bigResult);
-		mp_and(First, &bigResult, &bigResult);
-		break;
-	    case 0:
-		/* Both arguments negative
-		 * a & b = ~ (~a | ~b) = -(-a-1|-b-1)-1 */
-		mp_neg(First, First);
-		mp_sub_d(First, 1, First);
-		mp_neg(Second, Second);
-		mp_sub_d(Second, 1, Second);
-		mp_or(First, Second, &bigResult);
-		mp_neg(&bigResult, &bigResult);
-		mp_sub_d(&bigResult, 1, &bigResult);
-		break;
-	    }
-	    break;
-
-	case INST_BITOR:
-	    switch (numPos) {
-	    case 2:
-		/* Both arguments positive, base case */
-		mp_or(First, Second, &bigResult);
-		break;
-	    case 1:
-		/* First is positive; Second negative
-		 * N|P = ~(~N&~P) = ~((-N-1)&~P) = -((-N-1)&((-N-1)^P))-1 */
-		mp_neg(Second, Second);
-		mp_sub_d(Second, 1, Second);
-		mp_xor(First, Second, &bigResult);
-		mp_and(Second, &bigResult, &bigResult);
-		mp_neg(&bigResult, &bigResult);
-		mp_sub_d(&bigResult, 1, &bigResult);
-		break;
-	    case 0:
-		/* Both arguments negative
-		 * a | b = ~ (~a & ~b) = -(-a-1&-b-1)-1 */
-		mp_neg(First, First);
-		mp_sub_d(First, 1, First);
-		mp_neg(Second, Second);
-		mp_sub_d(Second, 1, Second);
-		mp_and(First, Second, &bigResult);
-		mp_neg(&bigResult, &bigResult);
-		mp_sub_d(&bigResult, 1, &bigResult);
-		break;
-	    }
-	    break;
-
-	case INST_BITXOR:
-	    switch (numPos) {
-	    case 2:
-		/* Both arguments positive, base case */
-		mp_xor(First, Second, &bigResult);
-		break;
-	    case 1:
-		/* First is positive; Second negative
-		 * P^N = ~(P^~N) = -(P^(-N-1))-1 */
-		mp_neg(Second, Second);
-		mp_sub_d(Second, 1, Second);
-		mp_xor(First, Second, &bigResult);
-		mp_neg(&bigResult, &bigResult);
-		mp_sub_d(&bigResult, 1, &bigResult);
-		break;
-	    case 0:
-		/* Both arguments negative
-		 * a ^ b = (~a ^ ~b) = (-a-1^-b-1) */
-		mp_neg(First, First);
-		mp_sub_d(First, 1, First);
-		mp_neg(Second, Second);
-		mp_sub_d(Second, 1, Second);
-		mp_xor(First, Second, &bigResult);
-		break;
-	    }
-	    break;
-	}
+	TclBitWiseBignumOp(opcode, &big1, &big2, &bigResult);
 
 	mp_clear(&big1);
 	mp_clear(&big2);
@@ -690,41 +548,7 @@
 	return valuePtr;
     }
 
-    {
-	const char *description, *operator;
-
-    illegalOperand:
-	switch (opcode) {
-	case INST_BITAND: operator = "&";  break;
-	case INST_BITOR:  operator = "|";  break;
-	case INST_BITXOR: operator = "^";  break;
-	default:
-	    operator = "???";
-	}
-
-	if (TclGetNumberFromObj(NULL, errPtr, &ptr1, &type1) != TCL_OK) {
-	    int numBytes;
-	    CONST char *bytes = Tcl_GetStringFromObj(errPtr, &numBytes);
-	    if (numBytes == 0) {
-		description = "empty string";
-	    } else if (TclCheckBadOctal(NULL, bytes)) {
-		description = "invalid octal number";
-	    } else {
-		description = "non-numeric string";
-	    }
-	} else if (type1 == TCL_NUMBER_NAN) {
-	    description = "non-numeric floating-point value";
-	} else if (type1 == TCL_NUMBER_DOUBLE) {
-	    description = "floating-point value";
-	} else {
-	    /* TODO: No caller needs this.  Eliminate? */
-	    description = "(big) integer";
-	}
-
-	Tcl_SetObjResult(interp, Tcl_ObjPrintf(
-		"can't use %s as operand of \"%s\"", description, operator));
-	return NULL;
-    }
+    return NULL;
 }
 
 /*
@@ -1034,6 +858,118 @@
 /*
  *----------------------------------------------------------------------
  *
+ * TclStrCompare --
+ *
+ *	Compare two strings.
+ *
+ * Results:
+ *      -1 : less than
+ *       0 : equal
+ *       1 : greater than (or non-equal if equal is true)
+ *
+ * Side effects:
+ *	Values may get their string representation filled in or change
+ *      internal representation.
+ *
+ *----------------------------------------------------------------------
+ */
+
+int
+TclStrCompare(
+    Tcl_Obj *obj1Ptr,    /* First value to compare  */
+    Tcl_Obj *obj2Ptr,    /* Second value to compare */
+    int nocase,          /* true for case insensitive compare */
+    int reqlength,       /* How many characters to compare. -1 for all */
+    int equal)           /* true if only equality is interesting */
+{
+    char *string1, *string2;
+    int length1, length2;
+    int match, length;
+    typedef int (*strCmpFn_t)(const char *, const char *, unsigned int);
+    strCmpFn_t strCmpFn;
+
+    if ((reqlength == 0) || (obj1Ptr == obj2Ptr)) {
+        /*
+         * Always match at 0 chars or if it is the same obj.
+         */
+
+        return 0;
+    } else if (!nocase && obj1Ptr->typePtr == &tclByteArrayType &&
+               obj2Ptr->typePtr == &tclByteArrayType) {
+        /*
+         * Use binary versions of comparisons since that won't cause undue
+         * type conversions and it is much faster. Only do this if we're
+         * case-sensitive (which is all that really makes sense with byte
+         * arrays anyway, and we have no memcasecmp() for some
+         * reason... :^)
+         */
+
+        string1 = (char*) Tcl_GetByteArrayFromObj(obj1Ptr, &length1);
+        string2 = (char*) Tcl_GetByteArrayFromObj(obj2Ptr, &length2);
+        strCmpFn = (strCmpFn_t) memcmp;
+    } else if ((obj1Ptr->typePtr == &tclStringType)
+               && (obj2Ptr->typePtr == &tclStringType)) {
+        /*
+         * Do a unicode-specific comparison if both of the args are of
+         * String type. In benchmark testing this proved the most
+         * efficient check between the unicode and string comparison
+         * operations.
+         */
+
+        string1 = (char*) Tcl_GetUnicodeFromObj(obj1Ptr, &length1);
+        string2 = (char*) Tcl_GetUnicodeFromObj(obj2Ptr, &length2);
+        strCmpFn = (strCmpFn_t)
+            (nocase ? Tcl_UniCharNcasecmp : Tcl_UniCharNcmp);
+    } else {
+        /*
+         * As a catch-all we will work with UTF-8. We cannot use memcmp()
+         * as that is unsafe with any string containing NULL (\xC0\x80 in
+         * Tcl's utf rep). We can use the more efficient TclpUtfNcmp2 if
+         * we are case-sensitive and no specific length was requested.
+         */
+
+        string1 = (char*) Tcl_GetStringFromObj(obj1Ptr, &length1);
+        string2 = (char*) Tcl_GetStringFromObj(obj2Ptr, &length2);
+        if ((reqlength < 0) && !nocase) {
+            strCmpFn = (strCmpFn_t) TclpUtfNcmp2;
+        } else {
+            length1 = Tcl_NumUtfChars(string1, length1);
+            length2 = Tcl_NumUtfChars(string2, length2);
+            strCmpFn = (strCmpFn_t)
+                (nocase ? Tcl_UtfNcasecmp : Tcl_UtfNcmp);
+        }
+    }
+
+    if (equal && (reqlength < 0) && (length1 != length2)) {
+        return 1;
+    }
+
+    length = (length1 < length2) ? length1 : length2;
+    if (reqlength > 0 && reqlength < length) {
+        length = reqlength;
+    } else if (reqlength < 0) {
+        /*
+         * The requested length is negative, so we ignore it by
+         * setting it to length + 1 so we correct the match var.
+         */
+
+        reqlength = length + 1;
+    }
+
+    match = strCmpFn(string1, string2, (unsigned) length);
+    if ((match == 0) && (reqlength > length)) {
+        match = length1 - length2;
+    }
+    if (equal) {
+	return (match != 0) ? 1 : 0;
+    } else {
+	return (match > 0) ? 1 : (match < 0) ? -1 : 0;
+    }
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
  * TclInvertOpCmd --
  *
  *	This procedure is invoked to process the "::tcl::mathop::~" Tcl
@@ -1063,6 +999,7 @@
 	return TCL_ERROR;
     }
     if (TclGetNumberFromObj(interp, objv[1], &val, &type) != TCL_OK) {
+	TclIllegalExprOperandType(interp, INST_BITNOT, objv[1]);
 	return TCL_ERROR;
     }
     switch (type) {
@@ -1080,7 +1017,7 @@
 	return TCL_OK;
     }
 #endif
-    default: {
+    case TCL_NUMBER_BIG: {
 	mp_int big;
 
 	Tcl_TakeBignumFromObj(NULL, objv[1], &big);
@@ -1096,6 +1033,9 @@
 	return TCL_OK;
     }
     }
+
+    TclIllegalExprOperandType(interp, INST_BITNOT, objv[1]);
+    return TCL_ERROR;
 }
 
 /*
@@ -1129,6 +1069,7 @@
 	return TCL_ERROR;
     }
     if (Tcl_GetBooleanFromObj(interp, objv[1], &b) != TCL_OK) {
+	TclIllegalExprOperandType(interp, INST_LNOT, objv[1]);
 	return TCL_ERROR;
     }
     Tcl_SetBooleanObj(Tcl_GetObjResult(interp), !b);
@@ -1163,6 +1104,12 @@
 	Tcl_SetIntObj(Tcl_GetObjResult(interp), 0);
 	return TCL_OK;
     } else if (objc == 2) {
+	ClientData ptr1;
+	int type1;
+	if (TclGetNumberFromObj(NULL, objv[1], &ptr1, &type1) != TCL_OK) {
+	    TclIllegalExprOperandType(interp, INST_ADD, objv[1]);
+	    return TCL_ERROR;
+	}
 	Tcl_SetObjResult(interp, objv[1]);
 	return TCL_OK;
     } else if (objc == 3) {
@@ -1229,6 +1176,12 @@
 	Tcl_SetIntObj(Tcl_GetObjResult(interp), 1);
 	return TCL_OK;
     } else if (objc == 2) {
+	ClientData ptr1;
+	int type1;
+	if (TclGetNumberFromObj(NULL, objv[1], &ptr1, &type1) != TCL_OK) {
+	    TclIllegalExprOperandType(interp, INST_MULT, objv[1]);
+	    return TCL_ERROR;
+	}
 	Tcl_SetObjResult(interp, objv[1]);
 	return TCL_OK;
     } else if (objc == 3) {
@@ -1295,6 +1248,13 @@
 	Tcl_SetIntObj(Tcl_GetObjResult(interp), -1);
 	return TCL_OK;
     } else if (objc == 2) {
+	ClientData ptr1;
+	int type1;
+	if ((TclGetNumberFromObj(NULL, objv[1], &ptr1, &type1) != TCL_OK)
+		|| (type1 == TCL_NUMBER_NAN) || (type1 == TCL_NUMBER_DOUBLE)) {
+	    TclIllegalExprOperandType(interp, INST_BITAND, objv[1]);
+	    return TCL_ERROR;
+	}
 	Tcl_SetObjResult(interp, objv[1]);
 	return TCL_OK;
     } else if (objc == 3) {
@@ -1361,6 +1321,13 @@
 	Tcl_SetIntObj(Tcl_GetObjResult(interp), 0);
 	return TCL_OK;
     } else if (objc == 2) {
+	ClientData ptr1;
+	int type1;
+	if ((TclGetNumberFromObj(NULL, objv[1], &ptr1, &type1) != TCL_OK)
+		|| (type1 == TCL_NUMBER_NAN) || (type1 == TCL_NUMBER_DOUBLE)) {
+	    TclIllegalExprOperandType(interp, INST_BITOR, objv[1]);
+	    return TCL_ERROR;
+	}
 	Tcl_SetObjResult(interp, objv[1]);
 	return TCL_OK;
     } else if (objc == 3) {
@@ -1427,6 +1394,13 @@
 	Tcl_SetIntObj(Tcl_GetObjResult(interp), 0);
 	return TCL_OK;
     } else if (objc == 2) {
+	ClientData ptr1;
+	int type1;
+	if ((TclGetNumberFromObj(NULL, objv[1], &ptr1, &type1) != TCL_OK)
+		|| (type1 == TCL_NUMBER_NAN) || (type1 == TCL_NUMBER_DOUBLE)) {
+	    TclIllegalExprOperandType(interp, INST_BITXOR, objv[1]);
+	    return TCL_ERROR;
+	}
 	Tcl_SetObjResult(interp, objv[1]);
 	return TCL_OK;
     } else if (objc == 3) {
@@ -1493,6 +1467,12 @@
 	Tcl_SetIntObj(Tcl_GetObjResult(interp), 1);
 	return TCL_OK;
     } else if (objc == 2) {
+	ClientData ptr1;
+	int type1;
+	if ((TclGetNumberFromObj(NULL, objv[1], &ptr1, &type1) != TCL_OK)) {
+	    TclIllegalExprOperandType(interp, INST_EXPON, objv[1]);
+	    return TCL_ERROR;
+	}
 	Tcl_SetObjResult(interp, objv[1]);
 	return TCL_OK;
     } else if (objc == 3) {
@@ -1716,8 +1696,7 @@
     Tcl_Obj *const objv[])
 {
     ClientData ptr1, ptr2;
-    int invalid, shift, type1, type2, idx;
-    const char *description;
+    int invalid, shift, type1, type2;
     long l1;
 
     if (objc != 3) {
@@ -1727,13 +1706,13 @@
 
     if ((TclGetNumberFromObj(NULL, objv[1], &ptr1, &type1) != TCL_OK)
 	    || (type1 == TCL_NUMBER_DOUBLE) || (type1 == TCL_NUMBER_NAN)) {
-	idx = 1;
-	goto illegalOperand;
+	TclIllegalExprOperandType(interp, INST_LSHIFT, objv[1]);
+	return TCL_ERROR;
     }
     if ((TclGetNumberFromObj(NULL, objv[2], &ptr2, &type2) != TCL_OK)
 	    || (type2 == TCL_NUMBER_DOUBLE) || (type2 == TCL_NUMBER_NAN)) {
-	idx = 2;
-	goto illegalOperand;
+	TclIllegalExprOperandType(interp, INST_LSHIFT, objv[2]);
+	return TCL_ERROR;
     }
 
     /* reject negative shift argument */
@@ -1767,7 +1746,9 @@
     }
 
     /* Large left shifts create integer overflow */
-    if (Tcl_GetIntFromObj(NULL, objv[2], &shift) != TCL_OK) {
+    if ((type2 != TCL_NUMBER_LONG) ||
+	    (*((const long *)ptr2) > (long) INT_MAX) ||
+	    Tcl_GetIntFromObj(NULL, objv[2], &shift) != TCL_OK) {
 	/*
 	 * Technically, we could hold the value (1 << (INT_MAX+1)) in an
 	 * mp_int, but since we're using mp_mul_2d() to do the work, and it
@@ -1817,27 +1798,6 @@
 	}
     }
     return TCL_OK;
-
-  illegalOperand:
-    if (TclGetNumberFromObj(NULL, objv[idx], &ptr1, &type1) != TCL_OK) {
-	int numBytes;
-	const char *bytes = Tcl_GetStringFromObj(objv[idx], &numBytes);
-	if (numBytes == 0) {
-	    description = "empty string";
-	} else if (TclCheckBadOctal(NULL, bytes)) {
-	    description = "invalid octal number";
-	} else {
-	    description = "non-numeric string";
-	}
-    } else if (type1 == TCL_NUMBER_NAN) {
-	description = "non-numeric floating-point value";
-    } else {
-	description = "floating-point value";
-    }
-
-    Tcl_SetObjResult(interp,
-	    Tcl_ObjPrintf("can't use %s as operand of \"<<\"", description));
-    return TCL_ERROR;
 }
 
 /*
@@ -1865,8 +1825,7 @@
     Tcl_Obj *const objv[])
 {
     ClientData ptr1, ptr2;
-    int invalid, shift, type1, type2, idx;
-    const char *description;
+    int invalid, shift, type1, type2;
     long l1;
 
     if (objc != 3) {
@@ -1876,13 +1835,13 @@
 
     if ((TclGetNumberFromObj(NULL, objv[1], &ptr1, &type1) != TCL_OK)
 	    || (type1 == TCL_NUMBER_DOUBLE) || (type1 == TCL_NUMBER_NAN)) {
-	idx = 1;
-	goto illegalOperand;
+	TclIllegalExprOperandType(interp, INST_RSHIFT, objv[1]);
+	return TCL_ERROR;
     }
     if ((TclGetNumberFromObj(NULL, objv[2], &ptr2, &type2) != TCL_OK)
 	    || (type2 == TCL_NUMBER_DOUBLE) || (type2 == TCL_NUMBER_NAN)) {
-	idx = 2;
-	goto illegalOperand;
+	TclIllegalExprOperandType(interp, INST_RSHIFT, objv[2]);
+	return TCL_ERROR;
     }
 
     /* reject negative shift argument */
@@ -1997,27 +1956,6 @@
 	}
     }
     return TCL_OK;
-
-  illegalOperand:
-    if (TclGetNumberFromObj(NULL, objv[idx], &ptr1, &type1) != TCL_OK) {
-	int numBytes;
-	const char *bytes = Tcl_GetStringFromObj(objv[idx], &numBytes);
-	if (numBytes == 0) {
-	    description = "empty string";
-	} else if (TclCheckBadOctal(NULL, bytes)) {
-	    description = "invalid octal number";
-	} else {
-	    description = "non-numeric string";
-	}
-    } else if (type1 == TCL_NUMBER_NAN) {
-	description = "non-numeric floating-point value";
-    } else {
-	description = "floating-point value";
-    }
-
-    Tcl_SetObjResult(interp,
-	    Tcl_ObjPrintf("can't use %s as operand of \">>\"", description));
-    return TCL_ERROR;
 }
 
 /*
@@ -2044,11 +1982,9 @@
     int objc,
     Tcl_Obj *const objv[])
 {
-    Tcl_Obj *argObj;
     ClientData ptr1, ptr2;
     int type1, type2;
     long l1, l2 = 0;
-    const char *description;
 
     if (objc != 3) {
 	Tcl_WrongNumArgs(interp, 1, objv, "value value");
@@ -2057,13 +1993,13 @@
 
     if ((TclGetNumberFromObj(NULL, objv[1], &ptr1, &type1) != TCL_OK)
 	    || (type1 == TCL_NUMBER_DOUBLE) || (type1 == TCL_NUMBER_NAN)) {
-	argObj = objv[1];
-	goto badArg;
+	TclIllegalExprOperandType(interp, INST_MOD, objv[1]);
+	return TCL_ERROR;
     }
     if ((TclGetNumberFromObj(NULL, objv[2], &ptr2, &type2) != TCL_OK)
 	    || (type2 == TCL_NUMBER_DOUBLE) || (type2 == TCL_NUMBER_NAN)) {
-	argObj = objv[2];
-	goto badArg;
+	TclIllegalExprOperandType(interp, INST_MOD, objv[2]);
+	return TCL_ERROR;
     }
 
     if (type2 == TCL_NUMBER_LONG) {
@@ -2203,27 +2139,6 @@
 	}
 	return TCL_OK;
     }
-
-  badArg:
-    if (TclGetNumberFromObj(NULL, argObj, &ptr1, &type1) != TCL_OK) {
-	int numBytes;
-	CONST char *bytes = Tcl_GetStringFromObj(argObj, &numBytes);
-	if (numBytes == 0) {
-	    description = "empty string";
-	} else if (TclCheckBadOctal(NULL, bytes)) {
-	    description = "invalid octal number";
-	} else {
-	    description = "non-numeric string";
-	}
-    } else if (type1 == TCL_NUMBER_NAN) {
-	description = "non-numeric floating-point value";
-    } else {
-	description = "floating-point value";
-    }
-
-    Tcl_SetObjResult(interp, Tcl_ObjPrintf(
-	    "can't use %s as operand of \"%%\"", description));
-    return TCL_ERROR;
 }
 
 /*
@@ -2250,8 +2165,7 @@
     int objc,
     Tcl_Obj *const objv[])
 {
-    int result = 1, cmp, len1, len2;
-    const char *str1, *str2;
+    int result = 1, cmp;
 
     if (objc != 3) {
 	Tcl_WrongNumArgs(interp, 1, objv, "value value");
@@ -2263,9 +2177,8 @@
 	/*
 	 * Got a string
 	 */
-	str1 = Tcl_GetStringFromObj(objv[1], &len1);
-	str2 = Tcl_GetStringFromObj(objv[2], &len2);
-	if (len1 == len2 && !strcmp(str1, str2)) {
+
+	if (TclStrCompare(objv[1], objv[2], 0, -1, 1) == 0) {
 	    result = 0;
 	}
     case TCL_BREAK:			/* Deliberate fallthrough */
@@ -2274,7 +2187,8 @@
 	/*
 	 * Got proper numbers
 	 */
-	if (cmp != MP_EQ) {
+
+	if (cmp == MP_EQ) {
 	    result = 0;
 	}
     }
@@ -2306,21 +2220,15 @@
     int objc,
     Tcl_Obj *const objv[])
 {
-    const char *s1, *s2;
-    int s1len, s2len;
+    int compare;
 
     if (objc != 3) {
 	Tcl_WrongNumArgs(interp, 1, objv, "value value");
 	return TCL_ERROR;
     }
 
-    s1 = Tcl_GetStringFromObj(objv[1], &s1len);
-    s2 = Tcl_GetStringFromObj(objv[2], &s2len);
-    if (s1len == s2len && !strcmp(s1, s2)) {
-	Tcl_SetBooleanObj(Tcl_GetObjResult(interp), 0);
-    } else {
-	Tcl_SetBooleanObj(Tcl_GetObjResult(interp), 1);
-    }
+    compare = TclStrCompare(objv[1], objv[2], 0, -1, 1);
+    Tcl_SetObjResult(interp, Tcl_NewBooleanObj(compare != 0));
     return TCL_OK;
 }
 
@@ -2447,8 +2355,7 @@
     int result = 1;
 
     if (objc > 2) {
-	int i, cmp, len1, len2;
-	const char *str1, *str2;
+	int i, cmp;
 
 	for (i=1 ; i<objc-1 ; i++) {
 	    switch (CompareNumbers(NULL, objv[i], objv[i+1], &cmp)) {
@@ -2456,10 +2363,8 @@
 		/*
 		 * Got a string
 		 */
-		str1 = Tcl_GetStringFromObj(objv[i], &len1);
-		str2 = Tcl_GetStringFromObj(objv[i+1], &len2);
-		if (TclpUtfNcmp2(str1, str2,
-			(size_t) ((len1 < len2) ? len1 : len2)) >= 0) {
+
+		if (TclStrCompare(objv[i], objv[i+1], 0, -1, 0) >= 0) {
 		    result = 0;
 		    i = objc;
 		}
@@ -2468,6 +2373,7 @@
 		/*
 		 * Got proper numbers
 		 */
+
 		if (cmp != MP_LT) {
 		    result = 0;
 		    i = objc;
@@ -2478,6 +2384,7 @@
 		 * Got a NaN (which is different from everything, including
 		 * itself)
 		 */
+
 		result = 0;
 		i = objc;
 		continue;
@@ -2515,8 +2422,7 @@
     int result = 1;
 
     if (objc > 2) {
-	int i, cmp, len1, len2;
-	const char *str1, *str2;
+	int i, cmp;
 
 	for (i=1 ; i<objc-1 ; i++) {
 	    switch (CompareNumbers(NULL, objv[i], objv[i+1], &cmp)) {
@@ -2524,10 +2430,8 @@
 		/*
 		 * Got a string
 		 */
-		str1 = Tcl_GetStringFromObj(objv[i], &len1);
-		str2 = Tcl_GetStringFromObj(objv[i+1], &len2);
-		if (TclpUtfNcmp2(str1, str2,
-			(size_t) ((len1 < len2) ? len1 : len2)) > 0) {
+
+		if (TclStrCompare(objv[i], objv[i+1], 0, -1, 0) > 0) {
 		    result = 0;
 		    i = objc;
 		}
@@ -2536,6 +2440,7 @@
 		/*
 		 * Got proper numbers
 		 */
+
 		if (cmp == MP_GT) {
 		    result = 0;
 		    i = objc;
@@ -2546,6 +2451,7 @@
 		 * Got a NaN (which is different from everything, including
 		 * itself)
 		 */
+
 		result = 0;
 		i = objc;
 		continue;
@@ -2583,8 +2489,7 @@
     int result = 1;
 
     if (objc > 2) {
-	int i, cmp, len1, len2;
-	const char *str1, *str2;
+	int i, cmp;
 
 	for (i=1 ; i<objc-1 ; i++) {
 	    switch (CompareNumbers(NULL, objv[i], objv[i+1], &cmp)) {
@@ -2592,10 +2497,8 @@
 		/*
 		 * Got a string
 		 */
-		str1 = Tcl_GetStringFromObj(objv[i], &len1);
-		str2 = Tcl_GetStringFromObj(objv[i+1], &len2);
-		if (TclpUtfNcmp2(str1, str2,
-			(size_t) ((len1 < len2) ? len1 : len2)) <= 0) {
+
+		if (TclStrCompare(objv[i], objv[i+1], 0, -1, 0) <= 0) {
 		    result = 0;
 		    i = objc;
 		}
@@ -2604,6 +2507,7 @@
 		/*
 		 * Got proper numbers
 		 */
+
 		if (cmp != MP_GT) {
 		    result = 0;
 		    i = objc;
@@ -2614,6 +2518,7 @@
 		 * Got a NaN (which is different from everything, including
 		 * itself)
 		 */
+
 		result = 0;
 		i = objc;
 		continue;
@@ -2651,8 +2556,7 @@
     int result = 1;
 
     if (objc > 2) {
-	int i, cmp, len1, len2;
-	const char *str1, *str2;
+	int i, cmp;
 
 	for (i=1 ; i<objc-1 ; i++) {
 	    switch (CompareNumbers(NULL, objv[i], objv[i+1], &cmp)) {
@@ -2660,10 +2564,8 @@
 		/*
 		 * Got a string
 		 */
-		str1 = Tcl_GetStringFromObj(objv[i], &len1);
-		str2 = Tcl_GetStringFromObj(objv[i+1], &len2);
-		if (TclpUtfNcmp2(str1, str2,
-			(size_t) ((len1 < len2) ? len1 : len2)) < 0) {
+
+		if (TclStrCompare(objv[i], objv[i+1], 0, -1, 0) < 0) {
 		    result = 0;
 		    i = objc;
 		}
@@ -2672,6 +2574,7 @@
 		/*
 		 * Got proper numbers
 		 */
+
 		if (cmp == MP_LT) {
 		    result = 0;
 		    i = objc;
@@ -2682,6 +2585,7 @@
 		 * Got a NaN (which is different from everything, including
 		 * itself)
 		 */
+
 		result = 0;
 		i = objc;
 		continue;
@@ -2719,8 +2623,7 @@
     int result = 1;
 
     if (objc > 2) {
-	int i, cmp, len1, len2;
-	const char *str1, *str2;
+	int i, cmp;
 
 	for (i=1 ; i<objc-1 ; i++) {
 	    switch (CompareNumbers(NULL, objv[i], objv[i+1], &cmp)) {
@@ -2728,9 +2631,8 @@
 		/*
 		 * Got a string
 		 */
-		str1 = Tcl_GetStringFromObj(objv[i], &len1);
-		str2 = Tcl_GetStringFromObj(objv[i+1], &len2);
-		if (len1 != len2 || strcmp(str1, str2)) {
+
+		if (TclStrCompare(objv[i], objv[i+1], 0, -1, 1) != 0) {
 		    result = 0;
 		    i = objc;
 		}
@@ -2786,13 +2688,10 @@
     int result = 1;
 
     if (objc > 2) {
-	int i, len1, len2;
-	const char *str1, *str2;
+	int i;
 
 	for (i=1 ; i<objc-1 ; i++) {
-	    str1 = Tcl_GetStringFromObj(objv[i], &len1);
-	    str2 = Tcl_GetStringFromObj(objv[i+1], &len2);
-	    if (len1 != len2 || strcmp(str1, str2)) {
+	    if (TclStrCompare(objv[i], objv[i+1], 0, -1, 1) != 0) {
 		result = 0;
 		break;
 	    }
diff -ru ../tcl-20061206/tests/mathop.test ./tests/mathop.test
--- ../tcl-20061206/tests/mathop.test	2006-12-07 08:02:35.000000000 +0100
+++ ./tests/mathop.test	2006-12-07 13:18:27.000000000 +0100
@@ -5,6 +5,7 @@
 # for errors. No output means no errors were found.
 #
 # Copyright (c) 2006 Donal K. Fellows
+# Copyright (c) 2006 Peter Spjuth
 #
 # See the file "license.terms" for information on usage and redistribution of
 # this file, and for a DISCLAIMER OF ALL WARRANTIES.
@@ -16,6 +17,87 @@
     namespace import -force ::tcltest::*
 }
 
+# A namespace to test that operators are exported and that they
+# work when imported
+namespace eval ::testmathop2 {
+    namespace import ::tcl::mathop::*
+}
+
+# Helper to test math ops.
+# Test different invokation variants and see that they do the same thing.
+# Byte compiled / non byte compiled version
+# Shared / unshared arguments
+# Original / imported
+proc TestOp {op args} {
+    set results {}
+
+    # Non byte compiled version, shared args
+    if {[catch {::tcl::mathop::$op {expand}$args} res]} {
+        append res " $::errorCode"
+    }
+    lappend results $res
+
+    # Non byte compiled version, unshared args
+    set cmd ::tcl::mathop::\$op
+    foreach arg $args {
+        append cmd " \[format %s [list $arg]\]"
+    }
+    if {[catch $cmd res]} {
+        append res " $::errorCode"
+    }
+    lappend results $res
+
+    # Non byte compiled imported
+    if {[catch {::testmathop2::$op {expand}$args} res]} {
+        append res " $::errorCode"
+    }
+    lappend results [string map {testmathop2 tcl::mathop} $res]
+
+    # BC version
+    set argList1 {}
+    set argList2 {}
+    set argList3 {}
+    for {set t 0} {$t < [llength $args]} {incr t} {
+        lappend argList1 a$t
+        lappend argList2 \$a$t
+        lappend argList3 "\[format %s \$a$t\]"
+    }
+    # Shared args
+    proc _TestOp  $argList1 "::tcl::mathop::$op [join $argList2]"
+    # Unshared args
+    proc _TestOp2 $argList1 "::tcl::mathop::$op [join $argList3]"
+    # Imported
+    proc _TestOp3 $argList1 "::testmathop2::$op [join $argList2]"
+
+    set ::tcl_traceCompile 0  ;# Set to 2 to help with debug
+    if {[catch {_TestOp {expand}$args} res]} {
+        append res " $::errorCode"
+    }
+    set ::tcl_traceCompile 0
+    lappend results $res
+
+    if {[catch {_TestOp2 {expand}$args} res]} {
+        append res " $::errorCode"
+    }
+    lappend results $res
+
+    if {[catch {_TestOp3 {expand}$args} res]} {
+        append res " $::errorCode"
+    }
+    lappend results [string map {testmathop2 tcl::mathop} $res]
+
+    # Check that they do the same
+    set len [llength $results]
+    for {set i 0} {$i < ($len - 1)} {incr i} {
+        set res1 [lindex $results $i]
+        set res2 [lindex $results $i+1]
+        if {$res1 ne $res2} {
+            return "$i:($res1 != $res2)"
+        }
+    }
+    return [lindex $results 0]
+}
+
 # start of tests
 
 namespace eval ::testmathop {
@@ -53,7 +135,7 @@
 	+ 0 [error expectedError]
     } -result expectedError
     test mathop-1.18 {compiled +: argument processing order} -body {
-	# Bytecode compilation known buggy for 3+ arguments
+	# Bytecode compilation known hard for 3+ arguments
 	list [catch {
 	    + [set x 0] [incr x] NaN [incr x] [error expected] [incr x]
 	} msg] $msg $x
@@ -128,7 +210,7 @@
 	* 0 [error expectedError]
     } -result expectedError
     test mathop-2.18 {compiled *: argument processing order} -body {
-	# Bytecode compilation known buggy for 3+ arguments
+	# Bytecode compilation known hard for 3+ arguments
 	list [catch {
 	    * [set x 0] [incr x] NaN [incr x] [error expected] [incr x]
 	} msg] $msg $x
@@ -172,10 +254,658 @@
     } -result {1 expected 2}
 
     # TODO: ! ~  & | ^  % ** << >>  - /  == != < <= > >=  eq ne  in ni
+
+    test mathop-3.18 {compiled /: argument processing order} -body {
+	# Bytecode compilation known hard for 3+ arguments
+	list [catch {
+	    / [set x 0] [incr x] NaN [incr x] [error expected] [incr x]
+	} msg] $msg $x
+    } -result {1 expected 2}
+
+    test mathop-4.18 {compiled -: argument processing order} -body {
+	# Bytecode compilation known hard for 3+ arguments
+	list [catch {
+	    - [set x 0] [incr x] NaN [incr x] [error expected] [incr x]
+	} msg] $msg $x
+    } -result {1 expected 2}
+}
+
+
+test mathop-20.1 { zero args, return unit } {
+    set res {}
+    foreach op {+ * & ^ | ** < <= > >= == eq} {
+        lappend res [TestOp $op]
+    }
+    set res
+} {0 1 -1 0 0 1 1 1 1 1 1 1}
+
+test mathop-20.2 { zero args, not allowed } {
+    set exp {}
+    foreach op {~ ! << >> % != ne in ni - /} {
+        set res [TestOp $op]
+        if {[string match "wrong # args* NONE" $res]} {
+            lappend exp 0
+        } else {
+            lappend exp $res
+        }
+    }
+    set exp
+} {0 0 0 0 0 0 0 0 0 0 0}
+
+test mathop-20.3 { one arg } {
+    set res {}
+    foreach val {7 8.3} {
+        foreach op {+ ** - * / < <= > >= == eq !} {
+            lappend res [TestOp $op $val]
+        }
+    }
+    set res
+} [list 7   7   -7   7   [expr {1.0/7.0}] 1 1 1 1 1 1 0 \
+        8.3 8.3 -8.3 8.3 [expr {1.0/8.3}] 1 1 1 1 1 1 0]
+
+test mathop-20.4 { one arg, integer only ops } {
+    set res {}
+    foreach val {23} {
+        foreach op {& | ^ ~} {
+            lappend res [TestOp $op $val]
+        }
+    }
+    set res
+} [list 23 23 23 -24]
+
+test mathop-20.5 { one arg, not allowed } {
+    set exp {}
+    foreach op {% != ne in ni << >>} {
+        set res [TestOp $op 1]
+        if {[string match "wrong # args* NONE" $res]} {
+            lappend exp 0
+        } else {
+            lappend exp $res
+        }
+    }
+    set exp
+} {0 0 0 0 0 0 0}
+
+test mathop-20.6 { one arg, error } {
+    set res {}
+    set exp {}
+    foreach vals {x {1 x} {1 1 x} {1 x 1}} {
+        # skipping - for now, knownbug...
+        foreach op {+ * / & | ^ **} {
+            lappend res [TestOp $op {expand}$vals]
+            lappend exp "can't use non-numeric string as operand of \"$op\" NONE"
+        }
+    }
+    expr {$res eq $exp ? 0 : $res}
+} 0
+
+test mathop-20.7 { multi arg } {
+    set res {}
+    foreach vals {{1 2} {3 4 5} {4 3 2 1}} {
+        foreach op {+ - * /} {
+            lappend res [TestOp $op {expand}$vals]
+        }
+    }
+    set res
+} [list 3 -1 2 0  12 -6 60 0  10 -2 24 0]
+
+test mathop-20.8 { multi arg, double } {
+    set res {}
+    foreach vals {{1.0 2} {3.0 4 5} {4 3.0 2 1}} {
+        foreach op {+ - * /} {
+            lappend res [TestOp $op {expand}$vals]
+        }
+    }
+    set res
+} [list 3.0 -1.0 2.0 0.5  12.0 -6.0 60.0 0.15  10.0 -2.0 24.0 [expr {2.0/3}]]
+
+test mathop-21.1 { unary ops, bitnot } {
+    set res {}
+    lappend res [TestOp ~ 7]
+    lappend res [TestOp ~ -5]
+    lappend res [TestOp ~ 354657483923456]
+    lappend res [TestOp ~ 123456789123456789123456789]
+    set res
+} [list -8 4 -354657483923457 -123456789123456789123456790]
+
+test mathop-21.2 { unary ops, logical not } {
+    set res {}
+    lappend res [TestOp ! 0]
+    lappend res [TestOp ! 1]
+    lappend res [TestOp ! true]
+    lappend res [TestOp ! false]
+    lappend res [TestOp ! 37]
+    lappend res [TestOp ! 8.5]
+    set res
+} [list 1 0 0 1 0 0]
+
+test mathop-21.3 { unary ops, negation } {
+    set res {}
+    lappend res [TestOp -  7.2]
+    lappend res [TestOp - -5]
+    lappend res [TestOp - -2147483648]                  ;# -2**31
+    lappend res [TestOp - -9223372036854775808]         ;# -2**63
+    lappend res [TestOp -  354657483923456]             ;# wide
+    lappend res [TestOp -  123456789123456789123456789] ;# big
+    set res
+} [list -7.2 5 2147483648 9223372036854775808 -354657483923456 \
+           -123456789123456789123456789]
+
+test mathop-21.4 { unary ops, inversion } {
+    set res {}
+    lappend res [TestOp / 1]
+    lappend res [TestOp / 5]
+    lappend res [TestOp / 5.6]
+    lappend res [TestOp / -8]
+    lappend res [TestOp /  354657483923456]             ;# wide
+    lappend res [TestOp /  123456789123456789123456789] ;# big
+    set res
+} [list 1.0 0.2 0.17857142857142858 -0.125 \
+           2.8196218755553604e-15 8.10000006561e-27]
+
+test mathop-21.5 { unary ops, bad values } {
+    set res {}
+    set exp {}
+    lappend res [TestOp / x]
+    lappend exp "can't use non-numeric string as operand of \"/\" NONE"
+    lappend res [TestOp - x]
+    lappend exp "can't use non-numeric string as operand of \"-\" NONE"
+    lappend res [TestOp ~ x]
+    lappend exp "can't use non-numeric string as operand of \"~\" NONE"
+    lappend res [TestOp ! x]
+    lappend exp "can't use non-numeric string as operand of \"!\" NONE"
+    lappend res [TestOp ~ 5.0]
+    lappend exp "can't use floating-point value as operand of \"~\" NONE"
+    expr {$res eq $exp ? 0 : $res}
+} 0
+
+test mathop-21.6 { unary ops, too many } {
+    set exp {}
+    foreach op {~ !} {
+        set res [TestOp $op 7 8]
+        if {[string match "wrong # args* NONE" $res]} {
+            lappend exp 0
+        } else {
+            lappend exp $res
+        }
+    }
+    set exp
+} {0 0}
+
+test mathop-22.1 { bitwise ops } {
+    set res {}
+    foreach vals {5 {1 6} {1 2 3} {1 2 3 4}} {
+        foreach op {& | ^} {
+            lappend res [TestOp $op {expand}$vals]
+        }
+    }
+    set res
+} [list 5 5 5  0 7 7  0 3 0  0 7 4]
+
+test mathop-22.2 { bitwise ops on bignums } {
+    set dig 50
+    set a 0x[string repeat 5 $dig]
+    set b 0x[string repeat 7 $dig]
+    set c 0x[string repeat 9 $dig]
+    set bn [expr {~$b}]
+    set cn [expr {~$c}]
+
+    set res {}
+    foreach vals [list [list $a $b] [list $a $c] [list $b $c] \
+                          [list $a $bn] [list $bn $c] [list $bn $cn]] {
+        foreach op {& | ^} {
+            lappend res [TestOp $op {expand}$vals]
+        }
+    }
+    set exp {}
+    foreach d {5 7 2  1 D C  1 F E  0 -D -D  8 -9 -1  -0 -E E} {
+        if {[string match "-*" $d]} {
+            set d [format %X [expr 15-0x[string range $d 1 end]]]
+            set val [expr -0x[string repeat $d $dig]-1]
+        } else {
+            set val [expr 0x[string repeat $d $dig]]
+        }
+        lappend exp $val
+    }
+    expr {$exp eq $res ? 1 : "($res != $exp"}
+} 1
+
+test mathop-22.3 { bitwise ops } {
+    set big1      12135435435354435435342423948763867876
+    set big2       2746237174783836746262564892918327847
+    set wide1                             12345678912345
+    set wide2                             87321847232215
+    set small1                                     87345
+    set small2                                     16753
+
+    set res {}
+    foreach op {& | ^} {
+        lappend res [TestOp $op $big1   $big2]
+        lappend res [TestOp $op $big1   $wide2]
+        lappend res [TestOp $op $big1   $small2]
+        lappend res [TestOp $op $wide1  $big2]
+        lappend res [TestOp $op $wide1  $wide2]
+        lappend res [TestOp $op $wide1  $small2]
+        lappend res [TestOp $op $small1 $big2]
+        lappend res [TestOp $op $small1 $wide2]
+        lappend res [TestOp $op $small1 $small2]
+    }
+    set res
+} [list \
+           712439449294653815890598856501796 \
+           78521450111684 \
+           96 \
+           2371422390785 \
+           12275881497169 \
+           16721 \
+           33 \
+           87057 \
+           16689 \
+           14880960170688977527789098242825693927 \
+           12135435435354435435342432749160988407 \
+           12135435435354435435342423948763884533 \
+           2746237174783836746262574867174849407 \
+           87391644647391 \
+           12345678912377 \
+           2746237174783836746262564892918415159 \
+           87321847232503 \
+           87409 \
+           14880247731239682873973207643969192131 \
+           12135435435354435435342354227710876723 \
+           12135435435354435435342423948763884437 \
+           2746237174783836746262572495752458622 \
+           75115763150222 \
+           12345678895656 \
+           2746237174783836746262564892918415126 \
+           87321847145446 \
+           70720 \
+          ]
+
+test mathop-22.4 { unary ops, bad values } {
+    set res {}
+    set exp {}
+    foreach op {& | ^} {
+        lappend res [TestOp $op x 5]
+        lappend exp "can't use non-numeric string as operand of \"$op\" NONE"
+        lappend res [TestOp $op 5 x]
+        lappend exp "can't use non-numeric string as operand of \"$op\" NONE"
+    }
+    expr {$res eq $exp ? 0 : $res}
+} 0
+
+test mathop-23.1 { comparison ops, numerical } {
+    set res {}
+    set todo {5 {1 6} {1 2 2 3} {4 3 2 1} {5.0 5.0} {6 3 3 1} {5.0 5}}
+    lappend todo [list 2342476234762482734623842342 234827463876473 3434]
+    lappend todo [list 2653 453735910264536 453735910264537 2384762472634982746239847637]
+    lappend todo [list 2653 2384762472634982746239847637]
+    lappend todo [list 2653 -2384762472634982746239847637]
+    lappend todo [list 3789253678212653 -2384762472634982746239847637]
+    lappend todo [list 5.0 6 7.0 8 1e13 1945628567352654 1.1e20 \
+                          6734253647589123456784564378 2.3e50]
+    set a 7
+    lappend todo [list $a $a] ;# Same object
+    foreach vals $todo {
+        foreach op {< <= > >= == eq} {
+            lappend res [TestOp $op {expand}$vals]
+        }
+    }
+    set res
+} [list 1 1 1 1 1 1 \
+        1 1 0 0 0 0 \
+        0 1 0 0 0 0 \
+        0 0 1 1 0 0 \
+        0 1 0 1 1 1 \
+        0 0 0 1 0 0 \
+        0 1 0 1 1 0 \
+        0 0 1 1 0 0 \
+        1 1 0 0 0 0 \
+        1 1 0 0 0 0 \
+        0 0 1 1 0 0 \
+        0 0 1 1 0 0 \
+        1 1 0 0 0 0 \
+        0 1 0 1 1 1 \
+       ]
+
+test mathop-23.2 { comparison ops, string } {
+    set res {}
+    set todo {a {a b} {5 b b c} {d c b a} {xy xy} {gy ef ef ab}}
+    set a x
+    lappend todo [list $a $a]
+    foreach vals $todo {
+        foreach op {< <= > >= == eq} {
+            lappend res [TestOp $op {expand}$vals]
+        }
+    }
+    set res
+} [list 1 1 1 1 1 1 \
+        1 1 0 0 0 0 \
+        0 1 0 0 0 0 \
+        0 0 1 1 0 0 \
+        0 1 0 1 1 1 \
+        0 0 0 1 0 0 \
+        0 1 0 1 1 1 \
+       ]
+
+test mathop-23.3 { comparison ops, nonequal} {
+    set res {}
+    foreach vals {{a b} {17.0 0x11} {foo foo} {10 10}} {
+        foreach op {!= ne} {
+            lappend res [TestOp $op {expand}$vals]
+        }
+    }
+    set res
+} [list 1 1  0 1  0 0  0 0 ]
+
+test mathop-24.1 { binary ops } {
+    set res {}
+    foreach vals {{3 5} {17 7} {199 5} {293234675763434238476239486 17} \
+                  {5 1} {0 7}} {
+        foreach op {% << >> in ni} {
+            lappend res [TestOp $op {expand}$vals]
+        }
+    }
+    set res
+} [list 3 96 0 0 1  3 2176 0 0 1  4 6368 6 0 1 \
+        14 38434855421664852505557661908992 2237203031642412097749 0 1 \
+        0 10 2 0 1  0 0 0 0 1]
+
+test mathop-24.2 { binary ops, modulo } {
+    # Test different combinations to get all code paths
+    set res {}
+
+    set bigbig 14372423674564535234543545248972634923869
+    set big       12135435435354435435342423948763867876
+    set wide                              12345678912345
+    set negwide                          -12345678912345
+    set small                                          5
+    set neg                                           -5
+
+    lappend res [TestOp % $bigbig  $big]
+    lappend res [TestOp % $wide    $big]
+    lappend res [TestOp % $negwide $big]
+    lappend res [TestOp % $small   $big]
+    lappend res [TestOp % $neg     $big]
+    lappend res [TestOp % $small  $wide]
+    lappend res [TestOp % $neg    $wide]
+    lappend res [TestOp % $wide  $small]
+    set res
+} [list   4068119104883679098115293636215358685 \
+                                 12345678912345 \
+         12135435435354435435342411603084955531 \
+                                              5 \
+         12135435435354435435342423948763867871 \
+                                              5 \
+                                 12345678912340 \
+                                              0 \
+          ]
+
+test mathop-24.3 { binary ops, bad values } {
+    set res {}
+    set exp {}
+    foreach op {% << >>} {
+        lappend res [TestOp $op x 1]
+        lappend exp "can't use non-numeric string as operand of \"$op\" NONE"
+        lappend res [TestOp $op 1 x]
+        lappend exp "can't use non-numeric string as operand of \"$op\" NONE"
+    }
+    foreach op {% << >>} {
+        lappend res [TestOp $op 5.0 1]
+        lappend exp "can't use floating-point value as operand of \"$op\" NONE"
+        lappend res [TestOp $op 1 5.0]
+        lappend exp "can't use floating-point value as operand of \"$op\" NONE"
+    }
+    foreach op {in ni} {
+        lappend res [TestOp $op 5 "a b \{ c"]
+        lappend exp "unmatched open brace in list NONE"
+    }
+    lappend res [TestOp % 5 0]
+    lappend exp "divide by zero ARITH DIVZERO {divide by zero}"
+    lappend res [TestOp % 9838923468297346238478737647637375 0]
+    lappend exp "divide by zero ARITH DIVZERO {divide by zero}"
+    lappend res [TestOp / 5 0]
+    lappend exp "divide by zero ARITH DIVZERO {divide by zero}"
+    lappend res [TestOp / 9838923468297346238478737647637375 0]
+    lappend exp "divide by zero ARITH DIVZERO {divide by zero}"
+    expr {$res eq $exp ? 0 : $res}
+} 0
+
+test mathop-24.4 { binary ops, negative shift } {
+    set res {}
+
+    set big      -12135435435354435435342423948763867876
+    set wide                             -12345678912345
+    set small                                         -1
+
+    lappend res [TestOp << 10 $big]
+    lappend res [TestOp << 10 $wide]
+    lappend res [TestOp << 10 $small]
+    lappend res [TestOp >> 10 $big]
+    lappend res [TestOp >> 10 $wide]
+    lappend res [TestOp >> 10 $small]
+
+    set exp [lrepeat 6 "negative shift argument NONE"]
+    expr {$res eq $exp ? 0 : $res}
+} 0
+
+test mathop-24.5 { binary ops, large shift } {
+    set res {}
+    set exp {}
+
+    set big      12135435435354435435342423948763867876
+    set wide                             12345678912345
+    set small                                         1
+
+    lappend res [TestOp << 1 2147483648]
+    lappend exp "integer value too large to represent NONE"
+    lappend res [TestOp << 1 4294967296]
+    lappend exp "integer value too large to represent NONE"
+    lappend res [TestOp << $small $wide]
+    lappend exp "integer value too large to represent NONE"
+    lappend res [TestOp << $small $big]
+    lappend exp "integer value too large to represent NONE"
+    lappend res [TestOp >> $big $wide]
+    lappend exp 0
+    lappend res [TestOp >> $big $big]
+    lappend exp 0
+    lappend res [TestOp >> $small 70]
+    lappend exp 0
+    lappend res [TestOp >> $wide 70]
+    lappend exp 0
+    lappend res [TestOp >> -$big $wide]
+    lappend exp -1
+    lappend res [TestOp >> -$wide $wide]
+    lappend exp -1
+    lappend res [TestOp >> -$small $wide]
+    lappend exp -1
+    lappend res [TestOp >> -$small 70]
+    lappend exp -1
+    lappend res [TestOp >> -$wide 70]
+    lappend exp -1
+
+    expr {$res eq $exp ? 0 : $res}
+} 0
+
+test mathop-24.6 { binary ops, shift } {
+    # Test different combinations to get all code paths
+    set res {}
+
+    set bigbig 14372423674564535234543545248972634923869
+    set big       12135435435354435435342423948763867876
+    set wide                              12345678912345
+    set negwide                          -12345678912345
+    set small                                          5
+    set neg                                           -5
+
+    lappend res [TestOp << $wide $small]
+    lappend res [TestOp >> $wide $small]
+    set res
+} [list   395061725195040 \
+             385802466010 \
+          ]
+
+test mathop-24.7 { binary ops, list search } {
+    set res {}
+
+    foreach op {in ni} {
+        lappend res [TestOp $op 5 {7 5 8}]
+        lappend res [TestOp $op hej {foo bar hej}]
+        lappend res [TestOp $op 5 {7 0x5 8}]
+    }
+    set res
+} [list 1 1 0  0 0 1]
+
+test mathop-24.8 { binary ops, too many } {
+    set exp {}
+    foreach op {<< >> % != ne in ni ~ !} {
+        set res [TestOp $op 7 8 9]
+        if {[string match "wrong # args* NONE" $res]} {
+            lappend exp 0
+        } else {
+            lappend exp $res
+        }
+    }
+    set exp
+} {0 0 0 0 0 0 0 0 0}
+
+
+test mathop-25.1  { exp operator } {TestOp **        } 1
+test mathop-25.2  { exp operator } {TestOp **   0    } 0
+test mathop-25.3  { exp operator } {TestOp **   0   5} 0
+test mathop-25.4  { exp operator } {TestOp ** 7.5    } 7.5
+test mathop-25.5  { exp operator } {TestOp **   1   5} 1
+test mathop-25.6  { exp operator } {TestOp **   5   1} 5
+test mathop-25.7  { exp operator } {TestOp ** 4 3 2 1} 262144
+test mathop-25.8  { exp operator } {TestOp ** 5.5   4} 915.0625
+test mathop-25.9  { exp operator } {TestOp **   6 3.5} 529.0897844411664
+test mathop-25.10 { exp operator } {TestOp ** 3.5   0} 1.0
+test mathop-25.11 { exp operator } {TestOp ** 378   0} 1
+test mathop-25.12 { exp operator } {TestOp ** 7.8   1} 7.8
+test mathop-25.13 { exp operator } {TestOp ** 748   1} 748
+test mathop-25.14 { exp operator } {TestOp ** 6.3  -1} 0.15873015873015872
+test mathop-25.15 { exp operator } {TestOp ** 683  -1} 0
+test mathop-25.16 { exp operator } {TestOp **   1  -1} 1
+test mathop-25.17 { exp operator } {TestOp **  -1  -1} -1
+test mathop-25.18 { exp operator } {TestOp **  -1  -2} 1
+test mathop-25.19 { exp operator } {TestOp **  -1   3} -1
+test mathop-25.20 { exp operator } {TestOp **  -1   4} 1
+test mathop-25.21 { exp operator } {TestOp **   2  63} 9223372036854775808
+test mathop-25.22 { exp operator } {TestOp ** 83756485763458746358734658473567847567473 2} 7015148907444467657897585474493757781161998914521537835809623408157343003287605729
+
+test mathop-25.23 { exp operator errors } {
+    set res {}
+    set exp {}
+
+    set huge     [string repeat 145782 1000]
+    set big      12135435435354435435342423948763867876
+    set wide                             12345678912345
+    set small                                         2
+
+    lappend res [TestOp ** 0 -5]
+    lappend exp "exponentiation of zero by negative power ARITH DOMAIN {exponentiation of zero by negative power}"
+    lappend res [TestOp ** 0.0 -5.0]
+    lappend exp "exponentiation of zero by negative power ARITH DOMAIN {exponentiation of zero by negative power}"
+    lappend res [TestOp ** $small $wide]
+    lappend exp "exponent too large NONE"
+    lappend res [TestOp ** 2 $big]
+    lappend exp "exponent too large NONE"
+    lappend res [TestOp ** $huge 2.1]
+    lappend exp "Inf"
+    lappend res [TestOp ** 2 foo]
+    lappend exp "can't use non-numeric string as operand of \"**\" NONE"
+    lappend res [TestOp ** foo 2]
+    lappend exp "can't use non-numeric string as operand of \"**\" NONE"
+
+    expr {$res eq $exp ? 0 : $res}
+} 0
+
+
+test mathop-26.1 { misc ops, size combinations } {
+    set big1      12135435435354435435342423948763867876
+    set big2       2746237174783836746262564892918327847
+    set wide1                             87321847232215
+    set wide2                             12345678912345
+    set small1                                     87345
+    set small2                                     16753
+
+    set res {}
+    foreach op {+ * - /} {
+        lappend res [TestOp $op $big1   $big2]
+        lappend res [TestOp $op $big1   $wide2]
+        lappend res [TestOp $op $big1   $small2]
+        lappend res [TestOp $op $wide1  $big2]
+        lappend res [TestOp $op $wide1  $wide2]
+        lappend res [TestOp $op $wide1  $small2]
+        lappend res [TestOp $op $small1 $big2]
+        lappend res [TestOp $op $small1 $wide2]
+        lappend res [TestOp $op $small1 $small2]
+    }
+    set res
+} [list \
+           14881672610138272181604988841682195723 \
+           12135435435354435435342436294442780221 \
+           12135435435354435435342423948763884629 \
+           2746237174783836746262652214765560062 \
+           99667526144560 \
+           87321847248968 \
+           2746237174783836746262564892918415192 \
+           12345678999690 \
+           104098 \
+           33326783924759424684447891401270222910405366244661685890993770489959542972 \
+           149820189346379518024969783068410988366610965329220 \
+           203304949848492856848291628413641078526628 \
+           239806503039903915972546163440347114360602909991105 \
+           1078047487961768329845194175 \
+           1462902906681297895 \
+           239870086031494220602303730571951345796215 \
+           1078333324598774025 \
+           1463290785 \
+           9389198260570598689079859055845540029 \
+           12135435435354435435342411603084955531 \
+           12135435435354435435342423948763851123 \
+           -2746237174783836746262477571071095632 \
+           74976168319870 \
+           87321847215462 \
+           -2746237174783836746262564892918240502 \
+           -12345678825000 \
+           70592 \
+           4 \
+           982970278225822587257201 \
+           724373869477373332259441529801460 \
+           0 \
+           7 \
+           5212311062 \
+           0 \
+           0 \
+           5 \
+          ]
+
+test mathop-26.2 { misc ops, corner cases } {
+    set res {}
+    lappend res [TestOp - 0 -2147483648]                  ;# -2**31
+    lappend res [TestOp - 0 -9223372036854775808]         ;# -2**63
+    lappend res [TestOp / -9223372036854775808 -1]
+    lappend res [TestOp * 2147483648 2]
+    lappend res [TestOp * 9223372036854775808 2]
+    set res
+} [list 2147483648 9223372036854775808 9223372036854775808 4294967296 18446744073709551616]
+
+if 0 {
+    # Compare ops to expr bytecodes
+    namespace import ::tcl::mathop::*
+    proc _X {a b c} {
+        set x [+ $a [- $b $c]]
+        set y [expr {$a + ($b - $c)}]
+        set z [< $a $b $c]
+    }
+    set ::tcl_traceCompile 2
+    _X 3 4 5
+    set ::tcl_traceCompile 0
 }
 
 # cleanup
 namespace delete ::testmathop
+namespace delete ::testmathop2
 ::tcltest::cleanupTests
 return