aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/jq/parse.zig
diff options
context:
space:
mode:
authornsfisis <nsfisis@gmail.com>2026-01-31 15:53:23 +0900
committernsfisis <nsfisis@gmail.com>2026-01-31 15:57:48 +0900
commit7712c1d10ec45349c1cd6e66281b7d602350065d (patch)
tree92208e7fb1955fd9847d91affa25ec096012ab9b /src/jq/parse.zig
parent617ddc62aa4d3153850362526069b85bfaf5e59e (diff)
downloadzgjq-7712c1d10ec45349c1cd6e66281b7d602350065d.tar.gz
zgjq-7712c1d10ec45349c1cd6e66281b7d602350065d.tar.zst
zgjq-7712c1d10ec45349c1cd6e66281b7d602350065d.zip
implement slice expression
Diffstat (limited to 'src/jq/parse.zig')
-rw-r--r--src/jq/parse.zig40
1 files changed, 36 insertions, 4 deletions
diff --git a/src/jq/parse.zig b/src/jq/parse.zig
index 6abd7c2..ad64824 100644
--- a/src/jq/parse.zig
+++ b/src/jq/parse.zig
@@ -12,6 +12,7 @@ pub const ParseError = error{
pub const AstKind = enum {
identity,
index,
+ slice,
literal,
binary_expr,
or_expr,
@@ -47,6 +48,7 @@ pub const BinaryOp = enum {
pub const Ast = union(AstKind) {
identity,
index: struct { base: *Ast, index: *Ast, is_optional: bool },
+ slice: struct { base: *Ast, from: ?*Ast, to: ?*Ast, is_optional: bool },
literal: ConstIndex,
binary_expr: struct { op: BinaryOp, lhs: *Ast, rhs: *Ast },
or_expr: struct { lhs: *Ast, rhs: *Ast },
@@ -397,13 +399,43 @@ const Parser = struct {
fn parseSuffix(self: *Self, base: *Ast) Error!*Ast {
_ = try self.tokens.expect(.bracket_left);
- const index_expr = try self.parseExpr();
- _ = try self.tokens.expect(.bracket_right);
- const is_optional = self.tokens.consumeIf(.question);
+ // Handle [:to] form.
+ if (self.tokens.consumeIf(.colon)) {
+ const to_expr = try self.parseQuery();
+ _ = try self.tokens.expect(.bracket_right);
+ const is_optional = self.tokens.consumeIf(.question);
+ const ast = try self.compile_allocator.create(Ast);
+ ast.* = .{ .slice = .{ .base = base, .from = null, .to = to_expr, .is_optional = is_optional } };
+ return ast;
+ }
+
+ const first_query = try self.parseQuery();
+ // Handle [from:to] or [from:] form.
+ if (self.tokens.consumeIf(.colon)) {
+ if (self.tokens.consumeIf(.bracket_right)) {
+ // [from:]
+ const is_optional = self.tokens.consumeIf(.question);
+ const ast = try self.compile_allocator.create(Ast);
+ ast.* = .{ .slice = .{ .base = base, .from = first_query, .to = null, .is_optional = is_optional } };
+ return ast;
+ } else {
+ // [from:to]
+ const to_expr = try self.parseQuery();
+ _ = try self.tokens.expect(.bracket_right);
+ const is_optional = self.tokens.consumeIf(.question);
+ const ast = try self.compile_allocator.create(Ast);
+ ast.* = .{ .slice = .{ .base = base, .from = first_query, .to = to_expr, .is_optional = is_optional } };
+ return ast;
+ }
+ }
+
+ // Handle [index] form.
+ _ = try self.tokens.expect(.bracket_right);
+ const is_optional = self.tokens.consumeIf(.question);
const ast = try self.compile_allocator.create(Ast);
- ast.* = .{ .index = .{ .base = base, .index = index_expr, .is_optional = is_optional } };
+ ast.* = .{ .index = .{ .base = base, .index = first_query, .is_optional = is_optional } };
return ast;
}
};