From b733dfaee788542daa20bd15d7711d3da3216cc8 Mon Sep 17 00:00:00 2001 From: itchyny Date: Sun, 18 May 2025 16:36:32 +0900 Subject: [PATCH] Improve error messages to show problematic position in the filter (#3292) This commit improves the parser and compiler error messages, making it more easier to understand where in the filter the problem is. Like modern compilers, jq will show the line in the filter where the error occurred, will display squiggly line under the invalid token. --- src/jq_test.c | 79 +-- src/locfile.c | 22 +- src/parser.c | 1298 ++++++++++++++++++++++++------------------------- src/parser.y | 26 +- tests/jq.test | 88 +++- tests/shtest | 23 + 6 files changed, 801 insertions(+), 735 deletions(-) diff --git a/src/jq_test.c b/src/jq_test.c index 0b76f795..9f3e1ea3 100644 --- a/src/jq_test.c +++ b/src/jq_test.c @@ -70,8 +70,6 @@ static void test_err_cb(void *data, jv e) { e = jv_dump_string(e, JV_PRINT_INVALID); if (!strncmp(jv_string_value(e), "jq: error", sizeof("jq: error") - 1)) snprintf(err_data->buf, sizeof(err_data->buf), "%s", jv_string_value(e)); - if (strchr(err_data->buf, '\n')) - *(strchr(err_data->buf, '\n')) = '\0'; jv_free(e); } @@ -108,18 +106,7 @@ static void run_jq_tests(jv lib_dirs, int verbose, FILE *testdata, int skip, int if (skip > 0) { skip--; - - // skip past test data - while (fgets(buf, sizeof(buf), testdata)) { - lineno++; - if (buf[0] == '\n' || (buf[0] == '\r' && buf[1] == '\n')) - break; - } - - must_fail = 0; - check_msg = 0; - - continue; + goto next; } else if (skip == 0) { printf("Skipped %d tests\n", tests_to_skip); skip = -1; @@ -139,37 +126,40 @@ static void run_jq_tests(jv lib_dirs, int verbose, FILE *testdata, int skip, int if (must_fail) { jq_set_error_cb(jq, NULL, NULL); - if (!fgets(buf, sizeof(buf), testdata)) { invalid++; break; } - lineno++; - if (buf[strlen(buf)-1] == '\n') buf[strlen(buf)-1] = 0; if (compiled) { - printf("*** Test program compiled that should not have at line %u: %s\n", lineno, prog); - must_fail = 0; - check_msg = 0; - invalid++; - continue; + printf("*** Test program compiled successfully, but should fail at line number %u: %s\n", lineno, prog); + goto fail; } - if (check_msg && strcmp(buf, err_msg.buf) != 0) { - printf("*** Erroneous test program failed with wrong message (%s) at line %u: %s\n", err_msg.buf, lineno, prog); + char *err_buf = err_msg.buf; + while (fgets(buf, sizeof(buf), testdata)) { + lineno++; + if (skipline(buf)) break; + if (check_msg) { + if (buf[strlen(buf)-1] == '\n') buf[strlen(buf)-1] = '\0'; + if (strncmp(buf, err_buf, strlen(buf)) != 0) { + if (strchr(err_buf, '\n')) *strchr(err_buf, '\n') = '\0'; + printf("*** Erroneous program failed with '%s', but expected '%s' at line number %u: %s\n", err_buf, buf, lineno, prog); + goto fail; + } + err_buf += strlen(buf); + if (*err_buf == '\n') err_buf++; + } + } + if (check_msg && *err_buf != '\0') { + if (strchr(err_buf, '\n')) *strchr(err_buf, '\n') = '\0'; + printf("*** Erroneous program failed with extra message '%s' at line %u: %s\n", err_buf, lineno, prog); invalid++; - } else { - passed++; + pass = 0; } must_fail = 0; check_msg = 0; + passed += pass; continue; } if (!compiled) { printf("*** Test program failed to compile at line %u: %s\n", lineno, prog); - invalid++; - // skip past test data - while (fgets(buf, sizeof(buf), testdata)) { - lineno++; - if (buf[0] == '\n' || (buf[0] == '\r' && buf[1] == '\n')) - break; - } - continue; + goto fail; } if (verbose) { printf("Disassembly:\n"); @@ -181,8 +171,7 @@ static void run_jq_tests(jv lib_dirs, int verbose, FILE *testdata, int skip, int jv input = jv_parse(buf); if (!jv_is_valid(input)) { printf("*** Input is invalid on line %u: %s\n", lineno, buf); - invalid++; - continue; + goto fail; } jq_start(jq, input, verbose ? JQ_DEBUG_TRACE : 0); @@ -192,8 +181,7 @@ static void run_jq_tests(jv lib_dirs, int verbose, FILE *testdata, int skip, int jv expected = jv_parse(buf); if (!jv_is_valid(expected)) { printf("*** Expected result is invalid on line %u: %s\n", lineno, buf); - invalid++; - continue; + goto fail; } jv actual = jq_next(jq); if (!jv_is_valid(actual)) { @@ -226,12 +214,25 @@ static void run_jq_tests(jv lib_dirs, int verbose, FILE *testdata, int skip, int printf("*** Superfluous result: "); jv_dump(extra, 0); printf(" for test at line number %u, %s\n", lineno, prog); + invalid++; pass = 0; } else { jv_free(extra); } } - passed+=pass; + passed += pass; + continue; + +fail: + invalid++; + +next: + while (fgets(buf, sizeof(buf), testdata)) { + lineno++; + if (skipline(buf)) break; + } + must_fail = 0; + check_msg = 0; } jq_teardown(&jq); diff --git a/src/locfile.c b/src/locfile.c index a1189e14..7e1c394e 100644 --- a/src/locfile.c +++ b/src/locfile.c @@ -7,7 +7,7 @@ #include "jq.h" #include "jv_alloc.h" #include "locfile.h" - +#include "util.h" struct locfile* locfile_init(jq_state *jq, const char *fname, const char* data, int length) { struct locfile* l = jv_mem_alloc(sizeof(struct locfile)); @@ -63,13 +63,6 @@ static int locfile_line_length(struct locfile* l, int line) { void locfile_locate(struct locfile* l, location loc, const char* fmt, ...) { va_list fmtargs; va_start(fmtargs, fmt); - int startline; - int offset; - - if (loc.start != -1) { - startline = locfile_get_line(l, loc.start); - offset = l->linemap[startline]; - } jv m1 = jv_string_vfmt(fmt, fmtargs); va_end(fmtargs); @@ -78,16 +71,23 @@ void locfile_locate(struct locfile* l, location loc, const char* fmt, ...) { return; } if (loc.start == -1) { - jq_report_error(l->jq, jv_string_fmt("jq: error: %s\n", jv_string_value(m1))); + jq_report_error(l->jq, jv_string_fmt("jq: error: %s", jv_string_value(m1))); jv_free(m1); return; } - jv m2 = jv_string_fmt("%s at %s, line %d, column %d:\n%.*s%*s", + + int startline = locfile_get_line(l, loc.start); + int offset = l->linemap[startline]; + int end = MIN(loc.end, l->linemap[startline+1] - 1); + assert(end > loc.start); + jv underline = jv_string_repeat(jv_string("^"), end - loc.start); + jv m2 = jv_string_fmt("%s at %s, line %d, column %d:\n %.*s\n %*s", jv_string_value(m1), jv_string_value(l->fname), startline + 1, loc.start - offset + 1, locfile_line_length(l, startline), l->data + offset, - loc.start - offset, ""); + end - offset, jv_string_value(underline)); jv_free(m1); + jv_free(underline); jq_report_error(l->jq, m2); return; } diff --git a/src/parser.c b/src/parser.c index 8e583c51..0eaefaf6 100644 --- a/src/parser.c +++ b/src/parser.c @@ -406,15 +406,7 @@ struct lexer_param { void yyerror(YYLTYPE* loc, block* answer, int* errors, struct locfile* locations, struct lexer_param* lexer_param_ptr, const char *s){ (*errors)++; - if (strstr(s, "unexpected")) { -#ifdef WIN32 - locfile_locate(locations, *loc, "jq: error: %s (Windows cmd shell quoting issues?)", s); -#else - locfile_locate(locations, *loc, "jq: error: %s (Unix shell quoting issues?)", s); -#endif - } else { - locfile_locate(locations, *loc, "jq: error: %s", s); - } + locfile_locate(locations, *loc, "jq: error: %s", s); } int yylex(YYSTYPE* yylval, YYLTYPE* yylloc, block* answer, int* errors, @@ -551,7 +543,7 @@ static block gen_loc_object(location *loc, struct locfile *locations) { } -#line 555 "src/parser.c" +#line 547 "src/parser.c" #ifdef short @@ -941,23 +933,23 @@ static const yytype_int8 yytranslate[] = /* YYRLINE[YYN] -- Source line where rule number YYN was defined. */ static const yytype_int16 yyrline[] = { - 0, 290, 290, 293, 298, 301, 316, 319, 324, 327, - 333, 336, 339, 345, 348, 351, 357, 360, 363, 366, - 369, 372, 375, 378, 381, 384, 387, 390, 393, 396, - 399, 402, 405, 408, 411, 414, 417, 420, 423, 429, - 432, 449, 458, 465, 473, 484, 489, 495, 498, 503, - 507, 514, 517, 523, 530, 533, 536, 542, 545, 548, - 554, 557, 560, 568, 572, 575, 578, 581, 584, 587, - 590, 593, 596, 600, 606, 609, 612, 615, 618, 621, - 624, 627, 630, 633, 636, 639, 642, 645, 648, 651, - 654, 657, 660, 663, 666, 669, 672, 679, 682, 685, - 688, 691, 695, 698, 702, 720, 724, 728, 731, 743, - 748, 749, 750, 751, 754, 757, 762, 767, 770, 775, - 778, 783, 787, 790, 795, 798, 803, 806, 811, 814, - 817, 820, 823, 826, 834, 840, 843, 846, 849, 852, - 855, 858, 861, 864, 867, 870, 873, 876, 879, 882, - 885, 888, 891, 897, 900, 903, 908, 911, 914, 917, - 921, 926, 930, 934, 938, 942, 950, 956, 959 + 0, 282, 282, 285, 290, 293, 308, 311, 316, 319, + 325, 328, 331, 337, 340, 343, 349, 352, 355, 358, + 361, 364, 367, 370, 373, 376, 379, 382, 385, 388, + 391, 394, 397, 400, 403, 406, 409, 412, 415, 421, + 424, 441, 450, 457, 465, 476, 481, 487, 490, 495, + 499, 506, 509, 515, 522, 525, 528, 534, 537, 540, + 546, 549, 552, 560, 564, 567, 570, 573, 576, 579, + 582, 585, 588, 592, 598, 601, 604, 607, 610, 613, + 616, 619, 622, 625, 628, 631, 634, 637, 640, 643, + 646, 649, 652, 655, 658, 661, 664, 671, 674, 677, + 680, 683, 687, 690, 694, 712, 716, 720, 723, 735, + 740, 741, 742, 743, 746, 749, 754, 759, 762, 767, + 770, 775, 779, 782, 787, 790, 795, 798, 803, 806, + 809, 812, 815, 818, 826, 832, 835, 838, 841, 844, + 847, 850, 853, 856, 859, 862, 865, 868, 871, 874, + 877, 880, 883, 889, 892, 895, 900, 903, 906, 909, + 913, 918, 922, 926, 930, 934, 942, 948, 951 }; #endif @@ -2018,205 +2010,205 @@ yydestruct (const char *yymsg, case YYSYMBOL_IDENT: /* IDENT */ #line 37 "src/parser.y" { jv_free(((*yyvaluep).literal)); } -#line 2022 "src/parser.c" +#line 2014 "src/parser.c" break; case YYSYMBOL_FIELD: /* FIELD */ #line 37 "src/parser.y" { jv_free(((*yyvaluep).literal)); } -#line 2028 "src/parser.c" +#line 2020 "src/parser.c" break; case YYSYMBOL_BINDING: /* BINDING */ #line 37 "src/parser.y" { jv_free(((*yyvaluep).literal)); } -#line 2034 "src/parser.c" +#line 2026 "src/parser.c" break; case YYSYMBOL_LITERAL: /* LITERAL */ #line 37 "src/parser.y" { jv_free(((*yyvaluep).literal)); } -#line 2040 "src/parser.c" +#line 2032 "src/parser.c" break; case YYSYMBOL_FORMAT: /* FORMAT */ #line 37 "src/parser.y" { jv_free(((*yyvaluep).literal)); } -#line 2046 "src/parser.c" +#line 2038 "src/parser.c" break; case YYSYMBOL_QQSTRING_TEXT: /* QQSTRING_TEXT */ #line 37 "src/parser.y" { jv_free(((*yyvaluep).literal)); } -#line 2052 "src/parser.c" +#line 2044 "src/parser.c" break; case YYSYMBOL_Module: /* Module */ #line 38 "src/parser.y" { block_free(((*yyvaluep).blk)); } -#line 2058 "src/parser.c" +#line 2050 "src/parser.c" break; case YYSYMBOL_Imports: /* Imports */ #line 38 "src/parser.y" { block_free(((*yyvaluep).blk)); } -#line 2064 "src/parser.c" +#line 2056 "src/parser.c" break; case YYSYMBOL_FuncDefs: /* FuncDefs */ #line 38 "src/parser.y" { block_free(((*yyvaluep).blk)); } -#line 2070 "src/parser.c" +#line 2062 "src/parser.c" break; case YYSYMBOL_Query: /* Query */ #line 38 "src/parser.y" { block_free(((*yyvaluep).blk)); } -#line 2076 "src/parser.c" +#line 2068 "src/parser.c" break; case YYSYMBOL_Expr: /* Expr */ #line 38 "src/parser.y" { block_free(((*yyvaluep).blk)); } -#line 2082 "src/parser.c" +#line 2074 "src/parser.c" break; case YYSYMBOL_Import: /* Import */ #line 38 "src/parser.y" { block_free(((*yyvaluep).blk)); } -#line 2088 "src/parser.c" +#line 2080 "src/parser.c" break; case YYSYMBOL_ImportWhat: /* ImportWhat */ #line 38 "src/parser.y" { block_free(((*yyvaluep).blk)); } -#line 2094 "src/parser.c" +#line 2086 "src/parser.c" break; case YYSYMBOL_ImportFrom: /* ImportFrom */ #line 38 "src/parser.y" { block_free(((*yyvaluep).blk)); } -#line 2100 "src/parser.c" +#line 2092 "src/parser.c" break; case YYSYMBOL_FuncDef: /* FuncDef */ #line 38 "src/parser.y" { block_free(((*yyvaluep).blk)); } -#line 2106 "src/parser.c" +#line 2098 "src/parser.c" break; case YYSYMBOL_Params: /* Params */ #line 38 "src/parser.y" { block_free(((*yyvaluep).blk)); } -#line 2112 "src/parser.c" +#line 2104 "src/parser.c" break; case YYSYMBOL_Param: /* Param */ #line 38 "src/parser.y" { block_free(((*yyvaluep).blk)); } -#line 2118 "src/parser.c" +#line 2110 "src/parser.c" break; case YYSYMBOL_StringStart: /* StringStart */ #line 37 "src/parser.y" { jv_free(((*yyvaluep).literal)); } -#line 2124 "src/parser.c" +#line 2116 "src/parser.c" break; case YYSYMBOL_String: /* String */ #line 38 "src/parser.y" { block_free(((*yyvaluep).blk)); } -#line 2130 "src/parser.c" +#line 2122 "src/parser.c" break; case YYSYMBOL_QQString: /* QQString */ #line 38 "src/parser.y" { block_free(((*yyvaluep).blk)); } -#line 2136 "src/parser.c" +#line 2128 "src/parser.c" break; case YYSYMBOL_ElseBody: /* ElseBody */ #line 38 "src/parser.y" { block_free(((*yyvaluep).blk)); } -#line 2142 "src/parser.c" +#line 2134 "src/parser.c" break; case YYSYMBOL_Term: /* Term */ #line 38 "src/parser.y" { block_free(((*yyvaluep).blk)); } -#line 2148 "src/parser.c" +#line 2140 "src/parser.c" break; case YYSYMBOL_Args: /* Args */ #line 38 "src/parser.y" { block_free(((*yyvaluep).blk)); } -#line 2154 "src/parser.c" +#line 2146 "src/parser.c" break; case YYSYMBOL_Arg: /* Arg */ #line 38 "src/parser.y" { block_free(((*yyvaluep).blk)); } -#line 2160 "src/parser.c" +#line 2152 "src/parser.c" break; case YYSYMBOL_RepPatterns: /* RepPatterns */ #line 38 "src/parser.y" { block_free(((*yyvaluep).blk)); } -#line 2166 "src/parser.c" +#line 2158 "src/parser.c" break; case YYSYMBOL_Patterns: /* Patterns */ #line 38 "src/parser.y" { block_free(((*yyvaluep).blk)); } -#line 2172 "src/parser.c" +#line 2164 "src/parser.c" break; case YYSYMBOL_Pattern: /* Pattern */ #line 38 "src/parser.y" { block_free(((*yyvaluep).blk)); } -#line 2178 "src/parser.c" +#line 2170 "src/parser.c" break; case YYSYMBOL_ArrayPats: /* ArrayPats */ #line 38 "src/parser.y" { block_free(((*yyvaluep).blk)); } -#line 2184 "src/parser.c" +#line 2176 "src/parser.c" break; case YYSYMBOL_ObjPats: /* ObjPats */ #line 38 "src/parser.y" { block_free(((*yyvaluep).blk)); } -#line 2190 "src/parser.c" +#line 2182 "src/parser.c" break; case YYSYMBOL_ObjPat: /* ObjPat */ #line 38 "src/parser.y" { block_free(((*yyvaluep).blk)); } -#line 2196 "src/parser.c" +#line 2188 "src/parser.c" break; case YYSYMBOL_Keyword: /* Keyword */ #line 37 "src/parser.y" { jv_free(((*yyvaluep).literal)); } -#line 2202 "src/parser.c" +#line 2194 "src/parser.c" break; case YYSYMBOL_DictPairs: /* DictPairs */ #line 38 "src/parser.y" { block_free(((*yyvaluep).blk)); } -#line 2208 "src/parser.c" +#line 2200 "src/parser.c" break; case YYSYMBOL_DictPair: /* DictPair */ #line 38 "src/parser.y" { block_free(((*yyvaluep).blk)); } -#line 2214 "src/parser.c" +#line 2206 "src/parser.c" break; case YYSYMBOL_DictExpr: /* DictExpr */ #line 38 "src/parser.y" { block_free(((*yyvaluep).blk)); } -#line 2220 "src/parser.c" +#line 2212 "src/parser.c" break; default: @@ -2520,332 +2512,332 @@ yyreduce: switch (yyn) { case 2: /* TopLevel: Module Imports Query */ -#line 290 "src/parser.y" +#line 282 "src/parser.y" { *answer = BLOCK((yyvsp[-2].blk), (yyvsp[-1].blk), gen_op_simple(TOP), (yyvsp[0].blk)); } +#line 2520 "src/parser.c" + break; + + case 3: /* TopLevel: Module Imports FuncDefs */ +#line 285 "src/parser.y" + { + *answer = BLOCK((yyvsp[-2].blk), (yyvsp[-1].blk), (yyvsp[0].blk)); +} #line 2528 "src/parser.c" break; - case 3: /* TopLevel: Module Imports FuncDefs */ -#line 293 "src/parser.y" - { - *answer = BLOCK((yyvsp[-2].blk), (yyvsp[-1].blk), (yyvsp[0].blk)); + case 4: /* Module: %empty */ +#line 290 "src/parser.y" + { + (yyval.blk) = gen_noop(); } #line 2536 "src/parser.c" break; - case 4: /* Module: %empty */ -#line 298 "src/parser.y" - { - (yyval.blk) = gen_noop(); -} -#line 2544 "src/parser.c" - break; - case 5: /* Module: "module" Query ';' */ -#line 301 "src/parser.y" +#line 293 "src/parser.y" { if (!block_is_const((yyvsp[-1].blk))) { - FAIL((yyloc), "Module metadata must be constant"); + FAIL((yylsp[-1]), "Module metadata must be constant"); (yyval.blk) = gen_noop(); block_free((yyvsp[-1].blk)); } else if (block_const_kind((yyvsp[-1].blk)) != JV_KIND_OBJECT) { - FAIL((yyloc), "Module metadata must be an object"); + FAIL((yylsp[-1]), "Module metadata must be an object"); (yyval.blk) = gen_noop(); block_free((yyvsp[-1].blk)); } else { (yyval.blk) = gen_module((yyvsp[-1].blk)); } } -#line 2562 "src/parser.c" +#line 2554 "src/parser.c" break; case 6: /* Imports: %empty */ -#line 316 "src/parser.y" +#line 308 "src/parser.y" { (yyval.blk) = gen_noop(); } +#line 2562 "src/parser.c" + break; + + case 7: /* Imports: Import Imports */ +#line 311 "src/parser.y" + { + (yyval.blk) = BLOCK((yyvsp[-1].blk), (yyvsp[0].blk)); +} #line 2570 "src/parser.c" break; - case 7: /* Imports: Import Imports */ -#line 319 "src/parser.y" - { - (yyval.blk) = BLOCK((yyvsp[-1].blk), (yyvsp[0].blk)); + case 8: /* FuncDefs: %empty */ +#line 316 "src/parser.y" + { + (yyval.blk) = gen_noop(); } #line 2578 "src/parser.c" break; - case 8: /* FuncDefs: %empty */ -#line 324 "src/parser.y" - { - (yyval.blk) = gen_noop(); + case 9: /* FuncDefs: FuncDef FuncDefs */ +#line 319 "src/parser.y" + { + (yyval.blk) = block_join((yyvsp[-1].blk), (yyvsp[0].blk)); } #line 2586 "src/parser.c" break; - case 9: /* FuncDefs: FuncDef FuncDefs */ -#line 327 "src/parser.y" - { - (yyval.blk) = block_join((yyvsp[-1].blk), (yyvsp[0].blk)); + case 10: /* Query: FuncDef Query */ +#line 325 "src/parser.y" + { + (yyval.blk) = block_bind_referenced((yyvsp[-1].blk), (yyvsp[0].blk), OP_IS_CALL_PSEUDO); } #line 2594 "src/parser.c" break; - case 10: /* Query: FuncDef Query */ -#line 333 "src/parser.y" - { - (yyval.blk) = block_bind_referenced((yyvsp[-1].blk), (yyvsp[0].blk), OP_IS_CALL_PSEUDO); + case 11: /* Query: Term "as" Patterns '|' Query */ +#line 328 "src/parser.y" + { + (yyval.blk) = gen_destructure((yyvsp[-4].blk), (yyvsp[-2].blk), (yyvsp[0].blk)); } #line 2602 "src/parser.c" break; - case 11: /* Query: Term "as" Patterns '|' Query */ -#line 336 "src/parser.y" - { - (yyval.blk) = gen_destructure((yyvsp[-4].blk), (yyvsp[-2].blk), (yyvsp[0].blk)); -} -#line 2610 "src/parser.c" - break; - case 12: /* Query: "label" BINDING '|' Query */ -#line 339 "src/parser.y" +#line 331 "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 2621 "src/parser.c" +#line 2613 "src/parser.c" break; case 13: /* Query: Query '|' Query */ -#line 345 "src/parser.y" +#line 337 "src/parser.y" { (yyval.blk) = block_join((yyvsp[-2].blk), (yyvsp[0].blk)); } +#line 2621 "src/parser.c" + break; + + case 14: /* Query: Query ',' Query */ +#line 340 "src/parser.y" + { + (yyval.blk) = gen_both((yyvsp[-2].blk), (yyvsp[0].blk)); +} #line 2629 "src/parser.c" break; - case 14: /* Query: Query ',' Query */ -#line 348 "src/parser.y" - { - (yyval.blk) = gen_both((yyvsp[-2].blk), (yyvsp[0].blk)); + case 15: /* Query: Expr */ +#line 343 "src/parser.y" + { + (yyval.blk) = (yyvsp[0].blk); } #line 2637 "src/parser.c" break; - case 15: /* Query: Expr */ -#line 351 "src/parser.y" - { - (yyval.blk) = (yyvsp[0].blk); + case 16: /* Expr: Expr "//" Expr */ +#line 349 "src/parser.y" + { + (yyval.blk) = gen_definedor((yyvsp[-2].blk), (yyvsp[0].blk)); } #line 2645 "src/parser.c" break; - case 16: /* Expr: Expr "//" Expr */ -#line 357 "src/parser.y" - { - (yyval.blk) = gen_definedor((yyvsp[-2].blk), (yyvsp[0].blk)); + case 17: /* Expr: Expr '=' Expr */ +#line 352 "src/parser.y" + { + (yyval.blk) = gen_call("_assign", BLOCK(gen_lambda((yyvsp[-2].blk)), gen_lambda((yyvsp[0].blk)))); } #line 2653 "src/parser.c" break; - case 17: /* Expr: Expr '=' Expr */ -#line 360 "src/parser.y" - { - (yyval.blk) = gen_call("_assign", BLOCK(gen_lambda((yyvsp[-2].blk)), gen_lambda((yyvsp[0].blk)))); + case 18: /* Expr: Expr "or" Expr */ +#line 355 "src/parser.y" + { + (yyval.blk) = gen_or((yyvsp[-2].blk), (yyvsp[0].blk)); } #line 2661 "src/parser.c" break; - case 18: /* Expr: Expr "or" Expr */ -#line 363 "src/parser.y" - { - (yyval.blk) = gen_or((yyvsp[-2].blk), (yyvsp[0].blk)); + case 19: /* Expr: Expr "and" Expr */ +#line 358 "src/parser.y" + { + (yyval.blk) = gen_and((yyvsp[-2].blk), (yyvsp[0].blk)); } #line 2669 "src/parser.c" break; - case 19: /* Expr: Expr "and" Expr */ -#line 366 "src/parser.y" + case 20: /* Expr: Expr "//=" Expr */ +#line 361 "src/parser.y" { - (yyval.blk) = gen_and((yyvsp[-2].blk), (yyvsp[0].blk)); + (yyval.blk) = gen_definedor_assign((yyvsp[-2].blk), (yyvsp[0].blk)); } #line 2677 "src/parser.c" break; - case 20: /* Expr: Expr "//=" Expr */ -#line 369 "src/parser.y" - { - (yyval.blk) = gen_definedor_assign((yyvsp[-2].blk), (yyvsp[0].blk)); + case 21: /* Expr: Expr "|=" Expr */ +#line 364 "src/parser.y" + { + (yyval.blk) = gen_call("_modify", BLOCK(gen_lambda((yyvsp[-2].blk)), gen_lambda((yyvsp[0].blk)))); } #line 2685 "src/parser.c" break; - case 21: /* Expr: Expr "|=" Expr */ -#line 372 "src/parser.y" - { - (yyval.blk) = gen_call("_modify", BLOCK(gen_lambda((yyvsp[-2].blk)), gen_lambda((yyvsp[0].blk)))); + case 22: /* Expr: Expr '+' Expr */ +#line 367 "src/parser.y" + { + (yyval.blk) = gen_binop((yyvsp[-2].blk), (yyvsp[0].blk), '+'); } #line 2693 "src/parser.c" break; - case 22: /* Expr: Expr '+' Expr */ -#line 375 "src/parser.y" - { - (yyval.blk) = gen_binop((yyvsp[-2].blk), (yyvsp[0].blk), '+'); + case 23: /* Expr: Expr "+=" Expr */ +#line 370 "src/parser.y" + { + (yyval.blk) = gen_update((yyvsp[-2].blk), (yyvsp[0].blk), '+'); } #line 2701 "src/parser.c" break; - case 23: /* Expr: Expr "+=" Expr */ -#line 378 "src/parser.y" - { - (yyval.blk) = gen_update((yyvsp[-2].blk), (yyvsp[0].blk), '+'); + case 24: /* Expr: Expr '-' Expr */ +#line 373 "src/parser.y" + { + (yyval.blk) = gen_binop((yyvsp[-2].blk), (yyvsp[0].blk), '-'); } #line 2709 "src/parser.c" break; - case 24: /* Expr: Expr '-' Expr */ -#line 381 "src/parser.y" - { - (yyval.blk) = gen_binop((yyvsp[-2].blk), (yyvsp[0].blk), '-'); + case 25: /* Expr: Expr "-=" Expr */ +#line 376 "src/parser.y" + { + (yyval.blk) = gen_update((yyvsp[-2].blk), (yyvsp[0].blk), '-'); } #line 2717 "src/parser.c" break; - case 25: /* Expr: Expr "-=" Expr */ -#line 384 "src/parser.y" - { - (yyval.blk) = gen_update((yyvsp[-2].blk), (yyvsp[0].blk), '-'); + case 26: /* Expr: Expr '*' Expr */ +#line 379 "src/parser.y" + { + (yyval.blk) = gen_binop((yyvsp[-2].blk), (yyvsp[0].blk), '*'); } #line 2725 "src/parser.c" break; - case 26: /* Expr: Expr '*' Expr */ -#line 387 "src/parser.y" - { - (yyval.blk) = gen_binop((yyvsp[-2].blk), (yyvsp[0].blk), '*'); + case 27: /* Expr: Expr "*=" Expr */ +#line 382 "src/parser.y" + { + (yyval.blk) = gen_update((yyvsp[-2].blk), (yyvsp[0].blk), '*'); } #line 2733 "src/parser.c" break; - case 27: /* Expr: Expr "*=" Expr */ -#line 390 "src/parser.y" - { - (yyval.blk) = gen_update((yyvsp[-2].blk), (yyvsp[0].blk), '*'); + case 28: /* Expr: Expr '/' Expr */ +#line 385 "src/parser.y" + { + (yyval.blk) = gen_binop((yyvsp[-2].blk), (yyvsp[0].blk), '/'); } #line 2741 "src/parser.c" break; - case 28: /* Expr: Expr '/' Expr */ -#line 393 "src/parser.y" + case 29: /* Expr: Expr '%' Expr */ +#line 388 "src/parser.y" { - (yyval.blk) = gen_binop((yyvsp[-2].blk), (yyvsp[0].blk), '/'); + (yyval.blk) = gen_binop((yyvsp[-2].blk), (yyvsp[0].blk), '%'); } #line 2749 "src/parser.c" break; - case 29: /* Expr: Expr '%' Expr */ -#line 396 "src/parser.y" - { - (yyval.blk) = gen_binop((yyvsp[-2].blk), (yyvsp[0].blk), '%'); + case 30: /* Expr: Expr "/=" Expr */ +#line 391 "src/parser.y" + { + (yyval.blk) = gen_update((yyvsp[-2].blk), (yyvsp[0].blk), '/'); } #line 2757 "src/parser.c" break; - case 30: /* Expr: Expr "/=" Expr */ -#line 399 "src/parser.y" - { - (yyval.blk) = gen_update((yyvsp[-2].blk), (yyvsp[0].blk), '/'); + case 31: /* Expr: Expr "%=" Expr */ +#line 394 "src/parser.y" + { + (yyval.blk) = gen_update((yyvsp[-2].blk), (yyvsp[0].blk), '%'); } #line 2765 "src/parser.c" break; - case 31: /* Expr: Expr "%=" Expr */ -#line 402 "src/parser.y" - { - (yyval.blk) = gen_update((yyvsp[-2].blk), (yyvsp[0].blk), '%'); + case 32: /* Expr: Expr "==" Expr */ +#line 397 "src/parser.y" + { + (yyval.blk) = gen_binop((yyvsp[-2].blk), (yyvsp[0].blk), EQ); } #line 2773 "src/parser.c" break; - case 32: /* Expr: Expr "==" Expr */ -#line 405 "src/parser.y" + case 33: /* Expr: Expr "!=" Expr */ +#line 400 "src/parser.y" { - (yyval.blk) = gen_binop((yyvsp[-2].blk), (yyvsp[0].blk), EQ); + (yyval.blk) = gen_binop((yyvsp[-2].blk), (yyvsp[0].blk), NEQ); } #line 2781 "src/parser.c" break; - case 33: /* Expr: Expr "!=" Expr */ -#line 408 "src/parser.y" - { - (yyval.blk) = gen_binop((yyvsp[-2].blk), (yyvsp[0].blk), NEQ); + case 34: /* Expr: Expr '<' Expr */ +#line 403 "src/parser.y" + { + (yyval.blk) = gen_binop((yyvsp[-2].blk), (yyvsp[0].blk), '<'); } #line 2789 "src/parser.c" break; - case 34: /* Expr: Expr '<' Expr */ -#line 411 "src/parser.y" + case 35: /* Expr: Expr '>' Expr */ +#line 406 "src/parser.y" { - (yyval.blk) = gen_binop((yyvsp[-2].blk), (yyvsp[0].blk), '<'); + (yyval.blk) = gen_binop((yyvsp[-2].blk), (yyvsp[0].blk), '>'); } #line 2797 "src/parser.c" break; - case 35: /* Expr: Expr '>' Expr */ -#line 414 "src/parser.y" - { - (yyval.blk) = gen_binop((yyvsp[-2].blk), (yyvsp[0].blk), '>'); + case 36: /* Expr: Expr "<=" Expr */ +#line 409 "src/parser.y" + { + (yyval.blk) = gen_binop((yyvsp[-2].blk), (yyvsp[0].blk), LESSEQ); } #line 2805 "src/parser.c" break; - case 36: /* Expr: Expr "<=" Expr */ -#line 417 "src/parser.y" + case 37: /* Expr: Expr ">=" Expr */ +#line 412 "src/parser.y" { - (yyval.blk) = gen_binop((yyvsp[-2].blk), (yyvsp[0].blk), LESSEQ); + (yyval.blk) = gen_binop((yyvsp[-2].blk), (yyvsp[0].blk), GREATEREQ); } #line 2813 "src/parser.c" break; - case 37: /* Expr: Expr ">=" Expr */ -#line 420 "src/parser.y" - { - (yyval.blk) = gen_binop((yyvsp[-2].blk), (yyvsp[0].blk), GREATEREQ); + case 38: /* Expr: Term */ +#line 415 "src/parser.y" + { + (yyval.blk) = (yyvsp[0].blk); } #line 2821 "src/parser.c" break; - case 38: /* Expr: Term */ -#line 423 "src/parser.y" - { - (yyval.blk) = (yyvsp[0].blk); + case 39: /* Import: ImportWhat ';' */ +#line 421 "src/parser.y" + { + (yyval.blk) = (yyvsp[-1].blk); } #line 2829 "src/parser.c" break; - case 39: /* Import: ImportWhat ';' */ -#line 429 "src/parser.y" - { - (yyval.blk) = (yyvsp[-1].blk); -} -#line 2837 "src/parser.c" - break; - case 40: /* Import: ImportWhat Query ';' */ -#line 432 "src/parser.y" +#line 424 "src/parser.y" { if (!block_is_const((yyvsp[-1].blk))) { - FAIL((yyloc), "Module metadata must be constant"); + FAIL((yylsp[-1]), "Module metadata must be constant"); (yyval.blk) = gen_noop(); block_free((yyvsp[-2].blk)); block_free((yyvsp[-1].blk)); } else if (block_const_kind((yyvsp[-1].blk)) != JV_KIND_OBJECT) { - FAIL((yyloc), "Module metadata must be an object"); + FAIL((yylsp[-1]), "Module metadata must be an object"); (yyval.blk) = gen_noop(); block_free((yyvsp[-2].blk)); block_free((yyvsp[-1].blk)); @@ -2853,11 +2845,11 @@ yyreduce: (yyval.blk) = gen_import_meta((yyvsp[-2].blk), (yyvsp[-1].blk)); } } -#line 2857 "src/parser.c" +#line 2849 "src/parser.c" break; case 41: /* ImportWhat: "import" ImportFrom "as" BINDING */ -#line 449 "src/parser.y" +#line 441 "src/parser.y" { jv v = block_const((yyvsp[-2].blk)); // XXX Make gen_import take only blocks and the int is_data so we @@ -2867,11 +2859,11 @@ yyreduce: jv_free((yyvsp[0].literal)); jv_free(v); } -#line 2871 "src/parser.c" +#line 2863 "src/parser.c" break; case 42: /* ImportWhat: "import" ImportFrom "as" IDENT */ -#line 458 "src/parser.y" +#line 450 "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); @@ -2879,177 +2871,177 @@ yyreduce: jv_free((yyvsp[0].literal)); jv_free(v); } -#line 2883 "src/parser.c" +#line 2875 "src/parser.c" break; case 43: /* ImportWhat: "include" ImportFrom */ -#line 465 "src/parser.y" +#line 457 "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 2894 "src/parser.c" +#line 2886 "src/parser.c" break; case 44: /* ImportFrom: String */ -#line 473 "src/parser.y" +#line 465 "src/parser.y" { if (!block_is_const((yyvsp[0].blk))) { - FAIL((yyloc), "Import path must be constant"); + FAIL((yylsp[0]), "Import path must be constant"); (yyval.blk) = gen_const(jv_string("")); block_free((yyvsp[0].blk)); } else { (yyval.blk) = (yyvsp[0].blk); } } -#line 2908 "src/parser.c" +#line 2900 "src/parser.c" break; case 45: /* FuncDef: "def" IDENT ':' Query ';' */ -#line 484 "src/parser.y" +#line 476 "src/parser.y" { (yyval.blk) = gen_function(jv_string_value((yyvsp[-3].literal)), gen_noop(), (yyvsp[-1].blk)); jv_free((yyvsp[-3].literal)); } -#line 2917 "src/parser.c" +#line 2909 "src/parser.c" break; case 46: /* FuncDef: "def" IDENT '(' Params ')' ':' Query ';' */ -#line 489 "src/parser.y" +#line 481 "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 2926 "src/parser.c" +#line 2918 "src/parser.c" break; case 47: /* Params: Param */ -#line 495 "src/parser.y" +#line 487 "src/parser.y" { (yyval.blk) = (yyvsp[0].blk); } +#line 2926 "src/parser.c" + break; + + case 48: /* Params: Params ';' Param */ +#line 490 "src/parser.y" + { + (yyval.blk) = BLOCK((yyvsp[-2].blk), (yyvsp[0].blk)); +} #line 2934 "src/parser.c" break; - case 48: /* Params: Params ';' Param */ -#line 498 "src/parser.y" - { - (yyval.blk) = BLOCK((yyvsp[-2].blk), (yyvsp[0].blk)); -} -#line 2942 "src/parser.c" - break; - case 49: /* Param: BINDING */ -#line 503 "src/parser.y" +#line 495 "src/parser.y" { (yyval.blk) = gen_param_regular(jv_string_value((yyvsp[0].literal))); jv_free((yyvsp[0].literal)); } -#line 2951 "src/parser.c" +#line 2943 "src/parser.c" break; case 50: /* Param: IDENT */ -#line 507 "src/parser.y" +#line 499 "src/parser.y" { (yyval.blk) = gen_param(jv_string_value((yyvsp[0].literal))); jv_free((yyvsp[0].literal)); } -#line 2960 "src/parser.c" +#line 2952 "src/parser.c" break; case 51: /* StringStart: FORMAT QQSTRING_START */ -#line 514 "src/parser.y" +#line 506 "src/parser.y" { (yyval.literal) = (yyvsp[-1].literal); } +#line 2960 "src/parser.c" + break; + + case 52: /* StringStart: QQSTRING_START */ +#line 509 "src/parser.y" + { + (yyval.literal) = jv_string("text"); +} #line 2968 "src/parser.c" break; - case 52: /* StringStart: QQSTRING_START */ -#line 517 "src/parser.y" - { - (yyval.literal) = jv_string("text"); -} -#line 2976 "src/parser.c" - break; - case 53: /* String: StringStart QQString QQSTRING_END */ -#line 523 "src/parser.y" +#line 515 "src/parser.y" { (yyval.blk) = (yyvsp[-1].blk); jv_free((yyvsp[-2].literal)); } -#line 2985 "src/parser.c" +#line 2977 "src/parser.c" break; case 54: /* QQString: %empty */ -#line 530 "src/parser.y" +#line 522 "src/parser.y" { (yyval.blk) = gen_const(jv_string("")); } +#line 2985 "src/parser.c" + break; + + case 55: /* QQString: QQString QQSTRING_TEXT */ +#line 525 "src/parser.y" + { + (yyval.blk) = gen_binop((yyvsp[-1].blk), gen_const((yyvsp[0].literal)), '+'); +} #line 2993 "src/parser.c" break; - case 55: /* QQString: QQString QQSTRING_TEXT */ -#line 533 "src/parser.y" - { - (yyval.blk) = gen_binop((yyvsp[-1].blk), gen_const((yyvsp[0].literal)), '+'); + case 56: /* QQString: QQString QQSTRING_INTERP_START Query QQSTRING_INTERP_END */ +#line 528 "src/parser.y" + { + (yyval.blk) = gen_binop((yyvsp[-3].blk), gen_format((yyvsp[-1].blk), jv_copy((yyvsp[-4].literal))), '+'); } #line 3001 "src/parser.c" break; - case 56: /* QQString: QQString QQSTRING_INTERP_START Query QQSTRING_INTERP_END */ -#line 536 "src/parser.y" - { - (yyval.blk) = gen_binop((yyvsp[-3].blk), gen_format((yyvsp[-1].blk), jv_copy((yyvsp[-4].literal))), '+'); + case 57: /* ElseBody: "elif" Query "then" Query ElseBody */ +#line 534 "src/parser.y" + { + (yyval.blk) = gen_cond((yyvsp[-3].blk), (yyvsp[-1].blk), (yyvsp[0].blk)); } #line 3009 "src/parser.c" break; - case 57: /* ElseBody: "elif" Query "then" Query ElseBody */ -#line 542 "src/parser.y" - { - (yyval.blk) = gen_cond((yyvsp[-3].blk), (yyvsp[-1].blk), (yyvsp[0].blk)); + case 58: /* ElseBody: "else" Query "end" */ +#line 537 "src/parser.y" + { + (yyval.blk) = (yyvsp[-1].blk); } #line 3017 "src/parser.c" break; - case 58: /* ElseBody: "else" Query "end" */ -#line 545 "src/parser.y" - { - (yyval.blk) = (yyvsp[-1].blk); + case 59: /* ElseBody: "end" */ +#line 540 "src/parser.y" + { + (yyval.blk) = gen_noop(); } #line 3025 "src/parser.c" break; - case 59: /* ElseBody: "end" */ -#line 548 "src/parser.y" - { + case 60: /* Term: '.' */ +#line 546 "src/parser.y" + { (yyval.blk) = gen_noop(); } #line 3033 "src/parser.c" break; - case 60: /* Term: '.' */ -#line 554 "src/parser.y" + case 61: /* Term: ".." */ +#line 549 "src/parser.y" { - (yyval.blk) = gen_noop(); + (yyval.blk) = gen_call("recurse", gen_noop()); } #line 3041 "src/parser.c" break; - case 61: /* Term: ".." */ -#line 557 "src/parser.y" - { - (yyval.blk) = gen_call("recurse", gen_noop()); -} -#line 3049 "src/parser.c" - break; - case 62: /* Term: "break" BINDING */ -#line 560 "src/parser.y" +#line 552 "src/parser.y" { jv v = jv_string_fmt("*label-%s", jv_string_value((yyvsp[0].literal))); // impossible symbol (yyval.blk) = gen_location((yyloc), locations, @@ -3058,279 +3050,279 @@ yyreduce: jv_free(v); jv_free((yyvsp[0].literal)); } -#line 3062 "src/parser.c" +#line 3054 "src/parser.c" break; case 63: /* Term: "break" error */ -#line 568 "src/parser.y" +#line 560 "src/parser.y" { FAIL((yyloc), "break requires a label to break to"); (yyval.blk) = gen_noop(); } -#line 3071 "src/parser.c" +#line 3063 "src/parser.c" break; case 64: /* Term: Term FIELD '?' */ -#line 572 "src/parser.y" +#line 564 "src/parser.y" { (yyval.blk) = gen_index_opt((yyvsp[-2].blk), gen_const((yyvsp[-1].literal))); } +#line 3071 "src/parser.c" + break; + + case 65: /* Term: FIELD '?' */ +#line 567 "src/parser.y" + { + (yyval.blk) = gen_index_opt(gen_noop(), gen_const((yyvsp[-1].literal))); +} #line 3079 "src/parser.c" break; - case 65: /* Term: FIELD '?' */ -#line 575 "src/parser.y" - { - (yyval.blk) = gen_index_opt(gen_noop(), gen_const((yyvsp[-1].literal))); + case 66: /* Term: Term '.' String '?' */ +#line 570 "src/parser.y" + { + (yyval.blk) = gen_index_opt((yyvsp[-3].blk), (yyvsp[-1].blk)); } #line 3087 "src/parser.c" break; - case 66: /* Term: Term '.' String '?' */ -#line 578 "src/parser.y" - { - (yyval.blk) = gen_index_opt((yyvsp[-3].blk), (yyvsp[-1].blk)); + case 67: /* Term: '.' String '?' */ +#line 573 "src/parser.y" + { + (yyval.blk) = gen_index_opt(gen_noop(), (yyvsp[-1].blk)); } #line 3095 "src/parser.c" break; - case 67: /* Term: '.' String '?' */ -#line 581 "src/parser.y" - { - (yyval.blk) = gen_index_opt(gen_noop(), (yyvsp[-1].blk)); + case 68: /* Term: Term FIELD */ +#line 576 "src/parser.y" + { + (yyval.blk) = gen_index((yyvsp[-1].blk), gen_const((yyvsp[0].literal))); } #line 3103 "src/parser.c" break; - case 68: /* Term: Term FIELD */ -#line 584 "src/parser.y" - { - (yyval.blk) = gen_index((yyvsp[-1].blk), gen_const((yyvsp[0].literal))); + case 69: /* Term: FIELD */ +#line 579 "src/parser.y" + { + (yyval.blk) = gen_index(gen_noop(), gen_const((yyvsp[0].literal))); } #line 3111 "src/parser.c" break; - case 69: /* Term: FIELD */ -#line 587 "src/parser.y" - { - (yyval.blk) = gen_index(gen_noop(), gen_const((yyvsp[0].literal))); + case 70: /* Term: Term '.' String */ +#line 582 "src/parser.y" + { + (yyval.blk) = gen_index((yyvsp[-2].blk), (yyvsp[0].blk)); } #line 3119 "src/parser.c" break; - case 70: /* Term: Term '.' String */ -#line 590 "src/parser.y" - { - (yyval.blk) = gen_index((yyvsp[-2].blk), (yyvsp[0].blk)); + case 71: /* Term: '.' String */ +#line 585 "src/parser.y" + { + (yyval.blk) = gen_index(gen_noop(), (yyvsp[0].blk)); } #line 3127 "src/parser.c" break; - case 71: /* Term: '.' String */ -#line 593 "src/parser.y" - { - (yyval.blk) = gen_index(gen_noop(), (yyvsp[0].blk)); -} -#line 3135 "src/parser.c" - break; - case 72: /* Term: '.' error */ -#line 596 "src/parser.y" +#line 588 "src/parser.y" { FAIL((yyloc), "try .[\"field\"] instead of .field for unusually named fields"); (yyval.blk) = gen_noop(); } -#line 3144 "src/parser.c" +#line 3136 "src/parser.c" break; case 73: /* Term: '.' IDENT error */ -#line 600 "src/parser.y" +#line 592 "src/parser.y" { jv_free((yyvsp[-1].literal)); FAIL((yyloc), "try .[\"field\"] instead of .field for unusually named fields"); (yyval.blk) = gen_noop(); } -#line 3154 "src/parser.c" +#line 3146 "src/parser.c" break; case 74: /* Term: Term '[' Query ']' '?' */ -#line 606 "src/parser.y" +#line 598 "src/parser.y" { (yyval.blk) = gen_index_opt((yyvsp[-4].blk), (yyvsp[-2].blk)); } +#line 3154 "src/parser.c" + break; + + case 75: /* Term: Term '[' Query ']' */ +#line 601 "src/parser.y" + { + (yyval.blk) = gen_index((yyvsp[-3].blk), (yyvsp[-1].blk)); +} #line 3162 "src/parser.c" break; - case 75: /* Term: Term '[' Query ']' */ -#line 609 "src/parser.y" - { - (yyval.blk) = gen_index((yyvsp[-3].blk), (yyvsp[-1].blk)); + case 76: /* Term: Term '.' '[' Query ']' '?' */ +#line 604 "src/parser.y" + { + (yyval.blk) = gen_index_opt((yyvsp[-5].blk), (yyvsp[-2].blk)); } #line 3170 "src/parser.c" break; - case 76: /* Term: Term '.' '[' Query ']' '?' */ -#line 612 "src/parser.y" - { - (yyval.blk) = gen_index_opt((yyvsp[-5].blk), (yyvsp[-2].blk)); + case 77: /* Term: Term '.' '[' Query ']' */ +#line 607 "src/parser.y" + { + (yyval.blk) = gen_index((yyvsp[-4].blk), (yyvsp[-1].blk)); } #line 3178 "src/parser.c" break; - case 77: /* Term: Term '.' '[' Query ']' */ -#line 615 "src/parser.y" - { - (yyval.blk) = gen_index((yyvsp[-4].blk), (yyvsp[-1].blk)); + case 78: /* Term: Term '[' ']' '?' */ +#line 610 "src/parser.y" + { + (yyval.blk) = block_join((yyvsp[-3].blk), gen_op_simple(EACH_OPT)); } #line 3186 "src/parser.c" break; - case 78: /* Term: Term '[' ']' '?' */ -#line 618 "src/parser.y" - { - (yyval.blk) = block_join((yyvsp[-3].blk), gen_op_simple(EACH_OPT)); + case 79: /* Term: Term '[' ']' */ +#line 613 "src/parser.y" + { + (yyval.blk) = block_join((yyvsp[-2].blk), gen_op_simple(EACH)); } #line 3194 "src/parser.c" break; - case 79: /* Term: Term '[' ']' */ -#line 621 "src/parser.y" - { - (yyval.blk) = block_join((yyvsp[-2].blk), gen_op_simple(EACH)); + case 80: /* Term: Term '.' '[' ']' '?' */ +#line 616 "src/parser.y" + { + (yyval.blk) = block_join((yyvsp[-4].blk), gen_op_simple(EACH_OPT)); } #line 3202 "src/parser.c" break; - case 80: /* Term: Term '.' '[' ']' '?' */ -#line 624 "src/parser.y" - { - (yyval.blk) = block_join((yyvsp[-4].blk), gen_op_simple(EACH_OPT)); + case 81: /* Term: Term '.' '[' ']' */ +#line 619 "src/parser.y" + { + (yyval.blk) = block_join((yyvsp[-3].blk), gen_op_simple(EACH)); } #line 3210 "src/parser.c" break; - case 81: /* Term: Term '.' '[' ']' */ -#line 627 "src/parser.y" - { - (yyval.blk) = block_join((yyvsp[-3].blk), gen_op_simple(EACH)); + case 82: /* Term: Term '[' Query ':' Query ']' '?' */ +#line 622 "src/parser.y" + { + (yyval.blk) = gen_slice_index((yyvsp[-6].blk), (yyvsp[-4].blk), (yyvsp[-2].blk), INDEX_OPT); } #line 3218 "src/parser.c" break; - case 82: /* Term: Term '[' Query ':' Query ']' '?' */ -#line 630 "src/parser.y" - { - (yyval.blk) = gen_slice_index((yyvsp[-6].blk), (yyvsp[-4].blk), (yyvsp[-2].blk), INDEX_OPT); + case 83: /* Term: Term '[' Query ':' ']' '?' */ +#line 625 "src/parser.y" + { + (yyval.blk) = gen_slice_index((yyvsp[-5].blk), (yyvsp[-3].blk), gen_const(jv_null()), INDEX_OPT); } #line 3226 "src/parser.c" break; - case 83: /* Term: Term '[' Query ':' ']' '?' */ -#line 633 "src/parser.y" + case 84: /* Term: Term '[' ':' Query ']' '?' */ +#line 628 "src/parser.y" { - (yyval.blk) = gen_slice_index((yyvsp[-5].blk), (yyvsp[-3].blk), gen_const(jv_null()), INDEX_OPT); + (yyval.blk) = gen_slice_index((yyvsp[-5].blk), gen_const(jv_null()), (yyvsp[-2].blk), INDEX_OPT); } #line 3234 "src/parser.c" break; - case 84: /* Term: Term '[' ':' Query ']' '?' */ -#line 636 "src/parser.y" - { - (yyval.blk) = gen_slice_index((yyvsp[-5].blk), gen_const(jv_null()), (yyvsp[-2].blk), INDEX_OPT); + case 85: /* Term: Term '[' Query ':' Query ']' */ +#line 631 "src/parser.y" + { + (yyval.blk) = gen_slice_index((yyvsp[-5].blk), (yyvsp[-3].blk), (yyvsp[-1].blk), INDEX); } #line 3242 "src/parser.c" break; - case 85: /* Term: Term '[' Query ':' Query ']' */ -#line 639 "src/parser.y" - { - (yyval.blk) = gen_slice_index((yyvsp[-5].blk), (yyvsp[-3].blk), (yyvsp[-1].blk), INDEX); + case 86: /* Term: Term '[' Query ':' ']' */ +#line 634 "src/parser.y" + { + (yyval.blk) = gen_slice_index((yyvsp[-4].blk), (yyvsp[-2].blk), gen_const(jv_null()), INDEX); } #line 3250 "src/parser.c" break; - case 86: /* Term: Term '[' Query ':' ']' */ -#line 642 "src/parser.y" + case 87: /* Term: Term '[' ':' Query ']' */ +#line 637 "src/parser.y" { - (yyval.blk) = gen_slice_index((yyvsp[-4].blk), (yyvsp[-2].blk), gen_const(jv_null()), INDEX); + (yyval.blk) = gen_slice_index((yyvsp[-4].blk), gen_const(jv_null()), (yyvsp[-1].blk), INDEX); } #line 3258 "src/parser.c" break; - case 87: /* Term: Term '[' ':' Query ']' */ -#line 645 "src/parser.y" - { - (yyval.blk) = gen_slice_index((yyvsp[-4].blk), gen_const(jv_null()), (yyvsp[-1].blk), INDEX); + case 88: /* Term: Term '?' */ +#line 640 "src/parser.y" + { + (yyval.blk) = gen_try((yyvsp[-1].blk), gen_op_simple(BACKTRACK)); } #line 3266 "src/parser.c" break; - case 88: /* Term: Term '?' */ -#line 648 "src/parser.y" - { - (yyval.blk) = gen_try((yyvsp[-1].blk), gen_op_simple(BACKTRACK)); + case 89: /* Term: LITERAL */ +#line 643 "src/parser.y" + { + (yyval.blk) = gen_const((yyvsp[0].literal)); } #line 3274 "src/parser.c" break; - case 89: /* Term: LITERAL */ -#line 651 "src/parser.y" - { - (yyval.blk) = gen_const((yyvsp[0].literal)); + case 90: /* Term: String */ +#line 646 "src/parser.y" + { + (yyval.blk) = (yyvsp[0].blk); } #line 3282 "src/parser.c" break; - case 90: /* Term: String */ -#line 654 "src/parser.y" + case 91: /* Term: FORMAT */ +#line 649 "src/parser.y" { - (yyval.blk) = (yyvsp[0].blk); + (yyval.blk) = gen_format(gen_noop(), (yyvsp[0].literal)); } #line 3290 "src/parser.c" break; - case 91: /* Term: FORMAT */ -#line 657 "src/parser.y" - { - (yyval.blk) = gen_format(gen_noop(), (yyvsp[0].literal)); + case 92: /* Term: '-' Term */ +#line 652 "src/parser.y" + { + (yyval.blk) = BLOCK((yyvsp[0].blk), gen_call("_negate", gen_noop())); } #line 3298 "src/parser.c" break; - case 92: /* Term: '-' Term */ -#line 660 "src/parser.y" - { - (yyval.blk) = BLOCK((yyvsp[0].blk), gen_call("_negate", gen_noop())); + case 93: /* Term: '(' Query ')' */ +#line 655 "src/parser.y" + { + (yyval.blk) = (yyvsp[-1].blk); } #line 3306 "src/parser.c" break; - case 93: /* Term: '(' Query ')' */ -#line 663 "src/parser.y" + case 94: /* Term: '[' Query ']' */ +#line 658 "src/parser.y" { - (yyval.blk) = (yyvsp[-1].blk); + (yyval.blk) = gen_collect((yyvsp[-1].blk)); } #line 3314 "src/parser.c" break; - case 94: /* Term: '[' Query ']' */ -#line 666 "src/parser.y" - { - (yyval.blk) = gen_collect((yyvsp[-1].blk)); + case 95: /* Term: '[' ']' */ +#line 661 "src/parser.y" + { + (yyval.blk) = gen_const(jv_array()); } #line 3322 "src/parser.c" break; - case 95: /* Term: '[' ']' */ -#line 669 "src/parser.y" - { - (yyval.blk) = gen_const(jv_array()); -} -#line 3330 "src/parser.c" - break; - case 96: /* Term: '{' DictPairs '}' */ -#line 672 "src/parser.y" +#line 664 "src/parser.y" { block o = gen_const_object((yyvsp[-1].blk)); if (o.first != NULL) @@ -3338,103 +3330,103 @@ yyreduce: else (yyval.blk) = BLOCK(gen_subexp(gen_const(jv_object())), (yyvsp[-1].blk), gen_op_simple(POP)); } -#line 3342 "src/parser.c" +#line 3334 "src/parser.c" break; case 97: /* Term: "reduce" Expr "as" Patterns '(' Query ';' Query ')' */ -#line 679 "src/parser.y" +#line 671 "src/parser.y" { (yyval.blk) = gen_reduce((yyvsp[-7].blk), (yyvsp[-5].blk), (yyvsp[-3].blk), (yyvsp[-1].blk)); } +#line 3342 "src/parser.c" + break; + + case 98: /* Term: "foreach" Expr "as" Patterns '(' Query ';' Query ';' Query ')' */ +#line 674 "src/parser.y" + { + (yyval.blk) = gen_foreach((yyvsp[-9].blk), (yyvsp[-7].blk), (yyvsp[-5].blk), (yyvsp[-3].blk), (yyvsp[-1].blk)); +} #line 3350 "src/parser.c" break; - case 98: /* Term: "foreach" Expr "as" Patterns '(' Query ';' Query ';' Query ')' */ -#line 682 "src/parser.y" - { - (yyval.blk) = gen_foreach((yyvsp[-9].blk), (yyvsp[-7].blk), (yyvsp[-5].blk), (yyvsp[-3].blk), (yyvsp[-1].blk)); + case 99: /* Term: "foreach" Expr "as" Patterns '(' Query ';' Query ')' */ +#line 677 "src/parser.y" + { + (yyval.blk) = gen_foreach((yyvsp[-7].blk), (yyvsp[-5].blk), (yyvsp[-3].blk), (yyvsp[-1].blk), gen_noop()); } #line 3358 "src/parser.c" break; - case 99: /* Term: "foreach" Expr "as" Patterns '(' Query ';' Query ')' */ -#line 685 "src/parser.y" - { - (yyval.blk) = gen_foreach((yyvsp[-7].blk), (yyvsp[-5].blk), (yyvsp[-3].blk), (yyvsp[-1].blk), gen_noop()); + case 100: /* Term: "if" Query "then" Query ElseBody */ +#line 680 "src/parser.y" + { + (yyval.blk) = gen_cond((yyvsp[-3].blk), (yyvsp[-1].blk), (yyvsp[0].blk)); } #line 3366 "src/parser.c" break; - case 100: /* Term: "if" Query "then" Query ElseBody */ -#line 688 "src/parser.y" - { - (yyval.blk) = gen_cond((yyvsp[-3].blk), (yyvsp[-1].blk), (yyvsp[0].blk)); -} -#line 3374 "src/parser.c" - break; - case 101: /* Term: "if" Query "then" error */ -#line 691 "src/parser.y" +#line 683 "src/parser.y" { FAIL((yyloc), "Possibly unterminated 'if' statement"); (yyval.blk) = (yyvsp[-2].blk); } -#line 3383 "src/parser.c" +#line 3375 "src/parser.c" break; case 102: /* Term: "try" Expr "catch" Expr */ -#line 695 "src/parser.y" +#line 687 "src/parser.y" { (yyval.blk) = gen_try((yyvsp[-2].blk), (yyvsp[0].blk)); } -#line 3391 "src/parser.c" +#line 3383 "src/parser.c" break; case 103: /* Term: "try" Expr "catch" error */ -#line 698 "src/parser.y" +#line 690 "src/parser.y" { FAIL((yyloc), "Possibly unterminated 'try' statement"); (yyval.blk) = (yyvsp[-2].blk); } -#line 3400 "src/parser.c" +#line 3392 "src/parser.c" break; case 104: /* Term: "try" Expr */ -#line 702 "src/parser.y" +#line 694 "src/parser.y" { (yyval.blk) = gen_try((yyvsp[0].blk), gen_op_simple(BACKTRACK)); } -#line 3408 "src/parser.c" +#line 3400 "src/parser.c" break; case 105: /* Term: '$' '$' '$' BINDING */ -#line 720 "src/parser.y" +#line 712 "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 3417 "src/parser.c" +#line 3409 "src/parser.c" break; case 106: /* Term: BINDING */ -#line 724 "src/parser.y" +#line 716 "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 3426 "src/parser.c" +#line 3418 "src/parser.c" break; case 107: /* Term: "$__loc__" */ -#line 728 "src/parser.y" +#line 720 "src/parser.y" { (yyval.blk) = gen_loc_object(&(yyloc), locations); } -#line 3434 "src/parser.c" +#line 3426 "src/parser.c" break; case 108: /* Term: IDENT */ -#line 731 "src/parser.y" +#line 723 "src/parser.y" { const char *s = jv_string_value((yyvsp[0].literal)); if (strcmp(s, "false") == 0) @@ -3447,505 +3439,505 @@ yyreduce: (yyval.blk) = gen_location((yyloc), locations, gen_call(s, gen_noop())); jv_free((yyvsp[0].literal)); } -#line 3451 "src/parser.c" +#line 3443 "src/parser.c" break; case 109: /* Term: IDENT '(' Args ')' */ -#line 743 "src/parser.y" +#line 735 "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 3461 "src/parser.c" +#line 3453 "src/parser.c" break; case 110: /* Term: '(' error ')' */ -#line 748 "src/parser.y" +#line 740 "src/parser.y" { (yyval.blk) = gen_noop(); } -#line 3467 "src/parser.c" +#line 3459 "src/parser.c" break; case 111: /* Term: '[' error ']' */ -#line 749 "src/parser.y" +#line 741 "src/parser.y" { (yyval.blk) = gen_noop(); } -#line 3473 "src/parser.c" +#line 3465 "src/parser.c" break; case 112: /* Term: Term '[' error ']' */ -#line 750 "src/parser.y" +#line 742 "src/parser.y" { (yyval.blk) = (yyvsp[-3].blk); } -#line 3479 "src/parser.c" +#line 3471 "src/parser.c" break; case 113: /* Term: '{' error '}' */ -#line 751 "src/parser.y" +#line 743 "src/parser.y" { (yyval.blk) = gen_noop(); } -#line 3485 "src/parser.c" +#line 3477 "src/parser.c" break; case 114: /* Args: Arg */ -#line 754 "src/parser.y" +#line 746 "src/parser.y" { (yyval.blk) = (yyvsp[0].blk); } +#line 3485 "src/parser.c" + break; + + case 115: /* Args: Args ';' Arg */ +#line 749 "src/parser.y" + { + (yyval.blk) = BLOCK((yyvsp[-2].blk), (yyvsp[0].blk)); +} #line 3493 "src/parser.c" break; - case 115: /* Args: Args ';' Arg */ -#line 757 "src/parser.y" - { - (yyval.blk) = BLOCK((yyvsp[-2].blk), (yyvsp[0].blk)); + case 116: /* Arg: Query */ +#line 754 "src/parser.y" + { + (yyval.blk) = gen_lambda((yyvsp[0].blk)); } #line 3501 "src/parser.c" break; - case 116: /* Arg: Query */ -#line 762 "src/parser.y" - { - (yyval.blk) = gen_lambda((yyvsp[0].blk)); + case 117: /* RepPatterns: RepPatterns "?//" Pattern */ +#line 759 "src/parser.y" + { + (yyval.blk) = BLOCK((yyvsp[-2].blk), gen_destructure_alt((yyvsp[0].blk))); } #line 3509 "src/parser.c" break; - case 117: /* RepPatterns: RepPatterns "?//" Pattern */ -#line 767 "src/parser.y" - { - (yyval.blk) = BLOCK((yyvsp[-2].blk), gen_destructure_alt((yyvsp[0].blk))); + case 118: /* RepPatterns: Pattern */ +#line 762 "src/parser.y" + { + (yyval.blk) = gen_destructure_alt((yyvsp[0].blk)); } #line 3517 "src/parser.c" break; - case 118: /* RepPatterns: Pattern */ -#line 770 "src/parser.y" - { - (yyval.blk) = gen_destructure_alt((yyvsp[0].blk)); + case 119: /* Patterns: RepPatterns "?//" Pattern */ +#line 767 "src/parser.y" + { + (yyval.blk) = BLOCK((yyvsp[-2].blk), (yyvsp[0].blk)); } #line 3525 "src/parser.c" break; - case 119: /* Patterns: RepPatterns "?//" Pattern */ -#line 775 "src/parser.y" - { - (yyval.blk) = BLOCK((yyvsp[-2].blk), (yyvsp[0].blk)); + case 120: /* Patterns: Pattern */ +#line 770 "src/parser.y" + { + (yyval.blk) = (yyvsp[0].blk); } #line 3533 "src/parser.c" break; - case 120: /* Patterns: Pattern */ -#line 778 "src/parser.y" - { - (yyval.blk) = (yyvsp[0].blk); -} -#line 3541 "src/parser.c" - break; - case 121: /* Pattern: BINDING */ -#line 783 "src/parser.y" +#line 775 "src/parser.y" { (yyval.blk) = gen_op_unbound(STOREV, jv_string_value((yyvsp[0].literal))); jv_free((yyvsp[0].literal)); } -#line 3550 "src/parser.c" +#line 3542 "src/parser.c" break; case 122: /* Pattern: '[' ArrayPats ']' */ -#line 787 "src/parser.y" +#line 779 "src/parser.y" { (yyval.blk) = BLOCK((yyvsp[-1].blk), gen_op_simple(POP)); } +#line 3550 "src/parser.c" + break; + + case 123: /* Pattern: '{' ObjPats '}' */ +#line 782 "src/parser.y" + { + (yyval.blk) = BLOCK((yyvsp[-1].blk), gen_op_simple(POP)); +} #line 3558 "src/parser.c" break; - case 123: /* Pattern: '{' ObjPats '}' */ -#line 790 "src/parser.y" - { - (yyval.blk) = BLOCK((yyvsp[-1].blk), gen_op_simple(POP)); + case 124: /* ArrayPats: Pattern */ +#line 787 "src/parser.y" + { + (yyval.blk) = gen_array_matcher(gen_noop(), (yyvsp[0].blk)); } #line 3566 "src/parser.c" break; - case 124: /* ArrayPats: Pattern */ -#line 795 "src/parser.y" - { - (yyval.blk) = gen_array_matcher(gen_noop(), (yyvsp[0].blk)); + case 125: /* ArrayPats: ArrayPats ',' Pattern */ +#line 790 "src/parser.y" + { + (yyval.blk) = gen_array_matcher((yyvsp[-2].blk), (yyvsp[0].blk)); } #line 3574 "src/parser.c" break; - case 125: /* ArrayPats: ArrayPats ',' Pattern */ -#line 798 "src/parser.y" - { - (yyval.blk) = gen_array_matcher((yyvsp[-2].blk), (yyvsp[0].blk)); + case 126: /* ObjPats: ObjPat */ +#line 795 "src/parser.y" + { + (yyval.blk) = (yyvsp[0].blk); } #line 3582 "src/parser.c" break; - case 126: /* ObjPats: ObjPat */ -#line 803 "src/parser.y" - { - (yyval.blk) = (yyvsp[0].blk); + case 127: /* ObjPats: ObjPats ',' ObjPat */ +#line 798 "src/parser.y" + { + (yyval.blk) = BLOCK((yyvsp[-2].blk), (yyvsp[0].blk)); } #line 3590 "src/parser.c" break; - case 127: /* ObjPats: ObjPats ',' ObjPat */ -#line 806 "src/parser.y" - { - (yyval.blk) = BLOCK((yyvsp[-2].blk), (yyvsp[0].blk)); + case 128: /* ObjPat: BINDING */ +#line 803 "src/parser.y" + { + (yyval.blk) = gen_object_matcher(gen_const((yyvsp[0].literal)), gen_op_unbound(STOREV, jv_string_value((yyvsp[0].literal)))); } #line 3598 "src/parser.c" break; - case 128: /* ObjPat: BINDING */ -#line 811 "src/parser.y" - { - (yyval.blk) = gen_object_matcher(gen_const((yyvsp[0].literal)), gen_op_unbound(STOREV, jv_string_value((yyvsp[0].literal)))); + case 129: /* ObjPat: BINDING ':' Pattern */ +#line 806 "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 3606 "src/parser.c" break; - case 129: /* ObjPat: BINDING ':' Pattern */ -#line 814 "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))); + case 130: /* ObjPat: IDENT ':' Pattern */ +#line 809 "src/parser.y" + { + (yyval.blk) = gen_object_matcher(gen_const((yyvsp[-2].literal)), (yyvsp[0].blk)); } #line 3614 "src/parser.c" break; - case 130: /* ObjPat: IDENT ':' Pattern */ -#line 817 "src/parser.y" - { + case 131: /* ObjPat: Keyword ':' Pattern */ +#line 812 "src/parser.y" + { (yyval.blk) = gen_object_matcher(gen_const((yyvsp[-2].literal)), (yyvsp[0].blk)); } #line 3622 "src/parser.c" break; - case 131: /* ObjPat: Keyword ':' Pattern */ -#line 820 "src/parser.y" - { - (yyval.blk) = gen_object_matcher(gen_const((yyvsp[-2].literal)), (yyvsp[0].blk)); + case 132: /* ObjPat: String ':' Pattern */ +#line 815 "src/parser.y" + { + (yyval.blk) = gen_object_matcher((yyvsp[-2].blk), (yyvsp[0].blk)); } #line 3630 "src/parser.c" break; - case 132: /* ObjPat: String ':' Pattern */ -#line 823 "src/parser.y" - { - (yyval.blk) = gen_object_matcher((yyvsp[-2].blk), (yyvsp[0].blk)); -} -#line 3638 "src/parser.c" - break; - case 133: /* ObjPat: '(' Query ')' ':' Pattern */ -#line 826 "src/parser.y" +#line 818 "src/parser.y" { jv msg = check_object_key((yyvsp[-3].blk)); if (jv_is_valid(msg)) { - FAIL((yyloc), jv_string_value(msg)); + FAIL((yylsp[-3]), jv_string_value(msg)); } jv_free(msg); (yyval.blk) = gen_object_matcher((yyvsp[-3].blk), (yyvsp[0].blk)); } -#line 3651 "src/parser.c" +#line 3643 "src/parser.c" break; case 134: /* ObjPat: error ':' Pattern */ -#line 834 "src/parser.y" +#line 826 "src/parser.y" { FAIL((yyloc), "May need parentheses around object key expression"); (yyval.blk) = (yyvsp[0].blk); } -#line 3660 "src/parser.c" +#line 3652 "src/parser.c" break; case 135: /* Keyword: "as" */ -#line 840 "src/parser.y" +#line 832 "src/parser.y" { (yyval.literal) = jv_string("as"); } +#line 3660 "src/parser.c" + break; + + case 136: /* Keyword: "def" */ +#line 835 "src/parser.y" + { + (yyval.literal) = jv_string("def"); +} #line 3668 "src/parser.c" break; - case 136: /* Keyword: "def" */ -#line 843 "src/parser.y" - { - (yyval.literal) = jv_string("def"); + case 137: /* Keyword: "module" */ +#line 838 "src/parser.y" + { + (yyval.literal) = jv_string("module"); } #line 3676 "src/parser.c" break; - case 137: /* Keyword: "module" */ -#line 846 "src/parser.y" + case 138: /* Keyword: "import" */ +#line 841 "src/parser.y" { - (yyval.literal) = jv_string("module"); + (yyval.literal) = jv_string("import"); } #line 3684 "src/parser.c" break; - case 138: /* Keyword: "import" */ -#line 849 "src/parser.y" - { - (yyval.literal) = jv_string("import"); + case 139: /* Keyword: "include" */ +#line 844 "src/parser.y" + { + (yyval.literal) = jv_string("include"); } #line 3692 "src/parser.c" break; - case 139: /* Keyword: "include" */ -#line 852 "src/parser.y" - { - (yyval.literal) = jv_string("include"); + case 140: /* Keyword: "if" */ +#line 847 "src/parser.y" + { + (yyval.literal) = jv_string("if"); } #line 3700 "src/parser.c" break; - case 140: /* Keyword: "if" */ -#line 855 "src/parser.y" - { - (yyval.literal) = jv_string("if"); + case 141: /* Keyword: "then" */ +#line 850 "src/parser.y" + { + (yyval.literal) = jv_string("then"); } #line 3708 "src/parser.c" break; - case 141: /* Keyword: "then" */ -#line 858 "src/parser.y" + case 142: /* Keyword: "else" */ +#line 853 "src/parser.y" { - (yyval.literal) = jv_string("then"); + (yyval.literal) = jv_string("else"); } #line 3716 "src/parser.c" break; - case 142: /* Keyword: "else" */ -#line 861 "src/parser.y" + case 143: /* Keyword: "elif" */ +#line 856 "src/parser.y" { - (yyval.literal) = jv_string("else"); + (yyval.literal) = jv_string("elif"); } #line 3724 "src/parser.c" break; - case 143: /* Keyword: "elif" */ -#line 864 "src/parser.y" - { - (yyval.literal) = jv_string("elif"); + case 144: /* Keyword: "reduce" */ +#line 859 "src/parser.y" + { + (yyval.literal) = jv_string("reduce"); } #line 3732 "src/parser.c" break; - case 144: /* Keyword: "reduce" */ -#line 867 "src/parser.y" - { - (yyval.literal) = jv_string("reduce"); + case 145: /* Keyword: "foreach" */ +#line 862 "src/parser.y" + { + (yyval.literal) = jv_string("foreach"); } #line 3740 "src/parser.c" break; - case 145: /* Keyword: "foreach" */ -#line 870 "src/parser.y" - { - (yyval.literal) = jv_string("foreach"); + case 146: /* Keyword: "end" */ +#line 865 "src/parser.y" + { + (yyval.literal) = jv_string("end"); } #line 3748 "src/parser.c" break; - case 146: /* Keyword: "end" */ -#line 873 "src/parser.y" + case 147: /* Keyword: "and" */ +#line 868 "src/parser.y" { - (yyval.literal) = jv_string("end"); + (yyval.literal) = jv_string("and"); } #line 3756 "src/parser.c" break; - case 147: /* Keyword: "and" */ -#line 876 "src/parser.y" - { - (yyval.literal) = jv_string("and"); + case 148: /* Keyword: "or" */ +#line 871 "src/parser.y" + { + (yyval.literal) = jv_string("or"); } #line 3764 "src/parser.c" break; - case 148: /* Keyword: "or" */ -#line 879 "src/parser.y" - { - (yyval.literal) = jv_string("or"); + case 149: /* Keyword: "try" */ +#line 874 "src/parser.y" + { + (yyval.literal) = jv_string("try"); } #line 3772 "src/parser.c" break; - case 149: /* Keyword: "try" */ -#line 882 "src/parser.y" - { - (yyval.literal) = jv_string("try"); + case 150: /* Keyword: "catch" */ +#line 877 "src/parser.y" + { + (yyval.literal) = jv_string("catch"); } #line 3780 "src/parser.c" break; - case 150: /* Keyword: "catch" */ -#line 885 "src/parser.y" + case 151: /* Keyword: "label" */ +#line 880 "src/parser.y" { - (yyval.literal) = jv_string("catch"); + (yyval.literal) = jv_string("label"); } #line 3788 "src/parser.c" break; - case 151: /* Keyword: "label" */ -#line 888 "src/parser.y" + case 152: /* Keyword: "break" */ +#line 883 "src/parser.y" { - (yyval.literal) = jv_string("label"); + (yyval.literal) = jv_string("break"); } #line 3796 "src/parser.c" break; - case 152: /* Keyword: "break" */ -#line 891 "src/parser.y" - { - (yyval.literal) = jv_string("break"); + case 153: /* DictPairs: %empty */ +#line 889 "src/parser.y" + { + (yyval.blk) = gen_noop(); } #line 3804 "src/parser.c" break; - case 153: /* DictPairs: %empty */ -#line 897 "src/parser.y" - { - (yyval.blk) = gen_noop(); + case 154: /* DictPairs: DictPair */ +#line 892 "src/parser.y" + { + (yyval.blk) = (yyvsp[0].blk); } #line 3812 "src/parser.c" break; - case 154: /* DictPairs: DictPair */ -#line 900 "src/parser.y" - { - (yyval.blk) = (yyvsp[0].blk); + case 155: /* DictPairs: DictPair ',' DictPairs */ +#line 895 "src/parser.y" + { + (yyval.blk) = block_join((yyvsp[-2].blk), (yyvsp[0].blk)); } #line 3820 "src/parser.c" break; - case 155: /* DictPairs: DictPair ',' DictPairs */ -#line 903 "src/parser.y" - { - (yyval.blk) = block_join((yyvsp[-2].blk), (yyvsp[0].blk)); + case 156: /* DictPair: IDENT ':' DictExpr */ +#line 900 "src/parser.y" + { + (yyval.blk) = gen_dictpair(gen_const((yyvsp[-2].literal)), (yyvsp[0].blk)); } #line 3828 "src/parser.c" break; - case 156: /* DictPair: IDENT ':' DictExpr */ -#line 908 "src/parser.y" - { + case 157: /* DictPair: Keyword ':' DictExpr */ +#line 903 "src/parser.y" + { (yyval.blk) = gen_dictpair(gen_const((yyvsp[-2].literal)), (yyvsp[0].blk)); } #line 3836 "src/parser.c" break; - case 157: /* DictPair: Keyword ':' DictExpr */ -#line 911 "src/parser.y" - { - (yyval.blk) = gen_dictpair(gen_const((yyvsp[-2].literal)), (yyvsp[0].blk)); + case 158: /* DictPair: String ':' DictExpr */ +#line 906 "src/parser.y" + { + (yyval.blk) = gen_dictpair((yyvsp[-2].blk), (yyvsp[0].blk)); } #line 3844 "src/parser.c" break; - case 158: /* DictPair: String ':' DictExpr */ -#line 914 "src/parser.y" - { - (yyval.blk) = gen_dictpair((yyvsp[-2].blk), (yyvsp[0].blk)); -} -#line 3852 "src/parser.c" - break; - case 159: /* DictPair: String */ -#line 917 "src/parser.y" +#line 909 "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 3861 "src/parser.c" +#line 3853 "src/parser.c" break; case 160: /* DictPair: BINDING ':' DictExpr */ -#line 921 "src/parser.y" +#line 913 "src/parser.y" { (yyval.blk) = gen_dictpair(gen_location((yyloc), locations, gen_op_unbound(LOADV, jv_string_value((yyvsp[-2].literal)))), (yyvsp[0].blk)); jv_free((yyvsp[-2].literal)); } -#line 3871 "src/parser.c" +#line 3863 "src/parser.c" break; case 161: /* DictPair: BINDING */ -#line 926 "src/parser.y" +#line 918 "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 3880 "src/parser.c" +#line 3872 "src/parser.c" break; case 162: /* DictPair: IDENT */ -#line 930 "src/parser.y" +#line 922 "src/parser.y" { (yyval.blk) = gen_dictpair(gen_const(jv_copy((yyvsp[0].literal))), gen_index(gen_noop(), gen_const((yyvsp[0].literal)))); } -#line 3889 "src/parser.c" +#line 3881 "src/parser.c" break; case 163: /* DictPair: "$__loc__" */ -#line 934 "src/parser.y" +#line 926 "src/parser.y" { (yyval.blk) = gen_dictpair(gen_const(jv_string("__loc__")), gen_loc_object(&(yyloc), locations)); } -#line 3898 "src/parser.c" +#line 3890 "src/parser.c" break; case 164: /* DictPair: Keyword */ -#line 938 "src/parser.y" +#line 930 "src/parser.y" { (yyval.blk) = gen_dictpair(gen_const(jv_copy((yyvsp[0].literal))), gen_index(gen_noop(), gen_const((yyvsp[0].literal)))); } -#line 3907 "src/parser.c" +#line 3899 "src/parser.c" break; case 165: /* DictPair: '(' Query ')' ':' DictExpr */ -#line 942 "src/parser.y" +#line 934 "src/parser.y" { jv msg = check_object_key((yyvsp[-3].blk)); if (jv_is_valid(msg)) { - FAIL((yyloc), jv_string_value(msg)); + FAIL((yylsp[-3]), jv_string_value(msg)); } jv_free(msg); (yyval.blk) = gen_dictpair((yyvsp[-3].blk), (yyvsp[0].blk)); } -#line 3920 "src/parser.c" +#line 3912 "src/parser.c" break; case 166: /* DictPair: error ':' DictExpr */ -#line 950 "src/parser.y" +#line 942 "src/parser.y" { - FAIL((yyloc), "May need parentheses around object key expression"); + FAIL((yylsp[-2]), "May need parentheses around object key expression"); (yyval.blk) = (yyvsp[0].blk); } +#line 3921 "src/parser.c" + break; + + case 167: /* DictExpr: DictExpr '|' DictExpr */ +#line 948 "src/parser.y" + { + (yyval.blk) = block_join((yyvsp[-2].blk), (yyvsp[0].blk)); +} #line 3929 "src/parser.c" break; - case 167: /* DictExpr: DictExpr '|' DictExpr */ -#line 956 "src/parser.y" - { - (yyval.blk) = block_join((yyvsp[-2].blk), (yyvsp[0].blk)); + case 168: /* DictExpr: Expr */ +#line 951 "src/parser.y" + { + (yyval.blk) = (yyvsp[0].blk); } #line 3937 "src/parser.c" break; - case 168: /* DictExpr: Expr */ -#line 959 "src/parser.y" - { - (yyval.blk) = (yyvsp[0].blk); -} -#line 3945 "src/parser.c" - break; - -#line 3949 "src/parser.c" +#line 3941 "src/parser.c" default: break; } @@ -4174,7 +4166,7 @@ yyreturnlab: return yyresult; } -#line 962 "src/parser.y" +#line 954 "src/parser.y" int jq_parse(struct locfile* locations, block* answer) { diff --git a/src/parser.y b/src/parser.y index 29730171..b1674315 100644 --- a/src/parser.y +++ b/src/parser.y @@ -139,15 +139,7 @@ struct lexer_param { void yyerror(YYLTYPE* loc, block* answer, int* errors, struct locfile* locations, struct lexer_param* lexer_param_ptr, const char *s){ (*errors)++; - if (strstr(s, "unexpected")) { -#ifdef WIN32 - locfile_locate(locations, *loc, "jq: error: %s (Windows cmd shell quoting issues?)", s); -#else - locfile_locate(locations, *loc, "jq: error: %s (Unix shell quoting issues?)", s); -#endif - } else { - locfile_locate(locations, *loc, "jq: error: %s", s); - } + locfile_locate(locations, *loc, "jq: error: %s", s); } int yylex(YYSTYPE* yylval, YYLTYPE* yylloc, block* answer, int* errors, @@ -300,11 +292,11 @@ Module: } | "module" Query ';' { if (!block_is_const($2)) { - FAIL(@$, "Module metadata must be constant"); + FAIL(@2, "Module metadata must be constant"); $$ = gen_noop(); block_free($2); } else if (block_const_kind($2) != JV_KIND_OBJECT) { - FAIL(@$, "Module metadata must be an object"); + FAIL(@2, "Module metadata must be an object"); $$ = gen_noop(); block_free($2); } else { @@ -431,12 +423,12 @@ ImportWhat ';' { } | ImportWhat Query ';' { if (!block_is_const($2)) { - FAIL(@$, "Module metadata must be constant"); + FAIL(@2, "Module metadata must be constant"); $$ = gen_noop(); block_free($1); block_free($2); } else if (block_const_kind($2) != JV_KIND_OBJECT) { - FAIL(@$, "Module metadata must be an object"); + FAIL(@2, "Module metadata must be an object"); $$ = gen_noop(); block_free($1); block_free($2); @@ -472,7 +464,7 @@ ImportWhat: ImportFrom: String { if (!block_is_const($1)) { - FAIL(@$, "Import path must be constant"); + FAIL(@1, "Import path must be constant"); $$ = gen_const(jv_string("")); block_free($1); } else { @@ -826,7 +818,7 @@ String ':' Pattern { '(' Query ')' ':' Pattern { jv msg = check_object_key($2); if (jv_is_valid(msg)) { - FAIL(@$, jv_string_value(msg)); + FAIL(@2, jv_string_value(msg)); } jv_free(msg); $$ = gen_object_matcher($2, $5); @@ -942,13 +934,13 @@ Keyword { '(' Query ')' ':' DictExpr { jv msg = check_object_key($2); if (jv_is_valid(msg)) { - FAIL(@$, jv_string_value(msg)); + FAIL(@2, jv_string_value(msg)); } jv_free(msg); $$ = gen_dictpair($2, $5); } | error ':' DictExpr { - FAIL(@$, "May need parentheses around object key expression"); + FAIL(@1, "May need parentheses around object key expression"); $$ = $3; } diff --git a/tests/jq.test b/tests/jq.test index faaf47e8..b4e6971e 100644 --- a/tests/jq.test +++ b/tests/jq.test @@ -59,6 +59,12 @@ null "Aa\r\n\t\b\f\u03bc" "Aa\u000d\u000a\u0009\u0008\u000c\u03bc" +%%FAIL +"u\vw" +jq: error: Invalid escape at line 1, column 4 (while parsing '"\v"') at , line 1, column 3: + "u\vw" + ^^ + "inter\("pol" + "ation")" null "interpolation" @@ -119,11 +125,21 @@ null %%FAIL {(0):1} -jq: error: Cannot use number (0) as object key at , line 1, column 2: +jq: error: Cannot use number (0) as object key at , line 1, column 3: + {(0):1} + ^ + +%%FAIL +{1+2:3} +jq: error: May need parentheses around object key expression at , line 1, column 2: + {1+2:3} + ^^^ %%FAIL {non_const:., (0):1} -jq: error: Cannot use number (0) as object key at , line 1, column 15: +jq: error: Cannot use number (0) as object key at , line 1, column 16: + {non_const:., (0):1} + ^ # # Field access, piping @@ -303,6 +319,8 @@ null %%FAIL . as $foo | break $foo jq: error: $*label-foo is not defined at , line 1, column 13: + . as $foo | break $foo + ^^^^^^^^^^ [.[]|[.,1]|until(.[0] < 1; [.[0] - 1, .[1] * .[0]])|.[1]] [1,2,3,4,5] @@ -518,13 +536,29 @@ null [0] [0] -%%FAIL IGNORE MSG +%%FAIL . as [] | null -jq: error: syntax error, unexpected ']', expecting '$' or '[' or '{' (Unix shell quoting issues?) at , line 1, column 7: +jq: error: syntax error, unexpected ']', expecting BINDING or '[' or '{' at , line 1, column 7: + . as [] | null + ^ -%%FAIL IGNORE MSG +%%FAIL . as {} | null -jq: error: syntax error, unexpected '}' (Unix shell quoting issues?) at , line 1, column 7: +jq: error: syntax error, unexpected '}' at , line 1, column 7: + . as {} | null + ^ + +%%FAIL +. as $foo | [$foo, $bar] +jq: error: $bar is not defined at , line 1, column 20: + . as $foo | [$foo, $bar] + ^^^^ + +%%FAIL +. as {(true):$foo} | $foo +jq: error: Cannot use boolean (true) as object key at , line 1, column 8: + . as {(true):$foo} | $foo + ^^^^ # [.,(.[] | {x:.},.),.,.[]] @@ -1840,27 +1874,39 @@ null %%FAIL module (.+1); 0 -jq: error: Module metadata must be constant at , line 1, column 1: +jq: error: Module metadata must be constant at , line 1, column 8: + module (.+1); 0 + ^^^^^ %%FAIL module []; 0 -jq: error: Module metadata must be an object at , line 1, column 1: +jq: error: Module metadata must be an object at , line 1, column 8: + module []; 0 + ^^ %%FAIL include "a" (.+1); 0 -jq: error: Module metadata must be constant at , line 1, column 1: +jq: error: Module metadata must be constant at , line 1, column 13: + include "a" (.+1); 0 + ^^^^^ %%FAIL include "a" []; 0 -jq: error: Module metadata must be an object at , line 1, column 1: +jq: error: Module metadata must be an object at , line 1, column 13: + include "a" []; 0 + ^^ %%FAIL include "\ "; 0 jq: error: Invalid escape at line 1, column 4 (while parsing '"\ "') at , line 1, column 10: + include "\ "; 0 + ^^ %%FAIL include "\(a)"; 0 jq: error: Import path must be constant at , line 1, column 9: + include "\(a)"; 0 + ^^^^^^ modulemeta "c" @@ -1876,11 +1922,15 @@ modulemeta | .defs | length %%FAIL IGNORE MSG import "syntaxerror" as e; . -jq: error: syntax error, unexpected ';', expecting $end (Unix shell quoting issues?) at /home/nico/ws/jq/tests/modules/syntaxerror/syntaxerror.jq, line 1, column 8: +jq: error: syntax error, unexpected ';', expecting end of file at tests/modules/syntaxerror/syntaxerror.jq, line 1, column 4: + wat; + ^ -%%FAIL IGNORE MSG +%%FAIL %::wat -jq: error: syntax error, unexpected '%', expecting $end (Unix shell quoting issues?) at , line 1, column 1: +jq: error: syntax error, unexpected '%', expecting end of file at , line 1, column 1: + %::wat + ^ import "test_bind_order" as check; check::check null @@ -1959,9 +2009,17 @@ true [range(-99/2;99/2;1)] as $orig | [$orig[]|pow(2;.)|log2] as $back | ($orig|keys)[]|. as $k | (($orig|.[$k])-($back|.[$k]))|if . < 0 then . * -1 else . end|select(.>.00005) null -%%FAIL IGNORE MSG +%%FAIL +{ +jq: error: syntax error, unexpected end of file at , line 1, column 1: + { + ^ + +%%FAIL } -jq: error: syntax error, unexpected INVALID_CHARACTER, expecting $end (Unix shell quoting issues?) at , line 1, column 1: +jq: error: syntax error, unexpected INVALID_CHARACTER, expecting end of file at , line 1, column 1: + } + ^ (.[{}] = 0)? null diff --git a/tests/shtest b/tests/shtest index e3e48421..a2459e51 100755 --- a/tests/shtest +++ b/tests/shtest @@ -634,6 +634,29 @@ EOF fi fi +# Test syntax error messages of multiline filter (we can't test in jq.test) +if $VALGRIND $Q $JQ -n '[ + try if . + then 1 + else 2 + catch ]' > $d/out 2>&1; then + echo 'syntax error not detected' + exit 1 +fi +cat > $d/expected <, line 5, column 3: + catch ] + ^^^^^ +jq: error: Possibly unterminated 'if' statement at , line 2, column 7: + try if . + ^^^^ +jq: error: Possibly unterminated 'try' statement at , line 2, column 3: + try if . + ^^^^^^^^ +jq: 3 compile errors +EOF +diff $d/out $d/expected + # Comments! if ! x=$($JQ -n '123 # comment') || [ "$x" != 123 ]; then echo 'comment did not work'