authorgravatar for hello@nektro.netMeghan <hello@nektro.net> 2020-11-14 02:11:27 -08:00
committergravatar for hello@nektro.netMeghan <hello@nektro.net> 2020-11-14 02:11:27 -08:00
log53ded53c8f3f8e06a8e75afdf81ad62d389d1311
tree2ff7b7cd9ac613e819d0894c3529421acea39357
parent281e1b232cfdc1bff350751aed201b3889ad8e1a

zig: add util/yaml


1 files changed, 236 insertions(+), 0 deletions(-)

src/util/yaml.zig created+236
...@@ -0,0 +1,236 @@
1const std = @import("std");
2
3const c = @import("./c.zig");
4const u = @import("./index.zig");
5
6//
7//
8
9const Array = [][]const u8;
10
11pub const Document = struct {
12 mapping: Mapping,
13};
14
15pub const Item = union(enum) {
16 event: c.yaml_event_t,
17 kv: Key,
18 mapping: Mapping,
19 sequence: []Item,
20 document: Document,
21};
22
23pub const Key = struct {
24 key: []const u8,
25 value: Value,
26};
27
28pub const Value = union(enum) {
29 string: []const u8,
30 mapping: Mapping,
31 sequence: []Item,
32};
33
34pub const Mapping = struct {
35 items: []Key,
36
37 pub fn get(self: Mapping, k: []const u8) ?Value {
38 for (self.items) |item| {
39 if (std.mem.eql(u8, item.key, k)) {
40 return item.value;
41 }
42 }
43 return null;
44 }
45};
46
47//
48//
49
50pub fn parse(alloc: *std.mem.Allocator, input: []const u8) !Document {
51
52 var parser: c.yaml_parser_t = undefined;
53 _ = c.yaml_parser_initialize(&parser);
54
55 const lines = try u.split(input, "\n");
56
57 _ = c.yaml_parser_set_input_string(&parser, input.ptr, input.len);
58
59 var all_events = std.ArrayList(Item).init(alloc);
60 var event: c.yaml_event_t = undefined;
61 while (true) {
62 const p = c.yaml_parser_parse(&parser, &event);
63 if (p == 0) {
64 break;
65 }
66
67 const et = @enumToInt(event.type);
68 try all_events.append(.{.event = event});
69 c.yaml_event_delete(&event);
70
71 if (et == c.YAML_STREAM_END_EVENT) {
72 break;
73 }
74 }
75
76 c.yaml_parser_delete(&parser);
77
78 var l: usize = all_events.items.len;
79 while (true) {
80 try condense_event_list(&all_events, lines);
81 if (l == all_events.items.len) {
82 break;
83 }
84 l = all_events.items.len;
85 }
86
87 std.debug.assert(all_events.items.len == 1);
88 return all_events.items[0].document;
89}
90
91fn get_event_string(event: c.yaml_event_t, lines: Array) []const u8 {
92 const sm = event.start_mark;
93 const em = event.end_mark;
94 return lines[sm.line][sm.column..em.column];
95}
96
97fn condense_event_list(list: *std.ArrayList(Item), lines: Array) !void {
98 var i: usize = 0;
99 var new_list = std.ArrayList(Item).init(list.allocator);
100
101 while (i < list.items.len) : (i += 1) {
102 if (try condense_event_list_key(list.items, i, &new_list, lines)) |len| {
103 i += len;
104 continue;
105 }
106 if (try condense_event_list_mapping(list.items, i, &new_list, lines)) |len| {
107 i += len;
108 continue;
109 }
110 if (try condense_event_list_sequence(list.items, i, &new_list, lines)) |len| {
111 i += len;
112 continue;
113 }
114 if (try condense_event_list_document(list.items, i, &new_list, lines)) |len| {
115 i += len;
116 continue;
117 }
118 try new_list.append(list.items[i]);
119 }
120
121 list.* = new_list;
122}
123
124fn condense_event_list_key(from: []Item, at: usize, to: *std.ArrayList(Item), lines: Array) !?usize {
125 if (at >= from.len-1) {
126 return null;
127 }
128 const t = from[at];
129 const n = from[at+1];
130
131 if (!(t == .event and @enumToInt(t.event.type) == c.YAML_SCALAR_EVENT)) {
132 return null;
133 }
134 if (n == .event and @enumToInt(n.event.type) == c.YAML_SCALAR_EVENT) {
135 try to.append(Item{
136 .kv = Key{
137 .key = get_event_string(t.event, lines),
138 .value = Value{ .string = get_event_string(n.event, lines) },
139 },
140 });
141 return 0+2-1;
142 }
143 if (n == .sequence) {
144 try to.append(Item{
145 .kv = Key{
146 .key = get_event_string(t.event, lines),
147 .value = Value{ .sequence = n.sequence },
148 },
149 });
150 return 0+2-1;
151 }
152 return null;
153}
154
155fn condense_event_list_mapping(from: []Item, at: usize, to: *std.ArrayList(Item), lines: Array) !?usize {
156 if (!(from[at] == .event and @enumToInt(from[at].event.type) == c.YAML_MAPPING_START_EVENT)) {
157 return null;
158 }
159 var i: usize = 1;
160 while (true) : (i += 1) {
161 const ele = from[at+i];
162 if (ele == .event and @enumToInt(ele.event.type) == c.YAML_MAPPING_END_EVENT) {
163 break;
164 }
165 if (ele == .event) {
166 return null;
167 }
168 }
169
170 const keys = &std.ArrayList(Key).init(to.allocator);
171 for (from[at+1..at+i]) |item| {
172 switch (item) {
173 .kv => {
174 try keys.append(item.kv);
175 },
176 else => unreachable,
177 }
178 }
179
180 try to.append(Item{
181 .mapping = Mapping{ .items = keys.items },
182 });
183 return 0+i;
184}
185
186fn condense_event_list_sequence(from: []Item, at: usize, to: *std.ArrayList(Item), lines: Array) !?usize {
187 if (!(from[at] == .event and @enumToInt(from[at].event.type) == c.YAML_SEQUENCE_START_EVENT)) {
188 return null;
189 }
190 var i: usize = 1;
191 while (true) : (i += 1) {
192 const ele = from[at+i];
193 if (ele == .event and @enumToInt(ele.event.type) == c.YAML_SEQUENCE_END_EVENT) {
194 break;
195 }
196 if (ele == .event) {
197 return null;
198 }
199 }
200
201 const result = from[at+1..at+i];
202 for (result) |item| {
203 std.debug.assert(item == .mapping);
204 }
205 try to.append(Item{
206 .sequence = result,
207 });
208 return 0+i;
209}
210
211fn condense_event_list_document(from: []Item, at: usize, to: *std.ArrayList(Item), lines: Array) !?usize {
212 if (from.len < at+4) {
213 return null;
214 }
215 if (!(from[at] == .event and @enumToInt(from[at].event.type) == c.YAML_STREAM_START_EVENT)) {
216 return null;
217 }
218 if (!(from[at+1] == .event and @enumToInt(from[at+1].event.type) == c.YAML_DOCUMENT_START_EVENT)) {
219 return null;
220 }
221 if (!(from[at+2] == .mapping)) {
222 return null;
223 }
224 if (!(from[at+3] == .event and @enumToInt(from[at+3].event.type) == c.YAML_DOCUMENT_END_EVENT)) {
225 return null;
226 }
227 if (!(from[at+4] == .event and @enumToInt(from[at+4].event.type) == c.YAML_STREAM_END_EVENT)) {
228 return null;
229 }
230 try to.append(Item{
231 .document = Document{
232 .mapping = from[at+2].mapping,
233 },
234 });
235 return 0+5-1;
236}