lib/zen/src/footnote/parse.zig
daab053ee43316e1809a84551d573ddd1e5bf3d2
1 const std = @import("std");
2 const model = @import("model.zig");
3 const scan = @import("scan.zig");
4 const storage_mod = @import("storage.zig");
5
6 pub fn parse(storage: *storage_mod.Storage, source: []const u8) model.Error!model.Set {
7 const regions = try storage.acquire(source);
8 var definition_index: usize = 0;
9 var joined_text_index: usize = 0;
10 var current_index: ?usize = null;
11 var current_joined_start: ?usize = null;
12 var iterator = scan.Iterator.init(source);
13 while (iterator.next()) |event| switch (event) {
14 .definition => |definition| {
15 const active = findActive(regions.definitions[0..definition_index], definition.key) == null;
16 regions.definitions[definition_index] = .{
17 .key = definition.key,
18 .text = definition.text,
19 .active = active,
20 };
21 current_index = definition_index;
22 current_joined_start = null;
23 definition_index += 1;
24 },
25 .continuation => |text| {
26 const index = current_index orelse unreachable;
27 const definition = ®ions.definitions[index];
28 if (current_joined_start == null) {
29 current_joined_start = joined_text_index;
30 if (definition.text.len != 0) {
31 copy(regions.joined_text, &joined_text_index, definition.text);
32 regions.joined_text[joined_text_index] = ' ';
33 joined_text_index += 1;
34 }
35 } else {
36 regions.joined_text[joined_text_index] = ' ';
37 joined_text_index += 1;
38 }
39 copy(regions.joined_text, &joined_text_index, text);
40 definition.text = regions.joined_text[current_joined_start.?..joined_text_index];
41 },
42 };
43 std.debug.assert(definition_index == regions.plan.definitions);
44 std.debug.assert(joined_text_index == regions.plan.joined_text_bytes);
45 return .{ .definitions = regions.definitions };
46 }
47
48 fn findActive(definitions: []const model.Definition, key: []const u8) ?usize {
49 for (definitions, 0..) |definition, index| {
50 if (definition.active and std.mem.eql(u8, definition.key, key)) return index;
51 }
52 return null;
53 }
54
55 fn copy(destination: []u8, index: *usize, source: []const u8) void {
56 @memcpy(destination[index.*..][0..source.len], source);
57 index.* += source.len;
58 }