{-# OPTIONS_GHC -Wno-unrecognised-pragmas #-}
{-# HLINT ignore "Use list literal" #-}
{-|
Module      : Toml.Semantics
Description : Semantic interpretation of raw TOML expressions
Copyright   : (c) Eric Mertens, 2023
License     : ISC
Maintainer  : emertens@gmail.com

This module extracts the nested Map representation of a TOML
file. It detects invalid key assignments and resolves dotted
key assignments.

-}
module Toml.Semantics (SemanticError(..), SemanticErrorKind(..), semantics) where

import Control.Monad (foldM)
import Data.List.NonEmpty (NonEmpty((:|)))
import Data.List.NonEmpty qualified as NonEmpty
import Data.Map (Map)
import Data.Map qualified as Map
import Toml.Located (locThing, Located)
import Toml.Parser.Types (SectionKind(..), Key, Val(..), Expr(..))
import Toml.Value (Table, Value(..))

-- | The type of errors that can be generated when resolving all the keys
-- used in a TOML document. These errors always pertain to some key that
-- caused one of three conflicts.
--
-- @since 1.3.0.0
data SemanticError = SemanticError {
    SemanticError -> String
errorKey :: String,
    SemanticError -> SemanticErrorKind
errorKind :: SemanticErrorKind
    } deriving (
        ReadPrec [SemanticError]
ReadPrec SemanticError
Int -> ReadS SemanticError
ReadS [SemanticError]
(Int -> ReadS SemanticError)
-> ReadS [SemanticError]
-> ReadPrec SemanticError
-> ReadPrec [SemanticError]
-> Read SemanticError
forall a.
(Int -> ReadS a)
-> ReadS [a] -> ReadPrec a -> ReadPrec [a] -> Read a
$creadsPrec :: Int -> ReadS SemanticError
readsPrec :: Int -> ReadS SemanticError
$creadList :: ReadS [SemanticError]
readList :: ReadS [SemanticError]
$creadPrec :: ReadPrec SemanticError
readPrec :: ReadPrec SemanticError
$creadListPrec :: ReadPrec [SemanticError]
readListPrec :: ReadPrec [SemanticError]
Read {- ^ Default instance -},
        Int -> SemanticError -> ShowS
[SemanticError] -> ShowS
SemanticError -> String
(Int -> SemanticError -> ShowS)
-> (SemanticError -> String)
-> ([SemanticError] -> ShowS)
-> Show SemanticError
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> SemanticError -> ShowS
showsPrec :: Int -> SemanticError -> ShowS
$cshow :: SemanticError -> String
show :: SemanticError -> String
$cshowList :: [SemanticError] -> ShowS
showList :: [SemanticError] -> ShowS
Show {- ^ Default instance -},
        SemanticError -> SemanticError -> Bool
(SemanticError -> SemanticError -> Bool)
-> (SemanticError -> SemanticError -> Bool) -> Eq SemanticError
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: SemanticError -> SemanticError -> Bool
== :: SemanticError -> SemanticError -> Bool
$c/= :: SemanticError -> SemanticError -> Bool
/= :: SemanticError -> SemanticError -> Bool
Eq   {- ^ Default instance -},
        Eq SemanticError
Eq SemanticError =>
(SemanticError -> SemanticError -> Ordering)
-> (SemanticError -> SemanticError -> Bool)
-> (SemanticError -> SemanticError -> Bool)
-> (SemanticError -> SemanticError -> Bool)
-> (SemanticError -> SemanticError -> Bool)
-> (SemanticError -> SemanticError -> SemanticError)
-> (SemanticError -> SemanticError -> SemanticError)
-> Ord SemanticError
SemanticError -> SemanticError -> Bool
SemanticError -> SemanticError -> Ordering
SemanticError -> SemanticError -> SemanticError
forall a.
Eq a =>
(a -> a -> Ordering)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> a)
-> (a -> a -> a)
-> Ord a
$ccompare :: SemanticError -> SemanticError -> Ordering
compare :: SemanticError -> SemanticError -> Ordering
$c< :: SemanticError -> SemanticError -> Bool
< :: SemanticError -> SemanticError -> Bool
$c<= :: SemanticError -> SemanticError -> Bool
<= :: SemanticError -> SemanticError -> Bool
$c> :: SemanticError -> SemanticError -> Bool
> :: SemanticError -> SemanticError -> Bool
$c>= :: SemanticError -> SemanticError -> Bool
>= :: SemanticError -> SemanticError -> Bool
$cmax :: SemanticError -> SemanticError -> SemanticError
max :: SemanticError -> SemanticError -> SemanticError
$cmin :: SemanticError -> SemanticError -> SemanticError
min :: SemanticError -> SemanticError -> SemanticError
Ord  {- ^ Default instance -})

-- | Enumeration of the kinds of conflicts a key can generate.
--
-- @since 1.3.0.0
data SemanticErrorKind
    = AlreadyAssigned -- ^ Attempted to assign to a key that was already assigned
    | ClosedTable     -- ^ Attempted to open a table already closed
    | ImplicitlyTable -- ^ Attempted to open a tables as an array of tables that was implicitly defined to be a table
    deriving (
        ReadPrec [SemanticErrorKind]
ReadPrec SemanticErrorKind
Int -> ReadS SemanticErrorKind
ReadS [SemanticErrorKind]
(Int -> ReadS SemanticErrorKind)
-> ReadS [SemanticErrorKind]
-> ReadPrec SemanticErrorKind
-> ReadPrec [SemanticErrorKind]
-> Read SemanticErrorKind
forall a.
(Int -> ReadS a)
-> ReadS [a] -> ReadPrec a -> ReadPrec [a] -> Read a
$creadsPrec :: Int -> ReadS SemanticErrorKind
readsPrec :: Int -> ReadS SemanticErrorKind
$creadList :: ReadS [SemanticErrorKind]
readList :: ReadS [SemanticErrorKind]
$creadPrec :: ReadPrec SemanticErrorKind
readPrec :: ReadPrec SemanticErrorKind
$creadListPrec :: ReadPrec [SemanticErrorKind]
readListPrec :: ReadPrec [SemanticErrorKind]
Read {- ^ Default instance -},
        Int -> SemanticErrorKind -> ShowS
[SemanticErrorKind] -> ShowS
SemanticErrorKind -> String
(Int -> SemanticErrorKind -> ShowS)
-> (SemanticErrorKind -> String)
-> ([SemanticErrorKind] -> ShowS)
-> Show SemanticErrorKind
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> SemanticErrorKind -> ShowS
showsPrec :: Int -> SemanticErrorKind -> ShowS
$cshow :: SemanticErrorKind -> String
show :: SemanticErrorKind -> String
$cshowList :: [SemanticErrorKind] -> ShowS
showList :: [SemanticErrorKind] -> ShowS
Show {- ^ Default instance -},
        SemanticErrorKind -> SemanticErrorKind -> Bool
(SemanticErrorKind -> SemanticErrorKind -> Bool)
-> (SemanticErrorKind -> SemanticErrorKind -> Bool)
-> Eq SemanticErrorKind
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: SemanticErrorKind -> SemanticErrorKind -> Bool
== :: SemanticErrorKind -> SemanticErrorKind -> Bool
$c/= :: SemanticErrorKind -> SemanticErrorKind -> Bool
/= :: SemanticErrorKind -> SemanticErrorKind -> Bool
Eq   {- ^ Default instance -},
        Eq SemanticErrorKind
Eq SemanticErrorKind =>
(SemanticErrorKind -> SemanticErrorKind -> Ordering)
-> (SemanticErrorKind -> SemanticErrorKind -> Bool)
-> (SemanticErrorKind -> SemanticErrorKind -> Bool)
-> (SemanticErrorKind -> SemanticErrorKind -> Bool)
-> (SemanticErrorKind -> SemanticErrorKind -> Bool)
-> (SemanticErrorKind -> SemanticErrorKind -> SemanticErrorKind)
-> (SemanticErrorKind -> SemanticErrorKind -> SemanticErrorKind)
-> Ord SemanticErrorKind
SemanticErrorKind -> SemanticErrorKind -> Bool
SemanticErrorKind -> SemanticErrorKind -> Ordering
SemanticErrorKind -> SemanticErrorKind -> SemanticErrorKind
forall a.
Eq a =>
(a -> a -> Ordering)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> a)
-> (a -> a -> a)
-> Ord a
$ccompare :: SemanticErrorKind -> SemanticErrorKind -> Ordering
compare :: SemanticErrorKind -> SemanticErrorKind -> Ordering
$c< :: SemanticErrorKind -> SemanticErrorKind -> Bool
< :: SemanticErrorKind -> SemanticErrorKind -> Bool
$c<= :: SemanticErrorKind -> SemanticErrorKind -> Bool
<= :: SemanticErrorKind -> SemanticErrorKind -> Bool
$c> :: SemanticErrorKind -> SemanticErrorKind -> Bool
> :: SemanticErrorKind -> SemanticErrorKind -> Bool
$c>= :: SemanticErrorKind -> SemanticErrorKind -> Bool
>= :: SemanticErrorKind -> SemanticErrorKind -> Bool
$cmax :: SemanticErrorKind -> SemanticErrorKind -> SemanticErrorKind
max :: SemanticErrorKind -> SemanticErrorKind -> SemanticErrorKind
$cmin :: SemanticErrorKind -> SemanticErrorKind -> SemanticErrorKind
min :: SemanticErrorKind -> SemanticErrorKind -> SemanticErrorKind
Ord  {- ^ Default instance -})

