From 1cf6515c0638f409ea266463bd29a5f87fb054e0 Mon Sep 17 00:00:00 2001 From: Nico Williams <nico@cryptonector.com> Date: Mon, 24 Jul 2023 06:20:21 -0500 Subject: [PATCH] Fix try/catch catches more than it should #1859 Close #1885, #2140, #2011, #2220, #2485, #2073 Rename the FORK_OPT opcode to TRY_BEGIN, add a TRY_END opcode, and wrap errors when raising through a TRY_END so that they will not be caught by the matching TRY_BEGIN. Now a `try exp catch handler` expression generates code like: TRY_BEGIN handler <exp> TRY_END JUMP past_handler handler: <handler> past_handler: ... On backtrack through TRY_BEGIN it just backtracks. If anything past the whole thing raises when <exp> produced a value, then the TRY_END will catch the error, wrap it in another, and backtrack. The TRY_BEGIN will see a wrapped error and then it will unwrap and re-raise the error. If <exp> raises, then TRY_BEGIN will catch the error and jump to the handler, but the TRY_BEGIN will not stack_save() in that case, so on raise/backtrack the TRY_BEGIN will not execute again (nor will the TRY_END). --- src/compile.c | 59 ++--- src/compile.h | 1 - src/execute.c | 56 +++- src/opcode_list.h | 5 +- src/parser.c | 656 +++++++++++++++++++++++----------------------- src/parser.y | 4 +- tests/jq.test | 55 ++++ 7 files changed, 468 insertions(+), 368 deletions(-) diff --git a/src/compile.c b/src/compile.c index 58d08573df..5645fa5f90 100644 --- a/src/compile.c +++ b/src/compile.c @@ -1034,43 +1034,40 @@ block gen_cond(block cond, block iftrue, block iffalse) { BLOCK(gen_op_simple(POP), iffalse))); } -block gen_try_handler(block handler) { - // Quite a pain just to hide jq's internal errors. - return gen_cond(// `if type=="object" and .__jq - gen_and(gen_call("_equal", - BLOCK(gen_lambda(gen_const(jv_string("object"))), - gen_lambda(gen_call("type", gen_noop())))), - BLOCK(gen_subexp(gen_const(jv_string("__jq"))), - gen_noop(), - gen_op_simple(INDEX))), - // `then error` - gen_call("error", gen_noop()), - // `else HANDLER end` - handler); -} - block gen_try(block exp, block handler) { /* - * Produce something like: - * FORK_OPT <address of handler> + * Produce: + * + * TRY_BEGIN handler * <exp> - * JUMP <end of handler> - * <handler> + * TRY_END + * JUMP past_handler + * handler: <handler> + * past_handler: * - * If this is not an internal try/catch, then catch and re-raise - * internal errors to prevent them from leaking. + * If <exp> backtracks then TRY_BEGIN will backtrack. * - * The handler will only execute if we backtrack to the FORK_OPT with - * an error (exception). If <exp> produces no value then FORK_OPT - * will backtrack (propagate the `empty`, as it were. If <exp> - * produces a value then we'll execute whatever bytecode follows this - * sequence. + * If <exp> produces a value then we'll execute whatever bytecode follows + * this sequence. If that code raises an exception, then TRY_END will wrap + * and re-raise that exception, and TRY_BEGIN will unwrap and re-raise the + * exception (see jq_next()). + * + * If <exp> raises then the TRY_BEGIN will see a non-wrapped exception and + * will jump to the handler (note the TRY_END will not execute in this case), + * and if the handler produces any values, then we'll execute whatever + * bytecode follows this sequence. Note that TRY_END will not execute in + * this case, so if the handler raises an exception, or code past the handler + * raises an exception, then that exception won't be wrapped and re-raised, + * and the TRY_BEGIN will not catch it because it does not stack_save() when + * it branches to the handler. */ - if (!handler.first && !handler.last) - // A hack to deal with `.` as the handler; we could use a real NOOP here - handler = BLOCK(gen_op_simple(DUP), gen_op_simple(POP), handler); - exp = BLOCK(exp, gen_op_target(JUMP, handler)); - return BLOCK(gen_op_target(FORK_OPT, exp), exp, handler); + + if (block_is_noop(handler)) + handler = BLOCK(gen_op_simple(DUP), gen_op_simple(POP)); + + block jump = gen_op_target(JUMP, handler); + return BLOCK(gen_op_target(TRY_BEGIN, jump), exp, gen_op_simple(TRY_END), + jump, handler); } block gen_label(const char *label, block exp) { diff --git a/src/compile.h b/src/compile.h index cccd661dcb..f690adc240 100644 --- a/src/compile.h +++ b/src/compile.h @@ -59,7 +59,6 @@ block gen_destructure(block var, block matcher, block body); block gen_destructure_alt(block matcher); block gen_cond(block cond, block iftrue, block iffalse); -block gen_try_handler(block handler); block gen_try(block exp, block handler); block gen_label(const char *label, block exp); diff --git a/src/execute.c b/src/execute.c index 34bb63dc93..091ddbc355 100644 --- a/src/execute.c +++ b/src/execute.c @@ -348,6 +348,7 @@ jv jq_next(jq_state *jq) { int raising; int backtracking = !jq->initial_execution; + jq->initial_execution = 0; assert(jv_get_kind(jq->error) == JV_KIND_NULL); while (1) { @@ -808,7 +809,59 @@ jv jq_next(jq_state *jq) { break; } - case FORK_OPT: + case TRY_BEGIN: + stack_save(jq, pc - 1, stack_get_pos(jq)); + pc++; // skip handler offset this time + break; + + case TRY_END: + stack_save(jq, pc - 1, stack_get_pos(jq)); + break; + + case ON_BACKTRACK(TRY_BEGIN): { + if (!raising) { + /* + * `try EXP ...` -- EXP backtracked (e.g., EXP was `empty`), so we + * backtrack more: + */ + jv_free(stack_pop(jq)); + goto do_backtrack; + } + + /* + * Else `(try EXP ... ) | EXP2` raised an error. + * + * If the error was wrapped in another error, then that means EXP2 raised + * the error. We unwrap it and re-raise it as it wasn't raised by EXP. + * + * See commentary in gen_try(). + */ + jv e = jv_invalid_get_msg(jv_copy(jq->error)); + if (!jv_is_valid(e) && jv_invalid_has_msg(jv_copy(e))) { + set_error(jq, e); + goto do_backtrack; + } + jv_free(e); + + /* + * Else we caught an error containing a non-error value, so we jump to + * the handler. + * + * See commentary in gen_try(). + */ + uint16_t offset = *pc++; + jv_free(stack_pop(jq)); // free the input + stack_push(jq, jv_invalid_get_msg(jq->error)); // push the error's message + jq->error = jv_null(); + pc += offset; + break; + } + case ON_BACKTRACK(TRY_END): + // Wrap the error so the matching TRY_BEGIN doesn't catch it + if (raising) + set_error(jq, jv_invalid_with_msg(jv_copy(jq->error))); + goto do_backtrack; + case DESTRUCTURE_ALT: case FORK: { stack_save(jq, pc - 1, stack_get_pos(jq)); @@ -816,7 +869,6 @@ jv jq_next(jq_state *jq) { break; } - case ON_BACKTRACK(FORK_OPT): case ON_BACKTRACK(DESTRUCTURE_ALT): { if (jv_is_valid(jq->error)) { // `try EXP ...` backtracked here (no value, `empty`), so we backtrack more diff --git a/src/opcode_list.h b/src/opcode_list.h index 886131d7c6..06147f0ff7 100644 --- a/src/opcode_list.h +++ b/src/opcode_list.h @@ -11,9 +11,10 @@ OP(STORE_GLOBAL, GLOBAL, 0, 0) OP(INDEX, NONE, 2, 1) OP(INDEX_OPT, NONE, 2, 1) OP(EACH, NONE, 1, 1) -OP(EACH_OPT, NONE, 1, 1) +OP(EACH_OPT, NONE, 1, 1) OP(FORK, BRANCH, 0, 0) -OP(FORK_OPT, BRANCH, 0, 0) +OP(TRY_BEGIN, BRANCH, 0, 0) +OP(TRY_END, NONE, 0, 0) OP(JUMP, BRANCH, 0, 0) OP(JUMP_F,BRANCH, 1, 0) OP(BACKTRACK, NONE, 0, 0) diff --git a/src/parser.c b/src/parser.c index 45e03b06b6..e7c6a4ea00 100644 --- a/src/parser.c +++ b/src/parser.c @@ -965,23 +965,23 @@ static const yytype_int8 yytranslate[] = static const yytype_int16 yyrline[] = { 0, 312, 312, 315, 320, 323, 338, 341, 346, 349, - 354, 358, 361, 365, 369, 373, 376, 381, 385, 389, - 394, 401, 405, 409, 413, 417, 421, 425, 429, 433, - 437, 441, 445, 449, 453, 457, 461, 465, 471, 477, - 481, 485, 489, 493, 497, 501, 505, 509, 514, 517, - 534, 543, 550, 558, 569, 574, 580, 583, 588, 592, - 599, 599, 603, 603, 610, 613, 616, 622, 625, 628, - 633, 636, 639, 645, 648, 651, 659, 663, 666, 669, - 672, 675, 678, 681, 684, 687, 691, 697, 700, 703, - 706, 709, 712, 715, 718, 721, 724, 727, 730, 733, - 736, 739, 742, 745, 748, 751, 754, 757, 779, 783, - 787, 790, 802, 807, 808, 809, 810, 813, 816, 821, - 826, 829, 834, 837, 842, 846, 849, 854, 857, 862, - 865, 870, 873, 876, 879, 882, 885, 893, 899, 902, - 905, 908, 911, 914, 917, 920, 923, 926, 929, 932, - 935, 938, 941, 944, 947, 950, 955, 958, 959, 960, - 963, 966, 969, 972, 976, 980, 984, 988, 992, 996, - 1004 + 354, 358, 361, 365, 369, 373, 376, 381, 384, 387, + 392, 399, 403, 407, 411, 415, 419, 423, 427, 431, + 435, 439, 443, 447, 451, 455, 459, 463, 469, 475, + 479, 483, 487, 491, 495, 499, 503, 507, 512, 515, + 532, 541, 548, 556, 567, 572, 578, 581, 586, 590, + 597, 597, 601, 601, 608, 611, 614, 620, 623, 626, + 631, 634, 637, 643, 646, 649, 657, 661, 664, 667, + 670, 673, 676, 679, 682, 685, 689, 695, 698, 701, + 704, 707, 710, 713, 716, 719, 722, 725, 728, 731, + 734, 737, 740, 743, 746, 749, 752, 755, 777, 781, + 785, 788, 800, 805, 806, 807, 808, 811, 814, 819, + 824, 827, 832, 835, 840, 844, 847, 852, 855, 860, + 863, 868, 871, 874, 877, 880, 883, 891, 897, 900, + 903, 906, 909, 912, 915, 918, 921, 924, 927, 930, + 933, 936, 939, 942, 945, 948, 953, 956, 957, 958, + 961, 964, 967, 970, 974, 978, 982, 986, 990, 994, + 1002 }; #endif @@ -2818,271 +2818,269 @@ YYLTYPE yylloc = yyloc_default; case 17: /* Exp: "try" Exp "catch" Exp */ #line 381 "src/parser.y" { - //$$ = BLOCK(gen_op_target(FORK_OPT, $2), $2, $4); - (yyval.blk) = gen_try((yyvsp[-2].blk), gen_try_handler((yyvsp[0].blk))); + (yyval.blk) = gen_try((yyvsp[-2].blk), (yyvsp[0].blk)); } -#line 2825 "src/parser.c" +#line 2824 "src/parser.c" break; case 18: /* Exp: "try" Exp */ -#line 385 "src/parser.y" +#line 384 "src/parser.y" { - //$$ = BLOCK(gen_op_target(FORK_OPT, $2), $2, gen_op_simple(BACKTRACK)); (yyval.blk) = gen_try((yyvsp[0].blk), gen_op_simple(BACKTRACK)); } -#line 2834 "src/parser.c" +#line 2832 "src/parser.c" break; case 19: /* Exp: "try" Exp "catch" error */ -#line 389 "src/parser.y" +#line 387 "src/parser.y" { FAIL((yyloc), "Possibly unterminated 'try' statement"); (yyval.blk) = (yyvsp[-2].blk); } -#line 2843 "src/parser.c" +#line 2841 "src/parser.c" break; case 20: /* Exp: "label" BINDING '|' Exp */ -#line 394 "src/parser.y" +#line 392 "src/parser.y" { jv v = jv_string_fmt("*label-%s", jv_string_value((yyvsp[-2].literal))); (yyval.blk) = gen_location((yyloc), locations, gen_label(jv_string_value(v), (yyvsp[0].blk))); jv_free((yyvsp[-2].literal)); jv_free(v); } -#line 2854 "src/parser.c" +#line 2852 "src/parser.c" break; case 21: /* Exp: Exp '?' */ -#line 401 "src/parser.y" +#line 399 "src/parser.y" { (yyval.blk) = gen_try((yyvsp[-1].blk), gen_op_simple(BACKTRACK)); } -#line 2862 "src/parser.c" +#line 2860 "src/parser.c" break; case 22: /* Exp: Exp '=' Exp */ -#line 405 "src/parser.y" +#line 403 "src/parser.y" { (yyval.blk) = gen_call("_assign", BLOCK(gen_lambda((yyvsp[-2].blk)), gen_lambda((yyvsp[0].blk)))); } -#line 2870 "src/parser.c" +#line 2868 "src/parser.c" break; case 23: /* Exp: Exp "or" Exp */ -#line 409 "src/parser.y" +#line 407 "src/parser.y" { (yyval.blk) = gen_or((yyvsp[-2].blk), (yyvsp[0].blk)); } -#line 2878 "src/parser.c" +#line 2876 "src/parser.c" break; case 24: /* Exp: Exp "and" Exp */ -#line 413 "src/parser.y" +#line 411 "src/parser.y" { (yyval.blk) = gen_and((yyvsp[-2].blk), (yyvsp[0].blk)); } -#line 2886 "src/parser.c" +#line 2884 "src/parser.c" break; case 25: /* Exp: Exp "//" Exp */ -#line 417 "src/parser.y" +#line 415 "src/parser.y" { (yyval.blk) = gen_definedor((yyvsp[-2].blk), (yyvsp[0].blk)); } -#line 2894 "src/parser.c" +#line 2892 "src/parser.c" break; case 26: /* Exp: Exp "//=" Exp */ -#line 421 "src/parser.y" +#line 419 "src/parser.y" { (yyval.blk) = gen_definedor_assign((yyvsp[-2].blk), (yyvsp[0].blk)); } -#line 2902 "src/parser.c" +#line 2900 "src/parser.c" break; case 27: /* Exp: Exp "|=" Exp */ -#line 425 "src/parser.y" +#line 423 "src/parser.y" { (yyval.blk) = gen_call("_modify", BLOCK(gen_lambda((yyvsp[-2].blk)), gen_lambda((yyvsp[0].blk)))); } -#line 2910 "src/parser.c" +#line 2908 "src/parser.c" break; case 28: /* Exp: Exp '|' Exp */ -#line 429 "src/parser.y" +#line 427 "src/parser.y" { (yyval.blk) = block_join((yyvsp[-2].blk), (yyvsp[0].blk)); } -#line 2918 "src/parser.c" +#line 2916 "src/parser.c" break; case 29: /* Exp: Exp ',' Exp */ -#line 433 "src/parser.y" +#line 431 "src/parser.y" { (yyval.blk) = gen_both((yyvsp[-2].blk), (yyvsp[0].blk)); } -#line 2926 "src/parser.c" +#line 2924 "src/parser.c" break; case 30: /* Exp: Exp '+' Exp */ -#line 437 "src/parser.y" +#line 435 "src/parser.y" { (yyval.blk) = gen_binop((yyvsp[-2].blk), (yyvsp[0].blk), '+'); } -#line 2934 "src/parser.c" +#line 2932 "src/parser.c" break; case 31: /* Exp: Exp "+=" Exp */ -#line 441 "src/parser.y" +#line 439 "src/parser.y" { (yyval.blk) = gen_update((yyvsp[-2].blk), (yyvsp[0].blk), '+'); } -#line 2942 "src/parser.c" +#line 2940 "src/parser.c" break; case 32: /* Exp: '-' Exp */ -#line 445 "src/parser.y" +#line 443 "src/parser.y" { (yyval.blk) = BLOCK((yyvsp[0].blk), gen_call("_negate", gen_noop())); } -#line 2950 "src/parser.c" +#line 2948 "src/parser.c" break; case 33: /* Exp: Exp '-' Exp */ -#line 449 "src/parser.y" +#line 447 "src/parser.y" { (yyval.blk) = gen_binop((yyvsp[-2].blk), (yyvsp[0].blk), '-'); } -#line 2958 "src/parser.c" +#line 2956 "src/parser.c" break; case 34: /* Exp: Exp "-=" Exp */ -#line 453 "src/parser.y" +#line 451 "src/parser.y" { (yyval.blk) = gen_update((yyvsp[-2].blk), (yyvsp[0].blk), '-'); } -#line 2966 "src/parser.c" +#line 2964 "src/parser.c" break; case 35: /* Exp: Exp '*' Exp */ -#line 457 "src/parser.y" +#line 455 "src/parser.y" { (yyval.blk) = gen_binop((yyvsp[-2].blk), (yyvsp[0].blk), '*'); } -#line 2974 "src/parser.c" +#line 2972 "src/parser.c" break; case 36: /* Exp: Exp "*=" Exp */ -#line 461 "src/parser.y" +#line 459 "src/parser.y" { (yyval.blk) = gen_update((yyvsp[-2].blk), (yyvsp[0].blk), '*'); } -#line 2982 "src/parser.c" +#line 2980 "src/parser.c" break; case 37: /* Exp: Exp '/' Exp */ -#line 465 "src/parser.y" +#line 463 "src/parser.y" { (yyval.blk) = gen_binop((yyvsp[-2].blk), (yyvsp[0].blk), '/'); if (block_is_const_inf((yyval.blk))) FAIL((yyloc), "Division by zero?"); } -#line 2992 "src/parser.c" +#line 2990 "src/parser.c" break; case 38: /* Exp: Exp '%' Exp */ -#line 471 "src/parser.y" +#line 469 "src/parser.y" { (yyval.blk) = gen_binop((yyvsp[-2].blk), (yyvsp[0].blk), '%'); if (block_is_const_inf((yyval.blk))) FAIL((yyloc), "Remainder by zero?"); } -#line 3002 "src/parser.c" +#line 3000 "src/parser.c" break; case 39: /* Exp: Exp "/=" Exp */ -#line 477 "src/parser.y" +#line 475 "src/parser.y" { (yyval.blk) = gen_update((yyvsp[-2].blk), (yyvsp[0].blk), '/'); } -#line 3010 "src/parser.c" +#line 3008 "src/parser.c" break; case 40: /* Exp: Exp "%=" Exp */ -#line 481 "src/parser.y" +#line 479 "src/parser.y" { (yyval.blk) = gen_update((yyvsp[-2].blk), (yyvsp[0].blk), '%'); } -#line 3018 "src/parser.c" +#line 3016 "src/parser.c" break; case 41: /* Exp: Exp "==" Exp */ -#line 485 "src/parser.y" +#line 483 "src/parser.y" { (yyval.blk) = gen_binop((yyvsp[-2].blk), (yyvsp[0].blk), EQ); } -#line 3026 "src/parser.c" +#line 3024 "src/parser.c" break; case 42: /* Exp: Exp "!=" Exp */ -#line 489 "src/parser.y" +#line 487 "src/parser.y" { (yyval.blk) = gen_binop((yyvsp[-2].blk), (yyvsp[0].blk), NEQ); } -#line 3034 "src/parser.c" +#line 3032 "src/parser.c" break; case 43: /* Exp: Exp '<' Exp */ -#line 493 "src/parser.y" +#line 491 "src/parser.y" { (yyval.blk) = gen_binop((yyvsp[-2].blk), (yyvsp[0].blk), '<'); } -#line 3042 "src/parser.c" +#line 3040 "src/parser.c" break; case 44: /* Exp: Exp '>' Exp */ -#line 497 "src/parser.y" +#line 495 "src/parser.y" { (yyval.blk) = gen_binop((yyvsp[-2].blk), (yyvsp[0].blk), '>'); } -#line 3050 "src/parser.c" +#line 3048 "src/parser.c" break; case 45: /* Exp: Exp "<=" Exp */ -#line 501 "src/parser.y" +#line 499 "src/parser.y" { (yyval.blk) = gen_binop((yyvsp[-2].blk), (yyvsp[0].blk), LESSEQ); } -#line 3058 "src/parser.c" +#line 3056 "src/parser.c" break; case 46: /* Exp: Exp ">=" Exp */ -#line 505 "src/parser.y" +#line 503 "src/parser.y" { (yyval.blk) = gen_binop((yyvsp[-2].blk), (yyvsp[0].blk), GREATEREQ); } -#line 3066 "src/parser.c" +#line 3064 "src/parser.c" break; case 47: /* Exp: Term */ -#line 509 "src/parser.y" +#line 507 "src/parser.y" { (yyval.blk) = (yyvsp[0].blk); } -#line 3074 "src/parser.c" +#line 3072 "src/parser.c" break; case 48: /* Import: ImportWhat ';' */ -#line 514 "src/parser.y" +#line 512 "src/parser.y" { (yyval.blk) = (yyvsp[-1].blk); } -#line 3082 "src/parser.c" +#line 3080 "src/parser.c" break; case 49: /* Import: ImportWhat Exp ';' */ -#line 517 "src/parser.y" +#line 515 "src/parser.y" { if (!block_is_const((yyvsp[-1].blk))) { FAIL((yyloc), "Module metadata must be constant"); @@ -3098,11 +3096,11 @@ YYLTYPE yylloc = yyloc_default; (yyval.blk) = gen_import_meta((yyvsp[-2].blk), (yyvsp[-1].blk)); } } -#line 3102 "src/parser.c" +#line 3100 "src/parser.c" break; case 50: /* ImportWhat: "import" ImportFrom "as" BINDING */ -#line 534 "src/parser.y" +#line 532 "src/parser.y" { jv v = block_const((yyvsp[-2].blk)); // XXX Make gen_import take only blocks and the int is_data so we @@ -3112,11 +3110,11 @@ YYLTYPE yylloc = yyloc_default; jv_free((yyvsp[0].literal)); jv_free(v); } -#line 3116 "src/parser.c" +#line 3114 "src/parser.c" break; case 51: /* ImportWhat: "import" ImportFrom "as" IDENT */ -#line 543 "src/parser.y" +#line 541 "src/parser.y" { jv v = block_const((yyvsp[-2].blk)); (yyval.blk) = gen_import(jv_string_value(v), jv_string_value((yyvsp[0].literal)), 0); @@ -3124,22 +3122,22 @@ YYLTYPE yylloc = yyloc_default; jv_free((yyvsp[0].literal)); jv_free(v); } -#line 3128 "src/parser.c" +#line 3126 "src/parser.c" break; case 52: /* ImportWhat: "include" ImportFrom */ -#line 550 "src/parser.y" +#line 548 "src/parser.y" { jv v = block_const((yyvsp[0].blk)); (yyval.blk) = gen_import(jv_string_value(v), NULL, 0); block_free((yyvsp[0].blk)); jv_free(v); } -#line 3139 "src/parser.c" +#line 3137 "src/parser.c" break; case 53: /* ImportFrom: String */ -#line 558 "src/parser.y" +#line 556 "src/parser.y" { if (!block_is_const((yyvsp[0].blk))) { FAIL((yyloc), "Import path must be constant"); @@ -3149,181 +3147,181 @@ YYLTYPE yylloc = yyloc_default; (yyval.blk) = (yyvsp[0].blk); } } -#line 3153 "src/parser.c" +#line 3151 "src/parser.c" break; case 54: /* FuncDef: "def" IDENT ':' Exp ';' */ -#line 569 "src/parser.y" +#line 567 "src/parser.y" { (yyval.blk) = gen_function(jv_string_value((yyvsp[-3].literal)), gen_noop(), (yyvsp[-1].blk)); jv_free((yyvsp[-3].literal)); } -#line 3162 "src/parser.c" +#line 3160 "src/parser.c" break; case 55: /* FuncDef: "def" IDENT '(' Params ')' ':' Exp ';' */ -#line 574 "src/parser.y" +#line 572 "src/parser.y" { (yyval.blk) = gen_function(jv_string_value((yyvsp[-6].literal)), (yyvsp[-4].blk), (yyvsp[-1].blk)); jv_free((yyvsp[-6].literal)); } -#line 3171 "src/parser.c" +#line 3169 "src/parser.c" break; case 56: /* Params: Param */ -#line 580 "src/parser.y" +#line 578 "src/parser.y" { (yyval.blk) = (yyvsp[0].blk); } -#line 3179 "src/parser.c" +#line 3177 "src/parser.c" break; case 57: /* Params: Params ';' Param */ -#line 583 "src/parser.y" +#line 581 "src/parser.y" { (yyval.blk) = BLOCK((yyvsp[-2].blk), (yyvsp[0].blk)); } -#line 3187 "src/parser.c" +#line 3185 "src/parser.c" break; case 58: /* Param: BINDING */ -#line 588 "src/parser.y" +#line 586 "src/parser.y" { (yyval.blk) = gen_param_regular(jv_string_value((yyvsp[0].literal))); jv_free((yyvsp[0].literal)); } -#line 3196 "src/parser.c" +#line 3194 "src/parser.c" break; case 59: /* Param: IDENT */ -#line 592 "src/parser.y" +#line 590 "src/parser.y" { (yyval.blk) = gen_param(jv_string_value((yyvsp[0].literal))); jv_free((yyvsp[0].literal)); } -#line 3205 "src/parser.c" +#line 3203 "src/parser.c" break; case 60: /* @1: %empty */ -#line 599 "src/parser.y" +#line 597 "src/parser.y" { (yyval.literal) = jv_string("text"); } -#line 3211 "src/parser.c" +#line 3209 "src/parser.c" break; case 61: /* String: QQSTRING_START @1 QQString QQSTRING_END */ -#line 599 "src/parser.y" +#line 597 "src/parser.y" { (yyval.blk) = (yyvsp[-1].blk); jv_free((yyvsp[-2].literal)); } -#line 3220 "src/parser.c" +#line 3218 "src/parser.c" break; case 62: /* @2: %empty */ -#line 603 "src/parser.y" +#line 601 "src/parser.y" { (yyval.literal) = (yyvsp[-1].literal); } -#line 3226 "src/parser.c" +#line 3224 "src/parser.c" break; case 63: /* String: FORMAT QQSTRING_START @2 QQString QQSTRING_END */ -#line 603 "src/parser.y" +#line 601 "src/parser.y" { (yyval.blk) = (yyvsp[-1].blk); jv_free((yyvsp[-2].literal)); } -#line 3235 "src/parser.c" +#line 3233 "src/parser.c" break; case 64: /* QQString: %empty */ -#line 610 "src/parser.y" +#line 608 "src/parser.y" { (yyval.blk) = gen_const(jv_string("")); } -#line 3243 "src/parser.c" +#line 3241 "src/parser.c" break; case 65: /* QQString: QQString QQSTRING_TEXT */ -#line 613 "src/parser.y" +#line 611 "src/parser.y" { (yyval.blk) = gen_binop((yyvsp[-1].blk), gen_const((yyvsp[0].literal)), '+'); } -#line 3251 "src/parser.c" +#line 3249 "src/parser.c" break; case 66: /* QQString: QQString QQSTRING_INTERP_START Exp QQSTRING_INTERP_END */ -#line 616 "src/parser.y" +#line 614 "src/parser.y" { (yyval.blk) = gen_binop((yyvsp[-3].blk), gen_format((yyvsp[-1].blk), jv_copy((yyvsp[-4].literal))), '+'); } -#line 3259 "src/parser.c" +#line 3257 "src/parser.c" break; case 67: /* ElseBody: "elif" Exp "then" Exp ElseBody */ -#line 622 "src/parser.y" +#line 620 "src/parser.y" { (yyval.blk) = gen_cond((yyvsp[-3].blk), (yyvsp[-1].blk), (yyvsp[0].blk)); } -#line 3267 "src/parser.c" +#line 3265 "src/parser.c" break; case 68: /* ElseBody: "else" Exp "end" */ -#line 625 "src/parser.y" +#line 623 "src/parser.y" { (yyval.blk) = (yyvsp[-1].blk); } -#line 3275 "src/parser.c" +#line 3273 "src/parser.c" break; case 69: /* ElseBody: "end" */ -#line 628 "src/parser.y" +#line 626 "src/parser.y" { (yyval.blk) = gen_noop(); } -#line 3283 "src/parser.c" +#line 3281 "src/parser.c" break; case 70: /* ExpD: ExpD '|' ExpD */ -#line 633 "src/parser.y" +#line 631 "src/parser.y" { (yyval.blk) = block_join((yyvsp[-2].blk), (yyvsp[0].blk)); } -#line 3291 "src/parser.c" +#line 3289 "src/parser.c" break; case 71: /* ExpD: '-' ExpD */ -#line 636 "src/parser.y" +#line 634 "src/parser.y" { (yyval.blk) = BLOCK((yyvsp[0].blk), gen_call("_negate", gen_noop())); } -#line 3299 "src/parser.c" +#line 3297 "src/parser.c" break; case 72: /* ExpD: Term */ -#line 639 "src/parser.y" +#line 637 "src/parser.y" { (yyval.blk) = (yyvsp[0].blk); } -#line 3307 "src/parser.c" +#line 3305 "src/parser.c" break; case 73: /* Term: '.' */ -#line 645 "src/parser.y" +#line 643 "src/parser.y" { (yyval.blk) = gen_noop(); } -#line 3315 "src/parser.c" +#line 3313 "src/parser.c" break; case 74: /* Term: ".." */ -#line 648 "src/parser.y" +#line 646 "src/parser.y" { (yyval.blk) = gen_call("recurse", gen_noop()); } -#line 3323 "src/parser.c" +#line 3321 "src/parser.c" break; case 75: /* Term: "break" BINDING */ -#line 651 "src/parser.y" +#line 649 "src/parser.y" { jv v = jv_string_fmt("*label-%s", jv_string_value((yyvsp[0].literal))); // impossible symbol (yyval.blk) = gen_location((yyloc), locations, @@ -3332,263 +3330,263 @@ YYLTYPE yylloc = yyloc_default; jv_free(v); jv_free((yyvsp[0].literal)); } -#line 3336 "src/parser.c" +#line 3334 "src/parser.c" break; case 76: /* Term: "break" error */ -#line 659 "src/parser.y" +#line 657 "src/parser.y" { FAIL((yyloc), "break requires a label to break to"); (yyval.blk) = gen_noop(); } -#line 3345 "src/parser.c" +#line 3343 "src/parser.c" break; case 77: /* Term: Term FIELD '?' */ -#line 663 "src/parser.y" +#line 661 "src/parser.y" { (yyval.blk) = gen_index_opt((yyvsp[-2].blk), gen_const((yyvsp[-1].literal))); } -#line 3353 "src/parser.c" +#line 3351 "src/parser.c" break; case 78: /* Term: FIELD '?' */ -#line 666 "src/parser.y" +#line 664 "src/parser.y" { (yyval.blk) = gen_index_opt(gen_noop(), gen_const((yyvsp[-1].literal))); } -#line 3361 "src/parser.c" +#line 3359 "src/parser.c" break; case 79: /* Term: Term '.' String '?' */ -#line 669 "src/parser.y" +#line 667 "src/parser.y" { (yyval.blk) = gen_index_opt((yyvsp[-3].blk), (yyvsp[-1].blk)); } -#line 3369 "src/parser.c" +#line 3367 "src/parser.c" break; case 80: /* Term: '.' String '?' */ -#line 672 "src/parser.y" +#line 670 "src/parser.y" { (yyval.blk) = gen_index_opt(gen_noop(), (yyvsp[-1].blk)); } -#line 3377 "src/parser.c" +#line 3375 "src/parser.c" break; case 81: /* Term: Term FIELD */ -#line 675 "src/parser.y" +#line 673 "src/parser.y" { (yyval.blk) = gen_index((yyvsp[-1].blk), gen_const((yyvsp[0].literal))); } -#line 3385 "src/parser.c" +#line 3383 "src/parser.c" break; case 82: /* Term: FIELD */ -#line 678 "src/parser.y" +#line 676 "src/parser.y" { (yyval.blk) = gen_index(gen_noop(), gen_const((yyvsp[0].literal))); } -#line 3393 "src/parser.c" +#line 3391 "src/parser.c" break; case 83: /* Term: Term '.' String */ -#line 681 "src/parser.y" +#line 679 "src/parser.y" { (yyval.blk) = gen_index((yyvsp[-2].blk), (yyvsp[0].blk)); } -#line 3401 "src/parser.c" +#line 3399 "src/parser.c" break; case 84: /* Term: '.' String */ -#line 684 "src/parser.y" +#line 682 "src/parser.y" { (yyval.blk) = gen_index(gen_noop(), (yyvsp[0].blk)); } -#line 3409 "src/parser.c" +#line 3407 "src/parser.c" break; case 85: /* Term: '.' error */ -#line 687 "src/parser.y" +#line 685 "src/parser.y" { FAIL((yyloc), "try .[\"field\"] instead of .field for unusually named fields"); (yyval.blk) = gen_noop(); } -#line 3418 "src/parser.c" +#line 3416 "src/parser.c" break; case 86: /* Term: '.' IDENT error */ -#line 691 "src/parser.y" +#line 689 "src/parser.y" { jv_free((yyvsp[-1].literal)); FAIL((yyloc), "try .[\"field\"] instead of .field for unusually named fields"); (yyval.blk) = gen_noop(); } -#line 3428 "src/parser.c" +#line 3426 "src/parser.c" break; case 87: /* Term: Term '[' Exp ']' '?' */ -#line 697 "src/parser.y" +#line 695 "src/parser.y" { (yyval.blk) = gen_index_opt((yyvsp[-4].blk), (yyvsp[-2].blk)); } -#line 3436 "src/parser.c" +#line 3434 "src/parser.c" break; case 88: /* Term: Term '[' Exp ']' */ -#line 700 "src/parser.y" +#line 698 "src/parser.y" { (yyval.blk) = gen_index((yyvsp[-3].blk), (yyvsp[-1].blk)); } -#line 3444 "src/parser.c" +#line 3442 "src/parser.c" break; case 89: /* Term: Term '.' '[' Exp ']' '?' */ -#line 703 "src/parser.y" +#line 701 "src/parser.y" { (yyval.blk) = gen_index_opt((yyvsp[-5].blk), (yyvsp[-2].blk)); } -#line 3452 "src/parser.c" +#line 3450 "src/parser.c" break; case 90: /* Term: Term '.' '[' Exp ']' */ -#line 706 "src/parser.y" +#line 704 "src/parser.y" { (yyval.blk) = gen_index((yyvsp[-4].blk), (yyvsp[-1].blk)); } -#line 3460 "src/parser.c" +#line 3458 "src/parser.c" break; case 91: /* Term: Term '[' ']' '?' */ -#line 709 "src/parser.y" +#line 707 "src/parser.y" { (yyval.blk) = block_join((yyvsp[-3].blk), gen_op_simple(EACH_OPT)); } -#line 3468 "src/parser.c" +#line 3466 "src/parser.c" break; case 92: /* Term: Term '[' ']' */ -#line 712 "src/parser.y" +#line 710 "src/parser.y" { (yyval.blk) = block_join((yyvsp[-2].blk), gen_op_simple(EACH)); } -#line 3476 "src/parser.c" +#line 3474 "src/parser.c" break; case 93: /* Term: Term '.' '[' ']' '?' */ -#line 715 "src/parser.y" +#line 713 "src/parser.y" { (yyval.blk) = block_join((yyvsp[-4].blk), gen_op_simple(EACH_OPT)); } -#line 3484 "src/parser.c" +#line 3482 "src/parser.c" break; case 94: /* Term: Term '.' '[' ']' */ -#line 718 "src/parser.y" +#line 716 "src/parser.y" { (yyval.blk) = block_join((yyvsp[-3].blk), gen_op_simple(EACH)); } -#line 3492 "src/parser.c" +#line 3490 "src/parser.c" break; case 95: /* Term: Term '[' Exp ':' Exp ']' '?' */ -#line 721 "src/parser.y" +#line 719 "src/parser.y" { (yyval.blk) = gen_slice_index((yyvsp[-6].blk), (yyvsp[-4].blk), (yyvsp[-2].blk), INDEX_OPT); } -#line 3500 "src/parser.c" +#line 3498 "src/parser.c" break; case 96: /* Term: Term '[' Exp ':' ']' '?' */ -#line 724 "src/parser.y" +#line 722 "src/parser.y" { (yyval.blk) = gen_slice_index((yyvsp[-5].blk), (yyvsp[-3].blk), gen_const(jv_null()), INDEX_OPT); } -#line 3508 "src/parser.c" +#line 3506 "src/parser.c" break; case 97: /* Term: Term '[' ':' Exp ']' '?' */ -#line 727 "src/parser.y" +#line 725 "src/parser.y" { (yyval.blk) = gen_slice_index((yyvsp[-5].blk), gen_const(jv_null()), (yyvsp[-2].blk), INDEX_OPT); } -#line 3516 "src/parser.c" +#line 3514 "src/parser.c" break; case 98: /* Term: Term '[' Exp ':' Exp ']' */ -#line 730 "src/parser.y" +#line 728 "src/parser.y" { (yyval.blk) = gen_slice_index((yyvsp[-5].blk), (yyvsp[-3].blk), (yyvsp[-1].blk), INDEX); } -#line 3524 "src/parser.c" +#line 3522 "src/parser.c" break; case 99: /* Term: Term '[' Exp ':' ']' */ -#line 733 "src/parser.y" +#line 731 "src/parser.y" { (yyval.blk) = gen_slice_index((yyvsp[-4].blk), (yyvsp[-2].blk), gen_const(jv_null()), INDEX); } -#line 3532 "src/parser.c" +#line 3530 "src/parser.c" break; case 100: /* Term: Term '[' ':' Exp ']' */ -#line 736 "src/parser.y" +#line 734 "src/parser.y" { (yyval.blk) = gen_slice_index((yyvsp[-4].blk), gen_const(jv_null()), (yyvsp[-1].blk), INDEX); } -#line 3540 "src/parser.c" +#line 3538 "src/parser.c" break; case 101: /* Term: LITERAL */ -#line 739 "src/parser.y" +#line 737 "src/parser.y" { (yyval.blk) = gen_const((yyvsp[0].literal)); } -#line 3548 "src/parser.c" +#line 3546 "src/parser.c" break; case 102: /* Term: String */ -#line 742 "src/parser.y" +#line 740 "src/parser.y" { (yyval.blk) = (yyvsp[0].blk); } -#line 3556 "src/parser.c" +#line 3554 "src/parser.c" break; case 103: /* Term: FORMAT */ -#line 745 "src/parser.y" +#line 743 "src/parser.y" { (yyval.blk) = gen_format(gen_noop(), (yyvsp[0].literal)); } -#line 3564 "src/parser.c" +#line 3562 "src/parser.c" break; case 104: /* Term: '(' Exp ')' */ -#line 748 "src/parser.y" +#line 746 "src/parser.y" { (yyval.blk) = (yyvsp[-1].blk); } -#line 3572 "src/parser.c" +#line 3570 "src/parser.c" break; case 105: /* Term: '[' Exp ']' */ -#line 751 "src/parser.y" +#line 749 "src/parser.y" { (yyval.blk) = gen_collect((yyvsp[-1].blk)); } -#line 3580 "src/parser.c" +#line 3578 "src/parser.c" break; case 106: /* Term: '[' ']' */ -#line 754 "src/parser.y" +#line 752 "src/parser.y" { (yyval.blk) = gen_const(jv_array()); } -#line 3588 "src/parser.c" +#line 3586 "src/parser.c" break; case 107: /* Term: '{' MkDict '}' */ -#line 757 "src/parser.y" +#line 755 "src/parser.y" { block o = gen_const_object((yyvsp[-1].blk)); if (o.first != NULL) @@ -3596,37 +3594,37 @@ YYLTYPE yylloc = yyloc_default; else (yyval.blk) = BLOCK(gen_subexp(gen_const(jv_object())), (yyvsp[-1].blk), gen_op_simple(POP)); } -#line 3600 "src/parser.c" +#line 3598 "src/parser.c" break; case 108: /* Term: '$' '$' '$' BINDING */ -#line 779 "src/parser.y" +#line 777 "src/parser.y" { (yyval.blk) = gen_location((yyloc), locations, gen_op_unbound(LOADVN, jv_string_value((yyvsp[0].literal)))); jv_free((yyvsp[0].literal)); } -#line 3609 "src/parser.c" +#line 3607 "src/parser.c" break; case 109: /* Term: BINDING */ -#line 783 "src/parser.y" +#line 781 "src/parser.y" { (yyval.blk) = gen_location((yyloc), locations, gen_op_unbound(LOADV, jv_string_value((yyvsp[0].literal)))); jv_free((yyvsp[0].literal)); } -#line 3618 "src/parser.c" +#line 3616 "src/parser.c" break; case 110: /* Term: "$__loc__" */ -#line 787 "src/parser.y" +#line 785 "src/parser.y" { (yyval.blk) = gen_loc_object(&(yyloc), locations); } -#line 3626 "src/parser.c" +#line 3624 "src/parser.c" break; case 111: /* Term: IDENT */ -#line 790 "src/parser.y" +#line 788 "src/parser.y" { const char *s = jv_string_value((yyvsp[0].literal)); if (strcmp(s, "false") == 0) @@ -3639,198 +3637,198 @@ YYLTYPE yylloc = yyloc_default; (yyval.blk) = gen_location((yyloc), locations, gen_call(s, gen_noop())); jv_free((yyvsp[0].literal)); } -#line 3643 "src/parser.c" +#line 3641 "src/parser.c" break; case 112: /* Term: IDENT '(' Args ')' */ -#line 802 "src/parser.y" +#line 800 "src/parser.y" { (yyval.blk) = gen_call(jv_string_value((yyvsp[-3].literal)), (yyvsp[-1].blk)); (yyval.blk) = gen_location((yylsp[-3]), locations, (yyval.blk)); jv_free((yyvsp[-3].literal)); } -#line 3653 "src/parser.c" +#line 3651 "src/parser.c" break; case 113: /* Term: '(' error ')' */ -#line 807 "src/parser.y" +#line 805 "src/parser.y" { (yyval.blk) = gen_noop(); } -#line 3659 "src/parser.c" +#line 3657 "src/parser.c" break; case 114: /* Term: '[' error ']' */ -#line 808 "src/parser.y" +#line 806 "src/parser.y" { (yyval.blk) = gen_noop(); } -#line 3665 "src/parser.c" +#line 3663 "src/parser.c" break; case 115: /* Term: Term '[' error ']' */ -#line 809 "src/parser.y" +#line 807 "src/parser.y" { (yyval.blk) = (yyvsp[-3].blk); } -#line 3671 "src/parser.c" +#line 3669 "src/parser.c" break; case 116: /* Term: '{' error '}' */ -#line 810 "src/parser.y" +#line 808 "src/parser.y" { (yyval.blk) = gen_noop(); } -#line 3677 "src/parser.c" +#line 3675 "src/parser.c" break; case 117: /* Args: Arg */ -#line 813 "src/parser.y" +#line 811 "src/parser.y" { (yyval.blk) = (yyvsp[0].blk); } -#line 3685 "src/parser.c" +#line 3683 "src/parser.c" break; case 118: /* Args: Args ';' Arg */ -#line 816 "src/parser.y" +#line 814 "src/parser.y" { (yyval.blk) = BLOCK((yyvsp[-2].blk), (yyvsp[0].blk)); } -#line 3693 "src/parser.c" +#line 3691 "src/parser.c" break; case 119: /* Arg: Exp */ -#line 821 "src/parser.y" +#line 819 "src/parser.y" { (yyval.blk) = gen_lambda((yyvsp[0].blk)); } -#line 3701 "src/parser.c" +#line 3699 "src/parser.c" break; case 120: /* RepPatterns: RepPatterns "?//" Pattern */ -#line 826 "src/parser.y" +#line 824 "src/parser.y" { (yyval.blk) = BLOCK((yyvsp[-2].blk), gen_destructure_alt((yyvsp[0].blk))); } -#line 3709 "src/parser.c" +#line 3707 "src/parser.c" break; case 121: /* RepPatterns: Pattern */ -#line 829 "src/parser.y" +#line 827 "src/parser.y" { (yyval.blk) = gen_destructure_alt((yyvsp[0].blk)); } -#line 3717 "src/parser.c" +#line 3715 "src/parser.c" break; case 122: /* Patterns: RepPatterns "?//" Pattern */ -#line 834 "src/parser.y" +#line 832 "src/parser.y" { (yyval.blk) = BLOCK((yyvsp[-2].blk), (yyvsp[0].blk)); } -#line 3725 "src/parser.c" +#line 3723 "src/parser.c" break; case 123: /* Patterns: Pattern */ -#line 837 "src/parser.y" +#line 835 "src/parser.y" { (yyval.blk) = (yyvsp[0].blk); } -#line 3733 "src/parser.c" +#line 3731 "src/parser.c" break; case 124: /* Pattern: BINDING */ -#line 842 "src/parser.y" +#line 840 "src/parser.y" { (yyval.blk) = gen_op_unbound(STOREV, jv_string_value((yyvsp[0].literal))); jv_free((yyvsp[0].literal)); } -#line 3742 "src/parser.c" +#line 3740 "src/parser.c" break; case 125: /* Pattern: '[' ArrayPats ']' */ -#line 846 "src/parser.y" +#line 844 "src/parser.y" { (yyval.blk) = BLOCK((yyvsp[-1].blk), gen_op_simple(POP)); } -#line 3750 "src/parser.c" +#line 3748 "src/parser.c" break; case 126: /* Pattern: '{' ObjPats '}' */ -#line 849 "src/parser.y" +#line 847 "src/parser.y" { (yyval.blk) = BLOCK((yyvsp[-1].blk), gen_op_simple(POP)); } -#line 3758 "src/parser.c" +#line 3756 "src/parser.c" break; case 127: /* ArrayPats: Pattern */ -#line 854 "src/parser.y" +#line 852 "src/parser.y" { (yyval.blk) = gen_array_matcher(gen_noop(), (yyvsp[0].blk)); } -#line 3766 "src/parser.c" +#line 3764 "src/parser.c" break; case 128: /* ArrayPats: ArrayPats ',' Pattern */ -#line 857 "src/parser.y" +#line 855 "src/parser.y" { (yyval.blk) = gen_array_matcher((yyvsp[-2].blk), (yyvsp[0].blk)); } -#line 3774 "src/parser.c" +#line 3772 "src/parser.c" break; case 129: /* ObjPats: ObjPat */ -#line 862 "src/parser.y" +#line 860 "src/parser.y" { (yyval.blk) = (yyvsp[0].blk); } -#line 3782 "src/parser.c" +#line 3780 "src/parser.c" break; case 130: /* ObjPats: ObjPats ',' ObjPat */ -#line 865 "src/parser.y" +#line 863 "src/parser.y" { (yyval.blk) = BLOCK((yyvsp[-2].blk), (yyvsp[0].blk)); } -#line 3790 "src/parser.c" +#line 3788 "src/parser.c" break; case 131: /* ObjPat: BINDING */ -#line 870 "src/parser.y" +#line 868 "src/parser.y" { (yyval.blk) = gen_object_matcher(gen_const((yyvsp[0].literal)), gen_op_unbound(STOREV, jv_string_value((yyvsp[0].literal)))); } -#line 3798 "src/parser.c" +#line 3796 "src/parser.c" break; case 132: /* ObjPat: BINDING ':' Pattern */ -#line 873 "src/parser.y" +#line 871 "src/parser.y" { (yyval.blk) = gen_object_matcher(gen_const((yyvsp[-2].literal)), BLOCK(gen_op_simple(DUP), gen_op_unbound(STOREV, jv_string_value((yyvsp[-2].literal))), (yyvsp[0].blk))); } -#line 3806 "src/parser.c" +#line 3804 "src/parser.c" break; case 133: /* ObjPat: IDENT ':' Pattern */ -#line 876 "src/parser.y" +#line 874 "src/parser.y" { (yyval.blk) = gen_object_matcher(gen_const((yyvsp[-2].literal)), (yyvsp[0].blk)); } -#line 3814 "src/parser.c" +#line 3812 "src/parser.c" break; case 134: /* ObjPat: Keyword ':' Pattern */ -#line 879 "src/parser.y" +#line 877 "src/parser.y" { (yyval.blk) = gen_object_matcher(gen_const((yyvsp[-2].literal)), (yyvsp[0].blk)); } -#line 3822 "src/parser.c" +#line 3820 "src/parser.c" break; case 135: /* ObjPat: String ':' Pattern */ -#line 882 "src/parser.y" +#line 880 "src/parser.y" { (yyval.blk) = gen_object_matcher((yyvsp[-2].blk), (yyvsp[0].blk)); } -#line 3830 "src/parser.c" +#line 3828 "src/parser.c" break; case 136: /* ObjPat: '(' Exp ')' ':' Pattern */ -#line 885 "src/parser.y" +#line 883 "src/parser.y" { jv msg = check_object_key((yyvsp[-3].blk)); if (jv_is_valid(msg)) { @@ -3839,268 +3837,268 @@ YYLTYPE yylloc = yyloc_default; jv_free(msg); (yyval.blk) = gen_object_matcher((yyvsp[-3].blk), (yyvsp[0].blk)); } -#line 3843 "src/parser.c" +#line 3841 "src/parser.c" break; case 137: /* ObjPat: error ':' Pattern */ -#line 893 "src/parser.y" +#line 891 "src/parser.y" { FAIL((yyloc), "May need parentheses around object key expression"); (yyval.blk) = (yyvsp[0].blk); } -#line 3852 "src/parser.c" +#line 3850 "src/parser.c" break; case 138: /* Keyword: "as" */ -#line 899 "src/parser.y" +#line 897 "src/parser.y" { (yyval.literal) = jv_string("as"); } -#line 3860 "src/parser.c" +#line 3858 "src/parser.c" break; case 139: /* Keyword: "def" */ -#line 902 "src/parser.y" +#line 900 "src/parser.y" { (yyval.literal) = jv_string("def"); } -#line 3868 "src/parser.c" +#line 3866 "src/parser.c" break; case 140: /* Keyword: "module" */ -#line 905 "src/parser.y" +#line 903 "src/parser.y" { (yyval.literal) = jv_string("module"); } -#line 3876 "src/parser.c" +#line 3874 "src/parser.c" break; case 141: /* Keyword: "import" */ -#line 908 "src/parser.y" +#line 906 "src/parser.y" { (yyval.literal) = jv_string("import"); } -#line 3884 "src/parser.c" +#line 3882 "src/parser.c" break; case 142: /* Keyword: "include" */ -#line 911 "src/parser.y" +#line 909 "src/parser.y" { (yyval.literal) = jv_string("include"); } -#line 3892 "src/parser.c" +#line 3890 "src/parser.c" break; case 143: /* Keyword: "if" */ -#line 914 "src/parser.y" +#line 912 "src/parser.y" { (yyval.literal) = jv_string("if"); } -#line 3900 "src/parser.c" +#line 3898 "src/parser.c" break; case 144: /* Keyword: "then" */ -#line 917 "src/parser.y" +#line 915 "src/parser.y" { (yyval.literal) = jv_string("then"); } -#line 3908 "src/parser.c" +#line 3906 "src/parser.c" break; case 145: /* Keyword: "else" */ -#line 920 "src/parser.y" +#line 918 "src/parser.y" { (yyval.literal) = jv_string("else"); } -#line 3916 "src/parser.c" +#line 3914 "src/parser.c" break; case 146: /* Keyword: "elif" */ -#line 923 "src/parser.y" +#line 921 "src/parser.y" { (yyval.literal) = jv_string("elif"); } -#line 3924 "src/parser.c" +#line 3922 "src/parser.c" break; case 147: /* Keyword: "reduce" */ -#line 926 "src/parser.y" +#line 924 "src/parser.y" { (yyval.literal) = jv_string("reduce"); } -#line 3932 "src/parser.c" +#line 3930 "src/parser.c" break; case 148: /* Keyword: "foreach" */ -#line 929 "src/parser.y" +#line 927 "src/parser.y" { (yyval.literal) = jv_string("foreach"); } -#line 3940 "src/parser.c" +#line 3938 "src/parser.c" break; case 149: /* Keyword: "end" */ -#line 932 "src/parser.y" +#line 930 "src/parser.y" { (yyval.literal) = jv_string("end"); } -#line 3948 "src/parser.c" +#line 3946 "src/parser.c" break; case 150: /* Keyword: "and" */ -#line 935 "src/parser.y" +#line 933 "src/parser.y" { (yyval.literal) = jv_string("and"); } -#line 3956 "src/parser.c" +#line 3954 "src/parser.c" break; case 151: /* Keyword: "or" */ -#line 938 "src/parser.y" +#line 936 "src/parser.y" { (yyval.literal) = jv_string("or"); } -#line 3964 "src/parser.c" +#line 3962 "src/parser.c" break; case 152: /* Keyword: "try" */ -#line 941 "src/parser.y" +#line 939 "src/parser.y" { (yyval.literal) = jv_string("try"); } -#line 3972 "src/parser.c" +#line 3970 "src/parser.c" break; case 153: /* Keyword: "catch" */ -#line 944 "src/parser.y" +#line 942 "src/parser.y" { (yyval.literal) = jv_string("catch"); } -#line 3980 "src/parser.c" +#line 3978 "src/parser.c" break; case 154: /* Keyword: "label" */ -#line 947 "src/parser.y" +#line 945 "src/parser.y" { (yyval.literal) = jv_string("label"); } -#line 3988 "src/parser.c" +#line 3986 "src/parser.c" break; case 155: /* Keyword: "break" */ -#line 950 "src/parser.y" +#line 948 "src/parser.y" { (yyval.literal) = jv_string("break"); } -#line 3996 "src/parser.c" +#line 3994 "src/parser.c" break; case 156: /* MkDict: %empty */ -#line 955 "src/parser.y" +#line 953 "src/parser.y" { (yyval.blk)=gen_noop(); } -#line 4004 "src/parser.c" +#line 4002 "src/parser.c" break; case 157: /* MkDict: MkDictPair */ -#line 958 "src/parser.y" +#line 956 "src/parser.y" { (yyval.blk) = (yyvsp[0].blk); } -#line 4010 "src/parser.c" +#line 4008 "src/parser.c" break; case 158: /* MkDict: MkDictPair ',' MkDict */ -#line 959 "src/parser.y" +#line 957 "src/parser.y" { (yyval.blk)=block_join((yyvsp[-2].blk), (yyvsp[0].blk)); } -#line 4016 "src/parser.c" +#line 4014 "src/parser.c" break; case 159: /* MkDict: error ',' MkDict */ -#line 960 "src/parser.y" +#line 958 "src/parser.y" { (yyval.blk) = (yyvsp[0].blk); } -#line 4022 "src/parser.c" +#line 4020 "src/parser.c" break; case 160: /* MkDictPair: IDENT ':' ExpD */ -#line 963 "src/parser.y" +#line 961 "src/parser.y" { (yyval.blk) = gen_dictpair(gen_const((yyvsp[-2].literal)), (yyvsp[0].blk)); } -#line 4030 "src/parser.c" +#line 4028 "src/parser.c" break; case 161: /* MkDictPair: Keyword ':' ExpD */ -#line 966 "src/parser.y" +#line 964 "src/parser.y" { (yyval.blk) = gen_dictpair(gen_const((yyvsp[-2].literal)), (yyvsp[0].blk)); } -#line 4038 "src/parser.c" +#line 4036 "src/parser.c" break; case 162: /* MkDictPair: String ':' ExpD */ -#line 969 "src/parser.y" +#line 967 "src/parser.y" { (yyval.blk) = gen_dictpair((yyvsp[-2].blk), (yyvsp[0].blk)); } -#line 4046 "src/parser.c" +#line 4044 "src/parser.c" break; case 163: /* MkDictPair: String */ -#line 972 "src/parser.y" +#line 970 "src/parser.y" { (yyval.blk) = gen_dictpair((yyvsp[0].blk), BLOCK(gen_op_simple(POP), gen_op_simple(DUP2), gen_op_simple(DUP2), gen_op_simple(INDEX))); } -#line 4055 "src/parser.c" +#line 4053 "src/parser.c" break; case 164: /* MkDictPair: BINDING ':' ExpD */ -#line 976 "src/parser.y" +#line 974 "src/parser.y" { (yyval.blk) = gen_dictpair(gen_location((yyloc), locations, gen_op_unbound(LOADV, jv_string_value((yyvsp[-2].literal)))), (yyvsp[0].blk)); } -#line 4064 "src/parser.c" +#line 4062 "src/parser.c" break; case 165: /* MkDictPair: BINDING */ -#line 980 "src/parser.y" +#line 978 "src/parser.y" { (yyval.blk) = gen_dictpair(gen_const((yyvsp[0].literal)), gen_location((yyloc), locations, gen_op_unbound(LOADV, jv_string_value((yyvsp[0].literal))))); } -#line 4073 "src/parser.c" +#line 4071 "src/parser.c" break; case 166: /* MkDictPair: IDENT */ -#line 984 "src/parser.y" +#line 982 "src/parser.y" { (yyval.blk) = gen_dictpair(gen_const(jv_copy((yyvsp[0].literal))), gen_index(gen_noop(), gen_const((yyvsp[0].literal)))); } -#line 4082 "src/parser.c" +#line 4080 "src/parser.c" break; case 167: /* MkDictPair: "$__loc__" */ -#line 988 "src/parser.y" +#line 986 "src/parser.y" { (yyval.blk) = gen_dictpair(gen_const(jv_string("__loc__")), gen_loc_object(&(yyloc), locations)); } -#line 4091 "src/parser.c" +#line 4089 "src/parser.c" break; case 168: /* MkDictPair: Keyword */ -#line 992 "src/parser.y" +#line 990 "src/parser.y" { (yyval.blk) = gen_dictpair(gen_const(jv_copy((yyvsp[0].literal))), gen_index(gen_noop(), gen_const((yyvsp[0].literal)))); } -#line 4100 "src/parser.c" +#line 4098 "src/parser.c" break; case 169: /* MkDictPair: '(' Exp ')' ':' ExpD */ -#line 996 "src/parser.y" +#line 994 "src/parser.y" { jv msg = check_object_key((yyvsp[-3].blk)); if (jv_is_valid(msg)) { @@ -4109,20 +4107,20 @@ YYLTYPE yylloc = yyloc_default; jv_free(msg); (yyval.blk) = gen_dictpair((yyvsp[-3].blk), (yyvsp[0].blk)); } -#line 4113 "src/parser.c" +#line 4111 "src/parser.c" break; case 170: /* MkDictPair: error ':' ExpD */ -#line 1004 "src/parser.y" +#line 1002 "src/parser.y" { FAIL((yyloc), "May need parentheses around object key expression"); (yyval.blk) = (yyvsp[0].blk); } -#line 4122 "src/parser.c" +#line 4120 "src/parser.c" break; -#line 4126 "src/parser.c" +#line 4124 "src/parser.c" default: break; } @@ -4351,7 +4349,7 @@ YYLTYPE yylloc = yyloc_default; return yyresult; } -#line 1008 "src/parser.y" +#line 1006 "src/parser.y" int jq_parse(struct locfile* locations, block* answer) { diff --git a/src/parser.y b/src/parser.y index 6924ad34dc..7599d9f2f4 100644 --- a/src/parser.y +++ b/src/parser.y @@ -379,11 +379,9 @@ Term "as" Patterns '|' Exp { } | "try" Exp "catch" Exp { - //$$ = BLOCK(gen_op_target(FORK_OPT, $2), $2, $4); - $$ = gen_try($2, gen_try_handler($4)); + $$ = gen_try($2, $4); } | "try" Exp { - //$$ = BLOCK(gen_op_target(FORK_OPT, $2), $2, gen_op_simple(BACKTRACK)); $$ = gen_try($2, gen_op_simple(BACKTRACK)); } | "try" Exp "catch" error { diff --git a/tests/jq.test b/tests/jq.test index da35e9a84c..2cc16bdbcf 100644 --- a/tests/jq.test +++ b/tests/jq.test @@ -1834,3 +1834,58 @@ null debug 1 1 + +# try/catch catches more than it should #1859 +"foo" | try ((try . catch "caught too much") | error) catch "caught just right" +null +"caught just right" + +.[]|(try (if .=="hi" then . else error end) catch empty) | "\(.) there!" +["hi","ho"] +"hi there!" + +try (["hi","ho"]|.[]|(try . catch (if .=="ho" then "BROKEN"|error else empty end)) | if .=="ho" then error else "\(.) there!" end) catch "caught outside \(.)" +null +"hi there!" +"caught outside ho" + +.[]|(try . catch (if .=="ho" then "BROKEN"|error else empty end)) | if .=="ho" then error else "\(.) there!" end +["hi","ho"] +"hi there!" + +try (try error catch "inner catch \(.)") catch "outer catch \(.)" +"foo" +"inner catch foo" + +try ((try error catch "inner catch \(.)")|error) catch "outer catch \(.)" +"foo" +"outer catch inner catch foo" + +# Also #1859, but from #1885 +first(.?,.?) +null +null + +# Also #1859, but from #2140 +{foo: "bar"} | .foo |= .? +null +{"foo": "bar"} + +# Also #1859, but from #2220 +. |= try 2 +1 +2 + +. |= try 2 catch 3 +1 +2 + +.[] |= try tonumber +["1", "2a", "3", 4] +[1, 3, 4] + +# Also 1859, but from 2073 +any(keys[]|tostring?;true) +{"a":"1","b":"2","c":"3"} +true +