MyNixOS website logo
Description

TOML 1.0.0 parser.

TOML parser using generated lexers and parsers with careful attention to the TOML 1.0.0 semantics for defining tables.

TOML Parser

This package implements a validating parser for TOML 1.0.0.

This package uses an alex-generated lexer and happy-generated parser.

It also provides a pair of classes for serializing into and out of TOML.

Package Structure

---
title: Package Structure
---
stateDiagram-v2
    classDef important font-weight:bold;

    TOML:::important --> ApplicationTypes:::important : decode
    ApplicationTypes --> TOML : encode
    TOML --> [Token]: Toml.Lexer
    [Token] --> [Expr]: Toml.Parser
    [Expr] --> Table : Toml.Semantics
    Table --> ApplicationTypes : Toml.FromValue
    ApplicationTypes --> Table : Toml.ToValue
    Table --> TOML : Toml.Pretty

The highest-level interface to this package is to define FromValue and ToTable instances for your application-specific datatypes. These can be used with encode and decode to convert to and from TOML.

For low-level access to the TOML format, the lexer, parser, and validator are available for direct use. The diagram above shows how the different modules enable you to advance through the increasingly high-level TOML representations.

Examples

This file uses markdown-unlit to ensure that its code typechecks and stays in sync with the rest of the package.

import GHC.Generics (Generic)
import QuoteStr (quoteStr)
import Test.Hspec (Spec, hspec, it, shouldBe)
import Toml (parse, decode, encode, Value(..))
import Toml.FromValue (Result(Success), FromValue(fromValue), parseTableFromValue, reqKey)
import Toml.Generic (GenericTomlTable(..))
import Toml.ToValue (ToValue(toValue), ToTable(toTable), defaultTableToValue, table, (.=))

main :: IO ()
main = hspec (parses >> decodes >> encodes)

Using the raw parser

Consider this sample TOML text from the TOML specification.

fruitStr :: String
fruitStr = [quoteStr|
[[fruits]]
name = "apple"

[fruits.physical]  # subtable
color = "red"
shape = "round"

[[fruits.varieties]]  # nested array of tables
name = "red delicious"

[[fruits.varieties]]
name = "granny smith"


[[fruits]]
name = "banana"

[[fruits.varieties]]
name = "plantain"
|]

Parsing using this package generates the following value

parses :: Spec
parses = it "parses" $
    parse fruitStr
    `shouldBe`
    Right (table [
        ("fruits", Array [
            Table (table [
                ("name", String "apple"),
                ("physical", Table (table [
                    ("color", String "red"),
                    ("shape", String "round")])),
                ("varieties", Array [
                    Table (table [("name", String "red delicious")]),
                    Table (table [("name", String "granny smith")])])]),
            Table (table [
                ("name", String "banana"),
                ("varieties", Array [
                    Table (table [("name", String "plantain")])])])])])

Using decoding classes

Here's an example of defining datatypes and deserializers for the TOML above. The FromValue typeclass is used to encode each datatype into a TOML value. Instances can be derived for simple record types. More complex examples can be manually derived.

newtype Fruits = Fruits { fruits :: [Fruit] }
    deriving (Eq, Show, Generic)
    deriving (ToTable, ToValue, FromValue) via GenericTomlTable Fruits

data Fruit = Fruit { name :: String, physical :: Maybe Physical, varieties :: [Variety] }
    deriving (Eq, Show, Generic)
    deriving (ToTable, ToValue, FromValue) via GenericTomlTable Fruit

data Physical = Physical { color :: String, shape :: String }
    deriving (Eq, Show)

newtype Variety = Variety String
    deriving (Eq, Show)

instance FromValue Physical where
    fromValue = parseTableFromValue (Physical <$> reqKey "color" <*> reqKey "shape")

instance FromValue Variety where
    fromValue = parseTableFromValue (Variety <$> reqKey "name")

