1
1
import util:: interner:: interner;
2
2
import diagnostic:: span_handler;
3
- import ast:: { tt_delim, tt_flat, tt_dotdotdot, tt_interpolate, ident} ;
4
- import earley_parser:: arb_depth;
3
+ import ast:: { token_tree , tt_delim, tt_flat, tt_dotdotdot, tt_interpolate, ident} ;
4
+ import earley_parser :: { arb_depth, seq , leaf } ;
5
5
import codemap:: span;
6
- import parse:: token:: { EOF , token} ;
6
+ import parse:: token:: { EOF , ACTUALLY , token} ;
7
+ import std:: map:: { hashmap, box_str_hash} ;
7
8
8
9
export tt_reader, new_tt_reader, dup_tt_reader, tt_next_token;
9
10
@@ -14,8 +15,9 @@ enum tt_frame_up { /* to break a circularity */
14
15
/* TODO: figure out how to have a uniquely linked stack, and change to `~` */
15
16
///an unzipping of `token_tree`s
16
17
type tt_frame = @{
17
- readme : [ ast:: token_tree ] /~ ,
18
+ readme : ~ [ ast:: token_tree ] ,
18
19
mut idx : uint ,
20
+ dotdotdoted : bool ,
19
21
up : tt_frame_up
20
22
} ;
21
23
@@ -25,6 +27,8 @@ type tt_reader = @{
25
27
mut cur : tt_frame ,
26
28
/* for MBE-style macro transcription */
27
29
interpolations : std:: map:: hashmap < ident , @arb_depth > ,
30
+ mut repeat_idx : ~[ mut uint ] ,
31
+ mut repeat_len : ~[ uint ] ,
28
32
/* cached: */
29
33
mut cur_tok : token ,
30
34
mut cur_span : span
@@ -35,15 +39,16 @@ type tt_reader = @{
35
39
* should) be none. */
36
40
fn new_tt_reader ( span_diagnostic : span_handler , itr : @interner < @str > ,
37
41
interp : option < std:: map:: hashmap < ident , @arb_depth > > ,
38
- src : [ ast:: token_tree ] /~ )
42
+ src : ~ [ ast:: token_tree ] )
39
43
-> tt_reader {
40
44
let r = @{ span_diagnostic: span_diagnostic, interner: itr,
41
- mut cur : @{ readme : src, mut idx : 0 u,
45
+ mut cur : @{ readme : src, mut idx : 0 u, dotdotdoted : false ,
42
46
up : tt_frame_up ( option:: none) } ,
43
47
interpolations: alt interp { /* just a convienience */
44
48
none { std:: map:: box_str_hash :: < @arb_depth > ( ) }
45
49
some( x) { x }
46
50
} ,
51
+ mut repeat_idx: ~[ mut] , mut repeat_len: ~[ ] ,
47
52
/* dummy values, never read: */
48
53
mut cur_tok: EOF ,
49
54
mut cur_span: ast_util:: mk_sp ( 0 u, 0 u)
@@ -53,7 +58,7 @@ fn new_tt_reader(span_diagnostic: span_handler, itr: @interner<@str>,
53
58
}
54
59
55
60
pure fn dup_tt_frame ( & & f: tt_frame) -> tt_frame {
56
- @{ readme : f. readme , mut idx : f. idx ,
61
+ @{ readme : f. readme , mut idx : f. idx , dotdotdoted : f . dotdotdoted ,
57
62
up : alt f. up {
58
63
tt_frame_up ( some ( up_frame) ) {
59
64
tt_frame_up ( some ( dup_tt_frame ( up_frame) ) )
@@ -67,46 +72,138 @@ pure fn dup_tt_reader(&&r: tt_reader) -> tt_reader {
67
72
@{ span_diagnostic : r. span_diagnostic , interner : r. interner ,
68
73
mut cur : dup_tt_frame ( r. cur ) ,
69
74
interpolations : r. interpolations ,
75
+ mut repeat_idx : copy r. repeat_idx , mut repeat_len : copy r. repeat_len ,
70
76
mut cur_tok : r. cur_tok , mut cur_span : r. cur_span }
71
77
}
72
78
73
79
80
+ pure fn lookup_cur_ad_by_ad ( r : tt_reader , start : @arb_depth ) -> @arb_depth {
81
+ pure fn red ( & & ad: @arb_depth , & & idx: uint ) -> @arb_depth {
82
+ alt * ad {
83
+ leaf( _) { ad /* end of the line; duplicate henceforth */ }
84
+ seq ( ads, _) { ads[ idx] }
85
+ }
86
+ }
87
+ vec:: foldl ( start, r. repeat_idx , red)
88
+ }
89
+
90
+ fn lookup_cur_ad ( r : tt_reader , name : ident ) -> @arb_depth {
91
+ lookup_cur_ad_by_ad ( r, r. interpolations . get ( name) )
92
+ }
93
+ enum lis {
94
+ lis_unconstrained, lis_constraint( uint , ident ) , lis_contradiction( str )
95
+ }
96
+
97
+ fn lockstep_iter_size ( & & t: token_tree , & & r: tt_reader ) -> lis {
98
+ fn lis_merge ( lhs : lis , rhs : lis ) -> lis {
99
+ alt lhs {
100
+ lis_unconstrained { rhs }
101
+ lis_contradiction ( _) { lhs }
102
+ lis_constraint ( l_len, l_id) {
103
+ alt rhs {
104
+ lis_unconstrained { lhs }
105
+ lis_contradiction ( _) { rhs }
106
+ lis_constraint ( r_len, _) if l_len == r_len { lhs }
107
+ lis_constraint ( r_len, r_id) {
108
+ lis_contradiction ( #fmt[ "Inconsistent lockstep iteration: \
109
+ '%s' has %u items, but '%s' has %u",
110
+ * l_id, l_len, * r_id, r_len] )
111
+ }
112
+ }
113
+ }
114
+ }
115
+ }
116
+ alt t {
117
+ tt_delim( tts) | tt_dotdotdot ( _, tts) {
118
+ vec:: foldl ( lis_unconstrained, tts, { |lis, tt|
119
+ lis_merge ( lis, lockstep_iter_size ( tt, r) ) } )
120
+ }
121
+ tt_flat( * ) { lis_unconstrained }
122
+ tt_interpolate ( _, name) {
123
+ alt * lookup_cur_ad ( r, name) {
124
+ leaf ( _) { lis_unconstrained }
125
+ seq ( ads, _) { lis_constraint ( ads. len ( ) , name) }
126
+ }
127
+ }
128
+ }
129
+ }
130
+
131
+
74
132
fn tt_next_token ( & & r: tt_reader) -> { tok: token, sp: span} {
75
133
let ret_val = { tok: r. cur_tok , sp: r. cur_span } ;
76
134
if r. cur . idx >= vec:: len ( r. cur . readme ) {
77
- /* done with this set; pop */
78
- alt r. cur . up {
79
- tt_frame_up ( none) {
80
- r. cur_tok = EOF ;
81
- ret ret_val;
82
- }
83
- tt_frame_up ( some ( tt_f) ) {
84
- r. cur = tt_f;
85
- /* the above `if` would need to be a `while` if we didn't know
86
- that the last thing in a `tt_delim` is always a `tt_flat` */
87
- r. cur . idx += 1 u;
88
- }
135
+ /* done with this set; pop or repeat? */
136
+ if ! r. cur . dotdotdoted
137
+ || r. repeat_idx . last ( ) == r. repeat_len . last ( ) - 1 {
138
+ if r. cur . dotdotdoted {
139
+ vec:: pop ( r. repeat_idx ) ; vec:: pop ( r. repeat_len ) ;
140
+ }
141
+ alt r. cur . up {
142
+ tt_frame_up ( none) {
143
+ r. cur_tok = EOF ;
144
+ ret ret_val;
145
+ }
146
+ tt_frame_up ( some ( tt_f) ) {
147
+ r. cur = tt_f;
148
+ /* the outermost `if` would need to be a `while` if we
149
+ didn't know that the last thing in a `tt_delim` is always
150
+ a `tt_flat`, and that a `tt_dotdotdot` is never empty */
151
+ r. cur . idx += 1 u;
152
+ }
153
+ }
154
+
155
+ } else {
156
+ r. cur . idx = 0 u;
157
+ r. repeat_idx [ r. repeat_idx . len ( ) - 1 u] += 1 u;
89
158
}
90
159
}
91
160
/* if `tt_delim`s could be 0-length, we'd need to be able to switch
92
161
between popping and pushing until we got to an actual `tt_flat` */
93
162
loop { /* because it's easiest, this handles `tt_delim` not starting
94
163
with a `tt_flat`, even though it won't happen */
95
- alt copy r. cur . readme [ r. cur . idx ] {
164
+ alt r. cur . readme [ r. cur . idx ] {
96
165
tt_delim ( tts) {
97
- r. cur = @{ readme: tts, mut idx: 0 u,
166
+ r. cur = @{ readme: tts, mut idx: 0 u, dotdotdoted : false ,
98
167
up: tt_frame_up ( option:: some ( r. cur ) ) } ;
99
168
}
100
169
tt_flat ( sp, tok) {
101
170
r. cur_span = sp; r. cur_tok = tok;
102
171
r. cur . idx += 1 u;
103
172
ret ret_val;
104
173
}
105
- tt_dotdotdot ( tts) {
106
- fail;
174
+ tt_dotdotdot ( sp, tts) {
175
+ alt lockstep_iter_size ( tt_dotdotdot ( sp, tts) , r) {
176
+ lis_unconstrained {
177
+ r. span_diagnostic . span_fatal (
178
+ copy r. cur_span , /* blame macro writer */
179
+ "attempted to repeat an expression containing no syntax \
180
+ variables matched as repeating at this depth") ;
181
+ }
182
+ lis_contradiction ( msg) { /* blame macro invoker */
183
+ r. span_diagnostic . span_fatal ( sp, msg) ;
184
+ }
185
+ lis_constraint ( len, _) {
186
+ vec:: push ( r. repeat_len , len) ;
187
+ vec:: push ( r. repeat_idx , 0 u) ;
188
+ r. cur = @{ readme: tts, mut idx: 0 u, dotdotdoted: true ,
189
+ up: tt_frame_up ( option:: some ( r. cur ) ) } ;
190
+ }
191
+ }
107
192
}
108
- tt_interpolate ( ident) {
109
- fail;
193
+ // TODO: think about span stuff here
194
+ tt_interpolate ( sp, ident) {
195
+ alt * lookup_cur_ad ( r, ident) {
196
+ leaf ( w_nt) {
197
+ r. cur_span = sp; r. cur_tok = ACTUALLY ( w_nt) ;
198
+ ret ret_val;
199
+ }
200
+ seq ( * ) {
201
+ r. span_diagnostic . span_fatal (
202
+ copy r. cur_span , /* blame the macro writer */
203
+ #fmt[ "variable '%s' is still repeating at this depth" ,
204
+ * ident] ) ;
205
+ }
206
+ }
110
207
}
111
208
}
112
209
}
0 commit comments