-- | Extract semantic value from sequence of raw TOML expressions
-- or report a semantic error.
--
-- @since 1.3.0.0
semantics :: [Expr] -> M Table
semantics :: [Expr] -> M Table
semantics [Expr]
exprs =
 do let (KeyVals
topKVs, [(SectionKind, Key, KeyVals)]
tables) = [Expr] -> (KeyVals, [(SectionKind, Key, KeyVals)])
gather [Expr]
exprs
    FrameTable
m1 <- KeyVals -> FrameTable -> M FrameTable
assignKeyVals KeyVals
topKVs FrameTable
forall k a. Map k a
Map.empty
    FrameTable
m2 <- (FrameTable -> (SectionKind, Key, KeyVals) -> M FrameTable)
-> FrameTable -> [(SectionKind, Key, KeyVals)] -> M FrameTable
forall (t :: * -> *) (m :: * -> *) b a.
(Foldable t, Monad m) =>
(b -> a -> m b) -> b -> t a -> m b
foldM (\FrameTable
m (SectionKind
kind, Key
key, KeyVals
kvs) ->
        SectionKind -> KeyVals -> Key -> FrameTable -> M FrameTable
addSection SectionKind
kind KeyVals
kvs Key
key FrameTable
m) FrameTable
m1 [(SectionKind, Key, KeyVals)]
tables
    Table -> M Table