We can run this example on the original value to deserialize it into domain-specific datatypes.

decodes :: Spec
decodes = it "decodes" $
    decode fruitStr
    `shouldBe`
    Success [] (Fruits [
        Fruit
            "apple"
            (Just (Physical "red" "round"))
            [Variety "red delicious", Variety "granny smith"],
        Fruit "banana" Nothing [Variety "plantain"]])

Using encoding classes

The ToValue class is for all datatypes that can be encoded into TOML. The more specialized ToTable class is for datatypes that encode into tables and are thus eligible to be top-level types (all TOML documents are tables at the top-level).

Generics can be used to derive ToTable for simple record types. Manually defined instances are available for the more complex cases.

instance ToValue Physical where toValue = defaultTableToValue
instance ToTable Physical where toTable x = table ["color" .= color x, "shape" .= shape x]
instance ToValue Variety  where toValue = defaultTableToValue
instance ToTable Variety  where toTable (Variety x) = table ["name" .= x]

encodes :: Spec
encodes = it "encodes" $
    show (encode (Fruits [Fruit
            "apple"
            (Just (Physical "red" "round"))
            [Variety "red delicious", Variety "granny smith"]]))
    `shouldBe` [quoteStr|
        [[fruits]]
        name = "apple"

        [fruits.physical]
        color = "red"
        shape = "round"

        [[fruits.varieties]]
        name = "red delicious"

        [[fruits.varieties]]
        name = "granny smith"|]

More Examples

A demonstration of using this package at a more realistic scale can be found in HieDemoSpec. The various unit test files demonstrate what you can do with this library and what outputs you can expect.

See the low-level operations used to build a TOML syntax highlighter in TomlHighlighter.

Metadata

Version

1.3.2.0

License

Platforms (77)

    Darwin
    FreeBSD
    Genode
    GHCJS
    Linux
    MMIXware
    NetBSD
    none
    OpenBSD
    Redox
    Solaris
    WASI
    Windows
Show all
  • aarch64-darwin
  • aarch64-freebsd
  • aarch64-genode
  • aarch64-linux
  • aarch64-netbsd
  • aarch64-none
  • aarch64-windows
  • aarch64_be-none
  • arm-none
  • armv5tel-linux
  • armv6l-linux
  • armv6l-netbsd
  • armv6l-none
  • armv7a-darwin
  • armv7a-linux
  • armv7a-netbsd
  • armv7l-linux
  • armv7l-netbsd
  • avr-none
  • i686-cygwin
  • i686-darwin
  • i686-freebsd
  • i686-genode
  • i686-linux
  • i686-netbsd
  • i686-none
  • i686-openbsd
  • i686-windows
  • javascript-ghcjs
  • loongarch64-linux
  • m68k-linux
  • m68k-netbsd
  • m68k-none
  • microblaze-linux
  • microblaze-none
  • microblazeel-linux
  • microblazeel-none
  • mips-linux
  • mips-none
  • mips64-linux
  • mips64-none
  • mips64el-linux
  • mipsel-linux
  • mipsel-netbsd
  • mmix-mmixware
  • msp430-none
  • or1k-none
  • powerpc-netbsd
  • powerpc-none
  • powerpc64-linux
  • powerpc64le-linux
  • powerpcle-none
  • riscv32-linux
  • riscv32-netbsd
  • riscv32-none
  • riscv64-linux
  • riscv64-netbsd
  • riscv64-none
  • rx-none
  • s390-linux
  • s390-none
  • s390x-linux
  • s390x-none
  • vc4-none
  • wasm32-wasi
  • wasm64-wasi
  • x86_64-cygwin
  • x86_64-darwin
  • x86_64-freebsd
  • x86_64-genode
  • x86_64-linux
  • x86_64-netbsd
  • x86_64-none
  • x86_64-openbsd
  • x86_64-redox
  • x86_64-solaris
  • x86_64-windows