diff options
author | Steve Bennett <steveb@workware.net.au> | 2010-01-24 12:00:22 +1000 |
---|---|---|
committer | Steve Bennett <steveb@workware.net.au> | 2010-10-15 11:02:43 +1000 |
commit | 2ae1c01c1b0b7d24fa2eeff3545b375d25c18c66 (patch) | |
tree | d37b63d50fea502fe61b98943ca380a4aa4d053d | |
parent | 17b0f14f5e17efb7e70e47e711c6339e524875f8 (diff) | |
download | jimtcl-2ae1c01c1b0b7d24fa2eeff3545b375d25c18c66.zip jimtcl-2ae1c01c1b0b7d24fa2eeff3545b375d25c18c66.tar.gz jimtcl-2ae1c01c1b0b7d24fa2eeff3545b375d25c18c66.tar.bz2 |
Simplify expr evaluation
-rw-r--r-- | BUGS | 12 | ||||
-rw-r--r-- | TODO | 41 | ||||
-rw-r--r-- | bench.tcl | 10 | ||||
-rw-r--r-- | jim.c | 599 | ||||
-rw-r--r-- | tests/case.test | 6 | ||||
-rw-r--r-- | tests/perf.test | 8 |
6 files changed, 307 insertions, 369 deletions
@@ -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. @@ -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. @@ -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}] @@ -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 |