forall a. a -> Either (Located SemanticError) a
forall (f :: * -> *) a. Applicative f => a -> f a
pure (FrameTable -> Table
framesToTable FrameTable
m2)

-- | Line number, key, value
type KeyVals = [(Key, Val)]

-- | Arrange the expressions in a TOML file into the top-level key-value pairs
-- and then all the key-value pairs for each subtable.
gather :: [Expr] -> (KeyVals, [(SectionKind, Key, KeyVals)])
gather :: [Expr] -> (KeyVals, [(SectionKind, Key, KeyVals)])
gather = KeyVals -> [Expr] -> (KeyVals, [(SectionKind, Key, KeyVals)])
goTop []
    where
        goTop :: KeyVals -> [Expr] -> (KeyVals, [(SectionKind, Key, KeyVals)])
goTop KeyVals
acc []                           = (KeyVals -> KeyVals
forall a. [a] -> [a]
reverse KeyVals
acc, [])
        goTop KeyVals
acc (ArrayTableExpr Key
key : [Expr]
exprs) = (KeyVals -> KeyVals
forall a. [a] -> [a]
reverse KeyVals
acc, SectionKind
-> Key -> KeyVals -> [Expr] -> [(SectionKind, Key, KeyVals)]
goTable SectionKind
ArrayTableKind Key
key [] [Expr]
exprs)
        goTop KeyVals
acc (TableExpr      Key
key : [Expr]
exprs) = (KeyVals -> KeyVals
forall a. [a] -> [a]
reverse KeyVals
acc, SectionKind
-> Key -> KeyVals -> [Expr] -> [(SectionKind, Key, KeyVals)]
goTable SectionKind
TableKind      Key
key [] [Expr]
exprs)
        goTop KeyVals
acc (KeyValExpr     Key
k Val
v : [Expr]
exprs) = KeyVals -> [Expr] -> (KeyVals, [(SectionKind, Key, KeyVals)])
goTop ((Key
k,Val
v)(Key, Val) -> KeyVals -> KeyVals
forall a. a -> [a] -> [a]
:KeyVals
acc) [Expr]
exprs

        goTable :: SectionKind
-> Key -> KeyVals -> [Expr] -> [(SectionKind, Key, KeyVals)]
goTable SectionKind
kind Key
key KeyVals
acc []                           = (SectionKind
kind, Key
key, KeyVals -> KeyVals
forall a. [a] -> [a]
reverse KeyVals
acc) (SectionKind, Key, KeyVals)
-> [(SectionKind, Key, KeyVals)] -> [(SectionKind, Key, KeyVals)]
forall a. a -> [a] -> [a]
: []
        goTable SectionKind
kind Key
key KeyVals
acc (TableExpr      Key
k   : [Expr]
exprs) = (SectionKind
kind, Key
key, KeyVals -> KeyVals
forall a. [a] -> [a]
reverse KeyVals
acc) (SectionKind, Key, KeyVals)
-> [(SectionKind, Key, KeyVals)] -> [(SectionKind, Key, KeyVals)]
forall a. a -> [a] -> [a]
: SectionKind
-> Key -> KeyVals -> [Expr] -> [(SectionKind, Key, KeyVals)]
goTable SectionKind
TableKind Key
k [] [Expr]
exprs
        goTable SectionKind
kind Key
key KeyVals
acc (ArrayTableExpr Key
k   : [Expr]
exprs) = (SectionKind
kind, Key
key, KeyVals -> KeyVals
forall a. [a] -> [a]
reverse KeyVals
acc) (SectionKind, Key, KeyVals)
-> [(SectionKind, Key, KeyVals)] -> [(SectionKind, Key, KeyVals)]
forall a. a -> [a] -> [a]
: SectionKind
-> Key -> KeyVals -> [Expr] -> [(SectionKind, Key, KeyVals)]
goTable SectionKind
ArrayTableKind Key
k [] [Expr]
exprs
        goTable SectionKind
kind Key
key KeyVals
acc (KeyValExpr     Key
k Val
v : [Expr]
exprs) = SectionKind
-> Key -> KeyVals -> [Expr] -> [(SectionKind, Key, KeyVals)]
goTable SectionKind
kind Key
key ((Key
k,Val
v)(Key, Val) -> KeyVals -> KeyVals
forall a. a -> [a] -> [a]
:KeyVals
acc) [Expr]
exprs

-- | A top-level table used to distinguish top-level defined arrays
-- and tables from inline values.
type FrameTable = Map String Frame

-- | M is the error-handling monad used through this module for
-- propagating semantic errors through the 'semantics' function.
type M = Either (Located SemanticError)

-- | Frames are the top-level skeleton of the TOML file that mirror the
-- subset of values that can be constructed with with top-level syntax.
-- TOML syntax makes a distinction between tables and arrays that are
-- defined at the top-level and those defined with inline syntax. This
-- separate type keeps these syntactic differences separate while table
-- and array resolution is still happening.
data Frame
    = FrameTable FrameKind FrameTable
    | FrameArray (NonEmpty FrameTable) -- stored in reverse order for easy "append"
    | FrameValue Value
    deriving Int -> Frame -> ShowS
