@cparra/apex-reflection 0.1.0-alpha.0 → 0.1.1-alpha.10
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/__tests__/end-to-end.test.ts +256 -0
- package/coverage/clover.xml +12857 -0
- package/coverage/coverage-final.json +3 -0
- package/coverage/lcov-report/base.css +224 -0
- package/coverage/lcov-report/block-navigation.js +79 -0
- package/coverage/lcov-report/favicon.png +0 -0
- package/coverage/lcov-report/index.html +126 -0
- package/coverage/lcov-report/index.js.html +104 -0
- package/coverage/lcov-report/out.js.html +41126 -0
- package/coverage/lcov-report/prettify.css +1 -0
- package/coverage/lcov-report/prettify.js +2 -0
- package/coverage/lcov-report/sort-arrow-sprite.png +0 -0
- package/coverage/lcov-report/sorter.js +170 -0
- package/coverage/lcov.info +24801 -0
- package/index.d.ts +118 -0
- package/index.js +8 -0
- package/index.ts +141 -0
- package/jest.config.js +11 -0
- package/out.js +13708 -0
- package/package.json +22 -17
- package/tsconfig.json +5 -3
- package/.idea/apexdocs-dart.iml +0 -18
- package/.idea/jsLibraryMappings.xml +0 -6
- package/.idea/libraries/Dart_Packages.xml +0 -556
- package/.idea/libraries/Dart_SDK.xml +0 -28
- package/.idea/misc.xml +0 -6
- package/.idea/modules.xml +0 -8
- package/.idea/runConfigurations/_template__of_Dart_Test.xml +0 -6
- package/.idea/vcs.xml +0 -6
- package/CHANGELOG.md +0 -3
- package/README.md +0 -26
- package/TODO.md +0 -5
- package/analysis_options.yaml +0 -30
- package/antlr4-4.9.2/CHANGELOG.md +0 -4
- package/antlr4-4.9.2/LICENSE +0 -52
- package/antlr4-4.9.2/README.md +0 -11
- package/antlr4-4.9.2/analysis_options.yaml +0 -1
- package/antlr4-4.9.2/lib/antlr4.dart +0 -21
- package/antlr4-4.9.2/lib/src/atn/atn.dart +0 -18
- package/antlr4-4.9.2/lib/src/atn/src/atn.dart +0 -170
- package/antlr4-4.9.2/lib/src/atn/src/atn_config.dart +0 -242
- package/antlr4-4.9.2/lib/src/atn/src/atn_config_set.dart +0 -283
- package/antlr4-4.9.2/lib/src/atn/src/atn_deserializer.dart +0 -809
- package/antlr4-4.9.2/lib/src/atn/src/atn_simulator.dart +0 -95
- package/antlr4-4.9.2/lib/src/atn/src/atn_state.dart +0 -296
- package/antlr4-4.9.2/lib/src/atn/src/atn_type.dart +0 -14
- package/antlr4-4.9.2/lib/src/atn/src/info.dart +0 -553
- package/antlr4-4.9.2/lib/src/atn/src/lexer_action.dart +0 -601
- package/antlr4-4.9.2/lib/src/atn/src/lexer_action_executor.dart +0 -167
- package/antlr4-4.9.2/lib/src/atn/src/lexer_atn_simulator.dart +0 -731
- package/antlr4-4.9.2/lib/src/atn/src/parser_atn_simulator.dart +0 -2630
- package/antlr4-4.9.2/lib/src/atn/src/profiling_atn_simulator.dart +0 -229
- package/antlr4-4.9.2/lib/src/atn/src/semantic_context.dart +0 -404
- package/antlr4-4.9.2/lib/src/atn/src/transition.dart +0 -305
- package/antlr4-4.9.2/lib/src/dfa/dfa.dart +0 -8
- package/antlr4-4.9.2/lib/src/dfa/src/dfa.dart +0 -138
- package/antlr4-4.9.2/lib/src/dfa/src/dfa_serializer.dart +0 -76
- package/antlr4-4.9.2/lib/src/dfa/src/dfa_state.dart +0 -151
- package/antlr4-4.9.2/lib/src/error/error.dart +0 -10
- package/antlr4-4.9.2/lib/src/error/src/diagnostic_error_listener.dart +0 -116
- package/antlr4-4.9.2/lib/src/error/src/error_listener.dart +0 -241
- package/antlr4-4.9.2/lib/src/error/src/error_strategy.dart +0 -902
- package/antlr4-4.9.2/lib/src/error/src/errors.dart +0 -204
- package/antlr4-4.9.2/lib/src/input_stream.dart +0 -335
- package/antlr4-4.9.2/lib/src/interval_set.dart +0 -735
- package/antlr4-4.9.2/lib/src/lexer.dart +0 -343
- package/antlr4-4.9.2/lib/src/ll1_analyzer.dart +0 -204
- package/antlr4-4.9.2/lib/src/misc/multi_map.dart +0 -32
- package/antlr4-4.9.2/lib/src/misc/pair.dart +0 -34
- package/antlr4-4.9.2/lib/src/parser.dart +0 -777
- package/antlr4-4.9.2/lib/src/parser_interpreter.dart +0 -393
- package/antlr4-4.9.2/lib/src/parser_rule_context.dart +0 -275
- package/antlr4-4.9.2/lib/src/prediction_context.dart +0 -877
- package/antlr4-4.9.2/lib/src/recognizer.dart +0 -182
- package/antlr4-4.9.2/lib/src/rule_context.dart +0 -192
- package/antlr4-4.9.2/lib/src/runtime_meta_data.dart +0 -188
- package/antlr4-4.9.2/lib/src/token.dart +0 -431
- package/antlr4-4.9.2/lib/src/token_factory.dart +0 -88
- package/antlr4-4.9.2/lib/src/token_source.dart +0 -241
- package/antlr4-4.9.2/lib/src/token_stream.dart +0 -627
- package/antlr4-4.9.2/lib/src/tree/src/pattern/chunk.dart +0 -90
- package/antlr4-4.9.2/lib/src/tree/src/pattern/parse_tree_match.dart +0 -635
- package/antlr4-4.9.2/lib/src/tree/src/tree.dart +0 -370
- package/antlr4-4.9.2/lib/src/tree/src/trees.dart +0 -226
- package/antlr4-4.9.2/lib/src/tree/tree.dart +0 -10
- package/antlr4-4.9.2/lib/src/util/bit_set.dart +0 -308
- package/antlr4-4.9.2/lib/src/util/murmur_hash.dart +0 -77
- package/antlr4-4.9.2/lib/src/util/utils.dart +0 -31
- package/antlr4-4.9.2/lib/src/vocabulary.dart +0 -254
- package/antlr4-4.9.2/pubspec.yaml +0 -13
- package/example/node_example/index.js +0 -8
- package/example/node_example/package.json +0 -12
- package/example/node_example_ts/package-lock.json +0 -70
- package/example/node_example_ts/package.json +0 -19
- package/example/node_example_ts/src/index.js +0 -5
- package/example/node_example_ts/src/index.ts +0 -9
- package/example/node_example_ts/tsconfig.json +0 -79
- package/js/dart2jsout.js +0 -25898
- package/js/dart2jsout.js.map +0 -16
- package/js/index.d.ts +0 -1
- package/js/index.js +0 -4
- package/js/out.js +0 -26023
- package/js/out.js.map +0 -16
- package/js/package-lock.json +0 -57
- package/js/preamble.js +0 -125
- package/lib/apexdocs_dart.dart +0 -28
- package/lib/src/antlr/grammars/Apexdoc/ApexdocLexer.g4 +0 -120
- package/lib/src/antlr/grammars/Apexdoc/ApexdocParser.g4 +0 -158
- package/lib/src/antlr/grammars/Apexdoc/gen/ApexdocLexer.interp +0 -95
- package/lib/src/antlr/grammars/Apexdoc/gen/ApexdocLexer.java +0 -238
- package/lib/src/antlr/grammars/Apexdoc/gen/ApexdocLexer.tokens +0 -23
- package/lib/src/antlr/grammars/apex/ApexLexer.g4 +0 -255
- package/lib/src/antlr/grammars/apex/ApexParser.g4 +0 -567
- package/lib/src/antlr/grammars/apex/examples/ApexClass.cls +0 -6
- package/lib/src/antlr/lib/apex/ApexLexer.dart +0 -1223
- package/lib/src/antlr/lib/apex/ApexLexer.interp +0 -393
- package/lib/src/antlr/lib/apex/ApexLexer.tokens +0 -212
- package/lib/src/antlr/lib/apex/ApexParser.dart +0 -9349
- package/lib/src/antlr/lib/apex/ApexParser.interp +0 -326
- package/lib/src/antlr/lib/apex/ApexParser.tokens +0 -212
- package/lib/src/antlr/lib/apex/ApexParserBaseListener.dart +0 -1036
- package/lib/src/antlr/lib/apex/ApexParserListener.dart +0 -975
- package/lib/src/antlr/lib/apexdoc/ApexdocLexer.dart +0 -373
- package/lib/src/antlr/lib/apexdoc/ApexdocLexer.interp +0 -95
- package/lib/src/antlr/lib/apexdoc/ApexdocLexer.tokens +0 -23
- package/lib/src/antlr/lib/apexdoc/ApexdocParser.dart +0 -2471
- package/lib/src/antlr/lib/apexdoc/ApexdocParser.interp +0 -69
- package/lib/src/antlr/lib/apexdoc/ApexdocParser.tokens +0 -23
- package/lib/src/antlr/lib/apexdoc/ApexdocParserBaseListener.dart +0 -252
- package/lib/src/antlr/lib/apexdoc/ApexdocParserListener.dart +0 -215
- package/lib/src/builders/builders.dart +0 -32
- package/lib/src/model/apex_file_manifest.dart +0 -37
- package/lib/src/model/apex_file_manifest.g.dart +0 -18
- package/lib/src/model/declaration.dart +0 -50
- package/lib/src/model/doc_comment.dart +0 -117
- package/lib/src/model/doc_comment.g.dart +0 -118
- package/lib/src/model/members.dart +0 -143
- package/lib/src/model/members.g.dart +0 -105
- package/lib/src/model/types.dart +0 -159
- package/lib/src/model/types.g.dart +0 -111
- package/lib/src/service/apex_listener.dart +0 -226
- package/lib/src/service/apexdoc_listener.dart +0 -82
- package/lib/src/service/parsers.dart +0 -33
- package/lib/src/service/utils/parsing/access_modifiers_parser.dart +0 -33
- package/lib/src/service/utils/parsing/parameters_parser.dart +0 -18
- package/lib/src/service/utils/parsing/parsing_utils.dart +0 -2
- package/lib/src/service/walker.dart +0 -82
- package/pubspec.yaml +0 -19
- package/test/apex_file_manifest_test.dart +0 -16
- package/test/apex_listener_test.dart +0 -703
- package/test/apexdoc_parser_test.dart +0 -179
- package/test/doc_comment_test.dart +0 -89
- package/test/members_serialization_test.dart +0 -158
- package/test/members_test.dart +0 -178
- package/test/types_serialization_test.dart +0 -191
- package/test/types_test.dart +0 -311
- package/test/walker_test.dart +0 -58
- package/tool/grind.dart +0 -20
|
@@ -1,635 +0,0 @@
|
|
|
1
|
-
/*
|
|
2
|
-
* Copyright (c) 2012-2017 The ANTLR Project. All rights reserved.
|
|
3
|
-
* Use of this file is governed by the BSD 3-clause license that
|
|
4
|
-
* can be found in the LICENSE.txt file in the project root.
|
|
5
|
-
*/
|
|
6
|
-
|
|
7
|
-
import '../../../error/error.dart';
|
|
8
|
-
import '../../../input_stream.dart';
|
|
9
|
-
import '../../../lexer.dart';
|
|
10
|
-
import '../../../misc/multi_map.dart';
|
|
11
|
-
import '../../../parser.dart';
|
|
12
|
-
import '../../../parser_interpreter.dart';
|
|
13
|
-
import '../../../parser_rule_context.dart';
|
|
14
|
-
import '../../../token.dart';
|
|
15
|
-
import '../../../token_source.dart';
|
|
16
|
-
import '../../../token_stream.dart';
|
|
17
|
-
import '../../../util/utils.dart';
|
|
18
|
-
import '../tree.dart';
|
|
19
|
-
import 'chunk.dart';
|
|
20
|
-
|
|
21
|
-
/// Represents the result of matching a [ParseTree] against a tree pattern.
|
|
22
|
-
class ParseTreeMatch {
|
|
23
|
-
/// Get the parse tree we are trying to match to a pattern.
|
|
24
|
-
///
|
|
25
|
-
/// @return The [ParseTree] we are trying to match to a pattern.
|
|
26
|
-
final ParseTree tree;
|
|
27
|
-
|
|
28
|
-
/// Get the tree pattern we are matching against.
|
|
29
|
-
///
|
|
30
|
-
/// @return The tree pattern we are matching against.
|
|
31
|
-
final ParseTreePattern pattern;
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
/// Return a mapping from label → [list of nodes].
|
|
35
|
-
///
|
|
36
|
-
/// <p>The map includes special entries corresponding to the names of rules and
|
|
37
|
-
/// tokens referenced in tags in the original pattern. For additional
|
|
38
|
-
/// information, see the description of {@link #getAll(String)}.</p>
|
|
39
|
-
///
|
|
40
|
-
/// @return A mapping from labels to parse tree nodes. If the parse tree
|
|
41
|
-
/// pattern did not contain any rule or token tags, this map will be empty.
|
|
42
|
-
final MultiMap<String, ParseTree> labels;
|
|
43
|
-
|
|
44
|
-
/// Get the node at which we first detected a mismatch.
|
|
45
|
-
///
|
|
46
|
-
/// @return the node at which we first detected a mismatch, or null
|
|
47
|
-
/// if the match was successful.
|
|
48
|
-
final ParseTree mismatchedNode;
|
|
49
|
-
|
|
50
|
-
/// Constructs a new instance of [ParseTreeMatch] from the specified
|
|
51
|
-
/// parse tree and pattern.
|
|
52
|
-
///
|
|
53
|
-
/// @param tree The parse tree to match against the pattern.
|
|
54
|
-
/// @param pattern The parse tree pattern.
|
|
55
|
-
/// @param labels A mapping from label names to collections of
|
|
56
|
-
/// [ParseTree] objects located by the tree pattern matching process.
|
|
57
|
-
/// @param mismatchedNode The first node which failed to match the tree
|
|
58
|
-
/// pattern during the matching process.
|
|
59
|
-
///
|
|
60
|
-
/// @exception ArgumentError.notNull) if [tree] is null
|
|
61
|
-
/// @exception ArgumentError.notNull) if [pattern] is null
|
|
62
|
-
/// @exception ArgumentError.notNull) if [labels] is null
|
|
63
|
-
ParseTreeMatch(this.tree, this.pattern, this.labels, this.mismatchedNode) {
|
|
64
|
-
if (tree == null) {
|
|
65
|
-
throw ArgumentError.notNull('tree');
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
if (pattern == null) {
|
|
69
|
-
throw ArgumentError.notNull('pattern');
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
if (labels == null) {
|
|
73
|
-
throw ArgumentError.notNull('labels');
|
|
74
|
-
}
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
/// Get the last node associated with a specific [label].
|
|
78
|
-
///
|
|
79
|
-
/// <p>For example, for pattern {@code <id:ID>}, {@code get("id")} returns the
|
|
80
|
-
/// node matched for that [ID]. If more than one node
|
|
81
|
-
/// matched the specified label, only the last is returned. If there is
|
|
82
|
-
/// no node associated with the label, this returns null.</p>
|
|
83
|
-
///
|
|
84
|
-
/// <p>Pattern tags like {@code <ID>} and {@code <expr>} without labels are
|
|
85
|
-
/// considered to be labeled with [ID] and [expr], respectively.</p>
|
|
86
|
-
///
|
|
87
|
-
/// @param label The label to check.
|
|
88
|
-
///
|
|
89
|
-
/// @return The last [ParseTree] to match a tag with the specified
|
|
90
|
-
/// label, or null if no parse tree matched a tag with the label.
|
|
91
|
-
|
|
92
|
-
ParseTree get(String label) {
|
|
93
|
-
final parseTrees = labels[label];
|
|
94
|
-
if (parseTrees == null || parseTrees.isEmpty) {
|
|
95
|
-
return null;
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
return parseTrees[parseTrees.length - 1]; // return last if multiple
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
/// Return all nodes matching a rule or token tag with the specified label.
|
|
102
|
-
///
|
|
103
|
-
/// <p>If the [label] is the name of a parser rule or token in the
|
|
104
|
-
/// grammar, the resulting list will contain both the parse trees matching
|
|
105
|
-
/// rule or tags explicitly labeled with the label and the complete set of
|
|
106
|
-
/// parse trees matching the labeled and unlabeled tags in the pattern for
|
|
107
|
-
/// the parser rule or token. For example, if [label] is {@code "foo"},
|
|
108
|
-
/// the result will contain <em>all</em> of the following.</p>
|
|
109
|
-
///
|
|
110
|
-
/// <ul>
|
|
111
|
-
/// <li>Parse tree nodes matching tags of the form {@code <foo:anyRuleName>} and
|
|
112
|
-
/// {@code <foo:AnyTokenName>}.</li>
|
|
113
|
-
/// <li>Parse tree nodes matching tags of the form {@code <anyLabel:foo>}.</li>
|
|
114
|
-
/// <li>Parse tree nodes matching tags of the form {@code <foo>}.</li>
|
|
115
|
-
/// </ul>
|
|
116
|
-
///
|
|
117
|
-
/// @param label The label.
|
|
118
|
-
///
|
|
119
|
-
/// @return A collection of all [ParseTree] nodes matching tags with
|
|
120
|
-
/// the specified [label]. If no nodes matched the label, an empty list
|
|
121
|
-
/// is returned.
|
|
122
|
-
|
|
123
|
-
List<ParseTree> getAll(String label) {
|
|
124
|
-
final nodes = labels[label];
|
|
125
|
-
if (nodes == null) {
|
|
126
|
-
return [];
|
|
127
|
-
}
|
|
128
|
-
|
|
129
|
-
return nodes;
|
|
130
|
-
}
|
|
131
|
-
|
|
132
|
-
/// Gets a value indicating whether the match operation succeeded.
|
|
133
|
-
///
|
|
134
|
-
/// @return [true] if the match operation succeeded; otherwise,
|
|
135
|
-
/// [false].
|
|
136
|
-
bool get succeeded => mismatchedNode == null;
|
|
137
|
-
|
|
138
|
-
/// {@inheritDoc}
|
|
139
|
-
@override
|
|
140
|
-
String toString() {
|
|
141
|
-
return "Match ${succeeded ? "succeeded" : "failed"}; found ${labels.length} labels";
|
|
142
|
-
}
|
|
143
|
-
}
|
|
144
|
-
|
|
145
|
-
/// A pattern like {@code <ID> = <expr>;} converted to a [ParseTree] by
|
|
146
|
-
/// {@link ParseTreePatternMatcher#compile(String, int)}.
|
|
147
|
-
class ParseTreePattern {
|
|
148
|
-
/// Get the parser rule which serves as the outermost rule for the tree
|
|
149
|
-
/// pattern.
|
|
150
|
-
///
|
|
151
|
-
/// @return The parser rule which serves as the outermost rule for the tree
|
|
152
|
-
/// pattern.
|
|
153
|
-
final int patternRuleIndex;
|
|
154
|
-
|
|
155
|
-
/// Get the tree pattern in concrete syntax form.
|
|
156
|
-
///
|
|
157
|
-
/// @return The tree pattern in concrete syntax form.
|
|
158
|
-
final String pattern;
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
/// Get the tree pattern as a [ParseTree]. The rule and token tags from
|
|
162
|
-
/// the pattern are present in the parse tree as terminal nodes with a symbol
|
|
163
|
-
/// of type [RuleTagToken] or [TokenTagToken].
|
|
164
|
-
///
|
|
165
|
-
/// @return The tree pattern as a [ParseTree].
|
|
166
|
-
final ParseTree patternTree;
|
|
167
|
-
|
|
168
|
-
/// Get the [ParseTreePatternMatcher] which created this tree pattern.
|
|
169
|
-
///
|
|
170
|
-
/// @return The [ParseTreePatternMatcher] which created this tree
|
|
171
|
-
/// pattern.
|
|
172
|
-
final ParseTreePatternMatcher matcher;
|
|
173
|
-
|
|
174
|
-
/// Construct a new instance of the [ParseTreePattern] class.
|
|
175
|
-
///
|
|
176
|
-
/// @param matcher The [ParseTreePatternMatcher] which created this
|
|
177
|
-
/// tree pattern.
|
|
178
|
-
/// @param pattern The tree pattern in concrete syntax form.
|
|
179
|
-
/// @param patternRuleIndex The parser rule which serves as the root of the
|
|
180
|
-
/// tree pattern.
|
|
181
|
-
/// @param patternTree The tree pattern in [ParseTree] form.
|
|
182
|
-
ParseTreePattern(
|
|
183
|
-
this.matcher, this.pattern, this.patternRuleIndex, this.patternTree);
|
|
184
|
-
|
|
185
|
-
/// Match a specific parse tree against this tree pattern.
|
|
186
|
-
///
|
|
187
|
-
/// @param tree The parse tree to match against this tree pattern.
|
|
188
|
-
/// @return A [ParseTreeMatch] object describing the result of the
|
|
189
|
-
/// match operation. The {@link ParseTreeMatch#succeeded()} method can be
|
|
190
|
-
/// used to determine whether or not the match was successful.
|
|
191
|
-
|
|
192
|
-
ParseTreeMatch match(ParseTree tree) {
|
|
193
|
-
return matcher.match(tree, pattern: this);
|
|
194
|
-
}
|
|
195
|
-
|
|
196
|
-
/// Determine whether or not a parse tree matches this tree pattern.
|
|
197
|
-
///
|
|
198
|
-
/// @param tree The parse tree to match against this tree pattern.
|
|
199
|
-
/// @return [true] if [tree] is a match for the current tree
|
|
200
|
-
/// pattern; otherwise, [false].
|
|
201
|
-
bool matches(ParseTree tree) {
|
|
202
|
-
return matcher.match(tree, pattern: this).succeeded;
|
|
203
|
-
}
|
|
204
|
-
}
|
|
205
|
-
|
|
206
|
-
/// A tree pattern matching mechanism for ANTLR [ParseTree]s.
|
|
207
|
-
///
|
|
208
|
-
/// <p>Patterns are strings of source input text with special tags representing
|
|
209
|
-
/// token or rule references such as:</p>
|
|
210
|
-
///
|
|
211
|
-
/// <p>{@code <ID> = <expr>;}</p>
|
|
212
|
-
///
|
|
213
|
-
/// <p>Given a pattern start rule such as [statement], this object constructs
|
|
214
|
-
/// a [ParseTree] with placeholders for the [ID] and [expr]
|
|
215
|
-
/// subtree. Then the {@link #match} routines can compare an actual
|
|
216
|
-
/// [ParseTree] from a parse with this pattern. Tag {@code <ID>} matches
|
|
217
|
-
/// any [ID] token and tag {@code <expr>} references the result of the
|
|
218
|
-
/// [expr] rule (generally an instance of [ExprContext].</p>
|
|
219
|
-
///
|
|
220
|
-
/// <p>Pattern {@code x = 0;} is a similar pattern that matches the same pattern
|
|
221
|
-
/// except that it requires the identifier to be [x] and the expression to
|
|
222
|
-
/// be {@code 0}.</p>
|
|
223
|
-
///
|
|
224
|
-
/// <p>The {@link #matches} routines return [true] or [false] based
|
|
225
|
-
/// upon a match for the tree rooted at the parameter sent in. The
|
|
226
|
-
/// {@link #match} routines return a [ParseTreeMatch] object that
|
|
227
|
-
/// contains the parse tree, the parse tree pattern, and a map from tag name to
|
|
228
|
-
/// matched nodes (more below). A subtree that fails to match, returns with
|
|
229
|
-
/// {@link ParseTreeMatch#mismatchedNode} set to the first tree node that did not
|
|
230
|
-
/// match.</p>
|
|
231
|
-
///
|
|
232
|
-
/// <p>For efficiency, you can compile a tree pattern in string form to a
|
|
233
|
-
/// [ParseTreePattern] object.</p>
|
|
234
|
-
///
|
|
235
|
-
/// <p>See [TestParseTreeMatcher] for lots of examples.
|
|
236
|
-
/// [ParseTreePattern] has two static helper methods:
|
|
237
|
-
/// {@link ParseTreePattern#findAll} and {@link ParseTreePattern#match} that
|
|
238
|
-
/// are easy to use but not super efficient because they create new
|
|
239
|
-
/// [ParseTreePatternMatcher] objects each time and have to compile the
|
|
240
|
-
/// pattern in string form before using it.</p>
|
|
241
|
-
///
|
|
242
|
-
/// <p>The lexer and parser that you pass into the [ParseTreePatternMatcher]
|
|
243
|
-
/// constructor are used to parse the pattern in string form. The lexer converts
|
|
244
|
-
/// the {@code <ID> = <expr>;} into a sequence of four tokens (assuming lexer
|
|
245
|
-
/// throws out whitespace or puts it on a hidden channel). Be aware that the
|
|
246
|
-
/// input stream is reset for the lexer (but not the parser; a
|
|
247
|
-
/// [ParserInterpreter] is created to parse the input.). Any user-defined
|
|
248
|
-
/// fields you have put into the lexer might get changed when this mechanism asks
|
|
249
|
-
/// it to scan the pattern string.</p>
|
|
250
|
-
///
|
|
251
|
-
/// <p>Normally a parser does not accept token {@code <expr>} as a valid
|
|
252
|
-
/// [expr] but, from the parser passed in, we create a special version of
|
|
253
|
-
/// the underlying grammar representation (an [ATN]) that allows imaginary
|
|
254
|
-
/// tokens representing rules ({@code <expr>}) to match entire rules. We call
|
|
255
|
-
/// these <em>bypass alternatives</em>.</p>
|
|
256
|
-
///
|
|
257
|
-
/// <p>Delimiters are {@code <} and {@code >}, with {@code \} as the escape string
|
|
258
|
-
/// by default, but you can set them to whatever you want using
|
|
259
|
-
/// {@link #setDelimiters}. You must escape both start and stop strings
|
|
260
|
-
/// {@code \<} and {@code \>}.</p>
|
|
261
|
-
class ParseTreePatternMatcher {
|
|
262
|
-
/// Used to convert the tree pattern string into a series of tokens. The
|
|
263
|
-
/// input stream is reset.
|
|
264
|
-
final Lexer lexer;
|
|
265
|
-
|
|
266
|
-
/// Used to collect to the grammar file name, token names, rule names for
|
|
267
|
-
/// used to parse the pattern into a parse tree.
|
|
268
|
-
final Parser parser;
|
|
269
|
-
|
|
270
|
-
String start = '<';
|
|
271
|
-
String stop = '>';
|
|
272
|
-
String escape = '\\'; // e.g., \< and \> must escape BOTH!
|
|
273
|
-
|
|
274
|
-
/// Constructs a [ParseTreePatternMatcher] or from a [Lexer] and
|
|
275
|
-
/// [Parser] object. The lexer input stream is altered for tokenizing
|
|
276
|
-
/// the tree patterns. The parser is used as a convenient mechanism to get
|
|
277
|
-
/// the grammar name, plus token, rule names.
|
|
278
|
-
ParseTreePatternMatcher(this.lexer, this.parser);
|
|
279
|
-
|
|
280
|
-
/// Set the delimiters used for marking rule and token tags within concrete
|
|
281
|
-
/// syntax used by the tree pattern parser.
|
|
282
|
-
///
|
|
283
|
-
/// @param start The start delimiter.
|
|
284
|
-
/// @param stop The stop delimiter.
|
|
285
|
-
/// @param escapeLeft The escape sequence to use for escaping a start or stop delimiter.
|
|
286
|
-
///
|
|
287
|
-
/// @exception ArgumentError if [start] is null or empty.
|
|
288
|
-
/// @exception ArgumentError if [stop] is null or empty.
|
|
289
|
-
void setDelimiters(String start, String stop, String escapeLeft) {
|
|
290
|
-
if (start == null || start.isEmpty) {
|
|
291
|
-
throw ArgumentError.value(start, 'start', 'cannot be null or empty');
|
|
292
|
-
}
|
|
293
|
-
|
|
294
|
-
if (stop == null || stop.isEmpty) {
|
|
295
|
-
throw ArgumentError.value(stop, 'stop', 'cannot be null or empty');
|
|
296
|
-
}
|
|
297
|
-
|
|
298
|
-
this.start = start;
|
|
299
|
-
this.stop = stop;
|
|
300
|
-
escape = escapeLeft;
|
|
301
|
-
}
|
|
302
|
-
|
|
303
|
-
/// Does [pattern] matched as rule patternRuleIndex match tree? Pass in a
|
|
304
|
-
/// compiled pattern instead of a string representation of a tree pattern.
|
|
305
|
-
bool matches(ParseTree tree,
|
|
306
|
-
{ParseTreePattern pattern, String patternStr, int patternRuleIndex}) {
|
|
307
|
-
pattern ??= compile(patternStr, patternRuleIndex);
|
|
308
|
-
|
|
309
|
-
final labels = MultiMap<String, ParseTree>();
|
|
310
|
-
final mismatchedNode =
|
|
311
|
-
matchImpl(tree, pattern.patternTree, labels);
|
|
312
|
-
return mismatchedNode == null;
|
|
313
|
-
}
|
|
314
|
-
|
|
315
|
-
/// Compare [pattern] matched against [tree] and return a
|
|
316
|
-
/// [ParseTreeMatch] object that contains the matched elements, or the
|
|
317
|
-
/// node at which the match failed. Pass in a compiled pattern instead of a
|
|
318
|
-
/// string representation of a tree pattern.
|
|
319
|
-
|
|
320
|
-
ParseTreeMatch match(ParseTree tree,
|
|
321
|
-
{ParseTreePattern pattern, String patternStr, int patternRuleIndex}) {
|
|
322
|
-
pattern ??= compile(patternStr, patternRuleIndex);
|
|
323
|
-
|
|
324
|
-
final labels = MultiMap<String, ParseTree>();
|
|
325
|
-
final mismatchedNode =
|
|
326
|
-
matchImpl(tree, pattern.patternTree, labels);
|
|
327
|
-
return ParseTreeMatch(tree, pattern, labels, mismatchedNode);
|
|
328
|
-
}
|
|
329
|
-
|
|
330
|
-
/// For repeated use of a tree pattern, compile it to a
|
|
331
|
-
/// [ParseTreePattern] using this method.
|
|
332
|
-
ParseTreePattern compile(String pattern, int patternRuleIndex) {
|
|
333
|
-
final tokenList = tokenize(pattern);
|
|
334
|
-
final tokenSrc = ListTokenSource(tokenList);
|
|
335
|
-
final tokens = CommonTokenStream(tokenSrc);
|
|
336
|
-
|
|
337
|
-
final parserInterp = ParserInterpreter(
|
|
338
|
-
parser.grammarFileName,
|
|
339
|
-
parser.vocabulary,
|
|
340
|
-
parser.ruleNames,
|
|
341
|
-
parser.ATNWithBypassAlts,
|
|
342
|
-
tokens);
|
|
343
|
-
|
|
344
|
-
ParseTree tree;
|
|
345
|
-
try {
|
|
346
|
-
parserInterp.errorHandler = BailErrorStrategy();
|
|
347
|
-
tree = parserInterp.parse(patternRuleIndex);
|
|
348
|
-
// System.out.println("pattern tree = "+tree.toStringTree(parserInterp));
|
|
349
|
-
} on ParseCancellationException {
|
|
350
|
-
rethrow;
|
|
351
|
-
} on RecognitionException {
|
|
352
|
-
rethrow;
|
|
353
|
-
} catch (e) {
|
|
354
|
-
throw CannotInvokeStartRule(e);
|
|
355
|
-
}
|
|
356
|
-
|
|
357
|
-
// Make sure tree pattern compilation checks for a complete parse
|
|
358
|
-
if (tokens.LA(1) != Token.EOF) {
|
|
359
|
-
throw StartRuleDoesNotConsumeFullPattern();
|
|
360
|
-
}
|
|
361
|
-
|
|
362
|
-
return ParseTreePattern(this, pattern, patternRuleIndex, tree);
|
|
363
|
-
}
|
|
364
|
-
|
|
365
|
-
// ---- SUPPORT CODE ----
|
|
366
|
-
|
|
367
|
-
/// Recursively walk [tree] against [patternTree], filling
|
|
368
|
-
/// {@code match.}{@link ParseTreeMatch#labels labels}.
|
|
369
|
-
///
|
|
370
|
-
/// @return the first node encountered in [tree] which does not match
|
|
371
|
-
/// a corresponding node in [patternTree], or null if the match
|
|
372
|
-
/// was successful. The specific node returned depends on the matching
|
|
373
|
-
/// algorithm used by the implementation, and may be overridden.
|
|
374
|
-
|
|
375
|
-
ParseTree matchImpl(ParseTree tree, ParseTree patternTree,
|
|
376
|
-
MultiMap<String, ParseTree> labels) {
|
|
377
|
-
if (tree == null) {
|
|
378
|
-
throw ArgumentError('tree cannot be null');
|
|
379
|
-
}
|
|
380
|
-
|
|
381
|
-
if (patternTree == null) {
|
|
382
|
-
throw ArgumentError('patternTree cannot be null');
|
|
383
|
-
}
|
|
384
|
-
|
|
385
|
-
// x and <ID>, x and y, or x and x; or could be mismatched types
|
|
386
|
-
if (tree is TerminalNode && patternTree is TerminalNode) {
|
|
387
|
-
final t1 = tree;
|
|
388
|
-
final t2 = patternTree;
|
|
389
|
-
ParseTree mismatchedNode;
|
|
390
|
-
// both are tokens and they have same type
|
|
391
|
-
if (t1.symbol.type == t2.symbol.type) {
|
|
392
|
-
if (t2.symbol is TokenTagToken) {
|
|
393
|
-
// x and <ID>
|
|
394
|
-
TokenTagToken tokenTagToken = t2.symbol;
|
|
395
|
-
// track label->list-of-nodes for both token name and label (if any)
|
|
396
|
-
labels.put(tokenTagToken.tokenName, tree);
|
|
397
|
-
if (tokenTagToken.label != null) {
|
|
398
|
-
labels.put(tokenTagToken.label, tree);
|
|
399
|
-
}
|
|
400
|
-
} else if (t1.text == t2.text) {
|
|
401
|
-
// x and x
|
|
402
|
-
} else {
|
|
403
|
-
// x and y
|
|
404
|
-
mismatchedNode ??= t1;
|
|
405
|
-
}
|
|
406
|
-
} else {
|
|
407
|
-
mismatchedNode ??= t1;
|
|
408
|
-
}
|
|
409
|
-
|
|
410
|
-
return mismatchedNode;
|
|
411
|
-
}
|
|
412
|
-
|
|
413
|
-
if (tree is ParserRuleContext && patternTree is ParserRuleContext) {
|
|
414
|
-
final r1 = tree;
|
|
415
|
-
final r2 = patternTree;
|
|
416
|
-
ParseTree mismatchedNode;
|
|
417
|
-
// (expr ...) and <expr>
|
|
418
|
-
final ruleTagToken = getRuleTagToken(r2);
|
|
419
|
-
if (ruleTagToken != null) {
|
|
420
|
-
if (r1.ruleContext.ruleIndex == r2.ruleContext.ruleIndex) {
|
|
421
|
-
// track label->list-of-nodes for both rule name and label (if any)
|
|
422
|
-
labels.put(ruleTagToken.ruleName, tree);
|
|
423
|
-
if (ruleTagToken.label != null) {
|
|
424
|
-
labels.put(ruleTagToken.label, tree);
|
|
425
|
-
}
|
|
426
|
-
} else {
|
|
427
|
-
mismatchedNode ??= r1;
|
|
428
|
-
}
|
|
429
|
-
|
|
430
|
-
return mismatchedNode;
|
|
431
|
-
}
|
|
432
|
-
|
|
433
|
-
// (expr ...) and (expr ...)
|
|
434
|
-
if (r1.childCount != r2.childCount) {
|
|
435
|
-
mismatchedNode ??= r1;
|
|
436
|
-
|
|
437
|
-
return mismatchedNode;
|
|
438
|
-
}
|
|
439
|
-
|
|
440
|
-
final n = r1.childCount;
|
|
441
|
-
for (var i = 0; i < n; i++) {
|
|
442
|
-
final childMatch =
|
|
443
|
-
matchImpl(r1.getChild(i), patternTree.getChild(i), labels);
|
|
444
|
-
if (childMatch != null) {
|
|
445
|
-
return childMatch;
|
|
446
|
-
}
|
|
447
|
-
}
|
|
448
|
-
|
|
449
|
-
return mismatchedNode;
|
|
450
|
-
}
|
|
451
|
-
|
|
452
|
-
// if nodes aren't both tokens or both rule nodes, can't match
|
|
453
|
-
return tree;
|
|
454
|
-
}
|
|
455
|
-
|
|
456
|
-
/// Is [t] {@code (expr <expr>)} subtree? */
|
|
457
|
-
RuleTagToken getRuleTagToken(ParseTree t) {
|
|
458
|
-
if (t is RuleNode) {
|
|
459
|
-
final r = t;
|
|
460
|
-
if (r.childCount == 1 && r.getChild(0) is TerminalNode) {
|
|
461
|
-
TerminalNode c = r.getChild(0);
|
|
462
|
-
if (c.symbol is RuleTagToken) {
|
|
463
|
-
// System.out.println("rule tag subtree "+t.toStringTree(parser));
|
|
464
|
-
return c.symbol;
|
|
465
|
-
}
|
|
466
|
-
}
|
|
467
|
-
}
|
|
468
|
-
return null;
|
|
469
|
-
}
|
|
470
|
-
|
|
471
|
-
List<Token> tokenize(String pattern) {
|
|
472
|
-
// split pattern into chunks: sea (raw input) and islands (<ID>, <expr>)
|
|
473
|
-
final chunks = split(pattern);
|
|
474
|
-
|
|
475
|
-
// create token stream from text and tags
|
|
476
|
-
final tokens = <Token>[];
|
|
477
|
-
for (var chunk in chunks) {
|
|
478
|
-
if (chunk is TagChunk) {
|
|
479
|
-
final tagChunk = chunk;
|
|
480
|
-
// add special rule token or conjure up new token from name
|
|
481
|
-
if (isUpperCase(tagChunk.tag[0])) {
|
|
482
|
-
final ttype = parser.getTokenType(tagChunk.tag);
|
|
483
|
-
if (ttype == Token.INVALID_TYPE) {
|
|
484
|
-
throw ArgumentError('Unknown token ' +
|
|
485
|
-
tagChunk.tag +
|
|
486
|
-
' in pattern: ' +
|
|
487
|
-
pattern);
|
|
488
|
-
}
|
|
489
|
-
final t =
|
|
490
|
-
TokenTagToken(tagChunk.tag, ttype, tagChunk.label);
|
|
491
|
-
tokens.add(t);
|
|
492
|
-
} else if (isLowerCase(tagChunk.tag[0])) {
|
|
493
|
-
final ruleIndex = parser.getRuleIndex(tagChunk.tag);
|
|
494
|
-
if (ruleIndex == -1) {
|
|
495
|
-
throw ArgumentError('Unknown rule ' +
|
|
496
|
-
tagChunk.tag +
|
|
497
|
-
' in pattern: ' +
|
|
498
|
-
pattern);
|
|
499
|
-
}
|
|
500
|
-
final ruleImaginaryTokenType =
|
|
501
|
-
parser.ATNWithBypassAlts.ruleToTokenType[ruleIndex];
|
|
502
|
-
tokens.add(RuleTagToken(
|
|
503
|
-
tagChunk.tag, ruleImaginaryTokenType, tagChunk.label));
|
|
504
|
-
} else {
|
|
505
|
-
throw ArgumentError(
|
|
506
|
-
'invalid tag: ' + tagChunk.tag + ' in pattern: ' + pattern);
|
|
507
|
-
}
|
|
508
|
-
} else {
|
|
509
|
-
TextChunk textChunk = chunk;
|
|
510
|
-
final inputStream =
|
|
511
|
-
InputStream.fromString(textChunk.text);
|
|
512
|
-
lexer.inputStream = inputStream;
|
|
513
|
-
var t = lexer.nextToken();
|
|
514
|
-
while (t.type != Token.EOF) {
|
|
515
|
-
tokens.add(t);
|
|
516
|
-
t = lexer.nextToken();
|
|
517
|
-
}
|
|
518
|
-
}
|
|
519
|
-
}
|
|
520
|
-
|
|
521
|
-
// System.out.println("tokens="+tokens);
|
|
522
|
-
return tokens;
|
|
523
|
-
}
|
|
524
|
-
|
|
525
|
-
/// Split {@code <ID> = <e:expr> ;} into 4 chunks for tokenizing by {@link #tokenize}. */
|
|
526
|
-
List<Chunk> split(String pattern) {
|
|
527
|
-
var p = 0;
|
|
528
|
-
final n = pattern.length;
|
|
529
|
-
final chunks = <Chunk>[];
|
|
530
|
-
// find all start and stop indexes first, then collect
|
|
531
|
-
final starts = <int>[];
|
|
532
|
-
final stops = <int>[];
|
|
533
|
-
while (p < n) {
|
|
534
|
-
if (p == pattern.indexOf(escape + start, p)) {
|
|
535
|
-
p += escape.length + start.length;
|
|
536
|
-
} else if (p == pattern.indexOf(escape + stop, p)) {
|
|
537
|
-
p += escape.length + stop.length;
|
|
538
|
-
} else if (p == pattern.indexOf(start, p)) {
|
|
539
|
-
starts.add(p);
|
|
540
|
-
p += start.length;
|
|
541
|
-
} else if (p == pattern.indexOf(stop, p)) {
|
|
542
|
-
stops.add(p);
|
|
543
|
-
p += stop.length;
|
|
544
|
-
} else {
|
|
545
|
-
p++;
|
|
546
|
-
}
|
|
547
|
-
}
|
|
548
|
-
|
|
549
|
-
// System.out.println("");
|
|
550
|
-
// System.out.println(starts);
|
|
551
|
-
// System.out.println(stops);
|
|
552
|
-
if (starts.length > stops.length) {
|
|
553
|
-
throw ArgumentError('unterminated tag in pattern: ' + pattern);
|
|
554
|
-
}
|
|
555
|
-
|
|
556
|
-
if (starts.length < stops.length) {
|
|
557
|
-
throw ArgumentError('missing start tag in pattern: ' + pattern);
|
|
558
|
-
}
|
|
559
|
-
|
|
560
|
-
final ntags = starts.length;
|
|
561
|
-
for (var i = 0; i < ntags; i++) {
|
|
562
|
-
if (starts[i] >= stops[i]) {
|
|
563
|
-
throw ArgumentError(
|
|
564
|
-
'tag delimiters out of order in pattern: ' + pattern);
|
|
565
|
-
}
|
|
566
|
-
}
|
|
567
|
-
|
|
568
|
-
// collect into chunks now
|
|
569
|
-
if (ntags == 0) {
|
|
570
|
-
final text = pattern.substring(0, n);
|
|
571
|
-
chunks.add(TextChunk(text));
|
|
572
|
-
}
|
|
573
|
-
|
|
574
|
-
if (ntags > 0 && starts[0] > 0) {
|
|
575
|
-
// copy text up to first tag into chunks
|
|
576
|
-
final text = pattern.substring(0, starts[0]);
|
|
577
|
-
chunks.add(TextChunk(text));
|
|
578
|
-
}
|
|
579
|
-
for (var i = 0; i < ntags; i++) {
|
|
580
|
-
// copy inside of <tag>
|
|
581
|
-
final tag = pattern.substring(starts[i] + start.length, stops[i]);
|
|
582
|
-
var ruleOrToken = tag;
|
|
583
|
-
String label;
|
|
584
|
-
final colon = tag.indexOf(':');
|
|
585
|
-
if (colon >= 0) {
|
|
586
|
-
label = tag.substring(0, colon);
|
|
587
|
-
ruleOrToken = tag.substring(colon + 1, tag.length);
|
|
588
|
-
}
|
|
589
|
-
chunks.add(TagChunk(ruleOrToken, label: label));
|
|
590
|
-
if (i + 1 < ntags) {
|
|
591
|
-
// copy from end of <tag> to start of next
|
|
592
|
-
final text = pattern.substring(stops[i] + stop.length, starts[i + 1]);
|
|
593
|
-
chunks.add(TextChunk(text));
|
|
594
|
-
}
|
|
595
|
-
}
|
|
596
|
-
if (ntags > 0) {
|
|
597
|
-
final afterLastTag = stops[ntags - 1] + stop.length;
|
|
598
|
-
if (afterLastTag < n) {
|
|
599
|
-
// copy text from end of last tag to end
|
|
600
|
-
final text = pattern.substring(afterLastTag, n);
|
|
601
|
-
chunks.add(TextChunk(text));
|
|
602
|
-
}
|
|
603
|
-
}
|
|
604
|
-
|
|
605
|
-
// strip out the escape sequences from text chunks but not tags
|
|
606
|
-
for (var i = 0; i < chunks.length; i++) {
|
|
607
|
-
final c = chunks[i];
|
|
608
|
-
if (c is TextChunk) {
|
|
609
|
-
final tc = c;
|
|
610
|
-
final unescaped = tc.text.replaceAll(escape, '');
|
|
611
|
-
if (unescaped.length < tc.text.length) {
|
|
612
|
-
chunks[i] = TextChunk(unescaped);
|
|
613
|
-
}
|
|
614
|
-
}
|
|
615
|
-
}
|
|
616
|
-
|
|
617
|
-
return chunks;
|
|
618
|
-
}
|
|
619
|
-
}
|
|
620
|
-
|
|
621
|
-
class CannotInvokeStartRule extends StateError {
|
|
622
|
-
CannotInvokeStartRule(String message) : super(message);
|
|
623
|
-
}
|
|
624
|
-
|
|
625
|
-
// Fixes https://github.com/antlr/antlr4/issues/413
|
|
626
|
-
// "Tree pattern compilation doesn't check for a complete parse"
|
|
627
|
-
class StartRuleDoesNotConsumeFullPattern extends Error {}
|
|
628
|
-
|
|
629
|
-
/// This exception is thrown to cancel a parsing operation. This exception does
|
|
630
|
-
/// not extend [RecognitionException], allowing it to bypass the standard
|
|
631
|
-
/// error recovery mechanisms. [BailErrorStrategy] throws this exception in
|
|
632
|
-
/// response to a parse error.
|
|
633
|
-
class ParseCancellationException extends StateError {
|
|
634
|
-
ParseCancellationException(String message) : super(message);
|
|
635
|
-
}
|