aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/jq/parse.zig
diff options
context:
space:
mode:
authornsfisis <nsfisis@gmail.com>2026-01-25 20:27:34 +0900
committernsfisis <nsfisis@gmail.com>2026-01-25 20:27:34 +0900
commit797ceeaa2b01070cf31c8d24ce440b8ee5feff7f (patch)
tree0c2bf8c3517f7512645f41acbca0dbf206b7c1b8 /src/jq/parse.zig
parent8b8bc79d647285a170aa928ff31a0989c9ef6e33 (diff)
downloadzgjq-797ceeaa2b01070cf31c8d24ce440b8ee5feff7f.tar.gz
zgjq-797ceeaa2b01070cf31c8d24ce440b8ee5feff7f.tar.zst
zgjq-797ceeaa2b01070cf31c8d24ce440b8ee5feff7f.zip
implement optional index access
Diffstat (limited to 'src/jq/parse.zig')
-rw-r--r--src/jq/parse.zig23
1 files changed, 20 insertions, 3 deletions
diff --git a/src/jq/parse.zig b/src/jq/parse.zig
index b257567..10a4ce9 100644
--- a/src/jq/parse.zig
+++ b/src/jq/parse.zig
@@ -45,7 +45,7 @@ pub const BinaryOp = enum {
pub const Ast = union(AstKind) {
identity,
- index: struct { base: *Ast, index: *Ast },
+ index: struct { base: *Ast, index: *Ast, is_optional: bool },
literal: ConstIndex,
binary_expr: struct { op: BinaryOp, lhs: *Ast, rhs: *Ast },
pipe: struct { lhs: *Ast, rhs: *Ast },
@@ -388,6 +388,14 @@ const Parser = struct {
},
.field => |name| {
_ = try self.tokens.next();
+ const is_optional = blk: {
+ const token = self.tokens.peek() catch break :blk false;
+ if (token.kind() == .question) {
+ _ = try self.tokens.next();
+ break :blk true;
+ }
+ break :blk false;
+ };
const base_ast = try self.parse_allocator.create(Ast);
base_ast.* = .identity;
try self.constants.append(self.allocator, .{ .string = try self.allocator.dupe(u8, name) });
@@ -395,7 +403,7 @@ const Parser = struct {
const key_ast = try self.parse_allocator.create(Ast);
key_ast.* = .{ .literal = idx };
const ast = try self.parse_allocator.create(Ast);
- ast.* = .{ .index = .{ .base = base_ast, .index = key_ast } };
+ ast.* = .{ .index = .{ .base = base_ast, .index = key_ast, .is_optional = is_optional } };
return ast;
},
else => return error.InvalidQuery,
@@ -407,13 +415,22 @@ const Parser = struct {
const index_token = try self.tokens.expect(.number);
_ = try self.tokens.expect(.bracket_right);
+ const is_optional = blk: {
+ const token = self.tokens.peek() catch break :blk false;
+ if (token.kind() == .question) {
+ _ = try self.tokens.next();
+ break :blk true;
+ }
+ break :blk false;
+ };
+
try self.constants.append(self.allocator, .{ .integer = @intFromFloat(index_token.number) });
const idx: ConstIndex = @enumFromInt(self.constants.items.len - 1);
const index_node = try self.parse_allocator.create(Ast);
index_node.* = .{ .literal = idx };
const ast = try self.parse_allocator.create(Ast);
- ast.* = .{ .index = .{ .base = base, .index = index_node } };
+ ast.* = .{ .index = .{ .base = base, .index = index_node, .is_optional = is_optional } };
return ast;
}
};