mirror of
				https://github.com/rust-lang/rust-analyzer.git
				synced 2025-10-31 03:54:42 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			197 lines
		
	
	
	
		
			6.2 KiB
		
	
	
	
		
			Rust
		
	
	
	
	
	
			
		
		
	
	
			197 lines
		
	
	
	
		
			6.2 KiB
		
	
	
	
		
			Rust
		
	
	
	
	
	
| //! The Rust parser.
 | |
| //!
 | |
| //! NOTE: The crate is undergoing refactors, don't believe everything the docs
 | |
| //! say :-)
 | |
| //!
 | |
| //! The parser doesn't know about concrete representation of tokens and syntax
 | |
| //! trees. Abstract [`TokenSource`] and [`TreeSink`] traits are used instead. As
 | |
| //! a consequence, this crate does not contain a lexer.
 | |
| //!
 | |
| //! The [`Parser`] struct from the [`parser`] module is a cursor into the
 | |
| //! sequence of tokens.  Parsing routines use [`Parser`] to inspect current
 | |
| //! state and advance the parsing.
 | |
| //!
 | |
| //! The actual parsing happens in the [`grammar`] module.
 | |
| //!
 | |
| //! Tests for this crate live in the `syntax` crate.
 | |
| //!
 | |
| //! [`Parser`]: crate::parser::Parser
 | |
| 
 | |
| #![allow(rustdoc::private_intra_doc_links)]
 | |
| #![cfg_attr(feature = "in-rust-tree", feature(rustc_private))]
 | |
| 
 | |
| #[cfg(not(feature = "in-rust-tree"))]
 | |
| extern crate ra_ap_rustc_lexer as rustc_lexer;
 | |
| #[cfg(feature = "in-rust-tree")]
 | |
| extern crate rustc_lexer;
 | |
| 
 | |
| mod event;
 | |
| mod grammar;
 | |
| mod input;
 | |
| mod lexed_str;
 | |
| mod output;
 | |
| mod parser;
 | |
| mod shortcuts;
 | |
| mod syntax_kind;
 | |
| mod token_set;
 | |
| 
 | |
| pub use T_ as T;
 | |
| 
 | |
| #[cfg(test)]
 | |
| mod tests;
 | |
| 
 | |
| pub(crate) use token_set::TokenSet;
 | |
| 
 | |
| pub use edition::Edition;
 | |
| 
 | |
| pub use crate::{
 | |
|     input::Input,
 | |
|     lexed_str::LexedStr,
 | |
|     output::{Output, Step},
 | |
|     shortcuts::StrStep,
 | |
|     syntax_kind::SyntaxKind,
 | |
| };
 | |
| 
 | |
| /// Parse the whole of the input as a given syntactic construct.
 | |
| ///
 | |
| /// This covers two main use-cases:
 | |
| ///
 | |
| ///   * Parsing a Rust file.
 | |
| ///   * Parsing a result of macro expansion.
 | |
| ///
 | |
| /// That is, for something like
 | |
| ///
 | |
| /// ```ignore
 | |
| /// quick_check! {
 | |
| ///    fn prop() {}
 | |
| /// }
 | |
| /// ```
 | |
| ///
 | |
| /// the input to the macro will be parsed with [`PrefixEntryPoint::Item`], and
 | |
| /// the result will be [`TopEntryPoint::MacroItems`].
 | |
| ///
 | |
| /// [`TopEntryPoint::parse`] makes a guarantee that
 | |
| ///   * all input is consumed
 | |
| ///   * the result is a valid tree (there's one root node)
 | |
| #[derive(Debug)]
 | |
| pub enum TopEntryPoint {
 | |
|     SourceFile,
 | |
|     MacroStmts,
 | |
|     MacroItems,
 | |
|     Pattern,
 | |
|     Type,
 | |
|     Expr,
 | |
|     /// Edge case -- macros generally don't expand to attributes, with the
 | |
|     /// exception of `cfg_attr` which does!
 | |
|     MetaItem,
 | |
| }
 | |
| 
 | |
