Toml.Literal

Writing a value that was not read from a file.

Every node in the AST carries the text it was written as, which is what makes a document that came from a file go back byte for byte. A value a program has just made up has no such text yet, so something has to choose it, and this is where that choosing is done -- once, so that Toml.Edit and Toml.Encode cannot disagree about how to spell a float.

The choices are the plain ones: a bare key when the grammar allows and a quoted one when it does not, decimal for integers, and only the escapes a string actually needs.

Which of TOML's four string forms to write is also a choice, and it is the caller's rather than this module's: string always writes "...", and each of the other three forms has its own constructor.

Toml.Literal.string "10.0.0.1"      -- ip = "10.0.0.1"
Toml.Literal.int 8000               -- ports = [8000]
Toml.Literal.float 79.5             -- cpu = 79.5
Toml.Literal.bool True              -- enabled = true

Toml.Literal.array
    [ Toml.Literal.int 8000, Toml.Literal.int 8001, Toml.Literal.int 8002 ]
-- ports = [8000, 8001, 8002]

Toml.Literal.inlineTable
    [ { key = "cpu", value = Toml.Literal.float 79.5 }
    , { key = "case", value = Toml.Literal.float 72.0 }
    ]
-- temp_targets = { cpu = 79.5, case = 72.0 }

The one to read twice is float, because a Float and a decimal are not the same thing and this module has to pick one of them to write.

string : String -> Value

A string, written in the basic form: "..." on one line, with \n for a newline.

This is the default, and it is what callers have always got, so it will not change. A string with newlines in it reads better as multilineString, but that is the caller's choice.

multilineString : String -> Value

A string, written in the multi-line basic form: """...""". The literal opens with a newline, which the reader trims, and the newlines and tabs in the text are written as themselves.

Every string can be written this way, because all the escapes still work inside """, so this never fails. It is the form for text with lines in it: a note, a query, anything a program puts in a config file for a person to read.

A value that is already in the file is not re-spelled. Toml.Edit.set compares by meaning, so a basic string that already says the same thing is left as it was written. The form is chosen when the key is first written, not on every save.

literalString : String -> Maybe Value

A string, written in the literal form: '...', with no escapes at all.

Returns Nothing if the string contains an apostrophe, a newline, or a control character other than tab. A literal string has no escapes, which is the point of the form and also why it cannot always be written.

It does not quietly write another form instead. If it did, the form of a key would depend on its value, and a key could change shape between two saves because somebody typed an apostrophe. A caller who would rather have a basic string than nothing can say so in one line:

Maybe.withDefault (Toml.Literal.string text)
    (Toml.Literal.literalString text)
multilineLiteralString : String -> Maybe Value

A string, written in the multi-line literal form: '''...''', with no escapes and with the newlines written as themselves.

Returns Nothing if the string cannot be written that way: three apostrophes in a row, an apostrophe at the very end where the closing delimiter goes, a lone carriage return, or a control character other than tab and newline. As with literalString, no other form is written in its place.

int : Int -> Value

An integer that fits in a Gren Int.

bigInt : BigInt -> Value

An integer of any size.

float : Float -> Value

A float.

inf and nan are written as those words. Everything else is written as the shortest decimal that reads back as the same Float, which is what String.fromFloat gives: 3.14 and not the fifty-one digits of the binary value that is nearest to it.

That is a choice, and it is the opposite of the one bigDecimal makes. A Float is the nearest double, so the exact expansion is not wrong -- but it is not what the caller meant either, and writing it into a config file would be a strange way to say 3.14. A caller who does mean the exact value has a BigDecimal and should say so.

Everything gets a decimal point even when it does not need one, because 1 without one is an integer in TOML and this function was asked for a float.

bigDecimal : BigDecimal -> Value

An exact decimal, written as it stands. Every digit of it, which is the whole reason for having one -- see float for the other choice.

bool : Bool -> Value

A boolean.

offsetDateTime : DateTime -> Value

A date and time with an offset. Fails over to a local date-time if the value has no offset, since that is what it is.

localDateTime : DateTime -> Value

A date and time with no offset.

localDate : Date -> Value

A date.

localTime : Time -> Value

A time of day.

array : Array Value -> Value

An array on one line: [1, 2, 3].

A space after each comma and none against the brackets, so an empty one is []. The elements are values, not fields, so an inline table inside an array is inlineTable -- there is no header to be had in there.

inlineTable : Array { key : String, value : Value } -> Value

An inline table on one line: { a = 1, b = 2 }.

A space inside each brace and one either side of every equals sign, except that an empty one is {} -- a space inside that would be an odd thing to write.

key : Array String -> Key

A whole key from its parts.

simpleKey : String -> SimpleKey

One part of a key, written bare when the grammar allows and quoted when it does not.

path : Key -> Array String

The parts of a key, as the table tree names them.