mirror of
https://github.com/divkit/divkit.git
synced 2026-06-06 20:07:59 +00:00
119 lines
3.2 KiB
Swift
119 lines
3.2 KiB
Swift
import LayoutKit
|
|
import VGSL
|
|
|
|
@_spi(Internal)
|
|
public final class DivFunctionsStorage {
|
|
private var functions: [CustomFunction.Signature: CustomFunction] = [:]
|
|
private var storages: [UIElementPath: DivFunctionsStorage] = [:]
|
|
|
|
private let reporter: DivReporter
|
|
private let lock = AllocatedUnfairLock()
|
|
|
|
let outerStorage: DivFunctionsStorage?
|
|
|
|
init(
|
|
outerStorage: DivFunctionsStorage? = DivFunctionsStorage(outerStorage: nil),
|
|
reporter: DivReporter = DefaultDivReporter()
|
|
) {
|
|
self.outerStorage = outerStorage
|
|
self.reporter = reporter
|
|
}
|
|
|
|
func set(cardId: DivCardID, functions: [DivFunction]) {
|
|
reset(cardId: cardId)
|
|
setIfNeeded(path: cardId.path, functions: functions)
|
|
}
|
|
|
|
func setIfNeeded(path: UIElementPath, functions: [DivFunction]) {
|
|
lock.withLock {
|
|
if storages[path] != nil {
|
|
return
|
|
}
|
|
|
|
let nearestStorage = getNearestStorage(path)
|
|
if functions.isEmpty {
|
|
storages[path] = nearestStorage
|
|
} else {
|
|
let storage = DivFunctionsStorage(outerStorage: nearestStorage)
|
|
for function in functions {
|
|
let signature = CustomFunction.Signature(
|
|
name: function.name,
|
|
arguments: function.arguments.map(\.type)
|
|
)
|
|
if storage.functions[signature] != nil {
|
|
reporter.asExpressionErrorTracker(cardId: path.cardId)(
|
|
ExpressionError(
|
|
makeErrorMessage(
|
|
name: function.name,
|
|
arguments: function.arguments.map(\.type.rawValue)
|
|
)
|
|
)
|
|
)
|
|
} else {
|
|
storage.functions[signature] = CustomFunction(
|
|
name: function.name,
|
|
arguments: function.arguments.compactMap { arg in
|
|
CustomFunction.Argument(name: arg.name, type: arg.type)
|
|
},
|
|
body: function.body,
|
|
returnType: function.returnType.systemType
|
|
)
|
|
}
|
|
}
|
|
storages[path] = storage
|
|
}
|
|
}
|
|
}
|
|
|
|
func getStorage(
|
|
path: UIElementPath,
|
|
contains name: String
|
|
) -> DivFunctionsStorage? {
|
|
lock.withLock {
|
|
var storage: DivFunctionsStorage? = getNearestStorage(path)
|
|
while storage != nil {
|
|
if storage?.functions.contains(where: { $0.key.name == name }) == true {
|
|
return storage
|
|
}
|
|
storage = storage?.outerStorage
|
|
}
|
|
return nil
|
|
}
|
|
}
|
|
|
|
func getFunctions(with name: String) -> [CustomFunction] {
|
|
functions.values.filter { $0.name == name }
|
|
}
|
|
|
|
func reset() {
|
|
lock.withLock {
|
|
storages.removeAll()
|
|
}
|
|
}
|
|
|
|
func reset(cardId: DivCardID) {
|
|
lock.withLock {
|
|
for path in storages.keys {
|
|
if path.cardId == cardId {
|
|
storages.removeValue(forKey: path)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
func getNearestStorage(_ path: UIElementPath) -> DivFunctionsStorage? {
|
|
var currentPath: UIElementPath? = path
|
|
while let path = currentPath {
|
|
if let storage = storages[path] {
|
|
return storage
|
|
}
|
|
currentPath = path.parent
|
|
}
|
|
return outerStorage
|
|
}
|
|
}
|
|
|
|
private func makeErrorMessage(name: String, arguments: [String]) -> String {
|
|
"Function \(name)(\(arguments.joined(separator: ", "))) declared multiple times."
|
|
}
|