mirror of
https://github.com/kazu-yamamoto/crypton.git
synced 2024-10-05 00:07:53 +03:00
db7c3bbb4f
use the typeclass for the lowest IO impure C bindings definitions, and define the pure interface as generic on top of this. At the same time define an Hash.IO interface to allow mutable manipulations of hash contextes when necessary. Use HashAlgorithm instead of HashFunction in the [PubKey] sections Tweak the HMAC, PBKDF2 functions to be more efficient and use the new interface
173 lines
6.0 KiB
Haskell
173 lines
6.0 KiB
Haskell
-- |
|
|
-- Module : Template
|
|
-- License : BSD-style
|
|
-- Maintainer : Vincent Hanquez <vincent@snarc.org>
|
|
-- Stability : experimental
|
|
-- Portability : portable
|
|
--
|
|
-- A very simple template engine
|
|
--
|
|
module Template
|
|
(
|
|
-- * Types
|
|
Template
|
|
, Attrs
|
|
-- * methods
|
|
, parseTemplate
|
|
, renderTemplate
|
|
) where
|
|
|
|
import Data.Char (isDigit, isAlpha)
|
|
import Data.List (isPrefixOf)
|
|
import Control.Applicative
|
|
import Control.Monad
|
|
|
|
data TAtom =
|
|
Text String
|
|
| Var String
|
|
| Tpl String Template
|
|
deriving (Show)
|
|
|
|
type Template = [TAtom]
|
|
|
|
type Attrs = [(String, String)]
|
|
|
|
renderTemplate :: Template
|
|
-> Attrs
|
|
-> [(String, [Attrs])]
|
|
-> String
|
|
renderTemplate template attrs multiAttrs =
|
|
concat $ map renderAtom template
|
|
where
|
|
renderAtom :: TAtom -> String
|
|
renderAtom (Text b) = b
|
|
renderAtom (Var s) = maybe "" id $ lookup s attrs
|
|
renderAtom (Tpl n t) =
|
|
case lookup n multiAttrs of
|
|
Nothing -> error ("cannot find inner template attributes for: " ++ n)
|
|
Just [] -> error ("empty multiattrs for: " ++ n)
|
|
Just (i:is) ->
|
|
renderTemplate t (i ++ attrs) [] ++
|
|
concatMap (\inAttrs -> renderTemplate t (inAttrs ++ attrs ++ [("COMMA", ",")]) []) is
|
|
|
|
parseTemplate :: String -> Template
|
|
parseTemplate = parseTemplateFromTokens . tokenize
|
|
|
|
parseTemplateFromTokens :: [Token] -> Template
|
|
parseTemplateFromTokens toks =
|
|
case runStreamParser parse toks of
|
|
Left err -> error ("template parse error: " ++ err)
|
|
Right (tatoms, []) -> tatoms
|
|
Right (_, over) -> error ("template left over: " ++ show over)
|
|
where parse = do
|
|
done <- isDone
|
|
if done
|
|
then return []
|
|
else do next <- getTemplate <|> getVariable <|> getOther
|
|
liftM (next:) parse
|
|
|
|
------------------------------------------------------------------------
|
|
-- parser methods
|
|
------------------------------------------------------------------------
|
|
getVariable :: StreamParser TAtom
|
|
getVariable = StreamParser $ \toks ->
|
|
case toks of
|
|
[] -> Left "variable: end of stream"
|
|
TokVariableMarker:TokText t:TokVariableMarker:rest
|
|
| isVariable t -> Right (Var t, rest)
|
|
| otherwise -> Left "not a variable, variable name invalid"
|
|
_ -> Left "not a variable: not starting by %%"
|
|
|
|
getTemplate :: StreamParser TAtom
|
|
getTemplate = StreamParser $ \toks ->
|
|
case toks of
|
|
[] -> Left "template: end of stream"
|
|
TokGroupStart:TokText t:TokGroupEnd:rest
|
|
| isVariable t ->
|
|
case break (== TokGroupStart) rest of
|
|
(_, []) -> Left "template: no end found"
|
|
(inner, TokGroupStart:TokText t2:TokGroupEnd:rest2)
|
|
| isVariable t2 ->
|
|
if t == t2
|
|
then Right (Tpl t (parseTemplateFromTokens inner), rest2)
|
|
else Left ("template: end name " ++ show t2 ++ " not matching start name " ++ show t)
|
|
| otherwise -> Left "template: end sequence: invalid name"
|
|
(_, _) -> Left "template: end sequence: not found"
|
|
| otherwise -> Left "template: start sequence: invalid name"
|
|
_ -> Left "template: not right starting sequence"
|
|
|
|
getOther :: StreamParser TAtom
|
|
getOther = StreamParser $ \toks ->
|
|
case toks of
|
|
(x:xs) -> Right (Text (show x), xs)
|
|
[] -> Left "getOther: end of string"
|
|
|
|
isVariable :: String -> Bool
|
|
isVariable = and . map isVariableChar
|
|
where isVariableChar :: Char -> Bool
|
|
isVariableChar c = isAlpha c || isDigit c || c == '_'
|
|
|
|
isDone :: StreamParser Bool
|
|
isDone = StreamParser $ \s -> Right (null s, s)
|
|
|
|
------------------------------------------------------------------------
|
|
-- parser subsystem
|
|
------------------------------------------------------------------------
|
|
newtype StreamParser a = StreamParser { runStreamParser :: [Token] -> Either String (a, [Token]) }
|
|
|
|
instance Functor StreamParser where
|
|
fmap f x = StreamParser $ \s ->
|
|
case (runStreamParser x) s of
|
|
Right (a, s') -> Right (f a, s')
|
|
Left err -> Left err
|
|
instance Applicative StreamParser where
|
|
pure = return
|
|
(<*>) fm m = StreamParser $ \s1 ->
|
|
case runStreamParser m s1 of
|
|
Left err -> Left err
|
|
Right (a, s2) ->
|
|
case runStreamParser fm s2 of
|
|
Left err -> Left err
|
|
Right (f, s3) -> Right (f a, s3)
|
|
instance Alternative StreamParser where
|
|
empty = mzero
|
|
(<|>) = mplus
|
|
instance Monad StreamParser where
|
|
return a = StreamParser $ \s -> Right (a, s)
|
|
(>>=) m1 m2 = StreamParser $ \s1 ->
|
|
case (runStreamParser m1) s1 of
|
|
Left err -> Left err
|
|
Right (a, s2) -> runStreamParser (m2 a) s2
|
|
instance MonadPlus StreamParser where
|
|
mzero = StreamParser $ \_ -> Left "empty"
|
|
mplus m1 m2 = StreamParser $ \s ->
|
|
case (runStreamParser m1) s of
|
|
Left _ -> (runStreamParser m2) s
|
|
Right (a, s2) -> Right (a, s2)
|
|
|
|
------------------------------------------------------------------------
|
|
-- token parsing
|
|
------------------------------------------------------------------------
|
|
|
|
data Token = TokVariableMarker
|
|
| TokGroupStart
|
|
| TokGroupEnd
|
|
| TokText String
|
|
deriving (Eq)
|
|
|
|
instance Show Token where
|
|
show TokVariableMarker = "%%"
|
|
show TokGroupStart = "%{"
|
|
show TokGroupEnd = "%}"
|
|
show (TokText t) = t
|
|
|
|
tokenize :: String -> [Token]
|
|
tokenize s
|
|
| "%%" `isPrefixOf` s = TokVariableMarker : tokenize (drop 2 s)
|
|
| "%{" `isPrefixOf` s = TokGroupStart : tokenize (drop 2 s)
|
|
| "%}" `isPrefixOf` s = TokGroupEnd : tokenize (drop 2 s)
|
|
| otherwise =
|
|
case break (== '%') s of
|
|
(t, "") -> [TokText t]
|
|
(t1, t2) -> TokText t1 : tokenize t2
|