@@ -155,57 +155,48 @@ pub enum SyntaxExtension {
155155// The SyntaxEnv is the environment that's threaded through the expansion
156156// of macros. It contains bindings for macros, and also a special binding
157157// 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 > ;
171159
172160pub struct BlockInfo {
173161 // should macros escape from this scope?
174162 macros_escape : bool ,
175163 // 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+ }
177174}
178175
179176// a list of ident->name renamings
180- type RenameList = ~[ ( ast:: Ident , Name ) ] ;
177+ pub type RenameList = ~[ ( ast:: Ident , Name ) ] ;
181178
182179// The base map of methods for expanding syntax extension
183180// AST nodes into full ASTs
184181pub fn syntax_expander_table ( ) -> SyntaxEnv {
185182 // utility function to simplify creating NormalTT syntax extensions
186183 fn builtin_normal_tt_no_ctxt ( f : SyntaxExpanderTTFunNoCtxt )
187- -> @ Transformer {
188- @ SE ( NormalTT ( @SyntaxExpanderTT {
184+ -> SyntaxExtension {
185+ NormalTT ( @SyntaxExpanderTT {
189186 expander : SyntaxExpanderTTExpanderWithoutContext ( f) ,
190187 span : None ,
191188 } as @SyntaxExpanderTTTrait ,
192- None ) )
189+ None )
193190 }
194191
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 ( ) ;
202193 syntax_expanders. insert ( intern ( & "macro_rules" ) ,
203- @ SE ( IdentTT ( @SyntaxExpanderTTItem {
194+ IdentTT ( @SyntaxExpanderTTItem {
204195 expander : SyntaxExpanderTTItemExpanderWithContext (
205196 ext:: tt:: macro_rules:: add_new_extension) ,
206197 span : None ,
207198 } as @SyntaxExpanderTTItemTrait ,
208- None ) ) ) ;
199+ None ) ) ;
209200 syntax_expanders. insert ( intern ( & "fmt" ) ,
210201 builtin_normal_tt_no_ctxt (
211202 ext:: fmt:: expand_syntax_ext) ) ;
@@ -231,8 +222,7 @@ pub fn syntax_expander_table() -> SyntaxEnv {
231222 builtin_normal_tt_no_ctxt (
232223 ext:: log_syntax:: expand_syntax_ext) ) ;
233224 syntax_expanders. insert ( intern ( & "deriving" ) ,
234- @SE ( ItemDecorator (
235- ext:: deriving:: expand_meta_deriving) ) ) ;
225+ ItemDecorator ( ext:: deriving:: expand_meta_deriving) ) ;
236226
237227 // Quasi-quoting expanders
238228 syntax_expanders. insert ( intern ( & "quote_tokens" ) ,
@@ -287,7 +277,7 @@ pub fn syntax_expander_table() -> SyntaxEnv {
287277 syntax_expanders. insert ( intern ( & "trace_macros" ) ,
288278 builtin_normal_tt_no_ctxt (
289279 ext:: trace_macros:: expand_trace_macros) ) ;
290- MapChain :: new ( ~ syntax_expanders)
280+ syntax_expanders
291281}
292282
293283// One of these is made during expansion and incrementally updated as we go;
@@ -298,11 +288,6 @@ pub struct ExtCtxt {
298288 cfg : ast:: CrateConfig ,
299289 backtrace : Option < @ExpnInfo > ,
300290
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
306291 mod_path : ~[ ast:: Ident ] ,
307292 trace_mac : bool
308293}
@@ -324,7 +309,7 @@ impl ExtCtxt {
324309 match e. node {
325310 ast:: ExprMac ( ..) => {
326311 let mut expander = expand:: MacroExpander {
327- extsbox : @ mut syntax_expander_table ( ) ,
312+ extsbox : syntax_expander_table ( ) ,
328313 cx : self ,
329314 } ;
330315 e = expand:: expand_expr ( e, & mut expander) ;
@@ -459,11 +444,7 @@ pub fn get_exprs_from_tts(cx: &ExtCtxt,
459444// we want to implement the notion of a transformation
460445// environment.
461446
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.
467448
468449// Actually, the following implementation is parameterized
469450// by both key and value types.
@@ -478,169 +459,98 @@ pub fn get_exprs_from_tts(cx: &ExtCtxt,
478459// able to refer to a macro that was added to an enclosing
479460// scope lexically later than the deeper scope.
480461
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 > ,
496466}
497467
468+ // Only generic to make it easy to test
469+ pub struct MapChain < K , V > {
470+ priv chain : ~[ MapChainFrame < K , V > ] ,
471+ }
498472
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
504478 }
505479
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+ } ) ;
509485 }
510486
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 ( ) ;
522490 }
523491
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+ }
533497 }
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 ! ( )
544499 }
545500
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 => { }
554506 }
555507 }
508+ None
556509 }
557510
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) ;
574513 }
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- }
603514
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
614517 }
615518}
616519
617520#[ cfg( test) ]
618521mod test {
619522 use super :: MapChain ;
620- use std:: hashmap:: HashMap ;
621523
622524 #[ test]
623525 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 ) ) ;
645555 }
646556}
0 commit comments