mirror of
https://github.com/divkit/divkit.git
synced 2026-06-06 20:07:59 +00:00
89 lines
2.3 KiB
Swift
89 lines
2.3 KiB
Swift
import Foundation
|
|
|
|
final class CustomFunction: SimpleFunction {
|
|
struct Signature: Hashable {
|
|
var name: String
|
|
var arguments: [DivEvaluableType]
|
|
}
|
|
|
|
struct Argument: Hashable {
|
|
let name: String
|
|
let type: DivEvaluableType
|
|
}
|
|
|
|
var signature: FunctionSignature
|
|
|
|
let name: String
|
|
|
|
private let arguments: [Argument]
|
|
private let body: String
|
|
|
|
init(
|
|
name: String,
|
|
arguments: [Argument],
|
|
body: String,
|
|
returnType: Any.Type
|
|
) {
|
|
self.signature = FunctionSignature(
|
|
arguments: arguments.map { ArgumentSignature(type: $0.type.systemType) },
|
|
resultType: returnType
|
|
)
|
|
self.name = name
|
|
self.arguments = arguments
|
|
self.body = body
|
|
}
|
|
|
|
func invoke(_ args: [Any], context: ExpressionContext) throws -> Any {
|
|
let matchedArguments: [String: Any] = Dictionary(
|
|
arguments.map(\.name),
|
|
args
|
|
)
|
|
let resolver = ExpressionResolver(
|
|
functionsProvider: FunctionsProvider(
|
|
persistentValuesStorage: DivPersistentValuesStorage()
|
|
),
|
|
customFunctionsStorageProvider: context.customFunctionsStorageProvider,
|
|
variableValueProvider: { [weak self] name in
|
|
if let argument = matchedArguments[name] {
|
|
return argument
|
|
}
|
|
context.errorTracker(
|
|
ExpressionError(
|
|
"Argument with name: \(name) is not found",
|
|
expression: self?.body
|
|
)
|
|
)
|
|
return nil
|
|
},
|
|
errorTracker: context.errorTracker
|
|
)
|
|
|
|
guard let result = resolver.resolve(body) else {
|
|
throw ExpressionError(
|
|
makeErrorMessage(name: name, arguments: arguments.map(\.type.rawValue), body: body)
|
|
)
|
|
}
|
|
return result
|
|
}
|
|
}
|
|
|
|
private func makeErrorMessage(name: String, arguments: [String], body: String) -> String {
|
|
"Failed to evaluate custom function \(name)() with arguments: [\(arguments.joined(separator: ", "))] and body: \(body)."
|
|
}
|
|
|
|
extension CustomFunction: Hashable {
|
|
static func ==(lhs: CustomFunction, rhs: CustomFunction) -> Bool {
|
|
lhs.name == rhs.name &&
|
|
lhs.body == rhs.body &&
|
|
lhs.arguments == rhs.arguments &&
|
|
lhs.signature == rhs.signature
|
|
}
|
|
|
|
func hash(into hasher: inout Hasher) {
|
|
hasher.combine(name)
|
|
hasher.combine(body)
|
|
hasher.combine(arguments)
|
|
hasher.combine(signature)
|
|
}
|
|
}
|