aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSteve Bennett <steveb@workware.net.au>2010-01-24 12:00:22 +1000
committerSteve Bennett <steveb@workware.net.au>2010-10-15 11:02:43 +1000
commit2ae1c01c1b0b7d24fa2eeff3545b375d25c18c66 (patch)
treed37b63d50fea502fe61b98943ca380a4aa4d053d
parent17b0f14f5e17efb7e70e47e711c6339e524875f8 (diff)
downloadjimtcl-2ae1c01c1b0b7d24fa2eeff3545b375d25c18c66.zip
jimtcl-2ae1c01c1b0b7d24fa2eeff3545b375d25c18c66.tar.gz
jimtcl-2ae1c01c1b0b7d24fa2eeff3545b375d25c18c66.tar.bz2
Simplify expr evaluation
-rw-r--r--BUGS12
-rw-r--r--TODO41
-rw-r--r--bench.tcl10
-rw-r--r--jim.c599
-rw-r--r--tests/case.test6
-rw-r--r--tests/perf.test8
6 files changed, 307 insertions, 369 deletions
diff --git a/BUGS b/BUGS
index 03cc8d2..927770d 100644
--- a/BUGS
+++ b/BUGS
@@ -1,3 +1,11 @@
-Known bugs:
+Known bugs
+==========
-EXPR: ?: is not lazy. Functions like sin(), cos(), not implemented.
+expr
+----
+
+right-to-left associativity of ?: is not 100% correct.
+1?2:0?3:4 should be 2, not 3.
+
+Math functions like sin(), cos(), are not implemented
+to avoid requiring libm. Could be a configuration option.
diff --git a/TODO b/TODO
index 0365f15..ffd26cf 100644
--- a/TODO
+++ b/TODO
@@ -1,41 +1,25 @@
CORE LANGUAGE FEATURES
-- Proc default arguments
-- Traces
-- [static] command
+- lrepeat
+- unset -nocomplain
+- parse foo($bar) into special tokens so that interpolation/parsing
+ is not required every time
CORE COMMANDS
- All the missing standard core commands not related to I/O, namespaces, ...
-- The current [expr] needs a lot of work, especially operators && and ||
- are not lazy. Math functions are not present but probably will never
- be added as expr functions, but as Tcl commands, like [sin], [cos] and
- so on.
+- More math functions in expr?
- [onleave] command, executing something as soon as the current procedure
returns. With no arguments it returns the script set, with one appends
the onleave script. There should be a way to reset.
-- [proc] without arguments may return a list of all the procedures
- (no C commands). While with a single argument (the name of a proc)
- may return [list $args $statics $body].
OTHER COMMANDS NOT IN TCL BUT THAT SHOULD BE IN JIM
- Set commands: [lunion], [lintersect], and [ldifference]
-EXTENSIONS LOADING
-
-- Avoid that the same extension can be loaded multiple times inside the
- same interpreter. The extension should return its name on initialization
- together with the version so that Jim_InitExtension will fail if the
- extension with the same name is already loaded.
-
EXTENSIONS
-- Regexp extension
- OOP system
-- Event loop
-- Files
-- Sockets
- Cryptography: hash functions, block ciphers, strim ciphers, PRNGs.
- Tuplespace extension (http://wiki.tcl.tk/3947) (using sqlite as backend)
- Zlib
@@ -51,7 +35,7 @@ SPEED OPTIMIZATIONS
- Organize the 'script' object so that a single data structure is
used for a full command, and interpolation is done using an
'interpolation token type' like JIM_TT_VAR and so on.
- This way there is no need to run the array if integer objects
+ This way there is no need to run the array of integer objects
with the command structure. Also should help for better cache usage.
- Generate .c from Jim programs, as calls to the Jim API to avoid
the performance penality of Jim_EvalObj() overhead. In the future
@@ -70,21 +54,10 @@ IMPLEMENTATION ISSUES
equivalent) handle in a list inside the interpreter structure. When
the interpreter is freed all this handles should be closed with dlclose().
- *AssocData() function should allow to specify a delProc C function like
- in the Tcl API. When the interpreter is destroyed all the delProc functions
+ in the Tcl API. When the interpreter is destroied all the delProc functions
should be called to free the memory before to free the interpreter.
- Convert dicts from lists directly without to pass from the string repr.
-ERROR MESSAGES
-
-- Display the procedure relative file number where the error happened.
- Like:
-
- In procedure 'check' line 11, called at file "test.tcl", line 1024
-
- instead of just:
-
- In procedure 'check' called at file "test.tcl", line 1024
-
REFERENCES SYSTEM
- Unify ref/getref/setref/collect/finalize under an unique [ref] command.
diff --git a/bench.tcl b/bench.tcl
index 0345537..cf53219 100644
--- a/bench.tcl
+++ b/bench.tcl
@@ -285,7 +285,7 @@ proc pi_digits {} {
proc expand {} {
for {set i 0} {$i < 100000} {incr i} {
set a [list a b c d e f]
- lappend b {expand}$a
+ lappend b {*}$a
}
}
@@ -511,17 +511,17 @@ proc commonsub_test {} {
### MANDEL #####################################################################
proc mandel {xres yres infx infy supx supy} {
- set incremx [expr {(0.0+$supx-$infx)/$xres}]
- set incremy [expr {(0.0+$supy-$infy)/$yres}]
+ set incremx [expr {double($supx-$infx)/$xres}]
+ set incremy [expr {double($supy-$infy)/$yres}]
for {set j 0} {$j < $yres} {incr j} {
- set cim [expr {$infy+($incremy*$j)}]
+ set cim [expr {$infy+$incremy*$j}]
set line {}
for {set i 0} {$i < $xres} {incr i} {
set counter 0
set zim 0
set zre 0
- set cre [expr {$infx+($incremx*$i)}]
+ set cre [expr {$infx+$incremx*$i}]
while {$counter < 255} {
set dam [expr {$zre*$zre-$zim*$zim+$cre}]
set zim [expr {2*$zim*$zre+$cim}]
diff --git a/jim.c b/jim.c
index 207aa9f..fefb3c7 100644
--- a/jim.c
+++ b/jim.c
@@ -6275,151 +6275,141 @@ typedef struct Jim_ExprOperator {
jim_expr_function_t *funcop;
} Jim_ExprOperator;
-#define GET_INT 1
-#define GET_DOUBLE 2
-#define GET_STRING 4
+static void expr_push(struct expr_state *e, Jim_Obj *obj)
+{
+ Jim_IncrRefCount(obj);
+ e->stack[e->stacklen++] = obj;
+}
-static Jim_Obj *expr_pop(Jim_Interp *interp, struct expr_state *e, int which)
+static Jim_Obj *expr_pop(struct expr_state *e)
{
- jim_wide wA;
- double dA;
+ assert(e->stacklen);
+ return e->stack[--e->stacklen];
+}
- if (e->stacklen > 0) {
- Jim_Obj *obj = e->stack[e->stacklen - 1];
+#define OBJ_IS_INT 0
+#define OBJ_IS_DOUBLE 1
+#define OBJ_NO_NUM -1
- /* If it is already an integer or double, use it */
- if ((which & GET_INT) && obj->typePtr == &intObjType) {
- e->stacklen--;
- return obj;
- }
- /* Don't consider a double type with no string rep since it may
- * have been explicitly converted.
- */
- if ((which & GET_DOUBLE) && obj->typePtr == &doubleObjType && !obj->bytes) {
- e->stacklen--;
- return obj;
- }
+static int expr_getnum(Jim_Interp *interp, struct expr_state *e, Jim_Obj **resultObjPtr, jim_wide *w, double *d)
+{
+ Jim_Obj *obj = expr_pop(e);
- /* Try to convert */
- if ((which & GET_INT) && Jim_GetWide(interp, obj, &wA) == JIM_OK) {
- e->stacklen--;
- return obj;
- }
- if ((which & GET_DOUBLE) && Jim_GetDouble(interp, obj, &dA) == JIM_OK) {
- e->stacklen--;
- return obj;
- }
+ *resultObjPtr = obj;
- /* Maybe a string is OK */
- if (which & GET_STRING) {
- Jim_GetString(obj, NULL);
- e->stacklen--;
- return obj;
- }
+ /* If it is already an integer or double, use it */
+ if (obj->typePtr == &intObjType) {
+ *w = obj->internalRep.wideValue;
+ return OBJ_IS_INT;
+ }
+ /* Don't consider a double type with no string rep since it may
+ * have been explicitly converted.
+ */
+ if (obj->typePtr == &doubleObjType && !obj->bytes) {
+ *d = obj->internalRep.doubleValue;
+ return OBJ_IS_DOUBLE;
}
- /* Failure - leave it on the stack */
- return NULL;
-}
+ /* Try to convert */
+ if (Jim_GetWide(interp, obj, w) == JIM_OK) {
+ return OBJ_IS_INT;
+ }
+ if (Jim_GetDouble(interp, obj, d) == JIM_OK) {
+ return OBJ_IS_DOUBLE;
+ }
-static void expr_push(struct expr_state *e, Jim_Obj *obj)
-{
- Jim_IncrRefCount(obj);
- e->stack[e->stacklen++] = obj;
+ return OBJ_NO_NUM;
}
static int JimExprOpNumUnary(Jim_Interp *interp, struct expr_state *e)
{
- Jim_Obj *A = expr_pop(interp, e, GET_INT | GET_DOUBLE);
+ int intresult = 0;
+ int rc = JIM_OK;
+ Jim_Obj *A;
+ double dA, dC;
+ jim_wide wA, wC;
+ int type = expr_getnum(interp, e, &A, &wA, &dA);
- if (A) {
- jim_wide wC;
- double dC;
- int intresult = 0;
-
- if (A->typePtr == &doubleObjType) {
- double dA;
-
- Jim_GetDouble(interp, A, &dA);
- switch (e->opcode) {
- case JIM_EXPROP_FUNC_INT: wC = dA; intresult = 1; break;
- case JIM_EXPROP_FUNC_ROUND: wC = dA < 0 ? (dA - 0.5) : (dA + 0.5); intresult = 1; break;
- case JIM_EXPROP_FUNC_DOUBLE: dC = dA; break;
- case JIM_EXPROP_FUNC_ABS: dC = dA >= 0 ? dA : -dA; break;
- case JIM_EXPROP_UNARYMINUS: dC = -dA; break;
- case JIM_EXPROP_UNARYPLUS: dC = dA; break;
- case JIM_EXPROP_NOT: wC = !dA; intresult = 1; break;
- default: abort();
- }
+ if (type == OBJ_IS_DOUBLE) {
+ switch (e->opcode) {
+ case JIM_EXPROP_FUNC_INT: wC = dA; intresult = 1; break;
+ case JIM_EXPROP_FUNC_ROUND: wC = dA < 0 ? (dA - 0.5) : (dA + 0.5); intresult = 1; break;
+ case JIM_EXPROP_FUNC_DOUBLE: dC = dA; break;
+ case JIM_EXPROP_FUNC_ABS: dC = dA >= 0 ? dA : -dA; break;
+ case JIM_EXPROP_UNARYMINUS: dC = -dA; break;
+ case JIM_EXPROP_UNARYPLUS: dC = dA; break;
+ case JIM_EXPROP_NOT: wC = !dA; intresult = 1; break;
+ default: abort();
}
- else {
- /* Must be an integer */
- jim_wide wA;
-
- intresult = 1;
-
- Jim_GetWide(interp, A, &wA);
+ }
+ else if (type == OBJ_IS_INT) {
+ intresult = 1;
- switch (e->opcode) {
- case JIM_EXPROP_FUNC_INT: wC = wA; break;
- case JIM_EXPROP_FUNC_ROUND: wC = wA; break;
- case JIM_EXPROP_FUNC_DOUBLE: dC = wA; intresult = 0; break;
- case JIM_EXPROP_FUNC_ABS: wC = wA >= 0 ? wA : -wA; break;
- case JIM_EXPROP_UNARYMINUS: wC = -wA; break;
- case JIM_EXPROP_UNARYPLUS: wC = wA; break;
- case JIM_EXPROP_NOT: wC = !wA; break;
- default: abort();
- }
+ switch (e->opcode) {
+ case JIM_EXPROP_FUNC_INT: wC = wA; break;
+ case JIM_EXPROP_FUNC_ROUND: wC = wA; break;
+ case JIM_EXPROP_FUNC_DOUBLE: dC = wA; intresult = 0; break;
+ case JIM_EXPROP_FUNC_ABS: wC = wA >= 0 ? wA : -wA; break;
+ case JIM_EXPROP_UNARYMINUS: wC = -wA; break;
+ case JIM_EXPROP_UNARYPLUS: wC = wA; break;
+ case JIM_EXPROP_NOT: wC = !wA; break;
+ default: abort();
}
+ }
+ else {
+ rc = JIM_ERR;
+ }
+ if (rc == JIM_OK) {
if (intresult) {
expr_push(e, Jim_NewIntObj(interp, wC));
}
else {
expr_push(e, Jim_NewDoubleObj(interp, dC));
}
- Jim_DecrRefCount(interp, A);
- return JIM_OK;
}
- return JIM_ERR;
+ Jim_DecrRefCount(interp, A);
+
+ return rc;
}
static int JimExprOpIntUnary(Jim_Interp *interp, struct expr_state *e)
{
- Jim_Obj *A = expr_pop(interp, e, GET_INT);
+ Jim_Obj *A = expr_pop(e);
+ jim_wide wA;
+ int rc = JIM_ERR;
+
- if (A) {
- jim_wide wA;
+ if (Jim_GetWide(interp, A, &wA) == JIM_OK) {
jim_wide wC;
- Jim_GetWide(interp, A, &wA);
-
switch (e->opcode) {
case JIM_EXPROP_BITNOT: wC = ~wA; break;
default: abort();
}
expr_push(e, Jim_NewIntObj(interp, wC));
- Jim_DecrRefCount(interp, A);
- return JIM_OK;
+ rc = JIM_OK;
}
- return JIM_ERR;
+ Jim_DecrRefCount(interp, A);
+
+ return rc;
}
/* A binary operation on two ints */
static int JimExprOpIntBin(Jim_Interp *interp, struct expr_state *e)
{
- Jim_Obj *B = expr_pop(interp, e, GET_INT);
- Jim_Obj *A = expr_pop(interp, e, GET_INT);
-
- if (A && B) {
- jim_wide wA, wB, wC;
- int rc = JIM_OK;
+ Jim_Obj *B = expr_pop(e);
+ Jim_Obj *A = expr_pop(e);
+ jim_wide wA, wB;
+ int rc = JIM_ERR;
+
+ if (Jim_GetWide(interp, A, &wA) == JIM_OK && Jim_GetWide(interp, B, &wB) == JIM_OK) {
+ jim_wide wC;
- Jim_GetWide(interp, A, &wA);
- Jim_GetWide(interp, B, &wB);
+ rc = JIM_OK;
switch (e->opcode) {
case JIM_EXPROP_LSHIFT: wC = wA<<wB; break;
@@ -6475,152 +6465,60 @@ static int JimExprOpIntBin(Jim_Interp *interp, struct expr_state *e)
}
expr_push(e, Jim_NewIntObj(interp, wC));
- Jim_DecrRefCount(interp, A);
- Jim_DecrRefCount(interp, B);
-
- return rc;
}
- if (A) {
- Jim_DecrRefCount(interp, A);
- }
- if (B) {
- Jim_DecrRefCount(interp, B);
- }
+ Jim_DecrRefCount(interp, A);
+ Jim_DecrRefCount(interp, B);
- return JIM_ERR;
+ return rc;
}
-/* A binary operation on two ints or two doubles */
-static int JimExprOpNumBin(Jim_Interp *interp, struct expr_state *e)
-{
- Jim_Obj *B = expr_pop(interp, e, GET_INT | GET_DOUBLE);
- Jim_Obj *A = expr_pop(interp, e, GET_INT | GET_DOUBLE);
-
- if (A && B) {
- int rc = JIM_OK;
- jim_wide wC;
- double dC;
- int intresult = 0;
-
- /* If either is a double, the result is a double */
- if (A->typePtr == &doubleObjType || B->typePtr == &doubleObjType) {
- double dA, dB;
-
- Jim_GetDouble(interp, A, &dA);
- Jim_GetDouble(interp, B, &dB);
-
- switch (e->opcode) {
- case JIM_EXPROP_ADD: dC = dA+dB; break;
- case JIM_EXPROP_SUB: dC = dA-dB; break;
- case JIM_EXPROP_MUL: dC = dA*dB; break;
- case JIM_EXPROP_DIV:
- if (dB == 0) {
- dC = 0;
- Jim_SetResultString(interp, "Division by zero", -1);
- rc = JIM_ERR;
- }
- else {
- dC = dA/dB;
- }
- break;
- default: abort();
- }
- }
- else {
- /* Must be both integers */
- jim_wide wA, wB;
-
- Jim_GetWide(interp, A, &wA);
- Jim_GetWide(interp, B, &wB);
-
- intresult = 1;
-
- switch (e->opcode) {
- case JIM_EXPROP_ADD: wC = wA+wB; break;
- case JIM_EXPROP_SUB: wC = wA-wB; break;
- case JIM_EXPROP_MUL: wC = wA*wB; break;
- case JIM_EXPROP_DIV:
- if (wB == 0) {
- wC = 0;
- Jim_SetResultString(interp, "Division by zero", -1);
- rc = JIM_ERR;
- }
- else {
- /*
- * From Tcl 8.x
- *
- * This code is tricky: C doesn't guarantee much
- * about the quotient or remainder, but Tcl does.
- * The remainder always has the same sign as the
- * divisor and a smaller absolute value.
- */
- if (wB < 0) {
- wB = -wB;
- wA = -wA;
- }
- wC = wA / wB;
- if (wA % wB < 0) {
- wC--;
- }
- }
- break;
- default: abort();
- }
- }
-
- if (intresult) {
- expr_push(e, Jim_NewIntObj(interp, wC));
- }
- else {
- expr_push(e, Jim_NewDoubleObj(interp, dC));
- }
-
- Jim_DecrRefCount(interp, A);
- Jim_DecrRefCount(interp, B);
-
- return rc;
- }
-
- if (A) {
- Jim_DecrRefCount(interp, A);
- }
- if (B) {
- Jim_DecrRefCount(interp, B);
- }
-
- return JIM_ERR;
-}
-
-/* A binary operation on two ints, two doubles or two strings returning a boolean (int) */
+/* A binary operation on two ints or two doubles (or two strings for some ops) */
static int JimExprOpBin(Jim_Interp *interp, struct expr_state *e)
{
- Jim_Obj *B = expr_pop(interp, e, GET_INT | GET_DOUBLE | GET_STRING);
- Jim_Obj *A = expr_pop(interp, e, GET_INT | GET_DOUBLE | GET_STRING);
+ int intresult = 0;
+ int rc = JIM_OK;
+ Jim_Obj *A, *B;
+ double dA, dB, dC;
+ jim_wide wA, wB, wC;
+ int typeB = expr_getnum(interp, e, &B, &wB, &dB);
+ int typeA = expr_getnum(interp, e, &A, &wA, &dA);
- double dA, dB;
- jim_wide wA, wB;
- jim_wide wC;
-
- /* If either is a double, cooerce to doubles */
- if ((A->typePtr == &doubleObjType || B->typePtr == &doubleObjType) &&
- Jim_GetDouble(interp, A, &dA) == JIM_OK && Jim_GetDouble(interp, B, &dB) == JIM_OK) {
+ if (typeA == OBJ_IS_INT && typeB == OBJ_IS_INT) {
+ /* Both are ints */
- switch (e->opcode) {
- case JIM_EXPROP_LT: wC = dA<dB; break;
- case JIM_EXPROP_GT: wC = dA>dB; break;
- case JIM_EXPROP_LTE: wC = dA<=dB; break;
- case JIM_EXPROP_GTE: wC = dA>=dB; break;
- case JIM_EXPROP_NUMEQ: wC = dA==dB; break;
- case JIM_EXPROP_NUMNE: wC = dA!=dB; break;
- default: abort();
- }
- }
- /* Try ints */
- else if (JimGetWideNoErr(interp, A, &wA) == JIM_OK && JimGetWideNoErr(interp, B, &wB) == JIM_OK) {
+ intresult = 1;
switch (e->opcode) {
+ case JIM_EXPROP_ADD: wC = wA+wB; break;
+ case JIM_EXPROP_SUB: wC = wA-wB; break;
+ case JIM_EXPROP_MUL: wC = wA*wB; break;
+ case JIM_EXPROP_DIV:
+ if (wB == 0) {
+ wC = 0;
+ Jim_SetResultString(interp, "Division by zero", -1);
+ rc = JIM_ERR;
+ }
+ else {
+ /*
+ * From Tcl 8.x
+ *
+ * This code is tricky: C doesn't guarantee much
+ * about the quotient or remainder, but Tcl does.
+ * The remainder always has the same sign as the
+ * divisor and a smaller absolute value.
+ */
+ if (wB < 0) {
+ wB = -wB;
+ wA = -wA;
+ }
+ wC = wA / wB;
+ if (wA % wB < 0) {
+ wC--;
+ }
+ }
+ break;
case JIM_EXPROP_LT: wC = wA<wB; break;
case JIM_EXPROP_GT: wC = wA>wB; break;
case JIM_EXPROP_LTE: wC = wA<=wB; break;
@@ -6630,13 +6528,47 @@ static int JimExprOpBin(Jim_Interp *interp, struct expr_state *e)
default: abort();
}
}
+ else if (typeA != OBJ_NO_NUM && typeB != OBJ_NO_NUM) {
+ /* At least one is a double */
+ if (typeA == OBJ_IS_INT) {
+ Jim_GetDouble(interp, A, &dA);
+ }
+ else if (typeB == OBJ_IS_INT) {
+ Jim_GetDouble(interp, B, &dB);
+ }
+
+ switch (e->opcode) {
+ case JIM_EXPROP_ADD: dC = dA+dB; break;
+ case JIM_EXPROP_SUB: dC = dA-dB; break;
+ case JIM_EXPROP_MUL: dC = dA*dB; break;
+ case JIM_EXPROP_DIV:
+ if (dB == 0) {
+ dC = 0;
+ Jim_SetResultString(interp, "Division by zero", -1);
+ rc = JIM_ERR;
+ }
+ else {
+ dC = dA/dB;
+ }
+ break;
+ case JIM_EXPROP_LT: wC = dA<dB; intresult = 1; break;
+ case JIM_EXPROP_GT: wC = dA>dB; intresult = 1; break;
+ case JIM_EXPROP_LTE: wC = dA<=dB; intresult = 1; break;
+ case JIM_EXPROP_GTE: wC = dA>=dB; intresult = 1; break;
+ case JIM_EXPROP_NUMEQ: wC = dA==dB; intresult = 1; break;
+ case JIM_EXPROP_NUMNE: wC = dA!=dB; intresult = 1; break;
+ default: abort();
+ }
+ }
else {
- /* Finally compare strings */
+ /* Handle the string case */
int Alen, Blen;
const char *sA = Jim_GetString(A, &Alen);
const char *sB = Jim_GetString(B, &Blen);
+ intresult = 1;
+
switch(e->opcode) {
case JIM_EXPROP_LT:
wC = JimStringCompare(sA, Alen, sB, Blen, 0) < 0; break;
@@ -6650,21 +6582,30 @@ static int JimExprOpBin(Jim_Interp *interp, struct expr_state *e)
wC = (Alen == Blen && memcmp(sA, sB, Alen) == 0); break;
case JIM_EXPROP_NUMNE:
wC = (Alen != Blen || memcmp(sA, sB, Alen) != 0); break;
- default: abort();
+ default:
+ rc = JIM_ERR; break;
+ }
+ }
+
+ if (rc == JIM_OK) {
+ if (intresult) {
+ expr_push(e, Jim_NewIntObj(interp, wC));
+ }
+ else {
+ expr_push(e, Jim_NewDoubleObj(interp, dC));
}
}
- expr_push(e, Jim_NewIntObj(interp, wC));
Jim_DecrRefCount(interp, A);
Jim_DecrRefCount(interp, B);
- return JIM_OK;
+ return rc;
}
static int JimExprOpStrBin(Jim_Interp *interp, struct expr_state *e)
{
- Jim_Obj *B = expr_pop(interp, e, GET_STRING);
- Jim_Obj *A = expr_pop(interp, e, GET_STRING);
+ Jim_Obj *B = expr_pop(e);
+ Jim_Obj *A = expr_pop(e);
int Alen, Blen;
jim_wide wC;
@@ -6687,134 +6628,148 @@ static int JimExprOpStrBin(Jim_Interp *interp, struct expr_state *e)
return JIM_OK;
}
-static int expr_bool(Jim_Obj *obj)
+static int expr_bool(Jim_Interp *interp, Jim_Obj *obj)
{
- if (obj->typePtr == &doubleObjType) {
- return obj->internalRep.doubleValue != 0;
+ long l;
+ double d;
+ if (Jim_GetLong(interp, obj, &l) == JIM_OK) {
+ return l != 0;
}
- else if (obj->typePtr == &intObjType) {
- return obj->internalRep.wideValue != 0;
+ if (Jim_GetDouble(interp, obj, &d) == JIM_OK) {
+ return d != 0;
}
- assert(0);
+ return -1;
}
static int JimExprOpAndLeft(Jim_Interp *interp, struct expr_state *e)
{
- Jim_Obj *skip = expr_pop(interp, e, GET_INT);
- Jim_Obj *A = expr_pop(interp, e, GET_INT | GET_DOUBLE);
+ Jim_Obj *skip = expr_pop(e);
+ Jim_Obj *A = expr_pop(e);
+ int rc = JIM_OK;
- if (skip && A) {
- if (!expr_bool(A)) {
- /* Failed, so skip RHS opcodes with a 0 result */
+ switch (expr_bool(interp, A)) {
+ case 0:
+ /* false, so skip RHS opcodes with a 0 result */
e->skip = skip->internalRep.wideValue;
expr_push(e, Jim_NewIntObj(interp, 0));
- }
- Jim_DecrRefCount(interp, skip);
- Jim_DecrRefCount(interp, A);
- return JIM_OK;
- }
+ break;
+
+ case 1:
+ /* true so continue */
+ break;
- if (skip) {
- Jim_DecrRefCount(interp, skip);
+ case -1:
+ /* Invalid */
+ rc = JIM_ERR;
}
+ Jim_DecrRefCount(interp, A);
+ Jim_DecrRefCount(interp, skip);
- return JIM_ERR;
+ return rc;
}
static int JimExprOpOrLeft(Jim_Interp *interp, struct expr_state *e)
{
- Jim_Obj *skip = expr_pop(interp, e, GET_INT);
- Jim_Obj *A = expr_pop(interp, e, GET_INT | GET_DOUBLE);
+ Jim_Obj *skip = expr_pop(e);
+ Jim_Obj *A = expr_pop(e);
+ int rc = JIM_OK;
+
+ switch (expr_bool(interp, A)) {
+ case 0:
+ /* false, so do nothing */
+ break;
- if (skip && A) {
- if (expr_bool(A)) {
- /* Succeeded, so skip RHS opcodes with a 1 result */
+ case 1:
+ /* true so skip RHS opcodes with a 1 result */
e->skip = skip->internalRep.wideValue;
expr_push(e, Jim_NewIntObj(interp, 1));
- }
- Jim_DecrRefCount(interp, skip);
- Jim_DecrRefCount(interp, A);
- return JIM_OK;
- }
+ break;
- if (skip) {
- Jim_DecrRefCount(interp, skip);
+ case -1:
+ /* Invalid */
+ rc = JIM_ERR;
+ break;
}
+ Jim_DecrRefCount(interp, A);
+ Jim_DecrRefCount(interp, skip);
- assert(A == NULL);
-
- return JIM_ERR;
+ return rc;
}
static int JimExprOpAndOrRight(Jim_Interp *interp, struct expr_state *e)
{
- Jim_Obj *A = expr_pop(interp, e, GET_INT | GET_DOUBLE);
+ Jim_Obj *A = expr_pop(e);
+ int rc = JIM_OK;
- if (A) {
- expr_push(e, Jim_NewIntObj(interp, expr_bool(A)));
- Jim_DecrRefCount(interp, A);
- return JIM_OK;
+ switch (expr_bool(interp, A)) {
+ case 0:
+ expr_push(e, Jim_NewIntObj(interp, 0));
+ break;
+
+ case 1:
+ expr_push(e, Jim_NewIntObj(interp, 1));
+ break;
+
+ case -1:
+ /* Invalid */
+ rc = JIM_ERR;
+ break;
}
+ Jim_DecrRefCount(interp, A);
- return JIM_ERR;
+ return rc;
}
static int JimExprOpTernaryLeft(Jim_Interp *interp, struct expr_state *e)
{
- Jim_Obj *skip = expr_pop(interp, e, GET_INT);
- Jim_Obj *A = expr_pop(interp, e, GET_INT | GET_DOUBLE);
+ Jim_Obj *skip = expr_pop(e);
+ Jim_Obj *A = expr_pop(e);
+ int rc = JIM_OK;
- if (skip && A) {
- /* Repush A */
- expr_push(e, A);
- if (!expr_bool(A)) {
- /* Failed, so skip RHS opcodes */
+ /* Repush A */
+ expr_push(e, A);
+
+ switch (expr_bool(interp, A)) {
+ case 0:
+ /* false, skip RHS opcodes */
e->skip = skip->internalRep.wideValue;
/* Push a dummy value */
expr_push(e, Jim_NewIntObj(interp, 0));
- }
- Jim_DecrRefCount(interp, skip);
- Jim_DecrRefCount(interp, A);
- return JIM_OK;
- }
+ break;
+
+ case 1:
+ /* true so do nothing */
+ break;
- if (skip) {
- Jim_DecrRefCount(interp, skip);
+ case -1:
+ /* Invalid */
+ rc = JIM_ERR;
+ break;
}
+ Jim_DecrRefCount(interp, A);
+ Jim_DecrRefCount(interp, skip);
- return JIM_ERR;
+ return rc;
}
static int JimExprOpColonLeft(Jim_Interp *interp, struct expr_state *e)
{
- Jim_Obj *skip = expr_pop(interp, e, GET_INT);
- Jim_Obj *B = expr_pop(interp, e, GET_INT | GET_DOUBLE | GET_STRING);
- Jim_Obj *A = expr_pop(interp, e, GET_INT | GET_DOUBLE);
+ Jim_Obj *skip = expr_pop(e);
+ Jim_Obj *B = expr_pop(e);
+ Jim_Obj *A = expr_pop(e);
- if (skip && A && B) {
- if (expr_bool(A)) {
- /* Success, so skip RHS opcodes */
- e->skip = skip->internalRep.wideValue;
- /* Repush B as the answer */
- expr_push(e, B);
- }
- Jim_DecrRefCount(interp, skip);
- Jim_DecrRefCount(interp, A);
- Jim_DecrRefCount(interp, B);
- return JIM_OK;
+ /* No need to check for A as non-boolean */
+ if (expr_bool(interp, A)) {
+ /* true, so skip RHS opcodes */
+ e->skip = skip->internalRep.wideValue;
+ /* Repush B as the answer */
+ expr_push(e, B);
}
- if (skip) {
- Jim_DecrRefCount(interp, skip);
- }
- if (A) {
- Jim_DecrRefCount(interp, A);
- }
- if (B) {
- Jim_DecrRefCount(interp, B);
- }
-
- return JIM_ERR;
+ Jim_DecrRefCount(interp, skip);
+ Jim_DecrRefCount(interp, A);
+ Jim_DecrRefCount(interp, B);
+ return JIM_OK;
}
static int JimExprOpNull(Jim_Interp *interp, struct expr_state *e)
@@ -6836,12 +6791,12 @@ static const struct Jim_ExprOperator Jim_ExprOperators[] = {
[JIM_EXPROP_POW] = {"**", 250, 2, JimExprOpIntBin },
- [JIM_EXPROP_MUL] = {"*", 200, 2, JimExprOpNumBin },
- [JIM_EXPROP_DIV] = {"/", 200, 2, JimExprOpNumBin },
+ [JIM_EXPROP_MUL] = {"*", 200, 2, JimExprOpBin },
+ [JIM_EXPROP_DIV] = {"/", 200, 2, JimExprOpBin },
[JIM_EXPROP_MOD] = {"%", 200, 2, JimExprOpIntBin },
- [JIM_EXPROP_SUB] = {"-", 100, 2, JimExprOpNumBin },
- [JIM_EXPROP_ADD] = {"+", 100, 2, JimExprOpNumBin },
+ [JIM_EXPROP_SUB] = {"-", 100, 2, JimExprOpBin },
+ [JIM_EXPROP_ADD] = {"+", 100, 2, JimExprOpBin },
[JIM_EXPROP_ROTL] = {"<<<", 90, 2, JimExprOpIntBin },
[JIM_EXPROP_ROTR] = {">>>", 90, 2, JimExprOpIntBin },
diff --git a/tests/case.test b/tests/case.test
index 1973477..ce6075a 100644
--- a/tests/case.test
+++ b/tests/case.test
@@ -55,10 +55,10 @@ proc do_case {var} {
return two
}
3 {
- return 33
+ continue
}
4 {
- continue
+ return 44
}
5 {
break
@@ -76,5 +76,5 @@ test control-2.1 "Return from case" {
lappend result [do_case $i]
}
set result
-} {zero one two 33}
+} {zero one two 44}
diff --git a/tests/perf.test b/tests/perf.test
index fd28dff..e792c96 100644
--- a/tests/perf.test
+++ b/tests/perf.test
@@ -1,3 +1,5 @@
+set iterations 10000
+
set version [info patchlevel]
proc bench {name cmd} {
@@ -11,7 +13,7 @@ proc bench {name cmd} {
}
proc set_dict_sugar {} {
- for {set i 0} {$i < 10000} {incr i} {
+ for {set i 0} {$i < $::iterations} {incr i} {
set a(b) $i
}
}
@@ -20,7 +22,7 @@ proc set_dict_sugar {} {
# speedup since a($b) needs to be interpolated and reparsed every time
proc set_var_dict_sugar {} {
set b b
- for {set i 0} {$i < 10000} {incr i} {
+ for {set i 0} {$i < $::iterations} {incr i} {
set a($b) $i
}
}
@@ -102,7 +104,7 @@ proc read_file_split_assign_lindex {file} {
# Create a really big file
set f [open test.in w]
-for {set i 0} {$i < 10000} {incr i} {
+for {set i 0} {$i < $::iterations} {incr i} {
puts $f "a\tb\tc\te\tf\tg\th\ti\tj\tk"
}
close $f