From: <cod...@go...> - 2008-09-28 23:01:21
|
Author: wol...@gm... Date: Sun Sep 28 16:00:58 2008 New Revision: 319 Modified: trunk/hoc/InterfaceGenerator2/Headers.hs trunk/hoc/InterfaceGenerator2/Parser.hs Log: Some more cleanup Modified: trunk/hoc/InterfaceGenerator2/Headers.hs ============================================================================== --- trunk/hoc/InterfaceGenerator2/Headers.hs (original) +++ trunk/hoc/InterfaceGenerator2/Headers.hs Sun Sep 28 16:00:58 2008 @@ -26,20 +26,6 @@ data HeaderInfo = HeaderInfo ModuleName [ModuleName] [Declaration] deriving(Show) -stripPreprocessor = unlines . stripPP . lines - where - stripPP (('#':'e':'l':'s':'e':_) : xs) = "" : dropElseHack xs - stripPP (x@('#':_) : xs) = dropPreprocessorLine x xs - stripPP (x : xs) = x : stripPP xs - stripPP [] = [] - dropPreprocessorLine x xs - | last x == '\\' = "" : dropPreprocessorLine (head xs) (tail xs) - | otherwise = "" : stripPP xs - - dropElseHack (('#':'e':'n':'d':'i':'f':_) : xs) = "" : stripPP xs - dropElseHack (x : xs) = "" : dropElseHack xs - dropElseHack [] = [] - findImports = mapMaybe checkImport . lines where checkImport line @@ -70,7 +56,7 @@ contents <- readFile $ headerPathName evaluate (length contents) let imports = findImports contents - preprocessed = preprocess headerFileName {- stripPreprocessor -} contents + preprocessed = preprocess headerFileName contents when dumpPreprocessed $ writeFile ("preprocessed-" ++ headerFileName) $ preprocessed let (parseResult, parseMessages) = runMessages (runParserT header () headerFileName preprocessed) Modified: trunk/hoc/InterfaceGenerator2/Parser.hs ============================================================================== --- trunk/hoc/InterfaceGenerator2/Parser.hs (original) +++ trunk/hoc/InterfaceGenerator2/Parser.hs Sun Sep 28 16:00:58 2008 @@ -22,6 +22,9 @@ type Parser a = ParsecT String () Messages a +-- type Parser a = forall b. ParsecT String b Messages a + + objcDef = LanguageDef { commentStart = "/*" , commentEnd = "*/" @@ -66,144 +69,126 @@ uninterestingThing = skipMany1 (satisfy (\x -> x /= '@' && x /= ';')) >> return Nothing interestingThing = - class_decl + ignoredToplevelThing + <|> class_decl <|> (try protocol_decl) <|> 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 []) -empty_decl = semi objc >> return [] +ignoredToplevelThing + = (foldl1 (<|>) . map (reserved objc)) + ["CA_EXTERN_C_BEGIN", "CA_EXTERN_C_END", + "CF_EXTERN_C_BEGIN", "CF_EXTERN_C_END"] + >> return [] +-- -class_decl = do - reserved objc "@class" - classes <- commaSep1 objc (identifier objc) - semi objc - return [ForwardClass classes] +skipParens = parens objc (skipMany ( + (satisfy (\x -> x /= '(' && x /= ')') >> return ()) + <|> skipParens + )) -protocol_decl = do - reserved objc "@protocol" - protos <- commaSep1 objc (identifier objc) - semi objc - return [ForwardProtocol protos] +skipBlockContents = (skipMany ( + (satisfy (\x -> x /= '{' && x /= '}') >> return ()) + <|> skipBlock + )) +skipBlock = braces objc skipBlockContents -interface_decl = do - proto <- (reserved objc "@interface" >> return False) - <|> (reserved objc "@protocol" >> return True) - class_name <- identifier objc - what <- if proto - then do - protos <- protocol_spec - return $ Protocol class_name protos - else (do - cat_name <- category_spec - protos <- protocol_spec - return $ Category class_name cat_name protos - ) <|> (do - super <- superclass_spec - protos <- protocol_spec - return $ Interface class_name super protos - ) - instance_variables - selectors <- fmap concat $ many selectorListItem - reserved objc "@end" - return [SelectorList what selectors] - -category_spec = parens objc (identifier objc) - -superclass_spec = (do - colon objc - superclass <- identifier objc - return $ Just superclass - ) <|> return Nothing - -protocol_spec = - angles objc (commaSep1 objc (identifier objc)) - <|> return [] - -instance_variables = skipBlock <|> return () +skipEnumValue = skipMany1 (satisfy (\x -> x /= '}' && x /= ',')) -selectorListItem - = fmap singleton selector - <|> fmap (map LocalDecl) type_declaration - <|> fmap (map LocalDecl) extern_decl - <|> property_declaration - <|> fmap singleton requiredOrOptional - <|> (semi objc >> return []) +-- Plain C -requiredOrOptional - = (reserved objc "@required" >> return (Required True)) - <|> (reserved objc "@optional" >> return (Required False)) +empty_decl :: Parser [a] +empty_decl = semi objc >> return [] -selector = do - classOrInstanceMethod <- - (symbol objc "-" >> return InstanceMethod) - <|> (symbol objc "+" >> return ClassMethod) - -- str <- many (satisfy (\c -> c /= ';' && c /= '@')) - rettype <- type_spec - (name,types,vararg) <- ( + +const_int_expr :: Map.Map String Integer -> Parser Integer +const_int_expr env = expr + where + expr = buildExpressionParser optable basic + + basic = suffixedInteger + <|> multiCharConstant + <|> definedConstant + <|> parens objc expr + + optable = [ [Infix (op "<<" (cast2nd shiftL)) AssocLeft], + [Infix (op "|" (.|.)) AssocLeft] ] + where + op str f = reservedOp objc str >> return f + cast2nd f x y = f x (fromIntegral y) + + suffixedInteger = do - manythings <- many1 (try $ do - namePart <- identifier objc <|> return "" - colon objc - argType <- type_spec - argName <- identifier objc - return (namePart, argType) - ) - vararg <- (symbol objc "," >> symbol objc "..." >> return True) <|> return False - let (nameParts,types) = unzip manythings - return (concat $ map (++":") nameParts , types, vararg) - ) <|> ( + val <- integer objc + optional (reserved objc "U" <|> reserved objc "L" + <|> reserved objc "UL") -- ### TODO: no space allowed before 'U' + return val + + multiCharConstant = + lexeme objc (between (char '\'') (char '\'') multiChars) + where + multiChars = do + chars <- many1 (satisfy (/= '\'')) + return $ sum $ zipWith (*) + (map (fromIntegral.ord) $ reverse chars) + (iterate (*256) 1) + + definedConstant = do name <- identifier objc - return (name,[],False) - ) - availability - semi objc - return (classOrInstanceMethod $ Selector name rettype types vararg) - -property_declaration - = do - reserved objc "@property" - properties <- option [] (parens objc (commaSep objc $ property_attribute)) - basetype <- type_no_pointers - things <- commaSep objc id_declarator - availability - semi objc - return $ map (\ (name, typeModifiers) -> PropertyDecl $ - Property (typeModifiers $ basetype) - name properties ) things - -property_attribute = - (do reserved objc "getter" - symbol objc "=" - name <- identifier objc - return $ Getter name) - <|> (do reserved objc "setter" - symbol objc "=" - name <- identifier objc - symbol objc ":" - return $ Setter (name ++ ":")) - <|> (reserved objc "readonly" >> return ReadOnly) - <|> (reserved objc "readwrite" >> return ReadWrite) - <|> (reserved objc "assign" >> return Assign) - <|> (reserved objc "retain" >> return Retain) - <|> (reserved objc "copy" >> return Copy) + Map.lookup name env <|> (parseWarning (name ++ " undefined") >> fail "") +-- A ctype is a complete C type, as you'd write it in a cast expression. +-- Examples include "int", "const char*", and "void (*)(int, float[3])" +ctype = do + simple <- simple_type + (_, f) <- declarator True (return ()) + return (f simple) ---type_spec = try (parens objc ctype) <|> (skipParens >> return CTUnknown) <|> return (CTIDType []) -type_spec = parens objc ctype <|> return (CTIDType []) +-- A simple_type is a C type without any pointers, arrays or functions. +-- (but including struct, enum and union declarations). +-- If you declare multiple variables in one C declaration, the simple_type +-- is what they have in common. +-- Examples include "int", "const char", "char const", "struct {int *x;}", +-- but NOT "const char*". -type_no_pointers = do -- "const char" in "const char *foo[32]" +simple_type = do -- "const char" in "const char *foo[32]" many ignored_type_qualifier -- ignore - t <- simple_type + t <- id_type + <|> enum_type + <|> struct_type + <|> try builtin_type + <|> do n <- identifier objc + protos <- protocol_spec -- TOOD: use these protocols + return $ CTSimple n many ignored_type_qualifier return t +ignored_type_qualifier = + reserved objc "const" + <|> reserved objc "volatile" + <|> reserved objc "in" + <|> reserved objc "out" + <|> reserved objc "inout" + <|> reserved objc "bycopy" + <|> reserved objc "byref" + <|> reserved objc "oneway" + <|> reserved objc "__strong" + +-- An id_declarator is an identifier surrounded by things like "*", "[]" and +-- function arguments. +-- In a declaration of a single C variable or function, everything except the +-- simple_type is part of the id_declarator. +-- In the declaration "const char *x[32]", "*x[32]" is the id_declarator. +-- The parser returns the identifier and a function that transforms the +-- simple_type ("const char" in the example) to the type of the identifier +-- ("const char * [32]" in the example). + +id_declarator :: Parser (String, CType -> CType) id_declarator = declarator False (identifier objc) declarator :: Bool -> Parser a -> Parser (a, CType -> CType) @@ -243,20 +228,11 @@ argument = (symbol objc "..." >> return Nothing) <|> do - t <- type_no_pointers + t <- simple_type (_, tf) <- declarator True (optional $ identifier objc) return $ Just $ tf t - -ctype = do - simple <- type_no_pointers - (_, f) <- declarator True (return ()) - return (f simple) -simple_type = id_type <|> enum_type <|> struct_type <|> try builtin_type - <|> do - n <- identifier objc - protos <- protocol_spec -- TOOD: use these protocols - return $ CTSimple n + builtin_type = do signedness <- (reserved objc "signed" >> return (Just True)) @@ -283,39 +259,6 @@ return $ CTIDType protos -multiCharConstant = - lexeme objc (between (char '\'') (char '\'') multiChars) - where - multiChars = do - chars <- many1 (satisfy (/= '\'')) - return $ sum $ zipWith (*) - (map (fromIntegral.ord) $ reverse chars) - (iterate (*256) 1) - - -suffixedInteger = - do - val <- integer objc - optional (reserved objc "U" <|> reserved objc "L" - <|> reserved objc "UL") -- ### TODO: no space allowed before 'U' - return val - -const_int_expr env = expr - where - expr = buildExpressionParser optable basic - basic = suffixedInteger - <|> multiCharConstant - <|> (do name <- identifier objc --- Map.lookup name env <?> (name ++ " undefined")) - Map.lookup name env <|> (parseWarning (name ++ " undefined") >> fail "")) - <|> parens objc expr - optable = [ [Infix shiftLeft AssocLeft], - [Infix bitwiseOr AssocLeft] ] - - shiftLeft = op "<<" (flip $ flip shiftL . fromIntegral) - bitwiseOr = op "|" (.|.) - - op str f = reservedOp objc str >> return f enum_type = do @@ -355,7 +298,7 @@ struct_union_body = try (many member) <|> (skipBlockContents >> parseWarning "problem parsing struct" >> return []) member = do - typ <- type_no_pointers + typ <- simple_type things <- commaSep objc $ do (name, typeModifiers) <- id_declarator bitfield <- option Nothing @@ -364,25 +307,11 @@ availability semi objc return [ (modifier typ, name) | (name, modifier) <- things ] - -type_operator = - (symbol objc "*" >> return CTPointer) - <|> (ignored_type_qualifier >> return id) -ignored_type_qualifier = - reserved objc "const" - <|> reserved objc "volatile" - <|> reserved objc "in" - <|> reserved objc "out" - <|> reserved objc "inout" - <|> reserved objc "bycopy" - <|> reserved objc "byref" - <|> reserved objc "oneway" - <|> reserved objc "__strong" typedef = do reserved objc "typedef" - baseType <- type_no_pointers + baseType <- simple_type newTypes <- commaSep objc id_declarator availability @@ -401,7 +330,7 @@ extern_decl = do optional extern_keyword - t <- type_no_pointers + t <- simple_type vars <- commaSep objc (one_var t) availability semi objc @@ -414,17 +343,7 @@ -> ExternFun (Selector n retval args varargs) otherType -> ExternVar otherType n - -availability :: Parser () -availability = optional $ - do reserved objc "__attribute__" - parens objc (skipParens) - return () - <|> - do x <- identifier objc - guard $ all (\c -> isUpper c || isDigit c || c == '_') x - -- guard (any (`isPrefixOf` x) ["AVAILABLE_MAC_", "DEPRECATED_IN_"]) - + extern_keyword = reserved objc "extern" <|> reserved objc "FOUNDATION_EXPORT" -- N.B. "Export" vs. "Extern". @@ -432,25 +351,147 @@ <|> reserved objc "GS_EXPORT" <|> reserved objc "CA_EXTERN" <|> reserved objc "CF_EXPORT" + <|> reserved objc "COREDATA_EXTERN" -skipParens = parens objc (skipMany ( - (satisfy (\x -> x /= '(' && x /= ')') >> return ()) - <|> skipParens - )) - -skipBlockContents = (skipMany ( - (satisfy (\x -> x /= '{' && x /= '}') >> return ()) - <|> skipBlock - )) -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 + t <- simple_type (n, tf) <- id_declarator skipBlock return [] + + +-- Ignore __attribute__((...)) and Apple's countless different availability macros, +-- which all expand to some __attribute__. My favourite example is +-- "AVAILABLE_MAC_OS_X_VERSION_10_1_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_3" + +availability :: Parser () +availability = fmap (const ()) $ many $ + do reserved objc "__attribute__" + parens objc (skipParens) + return () + <|> + do x <- identifier objc + guard $ all (\c -> isUpper c || isDigit c || c == '_') x + -- guard (any (`isPrefixOf` x) ["AVAILABLE_MAC_", "DEPRECATED_IN_"]) + + +-- Objective C + +class_decl = do + reserved objc "@class" + classes <- commaSep1 objc (identifier objc) + semi objc + return [ForwardClass classes] + +protocol_decl = do + reserved objc "@protocol" + protos <- commaSep1 objc (identifier objc) + semi objc + return [ForwardProtocol protos] + +interface_decl = do + proto <- (reserved objc "@interface" >> return False) + <|> (reserved objc "@protocol" >> return True) + class_name <- identifier objc + what <- if proto + then do + protos <- protocol_spec + return $ Protocol class_name protos + else (do + cat_name <- category_spec + protos <- protocol_spec + return $ Category class_name cat_name protos + ) <|> (do + super <- superclass_spec + protos <- protocol_spec + return $ Interface class_name super protos + ) + instance_variables + selectors <- fmap concat $ many selectorListItem + reserved objc "@end" + return [SelectorList what selectors] + where + category_spec = parens objc (identifier objc) + + superclass_spec = (do + colon objc + superclass <- identifier objc + return $ Just superclass + ) <|> return Nothing + +protocol_spec = + angles objc (commaSep1 objc (identifier objc)) + <|> return [] + +instance_variables = skipBlock <|> return () + +selectorListItem + = fmap singleton selector + <|> fmap (map LocalDecl) type_declaration + <|> fmap (map LocalDecl) extern_decl + <|> property_declaration + <|> fmap singleton requiredOrOptional + <|> (semi objc >> return []) + +requiredOrOptional + = (reserved objc "@required" >> return (Required True)) + <|> (reserved objc "@optional" >> return (Required False)) + +selector = do + classOrInstanceMethod <- + (symbol objc "-" >> return InstanceMethod) + <|> (symbol objc "+" >> return ClassMethod) + -- str <- many (satisfy (\c -> c /= ';' && c /= '@')) + rettype <- option (CTIDType []) (parens objc ctype) + (name,types,vararg) <- ( + do + manythings <- many1 (try $ do + namePart <- identifier objc <|> return "" + colon objc + argType <- option (CTIDType []) (parens objc ctype) + argName <- identifier objc + return (namePart, argType) + ) + vararg <- (symbol objc "," >> symbol objc "..." >> return True) <|> return False + let (nameParts,types) = unzip manythings + return (concat $ map (++":") nameParts , types, vararg) + ) <|> ( + do + name <- identifier objc + return (name,[],False) + ) + availability + semi objc + return (classOrInstanceMethod $ Selector name rettype types vararg) + +property_declaration + = do + reserved objc "@property" + properties <- option [] (parens objc (commaSep objc $ property_attribute)) + basetype <- simple_type + things <- commaSep objc id_declarator + availability + semi objc + return $ map (\ (name, typeModifiers) -> PropertyDecl $ + Property (typeModifiers $ basetype) + name properties ) things + where + property_attribute = + (do reserved objc "getter" + symbol objc "=" + name <- identifier objc + return $ Getter name) + <|> (do reserved objc "setter" + symbol objc "=" + name <- identifier objc + symbol objc ":" + return $ Setter (name ++ ":")) + <|> (reserved objc "readonly" >> return ReadOnly) + <|> (reserved objc "readwrite" >> return ReadWrite) + <|> (reserved objc "assign" >> return Assign) + <|> (reserved objc "retain" >> return Retain) + <|> (reserved objc "copy" >> return Copy) + |