Skip to content

Instantly share code, notes, and snippets.

@nighthawk
Created August 22, 2019 12:31
Show Gist options
  • Save nighthawk/c7daa27285da406e5b2a71f8b789bf3f to your computer and use it in GitHub Desktop.
Save nighthawk/c7daa27285da406e5b2a71f8b789bf3f to your computer and use it in GitHub Desktop.
Highlights a potential performance issue in Eval
import XCTest
import Eval // https://github.com/tevelee/Eval
class MiniExpressionStandardLibraryTest: XCTestCase {
private func evaluate<R>(_ expression: String, inputs: [String: Any] = [:]) -> R? {
let context = Context(variables: inputs)
let interpreter = TypedInterpreter(dataTypes: MiniExpressionStandardLibrary.dataTypes, functions: MiniExpressionStandardLibrary.functions, context: context)
let result = interpreter.evaluate(expression)
return result as? R
}
func testNotPerformance() {
measure {
let result: Bool? = evaluate("nothing == true")
XCTAssertNil(result)
}
}
func testNotPerformance2() {
measure {
let result: Bool? = evaluate("something == true")
XCTAssertNil(result)
}
}
}
class MiniExpressionStandardLibrary {
static var dataTypes: [DataTypeProtocol] {
return [
booleanType,
]
}
static var functions: [FunctionProtocol] {
return [
boolEqualsOperator,
notOperator,
negationOperator,
]
}
// MARK: - Types
static var booleanType: DataType<Bool> {
let trueLiteral = Literal("true", convertsTo: true)
let falseLiteral = Literal("false", convertsTo: false)
return DataType(type: Bool.self, literals: [trueLiteral, falseLiteral]) { $0.value ? "true" : "false" }
}
// MARK: - Functions
static var boolEqualsOperator: Function<Bool> {
return infixOperator("==") { (lhs: Bool, rhs: Bool) in lhs == rhs }
}
static var notOperator: Function<Bool> {
return prefixOperator("not") { (expression: Bool) in !expression }
}
static var negationOperator: Function<Bool> {
return prefixOperator("!") { (expression: Bool) in !expression }
}
// MARK: - Operator helpers
static func infixOperator<A, B, T>(_ symbol: String, body: @escaping (A, B) -> T) -> Function<T> {
return Function([Variable<A>("lhs"), Keyword(symbol), Variable<B>("rhs")], options: .backwardMatch) {
guard let lhs = $0.variables["lhs"] as? A, let rhs = $0.variables["rhs"] as? B else { return nil }
return body(lhs, rhs)
}
}
static func prefixOperator<A, T>(_ symbol: String, body: @escaping (A) -> T) -> Function<T> {
return Function([Keyword(symbol), Variable<A>("value")]) {
guard let value = $0.variables["value"] as? A else { return nil }
return body(value)
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment