302 lines
9.7 KiB
Zig
302 lines
9.7 KiB
Zig
/// This file *MUST* be kept in sync with tree-sitter/lib/src/query.c
|
|
/// It exactly represents the C structures in memory and must produce
|
|
/// the exact same results as the C tree-sitter library version used.
|
|
///
|
|
/// Yes,... it is not a public API! Here be dragons!
|
|
///
|
|
const std = @import("std");
|
|
const Io = std.Io;
|
|
const cbor = @import("cbor");
|
|
const build_options = @import("build_options");
|
|
const treez = if (build_options.use_tree_sitter) @import("treez") else @import("treez_dummy.zig");
|
|
|
|
pub const Slice = extern struct {
|
|
offset: u32,
|
|
length: u32,
|
|
|
|
pub fn cborEncode(self: *const @This(), writer: *Io.Writer) !void {
|
|
return cbor.writeArray(writer, self.*);
|
|
}
|
|
|
|
pub fn cborExtract(self: *@This(), iter: *[]const u8) cbor.Error!bool {
|
|
return cbor.matchValue(iter, .{
|
|
cbor.extract(&self.offset),
|
|
cbor.extract(&self.length),
|
|
});
|
|
}
|
|
};
|
|
|
|
pub fn Array(T: type) type {
|
|
return extern struct {
|
|
contents: ?*T,
|
|
size: u32,
|
|
capacity: u32,
|
|
|
|
pub fn cborEncode(self: *const @This(), writer: *Io.Writer) !void {
|
|
if (self.contents) |contents| {
|
|
const arr: []T = @as([*]T, @ptrCast(contents))[0..self.size];
|
|
try cbor.writeValue(writer, arr);
|
|
return;
|
|
}
|
|
try cbor.writeValue(writer, null);
|
|
}
|
|
|
|
pub fn cborExtract(self: *@This(), iter: *[]const u8, allocator: std.mem.Allocator) cbor.Error!bool {
|
|
var iter_ = iter.*;
|
|
if (cbor.matchValue(&iter_, cbor.null_) catch false) {
|
|
iter.* = iter_;
|
|
self.contents = null;
|
|
self.size = 0;
|
|
self.capacity = 0;
|
|
return true;
|
|
}
|
|
|
|
if (T == u8) {
|
|
var arr: []const u8 = undefined;
|
|
if (try cbor.matchValue(iter, cbor.extract(&arr))) {
|
|
self.contents = @ptrCast(@constCast(arr.ptr));
|
|
self.size = @intCast(arr.len);
|
|
self.capacity = @intCast(arr.len);
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
var i: usize = 0;
|
|
var n = try cbor.decodeArrayHeader(iter);
|
|
var arr: []T = try allocator.alloc(T, n);
|
|
while (n > 0) : (n -= 1) {
|
|
if (comptime cbor.isExtractableAlloc(T)) {
|
|
if (!(cbor.matchValue(iter, cbor.extractAlloc(&arr[i], allocator)) catch return false))
|
|
return false;
|
|
} else {
|
|
if (!(cbor.matchValue(iter, cbor.extract(&arr[i])) catch return false))
|
|
return false;
|
|
}
|
|
i += 1;
|
|
}
|
|
self.contents = @ptrCast(@constCast(arr.ptr));
|
|
self.size = @intCast(arr.len);
|
|
self.capacity = @intCast(arr.len);
|
|
return true;
|
|
}
|
|
};
|
|
}
|
|
|
|
pub const SymbolTable = extern struct {
|
|
characters: Array(u8),
|
|
slices: Array(Slice),
|
|
|
|
pub fn cborEncode(self: *const @This(), writer: *Io.Writer) !void {
|
|
return cbor.writeArray(writer, self.*);
|
|
}
|
|
|
|
pub fn cborExtract(self: *@This(), iter: *[]const u8, allocator: std.mem.Allocator) cbor.Error!bool {
|
|
return cbor.matchValue(iter, .{
|
|
cbor.extractAlloc(&self.characters, allocator),
|
|
cbor.extractAlloc(&self.slices, allocator),
|
|
});
|
|
}
|
|
};
|
|
pub const CaptureQuantifiers = Array(u8);
|
|
pub const PatternEntry = extern struct {
|
|
step_index: u16,
|
|
pattern_index: u16,
|
|
is_rooted: bool,
|
|
|
|
pub fn cborEncode(self: *const @This(), writer: *Io.Writer) !void {
|
|
return cbor.writeArray(writer, self.*);
|
|
}
|
|
|
|
pub fn cborExtract(self: *@This(), iter: *[]const u8) cbor.Error!bool {
|
|
return cbor.matchValue(iter, .{
|
|
cbor.extract(&self.step_index),
|
|
cbor.extract(&self.pattern_index),
|
|
cbor.extract(&self.is_rooted),
|
|
});
|
|
}
|
|
};
|
|
pub const QueryPattern = extern struct {
|
|
steps: Slice,
|
|
predicate_steps: Slice,
|
|
start_byte: u32,
|
|
end_byte: u32,
|
|
is_non_local: bool,
|
|
|
|
pub fn cborEncode(self: *const @This(), writer: *Io.Writer) !void {
|
|
return cbor.writeArray(writer, self.*);
|
|
}
|
|
|
|
pub fn cborExtract(self: *@This(), iter: *[]const u8, allocator: std.mem.Allocator) cbor.Error!bool {
|
|
return cbor.matchValue(iter, .{
|
|
cbor.extractAlloc(&self.steps, allocator),
|
|
cbor.extractAlloc(&self.predicate_steps, allocator),
|
|
cbor.extract(&self.start_byte),
|
|
cbor.extract(&self.end_byte),
|
|
cbor.extract(&self.is_non_local),
|
|
});
|
|
}
|
|
};
|
|
pub const StepOffset = extern struct {
|
|
byte_offset: u32,
|
|
step_index: u16,
|
|
|
|
pub fn cborEncode(self: *const @This(), writer: *Io.Writer) !void {
|
|
return cbor.writeArray(writer, self.*);
|
|
}
|
|
|
|
pub fn cborExtract(self: *@This(), iter: *[]const u8) cbor.Error!bool {
|
|
return cbor.matchValue(iter, .{
|
|
cbor.extract(&self.byte_offset),
|
|
cbor.extract(&self.step_index),
|
|
});
|
|
}
|
|
};
|
|
|
|
pub const MAX_STEP_CAPTURE_COUNT = 3;
|
|
|
|
pub const TSSymbol = u16;
|
|
pub const TSFieldId = u16;
|
|
|
|
pub const QueryStep = extern struct {
|
|
symbol: TSSymbol,
|
|
supertype_symbol: TSSymbol,
|
|
field: TSFieldId,
|
|
capture_ids: [MAX_STEP_CAPTURE_COUNT]u16,
|
|
depth: u16,
|
|
alternative_index: u16,
|
|
negated_field_list_id: u16,
|
|
// is_named: u1,
|
|
// is_immediate: u1,
|
|
// is_last_child: u1,
|
|
// is_pass_through: u1,
|
|
// is_dead_end: u1,
|
|
// is_inside_alternation: u1,
|
|
// contains_captures: u1,
|
|
// root_pattern_guaranteed: u1,
|
|
flags8: u8,
|
|
// parent_pattern_guaranteed: u1,
|
|
// is_missing: u1,
|
|
flags16: u8,
|
|
|
|
pub fn cborEncode(self: *const @This(), writer: *Io.Writer) !void {
|
|
return cbor.writeArray(writer, self.*);
|
|
}
|
|
|
|
pub fn cborExtract(self: *@This(), iter: *[]const u8) cbor.Error!bool {
|
|
return cbor.matchValue(iter, .{
|
|
cbor.extract(&self.symbol),
|
|
cbor.extract(&self.supertype_symbol),
|
|
cbor.extract(&self.field),
|
|
cbor.extract(&self.capture_ids),
|
|
cbor.extract(&self.depth),
|
|
cbor.extract(&self.alternative_index),
|
|
cbor.extract(&self.negated_field_list_id),
|
|
cbor.extract(&self.flags8),
|
|
cbor.extract(&self.flags16),
|
|
});
|
|
}
|
|
};
|
|
|
|
pub const PredicateStep = extern struct {
|
|
pub const Type = enum(c_uint) {
|
|
done,
|
|
capture,
|
|
string,
|
|
};
|
|
|
|
type: Type,
|
|
value_id: u32,
|
|
|
|
pub fn cborEncode(self: *const @This(), writer: *Io.Writer) !void {
|
|
return cbor.writeArray(writer, self.*);
|
|
}
|
|
|
|
pub fn cborExtract(self: *@This(), iter: *[]const u8) cbor.Error!bool {
|
|
return cbor.matchValue(iter, .{
|
|
cbor.extract(&self.type),
|
|
cbor.extract(&self.value_id),
|
|
});
|
|
}
|
|
};
|
|
|
|
pub const TSQuery = extern struct {
|
|
captures: SymbolTable,
|
|
predicate_values: SymbolTable,
|
|
capture_quantifiers: Array(CaptureQuantifiers),
|
|
steps: Array(QueryStep),
|
|
pattern_map: Array(PatternEntry),
|
|
predicate_steps: Array(PredicateStep),
|
|
patterns: Array(QueryPattern),
|
|
step_offsets: Array(StepOffset),
|
|
negated_fields: Array(TSFieldId),
|
|
string_buffer: Array(u8),
|
|
repeat_symbols_with_rootless_patterns: Array(TSSymbol),
|
|
language: usize,
|
|
// language: ?*const treez.Language,
|
|
wildcard_root_pattern_count: u16,
|
|
|
|
pub fn cborEncode(self: *const @This(), writer: *Io.Writer) !void {
|
|
return cbor.writeArray(writer, self.*);
|
|
}
|
|
|
|
pub fn cborExtract(self: *@This(), iter: *[]const u8, allocator: std.mem.Allocator) cbor.Error!bool {
|
|
const result = cbor.matchValue(iter, .{
|
|
cbor.extractAlloc(&self.captures, allocator),
|
|
cbor.extractAlloc(&self.predicate_values, allocator),
|
|
cbor.extractAlloc(&self.capture_quantifiers, allocator),
|
|
cbor.extractAlloc(&self.steps, allocator),
|
|
cbor.extractAlloc(&self.pattern_map, allocator),
|
|
cbor.extractAlloc(&self.predicate_steps, allocator),
|
|
cbor.extractAlloc(&self.patterns, allocator),
|
|
cbor.extractAlloc(&self.step_offsets, allocator),
|
|
cbor.extractAlloc(&self.negated_fields, allocator),
|
|
cbor.extractAlloc(&self.string_buffer, allocator),
|
|
cbor.extractAlloc(&self.repeat_symbols_with_rootless_patterns, allocator),
|
|
cbor.extract(&self.language),
|
|
cbor.extract(&self.wildcard_root_pattern_count),
|
|
});
|
|
self.language = 0;
|
|
return result;
|
|
}
|
|
};
|
|
|
|
pub const SerializeError = error{OutOfMemory};
|
|
|
|
pub fn toCbor(query: *TSQuery, allocator: std.mem.Allocator) SerializeError![]const u8 {
|
|
var cb: Io.Writer.Allocating = .init(allocator);
|
|
defer cb.deinit();
|
|
cbor.writeValue(&cb.writer, query.*) catch return error.OutOfMemory;
|
|
return cb.toOwnedSlice();
|
|
}
|
|
|
|
pub const DeserializeError = error{
|
|
WriteFailed,
|
|
OutOfMemory,
|
|
IntegerTooLarge,
|
|
IntegerTooSmall,
|
|
InvalidType,
|
|
TooShort,
|
|
InvalidFloatType,
|
|
InvalidArrayType,
|
|
InvalidPIntType,
|
|
InvalidMapType,
|
|
InvalidUnion,
|
|
JsonIncompatibleType,
|
|
InvalidQueryCbor,
|
|
NotAnObject,
|
|
BadArrayAllocExtract,
|
|
};
|
|
|
|
pub fn fromCbor(cb: []const u8, allocator: std.mem.Allocator) DeserializeError!struct { *TSQuery, *std.heap.ArenaAllocator } {
|
|
var arena = try allocator.create(std.heap.ArenaAllocator);
|
|
errdefer allocator.destroy(arena);
|
|
arena.* = std.heap.ArenaAllocator.init(allocator);
|
|
errdefer arena.deinit();
|
|
const query = try arena.allocator().create(TSQuery);
|
|
query.* = undefined;
|
|
var iter: []const u8 = cb;
|
|
if (!try cbor.matchValue(&iter, cbor.extractAlloc(query, arena.allocator())))
|
|
return error.InvalidQueryCbor;
|
|
return .{ query, arena };
|
|
}
|