aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/jq
diff options
context:
space:
mode:
Diffstat (limited to 'src/jq')
-rw-r--r--src/jq/compile.zig99
-rw-r--r--src/jq/execute.zig37
-rw-r--r--src/jq/parse.zig12
3 files changed, 142 insertions, 6 deletions
diff --git a/src/jq/compile.zig b/src/jq/compile.zig
index 32e309a..043262e 100644
--- a/src/jq/compile.zig
+++ b/src/jq/compile.zig
@@ -9,7 +9,10 @@ pub const Opcode = enum {
nop,
ret,
jump,
+ jump_unless,
fork,
+ dup,
+ pop,
subexp_begin,
subexp_end,
index,
@@ -26,6 +29,8 @@ pub const Opcode = enum {
le,
ge,
@"const",
+ const_true,
+ const_false,
};
pub const Instr = union(Opcode) {
@@ -34,7 +39,10 @@ pub const Instr = union(Opcode) {
nop,
ret,
jump: usize,
+ jump_unless: usize,
fork: usize,
+ dup,
+ pop,
subexp_begin,
subexp_end,
index,
@@ -51,6 +59,8 @@ pub const Instr = union(Opcode) {
le,
ge,
@"const": ConstIndex,
+ const_true,
+ const_false,
pub fn op(self: Self) Opcode {
return self;
@@ -101,6 +111,95 @@ fn compileExpr(allocator: std.mem.Allocator, compile_allocator: std.mem.Allocato
};
try instrs.append(allocator, op_instr);
},
+ .and_expr => |and_expr| {
+ // DUP
+ // <lhs>
+ // JUMP_UNLESS l3
+ // POP
+ // <rhs>
+ // JUMP_UNLESS l1
+ // CONST_TRUE
+ // JUMP l2
+ // l1: CONST_FALSE
+ // l2: JUMP l4
+ // l3: POP
+ // CONST_FALSE
+ // l4:
+ const lhs_instrs = try compileExpr(allocator, compile_allocator, and_expr.lhs);
+ defer allocator.free(lhs_instrs);
+ const rhs_instrs = try compileExpr(allocator, compile_allocator, and_expr.rhs);
+ defer allocator.free(rhs_instrs);
+
+ try instrs.append(allocator, .dup);
+ try instrs.appendSlice(allocator, lhs_instrs);
+ const jump1_idx = instrs.items.len;
+ try instrs.append(allocator, .{ .jump_unless = 0 });
+ try instrs.append(allocator, .pop);
+ try instrs.appendSlice(allocator, rhs_instrs);
+ const jump2_idx = instrs.items.len;
+ try instrs.append(allocator, .{ .jump_unless = 0 });
+ try instrs.append(allocator, .const_true);
+ const jump3_idx = instrs.items.len;
+ try instrs.append(allocator, .{ .jump = 0 });
+ const l1 = instrs.items.len;
+ try instrs.append(allocator, .const_false);
+ const jump4_idx = instrs.items.len;
+ const l2 = instrs.items.len;
+ try instrs.append(allocator, .{ .jump = 0 });
+ const l3 = instrs.items.len;
+ try instrs.append(allocator, .pop);
+ try instrs.append(allocator, .const_false);
+ const l4 = instrs.items.len;
+
+ instrs.items[jump1_idx] = .{ .jump_unless = l3 - jump1_idx };
+ instrs.items[jump2_idx] = .{ .jump_unless = l1 - jump2_idx };
+ instrs.items[jump3_idx] = .{ .jump = l2 - jump3_idx };
+ instrs.items[jump4_idx] = .{ .jump = l4 - jump4_idx };
+ },
+ .or_expr => |or_expr| {
+ // DUP
+ // <lhs>
+ // JUMP_UNLESS l1
+ // POP
+ // CONST_TRUE
+ // JUMP l3
+ // l1: POP
+ // <rhs>
+ // JUMP_UNLESS l2
+ // CONST_TRUE
+ // JUMP l3
+ // l2: CONST_FALSE
+ // l3:
+ const lhs_instrs = try compileExpr(allocator, compile_allocator, or_expr.lhs);
+ defer allocator.free(lhs_instrs);
+ const rhs_instrs = try compileExpr(allocator, compile_allocator, or_expr.rhs);
+ defer allocator.free(rhs_instrs);
+
+ try instrs.append(allocator, .dup);
+ try instrs.appendSlice(allocator, lhs_instrs);
+ const jump1_idx = instrs.items.len;
+ try instrs.append(allocator, .{ .jump_unless = 0 });
+ try instrs.append(allocator, .pop);
+ try instrs.append(allocator, .const_true);
+ const jump2_idx = instrs.items.len;
+ try instrs.append(allocator, .{ .jump = 0 });
+ const l1 = instrs.items.len;
+ try instrs.append(allocator, .pop);
+ try instrs.appendSlice(allocator, rhs_instrs);
+ const jump3_idx = instrs.items.len;
+ try instrs.append(allocator, .{ .jump_unless = 0 });
+ try instrs.append(allocator, .const_true);
+ const jump4_idx = instrs.items.len;
+ try instrs.append(allocator, .{ .jump = 0 });
+ const l2 = instrs.items.len;
+ try instrs.append(allocator, .const_false);
+ const l3 = instrs.items.len;
+
+ instrs.items[jump1_idx] = .{ .jump_unless = l1 - jump1_idx };
+ instrs.items[jump2_idx] = .{ .jump = l3 - jump2_idx };
+ instrs.items[jump3_idx] = .{ .jump_unless = l2 - jump3_idx };
+ instrs.items[jump4_idx] = .{ .jump = l3 - jump4_idx };
+ },
.pipe => |pipe_expr| {
const lhs_instrs = try compileExpr(allocator, compile_allocator, pipe_expr.lhs);
defer allocator.free(lhs_instrs);
diff --git a/src/jq/execute.zig b/src/jq/execute.zig
index caf525a..b30bd3d 100644
--- a/src/jq/execute.zig
+++ b/src/jq/execute.zig
@@ -183,9 +183,34 @@ pub const Runtime = struct {
.jump => |offset| {
self.pc += offset - 1;
},
+ .jump_unless => |offset| {
+ std.debug.assert(self.values.ensureSize(1));
+
+ const value = self.values.pop();
+ const is_falsy = switch (value) {
+ .null => true,
+ .bool => |b| !b,
+ else => false,
+ };
+ if (is_falsy) {
+ self.pc += offset - 1;
+ }
+ // FIXME: optimize pop and push
+ try self.values.push(value);
+ },
.fork => |offset| {
try self.save_stack(self.pc + offset);
},
+ .dup => {
+ std.debug.assert(self.values.ensureSize(1));
+
+ try self.values.dup();
+ },
+ .pop => {
+ std.debug.assert(self.values.ensureSize(1));
+
+ _ = self.values.pop();
+ },
.subexp_begin => try self.values.dup(),
.subexp_end => try self.values.swap(),
.index => {
@@ -309,6 +334,18 @@ pub const Runtime = struct {
_ = self.values.pop();
try self.values.push(self.constants.items[@intFromEnum(idx)]);
},
+ .const_true => {
+ std.debug.assert(self.values.ensureSize(1));
+
+ _ = self.values.pop();
+ try self.values.push(.{ .bool = true });
+ },
+ .const_false => {
+ std.debug.assert(self.values.ensureSize(1));
+
+ _ = self.values.pop();
+ try self.values.push(.{ .bool = false });
+ },
}
}
diff --git a/src/jq/parse.zig b/src/jq/parse.zig
index 58c3722..1760875 100644
--- a/src/jq/parse.zig
+++ b/src/jq/parse.zig
@@ -14,6 +14,8 @@ pub const AstKind = enum {
index,
literal,
binary_expr,
+ or_expr,
+ and_expr,
pipe,
comma,
};
@@ -28,8 +30,6 @@ pub const BinaryOp = enum {
mul_assign,
div_assign,
mod_assign,
- @"or",
- @"and",
eq,
ne,
lt,
@@ -48,6 +48,8 @@ pub const Ast = union(AstKind) {
index: struct { base: *Ast, index: *Ast, is_optional: bool },
literal: ConstIndex,
binary_expr: struct { op: BinaryOp, lhs: *Ast, rhs: *Ast },
+ or_expr: struct { lhs: *Ast, rhs: *Ast },
+ and_expr: struct { lhs: *Ast, rhs: *Ast },
pipe: struct { lhs: *Ast, rhs: *Ast },
comma: struct { lhs: *Ast, rhs: *Ast },
@@ -202,8 +204,7 @@ const Parser = struct {
}
const rhs = try self.parseExpr4();
const ast = try self.parse_allocator.create(Ast);
- ast.* = .{ .binary_expr = .{
- .op = .@"or",
+ ast.* = .{ .or_expr = .{
.lhs = lhs,
.rhs = rhs,
} };
@@ -217,8 +218,7 @@ const Parser = struct {
}
const rhs = try self.parseExpr5();
const ast = try self.parse_allocator.create(Ast);
- ast.* = .{ .binary_expr = .{
- .op = .@"and",
+ ast.* = .{ .and_expr = .{
.lhs = lhs,
.rhs = rhs,
} };