aboutsummaryrefslogtreecommitdiffhomepage
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/jq/parse.zig139
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;
}