A tab is never indentation, so flow-collection content reached through a
tab below the continuation indent ('- [' / '\tfoo') is malformed even
though the tab inflates the column. A tab at or past the indent is
separation, and a tab-only blank line stays blank, so both remain valid.
Track a tab in a flow continuation's leading whitespace below the
parent + 1 indent and reject content (but not a closing bracket) reached
through it. Surpasses libyaml on Y79Y/003; whole-suite conformance
400/402, canonical events 308/308.
60 lines
2.5 KiB
Swift
60 lines
2.5 KiB
Swift
extension PureYAML.Parsing.LibYAML.Scanner {
|
|
private typealias ScannerError = PureYAML.Parsing.LibYAML.ScannerError
|
|
|
|
/// Reject a flow-collection continuation line that is not indented past the
|
|
/// enclosing block context. YAML requires `s-flow-line-prefix` to be more
|
|
/// indented than the parent block; libyaml does not enforce it, so multi-line
|
|
/// flow content in column 0 (`[a,\nb]` under a key) wrongly parses.
|
|
mutating func checkFlowContinuationIndent() throws {
|
|
guard flowLevel > 0, crossedLineBreak, let next = reader.peek() else {
|
|
return
|
|
}
|
|
// A closing `]`/`}` (or a `,` separator) may sit at any indentation; only
|
|
// flow CONTENT must be indented past the parent block.
|
|
if next == "]" || next == "}" || next == "," {
|
|
return
|
|
}
|
|
// A tab in the leading whitespace is never valid indentation, even where
|
|
// spaces of the same width would be (the tab inflates the column).
|
|
if reader.column <= indentEngine.indent || flowLeadingTab {
|
|
throw ScannerError(
|
|
context: "while parsing a flow node",
|
|
problem: "found insufficiently indented line in a flow collection",
|
|
mark: reader.mark,
|
|
)
|
|
}
|
|
}
|
|
|
|
/// Whether the last emitted token bars a block sequence from opening on the
|
|
/// same line: a mapping value indicator or a node property (anchor/tag). After
|
|
/// another block entry a compact sequence is allowed, so that is not barred.
|
|
func lastTokenForbidsInlineSequence() -> Bool {
|
|
switch indentEngine.tokens.last?.type {
|
|
case .anchor, .tag:
|
|
true
|
|
case .value:
|
|
lastValueWasInline
|
|
default:
|
|
false
|
|
}
|
|
}
|
|
|
|
/// The error raised when a tab is used where indentation is required (before a
|
|
/// block indicator or an implicit mapping key). A tab is valid separation but
|
|
/// never indentation.
|
|
func tabIndentationError() -> PureYAML.Parsing.LibYAML.ScannerError {
|
|
ScannerError(
|
|
context: "while scanning for the next token",
|
|
problem: "found a tab character where an indentation space is expected",
|
|
mark: reader.mark,
|
|
)
|
|
}
|
|
|
|
/// Whether this flow level's pending simple key is a JSON (quoted) node, which
|
|
/// lets an adjacent `:` open its value without a separating space.
|
|
var flowKeyIsJSON: Bool {
|
|
let key = simpleKeys[simpleKeys.count - 1]
|
|
return key.possible && key.isJSON
|
|
}
|
|
}
|