From 48e09f29d9500bf146aba3d2d85a70e6d776b263 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Emilio=20Cobos=20=C3=81lvarez?= Date: Sat, 21 Jan 2017 14:03:44 +0100 Subject: [PATCH] fixup! Use a procedural macro to create jump tables instead of doing branching. --- src/macros/match_byte.rs | 98 ++++++++------- src/macros/mod.rs | 1 - src/macros/visit.rs | 260 --------------------------------------- 3 files changed, 56 insertions(+), 303 deletions(-) delete mode 100644 src/macros/visit.rs diff --git a/src/macros/match_byte.rs b/src/macros/match_byte.rs index 9c118b78..79519d01 100644 --- a/src/macros/match_byte.rs +++ b/src/macros/match_byte.rs @@ -3,10 +3,8 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ use quote::{ToTokens, Tokens}; -use super::visit::{Visitor, RecursiveVisitor}; use std::fs::File; use std::io::{Read, Write}; -use std::mem; use std::path::Path; use std::vec; use std::iter; @@ -15,42 +13,69 @@ use syn; pub fn expand(from: &Path, to: &Path) { let mut source = String::new(); File::open(from).unwrap().read_to_string(&mut source).unwrap(); - let mut crate_ = syn::parse_crate(&source).expect("Parsing rules.rs module"); - let mut visitor = ExpanderVisitor; - - RecursiveVisitor { node_visitor: &mut visitor }.visit_crate(&mut crate_); - + let tts = syn::parse_token_trees(&source).expect("Parsing rules.rs module"); let mut tokens = Tokens::new(); - crate_.to_tokens(&mut tokens); + tokens.append_all(expand_tts(tts)); + let code = tokens.to_string().replace("{ ", "{\n").replace(" }", "\n}"); File::create(to).unwrap().write_all(code.as_bytes()).unwrap(); } -struct ExpanderVisitor; +fn expand_tts(tts: Vec) -> Vec { + use syn::*; + let mut expanded = Vec::new(); + let mut tts = tts.into_iter(); + while let Some(tt) = tts.next() { + match tt { + TokenTree::Token(Token::Ident(ident)) => { + if ident != "match_byte" { + expanded.push(TokenTree::Token(Token::Ident(ident))); + continue; + } -impl Visitor for ExpanderVisitor { - fn visit_expression(&mut self, expr: &mut syn::Expr) { - let tokens = match expr.node { - syn::ExprKind::Mac(ref mut macro_) if macro_.path == syn::Path::from("match_byte") => { - mem::replace(&mut macro_.tts, vec![]) - } - _ => return, - }; - let (to_be_matched, table, cases, wildcard_binding) = parse_match_bytes_macro(tokens); - *expr = expand_match_bytes_macro(to_be_matched, &table, cases, wildcard_binding); - } + match tts.next() { + Some(TokenTree::Token(Token::Not)) => {}, + other => { + expanded.push(TokenTree::Token(Token::Ident(ident))); + if let Some(other) = other { + expanded.push(other); + } + continue; + } + } - fn visit_statement(&mut self, stmt: &mut syn::Stmt) { - let tokens = match *stmt { - syn::Stmt::Mac(ref mut macro_) if macro_.0.path == syn::Path::from("match_byte") => { - mem::replace(&mut macro_.0.tts, vec![]) + let tts = match tts.next() { + Some(TokenTree::Delimited(Delimited { tts, .. })) => tts, + other => { + expanded.push(TokenTree::Token(Token::Ident(ident))); + expanded.push(TokenTree::Token(Token::Not)); + if let Some(other) = other { + expanded.push(other); + } + continue; + } + }; + + let (to_be_matched, table, cases, wildcard_binding) = parse_match_bytes_macro(tts); + let expr = expand_match_bytes_macro(to_be_matched, + &table, + cases, + wildcard_binding); + + let tts = syn::parse_token_trees(&expr) + .expect("parsing macro expansion as token trees"); + expanded.extend(expand_tts(tts)); } - _ => return, - }; - let (to_be_matched, table, cases, wildcard_binding) = parse_match_bytes_macro(tokens); - let expr = expand_match_bytes_macro(to_be_matched, &table, cases, wildcard_binding); - *stmt = syn::Stmt::Expr(Box::new(expr)); + TokenTree::Delimited(Delimited { delim, tts }) => { + expanded.push(TokenTree::Delimited(Delimited { + delim: delim, + tts: expand_tts(tts), + })) + } + other => expanded.push(other), + } } + expanded } /// Parses a token tree corresponding to the `match_byte` macro. @@ -80,18 +105,7 @@ impl Visitor for ExpanderVisitor { /// this case). /// fn parse_match_bytes_macro(tts: Vec) -> (Vec, [u8; 256], Vec, Option) { - use syn::TokenTree::Delimited; - use syn::DelimToken::Brace; - let mut tts = tts.into_iter(); - let inner_tts = match tts.next() { - Some(Delimited(syn::Delimited { delim: Brace, tts })) => tts, - other => panic!("expected one top-level {{}} block, got: {:?}", other), - }; - - assert_eq!(tts.next(), None); - - let mut tts = inner_tts.into_iter(); // Grab the thing we're matching, until we find a comma. let mut left_hand_side = vec![]; @@ -204,7 +218,7 @@ fn expand_match_bytes_macro(to_be_matched: Vec, table: &[u8; 256], cases: Vec, binding: Option) - -> syn::Expr { + -> String { use std::fmt::Write; assert!(!to_be_matched.is_empty()); @@ -253,5 +267,5 @@ fn expand_match_bytes_macro(to_be_matched: Vec, expr.push_str("}\n"); // top - syn::parse_expr(&expr).expect("couldn't parse expression?") + expr } diff --git a/src/macros/mod.rs b/src/macros/mod.rs index 0553a2de..6799e549 100644 --- a/src/macros/mod.rs +++ b/src/macros/mod.rs @@ -3,4 +3,3 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ pub mod match_byte; -pub mod visit; diff --git a/src/macros/visit.rs b/src/macros/visit.rs deleted file mode 100644 index 331834d5..00000000 --- a/src/macros/visit.rs +++ /dev/null @@ -1,260 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -/// Just enough of an AST visitor to reach every expression and statement. - -use syn; - -pub trait Visitor { - fn visit_crate(&mut self, _crate: &mut syn::Crate) {} - fn visit_item(&mut self, _item: &mut syn::Item) {} - fn visit_trait_item(&mut self, _item: &mut syn::TraitItem) {} - fn visit_impl_item(&mut self, _item: &mut syn::ImplItem) {} - fn visit_block(&mut self, _expr: &mut syn::Block) {} - fn visit_statement(&mut self, _expr: &mut syn::Stmt) {} - fn visit_expression(&mut self, _expr: &mut syn::Expr) {} -} - -pub struct RecursiveVisitor<'a, V: 'a> { - pub node_visitor: &'a mut V, -} - -impl<'a, V: Visitor + 'a> Visitor for RecursiveVisitor<'a, V> { - fn visit_crate(&mut self, crate_: &mut syn::Crate) { - self.node_visitor.visit_crate(crate_); - for item in &mut crate_.items { - self.visit_item(item) - } - } - - fn visit_item(&mut self, item: &mut syn::Item) { - use syn::ItemKind::*; - self.node_visitor.visit_item(item); - match item.node { - ExternCrate(_) => {} - Use(_) => {} - Static(_, _, ref mut expr) => self.visit_expression(expr), - Const(_, ref mut expr) => self.visit_expression(expr), - Fn(_, _, _, _, _, ref mut block) => self.visit_block(block), - Mod(Some(ref mut items)) => { - for item in items { - self.visit_item(item) - } - } - Mod(None) => {} - ForeignMod(_) => {} - Ty(_, _) => {} - Enum(_, _) => {} - Struct(_, _) => {} - Union(_, _) => {} - Trait(_, _, _, ref mut trait_items) => { - for trait_item in trait_items { - self.visit_trait_item(trait_item) - } - } - DefaultImpl(_, _) => {} - Impl(_, _, _, _, _, ref mut impl_items) => { - for impl_item in impl_items { - self.visit_impl_item(impl_item) - } - } - Mac(_) => {} - } - } - - fn visit_trait_item(&mut self, trait_item: &mut syn::TraitItem) { - use syn::TraitItemKind::*; - self.node_visitor.visit_trait_item(trait_item); - match trait_item.node { - Const(_, Some(ref mut expr)) => self.visit_expression(expr), - Const(_, None) => {} - Method(_, Some(ref mut block)) => self.visit_block(block), - Method(_, None) => {} - Type(_, _) => {} - Macro(_) => {} - } - } - - fn visit_impl_item(&mut self, impl_item: &mut syn::ImplItem) { - use syn::ImplItemKind::*; - self.node_visitor.visit_impl_item(impl_item); - match impl_item.node { - Const(_, ref mut expr) => self.visit_expression(expr), - Method(_, ref mut block) => self.visit_block(block), - Type(_) => {} - Macro(_) => {} - } - } - - fn visit_block(&mut self, block: &mut syn::Block) { - self.node_visitor.visit_block(block); - for statement in &mut block.stmts { - self.visit_statement(statement) - } - } - - fn visit_statement(&mut self, statement: &mut syn::Stmt) { - use syn::Stmt::*; - self.node_visitor.visit_statement(statement); - match *statement { - Local(ref mut local) => { - if let Some(ref mut expr) = local.init { - self.visit_expression(expr) - } - } - Item(ref mut item) => self.visit_item(item), - Expr(ref mut expr) => self.visit_expression(expr), - Semi(ref mut expr) => self.visit_expression(expr), - Mac(_) => {} - } - } - - fn visit_expression(&mut self, expr: &mut syn::Expr) { - use syn::ExprKind::*; - self.node_visitor.visit_expression(expr); - match expr.node { - Box(ref mut boxed) => { - self.visit_expression(boxed) - } - Vec(ref mut elements) => { - for element in elements { - self.visit_expression(element) - } - } - Call(ref mut called, ref mut args) => { - self.visit_expression(called); - for arg in args { - self.visit_expression(arg) - } - } - MethodCall(_, _, ref mut args) => { - for arg in args { - self.visit_expression(arg) - } - } - Tup(ref mut elements) => { - for element in elements { - self.visit_expression(element) - } - } - Binary(_, ref mut left, ref mut right) => { - self.visit_expression(left); - self.visit_expression(right); - } - Unary(_, ref mut operand) => { - self.visit_expression(operand) - } - Lit(_) => {} - Cast(ref mut expr, _) => { - self.visit_expression(expr) - } - Type(ref mut expr, _) => { - self.visit_expression(expr) - } - If(ref mut test, ref mut then, ref mut else_) => { - self.visit_expression(test); - self.visit_block(then); - if let Some(ref mut else_) = *else_ { - self.visit_expression(else_); - } - } - IfLet(_, ref mut test, ref mut then, ref mut else_) => { - self.visit_expression(test); - self.visit_block(then); - if let Some(ref mut else_) = *else_ { - self.visit_expression(else_); - } - } - While(ref mut test, ref mut block, _) => { - self.visit_expression(test); - self.visit_block(block); - } - WhileLet(_, ref mut test, ref mut block, _) => { - self.visit_expression(test); - self.visit_block(block); - } - ForLoop(_, ref mut iterable, ref mut block, _) => { - self.visit_expression(iterable); - self.visit_block(block); - } - Loop(ref mut block, _) => { - self.visit_block(block); - } - Match(ref mut matched, ref mut arms) => { - self.visit_expression(matched); - for arm in arms { - if let Some(ref mut guard) = arm.guard { - self.visit_expression(guard) - } - self.visit_expression(&mut arm.body) - } - } - Closure(_, _, ref mut block) => { - self.visit_block(block) - } - Block(_, ref mut block) => { - self.visit_block(block) - } - Assign(ref mut left, ref mut right) => { - self.visit_expression(left); - self.visit_expression(right); - } - AssignOp(_, ref mut left, ref mut right) => { - self.visit_expression(left); - self.visit_expression(right); - } - Field(ref mut base, _) => { - self.visit_expression(base) - } - TupField(ref mut base, _) => { - self.visit_expression(base) - } - Index(ref mut base, ref mut index) => { - self.visit_expression(base); - self.visit_expression(index); - } - Range(ref mut start, ref mut end, _) => { - if let Some(ref mut start) = *start { - self.visit_expression(start) - } - if let Some(ref mut end) = *end { - self.visit_expression(end) - } - } - Path(_, _) => {} - AddrOf(_, ref mut base) => { - self.visit_expression(base) - } - Break(_) => {} - Continue(_) => {} - Ret(Some(ref mut expr)) => { - self.visit_expression(expr) - } - Ret(None) => {} - Mac(_) => {} - Struct(_, ref mut fields, ref mut base) => { - for field in fields { - self.visit_expression(&mut field.expr) - } - if let Some(ref mut base) = *base { - self.visit_expression(base) - } - } - Repeat(ref mut element, ref mut number) => { - self.visit_expression(element); - self.visit_expression(number); - } - Paren(ref mut expr) => { - self.visit_expression(expr) - } - Try(ref mut expr) => { - self.visit_expression(expr) - } - InPlace(ref mut expr, ref mut other) => { - self.visit_expression(expr); - self.visit_expression(other); - } - } - } -}