diff --git a/HSmarty.cabal b/HSmarty.cabal
new file mode 100644
--- /dev/null
+++ b/HSmarty.cabal
@@ -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
diff --git a/LICENSE b/LICENSE
new file mode 100644
--- /dev/null
+++ b/LICENSE
@@ -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.
diff --git a/Setup.hs b/Setup.hs
new file mode 100644
--- /dev/null
+++ b/Setup.hs
@@ -0,0 +1,2 @@
+import Distribution.Simple
+main = defaultMain
diff --git a/Tests.hs b/Tests.hs
new file mode 100644
--- /dev/null
+++ b/Tests.hs
@@ -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
diff --git a/Text/HSmarty.hs b/Text/HSmarty.hs
new file mode 100644
--- /dev/null
+++ b/Text/HSmarty.hs
@@ -0,0 +1,5 @@
+module Text.HSmarty
+    (module Text.HSmarty.Render.Engine)
+where
+
+import Text.HSmarty.Render.Engine
diff --git a/Text/HSmarty/Parser/Smarty.hs b/Text/HSmarty/Parser/Smarty.hs
new file mode 100644
--- /dev/null
+++ b/Text/HSmarty/Parser/Smarty.hs
@@ -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"]})]
diff --git a/test.tpl b/test.tpl
new file mode 100644
--- /dev/null
+++ b/test.tpl
@@ -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>
