Skip to content

Commit 2f81486

Browse files
committed
Initial commit
0 parents  commit 2f81486

File tree

14 files changed

+625
-0
lines changed

14 files changed

+625
-0
lines changed

.gitignore

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
.DS_Store
2+
/.build
3+
/Packages
4+
/*.xcodeproj

Package.swift

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
// swift-tools-version:4.0
2+
/*
3+
* Copyright 2017 Tris Foundation and the project authors
4+
*
5+
* Licensed under the Apache License, Version 2.0 (the "License");
6+
* you may not use this file except in compliance with the License
7+
*
8+
* See LICENSE.txt in the project root for license information
9+
* See CONTRIBUTORS.txt for the list of the project authors
10+
*/
11+
12+
import PackageDescription
13+
14+
let package = Package(
15+
name: "JavaScript",
16+
products: [
17+
.library(
18+
name: "JavaScriptCore",
19+
targets: ["JavaScriptCore"])
20+
],
21+
dependencies: [
22+
.package(
23+
url: "https://github.com/tris-foundation/test.git",
24+
.branch("master"))
25+
],
26+
targets: [
27+
.target(
28+
name: "CJavaScriptCore",
29+
dependencies: []),
30+
.target(
31+
name: "JavaScriptCore",
32+
dependencies: ["CJavaScriptCore"]),
33+
.testTarget(
34+
name: "JavaScriptCoreTests",
35+
dependencies: ["Test", "JavaScriptCore"])
36+
]
37+
)

README.md

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
# JavaScript
2+
3+
Linux version of JavaScriptCore written in Swift with closure support.
4+
5+
## Requirements
6+
7+
```bash
8+
apt install libjavascriptcoregtk-1.0-dev
9+
```
10+
11+
## Package.swift
12+
13+
```swift
14+
.package(url: "https://github.com/tris-foundation/javascript.git", .branch("master"))
15+
```
16+
17+
## Usage
18+
19+
```swift
20+
let context = JSContext()
21+
try context.evaluate("40 + 2")
22+
23+
try context.createFunction(name: "getResult") {
24+
return .string("result string")
25+
}
26+
let result = try context.evaluate("getResult()")
27+
assertTrue(result.isString)
28+
assertEqual(try result.toString(), "result string")
29+
assertEqual("\(result)", "result string")
30+
```

Sources/CJavaScriptCore/dumb.c

