Skip to content

Commit f83a91e

Browse files
committed
Initial arguments
1 parent 57d931b commit f83a91e

File tree

5 files changed

+152
-60
lines changed

5 files changed

+152
-60
lines changed
Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
1+
/*
2+
* Copyright 2017 Tris Foundation and the project authors
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License
6+
*
7+
* See LICENSE.txt in the project root for license information
8+
* See CONTRIBUTORS.txt for the list of the project authors
9+
*/
10+
11+
#if os(Linux)
12+
import CJavaScriptCore
13+
#else
14+
import JavaScriptCore
15+
#endif
16+
17+
public enum ReturnValue {
18+
case undefined
19+
case null
20+
case bool(Bool)
21+
case number(Double)
22+
case string(String)
23+
}
24+
25+
private var functions: [OpaquePointer: ([JSValue]) throws -> ReturnValue] = [:]
26+
27+
extension JSContext {
28+
public func createFunction(
29+
name: String,
30+
_ body: @escaping ([JSValue]) throws -> ReturnValue) throws
31+
{
32+
let function = try createFunction(name: name, callback: wrapper)
33+
functions[function] = body
34+
}
35+
36+
public func createFunction(
37+
name: String,
38+
_ body: @escaping ([JSValue]) throws -> Void) throws
39+
{
40+
let function = try createFunction(name: name, callback: wrapper)
41+
functions[function] = { arguments in
42+
try body(arguments)
43+
return .undefined
44+
}
45+
}
46+
}
47+
48+
extension JSContext {
49+
public func createFunction(
50+
name: String,
51+
_ body: @escaping () throws -> ReturnValue) throws
52+
{
53+
return try createFunction(name: name) { _ in
54+
return try body()
55+
}
56+
}
57+
58+
public func createFunction(
59+
name: String,
60+
_ body: @escaping () throws -> Void) throws
61+
{
62+
try createFunction(name: name) { _ in
63+
try body()
64+
}
65+
}
66+
}
67+
68+
func wrapper(
69+
ctx: JSContextRef!,
70+
function: JSObjectRef!,
71+
thisObject: JSObjectRef!,
72+
argumentCount: Int,
73+
arguments: UnsafePointer<JSValueRef?>?,
74+
exception: UnsafeMutablePointer<JSValueRef?>?) -> JSValueRef?
75+
{
76+
guard let body = functions[function] else {
77+
if let exception = exception {
78+
let error = "swift error: unregistered function"
79+
exception.pointee = JSValue(string: error, in: ctx).pointer
80+
}
81+
return nil
82+
}
83+
do {
84+
let arguments = [JSValue](
85+
start: arguments,
86+
count: argumentCount,
87+
in: ctx)
88+
let result = try body(arguments)
89+
switch result {
90+
case .undefined: return JSValueMakeUndefined(ctx)
91+
case .null: return JSValueMakeNull(ctx)
92+
case .bool(let value): return JSValueMakeBoolean(ctx, value)
93+
case .number(let value): return JSValueMakeNumber(ctx, value)
94+
case .string(let value): return JSValue(string: value, in: ctx).pointer
95+
}
96+
} catch {
97+
if let exception = exception {
98+
exception.pointee = JSValue(string: "\(error)", in: ctx).pointer
99+
}
100+
return nil
101+
}
102+
}

Sources/JavaScript/JSContext.swift

Lines changed: 0 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,6 @@ import CJavaScriptCore
1414
import JavaScriptCore
1515
#endif
1616

