SE-0216: User-defined dynamically callable types

Good idea. +1

Demo
import Foundation
import JavaScriptCore

//@dynamicCallable
@dynamicMemberLookup
public protocol JSDynamicValue: AnyObject {}

extension JSDynamicValue where Self: JSValue {

  @discardableResult
  func call(
    dynamicMember name: String,
    withArguments args: [Any]
  ) -> JSValue {
    if name.isEmpty {
      return call(withArguments: args)
    } else if name == "init" {
      return construct(withArguments: args)
    } else {
      return invokeMethod(name, withArguments: args)
    }
  }

  public subscript(dynamicMember name: String) -> JSValue {
    get {
      return objectForKeyedSubscript(name as NSString)
    }
    set {
      setObject(newValue, forKeyedSubscript: name as NSString)
    }
  }
}

extension JSValue: JSDynamicValue {}

//@dynamicCallable
@dynamicMemberLookup
public protocol JSDynamicContext: AnyObject {}

extension JSDynamicContext where Self: JSContext {

  @discardableResult
  func call(
    dynamicMember name: String,
    withArguments args: [Any]
  ) -> JSValue {
    return globalObject!.call(dynamicMember: name, withArguments: args)
  }

  public subscript(dynamicMember name: String) -> JSValue {
    get {
      return globalObject![dynamicMember: name]
    }
    set {
      globalObject![dynamicMember: name] = newValue
    }
  }
}

extension JSContext: JSDynamicContext {}

let context = JSContext()!

#if false
context.parseInt("0x2A", 16).toInt32()
#else
context.call(dynamicMember: "parseInt", withArguments: ["0x2A", 16]).toInt32()
#endif

#if true
let parseInt = context.parseInt
#else
let parseInt = context[dynamicMember: "parseInt"]
#endif

#if false
parseInt("0x2A", 16).toInt32()
#else
parseInt.call(dynamicMember: "", withArguments: ["0x2A", 16]).toInt32()
#endif