parseLines method
Implementation
List<Node> parseLines({
BlockSyntax? parentSyntax,
bool disabledSetextHeading = false,
}) {
_parentSyntax = parentSyntax;
_setextHeadingDisabled = disabledSetextHeading;
final blocks = <Node>[];
// If the `_pos` does not change before and after `parse()`, never try to
// parse the line at `_pos` with the same syntax again.
// For example the `TableSyntax` might not advance the `_pos` in `parse`
// method, beause of the header row does not match the delimiter row in the
// number of cells, which makes a table like structure not be recognized.
BlockSyntax? neverMatch;
var iterationsWithoutProgress = 0;
while (!isDone) {
final positionBefore = _pos;
for (final syntax in blockSyntaxes) {
if (neverMatch == syntax) {
continue;
}
if (syntax.canParse(this)) {
_previousSyntax = _currentSyntax;
_currentSyntax = syntax;
final block = syntax.parse(this);
if (block != null) {
blocks.add(block);
}
neverMatch = _pos != positionBefore ? null : syntax;
if (block != null ||
syntax is EmptyBlockSyntax ||
syntax is LinkReferenceDefinitionSyntax) {
_start = _pos;
}
break;
}
}
// Count the number of iterations without progress.
// This ensures that we don't have an infinite loop. And if we have an
// infinite loop, it's easier to gracefully recover from an error, than
// it is to discover an kill an isolate that's stuck in an infinite loop.
// Technically, it should be perfectly safe to remove this check
// But as it's possible to inject custom BlockSyntax implementations and
// combine existing ones, it is hard to promise that no combination can't
// trigger an infinite loop
if (positionBefore == _pos) {
iterationsWithoutProgress++;
if (iterationsWithoutProgress > 2) {
// If this happens we throw an error to avoid having the parser
// running in an infinite loop. An error is easier to handle.
// If you see this error in production please file a bug!
throw AssertionError('BlockParser.parseLines is not advancing');
}
} else {
iterationsWithoutProgress = 0;
}
}
return blocks;
}