I suggest using different subscripts for function/method calls and properties:
* `value(...)` ==> `value[dynamicFunction: ""](...)` * `value.name(...)` ==> `value[dynamicFunction: "name"](...)` * `value.name` ==> `value[dynamicProperty: "name"]` Dynamic callable types have an unnamed method. Dynamic argument labels are always allowed (but can be ignored). For example, the labels of `Date.UTC` below are not passed to JavaScript. //===----------------------------------------------------------------------===// // JavaScriptCore.playground //===----------------------------------------------------------------------===// import Foundation import JavaScriptCore typealias Arguments = DictionaryLiteral<String, Any> extension JSContext { subscript(dynamicFunction name: String) -> (_ arguments: Arguments) -> JSValue { return globalObject[dynamicFunction: name] } subscript(dynamicProperty name: String) -> JSValue { get { return globalObject[dynamicProperty: name] } set { globalObject[dynamicProperty: name] = newValue } } } extension JSValue { subscript(dynamicFunction name: String) -> (_ arguments: Arguments) -> JSValue { return { arguments in let argumentValues = arguments.map({ $0.value }) if name.isEmpty { return self.call(withArguments: argumentValues) } else if name == "new" { return self.construct(withArguments: argumentValues) } else { return self.invokeMethod(name, withArguments: argumentValues) } } } subscript(dynamicProperty name: String) -> JSValue { get { return forProperty(name) } set { setValue(newValue, forProperty: name) } } } //===----------------------------------------------------------------------===// // Examples //===----------------------------------------------------------------------===// let context = JSContext()! //: ``` //: context.isNaN(Double.nan) //: ``` context[dynamicFunction: "isNaN"](["": Double.nan]) //: ``` //: context.Math.PI //: ``` context[dynamicProperty: "Math"][dynamicProperty: "PI"] //: ``` //: context.Math.PI.toFixed(5) //: ``` context[dynamicProperty: "Math"][dynamicProperty: "PI"][dynamicFunction: "toFixed"](["": 5]) //: ``` //: context.Math.pow(2, 53) //: ``` context[dynamicProperty: "Math"][dynamicFunction: "pow"](["": 2, "": 53]) //: ``` //: let time = context.Date.UTC( //: year: 9999, month: 11, day: 31, //: hour: 23, minute: 59, second: 59, millisecond: 999) //: ``` let time = context[dynamicProperty: "Date"][dynamicFunction: "UTC"]([ "year": 9999, "month": 11, "day": 31, "hour": 23, "minute": 59, "second": 59, "millisecond": 999]) //: ``` //: let date = context.Date.new(time) //: ``` let date = context[dynamicProperty: "Date"][dynamicFunction: "new"](["": time]) //: ``` //: date.toISOString() //: ``` date[dynamicFunction: "toISOString"]([:]) > On 27 Nov 2017, at 06:04, Chris Lattner wrote: > > I’d like to formally propose the inclusion of user-defined dynamic member > lookup types. > > Here is my latest draft of the proposal: > https://gist.github.com/lattner/b016e1cf86c43732c8d82f90e5ae5438 > https://github.com/apple/swift-evolution/pull/768 > > An implementation of this design is available here: > https://github.com/apple/swift/pull/13076 > > The implementation is straight-forward and (IMO) non-invasive in the compiler. > > -Chris _______________________________________________ swift-evolution mailing list swift-evolution@swift.org https://lists.swift.org/mailman/listinfo/swift-evolution