|
From: <cod...@go...> - 2008-09-28 16:39:08
|
Author: wol...@gm...
Date: Sun Sep 28 09:37:57 2008
New Revision: 313
Modified:
trunk/hoc/InterfaceGenerator2/BuildEntities.hs
trunk/hoc/InterfaceGenerator2/Parser.hs
trunk/hoc/InterfaceGenerator2/SyntaxTree.hs
Log:
Improve the parser:
* parse ObjC 2.0 @property declarations (not handled in the other parts of
ifgen yet)
* more complete C type parsing, including function pointer types
* various small fixes
Also, the parser is now good enough that it can parse all of
Foundation, QuartzCore, AppKit and CoreData without skipping any
declarations;
from now on, declarations that we cannot parse will be reported as errors.
Modified: trunk/hoc/InterfaceGenerator2/BuildEntities.hs
==============================================================================
--- trunk/hoc/InterfaceGenerator2/BuildEntities.hs (original)
+++ trunk/hoc/InterfaceGenerator2/BuildEntities.hs Sun Sep 28 09:37:57 2008
@@ -135,7 +135,7 @@
= makeSelectorEntity True modName clsID clsName sel
makeEntitiesForSelectorListItem modName _clsID _clsName (LocalDecl
decl)
= makeEntity modName decl >> return Nothing
- makeEntitiesForSelectorListItem _modName _clsID _clsName
PropertyDecl
+ makeEntitiesForSelectorListItem _modName _clsID _clsName
(PropertyDecl _)
= return Nothing
makeEntitiesForSelectorListItem _modName _clsID _clsName (Required
_)
= return Nothing
Modified: trunk/hoc/InterfaceGenerator2/Parser.hs
==============================================================================
--- trunk/hoc/InterfaceGenerator2/Parser.hs (original)
+++ trunk/hoc/InterfaceGenerator2/Parser.hs Sun Sep 28 09:37:57 2008
@@ -1,8 +1,8 @@
-module Parser where
+module Parser( header, selector ) where
-import Data.Maybe(catMaybes, isJust)
+import Data.Maybe(catMaybes, isJust, fromJust)
import Data.Char(ord, isUpper, isDigit)
-import Data.Bits(shiftL)
+import Data.Bits(shiftL, (.|.))
import Control.Monad(guard)
import Text.ParserCombinators.Parsec
@@ -23,20 +23,27 @@
, identLetter = alphaNum <|> char '_'
, reservedNames =
["@class","@protocol","@interface","@implementation","@end","@property",
"const", "volatile", "struct", "union", "enum",
- "@required", "@optional"]
+ "__attribute__", "__strong",
+ "@required", "@optional", "@private", "@public" ]
, caseSensitive = True
}
objc :: TokenParser ()
objc = makeTokenParser objcDef
+singleton x = [x]
+
+header :: Parser [Declaration]
-header = try (whiteSpace objc >> eof >> return []) <|> (
- fmap catMaybes $ many (whiteSpace objc >>
- (try interestingThing
- <|> uninterestingThing))
- )
+header = do
+ optional (whiteSpace objc)
+ fmap concat $ many $ do
+ -- thing <- try interestingThing <|> uninterestingThing -- lenient
parsing
+ thing <- interestingThing -- strict parsing
+ optional (whiteSpace objc)
+ return thing
+uninterestingThing :: Parser (Maybe Declaration)
uninterestingThing = skipMany1 (satisfy (\x -> x /= '@' && x /= ';')) >>
return Nothing
interestingThing =
@@ -44,22 +51,23 @@
<|> (try protocol_decl)
<|> interface_decl
<|> empty_decl
- <|> (fmap Just type_declaration)
- <|> (fmap Just extern_decl)
+ <|> type_declaration
+ <|> extern_decl
+ <|> (semi objc >> return [])
-empty_decl = semi objc >> return Nothing
+empty_decl = semi objc >> return []
class_decl = do
reserved objc "@class"
classes <- commaSep1 objc (identifier objc)
semi objc
- return $ Just $ ForwardClass classes
+ return [ForwardClass classes]
protocol_decl = do
reserved objc "@protocol"
protos <- commaSep1 objc (identifier objc)
semi objc
- return $ Just $ ForwardProtocol protos
+ return [ForwardProtocol protos]
interface_decl = do
proto <- (reserved objc "@interface" >> return False)
@@ -79,9 +87,9 @@
return $ Interface class_name super protos
)
instance_variables
- selectors <- many selectorListItem
+ selectors <- fmap concat $ many selectorListItem
reserved objc "@end"
- return $ Just $ SelectorList what selectors
+ return [SelectorList what selectors]
category_spec = parens objc (identifier objc)
@@ -98,11 +106,12 @@
instance_variables = skipBlock <|> return ()
selectorListItem
- = selector
- <|> (fmap LocalDecl type_declaration)
- <|> fmap LocalDecl extern_decl
- <|> property
- <|> requiredOrOptional
+ = 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))
@@ -135,37 +144,103 @@
semi objc
return (classOrInstanceMethod $ Selector name rettype types vararg)
-property
+property_declaration
= do
reserved objc "@property"
- optional (parens objc (identifier objc))
+ properties <- option [] (parens objc (commaSep objc $
property_attribute))
basetype <- type_no_pointers
- args <- commaSep objc varname_with_stars
+ things <- commaSep objc id_declarator
+ availability
semi objc
- return PropertyDecl
+ 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)
--- type_spec = parens objc ctype <|> return CTNoType
- -- where
- -- ctype = fmap (CType . unwords) $ many (identifier objc <|> symbol
objc "*")
-type_spec = try (parens objc ctype) <|> (skipParens >> return CTUnknown) <|
> return (CTIDType [])
+--type_spec = try (parens objc ctype) <|> (skipParens >> return CTUnknown)
<|> return (CTIDType [])
+type_spec = parens objc ctype <|> return (CTIDType [])
type_no_pointers = do -- "const char" in "const char *foo[32]"
many ignored_type_qualifier -- ignore
- simple_type
-
-varname_with_stars = do
- pointers_and_such <- many type_operator
- name <- identifier objc
- arrays <- many (symbol objc "[" >> symbol objc "]" >> return CTPointer)
- return (name, \t -> foldl (flip ($)) t (pointers_and_such ++ arrays))
+ t <- simple_type
+ many ignored_type_qualifier
+ return t
+
+id_declarator = declarator False (identifier objc)
+
+declarator :: Bool -> Parser a -> Parser (a, CType -> CType)
+declarator emptyDeclaratorPossible thing = do
+ prefixes <- many prefix_operator
+ (name, typeFun) <- terminal
+ postfixes <- many postfix_operator
+ return (name, foldl (.) typeFun (postfixes ++ prefixes))
+ where
+ mbTry | emptyDeclaratorPossible = try
+ | otherwise = id
+ terminal =
+ mbTry (parens objc (declarator emptyDeclaratorPossible
thing))
+ <|> (thing >>= \name -> return (name, id))
+ prefix_operator =
+ do
+ symbol objc "*"
+ many ignored_type_qualifier
+ return CTPointer
+
+ postfix_operator =
+ brackets objc (optional (integer objc) >> return CTPointer)
+ <|> do
+ (args, vararg) <- parens objc arguments
+ return (\retval -> CTFunction retval args vararg)
+
+ arguments =
+ do
+ args <- commaSep objc argument
+ case reverse args of
+ (Nothing : moreArgs)
+ | all isJust moreArgs ->
+ return (map fromJust $ reverse moreArgs, True)
+ _ | all isJust args -> return (map fromJust args,
False)
+ | otherwise -> fail "'...' in the middle of
argument list"
+ where
+ argument =
+ (symbol objc "..." >> return Nothing)
+ <|> do
+ t <- type_no_pointers
+ (_, 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
- pointers_and_such <- many type_operator
- return $ foldl (flip ($)) simple pointers_and_such
+ (_, f) <- declarator True (return ())
+ return (f simple)
-simple_type = id_type <|> enum_type <|> struct_type <|> try builtin_type <|
> fmap CTSimple (identifier objc)
+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))
@@ -191,6 +266,7 @@
protos <- protocol_spec
return $ CTIDType protos
+
multiCharConstant =
lexeme objc (between (char '\'') (char '\'') multiChars)
where
@@ -201,14 +277,26 @@
(iterate (*256) 1)
-const_int_expr env = buildExpressionParser optable basic
+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
- basic = (integer objc) <|> multiCharConstant
+ expr = buildExpressionParser optable basic
+ basic = suffixedInteger
+ <|> multiCharConstant
<|> (do name <- identifier objc
Map.lookup name env)
- optable = [ [Infix shiftLeft AssocLeft] ]
+ <|> 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
@@ -216,34 +304,47 @@
do
key <- reserved objc "enum"
id <- identifier objc <|> return ""
- body <- braces objc (enum_body Map.empty (-1)) <|> return []
+ body <- braces objc (enum_body Map.empty (Just (-1))) <|> return []
return $ CTEnum id body
where
enum_body env lastVal = do
id <- identifier objc
- val <- (do
+ mbVal <- (do
symbol objc "="
- const_int_expr env
- ) <|> return (lastVal + 1)
+ try (fmap Just $ const_int_expr env)
+ <|> (skipEnumValue >> return Nothing)
+ ) <|> return (lastVal >>= Just . (+1))
- let env' = Map.insert id val env
- xs <- option [] $ comma objc >> option [] (enum_body env' val)
- return $ (id, GivenValue val) : xs
+ case mbVal of
+ Just val -> do
+ let env' = Map.insert id val env
+ xs <- option [] $ comma objc
+ >> option [] (enum_body env' (Just
val))
+ return $ (id, GivenValue val) : xs
+ Nothing -> do
+ xs <- option [] $ comma objc
+ >> option [] (enum_body env Nothing)
+ return $ (id, TooComplicatedValue "") : xs
struct_type =
do
key <- (reserved objc "struct" >> return CTStruct)
<|> (reserved objc "union" >> return CTUnion)
id <- identifier objc <|> return ""
- body <- braces objc struct_union_body <|> return []
+ body <- fmap concat $ braces objc struct_union_body <|> return []
return $ key id body
where
- struct_union_body = many member
+ struct_union_body = try (many member)
+ <|> (skipBlockContents >> return [])
member = do
- typ <- ctype
- name <- identifier objc
+ typ <- type_no_pointers
+ things <- commaSep objc $ do
+ (name, typeModifiers) <- id_declarator
+ bitfield <- option Nothing
+ (symbol objc ":" >> integer objc >>= return . Just)
+ return (name, typeModifiers)
semi objc
- return (typ, name)
+ return [ (modifier typ, name) | (name, modifier) <- things ]
type_operator =
(symbol objc "*" >> return CTPointer)
@@ -258,43 +359,52 @@
<|> reserved objc "bycopy"
<|> reserved objc "byref"
<|> reserved objc "oneway"
+ <|> reserved objc "__strong"
typedef = do
reserved objc "typedef"
- oldType <- ctype
- newType <- identifier objc
- semi objc
- return $ Typedef oldType newType
+ baseType <- type_no_pointers
+ newTypes <- commaSep objc id_declarator
+ availability
+ semi objc
+ return $ [Typedef (typeFun baseType) name
+ | (name, typeFun) <- newTypes ]
+
ctypeDecl = do
typ <- enum_type <|> struct_type
+ availability
semi objc
- return $ CTypeDecl typ
+ return [CTypeDecl typ]
type_declaration = typedef <|> ctypeDecl
extern_decl =
- extern_keyword >> ctype >>= \t -> identifier objc >>= \n ->
- do
- args <- parens objc (commaSep objc argument)
- availability
- semi objc
- return $ ExternFun (Selector n t args False)
- <|> do
- availability
- semi objc
- return $ ExternVar t n
+ do
+ extern_keyword
+ t <- type_no_pointers
+ vars <- commaSep objc (one_var t)
+ availability
+ semi objc
+ return vars
where
- argument = do t <- ctype
- optional (identifier objc)
- arrays <- many (symbol objc "[" >> symbol objc "]"
>> return CTPointer)
- return $ foldl (flip ($)) t arrays
-
+ one_var t = do
+ (n, typeOperators) <- id_declarator
+ return $ case typeOperators t of
+ CTFunction retval args varargs
+ -> ExternFun (Selector n retval args varargs)
+ otherType
+ -> ExternVar otherType n
+
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".
@@ -306,8 +416,10 @@
<|> skipParens
))
-skipBlock = braces objc (skipMany (
+skipBlockContents = (skipMany (
(satisfy (\x -> x /= '{' && x /= '}') >> return ())
<|> skipBlock
))
+skipBlock = braces objc skipBlockContents
+skipEnumValue = skipMany1 (satisfy (\x -> x /= '}' && x /= ','))
Modified: trunk/hoc/InterfaceGenerator2/SyntaxTree.hs
==============================================================================
--- trunk/hoc/InterfaceGenerator2/SyntaxTree.hs (original)
+++ trunk/hoc/InterfaceGenerator2/SyntaxTree.hs Sun Sep 28 09:37:57 2008
@@ -23,7 +23,7 @@
InstanceMethod Selector
| ClassMethod Selector
| LocalDecl Declaration
- | PropertyDecl
+ | PropertyDecl Property
| Required Bool
deriving (Show,Eq,Ord)
@@ -36,12 +36,27 @@
}
deriving (Read,Show,Eq,Ord,Typeable,Data)
+data Property = Property CType String [PropertyAttribute]
+ deriving (Show, Eq, Ord)
+
+data PropertyAttribute =
+ Getter String
+ | Setter String
+ | ReadOnly
+ | ReadWrite
+ | Assign
+ | Retain
+ | Copy
+ deriving (Show, Eq, Ord)
+
+
data EnumValue = NextValue | GivenValue Integer | TooComplicatedValue
String
deriving (Read, Show, Eq, Ord,Typeable,Data)
data CType = CTIDType [String {- protocols -}]
| CTSimple String
| CTPointer CType
+ | CTFunction CType [CType] Bool
| CTUnknown
| CTEnum String [(String, EnumValue)]
| CTStruct String [(CType, String)]
|