packages feed

boilerplate-0.0.2: library/Boilerplate/RuleParser.hs

{-# LANGUAGE OverloadedStrings #-}

module Boilerplate.RuleParser (ruleParser) where

import Boilerplate.Types
import Control.Applicative
import qualified Data.Text as T
import Text.Parser.Char
import Text.Parser.Combinators

data Kind = RootTree | TParamTree | DataTree | FieldTree
  deriving (Show)

ruleParser :: CharParsing m => m Rule
ruleParser = Rule <$> (pTree RootTree <* eof)
  where
    tryText = try . text
    pN = read <$> option "1" (some digit)
    pTree tree = (many $ (pMagic' . choice $ contextual <> [pType, pCustom tree]) <|> pRaw) <?> (show tree)
      where
        contextual = case tree of
          RootTree -> [pTParams, pProduct, pSum, pSugarInstance]
          TParamTree -> [pTParam]
          DataTree -> [pUncons, pCons, pField]
          FieldTree -> [pCons, pParam, pFieldName, pFieldType, pTyCase]
    pRaw = Raw <$> T.pack <$> some pSourceChar <?> "haskell source"
    pRaw' = T.pack <$> many pSourceChar <?> "haskell source"
    pSourceChar = choice $ noneOf "{}\\" : (escaped <$> "{}\\")
      where escaped c = try $ char '\\' *> char c
    pMagic' fa = between (char '{') (char '}') fa
    pMagic fa = (pMagic' fa) <* spaces
    pMagic_ fa = spaces *> pMagic fa
    pType = Type <$ tryText "Type"
    pTParams = tryText "TParams" *> space *> (try pTParams1 <|> pTParams2)
      where
        pTParams1 = TParams <$> pMagic_ (pTree RootTree) <*> pMagic (pTree RootTree) <*> pMagic (pTree TParamTree) <*> pMagic pRaw' <*> pMagic pRaw'
        pTParams2 = (\el sep -> TParams [] [] el sep "") <$> pMagic_ (pTree TParamTree) <*> pMagic pRaw'
    pTParam = TParam <$ tryText "TParam"
    pProduct = tryText "Product" *> space *> (Product <$> pTree DataTree)
    pSum = tryText "Sum" *> space *> (try pSum1 <|> try pSum2 <|> pSum3)
      where
        pSum1 = (\t -> Sum "" t "" "") <$> pTree DataTree
        pSum2 = (\t s -> Sum "" t s "") <$> pMagic_ (pTree DataTree)  <*> pMagic pRaw'
        pSum3 = Sum <$> pMagic_ pRaw' <*> pMagic (pTree DataTree) <*> pMagic pRaw' <*> pMagic pRaw'
    pUncons = Uncons <$> (tryText "Uncons" *> pN)
    pCons = Cons <$ tryText "Cons"
    pField = tryText "Field" *> space *> (try pField1 <|> pField2)
      where
        pField1 = Field <$> pMagic_ (pTree DataTree) <*> pMagic (pTree DataTree) <*> pMagic (pTree FieldTree) <*> pMagic pRaw' <*> pMagic pRaw'
        pField2 = (\el sep -> Field [] [] el sep "") <$> pMagic_ (pTree FieldTree) <*> pMagic pRaw'
    pTyCase = tryText "TyCase" *> space *> pTyCase'
      where
        pTyCase' = TyCase <$> pMagic_ (pTree FieldTree) <*> pMagic (pTree FieldTree) <*> pMagic (pTree FieldTree)
    pParam = Param <$> (tryText "Param" *> pN)
    pFieldName = FieldName <$ tryText "FieldName"
    pFieldType = FieldType <$ tryText "FieldType"
    pCustom tree = Custom <$> (tryText "Custom" *> space *> pId) <*> (optional $ space *> pTree tree)
      where pId = T.pack <$> some alphaNum
    pSugarInstance = Sugar <$> (instance' <|> data')
      where
        instance' = Instance . T.pack <$> (tryText "Instance" *> space *> (some alphaNum))
        data' = Data <$> (tryText "Data" *> space *> pTree DataTree)