Skip to main content

ktrs_parser/parsing/
token_stream.rs

1//! Ports of `TokenStreamPredicate`, `AbstractTokenStreamPredicate`, `TokenStreamPattern`,
2//! `AbstractTokenStreamPattern`, `FirstBefore`, `LastBefore`, and `AbstractKotlinParsing`'s
3//! `At`/`AtSet`/`matchTokenStreamPredicate`.
4//! Predicates query the parser (`at`/`at_set` may remap tokens), so they take `&mut Parser`.
5
6use ktrs_syntax::SyntaxKind::{self, *};
7
8use super::Parser;
9use crate::token_set::TokenSet;
10
11impl Parser {
12    /// `AbstractKotlinParsing.matchTokenStreamPredicate`.
13    pub(crate) fn match_token_stream_predicate(&mut self, pattern: &mut dyn TokenStreamPattern) -> i32 {
14        let current_position = self.mark();
15        let mut opens: Vec<SyntaxKind> = Vec::new();
16        let mut open_angle_brackets = 0;
17        let mut open_braces = 0;
18        let mut open_parentheses = 0;
19        let mut open_brackets = 0;
20        while !self.eof() {
21            let offset = self.my_builder.get_current_offset();
22            let top_level = pattern.is_top_level(open_angle_brackets, open_brackets, open_braces, open_parentheses);
23            if pattern.process_token(self, offset, top_level) {
24                break;
25            }
26            match self.get_token_id() {
27                Some(LPAR) => {
28                    open_parentheses += 1;
29                    opens.push(LPAR);
30                }
31                Some(LT) => {
32                    open_angle_brackets += 1;
33                    opens.push(LT);
34                }
35                Some(LBRACE) => {
36                    open_braces += 1;
37                    opens.push(LBRACE);
38                }
39                Some(LBRACKET) => {
40                    open_brackets += 1;
41                    opens.push(LBRACKET);
42                }
43                Some(RPAR) => {
44                    open_parentheses -= 1;
45                    // Upstream's `break` here only leaves the switch, so the result is unused.
46                    if opens.pop() != Some(LPAR) {
47                        pattern.handle_unmatched_closing(RPAR);
48                    }
49                }
50                Some(GT) => open_angle_brackets -= 1,
51                Some(RBRACE) => open_braces -= 1,
52                Some(RBRACKET) => open_brackets -= 1,
53                _ => {}
54            }
55
56            self.advance(); // skip token
57        }
58
59        current_position.rollback_to(self);
60
61        pattern.result()
62    }
63}
64
65pub trait TokenStreamPredicate {
66    fn matching(&self, p: &mut Parser, top_level: bool) -> bool;
67
68    /// `AbstractTokenStreamPredicate.or`.
69    fn or<O: TokenStreamPredicate>(self, other: O) -> Or<Self, O>
70    where
71        Self: Sized,
72    {
73        Or(self, other)
74    }
75}
76
77/// Anonymous `AbstractTokenStreamPredicate` subclasses.
78impl<F: Fn(&mut Parser, bool) -> bool> TokenStreamPredicate for F {
79    fn matching(&self, p: &mut Parser, top_level: bool) -> bool {
80        self(p, top_level)
81    }
82}
83
84pub struct Or<A, B>(A, B);
85
86impl<A: TokenStreamPredicate, B: TokenStreamPredicate> TokenStreamPredicate for Or<A, B> {
87    fn matching(&self, p: &mut Parser, top_level: bool) -> bool {
88        if self.0.matching(p, top_level) {
89            return true;
90        }
91        self.1.matching(p, top_level)
92    }
93}
94
95/// `TokenStreamPattern`, with `AbstractTokenStreamPattern`'s defaults.
96pub trait TokenStreamPattern {
97    /// Called on each token; `true` stops.
98    fn process_token(&mut self, p: &mut Parser, offset: i32, top_level: bool) -> bool;
99
100    /// The offset where the pattern matched, -1 if none.
101    fn result(&self) -> i32;
102
103    fn is_top_level(&self, open_angle_brackets: i32, open_brackets: i32, open_braces: i32, open_parentheses: i32) -> bool {
104        open_braces == 0 && open_brackets == 0 && open_parentheses == 0 && open_angle_brackets == 0
105    }
106
107    /// Called on unmatched `)`; `true` asks to stop (ignored by the caller upstream).
108    fn handle_unmatched_closing(&mut self, _token: SyntaxKind) -> bool {
109        false
110    }
111}
112
113/// The state of `AbstractTokenStreamPattern`.
114#[derive(Debug)]
115pub struct AbstractTokenStreamPattern {
116    pub last_occurrence: i32,
117}
118
119impl Default for AbstractTokenStreamPattern {
120    fn default() -> Self {
121        AbstractTokenStreamPattern { last_occurrence: -1 }
122    }
123}
124
125impl AbstractTokenStreamPattern {
126    pub fn fail(&mut self) {
127        self.last_occurrence = -1;
128    }
129
130    pub fn reset(&mut self) {
131        self.last_occurrence = -1;
132    }
133}
134
135pub struct FirstBefore<L, S> {
136    base: AbstractTokenStreamPattern,
137    look_for: L,
138    stop_at: S,
139}
140
141impl<L: TokenStreamPredicate, S: TokenStreamPredicate> FirstBefore<L, S> {
142    pub fn new(look_for: L, stop_at: S) -> Self {
143        FirstBefore { base: AbstractTokenStreamPattern::default(), look_for, stop_at }
144    }
145
146    pub fn reset(&mut self) {
147        self.base.reset();
148    }
149}
150
151impl<L: TokenStreamPredicate, S: TokenStreamPredicate> TokenStreamPattern for FirstBefore<L, S> {
152    fn process_token(&mut self, p: &mut Parser, offset: i32, top_level: bool) -> bool {
153        if self.look_for.matching(p, top_level) {
154            self.base.last_occurrence = offset;
155            return true;
156        }
157        if self.stop_at.matching(p, top_level) {
158            return true;
159        }
160        false
161    }
162
163    fn result(&self) -> i32 {
164        self.base.last_occurrence
165    }
166}
167
168pub struct LastBefore<L, S> {
169    base: AbstractTokenStreamPattern,
170    dont_stop_right_after_occurrence: bool,
171    look_for: L,
172    stop_at: S,
173    previous_look_for_result: bool,
174}
175
176impl<L: TokenStreamPredicate, S: TokenStreamPredicate> LastBefore<L, S> {
177    /// The private 3-arg constructor.
178    fn new_3(look_for: L, stop_at: S, dont_stop_right_after_occurrence: bool) -> Self {
179        LastBefore {
180            base: AbstractTokenStreamPattern::default(),
181            dont_stop_right_after_occurrence,
182            look_for,
183            stop_at,
184            previous_look_for_result: false,
185        }
186    }
187
188    pub fn new(look_for: L, stop_at: S) -> Self {
189        Self::new_3(look_for, stop_at, false)
190    }
191
192    pub fn reset(&mut self) {
193        self.base.reset();
194        self.previous_look_for_result = false;
195    }
196}
197
198impl<L: TokenStreamPredicate, S: TokenStreamPredicate> TokenStreamPattern for LastBefore<L, S> {
199    fn process_token(&mut self, p: &mut Parser, offset: i32, top_level: bool) -> bool {
200        let look_for_result = self.look_for.matching(p, top_level);
201        if look_for_result {
202            self.base.last_occurrence = offset;
203        }
204        if self.stop_at.matching(p, top_level)
205            && top_level
206            && (!self.dont_stop_right_after_occurrence || !self.previous_look_for_result)
207        {
208            return true;
209        }
210        self.previous_look_for_result = look_for_result;
211        false
212    }
213
214    fn result(&self) -> i32 {
215        self.base.last_occurrence
216    }
217}
218
219/// `AbstractKotlinParsing.At`.
220pub struct At {
221    look_for: SyntaxKind,
222    top_level_only: bool,
223}
224
225impl At {
226    pub fn new(look_for: SyntaxKind) -> At {
227        At::new_2(look_for, true)
228    }
229
230    pub fn new_2(look_for: SyntaxKind, top_level_only: bool) -> At {
231        At { look_for, top_level_only }
232    }
233}
234
235impl TokenStreamPredicate for At {
236    fn matching(&self, p: &mut Parser, top_level: bool) -> bool {
237        (top_level || !self.top_level_only) && p.at(self.look_for)
238    }
239}
240
241/// `AbstractKotlinParsing.AtSet`.
242pub struct AtSet {
243    look_for: TokenSet,
244    top_level_only: TokenSet,
245}
246
247impl AtSet {
248    pub fn new(look_for: TokenSet) -> AtSet {
249        AtSet::new_2(look_for, look_for)
250    }
251
252    pub fn new_2(look_for: TokenSet, top_level_only: TokenSet) -> AtSet {
253        AtSet { look_for, top_level_only }
254    }
255}
256
257impl TokenStreamPredicate for AtSet {
258    fn matching(&self, p: &mut Parser, top_level: bool) -> bool {
259        (top_level || !p.at_set(self.top_level_only)) && p.at_set(self.look_for)
260    }
261}