[Frame] -> ShowS
Frame -> String
(Int -> Frame -> ShowS)
-> (Frame -> String) -> ([Frame] -> ShowS) -> Show Frame
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> Frame -> ShowS
showsPrec :: Int -> Frame -> ShowS
$cshow :: Frame -> String
show :: Frame -> String
$cshowList :: [Frame] -> ShowS
showList :: [Frame] -> ShowS
Show

-- | Top-level tables can be in various states of completeness. This type
-- keeps track of the current state of a top-level defined table.
data FrameKind
    = Open   -- ^ table implicitly defined as supertable of [x.y.z]
    | Dotted -- ^ table implicitly defined using dotted key assignment
    | Closed -- ^ table closed to further extension
    deriving Int -> FrameKind -> ShowS
[FrameKind] -> ShowS
FrameKind -> String
(Int -> FrameKind -> ShowS)
-> (FrameKind -> String)
-> ([FrameKind] -> ShowS)
-> Show FrameKind
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> FrameKind -> ShowS
showsPrec :: Int -> FrameKind -> ShowS
$cshow :: FrameKind -> String
show :: FrameKind -> String
$cshowList :: [FrameKind] -> ShowS
showList :: [FrameKind] -> ShowS
Show

-- | Convert a top-level table "frame" representation into the plain Value
-- representation once the distinction is no longer needed.
framesToTable :: FrameTable -> Table
framesToTable :: FrameTable -> Table
framesToTable =
    (Frame -> Value) -> FrameTable -> Table
forall a b. (a -> b) -> Map String a -> Map String b
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap \case
        FrameTable FrameKind
_ FrameTable
t -> Table -> Value
Table (FrameTable -> Table
framesToTable FrameTable
t)
        FrameArray NonEmpty FrameTable
a   -> [Value] -> Value
Array (NonEmpty FrameTable -> [Value]
toArray NonEmpty FrameTable
a)
        FrameValue Value
v   -> Value
v
    where
        -- reverses the list while converting the frames to tables
        toArray :: NonEmpty FrameTable -> [Value]
toArray = ([Value] -> FrameTable -> [Value])
-> [Value] -> NonEmpty FrameTable -> [Value]
forall b a. (b -> a -> b) -> b -> NonEmpty a -> b
forall (t :: * -> *) b a.
Foldable t =>
(b -> a -> b) -> b -> t a -> b
foldl (\[Value]
acc FrameTable
frame -> Table -> Value
Table (FrameTable -> Table
framesToTable FrameTable
frame) Value -> [Value] -> [Value]
forall a. a -> [a] -> [a]
: [Value]
acc) []

-- | Build a 'Table' value out of a list of key-value pairs. These keys are
-- checked to not overlap. In the case of overlap a 'SemanticError' is returned.
constructTable :: [(Key, Value)] -> M Table
constructTable :: [(Key, Value)] -> M Table
constructTable = (Table -> (Key, Value) -> M Table)
-> Table -> [(Key, Value)] -> M Table
forall (t :: * -> *) (m :: * -> *) b a.
(Foldable t, Monad m) =>
(b -> a -> m b) -> b -> t a -> m b
foldM ((Key -> Value -> M Table) -> (Key, Value) -> M Table
forall a b c. (a -> b -> c) -> (a, b) -> c
uncurry ((Key -> Value -> M Table) -> (Key, Value) -> M Table)
-> (Table -> Key -> Value -> M Table)
-> Table
-> (Key, Value)
-> M Table
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Table -> Key -> Value -> M Table
addEntry) Table
forall k a. Map k a
Map.empty
    where
        -- turns x.y.z = v into a nested table of one leaf value
        singleCase :: Value -> [Located String] -> Value
singleCase = (Located String -> Value -> Value)
-> Value -> [Located String] -> Value
forall a b. (a -> b -> b) -> b -> [a] -> b
forall (t :: * -> *) a b.
Foldable t =>
(a -> b -> b) -> b -> t a -> b
foldr (\Located String
k Value
v -> Table -> Value
Table (String -> Value -> Table
forall k a. k -> a -> Map k a
Map.singleton (Located String -> String
forall a. Located a -> a
locThing Located String
k) Value
v))

        addEntry :: Table -> Key -> Value -> M Table
addEntry Table
tab (Located String
key :| [Located String]
subkey) Value
val = (Maybe Value -> Either (Located SemanticError) (Maybe Value))
-> String -> Table -> M Table
forall (f :: * -> *) k a.
(Functor f, Ord k) =>
(Maybe a -> f (Maybe a)) -> k -> Map k a -> f (Map k a)
Map.alterF Maybe Value -> Either (Located SemanticError) (Maybe Value)
f (Located String -> String
forall a. Located a -> a
locThing Located String
key) Table
tab
            where
                -- no existing assignment at this parent key - no more validation needed
                f :: Maybe Value -> Either (Located SemanticError) (Maybe Value)
