%token INVALID_CHARACTER %token IDENT %token FIELD %token BINDING %token LITERAL %token FORMAT String: StringStart QQString QQSTRING_END { $$ = $2; jv_free($1); }; Expr: Expr "//" Expr { $$ = gen_definedor($1, $3); } | Expr '=' Expr { $$ = gen_call("_assign", BLOCK(gen_lambda($1), gen_lambda($3))); } | Term %prec NONOPT { $$ = $1; } TopLevel: Module Imports Query { *answer = BLOCK($1, $2, gen_op_simple(TOP), $3); } | Module Imports FuncDefs { *answer = BLOCK($1, $2, $3); } Query: FuncDef Query %prec FUNCDEF { $$ = block_bind_referenced($1, $2, OP_IS_CALL_PSEUDO); } | Expr { $$ = $1; } Query '|' Query { $$ = block_join($1, $3); } | Query ',' Query { $$ = gen_both($1, $3); } Term FIELD '?' { $$ = gen_index_opt($1, gen_const($2)); } | Term '?' { $$ = gen_try($1, gen_op_simple(BACKTRACK)); } Expr "or" Expr { $$ = gen_or($1, $3); } | Expr "and" Expr { $$ = gen_and($1, $3); } | Expr "==" Expr { $$ = gen_binop($1, $3, EQ); } LITERAL { $$ = gen_const($1); } | IDENT { const char *s = jv_string_value($1); if (strcmp(s, "false") == 0) $$ = gen_const(jv_false()); else if (strcmp(s, "true") == 0) $$ = gen_const(jv_true()); else if (strcmp(s, "null") == 0) $$ = gen_const(jv_null()); Term FIELD %prec NONOPT { $$ = gen_index($1, gen_const($2)); } | Term '[' Query ']' %prec NONOPT { $$ = gen_index($1, $3); } Term '[' ']' %prec NONOPT { $$ = block_join($1, gen_op_simple(EACH)); } | Term '[' Query ':' Query ']' %prec NONOPT { $$ = gen_slice_index($1, $3, $5, INDEX); } Expr '+' Expr { $$ = gen_binop($1, $3, '+'); } | Expr "+=" Expr { $$ = gen_update($1, $3, '+'); } Expr "//" Expr { $$ = gen_definedor($1, $3); } | Expr "//=" Expr { $$ = gen_definedor_assign($1, $3); } "if" Query "then" Query ElseBody { $$ = gen_cond($2, $4, $5); } | "try" Expr "catch" Expr { $$ = gen_try($2, $4); } "label" BINDING '|' Query { jv v = jv_string_fmt("*label-%s", jv_string_value($2)); $$ = gen_location(@$, locations, gen_label(jv_string_value(v), $4)); } | BREAK BINDING { jv v = jv_string_fmt("*label-%s", jv_string_value($2)); "reduce" Expr "as" Patterns '(' Query ';' Query ')' { $$ = gen_reduce($2, $4, $6, $8); } | "foreach" Expr "as" Patterns '(' Query ';' Query ';' Query ')' { $$ = gen_foreach($2, $4, $6, $8, $10); } REC { $$ = gen_call("recurse", gen_noop()); } Expr "as" Patterns '|' Query { $$ = gen_destructure($1, $3, $5); } | BINDING { $$ = gen_location(@$, locations, gen_op_unbound(LOADV, jv_string_value($1))); jv_free($1); } Params: Param { $$ = $1; } | Params ';' Param { $$ = BLOCK($1, $3); } FuncDef: "def" IDENT ':' Query ';' { $$ = gen_function(jv_string_value($2), gen_noop(), $4); jv_free($2); } RepPatterns: RepPatterns "?//" Pattern { $$ = BLOCK($1, gen_destructure_alt($3)); } | Pattern { $$ = gen_destructure_alt($1); } static block gen_update(block object, block val, int optype) { block tmp = gen_op_var_fresh(STOREV, "tmp"); return BLOCK(gen_op_simple(DUP), val, tmp, gen_call("_modify", BLOCK(gen_lambda(object), gen_lambda(gen_binop(gen_noop(), gen_op_bound(LOADV, tmp), optype))))); } Expr "|=" Expr { $$ = gen_call("_modify", BLOCK(gen_lambda($1), gen_lambda($3))); } | Expr "+=" Expr { $$ = gen_update($1, $3, '+'); } Expr '=' Expr { $$ = gen_call("_assign", BLOCK(gen_lambda($1), gen_lambda($3))); } | Expr SETMOD Expr { $$ = gen_update($1, $3, '%'); } static block gen_format(block a, jv fmt) { return BLOCK(a, gen_call("format", gen_lambda(gen_const(fmt)))); } void yyerror(YYLTYPE* loc, block* answer, int* errors, struct locfile* locations, struct lexer_param* lexer_param_ptr, const char *s){ (*errors)++; locfile_locate(locations, *loc, "jq: error: %s", s); }