Skip to content

Commit 2ddcd53

Browse files
committed
Make match_token! macro work on token trees instead of AST.
Token trees are much simpler, and thus easier to work with and less subject to future breaking changes in the `syn` crate.
1 parent 50522b8 commit 2ddcd53

File tree

4 files changed

+41
-301
lines changed

4 files changed

+41
-301
lines changed

Cargo.toml

+1-1
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ rustc-test = "0.1.3"
5151
phf_codegen = "0.7.3"
5252
quote = "0.3.3"
5353
rustc-serialize = "0.3.15"
54-
syn = { version = "0.9.1", features = ["full", "visit"]}
54+
syn = { version = "0.9.2", features = ["full", "visit"] }
5555

5656
[profile.dev]
5757
debug = false

macros/match_token.rs

+38-36
Original file line numberDiff line numberDiff line change
@@ -100,68 +100,70 @@ matching, by enforcing the following restrictions on its input:
100100
*/
101101

102102
use quote::{ToTokens, Tokens};
103-
use self::visit::{Visitor, RecursiveVisitor};
104103
use std::collections::HashSet;
105104
use std::fs::File;
106105
use std::io::{Read, Write};
107-
use std::mem;
108106
use std::path::Path;
109107
use std::slice;
110108
use syn;
111109

112-
mod visit;
113-
114110
pub fn expand_match_tokens(from: &Path, to: &Path) {
115111
let mut source = String::new();
116112
File::open(from).unwrap().read_to_string(&mut source).unwrap();
117-
let mut crate_ = syn::parse_crate(&source).expect("Parsing rules.rs module");
118-
RecursiveVisitor { node_visitor: ExpanderVisitor }.visit_crate(&mut crate_);
113+
let tts = syn::parse_token_trees(&source).expect("Parsing rules.rs module");
119114
let mut tokens = Tokens::new();
120-
crate_.to_tokens(&mut tokens);
115+
tokens.append_all(expand_tts(&tts));
121116
let code = tokens.to_string().replace("{ ", "{\n").replace(" }", "\n}");
122117
File::create(to).unwrap().write_all(code.as_bytes()).unwrap();
123118
}
124119

125-
struct ExpanderVisitor;
126-
127-
impl Visitor for ExpanderVisitor {
128-
fn visit_expression(&mut self, expr: &mut syn::Expr) {
129-
let tts;
130-
if let syn::Expr::Mac(ref mut macro_) = *expr {
131-
if macro_.path == syn::Path::from("match_token") {
132-
tts = mem::replace(&mut macro_.tts, Vec::new());
133-
} else {
134-
return
120+
fn expand_tts(tts: &[syn::TokenTree]) -> Vec<syn::TokenTree> {
121+
use syn::*;
122+
123+
let mut expanded = Vec::new();
124+
let mut tts = tts.iter();
125+
while let Some(tt) = tts.next() {
126+
match *tt {
127+
TokenTree::Token(Token::Ident(ref ident)) if ident == "match_token" => {
128+
let start = tts.clone();
129+
if let Some(&TokenTree::Token(Token::Not)) = tts.next() {
130+
if let Some(&TokenTree::Delimited(Delimited { ref tts, .. })) = tts.next() {
131+
let (to_be_matched, arms) = parse_match_token_macro(tts);
132+
let tokens = expand_match_token_macro(to_be_matched, arms);
133+
let tts = syn::parse_token_trees(&tokens.to_string())
134+
.expect("parsing macro expansion as token trees");
135+
expanded.extend(tts);
136+
continue
137+
}
138+
}
139+
tts = start
140+
}
141+
TokenTree::Token(_) => {
142+
expanded.push(tt.clone())
143+
}
144+
TokenTree::Delimited(Delimited { delim, ref tts }) => {
145+
expanded.push(TokenTree::Delimited(Delimited {
146+
delim: delim,
147+
tts: expand_tts(tts),
148+
}))
135149
}
136-
} else {
137-
return
138150
}
139-
let (to_be_matched, arms) = parse_match_token_macro(tts);
140-
let tokens = expand_match_token_macro(to_be_matched, arms);
141-
*expr = syn::parse_expr(&tokens.to_string()).expect("Parsing a match expression");
142151
}
152+
expanded
143153
}
144154

145-
fn parse_match_token_macro(tts: Vec<syn::TokenTree>) -> (syn::Ident, Vec<Arm>) {
155+
fn parse_match_token_macro(tts: &[syn::TokenTree]) -> (&syn::Ident, Vec<Arm>) {
146156
use syn::TokenTree::Delimited;
147-
use syn::DelimToken::{Brace, Paren};
148-
149-
let mut tts = tts.into_iter();
150-
let inner_tts = if let Some(Delimited(syn::Delimited { delim: Paren, tts })) = tts.next() {
151-
tts
152-
} else {
153-
panic!("expected one top-level () block")
154-
};
155-
assert_eq!(tts.len(), 0);
157+
use syn::DelimToken::Brace;
156158

157-
let mut tts = inner_tts.into_iter();
158-
let ident = if let Some(syn::TokenTree::Token(syn::Token::Ident(ident))) = tts.next() {
159+
let mut tts = tts.iter();
160+
let ident = if let Some(&syn::TokenTree::Token(syn::Token::Ident(ref ident))) = tts.next() {
159161
ident
160162
} else {
161163
panic!("expected ident")
162164
};
163165

164-
let block = if let Some(Delimited(syn::Delimited { delim: Brace, tts })) = tts.next() {
166+
let block = if let Some(&Delimited(syn::Delimited { delim: Brace, ref tts })) = tts.next() {
165167
tts
166168
} else {
167169
panic!("expected one {} block")
@@ -310,7 +312,7 @@ fn parse_rhs(tts: &mut slice::Iter<syn::TokenTree>) -> RHS {
310312
RHS::Expression(expression)
311313
}
312314

313-
fn expand_match_token_macro(to_be_matched: syn::Ident, mut arms: Vec<Arm>) -> Tokens {
315+
fn expand_match_token_macro(to_be_matched: &syn::Ident, mut arms: Vec<Arm>) -> Tokens {
314316
// Handle the last arm specially at the end.
315317
let last_arm = arms.pop().unwrap();
316318

macros/visit.rs

-260
This file was deleted.

0 commit comments

Comments
 (0)