Files
divkit/client/ios/DivKit/Expressions/CustomFunctions/CustomFunction.swift
T
denlvovich ecb30a7aea Fixed a bug with resolving custom functions
commit_hash:f8b56a2141dd492d8db216704023bc9e56d6e626
2025-10-08 11:55:50 +03:00

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)
}
}