+#include <string.h>
#include "builtin.h"
#include "compile.h"
+#include "parser.h"
+#include "locfile.h"
+
static void f_plus(jv input[], jv output[]) {
jv_free(input[0]);
{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[] = {
j_not,
};
+static const char* jq_builtins[] = {
+ "def map(f): [.[] | f];"
+};
+
block builtins_bind(block b) {
+ block builtins = gen_noop();
for (unsigned i=0; i<sizeof(bytecoded_builtins)/sizeof(bytecoded_builtins[0]); i++) {
- b = block_bind(bytecoded_builtins[i](), b, OP_IS_CALL_PSEUDO);
+ block_append(&builtins, bytecoded_builtins[i]());
+ }
+ for (unsigned i=0; i<sizeof(jq_builtins)/sizeof(jq_builtins[0]); i++) {
+ struct locfile src;
+ locfile_init(&src, jq_builtins[i], strlen(jq_builtins[i]));
+ block funcs;
+ int nerrors = jq_parse_library(&src, &funcs);
+ assert(!nerrors);
+ block_append(&builtins, funcs);
+ locfile_free(&src);
}
- return gen_cbinding(&builtins, b);
+ b = block_bind(builtins, b, OP_IS_CALL_PSEUDO);
+ return gen_cbinding(&cbuiltins, b);
}
return c;
}
+int block_has_only_binders(block binders, int bindflags) {
+ bindflags |= OP_HAS_BINDING;
+ for (inst* curr = binders.first; curr; curr = curr->next) {
+ 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);
}
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);
}
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**);
#include <stdio.h>
#include <string.h>
#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();
%left '*' '/'
-%type <blk> Exp Term MkDict MkDictPair ExpD ElseBody QQString
+%type <blk> Exp Term MkDict MkDictPair ExpD ElseBody QQString FuncDef FuncDefs
%{
#include "lexer.yy.h"
#define FAIL(loc, msg) \
%}
%%
-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 {
$$ = $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 */ {
}
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;
+}