Mercurial > audlegacy
comparison src/audacious/tuple_compiler.c @ 3954:7afbcd87cd65
The compiler should now correctly recognize integer constants, thanks to
Yuri K. Schlesner for spotting this really stupid bug .. which I should've
seen much earlier.
| author | Matti Hamalainen <ccr@tnsp.org> |
|---|---|
| date | Fri, 16 Nov 2007 09:14:40 +0200 |
| parents | 047bf3ed21b2 |
| children | c4295265f61d |
comparison
equal
deleted
inserted
replaced
| 3953:de76dbec8e1e | 3954:7afbcd87cd65 |
|---|---|
| 54 | 54 |
| 55 static void tuple_evalctx_free_var(TupleEvalVar *var) | 55 static void tuple_evalctx_free_var(TupleEvalVar *var) |
| 56 { | 56 { |
| 57 assert(var != NULL); | 57 assert(var != NULL); |
| 58 var->fieldidx = -1; | 58 var->fieldidx = -1; |
| 59 g_free(var->defval); | 59 g_free(var->defvals); |
| 60 g_free(var->name); | 60 g_free(var->name); |
| 61 g_free(var); | 61 g_free(var); |
| 62 } | 62 } |
| 63 | 63 |
| 64 | 64 |
| 122 /* Zero context */ | 122 /* Zero context */ |
| 123 memset(ctx, 0, sizeof(TupleEvalContext)); | 123 memset(ctx, 0, sizeof(TupleEvalContext)); |
| 124 } | 124 } |
| 125 | 125 |
| 126 | 126 |
| 127 gint tuple_evalctx_add_var(TupleEvalContext *ctx, const gchar *name, const gboolean istemp, const gint type) | 127 gint tuple_evalctx_add_var(TupleEvalContext *ctx, const gchar *name, const gboolean istemp, const gint type, const TupleValueType ctype) |
| 128 { | 128 { |
| 129 gint i, ref = -1; | 129 gint i, ref = -1; |
| 130 TupleEvalVar *tmp = g_new0(TupleEvalVar, 1); | 130 TupleEvalVar *tmp = g_new0(TupleEvalVar, 1); |
| 131 assert(tmp != NULL); | 131 assert(tmp != NULL); |
| 132 | 132 |
| 133 tmp->name = g_strdup(name); | 133 tmp->name = g_strdup(name); |
| 134 tmp->istemp = istemp; | 134 tmp->istemp = istemp; |
| 135 tmp->type = type; | 135 tmp->type = type; |
| 136 tmp->fieldidx = ref; | 136 tmp->fieldidx = ref; |
| 137 tmp->ctype = ctype; | |
| 137 | 138 |
| 138 /* Find fieldidx, if any */ | 139 /* Find fieldidx, if any */ |
| 139 if (type == VAR_FIELD) { | 140 switch (type) { |
| 140 for (i = 0; i < FIELD_LAST && ref < 0; i++) | 141 case VAR_FIELD: |
| 141 if (strcmp(tuple_fields[i].name, name) == 0) ref = i; | 142 for (i = 0; i < FIELD_LAST && ref < 0; i++) |
| 142 | 143 if (strcmp(tuple_fields[i].name, name) == 0) ref = i; |
| 143 tmp->fieldidx = ref; | 144 |
| 145 tmp->fieldidx = ref; | |
| 146 break; | |
| 147 | |
| 148 case VAR_CONST: | |
| 149 if (ctype == TUPLE_INT) | |
| 150 tmp->defvali = atoi(name); | |
| 151 break; | |
| 144 } | 152 } |
| 145 | 153 |
| 146 /* Find a free slot */ | 154 /* Find a free slot */ |
| 147 for (i = 0; i < ctx->nvariables; i++) | 155 for (i = 0; i < ctx->nvariables; i++) |
| 148 if (!ctx->variables[i]) { | 156 if (!ctx->variables[i]) { |
| 277 | 285 |
| 278 | 286 |
| 279 static gint tc_get_variable(TupleEvalContext *ctx, gchar *name, gint type) | 287 static gint tc_get_variable(TupleEvalContext *ctx, gchar *name, gint type) |
| 280 { | 288 { |
| 281 gint i; | 289 gint i; |
| 282 | 290 TupleValueType ctype = TUPLE_UNKNOWN; |
| 283 if (*name == '\0') return -1; | 291 |
| 284 | 292 if (name == '\0') return -1; |
| 285 for (i = 0; i < ctx->nvariables; i++) | 293 |
| 286 if (ctx->variables[i] && !strcmp(ctx->variables[i]->name, name)) | 294 if (isdigit(name[0])) { |
| 287 return i; | 295 ctype = TUPLE_INT; |
| 288 | 296 type = VAR_CONST; |
| 289 return tuple_evalctx_add_var(ctx, name, FALSE, type); | 297 } else |
| 290 } | 298 ctype = TUPLE_STRING; |
| 291 | 299 |
| 292 | 300 if (type != VAR_CONST) { |
| 293 static gboolean tc_parse_construct1(TupleEvalContext *ctx, TupleEvalNode **res, gchar *item, gchar **c, gint *level, gint opcode) | 301 for (i = 0; i < ctx->nvariables; i++) |
| 302 if (ctx->variables[i] && !strcmp(ctx->variables[i]->name, name)) | |
| 303 return i; | |
| 304 } | |
| 305 | |
| 306 return tuple_evalctx_add_var(ctx, name, FALSE, type, ctype); | |
| 307 } | |
| 308 | |
| 309 | |
| 310 static gboolean tc_parse_construct(TupleEvalContext *ctx, TupleEvalNode **res, gchar *item, gchar **c, gint *level, gint opcode) | |
| 294 { | 311 { |
| 295 gchar tmps1[MAX_STR], tmps2[MAX_STR]; | 312 gchar tmps1[MAX_STR], tmps2[MAX_STR]; |
| 296 gboolean literal1 = TRUE, literal2 = TRUE; | 313 gboolean literal1 = TRUE, literal2 = TRUE; |
| 297 | 314 |
| 298 (*c)++; | 315 (*c)++; |
| 386 goto ret_error; | 403 goto ret_error; |
| 387 } else | 404 } else |
| 388 goto ret_error; | 405 goto ret_error; |
| 389 } else { | 406 } else { |
| 390 /* Equals? */ | 407 /* Equals? */ |
| 391 if (!tc_parse_construct1(ctx, &res, item, &c, level, OP_EQUALS)) | 408 if (!tc_parse_construct(ctx, &res, item, &c, level, OP_EQUALS)) |
| 392 goto ret_error; | 409 goto ret_error; |
| 393 } | 410 } |
| 394 break; | 411 break; |
| 395 | 412 |
| 396 case '!': c++; | 413 case '!': c++; |
| 397 if (*c != '=') goto ext_expression; | 414 if (*c != '=') goto ext_expression; |
| 398 if (!tc_parse_construct1(ctx, &res, item, &c, level, OP_NOT_EQUALS)) | 415 if (!tc_parse_construct(ctx, &res, item, &c, level, OP_NOT_EQUALS)) |
| 399 goto ret_error; | 416 goto ret_error; |
| 400 break; | 417 break; |
| 401 | 418 |
| 402 case '<': c++; | 419 case '<': c++; |
| 403 if (*c == '=') { | 420 if (*c == '=') { |
| 404 opcode = OP_LTEQ; | 421 opcode = OP_LTEQ; |
| 405 c++; | 422 c++; |
| 406 } else | 423 } else |
| 407 opcode = OP_LT; | 424 opcode = OP_LT; |
| 408 | 425 |
| 409 if (!tc_parse_construct1(ctx, &res, item, &c, level, opcode)) | 426 if (!tc_parse_construct(ctx, &res, item, &c, level, opcode)) |
| 410 goto ret_error; | 427 goto ret_error; |
| 411 break; | 428 break; |
| 412 | 429 |
| 413 case '>': c++; | 430 case '>': c++; |
| 414 if (*c == '=') { | 431 if (*c == '=') { |
| 415 opcode = OP_GTEQ; | 432 opcode = OP_GTEQ; |
| 416 c++; | 433 c++; |
| 417 } else | 434 } else |
| 418 opcode = OP_GT; | 435 opcode = OP_GT; |
| 419 | 436 |
| 420 if (!tc_parse_construct1(ctx, &res, item, &c, level, opcode)) | 437 if (!tc_parse_construct(ctx, &res, item, &c, level, opcode)) |
| 421 goto ret_error; | 438 goto ret_error; |
| 422 break; | 439 break; |
| 423 | 440 |
| 424 case '(': c++; | 441 case '(': c++; |
| 425 if (!strncmp(c, "empty)?", 7)) { | 442 if (!strncmp(c, "empty)?", 7)) { |
| 578 * Return VAR_* type for the variable. | 595 * Return VAR_* type for the variable. |
| 579 */ | 596 */ |
| 580 static TupleValueType tf_get_var(gchar **tmps, gint *tmpi, TupleEvalVar *var, Tuple *tuple) | 597 static TupleValueType tf_get_var(gchar **tmps, gint *tmpi, TupleEvalVar *var, Tuple *tuple) |
| 581 { | 598 { |
| 582 TupleValueType type = TUPLE_UNKNOWN; | 599 TupleValueType type = TUPLE_UNKNOWN; |
| 600 *tmps = NULL; | |
| 601 *tmpi = 0; | |
| 583 | 602 |
| 584 switch (var->type) { | 603 switch (var->type) { |
| 585 case VAR_DEF: *tmps = var->defval; type = TUPLE_STRING; break; | 604 case VAR_DEF: |
| 586 case VAR_CONST: *tmps = var->name; type = TUPLE_STRING; break; | 605 switch (var->ctype) { |
| 606 case TUPLE_STRING: *tmps = var->defvals; break; | |
| 607 case TUPLE_INT: *tmpi = var->defvali; break; | |
| 608 default: /* Possible, but should be prevented elsewhere */ break; | |
| 609 } | |
| 610 type = var->ctype; | |
| 611 break; | |
| 612 | |
| 613 case VAR_CONST: | |
| 614 switch (var->ctype) { | |
| 615 case TUPLE_STRING: *tmps = var->name; break; | |
| 616 case TUPLE_INT: *tmpi = var->defvali; break; | |
| 617 default: /* Cannot happen */ break; | |
| 618 } | |
| 619 type = var->ctype; | |
| 620 break; | |
| 621 | |
| 587 case VAR_FIELD: | 622 case VAR_FIELD: |
| 588 if (tf_get_fieldref(var, tuple)) { | 623 if (tf_get_fieldref(var, tuple)) { |
| 589 if (var->fieldref->type == TUPLE_STRING) | 624 if (var->fieldref->type == TUPLE_STRING) |
| 590 *tmps = var->fieldref->value.string; | 625 *tmps = var->fieldref->value.string; |
| 591 else | 626 else |
| 592 *tmpi = var->fieldref->value.integer; | 627 *tmpi = var->fieldref->value.integer; |
| 593 type = var->fieldref->type; | 628 type = var->fieldref->type; |
| 594 } | 629 } |
| 595 break; | 630 break; |
| 596 default: | |
| 597 tmps = NULL; | |
| 598 tmpi = 0; | |
| 599 } | 631 } |
| 600 | 632 |
| 601 return type; | 633 return type; |
| 602 } | 634 } |
| 603 | 635 |
| 628 case OP_FIELD: | 660 case OP_FIELD: |
| 629 var0 = ctx->variables[curr->var[0]]; | 661 var0 = ctx->variables[curr->var[0]]; |
| 630 | 662 |
| 631 switch (var0->type) { | 663 switch (var0->type) { |
| 632 case VAR_DEF: | 664 case VAR_DEF: |
| 633 str = var0->defval; | 665 switch (var0->ctype) { |
| 666 case TUPLE_STRING: | |
| 667 str = var0->defvals; | |
| 668 break; | |
| 669 | |
| 670 case TUPLE_INT: | |
| 671 g_snprintf(tmps, sizeof(tmps), "%d", var0->defvali); | |
| 672 str = tmps; | |
| 673 break; | |
| 674 | |
| 675 default: | |
| 676 break; | |
| 677 } | |
| 634 break; | 678 break; |
| 635 | 679 |
| 636 case VAR_FIELD: | 680 case VAR_FIELD: |
| 637 if (tf_get_fieldref(var0, tuple)) { | 681 if (tf_get_fieldref(var0, tuple)) { |
| 638 switch (var0->fieldref->type) { | 682 switch (var0->fieldref->type) { |
| 660 var0 = ctx->variables[curr->var[0]]; | 704 var0 = ctx->variables[curr->var[0]]; |
| 661 var1 = ctx->variables[curr->var[1]]; | 705 var1 = ctx->variables[curr->var[1]]; |
| 662 | 706 |
| 663 type0 = tf_get_var(&tmps0, &tmpi0, var0, tuple); | 707 type0 = tf_get_var(&tmps0, &tmpi0, var0, tuple); |
| 664 type1 = tf_get_var(&tmps1, &tmpi1, var1, tuple); | 708 type1 = tf_get_var(&tmps1, &tmpi1, var1, tuple); |
| 665 | 709 result = FALSE; |
| 666 if (type0 == type1) { | 710 |
| 667 if (type0 == TUPLE_STRING) | 711 if (type0 != TUPLE_UNKNOWN && type1 != TUPLE_UNKNOWN) { |
| 668 resulti = strcmp(tmps0, tmps1); | 712 if (type0 == type1) { |
| 669 else | 713 if (type0 == TUPLE_STRING) |
| 670 resulti = tmpi0 - tmpi1; | 714 resulti = strcmp(tmps0, tmps1); |
| 671 | 715 else |
| 716 resulti = tmpi0 - tmpi1; | |
| 717 } else { | |
| 718 if (type0 == TUPLE_INT) | |
| 719 resulti = tmpi0 - atoi(tmps1); | |
| 720 else | |
| 721 resulti = atoi(tmps0) - tmpi1; | |
| 722 } | |
| 723 | |
| 672 switch (curr->opcode) { | 724 switch (curr->opcode) { |
| 673 case OP_EQUALS: result = (resulti == 0); break; | 725 case OP_EQUALS: result = (resulti == 0); break; |
| 674 case OP_NOT_EQUALS: result = (resulti != 0); break; | 726 case OP_NOT_EQUALS: result = (resulti != 0); break; |
| 675 case OP_LT: result = (resulti < 0); break; | 727 case OP_LT: result = (resulti < 0); break; |
| 676 case OP_LTEQ: result = (resulti <= 0); break; | 728 case OP_LTEQ: result = (resulti <= 0); break; |
| 677 case OP_GT: result = (resulti > 0); break; | 729 case OP_GT: result = (resulti > 0); break; |
| 678 case OP_GTEQ: result = (resulti >= 0); break; | 730 case OP_GTEQ: result = (resulti >= 0); break; |
| 679 default: result = FALSE; | 731 default: result = FALSE; |
| 680 } | 732 } |
| 733 } | |
| 681 | 734 |
| 682 if (result && !tuple_formatter_eval_do(ctx, curr->children, tuple, res, resmax, reslen)) | 735 if (result && !tuple_formatter_eval_do(ctx, curr->children, tuple, res, resmax, reslen)) |
| 683 return FALSE; | 736 return FALSE; |
| 684 } else { | |
| 685 /* FIXME?! Warn that types are not same? */ | |
| 686 } | |
| 687 break; | 737 break; |
| 688 | 738 |
| 689 case OP_EXISTS: | 739 case OP_EXISTS: |
| 690 #ifdef NO_EXISTS_HACK | 740 #ifdef NO_EXISTS_HACK |
| 691 if (tf_get_fieldref(ctx->variables[curr->var[0]], tuple)) { | 741 if (tf_get_fieldref(ctx->variables[curr->var[0]], tuple)) { |
