packages feed

cpphs 1.18.2 → 1.18.3

raw patch · 11 files changed

+276/−347 lines, 11 filesdep +polyparsedep ~base

Dependencies added: polyparse

Dependency ranges changed: base

Files

CHANGELOG view
@@ -4,6 +4,7 @@   * (1.18.1): fix incomplete pattern match   * (1.18.2): bugfix for erroneous boolean intepretation of some macro               expansions in #if clauses+  * (1.18.3): further rewrites of the #if expression parser  Version 1.17 ------------
Language/Preprocessor/Cpphs/CppIfdef.hs view
@@ -18,8 +18,8 @@   ) where  +import Text.Parse import Language.Preprocessor.Cpphs.SymTab-import Text.ParserCombinators.HuttonMeijer import Language.Preprocessor.Cpphs.Position  (Posn,newfile,newline,newlines                                              ,cppline,cpp2hask,newpos) import Language.Preprocessor.Cpphs.ReadFirst (readFirst)@@ -28,11 +28,12 @@ import Language.Preprocessor.Cpphs.HashDefine(HashDefine(..),parseHashDefine                                              ,expandMacro) import Language.Preprocessor.Cpphs.MacroPass (preDefine,defineMacro)-import Data.Char      (isDigit)-import Numeric   (readHex,readOct,readDec)+import Data.Char        (isDigit,isSpace,isAlphaNum)+import Data.List        (intercalate)+import Numeric          (readHex,readOct,readDec) import System.IO.Unsafe (unsafeInterleaveIO) import System.IO        (hPutStrLn,stderr)-import Control.Monad (when)+import Control.Monad    (when)  -- | Run a first pass of cpp, evaluating \#ifdef's and processing \#include's, --   whilst taking account of \#define's and \#undef's as we encounter them.@@ -88,8 +89,8 @@ 	"undef"  -> skipn (deleteST sym syms) True (Keep ps) xs 	"ifndef" -> skipn syms False (keepIf (not (definedST sym syms))) xs 	"ifdef"  -> skipn syms False (keepIf      (definedST sym syms)) xs-	"if"     -> skipn syms False-                               (keepIf (gatherDefined p syms (unwords line))) xs+	"if"     -> do b <- gatherDefined p syms (unwords line)+                       skipn syms False (keepIf b) xs 	"else"   -> skipn syms False (Drop 1 False ps) xs 	"elif"   -> skipn syms False (Drop 1 True ps) xs 	"endif"  | null ps ->@@ -136,7 +137,7 @@                  | otherwise = Drop n b ps         dend     | n==1      = Keep (tail ps)                  | otherwise = Drop (n-1) b (tail ps)-        delif s  | n==1 && not b && gatherDefined p syms s+        delif v  | n==1 && not b && v                              = Keep ps                  | otherwise = Drop n b ps         skipn ud xs' =@@ -146,10 +147,11 @@     in     if      cmd == "ifndef" ||             cmd == "if"     ||-            cmd == "ifdef"  then  skipn (Drop (n+1) b (p:ps)) xs-    else if cmd == "elif"   then  skipn (delif (unwords (tail ws))) xs-    else if cmd == "else"   then  skipn  delse xs-    else if cmd == "endif"  then+            cmd == "ifdef" then    skipn (Drop (n+1) b (p:ps)) xs+    else if cmd == "elif"  then do v <- gatherDefined p syms (unwords (tail ws))+                                   skipn (delif v) xs+    else if cmd == "else"  then    skipn  delse xs+    else if cmd == "endif" then             if null ps then do hPutStrLn stderr $ "Unmatched #endif at "++show p                                return []                        else skipn  dend  xs@@ -174,55 +176,130 @@   -----gatherDefined :: Posn -> SymTab HashDefine -> String -> Bool+gatherDefined :: Posn -> SymTab HashDefine -> String -> IO Bool gatherDefined p st inp =-  case papply (parseBoolExp st) inp of-    []      -> error ("Cannot parse #if directive in file "++show p)-    [(b,_)] -> b-    _       -> error ("Ambiguous parse for #if directive in file "++show p)+  case runParser (preExpand st) inp of+    (Left msg, _) -> error ("Cannot expand #if directive in file "++show p+                           ++":\n    "++msg)+    (Right s, xs) -> do+--      hPutStrLn stderr $ "Expanded #if at "++show p++" is:\n  "++s+        when (any (not . isSpace) xs) $+             hPutStrLn stderr ("Warning: trailing characters after #if"+                              ++" macro expansion in file "++show p++": "++xs) -parseBoolExp :: SymTab HashDefine -> Parser Bool-parseBoolExp st =-  do  a <- parseExp1 st-      (do skip (string "||")-          b <- first (skip (parseBoolExp st))-          return (a || b)-       +++-       do return a)+        case runParser parseBoolExp s of+          (Left msg, _) -> error ("Cannot parse #if directive in file "++show p+                                 ++":\n    "++msg)+          (Right b, xs) -> do when (any (not . isSpace) xs) $+                                   hPutStrLn stderr+                                     ("Warning: trailing characters after #if"+                                      ++" directive in file "++show p++": "++xs)+                              return b -parseExp1 :: SymTab HashDefine -> Parser Bool-parseExp1 st =-  do  a <- parseExp0 st-      (do skip (string "&&")-          b <- first (skip (parseExp1 st))-          return (a && b)-       +++-       do return a)+-- | The preprocessor must expand all macros (recursively) before evaluating+--   the conditional.+preExpand :: SymTab HashDefine -> TextParser String+preExpand st =+  do  eof+      return ""+  <|>+  do  a <- many1 (satisfy notIdent)+      commit $ pure (a++) `apply` preExpand st+  <|>+  do  b <- expandSymOrCall st+      commit $ pure (b++) `apply` preExpand st -parseExp0 :: SymTab HashDefine -> Parser Bool-parseExp0 st =-  do  skip (string "defined")-      sym <- parens parseSym-      return (definedST sym st)-  +++-  do  ()  <- expandSymOrCall st-      parseBoolExp st-  +++-  do  parens (parseBoolExp st)-  +++-  do  skip (char '!')-      a <- parseExp0 st+-- | Expansion of symbols.+expandSymOrCall :: SymTab HashDefine -> TextParser String+expandSymOrCall st =+  do  sym <- parseSym+      ( do  args <- parenthesis (commit $ fragment `sepBy` skip (isWord ","))+            args' <- flip mapM args $ \arg->+                         case runParser (preExpand st) arg of+                             (Left msg, _) -> fail msg+                             (Right s, _)  -> return s+            convert sym args'+        <|>+        do  convert sym [] )+  where+    fragment = many1 (satisfy (`notElem`",)"))+    convert "defined" [arg] =+      case lookupST arg st of+        Nothing | all isDigit arg    -> return arg +        Nothing                      -> return "0"+        Just (a@AntiDefined{})       -> return "0"+        Just (a@SymbolReplacement{}) -> return "1"+        Just (a@MacroExpansion{})    -> return "1"+    convert sym args =+      case lookupST sym st of+        Nothing  -> if null args then return sym+                    else fail (disp sym args++" is not a defined macro")+        Just (a@SymbolReplacement{}) -> do reparse (replacement a)+                                           return ""+        Just (a@MacroExpansion{})    -> do reparse (expandMacro a args False)+                                           return ""+        Just (a@AntiDefined{})       ->+                    if null args then return sym+                    else fail (disp sym args++" explicitly undefined with -U")+    disp sym args = let len = length args+                        chars = map (:[]) ['a'..'z']+                    in sym ++ if null args then ""+                              else "("++intercalate "," (take len chars)++")"++parseBoolExp :: TextParser Bool+parseBoolExp =+  do  a <- parseExp1+      bs <- many (do skip (isWord "||")+                     commit $ skip parseBoolExp)+      return $ foldr (||) a bs++parseExp1 :: TextParser Bool+parseExp1 =+  do  a <- parseExp0+      bs <- many (do skip (isWord "&&")+                     commit $ skip parseExp1)+      return $ foldr (&&) a bs++parseExp0 :: TextParser Bool+parseExp0 =+  do  skip (isWord "!")+      a <- commit $ parseExp0       return (not a)-  +++-  do  sym1 <- skip parseSym-      op   <- parseOp st-      sym2 <- skip parseSym-      return (op (safeRead sym1) (safeRead sym2))-  +++-  do  sym <- skip parseSym-      case safeRead sym of+  <|>+  do  val1 <- parseArithExp1+      op   <- parseCmpOp+      val2 <- parseArithExp1+      return (val1 `op` val2)+  <|>+  do  sym <- parseArithExp1+      case sym of         0 -> return False         _ -> return True+  <|>+  do  parenthesis (commit parseBoolExp)++parseArithExp1 :: TextParser Integer+parseArithExp1 =+  do  val1 <- parseArithExp0+      ( do op   <- parseArithOp1+           val2 <- parseArithExp1+           return (val1 `op` val2)+        <|> return val1 )+  <|>+  do  parenthesis parseArithExp1++parseArithExp0 :: TextParser Integer+parseArithExp0 =+  do  val1 <- parseNumber+      ( do op   <- parseArithOp0+           val2 <- parseArithExp0+           return (val1 `op` val2)+        <|> return val1 )+  <|>+  do  parenthesis parseArithExp0++parseNumber :: TextParser Integer+parseNumber = fmap safeRead $ skip parseSym   where     safeRead s =       case s of@@ -234,50 +311,52 @@         []        -> 0 :: Integer         ((n,_):_) -> n :: Integer -parseOp :: SymTab HashDefine -> Parser (Integer -> Integer -> Bool)-parseOp _ =-  do  skip (string ">=")+parseCmpOp :: TextParser (Integer -> Integer -> Bool)+parseCmpOp =+  do  skip (isWord ">=")       return (>=)-  +++-  do  skip (char '>')+  <|>+  do  skip (isWord ">")       return (>)-  +++-  do  skip (string "<=")+  <|>+  do  skip (isWord "<=")       return (<=)-  +++-  do  skip (char '<')+  <|>+  do  skip (isWord "<")       return (<)-  +++-  do  skip (string "==")+  <|>+  do  skip (isWord "==")       return (==)-  +++-  do  skip (string "!=")+  <|>+  do  skip (isWord "!=")       return (/=) --- | Fails if no expansion is required, to prevent infinite recursion.-expandSymOrCall :: SymTab HashDefine -> Parser ()-expandSymOrCall st =-  do  sym <- skip parseSym-      args <- parens (parseSymOrCall st `sepby` skip (char ','))-      convert sym args-  +++-  do  sym <- skip parseSym-      convert sym []-  where-    convert sym args =-      case lookupST sym st of-        Nothing  -> fail "not a macro"-        Just (a@SymbolReplacement{}) -> reparse (replacement a)-        Just (a@MacroExpansion{})    -> reparse (expandMacro a args False)-        Just (a@AntiDefined{})       -> fail "anti-defined"+parseArithOp1 :: TextParser (Integer -> Integer -> Integer)+parseArithOp1 =+  do  skip (isWord "+")+      return (+)+  <|>+  do  skip (isWord "-")+      return (-) +parseArithOp0 :: TextParser (Integer -> Integer -> Integer)+parseArithOp0 =+  do  skip (isWord "*")+      return (*)+  <|>+  do  skip (isWord "/")+      return (div)+  <|>+  do  skip (isWord "%")+      return (rem)+ -- | Return the expansion of the symbol (if there is one).-parseSymOrCall :: SymTab HashDefine -> Parser String+parseSymOrCall :: SymTab HashDefine -> TextParser String parseSymOrCall st =   do  sym <- skip parseSym-      args <- parens (parseSymOrCall st `sepby` skip (char ','))+      args <- parenthesis (commit $ parseSymOrCall st `sepBy` skip (isWord ","))       return $ convert sym args-  ++++  <|>   do  sym <- skip parseSym       return $ convert sym []   where@@ -290,14 +369,28 @@  recursivelyExpand :: SymTab HashDefine -> String -> String recursivelyExpand st inp =-  case papply (parseSymOrCall st) inp of-    [(b,_)] -> b-    _       -> inp+  case runParser (parseSymOrCall st) inp of+    (Left msg, _) -> inp+    (Right s,  _) -> s -parseSym :: Parser String-parseSym = many1 (alphanum+++char '\''+++char '`')+parseSym :: TextParser String+parseSym = many1 (satisfy (\c-> isAlphaNum c || c`elem`"'`_"))+           `onFail`+           do xs <- allAsString+              fail $ "Expected an identifier, got \""++xs++"\"" -parens p = bracket (skip (char '(')) (skip p) (skip (char ')'))+notIdent :: Char -> Bool+notIdent c = not (isAlphaNum c || c`elem`"'`_")++skip :: TextParser a -> TextParser a+skip p = many (satisfy isSpace) >> p++-- | The standard "parens" parser does not work for us here.  Define our own.+parenthesis :: TextParser a -> TextParser a+parenthesis p = do isWord "("+                   x <- p+                   isWord ")"+                   return x  -- | Determine filename in \#include file :: SymTab HashDefine -> String -> String
Makefile view
@@ -1,5 +1,5 @@ LIBRARY = cpphs-VERSION = 1.18.2+VERSION = 1.18.3  DIRS	= Language/Preprocessor/Cpphs \ 	  Text/ParserCombinators@@ -15,7 +15,6 @@           Language/Preprocessor/Cpphs/SymTab.hs \           Language/Preprocessor/Cpphs/Tokenise.hs \           Language/Preprocessor/Unlit.hs \-          Text/ParserCombinators/HuttonMeijer.hs \           cpphs.hs  AUX	= README LICENCE* CHANGELOG $(LIBRARY).cabal Setup.hs Makefile \
− Text/ParserCombinators/HuttonMeijer.hs
@@ -1,228 +0,0 @@--------------------------------------------------------------------------------- |--- Module      :  ParseLib--- Copyright   :  ...--- Copyright   :  Graham Hutton (University of Nottingham), Erik Meijer (University of Utrecht)--- --- Maintainer  :  Malcolm Wallace <Malcolm.Wallace@cs.york.ac.uk>--- Stability   :  Stable--- Portability :  All------                  A LIBRARY OF MONADIC PARSER COMBINATORS--- ---                               29th July 1996--- ---                  Graham Hutton               Erik Meijer---             University of Nottingham    University of Utrecht--- --- This Haskell script defines a library of parser combinators, and is--- taken from sections 1-6 of our article "Monadic Parser Combinators".--- Some changes to the library have been made in the move from Gofer--- to Haskell:--- ---    * Do notation is used in place of monad comprehension notation;--- ---    * The parser datatype is defined using "newtype", to avoid the overhead---      of tagging and untagging parsers with the P constructor.---------------------------------------------------------------------------------module Text.ParserCombinators.HuttonMeijer-   (Parser(..), item, first, papply, (+++), sat, {-tok,-} many, many1,-    sepby, sepby1, chainl,-    chainl1, chainr, chainr1, ops, bracket, char, digit, lower, upper,-    letter, alphanum, string, ident, nat, int, spaces, comment, junk,-    skip, token, natural, integer, symbol, identifier, reparse) where--import Data.Char-import Control.Monad--infixr 5 +++--type Token = Char-------------------------------------------------------------- | The parser monad--newtype Parser a   = P ([Token] -> [(a,[Token])])--instance Functor Parser where-   -- map         :: (a -> b) -> (Parser a -> Parser b)-   fmap f (P p)    = P (\inp -> [(f v, out) | (v,out) <- p inp])--instance Monad Parser where-   -- return      :: a -> Parser a-   return v        = P (\inp -> [(v,inp)])--   -- >>=         :: Parser a -> (a -> Parser b) -> Parser b-   (P p) >>= f     = P (\inp -> concat [papply (f v) out | (v,out) <- p inp])--   -- fail        :: String -> Parser a-   fail _          = P (\_ -> [])--instance MonadPlus Parser where-   -- mzero       :: Parser a-   mzero           = P (\_ -> [])--   -- mplus       :: Parser a -> Parser a -> Parser a-   (P p) `mplus` (P q)  = P (\inp -> (p inp ++ q inp))---- --------------------------------------------------------------- * Other primitive parser combinators--- --------------------------------------------------------------item               :: Parser Token-item                = P (\inp -> case inp of-                                   []     -> []-                                   (x:xs) -> [(x,xs)])--first             :: Parser a -> Parser a-first (P p)        = P (\inp -> case p inp of-                                   []    -> []-                                   (x:_) -> [x])--papply            :: Parser a -> [Token] -> [(a,[Token])]-papply (P p) inp   = p inp---- --------------------------------------------------------------- * Derived combinators--- --------------------------------------------------------------(+++)             :: Parser a -> Parser a -> Parser a-p +++ q            = first (p `mplus` q)--sat               :: (Token -> Bool) -> Parser Token-sat p              = do {x <- item; if p x then return x else mzero}----tok               :: Token -> Parser Token---tok t              = do {x <- item; if t==snd x then return t else mzero}--many              :: Parser a -> Parser [a]-many p             = many1 p +++ return []---many p           = force (many1 p +++ return [])--many1             :: Parser a -> Parser [a]-many1 p            = do {x <- p; xs <- many p; return (x:xs)}--sepby             :: Parser a -> Parser b -> Parser [a]-p `sepby` sep      = (p `sepby1` sep) +++ return []--sepby1            :: Parser a -> Parser b -> Parser [a]-p `sepby1` sep     = do {x <- p; xs <- many (do {sep; p}); return (x:xs)}--chainl            :: Parser a -> Parser (a -> a -> a) -> a -> Parser a-chainl p op v      = (p `chainl1` op) +++ return v--chainl1           :: Parser a -> Parser (a -> a -> a) -> Parser a-p `chainl1` op     = do {x <- p; rest x}-                     where-                        rest x = do {f <- op; y <- p; rest (f x y)}-                                 +++ return x--chainr            :: Parser a -> Parser (a -> a -> a) -> a -> Parser a-chainr p op v      = (p `chainr1` op) +++ return v--chainr1           :: Parser a -> Parser (a -> a -> a) -> Parser a-p `chainr1` op     = do {x <- p; rest x}-                     where-                        rest x = do {f <- op; y <- p `chainr1` op; return (f x y)}-                                 +++ return x--ops               :: [(Parser a, b)] -> Parser b-ops xs             = foldr1 (+++) [do {p; return op} | (p,op) <- xs]--bracket           :: Parser a -> Parser b -> Parser c -> Parser b-bracket open p close = do {open; x <- p; close; return x}---- --------------------------------------------------------------- * Useful parsers--- --------------------------------------------------------------char              :: Char -> Parser Char-char x             = sat (\y -> x == y)--digit             :: Parser Char-digit              = sat isDigit--lower             :: Parser Char-lower              = sat isLower--upper             :: Parser Char-upper              = sat isUpper--letter            :: Parser Char-letter             = sat isAlpha--alphanum          :: Parser Char-alphanum           = sat isAlphaNum +++ char '_'--string            :: String -> Parser String-string ""          = return ""-string (x:xs)      = do {char x; string xs; return (x:xs)}--ident             :: Parser String-ident              = do {x <- lower; xs <- many alphanum; return (x:xs)}--nat               :: Parser Int-nat                = do {x <- digit; return (fromEnum x - fromEnum '0')} `chainl1` return op-                     where-                        m `op` n = 10*m + n--int               :: Parser Int-int                = do {char '-'; n <- nat; return (-n)} +++ nat---- --------------------------------------------------------------- * Lexical combinators--- --------------------------------------------------------------spaces            :: Parser ()-spaces             = do {many1 (sat isSpace); return ()}--comment           :: Parser ()---comment            = do {string "--"; many (sat (\x -> x /= '\n')); return ()}---comment            = do ---                       _ <- string "--"---                       _ <- many (sat (\x -> x /= '\n'))---                       return ()-comment            = do-                       bracket (string "/*") (many item) (string "*/")-                       return ()--junk              :: Parser ()-junk               = do {many (spaces +++ comment); return ()}--skip              :: Parser a -> Parser a-skip p             = do {junk; p}--token             :: Parser a -> Parser a-token p            = do {v <- p; junk; return v}---- --------------------------------------------------------------- * Token parsers--- --------------------------------------------------------------natural           :: Parser Int-natural            = token nat--integer           :: Parser Int-integer            = token int--symbol            :: String -> Parser String-symbol xs          = token (string xs)--identifier        :: [String] -> Parser String-identifier ks      = token (do {x <- ident;-                                if not (elem x ks) then return x-                                else return mzero})----- Push some tokens back onto the input stream and reparse ---------------------- | This is useful for recursively expanding macros.  When the---   user-parser recognises a macro use, it can lookup the macro---   expansion from the parse state, lex it, and then stuff the---   lexed expansion back down into the parser.-reparse    :: [Token] -> Parser ()-reparse ts  = P (\inp-> [((), ts++inp)])---------------------------------------------------------------------------------
cpphs.cabal view
@@ -1,5 +1,5 @@ Name: cpphs-Version: 1.18.2+Version: 1.18.3 Copyright: 2004-2014, Malcolm Wallace License: LGPL License-File: LICENCE-LGPL@@ -23,21 +23,20 @@ Extra-Source-Files: README, LICENCE-GPL, LICENCE-commercial, CHANGELOG, docs/cpphs.1, docs/index.html  Library-    Build-Depends: base>3&&<6, old-locale, old-time, directory+    Build-Depends: base>3&&<6, old-locale, old-time, directory, polyparse>=1.9     Exposed-Modules:         Language.Preprocessor.Cpphs         Language.Preprocessor.Unlit     Other-Modules:-        Language.Preprocessor.Cpphs.CppIfdef,-        Language.Preprocessor.Cpphs.HashDefine,-        Language.Preprocessor.Cpphs.MacroPass,-        Language.Preprocessor.Cpphs.Options,-        Language.Preprocessor.Cpphs.Position,-        Language.Preprocessor.Cpphs.ReadFirst,-        Language.Preprocessor.Cpphs.RunCpphs,-        Language.Preprocessor.Cpphs.SymTab,-        Language.Preprocessor.Cpphs.Tokenise,-        Text.ParserCombinators.HuttonMeijer+        Language.Preprocessor.Cpphs.CppIfdef+        Language.Preprocessor.Cpphs.HashDefine+        Language.Preprocessor.Cpphs.MacroPass+        Language.Preprocessor.Cpphs.Options+        Language.Preprocessor.Cpphs.Position+        Language.Preprocessor.Cpphs.ReadFirst+        Language.Preprocessor.Cpphs.RunCpphs+        Language.Preprocessor.Cpphs.SymTab+        Language.Preprocessor.Cpphs.Tokenise  Executable cpphs     Build-Depends: base>3&&<6, old-locale, old-time, directory@@ -45,16 +44,15 @@     Other-Modules:         Language.Preprocessor.Cpphs         Language.Preprocessor.Unlit-        Language.Preprocessor.Cpphs.CppIfdef,-        Language.Preprocessor.Cpphs.HashDefine,-        Language.Preprocessor.Cpphs.MacroPass,-        Language.Preprocessor.Cpphs.Options,-        Language.Preprocessor.Cpphs.Position,-        Language.Preprocessor.Cpphs.ReadFirst,-        Language.Preprocessor.Cpphs.RunCpphs,-        Language.Preprocessor.Cpphs.SymTab,-        Language.Preprocessor.Cpphs.Tokenise,-        Text.ParserCombinators.HuttonMeijer+        Language.Preprocessor.Cpphs.CppIfdef+        Language.Preprocessor.Cpphs.HashDefine+        Language.Preprocessor.Cpphs.MacroPass+        Language.Preprocessor.Cpphs.Options+        Language.Preprocessor.Cpphs.Position+        Language.Preprocessor.Cpphs.ReadFirst+        Language.Preprocessor.Cpphs.RunCpphs+        Language.Preprocessor.Cpphs.SymTab+        Language.Preprocessor.Cpphs.Tokenise  Source-Repository head     Type:     darcs
cpphs.hs view
@@ -20,7 +20,7 @@ import Data.List   ( isPrefixOf )  version :: String-version = "1.18.1"+version = "1.18.3"  main :: IO () main = do
docs/index.html view
@@ -198,12 +198,12 @@ <b>Current stable version:</b>  <p>-cpphs-1.18.2, release date 2014.02.24<br>+cpphs-1.18.3, release date 2014.03.03<br> By HTTP: <a href="http://hackage.haskell.org/package/cpphs">Hackage</a>. <ul>-<li> bugfix for erroneous boolean interpretation of some macro-     expansions in #if clauses+<li> further rewrites of the #if expression parser, for better error messages,+     support for integer operations, and fewer precedence bugs </ul>  <p>@@ -225,6 +225,15 @@  <p> <b>Older versions:</b>++<p>+cpphs-1.18.2, release date 2014.02.24<br>+By HTTP:+<a href="http://hackage.haskell.org/package/cpphs">Hackage</a>.+<ul>+<li> bugfix for erroneous boolean interpretation of some macro+     expansions in #if clauses+</ul>  <p> cpphs-1.18.1, release date 2014.02.18<br>
+ tests/booleanchain view
@@ -0,0 +1,21 @@+#define MIN_VERSION_base(x,y,z) (x>=4) && (y>=9) && (z>=0)+This file tests the #if boolean expression parser/evaluator.+#if !MIN_VERSION_base(4, 7, 0)+SUCCEED with not and no parens+#endif+#if !(MIN_VERSION_base(4, 7, 0))+SUCCEED with not and parens+#endif++Then we check for arithmetic.+#define AT_LEAST_4(x) ((x)>=4)+#if AT_LEAST_4(2+3)+simple ARITHMETIC works+#else+simple ARITHMETIC broken+#endif+#if 2+3 > 4 && 1+12*2*1+2 == 27+complex ARITHMETIC works+#else+complex ARITHMETIC broken+#endif
+ tests/expect58 view
@@ -0,0 +1,22 @@+#line 1 "booleanchain"++This file tests the #if boolean expression parser/evaluator.+++++SUCCEED with not and parens+++Then we check for arithmetic.+++simple ARITHMETIC works+++++complex ARITHMETIC works+++
+ tests/minversion view
@@ -0,0 +1,13 @@+#define MIN_VERSION_base(x,y,z) (x>=4) && (y>=5) && (z>=1)++#if !(MIN_VERSION_base(4, 7, 0))+import Data.Typeable     (Typeable2, typeOf2, mkTyConApp)+version not 4.7.0+#endif+#if MIN_VERSION_base(4, 4, 0)+import Data.Typeable     (mkTyCon3)+version 4.4.0+#else+import Data.Typeable     (mkTyCon)+version any+#endif
tests/runtests view
@@ -75,4 +75,5 @@ runtest "$CPPHS ballard" expect55 runtest "$CPPHS th" expect56 runtest "$CPPHS cheplyaka" expect57+runtest "$CPPHS booleanchain" expect58 exit $FAIL