diff --git a/Sources/main.swift b/Sources/main.swift index 127e086..d63cfc9 100644 --- a/Sources/main.swift +++ b/Sources/main.swift @@ -33,98 +33,63 @@ enum YamlItem { case boolean(Bool) case date(year: Int, month: Int, day: Int) case string(String) + case listItem(String) - private static let dateParser = Parse(input: Substring.self) { + private static let dateParser = Parse(input: Substring.UTF8View.self) { Digits(4) - "-" + "-".utf8 Digits(2) - "-" + "-".utf8 Digits(2) }.map { Self.date(year: $0.0, month: $0.1, day: $0.2) } - private static let booleanParser = Parse(input: Substring.self) { + private static let booleanParser = Parse(input: Substring.UTF8View.self) { Bool.parser() }.map { Self.boolean($0) } - private static let quotedString = Parse(input: Substring.self) { - "\"" - PrefixUpTo("\"") - "\"" + private static let quotedString = Parse(input: Substring.UTF8View.self) { + "\"".utf8 + PrefixUpTo("\"".utf8) + "\"".utf8 } - private static let stringParser = Parse(input: Substring.self) { + private static let stringParser = Parse(input: Substring.UTF8View.self) { OneOf { quotedString Rest() } - }.map { Self.string(String($0)) } + }.map { Self.string(String(Substring($0))) } + + private static let listItemParser = Parse(input: Substring.UTF8View.self) { + Skip { Whitespace() } + "- ".utf8 + Rest() + }.map { Self.listItem(String(Substring($0))) } static let parser = OneOf { dateParser booleanParser + listItemParser stringParser } } -enum YamlLine { - case keyValue(String, YamlItem) - case list(String, [String]) - - static let parser = OneOf { - listParser - keyValueParser - } - - static let keyParser = Parse(input: Substring.self) { - PrefixUpTo(":") - ":" - }.map(String.init) - - static let keyValueParser = Parse(input: Substring.self) { - PrefixUpTo(":").map(String.init) - ": " - YamlItem.parser - }.map { YamlLine.keyValue($0.0, $0.1) } - - static let listLineParser = Parse(input: Substring.self) { - Skip { PrefixThrough("- ") } - PrefixUpTo("\n").map(String.init) - "\n" - } - - static let listParser = Parse(input: Substring.self) { - PrefixUpTo(":\n").map(String.init) - ":\n" - Many { - Skip { PrefixThrough("- ") } - PrefixUpTo("\n").map(String.init) - "\n" - } - } - .map { YamlLine.list($0.0, $0.1) } -} - let yamlBlockParser = Parse(input: Substring.UTF8View.self) { "---\n".utf8 Many { - PrefixUpTo("\n".utf8) + PrefixUpTo(":".utf8) + ":".utf8 + Optionally { YamlItem.parser } + // PrefixUpTo("\n".utf8) // From(.substring) { YamlLine.parser } } separator: { "\n".utf8 + } terminator: { + // "\n".utf8 + "---".utf8 } - "\n".utf8 - "---".utf8 } -// let yamlLineParser = Parse(input: Substring.UTF8View.self) { -// PrefixUpTo(":".utf8).map(String.init) -// ":".utf8 -// OneOf { -// PrefixUpTo("\n".utf8) -// Rest() -// }.map(String.init) -// } - let stringLine = #"author: "Michael Housh""# // let parsedLine = try yamlLineParser.parse(stringLine[...].utf8) // print(parsedLine) @@ -140,19 +105,29 @@ try print(YamlItem.parser.parse(dateItem[...])) try print(YamlItem.parser.parse(boolItem[...])) let kvLine = "author: Michael Housh" -var listLine = """ -test: +var listLine = #""" - HVAC - General - Programming -"""[...] +"""#[...] -try print(YamlLine.parser.parse(kvLine[...])) -try print(YamlLine.parser.parse(&listLine)) -print(listLine) +struct YamlList: Parser { -// try print(YamlItem.parser.parse(listItem[...])) + var body: some Parser { + Many(into: [String]()) { array, string in + array.append(string) + } element: { + Whitespace() + "-".utf8 + Whitespace() + PrefixUpTo("\n".utf8).map(.string) + "\n".utf8 + } + } +} + +try print(YamlList().parse(listLine)) var yamlLines = """ author: Michael Housh @@ -163,28 +138,71 @@ test: """[...] -let lineParser = Many { - YamlLine.parser -} separator: { - "\n" +struct SimpleYamlValue: Parser { + enum Output: Equatable { + case array([String]) + case bool(Bool) + case date(year: Int, month: Int, day: Int) + case string(String) + } + + var body: some Parser { + OneOf { + // YamlList().map { Output.array($0) } + DateParser() + Bool.parser().map(.case(Output.bool)) + PrefixUpTo("\n".utf8).map(.string).map(.case(Output.string)) + Rest().map(.string).map(.case(Output.string)) + } + } + + struct DateParser: Parser { + var body: some Parser { + Parse { + Digits(4) + "-".utf8 + Digits(2) + "-".utf8 + Digits(2) + }.map(.case(Output.date)) + } + } } -try print(lineParser.parse(yamlLines)) +// This works, but doesn't handle lists well. +struct SimpleYamlParser: Parser { + var body: some Parser { + Many(into: [String: SimpleYamlValue.Output]()) { (dict: inout [String: SimpleYamlValue.Output], pair: (String, SimpleYamlValue.Output)) in + let (key, value) = pair + dict[key] = value + } element: { + PrefixUpTo(":".utf8).map(.string) + ":".utf8 + Whitespace() + SimpleYamlValue() + } separator: { + "\n".utf8 + } terminator: { + End() + } + } +} -// let lines = try yamlBlockParser.parse(yamlString[...].utf8) -// -// for line in lines { -// print("line: \(String(line)!)") -// if let parsed = try? YamlLine.keyValueParser.parse(Substring(line)) { -// print(parsed) -// } else { -// if let key = try? YamlLine.keyParser.parse(Substring(line)) { -// print("found key: \(String(key))") -// } else { -// print("not key value.") -// } -// } -// } +let simpleYamlString = #""" +author: Michael Housh +copy: true +draft: false +date: 2023-10-21 +lastmod: 2023-10-21 +image: banner.png +featuredImage: banner.png +"""# -// print(lines.map(String.init)) -// print(lines) +let parsed = try SimpleYamlParser().parse(simpleYamlString[...].utf8) +// print(parsed) + +for (key, value) in parsed { + print("\(key): \(value)") +} + +// try print(SimpleYamlParser().parse(simpleYamlString[...].utf8))