module Boilerplate.Types where

import Data.Map.Strict (Map)
import Data.Text (Text)

-- `BOILERPLATE ... BOILERPLATE END`
data Marker = Marker Text Int (Maybe Int) -- ^^ config (start position) (end position)
  deriving (Marker -> Marker -> Bool
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: Marker -> Marker -> Bool
$c/= :: Marker -> Marker -> Bool
== :: Marker -> Marker -> Bool
$c== :: Marker -> Marker -> Bool
Eq, Int -> Marker -> ShowS
[Marker] -> ShowS
Marker -> String
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [Marker] -> ShowS
$cshowList :: [Marker] -> ShowS
show :: Marker -> String
$cshow :: Marker -> String
showsPrec :: Int -> Marker -> ShowS
$cshowsPrec :: Int -> Marker -> ShowS
Show)

data Config = Config Text [Text] [(Text, Custom)] -- ^^ type [rule] [custom key, value]
            | ConfigStart
            | ConfigEnd
  deriving (Config -> Config -> Bool
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: Config -> Config -> Bool
$c/= :: Config -> Config -> Bool
== :: Config -> Config -> Bool
$c== :: Config -> Config -> Bool
Eq, Int -> Config -> ShowS
[Config] -> ShowS
Config -> String
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [Config] -> ShowS
$cshowList :: [Config] -> ShowS
show :: Config -> String
$cshow :: Config -> String
showsPrec :: Int -> Config -> ShowS
$cshowsPrec :: Int -> Config -> ShowS
Show)
-- TODO (Text, Custom) could have a namespace

data Custom = Global Text -- ^^ available anywhere
            | Indexed [Text] -- ^^ applies to ordered product fields
            | Named (Map Text Text) -- ^^ applies to record fields and data constructors
            | NamedIndexed (Map Text [Text]) -- ^^ applies to ordered fields inside a sum type
  deriving (Custom -> Custom -> Bool
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: Custom -> Custom -> Bool
$c/= :: Custom -> Custom -> Bool
== :: Custom -> Custom -> Bool
$c== :: Custom -> Custom -> Bool
Eq, Int -> Custom -> ShowS
[Custom] -> ShowS
Custom -> String
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [Custom] -> ShowS
$cshowList :: [Custom] -> ShowS
show :: Custom -> String
$cshow :: Custom -> String
showsPrec :: Int -> Custom -> ShowS
$cshowsPrec :: Int -> Custom -> ShowS
Show)

type Tree = [Atom]

newtype Rule = Rule Tree
  deriving (Rule -> Rule -> Bool
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: Rule -> Rule -> Bool
$c/= :: Rule -> Rule -> Bool
== :: Rule -> Rule -> Bool
$c== :: Rule -> Rule -> Bool
Eq, Int -> Rule -> ShowS
[Rule] -> ShowS
Rule -> String
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [Rule] -> ShowS
$cshowList :: [Rule] -> ShowS
show :: Rule -> String
$cshow :: Rule -> String
showsPrec :: Int -> Rule -> ShowS
$cshowsPrec :: Int -> Rule -> ShowS
Show)

-- TODO a lot of Text locations could be Tree: convert on demand
data Atom =
    Raw Text
  | Type
  | TParams Tree Tree Tree Text Text -- ^^ empty prefix elem sep suffix
  | TParam
  | Product Tree -- ^^ elem
  | Sum Text Tree Text Text -- ^^ prefix elem sep suffix
  | Uncons Int -- ^^ id
  | Cons
  | Field Tree Tree Tree Text Text -- ^^ empty prefix elem sep suffix
  | TyCase Tree Tree Tree -- ^^ (type param) (higher kinded) (neither)
  | Param Int -- ^^ id
  | FieldName
  | FieldType
  | Custom Text (Maybe Tree) -- ^^ name fallback
  | Sugar Sugar
    deriving (Atom -> Atom -> Bool
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: Atom -> Atom -> Bool
$c/= :: Atom -> Atom -> Bool
== :: Atom -> Atom -> Bool
$c== :: Atom -> Atom -> Bool
Eq, Int -> Atom -> ShowS
Tree -> ShowS
Atom -> String
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: Tree -> ShowS
$cshowList :: Tree -> ShowS
show :: Atom -> String
$cshow :: Atom -> String
showsPrec :: Int -> Atom -> ShowS
$cshowsPrec :: Int -> Atom -> ShowS
Show)

data Sugar = Instance Text
           | Data Tree
  deriving (Sugar -> Sugar -> Bool
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: Sugar -> Sugar -> Bool
$c/= :: Sugar -> Sugar -> Bool
== :: Sugar -> Sugar -> Bool
$c== :: Sugar -> Sugar -> Bool
Eq, Int -> Sugar -> ShowS
[Sugar] -> ShowS
Sugar -> String
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [Sugar] -> ShowS
$cshowList :: [Sugar] -> ShowS
show :: Sugar -> String
$cshow :: Sugar -> String
showsPrec :: Int -> Sugar -> ShowS
$cshowsPrec :: Int -> Sugar -> ShowS
Show)

-- TODO {RecordCase {RECORD}{DATA}} e.g. to support different Show for data vs records

-- TODO syntax sugar for a strict subset with semantics of Divisible, Decidable,
--      Applicative, Alt