|
From: <cod...@go...> - 2008-12-21 22:06:32
|
Author: wol...@gm...
Date: Sun Dec 21 13:42:00 2008
New Revision: 377
Added:
trunk/hoc/HOC_cbits/Ivars.h (contents, props changed)
trunk/hoc/HOC_cbits/Ivars.m
trunk/hoc/HOC_cbits/Methods.h (contents, props changed)
trunk/hoc/HOC_cbits/Methods.m
Modified:
trunk/hoc/HOC.cabal
trunk/hoc/HOC/HOC.hs
trunk/hoc/HOC/HOC/Base.hs
trunk/hoc/HOC/HOC/Class.hs
trunk/hoc/HOC/HOC/DeclareClass.hs
trunk/hoc/HOC/HOC/ExportClass.hs
trunk/hoc/HOC/HOC/NewClass.hs
trunk/hoc/HOC_cbits/Class.h
trunk/hoc/HOC_cbits/Class.m
trunk/hoc/HOC_cbits/Exceptions.m
trunk/hoc/HOC_cbits/GetNewHaskellData.m
trunk/hoc/HOC_cbits/NewClass.h
trunk/hoc/HOC_cbits/NewClass.m
trunk/hoc/InterfaceGenerator2/Output.hs
trunk/hoc/Setup.hs
trunk/hoc/Tests/TestFoundation.hs
Log:
Merge Objective-C 2.0 branch
Big thanks to James Cook for doing all the work.
Modified: trunk/hoc/HOC.cabal
==============================================================================
--- trunk/hoc/HOC.cabal (original)
+++ trunk/hoc/HOC.cabal Sun Dec 21 13:42:00 2008
@@ -14,6 +14,9 @@
description: build test cases
default: False
+Flag ObjC2
+ description: build for Objective-C 2.0
+
Library
build-depends: base, template-haskell, unix
@@ -54,13 +57,18 @@
hs-source-dirs: HOC
extra-libraries: objc, ffi
+ c-sources: HOC_cbits.o
if os(darwin)
+ include-dirs: /usr/include/ffi
frameworks: Foundation
cpp-options: -DMACOSX
else
-- paths are inserted by Setup.hs
extra-libraries: gnustep-base
cpp-options: -DGNUSTEP
+
+ if flag(ObjC2)
+ cpp-options: -D__OBJC2__=1
Executable hoc-ifgen
Modified: trunk/hoc/HOC/HOC.hs
==============================================================================
--- trunk/hoc/HOC/HOC.hs (original)
+++ trunk/hoc/HOC/HOC.hs Sun Dec 21 13:42:00 2008
@@ -4,6 +4,7 @@
nil,
Object(..),
Class,
+ MetaClass,
ClassAndObject,
ClassObject,
classObject,
Modified: trunk/hoc/HOC/HOC/Base.hs
==============================================================================
--- trunk/hoc/HOC/HOC/Base.hs (original)
+++ trunk/hoc/HOC/HOC/Base.hs Sun Dec 21 13:42:00 2008
@@ -20,6 +20,10 @@
--
+foreign import ccall "stdlib.h &free"
+ freePtr :: FunPtr (Ptr a -> IO ())
+
+--
foreign import ccall "MemoryManagement.h retainObject"
retainObject :: Ptr ObjCObject -> IO ()
Modified: trunk/hoc/HOC/HOC/Class.hs
==============================================================================
--- trunk/hoc/HOC/HOC/Class.hs (original)
+++ trunk/hoc/HOC/HOC/Class.hs Sun Dec 21 13:42:00 2008
@@ -11,15 +11,13 @@
import Foreign
import Foreign.C.String
-
data Class_ a
type Class a = ID (Class_ a)
-
+type MetaClass a = Class (Class_ a)
unsafeGetClassObject :: String -> Class a
-
foreign import ccall unsafe "Class.h getClassByName"
c_getClassByName :: CString -> IO (Ptr ObjCObject)
@@ -30,6 +28,16 @@
getClassByName name >>= importImmortal
+unsafeGetMetaclassForClass :: Class a -> MetaClass a
+
+foreign import ccall unsafe "Class.h getClassForObject"
+ c_getClassForObject :: Ptr ObjCObject -> IO (Ptr ObjCObject)
+
+getClassForObject obj = withExportedArgument obj c_getClassForObject
+
+{-# NOINLINE unsafeGetMetaclassForClass #-}
+unsafeGetMetaclassForClass obj = unsafePerformIO $
+ getClassForObject obj >>= importImmortal
class (Object a, Object b) => ClassAndObject a b | a -> b, b -> a
Modified: trunk/hoc/HOC/HOC/DeclareClass.hs
==============================================================================
--- trunk/hoc/HOC/HOC/DeclareClass.hs (original)
+++ trunk/hoc/HOC/HOC/DeclareClass.hs Sun Dec 21 13:42:00 2008
@@ -31,6 +31,12 @@
`appT` (conT (mkName phantomName)
`appT` varT (mkName "a"))),
+ -- type $(metaMetaClassName) a = $(superMetaMetaClassName)
($(phantomName) a)
+ tySynD (mkName metaMetaClassName) [mkName "a"]
+ (conT (mkName superMetaMetaClassName)
+ `appT` (conT (mkName phantomName)
+ `appT` varT (mkName "a"))),
+
-- $(classObjectName) :: $(metaClassName) ()
sigD (mkName classObjectName) (conT (mkName metaClassName)
`appT` [t| () |]),
@@ -39,6 +45,11 @@
valD (return $ VarP (mkName classObjectName))
(normalB [| unsafeGetClassObject $(stringE name) |]) [],
+ -- $(metaClassObjectName) = unsafeGetMetaclassForClass
$(classObjectName)
+ valD (return $ VarP (mkName metaClassObjectName))
+ (normalB [| unsafeGetMetaclassForClass $(varE (mkName
classObjectName)) |]) [],
+
+ -- $(superName) :: String
sigD (mkName superName) [t| String |],
-- $(superName) = "super"
@@ -47,20 +58,35 @@
-- instance SuperClass (name ()) (super ())
instanceD (cxt []) (conT ''SuperClass `appT` clsType `appT`
superType) [],
+ -- instance SuperClass (clsName ()) (superClsName ())
+ instanceD (cxt []) (conT ''SuperClass `appT` metaClsType `appT`
superMetaType) [],
+
-- instance ClassObject (metaClsName ())
-- where classObject = classObject
instanceD (cxt []) (conT ''ClassObject `appT` metaClsType)
- [funD 'classObject [clause [] (normalB $ varE (mkName
classObjectName)) []]]
+ [funD 'classObject [clause [] (normalB $ varE (mkName
classObjectName)) []]],
+
+ -- instance ClassObject metaMetaCls
+ -- where classObject = unsafeGetMetaclassForClass classObject
+ -- {- metaclass object, to support super calls in class methods -}
+ instanceD (cxt []) (conT ''ClassObject `appT` metaMetaClsType)
+ [funD 'classObject [clause [] (normalB $ varE (mkName
metaClassObjectName)) []]]
]
where
phantomName = name ++ "_"
metaClassName = name ++ "Class"
+ metaMetaClassName = name ++ "MetaClass"
metaPhantomName = metaClassName ++ "_"
superMetaClassName | super == "ID" = "Class"
| otherwise = super ++ "Class"
+ superMetaMetaClassName | super == "ID" = "MetaClass"
+ | otherwise = super ++ "MetaClass"
classObjectName = "_" ++ name
+ metaClassObjectName = "_" ++ metaClassName
superName = "super_" ++ name
+ metaMetaClsType = conT (mkName metaMetaClassName) `appT` [t| () |]
metaClsType = conT (mkName metaClassName) `appT` [t| () |]
clsType = conT (mkName name) `appT` [t| () |]
superType = conT (mkName super) `appT` [t| () |]
+ superMetaType = conT (mkName superMetaClassName) `appT` [t| () |]
Modified: trunk/hoc/HOC/HOC/ExportClass.hs
==============================================================================
--- trunk/hoc/HOC/HOC/ExportClass.hs (original)
+++ trunk/hoc/HOC/HOC/ExportClass.hs Sun Dec 21 13:42:00 2008
@@ -138,7 +138,7 @@
$(fillMethodList False 3 [|imethods|] instanceMethods)
$(fillMethodList True 0 [|cmethods|] classMethods)
clsname <- newCString name
- newClass super clsname defaultIvarSize ivars imethods
cmethods
+ newClass super clsname ivars imethods cmethods
|]
where
typedInitIvars = [|initializeInstanceVariables|]
Modified: trunk/hoc/HOC/HOC/NewClass.hs
==============================================================================
--- trunk/hoc/HOC/HOC/NewClass.hs (original)
+++ trunk/hoc/HOC/HOC/NewClass.hs Sun Dec 21 13:42:00 2008
@@ -9,7 +9,6 @@
setIvarInList,
setMethodInList,
makeDefaultIvarList,
- defaultIvarSize,
setHaskellRetainMethod,
setHaskellReleaseMethod,
setHaskellDataMethod
@@ -22,49 +21,79 @@
import HOC.Class
import Foreign.C.String
+import Foreign.C.Types
import Foreign
type IMP = FFICif -> Ptr () -> Ptr (Ptr ()) -> IO (Ptr ObjCObject)
foreign import ccall "wrapper" wrapIMP :: IMP -> IO (FunPtr IMP)
-newtype MethodList = MethodList (Ptr MethodList)
-newtype IvarList = IvarList (Ptr IvarList)
+newtype MethodList = MethodList (ForeignPtr MethodList)
+newtype IvarList = IvarList (ForeignPtr IvarList)
foreign import ccall "NewClass.h newClass"
- newClass :: Ptr ObjCObject -> CString
- -> Int -> IvarList
+ rawNewClass :: Ptr ObjCObject -> CString
+ -> Ptr IvarList
+ -> Ptr MethodList -> Ptr MethodList
+ -> IO ()
+
+newClass :: Ptr ObjCObject -> CString
+ -> IvarList
-> MethodList -> MethodList
-> IO ()
+newClass sc name (IvarList ivars) (MethodList ms) (MethodList cms) =
+ withForeignPtr ivars $ \ivars ->
+ withForeignPtr ms $ \ms ->
+ withForeignPtr cms $ \cms -> do
+ rawNewClass sc name ivars ms cms
foreign import ccall "NewClass.h makeMethodList"
- makeMethodList :: Int -> IO MethodList
+ rawMakeMethodList :: Int -> IO (Ptr MethodList)
foreign import ccall "NewClass.h setMethodInList"
- rawSetMethodInList :: MethodList -> Int
+ rawSetMethodInList :: Ptr MethodList -> Int
-> SEL -> CString
-> FFICif -> FunPtr IMP
-> IO ()
foreign import ccall "NewClass.h makeIvarList"
- makeIvarList :: Int -> IO IvarList
+ rawMakeIvarList :: Int -> IO (Ptr IvarList)
foreign import ccall "NewClass.h setIvarInList"
- setIvarInList :: IvarList -> Int
- -> CString -> CString -> Int -> IO ()
+ rawSetIvarInList :: Ptr IvarList -> Int
+ -> CString -> CString -> CSize -> Word8 -> IO ()
-setMethodInList methodList idx sel typ cif imp = do
- typC <- newCString typ
- thunk <- wrapIMP imp
- rawSetMethodInList methodList idx sel typC cif thunk
+makeIvarList :: Int -> IO IvarList
+makeIvarList n = do
+ ivars <- rawMakeIvarList n
+ ivars <- newForeignPtr freePtr ivars
+ return (IvarList ivars)
+
+setIvarInList:: IvarList -> Int
+ -> CString -> CString -> CSize -> Word8 -> IO ()
+setIvarInList (IvarList ivars) n name ty sz align =
+ withForeignPtr ivars $ \ivars -> do
+ rawSetIvarInList ivars n name ty sz align
+
+makeMethodList :: Int -> IO MethodList
+makeMethodList n = do
+ methods <- rawMakeMethodList n
+ methods <- newForeignPtr freePtr methods
+ return (MethodList methods)
+
+setMethodInList (MethodList methodList) idx sel typ cif imp =
+ withForeignPtr methodList $ \methodList -> do
+ typC <- newCString typ
+ thunk <- wrapIMP imp
+ rawSetMethodInList methodList idx sel typC cif thunk
makeDefaultIvarList = do
list <- makeIvarList 1
name <- newCString "__retained_haskell_part__"
typ <- newCString "^v"
- setIvarInList list 0 name typ 0
+ setIvarInList list 0 name typ
+ (fromIntegral $ sizeOf nullPtr)
+ (fromIntegral $ alignment nullPtr)
return list
-defaultIvarSize = 4 :: Int
-
retainSelector = getSelectorForName "retain"
retainCif = getCifForSelector (undefined :: ID () -> IO (ID ()))
@@ -75,33 +104,11 @@
getHaskellDataCif = getCifForSelector (undefined :: Class () -> ID () ->
IO (ID ()))
-- actually -> IO (Ptr
()) ...
-setHaskellRetainMethod methodList idx = do
- typC <- newCString "@@:"
- thunk <- wrapIMP haskellObject_retain_IMP
- rawSetMethodInList methodList
- idx
- retainSelector
- typC
- retainCif
- thunk
+setHaskellRetainMethod methodList idx =
+ setMethodInList methodList idx retainSelector "@@:" retainCif
haskellObject_retain_IMP
-setHaskellReleaseMethod methodList idx = do
- typC <- newCString "v@:"
- thunk <- wrapIMP haskellObject_release_IMP
- rawSetMethodInList methodList
- idx
- releaseSelector
- typC
- releaseCif
- thunk
-
-setHaskellDataMethod methodList idx super mbDat = do
- typC <- newCString "^v@:#"
- thunk <- wrapIMP (getHaskellData_IMP super mbDat)
- rawSetMethodInList methodList
- idx
- getHaskellDataSelector
- typC
- getHaskellDataCif
- thunk
+setHaskellReleaseMethod methodList idx =
+ setMethodInList methodList idx releaseSelector "v@:" releaseCif
haskellObject_release_IMP
+setHaskellDataMethod methodList idx super mbDat =
+ setMethodInList methodList idx getHaskellDataSelector "^v@:#"
getHaskellDataCif (getHaskellData_IMP super mbDat)
Modified: trunk/hoc/HOC_cbits/Class.h
==============================================================================
--- trunk/hoc/HOC_cbits/Class.h (original)
+++ trunk/hoc/HOC_cbits/Class.h Sun Dec 21 13:42:00 2008
@@ -1,3 +1,9 @@
#include <objc/objc.h>
id getClassByName(const char* name);
+
+Class getSuperclassForClass(Class class);
+Class getRootClassForClass(Class super_class);
+
+Class getClassForObject(id self);
+Class getSuperClassForObject(id self);
\ No newline at end of file
Modified: trunk/hoc/HOC_cbits/Class.m
==============================================================================
--- trunk/hoc/HOC_cbits/Class.m (original)
+++ trunk/hoc/HOC_cbits/Class.m Sun Dec 21 13:42:00 2008
@@ -13,3 +13,50 @@
return objc_getClass(name);
#endif
}
+
+Class getSuperclassForClass(Class class)
+{
+#ifdef GNUSTEP
+ if(CLS_ISRESOLV(class))
+ return class->super_class;
+ else
+ return getClassByName((const char*) class->super_class);
+
+#elif defined(__OBJC2__)
+ return class_getSuperclass(class);
+#else
+ return class->super_class;
+#endif
+}
+
+Class getRootClassForClass(Class super_class)
+{
+ Class root_class;
+
+ for(root_class = super_class;
+ getSuperclassForClass(root_class) != nil;
+ root_class = getSuperclassForClass(root_class))
+ ;
+
+ return root_class;
+}
+
+Class getClassForObject(id object)
+{
+#ifdef __OBJC2__
+ return object_getClass(object);
+#else
+ return object->isa;
+#endif
+}
+
+Class getSuperClassForObject(id self)
+{
+#ifdef GNUSTEP
+ return self->class_pointer->super_class;
+#elif defined(__OBJC2__)
+ return class_getSuperclass(object_getClass(self));
+#else
+ return self->isa->super_class;
+#endif
+}
\ No newline at end of file
Modified: trunk/hoc/HOC_cbits/Exceptions.m
==============================================================================
--- trunk/hoc/HOC_cbits/Exceptions.m (original)
+++ trunk/hoc/HOC_cbits/Exceptions.m Sun Dec 21 13:42:00 2008
@@ -1,10 +1,15 @@
#include <objc/objc.h>
#include "NewClass.h"
#include "Class.h"
+#include "Ivars.h"
+#include "Methods.h"
#include "Selector.h"
#include "Marshalling.h"
#include "HsFFI.h"
+#define hsExceptionClassName "HOCHaskellException"
+#define hsExceptionIvarName "_haskellException"
+
static BOOL excWrapperInited = NO;
static int stablePtrOffset;
static id clsHOCHaskellException;
@@ -21,12 +26,18 @@
#if GNUSTEP
super.self = self;
- super.class = self->class_pointer->super_class;
+ super.class = getSuperClassForObject(self);
(*objc_msg_lookup_super(&super, selDealloc))(self, selDealloc);
#else
super.receiver = self;
- super.class = self->isa->super_class;
+
+# ifdef __OBJC2__
+ super.super_class = getSuperClassForObject(self);
+# else
+ super.class = getSuperClassForObject(self);
+# endif
+
objc_msgSendSuper(&super, selDealloc);
#endif
}
@@ -35,30 +46,29 @@
{
if(!excWrapperInited)
{
- struct objc_method_list *methods = makeMethodList(1);
- struct objc_method_list *class_methods = makeMethodList(0);
- struct objc_ivar_list *ivars = makeIvarList(1);
+ struct hoc_method_list *methods = makeMethodList(1);
+ struct hoc_method_list *class_methods = makeMethodList(0);
+ struct hoc_ivar_list *ivars = makeIvarList(1);
+ struct objc_ivar *stablePtrIvar;
selDealloc = getSelectorForName("dealloc");
-#ifdef GNUSTEP
- methods->method_list[0].method_name = (SEL)"dealloc";
-#else
- methods->method_list[0].method_name = selDealloc;
-#endif
- methods->method_list[0].method_types = "v@:";
- methods->method_list[0].method_imp = (IMP) &exc_dealloc;
+ setMethodInListWithIMP(methods, 0, selDealloc, "v@:", (IMP)
&exc_dealloc);
- setIvarInList(ivars, 0, "_haskellExecption", "^v", 0);
+ setIvarInList(ivars, 0, hsExceptionIvarName, "^v", sizeof(void *),
IVAR_PTR_ALIGN);
newClass(getClassByName("NSException"),
- "HOCHaskellException",
- sizeof(void*),
+ hsExceptionClassName,
ivars, methods, class_methods);
clsHOCHaskellException = getClassByName("HOCHaskellException");
- stablePtrOffset = ivars->ivar_list[0].ivar_offset;
+ stablePtrIvar = class_getInstanceVariable(clsHOCHaskellException,
hsExceptionIvarName);
+#ifdef __OBJC2__
+ stablePtrOffset = ivar_getOffset(stablePtrIvar);
+#else
+ stablePtrOffset = stablePtrIvar->ivar_offset;
+#endif
selExceptionWithNameReasonUserInfo =
getSelectorForName("exceptionWithName:reason:userInfo:");
Modified: trunk/hoc/HOC_cbits/GetNewHaskellData.m
==============================================================================
--- trunk/hoc/HOC_cbits/GetNewHaskellData.m (original)
+++ trunk/hoc/HOC_cbits/GetNewHaskellData.m Sun Dec 21 13:42:00 2008
@@ -47,7 +47,13 @@
#endif
if(m)
+ {
+#ifdef __OBJC2__
+ imp = method_getImplementation(m);
+#else
imp = m->method_imp;
+#endif
+ }
if(imp)
return (*(getHaskellDataIMP)imp)(obj, selGetHaskellData);
Added: trunk/hoc/HOC_cbits/Ivars.h
==============================================================================
--- (empty file)
+++ trunk/hoc/HOC_cbits/Ivars.h Sun Dec 21 13:42:00 2008
@@ -0,0 +1,39 @@
+#include <stdlib.h>
+#include <stdint.h>
+
+struct hoc_ivar {
+ char *ivar_name;
+ char *ivar_types;
+ size_t ivar_size;
+ uint8_t ivar_alignment;
+};
+
+#define IVAR_PTR_ALIGN ((uint8_t) sizeof(void *))
+
+struct hoc_ivar_list {
+ int ivar_count;
+
+ /* variable length structure */
+ struct hoc_ivar ivar_list[1];
+};
+
+struct hoc_ivar_list * makeIvarList(int n);
+
+void setIvarInList(
+ struct hoc_ivar_list *list,
+ int i,
+ char *name, /* never deallocate this */
+ char *types, /* never deallocate this */
+ size_t size,
+ uint8_t alignment
+ );
+
+#ifndef __OBJC2__
+
+struct objc_ivar_list * buildIndexedIvarList(
+ struct hoc_ivar_list *list,
+ int start_offset,
+ int *instance_size /* out */
+ );
+
+#endif
\ No newline at end of file
Added: trunk/hoc/HOC_cbits/Ivars.m
==============================================================================
--- (empty file)
+++ trunk/hoc/HOC_cbits/Ivars.m Sun Dec 21 13:42:00 2008
@@ -0,0 +1,92 @@
+#ifdef GNUSTEP
+#include <objc/objc-api.h>
+#else
+#include <objc/objc-runtime.h>
+#endif
+
+#include <stdlib.h>
+#include <assert.h>
+
+#include "Ivars.h"
+
+struct hoc_ivar_list * makeIvarList(int n)
+{
+ struct hoc_ivar_list *list =
+ calloc(1, sizeof(struct hoc_ivar_list)
+ + (n-1) * sizeof(struct hoc_ivar));
+ list->ivar_count = n;
+ return list;
+}
+
+void setIvarInList(
+ struct hoc_ivar_list *list,
+ int i,
+ char *name,
+ char *types,
+ size_t size,
+ uint8_t alignment
+ )
+{
+ list->ivar_list[i].ivar_name = name;
+ list->ivar_list[i].ivar_types = types;
+ list->ivar_list[i].ivar_size = size;
+ list->ivar_list[i].ivar_alignment = alignment;
+}
+
+#ifndef __OBJC2__
+
+/* Used to be makeIvarList in NewClass.m */
+static struct objc_ivar_list * makeIndexedIvarList(int n)
+{
+ struct objc_ivar_list *list =
+ calloc(1, sizeof(struct objc_ivar_list)
+ + (n-1) * sizeof(struct objc_ivar));
+ list->ivar_count = n;
+ return list;
+}
+
+/* Used to be setIvarInList in NewClass.m */
+static void setIvarInIndexedList(
+ struct objc_ivar_list *list,
+ int i,
+ char *name,
+ char *type,
+ int offset
+ )
+{
+ list->ivar_list[i].ivar_name = name;
+ list->ivar_list[i].ivar_type = type;
+ list->ivar_list[i].ivar_offset = offset;
+}
+
+struct objc_ivar_list * buildIndexedIvarList(
+ struct hoc_ivar_list *list,
+ int start_offset,
+ int *instance_size /* out */
+ )
+{
+ struct objc_ivar_list * outList =
makeIndexedIvarList(list->ivar_count);
+ int offset = start_offset;
+ int i;
+
+ for (i = 0; i < list->ivar_count; i++)
+ {
+ struct hoc_ivar *ivar = &list->ivar_list[i];
+
+ int align = ivar->ivar_alignment;
+ int alignmask = align - 1;
+
+ assert((align & alignmask) == 0);
+ if ((offset & alignmask) != 0)
+ offset = (offset & ~alignmask) + align;
+
+ setIvarInIndexedList(outList, i, ivar->ivar_name,
ivar->ivar_types, offset);
+
+ offset += ivar->ivar_size;
+ }
+
+ *instance_size = offset - start_offset;
+ return outList;
+}
+
+#endif // ifndef __OBJC2__
\ No newline at end of file
Added: trunk/hoc/HOC_cbits/Methods.h
==============================================================================
--- (empty file)
+++ trunk/hoc/HOC_cbits/Methods.h Sun Dec 21 13:42:00 2008
@@ -0,0 +1,57 @@
+#ifdef GNUSTEP
+#include <objc/objc-api.h>
+#else
+#include <objc/objc-runtime.h>
+#endif
+
+#include <ffi.h>
+
+#ifdef __OBJC__
+@class NSException;
+#else
+typedef void NSException;
+#endif
+
+typedef NSException *(*haskellIMP)(
+ ffi_cif *cif,
+ void * ret,
+ void **args
+ );
+
+struct hoc_method {
+ SEL method_name;
+ char *method_types;
+ IMP method_imp;
+};
+
+struct hoc_method_list {
+ int method_count;
+
+ /* variable length structure */
+ struct hoc_method method_list[1];
+};
+
+struct hoc_method_list * makeMethodList(int n);
+
+void setMethodInListWithIMP(
+ struct hoc_method_list *list,
+ int i,
+ SEL sel,
+ char *types, /* never deallocate this */
+ IMP imp /* never deallocate this */
+ );
+
+void setMethodInList(
+ struct hoc_method_list *list,
+ int i,
+ SEL sel,
+ char *types, /* never deallocate this */
+ ffi_cif *cif, /* never deallocate this */
+ haskellIMP imp
+ );
+
+#ifndef __OBJC2__
+
+struct objc_method_list * convertMethodList(struct hoc_method_list * list);
+
+#endif
\ No newline at end of file
Added: trunk/hoc/HOC_cbits/Methods.m
==============================================================================
--- (empty file)
+++ trunk/hoc/HOC_cbits/Methods.m Sun Dec 21 13:42:00 2008
@@ -0,0 +1,104 @@
+#include <stdlib.h>
+#include "Methods.h"
+#include "Statistics.h"
+
+#ifdef __OBJC__
+#import <Foundation/NSException.h>
+#endif
+
+static void objcIMP(ffi_cif *cif, void * ret, void **args, void *userData)
+{
+ recordHOCEvent(kHOCAboutToEnterHaskell, args);
+ NSException *e = (*(haskellIMP)userData)(cif, ret, args);
+ recordHOCEvent(kHOCLeftHaskell, args);
+ if(e != nil)
+ [e raise];
+}
+
+static ffi_closure *newIMP(ffi_cif *cif, haskellIMP imp)
+{
+ ffi_closure *closure = (ffi_closure*) calloc(1, sizeof(ffi_closure));
+ ffi_prep_closure(closure, cif, &objcIMP, (void*) imp);
+ return closure;
+}
+
+struct hoc_method_list * makeMethodList(int n)
+{
+ struct hoc_method_list *list =
+ calloc(1, sizeof(struct hoc_method_list)
+ + (n-1) * sizeof(struct hoc_method));
+ list->method_count = n;
+ return list;
+}
+
+void setMethodInList(
+ struct hoc_method_list *list,
+ int i,
+ SEL sel,
+ char *types,
+ ffi_cif *cif,
+ haskellIMP imp
+ )
+{
+ setMethodInListWithIMP(list, i, sel, types, (IMP) newIMP(cif, imp) );
+}
+
+void setMethodInListWithIMP(
+ struct hoc_method_list *list,
+ int i,
+ SEL sel,
+ char *types,
+ IMP imp
+ )
+{
+ list->method_list[i].method_name = sel;
+ list->method_list[i].method_types = types;
+ list->method_list[i].method_imp = imp;
+}
+
+#ifndef __OBJC2__
+
+/* Was previously makeMethodList */
+static struct objc_method_list * makeObjcMethodList(int n)
+{
+ struct objc_method_list *list =
+ calloc(1, sizeof(struct objc_method_list)
+ + (n-1) * sizeof(struct objc_method));
+ list->method_count = n;
+ return list;
+}
+
+/* Was previously setMethodInList */
+static void setObjCMethodInList(
+ struct objc_method_list *list,
+ int i,
+ SEL sel,
+ char *types,
+ IMP imp
+ )
+{
+#ifdef GNUSTEP
+ list->method_list[i].method_name = (SEL) sel_get_name(sel);
+#else
+ list->method_list[i].method_name = sel;
+#endif
+ list->method_list[i].method_types = types;
+ list->method_list[i].method_imp = imp;
+}
+
+struct objc_method_list *
+convertMethodList(struct hoc_method_list * list) {
+ struct objc_method_list * newList =
makeObjcMethodList(list->method_count);
+ int i;
+
+ for(i = 0; i < list->method_count; i++)
+ {
+ struct hoc_method * method = &list->method_list[i];
+
+ setObjCMethodInList(newList, i, method->method_name,
method->method_types, method->method_imp);
+ }
+
+ return newList;
+}
+
+#endif // ifndef __OBJC2__
\ No newline at end of file
Modified: trunk/hoc/HOC_cbits/NewClass.h
==============================================================================
--- trunk/hoc/HOC_cbits/NewClass.h (original)
+++ trunk/hoc/HOC_cbits/NewClass.h Sun Dec 21 13:42:00 2008
@@ -4,42 +4,12 @@
#include <objc/objc-runtime.h>
#endif
-#include <ffi.h>
+struct hoc_ivar_list;
+struct hoc_method_list;
-#ifdef __OBJC__
-@class NSException;
-#else
-typedef void NSException;
-#endif
-
-void newClass(struct objc_class * super_class,
+void newClass(Class super_class,
const char * name, /* never
deallocate this */
- int instance_size,
- struct objc_ivar_list *ivars, /* never deallocate this */
- struct objc_method_list *methods, /* never deallocate this */
- struct objc_method_list *class_methods); /* never deallocate this */
+ struct hoc_ivar_list *ivars,
+ struct hoc_method_list *methods,
+ struct hoc_method_list *class_methods);
-typedef NSException *(*haskellIMP)(
- ffi_cif *cif,
- void * ret,
- void **args
- );
-
-struct objc_method_list * makeMethodList(int n);
-void setMethodInList(
- struct objc_method_list *list,
- int i,
- SEL sel,
- char *types, /* never deallocate this */
- ffi_cif *cif, /* never deallocate this */
- haskellIMP imp
- );
-
-struct objc_ivar_list * makeIvarList(int n);
-void setIvarInList(
- struct objc_ivar_list *list,
- int i,
- char *name, /* never deallocate this */
- char *type, /* never deallocate this */
- int offset
- );
Modified: trunk/hoc/HOC_cbits/NewClass.m
==============================================================================
--- trunk/hoc/HOC_cbits/NewClass.m (original)
+++ trunk/hoc/HOC_cbits/NewClass.m Sun Dec 21 13:42:00 2008
@@ -2,8 +2,9 @@
#include <Foundation/NSException.h>
#include <assert.h>
#include "Class.h"
+#include "Ivars.h"
+#include "Methods.h"
#include "NewClass.h"
-#include "Statistics.h"
#ifdef GNUSTEP
#define isa class_pointer
@@ -11,157 +12,133 @@
#define CLS_META _CLS_META
#endif
-static struct objc_class * getSuper(struct objc_class *class)
-{
-#ifdef GNUSTEP
- if(CLS_ISRESOLV(class))
- return class->super_class;
- else
- return getClassByName((const char*) class->super_class);
-
+static Class allocateClassPair(Class super_class, const char * name) {
+#ifdef __OBJC2__
+ return objc_allocateClassPair(super_class, name, 0);
#else
- return class->super_class;
+ Class new_class = calloc( 2, sizeof(struct objc_class) );
+ Class meta_class = &new_class[1];
+ Class root_class = getRootClassForClass(super_class);
+
+ new_class->isa = meta_class;
+ new_class->info = CLS_CLASS;
+ meta_class->info = CLS_META;
+
+ new_class->name = name;
+ meta_class->name = name;
+
+# ifdef GNUSTEP
+ new_class->super_class = (void*)(super_class->name);
+ meta_class->super_class = (void*)(super_class->isa->name);
+# else
+ new_class->super_class = super_class;
+ meta_class->super_class = super_class->isa;
+ meta_class->isa = (void *)root_class->isa;
+# endif
+
+ return new_class;
#endif
}
-void newClass(struct objc_class * super_class,
- const char * name,
- int instance_size,
- struct objc_ivar_list *ivars,
- struct objc_method_list *methods,
- struct objc_method_list *class_methods)
-{
- struct objc_class * meta_class;
- struct objc_class * new_class;
- struct objc_class * root_class;
- int i;
-
- assert(objc_lookUpClass(name) == nil);
-
- for(root_class = super_class;
- root_class->super_class != nil;
- root_class = getSuper(root_class))
- ;
-
- new_class = calloc( 2, sizeof(struct objc_class) );
- meta_class = &new_class[1];
-
- new_class->isa = meta_class;
- new_class->info = CLS_CLASS;
- meta_class->info = CLS_META;
-
- new_class->name = name;
- meta_class->name = name;
-
- new_class->instance_size = super_class->instance_size + instance_size;
- for(i=0; i<ivars->ivar_count; i++)
- ivars->ivar_list[i].ivar_offset += super_class->instance_size;
-
- new_class->ivars = ivars;
-
+static void registerClassPair(Class new_class) {
#ifdef GNUSTEP
- new_class->super_class = (void*)(super_class->name);
- meta_class->super_class = (void*)(super_class->isa->name);
-
- {
- Module_t module = calloc(1, sizeof(Module));
- Symtab_t symtab = calloc(1, sizeof(Symtab) + sizeof(void*) /* two
defs pointers */);
- extern void __objc_exec_class (Module_t module);
- extern void __objc_resolve_class_links ();
-
- module->version = 8;
- module->size = sizeof(Module);
- module->name = strdup(name);
- module->symtab = symtab;
- symtab->cls_def_cnt = 1;
- symtab->defs[0] = new_class;
- symtab->defs[1] = NULL;
-
- __objc_exec_class (module);
- __objc_resolve_class_links();
- }
+ Module_t module = calloc(1, sizeof(Module));
+ Symtab_t symtab = calloc(1, sizeof(Symtab) + sizeof(void*) /* two defs
pointers */);
+ extern void __objc_exec_class (Module_t module);
+ extern void __objc_resolve_class_links ();
+
+ module->version = 8;
+ module->size = sizeof(Module);
+ module->name = strdup(name);
+ module->symtab = symtab;
+ symtab->cls_def_cnt = 1;
+ symtab->defs[0] = new_class;
+ symtab->defs[1] = NULL;
- class_add_method_list(new_class, methods);
- class_add_method_list(meta_class, class_methods);
+ __objc_exec_class (module);
+ __objc_resolve_class_links();
+#elif defined(__OBJC2__)
+ objc_registerClassPair(new_class);
#else
- new_class->methodLists = calloc( 1, sizeof(struct objc_method_list *) );
- meta_class->methodLists = calloc( 1, sizeof(struct objc_method_list *) );
- new_class->methodLists[0] = (struct objc_method_list*) -1;
- meta_class->methodLists[0] = (struct objc_method_list*) -1;
-
- new_class->super_class = super_class;
- meta_class->super_class = super_class->isa;
- meta_class->isa = (void *)root_class->isa;
-
- objc_addClass( new_class );
-
- class_addMethods(new_class, methods);
- class_addMethods(meta_class, class_methods);
+ objc_addClass( new_class );
#endif
}
-
-static void objcIMP(ffi_cif *cif, void * ret, void **args, void *userData)
-{
- recordHOCEvent(kHOCAboutToEnterHaskell, args);
- NSException *e = (*(haskellIMP)userData)(cif, ret, args);
- recordHOCEvent(kHOCLeftHaskell, args);
- if(e != nil)
- [e raise];
-}
-
-static ffi_closure *newIMP(ffi_cif *cif, haskellIMP imp)
+static void addIvarsToClass(Class new_class, struct hoc_ivar_list *ivars)
{
- ffi_closure *closure = (ffi_closure*) calloc(1, sizeof(ffi_closure));
- ffi_prep_closure(closure, cif, &objcIMP, (void*) imp);
- return closure;
-}
-
-struct objc_method_list * makeMethodList(int n)
-{
- struct objc_method_list *list =
- calloc(1, sizeof(struct objc_method_list)
- + (n-1) * sizeof(struct objc_method));
- list->method_count = n;
- return list;
+#ifdef __OBJC2__
+ int i;
+
+ for (i = 0; i < ivars->ivar_count; i++)
+ {
+ struct hoc_ivar *ivar = &ivars->ivar_list[i];
+ class_addIvar(new_class, ivar->ivar_name,
+ ivar->ivar_size, ivar->ivar_alignment, ivar->ivar_types);
+ }
+#else
+ Class super_class = getSuperclassForClass(new_class);
+
+ int instance_size;
+ new_class->ivars = buildIndexedIvarList(
+ ivars,
+ super_class->instance_size,
+ &instance_size);
+
+ new_class->instance_size = super_class->instance_size + instance_size;
+#endif
}
-void setMethodInList(
- struct objc_method_list *list,
- int i,
- SEL sel,
- char *types,
- ffi_cif *cif,
- haskellIMP imp
- )
+static void addMethodsToClass(Class new_class, struct hoc_method_list
*methods)
{
#ifdef GNUSTEP
- list->method_list[i].method_name = (SEL) sel_get_name(sel);
+ class_add_method_list(new_class, convertMethodList(methods));
+#elif defined(__OBJC2__)
+ int i;
+ for (i = 0; i < methods->method_count; i++)
+ {
+ struct hoc_method * m = &methods->method_list[i];
+ class_addMethod(new_class, m->method_name, m->method_imp,
m->method_types);
+ }
#else
- list->method_list[i].method_name = sel;
+ new_class->methodLists = calloc( 1, sizeof(struct objc_method_list *)
);
+ new_class->methodLists[0] = (struct objc_method_list*) -1;
+
+ class_addMethods(new_class, convertMethodList(methods));
#endif
- list->method_list[i].method_types = types;
- list->method_list[i].method_imp = (IMP) newIMP(cif, imp);
}
-struct objc_ivar_list * makeIvarList(int n)
+void newClass(Class super_class,
+ const char * name,
+ struct hoc_ivar_list *ivars,
+ struct hoc_method_list *methods,
+ struct hoc_method_list *class_methods)
{
- struct objc_ivar_list *list =
- calloc(1, sizeof(struct objc_ivar_list)
- + (n-1) * sizeof(struct objc_ivar));
- list->ivar_count = n;
- return list;
-}
+ Class meta_class;
+ Class new_class;
+
+ assert(objc_lookUpClass(name) == nil);
+
+ /* Allocate the class and metaclass */
+ new_class = allocateClassPair(super_class, name);
+ meta_class = getClassForObject(new_class);
+
+ /* Add instance variables to the class */
+ addIvarsToClass(new_class, ivars);
+
+ /* Add methods and class methods */
+ /* I don't know whether order actually matters here in the non-objc2
cases,
+ so I'm leaving it as it was. */
+#ifdef __OBJC2__
+ addMethodsToClass(new_class, methods);
+ addMethodsToClass(meta_class, class_methods);
+
+ registerClassPair(new_class);
+#else
+ registerClassPair(new_class);
+
+ addMethodsToClass(new_class, methods);
+ addMethodsToClass(meta_class, class_methods);
+#endif
-void setIvarInList(
- struct objc_ivar_list *list,
- int i,
- char *name,
- char *type,
- int offset
- )
-{
- list->ivar_list[i].ivar_name = name;
- list->ivar_list[i].ivar_type = type;
- list->ivar_list[i].ivar_offset = offset;
}
+
Modified: trunk/hoc/InterfaceGenerator2/Output.hs
==============================================================================
--- trunk/hoc/InterfaceGenerator2/Output.hs (original)
+++ trunk/hoc/InterfaceGenerator2/Output.hs Sun Dec 21 13:42:00 2008
@@ -25,6 +25,7 @@
ClassEntity _ ->
[eHaskellName e, '_' `BS.cons` eHaskellName e,
eHaskellName e `BS.append` BS.pack "Class",
+ eHaskellName e `BS.append` BS.pack "MetaClass",
BS.pack "super_" `BS.append` eHaskellName e,
eHaskellName e `BS.snoc` '_' ]
EnumEntity complete values ->
@@ -56,11 +57,13 @@
LocalModule m
-> text "import {-# SOURCE #-}" <+> textBS m
<+> parens (textBS (eHaskellName e) <> comma
- <+> textBS (eHaskellName e) <> text "Class")
+ <+> textBS (eHaskellName e) <> text "Class" <>
comma
+ <+> textBS (eHaskellName e) <>
text "MetaClass")
FrameworkModule f m
-> text "import" <+> textBS m
<+> parens (textBS (eHaskellName e) <> comma
- <+> textBS (eHaskellName e) <> text "Class")
+ <+> textBS (eHaskellName e) <> text "Class" <>
comma
+ <+> textBS (eHaskellName e) <>
text "MetaClass")
pprHsBoot entityPile modName entities
= text "module" <+> textBS modName <+> text "where" $+$
@@ -78,6 +81,9 @@
<+> parens (textBS name <> char '_' <+> char 'a')
$+$
text "type" <+> textBS name <> text "Class" <+>
char 'a' <+> equals
<+> text (maybe "Class" ( (++ "Class") .
BS.unpack . eHaskellName ) mbSuper)
+ <+> parens (textBS name <> char '_' <+> char 'a')
$+$
+ text "type" <+> textBS name <> text "MetaClass" <+>
char 'a' <+> equals
+ <+> text (maybe "MetaClass" ( (++ "MetaClass") .
BS.unpack . eHaskellName ) mbSuper)
<+> parens (textBS name <> char '_' <+> char 'a')
| (name, mbSuper) <- classes0 ]
Modified: trunk/hoc/Setup.hs
==============================================================================
--- trunk/hoc/Setup.hs (original)
+++ trunk/hoc/Setup.hs Sun Dec 21 13:42:00 2008
@@ -1,6 +1,8 @@
import Distribution.Simple
import Distribution.PackageDescription
+import Distribution.Simple.Build
import Distribution.Simple.Setup
+import Distribution.Simple.PreProcess
import Distribution.Simple.Configure
import Distribution.Simple.LocalBuildInfo
import System.Cmd( system )
@@ -13,9 +15,46 @@
main = defaultMainWithHooks $ simpleUserHooks {
confHook = customConfig,
- preBuild = customPreBuild
+ buildHook = customBuild
}
+
+-- You probably don't need to change this, but if you do beware that
+-- it will not be sanitized for the shell.
+cbitsObjectFile = "dist/build/HOC_cbits.o"
+
+needsCBitsWhileBuilding :: Executable -> Bool
+needsCBitsWhileBuilding e
+ | exeName e == "hoc-test" = True
+ | otherwise = False
+
+objc2_flagName = FlagName "objc2"
+
+setObjC2Flag :: ConfigFlags -> IO ConfigFlags
+setObjC2Flag cf
+ -- if the flag is set on the command line, do nothing
+ | lookup (objc2_flagName) (configConfigurationsFlags cf) /= Nothing
+ = return cf
+
+ -- if we're not on darwin, assume false
+ | System.Info.os /= "darwin"
+ = return $ addFlag objc2_flagName False cf
+
+ -- otherwise make an educated guess
+ | otherwise
+ = do
+ value <- objC2Available
+ return $ addFlag objc2_flagName value cf
+ where addFlag flag value cf = cf { configConfigurationsFlags =
+ (flag,value) : configConfigurationsFlags cf }
+
+objC2Available :: IO Bool
+objC2Available
+ | System.Info.os /= "darwin" = return False
+ | otherwise = do
+ result <- system "grep -qR /usr/include/objc -e
objc_allocateClassPair"
+ return (result == ExitSuccess)
+
backquote :: String -> IO String
backquote cmd = do
(inp,out,err,pid) <- runInteractiveCommand cmd
@@ -43,6 +82,8 @@
customConfig :: (Either GenericPackageDescription PackageDescription,
HookedBuildInfo) -> ConfigFlags -> IO LocalBuildInfo
customConfig pdbi cf = do
+ cf <- setObjC2Flag cf
+
lbi <- configure pdbi cf
if System.Info.os == "darwin"
then return()
@@ -52,48 +93,56 @@
return lbi
-customPreBuild :: Args -> BuildFlags -> IO HookedBuildInfo
-customPreBuild args buildFlags = do
- putStrLn "Compiling HOC_cbits..."
- system "mkdir -p dist/build/"
+customBuild :: PackageDescription -> LocalBuildInfo -> UserHooks ->
BuildFlags -> IO ()
+customBuild pd lbi hooks buildFlags = do
+ let Just libInfo = library pd
+
+ extraFlags <- buildCBits (libBuildInfo libInfo)
+
+ let hooked_pd = pd
+ { library = Just $ libInfo
+ { libBuildInfo = addCompilerFlags extraFlags
+ (libBuildInfo libInfo)
+ }
+ , executables = alterExecutable needsCBitsWhileBuilding
+ (\exe -> exe {buildInfo = addCompilerFlags
extraFlags (buildInfo exe)})
+ (executables pd)
+ }
- (cflags, paths, extralibs) <-
- if System.Info.os == "darwin"
- then do
- return ("-I/usr/include/ffi -DMACOSX", [], ["-framework
Foundation"])
- else do
- (gcclibdir, system_libs, system_headers) <- gnustepPaths
- ffi_cflags <- backquote "pkg-config libffi --cflags"
- return ("-I" ++ system_headers ++ " -DGNUSTEP" ++ " " ++
ffi_cflags,
- ["-L" ++ gcclibdir, "-L" ++ system_libs],
- ["-lgnustep-base"])
+ build hooked_pd lbi buildFlags knownSuffixHandlers
+-- |Build HOC_cbits.o using the flags specified in the configuration
+-- stage, and return a list of flags to add to support usage of
+-- template-haskell while compiling (for both the library and the
+-- hoc-test executable)
+buildCBits :: BuildInfo -> IO [(CompilerFlavor, [String])]
+buildCBits buildInfo = do
+ putStrLn "Compiling HOC_cbits..."
+ system ("mkdir -p " ++ takeDirectory cbitsObjectFile)
+
+ let cflags = cppOptions buildInfo ++ ccOptions buildInfo
+ ++ ["-I" ++ dir | dir <- includeDirs buildInfo]
+ extraGHCflags = [cbitsObjectFile]
+ ++ ["-l" ++ lib | lib <- extraLibs buildInfo]
+ ++ ["-framework " ++ fw | fw <- frameworks buildInfo]
+
exitCode <- system $ "gcc -r -nostdlib -I`ghc --print-libdir`/include "
- ++ cflags ++ " HOC_cbits/*.m -o dist/build/HOC_cbits.o"
-
+ ++ unwords cflags
+ ++ " HOC_cbits/*.m -o " ++ cbitsObjectFile
+
case exitCode of
ExitSuccess -> return ()
_ -> fail "Failed in C compilation."
- -- system "cp dist/build/HOC_cbits.o dist/build/HOC_cbits.dyn_o"
- system "cp dist/build/HOC_cbits.o dist/build/hoc-test/hoc-test-tmp/"
-
- let buildInfo = emptyBuildInfo {
- options = [ (GHC, ["dist/build/HOC_cbits.o" ]
- ++ paths ++
- ["-lobjc",
- "-lffi"]
- ++ extralibs) ],
- cSources = ["HOC_cbits.o"]
- }
- buildInfo2 = emptyBuildInfo {
- options = [ (GHC,
["dist/build/hoc-test/hoc-test-tmp/HOC_cbits.o" ]
- ++ paths ++
- ["-lobjc",
- "-lffi"]
- ++ extralibs) ]{-,
- cSources = ["HOC_cbits.o"]-}
- }
-
- return (Just buildInfo, [("hoc-test", buildInfo2)])
+ return [(GHC, extraGHCflags)]
+
+-- TODO: check whether it's OK for the options field to have multiple
+-- entries for the same "compiler flavor"
+addCompilerFlags :: [(CompilerFlavor,[String])] -> BuildInfo -> BuildInfo
+addCompilerFlags flags buildInfo = buildInfo {
+ options = flags ++ options buildInfo
+ }
+alterExecutable :: (Executable -> Bool) -> (Executable -> Executable)
+ -> [Executable] -> [Executable]
+alterExecutable p f exes = [if p exe then f exe else exe | exe <- exes]
\ No newline at end of file
Modified: trunk/hoc/Tests/TestFoundation.hs
==============================================================================
--- trunk/hoc/Tests/TestFoundation.hs (original)
+++ trunk/hoc/Tests/TestFoundation.hs Sun Dec 21 13:42:00 2008
@@ -94,16 +94,19 @@
$(declareClass "HaskellObjectCountingInvocations" "NSObject")
$(exportClass "HaskellObjectCountingInvocations" "hoci_1_" [
- InstanceMethod 'countInvocationsUpto
+ InstanceMethod 'countInvocationsUpto,
+ ClassMethod 'countInvocationsUpto
])
instance Has_countInvocationsUpto (HaskellObjectCountingInvocations a)
+instance Has_countInvocationsUpto (HaskellObjectCountingInvocationsClass a)
hoci_1_countInvocationsUpto start limit self = return (start + 1)
$(declareClass "HaskellObjectUsingSuper" "HaskellObjectCountingInvocations")
$(exportClass "HaskellObjectUsingSuper" "hoci_2_" [
- InstanceMethod 'countInvocationsUpto
+ InstanceMethod 'countInvocationsUpto,
+ ClassMethod 'countInvocationsUpto
])
hoci_2_countInvocationsUpto start limit self
@@ -268,7 +271,7 @@
str <- hobj # description
fromNSString str @?= "<HaskellObjectWithDescription: TEST>"
),
- "chaining" ~: test [
+ "instanceChaining" ~: test [
"base" ~: (assertNoLeaks $ do
hobj <- _HaskellObjectCountingInvocations # alloc >>=
init
count <- hobj # countInvocationsUpto 0 100
@@ -284,6 +287,22 @@
count <- hobj # countInvocationsUpto 0 100
count @?= 2
)
+
+ ],
+ "classChaining" ~: test [
+ "base" ~: (assertNoLeaks $ do
+ count <- _HaskellObjectCountingInvocations #
countInvocationsUpto 0 100
+ count @?= 1
+ ),
+ "subclass" ~: (assertNoLeaks $ do
+ count <- _HaskellObjectUsingSuper #
countInvocationsUpto 0 100
+ count @?= 2
+ ),
+ "subsubclass" ~: (assertNoLeaks $ do
+ count <- _HaskellSubclassOfObjectUsingSuper #
countInvocationsUpto 0 100
+ count @?= 2
+ )
+
]
],
"structs" ~: test [
|