diff options
| author | Ruben Beltran del Rio <git@r.bdr.sh> | 2025-08-01 15:32:00 +0200 |
|---|---|---|
| committer | Ruben Beltran del Rio <git@r.bdr.sh> | 2025-08-01 15:32:00 +0200 |
| commit | 143f2bbb517c9f25b99d00a16d9850dbdbd09ae1 (patch) | |
| tree | c3b4267286934436a20a95e0ae29297bd1097771 /Map/Business | |
| parent | b1d551ddcf05a9251814418e1b8fcf59afdb33bc (diff) | |
Add state tracking to better handle note text parsing
Diffstat (limited to 'Map/Business')
| -rw-r--r-- | Map/Business/WmapParser/Lexer.swift | 79 |
1 files changed, 73 insertions, 6 deletions
diff --git a/Map/Business/WmapParser/Lexer.swift b/Map/Business/WmapParser/Lexer.swift index 4b5659e..93ba712 100644 --- a/Map/Business/WmapParser/Lexer.swift +++ b/Map/Business/WmapParser/Lexer.swift @@ -14,11 +14,18 @@ // along with this program. If not, see https://map.tranquil.systems. extension Wmap { class Lexer { + private enum LexerState { + case normal + case afterNoteKeyword + case inNotePosition(tokensNeeded: Int) // tracks: leftParen(1), number(2), comma(3), number(4), rightParen(5) + case expectingText + } + let input: String private var current: String.Index private var line = 1 private var column = 1 - private var expectingText = false + private var state: LexerState = .normal init(_ input: String) { self.input = input @@ -37,16 +44,23 @@ extension Wmap { ) } + // Handle text scanning before character-specific parsing + if case .expectingText = state { + state = .normal // Reset after scanning text + return scanText() + } + let char = input[current].lowercased().first! let pos = currentPosition() let tokenStart = current switch char { case "\n", "\r": - expectingText = false // Reset expectingText on newline + state = .normal // Reset state on newline return scanLineEnding() case "(": + updateStateForToken(.leftParen) advance() return Token( type: .leftParen, @@ -56,6 +70,7 @@ extension Wmap { ) case ")": + updateStateForToken(.rightParen) advance() return Token( type: .rightParen, @@ -68,6 +83,7 @@ extension Wmap { return scanBracketedToken() case ",": + updateStateForToken(.comma) advance() return Token( type: .comma, @@ -115,12 +131,14 @@ extension Wmap { } case "0"..."9", ".": - return scanNumber() + let numberToken = scanNumber() + updateStateForToken(.realNumber) + return numberToken default: // If we're expecting text, scan as text instead of vertex label - if expectingText { - expectingText = false // Reset after scanning text + if case .expectingText = state { + state = .normal // Reset after scanning text return scanText() } @@ -130,6 +148,55 @@ extension Wmap { } } + private func updateStateForToken(_ tokenType: TokenType) { + switch state { + case .normal: + // No state changes needed for normal parsing + break + + case .afterNoteKeyword: + if tokenType == .leftParen { + state = .inNotePosition(tokensNeeded: 1) // Expecting: number, comma, number, rightParen + } else { + state = .normal // Invalid sequence, reset + } + + case .inNotePosition(let tokensNeeded): + switch tokensNeeded { + case 1: // Expecting first number + if tokenType == .realNumber { + state = .inNotePosition(tokensNeeded: 2) + } else { + state = .normal + } + case 2: // Expecting comma + if tokenType == .comma { + state = .inNotePosition(tokensNeeded: 3) + } else { + state = .normal + } + case 3: // Expecting second number + if tokenType == .realNumber { + state = .inNotePosition(tokensNeeded: 4) + } else { + state = .normal + } + case 4: // Expecting right paren + if tokenType == .rightParen { + state = .expectingText // Complete position sequence, now expect text + } else { + state = .normal + } + default: + state = .normal + } + + case .expectingText: + // Text has been consumed, reset to normal + state = .normal + } + } + func scanText() -> Token { let pos = currentPosition() @@ -230,7 +297,7 @@ extension Wmap { switch lowercaseContent { case "note": - expectingText = true // Set expectingText when we return a note keyword + state = .afterNoteKeyword // Set state to track note parsing sequence return Token( type: .noteKeyword, value: "[Note]", |