Your First Parser โ
What you'll learn โ
- The five calls every program makes: init, setLanguage, parse, inspect, deinit.
Complete example โ
zig
const std = @import("std");
const treesitter = @import("treesitter");
const grammar = treesitter.expression_language;
pub fn main() !void {
var gpa_state = std.heap.DebugAllocator(.{}).init;
defer _ = gpa_state.deinit();
var parser = treesitter.Parser.init(gpa_state.allocator());
defer parser.deinit();
try parser.setLanguage(grammar);
var tree = try parser.parseString("1 + 2 * 3");
defer tree.deinit();
const root = tree.rootNode();
std.debug.print("root: {s} [{d}, {d}]\n", .{ root.nodeType(), root.startByte(), root.endByte() });
std.debug.print("has error: {}\n", .{tree.hasError()});
std.debug.print("text: {s}\n", .{root.text()});
}This is examples/basic_parse.zig from the repository.
Expected output โ
text
root: program [0, 9]
has error: false
text: 1 + 2 * 3How it works โ
- Allocator once.
Parser.initis the only call that takes an allocator. The parser stores it and every derived object reuses it. - Language.
setLanguagevalidates the grammar's ABI version and loads its tables. Without it,parseStringreturnserror.NoLanguage. - Parse.
parseStringruns the lexer plus the LR engine and returns an owningTree. - Inspect.
rootNode()gives aNodeโ a small handle (tree pointer + index), not an allocation. - Cleanup. Each
deinitfrees exactly what its object owns: parser scratch, tree pool and source copy.
API used โ
Related guides โ
- Parsing Source for non-string inputs.
- Understanding Trees for reading the result.
