Utils.swift 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170
  1. //
  2. // Created by jason akakpo on 03/07/16.
  3. // Copyright © 2016 IBAnimatable. All rights reserved.
  4. //
  5. import Foundation
  6. import UIKit
  7. extension Array {
  8. /// Returns the element at the specified index iff it is within bounds, otherwise nil.
  9. subscript(safe index: Int) -> Element? {
  10. return indices.contains(index) ? self[index] : nil /// Returns the element at the specified index iff it is within bounds, otherwise nil.
  11. }
  12. }
  13. extension Array where Element: Udra.Node {
  14. // MARK: String
  15. func toString(_ index: Int) -> String? {
  16. if let node = self[safe: index] as? Udra.VariableNode {
  17. return node.name
  18. }
  19. return nil
  20. }
  21. func contains(_ name: String) -> Bool {
  22. for node in self where node.name == name {
  23. return true
  24. }
  25. return false
  26. }
  27. // MARK: Number
  28. fileprivate func numberNode(at index: Int) -> Udra.NumberNode? {
  29. var node: Udra.Node? = self[safe: index]
  30. if let operatorNode = node as? Udra.BinaryOperatorNode,
  31. let evaluate = operatorNode.evaluate() as? Udra.NumberNode {
  32. node = evaluate
  33. }
  34. return node as? Udra.NumberNode
  35. }
  36. func toDouble(_ index: Int) -> Double? {
  37. if let node = numberNode(at: index) {
  38. return node.value
  39. }
  40. return nil
  41. }
  42. func toDoubles() -> [Double] {
  43. let nodes = self.compactMap { $0 as? Udra.NumberNode }
  44. return nodes.map { Double($0.value) }
  45. }
  46. func toInt(_ index: Int) -> Int? {
  47. if let node = numberNode(at: index) {
  48. return Int(node.value)
  49. }
  50. return nil
  51. }
  52. func toFloat(_ index: Int) -> Float? {
  53. if let node = numberNode(at: index) {
  54. return Float(node.value)
  55. }
  56. return nil
  57. }
  58. func toCGFloat(_ index: Int) -> CGFloat? {
  59. if let node = numberNode(at: index) {
  60. return CGFloat(node.value)
  61. }
  62. return nil
  63. }
  64. func toBool(_ index: Int) -> Bool? {
  65. if let node = self[safe: index] as? Udra.NumberNode {
  66. return node.value != 0
  67. }
  68. if let node = self[safe: index] as? Udra.VariableNode, let value = Bool(node.name) {
  69. return value
  70. }
  71. return nil
  72. }
  73. }
  74. extension RawRepresentable {
  75. init?(raw: RawValue?) {
  76. guard let raw = raw else {
  77. return nil
  78. }
  79. self.init(rawValue: raw)
  80. }
  81. init(raw: RawValue?, defaultValue: Self) {
  82. guard let value = raw else {
  83. self = defaultValue
  84. return
  85. }
  86. self = Self(rawValue: value) ?? defaultValue
  87. }
  88. }
  89. #if swift(>=4.2)
  90. func iterateEnum<T: CaseIterable>(from: T.Type) -> AnyIterator<T> {
  91. return AnyIterator(T.allCases.makeIterator())
  92. }
  93. #else
  94. func iterateEnum<T: Hashable>(from: T.Type) -> AnyIterator<T> {
  95. var x = 0
  96. return AnyIterator {
  97. let next = withUnsafePointer(to: &x) {
  98. $0.withMemoryRebound(to: T.self, capacity: 1) { $0.pointee }
  99. }
  100. defer {
  101. x += 1
  102. }
  103. return next.hashValue == x ? next : nil
  104. }
  105. }
  106. #endif
  107. extension String {
  108. func parseNameAndParams() -> [Udra.Node] {
  109. let parser = Udra.Parser(tokens: Udra.Lexer.tokenize(self.lowercased()))
  110. do {
  111. return try parser.parse()
  112. } catch {
  113. #if DEBUG
  114. print("Failed to parse \"\(self)\", error: \(error)")
  115. #endif
  116. return []
  117. }
  118. }
  119. /**
  120. Helper function that returns a tuple containing the name and params from a string
  121. - Parameter from string: The string to be converted into `enum`.
  122. - Discussion: the string format is like "enumName(param1,param2,param3)"
  123. - Returns: A tuple containing the name and an array of parameter string
  124. */
  125. func extractNameAndParams() -> (String, [Udra.Node])? {
  126. let nodes = self.parseNameAndParams()
  127. guard let firstNode = nodes.first else {
  128. return nil
  129. }
  130. let params: [Udra.Node] = (firstNode as? Udra.CallNode)?.arguments ?? []
  131. return (firstNode.name, params)
  132. }
  133. public func parse<T: IBEnum>() -> T? {
  134. return T(string: self)
  135. }
  136. public func parse<T: IBEnum>(default defaultValue: T) -> T {
  137. return T(string: self) ?? defaultValue
  138. }
  139. }
  140. extension NSRegularExpression {
  141. func matched(_ string: String) -> (String, CountableRange<Int>)? {
  142. let range = self.rangeOfFirstMatch(in: string, options: [], range: NSRange(0 ..< string.utf16.count))
  143. if range.location != NSNotFound {
  144. return ((string as NSString).substring(with: range), range.location ..< range.location + range.length)
  145. }
  146. return nil
  147. }
  148. }