From: <cod...@go...> - 2008-09-28 20:59:04
|
Author: wol...@gm... Date: Sun Sep 28 13:58:13 2008 New Revision: 317 Modified: trunk/hoc/InterfaceGenerator2/BindingScript.hs trunk/hoc/InterfaceGenerator2/Headers.hs trunk/hoc/InterfaceGenerator2/Messages.hs trunk/hoc/InterfaceGenerator2/Parser.hs trunk/hoc/InterfaceGenerator2/Preprocessor.hs Log: Further parser improvements: * some bugfixes * recognise & skip inline functions * require parsec 3.0 * output warning messages for unhandled enum values Modified: trunk/hoc/InterfaceGenerator2/BindingScript.hs ============================================================================== --- trunk/hoc/InterfaceGenerator2/BindingScript.hs (original) +++ trunk/hoc/InterfaceGenerator2/BindingScript.hs Sun Sep 28 13:58:13 2008 @@ -13,6 +13,7 @@ Selector(..) ) import qualified Parser(selector) +import Parser(Parser) import Control.Monad(when) import qualified Data.Map as Map @@ -20,9 +21,10 @@ import qualified Data.Set as Set hiding (Set) import Data.List(intersperse) -import Text.ParserCombinators.Parsec.Language(haskellStyle) -import Text.ParserCombinators.Parsec.Token -import Text.ParserCombinators.Parsec +import Text.Parsec.Token +import Text.Parsec + +import Messages data BindingScript = BindingScript { bsHiddenFromPrelude :: Set String, @@ -80,10 +82,23 @@ where top = bsTopLevelOptions bindingScript -tokenParser :: TokenParser () -tokenParser = makeTokenParser $ haskellStyle { identStart = letter <|> char '_' } +tokenParser :: GenTokenParser String () Messages +tokenParser = makeTokenParser $ + LanguageDef + { commentStart = "{-" + , commentEnd = "-}" + , commentLine = "--" + , nestedComments = True + , identStart = letter <|> char '_' + , identLetter = alphaNum <|> oneOf "_'" + , opStart = oneOf ":!#$%&*+./<=>?@\\^|-~" + , opLetter = oneOf ":!#$%&*+./<=>?@\\^|-~" + , reservedOpNames= [] + , reservedNames = [] + , caseSensitive = True + } -selector, qualified :: TokenParser () -> Parser String +selector, qualified :: GenTokenParser String () Messages -> Parser String selector tp = lexeme tp $ do c <- letter <|> char '_' s <- many (alphaNum <|> oneOf "_:") @@ -181,7 +196,8 @@ readBindingScript :: String -> IO BindingScript readBindingScript fn = do - either <- parseFromFile bindingScript fn + f <- readFile fn + let (either, messages) = runMessages (runParserT bindingScript () fn f) case either of Left err -> error (show err) Right result -> return result Modified: trunk/hoc/InterfaceGenerator2/Headers.hs ============================================================================== --- trunk/hoc/InterfaceGenerator2/Headers.hs (original) +++ trunk/hoc/InterfaceGenerator2/Headers.hs Sun Sep 28 13:58:13 2008 @@ -14,7 +14,8 @@ import Data.Maybe(mapMaybe) import System.Directory(getDirectoryContents) import System.Info(os) -import Text.ParserCombinators.Parsec(parse) +import Text.Parsec( runParserT ) +import Messages( runMessages ) import Data.ByteString.Char8(ByteString) import qualified Data.ByteString.Char8 as BS import Progress @@ -71,7 +72,10 @@ let imports = findImports contents preprocessed = preprocess headerFileName {- stripPreprocessor -} contents when dumpPreprocessed $ writeFile ("preprocessed-" ++ headerFileName) $ preprocessed - result <- case parse header headerFileName preprocessed of + + let (parseResult, parseMessages) = runMessages (runParserT header () headerFileName preprocessed) + mapM_ print parseMessages + result <- case parseResult of Left err -> error $ show err Right decls -> do when dumpParsed $ writeFile ("parsed-" ++ headerFileName) $ unlines $ map show decls Modified: trunk/hoc/InterfaceGenerator2/Messages.hs ============================================================================== --- trunk/hoc/InterfaceGenerator2/Messages.hs (original) +++ trunk/hoc/InterfaceGenerator2/Messages.hs Sun Sep 28 13:58:13 2008 @@ -24,7 +24,7 @@ -- mappend a EmptyBag = a more lazyness! mappend a b = BagOfTwo a b -type Messages a = Writer (Bag Doc) a +type Messages = Writer (Bag Doc) message d = tell (UnitBag d) runMessages :: Messages a -> (a, [Doc]) Modified: trunk/hoc/InterfaceGenerator2/Parser.hs ============================================================================== --- trunk/hoc/InterfaceGenerator2/Parser.hs (original) +++ trunk/hoc/InterfaceGenerator2/Parser.hs Sun Sep 28 13:58:13 2008 @@ -1,47 +1,66 @@ -module Parser( header, selector ) where +{-# LANGUAGE TypeSynonymInstances #-} +module Parser( Parser, header, selector ) where import Data.Maybe(catMaybes, isJust, fromJust) import Data.Char(ord, isUpper, isDigit) import Data.Bits(shiftL, (.|.)) import Control.Monad(guard) -import Text.ParserCombinators.Parsec -import Text.ParserCombinators.Parsec.Token -import Text.ParserCombinators.Parsec.Language(emptyDef) -import Text.ParserCombinators.Parsec.Expr +import Text.Parsec +import Text.Parsec.Token +import Text.Parsec.Language(emptyDef) +import Text.Parsec.Expr import SyntaxTree import qualified Data.Map as Map -objcDef = emptyDef +import Control.Monad.Trans( lift ) +import Messages + +import qualified Text.PrettyPrint.HughesPJ as PP + +type Parser a = ParsecT String () Messages a + +objcDef = LanguageDef { commentStart = "/*" , commentEnd = "*/" , commentLine = "//" , nestedComments = False , identStart = letter <|> char '_' , identLetter = alphaNum <|> char '_' + , opStart = oneOf ":!#$%&*+./<=>?@\\^|-~" + , opLetter = oneOf ":!#$%&*+./<=>?@\\^|-~" + , reservedOpNames = [] , reservedNames = ["@class","@protocol","@interface","@implementation","@end","@property", - "const", "volatile", "struct", "union", "enum", + "const", "volatile", "struct", "union", "enum", "typedef", "__attribute__", "__strong", "@required", "@optional", "@private", "@public" ] , caseSensitive = True } -objc :: TokenParser () +objc :: GenTokenParser String () Messages objc = makeTokenParser objcDef singleton x = [x] +parseWarning :: String -> Parser () +parseWarning msg + = do + pos <- getPosition + lift (message $ PP.text (show pos ++ ": " ++ msg)) + header :: Parser [Declaration] header = do optional (whiteSpace objc) - fmap concat $ many $ do + things <- fmap concat $ many $ do -- thing <- try interestingThing <|> uninterestingThing -- lenient parsing thing <- interestingThing -- strict parsing optional (whiteSpace objc) return thing + eof + return things uninterestingThing :: Parser (Maybe Declaration) uninterestingThing = skipMany1 (satisfy (\x -> x /= '@' && x /= ';')) >> return Nothing @@ -52,6 +71,9 @@ <|> interface_decl <|> empty_decl <|> type_declaration + <|> (reserved objc "CF_EXTERN_C_BEGIN" >> return []) + <|> (reserved objc "CF_EXTERN_C_END" >> return []) + <|> inline_function <|> extern_decl <|> (semi objc >> return []) @@ -225,12 +247,6 @@ (_, tf) <- declarator True (optional $ identifier objc) return $ Just $ tf t - -testdecl :: String -> IO () -testdecl s = case parse (declarator True (return ()){- (identifier objc)-}) "" s of - Right (n, t) -> print $ t (CTSimple "void") - Left e -> print e - ctype = do simple <- type_no_pointers (_, f) <- declarator True (return ()) @@ -290,7 +306,8 @@ basic = suffixedInteger <|> multiCharConstant <|> (do name <- identifier objc - Map.lookup name env) +-- Map.lookup name env <?> (name ++ " undefined")) + Map.lookup name env <|> (parseWarning (name ++ " undefined") >> fail "")) <|> parens objc expr optable = [ [Infix shiftLeft AssocLeft], [Infix bitwiseOr AssocLeft] ] @@ -322,6 +339,7 @@ >> option [] (enum_body env' (Just val)) return $ (id, GivenValue val) : xs Nothing -> do + parseWarning $ "Couldn't handle enum value for " ++ id xs <- option [] $ comma objc >> option [] (enum_body env Nothing) return $ (id, TooComplicatedValue "") : xs @@ -335,7 +353,7 @@ return $ key id body where struct_union_body = try (many member) - <|> (skipBlockContents >> return []) + <|> (skipBlockContents >> parseWarning "problem parsing struct" >> return []) member = do typ <- type_no_pointers things <- commaSep objc $ do @@ -343,6 +361,7 @@ bitfield <- option Nothing (symbol objc ":" >> integer objc >>= return . Just) return (name, typeModifiers) + availability semi objc return [ (modifier typ, name) | (name, modifier) <- things ] @@ -381,7 +400,7 @@ extern_decl = do - extern_keyword + optional extern_keyword t <- type_no_pointers vars <- commaSep objc (one_var t) availability @@ -395,7 +414,8 @@ -> ExternFun (Selector n retval args varargs) otherType -> ExternVar otherType n - + +availability :: Parser () availability = optional $ do reserved objc "__attribute__" parens objc (skipParens) @@ -410,7 +430,9 @@ <|> reserved objc "FOUNDATION_EXPORT" -- N.B. "Export" vs. "Extern". <|> reserved objc "APPKIT_EXTERN" <|> reserved objc "GS_EXPORT" - + <|> reserved objc "CA_EXTERN" + <|> reserved objc "CF_EXPORT" + skipParens = parens objc (skipMany ( (satisfy (\x -> x /= '(' && x /= ')') >> return ()) <|> skipParens @@ -423,3 +445,12 @@ skipBlock = braces objc skipBlockContents skipEnumValue = skipMany1 (satisfy (\x -> x /= '}' && x /= ',')) + +inline_function = + do + reserved objc "inline" <|> reserved objc "NS_INLINE" + <|> reserved objc "CF_INLINE" + t <- type_no_pointers + (n, tf) <- id_declarator + skipBlock + return [] Modified: trunk/hoc/InterfaceGenerator2/Preprocessor.hs ============================================================================== --- trunk/hoc/InterfaceGenerator2/Preprocessor.hs (original) +++ trunk/hoc/InterfaceGenerator2/Preprocessor.hs Sun Sep 28 13:58:13 2008 @@ -1,9 +1,9 @@ module Preprocessor( preprocess ) where -import Text.ParserCombinators.Parsec -import Text.ParserCombinators.Parsec.Token -import Text.ParserCombinators.Parsec.Language(emptyDef) -import Text.ParserCombinators.Parsec.Expr +import Text.Parsec +import Text.Parsec.Token +import Text.Parsec.Language(emptyDef) +import Text.Parsec.Expr import Control.Monad.State as StateM @@ -54,7 +54,7 @@ expression = try (buildExpressionParser optable basic) <|> return (return 0) where - basic :: CharParser () Expr + basic :: Parsec String () Expr basic = do i <- integer cpp return (return i) <|> do reserved cpp "defined" @@ -145,7 +145,15 @@ parseDirectives = map (\l -> case parse line "" l of Left e -> Text $ l ++ "// " ++ show (show e) - Right x -> x) . lines . unblockComments + Right x -> x) . handleBackslashes . lines . unblockComments + +handleBackslashes [] = [] +handleBackslashes (l : ls) + | null l = [] : handleBackslashes ls + | last l == '\\' = case handleBackslashes ls of + (l2 : ls') -> (l ++ '\n' : l2) : ls' + ls' -> ls' + | otherwise = l : handleBackslashes ls preprocess fn f = execute fn $ parseDirectives f |