Skip to content
This repository has been archived by the owner on Dec 5, 2019. It is now read-only.

Commit

Permalink
Merge branch 'Issue-5'
Browse files Browse the repository at this point in the history
This completes issue #5.
  • Loading branch information
jspahrsummers committed Jul 15, 2012
2 parents 648a4f1 + 88bc1de commit afef8bd
Show file tree
Hide file tree
Showing 5 changed files with 28 additions and 27 deletions.
35 changes: 18 additions & 17 deletions ObjectiveHaskell/MsgSend.hs
Original file line number Diff line number Diff line change
Expand Up @@ -34,14 +34,13 @@ becomes:
funcTypeFromMethodSig :: MethodSig -> Q Type
funcTypeFromMethodSig (MethodSig ret params) =
let mapf :: Type -> Q Type
mapf t | t == ConT ''Id = return $ ConT ''UnsafeId
mapf t | t == ConT ''Id = conT ''UnsafeId
| t == (AppT (ConT ''IO) (ConT ''Id)) = appT (conT ''IO) (conT ''UnsafeId)
| otherwise = return t

foldf :: Q Type -> Q Type -> Q Type
foldf l r = [t| $l -> $r |]

ioRet = appT (conT ''IO) (mapf ret)
in foldr foldf ioRet $ map mapf params
in foldr foldf (mapf ret) $ map mapf params

-- Given a list of argument types and names, applies each argument to expr in a left-associative fashion.
-- Any arguments of type Id will automatically be mapped to an UnsafeId.
Expand All @@ -63,26 +62,28 @@ applyMethodArgs expr (t:argTypes) (arg:args)
-- This is used to map UnsafeId return values to Id.
wrapReturnedExpr :: Q Exp -> Type -> Q Exp
wrapReturnedExpr expr t
| t == ConT ''Id = [| $expr >>= retainedId |]
| t == (AppT (ConT ''IO) (ConT ''Id)) = [| $expr >>= retainedId |]
| otherwise = expr

-- Creates an expression that returns a IO Sel of the given name.
selectorExpr :: String -> Q Exp
selectorExpr str = [| selector $(litE $ StringL str) |]

-- Given a string name, selector, a return type, and a list of parameter types (without self and _cmd),
-- declares a variant of objc_msgSend which accepts the parameter types and a final self parameter.
-- _cmd is automatically filled in.
--
-- Any arguments or return values of type Id (and not a synonym thereof) will be automatically memory-managed.
declMessage :: String -> String -> Name -> [Name] -> Q [Dec]
declMessage name selName ret params = do
-- Given a string name, a function type (without _cmd), and a selector,
-- declares a variant of objc_msgSend which matches the given signature, automatically fills in _cmd,
-- unwraps Ids for Objective-C, and wraps any UnstableId return value for Haskell.
declMessage :: String -> Q Type -> String -> Q [Dec]
declMessage name qt selName = do
t <- qt

-- Create a method signature from the given types
let baseRet = ConT ret
paramTypes = (ConT ''Id) : (ConT ''Sel) : (map ConT params)
methodSig = MethodSig baseRet paramTypes
let types = decomposeFunctionType t
retType = last types
paramTypes = (ConT ''Id) : (ConT ''Sel) : (init $ init types)
methodSig = MethodSig retType paramTypes

uniqArgNames <- argumentNames $ length params
-- Don't include the return type or 'self'
uniqArgNames <- argumentNames $ (length types) - 2

-- A unique generated name for our dynamic foreign import
-- (which is just a trampoline from a FunPtr to a callable function)
Expand All @@ -108,7 +109,7 @@ declMessage name selName ret params = do

-- "do _cmd <- selector fn_name; body >>= retainedId"
doBody = doE [bindS (varP cmdName) (selectorExpr selName),
noBindS $ wrapReturnedExpr funcBody baseRet]
noBindS $ wrapReturnedExpr funcBody retType]

funcDecl = singleClauseFunc (mkName name) paramNames doBody

Expand Down
6 changes: 3 additions & 3 deletions ObjectiveHaskell/NSArray.hs
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,9 @@ import ObjectiveHaskell.NSObject
import ObjectiveHaskell.ObjC

-- NSArray methods
declMessage "array" "array" ''Id []
declMessage "addObject" "addObject:" ''() [''Id]
declMessage "objectAtIndex" "objectAtIndex:" ''Id [''CSize]
declMessage "array" [t| Id -> IO Id |] "array"
declMessage "addObject" [t| Id -> Id -> IO () |] "addObject:"
declMessage "objectAtIndex" [t| CSize -> Id -> IO Id |] "objectAtIndex:"

-- Converts an NSArray into a Seq.
fromNSArray :: Id -> IO (Seq Id)
Expand Down
8 changes: 4 additions & 4 deletions ObjectiveHaskell/NSDictionary.hs
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,10 @@ import ObjectiveHaskell.NSObject
import ObjectiveHaskell.ObjC

-- NSDictionary methods
declMessage "allKeys" "allKeys" ''Id []
declMessage "dictionary" "dictionary" ''Id []
declMessage "objectForKey" "objectForKey:" ''Id [''Id]
declMessage "setObjectForKey" "setObject:forKey:" ''() [''Id, ''Id]
declMessage "allKeys" [t| Id -> IO Id |] "allKeys"
declMessage "dictionary" [t| Id -> IO Id |] "dictionary"
declMessage "objectForKey" [t| Id -> Id -> IO Id |] "objectForKey:"
declMessage "setObjectForKey" [t| Id -> Id -> Id -> IO () |] "setObject:forKey:"

-- Converts an NSDictionary into a Map.
fromNSDictionary :: Id -> IO (Map Id Id)
Expand Down
4 changes: 2 additions & 2 deletions ObjectiveHaskell/NSObject.hs
Original file line number Diff line number Diff line change
Expand Up @@ -8,5 +8,5 @@ import ObjectiveHaskell.ObjC

-- Some common messages for Objective-C objects,
-- including those that are not necessarily at the NSObject level.
declMessage "objc_copy" "copy" ''Id []
declMessage "objc_count" "count" ''CSize []
declMessage "objc_copy" [t| Id -> IO Id |] "copy"
declMessage "objc_count" [t| Id -> IO CSize |] "count"
2 changes: 1 addition & 1 deletion ObjectiveHaskellTests/MsgSendTest.hs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import Control.Monad
import ObjectiveHaskell.MsgSend
import ObjectiveHaskell.ObjC

declMessage "stringWithString" "stringWithString:" ''Id [''Id]
declMessage "stringWithString" [t| Id -> Id -> IO Id |] "stringWithString:"

-- This is what a Haskell function that invokes Objective-C code might look like.
mutableStringWithString :: Id -> IO Id
Expand Down

0 comments on commit afef8bd

Please sign in to comment.