config-value-0.8.3: Simple, layout-based value language similar to YAML or JSON

Copyright | (c) Eric Mertens 2020
License | ISC
Maintainer | emertens@gmail.com
Safe Haskell | Safe
Language | Haskell2010

Config.Macro

Contents

- Macro expansion primitives
- File loader with inclusion

Description

This module provides assigns meaning to atoms and section names that start with `@` and `$`. It provides processing pass for configuration to use local variables and inclusion to better structure configuration.

# Sigils

- `$` starts a variable.
- `@` starts a directive.

Merge key-value mappings using `@splice`.

Load external configuration with `@load`.

# Variables

Variables are atoms that start with a `$` sigil. Variables are defined by setting a variable as a section name. This variable will remain in scope for the remainder of the sections being defined.

Variables used in a value position will be replaced with their previously defined values.

    $example: 42
    field1: $example
    field2: [0, $example]

expands to

    field1: 42
    field2: [0, 42]

Later variable definitions will shadow earlier definitions.

    { $x: 1, $x: 2, k: $x }

expands to

    { k: 2 }

Scoping examples:

    top1:
      a:  $x                     -- BAD: $x not defined yet
      $x: 42                     -- $x is now defined to be 42
      b:  $x                     -- OK: $x was defined above
      c:  {sub1: $x, sub2: [$x]} -- OK: $x in scope in subsections
                                 -- note: $x now goes out of scope
    top2: $x                     -- BAD: $x no longer in scope

Macros are expanded at their definition site. All variables are resolved before adding the new variable into the environment. Variables are lexically scoped rather than dynamically scoped.

Allowed:

    $x: 1
    $y: $x -- OK, y is now 1

Not allowed:

    $y: $x -- BAD: $x was not in scope
    $x: 1
    z:  $y

# Sections splicing

One sections value can be spliced into another sections value using the `@splice` directive. It is an error to splice a value that is not a key-value sections.

    $xy: { x: 0, y: 1 }
    example:
      @splice: $xy
      z: 2

expands to

    example:
      x: 0
      y: 1
      z: 2

# File loading

The `@load` directive is intended including configuration from other sources. `loadFileWithMacros` provides an interpretation of this directive that loads other files. An arbitrary interpretation can be defined with `expandMacros'`

To load a value define a key-value mapping with a single `@load` key with a value specifying the location to load from.

    x: @load: "fourty-two.cfg"

could expand to

    x: 42

Synopsis

- data MacroError a
  - = UndeclaredVariable a Text
  - | UnknownDirective a Text
  - | BadSplice a
  - | BadLoad a
- expandMacros :: Value a -> Either (MacroError a) (Value a)
- expandMacros' :: Monad m => (forall b. MacroError a -> m b) -> (Value a -> m (Value a)) -> Map Text (Value a) -> Value a -> m (Value a)
- data LoadFileError
  - = LoadFileParseError FilePath ParseError
  - | LoadFileMacroError (MacroError FilePosition)
- data FilePosition = FilePosition FilePath Position
- loadFileWithMacros :: (Text -> FilePath -> IO FilePath) -> FilePath -> IO (Value FilePosition)

# Macro expansion primitives

data MacroError a Source #

Errors from macro expansion annotated with the `valueAnn` from the `Value` nearest to the problem (typically a file position).

Constructors

UndeclaredVariable a Text | Variable used before its defintion
UnknownDirective a Text | Unknown directive
BadSplice a | Incorrect use of `@splice`
BadLoad a | Incorrect use of `@load`

#### Instances

Instances details

Functor MacroError Source # |
Instance details Defined in Config.Macro Methods fmap :: (a -> b) -> MacroError a -> MacroError b Source # (<$) :: a -> MacroError b -> MacroError a Source #
Foldable MacroError Source # |

Instance details

Defined in Config.Macro

Methods

fold :: Monoid m => MacroError m -> m Source #

foldMap :: Monoid m => (a -> m) -> MacroError a -> m Source #

foldMap' :: Monoid m => (a -> m) -> MacroError a -> m Source #

foldr :: (a -> b -> b) -> b -> MacroError a -> b Source #

foldr' :: (a -> b -> b) -> b -> MacroError a -> b Source #

foldl :: (b -> a -> b) -> b -> MacroError a -> b Source #

foldl' :: (b -> a -> b) -> b -> MacroError a -> b Source #

foldr1 :: (a -> a -> a) -> MacroError a -> a Source #

foldl1 :: (a -> a -> a) -> MacroError a -> a Source #

toList :: MacroError a -> [a] Source #

null :: MacroError a -> Bool Source #

length :: MacroError a -> Int Source #

elem :: Eq a => a -> MacroError a -> Bool Source #

maximum :: Ord a => MacroError a -> a Source #

minimum :: Ord a => MacroError a -> a Source #

sum :: Num a => MacroError a -> a Source #

product :: Num a => MacroError a -> a Source #