f Maybe Value
Nothing = Maybe Value -> Either (Located SemanticError) (Maybe Value)
forall a. a -> Either (Located SemanticError) a
forall (f :: * -> *) a. Applicative f => a -> f a
pure (Value -> Maybe Value
forall a. a -> Maybe a
Just (Value -> [Located String] -> Value
singleCase Value
val [Located String]
subkey))

                -- there's already a table at this parent key, attempt to extend it
                f (Just (Table Table
subtab)) | Just Key
subkey' <- [Located String] -> Maybe Key
forall a. [a] -> Maybe (NonEmpty a)
NonEmpty.nonEmpty [Located String]
subkey =
                    Value -> Maybe Value
forall a. a -> Maybe a
Just (Value -> Maybe Value) -> (Table -> Value) -> Table -> Maybe Value
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Table -> Value
Table (Table -> Maybe Value)
-> M Table -> Either (Located SemanticError) (Maybe Value)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Table -> Key -> Value -> M Table
addEntry Table
subtab Key
subkey' Value
val

                -- attempted to overwrite an existing assignment, abort
                f Maybe Value
_ = Located String
-> SemanticErrorKind
-> Either (Located SemanticError) (Maybe Value)
forall a. Located String -> SemanticErrorKind -> M a
invalidKey Located String
key SemanticErrorKind
AlreadyAssigned

-- | Attempts to insert the key-value pairs given into a new section
-- located at the given key-path in a frame map.
addSection ::
    SectionKind  {- ^ section kind                               -} ->
    KeyVals      {- ^ values to install                          -} ->
    Key          {- ^ section key                                -} ->
    FrameTable   {- ^ local frame map                            -} ->
    M FrameTable {- ^ error message or updated local frame table -}
addSection :: SectionKind -> KeyVals -> Key -> FrameTable -> M FrameTable
addSection SectionKind
kind KeyVals
kvs = Key -> FrameTable -> M FrameTable
walk
    where
        walk :: Key -> FrameTable -> M FrameTable
walk (Located String
k1 :| []) = ((Maybe Frame -> Either (Located SemanticError) (Maybe Frame))
 -> String -> FrameTable -> M FrameTable)
-> String
-> (Maybe Frame -> Either (Located SemanticError) (Maybe Frame))
-> FrameTable
-> M FrameTable
forall a b c. (a -> b -> c) -> b -> a -> c
flip (Maybe Frame -> Either (Located SemanticError) (Maybe Frame))
-> String -> FrameTable -> M FrameTable
forall (f :: * -> *) k a.
(Functor f, Ord k) =>
(Maybe a -> f (Maybe a)) -> k -> Map k a -> f (Map k a)
Map.alterF (Located String -> String
forall a. Located a -> a
locThing Located String
k1) \case
            -- defining a new table
            Maybe Frame
Nothing ->
                case SectionKind
kind of
                    SectionKind
TableKind      -> (FrameTable -> Frame)
-> FrameTable -> Either (Located SemanticError) (Maybe Frame)
forall {b}.
(FrameTable -> b)
-> FrameTable -> Either (Located SemanticError) (Maybe b)
go (FrameKind -> FrameTable -> Frame
FrameTable FrameKind
Closed) FrameTable
forall k a. Map k a
Map.empty
                    SectionKind
ArrayTableKind -> (FrameTable -> Frame)
-> FrameTable -> Either (Located SemanticError) (Maybe Frame)
forall {b}.
(FrameTable -> b)
-> FrameTable -> Either (Located SemanticError) (Maybe b)
go (NonEmpty FrameTable -> Frame
FrameArray (NonEmpty FrameTable -> Frame)
-> (FrameTable -> NonEmpty FrameTable) -> FrameTable -> Frame
forall b c a. (b -> c) -> (a -> b) -> a -> c
. FrameTable -> NonEmpty FrameTable
forall a. a -> NonEmpty a
forall (f :: * -> *) a. Applicative f => a -> f a
pure) FrameTable
forall k a. Map k a
Map.empty

            -- defining a super table of a previously defined subtable
            Just (FrameTable FrameKind
Open FrameTable
t) ->
                case SectionKind
kind of
                    SectionKind
TableKind      -> (FrameTable -> Frame)
-> FrameTable -> Either (Located SemanticError) (Maybe Frame)
forall {b}.
(FrameTable -> b)
-> FrameTable -> Either (Located SemanticError) (Maybe b)
go (FrameKind -> FrameTable -> Frame
FrameTable FrameKind
Closed) FrameTable
t
                    SectionKind
ArrayTableKind -> Located String
-> SemanticErrorKind
-> Either (Located SemanticError) (Maybe Frame)
forall a. Located String -> SemanticErrorKind -> M a
invalidKey Located String
k1 SemanticErrorKind
ImplicitlyTable

            -- Add a new array element to an existing table array
            Just (FrameArray NonEmpty FrameTable
a) ->
                case SectionKind
kind of
                    SectionKind
ArrayTableKind -> (FrameTable -> Frame)
-> FrameTable -> Either (Located SemanticError) (Maybe Frame)
forall {b}.
(FrameTable -> b)
-> FrameTable -> Either (Located SemanticError) (Maybe b)
go (NonEmpty FrameTable -> Frame
FrameArray (NonEmpty FrameTable -> Frame)
-> (FrameTable -> NonEmpty FrameTable) -> FrameTable -> Frame
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (FrameTable -> NonEmpty FrameTable -> NonEmpty FrameTable
forall a. a -> NonEmpty a -> NonEmpty a
`NonEmpty.cons` NonEmpty FrameTable
a)) FrameTable
forall k a. Map k a
Map.empty
                    SectionKind
