toml-parser: TOML 1.0.0 parser

[ library, text ] [ Propose Tags ]

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


[Skip to Readme]

Downloads

Maintainer's Corner

Package maintainers

For package maintainers and hackage trustees

Candidates

  • No Candidates
Versions [RSS] 0.1.0.0, 1.0.0.0, 1.0.1.0, 1.1.0.0, 1.1.1.0, 1.2.0.0, 1.2.1.0, 1.3.0.0, 1.3.1.0, 1.3.1.1, 1.3.1.2, 1.3.1.3, 1.3.2.0, 2.0.0.0
Change log ChangeLog.md
Dependencies array (>=0.5 && <0.6), base (>=4.14 && <4.19), containers (>=0.5 && <0.7), prettyprinter (>=1.7 && <1.8), time (>=1.9 && <1.13), transformers (>=0.5 && <0.7) [details]
License ISC
Copyright 2023 Eric Mertens
Author Eric Mertens
Maintainer emertens@gmail.com
Category Text
Source repo head: git clone https://github.com/glguy/toml-parser(tag main)
Uploaded by EricMertens at 2023-07-09T22:01:41Z
Distributions Arch:1.3.1.3, Fedora:1.3.0.0, LTSHaskell:1.3.2.0, NixOS:1.3.2.0, Stackage:2.0.0.0, openSUSE:1.3.2.0
Reverse Dependencies 5 direct, 167 indirect [details]
Downloads 3549 total (276 in the last 30 days)
Rating 2.5 (votes: 4) [estimated by Bayesian average]
Your Rating
  • λ
  • λ
  • λ
Status Docs available [build log]
Last success reported on 2023-07-10 [all 1 reports]

Readme for toml-parser-1.2.0.0

[back to package description]

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.

Example

Consider this sample TOML text from the specification.

[[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

>>> Right fruitToml = parse fruitStr
>>> fruitToml
Right (fromList [
    ("fruits",Array [
        Table (fromList [
            ("name",String "apple"),
            ("physical",Table (fromList [
                ("color",String "red"),
                ("shape",String "round")])),
            ("varieties",Array [
                Table (fromList [("name",String "red delicious")]),
                Table (fromList [("name",String "granny smith")])])]),
        Table (fromList [
            ("name",String "banana"),
            ("varieties",Array [
                Table (fromList [("name",String "plantain")])])])])])

We can render this parsed value back to TOML text using prettyToml fruitToml. In this case the input was already sorted, so the generated text will happen to match almost exactly.

Here's an example of defining datatypes and deserializers for the TOML above.

newtype Fruits = Fruits [Fruit]
    deriving (Eq, Show)

data Fruit = Fruit String (Maybe Physical) [Variety]
    deriving (Eq, Show)

data Physical = Physical String String
    deriving (Eq, Show)

newtype Variety = Variety String
    deriving (Eq, Show)

instance FromValue Fruits where
    fromValue = parseTableFromValue (Fruits <$> reqKey "fruits")

instance FroValue Fruit where
    fromValue = parseTableFromValue (Fruit <$> reqKey "name" <*> optKey "physical" <*> reqKey "varieties")

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.

>>> decode fruitToml :: Either String Fruits
Right (Fruits [
    Fruit "apple" (Just (Physical "red" "round")) [Variety "red delicious", Variety "granny smith"],
    Fruit "banana" Nothing [Variety "plantain"]])

Generics

Code for generating and matching tables to records can be derived using GHC.Generics. This will generate tables using the field names as table keys.

data ExampleRecord = ExampleRecord {
  exString :: String,
  exList   :: [Int],
  exOpt    :: Maybe Bool}
  deriving (Show, Generic, Eq)

instance FromValue ExampleRecord where fromValue = parseTableFromValue genericParseTable
instance ToTable   ExampleRecord where toTable   = genericToTable
instance ToValue   ExampleRecord where toValue   = defaultTableToValue

Larger Example

A demonstration of using this package at a more realistic scale can be found in HieDemoSpec.