summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorNicolas Williams <nico@cryptonector.com>2013-06-17 20:21:37 -0500
committerNicolas Williams <nico@cryptonector.com>2013-06-21 15:27:34 -0500
commit3403d07912ceb49aff1402ba5b23ecc5f893d608 (patch)
treef9ebc57dc0b903f8742b2f2b559fa08e1c4b8d80
parentdc2fe63e42341d1d34cc8e36694b98b9dda16c52 (diff)
Add mod (and setmod) operators
-rw-r--r--builtin.c10
-rw-r--r--lexer.l3
-rw-r--r--parser.y14
-rw-r--r--tests/all.test15
4 files changed, 38 insertions, 4 deletions
diff --git a/builtin.c b/builtin.c
index a2adb1ac..96f6ef42 100644
--- 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 96c0efc4..16d0505b 100644
--- 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);
diff --git a/parser.y b/parser.y
index 4ec10383..8d3be642 100644
--- 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);
} |
diff --git a/tests/all.test b/tests/all.test
index 122b9a61..a9efff0b 100644
--- a/tests/all.test
+++ b/tests/all.test
@@ -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}