aboutsummaryrefslogtreecommitdiff
path: root/aoc2023/build/packages/tom/src/tom.gleam
diff options
context:
space:
mode:
Diffstat (limited to 'aoc2023/build/packages/tom/src/tom.gleam')
-rw-r--r--aoc2023/build/packages/tom/src/tom.gleam1317
1 files changed, 0 insertions, 1317 deletions
diff --git a/aoc2023/build/packages/tom/src/tom.gleam b/aoc2023/build/packages/tom/src/tom.gleam
deleted file mode 100644
index e19ce3e..0000000
--- a/aoc2023/build/packages/tom/src/tom.gleam
+++ /dev/null
@@ -1,1317 +0,0 @@
-//// A pure Gleam TOML parser!
-////
-//// ```gleam
-//// import tom
-////
-//// const config = "
-//// [person]
-//// name = \"Lucy\"
-//// is_cool = true
-//// "
-////
-//// pub fn main() {
-//// // Parse a string of TOML
-//// let assert Ok(parsed) = tom.parse(config)
-////
-//// // Now you can work with the data directly, or you can use the `get_*`
-//// // functions to retrieve values.
-////
-//// tom.get_string(parsed, ["person", "name"])
-//// // -> Ok("Lucy")
-////
-//// let is_cool = tom.get_bool(parsed, ["person", "is_cool"])
-//// // -> Ok(True)
-//// }
-//// ```
-
-import gleam/int
-import gleam/list
-import gleam/float
-import gleam/string
-import gleam/result
-import gleam/map.{type Map}
-
-/// A TOML document.
-pub type Toml {
- Int(Int)
- Float(Float)
- /// Infinity is a valid number in TOML but Gleam does not support it, so this
- /// variant represents the infinity values.
- Infinity(Sign)
- /// NaN is a valid number in TOML but Gleam does not support it, so this
- /// variant represents the NaN values.
- Nan(Sign)
- Bool(Bool)
- String(String)
- Date(Date)
- Time(Time)
- DateTime(DateTime)
- Array(List(Toml))
- ArrayOfTables(List(Map(String, Toml)))
- Table(Map(String, Toml))
- InlineTable(Map(String, Toml))
-}
-
-pub type DateTime {
- DateTimeValue(date: Date, time: Time, offset: Offset)
-}
-
-pub type Date {
- DateValue(year: Int, month: Int, day: Int)
-}
-
-pub type Time {
- TimeValue(hour: Int, minute: Int, second: Int, millisecond: Int)
-}
-
-pub type Offset {
- Local
- Offset(direction: Sign, hours: Int, minutes: Int)
-}
-
-pub type Sign {
- Positive
- Negative
-}
-
-/// An error that can occur when parsing a TOML document.
-pub type ParseError {
- /// An unexpected character was encountered when parsing the document.
- Unexpected(got: String, expected: String)
- /// More than one items have the same key in the document.
- KeyAlreadyInUse(key: List(String))
-}
-
-type Tokens =
- List(String)
-
-type Parsed(a) =
- Result(#(a, Tokens), ParseError)
-
-/// A number of any kind, returned by the `get_number` function.
-pub type Number {
- NumberInt(Int)
- NumberFloat(Float)
- NumberInfinity(Sign)
- NumberNan(Sign)
-}
-
-/// An error that can occur when retrieving a value from a TOML document with
-/// one of the `get_*` functions.
-pub type GetError {
- /// There was no value at the given key.
- NotFound(key: List(String))
- /// The value at the given key was not of the expected type.
- WrongType(key: List(String), expected: String, got: String)
-}
-
-// TODO: test
-/// Get a value of any type from a TOML document.
-///
-/// ## Examples
-///
-/// ```gleam
-/// let assert Ok(parsed) = parse("a.b.c = 1")
-/// get(parsed, ["a", "b", "c"])
-/// // -> Ok(Int(1))
-/// ```
-///
-pub fn get(toml: Map(String, Toml), key: List(String)) -> Result(Toml, GetError) {
- case key {
- [] -> Error(NotFound([]))
- [k] -> result.replace_error(map.get(toml, k), NotFound([k]))
- [k, ..key] -> {
- case map.get(toml, k) {
- Ok(Table(t)) -> push_key(get(t, key), k)
- Ok(other) -> Error(WrongType([k], "Table", classify(other)))
- Error(_) -> Error(NotFound([k]))
- }
- }
- }
-}
-
-// TODO: test
-/// Get an int from a TOML document.
-///
-/// ## Examples
-///
-/// ```gleam
-/// let assert Ok(parsed) = parse("a.b.c = 1")
-/// get_int(parsed, ["a", "b", "c"])
-/// // -> Ok(1)
-/// ```
-///
-pub fn get_int(
- toml: Map(String, Toml),
- key: List(String),
-) -> Result(Int, GetError) {
- case get(toml, key) {
- Ok(Int(i)) -> Ok(i)
- Ok(other) -> Error(WrongType(key, "Int", classify(other)))
- Error(e) -> Error(e)
- }
-}
-
-// TODO: test
-/// Get a float from a TOML document.
-///
-/// ## Examples
-///
-/// ```gleam
-/// let assert Ok(parsed) = parse("a.b.c = 1.1")
-/// get_float(parsed, ["a", "b", "c"])
-/// // -> Ok(1.1)
-/// ```
-///
-pub fn get_float(
- toml: Map(String, Toml),
- key: List(String),
-) -> Result(Float, GetError) {
- case get(toml, key) {
- Ok(Float(i)) -> Ok(i)
- Ok(other) -> Error(WrongType(key, "Float", classify(other)))
- Error(e) -> Error(e)
- }
-}
-
-// TODO: test
-/// Get a bool from a TOML document.
-///
-/// ## Examples
-///
-/// ```gleam
-/// let assert Ok(parsed) = parse("a.b.c = true")
-/// get_bool(parsed, ["a", "b", "c"])
-/// // -> Ok(True)
-/// ```
-///
-pub fn get_bool(
- toml: Map(String, Toml),
- key: List(String),
-) -> Result(Bool, GetError) {
- case get(toml, key) {
- Ok(Bool(i)) -> Ok(i)
- Ok(other) -> Error(WrongType(key, "Bool", classify(other)))
- Error(e) -> Error(e)
- }
-}
-
-// TODO: test
-/// Get a string from a TOML document.
-///
-/// ## Examples
-///
-/// ```gleam
-/// let assert Ok(parsed) = parse("a.b.c = \"ok\"")
-/// get_string(parsed, ["a", "b", "c"])
-/// // -> Ok("ok")
-/// ```
-///
-pub fn get_string(
- toml: Map(String, Toml),
- key: List(String),
-) -> Result(String, GetError) {
- case get(toml, key) {
- Ok(String(i)) -> Ok(i)
- Ok(other) -> Error(WrongType(key, "String", classify(other)))
- Error(e) -> Error(e)
- }
-}
-
-// TODO: test
-/// Get a date from a TOML document.
-///
-/// ## Examples
-///
-/// ```gleam
-/// let assert Ok(parsed) = parse("a.b.c = 1979-05-27")
-/// get_date(parsed, ["a", "b", "c"])
-/// // -> Ok("1979-05-27")
-/// ```
-///
-pub fn get_date(
- toml: Map(String, Toml),
- key: List(String),
-) -> Result(Date, GetError) {
- case get(toml, key) {
- Ok(Date(i)) -> Ok(i)
- Ok(other) -> Error(WrongType(key, "Date", classify(other)))
- Error(e) -> Error(e)
- }
-}
-
-// TODO: test
-/// Get a time from a TOML document.
-///
-/// ## Examples
-///
-/// ```gleam
-/// let assert Ok(parsed) = parse("a.b.c = 07:32:00")
-/// get_time(parsed, ["a", "b", "c"])
-/// // -> Ok("07:32:00")
-/// ```
-///
-pub fn get_time(
- toml: Map(String, Toml),
- key: List(String),
-) -> Result(Time, GetError) {
- case get(toml, key) {
- Ok(Time(i)) -> Ok(i)
- Ok(other) -> Error(WrongType(key, "Time", classify(other)))
- Error(e) -> Error(e)
- }
-}
-
-// TODO: test
-/// Get a date-time from a TOML document.
-///
-/// ## Examples
-///
-/// ```gleam
-/// let assert Ok(parsed) = parse("a.b.c = 1979-05-27T07:32:00")
-/// get_date_time(parsed, ["a", "b", "c"])
-/// // -> Ok("1979-05-27T07:32:00")
-/// ```
-///
-pub fn get_date_time(
- toml: Map(String, Toml),
- key: List(String),
-) -> Result(DateTime, GetError) {
- case get(toml, key) {
- Ok(DateTime(i)) -> Ok(i)
- Ok(other) -> Error(WrongType(key, "DateTime", classify(other)))
- Error(e) -> Error(e)
- }
-}
-
-// TODO: test
-/// Get an array from a TOML document.
-///
-/// ## Examples
-///
-/// ```gleam
-/// let assert Ok(parsed) = parse("a.b.c = [1, 2]")
-/// get_array(parsed, ["a", "b", "c"])
-/// // -> Ok([Int(1), Int(2)])
-/// ```
-///
-pub fn get_array(
- toml: Map(String, Toml),
- key: List(String),
-) -> Result(List(Toml), GetError) {
- case get(toml, key) {
- Ok(Array(i)) -> Ok(i)
- Ok(ArrayOfTables(i)) -> Ok(list.map(i, Table))
- Ok(other) -> Error(WrongType(key, "Array", classify(other)))
- Error(e) -> Error(e)
- }
-}
-
-// TODO: test
-/// Get a table from a TOML document.
-///
-/// ## Examples
-///
-/// ```gleam
-/// let assert Ok(parsed) = parse("a.b.c = { d = 1 }")
-/// get_table(parsed, ["a", "b", "c"])
-/// // -> Ok(map.from_list([#("d", Int(1))]))
-/// ```
-///
-pub fn get_table(
- toml: Map(String, Toml),
- key: List(String),
-) -> Result(Map(String, Toml), GetError) {
- case get(toml, key) {
- Ok(Table(i)) -> Ok(i)
- Ok(InlineTable(i)) -> Ok(i)
- Ok(other) -> Error(WrongType(key, "Table", classify(other)))
- Error(e) -> Error(e)
- }
-}
-
-// TODO: test
-/// Get a number of any kind from a TOML document.
-/// This could be an int, a float, a NaN, or an infinity.
-///
-/// ## Examples
-///
-/// ```gleam
-/// let assert Ok(parsed) = parse("a.b.c = { d = inf }")
-/// get_number(parsed, ["a", "b", "c"])
-/// // -> Ok(NumberInfinity(Positive)))
-/// ```
-///
-pub fn get_number(
- toml: Map(String, Toml),
- key: List(String),
-) -> Result(Number, GetError) {
- case get(toml, key) {
- Ok(Int(x)) -> Ok(NumberInt(x))
- Ok(Float(x)) -> Ok(NumberFloat(x))
- Ok(Nan(x)) -> Ok(NumberNan(x))
- Ok(Infinity(x)) -> Ok(NumberInfinity(x))
- Ok(other) -> Error(WrongType(key, "Number", classify(other)))
- Error(e) -> Error(e)
- }
-}
-
-fn classify(toml: Toml) -> String {
- case toml {
- Int(_) -> "Int"
- Float(_) -> "Float"
- Nan(Positive) -> "NaN"
- Nan(Negative) -> "Negative NaN"
- Infinity(Positive) -> "Infinity"
- Infinity(Negative) -> "Negative Infinity"
- Bool(_) -> "Bool"
- String(_) -> "String"
- Date(_) -> "Date"
- Time(_) -> "Time"
- DateTime(_) -> "DateTime"
- Array(_) -> "Array"
- ArrayOfTables(_) -> "Array"
- Table(_) -> "Table"
- InlineTable(_) -> "Table"
- }
-}
-
-fn push_key(result: Result(t, GetError), key: String) -> Result(t, GetError) {
- case result {
- Ok(t) -> Ok(t)
- Error(NotFound(path)) -> Error(NotFound([key, ..path]))
- Error(WrongType(path, expected, got)) ->
- Error(WrongType([key, ..path], expected, got))
- }
-}
-
-pub fn parse(input: String) -> Result(Map(String, Toml), ParseError) {
- let input = string.to_graphemes(input)
- let input = drop_comments(input, [])
- let input = skip_whitespace(input)
- use toml, input <- do(parse_table(input, map.new()))
- case parse_tables(input, toml) {
- Ok(toml) -> Ok(reverse_arrays_of_tables_table(toml))
- Error(e) -> Error(e)
- }
-}
-
-fn parse_tables(
- input: Tokens,
- toml: Map(String, Toml),
-) -> Result(Map(String, Toml), ParseError) {
- case input {
- ["[", "[", ..input] -> {
- case parse_array_of_tables(input) {
- Error(e) -> Error(e)
- Ok(#(#(key, table), input)) -> {
- case insert(toml, key, ArrayOfTables([table])) {
- Ok(toml) -> parse_tables(input, toml)
- Error(e) -> Error(e)
- }
- }
- }
- }
- ["[", ..input] -> {
- case parse_table_and_header(input) {
- Error(e) -> Error(e)
- Ok(#(#(key, table), input)) -> {
- case insert(toml, key, Table(table)) {
- Ok(toml) -> parse_tables(input, toml)
- Error(e) -> Error(e)
- }
- }
- }
- }
- [g, ..] -> Error(Unexpected(g, "["))
- [] -> Ok(toml)
- }
-}
-
-fn parse_array_of_tables(
- input: Tokens,
-) -> Parsed(#(List(String), Map(String, Toml))) {
- let input = skip_line_whitespace(input)
- use key, input <- do(parse_key(input, []))
- use input <- expect(input, "]")
- use input <- expect(input, "]")
- use table, input <- do(parse_table(input, map.new()))
- Ok(#(#(key, table), input))
-}
-
-fn parse_table_header(input: Tokens) -> Parsed(List(String)) {
- let input = skip_line_whitespace(input)
- use key, input <- do(parse_key(input, []))
- use input <- expect(input, "]")
- let input = skip_line_whitespace(input)
- use input <- expect_end_of_line(input)
- Ok(#(key, input))
-}
-
-fn parse_table_and_header(
- input: Tokens,
-) -> Parsed(#(List(String), Map(String, Toml))) {
- use key, input <- do(parse_table_header(input))
- use table, input <- do(parse_table(input, map.new()))
- Ok(#(#(key, table), input))
-}
-
-fn parse_table(
- input: Tokens,
- toml: Map(String, Toml),
-) -> Parsed(Map(String, Toml)) {
- let input = skip_whitespace(input)
- case input {
- ["[", ..] | [] -> Ok(#(toml, input))
- _ ->
- case parse_key_value(input, toml) {
- Ok(#(toml, input)) ->
- case skip_line_whitespace(input) {
- [] -> Ok(#(toml, []))
- ["\n", ..in] | ["\r\n", ..in] -> parse_table(in, toml)
- [g, ..] -> Error(Unexpected(g, "\n"))
- }
- e -> e
- }
- }
-}
-
-fn parse_key_value(
- input: Tokens,
- toml: Map(String, Toml),
-) -> Parsed(Map(String, Toml)) {
- use key, input <- do(parse_key(input, []))
- let input = skip_line_whitespace(input)
- use input <- expect(input, "=")
- let input = skip_line_whitespace(input)
- use value, input <- do(parse_value(input))
- case insert(toml, key, value) {
- Ok(toml) -> Ok(#(toml, input))
- Error(e) -> Error(e)
- }
-}
-
-fn insert(
- table: Map(String, Toml),
- key: List(String),
- value: Toml,
-) -> Result(Map(String, Toml), ParseError) {
- case insert_loop(table, key, value) {
- Ok(table) -> Ok(table)
- Error(path) -> Error(KeyAlreadyInUse(path))
- }
-}
-
-fn insert_loop(
- table: Map(String, Toml),
- key: List(String),
- value: Toml,
-) -> Result(Map(String, Toml), List(String)) {
- case key {
- [] -> panic as "unreachable"
- [k] -> {
- case map.get(table, k) {
- Error(Nil) -> Ok(map.insert(table, k, value))
- Ok(old) -> merge(table, k, old, value)
- }
- }
- [k, ..key] -> {
- case map.get(table, k) {
- Error(Nil) -> {
- case insert_loop(map.new(), key, value) {
- Ok(inner) -> Ok(map.insert(table, k, Table(inner)))
- Error(path) -> Error([k, ..path])
- }
- }
- Ok(ArrayOfTables([inner, ..rest])) -> {
- case insert_loop(inner, key, value) {
- Ok(inner) ->
- Ok(map.insert(table, k, ArrayOfTables([inner, ..rest])))
- Error(path) -> Error([k, ..path])
- }
- }
- Ok(Table(inner)) -> {
- case insert_loop(inner, key, value) {
- Ok(inner) -> Ok(map.insert(table, k, Table(inner)))
- Error(path) -> Error([k, ..path])
- }
- }
- Ok(_) -> Error([k])
- }
- }
- }
-}
-
-fn merge(
- table: Map(String, Toml),
- key: String,
- old: Toml,
- new: Toml,
-) -> Result(Map(String, Toml), List(String)) {
- case old, new {
- // When both are arrays of tables then they are merged together
- ArrayOfTables(tables), ArrayOfTables(new) ->
- Ok(map.insert(table, key, ArrayOfTables(list.append(new, tables))))
-
- _, _ -> Error([key])
- }
-}
-
-fn expect_end_of_line(input: Tokens, next: fn(Tokens) -> Parsed(a)) -> Parsed(a) {
- case input {
- ["\n", ..input] -> next(input)
- ["\r\n", ..input] -> next(input)
- [g, ..] -> Error(Unexpected(g, "\n"))
- [] -> Error(Unexpected("EOF", "\n"))
- }
-}
-
-fn parse_value(input) -> Parsed(Toml) {
- case input {
- ["t", "r", "u", "e", ..input] -> Ok(#(Bool(True), input))
- ["f", "a", "l", "s", "e", ..input] -> Ok(#(Bool(False), input))
-
- ["n", "a", "n", ..input] -> Ok(#(Nan(Positive), input))
- ["+", "n", "a", "n", ..input] -> Ok(#(Nan(Positive), input))
- ["-", "n", "a", "n", ..input] -> Ok(#(Nan(Negative), input))
-
- ["i", "n", "f", ..input] -> Ok(#(Infinity(Positive), input))
- ["+", "i", "n", "f", ..input] -> Ok(#(Infinity(Positive), input))
- ["-", "i", "n", "f", ..input] -> Ok(#(Infinity(Negative), input))
-
- ["[", ..input] -> parse_array(input, [])
- ["{", ..input] -> parse_inline_table(input, map.new())
-
- ["0", "x", ..input] -> parse_hex(input, 0, Positive)
- ["+", "0", "x", ..input] -> parse_hex(input, 0, Positive)
- ["-", "0", "x", ..input] -> parse_hex(input, 0, Negative)
-
- ["0", "o", ..input] -> parse_octal(input, 0, Positive)
- ["+", "0", "o", ..input] -> parse_octal(input, 0, Positive)
- ["-", "0", "o", ..input] -> parse_octal(input, 0, Negative)
-
- ["0", "b", ..input] -> parse_binary(input, 0, Positive)
- ["+", "0", "b", ..input] -> parse_binary(input, 0, Positive)
- ["-", "0", "b", ..input] -> parse_binary(input, 0, Negative)
-
- ["+", ..input] -> parse_number(input, 0, Positive)
- ["-", ..input] -> parse_number(input, 0, Negative)
- ["0", ..]
- | ["1", ..]
- | ["2", ..]
- | ["3", ..]
- | ["4", ..]
- | ["5", ..]
- | ["6", ..]
- | ["7", ..]
- | ["8", ..]
- | ["9", ..] -> parse_number(input, 0, Positive)
-
- ["\"", "\"", "\"", ..input] -> parse_multi_line_string(input, "")
- ["\"", ..input] -> parse_string(input, "")
-
- ["'", "'", "'", ..input] -> parse_multi_line_literal_string(input, "")
- ["'", ..input] -> parse_literal_string(input, "")
-
- [g, ..] -> Error(Unexpected(g, "value"))
- [] -> Error(Unexpected("EOF", "value"))
- }
-}
-
-fn parse_key(input: Tokens, segments: List(String)) -> Parsed(List(String)) {
- use segment, input <- do(parse_key_segment(input))
- let segments = [segment, ..segments]
- let input = skip_line_whitespace(input)
-
- case input {
- [".", ..input] -> parse_key(input, segments)
- _ -> Ok(#(list.reverse(segments), input))
- }
-}
-
-fn parse_key_segment(input: Tokens) -> Parsed(String) {
- let input = skip_line_whitespace(input)
- case input {
- ["=", ..] -> Error(Unexpected("=", "Key"))
- ["\n", ..] -> Error(Unexpected("\n", "Key"))
- ["\r\n", ..] -> Error(Unexpected("\r\n", "Key"))
- ["[", ..] -> Error(Unexpected("[", "Key"))
- ["\"", ..input] -> parse_key_quoted(input, "\"", "")
- ["'", ..input] -> parse_key_quoted(input, "'", "")
- _ -> parse_key_bare(input, "")
- }
-}
-
-fn parse_key_quoted(
- input: Tokens,
- close: String,
- name: String,
-) -> Parsed(String) {
- case input {
- [g, ..input] if g == close -> Ok(#(name, input))
- [g, ..input] -> parse_key_quoted(input, close, name <> g)
- [] -> Error(Unexpected("EOF", close))
- }
-}
-
-fn parse_key_bare(input: Tokens, name: String) -> Parsed(String) {
- case input {
- [" ", ..input] if name != "" -> Ok(#(name, input))
- ["=", ..] if name != "" -> Ok(#(name, input))
- [".", ..] if name != "" -> Ok(#(name, input))
- ["]", ..] if name != "" -> Ok(#(name, input))
- [",", ..] if name != "" -> Error(Unexpected(",", "="))
- ["\n", ..] if name != "" -> Error(Unexpected("\n", "="))
- ["\r\n", ..] if name != "" -> Error(Unexpected("\r\n", "="))
- ["\n", ..] -> Error(Unexpected("\n", "key"))
- ["\r\n", ..] -> Error(Unexpected("\r\n", "key"))
- ["]", ..] -> Error(Unexpected("]", "key"))
- [",", ..] -> Error(Unexpected(",", "key"))
- [g, ..input] -> parse_key_bare(input, name <> g)
- [] -> Error(Unexpected("EOF", "key"))
- }
-}
-
-fn skip_line_whitespace(input: Tokens) -> Tokens {
- list.drop_while(input, fn(g) { g == " " || g == "\t" })
-}
-
-fn skip_whitespace(input: Tokens) -> Tokens {
- case input {
- [" ", ..input] -> skip_whitespace(input)
- ["\t", ..input] -> skip_whitespace(input)
- ["\n", ..input] -> skip_whitespace(input)
- ["\r\n", ..input] -> skip_whitespace(input)
- input -> input
- }
-}
-
-fn drop_comments(input: Tokens, acc: Tokens) -> Tokens {
- case input {
- ["#", ..input] ->
- input
- |> list.drop_while(fn(g) { g != "\n" })
- |> drop_comments(acc)
- [g, ..input] -> drop_comments(input, [g, ..acc])
- [] -> list.reverse(acc)
- }
-}
-
-fn do(
- result: Result(#(a, Tokens), ParseError),
- next: fn(a, Tokens) -> Result(b, ParseError),
-) -> Result(b, ParseError) {
- case result {
- Ok(#(a, input)) -> next(a, input)
- Error(e) -> Error(e)
- }
-}
-
-fn expect(
- input: Tokens,
- expected: String,
- next: fn(Tokens) -> Parsed(a),
-) -> Parsed(a) {
- case input {
- [g, ..input] if g == expected -> next(input)
- [g, ..] -> Error(Unexpected(g, expected))
- [] -> Error(Unexpected("EOF", expected))
- }
-}
-
-fn parse_inline_table(
- input: Tokens,
- properties: Map(String, Toml),
-) -> Parsed(Toml) {
- let input = skip_whitespace(input)
- case input {
- ["}", ..input] -> Ok(#(InlineTable(properties), input))
- _ ->
- case parse_inline_table_property(input, properties) {
- Ok(#(properties, input)) -> {
- let input = skip_whitespace(input)
- case input {
- ["}", ..input] -> Ok(#(InlineTable(properties), input))
- [",", ..input] -> {
- let input = skip_whitespace(input)
- parse_inline_table(input, properties)
- }
- [g, ..] -> Error(Unexpected(g, "}"))
- [] -> Error(Unexpected("EOF", "}"))
- }
- }
- Error(e) -> Error(e)
- }
- }
-}
-
-fn parse_inline_table_property(
- input: Tokens,
- properties: Map(String, Toml),
-) -> Parsed(Map(String, Toml)) {
- let input = skip_whitespace(input)
- use key, input <- do(parse_key(input, []))
- let input = skip_line_whitespace(input)
- use input <- expect(input, "=")
- let input = skip_line_whitespace(input)
- use value, input <- do(parse_value(input))
- case insert(properties, key, value) {
- Ok(properties) -> Ok(#(properties, input))
- Error(e) -> Error(e)
- }
-}
-
-fn parse_array(input: Tokens, elements: List(Toml)) -> Parsed(Toml) {
- let input = skip_whitespace(input)
- case input {
- ["]", ..input] -> Ok(#(Array(list.reverse(elements)), input))
- _ -> {
- use element, input <- do(parse_value(input))
- let elements = [element, ..elements]
- let input = skip_whitespace(input)
- case input {
- ["]", ..input] -> Ok(#(Array(list.reverse(elements)), input))
- [",", ..input] -> {
- let input = skip_whitespace(input)
- parse_array(input, elements)
- }
- [g, ..] -> Error(Unexpected(g, "]"))
- [] -> Error(Unexpected("EOF", "]"))
- }
- }
- }
-}
-
-fn parse_hex(input: Tokens, number: Int, sign: Sign) -> Parsed(Toml) {
- case input {
- ["_", ..input] -> parse_hex(input, number, sign)
- ["0", ..input] -> parse_hex(input, number * 16 + 0, sign)
- ["1", ..input] -> parse_hex(input, number * 16 + 1, sign)
- ["2", ..input] -> parse_hex(input, number * 16 + 2, sign)
- ["3", ..input] -> parse_hex(input, number * 16 + 3, sign)
- ["4", ..input] -> parse_hex(input, number * 16 + 4, sign)
- ["5", ..input] -> parse_hex(input, number * 16 + 5, sign)
- ["6", ..input] -> parse_hex(input, number * 16 + 6, sign)
- ["7", ..input] -> parse_hex(input, number * 16 + 7, sign)
- ["8", ..input] -> parse_hex(input, number * 16 + 8, sign)
- ["9", ..input] -> parse_hex(input, number * 16 + 9, sign)
- ["a", ..input] -> parse_hex(input, number * 16 + 10, sign)
- ["b", ..input] -> parse_hex(input, number * 16 + 11, sign)
- ["c", ..input] -> parse_hex(input, number * 16 + 12, sign)
- ["d", ..input] -> parse_hex(input, number * 16 + 13, sign)
- ["e", ..input] -> parse_hex(input, number * 16 + 14, sign)
- ["f", ..input] -> parse_hex(input, number * 16 + 15, sign)
- ["A", ..input] -> parse_hex(input, number * 16 + 10, sign)
- ["B", ..input] -> parse_hex(input, number * 16 + 11, sign)
- ["C", ..input] -> parse_hex(input, number * 16 + 12, sign)
- ["D", ..input] -> parse_hex(input, number * 16 + 13, sign)
- ["E", ..input] -> parse_hex(input, number * 16 + 14, sign)
- ["F", ..input] -> parse_hex(input, number * 16 + 15, sign)
-
- // Anything else and the number is terminated
- input -> {
- let number = case sign {
- Positive -> number
- Negative -> -number
- }
- Ok(#(Int(number), input))
- }
- }
-}
-
-fn parse_octal(input: Tokens, number: Int, sign: Sign) -> Parsed(Toml) {
- case input {
- ["_", ..input] -> parse_octal(input, number, sign)
- ["0", ..input] -> parse_octal(input, number * 8 + 0, sign)
- ["1", ..input] -> parse_octal(input, number * 8 + 1, sign)
- ["2", ..input] -> parse_octal(input, number * 8 + 2, sign)
- ["3", ..input] -> parse_octal(input, number * 8 + 3, sign)
- ["4", ..input] -> parse_octal(input, number * 8 + 4, sign)
- ["5", ..input] -> parse_octal(input, number * 8 + 5, sign)
- ["6", ..input] -> parse_octal(input, number * 8 + 6, sign)
- ["7", ..input] -> parse_octal(input, number * 8 + 7, sign)
-
- // Anything else and the number is terminated
- input -> {
- let number = case sign {
- Positive -> number
- Negative -> -number
- }
- Ok(#(Int(number), input))
- }
- }
-}
-
-fn parse_binary(input: Tokens, number: Int, sign: Sign) -> Parsed(Toml) {
- case input {
- ["_", ..input] -> parse_binary(input, number, sign)
- ["0", ..input] -> parse_binary(input, number * 2 + 0, sign)
- ["1", ..input] -> parse_binary(input, number * 2 + 1, sign)
-
- // Anything else and the number is terminated
- input -> {
- let number = case sign {
- Positive -> number
- Negative -> -number
- }
- Ok(#(Int(number), input))
- }
- }
-}
-
-fn parse_number(input: Tokens, number: Int, sign: Sign) -> Parsed(Toml) {
- case input {
- ["_", ..input] -> parse_number(input, number, sign)
- ["0", ..input] -> parse_number(input, number * 10 + 0, sign)
- ["1", ..input] -> parse_number(input, number * 10 + 1, sign)
- ["2", ..input] -> parse_number(input, number * 10 + 2, sign)
- ["3", ..input] -> parse_number(input, number * 10 + 3, sign)
- ["4", ..input] -> parse_number(input, number * 10 + 4, sign)
- ["5", ..input] -> parse_number(input, number * 10 + 5, sign)
- ["6", ..input] -> parse_number(input, number * 10 + 6, sign)
- ["7", ..input] -> parse_number(input, number * 10 + 7, sign)
- ["8", ..input] -> parse_number(input, number * 10 + 8, sign)
- ["9", ..input] -> parse_number(input, number * 10 + 9, sign)
-
- ["-", ..input] -> parse_date(input, number)
- [":", ..input] if number < 24 -> parse_time_minute(input, number)
-
- [".", ..input] -> parse_float(input, int.to_float(number), sign, 0.1)
-
- ["e", "+", ..input] ->
- parse_exponent(input, int.to_float(number), sign, 0, Positive)
- ["e", "-", ..input] ->
- parse_exponent(input, int.to_float(number), sign, 0, Negative)
- ["e", ..input] ->
- parse_exponent(input, int.to_float(number), sign, 0, Positive)
- ["E", "+", ..input] ->
- parse_exponent(input, int.to_float(number), sign, 0, Positive)
- ["E", "-", ..input] ->
- parse_exponent(input, int.to_float(number), sign, 0, Negative)
- ["E", ..input] ->
- parse_exponent(input, int.to_float(number), sign, 0, Positive)
-
- // Anything else and the number is terminated
- input -> {
- let number = case sign {
- Positive -> number
- Negative -> -number
- }
- Ok(#(Int(number), input))
- }
- }
-}
-
-fn parse_exponent(
- input: Tokens,
- n: Float,
- n_sign: Sign,
- ex: Int,
- ex_sign: Sign,
-) -> Parsed(Toml) {
- case input {
- ["_", ..input] -> parse_exponent(input, n, n_sign, ex, ex_sign)
- ["0", ..input] -> parse_exponent(input, n, n_sign, ex * 10, ex_sign)
- ["1", ..input] -> parse_exponent(input, n, n_sign, ex * 10 + 1, ex_sign)
- ["2", ..input] -> parse_exponent(input, n, n_sign, ex * 10 + 2, ex_sign)
- ["3", ..input] -> parse_exponent(input, n, n_sign, ex * 10 + 3, ex_sign)
- ["4", ..input] -> parse_exponent(input, n, n_sign, ex * 10 + 4, ex_sign)
- ["5", ..input] -> parse_exponent(input, n, n_sign, ex * 10 + 5, ex_sign)
- ["6", ..input] -> parse_exponent(input, n, n_sign, ex * 10 + 6, ex_sign)
- ["7", ..input] -> parse_exponent(input, n, n_sign, ex * 10 + 7, ex_sign)
- ["8", ..input] -> parse_exponent(input, n, n_sign, ex * 10 + 8, ex_sign)
- ["9", ..input] -> parse_exponent(input, n, n_sign, ex * 10 + 9, ex_sign)
-
- // Anything else and the number is terminated
- input -> {
- let number = case n_sign {
- Positive -> n
- Negative -> n *. -1.0
- }
- let exponent =
- int.to_float(case ex_sign {
- Positive -> ex
- Negative -> -ex
- })
- let multiplier = case float.power(10.0, exponent) {
- Ok(multiplier) -> multiplier
- Error(_) -> 1.0
- }
- Ok(#(Float(number *. multiplier), input))
- }
- }
-}
-
-fn parse_float(
- input: Tokens,
- number: Float,
- sign: Sign,
- unit: Float,
-) -> Parsed(Toml) {
- case input {
- ["_", ..input] -> parse_float(input, number, sign, unit)
- ["0", ..input] -> parse_float(input, number, sign, unit *. 0.1)
- ["1", ..input] ->
- parse_float(input, number +. 1.0 *. unit, sign, unit *. 0.1)
- ["2", ..input] ->
- parse_float(input, number +. 2.0 *. unit, sign, unit *. 0.1)
- ["3", ..input] ->
- parse_float(input, number +. 3.0 *. unit, sign, unit *. 0.1)
- ["4", ..input] ->
- parse_float(input, number +. 4.0 *. unit, sign, unit *. 0.1)
- ["5", ..input] ->
- parse_float(input, number +. 5.0 *. unit, sign, unit *. 0.1)
- ["6", ..input] ->
- parse_float(input, number +. 6.0 *. unit, sign, unit *. 0.1)
- ["7", ..input] ->
- parse_float(input, number +. 7.0 *. unit, sign, unit *. 0.1)
- ["8", ..input] ->
- parse_float(input, number +. 8.0 *. unit, sign, unit *. 0.1)
- ["9", ..input] ->
- parse_float(input, number +. 9.0 *. unit, sign, unit *. 0.1)
-
- ["e", "+", ..input] -> parse_exponent(input, number, sign, 0, Positive)
- ["e", "-", ..input] -> parse_exponent(input, number, sign, 0, Negative)
- ["e", ..input] -> parse_exponent(input, number, sign, 0, Positive)
- ["E", "+", ..input] -> parse_exponent(input, number, sign, 0, Positive)
- ["E", "-", ..input] -> parse_exponent(input, number, sign, 0, Negative)
- ["E", ..input] -> parse_exponent(input, number, sign, 0, Positive)
-
- // Anything else and the number is terminated
- input -> {
- let number = case sign {
- Positive -> number
- Negative -> number *. -1.0
- }
- Ok(#(Float(number), input))
- }
- }
-}
-
-fn parse_string(input: Tokens, string: String) -> Parsed(Toml) {
- case input {
- ["\"", ..input] -> Ok(#(String(string), input))
- ["\\", "t", ..input] -> parse_string(input, string <> "\t")
- ["\\", "n", ..input] -> parse_string(input, string <> "\n")
- ["\\", "r", ..input] -> parse_string(input, string <> "\r")
- ["\\", "\"", ..input] -> parse_string(input, string <> "\"")
- ["\\", "\\", ..input] -> parse_string(input, string <> "\\")
- [] -> Error(Unexpected("EOF", "\""))
- ["\n", ..] -> Error(Unexpected("\n", "\""))
- ["\r\n", ..] -> Error(Unexpected("\r\n", "\""))
- [g, ..input] -> parse_string(input, string <> g)
- }
-}
-
-fn parse_multi_line_string(input: Tokens, string: String) -> Parsed(Toml) {
- case input {
- ["\"", "\"", "\"", ..input] -> Ok(#(String(string), input))
- ["\\", "\n", ..input] ->
- parse_multi_line_string(skip_whitespace(input), string)
- ["\\", "\r\n", ..input] ->
- parse_multi_line_string(skip_whitespace(input), string)
- ["\r\n", ..input] if string == "" -> parse_multi_line_string(input, string)
- ["\n", ..input] if string == "" -> parse_multi_line_string(input, string)
- ["\r\n", ..input] if string == "" -> parse_multi_line_string(input, string)
- ["\\", "t", ..input] -> parse_multi_line_string(input, string <> "\t")
- ["\\", "n", ..input] -> parse_multi_line_string(input, string <> "\n")
- ["\\", "r", ..input] -> parse_multi_line_string(input, string <> "\r")
- ["\\", "\"", ..input] -> parse_multi_line_string(input, string <> "\"")
- ["\\", "\\", ..input] -> parse_multi_line_string(input, string <> "\\")
- [] -> Error(Unexpected("EOF", "\""))
- [g, ..input] -> parse_multi_line_string(input, string <> g)
- }
-}
-
-fn parse_multi_line_literal_string(
- input: Tokens,
- string: String,
-) -> Parsed(Toml) {
- case input {
- [] -> Error(Unexpected("EOF", "\""))
- ["'", "'", "'", "'", ..] -> Error(Unexpected("''''", "'''"))
- ["'", "'", "'", ..input] -> Ok(#(String(string), input))
- ["\n", ..input] if string == "" ->
- parse_multi_line_literal_string(input, string)
- ["\r\n", ..input] if string == "" ->
- parse_multi_line_literal_string(input, string)
- [g, ..input] -> parse_multi_line_literal_string(input, string <> g)
- }
-}
-
-fn parse_literal_string(input: Tokens, string: String) -> Parsed(Toml) {
- case input {
- [] -> Error(Unexpected("EOF", "\""))
- ["\n", ..] -> Error(Unexpected("\n", "'"))
- ["\r\n", ..] -> Error(Unexpected("\r\n", "'"))
- ["'", ..input] -> Ok(#(String(string), input))
- [g, ..input] -> parse_literal_string(input, string <> g)
- }
-}
-
-fn reverse_arrays_of_tables(toml: Toml) -> Toml {
- case toml {
- ArrayOfTables(tables) ->
- ArrayOfTables(reverse_arrays_of_tables_array(tables, []))
-
- Table(table) -> Table(reverse_arrays_of_tables_table(table))
-
- _ -> toml
- }
-}
-
-fn reverse_arrays_of_tables_table(table: Map(String, Toml)) -> Map(String, Toml) {
- map.map_values(table, fn(_, v) { reverse_arrays_of_tables(v) })
-}
-
-fn reverse_arrays_of_tables_array(
- array: List(Map(String, Toml)),
- acc: List(Map(String, Toml)),
-) -> List(Map(String, Toml)) {
- case array {
- [] -> acc
- [first, ..rest] -> {
- let first = reverse_arrays_of_tables_table(first)
- reverse_arrays_of_tables_array(rest, [first, ..acc])
- }
- }
-}
-
-fn parse_time_minute(input: Tokens, hours: Int) -> Parsed(Toml) {
- use minutes, input <- do(parse_number_under_60(input, "minutes"))
- use #(seconds, ms), input <- do(parse_time_s_ms(input))
- let time = TimeValue(hours, minutes, seconds, ms)
- Ok(#(Time(time), input))
-}
-
-fn parse_hour_minute(input: Tokens) -> Parsed(#(Int, Int)) {
- use hours, input <- do(case input {
- ["0", "0", ":", ..input] -> Ok(#(0, input))
- ["0", "1", ":", ..input] -> Ok(#(1, input))
- ["0", "2", ":", ..input] -> Ok(#(2, input))
- ["0", "3", ":", ..input] -> Ok(#(3, input))
- ["0", "4", ":", ..input] -> Ok(#(4, input))
- ["0", "5", ":", ..input] -> Ok(#(5, input))
- ["0", "6", ":", ..input] -> Ok(#(6, input))
- ["0", "7", ":", ..input] -> Ok(#(7, input))
- ["0", "8", ":", ..input] -> Ok(#(8, input))
- ["0", "9", ":", ..input] -> Ok(#(9, input))
- ["1", "0", ":", ..input] -> Ok(#(10, input))
- ["1", "1", ":", ..input] -> Ok(#(11, input))
- ["1", "2", ":", ..input] -> Ok(#(12, input))
- ["1", "3", ":", ..input] -> Ok(#(13, input))
- ["1", "4", ":", ..input] -> Ok(#(14, input))
- ["1", "5", ":", ..input] -> Ok(#(15, input))
- ["1", "6", ":", ..input] -> Ok(#(16, input))
- ["1", "7", ":", ..input] -> Ok(#(17, input))
- ["1", "8", ":", ..input] -> Ok(#(18, input))
- ["1", "9", ":", ..input] -> Ok(#(19, input))
- ["2", "0", ":", ..input] -> Ok(#(20, input))
- ["2", "1", ":", ..input] -> Ok(#(21, input))
- ["2", "2", ":", ..input] -> Ok(#(22, input))
- ["2", "3", ":", ..input] -> Ok(#(23, input))
- [g, ..] -> Error(Unexpected(g, "time"))
- [] -> Error(Unexpected("EOF", "time"))
- })
-
- use minutes, input <- do(parse_number_under_60(input, "minutes"))
- Ok(#(#(hours, minutes), input))
-}
-
-fn parse_time_value(input: Tokens) -> Parsed(Time) {
- use #(hours, minutes), input <- do(parse_hour_minute(input))
- use #(seconds, ms), input <- do(parse_time_s_ms(input))
- let time = TimeValue(hours, minutes, seconds, ms)
- Ok(#(time, input))
-}
-
-fn parse_time_s_ms(input: Tokens) -> Parsed(#(Int, Int)) {
- case input {
- [":", ..input] -> {
- use seconds, input <- do(parse_number_under_60(input, "seconds"))
- case input {
- [".", ..input] -> parse_time_ms(input, seconds, 0)
- _ -> Ok(#(#(seconds, 0), input))
- }
- }
-
- _ -> Ok(#(#(0, 0), input))
- }
-}
-
-fn parse_time_ms(input: Tokens, seconds: Int, ms: Int) -> Parsed(#(Int, Int)) {
- case input {
- ["0", ..input] if ms < 100_000 -> parse_time_ms(input, seconds, ms * 10 + 0)
- ["1", ..input] if ms < 100_000 -> parse_time_ms(input, seconds, ms * 10 + 1)
- ["2", ..input] if ms < 100_000 -> parse_time_ms(input, seconds, ms * 10 + 2)
- ["3", ..input] if ms < 100_000 -> parse_time_ms(input, seconds, ms * 10 + 3)
- ["4", ..input] if ms < 100_000 -> parse_time_ms(input, seconds, ms * 10 + 4)
- ["5", ..input] if ms < 100_000 -> parse_time_ms(input, seconds, ms * 10 + 5)
- ["6", ..input] if ms < 100_000 -> parse_time_ms(input, seconds, ms * 10 + 6)
- ["7", ..input] if ms < 100_000 -> parse_time_ms(input, seconds, ms * 10 + 7)
- ["8", ..input] if ms < 100_000 -> parse_time_ms(input, seconds, ms * 10 + 8)
- ["9", ..input] if ms < 100_000 -> parse_time_ms(input, seconds, ms * 10 + 9)
-
- // Anything else and the number is terminated
- _ -> Ok(#(#(seconds, ms), input))
- }
-}
-
-fn parse_number_under_60(input: Tokens, expected: String) -> Parsed(Int) {
- case input {
- ["0", "0", ..input] -> Ok(#(0, input))
- ["0", "1", ..input] -> Ok(#(1, input))
- ["0", "2", ..input] -> Ok(#(2, input))
- ["0", "3", ..input] -> Ok(#(3, input))
- ["0", "4", ..input] -> Ok(#(4, input))
- ["0", "5", ..input] -> Ok(#(5, input))
- ["0", "6", ..input] -> Ok(#(6, input))
- ["0", "7", ..input] -> Ok(#(7, input))
- ["0", "8", ..input] -> Ok(#(8, input))
- ["0", "9", ..input] -> Ok(#(9, input))
- ["1", "0", ..input] -> Ok(#(10, input))
- ["1", "1", ..input] -> Ok(#(11, input))
- ["1", "2", ..input] -> Ok(#(12, input))
- ["1", "3", ..input] -> Ok(#(13, input))
- ["1", "4", ..input] -> Ok(#(14, input))
- ["1", "5", ..input] -> Ok(#(15, input))
- ["1", "6", ..input] -> Ok(#(16, input))
- ["1", "7", ..input] -> Ok(#(17, input))
- ["1", "8", ..input] -> Ok(#(18, input))
- ["1", "9", ..input] -> Ok(#(19, input))
- ["2", "0", ..input] -> Ok(#(20, input))
- ["2", "1", ..input] -> Ok(#(21, input))
- ["2", "2", ..input] -> Ok(#(22, input))
- ["2", "3", ..input] -> Ok(#(23, input))
- ["2", "4", ..input] -> Ok(#(24, input))
- ["2", "5", ..input] -> Ok(#(25, input))
- ["2", "6", ..input] -> Ok(#(26, input))
- ["2", "7", ..input] -> Ok(#(27, input))
- ["2", "8", ..input] -> Ok(#(28, input))
- ["2", "9", ..input] -> Ok(#(29, input))
- ["3", "0", ..input] -> Ok(#(30, input))
- ["3", "1", ..input] -> Ok(#(31, input))
- ["3", "2", ..input] -> Ok(#(32, input))
- ["3", "3", ..input] -> Ok(#(33, input))
- ["3", "4", ..input] -> Ok(#(34, input))
- ["3", "5", ..input] -> Ok(#(35, input))
- ["3", "6", ..input] -> Ok(#(36, input))
- ["3", "7", ..input] -> Ok(#(37, input))
- ["3", "8", ..input] -> Ok(#(38, input))
- ["3", "9", ..input] -> Ok(#(39, input))
- ["4", "0", ..input] -> Ok(#(40, input))
- ["4", "1", ..input] -> Ok(#(41, input))
- ["4", "2", ..input] -> Ok(#(42, input))
- ["4", "3", ..input] -> Ok(#(43, input))
- ["4", "4", ..input] -> Ok(#(44, input))
- ["4", "5", ..input] -> Ok(#(45, input))
- ["4", "6", ..input] -> Ok(#(46, input))
- ["4", "7", ..input] -> Ok(#(47, input))
- ["4", "8", ..input] -> Ok(#(48, input))
- ["4", "9", ..input] -> Ok(#(49, input))
- ["5", "0", ..input] -> Ok(#(50, input))
- ["5", "1", ..input] -> Ok(#(51, input))
- ["5", "2", ..input] -> Ok(#(52, input))
- ["5", "3", ..input] -> Ok(#(53, input))
- ["5", "4", ..input] -> Ok(#(54, input))
- ["5", "5", ..input] -> Ok(#(55, input))
- ["5", "6", ..input] -> Ok(#(56, input))
- ["5", "7", ..input] -> Ok(#(57, input))
- ["5", "8", ..input] -> Ok(#(58, input))
- ["5", "9", ..input] -> Ok(#(59, input))
-
- [g, ..] -> Error(Unexpected(g, expected))
- [] -> Error(Unexpected("EOF", expected))
- }
-}
-
-fn parse_date(input: Tokens, year: Int) -> Parsed(Toml) {
- case input {
- ["0", "1", "-", ..input] -> parse_date_day(input, year, 1)
- ["0", "2", "-", ..input] -> parse_date_day(input, year, 2)
- ["0", "3", "-", ..input] -> parse_date_day(input, year, 3)
- ["0", "4", "-", ..input] -> parse_date_day(input, year, 4)
- ["0", "5", "-", ..input] -> parse_date_day(input, year, 5)
- ["0", "6", "-", ..input] -> parse_date_day(input, year, 6)
- ["0", "7", "-", ..input] -> parse_date_day(input, year, 7)
- ["0", "8", "-", ..input] -> parse_date_day(input, year, 8)
- ["0", "9", "-", ..input] -> parse_date_day(input, year, 9)
- ["1", "0", "-", ..input] -> parse_date_day(input, year, 10)
- ["1", "1", "-", ..input] -> parse_date_day(input, year, 11)
- ["1", "2", "-", ..input] -> parse_date_day(input, year, 12)
-
- [g, ..] -> Error(Unexpected(g, "date month"))
- [] -> Error(Unexpected("EOF", "date month"))
- }
-}
-
-fn parse_date_day(input: Tokens, year: Int, month: Int) -> Parsed(Toml) {
- case input {
- ["0", "1", ..input] -> parse_date_end(input, year, month, 1)
- ["0", "2", ..input] -> parse_date_end(input, year, month, 2)
- ["0", "3", ..input] -> parse_date_end(input, year, month, 3)
- ["0", "4", ..input] -> parse_date_end(input, year, month, 4)
- ["0", "5", ..input] -> parse_date_end(input, year, month, 5)
- ["0", "6", ..input] -> parse_date_end(input, year, month, 6)
- ["0", "7", ..input] -> parse_date_end(input, year, month, 7)
- ["0", "8", ..input] -> parse_date_end(input, year, month, 8)
- ["0", "9", ..input] -> parse_date_end(input, year, month, 9)
- ["1", "0", ..input] -> parse_date_end(input, year, month, 10)
- ["1", "1", ..input] -> parse_date_end(input, year, month, 11)
- ["1", "2", ..input] -> parse_date_end(input, year, month, 12)
- ["1", "3", ..input] -> parse_date_end(input, year, month, 13)
- ["1", "4", ..input] -> parse_date_end(input, year, month, 14)
- ["1", "5", ..input] -> parse_date_end(input, year, month, 15)
- ["1", "6", ..input] -> parse_date_end(input, year, month, 16)
- ["1", "7", ..input] -> parse_date_end(input, year, month, 17)
- ["1", "8", ..input] -> parse_date_end(input, year, month, 18)
- ["1", "9", ..input] -> parse_date_end(input, year, month, 19)
- ["2", "0", ..input] -> parse_date_end(input, year, month, 20)
- ["2", "1", ..input] -> parse_date_end(input, year, month, 21)
- ["2", "2", ..input] -> parse_date_end(input, year, month, 22)
- ["2", "3", ..input] -> parse_date_end(input, year, month, 23)
- ["2", "4", ..input] -> parse_date_end(input, year, month, 24)
- ["2", "5", ..input] -> parse_date_end(input, year, month, 25)
- ["2", "6", ..input] -> parse_date_end(input, year, month, 26)
- ["2", "7", ..input] -> parse_date_end(input, year, month, 27)
- ["2", "8", ..input] -> parse_date_end(input, year, month, 28)
- ["2", "9", ..input] -> parse_date_end(input, year, month, 29)
- ["3", "0", ..input] -> parse_date_end(input, year, month, 30)
- ["3", "1", ..input] -> parse_date_end(input, year, month, 31)
-
- [g, ..] -> Error(Unexpected(g, "date day"))
- [] -> Error(Unexpected("EOF", "date day"))
- }
-}
-
-fn parse_date_end(
- input: Tokens,
- year: Int,
- month: Int,
- day: Int,
-) -> Parsed(Toml) {
- let date = DateValue(year, month, day)
- case input {
- [" ", ..input] | ["T", ..input] -> {
- use time, input <- do(parse_time_value(input))
- use offset, input <- do(parse_offset(input))
- Ok(#(DateTime(DateTimeValue(date, time, offset)), input))
- }
-
- _ -> Ok(#(Date(date), input))
- }
-}
-
-fn parse_offset(input: Tokens) -> Parsed(Offset) {
- case input {
- ["Z", ..input] -> Ok(#(Offset(Positive, 0, 0), input))
- ["+", ..input] -> parse_offset_hours(input, Positive)
- ["-", ..input] -> parse_offset_hours(input, Negative)
- _ -> Ok(#(Local, input))
- }
-}
-
-fn parse_offset_hours(input: Tokens, sign: Sign) -> Parsed(Offset) {
- use #(hours, minutes), input <- do(parse_hour_minute(input))
- Ok(#(Offset(sign, hours, minutes), input))
-}