Whitespace-only changes.
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
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+
#ifndef __JAVASCRIPTCORE_H__
12+
#define __JAVASCRIPTCORE_H__
13+
14+
#include <JavaScriptCore/JavaScript.h>
15+
16+
#endif
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
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+
module CJavaScriptCore [system] {
12+
header "include.h"
13+
link "javascriptcoregtk-1.0"
14+
export *
15+
}
Lines changed: 118 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,118 @@
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+
import CJavaScriptCore
12+
import struct Foundation.URL
13+
14+
public class JSContext {
15+
let group: JSContextGroupRef
16+
let context: JSGlobalContextRef
17+
var exception: JSObjectRef? = nil
18+
19+
var global: JSObjectRef {
20+
return JSContextGetGlobalObject(context)!
21+
}
22+
23+
public init() {
24+
guard let group = JSContextGroupCreate(),
25+
let context = JSGlobalContextCreateInGroup(group, nil) else {
26+
fatalError("can't create context")
27+
}
28+
29+
self.group = group
30+
self.context = context
31+
}
32+
33+
deinit {
34+
JSGlobalContextRelease(context)
35+
JSContextGroupRelease(group)
36+
}
37+
38+
@discardableResult
39+
public func evaluate(
40+
_ script: String,
41+
source: String? = nil
42+
) throws -> JSValue {
43+
let file = JSStringCreateWithUTF8CString(source)
44+
let script = JSStringCreateWithUTF8CString(script)
45+
defer {
46+
JSStringRelease(file)
47+
JSStringRelease(script)
48+
}
49+
let result = try JSEvaluateScript(context, script, global, file, 0)
50+
return JSValue(context: context, pointer: result)
51+
}
52+
53+
@discardableResult
54+
public func createFunction(
55+
name: String,
56+
callback: @escaping JSObjectCallAsFunctionCallback
57+
) throws -> JSObjectRef {
58+
let name = JSStringCreateWithUTF8CString(name)
59+
defer { JSStringRelease(name) }
60+
let function = JSObjectMakeFunctionWithCallback(context, name, callback)
61+
try JSObjectSetProperty(context, global, name, function, .none)
62+
return function!
63+
}
64+
}
65+
66+
// MARK: register swift closure as javascript function
67+
68+
public enum ReturnValue {
69+
case undefined
70+
case null
71+
case bool(Bool)
72+
case number(Double)
73+
case string(String)
74+
}
75+
76+
var functions: [OpaquePointer: [OpaquePointer: () throws -> ReturnValue]] = [:]
77+
78+
extension JSContext {
79+
public func createFunction(
80+
name: String,
81+
_ body: @escaping () throws -> ReturnValue
82+
) throws {
83+
let function = try createFunction(name: name, callback: wrapper)
84+
functions[global, default: [:]][function] = body
85+
}
86+
}
87+
88+
func wrapper(
89+
ctx: JSContextRef!,
90+
function: JSObjectRef!,
91+
thisObject: JSObjectRef!,
92+
argumentCount: Int,
93+
arguments: UnsafePointer<JSValueRef?>?,
94+
exception: UnsafeMutablePointer<JSValueRef?>?
95+
) -> JSValueRef? {
96+
guard let body = functions[thisObject]?[function] else {
97+
if let exception = exception {
98+
let error = "swift error: unregistered function"
99+
exception.pointee = JSValue(string: error, in: thisObject).pointer
100+
}
101+
return nil
102+
}
103+
do {
104+
let result = try body()
105+
switch result {
106+
case .undefined: return JSValueMakeUndefined(ctx)
107+
case .null: return JSValueMakeNull(ctx)
108+
case .bool(let value): return JSValueMakeBoolean(ctx, value)
109+
case .number(let value): return JSValueMakeNumber(ctx, value)
110+
case .string(let value): return JSValue(string: value, in: ctx).pointer
111+
}
112+
} catch {
113+
if let exception = exception {
114+
exception.pointee = JSValue(string: "\(error)", in: ctx).pointer
115+
}
116+
return nil
117+
}
118+
}
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
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+
import CJavaScriptCore
12+
13+
public struct JSError: Error, CustomStringConvertible {
14+
public var description: String
15+
16+
init(context: JSContextRef, pointer: JSValueRef) {
17+
let value = JSValue(context: context, pointer: pointer)
18+
do {
19+
self.description = try value.toString()
20+
} catch {
21+
self.description = "\(error)"
22+
}
23+
}
24+
}
Lines changed: 120 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,120 @@
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+
import CJavaScriptCore
12+
13+
public class JSValue {
14+
let context: JSContextRef
15+
let pointer: JSValueRef
16+
17+
init(context: JSContextRef, pointer: JSValueRef) {
18+
self.context = context
19+
self.pointer = pointer
20+
}
21+
22+
init(undefinedIn context: JSContextRef) {
23+
self.context = context
24+
self.pointer = JSValueMakeUndefined(context)
25+
}
26+
27+
init(bool: Bool, in context: JSContextRef) {
28+
self.context = context
29+
self.pointer = JSValueMakeBoolean(context, bool)
30+
}
31+
32+
init(number: Double, in context: JSContextRef) {
33+
self.context = context
34+
self.pointer = JSValueMakeNumber(context, number)
35+
}
36+
37+
init(string: String, in context: JSContextRef) {
38+
self.context = context
39+
let bytes = [UInt16](string.utf16)
40+
let stringRef = JSStringCreateWithCharacters(bytes, bytes.count)
41+
self.pointer = JSValueMakeString(context, stringRef)
42+
}
43+
}
44+
45+
extension JSValue {
46+
convenience
47+
public init(undefinedIn context: JSContext) {
48+
self.init(undefinedIn: context.context)
49+
}
50+
51+
convenience
52+
public init(bool: Bool, in context: JSContext) {
53+
self.init(bool: bool, in: context.context)
54+
}
55+
56+
convenience
57+
public init(number: Double, in context: JSContext) {
58+
self.init(number: number, in: context.context)
59+
}
60+
61+
convenience
62+
public init(string: String, in context: JSContext) {
63+
self.init(string: string, in: context.context)
64+
}
65+
}
66+
67+
extension JSValue {
68+
public var isNull: Bool {
69+
return JSValueIsNull(context, pointer)
70+
}
71+
72+
public var isUndefined: Bool {
73+
return JSValueIsUndefined(context, pointer)
74+
}
75+
76+
public var isBool: Bool {
77+
return JSValueIsBoolean(context, pointer)
78+
}
79+
80+
public var isNumber: Bool {
81+
return JSValueIsNumber(context, pointer)
82+
}
83+
84+
public var isString: Bool {
85+
return JSValueIsString(context, pointer)
86+
}
87+
}
88+
89+
extension JSValue {
90+
public func toBool() -> Bool {
91+
return JSValueToBoolean(context, pointer)
92+
}
93+
94+
public func toDouble() throws -> Double {
95+
return try JSValueToNumber(context, pointer)
96+
}
97+
98+
public func toInt() throws -> Int {
99+
return Int(try JSValueToNumber(context, pointer))
100+
}
101+
102+
public func toString() throws -> String {
103+
let stringRef = try JSValueToStringCopy(context, pointer)
104+
defer { JSStringRelease(stringRef) }
105+
let len = JSStringGetLength(stringRef)
106+
let characters = JSStringGetCharactersPtr(stringRef)
107+
let buffer = UnsafeBufferPointer<UInt16>(start: characters!, count: len)
108+
return String(decoding: buffer, as: UTF16.self)
109+
}
110+
}
111+
112+
extension JSValue: CustomStringConvertible {
113+
public var description: String {
114+
do {
115+
return try toString()
116+
} catch {
117+
return "unknown"
118+
}
119+
}
120+
}

0 commit comments

Comments
 (0)