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