Many hyperlinks are disabled.
Use anonymous login
to enable hyperlinks.
Changes In Branch tip-582 Excluding Merge-Ins
This is equivalent to a diff from c15e8bc4bb to ef5fd3e260
2020-11-08
| ||
17:21 | TIP 582: Comments in Expressions check-in: e518808108 user: dkf tags: core-8-branch | |
2020-11-06
| ||
14:43 | Deprecate the (internal) functions TclGuessPackageName/TclGetLoadedPackages functions, since they tu... check-in: 7b2277bf8b user: jan.nijtmans tags: core-8-branch | |
09:59 | Lesser TIP #590 implementation: Only package renaming, no code changes check-in: 5cb1460243 user: jan.nijtmans tags: tip-590 | |
2020-11-05
| ||
17:06 | Merge 8.7 check-in: 23c0c45dd0 user: jan.nijtmans tags: tip-575 | |
2020-11-03
| ||
15:32 | Case-sensitive package names check-in: b15b349bfb user: jan.nijtmans tags: case-sensitive-pkg | |
2020-11-01
| ||
14:25 | Merge 8.7 Closed-Leaf check-in: ef5fd3e260 user: dkf tags: tip-582 | |
2020-10-30
| ||
20:23 | merge 8.7 check-in: 8da1570d62 user: dgp tags: tip-568 | |
20:17 | merge 8.7 check-in: 5cbe392b39 user: dgp tags: dgp-review | |
15:31 | Merge 8.7 check-in: 707d6eadba user: jan.nijtmans tags: build-info | |
15:13 | Merge 8.7 Closed-Leaf check-in: 2c1ee70bdc user: jan.nijtmans tags: tip-586-binary-scan-c-string | |
14:25 | Merge 8.7 check-in: 0f952be066 user: jan.nijtmans tags: trunk, main | |
14:05 | Merge 8.6 check-in: c15e8bc4bb user: jan.nijtmans tags: core-8-branch | |
13:56 | Simplify testcases using "incr" check-in: 165a804445 user: jan.nijtmans tags: core-8-6-branch | |
13:37 | Merge 8.6 check-in: 6312e0d10c user: jan.nijtmans tags: core-8-branch | |
2020-10-24
| ||
14:50 | Merge 8.7 check-in: 1f4f5e1fcd user: jan.nijtmans tags: tip-582 | |
Changes to doc/expr.n.
︙ | ︙ | |||
37 38 39 40 41 42 43 44 45 46 47 48 49 50 | non-numeric operands, string comparisons, and some additional operators not found in C. .PP When an expression evaluates to an integer, the value is the decimal form of the integer, and when an expression evaluates to a floating-point number, the value is the form produced by the \fB%g\fR format specifier of Tcl's \fBformat\fR command. .SS OPERANDS .PP An expression consists of a combination of operands, operators, parentheses and commas, possibly with whitespace between any of these elements, which is ignored. .PP An operand may be specified in any of the following ways: | > > > > > > | 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 | non-numeric operands, string comparisons, and some additional operators not found in C. .PP When an expression evaluates to an integer, the value is the decimal form of the integer, and when an expression evaluates to a floating-point number, the value is the form produced by the \fB%g\fR format specifier of Tcl's \fBformat\fR command. .PP .VS "TIP 582" You can use \fB#\fR at any point in the expression (except inside double quotes or braces) to start a comment. Comments last to the end of the line or the end of the expression, whichever comes first. .VE "TIP 582" .SS OPERANDS .PP An expression consists of a combination of operands, operators, parentheses and commas, possibly with whitespace between any of these elements, which is ignored. .PP An operand may be specified in any of the following ways: |
︙ | ︙ | |||
483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 | .CE .PP Set a variable indicating whether an environment variable is defined and has value of true: .PP .CS set isTrue [\fBexpr\fR { [info exists ::env(SOME_ENV_VAR)] && [string is true -strict $::env(SOME_ENV_VAR)] }] .CE .PP Generate a random integer in the range 0..99 inclusive: .PP .CS | > > | 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 | .CE .PP Set a variable indicating whether an environment variable is defined and has value of true: .PP .CS set isTrue [\fBexpr\fR { # Does the environment variable exist, and... [info exists ::env(SOME_ENV_VAR)] && # ...does it contain a proper true value? [string is true -strict $::env(SOME_ENV_VAR)] }] .CE .PP Generate a random integer in the range 0..99 inclusive: .PP .CS |
︙ | ︙ |
Changes to generic/tclCompExpr.c.
︙ | ︙ | |||
160 161 162 163 164 165 166 167 168 169 170 171 172 173 | #define BAREWORD 3 /* Ambigous. Resolves to BOOLEAN or to * FUNCTION or a parse error according to * context and value. */ #define INCOMPLETE 4 /* A parse error. Used only when the single * "=" is encountered. */ #define INVALID 5 /* A parse error. Used when any punctuation * appears that's not a supported operator. */ /* Leaf lexemes */ #define NUMBER (LEAF | 1) /* For literal numbers */ #define SCRIPT (LEAF | 2) /* Script substitution; [foo] */ | > > | 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 | #define BAREWORD 3 /* Ambigous. Resolves to BOOLEAN or to * FUNCTION or a parse error according to * context and value. */ #define INCOMPLETE 4 /* A parse error. Used only when the single * "=" is encountered. */ #define INVALID 5 /* A parse error. Used when any punctuation * appears that's not a supported operator. */ #define COMMENT 6 /* Comment. Lasts to end of line or end of * expression, whichever comes first. */ /* Leaf lexemes */ #define NUMBER (LEAF | 1) /* For literal numbers */ #define SCRIPT (LEAF | 2) /* Script substitution; [foo] */ |
︙ | ︙ | |||
458 459 460 461 462 463 464 | INVALID /* DC4 */, INVALID /* NAK */, INVALID /* SYN */, INVALID /* ETB */, INVALID /* CAN */, INVALID /* EM */, INVALID /* SUB */, INVALID /* ESC */, INVALID /* FS */, INVALID /* GS */, INVALID /* RS */, INVALID /* US */, INVALID /* SPACE */, 0 /* ! or != */, | | | 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 | INVALID /* DC4 */, INVALID /* NAK */, INVALID /* SYN */, INVALID /* ETB */, INVALID /* CAN */, INVALID /* EM */, INVALID /* SUB */, INVALID /* ESC */, INVALID /* FS */, INVALID /* GS */, INVALID /* RS */, INVALID /* US */, INVALID /* SPACE */, 0 /* ! or != */, QUOTED /* " */, 0 /* # */, VARIABLE /* $ */, MOD /* % */, 0 /* & or && */, INVALID /* ' */, OPEN_PAREN /* ( */, CLOSE_PAREN /* ) */, 0 /* * or ** */, PLUS /* + */, COMMA /* , */, MINUS /* - */, 0 /* . */, DIVIDE /* / */, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0-9 */ |
︙ | ︙ | |||
670 671 672 673 674 675 676 | */ if (nodesUsed >= nodesAvailable) { unsigned int size = nodesUsed * 2; OpNode *newPtr = NULL; do { | | > | | | 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 | */ if (nodesUsed >= nodesAvailable) { unsigned int size = nodesUsed * 2; OpNode *newPtr = NULL; do { if (size <= UINT_MAX/sizeof(OpNode)) { newPtr = (OpNode *) attemptckrealloc(nodes, size * sizeof(OpNode)); } } while ((newPtr == NULL) && ((size -= (size - nodesUsed) / 2) > nodesUsed)); if (newPtr == NULL) { TclNewLiteralStringObj(msg, "not enough memory to parse expression"); errCode = "NOMEM"; goto error; |
︙ | ︙ | |||
704 705 706 707 708 709 710 711 712 713 714 715 716 717 | * Use context to categorize the lexemes that are ambiguous. */ if ((NODE_TYPE & lexeme) == 0) { int b; switch (lexeme) { case INVALID: msg = Tcl_ObjPrintf("invalid character \"%.*s\"", scanned, start); errCode = "BADCHAR"; goto error; case INCOMPLETE: msg = Tcl_ObjPrintf("incomplete operator \"%.*s\"", | > > > > | 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 | * Use context to categorize the lexemes that are ambiguous. */ if ((NODE_TYPE & lexeme) == 0) { int b; switch (lexeme) { case COMMENT: start += scanned; numBytes -= scanned; continue; case INVALID: msg = Tcl_ObjPrintf("invalid character \"%.*s\"", scanned, start); errCode = "BADCHAR"; goto error; case INCOMPLETE: msg = Tcl_ObjPrintf("incomplete operator \"%.*s\"", |
︙ | ︙ | |||
738 739 740 741 742 743 744 745 746 747 748 749 750 751 | * names we've parsed in the order we found them. */ Tcl_ListObjAppendElement(NULL, funcList, literal); } else if (Tcl_GetBooleanFromObj(NULL,literal,&b) == TCL_OK) { lexeme = BOOLEAN; } else { Tcl_DecrRefCount(literal); msg = Tcl_ObjPrintf("invalid bareword \"%.*s%s\"", (scanned < limit) ? scanned : limit - 3, start, (scanned < limit) ? "" : "..."); post = Tcl_ObjPrintf( "should be \"$%.*s%s\" or \"{%.*s%s}\"", (scanned < limit) ? scanned : limit - 3, | > > > > > > > > > > > > > > > > > > > > > > > > > > | 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 | * names we've parsed in the order we found them. */ Tcl_ListObjAppendElement(NULL, funcList, literal); } else if (Tcl_GetBooleanFromObj(NULL,literal,&b) == TCL_OK) { lexeme = BOOLEAN; } else { /* * Tricky case: see test expr-62.10 */ int scanned2 = scanned; do { scanned2 += TclParseAllWhiteSpace( start + scanned2, numBytes - scanned2); scanned2 += ParseLexeme( start + scanned2, numBytes - scanned2, &lexeme, NULL); } while (lexeme == COMMENT); if (lexeme == OPEN_PAREN) { /* * Actually a function call, but with obscuring * comments. Skip to the start of the parentheses. * Note that we assume that open parentheses are one * byte long. */ lexeme = FUNCTION; Tcl_ListObjAppendElement(NULL, funcList, literal); scanned = scanned2 - 1; break; } Tcl_DecrRefCount(literal); msg = Tcl_ObjPrintf("invalid bareword \"%.*s%s\"", (scanned < limit) ? scanned : limit - 3, start, (scanned < limit) ? "" : "..."); post = Tcl_ObjPrintf( "should be \"$%.*s%s\" or \"{%.*s%s}\"", (scanned < limit) ? scanned : limit - 3, |
︙ | ︙ | |||
1890 1891 1892 1893 1894 1895 1896 | int numBytes, /* Number of bytes in string. */ unsigned char *lexemePtr, /* Write code of parsed lexeme to this * storage. */ Tcl_Obj **literalPtr) /* Write corresponding literal value to this storage, if non-NULL. */ { const char *end; | | > > > > > > > > > > | 1923 1924 1925 1926 1927 1928 1929 1930 1931 1932 1933 1934 1935 1936 1937 1938 1939 1940 1941 1942 1943 1944 1945 1946 1947 1948 1949 1950 1951 1952 1953 1954 1955 1956 1957 1958 1959 1960 1961 | int numBytes, /* Number of bytes in string. */ unsigned char *lexemePtr, /* Write code of parsed lexeme to this * storage. */ Tcl_Obj **literalPtr) /* Write corresponding literal value to this storage, if non-NULL. */ { const char *end; int scanned, size; Tcl_UniChar ch = 0; Tcl_Obj *literal = NULL; unsigned char byte; if (numBytes == 0) { *lexemePtr = END; return 0; } byte = UCHAR(*start); if (byte < sizeof(Lexeme) && Lexeme[byte] != 0) { *lexemePtr = Lexeme[byte]; return 1; } switch (byte) { case '#': /* * Scan forward over the comment contents. */ for (size = 0; byte != '\n' && byte != 0 && size < numBytes; size++) { byte = UCHAR(start[size]); } *lexemePtr = COMMENT; return size - (byte == '\n'); case '*': if ((numBytes > 1) && (start[1] == '*')) { *lexemePtr = EXPON; return 2; } *lexemePtr = MULT; return 1; |
︙ | ︙ |
Changes to tests/compExpr.test.
︙ | ︙ | |||
367 368 369 370 371 372 373 | set end [getbytes] } set leakedBytes [expr {$end - $tmp}] } -cleanup { unset end i tmp rename getbytes {} } -result 0 | | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 | set end [getbytes] } set leakedBytes [expr {$end - $tmp}] } -cleanup { unset end i tmp rename getbytes {} } -result 0 proc extract {opcodes descriptor} { set instructions [dict values [dict get $descriptor instructions]] return [lmap i $instructions { if {[lindex $i 0] in $opcodes} {string cat $i} else continue }] } test compExpr-8.1 {TIP 582: expression comments} -setup {} -body { extract {loadStk add} [tcl::unsupported::getbytecode script {expr { $abc # + $def + $ghi }}] } -result {loadStk loadStk add} test compExpr-8.2 {TIP 582: expression comments} -setup {} -body { extract {loadStk add} [tcl::unsupported::getbytecode script {expr { $abc # + $def # + $ghi }}] } -result loadStk test compExpr-8.3 {TIP 582: expression comments} -setup {} -body { extract {loadStk add} [tcl::unsupported::getbytecode script {expr { $abc # + $def\ + $ghi }}] } -result loadStk test compExpr-8.4 {TIP 582: expression comments} -setup {} -body { extract {loadStk add} [tcl::unsupported::getbytecode script {expr { $abc # + $def\\ + $ghi }}] } -result {loadStk loadStk add} # cleanup catch {unset a} catch {unset b} catch {rename extract ""} ::tcltest::cleanupTests return # Local Variables: # mode: tcl # fill-column: 78 # End: |
Changes to tests/expr-old.test.
︙ | ︙ | |||
520 521 522 523 524 525 526 | test expr-old-26.10a {error conditions} !ieeeFloatingPoint { list [catch {expr 2.0/0.0} msg] $msg $errorCode } {1 {divide by zero} {ARITH DIVZERO {divide by zero}}} test expr-old-26.10b {error conditions} ieeeFloatingPoint { list [catch {expr 2.0/0.0} msg] $msg } {0 Inf} test expr-old-26.11 {error conditions} -body { | | | 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 | test expr-old-26.10a {error conditions} !ieeeFloatingPoint { list [catch {expr 2.0/0.0} msg] $msg $errorCode } {1 {divide by zero} {ARITH DIVZERO {divide by zero}}} test expr-old-26.10b {error conditions} ieeeFloatingPoint { list [catch {expr 2.0/0.0} msg] $msg } {0 Inf} test expr-old-26.11 {error conditions} -body { expr 2` } -returnCodes error -match glob -result * test expr-old-26.12 {error conditions} -body { expr a.b } -returnCodes error -match glob -result * test expr-old-26.13 {error conditions} { list [catch {expr {"a"/"b"}} msg] $msg } {1 {can't use non-numeric string as operand of "/"}} |
︙ | ︙ |
Changes to tests/expr.test.
︙ | ︙ | |||
7380 7381 7382 7383 7384 7385 7386 7387 7388 7389 7390 7391 7392 7393 | foreach v2 $values r2 $results { test expr-61.[incr ctr] "float classification: isunordered($v1,$v2)" { expr {isunordered($v1, $v2)} } [expr {$r1 || $r2}] } } unset -nocomplain values results ctr # cleanup unset -nocomplain a unset -nocomplain min unset -nocomplain max ::tcltest::cleanupTests return | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 7380 7381 7382 7383 7384 7385 7386 7387 7388 7389 7390 7391 7392 7393 7394 7395 7396 7397 7398 7399 7400 7401 7402 7403 7404 7405 7406 7407 7408 7409 7410 7411 7412 7413 7414 7415 7416 7417 7418 7419 7420 7421 7422 7423 7424 7425 7426 7427 7428 7429 7430 7431 7432 7433 7434 7435 7436 7437 7438 7439 7440 7441 7442 7443 7444 7445 7446 7447 7448 7449 7450 7451 7452 7453 7454 | foreach v2 $values r2 $results { test expr-61.[incr ctr] "float classification: isunordered($v1,$v2)" { expr {isunordered($v1, $v2)} } [expr {$r1 || $r2}] } } unset -nocomplain values results ctr test expr-62.1 {TIP 582: comments} -body { expr {1 # + 2} } -result 1 test expr-62.2 {TIP 582: comments} -body { expr "1 #\n+ 2" } -result 3 test expr-62.3 {TIP 582: comments} -setup { set ctr 0 } -body { expr { # This is a demonstration of a comment 1 + 2 + 3 # and another comment + 4 + 5 # + [incr ctr] + [incr ctr] } } -result 16 # Buggy because line breaks aren't tracked inside expressions at all test expr-62.4 {TIP 582: comments don't hide line breaks} -setup { proc getline {} { dict get [info frame -1] line } set base [getline] } -constraints knownBug -body { expr { 0 # a comment + [getline] - $base } } -cleanup { rename getline "" } -result 5 test expr-62.5 {TIP 582: comments don't splice tokens} { set a False expr {$a#don't splice ne#don't splice false} } 1 test expr-62.6 {TIP 582: comments don't splice tokens} { expr {0x2#don't splice ne#don't splice 2} } 1 test expr-62.7 {TIP 582: comments can go inside function calls} { expr {max(1,# comment 2)} } 2 test expr-62.8 {TIP 582: comments can go inside function calls} { expr {max(1# comment ,2)} } 2 test expr-62.9 {TIP 582: comments can go inside function calls} { expr {max(# comment 1,2)} } 2 test expr-62.10 {TIP 582: comments can go inside function calls} { expr {max# comment (1,2)} } 2 # cleanup unset -nocomplain a unset -nocomplain min unset -nocomplain max ::tcltest::cleanupTests return |
︙ | ︙ |
Changes to tests/parseExpr.test.
︙ | ︙ | |||
1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 | } -returnCodes error -match glob -result {*invalid character*} test parseExpr-22.20 {Bug d2ffcca163} -constraints testexprparser -body { testexprparser \u043f -1 } -returnCodes error -match glob -result {*invalid character*} test parseExpr-22.21 {Bug d2ffcca163} -constraints testexprparser -body { testexprparser in\u0433(0) -1 } -returnCodes error -match glob -result {missing operand*} # cleanup cleanupTests return | > > > > > > > > | 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 | } -returnCodes error -match glob -result {*invalid character*} test parseExpr-22.20 {Bug d2ffcca163} -constraints testexprparser -body { testexprparser \u043f -1 } -returnCodes error -match glob -result {*invalid character*} test parseExpr-22.21 {Bug d2ffcca163} -constraints testexprparser -body { testexprparser in\u0433(0) -1 } -returnCodes error -match glob -result {missing operand*} test parseExpr-23.1 {TIP 582: comments} -constraints testexprparser -body { testexprparser "7 # * 8 " -1 } -result {- {} 0 subexpr 7 1 text 7 0 {}} test parseExpr-23.2 {TIP 582: comments} -constraints testexprparser -body { testexprparser "7 #\n* 8 " -1 } -result {- {} 0 subexpr {7 # *} 5 operator # 0 subexpr 7 1 text 7 0 subexpr * 1 text * 0 {}} # cleanup cleanupTests return |