trace<T> function Null safety

Parser<T> trace<T>(
  1. Parser<T> root,
  2. {VoidCallback<TraceEvent> output = print,
  3. Predicate<Parser>? predicate}
)

Returns a transformed Parser that when being used to read input prints a trace of all activated parsers and their respective parse results.

For example, the snippet

final parser = letter() & word().star();
trace(parser).parse('f1');

produces the following output:

Instance of 'SequenceParser'
  Instance of 'CharacterParser'[letter expected]
  Success[1:2]: f
  Instance of 'PossessiveRepeatingParser'[0..*]
    Instance of 'CharacterParser'[letter or digit expected]
    Success[1:3]: 1
    Instance of 'CharacterParser'[letter or digit expected]
    Failure[1:3]: letter or digit expected
  Success[1:3]: [1]
Success[1:3]: [f, [1]]

Indentation signifies the activation of a parser object. Reverse indentation signifies the returning of a parse result either with a success or failure context.

The optional output callback can be used to continuously receive TraceEvent objects with current enter and exit data.

Implementation

Parser<T> trace<T>(Parser<T> root,
    {VoidCallback<TraceEvent> output = print, Predicate<Parser>? predicate}) {
  TraceEvent? parent;
  return transformParser(root, <T>(parser) {
    if (predicate == null || predicate(parser)) {
      return parser.callCC((continuation, context) {
        final currentParent = parent;
        output(parent = _TraceEvent(currentParent, parser, context));
        final result = continuation(context);
        output(_TraceEvent(currentParent, parser, context, result));
        parent = currentParent;
        return result;
      });
    } else {
      return parser;
    }
  });
}