aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authornsfisis <nsfisis@gmail.com>2026-01-17 18:40:47 +0900
committernsfisis <nsfisis@gmail.com>2026-01-17 18:40:47 +0900
commit22a5d1617e79f176ecfca22d6c72be215f0da8b6 (patch)
tree4424a15f2e069aa27312a9e1885d8446ad12bea1
parentd4bacf19b56c21afc7f2f0b5efb244b072873119 (diff)
downloadzgjq-22a5d1617e79f176ecfca22d6c72be215f0da8b6.tar.gz
zgjq-22a5d1617e79f176ecfca22d6c72be215f0da8b6.tar.zst
zgjq-22a5d1617e79f176ecfca22d6c72be215f0da8b6.zip
implement object key access
-rw-r--r--src/jq/compile.zig3
-rw-r--r--src/jq/execute.zig13
-rw-r--r--src/jq/parse.zig15
-rw-r--r--src/root.zig12
4 files changed, 43 insertions, 0 deletions
diff --git a/src/jq/compile.zig b/src/jq/compile.zig
index ddb4be5..0c30a3d 100644
--- a/src/jq/compile.zig
+++ b/src/jq/compile.zig
@@ -5,12 +5,14 @@ const Ast = @import("./parse.zig").Ast;
pub const Opcode = enum {
nop,
array_index,
+ object_key,
literal,
};
pub const Instr = union(Opcode) {
nop,
array_index,
+ object_key: []const u8,
literal: *jv.Value,
pub fn op(self: @This()) Opcode {
@@ -29,6 +31,7 @@ pub fn compile(allocator: std.mem.Allocator, compile_allocator: std.mem.Allocato
try instrs.appendSlice(allocator, index_instrs);
try instrs.append(allocator, .array_index);
},
+ .object_key => |key| try instrs.append(allocator, .{ .object_key = key }),
.literal => |value| try instrs.append(allocator, .{ .literal = value }),
}
diff --git a/src/jq/execute.zig b/src/jq/execute.zig
index a07204a..8e9bbb0 100644
--- a/src/jq/execute.zig
+++ b/src/jq/execute.zig
@@ -66,6 +66,14 @@ const ValueStack = struct {
else => error.InvalidType,
};
}
+
+ pub fn popObject(self: *Self) ExecuteError!jv.Object {
+ const value = try self.pop();
+ return switch (value) {
+ .object => |o| o,
+ else => error.InvalidType,
+ };
+ }
};
pub fn execute(allocator: std.mem.Allocator, instrs: []const Instr, input: jv.Value) !jv.Value {
@@ -86,6 +94,11 @@ pub fn execute(allocator: std.mem.Allocator, instrs: []const Instr, input: jv.Va
const result = if (index < array.items.len) array.items[index] else .null;
try value_stack.push(result);
},
+ .object_key => |key| {
+ const obj = try value_stack.popObject();
+ const result = obj.get(key) orelse .null;
+ try value_stack.push(result);
+ },
.literal => |value| {
try value_stack.push(value.*);
},
diff --git a/src/jq/parse.zig b/src/jq/parse.zig
index 5269ef5..dc9f6b9 100644
--- a/src/jq/parse.zig
+++ b/src/jq/parse.zig
@@ -10,12 +10,14 @@ pub const ParseError = error{
pub const AstKind = enum {
identity,
array_index,
+ object_key,
literal,
};
pub const Ast = union(AstKind) {
identity,
array_index: *Ast,
+ object_key: []const u8,
literal: *jv.Value,
pub fn kind(self: @This()) AstKind {
@@ -42,6 +44,19 @@ pub fn parse(allocator: std.mem.Allocator, tokens: []const Token) !*Ast {
return root;
}
+ if (t2.kind() == .identifier) {
+ i += 1;
+ const t3 = tokens[i];
+ if (t3.kind() != .end) {
+ return error.InvalidQuery;
+ }
+ const root = try allocator.create(Ast);
+ root.* = .{
+ .object_key = t2.identifier,
+ };
+ return root;
+ }
+
if (t2.kind() != .bracket_left) {
return error.InvalidQuery;
}
diff --git a/src/root.zig b/src/root.zig
index fa48c7b..f75f062 100644
--- a/src/root.zig
+++ b/src/root.zig
@@ -58,3 +58,15 @@ test "array index filter" {
\\ 81,82,83,84,85,86,87,88,89,90,91,92,93,94,95,96,97,98,99,100]
, ".[100]");
}
+
+test "object key filter" {
+ var debug_allocator = std.heap.DebugAllocator(.{}).init;
+ defer std.debug.assert(debug_allocator.deinit() == .ok);
+ const allocator = debug_allocator.allocator();
+
+ try testRun("123", allocator, "{\"a\":123}", ".a");
+ try testRun("null", allocator, "{\"a\":123}", ".b");
+ try testRun("\"hello\"", allocator, "{\"foo\":\"hello\"}", ".foo");
+ try testRun("[1,2,3]", allocator, "{\"arr\":[1,2,3]}", ".arr");
+ try testRun("{\"bar\":true}", allocator, "{\"foo\":{\"bar\":true}}", ".foo");
+}