TableKind      -> Located String
-> SemanticErrorKind
-> Either (Located SemanticError) (Maybe Frame)
forall a. Located String -> SemanticErrorKind -> M a
invalidKey Located String
k1 SemanticErrorKind
ClosedTable

            -- failure cases
            Just (FrameTable FrameKind
Closed FrameTable
_) -> Located String
-> SemanticErrorKind
-> Either (Located SemanticError) (Maybe Frame)
forall a. Located String -> SemanticErrorKind -> M a
invalidKey Located String
k1 SemanticErrorKind
ClosedTable
            Just (FrameTable FrameKind
Dotted FrameTable
_) -> String -> Either (Located SemanticError) (Maybe Frame)
forall a. HasCallStack => String -> a
error String
"addSection: dotted table left unclosed"
            Just (FrameValue {})       -> Located String
-> SemanticErrorKind
-> Either (Located SemanticError) (Maybe Frame)
forall a. Located String -> SemanticErrorKind -> M a
invalidKey Located String
k1 SemanticErrorKind
AlreadyAssigned
            where
                go :: (FrameTable -> b)
-> FrameTable -> Either (Located SemanticError) (Maybe b)
go FrameTable -> b
g FrameTable
t = b -> Maybe b
forall a. a -> Maybe a
Just (b -> Maybe b) -> (FrameTable -> b) -> FrameTable -> Maybe b
forall b c a. (b -> c) -> (a -> b) -> a -> c
. FrameTable -> b
g (FrameTable -> b) -> (FrameTable -> FrameTable) -> FrameTable -> b
forall b c a. (b -> c) -> (a -> b) -> a -> c
. FrameTable -> FrameTable
closeDots (FrameTable -> Maybe b)
-> M FrameTable -> Either (Located SemanticError) (Maybe b)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> KeyVals -> FrameTable -> M FrameTable
assignKeyVals KeyVals
kvs FrameTable
t

        walk (Located String
k1 :| Located String
k2 : [Located String]
ks) = ((Maybe Frame -> Either (Located SemanticError) (Maybe Frame))
 -> String -> FrameTable -> M FrameTable)
-> String
-> (Maybe Frame -> Either (Located SemanticError) (Maybe Frame))
-> FrameTable
-> M FrameTable
forall a b c. (a -> b -> c) -> b -> a -> c
flip (Maybe Frame -> Either (Located SemanticError) (Maybe Frame))
-> String -> FrameTable -> M FrameTable
forall (f :: * -> *) k a.
(Functor f, Ord k) =>
(Maybe a -> f (Maybe a)) -> k -> Map k a -> f (Map k a)
Map.alterF (Located String -> String
forall a. Located a -> a
locThing Located String
k1) \case
            Maybe Frame
Nothing                     -> (FrameTable -> Frame)
-> FrameTable -> Either (Located SemanticError) (Maybe Frame)
forall {b}.
(FrameTable -> b)
-> FrameTable -> Either (Located SemanticError) (Maybe b)
go (FrameKind -> FrameTable -> Frame
FrameTable FrameKind
Open     ) FrameTable
forall k a. Map k a
Map.empty
            Just (FrameTable FrameKind
tk FrameTable
t)      -> (FrameTable -> Frame)
-> FrameTable -> Either (Located SemanticError) (Maybe Frame)
forall {b}.
(FrameTable -> b)
-> FrameTable -> Either (Located SemanticError) (Maybe b)
go (FrameKind -> FrameTable -> Frame
FrameTable FrameKind
tk       ) FrameTable
t
            Just (FrameArray (FrameTable
t :| [FrameTable]
ts)) -> (FrameTable -> Frame)
-> FrameTable -> Either (Located SemanticError) (Maybe Frame)
forall {b}.
(FrameTable -> b)
-> FrameTable -> Either (Located SemanticError) (Maybe b)
go (NonEmpty FrameTable -> Frame
FrameArray (NonEmpty FrameTable -> Frame)
-> (FrameTable -> NonEmpty FrameTable) -> FrameTable -> Frame
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (FrameTable -> [FrameTable] -> NonEmpty FrameTable
forall a. a -> [a] -> NonEmpty a
:| [FrameTable]
ts)) FrameTable
t
            Just (FrameValue Value
_)         -> Located String
-> SemanticErrorKind
-> Either (Located SemanticError) (Maybe Frame)
forall a. Located String -> SemanticErrorKind -> M a
invalidKey Located String
k1 SemanticErrorKind
AlreadyAssigned
            where
                go :: (FrameTable -> b)
-> FrameTable -> Either (Located SemanticError) (Maybe b)
go FrameTable -> b
g FrameTable
t = b -> Maybe b
forall a. a -> Maybe a
Just (b -> Maybe b) -> (FrameTable -> b) -> FrameTable -> Maybe b
forall b c a. (b -> c) -> (a -> b) -> a -> c
. FrameTable -> b
g (FrameTable -> Maybe b)
-> M FrameTable -> Either (Located SemanticError) (Maybe b)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Key -> FrameTable -> M FrameTable
walk (Located String
k2 Located String -> [Located String] -> Key
forall a. a -> [a] -> NonEmpty a
:| [Located String]
ks) FrameTable
t

