aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--src/jq.zig15
-rw-r--r--src/jq/compile.zig12
-rw-r--r--src/jq/execute.zig42
-rw-r--r--src/jq/parse.zig42
-rw-r--r--src/root.zig24
5 files changed, 73 insertions, 62 deletions
diff --git a/src/jq.zig b/src/jq.zig
index cf29e78..fe31ae4 100644
--- a/src/jq.zig
+++ b/src/jq.zig
@@ -1,16 +1 @@
-pub const TokenizeError = @import("./jq/tokenize.zig").TokenizeError;
-pub const TokenKind = @import("./jq/tokenize.zig").TokenKind;
-pub const Token = @import("./jq/tokenize.zig").Token;
-pub const tokenize = @import("./jq/tokenize.zig").tokenize;
-
-pub const ParseError = @import("./jq/parse.zig").ParseError;
-pub const AstKind = @import("./jq/parse.zig").AstKind;
-pub const Ast = @import("./jq/parse.zig").Ast;
-pub const parse = @import("./jq/parse.zig").parse;
-
-pub const Opcode = @import("./jq/compile.zig").Opcode;
-pub const Instr = @import("./jq/compile.zig").Instr;
-pub const compile = @import("./jq/compile.zig").compile;
-
-pub const ExecuteError = @import("./jq/execute.zig").ExecuteError;
pub const Runtime = @import("./jq/execute.zig").Runtime;
diff --git a/src/jq/compile.zig b/src/jq/compile.zig
index 5719f9c..54563de 100644
--- a/src/jq/compile.zig
+++ b/src/jq/compile.zig
@@ -14,6 +14,8 @@ pub const Opcode = enum {
};
pub const Instr = union(Opcode) {
+ const Self = @This();
+
nop,
ret,
subexp_begin,
@@ -23,9 +25,17 @@ pub const Instr = union(Opcode) {
object_key: []const u8,
literal: *jv.Value,
- pub fn op(self: @This()) Opcode {
+ pub fn op(self: Self) Opcode {
return self;
}
+
+ pub fn deinit(self: Self, allocator: std.mem.Allocator) void {
+ switch (self) {
+ .object_key => |key| allocator.free(key),
+ .literal => |value| allocator.destroy(value),
+ else => {},
+ }
+ }
};
fn compileExpr(allocator: std.mem.Allocator, compile_allocator: std.mem.Allocator, ast: *const Ast) ![]Instr {
diff --git a/src/jq/execute.zig b/src/jq/execute.zig
index 3916d5b..82b6557 100644
--- a/src/jq/execute.zig
+++ b/src/jq/execute.zig
@@ -1,6 +1,9 @@
const std = @import("std");
const jv = @import("../jv.zig");
+const tokenize = @import("./tokenize.zig").tokenize;
+const parse = @import("./parse.zig").parse;
const Instr = @import("./compile.zig").Instr;
+const compile = @import("./compile.zig").compile;
pub const ExecuteError = error{
Unimplemented,
@@ -105,27 +108,52 @@ const ValueStack = struct {
pub const Runtime = struct {
const Self = @This();
+ allocator: std.mem.Allocator,
values: ValueStack,
instrs: []const Instr,
- input: jv.Value,
pc: usize,
- pub fn init(allocator: std.mem.Allocator, instrs: []const Instr, input: jv.Value) !Self {
- var self = Self{
+ pub fn init(allocator: std.mem.Allocator) !Self {
+ return .{
+ .allocator = allocator,
.values = try ValueStack.init(allocator),
- .instrs = instrs,
- .input = input,
+ .instrs = &[_]Instr{},
.pc = 0,
};
- try self.values.push(input);
- return self;
}
pub fn deinit(self: *Self) void {
+ for (self.instrs) |instr| {
+ instr.deinit(self.allocator);
+ }
+ self.allocator.free(self.instrs);
+
self.values.deinit();
}
+ pub fn compileFromReader(self: *Self, reader: *std.Io.Reader) !void {
+ std.debug.assert(self.instrs.len == 0);
+
+ var compile_allocator = std.heap.ArenaAllocator.init(self.allocator);
+ defer compile_allocator.deinit();
+ const tokens = try tokenize(compile_allocator.allocator(), reader);
+ const ast = try parse(self.allocator, compile_allocator.allocator(), tokens);
+ const instrs = try compile(self.allocator, compile_allocator.allocator(), ast);
+ self.instrs = instrs;
+ }
+
+ pub fn compileFromSlice(self: *Self, query: []const u8) !void {
+ var reader = std.Io.Reader.fixed(query);
+ return self.compileFromReader(&reader);
+ }
+
+ pub fn start(self: *Self, input: jv.Value) !void {
+ try self.values.push(input);
+ }
+
pub fn next(self: *Self) !?jv.Value {
+ std.debug.assert(self.instrs.len > 0);
+
while (self.pc < self.instrs.len) : (self.pc += 1) {
const cur = self.instrs[self.pc];
switch (cur) {
diff --git a/src/jq/parse.zig b/src/jq/parse.zig
index 26458f9..fa8b28a 100644
--- a/src/jq/parse.zig
+++ b/src/jq/parse.zig
@@ -72,21 +72,21 @@ pub const TokenStream = struct {
}
};
-pub fn parse(allocator: std.mem.Allocator, tokens: []const Token) !*Ast {
+pub fn parse(allocator: std.mem.Allocator, parse_allocator: std.mem.Allocator, tokens: []const Token) !*Ast {
var token_stream = TokenStream.init(tokens);
- return parseQuery(allocator, &token_stream);
+ return parseQuery(allocator, parse_allocator, &token_stream);
}
// GRAMMAR
// query := expr ("|" expr)*
-fn parseQuery(allocator: std.mem.Allocator, tokens: *TokenStream) !*Ast {
- var lhs = try parseExpr(allocator, tokens);
+fn parseQuery(allocator: std.mem.Allocator, parse_allocator: std.mem.Allocator, tokens: *TokenStream) !*Ast {
+ var lhs = try parseExpr(allocator, parse_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);
+ const rhs = try parseExpr(allocator, parse_allocator, tokens);
+ const ast = try parse_allocator.create(Ast);
ast.* = .{ .pipe = .{
.lhs = lhs,
.rhs = rhs,
@@ -102,14 +102,14 @@ fn parseQuery(allocator: std.mem.Allocator, tokens: *TokenStream) !*Ast {
// GRAMMAR
// expr := term ("+" term)*
-fn parseExpr(allocator: std.mem.Allocator, tokens: *TokenStream) !*Ast {
- var lhs = try parseTerm(allocator, tokens);
+fn parseExpr(allocator: std.mem.Allocator, parse_allocator: std.mem.Allocator, tokens: *TokenStream) !*Ast {
+ var lhs = try parseTerm(allocator, parse_allocator, tokens);
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);
+ const rhs = try parseTerm(allocator, parse_allocator, tokens);
+ const ast = try parse_allocator.create(Ast);
ast.* = .{ .binary_expr = .{
.op = .add,
.lhs = lhs,
@@ -128,13 +128,13 @@ fn parseExpr(allocator: std.mem.Allocator, tokens: *TokenStream) !*Ast {
// | "." field_access
// | "." index_access
// | NUMBER
-fn parseTerm(allocator: std.mem.Allocator, tokens: *TokenStream) !*Ast {
+fn parseTerm(allocator: std.mem.Allocator, parse_allocator: std.mem.Allocator, tokens: *TokenStream) !*Ast {
const first_token = try tokens.peek();
if (first_token.kind() == .number) {
_ = try tokens.next();
const number_value = try allocator.create(jv.Value);
number_value.* = .{ .integer = first_token.number };
- const number_node = try allocator.create(Ast);
+ const number_node = try parse_allocator.create(Ast);
number_node.* = .{ .literal = number_value };
return number_node;
}
@@ -144,15 +144,15 @@ fn parseTerm(allocator: std.mem.Allocator, tokens: *TokenStream) !*Ast {
const next_token = try tokens.peek();
switch (next_token.kind()) {
.end, .pipe, .plus => {
- const ast = try allocator.create(Ast);
+ const ast = try parse_allocator.create(Ast);
ast.* = .identity;
return ast;
},
.identifier => {
- return parseFieldAccess(allocator, tokens);
+ return parseFieldAccess(allocator, parse_allocator, tokens);
},
.bracket_left => {
- return parseIndexAccess(allocator, tokens);
+ return parseIndexAccess(allocator, parse_allocator, tokens);
},
else => return error.InvalidQuery,
}
@@ -160,25 +160,25 @@ fn parseTerm(allocator: std.mem.Allocator, tokens: *TokenStream) !*Ast {
// GRAMMAR
// field_access := IDENTIFIER
-fn parseFieldAccess(allocator: std.mem.Allocator, tokens: *TokenStream) !*Ast {
+fn parseFieldAccess(allocator: std.mem.Allocator, parse_allocator: std.mem.Allocator, tokens: *TokenStream) !*Ast {
const token = try tokens.expect(.identifier);
- const ast = try allocator.create(Ast);
- ast.* = .{ .object_key = token.identifier };
+ const ast = try parse_allocator.create(Ast);
+ ast.* = .{ .object_key = try allocator.dupe(u8, token.identifier) };
return ast;
}
// GRAMMAR
// index_access := "[" NUMBER "]"
-fn parseIndexAccess(allocator: std.mem.Allocator, tokens: *TokenStream) !*Ast {
+fn parseIndexAccess(allocator: std.mem.Allocator, parse_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 = index_token.number };
- const index_node = try allocator.create(Ast);
+ const index_node = try parse_allocator.create(Ast);
index_node.* = .{ .literal = index_value };
- const ast = try allocator.create(Ast);
+ const ast = try parse_allocator.create(Ast);
ast.* = .{ .array_index = index_node };
return ast;
}
diff --git a/src/root.zig b/src/root.zig
index 9c22deb..ccfd36d 100644
--- a/src/root.zig
+++ b/src/root.zig
@@ -3,40 +3,28 @@ pub const jq = @import("./jq.zig");
pub const jv = @import("./jv.zig");
pub fn run(allocator: std.mem.Allocator, input: []const u8, query: []const u8) ![]const u8 {
- var compile_allocator = std.heap.ArenaAllocator.init(allocator);
- defer compile_allocator.deinit();
- var reader = std.Io.Reader.fixed(query);
- const tokens = try jq.tokenize(compile_allocator.allocator(), &reader);
- const ast = try jq.parse(compile_allocator.allocator(), tokens);
- const instrs = try jq.compile(allocator, compile_allocator.allocator(), ast);
- defer allocator.free(instrs);
-
const parsed = try jv.parse(allocator, input);
defer parsed.deinit();
const json = parsed.value;
- var runtime = try jq.Runtime.init(allocator, instrs, json);
+ var runtime = try jq.Runtime.init(allocator);
defer runtime.deinit();
+ try runtime.compileFromSlice(query);
+ try runtime.start(json);
const result = try runtime.next() orelse return error.NoResult;
const output = try jv.stringify(allocator, result);
return output;
}
fn testRun(expected: []const u8, allocator: std.mem.Allocator, input: []const u8, query: []const u8) !void {
- var compile_allocator = std.heap.ArenaAllocator.init(allocator);
- defer compile_allocator.deinit();
- var reader = std.Io.Reader.fixed(query);
- const tokens = try jq.tokenize(compile_allocator.allocator(), &reader);
- const ast = try jq.parse(compile_allocator.allocator(), tokens);
- const instrs = try jq.compile(allocator, compile_allocator.allocator(), ast);
- defer allocator.free(instrs);
-
const parsed = try jv.parse(allocator, input);
defer parsed.deinit();
const json = parsed.value;
- var runtime = try jq.Runtime.init(allocator, instrs, json);
+ var runtime = try jq.Runtime.init(allocator);
defer runtime.deinit();
+ try runtime.compileFromSlice(query);
+ try runtime.start(json);
const result_value = try runtime.next() orelse return error.NoResult;
const result = try jv.stringify(allocator, result_value);