diff options
author | Kevin Mehall <[email protected]> | 2021-03-06 16:46:32 +0000 |
---|---|---|
committer | Kevin Mehall <[email protected]> | 2021-03-06 16:48:30 +0000 |
commit | 62f594b390e5f648a32b5b08863a6413b4271d19 (patch) | |
tree | 47de88bc047e957149544f48f2696f2706b9ed4b | |
parent | 632fa8ef4a3c9e7440b79e04a9f7dd9bd23a4de4 (diff) |
Refactor TokenStream to hold Vec<TokenTree> instead of tt::Subtree
`TokenStream` assumes that its subtree's delimeter is `None`, and this
should be encoded in the type system instead of having a delimiter field
that is mostly ignored.
`tt::Subtree` is just `pub delimiter: Option<Delimiter>, pub
token_trees: Vec<TokenTree>`, so a Subtree that is statically guaranteed
not to have a delimiter is just Vec<TokenTree>.
-rw-r--r-- | crates/proc_macro_srv/src/dylib.rs | 6 | ||||
-rw-r--r-- | crates/proc_macro_srv/src/rustc_server.rs | 113 | ||||
-rw-r--r-- | crates/proc_macro_srv/src/tests/utils.rs | 2 |
3 files changed, 56 insertions, 65 deletions
diff --git a/crates/proc_macro_srv/src/dylib.rs b/crates/proc_macro_srv/src/dylib.rs index 28a6ee547..baf10fea9 100644 --- a/crates/proc_macro_srv/src/dylib.rs +++ b/crates/proc_macro_srv/src/dylib.rs | |||
@@ -138,7 +138,7 @@ impl Expander { | |||
138 | parsed_body, | 138 | parsed_body, |
139 | false, | 139 | false, |
140 | ); | 140 | ); |
141 | return res.map(|it| it.subtree); | 141 | return res.map(|it| it.into_subtree()); |
142 | } | 142 | } |
143 | bridge::client::ProcMacro::Bang { name, client } if *name == macro_name => { | 143 | bridge::client::ProcMacro::Bang { name, client } if *name == macro_name => { |
144 | let res = client.run( | 144 | let res = client.run( |
@@ -147,7 +147,7 @@ impl Expander { | |||
147 | parsed_body, | 147 | parsed_body, |
148 | false, | 148 | false, |
149 | ); | 149 | ); |
150 | return res.map(|it| it.subtree); | 150 | return res.map(|it| it.into_subtree()); |
151 | } | 151 | } |
152 | bridge::client::ProcMacro::Attr { name, client } if *name == macro_name => { | 152 | bridge::client::ProcMacro::Attr { name, client } if *name == macro_name => { |
153 | let res = client.run( | 153 | let res = client.run( |
@@ -157,7 +157,7 @@ impl Expander { | |||
157 | parsed_body, | 157 | parsed_body, |
158 | false, | 158 | false, |
159 | ); | 159 | ); |
160 | return res.map(|it| it.subtree); | 160 | return res.map(|it| it.into_subtree()); |
161 | } | 161 | } |
162 | _ => continue, | 162 | _ => continue, |
163 | } | 163 | } |
diff --git a/crates/proc_macro_srv/src/rustc_server.rs b/crates/proc_macro_srv/src/rustc_server.rs index f02b0af60..2798dbf0d 100644 --- a/crates/proc_macro_srv/src/rustc_server.rs +++ b/crates/proc_macro_srv/src/rustc_server.rs | |||
@@ -25,36 +25,35 @@ type Span = tt::TokenId; | |||
25 | 25 | ||
26 | #[derive(Debug, Clone)] | 26 | #[derive(Debug, Clone)] |
27 | pub struct TokenStream { | 27 | pub struct TokenStream { |
28 | pub subtree: tt::Subtree, | 28 | pub token_trees: Vec<TokenTree>, |
29 | } | 29 | } |
30 | 30 | ||
31 | impl TokenStream { | 31 | impl TokenStream { |
32 | pub fn new() -> Self { | 32 | pub fn new() -> Self { |
33 | TokenStream { subtree: Default::default() } | 33 | TokenStream { token_trees: Default::default() } |
34 | } | 34 | } |
35 | 35 | ||
36 | pub fn with_subtree(subtree: tt::Subtree) -> Self { | 36 | pub fn with_subtree(subtree: tt::Subtree) -> Self { |
37 | if subtree.delimiter.is_some() { | 37 | if subtree.delimiter.is_some() { |
38 | TokenStream { | 38 | TokenStream { token_trees: vec![TokenTree::Subtree(subtree)] } |
39 | subtree: tt::Subtree { | ||
40 | token_trees: vec![TokenTree::Subtree(subtree)], | ||
41 | delimiter: None, | ||
42 | }, | ||
43 | } | ||
44 | } else { | 39 | } else { |
45 | TokenStream { subtree } | 40 | TokenStream { token_trees: subtree.token_trees } |
46 | } | 41 | } |
47 | } | 42 | } |
48 | 43 | ||
44 | pub fn into_subtree(self) -> tt::Subtree { | ||
45 | tt::Subtree { delimiter: None, token_trees: self.token_trees } | ||
46 | } | ||
47 | |||
49 | pub fn is_empty(&self) -> bool { | 48 | pub fn is_empty(&self) -> bool { |
50 | self.subtree.token_trees.is_empty() | 49 | self.token_trees.is_empty() |
51 | } | 50 | } |
52 | } | 51 | } |
53 | 52 | ||
54 | /// Creates a token stream containing a single token tree. | 53 | /// Creates a token stream containing a single token tree. |
55 | impl From<TokenTree> for TokenStream { | 54 | impl From<TokenTree> for TokenStream { |
56 | fn from(tree: TokenTree) -> TokenStream { | 55 | fn from(tree: TokenTree) -> TokenStream { |
57 | TokenStream { subtree: tt::Subtree { delimiter: None, token_trees: vec![tree] } } | 56 | TokenStream { token_trees: vec![tree] } |
58 | } | 57 | } |
59 | } | 58 | } |
60 | 59 | ||
@@ -87,10 +86,10 @@ impl Extend<TokenStream> for TokenStream { | |||
87 | for tkn in item { | 86 | for tkn in item { |
88 | match tkn { | 87 | match tkn { |
89 | tt::TokenTree::Subtree(subtree) if subtree.delimiter.is_none() => { | 88 | tt::TokenTree::Subtree(subtree) if subtree.delimiter.is_none() => { |
90 | self.subtree.token_trees.extend(subtree.token_trees); | 89 | self.token_trees.extend(subtree.token_trees); |
91 | } | 90 | } |
92 | _ => { | 91 | _ => { |
93 | self.subtree.token_trees.push(tkn); | 92 | self.token_trees.push(tkn); |
94 | } | 93 | } |
95 | } | 94 | } |
96 | } | 95 | } |
@@ -173,7 +172,7 @@ pub mod token_stream { | |||
173 | type IntoIter = super::IntoIter<TokenTree>; | 172 | type IntoIter = super::IntoIter<TokenTree>; |
174 | 173 | ||
175 | fn into_iter(self) -> Self::IntoIter { | 174 | fn into_iter(self) -> Self::IntoIter { |
176 | self.subtree.token_trees.into_iter() | 175 | self.token_trees.into_iter() |
177 | } | 176 | } |
178 | } | 177 | } |
179 | 178 | ||
@@ -200,32 +199,32 @@ pub mod token_stream { | |||
200 | 199 | ||
201 | impl ToString for TokenStream { | 200 | impl ToString for TokenStream { |
202 | fn to_string(&self) -> String { | 201 | fn to_string(&self) -> String { |
203 | let tt = self.subtree.clone().into(); | 202 | tokentrees_to_text(&self.token_trees[..]) |
204 | to_text(&tt) | ||
205 | } | 203 | } |
206 | } | 204 | } |
207 | 205 | ||
208 | fn to_text(tkn: &tt::TokenTree) -> String { | 206 | fn tokentrees_to_text(tkns: &[tt::TokenTree]) -> String { |
207 | tkns.iter() | ||
208 | .fold((String::new(), true), |(last, last_to_joint), tkn| { | ||
209 | let s = [last, tokentree_to_text(tkn)].join(if last_to_joint { "" } else { " " }); | ||
210 | let mut is_joint = false; | ||
211 | if let tt::TokenTree::Leaf(tt::Leaf::Punct(punct)) = tkn { | ||
212 | if punct.spacing == tt::Spacing::Joint { | ||
213 | is_joint = true; | ||
214 | } | ||
215 | } | ||
216 | (s, is_joint) | ||
217 | }) | ||
218 | .0 | ||
219 | } | ||
220 | |||
221 | fn tokentree_to_text(tkn: &tt::TokenTree) -> String { | ||
209 | match tkn { | 222 | match tkn { |
210 | tt::TokenTree::Leaf(tt::Leaf::Ident(ident)) => ident.text.clone().into(), | 223 | tt::TokenTree::Leaf(tt::Leaf::Ident(ident)) => ident.text.clone().into(), |
211 | tt::TokenTree::Leaf(tt::Leaf::Literal(literal)) => literal.text.clone().into(), | 224 | tt::TokenTree::Leaf(tt::Leaf::Literal(literal)) => literal.text.clone().into(), |
212 | tt::TokenTree::Leaf(tt::Leaf::Punct(punct)) => format!("{}", punct.char), | 225 | tt::TokenTree::Leaf(tt::Leaf::Punct(punct)) => format!("{}", punct.char), |
213 | tt::TokenTree::Subtree(subtree) => { | 226 | tt::TokenTree::Subtree(subtree) => { |
214 | let content = subtree | 227 | let content = tokentrees_to_text(&subtree.token_trees); |
215 | .token_trees | ||
216 | .iter() | ||
217 | .fold((String::new(), true), |(last, last_to_joint), tkn| { | ||
218 | let s = [last, to_text(tkn)].join(if last_to_joint { "" } else { " " }); | ||
219 | let mut is_joint = false; | ||
220 | if let tt::TokenTree::Leaf(tt::Leaf::Punct(punct)) = tkn { | ||
221 | if punct.spacing == tt::Spacing::Joint { | ||
222 | is_joint = true; | ||
223 | } | ||
224 | } | ||
225 | (s, is_joint) | ||
226 | }) | ||
227 | .0; | ||
228 | |||
229 | let (open, close) = match subtree.delimiter.map(|it| it.kind) { | 228 | let (open, close) = match subtree.delimiter.map(|it| it.kind) { |
230 | None => ("", ""), | 229 | None => ("", ""), |
231 | Some(tt::DelimiterKind::Brace) => ("{", "}"), | 230 | Some(tt::DelimiterKind::Brace) => ("{", "}"), |
@@ -442,10 +441,7 @@ fn spacing_to_external(spacing: Spacing) -> bridge::Spacing { | |||
442 | 441 | ||
443 | impl server::Group for Rustc { | 442 | impl server::Group for Rustc { |
444 | fn new(&mut self, delimiter: bridge::Delimiter, stream: Self::TokenStream) -> Self::Group { | 443 | fn new(&mut self, delimiter: bridge::Delimiter, stream: Self::TokenStream) -> Self::Group { |
445 | Self::Group { | 444 | Self::Group { delimiter: delim_to_internal(delimiter), token_trees: stream.token_trees } |
446 | delimiter: delim_to_internal(delimiter), | ||
447 | token_trees: stream.subtree.token_trees, | ||
448 | } | ||
449 | } | 445 | } |
450 | fn delimiter(&mut self, group: &Self::Group) -> bridge::Delimiter { | 446 | fn delimiter(&mut self, group: &Self::Group) -> bridge::Delimiter { |
451 | delim_to_external(group.delimiter) | 447 | delim_to_external(group.delimiter) |
@@ -453,9 +449,7 @@ impl server::Group for Rustc { | |||
453 | 449 | ||
454 | // NOTE: Return value of do not include delimiter | 450 | // NOTE: Return value of do not include delimiter |
455 | fn stream(&mut self, group: &Self::Group) -> Self::TokenStream { | 451 | fn stream(&mut self, group: &Self::Group) -> Self::TokenStream { |
456 | TokenStream { | 452 | TokenStream { token_trees: group.token_trees.clone() } |
457 | subtree: tt::Subtree { delimiter: None, token_trees: group.token_trees.clone() }, | ||
458 | } | ||
459 | } | 453 | } |
460 | 454 | ||
461 | fn span(&mut self, group: &Self::Group) -> Self::Span { | 455 | fn span(&mut self, group: &Self::Group) -> Self::Span { |
@@ -764,26 +758,23 @@ mod tests { | |||
764 | #[test] | 758 | #[test] |
765 | fn test_rustc_server_to_string() { | 759 | fn test_rustc_server_to_string() { |
766 | let s = TokenStream { | 760 | let s = TokenStream { |
767 | subtree: tt::Subtree { | 761 | token_trees: vec![ |
768 | delimiter: None, | 762 | tt::TokenTree::Leaf(tt::Leaf::Ident(tt::Ident { |
769 | token_trees: vec![ | 763 | text: "struct".into(), |
770 | tt::TokenTree::Leaf(tt::Leaf::Ident(tt::Ident { | 764 | id: tt::TokenId::unspecified(), |
771 | text: "struct".into(), | 765 | })), |
772 | id: tt::TokenId::unspecified(), | 766 | tt::TokenTree::Leaf(tt::Leaf::Ident(tt::Ident { |
773 | })), | 767 | text: "T".into(), |
774 | tt::TokenTree::Leaf(tt::Leaf::Ident(tt::Ident { | 768 | id: tt::TokenId::unspecified(), |
775 | text: "T".into(), | 769 | })), |
770 | tt::TokenTree::Subtree(tt::Subtree { | ||
771 | delimiter: Some(tt::Delimiter { | ||
776 | id: tt::TokenId::unspecified(), | 772 | id: tt::TokenId::unspecified(), |
777 | })), | 773 | kind: tt::DelimiterKind::Brace, |
778 | tt::TokenTree::Subtree(tt::Subtree { | ||
779 | delimiter: Some(tt::Delimiter { | ||
780 | id: tt::TokenId::unspecified(), | ||
781 | kind: tt::DelimiterKind::Brace, | ||
782 | }), | ||
783 | token_trees: vec![], | ||
784 | }), | 774 | }), |
785 | ], | 775 | token_trees: vec![], |
786 | }, | 776 | }), |
777 | ], | ||
787 | }; | 778 | }; |
788 | 779 | ||
789 | assert_eq!(s.to_string(), "struct T {}"); | 780 | assert_eq!(s.to_string(), "struct T {}"); |
@@ -804,11 +795,11 @@ mod tests { | |||
804 | }); | 795 | }); |
805 | 796 | ||
806 | let t1 = TokenStream::from_str("(a)").unwrap(); | 797 | let t1 = TokenStream::from_str("(a)").unwrap(); |
807 | assert_eq!(t1.subtree.token_trees.len(), 1); | 798 | assert_eq!(t1.token_trees.len(), 1); |
808 | assert_eq!(t1.subtree.token_trees[0], subtree_paren_a); | 799 | assert_eq!(t1.token_trees[0], subtree_paren_a); |
809 | 800 | ||
810 | let t2 = TokenStream::from_str("(a);").unwrap(); | 801 | let t2 = TokenStream::from_str("(a);").unwrap(); |
811 | assert_eq!(t2.subtree.token_trees.len(), 2); | 802 | assert_eq!(t2.token_trees.len(), 2); |
812 | assert_eq!(t2.subtree.token_trees[0], subtree_paren_a); | 803 | assert_eq!(t2.token_trees[0], subtree_paren_a); |
813 | } | 804 | } |
814 | } | 805 | } |
diff --git a/crates/proc_macro_srv/src/tests/utils.rs b/crates/proc_macro_srv/src/tests/utils.rs index 22813052d..0484c3af4 100644 --- a/crates/proc_macro_srv/src/tests/utils.rs +++ b/crates/proc_macro_srv/src/tests/utils.rs | |||
@@ -52,7 +52,7 @@ pub fn assert_expand( | |||
52 | let expander = dylib::Expander::new(&path).unwrap(); | 52 | let expander = dylib::Expander::new(&path).unwrap(); |
53 | let fixture = parse_string(ra_fixture).unwrap(); | 53 | let fixture = parse_string(ra_fixture).unwrap(); |
54 | 54 | ||
55 | let res = expander.expand(macro_name, &fixture.subtree, None).unwrap(); | 55 | let res = expander.expand(macro_name, &fixture.into_subtree(), None).unwrap(); |
56 | assert_eq_text!(&expect.trim(), &format!("{:?}", res)); | 56 | assert_eq_text!(&expect.trim(), &format!("{:?}", res)); |
57 | } | 57 | } |
58 | 58 | ||