17-
import struct Foundation.URL
18-
1917
public class JSContext {
2018
let group: JSContextGroupRef
2119
let context: JSGlobalContextRef
@@ -67,57 +65,3 @@ public class JSContext {
6765
return function!
6866
}
6967
}
70-
71-
// MARK: register swift closure as javascript function
72-
73-
public enum ReturnValue {
74-
case undefined
75-
case null
76-
case bool(Bool)
77-
case number(Double)
78-
case string(String)
79-
}
80-
81-
var functions: [OpaquePointer: [OpaquePointer: () throws -> ReturnValue]] = [:]
82-
83-
extension JSContext {
84-
public func createFunction(
85-
name: String,
86-
_ body: @escaping () throws -> ReturnValue
87-
) throws {
88-
let function = try createFunction(name: name, callback: wrapper)
89-
functions[global, default: [:]][function] = body
90-
}
91-
}
92-
93-
func wrapper(
94-
ctx: JSContextRef!,
95-
function: JSObjectRef!,
96-
thisObject: JSObjectRef!,
97-
argumentCount: Int,
98-
arguments: UnsafePointer<JSValueRef?>?,
99-
exception: UnsafeMutablePointer<JSValueRef?>?
100-
) -> JSValueRef? {
101-
guard let body = functions[thisObject]?[function] else {
102-
if let exception = exception {
103-
let error = "swift error: unregistered function"
104-
exception.pointee = JSValue(string: error, in: thisObject).pointer
105-
}
106-
return nil
107-
}
108-
do {
109-
let result = try body()
110-
switch result {
111-
case .undefined: return JSValueMakeUndefined(ctx)
112-
case .null: return JSValueMakeNull(ctx)
113-
case .bool(let value): return JSValueMakeBoolean(ctx, value)
114-
case .number(let value): return JSValueMakeNumber(ctx, value)
115-
case .string(let value): return JSValue(string: value, in: ctx).pointer
116-
}
117-
} catch {
118-
if let exception = exception {
119-
exception.pointee = JSValue(string: "\(error)", in: ctx).pointer
120-
}
121-
return nil
122-
}
123-
}

Sources/JavaScript/JSValue.swift

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,21 @@ extension JSValue {
113113
}
114114
}
115115

116+
extension Array where Element == JSValue {
117+
init(
118+
start: UnsafePointer<JSValueRef?>?,
119+
count: Int,
120+
in context: JSObjectRef
121+
) {
122+
var arguments = [JSValue]()
123+
for i in 0..<count {
124+
let valueRef = start!.advanced(by: i).pointee!
125+
arguments.append(JSValue(context: context, pointer: valueRef))
126+
}
127+
self = arguments
128+
}
129+
}
130+
116131
extension JSValue: CustomStringConvertible {
117132
public var description: String {
118133
do {

Tests/JavaScriptTests/JavaScriptTests.swift

Lines changed: 33 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -41,14 +41,10 @@ final class JavaScriptCoreTests: TestCase {
4141
do {
4242
let context = JSContext()
4343

44-
45-
var captured = false
4644
try context.createFunction(name: "testUndefined") {
47-
captured = true
4845
return .undefined
4946
}
5047
let undefinedResult = try context.evaluate("testUndefined()")
51-
assertTrue(captured)
5248
assertTrue(undefinedResult.isUndefined)
5349
assertFalse(undefinedResult.isNull)
5450
assertFalse(undefinedResult.isBool)
@@ -105,4 +101,37 @@ final class JavaScriptCoreTests: TestCase {
105101
fail(String(describing: error))
106102
}
107103
}
104+
105+
func testCapture() {
106+
do {
107+
let context = JSContext()
108+
109+
var captured = false
110+
try context.createFunction(name: "testCapture")
111+
{ (_) -> ReturnValue in
112+
captured = true
113+
return .string("captured")
114+
}
115+
let result = try context.evaluate("testCapture()")
116+
assertTrue(captured)
117+
assertEqual("\(result)", "captured")
118+
} catch {
119+
fail(String(describing: error))
120+
}
121+
}
122+
123+
func testArguments() {
124+
do {
125+
let context = JSContext()
126+
127+
var result = [String]()
128+
try context.createFunction(name: "testArguments") { arguments in
129+
result = try arguments.map(String.init)
130+
}
131+
try context.evaluate("testArguments('one', 'two')")
132+
assertEqual(result, ["one", "two"])
133+
} catch {
134+
fail(String(describing: error))
135+
}
136+
}
108137
}

Tests/JavaScriptTests/XCTestManifests.swift

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@ extension JSValueTests {
99

1010
extension JavaScriptCoreTests {
1111
static let __allTests = [
12+
("testArguments", testArguments),
13+
("testCapture", testCapture),
1214
("testClosure", testClosure),
1315
("testEvaluate", testEvaluate),
1416
("testException", testException),

0 commit comments

Comments
 (0)