]> granicus.if.org Git - jq/commitdiff
Subtraction - as expected for numbers, ruby-style set diff for arrays.
authorStephen Dolan <mu@netsoc.tcd.ie>
Mon, 10 Sep 2012 15:49:25 +0000 (16:49 +0100)
committerStephen Dolan <mu@netsoc.tcd.ie>
Mon, 10 Sep 2012 15:49:25 +0000 (16:49 +0100)
c/builtin.c
c/lexer.l
c/parser.y
c/testdata

index bdca2540095167a3a71a26bbc4177a66e943e796..65ecb52ca00d8065bc8f27d0b976e2dad0890802 100644 (file)
@@ -37,10 +37,44 @@ static void f_plus(jv input[], jv output[]) {
   }
 }
 
+static void f_minus(jv input[], jv output[]) {
+  jv_free(input[0]);
+  jv a = input[2];
+  jv b = input[1];
+  if (jv_get_kind(a) == JV_KIND_NUMBER && jv_get_kind(b) == JV_KIND_NUMBER) {
+    output[0] = jv_number(jv_number_value(a) - jv_number_value(b));
+  } else if (jv_get_kind(a) == JV_KIND_ARRAY && jv_get_kind(b) == JV_KIND_ARRAY) {
+    jv out = jv_array();
+    for (int i=0; i<jv_array_length(jv_copy(a)); i++) {
+      jv x = jv_array_get(jv_copy(a), i);
+      int include = 1;
+      for (int j=0; j<jv_array_length(jv_copy(b)); j++) {
+        if (jv_equal(jv_copy(x), jv_array_get(jv_copy(b), j))) {
+          include = 0;
+          break;
+        }
+      }
+      if (include)
+        out = jv_array_append(out, jv_copy(x));
+      jv_free(x);
+    }
+    jv_free(a);
+    jv_free(b);
+    output[0] = out;
+  } else {
+    output[0] = jv_invalid_with_msg(jv_string_fmt("Attempted to subtract %s and %s",
+                                                  jv_kind_name(jv_get_kind(a)),
+                                                  jv_kind_name(jv_get_kind(b))));
+    jv_free(a);
+    jv_free(b);
+  }
+}
+
 struct cfunction function_list[] = {
   {f_true, "true", CALL_BUILTIN_1_1},
   {f_false, "false", CALL_BUILTIN_1_1},
   {f_null, "null", CALL_BUILTIN_1_1},
   {f_plus, "_plus", CALL_BUILTIN_3_1},
+  {f_minus, "_minus", CALL_BUILTIN_3_1},
 };
 struct symbol_table builtins = {function_list, sizeof(function_list)/sizeof(function_list[0])};
index f265176269623374162da6f1e9ec7c0c2e29d65b..1b74d43ffada18560227462349d1343fa33e5aad 100644 (file)
--- a/c/lexer.l
+++ b/c/lexer.l
@@ -22,7 +22,7 @@
 "not" { return NOT; }
 "end" { return END; }
 "//" { return DEFINEDOR; }
-"."|"="|";"|"["|"]"|","|":"|"("|")"|"{"|"}"|"|"|"+"|"\$" { return yytext[0];}
+"."|"="|";"|"["|"]"|","|":"|"("|")"|"{"|"}"|"|"|"+"|"-"|"\$" { return yytext[0];}
 
 \"(\\.|[^\\"])*\" |
 -?[0-9.]+([eE][+-]?[0-9]+)? { 
index 54456d09062fb0bd8001987fc779ef1f95e92f8c..72b91a1aff7dc6a290e98e6a45b4b9ceb7a74328 100644 (file)
 %nonassoc EQ
 %left OR
 %left AND
-%left '+'
+%left '+' '-'
 
 
 %type <blk> Exp Term MkDict MkDictPair ExpD ElseBody
-
 %{
 #include "lexer.yy.h"
 void yyerror(YYLTYPE* loc, block* answer, yyscan_t lexer, const char *s){
@@ -64,6 +63,21 @@ static block gen_index(block obj, block key) {
   return block_join(obj, block_join(gen_subexp(key), gen_op_simple(INDEX)));
 }
 
+static block gen_binop(block a, block b, char op) {
+  const char* funcname = 0;
+  switch (op) {
+  case '+': funcname = "_plus"; break;
+  case '-': funcname = "_minus"; break;
+  }
+  assert(funcname);
+
+  block c = gen_noop();
+  block_append(&c, gen_subexp(a));
+  block_append(&c, gen_subexp(b));
+  block_append(&c, gen_op_call(CALL_1_1, gen_op_block_unbound(CLOSURE_REF, funcname)));
+  return c;
+}
+
 %}
 
 %%
@@ -136,10 +150,11 @@ Exp ',' Exp {
 } |
 
 Exp '+' Exp {
-  $$ = gen_noop();
-  block_append(&$$, gen_subexp($1));
-  block_append(&$$, gen_subexp($3));
-  block_append(&$$, gen_op_call(CALL_1_1, gen_op_block_unbound(CLOSURE_REF, "_plus")));
+  $$ = gen_binop($1, $3, '+');
+} |
+
+Exp '-' Exp {
+  $$ = gen_binop($1, $3, '-');
 } |
 
 Term { 
@@ -154,7 +169,6 @@ ElseBody:
   $$ = $2;
 }
 
-
 ExpD:
 ExpD '|' ExpD { 
   $$ = block_join($1, $3);
index c353dc2f4ae90f1928addeab3acb90d7d5300ce2..6386ac08d455cc04a21b88fb364b5b5bb67638c0 100644 (file)
@@ -167,6 +167,14 @@ null
 "\u0000\u0020\u0000"
 "\u0000 \u0000\u0000 \u0000"
 
+42 - .
+11
+31
+
+[1,2,3,4,1] - [.,3]
+1
+[2,4]
+
 #
 # User-defined functions
 # Oh god.