From 65bd4bc92fd1092fd928a04ccb6f552a040a9a29 Mon Sep 17 00:00:00 2001 From: Christian Guinard <28689358+christiangnrd@users.noreply.github.com> Date: Mon, 3 Mar 2025 06:33:47 -0400 Subject: [PATCH] Indentation consistency (#58) --- README.md | 74 ++++----- src/blocks.jl | 40 ++--- src/classes.jl | 34 ++--- src/foundation.jl | 346 +++++++++++++++++++++--------------------- src/methods.jl | 58 +++---- src/primitives.jl | 86 +++++------ src/syntax.jl | 376 +++++++++++++++++++++++----------------------- 7 files changed, 507 insertions(+), 507 deletions(-) diff --git a/README.md b/README.md index 5cffeb0..5195f96 100644 --- a/README.md +++ b/README.md @@ -68,9 +68,9 @@ it is possible to access these directly using `@objc`, ObjectiveC.jl provides a automatically generate the appropriate `getproperty`, `setproperty!` and `propertynames` definitions: -```julia +```julia-repl julia> @objcproperties NSValue begin - @autoproperty pointerValue::Ptr{Cvoid} + @autoproperty pointerValue::Ptr{Cvoid} end julia> obj.pointerValue @@ -82,30 +82,30 @@ property macros: ```julia @objcproperties SomeObject begin - # simplest definition: just generate a getter, - # and convert the property value to `DstTyp` - @autoproperty someProperty::DstTyp - - # also generate a setter - @autoproperty someProperty::DstTyp setter=setSomeProperty - - # if the property is an ObjC object, use an object pointer type. - # this will make sure to do a nil check and return nothing, - # or convert the pointer to an instance of the specified type - @autoproperty someProperty::id{DstTyp} - - # sometimes you may want to convert to a different type - @autoproperty someStringProperty::id{NSString} type=String - - # and finally, if more control is needed, just do it yourselv: - @getproperty someComplexProperty function(obj) - # do something with obj - # return a value - end - @setproperty! someComplexProperty function(obj, val) - # do something with obj and val - # return nothing - end + # simplest definition: just generate a getter, + # and convert the property value to `DstTyp` + @autoproperty someProperty::DstTyp + + # also generate a setter + @autoproperty someProperty::DstTyp setter=setSomeProperty + + # if the property is an ObjC object, use an object pointer type. + # this will make sure to do a nil check and return nothing, + # or convert the pointer to an instance of the specified type + @autoproperty someProperty::id{DstTyp} + + # sometimes you may want to convert to a different type + @autoproperty someStringProperty::id{NSString} type=String + + # and finally, if more control is needed, just do it yourself: + @getproperty someComplexProperty function(obj) + # do something with obj + # return a value + end + @setproperty! someComplexProperty function(obj, val) + # do something with obj and val + # return nothing + end end ``` @@ -114,10 +114,10 @@ end Julia callables can be converted to Objective-C blocks using the `@objcblock` macro: -```julia +```julia-repl julia> function hello(x) - println("Hello, $x!") - x+1 + println("Hello, $x!") + x+1 end julia> block = @objcblock(hello, Cint, (Cint,)) ``` @@ -134,11 +134,11 @@ may decide to coalesce multiple conditions into a single execution, so it is pre use `@objcblock` whenever possible. It is also not possible to pass any arguments to the condition, but you can use a closure to capture any state you need: -```julia +```julia-repl julia> counter = 0 julia> cond = Base.AsyncCondition() do async_cond - counter += 1 - end + counter += 1 + end julia> block = @objcasyncblock(cond) ``` @@ -147,7 +147,7 @@ julia> block = @objcasyncblock(cond) ObjectiveC.jl also provides ready-made wrappers for essential frameworks like Foundation: -```julia +```julia-repl julia> using .Foundation @@ -156,9 +156,9 @@ NSString("test") julia> NSArray([str, str]) -( - test, - test +<__NSArrayI 0x12e69b9b0>( +test, +test ) @@ -181,7 +181,7 @@ Dict{NSString, NSString} with 1 entry: To see what ObjectiveC.jl is doing under the hood, you can toggle the `tracing` preference, which will make the package print out the Objective-C calls it makes: -```julia +```julia-repl julia> using ObjectiveC julia> ObjectiveC.enable_tracing(true) [ Info: ObjectiveC.jl tracing setting changed; restart your Julia session for this change to take effect! diff --git a/src/blocks.jl b/src/blocks.jl index 1f1f73a..83149ba 100644 --- a/src/blocks.jl +++ b/src/blocks.jl @@ -32,22 +32,22 @@ end # NSBlocks are untracked by the Julia GC, so we need to manually root the Julia objects const julia_block_roots = Dict{NSBlock,JuliaBlock}() function julia_block_copy(_dst, _src) - dst_nsblock = NSBlock(reinterpret(id{NSBlock}, _dst)) - src_nsblock = NSBlock(reinterpret(id{NSBlock}, _src)) + dst_nsblock = NSBlock(reinterpret(id{NSBlock}, _dst)) + src_nsblock = NSBlock(reinterpret(id{NSBlock}, _src)) - @assert haskey(julia_block_roots, src_nsblock) - julia_block_roots[dst_nsblock] = julia_block_roots[src_nsblock] + @assert haskey(julia_block_roots, src_nsblock) + julia_block_roots[dst_nsblock] = julia_block_roots[src_nsblock] - return + return end function julia_block_dispose(_block) - block = unsafe_load(_block) - nsblock = NSBlock(reinterpret(id{NSBlock}, _block)) + block = unsafe_load(_block) + nsblock = NSBlock(reinterpret(id{NSBlock}, _block)) - @assert haskey(julia_block_roots, nsblock) - delete!(julia_block_roots, nsblock) + @assert haskey(julia_block_roots, nsblock) + delete!(julia_block_roots, nsblock) - return + return end # JuliaBlock is the concrete version of NSBlock, so make it possible to derive a regular @@ -78,13 +78,13 @@ const julia_block_descriptor_initialized = Ref{Bool}(false) function JuliaBlock(trampoline, callable) # lazily create a descriptor (these sometimes don't precompile properly) if !julia_block_descriptor_initialized[] - # simple cfunctions, so don't need to be rooted - copy_cb = @cfunction(julia_block_copy, Nothing, (Ptr{JuliaBlock}, Ptr{JuliaBlock})) - dispose_cb = @cfunction(julia_block_dispose, Nothing, (Ptr{JuliaBlock},)) + # simple cfunctions, so don't need to be rooted + copy_cb = @cfunction(julia_block_copy, Nothing, (Ptr{JuliaBlock}, Ptr{JuliaBlock})) + dispose_cb = @cfunction(julia_block_dispose, Nothing, (Ptr{JuliaBlock},)) - julia_block_descriptor[] = JuliaBlockDescriptor(0, sizeof(JuliaBlock), - copy_cb, dispose_cb) - julia_block_descriptor_initialized[] = true + julia_block_descriptor[] = JuliaBlockDescriptor(0, sizeof(JuliaBlock), + copy_cb, dispose_cb) + julia_block_descriptor_initialized[] = true end # set-up the block data structures @@ -183,10 +183,10 @@ const julia_async_block_descriptor_initialized = Ref{Bool}(false) function JuliaAsyncBlock(cond) # lazily create a descriptor (these sometimes don't precompile properly) if !julia_async_block_descriptor_initialized[] - # simple cfunctions, so don't need to be rooted - julia_async_block_descriptor[] = JuliaAsyncBlockDescriptor(0, sizeof(JuliaAsyncBlock), - C_NULL, C_NULL) - julia_async_block_descriptor_initialized[] = true + # simple cfunctions, so don't need to be rooted + julia_async_block_descriptor[] = JuliaAsyncBlockDescriptor(0, sizeof(JuliaAsyncBlock), + C_NULL, C_NULL) + julia_async_block_descriptor_initialized[] = true end # create a trampoline to wake libuv with the user-provided condition diff --git a/src/classes.jl b/src/classes.jl index eb4a68f..a84abfd 100644 --- a/src/classes.jl +++ b/src/classes.jl @@ -2,39 +2,39 @@ # resurrecting it, please look at the repository at commit 22118319da. function allocclass(name, super) - ptr = ccall(:objc_allocateClassPair, Ptr{Cvoid}, (Ptr{Cvoid}, Ptr{Cchar}, Csize_t), - super, name, 0) - ptr == C_NULL && error("Couldn't allocate class $name") - return Class(ptr) + ptr = ccall(:objc_allocateClassPair, Ptr{Cvoid}, (Ptr{Cvoid}, Ptr{Cchar}, Csize_t), + super, name, 0) + ptr == C_NULL && error("Couldn't allocate class $name") + return Class(ptr) end function register(class::Class) - ccall(:objc_registerClassPair, Cvoid, (Ptr{Cvoid},), - class) - return class + ccall(:objc_registerClassPair, Cvoid, (Ptr{Cvoid},), + class) + return class end createclass(name, super) = allocclass(name, super) |> register getmethod(class::Class, sel::Selector) = - ccall(:class_getInstanceMethod, Ptr{Cvoid}, (Ptr{Cvoid}, Ptr{Cvoid}), - class, sel) + ccall(:class_getInstanceMethod, Ptr{Cvoid}, (Ptr{Cvoid}, Ptr{Cvoid}), + class, sel) methodtypeenc(method::Ptr) = - ccall(:method_getTypeEncoding, Ptr{Cchar}, (Ptr{Cvoid},), - method) |> unsafe_string + ccall(:method_getTypeEncoding, Ptr{Cchar}, (Ptr{Cvoid},), + method) |> unsafe_string methodtypeenc(class::Class, sel::Selector) = methodtypeenc(getmethod(class, sel)) methodtype(args...) = methodtypeenc(args...) |> parseencoding replacemethod(class::Class, sel::Selector, imp::Ptr{Cvoid}, types::String) = - ccall(:class_replaceMethod, Bool, (Ptr{Cvoid}, Ptr{Cvoid}, Ptr{Cvoid}, Ptr{Cchar}), - class, sel, imp, types) + ccall(:class_replaceMethod, Bool, (Ptr{Cvoid}, Ptr{Cvoid}, Ptr{Cvoid}, Ptr{Cchar}), + class, sel, imp, types) function setmethod(class::Class, sel::Selector, imp::Ptr{Cvoid}, types::String) - meth = getmethod(class, sel) - meth ≠ C_NULL && methodtype(meth) != parseencoding(types) && - error("New method $(name(sel)) of $class must match $(methodtype(meth))") - replacemethod(class, sel, imp, types) + meth = getmethod(class, sel) + meth ≠ C_NULL && methodtype(meth) != parseencoding(types) && + error("New method $(name(sel)) of $class must match $(methodtype(meth))") + replacemethod(class, sel, imp, types) end diff --git a/src/foundation.jl b/src/foundation.jl index fde3d8c..aa72eff 100644 --- a/src/foundation.jl +++ b/src/foundation.jl @@ -7,11 +7,11 @@ using ..CEnum export NSInteger, MSIntegerMin, NSIntegerMax, NSUInteger, NSUIntegerMax if sizeof(Ptr{Cvoid}) == 8 - const NSInteger = Int64 - const NSUInteger = UInt64 + const NSInteger = Int64 + const NSUInteger = UInt64 else - const NSInteger = Int32 - const NSUInteger = UInt32 + const NSInteger = Int32 + const NSUInteger = UInt32 end const NSIntegerMin = typemin(NSInteger) const NSIntegerMax = typemax(NSInteger) @@ -34,11 +34,11 @@ export NSObject, retain, release, autorelease, is_kind_of end function Base.show(io::IO, ::MIME"text/plain", obj::NSObject) - if get(io, :compact, false) - print(io, String(obj.description)) - else - print(io, String(obj.debugDescription)) - end + if get(io, :compact, false) + print(io, String(obj.description)) + else + print(io, String(obj.debugDescription)) + end end release(obj::NSObject) = @objc [obj::id{NSObject} release]::Cvoid @@ -50,11 +50,11 @@ retain(obj::NSObject) = @objc [obj::id{NSObject} retain]::Cvoid ObjectiveC.class(obj::NSObject) = @objc [obj::id{NSObject} class]::Class function is_kind_of(obj::NSObject, class::Class) - @objc [obj::id{NSObject} isKindOfClass:class::Class]::Bool + @objc [obj::id{NSObject} isKindOfClass:class::Class]::Bool end function Base.:(==)(obj1::NSObject, obj2::NSObject) - @objc [obj1::id{NSObject} isEqual:obj2::id{NSObject}]::Bool + @objc [obj1::id{NSObject} isEqual:obj2::id{NSObject}]::Bool end @@ -77,7 +77,7 @@ export NSValue @objcwrapper NSValue <: NSObject Base.:(==)(v1::NSValue, v2::NSValue) = - @objc [v1::id{NSValue} isEqualToValue:v2::id{NSValue}]::Bool + @objc [v1::id{NSValue} isEqualToValue:v2::id{NSValue}]::Bool @objcproperties NSValue begin @autoproperty objCType::Ptr{Cchar} @@ -88,7 +88,7 @@ end NSValue(x::Ptr) = NSValue(@objc [NSValue valueWithPointer:x::Ptr{Cvoid}]::id{NSValue}) NSValue(x::Union{NSRange,UnitRange}) = - NSValue(@objc [NSValue valueWithRange:x::NSRange]::id{NSValue}) + NSValue(@objc [NSValue valueWithRange:x::NSRange]::id{NSValue}) # ... @@ -134,11 +134,11 @@ end Base.isnan(dec::NSDecimal) = dec.length == 0 && dec.isNegative function Base.show(io::IO, dec::NSDecimal) - if isnan(dec) - print(io, "NaN") - else - print(io, "NSDecimal(", dec.mantissa, "e", dec.exponent, ")") - end + if isnan(dec) + print(io, "NaN") + else + print(io, "NSDecimal(", dec.mantissa, "e", dec.exponent, ")") + end end @@ -183,13 +183,13 @@ const NSNumberTypes = [ ] let - unique_number_types = Set{Type}(map(first, NSNumberTypes)) - for T in unique_number_types - i = findfirst(x->x[1] == T, NSNumberTypes) - method = NSNumberTypes[i][2] - @eval NSNumber(x::$T) = NSNumber(@objc [NSNumber $method:x::$T]::id{NSNumber}) - @eval Base.convert(::Type{NSNumber}, x::$T) = NSNumber(x) - end + unique_number_types = Set{Type}(map(first, NSNumberTypes)) + for T in unique_number_types + i = findfirst(x->x[1] == T, NSNumberTypes) + method = NSNumberTypes[i][2] + @eval NSNumber(x::$T) = NSNumber(@objc [NSNumber $method:x::$T]::id{NSNumber}) + @eval Base.convert(::Type{NSNumber}, x::$T) = NSNumber(x) + end end @@ -265,13 +265,13 @@ Base.cconvert(::Type{id{NSString}}, str::String) = NSString(str) Base.convert(::Type{NSString}, str::String) = NSString(str) Base.:(==)(s1::Union{String,NSString}, s2::Union{String,NSString}) = - String(s1) == String(s2) + String(s1) == String(s2) Base.:(==)(s1::NSString, s2::NSString) = - @objc [s1::id{NSString} isEqualToString:s2::id{NSString}]::Bool + @objc [s1::id{NSString} isEqualToString:s2::id{NSString}]::Bool NSString() = NSString(@objc [NSString string]::id{NSString}) NSString(data::String) = - NSString(@objc [NSString stringWithUTF8String:data::Ptr{Cchar}]::id{NSString}) + NSString(@objc [NSString stringWithUTF8String:data::Ptr{Cchar}]::id{NSString}) Base.length(s::NSString) = Int(s.length) Base.String(s::NSString) = unsafe_string(@objc [s::id{NSString} UTF8String]::Ptr{Cchar}) @@ -280,13 +280,13 @@ Base.string(s::NSString) = String(s) Base.print(io::IO, s::NSString) = print(io, String(s)) Base.show(io::IO, ::MIME"text/plain", s::NSString) = - print(io, "NSString(", repr(String(s)), ")") + print(io, "NSString(", repr(String(s)), ")") Base.show(io::IO, s::NSString) = show(io, String(s)) Base.contains(s::NSString, t::AbstractString) = - @objc [s::id{NSString} containsString:t::id{NSString}]::Bool + @objc [s::id{NSString} containsString:t::id{NSString}]::Bool Base.contains(s::AbstractString, t::NSString) = - @objc [s::id{NSString} containsString:t::id{NSString}]::Bool + @objc [s::id{NSString} containsString:t::id{NSString}]::Bool export NSArray @@ -307,18 +307,18 @@ end Base.length(arr::NSArray) = Int(arr.count) function Base.getindex(arr::NSArray, i::Int) - @boundscheck 1 <= i <= length(arr) || throw(BoundsError(arr, i)) - @objc [arr::id{NSArray} objectAtIndex:(i-1)::NSUInteger]::id{Object} + @boundscheck 1 <= i <= length(arr) || throw(BoundsError(arr, i)) + @objc [arr::id{NSArray} objectAtIndex:(i-1)::NSUInteger]::id{Object} end Base.iterate(arr::NSArray, i::Int=1) = i > length(arr) ? nothing : (arr[i], i+1) Base.:(==)(a1::NSArray, a2::NSArray) = - @objc [a1::id{NSArray} isEqualToArray:a2::id{NSArray}]::Bool + @objc [a1::id{NSArray} isEqualToArray:a2::id{NSArray}]::Bool # conversion to typed Julia array function Base.convert(::Type{Vector{T}}, arr::NSArray) where {T} - [reinterpret(T, arr[i]) for i in 1:length(arr)] + [reinterpret(T, arr[i]) for i in 1:length(arr)] end Vector{T}(arr::NSArray) where {T} = convert(Vector{T}, arr) @@ -350,15 +350,15 @@ Base.keys(dict::NSDictionary) = dict.allKeys Base.values(dict::NSDictionary) = dict.allValues function Base.getindex(dict::NSDictionary, key::NSObject) - ptr = @objc [dict::id{NSDictionary} objectForKey:key::id{NSObject}]::id{Object} - ptr == nil && throw(KeyError(key)) - return ptr + ptr = @objc [dict::id{NSDictionary} objectForKey:key::id{NSObject}]::id{Object} + ptr == nil && throw(KeyError(key)) + return ptr end # conversion to typed Julia dictionary function Base.convert(::Type{Dict{K,V}}, dict::NSDictionary) where {K,V} - Dict{K,V}(zip(map(Base.Fix1(reinterpret, K), keys(dict)), - map(Base.Fix1(reinterpret, V), values(dict)))) + Dict{K,V}(zip(map(Base.Fix1(reinterpret, K), keys(dict)), + map(Base.Fix1(reinterpret, V), values(dict)))) end Dict{K,V}(dict::NSDictionary) where {K,V} = convert(Dict{K,V}, dict) @@ -379,33 +379,33 @@ end # TODO: userInfo function NSError(domain, code) - err = @objc [NSError errorWithDomain:domain::id{NSString} - code:code::NSInteger - userInfo:nil::id{NSDictionary}]::id{NSError} - return NSError(err) + err = @objc [NSError errorWithDomain:domain::id{NSString} + code:code::NSInteger + userInfo:nil::id{NSDictionary}]::id{NSError} + return NSError(err) end function NSError(domain, code, userInfo) - err = @objc [NSError errorWithDomain:domain::id{NSString} - code:code::NSInteger - userInfo:userInfo::id{NSDictionary}]::id{NSError} - return NSError(err) + err = @objc [NSError errorWithDomain:domain::id{NSString} + code:code::NSInteger + userInfo:userInfo::id{NSDictionary}]::id{NSError} + return NSError(err) end function Base.showerror(io::IO, err::NSError) - print(io, "NSError: $(err.localizedDescription) ($(err.domain), code $(err.code))") + print(io, "NSError: $(err.localizedDescription) ($(err.domain), code $(err.code))") - if err.localizedFailureReason !== nothing - print(io, "\nFailure reason: $(err.localizedFailureReason)") - end + if err.localizedFailureReason !== nothing + print(io, "\nFailure reason: $(err.localizedFailureReason)") + end - recovery_options = err.localizedRecoveryOptions - if recovery_options !== nothing - print(io, "\nRecovery Options:") - for option in recovery_options - print(io, "\n - $(option)") + recovery_options = err.localizedRecoveryOptions + if recovery_options !== nothing + print(io, "\nRecovery Options:") + for option in recovery_options + print(io, "\n - $(option)") + end end - end end @@ -429,14 +429,14 @@ export NSBundle, load_framework @objcwrapper NSBundle <: NSObject function NSBundle(path::Union{String,NSString}) - ptr = @objc [NSBundle bundleWithPath:path::id{NSString}]::id{NSBundle} - ptr == nil && error("Couldn't find bundle '$path'") - NSBundle(ptr) + ptr = @objc [NSBundle bundleWithPath:path::id{NSString}]::id{NSBundle} + ptr == nil && error("Couldn't find bundle '$path'") + NSBundle(ptr) end function load(bundle::NSBundle) - loaded = @objc [bundle::id{NSBundle} load]::Bool - loaded || error("Couldn't load bundle") + loaded = @objc [bundle::id{NSBundle} load]::Bool + loaded || error("Couldn't load bundle") end load_framework(name) = load(NSBundle("/System/Library/Frameworks/$name.framework")) @@ -447,47 +447,47 @@ export NSURL, NSFileURL @objcwrapper NSURL <: NSObject @objcproperties NSURL begin - # Querying an NSURL - @autoproperty isFileURL::Bool - @autoproperty isFileReferenceURL::Bool - - # Accessing the Parts of the URL - @autoproperty absoluteString::id{NSString} - @autoproperty absoluteURL::id{NSURL} - @autoproperty baseURL::id{NSURL} - @autoproperty fileSystemRepresentation::id{NSString} - @autoproperty fragment::id{NSString} - @autoproperty host::id{NSString} - @autoproperty lastPathComponent::id{NSString} - @autoproperty parameterString::id{NSString} - @autoproperty password::id{NSString} - @autoproperty path::id{NSString} - @autoproperty pathComponents::id{NSArray} type=Vector{NSString} - @autoproperty pathExtension::id{NSString} - @autoproperty port::id{NSNumber} - @autoproperty query::id{NSString} - @autoproperty relativePath::id{NSString} - @autoproperty relativeString::id{NSString} - @autoproperty resourceSpecifier::id{NSString} - @autoproperty scheme::id{NSString} - @autoproperty standardizedURL::id{NSURL} - @autoproperty user::id{NSString} - - # Modifying and Converting a File URL - @autoproperty filePathURL::id{NSURL} - @autoproperty fileReferenceURL::id{NSURL} + # Querying an NSURL + @autoproperty isFileURL::Bool + @autoproperty isFileReferenceURL::Bool + + # Accessing the Parts of the URL + @autoproperty absoluteString::id{NSString} + @autoproperty absoluteURL::id{NSURL} + @autoproperty baseURL::id{NSURL} + @autoproperty fileSystemRepresentation::id{NSString} + @autoproperty fragment::id{NSString} + @autoproperty host::id{NSString} + @autoproperty lastPathComponent::id{NSString} + @autoproperty parameterString::id{NSString} + @autoproperty password::id{NSString} + @autoproperty path::id{NSString} + @autoproperty pathComponents::id{NSArray} type=Vector{NSString} + @autoproperty pathExtension::id{NSString} + @autoproperty port::id{NSNumber} + @autoproperty query::id{NSString} + @autoproperty relativePath::id{NSString} + @autoproperty relativeString::id{NSString} + @autoproperty resourceSpecifier::id{NSString} + @autoproperty scheme::id{NSString} + @autoproperty standardizedURL::id{NSURL} + @autoproperty user::id{NSString} + + # Modifying and Converting a File URL + @autoproperty filePathURL::id{NSURL} + @autoproperty fileReferenceURL::id{NSURL} end function NSURL(str::Union{String,NSString}) - NSURL(@objc [NSURL URLWithString:str::id{NSString}]::id{NSURL}) + NSURL(@objc [NSURL URLWithString:str::id{NSString}]::id{NSURL}) end function NSFileURL(path::Union{String,NSString}) - NSURL(@objc [NSURL fileURLWithPath:path::id{NSString}]::id{NSURL}) + NSURL(@objc [NSURL fileURLWithPath:path::id{NSString}]::id{NSURL}) end function Base.:(==)(a::NSURL, b::NSURL) - @objc [a::id{NSURL} isEqual:b::id{NSURL}]::Bool + @objc [a::id{NSURL} isEqual:b::id{NSURL}]::Bool end @@ -531,12 +531,12 @@ For high-level usage, consider using the do-block syntax, or [`@autoreleasepool` instead. """ function NSAutoreleasePool() - obj = NSAutoreleasePool(@objc [NSAutoreleasePool alloc]::id{NSAutoreleasePool}) - # XXX: this init call itself requires an autoreleasepool to be active... - @objc [obj::id{NSAutoreleasePool} init]::id{NSAutoreleasePool} - # NOTE: we don't register a finalizer, as it's better to drain the pool, - # and it's not allowed to both drain and release. - obj + obj = NSAutoreleasePool(@objc [NSAutoreleasePool alloc]::id{NSAutoreleasePool}) + # XXX: this init call itself requires an autoreleasepool to be active... + @objc [obj::id{NSAutoreleasePool} init]::id{NSAutoreleasePool} + # NOTE: we don't register a finalizer, as it's better to drain the pool, + # and it's not allowed to both drain and release. + obj end drain(pool::NSAutoreleasePool) = @objc [pool::id{NSAutoreleasePool} drain]::Cvoid @@ -559,34 +559,34 @@ To disable these limitations, use the unsafe [`NSUnsafeAutoreleasePool`](@ref) i See also: [`@autoreleasepool`](@ref) """ function NSAutoreleasePool(f::Base.Callable) - # we cannot switch between multiple autorelease pools, so ensure only one is ever active. - # XXX: support multiple pools, as long as they run on separate threads? - Base.@lock NSAutoreleaseLock begin - # autorelease pools are thread-bound, so ensure we don't migrate to another thread - task = current_task() - sticky = task.sticky - task.sticky = true - - pool = NSAutoreleasePool() - try - f() - finally - drain(pool) - #task.sticky = sticky - # XXX: we cannot safely re-enable thread migration, as the called code might have - # disabled it too. instead, Julia should have a notion of "temporary pinning" + # we cannot switch between multiple autorelease pools, so ensure only one is ever active. + # XXX: support multiple pools, as long as they run on separate threads? + Base.@lock NSAutoreleaseLock begin + # autorelease pools are thread-bound, so ensure we don't migrate to another thread + task = current_task() + sticky = task.sticky + task.sticky = true + + pool = NSAutoreleasePool() + try + f() + finally + drain(pool) + #task.sticky = sticky + # XXX: we cannot safely re-enable thread migration, as the called code might have + # disabled it too. instead, Julia should have a notion of "temporary pinning" + end end - end end const NSAutoreleaseLock = ReentrantLock() function NSUnsafeAutoreleasePool(f::Base.Callable) - pool = NSAutoreleasePool() - try - f() - finally - drain(pool) - end + pool = NSAutoreleasePool() + try + f() + finally + drain(pool) + end end @@ -602,57 +602,57 @@ enclosed code block has finished. See also: [`NSAutoreleasePool`](@ref) """ macro autoreleasepool(ex...) - code = ex[end] - kwargs = ex[1:end-1] - - # extract keyword arguments that are handled by this macro - unsafe = false - for kwarg in kwargs - if Meta.isexpr(kwarg, :(=)) - key, value = kwarg.args - if key == :unsafe - isa(value, Bool) || throw(ArgumentError("Invalid value for keyword argument `unsafe`: got `$value`, expected literal boolean value")) - unsafe = value - else - error("Invalid keyword argument to @autoreleasepool: $kwarg") - end - else - throw(ArgumentError("Invalid keyword argument to @autoreleasepool: $kwarg")) - end - end - f = unsafe ? NSUnsafeAutoreleasePool : NSAutoreleasePool - - if Meta.isexpr(code, :(=)) && - (Meta.isexpr(code.args[1], :call) || Meta.isexpr(code.args[1], :where)) - # function definition, short form - sig, body = code.args - @assert Meta.isexpr(body, :block) - managed_body = quote - $f() do - $body - end - end - esc(Expr(:(=), sig, managed_body)) - elseif Meta.isexpr(code, :function) - # function definition, long form - sig = code.args[1] - @assert Meta.isexpr(sig, :call) || Meta.isexpr(sig, :where) - body = code.args[2] - @assert Meta.isexpr(body, :block) - managed_body = quote - $f() do - $body - end + code = ex[end] + kwargs = ex[1:end-1] + + # extract keyword arguments that are handled by this macro + unsafe = false + for kwarg in kwargs + if Meta.isexpr(kwarg, :(=)) + key, value = kwarg.args + if key == :unsafe + isa(value, Bool) || throw(ArgumentError("Invalid value for keyword argument `unsafe`: got `$value`, expected literal boolean value")) + unsafe = value + else + error("Invalid keyword argument to @autoreleasepool: $kwarg") + end + else + throw(ArgumentError("Invalid keyword argument to @autoreleasepool: $kwarg")) + end end - esc(Expr(:function, sig, managed_body)) - else - # code block - quote - $f() do - $(esc(code)) - end + f = unsafe ? NSUnsafeAutoreleasePool : NSAutoreleasePool + + if Meta.isexpr(code, :(=)) && + (Meta.isexpr(code.args[1], :call) || Meta.isexpr(code.args[1], :where)) + # function definition, short form + sig, body = code.args + @assert Meta.isexpr(body, :block) + managed_body = quote + $f() do + $body + end + end + esc(Expr(:(=), sig, managed_body)) + elseif Meta.isexpr(code, :function) + # function definition, long form + sig = code.args[1] + @assert Meta.isexpr(sig, :call) || Meta.isexpr(sig, :where) + body = code.args[2] + @assert Meta.isexpr(body, :block) + managed_body = quote + $f() do + $body + end + end + esc(Expr(:function, sig, managed_body)) + else + # code block + quote + $f() do + $(esc(code)) + end + end end - end end diff --git a/src/methods.jl b/src/methods.jl index 93a287b..beadf57 100644 --- a/src/methods.jl +++ b/src/methods.jl @@ -1,18 +1,18 @@ export signature method(class::Class, sel::Selector) = - ccall(:class_getInstanceMethod, Ptr{Cvoid}, (Ptr{Cvoid}, Ptr{Cvoid}), - class, sel) + ccall(:class_getInstanceMethod, Ptr{Cvoid}, (Ptr{Cvoid}, Ptr{Cvoid}), + class, sel) method(obj::Object, sel::Selector) = - method(class(obj), sel) + method(class(obj), sel) types(m::Ptr) = - ccall(:method_getTypeEncoding, Ptr{Cchar}, (Ptr{Cvoid},), m) |> unsafe_string + ccall(:method_getTypeEncoding, Ptr{Cchar}, (Ptr{Cvoid},), m) |> unsafe_string implementation(m::Ptr) = - ccall(:method_getImplementation, Ptr{Cvoid}, (Ptr{Cvoid},), - m) + ccall(:method_getImplementation, Ptr{Cvoid}, (Ptr{Cvoid},), + m) # From https://developer.apple.com/library/mac/documentation/Cocoa/Conceptual/ObjCRuntimeGuide/Articles/ocrtTypeEncodings.html const typeencodings = Dict('c' => Cchar, @@ -48,21 +48,21 @@ const skip = Set(['r', 'V', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9']) function nexttype(io::IO) - c = read(io, Char) - c in skip && return - haskey(typeencodings, c) || error("Unsupported method type: $(String(take!(io)))") - t = typeencodings[c] - t == Ptr && (t = Ptr{nexttype(io)}) - return t + c = read(io, Char) + c in skip && return + haskey(typeencodings, c) || error("Unsupported method type: $(String(take!(io)))") + t = typeencodings[c] + t == Ptr && (t = Ptr{nexttype(io)}) + return t end function parseencoding(io::IO) - types = DataType[] - while !eof(io) - t = nexttype(io) - t == nothing || push!(types, t) - end - return types + types = DataType[] + while !eof(io) + t = nexttype(io) + t == nothing || push!(types, t) + end + return types end parseencoding(s::String) = parseencoding(IOBuffer(s)) @@ -70,24 +70,24 @@ parseencoding(s::String) = parseencoding(IOBuffer(s)) signature(m::Ptr) = m |> types |> parseencoding function signature(class::Class, sel::Selector) - m = method(class, sel) - m == C_NULL && error("$class doesn't respond to $sel") - signature(m) + m = method(class, sel) + m == C_NULL && error("$class doesn't respond to $sel") + signature(m) end signature(obj::Object, sel::Selector) = - signature(class(obj), sel) + signature(class(obj), sel) # Creating Methods const revtypeencodings = Dict(v => k for (k, v) in typeencodings) function encodetype(ts...) - buf = IOBuffer() - for t in ts - (t <: Ptr) && (print(buf, "^"); t = eltype(t)) - haskey(revtypeencodings, t) || error("$t isn't a valid ObjectiveC type") - print(buf, revtypeencodings[t]) - end - return String(take!(buf)) + buf = IOBuffer() + for t in ts + (t <: Ptr) && (print(buf, "^"); t = eltype(t)) + haskey(revtypeencodings, t) || error("$t isn't a valid ObjectiveC type") + print(buf, revtypeencodings[t]) + end + return String(take!(buf)) end diff --git a/src/primitives.jl b/src/primitives.jl index 60f5cfe..c64a56e 100644 --- a/src/primitives.jl +++ b/src/primitives.jl @@ -7,36 +7,36 @@ const NO = false # Selectors selname(s::Ptr{Cvoid}) = - ccall(:sel_getName, Ptr{Cchar}, (Ptr{Cvoid},), s) |> unsafe_string + ccall(:sel_getName, Ptr{Cchar}, (Ptr{Cvoid},), s) |> unsafe_string struct Selector - ptr::Ptr{Cvoid} - Selector(ptr::Ptr{Cvoid}) = new(ptr) + ptr::Ptr{Cvoid} + Selector(ptr::Ptr{Cvoid}) = new(ptr) end Base.unsafe_convert(::Type{Ptr{Cvoid}}, sel::Selector) = sel.ptr function Selector(name) - Selector(ccall(:sel_registerName, Ptr{Cvoid}, (Ptr{Cchar},), name)) + Selector(ccall(:sel_registerName, Ptr{Cvoid}, (Ptr{Cchar},), name)) end macro sel_str(name) - Selector(name) + Selector(name) end name(sel::Selector) = selname(sel.ptr) function Base.show(io::IO, sel::Selector) - print(io, "sel") - show(io, string(name(sel))) + print(io, "sel") + show(io, string(name(sel))) end # Classes struct Class - ptr::Ptr{Cvoid} - Class(ptr::Ptr{Cvoid}) = new(ptr) + ptr::Ptr{Cvoid} + Class(ptr::Ptr{Cvoid}) = new(ptr) end Base.unsafe_convert(::Type{Ptr{Cvoid}}, class::Class) = class.ptr @@ -44,47 +44,47 @@ Base.unsafe_convert(::Type{Ptr{Cvoid}}, class::Class) = class.ptr classptr(name) = ccall(:objc_getClass, Ptr{Cvoid}, (Ptr{Cchar},), name) function Class(name) - ptr = classptr(name) - ptr == C_NULL && error("Couldn't find class $name") - return Class(ptr) + ptr = classptr(name) + ptr == C_NULL && error("Couldn't find class $name") + return Class(ptr) end classexists(name) = classptr(name) ≠ C_NULL name(class::Class) = - ccall(:class_getName, Ptr{Cchar}, (Ptr{Cvoid},), - class) |> unsafe_string |> Symbol + ccall(:class_getName, Ptr{Cchar}, (Ptr{Cvoid},), + class) |> unsafe_string |> Symbol ismeta(class::Class) = ccall(:class_isMetaClass, Bool, (Ptr{Cvoid},), class) function Base.supertype(class::Class) - ptr = ccall(:class_getSuperclass, Ptr{Cvoid}, (Ptr{Cvoid},), - class.ptr) - ptr == C_NULL && return nothing - Class(ptr) + ptr = ccall(:class_getSuperclass, Ptr{Cvoid}, (Ptr{Cvoid},), + class.ptr) + ptr == C_NULL && return nothing + Class(ptr) end function Base.show(io::IO, class::Class) - ismeta(class) && print(io, "^") - print(io, name(class)) + ismeta(class) && print(io, "^") + print(io, name(class)) end function Base.methods(class::Class) - count = Cuint[0] - meths = ccall(:class_copyMethodList, Ptr{Ptr{Cvoid}}, (Ptr{Cvoid}, Ptr{Cuint}), - class, count) - meths′ = [unsafe_load(meths, i) for i = 1:count[1]] - Libc.free(meths) - meths = [ccall(:method_getName, Ptr{Cvoid}, (Ptr{Cvoid},), meth) for meth in meths′] - return map(meth->selname(meth), meths) + count = Cuint[0] + meths = ccall(:class_copyMethodList, Ptr{Ptr{Cvoid}}, (Ptr{Cvoid}, Ptr{Cuint}), + class, count) + meths′ = [unsafe_load(meths, i) for i = 1:count[1]] + Libc.free(meths) + meths = [ccall(:method_getName, Ptr{Cvoid}, (Ptr{Cvoid},), meth) for meth in meths′] + return map(meth->selname(meth), meths) end # Protocols struct Protocol - ptr::Ptr{Cvoid} - Protocol(ptr::Ptr{Cvoid}) = new(ptr) + ptr::Ptr{Cvoid} + Protocol(ptr::Ptr{Cvoid}) = new(ptr) end Base.unsafe_convert(::Type{Ptr{Cvoid}}, proto::Protocol) = proto.ptr @@ -92,19 +92,19 @@ Base.unsafe_convert(::Type{Ptr{Cvoid}}, proto::Protocol) = proto.ptr protoptr(name) = ccall(:objc_getProtocol, Ptr{Cvoid}, (Ptr{Cchar},), name) function Protocol(name) - ptr = protoptr(name) - ptr == C_NULL && error("Couldn't find proto $name") - return Protocol(ptr) + ptr = protoptr(name) + ptr == C_NULL && error("Couldn't find proto $name") + return Protocol(ptr) end protoexists(name) = protoptr(name) ≠ C_NULL name(proto::Protocol) = - ccall(:protocol_getName, Ptr{Cchar}, (Ptr{Cvoid},), - proto) |> unsafe_string |> Symbol + ccall(:protocol_getName, Ptr{Cchar}, (Ptr{Cvoid},), + proto) |> unsafe_string |> Symbol function Base.show(io::IO, proto::Protocol) - print(io, name(proto)) + print(io, name(proto)) end @@ -130,11 +130,11 @@ Base.:(==)(x::Ptr, y::id) = throw(ArgumentError("Cannot compare id with Ptr")) # conversion between pointers: refuse to convert between unrelated types function Base.convert(::Type{id{T}}, x::id{U}) where {T,U} - # nil is an exception (we want to be able to use `nil` in `@objc` directly) - x == nil && return Base.bitcast(id{T}, nil) - # otherwise, types must match (i.e., only allow converting to a supertype) - U <: T || throw(ArgumentError("Cannot convert id{$U} to id{$T}")) - Base.bitcast(id{T}, x) + # nil is an exception (we want to be able to use `nil` in `@objc` directly) + x == nil && return Base.bitcast(id{T}, nil) + # otherwise, types must match (i.e., only allow converting to a supertype) + U <: T || throw(ArgumentError("Cannot convert id{$U} to id{$T}")) + Base.bitcast(id{T}, x) end # conversion to integer @@ -166,15 +166,15 @@ const nil = id{Object}(0) Base.reinterpret(::Type{T}, x::id) where {T<:Object} = T(Base.bitcast(id{T}, x)) class(obj::Union{Object,id}) = - ccall(:object_getClass, Ptr{Cvoid}, (id{Object},), obj) |> Class + ccall(:object_getClass, Ptr{Cvoid}, (id{Object},), obj) |> Class Base.methods(obj::Union{Object,id}) = methods(class(obj)) Base.show(io::IO, obj::T) where {T <: Object} = print(io, "$T (object of type ", class(obj), ")") struct UnknownObject <: Object - ptr::id - UnknownObject(ptr::id) = new(ptr) + ptr::id + UnknownObject(ptr::id) = new(ptr) end Base.unsafe_convert(T::Type{<:id}, obj::UnknownObject) = convert(T, obj.ptr) Object(ptr::id) = UnknownObject(ptr) diff --git a/src/syntax.jl b/src/syntax.jl index bff8593..029b7eb 100644 --- a/src/syntax.jl +++ b/src/syntax.jl @@ -8,14 +8,14 @@ callerror(msg) = error("""ObjectiveC call: $msg # convert a vcat to a hcat so that we can split the @objc expressions into multiple lines function flatvcat(ex::Expr) - any(ex->Meta.isexpr(ex, :row), ex.args) || return ex - flat = Expr(:hcat) - for row in ex.args - Meta.isexpr(row, :row) ? - push!(flat.args, row.args...) : - push!(flat.args, row) - end - return flat + any(ex->Meta.isexpr(ex, :row), ex.args) || return ex + flat = Expr(:hcat) + for row in ex.args + Meta.isexpr(row, :row) ? + push!(flat.args, row.args...) : + push!(flat.args, row) + end + return flat end function objcm(mod, ex) @@ -30,7 +30,7 @@ function objcm(mod, ex) # parse the call if Meta.isexpr(call, :vcat) - call = flatvcat(call) + call = flatvcat(call) end Meta.isexpr(call, :hcat) || return esc(call) obj, method, args... = call.args @@ -40,11 +40,11 @@ function objcm(mod, ex) function parse_argument(arg; named=true) # name before the parameter (name:value::type) is optional if Meta.isexpr(arg, :call) && arg.args[1] == :(:) - # form: name:value::typ - name = String(arg.args[2]) - arg = arg.args[3] + # form: name:value::typ + name = String(arg.args[2]) + arg = arg.args[3] else - name = nothing + name = nothing end push!(argnames, name) @@ -108,17 +108,17 @@ end # argument renderers, for tracing functionality render(io, obj) = Core.print(io, repr(obj)) function render(io, ptr::id{T}) where T - Core.print(io, "(id<", String(T.name.name), ">)0x", string(UInt(ptr), base=16, pad = Sys.WORD_SIZE>>2)) + Core.print(io, "(id<", String(T.name.name), ">)0x", string(UInt(ptr), base=16, pad = Sys.WORD_SIZE>>2)) end function render(io, ptr::Ptr{T}) where T - Core.print(io, "(", String(T.name.name), "*)0x", string(UInt(ptr), base=16, pad = Sys.WORD_SIZE>>2)) + Core.print(io, "(", String(T.name.name), "*)0x", string(UInt(ptr), base=16, pad = Sys.WORD_SIZE>>2)) end ## mimic ccall's conversion function render_c_arg(io, obj, typ) - GC.@preserve obj begin - ptr = Base.unsafe_convert(typ, Base.cconvert(typ, obj)) - render(io, ptr) - end + GC.@preserve obj begin + ptr = Base.unsafe_convert(typ, Base.cconvert(typ, obj)) + render(io, ptr) + end end # ensure that the GC can run during a ccall. this is only safe if callbacks @@ -129,41 +129,41 @@ end # # TODO: replace with JuliaLang/julia#49933 once merged function make_gcsafe(ex) - # decode the ccall - if !Meta.isexpr(ex, :call) || ex.args[1] != :ccall - error("Can only make ccall expressions GC-safe") - end - target = ex.args[2] - rettyp = ex.args[3] - argtypes = ex.args[4].args - args = ex.args[5:end] - - code = quote - end - - # assign argument values to variables - vars = [Symbol("arg$i") for i in 1:length(args)] - for (var, arg) in zip(vars, args) - push!(code.args, :($var = $arg)) - end - - # convert the arguments - converted = [Symbol("converted_arg$i") for i in 1:length(args)] - for (converted, argtyp, var) in zip(converted, argtypes, vars) - push!(code.args, :($converted = Base.unsafe_convert($argtyp, Base.cconvert($argtyp, $var)))) - end - - # emit a gcsafe ccall - append!(code.args, (quote - GC.@preserve $(vars...) begin - gc_state = ccall(:jl_gc_safe_enter, Int8, ()) - ret = ccall($target, $rettyp, ($(argtypes...),), $(converted...)) - ccall(:jl_gc_safe_leave, Cvoid, (Int8,), gc_state) - ret + # decode the ccall + if !Meta.isexpr(ex, :call) || ex.args[1] != :ccall + error("Can only make ccall expressions GC-safe") + end + target = ex.args[2] + rettyp = ex.args[3] + argtypes = ex.args[4].args + args = ex.args[5:end] + + code = quote + end + + # assign argument values to variables + vars = [Symbol("arg$i") for i in 1:length(args)] + for (var, arg) in zip(vars, args) + push!(code.args, :($var = $arg)) end - end).args) - return code + # convert the arguments + converted = [Symbol("converted_arg$i") for i in 1:length(args)] + for (converted, argtyp, var) in zip(converted, argtypes, vars) + push!(code.args, :($converted = Base.unsafe_convert($argtyp, Base.cconvert($argtyp, $var)))) + end + + # emit a gcsafe ccall + append!(code.args, (quote + GC.@preserve $(vars...) begin + gc_state = ccall(:jl_gc_safe_enter, Int8, ()) + ret = ccall($target, $rettyp, ($(argtypes...),), $(converted...)) + ccall(:jl_gc_safe_leave, Cvoid, (Int8,), gc_state) + ret + end + end).args) + + return code end function class_message(class_name, msg, rettyp, argtyps, argvals) @@ -198,9 +198,9 @@ function class_message(class_name, msg, rettyp, argtyps, argvals) ) @static if $tracing if $rettyp !== Nothing - Core.print(io, " ") - render(io, ret) - Core.println(io) + Core.print(io, " ") + render(io, ret) + Core.println(io) end end ret @@ -241,9 +241,9 @@ function instance_message(instance, typ, msg, rettyp, argtyps, argvals) ) @static if $tracing if $rettyp !== Nothing - Core.print(io, " ") - render(io, ret) - Core.println(io) + Core.print(io, " ") + render(io, ret) + Core.println(io) end end ret @@ -252,7 +252,7 @@ end # TODO: support availability macro objc(ex) - objcm(__module__, ex) + objcm(__module__, ex) end # Wrapper Classes @@ -284,94 +284,94 @@ keyword arguments: case the default `==` and `hash` methods are sufficient. """ macro objcwrapper(ex...) - def = ex[end] - kwargs = ex[1:end-1] - - # parse kwargs - comparison = nothing - immutable = nothing - availability = nothing - for kw in kwargs - if kw isa Expr && kw.head == :(=) - kw, value = kw.args - if kw == :comparison - value isa Bool || wrappererror("comparison keyword argument must be a literal boolean") - comparison = value - elseif kw == :immutable - value isa Bool || wrappererror("immutable keyword argument must be a literal boolean") - immutable = value - elseif kw == :availability - availability = get_avail_exprs(__module__, value) - else - wrappererror("unrecognized keyword argument: $kw") - end + def = ex[end] + kwargs = ex[1:end-1] + + # parse kwargs + comparison = nothing + immutable = nothing + availability = nothing + for kw in kwargs + if kw isa Expr && kw.head == :(=) + kw, value = kw.args + if kw == :comparison + value isa Bool || wrappererror("comparison keyword argument must be a literal boolean") + comparison = value + elseif kw == :immutable + value isa Bool || wrappererror("immutable keyword argument must be a literal boolean") + immutable = value + elseif kw == :availability + availability = get_avail_exprs(__module__, value) + else + wrappererror("unrecognized keyword argument: $kw") + end + else + wrappererror("invalid keyword argument: $kw") + end + end + immutable = something(immutable, true) + comparison = something(comparison, !immutable) + availability = something(availability, PlatformAvailability[]) + + # parse class definition + if Meta.isexpr(def, :(<:)) + name, super = def.args + elseif def isa Symbol + name = def + super = Object else - wrappererror("invalid keyword argument: $kw") + wrappererror() end - end - immutable = something(immutable, true) - comparison = something(comparison, !immutable) - availability = something(availability, PlatformAvailability[]) - - # parse class definition - if Meta.isexpr(def, :(<:)) - name, super = def.args - elseif def isa Symbol - name = def - super = Object - else - wrappererror() - end - - # generate type hierarchy - ex = quote - abstract type $name <: $super end - end - - # generate the instance class - instance = Symbol(name, "Instance") - ex = if immutable - quote - $(ex.args...) - struct $instance <: $name - ptr::id{$name} - end + + # generate type hierarchy + ex = quote + abstract type $name <: $super end end - else - quote - $(ex.args...) - mutable struct $instance <: $name - ptr::id{$name} - end + + # generate the instance class + instance = Symbol(name, "Instance") + ex = if immutable + quote + $(ex.args...) + struct $instance <: $name + ptr::id{$name} + end + end + else + quote + $(ex.args...) + mutable struct $instance <: $name + ptr::id{$name} + end + end end - end - # add essential methods - ex = quote - $(ex.args...) + # add essential methods + ex = quote + $(ex.args...) - # add a pseudo constructor to the abstract type that also checks for nil pointers. - function $name(ptr::id) - @static if !ObjectiveC.is_available($availability) - throw($UnavailableError(Symbol($name), $availability)) - end + # add a pseudo constructor to the abstract type that also checks for nil pointers. + function $name(ptr::id) + @static if !ObjectiveC.is_available($availability) + throw($UnavailableError(Symbol($name), $availability)) + end - ptr == nil && throw(UndefRefError()) - $instance(ptr) + ptr == nil && throw(UndefRefError()) + $instance(ptr) + end end - end - # add optional methods - if comparison - ex = quote - $(ex.args...) + # add optional methods + if comparison + ex = quote + $(ex.args...) - Base.:(==)(a::$instance, b::$instance) = pointer(a) == pointer(b) - Base.hash(obj::$instance, h::UInt) = hash(pointer(obj), h) + Base.:(==)(a::$instance, b::$instance) = pointer(a) == pointer(b) + Base.hash(obj::$instance, h::UInt) = hash(pointer(obj), h) + end end - end - esc(ex) + esc(ex) end Base.pointer(obj::Object) = obj.ptr @@ -382,13 +382,13 @@ Base.unsafe_convert(T::Type{<:id}, obj::Object) = convert(T, pointer(obj)) # when passing an array of objects, perform recursive conversion to object pointers # this is similar to Base.RefArray, which is used for conversion to regular pointers. struct idArray{T} - ids::Vector{id{T}} - roots::Vector{<:Object} + ids::Vector{id{T}} + roots::Vector{<:Object} end Base.cconvert(T::Type{<:id}, objs::Vector{<:Object}) = - idArray{eltype(T)}([pointer(obj) for obj in objs], objs) + idArray{eltype(T)}([pointer(obj) for obj in objs], objs) Base.unsafe_convert(T::Type{<:id}, arr::idArray) = - reinterpret(T, pointer(arr.ids)) + reinterpret(T, pointer(arr.ids)) # Property Accesors @@ -581,66 +581,66 @@ macro objcproperties(typ, ex) return properties end function Base.propertynames(::$(esc(typ))) - $ObjectiveC.objc_propertynames($(esc(typ))) + $ObjectiveC.objc_propertynames($(esc(typ))) end end # generate `Base.getproperty` definition, if needed getproperties_ex = quote end if !isempty(read_properties) - current = nothing - for (property, body) in read_properties - test = :(field === $(QuoteNode(property))) - if current === nothing - current = Expr(:if, test, body) - getproperties_ex = current - else - new = Expr(:elseif, test, body) - push!(current.args, new) - current = new - end - end - - # finally, call our parent's `getproperty` - final = :(@inline invoke(getproperty, - Tuple{supertype($(esc(typ))), Symbol}, - object, field)) - push!(current.args, final) - getproperties_ex = quote - # XXX: force const-prop on field, without inlining everything? - function Base.getproperty(object::$(esc(typ)), field::Symbol) - $getproperties_ex - end - end + current = nothing + for (property, body) in read_properties + test = :(field === $(QuoteNode(property))) + if current === nothing + current = Expr(:if, test, body) + getproperties_ex = current + else + new = Expr(:elseif, test, body) + push!(current.args, new) + current = new + end + end + + # finally, call our parent's `getproperty` + final = :(@inline invoke(getproperty, + Tuple{supertype($(esc(typ))), Symbol}, + object, field)) + push!(current.args, final) + getproperties_ex = quote + # XXX: force const-prop on field, without inlining everything? + function Base.getproperty(object::$(esc(typ)), field::Symbol) + $getproperties_ex + end + end end # generate `Base.setproperty!` definition, if needed setproperties_ex = quote end if !isempty(write_properties) - current = nothing - for (property, body) in write_properties - test = :(field === $(QuoteNode(property))) - if current === nothing - current = Expr(:if, test, body) - setproperties_ex = current - else - new = Expr(:elseif, test, body) - push!(current.args, new) - current = new - end - end - - # finally, call our parent's `setproperty!` - final = :(@inline invoke(setproperty!, - Tuple{supertype($(esc(typ))), Symbol, Any}, - object, field, value)) - push!(current.args, final) - setproperties_ex = quote - # XXX: force const-prop on field, without inlining everything? - function Base.setproperty!(object::$(esc(typ)), field::Symbol, value::Any) - $setproperties_ex - end - end + current = nothing + for (property, body) in write_properties + test = :(field === $(QuoteNode(property))) + if current === nothing + current = Expr(:if, test, body) + setproperties_ex = current + else + new = Expr(:elseif, test, body) + push!(current.args, new) + current = new + end + end + + # finally, call our parent's `setproperty!` + final = :(@inline invoke(setproperty!, + Tuple{supertype($(esc(typ))), Symbol, Any}, + object, field, value)) + push!(current.args, final) + setproperties_ex = quote + # XXX: force const-prop on field, without inlining everything? + function Base.setproperty!(object::$(esc(typ)), field::Symbol, value::Any) + $setproperties_ex + end + end end return quote