mirror of
https://github.com/divkit/divkit.git
synced 2026-06-06 20:07:59 +00:00
290a1febad
Немного причесал API в выражениях и разложил по папкам.
256 lines
5.8 KiB
Swift
256 lines
5.8 KiB
Swift
import Foundation
|
|
|
|
enum MathFunctions: String, CaseIterable {
|
|
case div
|
|
case mod
|
|
case mul
|
|
case sub
|
|
case sum
|
|
case maxInteger
|
|
case minInteger
|
|
case maxNumber
|
|
case minNumber
|
|
case max
|
|
case min
|
|
case abs
|
|
case signum
|
|
case round
|
|
case floor
|
|
case ceil
|
|
case copySign
|
|
|
|
var declaration: [AnyCalcExpression.Symbol: AnyCalcExpression.SymbolEvaluator] {
|
|
[.function(rawValue, arity: function.arity): function.symbolEvaluator]
|
|
}
|
|
|
|
var function: Function {
|
|
switch self {
|
|
case .div:
|
|
return OverloadedFunction(
|
|
functions: [
|
|
FunctionBinary(impl: _divInt),
|
|
FunctionBinary(impl: _divDouble),
|
|
]
|
|
)
|
|
case .mod:
|
|
return OverloadedFunction(
|
|
functions: [
|
|
FunctionBinary(impl: _modInt),
|
|
FunctionBinary(impl: _modDouble),
|
|
]
|
|
)
|
|
case .mul:
|
|
return OverloadedFunction(
|
|
functions: [
|
|
FunctionVarUnary(impl: _mulInt),
|
|
FunctionVarUnary(impl: _mulDouble),
|
|
]
|
|
)
|
|
case .sub:
|
|
return OverloadedFunction(
|
|
functions: [
|
|
FunctionVarUnary(impl: _subInt),
|
|
FunctionVarUnary(impl: _subDouble),
|
|
]
|
|
)
|
|
case .sum:
|
|
return OverloadedFunction(
|
|
functions: [
|
|
FunctionVarUnary(impl: _sumInt),
|
|
FunctionVarUnary(impl: _sumDouble),
|
|
]
|
|
)
|
|
case .maxInteger:
|
|
return FunctionNullary(impl: _maxInteger)
|
|
case .minInteger:
|
|
return FunctionNullary(impl: _minInteger)
|
|
case .maxNumber:
|
|
return FunctionNullary(impl: _maxNumber)
|
|
case .minNumber:
|
|
return FunctionNullary(impl: _minNumber)
|
|
case .max:
|
|
return OverloadedFunction(
|
|
functions: [
|
|
FunctionVarUnary(impl: _maxInt),
|
|
FunctionVarUnary(impl: _maxDouble),
|
|
]
|
|
)
|
|
case .min:
|
|
return OverloadedFunction(
|
|
functions: [
|
|
FunctionVarUnary(impl: _minInt),
|
|
FunctionVarUnary(impl: _minDouble),
|
|
]
|
|
)
|
|
case .abs:
|
|
return OverloadedFunction(
|
|
functions: [
|
|
FunctionUnary(impl: _absInt),
|
|
FunctionUnary(impl: _absDouble),
|
|
]
|
|
)
|
|
case .signum:
|
|
return OverloadedFunction(
|
|
functions: [
|
|
FunctionUnary(impl: _signumInt),
|
|
FunctionUnary(impl: _signumDouble),
|
|
]
|
|
)
|
|
case .round:
|
|
return FunctionUnary(impl: _round)
|
|
case .floor:
|
|
return FunctionUnary(impl: _floor)
|
|
case .ceil:
|
|
return FunctionUnary(impl: _ceil)
|
|
case .copySign:
|
|
return OverloadedFunction(
|
|
functions: [
|
|
FunctionBinary(impl: _copySignInt),
|
|
FunctionBinary(impl: _copySignDouble),
|
|
]
|
|
)
|
|
}
|
|
}
|
|
}
|
|
|
|
private func _divInt(lhs: Int, rhs: Int) throws -> Int {
|
|
guard rhs != 0 else {
|
|
throw Error.divisionByZero("div", lhs, rhs).message
|
|
}
|
|
return lhs / rhs
|
|
}
|
|
|
|
private func _divDouble(lhs: Double, rhs: Double) throws -> Double {
|
|
guard !rhs.isApproximatelyEqualTo(0) else {
|
|
throw Error.divisionByZero("div", lhs, rhs).message
|
|
}
|
|
return lhs / rhs
|
|
}
|
|
|
|
private func _modInt(lhs: Int, rhs: Int) throws -> Int {
|
|
guard rhs != 0 else {
|
|
throw Error.divisionByZero("mod", lhs, rhs).message
|
|
}
|
|
return lhs % rhs
|
|
}
|
|
|
|
private func _modDouble(lhs: Double, rhs: Double) throws -> Double {
|
|
guard !rhs.isApproximatelyEqualTo(0) else {
|
|
throw Error.divisionByZero("mod", lhs, rhs).message
|
|
}
|
|
return fmod(lhs, rhs)
|
|
}
|
|
|
|
private func _mulInt(args: [Int]) throws -> Int {
|
|
args.reduce(1) { $0 * $1 }
|
|
}
|
|
|
|
private func _mulDouble(args: [Double]) throws -> Double {
|
|
args.reduce(1) { $0 * $1 }
|
|
}
|
|
|
|
private func _subInt(args: [Int]) throws -> Int {
|
|
args.dropFirst().reduce(args[0]) { $0 - $1 }
|
|
}
|
|
|
|
private func _subDouble(args: [Double]) throws -> Double {
|
|
args.dropFirst().reduce(args[0]) { $0 - $1 }
|
|
}
|
|
|
|
private func _sumInt(args: [Int]) throws -> Int {
|
|
args.reduce(0) { $0 + $1 }
|
|
}
|
|
|
|
private func _sumDouble(args: [Double]) throws -> Double {
|
|
args.reduce(0) { $0 + $1 }
|
|
}
|
|
|
|
private func _maxInteger() -> Int {
|
|
Int(Int32.max)
|
|
}
|
|
|
|
private func _minInteger() -> Int {
|
|
Int(Int32.min)
|
|
}
|
|
|
|
private func _maxNumber() -> Double {
|
|
Double.greatestFiniteMagnitude
|
|
}
|
|
|
|
private func _minNumber() -> Double {
|
|
Double.leastNonzeroMagnitude
|
|
}
|
|
|
|
private func _maxInt(args: [Int]) -> Int {
|
|
args.reduce(args[0]) { max($0, $1) }
|
|
}
|
|
|
|
private func _maxDouble(args: [Double]) -> Double {
|
|
args.reduce(args[0]) { max($0, $1) }
|
|
}
|
|
|
|
private func _minInt(args: [Int]) -> Int {
|
|
args.reduce(args[0]) { min($0, $1) }
|
|
}
|
|
|
|
private func _minDouble(args: [Double]) -> Double {
|
|
args.reduce(args[0]) { min($0, $1) }
|
|
}
|
|
|
|
private func _absInt(value: Int) -> Int {
|
|
abs(value)
|
|
}
|
|
|
|
private func _absDouble(value: Double) -> Double {
|
|
abs(value)
|
|
}
|
|
|
|
private func _signumInt(value: Int) -> Int {
|
|
value > 0 ? 1 : (value < 0 ? -1 : 0)
|
|
}
|
|
|
|
private func _signumDouble(value: Double) -> Double {
|
|
value.isApproximatelyGreaterThan(0) ? 1 : (value.isApproximatelyLessThan(0) ? -1 : 0)
|
|
}
|
|
|
|
private func _round(value: Double) -> Double {
|
|
round(value)
|
|
}
|
|
|
|
private func _floor(value: Double) -> Double {
|
|
floor(value)
|
|
}
|
|
|
|
private func _ceil(value: Double) -> Double {
|
|
ceil(value)
|
|
}
|
|
|
|
private func _copySignInt(lhs: Int, rhs: Int) -> Int {
|
|
guard rhs != 0 else {
|
|
return lhs
|
|
}
|
|
return Int(copysign(Double(lhs), Double(rhs)))
|
|
}
|
|
|
|
private func _copySignDouble(lhs: Double, rhs: Double) -> Double {
|
|
copysign(lhs, rhs)
|
|
}
|
|
|
|
private enum Error {
|
|
case typeMismatch(args: [Any])
|
|
case divisionByZero(String, Any, Any)
|
|
|
|
private var description: String {
|
|
switch self {
|
|
case let .typeMismatch(args):
|
|
return "Type mismatch \(args.map { "\($0)" }.joined(separator: " "))"
|
|
case let .divisionByZero(function, lhs, rhs):
|
|
return "Failed to evaluate [\(function)(\(lhs), \(rhs))]. Division by zero is not supported."
|
|
}
|
|
}
|
|
|
|
var message: AnyCalcExpression.Error {
|
|
AnyCalcExpression.Error.message(description)
|
|
}
|
|
}
|