From 5a158f1d19d93af4223fea2da49209e73a3ed002 Mon Sep 17 00:00:00 2001 From: John Clements Date: Tue, 4 Jun 2013 14:56:33 -0700 Subject: add hygiene support functions --- src/libsyntax/ext/base.rs | 10 ++++++++ src/libsyntax/ext/expand.rs | 58 +++++++++++++++++++++++++++++++++++++++++---- 2 files changed, 64 insertions(+), 4 deletions(-) (limited to 'src/libsyntax/ext') diff --git a/src/libsyntax/ext/base.rs b/src/libsyntax/ext/base.rs index cc819a00f7d..a3432a00edc 100644 --- a/src/libsyntax/ext/base.rs +++ b/src/libsyntax/ext/base.rs @@ -479,6 +479,15 @@ impl MapChain{ } } + 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 MapChain{ } } +// returns true if the binding for 'n' satisfies 'pred' in 'map' fn satisfies_pred(map : &mut HashMap, n: &K, pred: &fn(&V)->bool) diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs index 47c22c438a8..f5edc50377e 100644 --- a/src/libsyntax/ext/expand.rs +++ b/src/libsyntax/ext/expand.rs @@ -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"])); + } } -- cgit 1.4.1-3-g733a5