-- | Close all of the tables that were implicitly defined with
-- dotted prefixes. These tables are only eligible for extension
-- within the @[table]@ section in which they were introduced.
closeDots :: FrameTable -> FrameTable
closeDots :: FrameTable -> FrameTable
closeDots =
    (Frame -> Frame) -> FrameTable -> FrameTable
forall a b. (a -> b) -> Map String a -> Map String b
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap \case
        FrameTable FrameKind
Dotted FrameTable
t -> FrameKind -> FrameTable -> Frame
FrameTable FrameKind
Closed (FrameTable -> FrameTable
closeDots FrameTable
t)
        Frame
frame               -> Frame
frame

-- | Extend the given frame table with a list of key-value pairs.
-- Either the updated frame table will be returned
assignKeyVals :: KeyVals -> FrameTable -> M FrameTable
assignKeyVals :: KeyVals -> FrameTable -> M FrameTable
assignKeyVals KeyVals
kvs FrameTable
t = FrameTable -> FrameTable
closeDots (FrameTable -> FrameTable) -> M FrameTable -> M FrameTable
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> (FrameTable -> (Key, Val) -> M FrameTable)
-> FrameTable -> KeyVals -> M FrameTable
forall (t :: * -> *) (m :: * -> *) b a.
(Foldable t, Monad m) =>
(b -> a -> m b) -> b -> t a -> m b
foldM FrameTable -> (Key, Val) -> M FrameTable
f FrameTable
t KeyVals
kvs
    where
        f :: FrameTable -> (Key, Val) -> M FrameTable
f FrameTable
m (Key
k,Val
v) = Key -> Val -> FrameTable -> M FrameTable
assign Key
k Val
v FrameTable
m

-- | Assign a single dotted key in a frame.
assign :: Key -> Val -> FrameTable -> M FrameTable

assign :: Key -> Val -> FrameTable -> M FrameTable
assign (Located String
key :| []) Val
val = ((Maybe Frame -> Either (Located SemanticError) (Maybe Frame))
 -> String -> FrameTable -> M FrameTable)
-> String
-> (Maybe Frame -> Either (Located SemanticError) (Maybe Frame))
-> FrameTable
-> M FrameTable
forall a b c. (a -> b -> c) -> b -> a -> c
flip (Maybe Frame -> Either (Located SemanticError) (Maybe Frame))
-> String -> FrameTable -> M FrameTable
forall (f :: * -> *) k a.
(Functor f, Ord k) =>
(Maybe a -> f (Maybe a)) -> k -> Map k a -> f (Map k a)
Map.alterF (Located String -> String
forall a. Located a -> a
locThing Located String
key) \case
    Maybe Frame
Nothing -> Frame -> Maybe Frame
forall a. a -> Maybe a
Just (Frame -> Maybe Frame) -> (Value -> Frame) -> Value -> Maybe Frame
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Value -> Frame
FrameValue (Value -> Maybe Frame)
-> Either (Located SemanticError) Value
-> Either (Located SemanticError) (Maybe Frame)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Val -> Either (Located SemanticError) Value
valToValue Val
val
    Just{}  -> Located String
-> SemanticErrorKind
-> Either (Located SemanticError) (Maybe Frame)
forall a. Located String -> SemanticErrorKind -> M a
invalidKey Located String
key SemanticErrorKind
AlreadyAssigned

assign (Located String
key :| Located String
k1 : [Located String]
keys) Val
val = ((Maybe Frame -> Either (Located SemanticError) (Maybe Frame))
 -> String -> FrameTable -> M FrameTable)
-> String
-> (Maybe Frame -> Either (Located SemanticError) (Maybe Frame))
-> FrameTable
-> M FrameTable
forall a b c. (a -> b -> c) -> b -> a -> c
flip (Maybe Frame -> Either (Located SemanticError) (Maybe Frame))
-> String -> FrameTable -> M FrameTable
forall (f :: * -> *) k a.
(Functor f, Ord k) =>
(Maybe a -> f (Maybe a)) -> k -> Map k a -> f (Map k a)
Map.alterF (Located String -> String
forall a. Located a -> a
locThing Located String
key) \case
    Maybe Frame
Nothing                    -> FrameTable -> Either (Located SemanticError) (Maybe Frame)
go FrameTable
forall k a. Map k a
Map.empty
    Just (FrameTable FrameKind
Open   FrameTable
t) -> FrameTable -> Either (Located SemanticError) (Maybe Frame)
go FrameTable
t
    Just (FrameTable FrameKind
Dotted FrameTable
t) -> FrameTable -> Either (Located SemanticError) (Maybe Frame)
go FrameTable
t
    Just (FrameTable FrameKind
Closed FrameTable
_) -> Located String
-> SemanticErrorKind
-> Either (Located SemanticError) (Maybe Frame)
forall a. Located String -> SemanticErrorKind -> M a
invalidKey Located String
key SemanticErrorKind
ClosedTable
    Just (FrameArray        NonEmpty FrameTable
_) -> Located String
-> SemanticErrorKind
-> Either (Located SemanticError) (Maybe Frame)
forall a. Located String -> SemanticErrorKind -> M a
invalidKey Located String
key SemanticErrorKind
ClosedTable
    Just (FrameValue        Value
_) -> Located String
-> SemanticErrorKind
-> Either (Located SemanticError) (Maybe Frame)
forall a. Located String -> SemanticErrorKind -> M a
invalidKey Located String
key SemanticErrorKind
AlreadyAssigned
    where
        go :: FrameTable -> Either (Located SemanticError) (Maybe Frame)
