aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/jq
diff options
context:
space:
mode:
authornsfisis <nsfisis@gmail.com>2026-01-18 00:49:33 +0900
committernsfisis <nsfisis@gmail.com>2026-01-18 00:53:35 +0900
commit8e8fcf1dd73c785f6901cf53ce17380099d15bd1 (patch)
treee0bab2aaf525ad874ce013a3ace046ff224fc86a /src/jq
parent6739144edaf34d10e0c0901231b196f377007934 (diff)
downloadzgjq-8e8fcf1dd73c785f6901cf53ce17380099d15bd1.tar.gz
zgjq-8e8fcf1dd73c785f6901cf53ce17380099d15bd1.tar.zst
zgjq-8e8fcf1dd73c785f6901cf53ce17380099d15bd1.zip
implement pipe operator
Diffstat (limited to 'src/jq')
-rw-r--r--src/jq/compile.zig8
-rw-r--r--src/jq/execute.zig4
-rw-r--r--src/jq/parse.zig54
3 files changed, 47 insertions, 19 deletions
diff --git a/src/jq/compile.zig b/src/jq/compile.zig
index e3937c6..f4044c9 100644
--- a/src/jq/compile.zig
+++ b/src/jq/compile.zig
@@ -54,6 +54,14 @@ pub fn compile(allocator: std.mem.Allocator, compile_allocator: std.mem.Allocato
try instrs.append(allocator, .subexp_end);
try instrs.append(allocator, .add);
},
+ .pipe => |pipe_expr| {
+ const lhs_instrs = try compile(allocator, compile_allocator, pipe_expr.lhs);
+ defer allocator.free(lhs_instrs);
+ const rhs_instrs = try compile(allocator, compile_allocator, pipe_expr.rhs);
+ defer allocator.free(rhs_instrs);
+ try instrs.appendSlice(allocator, lhs_instrs);
+ try instrs.appendSlice(allocator, rhs_instrs);
+ },
}
return instrs.toOwnedSlice(allocator);
diff --git a/src/jq/execute.zig b/src/jq/execute.zig
index 29025b4..8982458 100644
--- a/src/jq/execute.zig
+++ b/src/jq/execute.zig
@@ -100,6 +100,8 @@ pub fn execute(allocator: std.mem.Allocator, instrs: []const Instr, input: jv.Va
const cur = instrs[pc];
switch (cur) {
.nop => {},
+ .subexp_begin => try value_stack.dup(),
+ .subexp_end => value_stack.swap(),
.array_index => {
const array = try value_stack.popArray();
const index: usize = @intCast(try value_stack.popInteger());
@@ -113,8 +115,6 @@ pub fn execute(allocator: std.mem.Allocator, instrs: []const Instr, input: jv.Va
const result = lhs + rhs;
try value_stack.push(.{ .integer = result });
},
- .subexp_begin => try value_stack.dup(),
- .subexp_end => value_stack.swap(),
.object_key => |key| {
const obj = try value_stack.popObject();
const result = obj.get(key) orelse .null;
diff --git a/src/jq/parse.zig b/src/jq/parse.zig
index 244d2a3..26458f9 100644
--- a/src/jq/parse.zig
+++ b/src/jq/parse.zig
@@ -14,6 +14,7 @@ pub const AstKind = enum {
object_key,
literal,
binary_expr,
+ pipe,
};
pub const BinaryOp = enum {
@@ -26,6 +27,7 @@ pub const Ast = union(AstKind) {
object_key: []const u8,
literal: *jv.Value,
binary_expr: struct { op: BinaryOp, lhs: *Ast, rhs: *Ast },
+ pipe: struct { lhs: *Ast, rhs: *Ast },
pub fn kind(self: @This()) AstKind {
return self;
@@ -76,29 +78,47 @@ pub fn parse(allocator: std.mem.Allocator, tokens: []const Token) !*Ast {
}
// GRAMMAR
-// query := expr
+// query := expr ("|" expr)*
fn parseQuery(allocator: std.mem.Allocator, tokens: *TokenStream) !*Ast {
- const result = try parseExpr(allocator, tokens);
+ var lhs = try parseExpr(allocator, tokens);
+ while (true) {
+ const token = try tokens.peek();
+ if (token.kind() == .pipe) {
+ _ = try tokens.next();
+ const rhs = try parseExpr(allocator, tokens);
+ const ast = try allocator.create(Ast);
+ ast.* = .{ .pipe = .{
+ .lhs = lhs,
+ .rhs = rhs,
+ } };
+ lhs = ast;
+ } else {
+ break;
+ }
+ }
_ = try tokens.expect(.end);
- return result;
+ return lhs;
}
// GRAMMAR
-// expr := term
-// | term + term
+// expr := term ("+" term)*
fn parseExpr(allocator: std.mem.Allocator, tokens: *TokenStream) !*Ast {
var lhs = try parseTerm(allocator, tokens);
- const token = try tokens.peek();
- if (token.kind() == .plus) {
- _ = try tokens.next();
- const rhs = try parseTerm(allocator, tokens);
- const ast = try allocator.create(Ast);
- ast.* = .{ .binary_expr = .{
- .op = .add,
- .lhs = lhs,
- .rhs = rhs,
- } };
- lhs = ast;
+ while (true) {
+ const token = try tokens.peek();
+ if (token.kind() == .plus) {
+ _ = try tokens.next();
+ const rhs = try parseTerm(allocator, tokens);
+ const ast = try allocator.create(Ast);
+ ast.* = .{ .binary_expr = .{
+ .op = .add,
+ .lhs = lhs,
+ .rhs = rhs,
+ } };
+ lhs = ast;
+ } else {
+ break;
+ }
}
return lhs;
}
@@ -123,7 +143,7 @@ fn parseTerm(allocator: std.mem.Allocator, tokens: *TokenStream) !*Ast {
const next_token = try tokens.peek();
switch (next_token.kind()) {
- .end => {
+ .end, .pipe, .plus => {
const ast = try allocator.create(Ast);
ast.* = .identity;
return ast;