From 5a158f1d19d93af4223fea2da49209e73a3ed002 Mon Sep 17 00:00:00 2001 From: John Clements Date: Tue, 4 Jun 2013 14:56:33 -0700 Subject: [PATCH] add hygiene support functions --- src/libsyntax/ext/base.rs | 10 +++++ src/libsyntax/ext/expand.rs | 58 ++++++++++++++++++++++++++-- src/libsyntax/parse/mod.rs | 34 ++++++---------- src/libsyntax/util/parser_testing.rs | 3 +- 4 files changed, 78 insertions(+), 27 deletions(-) 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"])); + } } diff --git a/src/libsyntax/parse/mod.rs b/src/libsyntax/parse/mod.rs index 7f7e607d37f..d7248204e1c 100644 --- a/src/libsyntax/parse/mod.rs +++ b/src/libsyntax/parse/mod.rs @@ -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)}, diff --git a/src/libsyntax/util/parser_testing.rs b/src/libsyntax/util/parser_testing.rs index 2b74ef7fbea..c5528069926 100644 --- a/src/libsyntax/util/parser_testing.rs +++ b/src/libsyntax/util/parser_testing.rs @@ -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(~[]) }