From 53ded53c8f3f8e06a8e75afdf81ad62d389d1311 Mon Sep 17 00:00:00 2001 From: Meghan Date: Sat, 14 Nov 2020 02:11:27 -0800 Subject: [PATCH] zig: add util/yaml --- src/util/yaml.zig | 236 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 236 insertions(+) create mode 100644 src/util/yaml.zig diff --git a/src/util/yaml.zig b/src/util/yaml.zig new file mode 100644 index 0000000000000000000000000000000000000000..8eb6ce931b51661358c6caa2c474399c98bbcbc0 --- /dev/null +++ b/src/util/yaml.zig @@ -0,0 +1,236 @@ +const std = @import("std"); + +const c = @import("./c.zig"); +const u = @import("./index.zig"); + +// +// + +const Array = [][]const u8; + +pub const Document = struct { + mapping: Mapping, +}; + +pub const Item = union(enum) { + event: c.yaml_event_t, + kv: Key, + mapping: Mapping, + sequence: []Item, + document: Document, +}; + +pub const Key = struct { + key: []const u8, + value: Value, +}; + +pub const Value = union(enum) { + string: []const u8, + mapping: Mapping, + sequence: []Item, +}; + +pub const Mapping = struct { + items: []Key, + + pub fn get(self: Mapping, k: []const u8) ?Value { + for (self.items) |item| { + if (std.mem.eql(u8, item.key, k)) { + return item.value; + } + } + return null; + } +}; + +// +// + +pub fn parse(alloc: *std.mem.Allocator, input: []const u8) !Document { + + var parser: c.yaml_parser_t = undefined; + _ = c.yaml_parser_initialize(&parser); + + const lines = try u.split(input, "\n"); + + _ = c.yaml_parser_set_input_string(&parser, input.ptr, input.len); + + var all_events = std.ArrayList(Item).init(alloc); + var event: c.yaml_event_t = undefined; + while (true) { + const p = c.yaml_parser_parse(&parser, &event); + if (p == 0) { + break; + } + + const et = @enumToInt(event.type); + try all_events.append(.{.event = event}); + c.yaml_event_delete(&event); + + if (et == c.YAML_STREAM_END_EVENT) { + break; + } + } + + c.yaml_parser_delete(&parser); + + var l: usize = all_events.items.len; + while (true) { + try condense_event_list(&all_events, lines); + if (l == all_events.items.len) { + break; + } + l = all_events.items.len; + } + + std.debug.assert(all_events.items.len == 1); + return all_events.items[0].document; +} + +fn get_event_string(event: c.yaml_event_t, lines: Array) []const u8 { + const sm = event.start_mark; + const em = event.end_mark; + return lines[sm.line][sm.column..em.column]; +} + +fn condense_event_list(list: *std.ArrayList(Item), lines: Array) !void { + var i: usize = 0; + var new_list = std.ArrayList(Item).init(list.allocator); + + while (i < list.items.len) : (i += 1) { + if (try condense_event_list_key(list.items, i, &new_list, lines)) |len| { + i += len; + continue; + } + if (try condense_event_list_mapping(list.items, i, &new_list, lines)) |len| { + i += len; + continue; + } + if (try condense_event_list_sequence(list.items, i, &new_list, lines)) |len| { + i += len; + continue; + } + if (try condense_event_list_document(list.items, i, &new_list, lines)) |len| { + i += len; + continue; + } + try new_list.append(list.items[i]); + } + + list.* = new_list; +} + +fn condense_event_list_key(from: []Item, at: usize, to: *std.ArrayList(Item), lines: Array) !?usize { + if (at >= from.len-1) { + return null; + } + const t = from[at]; + const n = from[at+1]; + + if (!(t == .event and @enumToInt(t.event.type) == c.YAML_SCALAR_EVENT)) { + return null; + } + if (n == .event and @enumToInt(n.event.type) == c.YAML_SCALAR_EVENT) { + try to.append(Item{ + .kv = Key{ + .key = get_event_string(t.event, lines), + .value = Value{ .string = get_event_string(n.event, lines) }, + }, + }); + return 0+2-1; + } + if (n == .sequence) { + try to.append(Item{ + .kv = Key{ + .key = get_event_string(t.event, lines), + .value = Value{ .sequence = n.sequence }, + }, + }); + return 0+2-1; + } + return null; +} + +fn condense_event_list_mapping(from: []Item, at: usize, to: *std.ArrayList(Item), lines: Array) !?usize { + if (!(from[at] == .event and @enumToInt(from[at].event.type) == c.YAML_MAPPING_START_EVENT)) { + return null; + } + var i: usize = 1; + while (true) : (i += 1) { + const ele = from[at+i]; + if (ele == .event and @enumToInt(ele.event.type) == c.YAML_MAPPING_END_EVENT) { + break; + } + if (ele == .event) { + return null; + } + } + + const keys = &std.ArrayList(Key).init(to.allocator); + for (from[at+1..at+i]) |item| { + switch (item) { + .kv => { + try keys.append(item.kv); + }, + else => unreachable, + } + } + + try to.append(Item{ + .mapping = Mapping{ .items = keys.items }, + }); + return 0+i; +} + +fn condense_event_list_sequence(from: []Item, at: usize, to: *std.ArrayList(Item), lines: Array) !?usize { + if (!(from[at] == .event and @enumToInt(from[at].event.type) == c.YAML_SEQUENCE_START_EVENT)) { + return null; + } + var i: usize = 1; + while (true) : (i += 1) { + const ele = from[at+i]; + if (ele == .event and @enumToInt(ele.event.type) == c.YAML_SEQUENCE_END_EVENT) { + break; + } + if (ele == .event) { + return null; + } + } + + const result = from[at+1..at+i]; + for (result) |item| { + std.debug.assert(item == .mapping); + } + try to.append(Item{ + .sequence = result, + }); + return 0+i; +} + +fn condense_event_list_document(from: []Item, at: usize, to: *std.ArrayList(Item), lines: Array) !?usize { + if (from.len < at+4) { + return null; + } + if (!(from[at] == .event and @enumToInt(from[at].event.type) == c.YAML_STREAM_START_EVENT)) { + return null; + } + if (!(from[at+1] == .event and @enumToInt(from[at+1].event.type) == c.YAML_DOCUMENT_START_EVENT)) { + return null; + } + if (!(from[at+2] == .mapping)) { + return null; + } + if (!(from[at+3] == .event and @enumToInt(from[at+3].event.type) == c.YAML_DOCUMENT_END_EVENT)) { + return null; + } + if (!(from[at+4] == .event and @enumToInt(from[at+4].event.type) == c.YAML_STREAM_END_EVENT)) { + return null; + } + try to.append(Item{ + .document = Document{ + .mapping = from[at+2].mapping, + }, + }); + return 0+5-1; +} -- 2.54.0