aboutsummaryrefslogtreecommitdiffhomepage
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/jq/compile.zig19
-rw-r--r--src/jq/execute.zig36
-rw-r--r--src/root.zig22
3 files changed, 75 insertions, 2 deletions
diff --git a/src/jq/compile.zig b/src/jq/compile.zig
index 40459c0..bb3a832 100644
--- a/src/jq/compile.zig
+++ b/src/jq/compile.zig
@@ -1,6 +1,7 @@
const std = @import("std");
const jv = @import("../jv.zig");
const Ast = @import("./parse.zig").Ast;
+const BinaryOp = @import("./parse.zig").BinaryOp;
pub const Opcode = enum {
nop,
@@ -11,6 +12,10 @@ pub const Opcode = enum {
subexp_end,
array_index,
add,
+ sub,
+ mul,
+ div,
+ mod,
object_key,
literal,
};
@@ -26,6 +31,10 @@ pub const Instr = union(Opcode) {
subexp_end,
array_index,
add,
+ sub,
+ mul,
+ div,
+ mod,
object_key: []const u8,
literal: *jv.Value,
@@ -68,7 +77,15 @@ fn compileExpr(allocator: std.mem.Allocator, compile_allocator: std.mem.Allocato
try instrs.append(allocator, .subexp_begin);
try instrs.appendSlice(allocator, lhs_instrs);
try instrs.append(allocator, .subexp_end);
- try instrs.append(allocator, .add);
+ const op_instr: Instr = switch (binary_expr.op) {
+ .add => .add,
+ .sub => .sub,
+ .mul => .mul,
+ .div => .div,
+ .mod => .mod,
+ else => return error.Unimplemented,
+ };
+ try instrs.append(allocator, op_instr);
},
.pipe => |pipe_expr| {
const lhs_instrs = try compileExpr(allocator, compile_allocator, pipe_expr.lhs);
diff --git a/src/jq/execute.zig b/src/jq/execute.zig
index 6d4f194..3c83d23 100644
--- a/src/jq/execute.zig
+++ b/src/jq/execute.zig
@@ -198,6 +198,42 @@ pub const Runtime = struct {
const result = lhs + rhs;
try self.values.push(.{ .integer = result });
},
+ .sub => {
+ std.debug.assert(self.values.ensureSize(3));
+
+ _ = self.values.pop();
+ const lhs = try self.values.popInteger();
+ const rhs = try self.values.popInteger();
+ const result = lhs - rhs;
+ try self.values.push(.{ .integer = result });
+ },
+ .mul => {
+ std.debug.assert(self.values.ensureSize(3));
+
+ _ = self.values.pop();
+ const lhs = try self.values.popInteger();
+ const rhs = try self.values.popInteger();
+ const result = lhs * rhs;
+ try self.values.push(.{ .integer = result });
+ },
+ .div => {
+ std.debug.assert(self.values.ensureSize(3));
+
+ _ = self.values.pop();
+ const lhs = try self.values.popInteger();
+ const rhs = try self.values.popInteger();
+ const result = @divTrunc(lhs, rhs);
+ try self.values.push(.{ .integer = result });
+ },
+ .mod => {
+ std.debug.assert(self.values.ensureSize(3));
+
+ _ = self.values.pop();
+ const lhs = try self.values.popInteger();
+ const rhs = try self.values.popInteger();
+ const result = @mod(lhs, rhs);
+ try self.values.push(.{ .integer = result });
+ },
.object_key => |key| {
std.debug.assert(self.values.ensureSize(1));
diff --git a/src/root.zig b/src/root.zig
index 0d2a3ce..782f078 100644
--- a/src/root.zig
+++ b/src/root.zig
@@ -76,11 +76,31 @@ test "object key filter" {
try testRun("{\"bar\":true}", "{\"foo\":{\"bar\":true}}", ".foo");
}
-test "addition" {
+test "arithmetic operations" {
try testRun("579", "null", "123 + 456");
try testRun("35", "{\"a\":12,\"b\":23}", ".a + .b");
try testRun("12", "[1,2,3]", ".[1] + 10");
try testRun("6", "null", "1 + 2 + 3");
+
+ try testRun("333", "null", "456 - 123");
+ try testRun("-11", "{\"a\":12,\"b\":23}", ".a - .b");
+ try testRun("-8", "[1,2,3]", ".[1] - 10");
+ try testRun("-4", "null", "1 - 2 - 3");
+
+ try testRun("56088", "null", "123 * 456");
+ try testRun("276", "{\"a\":12,\"b\":23}", ".a * .b");
+ try testRun("20", "[1,2,3]", ".[1] * 10");
+ try testRun("6", "null", "1 * 2 * 3");
+
+ try testRun("3", "null", "456 / 123");
+ try testRun("0", "{\"a\":12,\"b\":23}", ".a / .b");
+ try testRun("5", "[10,20,30]", ".[1] / 4");
+ try testRun("2", "null", "12 / 2 / 3");
+
+ try testRun("87", "null", "456 % 123");
+ try testRun("12", "{\"a\":12,\"b\":23}", ".a % .b");
+ try testRun("0", "[1,2,3]", ".[1] % 2");
+ try testRun("0", "null", "12 % 2 % 3");
}
test "pipe operator" {