mchakravarty / language-c-inline

Inline C & Objective-C in Haskell
Other
147 stars 29 forks source link

objc_interface: parse error on NSString #45

Closed sboosali closed 10 years ago

sboosali commented 10 years ago

the AppDelegate example only has @property, and seems to include an @interface in both objc_interface and objc_implementation.

the file below errors with (See below for makefile, if needed, it's based off the app delegate example):

$ make 
...
Events.hs:11:23: Events.hs:12:3:
    parse error on `NSString'
*** Deleting temp files:
Deleting: 
*** Deleting temp dirs:
Deleting: 
make: *** [Events.o] Error 1

The app delegate example runs, and the in-line Objective-C parses when I copy and paste it into the Haskell file.

also, when put into their own files and run without Haskell, the Objective-C code both parses and runs correctly (see below for the exact .m and .h files)

A minimal example:

{-# LANGUAGE TemplateHaskell, QuasiQuotes, DeriveDataTypeable #-}
module Main where
import Foreign.C.Types
import Language.C.Quote.ObjC
import Language.C.Inline.ObjC

objc_import [ "<Carbon/Carbon.h>" 
            , "<Cocoa/Cocoa.h>"
            , "<Foundation/Foundation.h>"]

objc_interface [cunit|@interface Actor : NSObject {}
+(NSString*) currentApplicationPath;
@end|]

objc_implementation [] [cunit|@implementation Actor
+(NSString*) currentApplicationPath {
 return [[[NSWorkspace sharedWorkspace] activeApplication] objectForKey:@"NSApplicationPath"];
}
@end|]

currentApplicationPathO :: IO String
currentApplicationPathO = $(objc [] $ [t|String|] <: [cexp|
 [Actor currentApplicationPath]
|])

objc_emit

main =  do
 objc_initialise
 currentApplicationPathO >>= print 

how can I get the file above to work?

whole files: https://github.com/sboosali/Haskell-DragonNaturallySpeaking/blob/issue/Makefile https://github.com/sboosali/Haskell-DragonNaturallySpeaking/blob/issue/Events.hs https://github.com/sboosali/Haskell-DragonNaturallySpeaking/blob/issue/actor.m https://github.com/sboosali/Haskell-DragonNaturallySpeaking/blob/issue/actor.h

thank you!

mchakravarty commented 10 years ago

the AppDelegate example only has @property, and seems to include an @interface in both objc_interface and objc_implementation.

The @interface in the objc_implementation part is a class extension. This is a common idiom in Objective-C, see https://developer.apple.com/library/ios/documentation/cocoa/conceptual/programmingwithobjectivec/CustomizingExistingClasses/CustomizingExistingClasses.html#//apple_ref/doc/uid/TP40011210-CH6-SW3

Events.hs:11:23: Events.hs:12:3:
    parse error on `NSString'

This error is because we don't know in inline Objective-C which types are predefined in included headers. Hence, instead of just NSString*, you need to write typename NSString*. This is necessary for all types that are pre-defined in Apple's libraries and that you use in inline code.

If you look at the examples, they do the same; e.g., in the AppDelegate, we have

objc_interface [cunit|

@interface AppDelegate : NSResponder <NSApplicationDelegate>

// IBOutlets
@property (weak, nonatomic) typename NSWindow     *window;
@property (weak, nonatomic) typename NSScrollView *scrollView;
@property (weak, nonatomic) typename NSTextField  *textField;

@end
|]

Note the typename before any type pre-defined from Apple libraries (such as NSWindow).

Does that fix your problem?

sboosali commented 10 years ago

it does!

is this related to how C++ parsing needs info from type checking? I made sure to include Foundation in objc_import, since NSString is defined there, but it seems each cunit template is parsed independently. I should've tried built-in types alone like void. sorry you had to debug that.

mchakravarty commented 10 years ago

is this related to how C++ parsing needs info from type checking?

Even in plain C, the lexical analyser (tokenising the program) needs info from the part of the frontend processing typedef. That's why you need to add the typename.

I made sure to include Foundation in objc_import, since NSString is defined there, but it seems each cunit template is parsed independently.

That's right.

I should've tried built-in types alone like void. sorry you had to debug that.

No, not a problem. Let me know if you encounter any other obstacles.