summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authoritchyny <itchyny@cybozu.co.jp>2023-07-31 12:48:14 +0900
committerNico Williams <nico@cryptonector.com>2023-07-31 15:39:13 -0500
commit0f80921268edcc3d502e6d84612ba71fed6b0947 (patch)
tree40da8d84c1235bd94b5018a3fd015a60a7cda44f
parent6716e23ae6d534db0d3f2af2d1610f17444fb5a9 (diff)
Fix constant folding of division and reminder with zero divisor
Previously constant folding of zero division (e.x. 1/0) produces a compile error. This was incorrectly implemented by checking if the division result is infinite, so produces wrong results compared to the query where no constant folding is processed (e.x. 1e308/0.1). This patch delays the operation when the divisor is zero. This makes the results more consistent, but changes the exit code on zero division from 3 to 5. Also 0/0 now produces the zero division error, not NaN. This patch also fixes the modulo operation. Previously constant folding logic does not take care of the % operator, but now it folds if the both dividend and divisor are safe numbers to cast to the integer type, and the divisor is not zero. This patch also fixes some code that relies on undefined cast behaviors in C. The modulo operation produces NaN if either the dividend or divisor is NaN.
-rw-r--r--src/builtin.c15
-rw-r--r--src/compile.c6
-rw-r--r--src/compile.h1
-rw-r--r--src/parser.c799
-rw-r--r--src/parser.y15
-rw-r--r--tests/jq.test23
-rwxr-xr-xtests/shtest54
7 files changed, 476 insertions, 437 deletions
diff --git a/src/builtin.c b/src/builtin.c
index 26205f91..793b5976 100644
--- a/src/builtin.c
+++ b/src/builtin.c
@@ -383,7 +383,7 @@ static jv f_multiply(jq_state *jq, jv input, jv a, jv b) {
static jv f_divide(jq_state *jq, jv input, jv a, jv b) {
jv_free(input);
if (jv_get_kind(a) == JV_KIND_NUMBER && jv_get_kind(b) == JV_KIND_NUMBER) {
- if (jv_number_value(b) == 0.0 && jv_number_value(a) != 0.0)
+ if (jv_number_value(b) == 0.0)
return type_error2(a, b, "cannot be divided because the divisor is zero");
jv r = jv_number(jv_number_value(a) / jv_number_value(b));
jv_free(a);
@@ -396,14 +396,22 @@ static jv f_divide(jq_state *jq, jv input, jv a, jv b) {
}
}
+#define dtoi(n) ((n) < INTMAX_MIN ? INTMAX_MIN : -(n) < INTMAX_MIN ? INTMAX_MAX : (intmax_t)(n))
static jv f_mod(jq_state *jq, jv input, jv a, jv b) {
jv_free(input);
if (jv_get_kind(a) == JV_KIND_NUMBER && jv_get_kind(b) == JV_KIND_NUMBER) {
- intmax_t bi = (intmax_t)jv_number_value(b);
+ double na = jv_number_value(a);
+ double nb = jv_number_value(b);
+ if (isnan(na) || isnan(nb)) {
+ jv_free(a);
+ jv_free(b);
+ return jv_number(NAN);
+ }
+ intmax_t bi = dtoi(nb);
if (bi == 0)
return type_error2(a, b, "cannot be divided (remainder) because the divisor is zero");
// Check if the divisor is -1 to avoid overflow when the dividend is INTMAX_MIN.
- jv r = jv_number(bi == -1 ? 0 : (intmax_t)jv_number_value(a) % bi);
+ jv r = jv_number(bi == -1 ? 0 : dtoi(na) % bi);
jv_free(a);
jv_free(b);
return r;
@@ -411,6 +419,7 @@ static jv f_mod(jq_state *jq, jv input, jv a, jv b) {
return type_error2(a, b, "cannot be divided (remainder)");
}
}
+#undef dtoi
static jv f_equal(jq_state *jq, jv input, jv a, jv b) {
jv_free(input);
diff --git a/src/compile.c b/src/compile.c
index 4af74ff6..492340b1 100644
--- a/src/compile.c
+++ b/src/compile.c
@@ -172,12 +172,6 @@ int block_is_const(block b) {
return (block_is_single(b) && (b.first->op == LOADK || b.first->op == PUSHK_UNDER));
}
-int block_is_const_inf(block b) {
- return (block_is_single(b) && b.first->op == LOADK &&
- jv_get_kind(b.first->imm.constant) == JV_KIND_NUMBER &&
- isinf(jv_number_value(b.first->imm.constant)));
-}
-
jv_kind block_const_kind(block b) {
assert(block_is_const(b));
return jv_get_kind(b.first->imm.constant);
diff --git a/src/compile.h b/src/compile.h
index f690adc2..03cb54f5 100644
--- a/src/compile.h
+++ b/src/compile.h
@@ -22,7 +22,6 @@ block gen_op_simple(opcode op);
block gen_const(jv constant);
block gen_const_global(jv constant, const char *name);
int block_is_const(block b);
-int block_is_const_inf(block b);
jv_kind block_const_kind(block b);
jv block_const(block b);
block gen_op_target(opcode op, block target);
diff --git a/src/parser.c b/src/parser.c
index 541cef84..fc1a978c 100644
--- a/src/parser.c
+++ b/src/parser.c
@@ -497,7 +497,16 @@ static block constant_fold(block a, block b, int op) {
case '+': res = jv_number(na + nb); break;
case '-': res = jv_number(na - nb); break;
case '*': res = jv_number(na * nb); break;
- case '/': res = jv_number(na / nb); break;
+ case '/':
+ if (nb == 0.0) return gen_noop();
+ res = jv_number(na / nb);
+ break;
+ case '%':
+#define is_unsafe_double(n) (isnan(n) || (n) < INTMAX_MIN || -(n) < INTMAX_MIN)
+ if (is_unsafe_double(na) || is_unsafe_double(nb) || (intmax_t)nb == 0) return gen_noop();
+#undef is_unsafe_double
+ res = jv_number((intmax_t)na % (intmax_t)nb);
+ break;
case EQ: res = (cmp == 0 ? jv_true() : jv_false()); break;
case NEQ: res = (cmp != 0 ? jv_true() : jv_false()); break;
case '<': res = (cmp < 0 ? jv_true() : jv_false()); break;
@@ -574,7 +583,7 @@ static block gen_loc_object(location *loc, struct locfile *locations) {
}
-#line 578 "src/parser.c"
+#line 587 "src/parser.c"
#ifdef short
@@ -964,24 +973,24 @@ static const yytype_int8 yytranslate[] =
/* YYRLINE[YYN] -- Source line where rule number YYN was defined. */
static const yytype_int16 yyrline[] =
{
- 0, 313, 313, 316, 321, 324, 339, 342, 347, 350,
- 355, 359, 362, 366, 370, 374, 377, 382, 385, 388,
- 393, 400, 404, 408, 412, 416, 420, 424, 428, 432,
- 436, 440, 444, 448, 452, 456, 460, 464, 470, 476,
- 480, 484, 488, 492, 496, 500, 504, 508, 513, 516,
- 533, 542, 549, 557, 568, 573, 579, 582, 587, 591,
- 598, 603, 607, 607, 614, 617, 620, 626, 629, 632,
- 637, 640, 643, 649, 652, 655, 663, 667, 670, 673,
- 676, 679, 682, 685, 688, 691, 695, 701, 704, 707,
- 710, 713, 716, 719, 722, 725, 728, 731, 734, 737,
- 740, 743, 746, 749, 752, 755, 758, 761, 783, 787,
- 791, 794, 806, 811, 812, 813, 814, 817, 820, 825,
- 830, 833, 838, 841, 846, 850, 853, 858, 861, 866,
- 869, 874, 877, 880, 883, 886, 889, 897, 903, 906,
- 909, 912, 915, 918, 921, 924, 927, 930, 933, 936,
- 939, 942, 945, 948, 951, 954, 959, 962, 963, 964,
- 967, 970, 973, 976, 980, 985, 989, 993, 997, 1001,
- 1009
+ 0, 322, 322, 325, 330, 333, 348, 351, 356, 359,
+ 364, 368, 371, 375, 379, 383, 386, 391, 394, 397,
+ 402, 409, 413, 417, 421, 425, 429, 433, 437, 441,
+ 445, 449, 453, 457, 461, 465, 469, 473, 477, 481,
+ 485, 489, 493, 497, 501, 505, 509, 513, 518, 521,
+ 538, 547, 554, 562, 573, 578, 584, 587, 592, 596,
+ 603, 608, 612, 612, 619, 622, 625, 631, 634, 637,
+ 642, 645, 648, 654, 657, 660, 668, 672, 675, 678,
+ 681, 684, 687, 690, 693, 696, 700, 706, 709, 712,
+ 715, 718, 721, 724, 727, 730, 733, 736, 739, 742,
+ 745, 748, 751, 754, 757, 760, 763, 766, 788, 792,
+ 796, 799, 811, 816, 817, 818, 819, 822, 825, 830,
+ 835, 838, 843, 846, 851, 855, 858, 863, 866, 871,
+ 874, 879, 882, 885, 888, 891, 894, 902, 908, 911,
+ 914, 917, 920, 923, 926, 929, 932, 935, 938, 941,
+ 944, 947, 950, 953, 956, 959, 964, 967, 968, 969,
+ 972, 975, 978, 981, 985, 990, 994, 998, 1002, 1006,
+ 1014
};
#endif
@@ -2195,199 +2204,199 @@ yydestruct (const char *yymsg,
case YYSYMBOL_IDENT: /* IDENT */
#line 36 "src/parser.y"
{ jv_free(((*yyvaluep).literal)); }
-#line 2199 "src/parser.c"
+#line 2208 "src/parser.c"
break;
case YYSYMBOL_FIELD: /* FIELD */
#line 36 "src/parser.y"
{ jv_free(((*yyvaluep).literal)); }
-#line 2205 "src/parser.c"
+#line 2214 "src/parser.c"
break;
case YYSYMBOL_BINDING: /* BINDING */
#line 36 "src/parser.y"
{ jv_free(((*yyvaluep).literal)); }
-#line 2211 "src/parser.c"
+#line 2220 "src/parser.c"
break;
case YYSYMBOL_LITERAL: /* LITERAL */
#line 36 "src/parser.y"
{ jv_free(((*yyvaluep).literal)); }
-#line 2217 "src/parser.c"
+#line 2226 "src/parser.c"
break;
case YYSYMBOL_FORMAT: /* FORMAT */
#line 36 "src/parser.y"
{ jv_free(((*yyvaluep).literal)); }
-#line 2223 "src/parser.c"
+#line 2232 "src/parser.c"
break;
case YYSYMBOL_QQSTRING_TEXT: /* QQSTRING_TEXT */
#line 36 "src/parser.y"
{ jv_free(((*yyvaluep).literal)); }
-#line 2229 "src/parser.c"
+#line 2238 "src/parser.c"
break;
case YYSYMBOL_Module: /* Module */
#line 37 "src/parser.y"
{ block_free(((*yyvaluep).blk)); }
-#line 2235 "src/parser.c"
+#line 2244 "src/parser.c"
break;
case YYSYMBOL_Imports: /* Imports */
#line 37 "src/parser.y"
{ block_free(((*yyvaluep).blk)); }
-#line 2241 "src/parser.c"
+#line 2250 "src/parser.c"
break;
case YYSYMBOL_FuncDefs: /* FuncDefs */
#line 37 "src/parser.y"
{ block_free(((*yyvaluep).blk)); }
-#line 2247 "src/parser.c"
+#line 2256 "src/parser.c"
break;
case YYSYMBOL_Exp: /* Exp */
#line 37 "src/parser.y"
{ block_free(((*yyvaluep).blk)); }
-#line 2253 "src/parser.c"
+#line 2262 "src/parser.c"
break;
case YYSYMBOL_Import: /* Import */
#line 37 "src/parser.y"
{ block_free(((*yyvaluep).blk)); }
-#line 2259 "src/parser.c"
+#line 2268 "src/parser.c"
break;
case YYSYMBOL_ImportWhat: /* ImportWhat */
#line 37 "src/parser.y"
{ block_free(((*yyvaluep).blk)); }
-#line 2265 "src/parser.c"
+#line 2274 "src/parser.c"
break;
case YYSYMBOL_ImportFrom: /* ImportFrom */
#line 37 "src/parser.y"
{ block_free(((*yyvaluep).blk)); }
-#line 2271 "src/parser.c"
+#line 2280 "src/parser.c"
break;
case YYSYMBOL_FuncDef: /* FuncDef */
#line 37 "src/parser.y"
{ block_free(((*yyvaluep).blk)); }
-#line 2277 "src/parser.c"
+#line 2286 "src/parser.c"
break;
case YYSYMBOL_Params: /* Params */
#line 37 "src/parser.y"
{ block_free(((*yyvaluep).blk)); }
-#line 2283 "src/parser.c"
+#line 2292 "src/parser.c"
break;
case YYSYMBOL_Param: /* Param */
#line 37 "src/parser.y"
{ block_free(((*yyvaluep).blk)); }
-#line 2289 "src/parser.c"
+#line 2298 "src/parser.c"
break;
case YYSYMBOL_NoFormat: /* NoFormat */
#line 36 "src/parser.y"
{ jv_free(((*yyvaluep).literal)); }
-#line 2295 "src/parser.c"
+#line 2304 "src/parser.c"
break;
case YYSYMBOL_String: /* String */
#line 37 "src/parser.y"
{ block_free(((*yyvaluep).blk)); }
-#line 2301 "src/parser.c"
+#line 2310 "src/parser.c"
break;
case YYSYMBOL_QQString: /* QQString */
#line 37 "src/parser.y"
{ block_free(((*yyvaluep).blk)); }
-#line 2307 "src/parser.c"
+#line 2316 "src/parser.c"
break;
case YYSYMBOL_ElseBody: /* ElseBody */
#line 37 "src/parser.y"
{ block_free(((*yyvaluep).blk)); }
-#line 2313 "src/parser.c"
+#line 2322 "src/parser.c"
break;
case YYSYMBOL_ExpD: /* ExpD */
#line 37 "src/parser.y"
{ block_free(((*yyvaluep).blk)); }
-#line 2319 "src/parser.c"
+#line 2328 "src/parser.c"
break;
case YYSYMBOL_Term: /* Term */
#line 37 "src/parser.y"
{ block_free(((*yyvaluep).blk)); }
-#line 2325 "src/parser.c"
+#line 2334 "src/parser.c"
break;
case YYSYMBOL_Args: /* Args */
#line 37 "src/parser.y"
{ block_free(((*yyvaluep).blk)); }
-#line 2331 "src/parser.c"
+#line 2340 "src/parser.c"
break;
case YYSYMBOL_Arg: /* Arg */
#line 37 "src/parser.y"
{ block_free(((*yyvaluep).blk)); }
-#line 2337 "src/parser.c"
+#line 2346 "src/parser.c"
break;
case YYSYMBOL_RepPatterns: /* RepPatterns */
#line 37 "src/parser.y"
{ block_free(((*yyvaluep).blk)); }
-#line 2343 "src/parser.c"
+#line 2352 "src/parser.c"
break;
case YYSYMBOL_Patterns: /* Patterns */
#line 37 "src/parser.y"
{ block_free(((*yyvaluep).blk)); }
-#line 2349 "src/parser.c"
+#line 2358 "src/parser.c"
break;
case YYSYMBOL_Pattern: /* Pattern */
#line 37 "src/parser.y"
{ block_free(((*yyvaluep).blk)); }
-#line 2355 "src/parser.c"
+#line 2364 "src/parser.c"
break;
case YYSYMBOL_ArrayPats: /* ArrayPats */
#line 37 "src/parser.y"
{ block_free(((*yyvaluep).blk)); }
-#line 2361 "src/parser.c"
+#line 2370 "src/parser.c"
break;
case YYSYMBOL_ObjPats: /* ObjPats */
#line 37 "src/parser.y"
{ block_free(((*yyvaluep).blk)); }
-#line 2367 "src/parser.c"
+#line 2376 "src/parser.c"
break;
case YYSYMBOL_ObjPat: /* ObjPat */
#line 37 "src/parser.y"
{ block_free(((*yyvaluep).blk)); }
-#line 2373 "src/parser.c"
+#line 2382 "src/parser.c"
break;
case YYSYMBOL_Keyword: /* Keyword */
#line 36 "src/parser.y"
{ jv_free(((*yyvaluep).literal)); }
-#line 2379 "src/parser.c"
+#line 2388 "src/parser.c"
break;
case YYSYMBOL_MkDict: /* MkDict */
#line 37 "src/parser.y"
{ block_free(((*yyvaluep).blk)); }
-#line 2385 "src/parser.c"
+#line 2394 "src/parser.c"
break;
case YYSYMBOL_MkDictPair: /* MkDictPair */
#line 37 "src/parser.y"
{ block_free(((*yyvaluep).blk)); }
-#line 2391 "src/parser.c"
+#line 2400 "src/parser.c"
break;
default:
@@ -2691,31 +2700,31 @@ yyreduce:
switch (yyn)
{
case 2: /* TopLevel: Module Imports Exp */
-#line 313 "src/parser.y"
+#line 322 "src/parser.y"
{
*answer = BLOCK((yyvsp[-2].blk), (yyvsp[-1].blk), gen_op_simple(TOP), (yyvsp[0].blk));
}
-#line 2699 "src/parser.c"
+#line 2708 "src/parser.c"
break;
case 3: /* TopLevel: Module Imports FuncDefs */
-#line 316 "src/parser.y"
+#line 325 "src/parser.y"
{
*answer = BLOCK((yyvsp[-2].blk), (yyvsp[-1].blk), (yyvsp[0].blk));
}
-#line 2707 "src/parser.c"
+#line 2716 "src/parser.c"
break;
case 4: /* Module: %empty */
-#line 321 "src/parser.y"
+#line 330 "src/parser.y"
{
(yyval.blk) = gen_noop();
}
-#line 2715 "src/parser.c"
+#line 2724 "src/parser.c"
break;
case 5: /* Module: "module" Exp ';' */
-#line 324 "src/parser.y"
+#line 333 "src/parser.y"
{
if (!block_is_const((yyvsp[-1].blk))) {
FAIL((yyloc), "Module metadata must be constant");
@@ -2729,364 +2738,360 @@ yyreduce:
(yyval.blk) = gen_module((yyvsp[-1].blk));
}
}
-#line 2733 "src/parser.c"
+#line 2742 "src/parser.c"
break;
case 6: /* Imports: %empty */
-#line 339 "src/parser.y"
+#line 348 "src/parser.y"
{
(yyval.blk) = gen_noop();
}
-#line 2741 "src/parser.c"
+#line 2750 "src/parser.c"
break;
case 7: /* Imports: Import Imports */
-#line 342 "src/parser.y"
+#line 351 "src/parser.y"
{
(yyval.blk) = BLOCK((yyvsp[-1].blk), (yyvsp[0].blk));
}
-#line 2749 "src/parser.c"
+#line 2758 "src/parser.c"
break;
case 8: /* FuncDefs: %empty */
-#line 347 "src/parser.y"
+#line 356 "src/parser.y"
{
(yyval.blk) = gen_noop();
}
-#line 2757 "src/parser.c"
+#line 2766 "src/parser.c"
break;
case 9: /* FuncDefs: FuncDef FuncDefs */
-#line 350 "src/parser.y"
+#line 359 "src/parser.y"
{
(yyval.blk) = block_join((yyvsp[-1].blk), (yyvsp[0].blk));
}
-#line 2765 "src/parser.c"
+#line 2774 "src/parser.c"
break;
case 10: /* Exp: FuncDef Exp */
-#line 355 "src/parser.y"
+#line 364 "src/parser.y"
{
(yyval.blk) = block_bind_referenced((yyvsp[-1].blk), (yyvsp[0].blk), OP_IS_CALL_PSEUDO);
}
-#line 2773 "src/parser.c"
+#line 2782 "src/parser.c"
break;
case 11: /* Exp: Term "as" Patterns '|' Exp */
-#line 359 "src/parser.y"
+#line 368 "src/parser.y"
{
(yyval.blk) = gen_destructure((yyvsp[-4].blk), (yyvsp[-2].blk), (yyvsp[0].blk));
}
-#line 2781 "src/parser.c"
+#line 2790 "src/parser.c"
break;
case 12: /* Exp: "reduce" Term "as" Patterns '(' Exp ';' Exp ')' */
-#line 362 "src/parser.y"
+#line 371 "src/parser.y"
{
(yyval.blk) = gen_reduce((yyvsp[-7].blk), (yyvsp[-5].blk), (yyvsp[-3].blk), (yyvsp[-1].blk));
}
-#line 2789 "src/parser.c"
+#line 2798 "src/parser.c"
break;
case 13: /* Exp: "foreach" Term "as" Patterns '(' Exp ';' Exp ';' Exp ')' */
-#line 366 "src/parser.y"
+#line 375 "src/parser.y"
{
(yyval.blk) = gen_foreach((yyvsp[-9].blk), (yyvsp[-7].blk), (yyvsp[-5].blk), (yyvsp[-3].blk), (yyvsp[-1].blk));
}
-#line 2797 "src/parser.c"
+#line 2806 "src/parser.c"
break;
case 14: /* Exp: "foreach" Term "as" Patterns '(' Exp ';' Exp ')' */
-#line 370 "src/parser.y"
+#line 379 "src/parser.y"
{
(yyval.blk) = gen_foreach((yyvsp[-7].blk), (yyvsp[-5].blk), (yyvsp[-3].blk), (yyvsp[-1].blk), gen_noop());
}
-#line 2805 "src/parser.c"
+#line 2814 "src/parser.c"
break;
case 15: /* Exp: "if" Exp "then" Exp ElseBody */
-#line 374 "src/parser.y"
+#line 383 "src/parser.y"
{
(yyval.blk) = gen_cond((yyvsp[-3].blk), (yyvsp[-1].blk), (yyvsp[0].blk));
}
-#line 2813 "src/parser.c"
+#line 2822 "src/parser.c"
break;
case 16: /* Exp: "if" Exp "then" error */
-#line 377 "src/parser.y"
+#line 386 "src/parser.y"
{
FAIL((yyloc), "Possibly unterminated 'if' statement");
(yyval.blk) = (yyvsp[-2].blk);
}
-#line 2822 "src/parser.c"
+#line 2831 "src/parser.c"
break;
case 17: /* Exp: "try" Exp "catch" Exp */
-#line 382 "src/parser.y"
+#line 391 "src/parser.y"
{
(yyval.blk) = gen_try((yyvsp[-2].blk), (yyvsp[0].blk));
}
-#line 2830 "src/parser.c"
+#line 2839 "src/parser.c"
break;
case 18: /* Exp: "try" Exp */
-#line 385 "src/parser.y"
+#line 394 "src/parser.y"
{
(yyval.blk) = gen_try((yyvsp[0].blk), gen_op_simple(BACKTRACK));
}
-#line 2838 "src/parser.c"
+#line 2847 "src/parser.c"
break;
case 19: /* Exp: "try" Exp "catch" error */
-#line 388 "src/parser.y"
+#line 397 "src/parser.y"
{
FAIL((yyloc), "Possibly unterminated 'try' statement");
(yyval.blk) = (yyvsp[-2].blk);
}
-#line 2847 "src/parser.c"
+#line 2856 "src/parser.c"
break;
case 20: /* Exp: "label" BINDING '|' Exp */
-#line 393 "src/parser.y"
+#line 402 "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 2858 "src/parser.c"
+#line 2867 "src/parser.c"
break;
case 21: /* Exp: Exp '?' */
-#line 400 "src/parser.y"
+#line 409 "src/parser.y"
{
(yyval.blk) = gen_try((yyvsp[-1].blk), gen_op_simple(BACKTRACK));
}
-#line 2866 "src/parser.c"
+#line 2875 "src/parser.c"
break;
case 22: /* Exp: Exp '=' Exp */
-#line 404 "src/parser.y"
+#line 413 "src/parser.y"
{
(yyval.blk) = gen_call("_assign", BLOCK(gen_lambda((yyvsp[-2].blk)), gen_lambda((yyvsp[0].blk))));
}
-#line 2874 "src/parser.c"
+#line 2883 "src/parser.c"
break;
case 23: /* Exp: Exp "or" Exp */
-#line 408 "src/parser.y"
+#line 417 "src/parser.y"
{
(yyval.blk) = gen_or((yyvsp[-2].blk), (yyvsp[0].blk));
}
-#line 2882 "src/parser.c"
+#line 2891 "src/parser.c"
break;
case 24: /* Exp: Exp "and" Exp */
-#line 412 "src/parser.y"
+#line 421 "src/parser.y"
{
(yyval.blk) = gen_and((yyvsp[-2].blk), (yyvsp[0].blk));
}
-#line 2890 "src/parser.c"
+#line 2899 "src/parser.c"
break;
case 25: /* Exp: Exp "//" Exp */
-#line 416 "src/parser.y"
+#line 425 "src/parser.y"
{
(yyval.blk) = gen_definedor((yyvsp[-2].blk), (yyvsp[0].blk));
}
-#line 2898 "src/parser.c"
+#line 2907 "src/parser.c"
break;
case 26: /* Exp: Exp "//=" Exp */
-#line 420 "src/parser.y"
+#line 429 "src/parser.y"
{
(yyval.blk) = gen_definedor_assign((yyvsp[-2].blk), (yyvsp[0].blk));
}
-#line 2906 "src/parser.c"
+#line 2915 "src/parser.c"
break;
case 27: /* Exp: Exp "|=" Exp */
-#line 424 "src/parser.y"
+#line 433 "src/parser.y"
{
(yyval.blk) = gen_call("_modify", BLOCK(gen_lambda((yyvsp[-2].blk)), gen_lambda((yyvsp[0].blk))));
}
-#line 2914 "src/parser.c"
+#line 2923 "src/parser.c"
break;
case 28: /* Exp: Exp '|' Exp */
-#line 428 "src/parser.y"
+#line 437 "src/parser.y"
{
(yyval.blk) = block_join((yyvsp[-2].blk), (yyvsp[0].blk));
}
-#line 2922 "src/parser.c"
+#line 2931 "src/parser.c"
break;
case 29: /* Exp: Exp ',' Exp */
-#line 432 "src/parser.y"
+#line 441 "src/parser.y"
{
(yyval.blk) = gen_both((yyvsp[-2].blk), (yyvsp[0].blk));
}
-#line 2930 "src/parser.c"
+#line 2939 "src/parser.c"
break;
case 30: /* Exp: Exp '+' Exp */
-#line 436 "src/parser.y"
+#line 445 "src/parser.y"
{
(yyval.blk) = gen_binop((yyvsp[-2].blk), (yyvsp[0].blk), '+');
}
-#line 2938 "src/parser.c"
+#line 2947 "src/parser.c"
break;
case 31: /* Exp: Exp "+=" Exp */
-#line 440 "src/parser.y"
+#line 449 "src/parser.y"
{
(yyval.blk) = gen_update((yyvsp[-2].blk), (yyvsp[0].blk), '+');
}
-#line 2946 "src/parser.c"
+#line 2955 "src/parser.c"
break;
case 32: /* Exp: '-' Exp */
-#line 444 "src/parser.y"
+#line 453 "src/parser.y"
{
(yyval.blk) = BLOCK((yyvsp[0].blk), gen_call("_negate", gen_noop()));
}
-#line 2954 "src/parser.c"
+#line 2963 "src/parser.c"
break;
case 33: /* Exp: Exp '-' Exp */
-#line 448 "src/parser.y"
+#line 457 "src/parser.y"
{
(yyval.blk) = gen_binop((yyvsp[-2].blk), (yyvsp[0].blk), '-');
}
-#line 2962 "src/parser.c"
+#line 2971 "src/parser.c"
break;
case 34: /* Exp: Exp "-=" Exp */
-#line 452 "src/parser.y"
+#line 461 "src/parser.y"
{
(yyval.blk) = gen_update((yyvsp[-2].blk), (yyvsp[0].blk), '-');
}
-#line 2970 "src/parser.c"
+#line 2979 "src/parser.c"
break;
case 35: /* Exp: Exp '*' Exp */
-#line 456 "src/parser.y"
+#line 465 "src/parser.y"
{
(yyval.blk) = gen_binop((yyvsp[-2].blk), (yyvsp[0].blk), '*');
}
-#line 2978 "src/parser.c"
+#line 2987 "src/parser.c"
break;
case 36: /* Exp: Exp "*=" Exp */
-#line 460 "src/parser.y"
+#line 469 "src/parser.y"
{
(yyval.blk) = gen_update((yyvsp[-2].blk), (yyvsp[0].blk), '*');
}
-#line 2986 "src/parser.c"
+#line 2995 "src/parser.c"
break;
case 37: /* Exp: Exp '/' Exp */
-#line 464 "src/parser.y"
+#line 473 "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 2996 "src/parser.c"
+#line 3003 "src/parser.c"
break;
case 38: /* Exp: Exp '%' Exp */
-#line 470 "src/parser.y"
+#line 477 "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 3006 "src/parser.c"
+#line 3011 "src/parser.c"
break;
case 39: /* Exp: Exp "/=" Exp */
-#line 476 "src/parser.y"
+#line 481 "src/parser.y"
{
(yyval.blk) = gen_update((yyvsp[-2].blk), (yyvsp[0].blk), '/');
}
-#line 3014 "src/parser.c"
+#line 3019 "src/parser.c"
break;
case 40: /* Exp: Exp "%=" Exp */
-#line 480 "src/parser.y"
+#line 485 "src/parser.y"
{
(yyval.blk) = gen_update((yyvsp[-2].blk), (yyvsp[0].blk), '%');
}
-#line 3022 "src/parser.c"
+#line 3027 "src/parser.c"
break;
case 41: /* Exp: Exp "==" Exp */
-#line 484 "src/parser.y"
+#line 489 "src/parser.y"
{
(yyval.blk) = gen_binop((yyvsp[-2].blk), (yyvsp[0].blk), EQ);
}
-#line 3030 "src/parser.c"
+#line 3035 "src/parser.c"
break;
case 42: /* Exp: Exp "!=" Exp */
-#line 488 "src/parser.y"
+#line 493 "src/parser.y"
{
(yyval.blk) = gen_binop((yyvsp[-2].blk), (yyvsp[0].blk), NEQ);
}
-#line 3038 "src/parser.c"
+#line 3043 "src/parser.c"
break;
case 43: /* Exp: Exp '<' Exp */
-#line 492 "src/parser.y"
+#line 497 "src/parser.y"
{
(yyval.blk) = gen_binop((yyvsp[-2].blk), (yyvsp[0].blk), '<');
}
-#line 3046 "src/parser.c"
+#line 3051 "src/parser.c"
break;
case 44: /* Exp: Exp '>' Exp */
-#line 496 "src/parser.y"
+#line 501 "src/parser.y"
{
(yyval.blk) = gen_binop((yyvsp[-2].blk), (yyvsp[0].blk), '>');
}
-#line 3054 "src/parser.c"
+#line 3059 "src/parser.c"
break;
case 45: /* Exp: Exp "<=" Exp */
-#line 500 "src/parser.y"
+#line 505 "src/parser.y"
{
(yyval.blk) = gen_binop((yyvsp[-2].blk), (yyvsp[0].blk), LESSEQ);
}
-#line 3062 "src/parser.c"
+#line 3067 "src/parser.c"
break;
case 46: /* Exp: Exp ">=" Exp */
-#line 504 "src/parser.y"
+#line 509 "src/parser.y"
{
(yyval.blk) = gen_binop((yyvsp[-2].blk), (yyvsp[0].blk), GREATEREQ);
}
-#line 3070 "src/parser.c"
+#line 3075 "src/parser.c"
break;
case 47: /* Exp: Term */
-#line 508 "src/parser.y"
+#line 513 "src/parser.y"
{
(yyval.blk) = (yyvsp[0].blk);
}
-#line 3078 "src/parser.c"
+#line 3083 "src/parser.c"
break;
case 48: /* Import: ImportWhat ';' */
-#line 513 "src/parser.y"
+#line 518 "src/parser.y"
{
(yyval.blk) = (yyvsp[-1].blk);
}
-#line 3086 "src/parser.c"
+#line 3091 "src/parser.c"
break;
case 49: /* Import: ImportWhat Exp ';' */
-#line 516 "src/parser.y"
+#line 521 "src/parser.y"
{
if (!block_is_const((yyvsp[-1].blk))) {
FAIL((yyloc), "Module metadata must be constant");
@@ -3102,11 +3107,11 @@ yyreduce:
(yyval.blk) = gen_import_meta((yyvsp[-2].blk), (yyvsp[-1].blk));
}
}
-#line 3106 "src/parser.c"
+#line 3111 "src/parser.c"
break;
case 50: /* ImportWhat: "import" ImportFrom "as" BINDING */
-#line 533 "src/parser.y"
+#line 538 "src/parser.y"
{
jv v = block_const((yyvsp[-2].blk));
// XXX Make gen_import take only blocks and the int is_data so we
@@ -3116,11 +3121,11 @@ yyreduce:
jv_free((yyvsp[0].literal));
jv_free(v);
}
-#line 3120 "src/parser.c"
+#line 3125 "src/parser.c"
break;
case 51: /* ImportWhat: "import" ImportFrom "as" IDENT */
-#line 542 "src/parser.y"
+#line 547 "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);
@@ -3128,22 +3133,22 @@ yyreduce:
jv_free((yyvsp[0].literal));
jv_free(v);
}
-#line 3132 "src/parser.c"
+#line 3137 "src/parser.c"
break;
case 52: /* ImportWhat: "include" ImportFrom */
-#line 549 "src/parser.y"
+#line 554 "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 3143 "src/parser.c"
+#line 3148 "src/parser.c"
break;
case 53: /* ImportFrom: String */
-#line 557 "src/parser.y"
+#line 562 "src/parser.y"
{
if (!block_is_const((yyvsp[0].blk))) {
FAIL((yyloc), "Import path must be constant");
@@ -3153,183 +3158,183 @@ yyreduce:
(yyval.blk) = (yyvsp[0].blk);
}
}
-#line 3157 "src/parser.c"
+#line 3162 "src/parser.c"
break;
case 54: /* FuncDef: "def" IDENT ':' Exp ';' */
-#line 568 "src/parser.y"
+#line 573 "src/parser.y"
{
(yyval.blk) = gen_function(jv_string_value((yyvsp[-3].literal)), gen_noop(), (yyvsp[-1].blk));
jv_free((yyvsp[-3].literal));
}
-#line 3166 "src/parser.c"
+#line 3171 "src/parser.c"
break;
case 55: /* FuncDef: "def" IDENT '(' Params ')' ':' Exp ';' */
-#line 573 "src/parser.y"
+#line 578 "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 3175 "src/parser.c"
+#line 3180 "src/parser.c"
break;
case 56: /* Params: Param */
-#line 579 "src/parser.y"
+#line 584 "src/parser.y"
{
(yyval.blk) = (yyvsp[0].blk);
}
-#line 3183 "src/parser.c"
+#line 3188 "src/parser.c"
break;
case 57: /* Params: Params ';' Param */
-#line 582 "src/parser.y"
+#line 587 "src/parser.y"
{
(yyval.blk) = BLOCK((yyvsp[-2].blk), (yyvsp[0].blk));
}
-#line 3191 "src/parser.c"
+#line 3196 "src/parser.c"
break;
case 58: /* Param: BINDING */
-#line 587 "src/parser.y"
+#line 592 "src/parser.y"
{
(yyval.blk) = gen_param_regular(jv_string_value((yyvsp[0].literal)));
jv_free((yyvsp[0].literal));
}
-#line 3200 "src/parser.c"
+#line 3205 "src/parser.c"
break;
case 59: /* Param: IDENT */
-#line 591 "src/parser.y"
+#line 596 "src/parser.y"
{
(yyval.blk) = gen_param(jv_string_value((yyvsp[0].literal)));
jv_free((yyvsp[0].literal));
}
-#line 3209 "src/parser.c"
+#line 3214 "src/parser.c"
break;
case 60: /* NoFormat: %empty */
-#line 598 "src/parser.y"
+#line 603 "src/parser.y"
{
(yyval.literal) = jv_string("text");
}
-#line 3217 "src/parser.c"
+#line 3222 "src/parser.c"
break;
case 61: /* String: QQSTRING_START NoFormat QQString QQSTRING_END */
-#line 603 "src/parser.y"
+#line 608 "src/parser.y"
{
(yyval.blk) = (yyvsp[-1].blk);
jv_free((yyvsp[-2].literal));
}
-#line 3226 "src/parser.c"
+#line 3231 "src/parser.c"
break;
case 62: /* @1: %empty */
-#line 607 "src/parser.y"
+#line 612 "src/parser.y"
{ (yyval.literal) = (yyvsp[-1].literal); }
-#line 3232 "src/parser.c"
+#line 3237 "src/parser.c"
break;
case 63: /* String: FORMAT QQSTRING_START @1 QQString QQSTRING_END */
-#line 607 "src/parser.y"
+#line 612 "src/parser.y"
{
(yyval.blk) = (yyvsp[-1].blk);
jv_free((yyvsp[-2].literal));
}
-#line 3241 "src/parser.c"
+#line 3246 "src/parser.c"
break;
case 64: /* QQString: %empty */
-#line 614 "src/parser.y"
+#line 619 "src/parser.y"
{
(yyval.blk) = gen_const(jv_string(""));
}
-#line 3249 "src/parser.c"
+#line 3254 "src/parser.c"
break;
case 65: /* QQString: QQString QQSTRING_TEXT */
-#line 617 "src/parser.y"
+#line 622 "src/parser.y"
{
(yyval.blk) = gen_binop((yyvsp[-1].blk), gen_const((yyvsp[0].literal)), '+');
}
-#line 3257 "src/parser.c"
+#line 3262 "src/parser.c"
break;
case 66: /* QQString: QQString QQSTRING_INTERP_START Exp QQSTRING_INTERP_END */
-#line 620 "src/parser.y"
+#line 625 "src/parser.y"
{
(yyval.blk) = gen_binop((yyvsp[-3].blk), gen_format((yyvsp[-1].blk), jv_copy((yyvsp[-4].literal))), '+');
}
-#line 3265 "src/parser.c"
+#line 3270 "src/parser.c"
break;
case 67: /* ElseBody: "elif" Exp "then" Exp ElseBody */
-#line 626 "src/parser.y"