authorgravatar for hello@nektro.netMeghan <hello@nektro.net> 2023-02-27 20:16:39 -08:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2023-02-27 20:16:39 -08:00
log4a984c27e0aa967070eae951d23ba51ef0737d3a
treec2434e79b33f68fe74b522940a82299e39f5248c
parentada783df8fa0cfb715e06d0076346279aebe74ee
signaturebadge-question-mark Signed by PGP key 4AEE18F83AFDEB23

Create yaml.zig


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

yaml.zig created+339
......@@ -0,0 +1,339 @@
1const std = @import("std");
2const string = []const u8;
3const extras = @import("extras");
4
5const c = @cImport({
6 @cInclude("yaml.h");
7});
8
9//
10//
11
12pub const Stream = struct {
13 docs: []const Document,
14};
15
16pub const Document = struct {
17 mapping: Mapping,
18};
19
20pub const Item = union(enum) {
21 event: Token,
22 kv: Key,
23 mapping: Mapping,
24 sequence: Sequence,
25 document: Document,
26 string: string,
27 stream: Stream,
28
29 pub fn format(self: Item, comptime fmt: string, options: std.fmt.FormatOptions, writer: anytype) @TypeOf(writer).Error!void {
30 _ = fmt;
31 _ = options;
32
33 try writer.writeAll("Item{");
34 switch (self) {
35 .event => {
36 // try std.fmt.format(writer, "{s}", .{@tagName(self.event.type)});
37 try std.fmt.format(writer, "event {d}", .{self.event});
38 },
39 .kv, .document, .stream => {
40 unreachable;
41 },
42 .mapping => {
43 try std.fmt.format(writer, "{}", .{self.mapping});
44 },
45 .sequence => {
46 try writer.writeAll("[ ");
47 for (self.sequence) |it| {
48 try std.fmt.format(writer, "{}, ", .{it});
49 }
50 try writer.writeAll("]");
51 },
52 .string => {
53 try std.fmt.format(writer, "{s}", .{self.string});
54 },
55 }
56 try writer.writeAll("}");
57 }
58};
59
60pub const Sequence = []const Item;
61
62pub const Key = struct {
63 key: string,
64 value: Value,
65};
66
67pub const Value = union(enum) {
68 string: string,
69 mapping: Mapping,
70 sequence: Sequence,
71
72 pub fn format(self: Value, comptime fmt: string, options: std.fmt.FormatOptions, writer: anytype) @TypeOf(writer).Error!void {
73 _ = fmt;
74 _ = options;
75
76 try writer.writeAll("Value{");
77 switch (self) {
78 .string => {
79 try std.fmt.format(writer, "{s}", .{self.string});
80 },
81 .mapping => {
82 try std.fmt.format(writer, "{}", .{self.mapping});
83 },
84 .sequence => {
85 try writer.writeAll("[ ");
86 for (self.sequence) |it| {
87 try std.fmt.format(writer, "{}, ", .{it});
88 }
89 try writer.writeAll("]");
90 },
91 }
92 try writer.writeAll("}");
93 }
94};
95
96pub const Mapping = struct {
97 items: []const Key,
98
99 pub fn get(self: Mapping, k: string) ?Value {
100 for (self.items) |item| {
101 if (std.mem.eql(u8, item.key, k)) {
102 return item.value;
103 }
104 }
105 return null;
106 }
107
108 pub fn getT(self: Mapping, k: string, comptime f: std.meta.FieldEnum(Value)) ?extras.FieldType(Value, f) {
109 for (self.items) |item| {
110 if (std.mem.eql(u8, item.key, k)) {
111 return @field(item.value, @tagName(f));
112 }
113 }
114 return null;
115 }
116
117 pub fn get_string(self: Mapping, k: string) string {
118 return if (self.get(k)) |v| v.string else "";
119 }
120
121 pub fn get_string_array(self: Mapping, alloc: std.mem.Allocator, k: string) ![]string {
122 var list = std.ArrayList(string).init(alloc);
123 defer list.deinit();
124 if (self.get(k)) |val| {
125 if (val == .sequence) {
126 for (val.sequence) |item| {
127 if (item != .string) {
128 continue;
129 }
130 try list.append(item.string);
131 }
132 }
133 }
134 return list.toOwnedSlice();
135 }
136
137 pub fn format(self: Mapping, comptime fmt: string, options: std.fmt.FormatOptions, writer: anytype) @TypeOf(writer).Error!void {
138 _ = fmt;
139 _ = options;
140
141 try writer.writeAll("{ ");
142 for (self.items) |it| {
143 try std.fmt.format(writer, "{s}: ", .{it.key});
144 try std.fmt.format(writer, "{}, ", .{it.value});
145 }
146 try writer.writeAll("}");
147 }
148};
149
150pub const Token = c.yaml_event_t;
151pub const TokenList = []const Token;
152
153//
154//
155
156pub fn parse(alloc: std.mem.Allocator, input: string) !Document {
157 var parser: c.yaml_parser_t = undefined;
158 _ = c.yaml_parser_initialize(&parser);
159 defer c.yaml_parser_delete(&parser);
160
161 const lines = try split(alloc, input, "\n");
162
163 _ = c.yaml_parser_set_input_string(&parser, input.ptr, input.len);
164
165 var all_events = std.ArrayList(Token).init(alloc);
166 var event: Token = undefined;
167 while (true) {
168 const p = c.yaml_parser_parse(&parser, &event);
169 if (p == 0) {
170 break;
171 }
172
173 const et = event.type;
174 try all_events.append(event);
175 c.yaml_event_delete(&event);
176
177 if (et == c.YAML_STREAM_END_EVENT) {
178 break;
179 }
180 }
181
182 const p = &Parser{
183 .alloc = alloc,
184 .tokens = all_events.items,
185 .lines = lines,
186 .index = 0,
187 };
188 const stream = try p.parse();
189 return stream.docs[0];
190}
191
192pub const Parser = struct {
193 alloc: std.mem.Allocator,
194 tokens: TokenList,
195 lines: []const string,
196 index: usize,
197
198 pub fn parse(self: *Parser) !Stream {
199 const item = try parse_item(self, null);
200 return item.stream;
201 }
202
203 fn next(self: *Parser) ?Token {
204 if (self.index >= self.tokens.len) {
205 return null;
206 }
207 defer self.index += 1;
208 return self.tokens[self.index];
209 }
210};
211
212pub const Error =
213 std.mem.Allocator.Error ||
214 error{YamlUnexpectedToken};
215
216fn parse_item(p: *Parser, start: ?Token) Error!Item {
217 const tok = start orelse p.next();
218 return switch (tok.?.type) {
219 c.YAML_STREAM_START_EVENT => Item{ .stream = try parse_stream(p) },
220 c.YAML_DOCUMENT_START_EVENT => Item{ .document = try parse_document(p) },
221 c.YAML_MAPPING_START_EVENT => Item{ .mapping = try parse_mapping(p) },
222 c.YAML_SEQUENCE_START_EVENT => Item{ .sequence = try parse_sequence(p) },
223 c.YAML_SCALAR_EVENT => Item{ .string = try get_event_string(tok.?, p) },
224 else => unreachable,
225 };
226}
227
228fn parse_stream(p: *Parser) Error!Stream {
229 var res = std.ArrayList(Document).init(p.alloc);
230 errdefer res.deinit();
231
232 while (true) {
233 const tok = p.next();
234 if (tok.?.type == c.YAML_STREAM_END_EVENT) {
235 return Stream{ .docs = try res.toOwnedSlice() };
236 }
237 if (tok.?.type != c.YAML_DOCUMENT_START_EVENT) {
238 return error.YamlUnexpectedToken;
239 }
240 const item = try parse_item(p, tok);
241 try res.append(item.document);
242 }
243}
244
245fn parse_document(p: *Parser) Error!Document {
246 const tok = p.next();
247 if (tok.?.type != c.YAML_MAPPING_START_EVENT) {
248 return error.YamlUnexpectedToken;
249 }
250 const item = try parse_item(p, tok);
251
252 if (p.next().?.type != c.YAML_DOCUMENT_END_EVENT) {
253 return error.YamlUnexpectedToken;
254 }
255 return Document{ .mapping = item.mapping };
256}
257
258fn parse_mapping(p: *Parser) Error!Mapping {
259 var res = std.ArrayList(Key).init(p.alloc);
260 errdefer res.deinit();
261
262 while (true) {
263 const tok = p.next();
264 if (tok.?.type == c.YAML_MAPPING_END_EVENT) {
265 return Mapping{ .items = try res.toOwnedSlice() };
266 }
267 if (tok.?.type != c.YAML_SCALAR_EVENT) {
268 return error.YamlUnexpectedToken;
269 }
270 try res.append(Key{
271 .key = try get_event_string(tok.?, p),
272 .value = try parse_value(p),
273 });
274 }
275}
276
277fn parse_value(p: *Parser) Error!Value {
278 const item = try parse_item(p, null);
279 return switch (item) {
280 .mapping => |x| Value{ .mapping = x },
281 .sequence => |x| Value{ .sequence = x },
282 .string => |x| Value{ .string = x },
283 else => unreachable,
284 };
285}
286
287fn parse_sequence(p: *Parser) Error!Sequence {
288 var res = std.ArrayList(Item).init(p.alloc);
289 errdefer res.deinit();
290
291 while (true) {
292 const tok = p.next();
293 if (tok.?.type == c.YAML_SEQUENCE_END_EVENT) {
294 return try res.toOwnedSlice();
295 }
296 try res.append(try parse_item(p, tok));
297 }
298}
299
300fn get_event_string(event: Token, p: *const Parser) !string {
301 const sm = event.start_mark;
302 const em = event.end_mark;
303 const lines = p.lines;
304 if (sm.line != em.line) {
305 const starter = lines[sm.line][sm.column..];
306 std.debug.assert(starter.len == 1);
307 switch (starter[0]) {
308 '|' => {
309 var list = std.ArrayList(u8).init(p.alloc);
310 errdefer list.deinit();
311 var i = sm.line + 1;
312 while (i <= em.line) : (i += 1) {
313 try list.appendSlice(std.mem.trimLeft(u8, lines[i], " "));
314 try list.append('\n');
315 }
316 return try list.toOwnedSlice();
317 },
318 else => @panic("TODO"),
319 }
320 }
321 const s = lines[sm.line][sm.column..em.column];
322 if (s.len < 2) return s;
323 if (s[0] == '"' and s[s.len - 1] == '"') return std.mem.trim(u8, s, "\"");
324 return s;
325}
326
327//
328//
329
330fn split(alloc: std.mem.Allocator, in: string, delim: string) ![]string {
331 var list = std.ArrayList(string).init(alloc);
332 errdefer list.deinit();
333
334 var iter = std.mem.split(u8, in, delim);
335 while (iter.next()) |str| {
336 try list.append(str);
337 }
338 return try list.toOwnedSlice();
339}