haskell-exp-parser (empty) → 0.1
raw patch · 5 files changed
+243/−0 lines, 5 filesdep +basedep +haskell-exp-parserdep +template-haskellsetup-changed
Dependencies added: base, haskell-exp-parser, template-haskell
Files
- LICENSE +30/−0
- Setup.hs +2/−0
- haskell-exp-parser.cabal +58/−0
- src/Language/Haskell/ParseExp.hs +129/−0
- tests/Splice.hs +24/−0
+ LICENSE view
@@ -0,0 +1,30 @@+Copyright (c) 2015, Emil Axelsson++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 Emil Axelsson 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
+ haskell-exp-parser.cabal view
@@ -0,0 +1,58 @@+name: haskell-exp-parser+version: 0.1+synopsis: Simple parser parser from Haskell to TemplateHaskell expressions+description: This package defines a simple parser for a subset of Haskell expressions and patterns to the TemplateHaskell AST.+ .+ It provides a very lightweight alternative to the functions @parseExp@ and @parsePat@ from <http://hackage.haskell.org/package/haskell-src-meta>.+ .+ The following expressions are currently supported:+ .+ * Variables+ * Integer and string literals+ * Prefix function application+ * Lists and tuples+ .+ The following patterns are currently supported:+ .+ * Variables+license: BSD3+license-file: LICENSE+author: Emil Axelsson+maintainer: emax@chalmers.se+copyright: Copyright (c) 2015, Emil Axelsson+homepage: https://github.com/emilaxelsson/haskell-exp-parser+bug-reports: https://github.com/emilaxelsson/haskell-exp-parser/issues+category: Language+build-type: Simple+cabal-version: >=1.10++source-repository head+ type: git+ location: git@github.com:emilaxelsson/haskell-exp-parser.git++library+ exposed-modules:+ Language.Haskell.ParseExp++ build-depends:+ base >=4 && <5,+ template-haskell++ hs-source-dirs: src++ default-language: Haskell2010++test-suite Tests+ type: exitcode-stdio-1.0++ hs-source-dirs: tests++ main-is: Splice.hs++ default-language: Haskell2010++ build-depends:+ base,+ haskell-exp-parser,+ template-haskell+
+ src/Language/Haskell/ParseExp.hs view
@@ -0,0 +1,129 @@+-- | Simple parser for a subset of Haskell expressions and patterns to the+-- TemplateHaskell AST+--+-- The following expressions are currently supported:+--+-- * Variables+-- * Integer and string literals+-- * Prefix function application+-- * Lists and tuples+--+-- The following patterns are currently supported:+--+-- * Variables++module Language.Haskell.ParseExp+ ( parseExp+ , parsePat+ ) where++++import Control.Monad+import Data.Char+import Language.Haskell.TH+import Text.ParserCombinators.ReadP++++-- | Skip any amount of whitespace+skipSpace :: ReadP ()+skipSpace = void $ munch isSpace++-- | Check if a character is a valid non-initial character in a name (variable+-- or constructor)+nameChar :: Char -> Bool+nameChar c = isAlphaNum c || elem c ['\'','_']++-- | Parse a Haskell variable name+name :: ReadP Name+name = do+ skipSpace+ h <- get+ guard ('a' <= h && h <= 'z')+ rest <- munch nameChar+ return $ mkName (h:rest)++-- | Parse a Haskell variable+variable :: ReadP Exp+variable = fmap VarE name++-- | Parse a Haskell Constructor+constructor :: ReadP Exp+constructor = do+ skipSpace+ h <- get+ guard ('A' <= h && h <= 'Z')+ rest <- munch nameChar+ return $ ConE $ mkName (h:rest)++-- | Parse an integer+integer :: Bool -> ReadP Integer+integer first = do+ c:_ <- look+ guard (first || isNumber c)+ readS_to_P reads++-- | Parse a Haskell literal+literal :: Bool -> ReadP Exp+literal first+ = fmap (LitE . IntegerL) (integer first)+ <++ fmap (LitE . CharL) (readS_to_P reads)+ <++ fmap (LitE . StringL) (readS_to_P reads)++-- | Parse a comma-separated list of expressions+expressionList :: ReadP [Exp]+expressionList = expression `sepBy` char ','++-- | Parse a list expression+list :: ReadP Exp+list = fmap ListE $ between (char '[') (char ']') expressionList++-- | Parse a tuple expression+--+-- This also handles empty tuples ('()') and parenthesized expressions+tuple :: ReadP Exp+tuple = do+ es <- between (char '(') (char ')') (skipSpace >> expressionList)+ -- skipSpace needed to parse empty tuples with space inside+ case es of+ [] -> return $ ConE $ mkName "()"+ [e] -> return e+ _ -> return $ TupE es++-- | Parse an expression that is not an application+expPart :: Bool -> ReadP Exp+expPart first = do+ skipSpace+ pfail <++ variable+ <++ constructor+ <++ list+ <++ literal first+ <++ tuple+ -- Must handle lists before literals, because the "['a']" is accepted as a+ -- String literal++-- | Expression parser+expression :: ReadP Exp+expression = do+ skipSpace+ f <- expPart True+ args <- many (expPart False)+ let expr = foldl AppE f args+ skipSpace+ return expr++-- | Parse a Haskell expression (the supported subset is given above)+parseExp :: String -> Either String Exp+parseExp str = case [expr | (expr,"") <- readP_to_S expression str] of+ [expr] -> return expr+ _ -> fail $ "parseExp: cannot parse '" ++ str ++ "'"+ ++ " (parseExp only supports a limited subset of Haskell)"++-- | Parse a Haskell pattern (the supported subset is given above)+parsePat :: String -> Either String Pat+parsePat str = case [pat | (pat,"") <- readP_to_S name str] of+ [pat] -> return (VarP pat)+ _ -> fail $ "parsePat: cannot parse '" ++ str ++ "'"+ ++ " (parsePat only supports a limited subset of Haskell)"+
+ tests/Splice.hs view
@@ -0,0 +1,24 @@+{-# LANGUAGE TemplateHaskell #-}++import System.Exit++import ParseExp++++tests =+ [ (show ($exp1), show "sdf")+ , (show ($exp2), show (sum [1,2,3]))+ , (show ($exp3), show (min (max (negate (-34)) 888) (signum (-45))))+ , (show ($exp4), show ( min ( max ( negate ( - 34 ) ) 888 ) ( signum ( - 45 ) ) ))+ , (show ($exp5), show ([(1,'a'),(2,'b'),(3,'c')]))+ ]++main = if and oks+ then putStrLn "All tests passed"+ else do+ putStrLn $ "Tests " ++ show [i | (i,False) <- zip [1..] oks] ++ " failed"+ exitFailure+ where+ oks = map (uncurry (==)) tests+