Skip to content

Commit 29773ec

Browse files
Support Syntax sugar
1 parent b34607b commit 29773ec

File tree

5 files changed

+144
-32
lines changed

5 files changed

+144
-32
lines changed

Diff for: src/swift/Sources/JavaScriptKit/JSFunction.swift

+4-3
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,8 @@ public class JSFunctionRef: Equatable {
1212
return lhs.id == rhs.id
1313
}
1414

15-
public func dynamicallyCall(withArguments arguments: [JSValue]) -> JSValue {
15+
@discardableResult
16+
public func dynamicallyCall(withArguments arguments: [JSValueConvertible]) -> JSValue {
1617
let result = arguments.withRawJSValues { rawValues in
1718
rawValues.withUnsafeBufferPointer { bufferPointer -> RawJSValue in
1819
let argv = bufferPointer.baseAddress
@@ -28,7 +29,7 @@ public class JSFunctionRef: Equatable {
2829
return result.jsValue()
2930
}
3031

31-
public func apply(this: JSObjectRef, arguments: [JSValue]) -> JSValue {
32+
public func apply(this: JSObjectRef, arguments: JSValueConvertible...) -> JSValue {
3233
let result = arguments.withRawJSValues { rawValues in
3334
rawValues.withUnsafeBufferPointer { bufferPointer -> RawJSValue in
3435
let argv = bufferPointer.baseAddress
@@ -44,7 +45,7 @@ public class JSFunctionRef: Equatable {
4445
return result.jsValue()
4546
}
4647

47-
public func new(_ arguments: [JSValue]) -> JSObjectRef {
48+
public func new(_ arguments: JSValueConvertible...) -> JSObjectRef {
4849
return arguments.withRawJSValues { rawValues in
4950
rawValues.withUnsafeBufferPointer { bufferPointer in
5051
let argv = bufferPointer.baseAddress

Diff for: src/swift/Sources/JavaScriptKit/JSObject.swift

+32
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,42 @@
11
import _CJavaScriptKit
22

3+
@dynamicMemberLookup
34
public class JSObjectRef: Equatable {
45
let id: UInt32
56
init(id: UInt32) {
67
self.id = id
78
}
9+
10+
public subscript(dynamicMember name: String) -> JSFunctionRef? {
11+
get { self[dynamicMember: name].function }
12+
}
13+
14+
public subscript(dynamicMember name: String) -> JSValue {
15+
get { get(name) }
16+
set { set(name, newValue) }
17+
}
18+
19+
public func get(_ name: String) -> JSValue {
20+
getJSValue(this: self, name: name)
21+
}
22+
23+
public func set(_ name: String, _ value: JSValue) {
24+
setJSValue(this: self, name: name, value: value)
25+
}
26+
27+
public func get(_ index: Int) -> JSValue {
28+
getJSValue(this: self, index: Int32(index))
29+
}
30+
31+
public subscript(_ index: Int) -> JSValue {
32+
get { get(index) }
33+
set { set(index, newValue) }
34+
}
35+
36+
public func set(_ index: Int, _ value: JSValue) {
37+
setJSValue(this: self, index: Int32(index), value: value)
38+
}
39+
840
public static func global() -> JSObjectRef {
941
.init(id: _JS_Predef_Value_Global)
1042
}

Diff for: src/swift/Sources/JavaScriptKit/JSValue.swift

+34
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,40 @@ public enum JSValue: Equatable {
88
case null
99
case undefined
1010
case function(JSFunctionRef)
11+
12+
var boolean: Bool? {
13+
switch self {
14+
case let .boolean(boolean): return boolean
15+
default: return nil
16+
}
17+
}
18+
19+
var string: String? {
20+
switch self {
21+
case let .string(string): return string
22+
default: return nil
23+
}
24+
}
25+
var number: Int32? {
26+
switch self {
27+
case let .number(number): return number
28+
default: return nil
29+
}
30+
}
31+
var object: JSObjectRef? {
32+
switch self {
33+
case let .object(object): return object
34+
default: return nil
35+
}
36+
}
37+
var isNull: Bool { return self == .null }
38+
var isUndefined: Bool { return self == .undefined }
39+
var function: JSFunctionRef? {
40+
switch self {
41+
case let .function(function): return function
42+
default: return nil
43+
}
44+
}
1145
}
1246

1347
public func getJSValue(this: JSObjectRef, name: String) -> JSValue {

Diff for: src/swift/Sources/JavaScriptKit/JSValueConvertible.swift

+61-16
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,51 @@
11
import _CJavaScriptKit
22

3-
protocol JSValueConvertible {
3+
public protocol JSValueConvertible {
44
func jsValue() -> JSValue
55
}
66

7+
extension JSValue: JSValueConvertible {
8+
public func jsValue() -> JSValue { self }
9+
}
10+
711
extension Bool: JSValueConvertible {
8-
func jsValue() -> JSValue {
9-
.boolean(self)
12+
public func jsValue() -> JSValue { .boolean(self) }
13+
}
14+
15+
extension Int: JSValueConvertible {
16+
public func jsValue() -> JSValue { .number(Int32(self)) }
17+
}
18+
19+
extension String: JSValueConvertible {
20+
public func jsValue() -> JSValue { .string(self) }
21+
}
22+
23+
private let Object = JSObjectRef.global().Object.function!
24+
25+
extension Dictionary: JSValueConvertible where Value: JSValueConvertible, Key == String {
26+
public func jsValue() -> JSValue {
27+
let object = Object.new()
28+
for (key, value) in self {
29+
object.set(key, value.jsValue())
30+
}
31+
return .object(object)
32+
}
33+
}
34+
35+
private let Array = JSObjectRef.global().Array.function!
36+
37+
extension Array: JSValueConvertible where Element: JSValueConvertible {
38+
public func jsValue() -> JSValue {
39+
let array = Array.new(count)
40+
for element in self {
41+
array.push!(element)
42+
}
43+
return .object(array)
1044
}
1145
}
1246

1347
extension RawJSValue: JSValueConvertible {
14-
func jsValue() -> JSValue {
48+
public func jsValue() -> JSValue {
1549
switch kind {
1650
case JavaScriptValueKind_Invalid:
1751
fatalError()
@@ -84,18 +118,29 @@ extension JSValue {
84118
}
85119
}
86120

87-
extension Array where Element == JSValue {
88-
func withRawJSValues<T>(_ body: ([RawJSValue]) -> T) -> T {
89-
func _withCollectedRawJSValue<T>(
90-
_ values: [JSValue], _ index: Int,
91-
_ results: inout [RawJSValue], _ body: ([RawJSValue]) -> T) -> T {
92-
if index == values.count { return body(results) }
93-
return values[index].withRawJSValue { (rawValue) -> T in
94-
results.append(rawValue)
95-
return _withCollectedRawJSValue(values, index + 1, &results, body)
96-
}
121+
122+
private func withRawJSValues<T>(_ this: [JSValueConvertible], _ body: ([RawJSValue]) -> T) -> T {
123+
func _withRawJSValues<T>(
124+
_ values: [JSValueConvertible], _ index: Int,
125+
_ results: inout [RawJSValue], _ body: ([RawJSValue]) -> T) -> T {
126+
if index == values.count { return body(results) }
127+
return values[index].jsValue().withRawJSValue { (rawValue) -> T in
128+
results.append(rawValue)
129+
return _withRawJSValues(values, index + 1, &results, body)
97130
}
98-
var _results = [RawJSValue]()
99-
return _withCollectedRawJSValue(self, 0, &_results, body)
131+
}
132+
var _results = [RawJSValue]()
133+
return _withRawJSValues(this, 0, &_results, body)
134+
}
135+
136+
extension Array where Element == JSValueConvertible {
137+
func withRawJSValues<T>(_ body: ([RawJSValue]) -> T) -> T {
138+
JavaScriptKit.withRawJSValues(self, body)
139+
}
140+
}
141+
142+
extension Array where Element: JSValueConvertible {
143+
func withRawJSValues<T>(_ body: ([RawJSValue]) -> T) -> T {
144+
JavaScriptKit.withRawJSValues(self, body)
100145
}
101146
}

Diff for: test/JavaScriptKitExec/Sources/JavaScriptKitExec/main.swift

+13-13
Original file line numberDiff line numberDiff line change
@@ -98,16 +98,16 @@ Function_Call: do {
9898
let func2 = try expectFunction(getJSValue(this: prop_5Ref, name: "func2"))
9999
try expectEqual(func2(), .number(1))
100100
let func3 = try expectFunction(getJSValue(this: prop_5Ref, name: "func3"))
101-
try expectEqual(func3(.number(2)), .number(4))
101+
try expectEqual(func3(2), .number(4))
102102
let func4 = try expectFunction(getJSValue(this: prop_5Ref, name: "func4"))
103-
try expectEqual(func4(.number(2), .number(3), .number(4)), .number(9))
104-
try expectEqual(func4(.number(2), .number(3), .number(4), .number(5)), .number(9))
103+
try expectEqual(func4(2, 3, 4), .number(9))
104+
try expectEqual(func4(2, 3, 4, 5), .number(9))
105105
let func5 = try expectFunction(getJSValue(this: prop_5Ref, name: "func5"))
106-
try expectEqual(func5(.string("World!")), .string("Hello, World!"))
106+
try expectEqual(func5("World!"), .string("Hello, World!"))
107107
let func6 = try expectFunction(getJSValue(this: prop_5Ref, name: "func6"))
108-
try expectEqual(func6(.boolean(true), .number(1), .number(2)), .number(1))
109-
try expectEqual(func6(.boolean(false), .number(1), .number(2)), .number(2))
110-
try expectEqual(func6(.boolean(true), .string("OK"), .number(2)), .string("OK"))
108+
try expectEqual(func6(true, 1, 2), .number(1))
109+
try expectEqual(func6(false, 1, 2), .number(2))
110+
try expectEqual(func6(true, "OK", 2), .string("OK"))
111111

112112
} catch {
113113
print(error)
@@ -152,8 +152,8 @@ Host_Function_Registration: do {
152152
}
153153
}
154154

155-
try expectEqual(hostFunc2(.number(3)), .number(6))
156-
_ = try expectString(hostFunc2(.boolean(true)))
155+
try expectEqual(hostFunc2(3), .number(6))
156+
_ = try expectString(hostFunc2(true))
157157
} catch {
158158
print(error)
159159
}
@@ -170,13 +170,13 @@ New_Object_Construction: do {
170170
// }
171171
// ```
172172
let objectConstructor = try expectFunction(getJSValue(this: .global(), name: "Animal"))
173-
let cat1 = objectConstructor.new([.string("Tama"), .number(3), .boolean(true)])
173+
let cat1 = objectConstructor.new("Tama", 3, true)
174174
try expectEqual(getJSValue(this: cat1, name: "name"), .string("Tama"))
175175
try expectEqual(getJSValue(this: cat1, name: "age"), .number(3))
176176
let cat1Bark = try expectFunction(getJSValue(this: cat1, name: "bark"))
177177
try expectEqual(cat1Bark(), .string("nyan"))
178178

179-
let dog1 = objectConstructor.new([.string("Pochi"), .number(3), .boolean(false)])
179+
let dog1 = objectConstructor.new("Pochi", 3, false)
180180
let dog1Bark = try expectFunction(getJSValue(this: dog1, name: "bark"))
181181
try expectEqual(dog1Bark(), .string("wan"))
182182
} catch {
@@ -199,14 +199,14 @@ Call_Function_With_This: do {
199199
// }
200200
// ```
201201
let objectConstructor = try expectFunction(getJSValue(this: .global(), name: "Animal"))
202-
let cat1 = objectConstructor.new([.string("Tama"), .number(3), .boolean(true)])
202+
let cat1 = objectConstructor.new("Tama", 3, true)
203203
let getIsCat = try expectFunction(getJSValue(this: cat1, name: "getIsCat"))
204204

205205
// Direct call without this
206206
try expectEqual(getIsCat(), .undefined)
207207

208208
// Call with this
209-
let gotIsCat = getIsCat.apply(this: cat1, arguments: [])
209+
let gotIsCat = getIsCat.apply(this: cat1)
210210
try expectEqual(gotIsCat, .boolean(true))
211211

212212
} catch {

0 commit comments

Comments
 (0)