]> granicus.if.org Git - jq/commitdiff
Builtin functions defined in jq.
authorStephen Dolan <mu@netsoc.tcd.ie>
Tue, 18 Sep 2012 09:17:38 +0000 (10:17 +0100)
committerStephen Dolan <mu@netsoc.tcd.ie>
Tue, 18 Sep 2012 09:17:38 +0000 (10:17 +0100)
c/builtin.c
c/compile.c
c/compile.h
c/main.c
c/parser.y

index 74264f40ae07d050fc626b3f69508bb023c12d40..6d0235e78dbe6bfed9648824e787173ffe2c931e 100644 (file)
@@ -1,5 +1,9 @@
+#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]);
@@ -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; 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);
 }
index 952aff3ba5026f1a35538823592e53dcf2a4940f..719a2706e18ed5d4ca37b1571ed51ca1e2022052 100644 (file)
@@ -237,6 +237,16 @@ block block_join(block a, block 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);
@@ -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);
 }
 
index ce27b4b8acba108c6f3adad35b658a8af90438a6..5390420b64414f49b39e7f5e56a853632e39bb43 100644 (file)
@@ -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**);
index c9188b3e5abbcaf1f3d5e57a8c153341a02afdfa..0a9eefe8d1c040cb3af20ddf85e2bc16881f492c 100644 (file)
--- a/c/main.c
+++ b/c/main.c
@@ -1,13 +1,12 @@
 #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();
index fd5dfbc786c821ec2314061d2cb8910a24880da6..73972e7958190d730dd41baf8b5fe33b4f5544d0 100644 (file)
@@ -79,7 +79,7 @@
 %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)                                   \
@@ -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;
+}