Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- #!/usr/bin/env swift
- // REPL for JavaScriptCore (for arrow keys, use rlwrap command)
- import JavaScriptCore
- class Repl {
- private let sem: DispatchSemaphore
- private let ctx: JSContext
- private let syntaxError: JSValue
- init() {
- self.sem = DispatchSemaphore(value: 0)
- guard let ctx = JSContext() else {exit(1)}
- guard let syntaxError = ctx.globalObject?.forProperty("SyntaxError") else {exit(1)}
- self.ctx = ctx
- self.syntaxError = syntaxError
- // simple console.log()
- guard let console = ctx.evaluateScript("console") else {exit(1)}
- let log: @convention(block) (JSValue) -> Void = {arg in
- if arg.isUndefined {print()} else {print(arg)}
- }
- console.setValue(log, forProperty: "log")
- // setTimeout(fn, ms, v) without clearTimeout
- let setTimeout: @convention(block) (JSValue, JSValue, JSValue) -> Void = {fn, ms, v in
- let n = ms.toNumber().doubleValue / 1000
- DispatchQueue.global().asyncAfter(deadline: .now() + n) {
- fn.call(withArguments: [v as Any])
- }
- }
- ctx.globalObject.setValue(setTimeout, forProperty: "setTimeout")
- }
- private func repl(_ lines: String, _ prompt: String) {
- print(prompt, terminator: "")
- if let line = readLine(strippingNewline: false) {
- let code = lines + line
- if code == "\n" {return asyncRepl(lines, prompt)}
- let value = self.ctx.evaluateScript(code)!
- if let exp = self.ctx.exception {
- self.ctx.exception = nil
- let se = exp.isObject && exp.forProperty("constructor").isEqual(to: syntaxError)
- let cont = se && exp.forProperty("message").isEqual(to: "Unexpected end of script")
- if se && !cont {
- // try toplevel await
- let asyncF = self.ctx.evaluateScript("async () => \(code)")!
- if self.ctx.exception == nil {
- callAsyncF(asyncF)
- return asyncRepl("", "> ")
- }
- self.ctx.exception = nil
- }
- if cont {
- return asyncRepl(code, "+ ")
- } else {
- print(exp)
- return asyncRepl("", "> ")
- }
- } else {
- print(value)
- return asyncRepl("", "> ")
- }
- } else {
- self.sem.signal()
- }
- }
- private func asyncRepl(_ lines: String, _ prompt: String) {
- DispatchQueue.global().async {[weak self] in self?.repl(lines, prompt)}
- }
- private func callAsyncF(_ asyncF: JSValue) {
- let promise = asyncF.call(withArguments: [])!
- let out: @convention(block) (JSValue) -> Void = {obj in print(obj)}
- let cb = JSValue(object: out, in: self.ctx)
- promise.invokeMethod("then", withArguments: [cb as Any, cb as Any])
- }
- func run() {
- self.asyncRepl("", "> ")
- self.sem.wait()
- }
- }
- Repl().run()
Add Comment
Please, Sign In to add comment