@@ -156,57 +156,48 @@ pub enum SyntaxExtension {
156156// The SyntaxEnv is the environment that's threaded through the expansion
157157// of macros. It contains bindings for macros, and also a special binding
158158// 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 > ;
172160
173161pub struct BlockInfo {
174162 // should macros escape from this scope?
175163 macros_escape : bool ,
176164 // 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+ }
178175}
179176
180177// a list of ident->name renamings
181- type RenameList = ~[ ( ast:: Ident , Name ) ] ;
178+ pub type RenameList = ~[ ( ast:: Ident , Name ) ] ;
182179
183180// The base map of methods for expanding syntax extension
184181// AST nodes into full ASTs
185182pub fn syntax_expander_table ( ) -> SyntaxEnv {
186183 // utility function to simplify creating NormalTT syntax extensions
187184 fn builtin_normal_tt_no_ctxt ( f : SyntaxExpanderTTFunNoCtxt )
188- -> @ Transformer {
189- @ SE ( NormalTT ( @SyntaxExpanderTT {
185+ -> SyntaxExtension {
186+ NormalTT ( @SyntaxExpanderTT {
190187 expander : SyntaxExpanderTTExpanderWithoutContext ( f) ,
191188 span : None ,
192189 } as @SyntaxExpanderTTTrait ,
193- None ) )
190+ None )
194191 }
195192
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 ( ) ;
203194 syntax_expanders. insert ( intern ( & "macro_rules" ) ,
204- @ SE ( IdentTT ( @SyntaxExpanderTTItem {
195+ IdentTT ( @SyntaxExpanderTTItem {
205196 expander : SyntaxExpanderTTItemExpanderWithContext (
206197 ext:: tt:: macro_rules:: add_new_extension) ,
207198 span : None ,
208199 } as @SyntaxExpanderTTItemTrait ,
209- None ) ) ) ;
200+ None ) ) ;
210201 syntax_expanders. insert ( intern ( & "fmt" ) ,
211202 builtin_normal_tt_no_ctxt (
212203 ext:: fmt:: expand_syntax_ext) ) ;
@@ -232,8 +223,7 @@ pub fn syntax_expander_table() -> SyntaxEnv {
232223 builtin_normal_tt_no_ctxt (
233224 ext:: log_syntax:: expand_syntax_ext) ) ;
234225 syntax_expanders. insert ( intern ( & "deriving" ) ,
235- @SE ( ItemDecorator (
236- ext:: deriving:: expand_meta_deriving) ) ) ;
226+ ItemDecorator ( ext:: deriving:: expand_meta_deriving) ) ;
237227
238228 // Quasi-quoting expanders
239229 syntax_expanders. insert ( intern ( & "quote_tokens" ) ,
@@ -288,7 +278,7 @@ pub fn syntax_expander_table() -> SyntaxEnv {
288278 syntax_expanders. insert ( intern ( & "trace_macros" ) ,
289279 builtin_normal_tt_no_ctxt (
290280 ext:: trace_macros:: expand_trace_macros) ) ;
291- MapChain :: new ( ~ syntax_expanders)
281+ syntax_expanders
292282}
293283
294284// One of these is made during expansion and incrementally updated as we go;
@@ -299,11 +289,6 @@ pub struct ExtCtxt {
299289 cfg : ast:: CrateConfig ,
300290 backtrace : Option < @ExpnInfo > ,
301291
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
307292 mod_path : ~[ ast:: Ident ] ,
308293 trace_mac : bool
309294}
@@ -325,7 +310,7 @@ impl ExtCtxt {
325310 match e. node {
326311 ast:: ExprMac ( ..) => {
327312 let mut expander = expand:: MacroExpander {
328- extsbox : @ mut syntax_expander_table ( ) ,
313+ extsbox : syntax_expander_table ( ) ,
329314 cx : self ,
330315 } ;
331316 e = expand:: expand_expr ( e, & mut expander) ;
@@ -460,11 +445,7 @@ pub fn get_exprs_from_tts(cx: &ExtCtxt,
460445// we want to implement the notion of a transformation
461446// environment.
462447
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.
468449
469450// Actually, the following implementation is parameterized
470451// by both key and value types.
@@ -479,169 +460,98 @@ pub fn get_exprs_from_tts(cx: &ExtCtxt,
479460// able to refer to a macro that was added to an enclosing
480461// scope lexically later than the deeper scope.
481462
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 > ,
497467}
498468
469+ // Only generic to make it easy to test
470+ pub struct MapChain < K , V > {
471+ priv chain : ~[ MapChainFrame < K , V > ] ,
472+ }
499473
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
505479 }
506480
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+ } ) ;
510486 }
511487
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 ( ) ;
523491 }
524492
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+ }
534498 }
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 ! ( )
545500 }
546501
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 => { }
555507 }
556508 }
509+ None
557510 }
558511
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) ;
575514 }
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- }
604515
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
615518 }
616519}
617520
618521#[ cfg( test) ]
619522mod test {
620523 use super :: MapChain ;
621- use std:: hashmap:: HashMap ;
622524
623525 #[ test]
624526 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 ) ) ;
646556 }
647557}
0 commit comments