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 +1/−0
- Language/Preprocessor/Cpphs/CppIfdef.hs +184/−91
- Makefile +1/−2
- Text/ParserCombinators/HuttonMeijer.hs +0/−228
- cpphs.cabal +20/−22
- cpphs.hs +1/−1
- docs/index.html +12/−3
- tests/booleanchain +21/−0
- tests/expect58 +22/−0
- tests/minversion +13/−0
- tests/runtests +1/−0
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