packages feed

HSmarty (empty) → 0.1.0.0

raw patch · 7 files changed

+285/−0 lines, 7 filesdep +HTFdep +HTTPdep +aesonsetup-changed

Dependencies added: HTF, HTTP, aeson, attoparsec, base, mtl, text, unordered-containers, vector

Files

+ HSmarty.cabal view
@@ -0,0 +1,39 @@+name:                HSmarty+version:             0.1.0.0+synopsis:            Haskell implementation of a subset of the PHP-Smarty template language+-- description:         +license:             BSD3+license-file:        LICENSE+author:              Alexander Thiemann <mail@agrafix.net>+maintainer:          mail@agrafix.net+copyright:           (c) 2013 by Alexander Thiemann+category:            Text+build-type:          Simple+cabal-version:       >=1.8+extra-source-files:  test.tpl++Library+  exposed-modules:   Text.HSmarty+  other-modules:     Text.HSmarty.Parser.Smarty+  build-depends:     base ==4.6.*,+                     vector ==0.10.*,+                     text ==0.11.*,+                     unordered-containers ==0.2.*,+                     aeson ==0.6.*,+                     attoparsec ==0.10.*,+                     mtl ==2.1.*,+                     HTTP,+                     HTF++Executable TestHSmarty+  Main-Is:           Tests.hs+  Ghc-Options:       -Wall+  build-depends:     base ==4.6.*,+                     vector ==0.10.*,+                     text ==0.11.*,+                     unordered-containers ==0.2.*,+                     aeson ==0.6.*,+                     attoparsec ==0.10.*,+                     mtl ==2.1.*,+                     HTTP,+                     HTF
+ LICENSE view
@@ -0,0 +1,30 @@+Copyright (c) 2013, Alexander Thiemann <mail@agrafix.net>++All rights reserved.++Redistribution and use in source and binary forms, with or without+modification, are permitted provided that the following conditions are met:++    * Redistributions of source code must retain the above copyright+      notice, this list of conditions and the following disclaimer.++    * Redistributions in binary form must reproduce the above+      copyright notice, this list of conditions and the following+      disclaimer in the documentation and/or other materials provided+      with the distribution.++    * Neither the name of Alexander Thiemann <mail@agrafix.net> nor the names of other+      contributors may be used to endorse or promote products derived+      from this software without specific prior written permission.++THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ Setup.hs view
@@ -0,0 +1,2 @@+import Distribution.Simple+main = defaultMain
+ Tests.hs view
@@ -0,0 +1,8 @@+{-# OPTIONS_GHC -F -pgmF htfpp #-}+module Main where++import Test.Framework+import {-@ HTF_TESTS @-} Text.HSmarty.Parser.Smarty++main :: IO ()+main = htfMain htf_importedTests
+ Text/HSmarty.hs view
@@ -0,0 +1,5 @@+module Text.HSmarty+    (module Text.HSmarty.Render.Engine)+where++import Text.HSmarty.Render.Engine
+ Text/HSmarty/Parser/Smarty.hs view
@@ -0,0 +1,190 @@+{-# OPTIONS_GHC -F -pgmF htfpp #-}+{-# OPTIONS_GHC -fwarn-unused-imports -fwarn-incomplete-patterns #-}+{-# LANGUAGE OverloadedStrings #-}+module Text.HSmarty.Parser.Smarty+    ( parseSmarty+    , htf_thisModulesTests+    )+where++import Text.HSmarty.Types+import Text.HSmarty.Parser.Util+import qualified Text.HSmarty.Parser.Expr as E++import Data.Attoparsec.Text+import Data.Char+import Control.Applicative+import Test.Framework+import qualified Data.Aeson as A+import qualified Data.Text as T++parseSmarty :: Monad m => FilePath -> T.Text -> m Smarty+parseSmarty fp t =+    either fail mk $ parseOnly pRoot t+    where+      mk exprs =+          return $ Smarty fp exprs++pRoot =+    (stripSpace $ many1 pStmt) <* endOfInput++pStmt :: Parser SmartyStmt+pStmt =+    SmartyComment <$> pComment <|>+    SmartyText <$> pLiteral <|>+    SmartyIf <$> pIf <|>+    SmartyForeach <$> pForeach <|>+    braced (char '{') (char '}') (SmartyPrint <$> pExpr <*> many pPrintDirective) <|>+    SmartyText <$> (takeWhile1 (/='{'))++pPrintDirective :: Parser PrintDirective+pPrintDirective =+    char '|' *> pName++pExpr :: Parser Expr+pExpr =+    E.buildExpressionParser opTable pValExpr++pValExpr :: Parser Expr+pValExpr =+    braced (char '(') (char ')') pExpr <|>+    ExprVar <$> pVar <|>+    ExprLit <$> pLit <|>+    ExprFun <$> pFunCall++pLit :: Parser A.Value+pLit =+    A.String <$> stringP <|>+    A.Bool <$> boolP <|>+    A.Number <$> number++pVar :: Parser Variable+pVar =+    Variable <$> (char '$' *> pName) <*> many pVarPath <*> optional pVarIndex <*> optional pVarProp+    where+      pVarProp =+          char '@' *> pName+      pVarIndex =+          braced (char '[') (char ']') pExpr+      pVarPath =+          char '.' *> pName++pName :: Parser T.Text+pName =+    identP isAlpha isAlphaNum++pLiteral :: Parser T.Text+pLiteral =+    (pOpen "literal") *> (T.pack <$> manyTill anyChar (pClose "literal"))++pComment :: Parser T.Text+pComment =+    (string "{*") *> (T.pack <$> manyTill anyChar (string "*}"))++pFunCall :: Parser FunctionCall+pFunCall =+    FunctionCall <$> pName <*> many1 pArg+    where+      pArg =+          (,) <$> (space_ *> pName <* (stripSpace $ char '='))+              <*> pExpr++pOpen :: T.Text -> Parser T.Text+pOpen t =+    string $ T.concat [ "{", t, "}" ]++pOpenExpr :: T.Text -> Parser Expr+pOpenExpr t =+    (string (T.concat [ "{", t]) *> space_) *> pExpr <* char '}'++pClose :: T.Text -> Parser T.Text+pClose t =+    string $ T.concat [ "{/", t, "}" ]++pIf :: Parser If+pIf =+    If <$> pBranches <*> optional (pOpen "else" *> many pStmt)+       <* pClose "if"+    where+      pBranch ty = (,) <$> pOpenExpr ty <*> many pStmt+      pBranches =+          (:) <$> pBranch "if" <*> (many $ pBranch "elseif")++pForeach :: Parser Foreach+pForeach =+    Foreach <$> ((string "{foreach" *> space_) *> pExpr <* (space_ <* (string "as") <* space_))+            <*> optional (char '$' *> pName <* (stripSpace $ string "=>"))+            <*> ((stripSpace (char '$' *> pName)) <* char '}')+            <*> many pStmt+            <*> optional (pOpen "foreachelse" *> many pStmt)+            <* pClose "foreach"++opTable =+    [ [ prefix (string "not" *> space_) $ arg1 BinNot+      , prefix (char '!') $ arg1 BinNot+      ]+    , [ sym "*" (arg2 BinMul) E.AssocLeft+      , sym "/" (arg2 BinDiv) E.AssocLeft+      ]+    , [ sym "+" (arg2 BinPlus) E.AssocLeft+      , sym "-" (arg2 BinMinus) E.AssocLeft+      ]+    , [ sym "<" (arg2 BinSmaller) E.AssocNone+      , sym ">" (arg2 BinLarger) E.AssocNone+      , sym "<=" (arg2 BinSmallerEq) E.AssocNone+      , sym ">=" (arg2 BinLargerEq) E.AssocNone+      ]+    , [ sym "==" (arg2 BinEq) E.AssocNone+      , sym "!=" (arg2 (\x y ->+                            BinNot $ ExprBin $ BinEq x y+                       )) E.AssocNone+      ]+    , [ wsym "and" (arg2 BinAnd) E.AssocLeft+      , wsym "or" (arg2 BinOr) E.AssocLeft+      , sym "&&" (arg2 BinAnd) E.AssocLeft+      , sym "||" (arg2 BinOr) E.AssocLeft+      ]+    ]+    where+      arg1 fun x = ExprBin $ fun x+      arg2 fun x y = ExprBin $ fun x y++      binary op fun assoc =+          E.Infix (fun <$ op <* optSpace_) assoc+      prefix op fun =+          E.Prefix (fun <$ op <* optSpace_)+      sym s =+          binary (stripSpace $ string s)+      wsym w =+          binary (between optSpace_ space_ $ string w)++-- tests+parserTest parser input expected =+    either fail comp $ parseOnly parser input+    where+      comp x =+          assertEqual x expected++test_literalParser =+    parserTest pLiteral "{literal}abc{/literal}" "abc"++test_commentParser =+    parserTest pComment "{* some comment *}" " some comment "++test_varParser =+    parserTest pVar "$hallo.sub@prop" (Variable "hallo" ["sub"] Nothing (Just "prop"))++test_rootParser =+    parserTest pRoot "{if true}{include file='hallo.tpl' var1=23}{else}Nothing{/if}" expect+    where+      expect = [SmartyIf+                (If{if_cases =+                        [(ExprLit (A.Bool True),+                                      [SmartyPrint+                                       (ExprFun+                                        (FunctionCall{f_name = "include",+                                                      f_args =+                                                          [("file", ExprLit (A.String "hallo.tpl")),+                                                           ("var1", ExprLit (A.Number 23))]}))+                                       []])],+                        if_else = Just [SmartyText "Nothing"]})]
+ test.tpl view
@@ -0,0 +1,11 @@+<html>+<head>+  <title>{$title}</title>+</head>+<body>+{foreach $list as $item}+      <li>{$item}</li>+      <li>{$item@last}</li>+{/foreach}+</body>+</html>