]> granicus.if.org Git - jq/commitdiff
Add <,>,<=,>= binops
authorStephen Roantree <stroantree@gmail.com>
Sun, 7 Oct 2012 21:34:12 +0000 (22:34 +0100)
committerStephen Roantree <stroantree@gmail.com>
Sun, 7 Oct 2012 21:34:12 +0000 (22:34 +0100)
builtin.c
lexer.l
parser.y
testdata

index 1eee5bb51de5261338fc57c977cea0b602e78876..c6ff785d0837140103066b7dbb8f894d875cc15d 100644 (file)
--- a/builtin.c
+++ b/builtin.c
@@ -4,6 +4,12 @@
 #include "parser.h"
 #include "locfile.h"
 
+enum {
+  CMP_OP_LESS,
+  CMP_OP_GREATER,
+  CMP_OP_LESSEQ,
+  CMP_OP_GREATEREQ
+} _cmp_op;
 
 static void f_plus(jv input[], jv output[]) {
   jv_free(input[0]);
@@ -114,6 +120,42 @@ static void f_equal(jv input[], jv output[]) {
   output[0] = jv_bool(jv_equal(input[2], input[1]));
 }
 
+static void order_cmp(jv input[], jv output[], int op) {
+  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) {
+    double da = jv_number_value(a);
+    double db = jv_number_value(b);
+    output[0] = jv_bool((op == CMP_OP_LESS && da < db) ||
+                        (op == CMP_OP_LESSEQ && da <= db) ||
+                        (op == CMP_OP_GREATEREQ && da >= db) ||
+                        (op == CMP_OP_GREATER && da > db));
+  } else {
+    output[0] = jv_invalid_with_msg(jv_string_fmt("Attempted to compare order of %s wrt %s",
+                                                  jv_kind_name(jv_get_kind(a)),
+                                                  jv_kind_name(jv_get_kind(b))));
+    jv_free(a);
+    jv_free(b);
+  }
+}
+
+static void f_less(jv input[], jv output[]) {
+  order_cmp(input, output, CMP_OP_LESS);
+}
+
+static void f_greater(jv input[], jv output[]) {
+  order_cmp(input, output, CMP_OP_GREATER);
+}
+
+static void f_lesseq(jv input[], jv output[]) {
+  order_cmp(input, output, CMP_OP_LESSEQ);
+}
+
+static void f_greatereq(jv input[], jv output[]) {
+  order_cmp(input, output, CMP_OP_GREATEREQ);
+}
+
 static void f_tonumber(jv input[], jv output[]) {
   if (jv_get_kind(input[0]) == JV_KIND_NUMBER) {
     output[0] = input[0];
@@ -202,6 +244,10 @@ static struct cfunction function_list[] = {
   {f_tonumber, "tonumber", CALL_BUILTIN_1_1},
   {f_tostring, "tostring", CALL_BUILTIN_1_1},
   {f_equal, "_equal", CALL_BUILTIN_3_1},
+  {f_less, "_less", CALL_BUILTIN_3_1},
+  {f_greater, "_greater", CALL_BUILTIN_3_1},
+  {f_lesseq, "_lesseq", CALL_BUILTIN_3_1},
+  {f_greatereq, "_greatereq", CALL_BUILTIN_3_1},
   {f_length, "length", CALL_BUILTIN_1_1},
   {f_type, "type", CALL_BUILTIN_1_1},
   {f_add, "add", CALL_BUILTIN_1_1},
diff --git a/lexer.l b/lexer.l
index fe0049a9b658c4a10b6ed7104d2920b32b5bd2d0..a353d89bf2de3b1d6a7068f935e23350127db07e 100644 (file)
--- a/lexer.l
+++ b/lexer.l
@@ -48,7 +48,9 @@
 "*=" { return SETMULT; }
 "/=" { return SETDIV; }
 "//=" { return SETDEFINEDOR; }
-"."|"="|";"|","|":"|"|"|"+"|"-"|"*"|"/"|"\$" { return yytext[0];}
+"<=" { return LESSEQ; }
+">=" { return GREATEREQ; }
+"."|"="|";"|","|":"|"|"|"+"|"-"|"*"|"/"|"\$"|"<"|">" { return yytext[0];}
 
 "["|"{"|"(" {
   return enter(yytext[0], YY_START, yyscanner);
index 0fda65bdfb0d7358a11d1185c346b09974bc2826..94700aee173d61191717c80aa917158a1cda05a2 100644 (file)
--- a/parser.y
+++ b/parser.y
@@ -59,6 +59,8 @@
 %token SETMULT "*="
 %token SETDIV "/="
 %token SETDEFINEDOR "//="
+%token LESSEQ "<="
+%token GREATEREQ ">="
 
 %token QQSTRING_START
 %token <literal> QQSTRING_TEXT
@@ -77,6 +79,7 @@
 %nonassoc EQ
 %left '+' '-'
 %left '*' '/'
+%right '<' '>' LESSEQ GREATEREQ
 
 
 %type <blk> Exp Term MkDict MkDictPair ExpD ElseBody QQString FuncDef FuncDefs
@@ -137,6 +140,10 @@ static block gen_binop(block a, block b, int op) {
   case '*': funcname = "_multiply"; break;
   case '/': funcname = "_divide"; break;
   case EQ: funcname = "_equal"; break;
+  case '<': funcname = "_less"; break;
+  case '>': funcname = "_greater"; break;
+  case LESSEQ: funcname = "_lesseq"; break;
+  case GREATEREQ: funcname = "_greatereq"; break;
   }
   assert(funcname);
 
@@ -273,6 +280,22 @@ Exp "==" Exp {
   $$ = gen_binop($1, $3, EQ);
 } |
 
+Exp '<' Exp {
+  $$ = gen_binop($1, $3, '<');
+} |
+
+Exp '>' Exp {
+  $$ = gen_binop($1, $3, '>');
+} |
+
+Exp "<=" Exp {
+  $$ = gen_binop($1, $3, LESSEQ);
+} |
+
+Exp ">=" Exp {
+  $$ = gen_binop($1, $3, GREATEREQ);
+} |
+
 QQSTRING_START QQString QQSTRING_END {
   $$ = $2;
 } |
index 307eaa6263cba25827165f1cced2925a793274e7..c37dee930403a4393dd845d0585731a1f6515bc1 100644 (file)
--- a/testdata
+++ b/testdata
@@ -348,3 +348,12 @@ def inc(x): x |= .+1; inc(.[].a)
 [.[] | not]
 [1,0,false,null,true,"hello"]
 [false,false,true,true,false,false]
+
+# Check numeric comparison binops
+[10 > 0, 10 > 10, 10 > 20, 10 < 0, 10 < 10, 10 < 20]
+{}
+[true,false,false,false,false,true]
+
+[10 >= 0, 10 >= 10, 10 >= 20, 10 <= 0, 10 <= 10, 10 <= 20]
+{}
+[true,true,false,false,true,true]
\ No newline at end of file