diff options
| author | Ruben Beltran del Rio <jj@r.bdr.sh> | 2025-12-14 16:16:22 +0100 |
|---|---|---|
| committer | Ruben Beltran del Rio <jj@r.bdr.sh> | 2025-12-14 16:40:52 +0100 |
| commit | 0b90075f76b6f2df77c01c303322323b1395641a (patch) | |
| tree | 4e13d3ce0b1f4792eab8d04caefda2218565f5a9 /Sources/WmapParser/KeywordParser.swift | |
| parent | 088a941a72c2f3e9b3382eb9c5d2f21203dd401c (diff) | |
Use WmapParser namespace
Diffstat (limited to 'Sources/WmapParser/KeywordParser.swift')
| -rw-r--r-- | Sources/WmapParser/KeywordParser.swift | 306 |
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) + } } |