diff options
Diffstat (limited to 'crates')
-rw-r--r-- | crates/ra_mbe/src/lib.rs | 8 | ||||
-rw-r--r-- | crates/ra_mbe/src/mbe_expander.rs | 4 | ||||
-rw-r--r-- | crates/ra_mbe/src/mbe_parser.rs | 2 | ||||
-rw-r--r-- | crates/ra_mbe/src/syntax_bridge.rs | 46 | ||||
-rw-r--r-- | crates/ra_tt/src/lib.rs | 18 |
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. |
4 | use rustc_hash::FxHashMap; | 4 | use rustc_hash::FxHashMap; |
5 | use ra_syntax::SmolStr; | 5 | use ra_syntax::SmolStr; |
6 | use tt::TokenId; | ||
6 | 7 | ||
7 | use crate::tt_cursor::TtCursor; | 8 | use 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 @@ | |||
1 | use ra_syntax::{ast, AstNode, SyntaxNode, SyntaxKind::*}; | 1 | use ra_syntax::{ |
2 | AstNode, SyntaxNode, TextRange, | ||
3 | ast, SyntaxKind::*, TextUnit | ||
4 | }; | ||
2 | 5 | ||
3 | pub 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)] |
8 | pub struct TokenMap { | ||
9 | /// Maps `tt::TokenId` to the *relative* source range. | ||
10 | toknes: Vec<TextRange>, | ||
5 | } | 11 | } |
6 | 12 | ||
7 | fn convert_tt(tt: &SyntaxNode) -> Option<tt::Subtree> { | 13 | /// Convert the syntax tree (what user has written) to a `TokenTree` (what macro |
14 | /// will consume). | ||
15 | pub 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 | |||
22 | impl 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 | |||
35 | fn 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 | ||
19 | use smol_str::SmolStr; | 19 | use 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)] | ||
28 | pub struct TokenId(pub u32); | ||
29 | |||
30 | impl TokenId { | ||
31 | pub const fn unspecified() -> TokenId { | ||
32 | TokenId(!0) | ||
33 | } | ||
34 | } | ||
35 | |||
21 | #[derive(Debug, Clone)] | 36 | #[derive(Debug, Clone)] |
22 | pub enum TokenTree { | 37 | pub enum TokenTree { |
23 | Leaf(Leaf), | 38 | Leaf(Leaf), |
@@ -67,6 +82,7 @@ pub enum Spacing { | |||
67 | #[derive(Debug, Clone)] | 82 | #[derive(Debug, Clone)] |
68 | pub struct Ident { | 83 | pub struct Ident { |
69 | pub text: SmolStr, | 84 | pub text: SmolStr, |
85 | pub id: TokenId, | ||
70 | } | 86 | } |
71 | 87 | ||
72 | impl fmt::Display for TokenTree { | 88 | impl fmt::Display for TokenTree { |