Skip to content

Instantly share code, notes, and snippets.

@zokier
Created August 11, 2014 18:37
Show Gist options
  • Star 6 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save zokier/6669cc2236c4a56cf70d to your computer and use it in GitHub Desktop.
Save zokier/6669cc2236c4a56cf70d to your computer and use it in GitHub Desktop.
Rust bitlevel pattern matching
#![feature(plugin_registrar)]
extern crate syntax;
extern crate rustc;
use syntax::ast;
use syntax::codemap::Span;
use syntax::ext::base;
use syntax::ext::base::{ExtCtxt, MacExpr};
use syntax::ext::build::AstBuilder;
use syntax::parse::token;
use rustc::plugin::Registry;
#[plugin_registrar]
pub fn plugin_registrar(reg: &mut Registry) {
reg.register_macro("bitmatch", expand_bitmatch);
}
pub fn expand_bitmatch(cx: &mut ExtCtxt, sp: Span, tts: &[ast::TokenTree])
-> Box<base::MacResult> {
// ----- PARSE TOKEN TREE -----
let p = &mut cx.new_parser_from_tts(tts);
let var_ident = p.parse_ident();
p.expect(&token::COMMA);
// whats this style thing
let (pattern_str, _pattern_str_style) = p.parse_str();
if p.token != token::EOF {
p.unexpected();
}
let pattern_str = pattern_str.get(); //huh?
// ----- END OF TOKEN TREE PARSING -----
// ----- PARSE PATTERN -----
let (mut mask, mut check) = (0u8, 0u8);
match pattern_str.len() {
8 => {},
len => {
cx.span_err(sp, format!("invalid length for bitmatch: {}", len).as_slice());
return base::DummyResult::expr(sp);
}
}
for (i, ch) in pattern_str.chars().rev().enumerate() {
match ch {
'0' => {mask |= 1 << i;},
'1' => {check |= 1 << i; mask |= 1 << i;},
'x' => {},
ch => { cx.span_err(sp, format!("invalid character in bitmatch: '{}' (pos: {})", ch, i).as_slice()); return base::DummyResult::expr(sp); }
}
}
// ----- END OF PATTERN PARSING -----
// cx.span_note(sp, format!("bitmatch: mask: {:02x}, check: {:02x}", mask, check).as_slice());
// ----- BUILD AST -----
return MacExpr::new(
cx.expr_binary(
sp,
ast::BiEq,
cx.expr_binary(
sp,
ast::BiBitAnd,
cx.expr_ident(
sp,
var_ident
),
cx.expr_u8(
sp,
mask
)
),
cx.expr_u8(
sp,
check
)
)
);
// ----- END OF AST BUILDING -----
}
#![feature(phase)]
#[phase(plugin)]
extern crate bitmatch;
fn main() {
let x: u8 = 0xAB;
match x {
x if bitmatch!(x, "0xxxx11x") => println!("well this is embarrasing"),
x if bitmatch!(x, "x0x0xx11") => println!("everything is a-ok!"),
_ => println!("something is amiss")
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment