packages feed

mischief-ecs-0.2.0.0: src/Mischief/ECS/World/Query/TH/Common.hs

module Mischief.ECS.World.Query.TH.Common where

import Data.Maybe
import Data.Text (Text)
import Data.Text qualified as T
import Data.Void
import Language.Haskell.Meta.Parse as M
import Language.Haskell.TH
import Mischief.ECS.World.Query.Markers hiding (Q)
import Text.Megaparsec (Parsec, many, optional, (<|>))
import Text.Megaparsec.Char
import Text.Megaparsec.Char.Lexer qualified as L

data CompType = Single | Pair Text | PairAny | Resource deriving (Show)

type Parser = Parsec Void Text

pTup :: Parser a -> Parser [a]
pTup !p = do
  !r <- optional p
  whitespace

  !comma <- optional $ string ","
  whitespace

  case r of
    Nothing -> return []
    Just !r -> do
      case comma of
        (Just _) -> ([r] ++) <$> pTup p
        _ -> return [r]

whitespace :: Parser ()
whitespace =
  L.space
    space1
    (L.skipLineComment "//")
    (L.skipBlockComment "/*" "*/")

pNameTup :: Parser Text
pNameTup = (char '(' *> whitespace) *> pNameRec <* (char ')' *> whitespace)

pNameRec :: Parser Text
pNameRec = do
  !s <- T.pack <$> many (alphaNumChar <|> (' ' <$ space1) <|> char ',')
  whitespace

  !o <- optional $ (char '(' *> whitespace) *> pNameRec <* (char ')' *> whitespace)
  whitespace

  case o of
    Nothing -> do
      pure s
    Just !o -> do
      !n <- pNameRec

      pure $ s <> "(" <> o <> ")" <> n

getType :: Text -> Type
getType !name = do
  let !t = M.parseType (T.unpack name)
  case t of
    Left !e -> error e
    Right !t -> t

getValueName :: Text -> Q Name
getValueName !name = do
  !t <- lookupValueName $ T.unpack name
  pure $ fromMaybe (error $ "Invalid value: " ++ T.unpack name ++ ".") t

processC :: Text -> Q Exp
processC !name = do
  let !t = M.parseType (T.unpack name)
  case t of
    Left !e -> error e
    Right !t -> pure $ AppTypeE (ConE 'C) t

processR :: Text -> Exp -> Q Exp
processR !name !e = do
  let !name' = getType name
  pure $ AppE (AppTypeE (ConE 'R) name') e

relExp :: CompType -> Q Exp
relExp PairAny = return $ ConE 'Any
relExp (Pair !x) = VarE <$> getValueName x
relExp _ = undefined