From 8eac450f41c6d94215f5d8c02235cd5917abaa69 Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Sat, 23 Feb 2019 17:21:56 +0300 Subject: implement tt -> ast --- crates/ra_mbe/src/lib.rs | 2 +- crates/ra_mbe/src/syntax_bridge.rs | 58 +++++++++++++++++++++++++++++++++++--- 2 files changed, 55 insertions(+), 5 deletions(-) diff --git a/crates/ra_mbe/src/lib.rs b/crates/ra_mbe/src/lib.rs index cdca3cafb..768f335fa 100644 --- a/crates/ra_mbe/src/lib.rs +++ b/crates/ra_mbe/src/lib.rs @@ -24,7 +24,7 @@ use ra_syntax::SmolStr; pub use tt::{Delimiter, Punct}; -pub use crate::syntax_bridge::ast_to_token_tree; +pub use crate::syntax_bridge::{ast_to_token_tree, token_tree_to_ast_item_list}; /// This struct contains AST for a single `macro_rules` definition. What might /// be very confusing is that AST has almost exactly the same shape as diff --git a/crates/ra_mbe/src/syntax_bridge.rs b/crates/ra_mbe/src/syntax_bridge.rs index 24a043175..521b96d68 100644 --- a/crates/ra_mbe/src/syntax_bridge.rs +++ b/crates/ra_mbe/src/syntax_bridge.rs @@ -1,6 +1,6 @@ -use ra_parser::TokenSource; +use ra_parser::{TokenSource, TreeSink, ParseError}; use ra_syntax::{ - AstNode, SyntaxNode, TextRange, SyntaxKind, SmolStr, + AstNode, SyntaxNode, TextRange, SyntaxKind, SmolStr, SyntaxTreeBuilder, TreeArc, ast, SyntaxKind::*, TextUnit }; @@ -21,8 +21,12 @@ pub fn ast_to_token_tree(ast: &ast::TokenTree) -> Option<(tt::Subtree, TokenMap) } /// Parses the token tree (result of macro expansion) as a sequence of items -pub fn token_tree_to_ast_item_list(tt: &tt::Subtree) -> ast::SourceFile { - unimplemented!() +pub fn token_tree_to_ast_item_list(tt: &tt::Subtree) -> TreeArc { + let token_source = TtTokenSource::new(tt); + let mut tree_sink = TtTreeSink::new(&token_source.tokens); + ra_parser::parse(&token_source, &mut tree_sink); + let syntax = tree_sink.inner.finish(); + ast::SourceFile::cast(&syntax).unwrap().to_owned() } impl TokenMap { @@ -166,3 +170,49 @@ impl TokenSource for TtTokenSource { self.tokens[pos].text == *kw } } + +#[derive(Default)] +struct TtTreeSink<'a> { + buf: String, + tokens: &'a [Tok], + text_pos: TextUnit, + token_pos: usize, + inner: SyntaxTreeBuilder, +} + +impl<'a> TtTreeSink<'a> { + fn new(tokens: &'a [Tok]) -> TtTreeSink { + TtTreeSink { + buf: String::new(), + tokens, + text_pos: 0.into(), + token_pos: 0, + inner: SyntaxTreeBuilder::default(), + } + } +} + +impl<'a> TreeSink for TtTreeSink<'a> { + fn leaf(&mut self, kind: SyntaxKind, n_tokens: u8) { + for _ in 0..n_tokens { + self.buf += self.tokens[self.token_pos].text.as_str(); + self.token_pos += 1; + } + self.text_pos += TextUnit::of_str(&self.buf); + let text = SmolStr::new(self.buf.as_str()); + self.buf.clear(); + self.inner.leaf(kind, text) + } + + fn start_branch(&mut self, kind: SyntaxKind) { + self.inner.start_branch(kind); + } + + fn finish_branch(&mut self) { + self.inner.finish_branch(); + } + + fn error(&mut self, error: ParseError) { + self.inner.error(error, self.text_pos) + } +} -- cgit v1.2.3