sway_parse/
parser.rs

1use crate::{Parse, ParseToEnd, Peek};
2use core::marker::PhantomData;
3use std::cell::RefCell;
4use sway_ast::keywords::Keyword;
5use sway_ast::literal::Literal;
6use sway_ast::token::{
7    DocComment, GenericTokenTree, Group, Punct, Spacing, TokenStream, TokenTree,
8};
9use sway_ast::PubToken;
10use sway_error::error::CompileError;
11use sway_error::handler::{ErrorEmitted, Handler};
12use sway_error::parser_error::{ParseError, ParseErrorKind};
13use sway_types::{
14    ast::{Delimiter, PunctKind},
15    Ident, Span, Spanned,
16};
17
18pub struct Parser<'a, 'e> {
19    token_trees: &'a [TokenTree],
20    full_span: Span,
21    handler: &'e Handler,
22    pub check_double_underscore: bool,
23}
24
25impl<'a, 'e> Parser<'a, 'e> {
26    pub fn new(handler: &'e Handler, token_stream: &'a TokenStream) -> Parser<'a, 'e> {
27        Parser {
28            token_trees: token_stream.token_trees(),
29            full_span: token_stream.span(),
30            handler,
31            check_double_underscore: true,
32        }
33    }
34
35    pub fn emit_error(&mut self, kind: ParseErrorKind) -> ErrorEmitted {
36        let span = match self.token_trees {
37            [token_tree, ..] => token_tree.span(),
38            _ => {
39                // Create a new span that points to _just_ after the last parsed item or 1
40                // character before that if the last parsed item is the last item in the full span.
41                let num_trailing_spaces =
42                    self.full_span.as_str().len() - self.full_span.as_str().trim_end().len();
43                let trim_offset = if num_trailing_spaces == 0 {
44                    1
45                } else {
46                    num_trailing_spaces
47                };
48                Span::new(
49                    self.full_span.src().clone(),
50                    self.full_span.end().saturating_sub(trim_offset),
51                    (self.full_span.end() + 1).saturating_sub(trim_offset),
52                    self.full_span.source_id().cloned(),
53                )
54                .unwrap_or(Span::dummy())
55            }
56        };
57        self.emit_error_with_span(kind, span)
58    }
59
60    pub fn emit_error_with_span(&mut self, kind: ParseErrorKind, span: Span) -> ErrorEmitted {
61        let error = ParseError { span, kind };
62        self.handler.emit_err(CompileError::Parse { error })
63    }
64
65    /// Eats a `P` in its canonical way by peeking.
66    ///
67    /// Unlike [`Parser::peek`], this method advances the parser on success, but not on failure.
68    pub fn take<P: Peek>(&mut self) -> Option<P> {
69        let (value, tokens) = Peeker::with(self.token_trees)?;
70        self.token_trees = tokens;
71        Some(value)
72    }
73
74    /// Tries to peek a `P` in its canonical way.
75    ///
76    /// Either way, on success or failure, the parser is not advanced.
77    pub fn peek<P: Peek>(&self) -> Option<P> {
78        Peeker::with(self.token_trees).map(|(v, _)| v)
79    }
80
81    /// This function will fork the current parse, and call the parsing function.
82    /// If it succeeds it will sync the original parser with the forked one;
83    ///
84    /// If it fails it will return a `Recoverer` together with the `ErrorEmitted`.
85    ///
86    /// This recoverer can be used to put the forked parsed back in track and then
87    /// sync the original parser to allow the parsing to continue.
88    pub fn call_parsing_function_with_recovery<
89        'original,
90        T,
91        F: FnOnce(&mut Parser<'a, '_>) -> ParseResult<T>,
92    >(
93        &'original mut self,
94        parsing_function: F,
95    ) -> Result<T, ParseRecoveryStrategies<'original, 'a, 'e>> {
96        let handler = Handler::default();
97        let mut fork = Parser {
98            token_trees: self.token_trees,
99            full_span: self.full_span.clone(),
100            handler: &handler,
101            check_double_underscore: self.check_double_underscore,
102        };
103
104        match parsing_function(&mut fork) {
105            Ok(result) => {
106                self.token_trees = fork.token_trees;
107                self.handler.append(handler);
108                Ok(result)
109            }
110            Err(error) => {
111                let Parser {
112                    token_trees,
113                    full_span,
114                    ..
115                } = fork;
116                Err(ParseRecoveryStrategies {
117                    original: RefCell::new(self),
118                    handler,
119                    fork_token_trees: token_trees,
120                    fork_full_span: full_span,
121                    error,
122                })
123            }
124        }
125    }
126
127    /// This function will fork the current parse, and try to parse
128    /// T using the fork. If it succeeds it will sync the original parser with the forked one;
129    ///
130    /// If it fails it will return a `Recoverer` together with the `ErrorEmitted`.
131    ///
132    /// This recoverer can be used to put the forked parsed back in track and then
133    /// sync the original parser to allow the parsing to continue.
134    pub fn parse_with_recovery<'original, T: Parse>(
135        &'original mut self,
136    ) -> Result<T, ParseRecoveryStrategies<'original, 'a, 'e>> {
137        self.call_parsing_function_with_recovery(|p| p.parse())
138    }
139
140    /// This function does three things
141    /// 1 - it peeks P;
142    /// 2 - it forks the current parser and tries to parse
143    /// T using this fork. If it succeeds it syncs the original
144    /// parser with the forked one;
145    /// 3 - if it fails it will return a `Recoverer` together with the `ErrorEmitted`.
146    ///
147    /// This recoverer can be used to put the forked parsed back in track and then
148    /// sync the original parser to allow the parsing to continue.
149    pub fn guarded_parse_with_recovery<'original, P: Peek, T: Parse>(
150        &'original mut self,
151    ) -> Result<Option<T>, ParseRecoveryStrategies<'original, 'a, 'e>> {
152        if self.peek::<P>().is_none() {
153            return Ok(None);
154        }
155
156        let handler = Handler::default();
157        let mut fork = Parser {
158            token_trees: self.token_trees,
159            full_span: self.full_span.clone(),
160            handler: &handler,
161            check_double_underscore: self.check_double_underscore,
162        };
163
164        match fork.parse() {
165            Ok(result) => {
166                self.token_trees = fork.token_trees;
167                self.handler.append(handler);
168                Ok(Some(result))
169            }
170            Err(error) => {
171                let Parser {
172                    token_trees,
173                    full_span,
174                    ..
175                } = fork;
176                Err(ParseRecoveryStrategies {
177                    original: RefCell::new(self),
178                    handler,
179                    fork_token_trees: token_trees,
180                    fork_full_span: full_span,
181                    error,
182                })
183            }
184        }
185    }
186
187    /// Parses a `T` in its canonical way.
188    /// Do not advance the parser on failure
189    pub fn try_parse<T: Parse>(&mut self, append_diagnostics: bool) -> ParseResult<T> {
190        let handler = Handler::default();
191        let mut fork = Parser {
192            token_trees: self.token_trees,
193            full_span: self.full_span.clone(),
194            handler: &handler,
195            check_double_underscore: self.check_double_underscore,
196        };
197        let r = match T::parse(&mut fork) {
198            Ok(result) => {
199                self.token_trees = fork.token_trees;
200                Ok(result)
201            }
202            Err(err) => Err(err),
203        };
204        if append_diagnostics {
205            self.handler.append(handler);
206        }
207        r
208    }
209
210    /// This method is useful if `T` does not impl `ParseToEnd`
211    pub fn try_parse_and_check_empty<T: Parse>(
212        mut self,
213        append_diagnostics: bool,
214    ) -> ParseResult<Option<(T, ParserConsumed<'a>)>> {
215        let value = self.try_parse(append_diagnostics)?;
216        match self.check_empty() {
217            Some(consumed) => Ok(Some((value, consumed))),
218            None => Ok(None),
219        }
220    }
221
222    /// Parses a `T` in its canonical way.
223    pub fn parse<T: Parse>(&mut self) -> ParseResult<T> {
224        T::parse(self)
225    }
226
227    /// Parses `T` given that the guard `G` was successfully peeked.
228    ///
229    /// Useful to parse e.g., `$keyword $stuff` as a unit where `$keyword` is your guard.
230    pub fn guarded_parse<G: Peek, T: Parse>(&mut self) -> ParseResult<Option<T>> {
231        self.peek::<G>().map(|_| self.parse()).transpose()
232    }
233
234    pub fn parse_to_end<T: ParseToEnd>(self) -> ParseResult<(T, ParserConsumed<'a>)> {
235        T::parse_to_end(self)
236    }
237
238    /// Do not advance the parser on failure
239    pub fn try_parse_to_end<T: ParseToEnd>(
240        &mut self,
241        append_diagnostics: bool,
242    ) -> ParseResult<(T, ParserConsumed<'a>)> {
243        let handler = Handler::default();
244        let fork = Parser {
245            token_trees: self.token_trees,
246            full_span: self.full_span.clone(),
247            handler: &handler,
248            check_double_underscore: self.check_double_underscore,
249        };
250        let r = T::parse_to_end(fork);
251        if append_diagnostics {
252            self.handler.append(handler);
253        }
254        r
255    }
256
257    pub fn enter_delimited(
258        &mut self,
259        expected_delimiter: Delimiter,
260    ) -> Option<(Parser<'_, '_>, Span)> {
261        match self.token_trees {
262            [TokenTree::Group(Group {
263                delimiter,
264                token_stream,
265                span,
266            }), rest @ ..]
267                if *delimiter == expected_delimiter =>
268            {
269                self.token_trees = rest;
270                let parser = Parser {
271                    token_trees: token_stream.token_trees(),
272                    full_span: token_stream.span(),
273                    handler: self.handler,
274                    check_double_underscore: self.check_double_underscore,
275                };
276                Some((parser, span.clone()))
277            }
278            _ => None,
279        }
280    }
281
282    pub fn is_empty(&self) -> bool {
283        self.token_trees.is_empty()
284    }
285
286    pub fn check_empty(&self) -> Option<ParserConsumed<'a>> {
287        self.is_empty()
288            .then_some(ParserConsumed { _priv: PhantomData })
289    }
290
291    pub fn debug_tokens(&self) -> &[TokenTree] {
292        let len = std::cmp::min(5, self.token_trees.len());
293        &self.token_trees[..len]
294    }
295
296    /// Errors given `Some(PubToken)`.
297    pub fn ban_visibility_qualifier(&mut self, vis: &Option<PubToken>) -> ParseResult<()> {
298        if let Some(token) = vis {
299            return Err(self.emit_error_with_span(
300                ParseErrorKind::UnnecessaryVisibilityQualifier {
301                    visibility: token.ident(),
302                },
303                token.span(),
304            ));
305        }
306        Ok(())
307    }
308
309    pub fn full_span(&self) -> &Span {
310        &self.full_span
311    }
312    /// Consume tokens while its line equals to `line`.
313    ///
314    /// # Warning
315    ///
316    /// To calculate lines the original source code needs to be transversed.
317    pub fn consume_while_line_equals(&mut self, line: usize) {
318        loop {
319            let Some(current_token) = self.token_trees.first() else {
320                break;
321            };
322
323            let current_span = current_token.span();
324            let current_span_line = current_span.start_pos().line_col().line;
325
326            if current_span_line != line {
327                break;
328            } else {
329                self.token_trees = &self.token_trees[1..];
330            }
331        }
332    }
333
334    pub fn has_errors(&self) -> bool {
335        self.handler.has_errors()
336    }
337
338    pub fn has_warnings(&self) -> bool {
339        self.handler.has_warnings()
340    }
341}
342
343pub struct Peeker<'a> {
344    pub token_trees: &'a [TokenTree],
345    num_tokens: &'a mut usize,
346}
347
348impl<'a> Peeker<'a> {
349    /// Peek a `P` in `token_trees`, if any, and return the `P` + the remainder of the token trees.
350    pub fn with<P: Peek>(token_trees: &'a [TokenTree]) -> Option<(P, &'a [TokenTree])> {
351        let mut num_tokens = 0;
352        let peeker = Peeker {
353            token_trees,
354            num_tokens: &mut num_tokens,
355        };
356        let value = P::peek(peeker)?;
357        Some((value, &token_trees[num_tokens..]))
358    }
359
360    pub fn peek_ident(self) -> Result<&'a Ident, Self> {
361        match self.token_trees {
362            [TokenTree::Ident(ident), ..] => {
363                *self.num_tokens = 1;
364                Ok(ident)
365            }
366            _ => Err(self),
367        }
368    }
369
370    pub fn peek_literal(self) -> Result<&'a Literal, Self> {
371        match self.token_trees {
372            [TokenTree::Literal(literal), ..] => {
373                *self.num_tokens = 1;
374                Ok(literal)
375            }
376            _ => Err(self),
377        }
378    }
379
380    pub fn peek_punct_kinds(
381        self,
382        punct_kinds: &[PunctKind],
383        not_followed_by: &[PunctKind],
384    ) -> Result<Span, Self> {
385        let (last_punct_kind, first_punct_kinds) = punct_kinds
386            .split_last()
387            .unwrap_or_else(|| panic!("peek_punct_kinds called with empty slice"));
388        if self.token_trees.len() < punct_kinds.len() {
389            return Err(self);
390        }
391        for (punct_kind, tt) in first_punct_kinds.iter().zip(self.token_trees.iter()) {
392            match tt {
393                TokenTree::Punct(Punct {
394                    kind,
395                    spacing: Spacing::Joint,
396                    ..
397                }) if *kind == *punct_kind => {}
398                _ => return Err(self),
399            }
400        }
401        let span_end = match &self.token_trees[punct_kinds.len() - 1] {
402            TokenTree::Punct(Punct {
403                kind,
404                spacing,
405                span,
406            }) if *kind == *last_punct_kind => match spacing {
407                Spacing::Alone => span,
408                Spacing::Joint => match &self.token_trees.get(punct_kinds.len()) {
409                    Some(TokenTree::Punct(Punct { kind, .. })) => {
410                        if not_followed_by.contains(kind) {
411                            return Err(self);
412                        }
413                        span
414                    }
415                    _ => span,
416                },
417            },
418            _ => return Err(self),
419        };
420        let span_start = match &self.token_trees[0] {
421            TokenTree::Punct(Punct { span, .. }) => span,
422            _ => unreachable!(),
423        };
424        let span = Span::join(span_start.clone(), span_end);
425        *self.num_tokens = punct_kinds.len();
426        Ok(span)
427    }
428
429    pub fn peek_delimiter(self) -> Result<Delimiter, Self> {
430        match self.token_trees {
431            [TokenTree::Group(Group { delimiter, .. }), ..] => {
432                *self.num_tokens = 1;
433                Ok(*delimiter)
434            }
435            _ => Err(self),
436        }
437    }
438
439    pub fn peek_doc_comment(self) -> Result<&'a DocComment, Self> {
440        match self.token_trees {
441            [TokenTree::DocComment(doc_comment), ..] => {
442                *self.num_tokens = 1;
443                Ok(doc_comment)
444            }
445            _ => Err(self),
446        }
447    }
448}
449
450/// This struct is returned by some parser methods that allow
451/// parser recovery.
452///
453/// It implements some standardized recovery strategies or it allows
454/// custom strategies using the `start` method.
455pub struct ParseRecoveryStrategies<'original, 'a, 'e> {
456    original: RefCell<&'original mut Parser<'a, 'e>>,
457    handler: Handler,
458    fork_token_trees: &'a [TokenTree],
459    fork_full_span: Span,
460    error: ErrorEmitted,
461}
462
463impl<'a> ParseRecoveryStrategies<'_, 'a, '_> {
464    /// This strategy consumes everything at the current line and emits the fallback error
465    /// if the forked parser does not contains any error.
466    pub fn recover_at_next_line_with_fallback_error(
467        &self,
468        kind: ParseErrorKind,
469    ) -> (Box<[Span]>, ErrorEmitted) {
470        let line = if self.fork_token_trees.is_empty() {
471            None
472        } else {
473            self.last_consumed_token()
474                .map(|x| x.span())
475                .or_else(|| self.fork_token_trees.first().map(|x| x.span()))
476                .map(|x| x.start_pos().line_col().line)
477        };
478
479        self.start(|p| {
480            if let Some(line) = line {
481                p.consume_while_line_equals(line);
482            }
483            if !p.has_errors() {
484                p.emit_error_with_span(kind, self.diff_span(p));
485            }
486        })
487    }
488
489    /// Starts the parser recovery process calling the callback with the forked parser.
490    /// All the changes to this forked parser will be imposed into the original parser,
491    /// including diagnostics.
492    pub fn start<'this>(
493        &'this self,
494        f: impl FnOnce(&mut Parser<'a, 'this>),
495    ) -> (Box<[Span]>, ErrorEmitted) {
496        let mut p = Parser {
497            token_trees: self.fork_token_trees,
498            full_span: self.fork_full_span.clone(),
499            handler: &self.handler,
500            check_double_underscore: self.original.borrow().check_double_underscore,
501        };
502        f(&mut p);
503        self.finish(p)
504    }
505
506    /// This is the token before the whole tentative parser started.
507    pub fn starting_token(&self) -> &GenericTokenTree<TokenStream> {
508        let original = self.original.borrow();
509        &original.token_trees[0]
510    }
511
512    /// This is the last consumed token of the forked parser. This the token
513    /// immediately before the forked parser head.
514    pub fn last_consumed_token(&self) -> Option<&GenericTokenTree<TokenStream>> {
515        let fork_head_span = self.fork_token_trees.first()?.span();
516
517        // find the last token consumed by the fork
518        let original = self.original.borrow();
519        let fork_pos = original
520            .token_trees
521            .iter()
522            .position(|x| x.span() == fork_head_span)?;
523
524        let before_fork_pos = fork_pos.checked_sub(1)?;
525        original.token_trees.get(before_fork_pos)
526    }
527
528    /// This return a span encopassing all tokens that were consumed by the `p` since the start
529    /// of the tentative parsing
530    ///
531    /// This is useful to show one single error for all the consumed tokens.
532    pub fn diff_span<'this>(&self, p: &Parser<'a, 'this>) -> Span {
533        let original = self.original.borrow_mut();
534
535        // collect all tokens trees that were consumed by the fork
536        let qty = if let Some(first_fork_tt) = p.token_trees.first() {
537            original
538                .token_trees
539                .iter()
540                .position(|tt| tt.span() == first_fork_tt.span())
541                .expect("not finding fork head")
542        } else {
543            original.token_trees.len()
544        };
545
546        let garbage: Vec<_> = original
547            .token_trees
548            .iter()
549            .take(qty)
550            .map(|x| x.span())
551            .collect();
552
553        Span::join_all(garbage)
554    }
555
556    fn finish(&self, p: Parser<'a, '_>) -> (Box<[Span]>, ErrorEmitted) {
557        let mut original = self.original.borrow_mut();
558
559        // collect all tokens trees that were consumed by the fork
560        let qty = if let Some(first_fork_tt) = p.token_trees.first() {
561            original
562                .token_trees
563                .iter()
564                .position(|tt| tt.span() == first_fork_tt.span())
565                .expect("not finding fork head")
566        } else {
567            original.token_trees.len()
568        };
569
570        let garbage: Vec<_> = original
571            .token_trees
572            .iter()
573            .take(qty)
574            .map(|x| x.span())
575            .collect();
576
577        original.token_trees = p.token_trees;
578        original.handler.append(self.handler.clone());
579
580        (garbage.into_boxed_slice(), self.error)
581    }
582}
583
584pub struct ParserConsumed<'a> {
585    _priv: PhantomData<fn(&'a ()) -> &'a ()>,
586}
587
588pub type ParseResult<T> = Result<T, ErrorEmitted>;