go FrameTable
t = Frame -> Maybe Frame
forall a. a -> Maybe a
Just (Frame -> Maybe Frame)
-> (FrameTable -> Frame) -> FrameTable -> Maybe Frame
forall b c a. (b -> c) -> (a -> b) -> a -> c
. FrameKind -> FrameTable -> Frame
FrameTable FrameKind
Dotted (FrameTable -> Maybe Frame)
-> M FrameTable -> Either (Located SemanticError) (Maybe Frame)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Key -> Val -> FrameTable -> M FrameTable
assign (Located String
k1 Located String -> [Located String] -> Key
forall a. a -> [a] -> NonEmpty a
:| [Located String]
keys) Val
val FrameTable
t

-- | Convert 'Val' to 'Value' potentially raising an error if
-- it has inline tables with key-conflicts.
valToValue :: Val -> M Value
valToValue :: Val -> Either (Located SemanticError) Value
valToValue = \case
    ValInteger   Integer
x    -> Value -> Either (Located SemanticError) Value
forall a b. b -> Either a b
Right (Integer -> Value
Integer   Integer
x)
    ValFloat     Double
x    -> Value -> Either (Located SemanticError) Value
forall a b. b -> Either a b
Right (Double -> Value
Float     Double
x)
    ValBool      Bool
x    -> Value -> Either (Located SemanticError) Value
forall a b. b -> Either a b
Right (Bool -> Value
Bool      Bool
x)
    ValString    String
x    -> Value -> Either (Located SemanticError) Value
forall a b. b -> Either a b
Right (String -> Value
String    String
x)
    ValTimeOfDay TimeOfDay
x    -> Value -> Either (Located SemanticError) Value
forall a b. b -> Either a b
Right (TimeOfDay -> Value
TimeOfDay TimeOfDay
x)
    ValZonedTime ZonedTime
x    -> Value -> Either (Located SemanticError) Value
forall a b. b -> Either a b
Right (ZonedTime -> Value
ZonedTime ZonedTime
x)
    ValLocalTime LocalTime
x    -> Value -> Either (Located SemanticError) Value
forall a b. b -> Either a b
Right (LocalTime -> Value
LocalTime LocalTime
x)
    ValDay       Day
x    -> Value -> Either (Located SemanticError) Value
forall a b. b -> Either a b
Right (Day -> Value
Day       Day
x)
    ValArray [Val]
xs       -> [Value] -> Value
Array ([Value] -> Value)
-> Either (Located SemanticError) [Value]
-> Either (Located SemanticError) Value
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> (Val -> Either (Located SemanticError) Value)
-> [Val] -> Either (Located SemanticError) [Value]
forall (t :: * -> *) (f :: * -> *) a b.
(Traversable t, Applicative f) =>
(a -> f b) -> t a -> f (t b)
forall (f :: * -> *) a b.
Applicative f =>
(a -> f b) -> [a] -> f [b]
traverse Val -> Either (Located SemanticError) Value
valToValue [Val]
xs
    ValTable KeyVals
kvs      -> do [(Key, Value)]
entries <- (((Key, Val) -> Either (Located SemanticError) (Key, Value))
-> KeyVals -> Either (Located SemanticError) [(Key, Value)]
forall (t :: * -> *) (f :: * -> *) a b.
(Traversable t, Applicative f) =>
(a -> f b) -> t a -> f (t b)
forall (f :: * -> *) a b.
Applicative f =>
(a -> f b) -> [a] -> f [b]
traverse (((Key, Val) -> Either (Located SemanticError) (Key, Value))
 -> KeyVals -> Either (Located SemanticError) [(Key, Value)])
-> ((Val -> Either (Located SemanticError) Value)
    -> (Key, Val) -> Either (Located SemanticError) (Key, Value))
-> (Val -> Either (Located SemanticError) Value)
-> KeyVals
-> Either (Located SemanticError) [(Key, Value)]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Val -> Either (Located SemanticError) Value)
-> (Key, Val) -> Either (Located SemanticError) (Key, Value)
forall (t :: * -> *) (f :: * -> *) a b.
(Traversable t, Applicative f) =>
(a -> f b) -> t a -> f (t b)
forall (f :: * -> *) a b.
Applicative f =>
(a -> f b) -> (Key, a) -> f (Key, b)
traverse) Val -> Either (Located SemanticError) Value
valToValue KeyVals
kvs
                            Table -> Value
Table (Table -> Value) -> M Table -> Either (Located SemanticError) Value
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> [(Key, Value)] -> M Table
constructTable [(Key, Value)]
entries

-- | Abort validation by reporting an error about the given key.
invalidKey ::
    Located String    {- ^ subkey     -} ->
    SemanticErrorKind {- ^ error kind -} ->
    M a
invalidKey :: forall a. Located String -> SemanticErrorKind -> M a
invalidKey Located String
key SemanticErrorKind
kind = Located SemanticError -> Either (Located SemanticError) a
forall a b. a -> Either a b
Left ((String -> SemanticErrorKind -> SemanticError
`SemanticError` SemanticErrorKind
kind) (String -> SemanticError)
-> Located String -> Located SemanticError
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Located String
key)