diff options
| author | nsfisis <nsfisis@gmail.com> | 2026-01-17 18:52:57 +0900 |
|---|---|---|
| committer | nsfisis <nsfisis@gmail.com> | 2026-01-17 19:01:21 +0900 |
| commit | 419a606657f4186ab243ed22d35ae173fa6ebaa6 (patch) | |
| tree | f46e5b4dad7378937a200c4d2adfaaa7fb4ab63b /src/jq/parse.zig | |
| parent | 22a5d1617e79f176ecfca22d6c72be215f0da8b6 (diff) | |
| download | zgjq-419a606657f4186ab243ed22d35ae173fa6ebaa6.tar.gz zgjq-419a606657f4186ab243ed22d35ae173fa6ebaa6.tar.zst zgjq-419a606657f4186ab243ed22d35ae173fa6ebaa6.zip | |
refactor parse()
Diffstat (limited to 'src/jq/parse.zig')
| -rw-r--r-- | src/jq/parse.zig | 139 |
1 files changed, 88 insertions, 51 deletions
diff --git a/src/jq/parse.zig b/src/jq/parse.zig index dc9f6b9..7ceda69 100644 --- a/src/jq/parse.zig +++ b/src/jq/parse.zig @@ -1,6 +1,7 @@ const std = @import("std"); const jv = @import("../jv.zig"); const Token = @import("./tokenize.zig").Token; +const TokenKind = @import("./tokenize.zig").TokenKind; pub const ParseError = error{ UnexpectedEnd, @@ -25,73 +26,109 @@ pub const Ast = union(AstKind) { } }; -pub fn parse(allocator: std.mem.Allocator, tokens: []const Token) !*Ast { - if (tokens.len < 2) { - return error.InvalidQuery; +pub const TokenStream = struct { + const Self = @This(); + + tokens: []const Token, + current_position: usize, + + pub fn init(tokens: []const Token) Self { + return .{ + .tokens = tokens, + .current_position = 0, + }; } - var i: usize = 0; - const t1 = tokens[i]; - if (t1.kind() != .dot) { - return error.InvalidQuery; + pub fn next(self: *Self) ParseError!Token { + if (self.current_position >= self.tokens.len) { + return error.UnexpectedEnd; + } + const token = self.tokens[self.current_position]; + self.current_position += 1; + return token; } - i += 1; - const t2 = tokens[i]; - if (t2.kind() == .end) { - const root = try allocator.create(Ast); - root.* = .identity; - return root; + pub fn peek(self: *Self) ParseError!Token { + if (self.current_position >= self.tokens.len) { + return error.UnexpectedEnd; + } + return self.tokens[self.current_position]; } - if (t2.kind() == .identifier) { - i += 1; - const t3 = tokens[i]; - if (t3.kind() != .end) { + pub fn expect(self: *Self, expected: TokenKind) ParseError!Token { + const token = try self.next(); + if (token.kind() != expected) { return error.InvalidQuery; } - const root = try allocator.create(Ast); - root.* = .{ - .object_key = t2.identifier, - }; - return root; + return token; } +}; - if (t2.kind() != .bracket_left) { - return error.InvalidQuery; - } +pub fn parse(allocator: std.mem.Allocator, tokens: []const Token) !*Ast { + var token_stream = TokenStream.init(tokens); + return parseQuery(allocator, &token_stream); +} - i += 1; - if (tokens.len < 5) { - return error.UnexpectedEnd; - } - const t3 = tokens[i]; - i += 1; - const t4 = tokens[i]; - i += 1; - const t5 = tokens[i]; +// GRAMMAR +// query := filter +fn parseQuery(allocator: std.mem.Allocator, tokens: *TokenStream) !*Ast { + const result = try parseFilter(allocator, tokens); + _ = try tokens.expect(.end); + return result; +} + +// GRAMMAR +// filter := "." accessor? +fn parseFilter(allocator: std.mem.Allocator, tokens: *TokenStream) !*Ast { + _ = try tokens.expect(.dot); + + const next_token = try tokens.peek(); - if (t3.kind() != .number) { - return error.InvalidQuery; + if (next_token.kind() == .end) { + const ast = try allocator.create(Ast); + ast.* = .identity; + return ast; } - if (t4.kind() != .bracket_right) { - return error.InvalidQuery; + + return parseAccessor(allocator, tokens); +} + +// GRAMMAR +// accessor := field_access | index_access +fn parseAccessor(allocator: std.mem.Allocator, tokens: *TokenStream) !*Ast { + const token = try tokens.peek(); + + if (token.kind() == .identifier) { + return parseFieldAccess(allocator, tokens); } - if (t5.kind() != .end) { - return error.InvalidQuery; + if (token.kind() == .bracket_left) { + return parseIndexAccess(allocator, tokens); } + return error.InvalidQuery; +} + +// GRAMMAR +// field_access := IDENTIFIER +fn parseFieldAccess(allocator: std.mem.Allocator, tokens: *TokenStream) !*Ast { + const token = try tokens.expect(.identifier); + const ast = try allocator.create(Ast); + ast.* = .{ .object_key = token.identifier }; + return ast; +} + +// GRAMMAR +// index_access := "[" NUMBER "]" +fn parseIndexAccess(allocator: std.mem.Allocator, tokens: *TokenStream) !*Ast { + _ = try tokens.expect(.bracket_left); + const index_token = try tokens.expect(.number); + _ = try tokens.expect(.bracket_right); + const index_value = try allocator.create(jv.Value); - index_value.* = .{ - .integer = t3.number, - }; + index_value.* = .{ .integer = index_token.number }; const index_node = try allocator.create(Ast); - index_node.* = .{ - .literal = index_value, - }; - const root = try allocator.create(Ast); - root.* = .{ - .array_index = index_node, - }; - return root; + index_node.* = .{ .literal = index_value }; + const ast = try allocator.create(Ast); + ast.* = .{ .array_index = index_node }; + return ast; } |
