PureYAML/Sources/Parsing/Reader.swift

76 lines
2.2 KiB
Swift

extension PureYAML.Parsing {
struct Reader {
private let source: String
private var position: String.Index
private var line: Int
private var column: Int
private var utf8Index: Int
init(_ source: String) {
self.source = source
position = source.startIndex
line = 1
column = 1
utf8Index = 0
}
var isAtEnd: Bool {
position >= source.endIndex
}
var mark: Mark {
Mark(line: line, column: column, index: utf8Index)
}
func peek(offset: Int = 0) -> Character? {
var cursor = position
for _ in 0 ..< offset {
guard cursor < source.endIndex else {
return nil
}
cursor = source.index(after: cursor)
}
guard cursor < source.endIndex else {
return nil
}
return source[cursor]
}
@discardableResult
mutating func advance() -> Character? {
guard position < source.endIndex else {
return nil
}
let character = source[position]
position = source.index(after: position)
utf8Index += String(character).utf8.count
if character == "\r\n" {
line += 1
column = 1
} else if character == "\r" {
if position < source.endIndex, source[position] == "\n" {
position = source.index(after: position)
utf8Index += 1
}
line += 1
column = 1
} else if character == "\n" {
line += 1
column = 1
} else {
column += 1
}
return character
}
mutating func consume(while predicate: (Character) -> Bool) -> String {
var output = ""
while let character = peek(), predicate(character) {
output.append(character)
advance()
}
return output
}
}
}