Add structured validation diagnostics, JSON and Yams comparison gates, and lazy token/event parsing so production behavior is measured without retaining full intermediate parser arrays.
108 lines
3.3 KiB
Swift
108 lines
3.3 KiB
Swift
extension PureYAML.Parsing {
|
|
struct Reader {
|
|
private let source: String
|
|
private let utf8: String.UTF8View
|
|
private var position: String.Index
|
|
private var utf8Position: String.UTF8View.Index
|
|
private var line: Int
|
|
private var column: Int
|
|
private var utf8Index: Int
|
|
|
|
init(_ source: String) {
|
|
self.source = source
|
|
utf8 = source.utf8
|
|
position = source.startIndex
|
|
utf8Position = source.utf8.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]
|
|
switch utf8[utf8Position] {
|
|
case 13:
|
|
advanceCarriageReturn()
|
|
line += 1
|
|
column = 1
|
|
case 10:
|
|
advanceASCIICharacter()
|
|
line += 1
|
|
column = 1
|
|
case 0 ..< 128:
|
|
advanceASCIICharacter()
|
|
column += 1
|
|
default:
|
|
advanceExtendedCharacter()
|
|
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
|
|
}
|
|
|
|
private mutating func advanceASCIICharacter() {
|
|
position = source.index(after: position)
|
|
utf8Position = utf8.index(after: utf8Position)
|
|
utf8Index += 1
|
|
}
|
|
|
|
private mutating func advanceCarriageReturn() {
|
|
position = source.index(after: position)
|
|
utf8Position = utf8.index(after: utf8Position)
|
|
utf8Index += 1
|
|
guard utf8Position < utf8.endIndex, utf8[utf8Position] == 10 else {
|
|
return
|
|
}
|
|
utf8Position = utf8.index(after: utf8Position)
|
|
utf8Index += 1
|
|
if position < source.endIndex, source[position] == "\n" {
|
|
position = source.index(after: position)
|
|
}
|
|
}
|
|
|
|
private mutating func advanceExtendedCharacter() {
|
|
position = source.index(after: position)
|
|
guard let nextUTF8Position = position.samePosition(in: utf8) else {
|
|
utf8Index += String(source[source.index(before: position)]).utf8.count
|
|
return
|
|
}
|
|
utf8Index += utf8.distance(from: utf8Position, to: nextUTF8Position)
|
|
utf8Position = nextUTF8Position
|
|
}
|
|
}
|
|
}
|