packages feed

ucd-0.0.0.0: Setup.hs

{-# LANGUAGE DeriveFunctor, DeriveFoldable, DeriveTraversable #-}
{-# LANGUAGE OverloadedStrings #-}
module Main where

import           Control.Applicative
import           Control.Monad (join)
import           Data.Char
import           Data.Foldable
import           Data.List (dropWhileEnd, intercalate)
import           Data.Map (Map)
import qualified Data.Map as Map
import           Text.Regex.Applicative (RE)
import qualified Text.Regex.Applicative as RE
import qualified Text.Regex.Applicative.Common as RE
import           Util hiding (intercalate)

import Distribution.Simple
import Distribution.Simple.PreProcess

main = defaultMainWithHooks simpleUserHooks
  { hookedPreProcessors = ("ucd-derived-core-properties", \ _ _ _ -> PreProcessor
      { platformIndependent = True
      , runPreProcessor = mkSimplePreProcessor $ \ inFile outFile _verbosity ->
        readFile inFile >>=
        writeFile outFile .
        ("module Data.Char.Properties.DerivedCore where\n" ++) .
        maybe (error "bad format") generate . parseProps
      }) : hookedPreProcessors simpleUserHooks
  }

data Range a = Range a a
  deriving (Foldable, Functor, Traversable)

rangeRE :: RE Char (Range Int)
rangeRE = join Range <$> n <|> Range <$> n <* ".." <*> n where n = RE.hexadecimal

lineRE :: RE Char ([Char], Range Char)
lineRE = flip ((,) . filter (/= '_')) . fmap toEnum <$> rangeRE <* many (RE.psym isSpace) <* "; " <*> many (RE.psym (liftA2 (||) isAlphaNum (== '_')))

generate :: Map [Char] [Range Char] -> [Char]
generate = unlines . ((:) <$> generateTypes . Map.keys <*> generateCode)

generateTypes :: [[Char]] -> [Char]
generateTypes names = intercalate ", " (("is" ++) <$> names) ++ " :: Char -> Bool"

generateCode :: Map [Char] [Range Char] -> [[Char]]
generateCode = toList . Map.mapWithKey (\ name ranges -> asum ["is", name, " x = ", intercalate " || " [asum ["x >= ", show a, " && x <= ", show b] | Range a b <- ranges]])

parseProps :: [Char] -> Maybe (Map [Char] [Range Char])
parseProps = lines & fmap (takeWhile (/= '#') & dropWhileEnd isSpace) & filter (not . null) & traverse (RE.match lineRE) & fmap ((fmap . fmap) pure & Map.fromListWith (flip (++)))