@@ -155,57 +155,48 @@ pub enum SyntaxExtension {
155
155
// The SyntaxEnv is the environment that's threaded through the expansion
156
156
// of macros. It contains bindings for macros, and also a special binding
157
157
// for " block" (not a legal identifier) that maps to a BlockInfo
158
- pub type SyntaxEnv = @mut MapChain < Name , Transformer > ;
159
-
160
- // Transformer : the codomain of SyntaxEnvs
161
-
162
- pub enum Transformer {
163
- // this identifier maps to a syntax extension or macro
164
- SE ( SyntaxExtension ) ,
165
- // blockinfo : this is ... well, it's simpler than threading
166
- // another whole data stack-structured data structure through
167
- // expansion. Basically, there's an invariant that every
168
- // map must contain a binding for " block".
169
- BlockInfo ( BlockInfo )
170
- }
158
+ pub type SyntaxEnv = MapChain < Name , SyntaxExtension > ;
171
159
172
160
pub struct BlockInfo {
173
161
// should macros escape from this scope?
174
162
macros_escape : bool ,
175
163
// what are the pending renames?
176
- pending_renames : @mut RenameList
164
+ pending_renames : RenameList
165
+ }
166
+
167
+ impl BlockInfo {
168
+ pub fn new ( ) -> BlockInfo {
169
+ BlockInfo {
170
+ macros_escape : false ,
171
+ pending_renames : ~[ ]
172
+ }
173
+ }
177
174
}
178
175
179
176
// a list of ident->name renamings
180
- type RenameList = ~[ ( ast:: Ident , Name ) ] ;
177
+ pub type RenameList = ~[ ( ast:: Ident , Name ) ] ;
181
178
182
179
// The base map of methods for expanding syntax extension
183
180
// AST nodes into full ASTs
184
181
pub fn syntax_expander_table ( ) -> SyntaxEnv {
185
182
// utility function to simplify creating NormalTT syntax extensions
186
183
fn builtin_normal_tt_no_ctxt ( f : SyntaxExpanderTTFunNoCtxt )
187
- -> @ Transformer {
188
- @ SE ( NormalTT ( @SyntaxExpanderTT {
184
+ -> SyntaxExtension {
185
+ NormalTT ( @SyntaxExpanderTT {
189
186
expander : SyntaxExpanderTTExpanderWithoutContext ( f) ,
190
187
span : None ,
191
188
} as @SyntaxExpanderTTTrait ,
192
- None ) )
189
+ None )
193
190
}
194
191
195
- let mut syntax_expanders = HashMap :: new ( ) ;
196
- // NB identifier starts with space, and can't conflict with legal idents
197
- syntax_expanders. insert ( intern ( & " block" ) ,
198
- @BlockInfo ( BlockInfo {
199
- macros_escape : false ,
200
- pending_renames : @mut ~[ ]
201
- } ) ) ;
192
+ let mut syntax_expanders = MapChain :: new ( ) ;
202
193
syntax_expanders. insert ( intern ( & "macro_rules" ) ,
203
- @ SE ( IdentTT ( @SyntaxExpanderTTItem {
194
+ IdentTT ( @SyntaxExpanderTTItem {
204
195
expander : SyntaxExpanderTTItemExpanderWithContext (
205
196
ext:: tt:: macro_rules:: add_new_extension) ,
206
197
span : None ,
207
198
} as @SyntaxExpanderTTItemTrait ,
208
- None ) ) ) ;
199
+ None ) ) ;
209
200
syntax_expanders. insert ( intern ( & "fmt" ) ,
210
201
builtin_normal_tt_no_ctxt (
211
202
ext:: fmt:: expand_syntax_ext) ) ;
@@ -231,8 +222,7 @@ pub fn syntax_expander_table() -> SyntaxEnv {
231
222
builtin_normal_tt_no_ctxt (
232
223
ext:: log_syntax:: expand_syntax_ext) ) ;
233
224
syntax_expanders. insert ( intern ( & "deriving" ) ,
234
- @SE ( ItemDecorator (
235
- ext:: deriving:: expand_meta_deriving) ) ) ;
225
+ ItemDecorator ( ext:: deriving:: expand_meta_deriving) ) ;
236
226
237
227
// Quasi-quoting expanders
238
228
syntax_expanders. insert ( intern ( & "quote_tokens" ) ,
@@ -287,7 +277,7 @@ pub fn syntax_expander_table() -> SyntaxEnv {
287
277
syntax_expanders. insert ( intern ( & "trace_macros" ) ,
288
278
builtin_normal_tt_no_ctxt (
289
279
ext:: trace_macros:: expand_trace_macros) ) ;
290
- MapChain :: new ( ~ syntax_expanders)
280
+ syntax_expanders
291
281
}
292
282
293
283
// One of these is made during expansion and incrementally updated as we go;
@@ -298,11 +288,6 @@ pub struct ExtCtxt {
298
288
cfg : ast:: CrateConfig ,
299
289
backtrace : Option < @ExpnInfo > ,
300
290
301
- // These two @mut's should really not be here,
302
- // but the self types for CtxtRepr are all wrong
303
- // and there are bugs in the code for object
304
- // types that make this hard to get right at the
305
- // moment. - nmatsakis
306
291
mod_path : ~[ ast:: Ident ] ,
307
292
trace_mac : bool
308
293
}
@@ -324,7 +309,7 @@ impl ExtCtxt {
324
309
match e. node {
325
310
ast:: ExprMac ( ..) => {
326
311
let mut expander = expand:: MacroExpander {
327
- extsbox : @ mut syntax_expander_table ( ) ,
312
+ extsbox : syntax_expander_table ( ) ,
328
313
cx : self ,
329
314
} ;
330
315
e = expand:: expand_expr ( e, & mut expander) ;
@@ -459,11 +444,7 @@ pub fn get_exprs_from_tts(cx: &ExtCtxt,
459
444
// we want to implement the notion of a transformation
460
445
// environment.
461
446
462
- // This environment maps Names to Transformers.
463
- // Initially, this includes macro definitions and
464
- // block directives.
465
-
466
-
447
+ // This environment maps Names to SyntaxExtensions.
467
448
468
449
// Actually, the following implementation is parameterized
469
450
// by both key and value types.
@@ -478,169 +459,98 @@ pub fn get_exprs_from_tts(cx: &ExtCtxt,
478
459
// able to refer to a macro that was added to an enclosing
479
460
// scope lexically later than the deeper scope.
480
461
481
- // Note on choice of representation: I've been pushed to
482
- // use a top-level managed pointer by some difficulties
483
- // with pushing and popping functionally, and the ownership
484
- // issues. As a result, the values returned by the table
485
- // also need to be managed; the &'a ... type that Maps
486
- // return won't work for things that need to get outside
487
- // of that managed pointer. The easiest way to do this
488
- // is just to insist that the values in the tables are
489
- // managed to begin with.
490
-
491
- // a transformer env is either a base map or a map on top
492
- // of another chain.
493
- pub enum MapChain < K , V > {
494
- BaseMapChain ( ~HashMap < K , @V > ) ,
495
- ConsMapChain ( ~HashMap < K , @V > , @mut MapChain < K , V > )
462
+ // Only generic to make it easy to test
463
+ struct MapChainFrame < K , V > {
464
+ info : BlockInfo ,
465
+ map : HashMap < K , V > ,
496
466
}
497
467
468
+ // Only generic to make it easy to test
469
+ pub struct MapChain < K , V > {
470
+ priv chain : ~[ MapChainFrame < K , V > ] ,
471
+ }
498
472
499
- // get the map from an env frame
500
- impl < K : Eq + Hash + IterBytes + ' static , V : ' static > MapChain < K , V > {
501
- // Constructor. I don't think we need a zero-arg one.
502
- pub fn new ( init : ~ HashMap < K , @ V > ) -> @ mut MapChain < K , V > {
503
- @ mut BaseMapChain ( init )
473
+ impl < K : Hash + Eq , V > MapChain < K , V > {
474
+ pub fn new ( ) - > MapChain < K , V > {
475
+ let mut map = MapChain { chain : ~ [ ] } ;
476
+ map . push_frame ( ) ;
477
+ map
504
478
}
505
479
506
- // add a new frame to the environment (functionally)
507
- pub fn push_frame ( @mut self ) -> @mut MapChain < K , V > {
508
- @mut ConsMapChain ( ~HashMap :: new ( ) , self )
480
+ pub fn push_frame ( & mut self ) {
481
+ self . chain . push ( MapChainFrame {
482
+ info : BlockInfo :: new ( ) ,
483
+ map : HashMap :: new ( ) ,
484
+ } ) ;
509
485
}
510
486
511
- // no need for pop, it'll just be functional.
512
-
513
- // utility fn...
514
-
515
- // ugh: can't get this to compile with mut because of the
516
- // lack of flow sensitivity.
517
- pub fn get_map < ' a > ( & ' a self ) -> & ' a HashMap < K , @V > {
518
- match * self {
519
- BaseMapChain ( ~ref map) => map,
520
- ConsMapChain ( ~ref map, _) => map
521
- }
487
+ pub fn pop_frame ( & mut self ) {
488
+ assert ! ( self . chain. len( ) > 1 , "too many pops on MapChain!" ) ;
489
+ self . chain . pop ( ) ;
522
490
}
523
491
524
- // traits just don't work anywhere...?
525
- //impl Map<Name,SyntaxExtension> for MapChain {
526
-
527
- pub fn contains_key ( & self , key : & K ) -> bool {
528
- match * self {
529
- BaseMapChain ( ref map) => map. contains_key ( key) ,
530
- ConsMapChain ( ref map, ref rest) =>
531
- ( map. contains_key ( key)
532
- || rest. contains_key ( key) )
492
+ fn find_escape_frame < ' a > ( & ' a mut self ) -> & ' a mut MapChainFrame < K , V > {
493
+ for ( i, frame) in self . chain . mut_iter ( ) . enumerate ( ) . invert ( ) {
494
+ if !frame. info . macros_escape || i == 0 {
495
+ return frame
496
+ }
533
497
}
534
- }
535
- // should each_key and each_value operate on shadowed
536
- // names? I think not.
537
- // delaying implementing this....
538
- pub fn each_key ( & self , _f: |& K | -> bool) {
539
- fail ! ( "unimplemented 2013-02-15T10:01" ) ;
540
- }
541
-
542
- pub fn each_value ( & self , _f: |& V | -> bool) {
543
- fail ! ( "unimplemented 2013-02-15T10:02" ) ;
498
+ unreachable ! ( )
544
499
}
545
500
546
- // Returns a copy of the value that the name maps to.
547
- // Goes down the chain 'til it finds one (or bottom out).
548
- pub fn find ( & self , key : & K ) -> Option < @V > {
549
- match self . get_map ( ) . find ( key) {
550
- Some ( ref v) => Some ( * * v) ,
551
- None => match * self {
552
- BaseMapChain ( _) => None ,
553
- ConsMapChain ( _, ref rest) => rest. find ( key)
501
+ pub fn find < ' a > ( & ' a self , k : & K ) -> Option < & ' a V > {
502
+ for frame in self . chain . iter ( ) . invert ( ) {
503
+ match frame. map . find ( k) {
504
+ Some ( v) => return Some ( v) ,
505
+ None => { }
554
506
}
555
507
}
508
+ None
556
509
}
557
510
558
- pub fn find_in_topmost_frame ( & self , key : & K ) -> Option < @V > {
559
- let map = match * self {
560
- BaseMapChain ( ref map) => map,
561
- ConsMapChain ( ref map, _) => map
562
- } ;
563
- // strip one layer of indirection off the pointer.
564
- map. find ( key) . map ( |r| { * r} )
565
- }
566
-
567
- // insert the binding into the top-level map
568
- pub fn insert ( & mut self , key : K , ext : @V ) -> bool {
569
- // can't abstract over get_map because of flow sensitivity...
570
- match * self {
571
- BaseMapChain ( ~ref mut map) => map. insert ( key, ext) ,
572
- ConsMapChain ( ~ref mut map, _) => map. insert ( key, ext)
573
- }
511
+ pub fn insert ( & mut self , k : K , v : V ) {
512
+ self . find_escape_frame ( ) . map . insert ( k, v) ;
574
513
}
575
- // insert the binding into the topmost frame for which the binding
576
- // associated with 'n' exists and satisfies pred
577
- // ... there are definitely some opportunities for abstraction
578
- // here that I'm ignoring. (e.g., manufacturing a predicate on
579
- // the maps in the chain, and using an abstract "find".
580
- pub fn insert_into_frame ( & mut self ,
581
- key : K ,
582
- ext : @V ,
583
- n : K ,
584
- pred: |& @V | -> bool) {
585
- match * self {
586
- BaseMapChain ( ~ref mut map) => {
587
- if satisfies_pred ( map, & n, pred) {
588
- map. insert ( key, ext) ;
589
- } else {
590
- fail ! ( "expected map chain containing satisfying frame" )
591
- }
592
- } ,
593
- ConsMapChain ( ~ref mut map, rest) => {
594
- if satisfies_pred ( map, & n, |v|pred ( v) ) {
595
- map. insert ( key, ext) ;
596
- } else {
597
- rest. insert_into_frame ( key, ext, n, pred)
598
- }
599
- }
600
- }
601
- }
602
- }
603
514
604
- // returns true if the binding for 'n' satisfies 'pred' in 'map'
605
- fn satisfies_pred < K : Eq + Hash + IterBytes ,
606
- V > (
607
- map : & mut HashMap < K , V > ,
608
- n : & K ,
609
- pred: |& V | -> bool)
610
- -> bool {
611
- match map. find ( n) {
612
- Some ( ref v) => ( pred ( * v) ) ,
613
- None => false
515
+ pub fn info < ' a > ( & ' a mut self ) -> & ' a mut BlockInfo {
516
+ & mut self . chain [ self . chain . len ( ) -1 ] . info
614
517
}
615
518
}
616
519
617
520
#[ cfg( test) ]
618
521
mod test {
619
522
use super :: MapChain ;
620
- use std:: hashmap:: HashMap ;
621
523
622
524
#[ test]
623
525
fn testenv ( ) {
624
- let mut a = HashMap :: new ( ) ;
625
- a. insert ( @"abc", @15 ) ;
626
- let m = MapChain :: new ( ~a) ;
627
- m. insert ( @"def", @16 ) ;
628
- assert_eq ! ( m. find( & @"abc" ) , Some ( @15 ) ) ;
629
- assert_eq ! ( m. find( & @"def" ) , Some ( @16 ) ) ;
630
- assert_eq ! ( * ( m. find( & @"abc" ) . unwrap( ) ) , 15 ) ;
631
- assert_eq ! ( * ( m. find( & @"def" ) . unwrap( ) ) , 16 ) ;
632
- let n = m. push_frame ( ) ;
633
- // old bindings are still present:
634
- assert_eq ! ( * ( n. find( & @"abc" ) . unwrap( ) ) , 15 ) ;
635
- assert_eq ! ( * ( n. find( & @"def" ) . unwrap( ) ) , 16 ) ;
636
- n. insert ( @"def", @17 ) ;
637
- // n shows the new binding
638
- assert_eq ! ( * ( n. find( & @"abc" ) . unwrap( ) ) , 15 ) ;
639
- assert_eq ! ( * ( n. find( & @"def" ) . unwrap( ) ) , 17 ) ;
640
- // ... but m still has the old ones
641
- assert_eq ! ( m. find( & @"abc" ) , Some ( @15 ) ) ;
642
- assert_eq ! ( m. find( & @"def" ) , Some ( @16 ) ) ;
643
- assert_eq ! ( * ( m. find( & @"abc" ) . unwrap( ) ) , 15 ) ;
644
- assert_eq ! ( * ( m. find( & @"def" ) . unwrap( ) ) , 16 ) ;
526
+ let mut m = MapChain :: new ( ) ;
527
+ let ( a, b, c, d) = ( "a" , "b" , "c" , "d" ) ;
528
+ m. insert ( 1 , a) ;
529
+ assert_eq ! ( Some ( & a) , m. find( & 1 ) ) ;
530
+
531
+ m. push_frame ( ) ;
532
+ m. info ( ) . macros_escape = true ;
533
+ m. insert ( 2 , b) ;
534
+ assert_eq ! ( Some ( & a) , m. find( & 1 ) ) ;
535
+ assert_eq ! ( Some ( & b) , m. find( & 2 ) ) ;
536
+ m. pop_frame ( ) ;
537
+
538
+ assert_eq ! ( Some ( & a) , m. find( & 1 ) ) ;
539
+ assert_eq ! ( Some ( & b) , m. find( & 2 ) ) ;
540
+
541
+ m. push_frame ( ) ;
542
+ m. push_frame ( ) ;
543
+ m. info ( ) . macros_escape = true ;
544
+ m. insert ( 3 , c) ;
545
+ assert_eq ! ( Some ( & c) , m. find( & 3 ) ) ;
546
+ m. pop_frame ( ) ;
547
+ assert_eq ! ( Some ( & c) , m. find( & 3 ) ) ;
548
+ m. pop_frame ( ) ;
549
+ assert_eq ! ( None , m. find( & 3 ) ) ;
550
+
551
+ m. push_frame ( ) ;
552
+ m. insert ( 4 , d) ;
553
+ m. pop_frame ( ) ;
554
+ assert_eq ! ( None , m. find( & 4 ) ) ;
645
555
}
646
556
}
0 commit comments