From: Stephen Dolan Date: Tue, 18 Sep 2012 09:17:38 +0000 (+0100) Subject: Builtin functions defined in jq. X-Git-Tag: jq-1.1~34 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=940f8c427097d15d8d9227ce0b0c9c78360c4325;p=jq Builtin functions defined in jq. --- diff --git a/c/builtin.c b/c/builtin.c index 74264f4..6d0235e 100644 --- a/c/builtin.c +++ b/c/builtin.c @@ -1,5 +1,9 @@ +#include #include "builtin.h" #include "compile.h" +#include "parser.h" +#include "locfile.h" + static void f_plus(jv input[], jv output[]) { jv_free(input[0]); @@ -183,7 +187,7 @@ static struct cfunction function_list[] = { {f_type, "type", CALL_BUILTIN_1_1}, }; -static struct symbol_table builtins = {function_list, sizeof(function_list)/sizeof(function_list[0])}; +static struct symbol_table cbuiltins = {function_list, sizeof(function_list)/sizeof(function_list[0])}; typedef block (*bytecoded_builtin)(); static bytecoded_builtin bytecoded_builtins[] = { @@ -194,10 +198,25 @@ static bytecoded_builtin bytecoded_builtins[] = { j_not, }; +static const char* jq_builtins[] = { + "def map(f): [.[] | f];" +}; + block builtins_bind(block b) { + block builtins = gen_noop(); for (unsigned i=0; inext) { + if ((opcode_describe(curr->op)->flags & bindflags) != bindflags) { + return 0; + } + } + return 1; +} + static void block_bind_subblock(block binder, block body, int bindflags) { assert(block_is_single(binder)); assert((opcode_describe(binder.first->op)->flags & bindflags) == bindflags); @@ -260,8 +270,11 @@ static void block_bind_subblock(block binder, block body, int bindflags) { } block block_bind(block binder, block body, int bindflags) { + assert(block_has_only_binders(binder, bindflags)); bindflags |= OP_HAS_BINDING; - block_bind_subblock(binder, body, bindflags); + for (inst* curr = binder.first; curr; curr = curr->next) { + block_bind_subblock(inst_block(curr), body, bindflags); + } return block_join(binder, body); } diff --git a/c/compile.h b/c/compile.h index ce27b4b..5390420 100644 --- a/c/compile.h +++ b/c/compile.h @@ -43,6 +43,7 @@ block gen_cbinding(struct symbol_table* functions, block b); void block_append(block* b, block b2); block block_join(block a, block b); +int block_has_only_binders(block, int bindflags); block block_bind(block binder, block body, int bindflags); int block_compile(block, struct locfile*, struct bytecode**); diff --git a/c/main.c b/c/main.c index c9188b3..0a9eefe 100644 --- a/c/main.c +++ b/c/main.c @@ -1,13 +1,12 @@ #include #include #include "compile.h" -#include "parser.tab.h" #include "builtin.h" #include "jv.h" #include "jv_parse.h" #include "locfile.h" +#include "parser.h" -int jq_parse(struct locfile* source, block* answer); void jq_init(struct bytecode* bc, jv value); jv jq_next(); diff --git a/c/parser.y b/c/parser.y index fd5dfbc..73972e7 100644 --- a/c/parser.y +++ b/c/parser.y @@ -79,7 +79,7 @@ %left '*' '/' -%type Exp Term MkDict MkDictPair ExpD ElseBody QQString +%type Exp Term MkDict MkDictPair ExpD ElseBody QQString FuncDef FuncDefs %{ #include "lexer.yy.h" #define FAIL(loc, msg) \ @@ -160,21 +160,25 @@ static block gen_update(block a, block op, int optype) { %} %% -program: Exp { *answer = $1; } +TopLevel: +Exp { + *answer = $1; +} | +FuncDefs { + *answer = $1; +} -Exp: -"def" IDENT ':' Exp ';' Exp { - block body = block_join($4, gen_op_simple(RET)); - $$ = block_bind(gen_op_block_defn_rec(CLOSURE_CREATE, jv_string_value($2), body), - $6, OP_IS_CALL_PSEUDO); - jv_free($2); +FuncDefs: +/* empty */ { + $$ = gen_noop(); } | +FuncDef FuncDefs { + $$ = block_join($1, $2); +} -"def" IDENT '(' IDENT ')' ':' Exp ';' Exp { - block body = block_bind(gen_op_block_unbound(CLOSURE_PARAM, jv_string_value($4)), block_join($7, gen_op_simple(RET)), OP_IS_CALL_PSEUDO); - $$ = block_bind(gen_op_block_defn_rec(CLOSURE_CREATE, jv_string_value($2), body), $9, OP_IS_CALL_PSEUDO); - jv_free($2); - jv_free($4); +Exp: +FuncDef Exp %prec ';' { + $$ = block_bind($1, $2, OP_IS_CALL_PSEUDO); } | Term "as" '$' IDENT '|' Exp { @@ -273,6 +277,19 @@ Term { $$ = $1; } +FuncDef: +"def" IDENT ':' Exp ';' { + block body = block_join($4, gen_op_simple(RET)); + $$ = gen_op_block_defn_rec(CLOSURE_CREATE, jv_string_value($2), body); + jv_free($2); +} | + +"def" IDENT '(' IDENT ')' ':' Exp ';' { + block body = block_bind(gen_op_block_unbound(CLOSURE_PARAM, jv_string_value($4)), block_join($7, gen_op_simple(RET)), OP_IS_CALL_PSEUDO); + $$ = gen_op_block_defn_rec(CLOSURE_CREATE, jv_string_value($2), body); + jv_free($2); + jv_free($4); +} QQString: /* empty */ { @@ -405,3 +422,13 @@ int jq_parse(struct locfile* locations, block* answer) { } return errors; } + +int jq_parse_library(struct locfile* locations, block* answer) { + int errs = jq_parse(locations, answer); + if (errs) return errs; + if (!block_has_only_binders(*answer, OP_IS_CALL_PSEUDO)) { + locfile_locate(locations, UNKNOWN_LOCATION, "error: library should only have function definitions, not a main expression"); + return 1; + } + return 0; +}