]> granicus.if.org Git - jq/commitdiff
Add mod (and setmod) operators
authorNicolas Williams <nico@cryptonector.com>
Tue, 18 Jun 2013 01:21:37 +0000 (20:21 -0500)
committerNicolas Williams <nico@cryptonector.com>
Fri, 21 Jun 2013 20:27:34 +0000 (15:27 -0500)
builtin.c
lexer.l
parser.y
tests/all.test

index a2adb1acf613a3915817db3366409da08e51c0d1..96f6ef428dc068bc590092cccc08a44a72083910 100644 (file)
--- a/builtin.c
+++ b/builtin.c
@@ -119,6 +119,15 @@ static jv f_divide(jv input, jv a, jv b) {
   }  
 }
 
+static jv f_mod(jv input, jv a, jv b) {
+  jv_free(input);
+  if (jv_get_kind(a) == JV_KIND_NUMBER && jv_get_kind(b) == JV_KIND_NUMBER) {
+    return jv_number((intmax_t)jv_number_value(a) % (intmax_t)jv_number_value(b));
+  } else {
+    return type_error2(a, b, "cannot be divided");
+  }  
+}
+
 static jv f_equal(jv input, jv a, jv b) {
   jv_free(input);
   return jv_bool(jv_equal(a, b));
@@ -476,6 +485,7 @@ static const struct cfunction function_list[] = {
   {(cfunction_ptr)f_minus, "_minus", 3},
   {(cfunction_ptr)f_multiply, "_multiply", 3},
   {(cfunction_ptr)f_divide, "_divide", 3},
+  {(cfunction_ptr)f_mod, "_mod", 3},
   {(cfunction_ptr)f_tonumber, "tonumber", 1},
   {(cfunction_ptr)f_tostring, "tostring", 1},
   {(cfunction_ptr)f_keys, "keys", 1},
diff --git a/lexer.l b/lexer.l
index 96c0efc407d3127e03b3a1b1466735b421864b25..16d0505bfef7ad1422a962da3e7e7cf317446db8 100644 (file)
--- a/lexer.l
+++ b/lexer.l
@@ -56,10 +56,11 @@ struct lexer_param;
 "-=" { return SETMINUS; }
 "*=" { return SETMULT; }
 "/=" { return SETDIV; }
+"%=" { return SETMOD; }
 "//=" { return SETDEFINEDOR; }
 "<=" { return LESSEQ; }
 ">=" { return GREATEREQ; }
-"."|"="|";"|","|":"|"|"|"+"|"-"|"*"|"/"|"\$"|"<"|">" { return yytext[0];}
+"."|"="|";"|","|":"|"|"|"+"|"-"|"*"|"/"|"%"|"\$"|"<"|">" { return yytext[0];}
 
 "["|"{"|"(" {
   return enter(yytext[0], YY_START, yyscanner);
index 4ec10383444e11f838ca0b463596b67b75ac06d6..8d3be642c13274b198edf295e0a0301f79c8b558 100644 (file)
--- a/parser.y
+++ b/parser.y
@@ -49,6 +49,7 @@ struct lexer_param;
 %token <literal> FIELD
 %token <literal> LITERAL
 %token <literal> FORMAT
+%token SETMOD "%="
 %token EQ "=="
 %token NEQ "!="
 %token DEFINEDOR "//"
@@ -82,12 +83,12 @@ struct lexer_param;
 %right '|'
 %left ','
 %right "//"
-%nonassoc '=' SETPIPE SETPLUS SETMINUS SETMULT SETDIV SETDEFINEDOR
+%nonassoc '=' SETPIPE SETPLUS SETMINUS SETMULT SETDIV SETMOD SETDEFINEDOR
 %left OR
 %left AND
 %nonassoc NEQ EQ '<' '>' LESSEQ GREATEREQ
 %left '+' '-'
-%left '*' '/'
+%left '*' '/' '%'
 
 
 %type <blk> Exp Term MkDict MkDictPair ExpD ElseBody QQString FuncDef FuncDefs String
@@ -153,6 +154,7 @@ static block gen_binop(block a, block b, int op) {
   case '-': funcname = "_minus"; break;
   case '*': funcname = "_multiply"; break;
   case '/': funcname = "_divide"; break;
+  case '%': funcname = "_mod"; break;
   case EQ: funcname = "_equal"; break;
   case NEQ: funcname = "_notequal"; break;
   case '<': funcname = "_less"; break;
@@ -295,10 +297,18 @@ Exp '/' Exp {
   $$ = gen_binop($1, $3, '/');
 } |
 
+Exp '%' Exp {
+  $$ = gen_binop($1, $3, '%');
+} |
+
 Exp "/=" Exp {
   $$ = gen_update($1, $3, '/');
 } |
 
+Exp SETMOD Exp {
+  $$ = gen_update($1, $3, '%');
+} |
+
 Exp "==" Exp {
   $$ = gen_binop($1, $3, EQ);
 } |
index 122b9a6178501f5f5ca80ad1145bfb344c3379b2..a9efff0bee7282517ebd5a723ac27ee111ed94b1 100644 (file)
@@ -289,6 +289,14 @@ null
 null
 [2, 8, 10, 14]
 
+25 % 7
+null
+4
+
+49732 % 472
+null
+172
+
 1 + tonumber + ("10" | tonumber)
 4
 15
@@ -452,12 +460,17 @@ null
 {"foo": 42}
 {"foo": 43}
 
-.[] += 2, .[] *= 2, .[] -= 2, .[] /= 2
+.[] += 2, .[] *= 2, .[] -= 2, .[] /= 2, .[] %=2
 [1,3,5]
 [3,5,7]
 [2,6,10]
 [-1,1,3]
 [0.5, 1.5, 2.5]
+[1,1,1]
+
+[.[] % 7]
+[-7,-6,-5,-4,-3,-2,-1,0,1,2,3,4,5,6,7]
+[0,-6,-5,-4,-3,-2,-1,0,1,2,3,4,5,6,0]
 
 .foo += .foo
 {"foo":2}