Skip to content

Commit f785ccc

Browse files
committed
Bugfix: make the parser handle the case where zero repetitions occur, by handling parse results on the basis of what names the matcher expects to bind, not on what names are actually bound.
1 parent 1c47256 commit f785ccc

File tree

5 files changed

+35
-15
lines changed

5 files changed

+35
-15
lines changed

src/libsyntax/ast.rs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -378,8 +378,9 @@ type matcher = spanned<matcher_>;
378378
enum matcher_ {
379379
/* match one token */
380380
mtc_tok(token::token),
381-
/* match repetitions of a sequence: body, separator, zero ok? : */
382-
mtc_rep(~[matcher], option<token::token>, bool),
381+
/* match repetitions of a sequence: body, separator, zero ok?,
382+
lo, hi position-in-match-array used: */
383+
mtc_rep(~[matcher], option<token::token>, bool, uint, uint),
383384
/* parse a Rust NT: name to bind, name of NT, position in match array : */
384385
mtc_bb(ident, ident, uint)
385386
}

src/libsyntax/ext/tt/earley_parser.rs

Lines changed: 27 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ type matcher_pos = ~{
4141
mut idx: uint,
4242
mut up: matcher_pos_up, // mutable for swapping only
4343
matches: ~[dvec<@arb_depth>],
44+
match_lo: uint, match_hi: uint,
4445
sp_lo: uint,
4546
};
4647

@@ -55,17 +56,25 @@ fn count_names(ms: &[matcher]) -> uint {
5556
vec::foldl(0u, ms, |ct, m| {
5657
ct + alt m.node {
5758
mtc_tok(_) { 0u }
58-
mtc_rep(more_ms, _, _) { count_names(more_ms) }
59+
mtc_rep(more_ms, _, _, _, _) { count_names(more_ms) }
5960
mtc_bb(_,_,_) { 1u }
6061
}})
6162
}
6263

6364
#[warn(no_non_implicitly_copyable_typarams)]
64-
fn new_matcher_pos(ms: ~[matcher], sep: option<token>, lo: uint)
65+
fn initial_matcher_pos(ms: ~[matcher], sep: option<token>, lo: uint)
6566
-> matcher_pos {
67+
let mut match_idx_hi = 0u;
68+
for ms.each() |elt| {
69+
alt elt.node {
70+
mtc_tok(_) {}
71+
mtc_rep(_,_,_,_,hi) { match_idx_hi = hi; } //it is monotonic...
72+
mtc_bb(_,_,pos) { match_idx_hi = pos+1u; } //...so latest is highest
73+
}
74+
}
6675
~{elts: ms, sep: sep, mut idx: 0u, mut up: matcher_pos_up(none),
6776
matches: copy vec::from_fn(count_names(ms), |_i| dvec::dvec()),
68-
sp_lo: lo}
77+
match_lo: 0u, match_hi: match_idx_hi, sp_lo: lo}
6978
}
7079

