Skip to content

Commit 48e09f2

Browse files
committed
fixup! Use a procedural macro to create jump tables instead of doing branching.
1 parent e656282 commit 48e09f2

File tree

3 files changed

+56
-303
lines changed

3 files changed

+56
-303
lines changed

src/macros/match_byte.rs

+56-42
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,8 @@
33
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
44

55
use quote::{ToTokens, Tokens};
6-
use super::visit::{Visitor, RecursiveVisitor};
76
use std::fs::File;
87
use std::io::{Read, Write};
9-
use std::mem;
108
use std::path::Path;
119
use std::vec;
1210
use std::iter;
@@ -15,42 +13,69 @@ use syn;
1513
pub fn expand(from: &Path, to: &Path) {
1614
let mut source = String::new();
1715
File::open(from).unwrap().read_to_string(&mut source).unwrap();
18-
let mut crate_ = syn::parse_crate(&source).expect("Parsing rules.rs module");
19-
let mut visitor = ExpanderVisitor;
20-
21-
RecursiveVisitor { node_visitor: &mut visitor }.visit_crate(&mut crate_);
22-
16+
let tts = syn::parse_token_trees(&source).expect("Parsing rules.rs module");
2317
let mut tokens = Tokens::new();
24-
crate_.to_tokens(&mut tokens);
18+
tokens.append_all(expand_tts(tts));
19+
2520
let code = tokens.to_string().replace("{ ", "{\n").replace(" }", "\n}");
2621
File::create(to).unwrap().write_all(code.as_bytes()).unwrap();
2722
}
2823

29-
struct ExpanderVisitor;
24+
fn expand_tts(tts: Vec<syn::TokenTree>) -> Vec<syn::TokenTree> {
25+
use syn::*;
26+
let mut expanded = Vec::new();
27+
let mut tts = tts.into_iter();
28+
while let Some(tt) = tts.next() {
29+
match tt {
30+
TokenTree::Token(Token::Ident(ident)) => {
31+
if ident != "match_byte" {
32+
expanded.push(TokenTree::Token(Token::Ident(ident)));
33+
continue;
34+
}
3035

31-
impl Visitor for ExpanderVisitor {
32-
fn visit_expression(&mut self, expr: &mut syn::Expr) {
33-
let tokens = match expr.node {
34-
syn::ExprKind::Mac(ref mut macro_) if macro_.path == syn::Path::from("match_byte") => {
35-
mem::replace(&mut macro_.tts, vec![])
36-
}
37-
_ => return,
38-
};
39-
let (to_be_matched, table, cases, wildcard_binding) = parse_match_bytes_macro(tokens);
40-
*expr = expand_match_bytes_macro(to_be_matched, &table, cases, wildcard_binding);
41-
}
36+
match tts.next() {
37+
Some(TokenTree::Token(Token::Not)) => {},
38+
other => {
39+
expanded.push(TokenTree::Token(Token::Ident(ident)));
40+
if let Some(other) = other {
41+
expanded.push(other);
42+
}
43+
continue;
44+
}
45+
}
4246

43-
fn visit_statement(&mut self, stmt: &mut syn::Stmt) {
44-
let tokens = match *stmt {
45-
syn::Stmt::Mac(ref mut macro_) if macro_.0.path == syn::Path::from("match_byte") => {
46-
mem::replace(&mut macro_.0.tts, vec![])
47+
let tts = match tts.next() {
48+
Some(TokenTree::Delimited(Delimited { tts, .. })) => tts,
49+
other => {
50+
expanded.push(TokenTree::Token(Token::Ident(ident)));
51+
expanded.push(TokenTree::Token(Token::Not));
52+
if let Some(other) = other {
53+
expanded.push(other);
54+
}
55+
continue;
56+
}
57+
};
58+
59+
let (to_be_matched, table, cases, wildcard_binding) = parse_match_bytes_macro(tts);
60+
let expr = expand_match_bytes_macro(to_be_matched,
61+
&table,
62+
cases,
63+
wildcard_binding);
64+
65+
let tts = syn::parse_token_trees(&expr)
66+
.expect("parsing macro expansion as token trees");
67+
expanded.extend(expand_tts(tts));
4768
}
48-
_ => return,
49-
};
50-
let (to_be_matched, table, cases, wildcard_binding) = parse_match_bytes_macro(tokens);
51-
let expr = expand_match_bytes_macro(to_be_matched, &table, cases, wildcard_binding);
52-
*stmt = syn::Stmt::Expr(Box::new(expr));
69+
TokenTree::Delimited(Delimited { delim, tts }) => {
70+
expanded.push(TokenTree::Delimited(Delimited {
71+
delim: delim,
72+
tts: expand_tts(tts),
73+
}))
74+
}
75+
other => expanded.push(other),
76+
}
5377
}
78+
expanded
5479
}
5580

5681
/// Parses a token tree corresponding to the `match_byte` macro.
@@ -80,18 +105,7 @@ impl Visitor for ExpanderVisitor {
80105
/// this case).
81106
///
82107
fn parse_match_bytes_macro(tts: Vec<syn::TokenTree>) -> (Vec<syn::TokenTree>, [u8; 256], Vec<Case>, Option<syn::Ident>) {
83-
use syn::TokenTree::Delimited;
84-
use syn::DelimToken::Brace;
85-
86108
let mut tts = tts.into_iter();
87-
let inner_tts = match tts.next() {
88-
Some(Delimited(syn::Delimited { delim: Brace, tts })) => tts,
89-
other => panic!("expected one top-level {{}} block, got: {:?}", other),
90-
};
91-
92-
assert_eq!(tts.next(), None);
93-
94-
let mut tts = inner_tts.into_iter();
95109

96110
// Grab the thing we're matching, until we find a comma.
97111
let mut left_hand_side = vec![];
@@ -204,7 +218,7 @@ fn expand_match_bytes_macro(to_be_matched: Vec<syn::TokenTree>,
204218
table: &[u8; 256],
205219
cases: Vec<Case>,
206220
binding: Option<syn::Ident>)
207-
-> syn::Expr {
221+
-> String {
208222
use std::fmt::Write;
209223

210224
assert!(!to_be_matched.is_empty());
@@ -253,5 +267,5 @@ fn expand_match_bytes_macro(to_be_matched: Vec<syn::TokenTree>,
253267

254268
expr.push_str("}\n"); // top
255269

256-
syn::parse_expr(&expr).expect("couldn't parse expression?")
270+
expr
257271
}

src/macros/mod.rs

-1
Original file line numberDiff line numberDiff line change
@@ -3,4 +3,3 @@
33
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
44

55
pub mod match_byte;
6-
pub mod visit;

0 commit comments

Comments
 (0)