Many hyperlinks are disabled.
Use anonymous login
to enable hyperlinks.
Changes In Branch bg-tip-282 Through [7a3f8cded6] Excluding Merge-Ins
This is equivalent to a diff from 6c53c071ed to 7a3f8cded6
|
2017-02-16
| ||
| 18:32 | Contibuted patch from Brian Griffin implementing a variation on TIP 282. Closed-Leaf check-in: 7a3f8cded6 user: dgp tags: bg-tip-282 | |
|
2016-11-02
| ||
| 01:42 | Fix the generated copyright sections in the HTML help file. Closed-Leaf check-in: 13b8547f59 user: mistachkin tags: htmlCopyrightsFix | |
|
2016-07-27
| ||
| 18:55 | merge release check-in: cea1f5457e user: dgp tags: core-8-6-branch | |
|
2016-07-26
| ||
| 13:54 | a few test & docs fixes Closed-Leaf check-in: 6c53c071ed user: dgp tags: rc2, release, core-8-6-6-rc, core-8-6-6 | |
| 10:08 | [db0a5f6417] Make a few tests resilient to differences in semantics of pipes between OSs. check-in: 1cf98255a8 user: dkf tags: core-8-6-branch | |
|
2016-07-22
| ||
| 15:28 | test repairs check-in: 09fc39def5 user: dgp tags: rc1, core-8-6-6-rc | |
Changes to generic/tclCompExpr.c.
| ︙ | ︙ | |||
179 180 181 182 183 184 185 186 187 188 189 190 191 192 | /* Variable substitution; $x */ #define QUOTED (LEAF | 6) /* Quoted string; "foo $bar [soom]" */ #define EMPTY (LEAF | 7) /* Used only for an empty argument list to a * function. Represents the empty string * within parens in the expression: rand() */ /* Unary operator lexemes */ #define UNARY_PLUS (UNARY | PLUS) #define UNARY_MINUS (UNARY | MINUS) #define FUNCTION (UNARY | BAREWORD) /* This is a bit of "creative interpretation" | > > | 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 |
/* Variable substitution; $x */
#define QUOTED (LEAF | 6)
/* Quoted string; "foo $bar [soom]" */
#define EMPTY (LEAF | 7)
/* Used only for an empty argument list to a
* function. Represents the empty string
* within parens in the expression: rand() */
#define VARNAME (LEAF | 8)
/* Bareword as varname target of assignment */
/* Unary operator lexemes */
#define UNARY_PLUS (UNARY | PLUS)
#define UNARY_MINUS (UNARY | MINUS)
#define FUNCTION (UNARY | BAREWORD)
/* This is a bit of "creative interpretation"
|
| ︙ | ︙ | |||
277 278 279 280 281 282 283 | * for us. In the end though, a close paren is * not really a binary operator, and some * special coding in ParseExpr() make sure we * never put an actual CLOSE_PAREN node in the * parse tree. The sub-expression between * parens becomes the single argument of the * matching OPEN_PAREN unary operator. */ | > > > > > > > | | 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 | * for us. In the end though, a close paren is * not really a binary operator, and some * special coding in ParseExpr() make sure we * never put an actual CLOSE_PAREN node in the * parse tree. The sub-expression between * parens becomes the single argument of the * matching OPEN_PAREN unary operator. */ #define SEPARATOR ( BINARY | 29) #define ASSIGN ( BINARY | 30) /* ASSIGN, like EXPON, is right * associative, and this distinction * is coded directly in ParseExpr() */ #define END (BINARY | 31) /* This lexeme represents the end of the * string being parsed. Treating it as a * binary operator follows the same logic as * the CLOSE_PAREN lexeme and END pairs with * START, in the same way that CLOSE_PAREN * pairs with OPEN_PAREN. */ |
| ︙ | ︙ | |||
300 301 302 303 304 305 306 307 308 309 310 311 312 313 |
enum Precedence {
PREC_END = 1, /* END */
PREC_START, /* START */
PREC_CLOSE_PAREN, /* ")" */
PREC_OPEN_PAREN, /* "(" */
PREC_COMMA, /* "," */
PREC_CONDITIONAL, /* "?", ":" */
PREC_OR, /* "||" */
PREC_AND, /* "&&" */
PREC_BIT_OR, /* "|" */
PREC_BIT_XOR, /* "^" */
PREC_BIT_AND, /* "&" */
PREC_EQUAL, /* "==", "!=", "eq", "ne", "in", "ni" */
| > > | 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 |
enum Precedence {
PREC_END = 1, /* END */
PREC_START, /* START */
PREC_CLOSE_PAREN, /* ")" */
PREC_OPEN_PAREN, /* "(" */
PREC_COMMA, /* "," */
PREC_SEPARATOR, /* ";" */
PREC_ASSIGN, /* "=" */
PREC_CONDITIONAL, /* "?", ":" */
PREC_OR, /* "||" */
PREC_AND, /* "&&" */
PREC_BIT_OR, /* "|" */
PREC_BIT_XOR, /* "^" */
PREC_BIT_AND, /* "&" */
PREC_EQUAL, /* "==", "!=", "eq", "ne", "in", "ni" */
|
| ︙ | ︙ | |||
357 358 359 360 361 362 363 364 |
PREC_EQUAL, /* STREQ */
PREC_EQUAL, /* STRNEQ */
PREC_EXPON, /* EXPON */
PREC_EQUAL, /* IN_LIST */
PREC_EQUAL, /* NOT_IN_LIST */
PREC_CLOSE_PAREN, /* CLOSE_PAREN */
PREC_END, /* END */
/* Expansion room for more binary operators */
| > > | | 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 |
PREC_EQUAL, /* STREQ */
PREC_EQUAL, /* STRNEQ */
PREC_EXPON, /* EXPON */
PREC_EQUAL, /* IN_LIST */
PREC_EQUAL, /* NOT_IN_LIST */
PREC_CLOSE_PAREN, /* CLOSE_PAREN */
PREC_END, /* END */
PREC_SEPARATOR, /* SEPARATOR */
PREC_ASSIGN, /* ASSIGN */
/* Expansion room for more binary operators */
0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0,
/* Unary operator lexemes */
PREC_UNARY, /* UNARY_PLUS */
PREC_UNARY, /* UNARY_MINUS */
PREC_UNARY, /* FUNCTION */
|
| ︙ | ︙ | |||
412 413 414 415 416 417 418 419 |
INST_STR_EQ, /* STREQ */
INST_STR_NEQ, /* STRNEQ */
INST_EXPON, /* EXPON */
INST_LIST_IN, /* IN_LIST */
INST_LIST_NOT_IN, /* NOT_IN_LIST */
0, /* CLOSE_PAREN */
0, /* END */
/* Expansion room for more binary operators */
| > > | | 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 |
INST_STR_EQ, /* STREQ */
INST_STR_NEQ, /* STRNEQ */
INST_EXPON, /* EXPON */
INST_LIST_IN, /* IN_LIST */
INST_LIST_NOT_IN, /* NOT_IN_LIST */
0, /* CLOSE_PAREN */
0, /* END */
0, /* SEPARATOR */
0, /* ASSIGN */
/* Expansion room for more binary operators */
0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0,
/* Unary operator lexemes */
INST_UPLUS, /* UNARY_PLUS */
INST_UMINUS, /* UNARY_MINUS */
0, /* FUNCTION */
|
| ︙ | ︙ | |||
458 459 460 461 462 463 464 | 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 */ | | | | 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 | 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 */ /*COLON*/0 /* : */, SEPARATOR /* ; */, 0 /* < or << or <= */, 0 /* = or == */, 0 /* > or >> or >= */, QUESTION /* ? */, INVALID /* @ */, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* A-M */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* N-Z */ SCRIPT /* [ */, INVALID /* \ */, INVALID /* ] */, BIT_XOR /* ^ */, INVALID /* _ */, INVALID /* ` */, |
| ︙ | ︙ | |||
727 728 729 730 731 732 733 734 735 736 737 738 739 740 |
* When we compile the expression we'll need the function
* name, and there's no place in the parse tree to store
* it, so we keep a separate list of all the function
* 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) ? "" : "...");
| > > > > > > > > > > > > > > > | 742 743 744 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 |
* When we compile the expression we'll need the function
* name, and there's no place in the parse tree to store
* it, so we keep a separate list of all the function
* names we've parsed in the order we found them.
*/
Tcl_ListObjAppendElement(NULL, funcList, literal);
} else if (start[scanned+TclParseAllWhiteSpace(
start+scanned, numBytes-scanned)] == ':' &&
start[scanned+TclParseAllWhiteSpace(
start+scanned, numBytes-scanned)+1] == '=') {
lexeme = VARNAME;
/*
* When we compile the expression we'll need the function
* name, and there's no place in the parse tree to store
* it, so we keep a separate list of all the function
* 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) ? "" : "...");
|
| ︙ | ︙ | |||
837 838 839 840 841 842 843 844 845 846 847 848 849 850 |
}
goto error;
}
switch (lexeme) {
case NUMBER:
case BOOLEAN:
/*
* TODO: Consider using a dict or hash to collapse all
* duplicate literals into a single representative value.
* (Like what is done with [split $s {}]).
* Pro: ~75% memory saving on expressions like
* {1+1+1+1+1+.....+1} (Convert "pointer + Tcl_Obj" cost
* to "pointer" cost only)
| > | 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 |
}
goto error;
}
switch (lexeme) {
case NUMBER:
case BOOLEAN:
case VARNAME:
/*
* TODO: Consider using a dict or hash to collapse all
* duplicate literals into a single representative value.
* (Like what is done with [split $s {}]).
* Pro: ~75% memory saving on expressions like
* {1+1+1+1+1+.....+1} (Convert "pointer + Tcl_Obj" cost
* to "pointer" cost only)
|
| ︙ | ︙ | |||
1169 1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 |
/*
* Right association rules for exponentiation.
*/
if (lexeme == EXPON) {
break;
}
/*
* Special association rules for the conditional
* operators. The "?" and ":" operators have equal
* precedence, but must be linked up in sensible pairs.
*/
| > > > > > | 1200 1201 1202 1203 1204 1205 1206 1207 1208 1209 1210 1211 1212 1213 1214 1215 1216 1217 1218 |
/*
* Right association rules for exponentiation.
*/
if (lexeme == EXPON) {
break;
}
/* Right association rules for assignment. */
if (lexeme == ASSIGN) {
break;
}
/*
* Special association rules for the conditional
* operators. The "?" and ":" operators have equal
* precedence, but must be linked up in sensible pairs.
*/
|
| ︙ | ︙ | |||
1247 1248 1249 1250 1251 1252 1253 1254 1255 1256 1257 1258 1259 1260 |
* they have a constant expression.
*/
if ((incompletePtr->lexeme == QUESTION)
|| (incompletePtr->lexeme == FUNCTION)) {
nodes[complete].constant = incompletePtr->constant;
}
if (incompletePtr->lexeme == START) {
/*
* Completing the START tree indicates we're done.
* Transfer the parse tree to the caller and return.
*/
| > > > > > > > > > > | 1283 1284 1285 1286 1287 1288 1289 1290 1291 1292 1293 1294 1295 1296 1297 1298 1299 1300 1301 1302 1303 1304 1305 1306 |
* they have a constant expression.
*/
if ((incompletePtr->lexeme == QUESTION)
|| (incompletePtr->lexeme == FUNCTION)) {
nodes[complete].constant = incompletePtr->constant;
}
/*
* We declare all ASSIGN operators to be non-constant
* expressions because we do not want to optimize their
* variable-setting side effects out of existence.
*/
if (incompletePtr->lexeme == ASSIGN) {
incompletePtr->constant = 0;
}
if (incompletePtr->lexeme == START) {
/*
* Completing the START tree indicates we're done.
* Transfer the parse tree to the caller and return.
*/
|
| ︙ | ︙ | |||
1903 1904 1905 1906 1907 1908 1909 1910 1911 1912 1913 1914 |
if ((numBytes > 1) && (start[1] == '*')) {
*lexemePtr = EXPON;
return 2;
}
*lexemePtr = MULT;
return 1;
case '=':
if ((numBytes > 1) && (start[1] == '=')) {
*lexemePtr = EQUAL;
return 2;
}
| > > > > > > > > > | | 1949 1950 1951 1952 1953 1954 1955 1956 1957 1958 1959 1960 1961 1962 1963 1964 1965 1966 1967 1968 1969 1970 1971 1972 1973 1974 1975 1976 1977 |
if ((numBytes > 1) && (start[1] == '*')) {
*lexemePtr = EXPON;
return 2;
}
*lexemePtr = MULT;
return 1;
case ':':
if ((numBytes > 1) && (start[1] == '=')) {
*lexemePtr = ASSIGN;
return 2;
}
*lexemePtr = COLON;
return 1;
case '=':
if ((numBytes > 1) && (start[1] == '=')) {
*lexemePtr = EQUAL;
return 2;
}
*lexemePtr = ASSIGN;
return 1;
case '!':
if ((numBytes > 1) && (start[1] == '=')) {
*lexemePtr = NEQ;
return 2;
}
|
| ︙ | ︙ | |||
2281 2282 2283 2284 2285 2286 2287 2288 2289 2290 2291 2292 2293 2294 | * progress (nested functions), save it in our unused "left" * field for restoring later. */ nodePtr->left = numWords; numWords = 2; /* Command plus one argument */ break; } case QUESTION: newJump = TclStackAlloc(interp, sizeof(JumpList)); newJump->next = jumpPtr; jumpPtr = newJump; TclEmitForwardJump(envPtr, TCL_FALSE_JUMP, &jumpPtr->jump); break; | > > > | 2336 2337 2338 2339 2340 2341 2342 2343 2344 2345 2346 2347 2348 2349 2350 2351 2352 | * progress (nested functions), save it in our unused "left" * field for restoring later. */ nodePtr->left = numWords; numWords = 2; /* Command plus one argument */ break; case SEPARATOR: TclEmitOpcode(INST_POP, envPtr); break; } case QUESTION: newJump = TclStackAlloc(interp, sizeof(JumpList)); newJump->next = jumpPtr; jumpPtr = newJump; TclEmitForwardJump(envPtr, TCL_FALSE_JUMP, &jumpPtr->jump); break; |
| ︙ | ︙ | |||
2319 2320 2321 2322 2323 2324 2325 2326 2327 2328 2329 2330 2331 2332 2333 |
switch (nodePtr->lexeme) {
case START:
case QUESTION:
if (convert && (nodePtr == rootPtr)) {
TclEmitOpcode(INST_TRY_CVT_TO_NUMERIC, envPtr);
}
break;
case OPEN_PAREN:
/* do nothing */
break;
case FUNCTION:
/*
* Use the numWords count we've kept to invoke the function
* command with the correct number of arguments.
| > > > > > > > > > > > | 2377 2378 2379 2380 2381 2382 2383 2384 2385 2386 2387 2388 2389 2390 2391 2392 2393 2394 2395 2396 2397 2398 2399 2400 2401 2402 |
switch (nodePtr->lexeme) {
case START:
case QUESTION:
if (convert && (nodePtr == rootPtr)) {
TclEmitOpcode(INST_TRY_CVT_TO_NUMERIC, envPtr);
}
break;
case ASSIGN:
if (convert) {
/*
* Make sure we assign to a variable only values that
* have been numerically normalized in the expr way.
*/
TclEmitOpcode(INST_TRY_CVT_TO_NUMERIC, envPtr);
}
TclEmitOpcode(INST_STORE_STK, envPtr);
break;
case OPEN_PAREN:
case SEPARATOR:
/* do nothing */
break;
case FUNCTION:
/*
* Use the numWords count we've kept to invoke the function
* command with the correct number of arguments.
|
| ︙ | ︙ |