Line data Source code
1 : // Copyright 2026 The Authors. See the AUTHORS file for details.
2 : //
3 : // Licensed under the Apache License, Version 2.0 (the "License");
4 : // you may not use this file except in compliance with the License.
5 : // You may obtain a copy of the License at
6 : //
7 : // https://www.apache.org/licenses/LICENSE-2.0
8 : //
9 : // Unless required by applicable law or agreed to in writing, software
10 : // distributed under the License is distributed on an "AS IS" BASIS,
11 : // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 : // See the License for the specific language governing permissions and
13 : // limitations under the License.
14 :
15 : import 'package:betto_common/collections.dart' show Stack, MappedObject;
16 :
17 : /// The result of parsing an input string.
18 : class ParseResult implements MappedObject {
19 : /// Whether the parse was successful.
20 : final bool success;
21 :
22 : /// The matched string, or null if there was no match (e.g., failed or optional match).
23 : final String? lexeme;
24 :
25 : /// The unparsed suffix of the input string.
26 : final String remaining;
27 :
28 : /// The name of the rule that produced this result, if any.
29 : final String? ruleName;
30 :
31 : /// A string representation of the parsed grammar element.
32 : final String? element;
33 :
34 : /// The hierarchical tree of child [ParseResult]s produced during this parse.
35 : final Stack<ParseResult> stack;
36 :
37 : /// Creates a [ParseResult].
38 : ///
39 : /// [success] indicates whether the sequence matched. [remaining] is the
40 : /// unconsumed portion of the source string. [lexeme] is the matched substring.
41 : /// [ruleName] and [element] provide debugging context. [stack] contains child
42 : /// parse results.
43 5 : ParseResult(
44 : this.success,
45 : this.remaining, {
46 : this.lexeme,
47 : this.ruleName,
48 : this.element,
49 : Stack<ParseResult>? stack,
50 5 : }) : stack = stack ?? Stack();
51 :
52 1 : @override
53 1 : Map<String, dynamic> toMap() => {
54 1 : 'ruleName': ruleName,
55 1 : 'success': success,
56 1 : 'lexeme': lexeme,
57 1 : 'remaining': remaining,
58 1 : 'elementName': element,
59 3 : 'stack': [for (final result in stack.toList()) result.toMap()],
60 : };
61 :
62 : /// Computes all lexemes for a given rule name in the parse tree.
63 : /// Uses a visited set to protect against infinite recursion if the
64 : /// parse tree contains cycles.
65 3 : List<String> getRuleLexemes(String ruleName) =>
66 3 : _getRuleLexemes(ruleName, <ParseResult>{});
67 :
68 3 : List<String> _getRuleLexemes(String ruleName, Set<ParseResult> visited) {
69 3 : if (visited.contains(this)) return const [];
70 3 : visited.add(this);
71 :
72 3 : final results = <String>[];
73 9 : for (final result in stack.toList()) {
74 3 : final lexeme = result.lexeme;
75 6 : if (result.ruleName == ruleName && lexeme != null) {
76 3 : results.add(lexeme);
77 : }
78 6 : results.addAll(result._getRuleLexemes(ruleName, visited));
79 : }
80 : return results;
81 : }
82 : }
|