aboutsummaryrefslogtreecommitdiff
path: root/crates
diff options
context:
space:
mode:
Diffstat (limited to 'crates')
-rw-r--r--crates/ra_mbe/src/lib.rs8
-rw-r--r--crates/ra_mbe/src/mbe_expander.rs4
-rw-r--r--crates/ra_mbe/src/mbe_parser.rs2
-rw-r--r--crates/ra_mbe/src/syntax_bridge.rs46
-rw-r--r--crates/ra_tt/src/lib.rs18
5 files changed, 65 insertions, 13 deletions
diff --git a/crates/ra_mbe/src/lib.rs b/crates/ra_mbe/src/lib.rs
index b9f555ef6..ec2fd1eb5 100644
--- a/crates/ra_mbe/src/lib.rs
+++ b/crates/ra_mbe/src/lib.rs
@@ -144,8 +144,8 @@ impl_froms!(TokenTree: Leaf, Subtree);
144 let macro_invocation = 144 let macro_invocation =
145 source_file.syntax().descendants().find_map(ast::MacroCall::cast).unwrap(); 145 source_file.syntax().descendants().find_map(ast::MacroCall::cast).unwrap();
146 146
147 let definition_tt = ast_to_token_tree(macro_definition.token_tree().unwrap()).unwrap(); 147 let (definition_tt, _) = ast_to_token_tree(macro_definition.token_tree().unwrap()).unwrap();
148 let invocation_tt = ast_to_token_tree(macro_invocation.token_tree().unwrap()).unwrap(); 148 let (invocation_tt, _) = ast_to_token_tree(macro_invocation.token_tree().unwrap()).unwrap();
149 let rules = crate::MacroRules::parse(&definition_tt).unwrap(); 149 let rules = crate::MacroRules::parse(&definition_tt).unwrap();
150 let expansion = rules.expand(&invocation_tt).unwrap(); 150 let expansion = rules.expand(&invocation_tt).unwrap();
151 assert_eq!( 151 assert_eq!(
@@ -160,7 +160,7 @@ impl_froms!(TokenTree: Leaf, Subtree);
160 let macro_definition = 160 let macro_definition =
161 source_file.syntax().descendants().find_map(ast::MacroCall::cast).unwrap(); 161 source_file.syntax().descendants().find_map(ast::MacroCall::cast).unwrap();
162 162
163 let definition_tt = ast_to_token_tree(macro_definition.token_tree().unwrap()).unwrap(); 163 let (definition_tt, _) = ast_to_token_tree(macro_definition.token_tree().unwrap()).unwrap();
164 crate::MacroRules::parse(&definition_tt).unwrap() 164 crate::MacroRules::parse(&definition_tt).unwrap()
165 } 165 }
166 166
@@ -169,7 +169,7 @@ impl_froms!(TokenTree: Leaf, Subtree);
169 let macro_invocation = 169 let macro_invocation =
170 source_file.syntax().descendants().find_map(ast::MacroCall::cast).unwrap(); 170 source_file.syntax().descendants().find_map(ast::MacroCall::cast).unwrap();
171 171
172 let invocation_tt = ast_to_token_tree(macro_invocation.token_tree().unwrap()).unwrap(); 172 let (invocation_tt, _) = ast_to_token_tree(macro_invocation.token_tree().unwrap()).unwrap();
173 173
174 let expaned = rules.expand(&invocation_tt).unwrap(); 174 let expaned = rules.expand(&invocation_tt).unwrap();
175 assert_eq!(expaned.to_string(), expansion); 175 assert_eq!(expaned.to_string(), expansion);
diff --git a/crates/ra_mbe/src/mbe_expander.rs b/crates/ra_mbe/src/mbe_expander.rs
index eec713d9c..f6177f078 100644
--- a/crates/ra_mbe/src/mbe_expander.rs
+++ b/crates/ra_mbe/src/mbe_expander.rs
@@ -3,6 +3,7 @@
3/// `tt::TokenTree` for the result of the expansion. 3/// `tt::TokenTree` for the result of the expansion.
4use rustc_hash::FxHashMap; 4use rustc_hash::FxHashMap;
5use ra_syntax::SmolStr; 5use ra_syntax::SmolStr;
6use tt::TokenId;
6 7
7use crate::tt_cursor::TtCursor; 8use crate::tt_cursor::TtCursor;
8 9
@@ -185,7 +186,8 @@ fn expand_tt(
185 } 186 }
186 crate::TokenTree::Leaf(leaf) => match leaf { 187 crate::TokenTree::Leaf(leaf) => match leaf {
187 crate::Leaf::Ident(ident) => { 188 crate::Leaf::Ident(ident) => {
188 tt::Leaf::from(tt::Ident { text: ident.text.clone() }).into() 189 tt::Leaf::from(tt::Ident { text: ident.text.clone(), id: TokenId::unspecified() })
190 .into()
189 } 191 }
190 crate::Leaf::Punct(punct) => tt::Leaf::from(punct.clone()).into(), 192 crate::Leaf::Punct(punct) => tt::Leaf::from(punct.clone()).into(),
191 crate::Leaf::Var(v) => bindings.get(&v.text, nesting)?.clone(), 193 crate::Leaf::Var(v) => bindings.get(&v.text, nesting)?.clone(),
diff --git a/crates/ra_mbe/src/mbe_parser.rs b/crates/ra_mbe/src/mbe_parser.rs
index 60e566ed2..58e2533f1 100644
--- a/crates/ra_mbe/src/mbe_parser.rs
+++ b/crates/ra_mbe/src/mbe_parser.rs
@@ -41,7 +41,7 @@ fn parse_subtree(tt: &tt::Subtree) -> Option<crate::Subtree> {
41 } 41 }
42 } 42 }
43 tt::Leaf::Punct(punct) => crate::Leaf::from(*punct).into(), 43 tt::Leaf::Punct(punct) => crate::Leaf::from(*punct).into(),
44 tt::Leaf::Ident(tt::Ident { text }) => { 44 tt::Leaf::Ident(tt::Ident { text, id: _ }) => {
45 crate::Leaf::from(crate::Ident { text: text.clone() }).into() 45 crate::Leaf::from(crate::Ident { text: text.clone() }).into()
46 } 46 }
47 tt::Leaf::Literal(tt::Literal { text }) => { 47 tt::Leaf::Literal(tt::Literal { text }) => {
diff --git a/crates/ra_mbe/src/syntax_bridge.rs b/crates/ra_mbe/src/syntax_bridge.rs
index 9a2eceaba..848c785f8 100644
--- a/crates/ra_mbe/src/syntax_bridge.rs
+++ b/crates/ra_mbe/src/syntax_bridge.rs
@@ -1,10 +1,42 @@
1use ra_syntax::{ast, AstNode, SyntaxNode, SyntaxKind::*}; 1use ra_syntax::{
2 AstNode, SyntaxNode, TextRange,
3 ast, SyntaxKind::*, TextUnit
4};
2 5
3pub fn ast_to_token_tree(ast: &ast::TokenTree) -> Option<tt::Subtree> { 6/// Maps `tt::TokenId` to the relative range of the original token.
4 convert_tt(ast.syntax()) 7#[derive(Default)]
8pub struct TokenMap {
9 /// Maps `tt::TokenId` to the *relative* source range.
10 toknes: Vec<TextRange>,
5} 11}
6 12
7fn convert_tt(tt: &SyntaxNode) -> Option<tt::Subtree> { 13/// Convert the syntax tree (what user has written) to a `TokenTree` (what macro
14/// will consume).
15pub fn ast_to_token_tree(ast: &ast::TokenTree) -> Option<(tt::Subtree, TokenMap)> {
16 let mut token_map = TokenMap::default();
17 let node = ast.syntax();
18 let tt = convert_tt(&mut token_map, node.range().start(), node)?;
19 Some((tt, token_map))
20}
21
22impl TokenMap {
23 pub fn relative_range_of(&self, tt: tt::TokenId) -> Option<TextRange> {
24 let idx = tt.0 as usize;
25 self.toknes.get(idx).map(|&it| it)
26 }
27
28 fn alloc(&mut self, relative_range: TextRange) -> tt::TokenId {
29 let id = self.toknes.len();
30 self.toknes.push(relative_range);
31 tt::TokenId(id as u32)
32 }
33}
34
35fn convert_tt(
36 token_map: &mut TokenMap,
37 global_offset: TextUnit,
38 tt: &SyntaxNode,
39) -> Option<tt::Subtree> {
8 let first_child = tt.first_child()?; 40 let first_child = tt.first_child()?;
9 let last_child = tt.last_child()?; 41 let last_child = tt.last_child()?;
10 let delimiter = match (first_child.kind(), last_child.kind()) { 42 let delimiter = match (first_child.kind(), last_child.kind()) {
@@ -34,10 +66,12 @@ fn convert_tt(tt: &SyntaxNode) -> Option<tt::Subtree> {
34 } 66 }
35 } else { 67 } else {
36 let child: tt::TokenTree = if child.kind() == TOKEN_TREE { 68 let child: tt::TokenTree = if child.kind() == TOKEN_TREE {
37 convert_tt(child)?.into() 69 convert_tt(token_map, global_offset, child)?.into()
38 } else if child.kind().is_keyword() || child.kind() == IDENT { 70 } else if child.kind().is_keyword() || child.kind() == IDENT {
71 let relative_range = child.range() - global_offset;
72 let id = token_map.alloc(relative_range);
39 let text = child.leaf_text().unwrap().clone(); 73 let text = child.leaf_text().unwrap().clone();
40 tt::Leaf::from(tt::Ident { text }).into() 74 tt::Leaf::from(tt::Ident { text, id }).into()
41 } else if child.kind().is_literal() { 75 } else if child.kind().is_literal() {
42 tt::Leaf::from(tt::Literal { text: child.leaf_text().unwrap().clone() }).into() 76 tt::Leaf::from(tt::Literal { text: child.leaf_text().unwrap().clone() }).into()
43 } else { 77 } else {
diff --git a/crates/ra_tt/src/lib.rs b/crates/ra_tt/src/lib.rs
index df31f72f3..c1f37b889 100644
--- a/crates/ra_tt/src/lib.rs
+++ b/crates/ra_tt/src/lib.rs
@@ -1,4 +1,4 @@
1/// `tt` crate defines a `TokenTree` datastructure: this is the interface (both 1/// `tt` crate defines a `TokenTree` data structure: this is the interface (both
2/// input and output) of macros. It closely mirrors `proc_macro` crate's 2/// input and output) of macros. It closely mirrors `proc_macro` crate's
3/// `TokenTree`. 3/// `TokenTree`.
4 4
@@ -18,6 +18,21 @@ use std::fmt;
18 18
19use smol_str::SmolStr; 19use smol_str::SmolStr;
20 20
21/// Represents identity of the token.
22///
23/// For hygiene purposes, we need to track which expanded tokens originated from
24/// which source tokens. We do it by assigning an distinct identity to each
25/// source token and making sure that identities are preserved during macro
26/// expansion.
27#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
28pub struct TokenId(pub u32);
29
30impl TokenId {
31 pub const fn unspecified() -> TokenId {
32 TokenId(!0)
33 }
34}
35
21#[derive(Debug, Clone)] 36#[derive(Debug, Clone)]
22pub enum TokenTree { 37pub enum TokenTree {
23 Leaf(Leaf), 38 Leaf(Leaf),
@@ -67,6 +82,7 @@ pub enum Spacing {
67#[derive(Debug, Clone)] 82#[derive(Debug, Clone)]
68pub struct Ident { 83pub struct Ident {
69 pub text: SmolStr, 84 pub text: SmolStr,
85 pub id: TokenId,
70} 86}
71 87
72impl fmt::Display for TokenTree { 88impl fmt::Display for TokenTree {