1// SPDX-FileCopyrightText: 2025 The Project Pterodactyl Developers 2// 3// SPDX-License-Identifier: MPL-2.0 4 5// 6 // SPDX-License-Identifier: MPL-2.0 7 8 import Foundation 9 10public struct Lexer { 11 private let input: String 12 private var index: String.Index 13 private var tokens: [PterodactylSyntax.Token] 14 15 public init(input: String) { 16 self.input = input 17 self.index = input.startIndex 18 self.tokens = [] 19 } 20 21 static let keywords: [String: Keyword] = [ 22 "import": .import 23 ] 24 25 public mutating func nextToken() -> Token { 26 guard !isAtEnd else { 27 return Token(kind: .eof, text: "") 28 } 29 30 let char = currentChar 31 32 if char.isNewline { 33 advance() 34 return Token(kind: .whitespace(.newline), text: String(char)) 35 } 36 37 if char.isWhitespace { 38 let text = readWhile { $0.isWhitespace && !$0.isNewline } 39 return Token(kind: .whitespace(.other), text: text) 40 } 41 42 if char.isLetter { 43 let word = readWhile { $0.isLetter || $0.isNumber || $0 == "_" } 44 let kind: TokenKind = 45 if let keyword = Self.keywords[word] { 46 .keyword(keyword) 47 } else { 48 .identifier 49 } 50 return Token(kind: kind, text: word) 51 } 52 53 advance() 54 return Token(kind: .error, text: String(char)) 55 } 56 57 private mutating func readWhile(_ condition: (Character) -> Bool) -> String { 58 var result = "" 59 while !isAtEnd && condition(currentChar) { 60 result.append(currentChar) 61 advance() 62 } 63 return result 64 } 65 66 private var currentChar: Character { input[index] } 67 68 private var isAtEnd: Bool { 69 index == input.endIndex 70 } 71 72 private mutating func advance() { 73 guard index < input.endIndex else { return } 74 index = input.index(after: index) 75 } 76 }