Skip to content

Instantly share code, notes, and snippets.

@rprichard
Last active August 29, 2015 14:18
#[allow_internal_unstable], syntax extension plugin
#!/bin/sh
set -e
rustc foo_macro.rs
rustc main.rs -L.
#![crate_type="dylib"]
#![feature(plugin_registrar, rustc_private, slice_patterns)]
extern crate syntax;
extern crate rustc;
use syntax::codemap::Span;
use syntax::ast;
use syntax::ext::base::*;
use syntax::ext::base;
use syntax::ext::build::AstBuilder;
use syntax::parse::token;
use syntax::ptr::P;
use rustc::plugin::Registry;
use std::collections::HashMap;
/// Copied from format.rs
fn parse_args(ecx: &mut ExtCtxt, sp: Span, tts: &[ast::TokenTree])
-> Option<(P<ast::Expr>, Vec<P<ast::Expr>>, Vec<String>,
HashMap<String, P<ast::Expr>>)> {
let mut args = Vec::new();
let mut names = HashMap::<String, P<ast::Expr>>::new();
let mut order = Vec::new();
let mut p = ecx.new_parser_from_tts(tts);
if p.token == token::Eof {
ecx.span_err(sp, "requires at least a format string argument");
return None;
}
let fmtstr = p.parse_expr();
let mut named = false;
while p.token != token::Eof {
if !p.eat(&token::Comma) {
ecx.span_err(sp, "expected token: `,`");
return None;
}
if p.token == token::Eof { break } // accept trailing commas
if named || (p.token.is_ident() && p.look_ahead(1, |t| *t == token::Eq)) {
named = true;
let ident = match p.token {
token::Ident(i, _) => {
p.bump();
i
}
_ if named => {
ecx.span_err(p.span,
"expected ident, positional arguments \
cannot follow named arguments");
return None;
}
_ => {
ecx.span_err(p.span,
&format!("expected ident for named argument, found `{}`",
p.this_token_to_string()));
return None;
}
};
let interned_name = token::get_ident(ident);
let name = &interned_name[..];
p.expect(&token::Eq);
let e = p.parse_expr();
match names.get(name) {
None => {}
Some(prev) => {
ecx.span_err(e.span,
&format!("duplicate argument named `{}`",
name));
ecx.parse_sess.span_diagnostic.span_note(prev.span, "previously here");
continue
}
}
order.push(name.to_string());
names.insert(name.to_string(), e);
} else {
args.push(p.parse_expr());
}
}
Some((fmtstr, args, order, names))
}
fn expand_foo(cx: &mut ExtCtxt, sp: Span, args: &[ast::TokenTree])
-> Box<MacResult + 'static> {
let (fmtexp, mut args, mut name_ordering, mut names) = parse_args(cx, sp, args).unwrap();
// let expr = cx.expr_path(cx.path_global(fmtexp.span, vec![
// cx.ident_of("std"),
// cx.ident_of("io"),
// cx.ident_of("_print"),
// ]));
//MacEager::expr(expr)
MacEager::expr(args.pop().unwrap())
}
#[plugin_registrar]
pub fn plugin_registrar(reg: &mut Registry) {
let expander: MacroExpanderFn = expand_foo;
reg.register_syntax_extension(token::intern("foo"),
NormalTT(Box::new(expander), None, true));
}
#![feature(plugin)]
#![plugin(foo_macro)]
macro_rules! exp_foo {
() => (foo!("ABC"))
}
fn main() {
//exp_rn!();
//rn!("weak");
println!("{}", foo!("weak", std::rt::DEFAULT_ERROR_CODE));
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment