aboutsummaryrefslogtreecommitdiff
path: root/Sources/WmapParser/KeywordParser.swift
diff options
context:
space:
mode:
authorRuben Beltran del Rio <jj@r.bdr.sh>2025-12-14 16:16:22 +0100
committerRuben Beltran del Rio <jj@r.bdr.sh>2025-12-14 16:40:52 +0100
commit0b90075f76b6f2df77c01c303322323b1395641a (patch)
tree4e13d3ce0b1f4792eab8d04caefda2218565f5a9 /Sources/WmapParser/KeywordParser.swift
parent088a941a72c2f3e9b3382eb9c5d2f21203dd401c (diff)
Use WmapParser namespace
Diffstat (limited to 'Sources/WmapParser/KeywordParser.swift')
-rw-r--r--Sources/WmapParser/KeywordParser.swift306
1 files changed, 154 insertions, 152 deletions
diff --git a/Sources/WmapParser/KeywordParser.swift b/Sources/WmapParser/KeywordParser.swift
index 8db1164..b560d6a 100644
--- a/Sources/WmapParser/KeywordParser.swift
+++ b/Sources/WmapParser/KeywordParser.swift
@@ -1,184 +1,186 @@
-/// Checks which keyword we're dealing with and routes it to the right parser.
-func parseKeywordLine<T: Collection>(
- _ bytes: T, _ start: Int, _ end: Int,
- _ context: inout KeywordParserContext
-) where T.Element == UInt8, T.Index == Int {
- guard let (keyword, rest) = extractKeyword(bytes, start, end) else { return }
+extension WmapParser {
+ /// Checks which keyword we're dealing with and routes it to the right parser.
+ static func parseKeywordLine<T: Collection>(
+ _ bytes: T, _ start: Int, _ end: Int,
+ _ context: inout KeywordParserContext
+ ) where T.Element == UInt8, T.Index == Int {
+ guard let (keyword, rest) = extractKeyword(bytes, start, end) else { return }
- if matchesKeyword(keyword, kInertiaKeyword), let inertia = parseInertia(bytes, rest, end) {
- context.inertias.append(inertia)
- } else if matchesKeyword(keyword, kEvolutionKeyword),
- let evolution = parseEvolution(bytes, rest, end) {
- context.evolutions.append(evolution)
- } else if matchesKeyword(keyword, kNoteKeyword), let note = parseNote(bytes, rest, end) {
- context.notes.append(note)
- } else if matchesKeyword(keyword, kGroupKeyword), let group = parseGroup(bytes, rest, end) {
- context.groups.append(group)
- } else if let stageNumber = isStageKeyword(keyword),
- let stage = parseStage(bytes, stageNumber, rest, end) {
- context.stages.append(stage)
- }
-}
+ if matchesKeyword(keyword, kInertiaKeyword), let inertia = parseInertia(bytes, rest, end) {
+ context.inertias.append(inertia)
+ } else if matchesKeyword(keyword, kEvolutionKeyword),
+ let evolution = parseEvolution(bytes, rest, end) {
+ context.evolutions.append(evolution)
+ } else if matchesKeyword(keyword, kNoteKeyword), let note = parseNote(bytes, rest, end) {
+ context.notes.append(note)
+ } else if matchesKeyword(keyword, kGroupKeyword), let group = parseGroup(bytes, rest, end) {
+ context.groups.append(group)
+ } else if let stageNumber = isStageKeyword(keyword),
+ let stage = parseStage(bytes, stageNumber, rest, end) {
+ context.stages.append(stage)
+ }
+ }
-/// Extracts a keyword from inside brackets. + the index of the rest of the
-/// line.
-@inline(__always)
-func extractKeyword<T: Collection>(_ bytes: T, _ start: Int, _ end: Int) -> (T.SubSequence, Int)?
-where T.Element == UInt8, T.Index == Int {
- var index = start + 1 // Skip '['
- let keywordStart = index
+ /// Extracts a keyword from inside brackets. + the index of the rest of the
+ /// line.
+ @inline(__always)
+ static func extractKeyword<T: Collection>(_ bytes: T, _ start: Int, _ end: Int) -> (T.SubSequence, Int)?
+ where T.Element == UInt8, T.Index == Int {
+ var index = start + 1 // Skip '['
+ let keywordStart = index
- while index < end && bytes[index] != kCloseSquareBracket { index += 1 } // Find ']'
- if index >= end { return nil }
+ while index < end && bytes[index] != kCloseSquareBracket { index += 1 } // Find ']'
+ if index >= end { return nil }
- let keywordEnd = index
- index += 1
+ let keywordEnd = index
+ index += 1
- // Skip whitespace after ']'
- index = skipWhitespace(bytes, end, index)
+ // Skip whitespace after ']'
+ index = skipWhitespace(bytes, end, index)
- return (bytes[keywordStart..<keywordEnd], index)
-}
+ return (bytes[keywordStart..<keywordEnd], index)
+ }
-/// Checks the four potential values for the stage keyword.
-@inline(__always)
-func isStageKeyword<T: Collection>(_ keyword: T) -> StageNumber?
-where T.Element == UInt8, T.Index == Int {
- if matchesKeyword(keyword, kIKeyword) {
- return .stageI
- }
- if matchesKeyword(keyword, kIIKeyword) {
- return .stageII
- }
- if matchesKeyword(keyword, kIIIKeyword) {
- return .stageIII
- }
- if matchesKeyword(keyword, kIVKeyword) {
- return .stageIV
- }
- return nil
-}
+ /// Checks the four potential values for the stage keyword.
+ @inline(__always)
+ static func isStageKeyword<T: Collection>(_ keyword: T) -> StageNumber?
+ where T.Element == UInt8, T.Index == Int {
+ if matchesKeyword(keyword, kIKeyword) {
+ return .stageI
+ }
+ if matchesKeyword(keyword, kIIKeyword) {
+ return .stageII
+ }
+ if matchesKeyword(keyword, kIIIKeyword) {
+ return .stageIII
+ }
+ if matchesKeyword(keyword, kIVKeyword) {
+ return .stageIV
+ }
+ return nil
+ }
-/// Compares a collection of bytes against a list of bytes.
-/// Short-Circuits by length, only two have the same length (ii and iv)
-@inline(__always)
-func matchesKeyword<T: Collection>(_ keyword: T, _ expected: [UInt8]) -> Bool
-where T.Element == UInt8, T.Index == Int {
- guard keyword.count == expected.count else { return false }
- var keywordIndex = keyword.startIndex
- for index in 0..<expected.count {
- let currentKeyword = keyword[keywordIndex]
- let expectedKeyword = expected[index]
+ /// Compares a collection of bytes against a list of bytes.
+ /// Short-Circuits by length, only two have the same length (ii and iv)
+ @inline(__always)
+ static func matchesKeyword<T: Collection>(_ keyword: T, _ expected: [UInt8]) -> Bool
+ where T.Element == UInt8, T.Index == Int {
+ guard keyword.count == expected.count else { return false }
+ var keywordIndex = keyword.startIndex
+ for index in 0..<expected.count {
+ let currentKeyword = keyword[keywordIndex]
+ let expectedKeyword = expected[index]
- let lowercasedKeyword =
- (currentKeyword >= kCapitalA && currentKeyword <= kCapitalZ)
- ? currentKeyword + kCapsToLowercaseDistance : currentKeyword
- if lowercasedKeyword != expectedKeyword { return false }
- keywordIndex += 1
- }
- return true
-}
+ let lowercasedKeyword =
+ (currentKeyword >= kCapitalA && currentKeyword <= kCapitalZ)
+ ? currentKeyword + kCapsToLowercaseDistance : currentKeyword
+ if lowercasedKeyword != expectedKeyword { return false }
+ keywordIndex += 1
+ }
+ return true
+ }
-/// Parses the stage. Assumes we got the stage number in the keyword check
-/// to avoid checking twice.
-func parseStage<T: Collection>(
- _ bytes: T, _ stageNumber: StageNumber, _ start: Int, _ end: Int
-) -> Stage?
-where T.Element == UInt8, T.Index == Int {
- guard let value = parseDouble(bytes, start, end) else { return nil }
+ /// Parses the stage. Assumes we got the stage number in the keyword check
+ /// to avoid checking twice.
+ static func parseStage<T: Collection>(
+ _ bytes: T, _ stageNumber: StageNumber, _ start: Int, _ end: Int
+ ) -> Stage?
+ where T.Element == UInt8, T.Index == Int {
+ guard let value = parseDouble(bytes, start, end) else { return nil }
- return Stage(stage: stageNumber, value: value)
-}
+ return Stage(stage: stageNumber, value: value)
+ }
-/// Parses the note coordinates and text.
-func parseNote<T: Collection>(_ bytes: T, _ start: Int, _ end: Int) -> Note?
-where T.Element == UInt8, T.Index == Int {
- var index = skipWhitespace(bytes, end, start)
+ /// Parses the note coordinates and text.
+ static func parseNote<T: Collection>(_ bytes: T, _ start: Int, _ end: Int) -> Note?
+ where T.Element == UInt8, T.Index == Int {
+ var index = skipWhitespace(bytes, end, start)
- guard index < end && bytes[index] == kOpenParenthesis else { return nil }
- index += 1
+ guard index < end && bytes[index] == kOpenParenthesis else { return nil }
+ index += 1
- guard let (coordinates, endIndex) = parseCoordinates(bytes, index, end) else {
- return nil
- }
- index = skipWhitespace(bytes, end, endIndex)
+ guard let (coordinates, endIndex) = parseCoordinates(bytes, index, end) else {
+ return nil
+ }
+ index = skipWhitespace(bytes, end, endIndex)
- let textEnd = shaveWhitespace(bytes, index, end)
+ let textEnd = shaveWhitespace(bytes, index, end)
- // Why not String(data:encoding:)? This is much faster.
- // swiftlint:disable:next optional_data_string_conversion
- let text = String(decoding: bytes[index..<textEnd], as: UTF8.self)
- return Note(text: text, coordinates: coordinates)
-}
+ // Why not String(data:encoding:)? This is much faster.
+ // swiftlint:disable:next optional_data_string_conversion
+ let text = String(decoding: bytes[index..<textEnd], as: UTF8.self)
+ return Note(text: text, coordinates: coordinates)
+ }
-/// Parses the comma separated labels for a group
-func parseGroup<T: Collection>(_ bytes: T, _ start: Int, _ end: Int) -> Group?
-where T.Element == UInt8, T.Index == Int {
- var components = [String]()
- var index = start
- var componentStart = start
+ /// Parses the comma separated labels for a group
+ static func parseGroup<T: Collection>(_ bytes: T, _ start: Int, _ end: Int) -> Group?
+ where T.Element == UInt8, T.Index == Int {
+ var components = [String]()
+ var index = start
+ var componentStart = start
- while index <= end {
- if index == end || bytes[index] == kComma {
- let trimStart = skipWhitespace(bytes, index, componentStart)
- let trimEnd = shaveWhitespace(bytes, trimStart, index)
+ while index <= end {
+ if index == end || bytes[index] == kComma {
+ let trimStart = skipWhitespace(bytes, index, componentStart)
+ let trimEnd = shaveWhitespace(bytes, trimStart, index)
- if trimStart < trimEnd {
- // Why not String(data:encoding:)? This is much faster.
- // swiftlint:disable:next optional_data_string_conversion
- let component = String(decoding: bytes[trimStart..<trimEnd], as: UTF8.self)
- components.append(component)
- }
+ if trimStart < trimEnd {
+ // Why not String(data:encoding:)? This is much faster.
+ // swiftlint:disable:next optional_data_string_conversion
+ let component = String(decoding: bytes[trimStart..<trimEnd], as: UTF8.self)
+ components.append(component)
+ }
- componentStart = index + 1
- }
- index += 1
- }
+ componentStart = index + 1
+ }
+ index += 1
+ }
- return components.isEmpty ? nil : Group(components: components)
-}
+ return components.isEmpty ? nil : Group(components: components)
+ }
-/// Parses the component label for inertia
-func parseInertia<T: Collection>(_ bytes: T, _ start: Int, _ end: Int) -> Inertia?
-where T.Element == UInt8, T.Index == Int {
- let trimStart = skipWhitespace(bytes, end, start)
- let trimEnd = shaveWhitespace(bytes, trimStart, end)
+ /// Parses the component label for inertia
+ static func parseInertia<T: Collection>(_ bytes: T, _ start: Int, _ end: Int) -> Inertia?
+ where T.Element == UInt8, T.Index == Int {
+ let trimStart = skipWhitespace(bytes, end, start)
+ let trimEnd = shaveWhitespace(bytes, trimStart, end)
- guard trimStart < trimEnd else { return nil }
+ guard trimStart < trimEnd else { return nil }
- // Why not String(data:encoding:)? This is much faster.
- // swiftlint:disable:next optional_data_string_conversion
- let component = String(decoding: bytes[trimStart..<trimEnd], as: UTF8.self)
- return Inertia(component: component)
-}
+ // Why not String(data:encoding:)? This is much faster.
+ // swiftlint:disable:next optional_data_string_conversion
+ let component = String(decoding: bytes[trimStart..<trimEnd], as: UTF8.self)
+ return Inertia(component: component)
+ }
-/// Parses the component label and value for inertia
-func parseEvolution<T: Collection>(_ bytes: T, _ start: Int, _ end: Int) -> Evolution?
-where T.Element == UInt8, T.Index == Int {
- var signIndex: Int?
- var sign = 1.0
+ /// Parses the component label and value for inertia
+ static func parseEvolution<T: Collection>(_ bytes: T, _ start: Int, _ end: Int) -> Evolution?
+ where T.Element == UInt8, T.Index == Int {
+ var signIndex: Int?
+ var sign = 1.0
- var index = start
- while index < end {
- if bytes[index] == kPlus || bytes[index] == kDash {
- signIndex = index
- sign = bytes[index] == 45 ? -1.0 : 1.0
- break
- }
- index += 1
- }
+ var index = start
+ while index < end {
+ if bytes[index] == kPlus || bytes[index] == kDash {
+ signIndex = index
+ sign = bytes[index] == 45 ? -1.0 : 1.0
+ break
+ }
+ index += 1
+ }
- guard let signIndex, signIndex > start else { return nil }
+ guard let signIndex, signIndex > start else { return nil }
- let trimStart = skipWhitespace(bytes, signIndex, start)
- let trimEnd = shaveWhitespace(bytes, trimStart, signIndex)
+ let trimStart = skipWhitespace(bytes, signIndex, start)
+ let trimEnd = shaveWhitespace(bytes, trimStart, signIndex)
- guard trimStart < trimEnd else { return nil }
+ guard trimStart < trimEnd else { return nil }
- // Why not String(data:encoding:)? This is much faster.
- // swiftlint:disable:next optional_data_string_conversion
- let component = String(decoding: bytes[trimStart..<trimEnd], as: UTF8.self)
- guard let value = parseDouble(bytes, signIndex + 1, end) else { return nil }
+ // Why not String(data:encoding:)? This is much faster.
+ // swiftlint:disable:next optional_data_string_conversion
+ let component = String(decoding: bytes[trimStart..<trimEnd], as: UTF8.self)
+ guard let value = parseDouble(bytes, signIndex + 1, end) else { return nil }
- return Evolution(component: component, value: sign * value)
+ return Evolution(component: component, value: sign * value)
+ }
}