-
Notifications
You must be signed in to change notification settings - Fork 47
/
progress.dart
74 lines (65 loc) · 2.08 KB
/
progress.dart
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
import 'package:meta/meta.dart';
import '../core/context.dart';
import '../core/parser.dart';
import '../parser/action/continuation.dart';
import '../reflection/transform.dart';
import '../shared/types.dart';
/// Returns a transformed [Parser] that when being used to read input
/// visually prints its progress while progressing.
///
/// For example, the snippet
///
/// ```dart
/// final parser = letter() & word().star();
/// progress(parser).parse('f123');
/// ```
///
/// prints the following output:
///
/// ```text
/// * SequenceParser
/// * SingleCharacterParser[letter expected]
/// ** PossessiveRepeatingParser[0..*]
/// ** SingleCharacterParser[letter or digit expected]
/// *** SingleCharacterParser[letter or digit expected]
/// **** SingleCharacterParser[letter or digit expected]
/// ***** SingleCharacterParser[letter or digit expected]
/// ```
///
/// Jumps backwards mean that the parser is back-tracking. Often choices can
/// be reordered to avoid such expensive parses.
///
/// The optional [output] callback can be used to continuously receive
/// [ProgressFrame] updates with the current progress information.
@useResult
Parser<R> progress<R>(Parser<R> root,
{VoidCallback<ProgressFrame> output = print,
Predicate<Parser>? predicate}) =>
transformParser(root, <R>(parser) {
if (predicate == null || predicate(parser)) {
return parser.callCC((continuation, context) {
output(_ProgressFrame(parser, context));
return continuation(context);
});
} else {
return parser;
}
});
/// Encapsulates the data around a parser progress.
abstract class ProgressFrame {
/// Return the parser of this frame.
Parser get parser;
/// Returns the activation context of this frame.
Context get context;
/// Returns the current position in the input.
int get position => context.position;
}
class _ProgressFrame extends ProgressFrame {
_ProgressFrame(this.parser, this.context);
@override
final Parser parser;
@override
final Context context;
@override
String toString() => '${'*' * (1 + position)} $parser';
}