Skip to content

Webidl support #22

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

Closed
wants to merge 3 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
208 changes: 108 additions & 100 deletions Runtime/src/index.ts

Large diffs are not rendered by default.

85 changes: 74 additions & 11 deletions Sources/JavaScriptKit/JSFunction.swift
Original file line number Diff line number Diff line change
Expand Up @@ -2,50 +2,55 @@ import _CJavaScriptKit

@dynamicCallable
public class JSFunctionRef: JSObjectRef {

public override class func canDecode(from jsValue: JSValue) -> Bool {
return jsValue.isFunction
}

@discardableResult
public func dynamicallyCall(withArguments arguments: [JSValueConvertible]) -> JSValue {
public func dynamicallyCall(withArguments arguments: [JSValueEncodable]) -> JSValue {
let result = arguments.withRawJSValues { rawValues -> RawJSValue in
rawValues.withUnsafeBufferPointer { bufferPointer -> RawJSValue in
let argv = bufferPointer.baseAddress
let argc = bufferPointer.count
var result = RawJSValue()
_call_function(
self.id, argv, Int32(argc),
&result.kind, &result.payload1, &result.payload2, &result.payload3
self._id, argv, Int32(argc),
&result
)
return result
}
}
return result.jsValue()
}

public func apply(this: JSObjectRef, arguments: JSValueConvertible...) -> JSValue {
public func apply(this: JSObjectRef, arguments: JSValueEncodable...) -> JSValue {
apply(this: this, argumentList: arguments)
}

public func apply(this: JSObjectRef, argumentList: [JSValueConvertible]) -> JSValue {
public func apply(this: JSObjectRef, argumentList: [JSValueEncodable]) -> JSValue {
let result = argumentList.withRawJSValues { rawValues in
rawValues.withUnsafeBufferPointer { bufferPointer -> RawJSValue in
let argv = bufferPointer.baseAddress
let argc = bufferPointer.count
var result = RawJSValue()
_call_function_with_this(this.id,
self.id, argv, Int32(argc),
&result.kind, &result.payload1, &result.payload2, &result.payload3)
_call_function_with_this(this._id,
self._id, argv, Int32(argc),
&result
)
return result
}
}
return result.jsValue()
}

public func new(_ arguments: JSValueConvertible...) -> JSObjectRef {
public func new(_ arguments: JSValueEncodable...) -> JSObjectRef {
return arguments.withRawJSValues { rawValues in
rawValues.withUnsafeBufferPointer { bufferPointer in
let argv = bufferPointer.baseAddress
let argc = bufferPointer.count
var resultObj = JavaScriptObjectRef()
_call_new(
self.id, argv, Int32(argc),
self._id, argv, Int32(argc),
&resultObj
)
return JSObjectRef(id: resultObj)
Expand All @@ -58,6 +63,15 @@ public class JSFunctionRef: JSObjectRef {
fatalError("unavailable")
}

public convenience required init(jsValue: JSValue) {
switch jsValue {
case .function(let value):
self.init(id: value._id)
default:
fatalError()
}
}

override public func jsValue() -> JSValue {
.function(self)
}
Expand Down Expand Up @@ -113,3 +127,52 @@ public func _call_host_function(
let callbackFuncRef = JSFunctionRef(id: callbackFuncRef)
_ = callbackFuncRef(result)
}


extension JSFunctionRef {

public static func from<A0: JSValueDecodable, RT: JSValueEncodable>(_ body: @escaping (A0) -> RT) -> JSFunctionRef {

return from({ arguments in body(arguments[0].fromJSValue()).jsValue() })
}

public static func from<A0: JSValueDecodable, A1: JSValueDecodable, RT: JSValueEncodable>(_ body: @escaping (A0, A1) -> RT) -> JSFunctionRef {

return from({ arguments in body(arguments[0].fromJSValue(), arguments[1].fromJSValue()).jsValue() })
}

public static func from<A0: JSValueDecodable, A1: JSValueDecodable, A2: JSValueDecodable, RT: JSValueEncodable>(_ body: @escaping (A0, A1, A2) -> RT) -> JSFunctionRef {

return from({ arguments in body(arguments[0].fromJSValue(), arguments[1].fromJSValue(), arguments[2].fromJSValue()).jsValue() })
}

public static func from<A0: JSValueDecodable, A1: JSValueDecodable, A2: JSValueDecodable, A3: JSValueDecodable, RT: JSValueEncodable>(_ body: @escaping (A0, A1, A2, A3) -> RT) -> JSFunctionRef {

return from({ arguments in body(arguments[0].fromJSValue(), arguments[1].fromJSValue(), arguments[2].fromJSValue(), arguments[3].fromJSValue()).jsValue() })
}

public static func from<A0: JSValueDecodable, A1: JSValueDecodable, A2: JSValueDecodable, A3: JSValueDecodable, A4: JSValueDecodable, RT: JSValueEncodable>(_ body: @escaping (A0, A1, A2, A3, A4) -> RT) -> JSFunctionRef {

return from({ arguments in body(arguments[0].fromJSValue(), arguments[1].fromJSValue(), arguments[2].fromJSValue(), arguments[3].fromJSValue(), arguments[4].fromJSValue()).jsValue() })
}

public func wrappedClosure<A0: JSValueEncodable, RT: JSValueDecodable>() -> (A0) -> RT {
return { (arg0) in self.dynamicallyCall(withArguments: [arg0]).fromJSValue() }
}

public func wrappedClosure<A0: JSValueEncodable, A1: JSValueEncodable, RT: JSValueDecodable>() -> (A0, A1) -> RT {
return { (arg0, arg1) in self.dynamicallyCall(withArguments: [arg0, arg1]).fromJSValue() }
}

public func wrappedClosure<A0: JSValueEncodable, A1: JSValueEncodable, A2: JSValueEncodable, RT: JSValueDecodable>() -> (A0, A1, A2) -> RT {
return { (arg0, arg1, arg2) in self.dynamicallyCall(withArguments: [arg0, arg1, arg2]).fromJSValue() }
}

public func wrappedClosure<A0: JSValueEncodable, A1: JSValueEncodable, A2: JSValueEncodable, A3: JSValueEncodable, RT: JSValueDecodable>() -> (A0, A1, A2, A3) -> RT {
return { (arg0, arg1, arg2, arg3) in self.dynamicallyCall(withArguments: [arg0, arg1, arg2, arg3]).fromJSValue() }
}

public func wrappedClosure<A0: JSValueEncodable, A1: JSValueEncodable, A2: JSValueEncodable, A3: JSValueEncodable, A4: JSValueEncodable, RT: JSValueDecodable>() -> (A0, A1, A2, A3, A4) -> RT {
return { (arg0, arg1, arg2, arg3, arg4) in self.dynamicallyCall(withArguments: [arg0, arg1, arg2, arg3, arg4]).fromJSValue() }
}
}
82 changes: 64 additions & 18 deletions Sources/JavaScriptKit/JSObject.swift
Original file line number Diff line number Diff line change
Expand Up @@ -2,55 +2,101 @@ import _CJavaScriptKit

@dynamicMemberLookup
public class JSObjectRef: Equatable {
internal var id: UInt32
init(id: UInt32) {
self.id = id

public class func canDecode(from jsValue: JSValue) -> Bool {
return jsValue.isObject
}

private var functionCache = [String : JSFunctionRef]()
public let _id: UInt32
public init(id: UInt32) {
self._id = id
}

@_disfavoredOverload
public subscript(dynamicMember name: String) -> ((JSValueConvertible...) -> JSValue)? {
guard let function = self[dynamicMember: name].function else { return nil }
return { (arguments: JSValueConvertible...) in
function.apply(this: self, argumentList: arguments)
public subscript(dynamicMember name: String) -> ((JSValueEncodable...) -> JSValue)? {
get {
let function: JSFunctionRef
if let f = functionCache[name] {
function = f
} else if let f = self[dynamicMember: name].function {
functionCache[name] = f
function = f
} else {
return nil
}
return { (arguments: JSValueEncodable...) in
function.apply(this: self, argumentList: arguments)
}
}
}

public subscript(dynamicMember name: String) -> JSValue {
get { get(name) }
set { set(name, newValue) }
get { js_get(name) }
set { js_set(name, newValue) }
}

public subscript<Type: JSValueEncodable & JSValueDecodable>(dynamicMember name: String) -> Type {
get { js_get(name).fromJSValue() }
set { js_set(name, newValue.jsValue()) }
}

public func get(_ name: String) -> JSValue {
func js_get(_ name: String) -> JSValue {
getJSValue(this: self, name: name)
}

public func set(_ name: String, _ value: JSValue) {
func js_set(_ name: String, _ value: JSValue) {
setJSValue(this: self, name: name, value: value)
}

public func get(_ index: Int) -> JSValue {
func js_get(_ index: Int) -> JSValue {
getJSValue(this: self, index: Int32(index))
}

public subscript(_ index: Int) -> JSValue {
get { get(index) }
set { set(index, newValue) }
get { js_get(index) }
set { js_set(index, newValue) }
}

public func set(_ index: Int, _ value: JSValue) {
func js_set(_ index: Int, _ value: JSValue) {
setJSValue(this: self, index: Int32(index), value: value)
}

static let _JS_Predef_Value_Global: UInt32 = 0
public func instanceOf(_ constructor: String) -> Bool {
var result = RawJSValue()
_instance_of(_id, constructor, Int32(constructor.count), &result)

return result.jsValue().fromJSValue()
}

public static let global = JSObjectRef(id: _JS_Predef_Value_Global)

deinit { _destroy_ref(id) }
deinit { _destroy_ref(_id) }

public static func == (lhs: JSObjectRef, rhs: JSObjectRef) -> Bool {
return lhs.id == rhs.id
return lhs._id == rhs._id
}

public convenience required init(jsValue: JSValue) {
switch jsValue {
case .object(let value):
self.init(id: value._id)
default:
fatalError()
}
}

public func jsValue() -> JSValue {
.object(self)
}
}

extension JSObjectRef {

public func copyTypedArrayContent<Type>(_ array: [Type]) {

array.withUnsafeBufferPointer { (ptr) in
_copy_typed_array_content(_id, ptr.baseAddress, Int32(array.count))
}
}
}
89 changes: 76 additions & 13 deletions Sources/JavaScriptKit/JSValue.swift
Original file line number Diff line number Diff line change
Expand Up @@ -41,14 +41,54 @@ public enum JSValue: Equatable {
object.flatMap { JSArrayRef($0) }
}

public var isNull: Bool { return self == .null }
public var isUndefined: Bool { return self == .undefined }
public var function: JSFunctionRef? {
switch self {
case let .function(function): return function
default: return nil
}
}

public var isNull: Bool { return self == .null }
public var isUndefined: Bool { return self == .undefined }

public var isBoolean: Bool {
guard case .boolean = self else { return false }
return true
}

public var isString: Bool {
guard case .string = self else { return false }
return true
}

public var isNumber: Bool {
guard case .number = self else { return false }
return true
}

public var isObject: Bool {
guard case .object = self else { return false }
return true
}

public var isNull: Bool {
return self == .null
}

public var isUndefined: Bool {
return self == .undefined
}

public var isFunction: Bool {
guard case .function = self else { return false }
return true
}
}

extension JSValue {
public func fromJSValue<Type>() -> Type where Type: JSValueDecodable {
return Type(jsValue: self)
}
}

extension JSValue {
Expand All @@ -64,37 +104,60 @@ extension JSValue: ExpressibleByStringLiteral {
}

extension JSValue: ExpressibleByIntegerLiteral {
public init(integerLiteral value: Double) {
public init(integerLiteral value: Int32) {
self = .number(Double(value))
}
}

extension JSValue: ExpressibleByFloatLiteral {
public init(floatLiteral value: Double) {
self = .number(value)
}
}

public func getJSValue(this: JSObjectRef, name: String) -> JSValue {
var rawValue = RawJSValue()
_get_prop(this.id, name, Int32(name.count),
&rawValue.kind,
&rawValue.payload1, &rawValue.payload2, &rawValue.payload3)
_get_prop(this._id, name, Int32(name.count), &rawValue)
return rawValue.jsValue()
}

public func setJSValue(this: JSObjectRef, name: String, value: JSValue) {
value.withRawJSValue { rawValue in
_set_prop(this.id, name, Int32(name.count), rawValue.kind, rawValue.payload1, rawValue.payload2, rawValue.payload3)
_set_prop(this._id, name, Int32(name.count), &rawValue)
}
}

public func getJSValue(this: JSObjectRef, index: Int32) -> JSValue {
var rawValue = RawJSValue()
_get_subscript(this.id, index,
&rawValue.kind,
&rawValue.payload1, &rawValue.payload2, &rawValue.payload3)
_get_subscript(this._id, index, &rawValue)
return rawValue.jsValue()
}

public func setJSValue(this: JSObjectRef, index: Int32, value: JSValue) {
value.withRawJSValue { rawValue in
_set_subscript(this.id, index,
rawValue.kind,
rawValue.payload1, rawValue.payload2, rawValue.payload3)
_set_subscript(this._id, index, &rawValue)
}
}

extension JSValue {

public func instanceOf(_ constructor: String) -> Bool {

switch self {
case .boolean:
return constructor == "Bool"
case .string:
return constructor == "String"
case .number:
fatalError()
case .object(let ref):
return ref.instanceOf(constructor)
case .null:
fatalError()
case .undefined:
fatalError()
case .function(_):
fatalError()
}
}
}
Loading