Traversable MacroError Source # |
Instance details Defined in Config.Macro Methods traverse :: Applicative f => (a -> f b) -> MacroError a -> f (MacroError b) Source # sequenceA :: Applicative f => MacroError (f a) -> f (MacroError a) Source # mapM :: Monad m => (a -> m b) -> MacroError a -> m (MacroError b) Source # sequence :: Monad m => MacroError (m a) -> m (MacroError a) Source #
(Typeable a, Show a) => Exception (MacroError a) Source # |
Instance details Defined in Config.Macro Methods toException :: MacroError a -> SomeException Source # fromException :: SomeException -> Maybe (MacroError a) Source # displayException :: MacroError a -> String Source # backtraceDesired :: MacroError a -> Bool Source #
Read a => Read (MacroError a) Source # |
Instance details Defined in Config.Macro Methods readsPrec :: Int -> ReadS (MacroError a) Source # readList :: ReadS [MacroError a] Source # readPrec :: ReadPrec (MacroError a) Source # readListPrec :: ReadPrec [MacroError a] Source #
Show a => Show (MacroError a) Source # |
Instance details Defined in Config.Macro Methods showsPrec :: Int -> MacroError a -> ShowS Source # show :: MacroError a -> String Source # showList :: [MacroError a] -> ShowS Source #
Eq a => Eq (MacroError a) Source # |
Instance details Defined in Config.Macro Methods (==) :: MacroError a -> MacroError a -> Bool Source # (/=) :: MacroError a -> MacroError a -> Bool Source #

expandMacros :: Value a -> Either (MacroError a) (Value a) Source #

Expand macros in a configuration value.

`@load` not supported and results in a `BadLoad` error.

expandMacros' Source #

Arguments

:: Monad m |
=> (forall b. MacroError a -> m b) | failure
-> (Value a -> m (Value a)) | `@load` implementation
-> Map Text (Value a) | variable environment
-> Value a | value to expand
-> m (Value a) | expanded value

Expand macros in a configuration value using a pre-populated environment.

# File loader with inclusion

data LoadFileError Source #

Errors thrown by `loadFileWithMacros`

Constructors

LoadFileParseError FilePath ParseError | failure to parse a file
LoadFileMacroError (MacroError FilePosition) | failure to expand macros

#### Instances

Instances details

Exception LoadFileError Source # |
Instance details Defined in Config.Macro Methods toException :: LoadFileError -> SomeException Source # fromException :: SomeException -> Maybe LoadFileError Source # displayException :: LoadFileError -> String Source # backtraceDesired :: LoadFileError -> Bool Source #
Read LoadFileError Source # |
Instance details Defined in Config.Macro Methods readsPrec :: Int -> ReadS LoadFileError Source # readList :: ReadS [LoadFileError] Source # readPrec :: ReadPrec LoadFileError Source # readListPrec :: ReadPrec [LoadFileError] Source #
Show LoadFileError Source # |
Instance details Defined in Config.Macro Methods showsPrec :: Int -> LoadFileError -> ShowS Source # show :: LoadFileError -> String Source # showList :: [LoadFileError] -> ShowS Source #
Eq LoadFileError Source # |
Instance details Defined in Config.Macro Methods (==) :: LoadFileError -> LoadFileError -> Bool Source # (/=) :: LoadFileError -> LoadFileError -> Bool Source #

data FilePosition Source #

A pair of filepath and position

Constructors

FilePosition FilePath Position |

#### Instances

Instances details

Read FilePosition Source # |
Instance details Defined in Config.Macro Methods readsPrec :: Int -> ReadS FilePosition Source # readList :: ReadS [FilePosition] Source # readPrec :: ReadPrec FilePosition Source # readListPrec :: ReadPrec [FilePosition] Source #
Show FilePosition Source # |
Instance details Defined in Config.Macro Methods showsPrec :: Int -> FilePosition -> ShowS Source # show :: FilePosition -> String Source # showList :: [FilePosition] -> ShowS Source #
Eq FilePosition Source # |
Instance details Defined in Config.Macro Methods (==) :: FilePosition -> FilePosition -> Bool Source # (/=) :: FilePosition -> FilePosition -> Bool Source #
Ord FilePosition Source # |

Instance details

Defined in Config.Macro

Methods

compare :: FilePosition -> FilePosition -> Ordering Source #

(<) :: FilePosition -> FilePosition -> Bool Source #

(<=) :: FilePosition -> FilePosition -> Bool Source #

(>) :: FilePosition -> FilePosition -> Bool Source #

(>=) :: FilePosition -> FilePosition -> Bool Source #

max :: FilePosition -> FilePosition -> FilePosition Source #

min :: FilePosition -> FilePosition -> FilePosition Source #

loadFileWithMacros Source #

Arguments

:: (Text -> FilePath -> IO FilePath) | inclusion path resolution
-> FilePath | starting file path
-> IO (Value FilePosition) | macro-expanded config value

Load a configuration value from a given file path.

`@load` will compute included file path from the given function given the load argument and current configuration file path.

Valid `@load` arguments are string literals use as arguments to the path resolution function.

Throws `IOError` from file loads and `LoadFileError`