aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAleksey Kladov <[email protected]>2019-01-31 15:51:17 +0000
committerAleksey Kladov <[email protected]>2019-01-31 20:23:30 +0000
commitad80a0c551458de7d27a98d182d7f559de04f291 (patch)
tree20a3e85a30a45365fe31360cb57b4f53a17b9a28
parent59347388541388347e86de9718bd69994c113203 (diff)
preserve token spacing
-rw-r--r--Cargo.lock1
-rw-r--r--crates/ra_hir/src/macros.rs44
-rw-r--r--crates/ra_macros/Cargo.toml1
-rw-r--r--crates/ra_macros/src/mbe.rs2
-rw-r--r--crates/ra_macros/src/mbe_parser.rs8
-rw-r--r--crates/ra_macros/src/tt.rs31
-rw-r--r--crates/ra_macros/src/tt_cursor.rs2
7 files changed, 59 insertions, 30 deletions
diff --git a/Cargo.lock b/Cargo.lock
index a9bc80c40..b48721622 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -1022,7 +1022,6 @@ dependencies = [
1022name = "ra_macros" 1022name = "ra_macros"
1023version = "0.1.0" 1023version = "0.1.0"
1024dependencies = [ 1024dependencies = [
1025 "join_to_string 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
1026 "rustc-hash 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", 1025 "rustc-hash 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
1027 "smol_str 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", 1026 "smol_str 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)",
1028] 1027]
diff --git a/crates/ra_hir/src/macros.rs b/crates/ra_hir/src/macros.rs
index 059543bf2..e6ba8c08f 100644
--- a/crates/ra_hir/src/macros.rs
+++ b/crates/ra_hir/src/macros.rs
@@ -218,14 +218,28 @@ fn convert_tt(tt: &SyntaxNode) -> Option<tt::Subtree> {
218 continue; 218 continue;
219 } 219 }
220 if child.kind().is_punct() { 220 if child.kind().is_punct() {
221 let leaves = child 221 let mut prev = None;
222 .leaf_text() 222 for char in child.leaf_text().unwrap().chars() {
223 .unwrap() 223 if let Some(char) = prev {
224 .chars() 224 token_trees.push(
225 .map(|char| tt::Punct { char }) 225 tt::Leaf::from(tt::Punct {
226 .map(tt::Leaf::from) 226 char,
227 .map(tt::TokenTree::from); 227 spacing: tt::Spacing::Joint,
228 token_trees.extend(leaves); 228 })
229 .into(),
230 );
231 }
232 prev = Some(char)
233 }
234 if let Some(char) = prev {
235 token_trees.push(
236 tt::Leaf::from(tt::Punct {
237 char,
238 spacing: tt::Spacing::Alone,
239 })
240 .into(),
241 );
242 }
229 } else { 243 } else {
230 let child: tt::TokenTree = if child.kind() == TOKEN_TREE { 244 let child: tt::TokenTree = if child.kind() == TOKEN_TREE {
231 convert_tt(child)?.into() 245 convert_tt(child)?.into()
@@ -254,7 +268,7 @@ fn convert_tt(tt: &SyntaxNode) -> Option<tt::Subtree> {
254 268
255#[test] 269#[test]
256fn test_convert_tt() { 270fn test_convert_tt() {
257 let macro_defenition = r#" 271 let macro_definition = r#"
258macro_rules! impl_froms { 272macro_rules! impl_froms {
259 ($e:ident: $($v:ident),*) => { 273 ($e:ident: $($v:ident),*) => {
260 $( 274 $(
@@ -272,8 +286,8 @@ macro_rules! impl_froms {
272impl_froms!(TokenTree: Leaf, Subtree); 286impl_froms!(TokenTree: Leaf, Subtree);
273"#; 287"#;
274 288
275 let source_file = ast::SourceFile::parse(macro_defenition); 289 let source_file = ast::SourceFile::parse(macro_definition);
276 let macro_defenition = source_file 290 let macro_definition = source_file
277 .syntax() 291 .syntax()
278 .descendants() 292 .descendants()
279 .find_map(ast::MacroCall::cast) 293 .find_map(ast::MacroCall::cast)
@@ -286,13 +300,13 @@ impl_froms!(TokenTree: Leaf, Subtree);
286 .find_map(ast::MacroCall::cast) 300 .find_map(ast::MacroCall::cast)
287 .unwrap(); 301 .unwrap();
288 302
289 let defenition_tt = macro_call_to_tt(macro_defenition).unwrap(); 303 let definition_tt = macro_call_to_tt(macro_definition).unwrap();
290 let invocation_tt = macro_call_to_tt(macro_invocation).unwrap(); 304 let invocation_tt = macro_call_to_tt(macro_invocation).unwrap();
291 let mbe = mbe::parse(&defenition_tt).unwrap(); 305 let mbe = mbe::parse(&definition_tt).unwrap();
292 let expansion = mbe::exapnd(&mbe, &invocation_tt).unwrap(); 306 let expansion = mbe::exapnd(&mbe, &invocation_tt).unwrap();
293 assert_eq!( 307 assert_eq!(
294 expansion.to_string(), 308 expansion.to_string(),
295 "{(impl From < Leaf > for TokenTree {fn from (it : Leaf) - > TokenTree {TokenTree : : Leaf (it)}}) \ 309 "{(impl From < Leaf > for TokenTree {fn from (it : Leaf) -> TokenTree {TokenTree :: Leaf (it)}}) \
296 (impl From < Subtree > for TokenTree {fn from (it : Subtree) - > TokenTree {TokenTree : : Subtree (it)}})}" 310 (impl From < Subtree > for TokenTree {fn from (it : Subtree) -> TokenTree {TokenTree :: Subtree (it)}})}"
297 ) 311 )
298} 312}
diff --git a/crates/ra_macros/Cargo.toml b/crates/ra_macros/Cargo.toml
index 1c9cc9e92..7d3cb055c 100644
--- a/crates/ra_macros/Cargo.toml
+++ b/crates/ra_macros/Cargo.toml
@@ -7,4 +7,3 @@ authors = ["Aleksey Kladov <[email protected]>"]
7[dependencies] 7[dependencies]
8rustc-hash = "1.0.0" 8rustc-hash = "1.0.0"
9smol_str = "0.1.9" 9smol_str = "0.1.9"
10join_to_string = "0.1.3"
diff --git a/crates/ra_macros/src/mbe.rs b/crates/ra_macros/src/mbe.rs
index ac76d64e4..d4106a41c 100644
--- a/crates/ra_macros/src/mbe.rs
+++ b/crates/ra_macros/src/mbe.rs
@@ -45,7 +45,7 @@ pub(crate) struct Subtree {
45pub(crate) struct Repeat { 45pub(crate) struct Repeat {
46 pub(crate) subtree: Subtree, 46 pub(crate) subtree: Subtree,
47 pub(crate) kind: RepeatKind, 47 pub(crate) kind: RepeatKind,
48 pub(crate) separator: Option<Punct>, 48 pub(crate) separator: Option<char>,
49} 49}
50 50
51#[derive(Debug)] 51#[derive(Debug)]
diff --git a/crates/ra_macros/src/mbe_parser.rs b/crates/ra_macros/src/mbe_parser.rs
index 279ab2f25..483594590 100644
--- a/crates/ra_macros/src/mbe_parser.rs
+++ b/crates/ra_macros/src/mbe_parser.rs
@@ -28,16 +28,14 @@ fn parse_subtree(tt: &tt::Subtree) -> Option<mbe::Subtree> {
28 while let Some(tt) = p.eat() { 28 while let Some(tt) = p.eat() {
29 let child: mbe::TokenTree = match tt { 29 let child: mbe::TokenTree = match tt {
30 tt::TokenTree::Leaf(leaf) => match leaf { 30 tt::TokenTree::Leaf(leaf) => match leaf {
31 tt::Leaf::Punct(tt::Punct { char: '$' }) => { 31 tt::Leaf::Punct(tt::Punct { char: '$', .. }) => {
32 if p.at_ident().is_some() { 32 if p.at_ident().is_some() {
33 mbe::Leaf::from(parse_var(&mut p)?).into() 33 mbe::Leaf::from(parse_var(&mut p)?).into()
34 } else { 34 } else {
35 parse_repeat(&mut p)?.into() 35 parse_repeat(&mut p)?.into()
36 } 36 }
37 } 37 }
38 tt::Leaf::Punct(tt::Punct { char }) => { 38 tt::Leaf::Punct(punct) => mbe::Leaf::from(*punct).into(),
39 mbe::Leaf::from(mbe::Punct { char: *char }).into()
40 }
41 tt::Leaf::Ident(tt::Ident { text }) => { 39 tt::Leaf::Ident(tt::Ident { text }) => {
42 mbe::Leaf::from(mbe::Ident { text: text.clone() }).into() 40 mbe::Leaf::from(mbe::Ident { text: text.clone() }).into()
43 } 41 }
@@ -78,7 +76,7 @@ fn parse_repeat(p: &mut TtCursor) -> Option<mbe::Repeat> {
78 let sep = p.eat_punct()?; 76 let sep = p.eat_punct()?;
79 let (separator, rep) = match sep.char { 77 let (separator, rep) = match sep.char {
80 '*' | '+' | '?' => (None, sep.char), 78 '*' | '+' | '?' => (None, sep.char),
81 char => (Some(mbe::Punct { char }), p.eat_punct()?.char), 79 char => (Some(char), p.eat_punct()?.char),
82 }; 80 };
83 81
84 let kind = match rep { 82 let kind = match rep {
diff --git a/crates/ra_macros/src/tt.rs b/crates/ra_macros/src/tt.rs
index 56e930f00..2855bae51 100644
--- a/crates/ra_macros/src/tt.rs
+++ b/crates/ra_macros/src/tt.rs
@@ -1,7 +1,6 @@
1use std::fmt; 1use std::fmt;
2 2
3use smol_str::SmolStr; 3use smol_str::SmolStr;
4use join_to_string::join;
5 4
6#[derive(Debug, Clone)] 5#[derive(Debug, Clone)]
7pub enum TokenTree { 6pub enum TokenTree {
@@ -37,9 +36,16 @@ pub struct Literal {
37 pub text: SmolStr, 36 pub text: SmolStr,
38} 37}
39 38
40#[derive(Debug, Clone, PartialEq, Eq)] 39#[derive(Debug, Clone, Copy, PartialEq, Eq)]
41pub struct Punct { 40pub struct Punct {
42 pub char: char, 41 pub char: char,
42 pub spacing: Spacing,
43}
44
45#[derive(Debug, Clone, Copy, PartialEq, Eq)]
46pub enum Spacing {
47 Alone,
48 Joint,
43} 49}
44 50
45#[derive(Debug, Clone)] 51#[derive(Debug, Clone)]
@@ -64,10 +70,23 @@ impl fmt::Display for Subtree {
64 Delimiter::Bracket => ("[", "]"), 70 Delimiter::Bracket => ("[", "]"),
65 Delimiter::None => ("", ""), 71 Delimiter::None => ("", ""),
66 }; 72 };
67 join(self.token_trees.iter()) 73 f.write_str(l)?;
68 .separator(" ") 74 let mut needs_space = false;
69 .surround_with(l, r) 75 for tt in self.token_trees.iter() {
70 .to_fmt(f) 76 if needs_space {
77 f.write_str(" ")?;
78 }
79 needs_space = true;
80 match tt {
81 TokenTree::Leaf(Leaf::Punct(p)) => {
82 needs_space = p.spacing == Spacing::Alone;
83 fmt::Display::fmt(p, f)?
84 }
85 tt => fmt::Display::fmt(tt, f)?,
86 }
87 }
88 f.write_str(r)?;
89 Ok(())
71 } 90 }
72} 91}
73 92
diff --git a/crates/ra_macros/src/tt_cursor.rs b/crates/ra_macros/src/tt_cursor.rs
index 6dc9f400d..046770a0f 100644
--- a/crates/ra_macros/src/tt_cursor.rs
+++ b/crates/ra_macros/src/tt_cursor.rs
@@ -28,7 +28,7 @@ impl<'a> TtCursor<'a> {
28 28
29 pub(crate) fn at_char(&self, char: char) -> bool { 29 pub(crate) fn at_char(&self, char: char) -> bool {
30 match self.at_punct() { 30 match self.at_punct() {
31 Some(tt::Punct { char: c }) if *c == char => true, 31 Some(tt::Punct { char: c, .. }) if *c == char => true,
32 _ => false, 32 _ => false,
33 } 33 }
34 } 34 }