| impl TopEntryPoint {
 | |
|     pub fn parse(&self, input: &Input, edition: Edition) -> Output {
 | |
|         let _p = tracing::info_span!("TopEntryPoint::parse", ?self).entered();
 | |
|         let entry_point: fn(&'_ mut parser::Parser<'_>) = match self {
 | |
|             TopEntryPoint::SourceFile => grammar::entry::top::source_file,
 | |
|             TopEntryPoint::MacroStmts => grammar::entry::top::macro_stmts,
 | |
|             TopEntryPoint::MacroItems => grammar::entry::top::macro_items,
 | |
|             TopEntryPoint::Pattern => grammar::entry::top::pattern,
 | |
|             TopEntryPoint::Type => grammar::entry::top::type_,
 | |
|             TopEntryPoint::Expr => grammar::entry::top::expr,
 | |
|             TopEntryPoint::MetaItem => grammar::entry::top::meta_item,
 | |
|         };
 | |
|         let mut p = parser::Parser::new(input, edition);
 | |
|         entry_point(&mut p);
 | |
|         let events = p.finish();
 | |
|         let res = event::process(events);
 | |
| 
 | |
|         if cfg!(debug_assertions) {
 | |
|             let mut depth = 0;
 | |
|             let mut first = true;
 | |
|             for step in res.iter() {
 | |
|                 assert!(depth > 0 || first);
 | |
|                 first = false;
 | |
|                 match step {
 | |
|                     Step::Enter { .. } => depth += 1,
 | |
|                     Step::Exit => depth -= 1,
 | |
|                     Step::FloatSplit { ends_in_dot: has_pseudo_dot } => {
 | |
|                         depth -= 1 + !has_pseudo_dot as usize
 | |
|                     }
 | |
|                     Step::Token { .. } | Step::Error { .. } => (),
 | |
|                 }
 | |
|             }
 | |
|             assert!(!first, "no tree at all");
 | |
|             assert_eq!(depth, 0, "unbalanced tree");
 | |
|         }
 | |
| 
 | |
|         res
 | |
|     }
 | |
| }
 | |
| 
 | |
| /// Parse a prefix of the input as a given syntactic construct.
 | |
| ///
 | |
| /// This is used by macro-by-example parser to implement things like `$i:item`
 | |
| /// and the naming of variants follows the naming of macro fragments.
 | |
| ///
 | |
| /// Note that this is generally non-optional -- the result is intentionally not
 | |
| /// `Option<Output>`. The way MBE work, by the time we *try* to parse `$e:expr`
 | |
| /// we already commit to expression. In other words, this API by design can't be
 | |
| /// used to implement "rollback and try another alternative" logic.
 | |
| #[derive(Debug)]
 | |
| pub enum PrefixEntryPoint {
 | |
|     Vis,
 | |
|     Block,
 | |
|     Stmt,
 | |
|     Pat,
 | |
|     PatTop,
 | |
|     Ty,
 | |
|     Expr,
 | |
|     Path,
 | |
|     Item,
 | |
|     MetaItem,
 | |
| }
 | |
| 
 | |
| impl PrefixEntryPoint {
 | |
|     pub fn parse(&self, input: &Input, edition: Edition) -> Output {
 | |
|         let entry_point: fn(&'_ mut parser::Parser<'_>) = match self {
 | |
|             PrefixEntryPoint::Vis => grammar::entry::prefix::vis,
 | |
|             PrefixEntryPoint::Block => grammar::entry::prefix::block,
 | |
|             PrefixEntryPoint::Stmt => grammar::entry::prefix::stmt,
 | |
|             PrefixEntryPoint::Pat => grammar::entry::prefix::pat,
 | |
|             PrefixEntryPoint::PatTop => grammar::entry::prefix::pat_top,
 | |
|             PrefixEntryPoint::Ty => grammar::entry::prefix::ty,
 | |
|             PrefixEntryPoint::Expr => grammar::entry::prefix::expr,
 | |
|             PrefixEntryPoint::Path => grammar::entry::prefix::path,
 | |
|             PrefixEntryPoint::Item => grammar::entry::prefix::item,
 | |
|             PrefixEntryPoint::MetaItem => grammar::entry::prefix::meta_item,
 | |
|         };
 | |
|         let mut p = parser::Parser::new(input, edition);
 | |
|         entry_point(&mut p);
 | |
|         let events = p.finish();
 | |
|         event::process(events)
 | |
|     }
 | |
| }
 | |
| 
 | |
| /// A parsing function for a specific braced-block.
 | |
| pub struct Reparser(fn(&mut parser::Parser<'_>));
 | |
| 
 | |
| impl Reparser {
 | |
|     /// If the node is a braced block, return the corresponding `Reparser`.
 | |
|     pub fn for_node(
 | |
|         node: SyntaxKind,
 | |
|         first_child: Option<SyntaxKind>,
 | |
|         parent: Option<SyntaxKind>,
 | |
|     ) -> Option<Reparser> {
 | |
|         grammar::reparser(node, first_child, parent).map(Reparser)
 | |
|     }
 | |
| 
 | |
|     /// Re-parse given tokens using this `Reparser`.
 | |
|     ///
 | |
|     /// Tokens must start with `{`, end with `}` and form a valid brace
 | |
|     /// sequence.
 | |
|     pub fn parse(self, tokens: &Input, edition: Edition) -> Output {
 | |
|         let Reparser(r) = self;
 | |
|         let mut p = parser::Parser::new(tokens, edition);
 | |
|         r(&mut p);
 | |
|         let events = p.finish();
 | |
|         event::process(events)
 | |
|     }
 | |
| }
 | 
