@@ -344,15 +344,16 @@ fn expand_item(it: Gc<ast::Item>, fld: &mut MacroExpander)
344
344
345
345
fn expand_item_modifiers ( mut it : Gc < ast:: Item > , fld : & mut MacroExpander )
346
346
-> Gc < ast:: Item > {
347
- let ( modifiers, attrs) = it. attrs . partitioned ( |attr| {
347
+ // partition the attributes into ItemModifiers and others
348
+ let ( modifiers, other_attrs) = it. attrs . partitioned ( |attr| {
348
349
match fld. extsbox . find ( & intern ( attr. name ( ) . get ( ) ) ) {
349
350
Some ( & ItemModifier ( _) ) => true ,
350
351
_ => false
351
352
}
352
353
} ) ;
353
-
354
+ // update the attrs, leave everything else alone. Is this mutation really a good idea?
354
355
it = box ( GC ) ast:: Item {
355
- attrs : attrs ,
356
+ attrs : other_attrs ,
356
357
..( * it) . clone ( )
357
358
} ;
358
359
@@ -385,6 +386,34 @@ fn expand_item_modifiers(mut it: Gc<ast::Item>, fld: &mut MacroExpander)
385
386
expand_item_modifiers ( it, fld)
386
387
}
387
388
389
+ /// Expand item_underscore
390
+ fn expand_item_underscore ( item : & ast:: Item_ , fld : & mut MacroExpander ) -> ast:: Item_ {
391
+ match * item {
392
+ ast:: ItemFn ( decl, fn_style, abi, ref generics, body) => {
393
+ let expanded_decl = fld. fold_fn_decl ( decl) ;
394
+ // avoiding the pattern_bindings abstraction here
395
+ // for efficiency's sake, to re-use one mutable vector
396
+ // in the collection.
397
+ let mut pat_idents = PatIdentFinder { ident_accumulator : Vec :: new ( ) } ;
398
+ //pat_idents.visit_fn_decl(expanded_decl,());
399
+ for arg in expanded_decl. inputs . iter ( ) {
400
+ pat_idents. visit_pat ( arg. pat , ( ) ) ;
401
+ }
402
+ let idents = pat_idents. ident_accumulator ;
403
+ let new_pending_renames =
404
+ idents. iter ( ) . map ( |id : & ast:: Ident | ( * id, fresh_name ( id) ) ) . collect ( ) ;
405
+ let mut rename_pat_fld = PatIdentRenamer { renames : & new_pending_renames} ;
406
+ let rewritten_fn_decl = rename_pat_fld. fold_fn_decl ( expanded_decl) ;
407
+ // now, a renamer for *all* idents:
408
+ let mut rename_fld = IdentRenamer { renames : & new_pending_renames} ;
409
+ let rewritten_body = fld. fold_block ( rename_fld. fold_block ( body) ) ;
410
+ let expanded_generics = fold:: fold_generics ( generics, fld) ;
411
+ ast:: ItemFn ( rewritten_fn_decl, fn_style, abi, expanded_generics, rewritten_body)
412
+ }
413
+ _ => noop_fold_item_underscore ( & * item, fld)
414
+ }
415
+ }
416
+
388
417
// does this attribute list contain "macro_escape" ?
389
418
fn contains_macro_escape ( attrs : & [ ast:: Attribute ] ) -> bool {
390
419
attr:: contains_name ( attrs, "macro_escape" )
@@ -667,19 +696,14 @@ fn expand_arm(arm: &ast::Arm, fld: &mut MacroExpander) -> ast::Arm {
667
696
// code duplicated from 'let', above. Perhaps this can be lifted
668
697
// into a separate function:
669
698
let idents = pattern_bindings ( * first_pat) ;
670
- let mut new_pending_renames =
699
+ let new_pending_renames =
671
700
idents. iter ( ) . map ( |id| ( * id, fresh_name ( id) ) ) . collect ( ) ;
672
- // rewrite all of the patterns using the new names (the old
673
- // ones have already been applied). Note that we depend here
674
- // on the guarantee that after expansion, there can't be any
675
- // Path expressions (a.k.a. varrefs) left in the pattern. If
676
- // this were false, we'd need to apply this renaming only to
677
- // the bindings, and not to the varrefs, using a more targeted
678
- // fold-er.
679
- let mut rename_fld = IdentRenamer { renames : & mut new_pending_renames} ;
701
+ // apply the renaming, but only to the PatIdents:
702
+ let mut rename_pats_fld = PatIdentRenamer { renames : & new_pending_renames} ;
680
703
let rewritten_pats =
681
- expanded_pats. iter ( ) . map ( |pat| rename_fld . fold_pat ( * pat) ) . collect ( ) ;
704
+ expanded_pats. iter ( ) . map ( |pat| rename_pats_fld . fold_pat ( * pat) ) . collect ( ) ;
682
705
// apply renaming and then expansion to the guard and the body:
706
+ let mut rename_fld = IdentRenamer { renames : & new_pending_renames} ;
683
707
let rewritten_guard =
684
708
arm. guard . map ( |g| fld. fold_expr ( rename_fld. fold_expr ( g) ) ) ;
685
709
let rewritten_body = fld. fold_expr ( rename_fld. fold_expr ( arm. body ) ) ;
@@ -905,6 +929,10 @@ impl<'a, 'b> Folder for MacroExpander<'a, 'b> {
905
929
expand_item ( item, self )
906
930
}
907
931
932
+ fn fold_item_underscore ( & mut self , item : & ast:: Item_ ) -> ast:: Item_ {
933
+ expand_item_underscore ( item, self )
934
+ }
935
+
908
936
fn fold_stmt ( & mut self , stmt : & ast:: Stmt ) -> SmallVector < Gc < ast:: Stmt > > {
909
937
expand_stmt ( stmt, self )
910
938
}
@@ -1052,13 +1080,14 @@ fn original_span(cx: &ExtCtxt) -> Gc<codemap::ExpnInfo> {
1052
1080
#[ cfg( test) ]
1053
1081
mod test {
1054
1082
use super :: { pattern_bindings, expand_crate, contains_macro_escape} ;
1055
- use super :: { PatIdentFinder } ;
1083
+ use super :: { PatIdentFinder , IdentRenamer , PatIdentRenamer } ;
1056
1084
use ast;
1057
1085
use ast:: { Attribute_ , AttrOuter , MetaWord } ;
1058
1086
use attr;
1059
1087
use codemap;
1060
1088
use codemap:: Spanned ;
1061
1089
use ext:: mtwt;
1090
+ use fold:: Folder ;
1062
1091
use parse;
1063
1092
use parse:: token;
1064
1093
use util:: parser_testing:: { string_to_parser} ;
@@ -1096,7 +1125,24 @@ mod test {
1096
1125
path_finder. path_accumulator
1097
1126
}
1098
1127
1128
+ /// A Visitor that extracts the identifiers from a thingy.
1129
+ // as a side note, I'm starting to want to abstract over these....
1130
+ struct IdentFinder {
1131
+ ident_accumulator : Vec < ast:: Ident >
1132
+ }
1099
1133
1134
+ impl Visitor < ( ) > for IdentFinder {
1135
+ fn visit_ident ( & mut self , _: codemap:: Span , id : ast:: Ident , _: ( ) ) {
1136
+ self . ident_accumulator . push ( id) ;
1137
+ }
1138
+ }
1139
+
1140
+ /// Find the idents in a crate
1141
+ fn crate_idents ( the_crate : & ast:: Crate ) -> Vec < ast:: Ident > {
1142
+ let mut ident_finder = IdentFinder { ident_accumulator : Vec :: new ( ) } ;
1143
+ visit:: walk_crate ( & mut ident_finder, the_crate, ( ) ) ;
1144
+ ident_finder. ident_accumulator
1145
+ }
1100
1146
1101
1147
// these following tests are quite fragile, in that they don't test what
1102
1148
// *kind* of failure occurs.
@@ -1196,6 +1242,7 @@ mod test {
1196
1242
name_finder. ident_accumulator
1197
1243
}
1198
1244
1245
+
1199
1246
//fn expand_and_resolve(crate_str: @str) -> ast::crate {
1200
1247
//let expanded_ast = expand_crate_str(crate_str);
1201
1248
// println!("expanded: {:?}\n",expanded_ast);
@@ -1321,7 +1368,7 @@ mod test {
1321
1368
// but *shouldnt* bind because it was inserted by a different macro....
1322
1369
// can't write this test case until we have macro-generating macros.
1323
1370
1324
- // FIXME #9383 : lambda var hygiene
1371
+ // lambda var hygiene
1325
1372
// expands to fn q(x_1:int){fn g(x_2:int){x_2 + x_1};}
1326
1373
#[ test]
1327
1374
fn issue_9383 ( ) {
@@ -1380,9 +1427,9 @@ mod test {
1380
1427
assert_eq ! ( varref_marks, binding_marks. clone( ) ) ;
1381
1428
}
1382
1429
} else {
1430
+ let varref_name = mtwt:: resolve ( varref. segments . get ( 0 ) . identifier ) ;
1383
1431
let fail = ( varref. segments . len ( ) == 1 )
1384
- && ( mtwt:: resolve ( varref. segments . get ( 0 ) . identifier )
1385
- == binding_name) ;
1432
+ && ( varref_name == binding_name) ;
1386
1433
// temp debugging:
1387
1434
if fail {
1388
1435
let varref_idents : Vec < ast:: Ident >
@@ -1393,15 +1440,18 @@ mod test {
1393
1440
println ! ( "text of test case: \" {}\" " , teststr) ;
1394
1441
println ! ( "" ) ;
1395
1442
println ! ( "uh oh, matches but shouldn't:" ) ;
1396
- println ! ( "varref: {}" , varref_idents) ;
1443
+ println ! ( "varref #{}: {}, resolves to {}" , idx, varref_idents,
1444
+ varref_name) ;
1397
1445
// good lord, you can't make a path with 0 segments, can you?
1398
1446
let string = token:: get_ident ( varref. segments
1399
1447
. get ( 0 )
1400
1448
. identifier ) ;
1401
1449
println ! ( "varref's first segment's uint: {}, and string: \" {}\" " ,
1402
1450
varref. segments. get( 0 ) . identifier. name,
1403
1451
string. get( ) ) ;
1404
- println ! ( "binding: {}" , * bindings. get( binding_idx) ) ;
1452
+ println ! ( "binding #{}: {}, resolves to {}" ,
1453
+ binding_idx, * bindings. get( binding_idx) ,
1454
+ binding_name) ;
1405
1455
mtwt:: with_sctable ( |x| mtwt:: display_sctable ( x) ) ;
1406
1456
}
1407
1457
assert ! ( !fail) ;
@@ -1464,13 +1514,43 @@ foo_module!()
1464
1514
// 'None' is listed as an identifier pattern because we don't yet know that
1465
1515
// it's the name of a 0-ary variant, and that 'i' appears twice in succession.
1466
1516
#[ test]
1467
- fn crate_idents ( ) {
1517
+ fn crate_bindings_test ( ) {
1468
1518
let the_crate = string_to_crate ( "fn main (a : int) -> int {|b| {
1469
1519
match 34 {None => 3, Some(i) | i => j, Foo{k:z,l:y} => \" banana\" }} }" . to_string ( ) ) ;
1470
1520
let idents = crate_bindings ( & the_crate) ;
1471
1521
assert_eq ! ( idents, strs_to_idents( vec!( "a" , "b" , "None" , "i" , "i" , "z" , "y" ) ) ) ;
1472
1522
}
1473
1523
1474
- //
1524
+ // test the IdentRenamer directly
1525
+ #[ test]
1526
+ fn ident_renamer_test ( ) {
1527
+ let the_crate = string_to_crate ( "fn f(x : int){let x = x; x}" . to_string ( ) ) ;
1528
+ let f_ident = token:: str_to_ident ( "f" ) ;
1529
+ let x_ident = token:: str_to_ident ( "x" ) ;
1530
+ let int_ident = token:: str_to_ident ( "int" ) ;
1531
+ let renames = vec ! ( ( x_ident, 16 ) ) ;
1532
+ let mut renamer = IdentRenamer { renames : & renames} ;
1533
+ let renamed_crate = renamer. fold_crate ( the_crate) ;
1534
+ let idents = crate_idents ( & renamed_crate) ;
1535
+ let resolved : Vec < ast:: Name > = idents. iter ( ) . map ( |id| mtwt:: resolve ( * id) ) . collect ( ) ;
1536
+ assert_eq ! ( resolved, vec!( f_ident. name, 16 , int_ident. name, 16 , 16 , 16 ) ) ;
1537
+ }
1538
+
1539
+ // test the PatIdentRenamer; only PatIdents get renamed
1540
+ #[ test]
1541
+ fn pat_ident_renamer_test ( ) {
1542
+ let the_crate = string_to_crate ( "fn f(x : int){let x = x; x}" . to_string ( ) ) ;
1543
+ let f_ident = token:: str_to_ident ( "f" ) ;
1544
+ let x_ident = token:: str_to_ident ( "x" ) ;
1545
+ let int_ident = token:: str_to_ident ( "int" ) ;
1546
+ let renames = vec ! ( ( x_ident, 16 ) ) ;
1547
+ let mut renamer = PatIdentRenamer { renames : & renames} ;
1548
+ let renamed_crate = renamer. fold_crate ( the_crate) ;
1549
+ let idents = crate_idents ( & renamed_crate) ;
1550
+ let resolved : Vec < ast:: Name > = idents. iter ( ) . map ( |id| mtwt:: resolve ( * id) ) . collect ( ) ;
1551
+ let x_name = x_ident. name ;
1552
+ assert_eq ! ( resolved, vec!( f_ident. name, 16 , int_ident. name, 16 , x_name, x_name) ) ;
1553
+ }
1554
+
1475
1555
1476
1556
}
0 commit comments