add hygiene support functions

This commit is contained in:
John Clements 2013-06-04 14:56:33 -07:00
parent ecdb6e4722
commit 5a158f1d19
4 changed files with 78 additions and 27 deletions

View File

@ -479,6 +479,15 @@ impl <K: Eq + Hash + IterBytes ,V: Copy> MapChain<K,V>{
}
}
fn find_in_topmost_frame(&self, key: &K) -> Option<@V> {
let map = match *self {
BaseMapChain(ref map) => map,
ConsMapChain(ref map,_) => map
};
// strip one layer of indirection off the pointer.
map.find(key).map(|r| {**r})
}
// insert the binding into the top-level map
fn insert (&mut self, key: K, ext: @V) -> bool {
// can't abstract over get_map because of flow sensitivity...
@ -512,6 +521,7 @@ impl <K: Eq + Hash + IterBytes ,V: Copy> MapChain<K,V>{
}
}
// returns true if the binding for 'n' satisfies 'pred' in 'map'
fn satisfies_pred<K : Eq + Hash + IterBytes,V>(map : &mut HashMap<K,V>,
n: &K,
pred: &fn(&V)->bool)

View File

@ -11,8 +11,8 @@
use core::prelude::*;
use ast::{blk_, attribute_, attr_outer, meta_word};
use ast::{crate, expr_, expr_mac, mac_invoc_tt};
use ast::{item_mac, stmt_, stmt_mac, stmt_expr, stmt_semi};
use ast::{crate, decl_local, expr_, expr_mac, mac_invoc_tt};
use ast::{item_mac, local_, stmt_, stmt_decl, stmt_mac, stmt_expr, stmt_semi};
use ast::{SCTable, illegal_ctxt};
use ast;
use ast_util::{new_rename, new_mark, resolve, new_sctable};
@ -26,6 +26,8 @@ use fold::*;
use parse;
use parse::{parse_item_from_source_str};
use parse::token::{ident_to_str, intern};
use visit;
use visit::{Visitor,mk_vt};
use core::vec;
@ -276,13 +278,13 @@ pub fn expand_item_mac(extsbox: @mut SyntaxEnv,
// insert a macro into the innermost frame that doesn't have the
// macro_escape tag.
fn insert_macro(exts: SyntaxEnv, name: ast::Name, transformer: @Transformer) {
let block_err_msg = "special identifier ' block' was bound to a non-BlockInfo";
let is_non_escaping_block =
|t : &@Transformer| -> bool{
match t {
&@BlockInfo(BlockInfo {macros_escape:false,_}) => true,
&@BlockInfo(BlockInfo {_}) => false,
_ => fail!(block_err_msg)
_ => fail!(fmt!("special identifier %? was bound to a non-BlockInfo",
special_block_name))
}
};
exts.insert_into_frame(name,transformer,intern(special_block_name),
@ -365,6 +367,34 @@ pub fn expand_stmt(extsbox: @mut SyntaxEnv,
}
// return a visitor that extracts the pat_ident paths
// from a given pattern and puts them in a mutable
// array (passed in to the traversal
pub fn new_name_finder() -> @Visitor<@mut ~[ast::ident]> {
let default_visitor = visit::default_visitor();
@Visitor{
visit_pat : |p:@ast::pat,ident_accum:@mut ~[ast::ident],v:visit::vt<@mut ~[ast::ident]>| {
match *p {
// we found a pat_ident!
ast::pat{id:_, node: ast::pat_ident(_,path,ref inner), span:_} => {
match path {
// a path of length one:
@ast::Path{global: false,idents: [id], span:_,rp:_,types:_} =>
ident_accum.push(id),
// I believe these must be enums...
_ => ()
}
// visit optional subpattern of pat_ident:
for inner.each |subpat: &@ast::pat| { (v.visit_pat)(*subpat, ident_accum, v) }
}
// use the default traversal for non-pat_idents
_ => visit::visit_pat(p,ident_accum,v)
}
},
.. *default_visitor
}
}
pub fn expand_block(extsbox: @mut SyntaxEnv,
@ -378,6 +408,17 @@ pub fn expand_block(extsbox: @mut SyntaxEnv,
with_exts_frame!(extsbox,false,orig(blk,sp,fld))
}
// get the (innermost) BlockInfo from an exts stack
fn get_block_info(exts : SyntaxEnv) -> BlockInfo {
match exts.find_in_topmost_frame(&intern(special_block_name)) {
Some(@BlockInfo(bi)) => bi,
_ => fail!(fmt!("special identifier %? was bound to a non-BlockInfo",
@~" block"))
}
}
// given a mutable list of renames, return a tree-folder that applies those
// renames.
fn renames_to_fold(renames : @mut ~[(ast::ident,ast::Name)]) -> @ast_fold {
@ -738,6 +779,7 @@ mod test {
use core::io;
use core::option::{None, Some};
use util::parser_testing::{string_to_item, string_to_pat, strs_to_idents};
use visit::{mk_vt,Visitor};
// make sure that fail! is present
#[test] fn fail_exists_test () {
@ -857,4 +899,12 @@ mod test {
io::print(fmt!("ast: %?\n",resolved_ast))
}
#[test]
fn pat_idents(){
let pat = string_to_pat(@~"(a,Foo{x:c @ (b,9),y:Bar(4,d)})");
let pat_idents = new_name_finder();
let idents = @mut ~[];
((*pat_idents).visit_pat)(pat,idents, mk_vt(pat_idents));
assert_eq!(idents,@mut strs_to_idents(~["a","c","b","d"]));
}
}

View File

@ -347,7 +347,7 @@ mod test {
use parse::token::{intern, str_to_ident};
use util::parser_testing::{string_to_tts_and_sess, string_to_parser};
use util::parser_testing::{string_to_expr, string_to_item};
use util::parser_testing::{string_to_stmt};
use util::parser_testing::{string_to_stmt, strs_to_idents};
// map a string to tts, return the tt without its parsesess
fn string_to_tts_only(source_str : @~str) -> ~[ast::token_tree] {
@ -368,22 +368,12 @@ mod test {
span{lo:BytePos(a),hi:BytePos(b),expn_info:None}
}
// compose new_ident and intern:
fn intern_ident(str : &str) -> ast::ident {
new_ident(intern(str))
}
// convert a vector of uints to a vector of ast::idents
fn ints_to_idents(ids: ~[~str]) -> ~[ast::ident] {
ids.map(|u| intern_ident(*u))
}
#[test] fn path_exprs_1 () {
assert_eq!(string_to_expr(@~"a"),
@ast::expr{id:1,
node:ast::expr_path(@ast::Path {span:sp(0,1),
global:false,
idents:~[intern_ident("a")],
idents:~[str_to_ident("a")],
rp:None,
types:~[]}),
span:sp(0,1)})
@ -395,7 +385,7 @@ mod test {
node:ast::expr_path(
@ast::Path {span:sp(0,6),
global:true,
idents:ints_to_idents(~[~"a",~"b"]),
idents:strs_to_idents(~["a","b"]),
rp:None,
types:~[]}),
span:sp(0,6)})
@ -445,7 +435,7 @@ mod test {
node:ast::expr_path(
@ast::Path{span:sp(7,8),
global:false,
idents:~[intern_ident("d")],
idents:~[str_to_ident("d")],
rp:None,
types:~[]
}),
@ -462,7 +452,7 @@ mod test {
@ast::Path{
span:sp(0,1),
global:false,
idents:~[intern_ident("b")],
idents:~[str_to_ident("b")],
rp:None,
types: ~[]}),
span: sp(0,1)},
@ -483,7 +473,7 @@ mod test {
@ast::Path{
span:sp(0,1),
global:false,
idents:~[intern_ident("b")],
idents:~[str_to_ident("b")],
rp: None,
types: ~[]},
None // no idea
@ -502,7 +492,7 @@ mod test {
span:sp(4,4), // this is bizarre...
// check this in the original parser?
global:false,
idents:~[intern_ident("int")],
idents:~[str_to_ident("int")],
rp: None,
types: ~[]},
2),
@ -512,7 +502,7 @@ mod test {
@ast::Path{
span:sp(0,1),
global:false,
idents:~[intern_ident("b")],
idents:~[str_to_ident("b")],
rp: None,
types: ~[]},
None // no idea
@ -528,7 +518,7 @@ mod test {
// assignment order of the node_ids.
assert_eq!(string_to_item(@~"fn a (b : int) { b; }"),
Some(
@ast::item{ident:intern_ident("a"),
@ast::item{ident:str_to_ident("a"),
attrs:~[],
id: 9, // fixme
node: ast::item_fn(ast::fn_decl{
@ -538,7 +528,7 @@ mod test {
node: ast::ty_path(@ast::Path{
span:sp(10,13),
global:false,
idents:~[intern_ident("int")],
idents:~[str_to_ident("int")],
rp: None,
types: ~[]},
2),
@ -549,7 +539,7 @@ mod test {
@ast::Path{
span:sp(6,7),
global:false,
idents:~[intern_ident("b")],
idents:~[str_to_ident("b")],
rp: None,
types: ~[]},
None // no idea
@ -579,7 +569,7 @@ mod test {
@ast::Path{
span:sp(17,18),
global:false,
idents:~[intern_ident("b")],
idents:~[str_to_ident("b")],
rp:None,
types: ~[]}),
span: sp(17,18)},

View File

@ -54,7 +54,8 @@ pub fn string_to_item_and_sess (source_str : @~str) -> (Option<@ast::item>,@mut
(p.parse_item(~[]),ps)
}
pub fn string_to_stmt (source_str : @~str) -> @ast::stmt {
// parse a string, return a stmt
pub fn string_to_stmt(source_str : @~str) -> @ast::stmt {
string_to_parser(source_str).parse_stmt(~[])
}