Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

an objc_msgSend() macro #8

Closed
dognotdog opened this issue Nov 24, 2015 · 1 comment
Closed

an objc_msgSend() macro #8

dognotdog opened this issue Nov 24, 2015 · 1 comment

Comments

@dognotdog
Copy link

While mucking about with how to do some GUI stuff for Julia on OSX, while I was having issues with ObjectiveC.jl, I've managed, somehow bending metaprogramming to my will, to come up with a macro version of objc_msgSend() with multiple args that doesnt rely on ccal(), and should produce a ccall() with no runtime overhead.

Maybe ObjectiveC.jl can benefit from this voodoo.

Its curious to note that

UP = (P...,U...)
ccallTypes = parse("$UP")

works in the REPL, if U,P are set to the appropriate datatype-tuples, and produce the same s-expr as

UU = parse("$U")
PP = parse("$P")
Expr(PP.head, PP.args..., UU.args...)

but not when put in the body of the macro, which generates a useless error.

Alas, this works:

# functions binding objc runtime

function SEL(aString::Union{ASCIIString,UTF8String})
  ccall(:sel_getUid, Ptr{Void}, (Ptr{UInt8},), aString)
end

# this objc_msgSend taken from Tk.jl
objc_msgSend{T}(id, uid, ::Type{T}=Ptr{Void}) = ccall(:objc_msgSend, T, (Ptr{Void}, Ptr{Void}), id, SEL(uid))

macro objc_msgSend(T, U, id, methodName::Union{ASCIIString,UTF8String}, args...)
  # the objc_msgSend types for self and selector
  P = (Ptr{Void},Ptr{Void})

  # re-parse the stringified type declarations
  UU = parse("$U")
  PP = parse("$P")
  # manually merge tuples
  ccallTypes = Expr(PP.head, PP.args..., UU.args...)

  # conatenating U and P via (P...,U...) does not seem to work in macro world (julia v0.4.1)

  rval = :(ccall(:objc_msgSend, $T, $ccallTypes, $id, SEL($methodName), $(args...)))
  # rval = Expr(:call, :ccall, :(:objc_msgSend), T, ccallTypes, id, :(SEL($methodName)), args...)
  # @show rval
  # println("\nsexpr(rval)")
  # Meta.show_sexpr(rval)
  # println("")

  return rval
end

# void objc_msgSend_stret(void * stretAddr, id theReceiver, SEL theSelector, ...)
function objc_msgSend_stret{T}(self, methodName, ::Type{T})
  rval = T()
  ccall(:objc_msgSend_stret, Void, (Ptr{T}, Ptr{Void}, Ptr{Void}), Ref(rval), self, SEL(methodName))
  return rval
end

usage like so:

function objcString(aString::Union{ASCIIString,UTF8String})
  oString = objc_msgSend(objc_getClass("NSString"), "alloc")
  oString = @objc_msgSend(Ptr{Void}, (Ptr{UInt8},), oString, "initWithUTF8String:", aString)
  oString = objc_msgSend(oString, "autorelease")
  return oString
end
@maleadt
Copy link
Member

maleadt commented Mar 8, 2023

I did something like this in #11, so I think we can close this issue.

@maleadt maleadt closed this as completed Mar 8, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants