-
Notifications
You must be signed in to change notification settings - Fork 0
/
none_of_tags.dart
97 lines (82 loc) · 2.28 KB
/
none_of_tags.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
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
part of '../../bytes.dart';
/// Parses [tags] and returns success if parsing was unsuccessful.
///
/// Example:
/// ```dart
/// NoneOfTags(['true', 'false'])
/// ```
class NoneOfTags extends ParserBuilder<String, void> {
static const _template = '''
state.ok = true;
if (state.pos < source.length) {
final pos = state.pos;
final c = source.codeUnitAt(pos);
switch (c) {
{{cases}}
}
}''';
static const _templateCase = '''
case {{cc}}:
{{body}}
break;''';
static const _templateTestLong = '''
if (source.startsWith({{tag}}, pos)) {
state.ok = false;
state.fail(pos, ParseError.unexpected, {{tag}}, pos, pos + {{length}});
break;
}''';
static const _templateTestShort = '''
state.ok = false;
state.fail(pos, ParseError.unexpected, {{tag}}, pos, pos + {{length}});''';
final List<String> tags;
const NoneOfTags(this.tags);
@override
String build(Context context, ParserResult? result) {
if (tags.isEmpty) {
throw ArgumentError.value(
tags, 'tags', 'The list of tags must not be empty: $this');
}
context.refersToStateSource = true;
final values = context.allocateLocals(['pos']);
final map = <int, List<String>>{};
for (final tag in tags) {
if (tag.isEmpty) {
throw ArgumentError.value(tags, 'tags',
'The list of tags must not contain empty tags: $tags');
}
final c = tag.codeUnitAt(0);
var list = map[c];
if (list == null) {
list = [];
map[c] = list;
}
list.add(tag);
}
final cases = <String>[];
for (final c in map.keys) {
final tags = map[c]!;
tags.sort((x, y) => y.length.compareTo(x.length));
final tests = <String>[];
for (final tag in tags) {
final values = {
'length': tag.length.toString(),
'tag': helper.escapeString(tag),
};
final template =
tag.length > 1 ? _templateTestLong : _templateTestShort;
final test = render(template, values);
tests.add(test);
}
final values = {
'body': tests.join('\n'),
'cc': c.toString(),
};
final case_ = render(_templateCase, values);
cases.add(case_);
}
values.addAll({
'cases': cases.join('\n'),
});
return render(_template, values, [result]);
}
}