Guest User

Untitled

a guest
Nov 15th, 2018
105
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 3.04 KB | None | 0 0
  1. #!/usr/bin/env swift
  2. // REPL for JavaScriptCore (for arrow keys, use rlwrap command)
  3. import JavaScriptCore
  4.  
  5. class Repl {
  6. private let sem: DispatchSemaphore
  7. private let ctx: JSContext
  8. private let syntaxError: JSValue
  9.  
  10. init() {
  11. self.sem = DispatchSemaphore(value: 0)
  12. guard let ctx = JSContext() else {exit(1)}
  13. guard let syntaxError = ctx.globalObject?.forProperty("SyntaxError") else {exit(1)}
  14. self.ctx = ctx
  15. self.syntaxError = syntaxError
  16.  
  17. // simple console.log()
  18. guard let console = ctx.evaluateScript("console") else {exit(1)}
  19. let log: @convention(block) (JSValue) -> Void = {arg in
  20. if arg.isUndefined {print()} else {print(arg)}
  21. }
  22. console.setValue(log, forProperty: "log")
  23.  
  24. // setTimeout(fn, ms, v) without clearTimeout
  25. let setTimeout: @convention(block) (JSValue, JSValue, JSValue) -> Void = {fn, ms, v in
  26. let n = ms.toNumber().doubleValue / 1000
  27. DispatchQueue.global().asyncAfter(deadline: .now() + n) {
  28. fn.call(withArguments: [v as Any])
  29. }
  30. }
  31. ctx.globalObject.setValue(setTimeout, forProperty: "setTimeout")
  32. }
  33.  
  34. private func repl(_ lines: String, _ prompt: String) {
  35. print(prompt, terminator: "")
  36. if let line = readLine(strippingNewline: false) {
  37. let code = lines + line
  38. if code == "\n" {return asyncRepl(lines, prompt)}
  39. let value = self.ctx.evaluateScript(code)!
  40. if let exp = self.ctx.exception {
  41. self.ctx.exception = nil
  42. let se = exp.isObject && exp.forProperty("constructor").isEqual(to: syntaxError)
  43. let cont = se && exp.forProperty("message").isEqual(to: "Unexpected end of script")
  44. if se && !cont {
  45. // try toplevel await
  46. let asyncF = self.ctx.evaluateScript("async () => \(code)")!
  47. if self.ctx.exception == nil {
  48. callAsyncF(asyncF)
  49. return asyncRepl("", "> ")
  50. }
  51. self.ctx.exception = nil
  52. }
  53. if cont {
  54. return asyncRepl(code, "+ ")
  55. } else {
  56. print(exp)
  57. return asyncRepl("", "> ")
  58. }
  59. } else {
  60. print(value)
  61. return asyncRepl("", "> ")
  62. }
  63. } else {
  64. self.sem.signal()
  65. }
  66. }
  67. private func asyncRepl(_ lines: String, _ prompt: String) {
  68. DispatchQueue.global().async {[weak self] in self?.repl(lines, prompt)}
  69. }
  70. private func callAsyncF(_ asyncF: JSValue) {
  71. let promise = asyncF.call(withArguments: [])!
  72. let out: @convention(block) (JSValue) -> Void = {obj in print(obj)}
  73. let cb = JSValue(object: out, in: self.ctx)
  74. promise.invokeMethod("then", withArguments: [cb as Any, cb as Any])
  75. }
  76.  
  77. func run() {
  78. self.asyncRepl("", "> ")
  79. self.sem.wait()
  80. }
  81. }
  82.  
  83. Repl().run()
Add Comment
Please, Sign In to add comment