diff options
| author | sebres <sebres@users.sourceforge.net> | 2024-06-12 00:17:18 (GMT) |
|---|---|---|
| committer | sebres <sebres@users.sourceforge.net> | 2024-06-12 00:17:18 (GMT) |
| commit | 9cca6cadd9fb96e7e52c48a1e9885bb9ca3c417d (patch) | |
| tree | e26e5a806e56720bc90c686a70462be9c8229b0f | |
| parent | 88a04f641970ef62f7e81a88ccddd914e16c38a0 (diff) | |
| parent | 57f3d0d139f13955e69bbc6833d6ad01b9983396 (diff) | |
| download | tcl-9cca6cadd9fb96e7e52c48a1e9885bb9ca3c417d.zip tcl-9cca6cadd9fb96e7e52c48a1e9885bb9ca3c417d.tar.gz tcl-9cca6cadd9fb96e7e52c48a1e9885bb9ca3c417d.tar.bz2 | |
merge 8.7 (fix for [f05f5ef759c1f7f9])
| -rw-r--r-- | generic/tclCmdIL.c | 136 | ||||
| -rw-r--r-- | tests/lseq.test | 26 |
2 files changed, 89 insertions, 73 deletions
diff --git a/generic/tclCmdIL.c b/generic/tclCmdIL.c index 83320cd..ad8eb94 100644 --- a/generic/tclCmdIL.c +++ b/generic/tclCmdIL.c @@ -105,12 +105,8 @@ static const char *const seq_operations[] = { typedef enum Sequence_Operators { LSEQ_DOTS, LSEQ_TO, LSEQ_COUNT, LSEQ_BY } SequenceOperators; -static const char *const seq_step_keywords[] = {"by", NULL}; -typedef enum Step_Operators { - STEP_BY = 4 -} SequenceByMode; typedef enum Sequence_Decoded { - NoneArg, NumericArg, RangeKeywordArg, ByKeywordArg + NoneArg, NumericArg, RangeKeywordArg } SequenceDecoded; /* @@ -4027,7 +4023,7 @@ Tcl_LsearchObjCmd( * 3 - value is a by keyword * * The decoded value will be assigned to the appropriate - * pointer, if supplied. + * pointer, numValuePtr reference count is incremented. */ static SequenceDecoded @@ -4037,71 +4033,45 @@ SequenceIdentifyArgument( Tcl_Obj **numValuePtr, /* Return numeric value */ int *keywordIndexPtr) /* Return keyword enum */ { - int status; + int result; SequenceOperators opmode; - SequenceByMode bymode; - void *clientData; + void *internalPtr; - status = Tcl_GetNumberFromObj(NULL, argPtr, &clientData, keywordIndexPtr); - if (status == TCL_OK) { - if (numValuePtr) { - *numValuePtr = argPtr; - } + result = Tcl_GetNumberFromObj(NULL, argPtr, &internalPtr, keywordIndexPtr); + if (result == TCL_OK) { + *numValuePtr = argPtr; + Tcl_IncrRefCount(argPtr); return NumericArg; + } + + result = Tcl_GetIndexFromObj(NULL, argPtr, seq_operations, + "range operation", 0, &opmode); + if (result == TCL_OK) { + *keywordIndexPtr = opmode; + return RangeKeywordArg; } else { /* Check for an index expression */ - long value; - double dvalue; + SequenceDecoded ret = NoneArg; Tcl_Obj *exprValueObj; int keyword; Tcl_InterpState savedstate; - savedstate = Tcl_SaveInterpState(interp, status); - if (Tcl_ExprLongObj(interp, argPtr, &value) != TCL_OK) { - status = Tcl_RestoreInterpState(interp, savedstate); - exprValueObj = argPtr; - } else { - // Determine if expression is double or int - if (Tcl_ExprDoubleObj(interp, argPtr, &dvalue) != TCL_OK) { - keyword = TCL_NUMBER_INT; - exprValueObj = argPtr; - } else { - if (floor(dvalue) == dvalue) { - TclNewIntObj(exprValueObj, value); - keyword = TCL_NUMBER_INT; - } else { - TclNewDoubleObj(exprValueObj, dvalue); - keyword = TCL_NUMBER_DOUBLE; - } - } - status = Tcl_RestoreInterpState(interp, savedstate); - if (numValuePtr) { - *numValuePtr = exprValueObj; - } - if (keywordIndexPtr) { - *keywordIndexPtr = keyword ;// type of expression result - } - return NumericArg; - } - } - - status = Tcl_GetIndexFromObj(NULL, argPtr, seq_operations, - "range operation", 0, &opmode); - if (status == TCL_OK) { - if (keywordIndexPtr) { - *keywordIndexPtr = opmode; + savedstate = Tcl_SaveInterpState(interp, result); + if (Tcl_ExprObj(interp, argPtr, &exprValueObj) != TCL_OK) { + goto done; } - return RangeKeywordArg; - } - - status = Tcl_GetIndexFromObj(NULL, argPtr, seq_step_keywords, - "step keyword", 0, &bymode); - if (status == TCL_OK) { - if (keywordIndexPtr) { - *keywordIndexPtr = bymode; + /* Determine if result of expression is double or int */ + if (Tcl_GetNumberFromObj(NULL, exprValueObj, &internalPtr, + &keyword) != TCL_OK + ) { + goto done; } - return ByKeywordArg; + *numValuePtr = exprValueObj; /* incremented in Tcl_ExprObj */ + *keywordIndexPtr = keyword; /* type of expression result */ + ret = NumericArg; + done: + (void)Tcl_RestoreInterpState(interp, savedstate); + return ret; } - return NoneArg; } /* @@ -4157,9 +4127,9 @@ Tcl_LseqObjCmd( SequenceOperators opmode; SequenceDecoded decoded; int i, arg_key = 0, value_i = 0; - // Default constants - Tcl_Obj *zero = Tcl_NewIntObj(0); - Tcl_Obj *one = Tcl_NewIntObj(1); + /* Default constants */ + #define zero ((Interp *)interp)->execEnvPtr->constants[0]; + #define one ((Interp *)interp)->execEnvPtr->constants[1]; /* * Create a decoding key by looping through the arguments and identify @@ -4187,7 +4157,6 @@ Tcl_LseqObjCmd( case NumericArg: arg_key += NumericArg; numValues[value_i] = numberObj; - Tcl_IncrRefCount(numValues[value_i]); values[value_i] = keyword; // This is the TCL_NUMBER_* value useDoubles = useDoubles ? useDoubles : keyword == TCL_NUMBER_DOUBLE; value_i++; @@ -4199,12 +4168,6 @@ Tcl_LseqObjCmd( value_i++; break; - case ByKeywordArg: - arg_key += ByKeywordArg; - values[value_i] = keyword; - value_i++; - break; - default: arg_key += 9; // Error state value_i++; @@ -4379,6 +4342,27 @@ Tcl_LseqObjCmd( break; } + /* Count needs to be integer, so try to convert if possible */ + if (elementCount && TclHasInternalRep(elementCount, &tclDoubleType)) { + double d; + (void)Tcl_GetDoubleFromObj(NULL, elementCount, &d); + if (floor(d) == d) { + if ((d >= (double)WIDE_MAX) || (d <= (double)WIDE_MIN)) { + mp_int big; + + if (Tcl_InitBignumFromDouble(NULL, d, &big) == TCL_OK) { + elementCount = Tcl_NewBignumObj(&big); + keyword = TCL_NUMBER_INT; + } + /* Infinity, don't convert, let fail later */ + } else { + elementCount = Tcl_NewWideIntObj((Tcl_WideInt)d); + keyword = TCL_NUMBER_INT; + } + } + } + + /* * Success! Now lets create the series object. */ @@ -4393,13 +4377,19 @@ Tcl_LseqObjCmd( // Free number arguments. while (--value_i>=0) { if (numValues[value_i]) { + if (elementCount == numValues[value_i]) { + elementCount = NULL; + } Tcl_DecrRefCount(numValues[value_i]); } } + if (elementCount) { + Tcl_DecrRefCount(elementCount); + } - // Free constants - Tcl_DecrRefCount(zero); - Tcl_DecrRefCount(one); + /* Undef constants */ + #undef zero + #undef one return status; } diff --git a/tests/lseq.test b/tests/lseq.test index feb0a29..569af95 100644 --- a/tests/lseq.test +++ b/tests/lseq.test @@ -140,6 +140,19 @@ test lseq-1.22 {n n by -n} { lseq 84 66 by -3 } {84 81 78 75 72 69 66} +test lseq-1.23 {consistence, accept double count representable as integer (but use double in series)} { + list [lseq 0.0 2.0] [lseq 3.0] [lseq 0 count 3.0] \ + [lseq 0.0 count 3.0] [lseq 0 count 3.0 by 1.0] +} [lrepeat 5 {0.0 1.0 2.0}] +test lseq-1.24 {consistence, use double (even if representable as integer) in all variants, if contains a double somewhere} { + list [lseq 0.0 2] [lseq 0 2.0] [lseq 0.0 count 3] \ + [lseq 0 count 3 by 1.0] [lseq 0 .. 2.0] [lseq 0 to 2 by 1.0] +} [lrepeat 6 {0.0 1.0 2.0}] +test lseq-1.25 {consistence, use double (even if representable as integer) in all variants, if contains a double somewhere} { + list [lseq double(0) 2] [lseq 0 double(2)] [lseq double(0) count 3] \ + [lseq 0 count 3 by double(1)] [lseq 0 .. double(2)] [lseq 0 to 2 by double(1)] +} [lrepeat 6 {0.0 1.0 2.0}] + # # Short-hand use cases # @@ -221,6 +234,19 @@ test lseq-2.18 {signs} { } {{-10 -8 -6 -4 -2} {} {} {10 6 2} {-10 -7 -4 -1} {10 5}} +test lseq-2.19 {expressions as indices} { + list [lseq {1+1}] \ + [lseq {1+1} {2+2}] \ + [lseq {1+1} count {2+2}] \ + [lseq {1+1} {5+5} {2+2}] \ + [lseq {1+1} count {2+2} by {2+2}] +} {{0 1} {2 3 4} {2 3 4 5} {2 6 10} {2 6 10 14}} + +test lseq-2.20 {expressions as indices, no duplicative eval of expr} { + set i 1 + list [lseq {[incr i]}] $i [lseq {0 + [incr i]}] $i [lseq {0.0 + [incr i]}] $i +} {{0 1} 2 {0 1 2} 3 {0.0 1.0 2.0 3.0} 4} + test lseq-3.1 {experiement} -body { set ans {} foreach factor [lseq 2.0 10.0] { |
