From 8e8fcf1dd73c785f6901cf53ce17380099d15bd1 Mon Sep 17 00:00:00 2001 From: nsfisis Date: Sun, 18 Jan 2026 00:49:33 +0900 Subject: implement pipe operator --- src/jq/compile.zig | 8 ++++++++ src/jq/execute.zig | 4 ++-- src/jq/parse.zig | 54 +++++++++++++++++++++++++++++++++++++----------------- src/root.zig | 11 +++++++++++ 4 files changed, 58 insertions(+), 19 deletions(-) (limited to 'src') 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; diff --git a/src/root.zig b/src/root.zig index e4df465..b89b54f 100644 --- a/src/root.zig +++ b/src/root.zig @@ -79,4 +79,15 @@ test "addition" { try testRun("579", allocator, "null", "123 + 456"); try testRun("35", allocator, "{\"a\":12,\"b\":23}", ".a + .b"); try testRun("12", allocator, "[1,2,3]", ".[1] + 10"); + try testRun("6", allocator, "null", "1 + 2 + 3"); +} + +test "pipe operator" { + 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\":{\"b\":123}}", ".a | .b"); + try testRun("584", allocator, "null", "123 + 456 | . + 5"); + try testRun("10", allocator, "null", "1 | . + 2 | . + 3 | . | 4 + ."); } -- cgit v1.3-1-g0d28