Thanks to visit codestin.com
Credit goes to github.com

Skip to content
Closed
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Next Next commit
rustc: Add the __tt_map_insert and __tt_map_get_expr macros
Behind the `__tt_map` feature gate. This feature name starts with
a double underscore to emphasize it's a hack, but there's no
precedent for naming features this way.
  • Loading branch information
brson committed Feb 10, 2014
commit b4f483db9afe60a00be74200b5f42d05253432e6
10 changes: 7 additions & 3 deletions src/librustc/front/feature_gate.rs
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,9 @@ static KNOWN_FEATURES: &'static [(&'static str, Status)] = &[
("default_type_params", Active),
("quote", Active),

// This is a syntax extension hack
("__tt_map", Active),

// These are used to test this portion of the compiler, they don't actually
// mean anything
("test_accepted_feature", Accepted),
Expand Down Expand Up @@ -214,9 +217,10 @@ impl Visitor<()> for Context {
else if id == self.sess.ident_of("trace_macros") {
self.gate_feature("trace_macros", path.span, "`trace_macros` is not \
stable enough for use and is subject to change");
}

else {
} else if id == self.sess.ident_of("__tt_map_insert") ||
id == self.sess.ident_of("__tt_map_get_expr") {
self.gate_feature("__tt_map", path.span, "__tt_map_* is a hack");
} else {
for &quote in quotes.iter() {
if id == self.sess.ident_of(quote) {
self.gate_feature("quote", path.span, quote + msg);
Expand Down
13 changes: 11 additions & 2 deletions src/libsyntax/ext/base.rs
Original file line number Diff line number Diff line change
Expand Up @@ -259,6 +259,12 @@ pub fn syntax_expander_table() -> SyntaxEnv {
syntax_expanders.insert(intern(&"trace_macros"),
builtin_normal_expander(
ext::trace_macros::expand_trace_macros));
syntax_expanders.insert(intern(&"__tt_map_insert"),
builtin_normal_expander(
ext::tt_map::insert_expr));
syntax_expanders.insert(intern(&"__tt_map_get_expr"),
builtin_normal_expander(
ext::tt_map::get_expr));
syntax_expanders
}

Expand All @@ -283,7 +289,9 @@ pub struct ExtCtxt<'a> {
loader: &'a mut CrateLoader,

mod_path: ~[ast::Ident],
trace_mac: bool
trace_mac: bool,
// State for the hacky __tt_map_* extensions
tt_maps: HashMap<ast::Name, HashMap<ast::Name, ast::TokenTree>>,
}

impl<'a> ExtCtxt<'a> {
Expand All @@ -295,7 +303,8 @@ impl<'a> ExtCtxt<'a> {
backtrace: None,
loader: loader,
mod_path: ~[],
trace_mac: false
trace_mac: false,
tt_maps: HashMap::new()
}
}

Expand Down
114 changes: 114 additions & 0 deletions src/libsyntax/ext/tt_map.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

/*
* The token-tree map syntax extension maintains an arbitrary number
* of named maps from ident to token-tree. Token trees can be stored
* into a map with the `__tt_map_insert!` macro and retrieved as an
* expression with the `__tt_map_get_expr!` macro.
*
* This is a hack used to maintain the tables of constants used by
* the rustc error reporting system. In particular, it allows string
* literals to be reused in multiple places without duplication.
*/

use ast;
use codemap::Span;
use ext::base::{ExtCtxt, MacResult, MRExpr, MRItem};
use ext::build::AstBuilder;
use parse::token;
use parse::token::{gensym, get_ident};
use parse::new_parser_from_tts;
use std::hashmap::HashMap;

pub fn insert_expr(ecx: &mut ExtCtxt, sp: Span,
tts: &[ast::TokenTree]) -> MacResult {

if tts.len() != 5 {
ecx.span_fatal(sp, "incorrect number of arguments");
}

let idxs = [1, 3];
for i in idxs.iter() {
match &tts[*i] {
&ast::TTTok(_, token::COMMA) => (),
_ => ecx.span_fatal(sp, "expecting comma")
}
}

let map_name = tree_2_name(ecx, &tts[0]);
let key_name = tree_2_name(ecx, &tts[2]);
let expr = tts[4].clone();

if !ecx.tt_maps.contains_key(&map_name) {
ecx.tt_maps.insert(map_name.clone(), HashMap::new());
}

let existed = {
let mut maybe_map = ecx.tt_maps.find_mut(&map_name);
let map = maybe_map.get_mut_ref();
!map.insert(key_name, expr)
};

if existed {
let key_ident = get_ident(key_name);
let key_name = key_ident.get();
ecx.span_fatal(sp, format!("key {} already exists in map", key_name));
}

// This item isn't used
let dummy_ident = ast::Ident::new(gensym("dummy_name"));
let dummy_item = ecx.item_mod(sp, dummy_ident, ~[], ~[], ~[]);
return MRItem(dummy_item);
}

pub fn get_expr(ecx: &mut ExtCtxt, sp: Span,
tts: &[ast::TokenTree]) -> MacResult {

if tts.len() != 3 {
ecx.span_fatal(sp, "incorrect number of arguments");
}

match &tts[1] {
&ast::TTTok(_, token::COMMA) => (),
_ => ecx.span_fatal(sp, "expecting comma")
}

let map_name = tree_2_name(ecx, &tts[0]);
let key_name = tree_2_name(ecx, &tts[2]);

match ecx.tt_maps.find(&map_name) {
Some(map) => {
match map.find(&key_name) {
Some(map_tree) => {
MRExpr(tree_2_expr(ecx, map_tree))
}
None => {
let key_ident = get_ident(key_name);
let key_name = key_ident.get();
ecx.span_fatal(sp, format!("key {} does not exist in map", key_name));
}
}
}
None => {
ecx.span_fatal(sp, "map does not exist");
}
}
}

fn tree_2_name(ecx: &ExtCtxt, tts: &ast::TokenTree) -> ast::Name {
let mut p = new_parser_from_tts(ecx.parse_sess(), ecx.cfg.clone(), ~[tts.clone()]);
return p.parse_ident().name;
}

fn tree_2_expr(ecx: &ExtCtxt, tts: &ast::TokenTree) -> @ast::Expr {
let mut p = new_parser_from_tts(ecx.parse_sess(), ecx.cfg.clone(), ~[tts.clone()]);
return p.parse_expr();
}
1 change: 1 addition & 0 deletions src/libsyntax/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,7 @@ pub mod ext {
pub mod concat_idents;
pub mod log_syntax;
pub mod source_util;
pub mod tt_map;

pub mod trace_macros;
}
14 changes: 14 additions & 0 deletions src/test/compile-fail/gated-tt_map.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

fn main() {
__tt_map_insert!(A, B, C); //~ ERROR __tt_map_* is a hack
let _foo = __tt_map_get_expr!(A, B, C); //~ ERROR __tt_map_* is a hack
}
18 changes: 18 additions & 0 deletions src/test/run-pass/tt_map.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

fn main() {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This test doesn't seem to have feature(__tt_map)? This may also need pub fn main


let j = 2;
mod m { __tt_map_insert!(my_tt_map, i, j) }

let k = __tt_map_get_expr!(my_tt_map, i);
assert!(j == k);
}