7180
/* logically, an arb_depth should contain only one kind of nonterminal */
@@ -79,7 +88,7 @@ fn nameize(p_s: parse_sess, ms: ~[matcher], res: ~[@arb_depth])
7988
ret_val: hashmap<ident, @arb_depth>) {
8089
alt m {
8190
{node: mtc_tok(_), span: _} { }
82-
{node: mtc_rep(more_ms, _, _), span: _} {
91+
{node: mtc_rep(more_ms, _, _, _, _), span: _} {
8392
for more_ms.each() |next_m| { n_rec(p_s, next_m, res, ret_val) };
8493
}
8594
{node: mtc_bb(bind_name, _, idx), span: sp} {
@@ -104,7 +113,7 @@ enum parse_result {
104113
fn parse(sess: parse_sess, cfg: ast::crate_cfg, rdr: reader, ms: ~[matcher])
105114
-> parse_result {
106115
let mut cur_eis = ~[];
107-
vec::push(cur_eis, new_matcher_pos(ms, none, rdr.peek().sp.lo));
116+
vec::push(cur_eis, initial_matcher_pos(ms, none, rdr.peek().sp.lo));
108117
109118
loop {
110119
let mut bb_eis = ~[]; // black-box parsed by parser.rs
@@ -141,10 +150,10 @@ fn parse(sess: parse_sess, cfg: ast::crate_cfg, rdr: reader, ms: ~[matcher])
141150
// I bet this is a perf problem: we're preemptively
142151
// doing a lot of array work that will get thrown away
143152
// most of the time.
144-
for ei.matches.eachi() |idx, elt| {
145-
let sub = elt.get();
146-
// Some subtrees don't contain the name at all
147-
if sub.len() == 0u { again; }
153+
154+
// Only touch the binders we have actually bound
155+
for uint::range(ei.match_lo, ei.match_hi) |idx| {
156+
let sub = ei.matches[idx].get();
148157
new_pos.matches[idx]
149158
.push(@seq(sub, mk_sp(ei.sp_lo,sp.hi)));
150159
}
@@ -176,10 +185,15 @@ fn parse(sess: parse_sess, cfg: ast::crate_cfg, rdr: reader, ms: ~[matcher])
176185
} else {
177186
alt copy ei.elts[idx].node {
178187
/* need to descend into sequence */
179-
mtc_rep(matchers, sep, zero_ok) {
188+
mtc_rep(matchers, sep, zero_ok, match_idx_lo, match_idx_hi){
180189
if zero_ok {
181190
let new_ei = copy ei;
182191
new_ei.idx += 1u;
192+
//we specifically matched zero repeats.
193+
for uint::range(match_idx_lo, match_idx_hi) |idx| {
194+
new_ei.matches[idx].push(@seq(~[], sp));
195+
}
196+
183197
vec::push(cur_eis, new_ei);
184198
}
185199

@@ -189,7 +203,9 @@ fn parse(sess: parse_sess, cfg: ast::crate_cfg, rdr: reader, ms: ~[matcher])
189203
vec::push(cur_eis, ~{
190204
elts: matchers, sep: sep, mut idx: 0u,
191205
mut up: matcher_pos_up(some(ei_t)),
192-
matches: matches, sp_lo: sp.lo
206+
matches: matches,
207+
match_lo: match_idx_lo, match_hi: match_idx_hi,
208+
sp_lo: sp.lo
193209
});
194210
}
195211
mtc_bb(_,_,_) { vec::push(bb_eis, ei) }

src/libsyntax/ext/tt/macro_rules.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ fn add_new_extension(cx: ext_ctxt, sp: span, name: ident,
2121
ms(mtc_bb(@~"lhs",@~"mtcs", 0u)),
2222
ms(mtc_tok(FAT_ARROW)),
2323
ms(mtc_bb(@~"rhs",@~"tt", 1u)),
24-
], some(SEMI), false))];
24+
], some(SEMI), false, 0u, 2u))];
2525

2626
let arg_reader = new_tt_reader(cx.parse_sess().span_diagnostic,
2727
cx.parse_sess().interner, none, arg);

src/libsyntax/ext/tt/transcribe.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,8 @@ pure fn lookup_cur_ad_by_ad(r: tt_reader, start: @arb_depth) -> @arb_depth {
8686
seq(ads, _) { ads[idx] }
8787
}
8888
}
89+
unchecked {io::println(#fmt["%? / %?", copy r.repeat_idx,
90+
copy r.repeat_len]);};
8991
vec::foldl(start, r.repeat_idx, red)
9092
}
9193

src/libsyntax/parse/parser.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1194,13 +1194,14 @@ class parser {
11941194
let m = if self.token == token::DOLLAR {
11951195
self.bump();
11961196
if self.token == token::LPAREN {
1197+
let name_idx_lo = *name_idx;
11971198
let ms = self.parse_matcher_subseq(name_idx, token::LPAREN,
11981199
token::RPAREN);
11991200
if ms.len() == 0u {
12001201
self.fatal(~"repetition body must be nonempty");
12011202
}
12021203
let (sep, zerok) = self.parse_sep_and_zerok();
1203-
mtc_rep(ms, sep, zerok)
1204+
mtc_rep(ms, sep, zerok, name_idx_lo, *name_idx)
12041205
} else {
12051206
let bound_to = self.parse_ident();
12061207
self.expect(token::COLON);

0 commit comments

Comments
 (0)