@@ -21,12 +21,12 @@ use parse::{parser, token};
21
21
22
22
use core:: io;
23
23
use core:: vec;
24
- use std :: oldmap :: HashMap ;
24
+ use core :: hashmap :: linear :: LinearMap ;
25
25
26
26
// new-style macro! tt code:
27
27
//
28
28
// SyntaxExpanderTT, SyntaxExpanderTTItem, MacResult,
29
- // NormalTT, ItemTT
29
+ // NormalTT, IdentTT
30
30
//
31
31
// also note that ast::mac used to have a bunch of extraneous cases and
32
32
// is now probably a redundant AST node, can be merged with
@@ -71,36 +71,66 @@ pub enum SyntaxExtension {
71
71
// Token-tree expanders
72
72
NormalTT ( SyntaxExpanderTT ) ,
73
73
74
+ // An IdentTT is a macro that has an
75
+ // identifier in between the name of the
76
+ // macro and the argument. Currently,
77
+ // the only examples of this are
78
+ // macro_rules! and proto!
79
+
74
80
// perhaps macro_rules! will lose its odd special identifier argument,
75
81
// and this can go away also
76
- ItemTT ( SyntaxExpanderTTItem ) ,
82
+ IdentTT ( SyntaxExpanderTTItem ) ,
77
83
}
78
84
79
- type SyntaxExtensions = HashMap < @~str , SyntaxExtension > ;
85
+ type SyntaxEnv = @mut MapChain < Name , Transformer > ;
86
+
87
+ // Name : the domain of SyntaxEnvs
88
+ // want to change these to uints....
89
+ // note that we use certain strings that are not legal as identifiers
90
+ // to indicate, for instance, how blocks are supposed to behave.
91
+ type Name = @~str ;
92
+
93
+ // Transformer : the codomain of SyntaxEnvs
94
+
95
+ // NB: it may seem crazy to lump both of these into one environment;
96
+ // what would it mean to bind "foo" to BlockLimit(true)? The idea
97
+ // is that this follows the lead of MTWT, and accommodates growth
98
+ // toward a more uniform syntax syntax (sorry) where blocks are just
99
+ // another kind of transformer.
100
+
101
+ enum Transformer {
102
+ // this identifier maps to a syntax extension or macro
103
+ SE ( SyntaxExtension ) ,
104
+ // should blocks occurring here limit macro scopes?
105
+ ScopeMacros ( bool )
106
+ }
80
107
81
- // A temporary hard-coded map of methods for expanding syntax extension
108
+ // The base map of methods for expanding syntax extension
82
109
// AST nodes into full ASTs
83
- pub fn syntax_expander_table ( ) -> SyntaxExtensions {
110
+ pub fn syntax_expander_table ( ) -> SyntaxEnv {
84
111
// utility function to simplify creating NormalTT syntax extensions
85
- fn builtin_normal_tt ( f : SyntaxExpanderTTFun ) -> SyntaxExtension {
86
- NormalTT ( SyntaxExpanderTT { expander : f, span : None } )
112
+ fn builtin_normal_tt ( f : SyntaxExpanderTTFun ) -> @ Transformer {
113
+ @ SE ( NormalTT ( SyntaxExpanderTT { expander : f, span : None } ) )
87
114
}
88
- // utility function to simplify creating ItemTT syntax extensions
89
- fn builtin_item_tt ( f : SyntaxExpanderTTItemFun ) -> SyntaxExtension {
90
- ItemTT ( SyntaxExpanderTTItem { expander : f, span : None } )
115
+ // utility function to simplify creating IdentTT syntax extensions
116
+ fn builtin_item_tt ( f : SyntaxExpanderTTItemFun ) -> @ Transformer {
117
+ @ SE ( IdentTT ( SyntaxExpanderTTItem { expander : f, span : None } ) )
91
118
}
92
- let syntax_expanders = HashMap ( ) ;
119
+ let mut syntax_expanders = LinearMap :: new ( ) ;
120
+ // NB identifier starts with space, and can't conflict with legal idents
121
+ syntax_expanders. insert ( @~" block",
122
+ @ScopeMacros ( true ) ) ;
93
123
syntax_expanders. insert ( @~"macro_rules",
94
124
builtin_item_tt (
95
125
ext:: tt:: macro_rules:: add_new_extension) ) ;
96
126
syntax_expanders. insert ( @~"fmt",
97
127
builtin_normal_tt ( ext:: fmt:: expand_syntax_ext) ) ;
98
128
syntax_expanders. insert (
99
129
@~"auto_encode",
100
- ItemDecorator ( ext:: auto_encode:: expand_auto_encode) ) ;
130
+ @ SE ( ItemDecorator ( ext:: auto_encode:: expand_auto_encode) ) ) ;
101
131
syntax_expanders. insert (
102
132
@~"auto_decode",
103
- ItemDecorator ( ext:: auto_encode:: expand_auto_decode) ) ;
133
+ @ SE ( ItemDecorator ( ext:: auto_encode:: expand_auto_decode) ) ) ;
104
134
syntax_expanders. insert ( @~"env",
105
135
builtin_normal_tt ( ext:: env:: expand_syntax_ext) ) ;
106
136
syntax_expanders. insert ( @~"concat_idents",
@@ -110,25 +140,25 @@ pub fn syntax_expander_table() -> SyntaxExtensions {
110
140
builtin_normal_tt (
111
141
ext:: log_syntax:: expand_syntax_ext) ) ;
112
142
syntax_expanders. insert ( @~"deriving_eq",
113
- ItemDecorator (
114
- ext:: deriving:: expand_deriving_eq) ) ;
143
+ @ SE ( ItemDecorator (
144
+ ext:: deriving:: expand_deriving_eq) ) ) ;
115
145
syntax_expanders. insert ( @~"deriving_iter_bytes",
116
- ItemDecorator (
117
- ext:: deriving:: expand_deriving_iter_bytes) ) ;
146
+ @ SE ( ItemDecorator (
147
+ ext:: deriving:: expand_deriving_iter_bytes) ) ) ;
118
148
119
149
// Quasi-quoting expanders
120
150
syntax_expanders. insert ( @~"quote_tokens",
121
151
builtin_normal_tt ( ext:: quote:: expand_quote_tokens) ) ;
122
152
syntax_expanders. insert ( @~"quote_expr",
123
- builtin_normal_tt ( ext:: quote:: expand_quote_expr) ) ;
153
+ builtin_normal_tt ( ext:: quote:: expand_quote_expr) ) ;
124
154
syntax_expanders. insert ( @~"quote_ty",
125
- builtin_normal_tt ( ext:: quote:: expand_quote_ty) ) ;
155
+ builtin_normal_tt ( ext:: quote:: expand_quote_ty) ) ;
126
156
syntax_expanders. insert ( @~"quote_item",
127
- builtin_normal_tt ( ext:: quote:: expand_quote_item) ) ;
157
+ builtin_normal_tt ( ext:: quote:: expand_quote_item) ) ;
128
158
syntax_expanders. insert ( @~"quote_pat",
129
- builtin_normal_tt ( ext:: quote:: expand_quote_pat) ) ;
159
+ builtin_normal_tt ( ext:: quote:: expand_quote_pat) ) ;
130
160
syntax_expanders. insert ( @~"quote_stmt",
131
- builtin_normal_tt ( ext:: quote:: expand_quote_stmt) ) ;
161
+ builtin_normal_tt ( ext:: quote:: expand_quote_stmt) ) ;
132
162
133
163
syntax_expanders. insert ( @~"line",
134
164
builtin_normal_tt (
@@ -159,7 +189,7 @@ pub fn syntax_expander_table() -> SyntaxExtensions {
159
189
syntax_expanders. insert (
160
190
@~"trace_macros",
161
191
builtin_normal_tt ( ext:: trace_macros:: expand_trace_macros) ) ;
162
- return syntax_expanders;
192
+ MapChain :: new ( ~ syntax_expanders)
163
193
}
164
194
165
195
// One of these is made during expansion and incrementally updated as we go;
@@ -348,6 +378,149 @@ pub fn get_exprs_from_tts(cx: ext_ctxt, tts: ~[ast::token_tree])
348
378
es
349
379
}
350
380
381
+ // in order to have some notion of scoping for macros,
382
+ // we want to implement the notion of a transformation
383
+ // environment.
384
+
385
+ // This environment maps Names to Transformers.
386
+ // Initially, this includes macro definitions and
387
+ // block directives.
388
+
389
+
390
+
391
+ // Actually, the following implementation is parameterized
392
+ // by both key and value types.
393
+
394
+ //impl question: how to implement it? Initially, the
395
+ // env will contain only macros, so it might be painful
396
+ // to add an empty frame for every context. Let's just
397
+ // get it working, first....
398
+
399
+ // NB! the mutability of the underlying maps means that
400
+ // if expansion is out-of-order, a deeper scope may be
401
+ // able to refer to a macro that was added to an enclosing
402
+ // scope lexically later than the deeper scope.
403
+
404
+ // Note on choice of representation: I've been pushed to
405
+ // use a top-level managed pointer by some difficulties
406
+ // with pushing and popping functionally, and the ownership
407
+ // issues. As a result, the values returned by the table
408
+ // also need to be managed; the &self/... type that Maps
409
+ // return won't work for things that need to get outside
410
+ // of that managed pointer. The easiest way to do this
411
+ // is just to insist that the values in the tables are
412
+ // managed to begin with.
413
+
414
+ // a transformer env is either a base map or a map on top
415
+ // of another chain.
416
+ pub enum MapChain < K , V > {
417
+ TEC_Base ( ~LinearMap < K , @V > ) ,
418
+ TEC_Cons ( ~LinearMap < K , @V > , @mut MapChain < K , V > )
419
+ }
420
+
421
+
422
+ // get the map from an env frame
423
+ impl < K : Eq + Hash + IterBytes , V : Copy > MapChain < K , V > {
424
+
425
+ // Constructor. I don't think we need a zero-arg one.
426
+ static fn new( +init: ~LinearMap < K , @V > ) -> @mut MapChain <K , V > {
427
+ @mut TEC_Base ( init)
428
+ }
429
+
430
+ // add a new frame to the environment (functionally)
431
+ fn push_frame ( @mut self ) -> @mut MapChain < K , V > {
432
+ @mut TEC_Cons ( ~LinearMap :: new ( ) , self )
433
+ }
434
+
435
+ // no need for pop, it'll just be functional.
436
+
437
+ // utility fn...
438
+
439
+ // ugh: can't get this to compile with mut because of the
440
+ // lack of flow sensitivity.
441
+ fn get_map ( & self ) -> & self /LinearMap < K , @V > {
442
+ match * self {
443
+ TEC_Base ( ~ref map) => map,
444
+ TEC_Cons ( ~ref map, _) => map
445
+ }
446
+ }
447
+
448
+ // traits just don't work anywhere...?
449
+ //pub impl Map<Name,SyntaxExtension> for MapChain {
450
+
451
+ pure fn contains_key ( & self , key : & K ) -> bool {
452
+ match * self {
453
+ TEC_Base ( ref map) => map. contains_key ( key) ,
454
+ TEC_Cons ( ref map, ref rest) =>
455
+ ( map. contains_key ( key)
456
+ || rest. contains_key ( key) )
457
+ }
458
+ }
459
+ // should each_key and each_value operate on shadowed
460
+ // names? I think not.
461
+ // delaying implementing this....
462
+ pure fn each_key ( & self , _f : & fn ( & K ) ->bool ) {
463
+ fail ! ( ~"unimplemented 2013 -02 -15 T10 : 01 ");
464
+ }
465
+
466
+ pure fn each_value (&self, _f: &fn (&V) -> bool) {
467
+ fail!(~" unimplemented 2013 -02 -15 T10 : 02 ");
468
+ }
469
+
470
+ // Returns a copy of the value that the name maps to.
471
+ // Goes down the chain 'til it finds one (or bottom out).
472
+ fn find (&self, key: &K) -> Option<@V> {
473
+ match self.get_map().find (key) {
474
+ Some(ref v) => Some(**v),
475
+ None => match *self {
476
+ TEC_Base (_) => None,
477
+ TEC_Cons (_,ref rest) => rest.find(key)
478
+ }
479
+ }
480
+ }
481
+
482
+ // insert the binding into the top-level map
483
+ fn insert (&mut self, +key: K, +ext: @V) -> bool {
484
+ // can't abstract over get_map because of flow sensitivity...
485
+ match *self {
486
+ TEC_Base (~ref mut map) => map.insert(key, ext),
487
+ TEC_Cons (~ref mut map,_) => map.insert(key,ext)
488
+ }
489
+ }
490
+
491
+ }
492
+
493
+ #[cfg(test)]
494
+ mod test {
495
+ use super::*;
496
+ use super::MapChain;
497
+ use util::testing::check_equal;
498
+
499
+ #[test] fn testenv () {
500
+ let mut a = LinearMap::new();
501
+ a.insert (@~" abc",@15);
502
+ let m = MapChain::new(~a);
503
+ m.insert (@~" def",@16);
504
+ // FIXME: #4492 (ICE) check_equal(m.find(&@~" abc"),Some(@15));
505
+ // .... check_equal(m.find(&@~" def"),Some(@16));
506
+ check_equal(*(m.find(&@~" abc").get()),15);
507
+ check_equal(*(m.find(&@~" def").get()),16);
508
+ let n = m.push_frame();
509
+ // old bindings are still present:
510
+ check_equal(*(n.find(&@~" abc").get()),15);
511
+ check_equal(*(n.find(&@~" def").get()),16);
512
+ n.insert (@~" def",@17);
513
+ // n shows the new binding
514
+ check_equal(*(n.find(&@~" abc").get()),15);
515
+ check_equal(*(n.find(&@~" def").get()),17);
516
+ // ... but m still has the old ones
517
+ // FIXME: #4492: check_equal(m.find(&@~" abc"),Some(@15));
518
+ // FIXME: #4492: check_equal(m.find(&@~" def"),Some(@16));
519
+ check_equal(*(m.find(&@~" abc").get()),15);
520
+ check_equal(*(m.find(&@~" def") . get( ) ) , 16 ) ;
521
+ }
522
+ }
523
+
351
524
//
352
525
// Local Variables:
353
526
// mode: rust
0 commit comments