Skip to content

Commit 571afe7

Browse files
committed
Safeguard against using statement or item keywords as value ids
This prevents insane things like 'auto while = 2', which would parse in the previous revision, but then break when you tried to mutate it with 'while = 10'.
1 parent 57ffa2a commit 571afe7

File tree

1 file changed

+78
-12
lines changed

1 file changed

+78
-12
lines changed

src/comp/front/parser.rs

Lines changed: 78 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ state type parser =
4242
fn get_str(token::str_num) -> str;
4343
fn get_reader() -> lexer::reader;
4444
fn get_filemap() -> codemap::filemap;
45+
fn get_bad_expr_words() -> std::map::hashmap[str, ()];
4546
fn get_chpos() -> uint;
4647
fn get_ann() -> ast::ann;
4748
fn next_ann_num() -> uint;
@@ -63,7 +64,8 @@ fn new_parser(session::session sess,
6364
ast::crate_num crate,
6465
lexer::reader rdr,
6566
vec[op_spec] precs,
66-
mutable uint next_ann_var)
67+
mutable uint next_ann_var,
68+
std::map::hashmap[str, ()] bad_words)
6769
{
6870
fn peek() -> token::token {
6971
ret tok;
@@ -132,6 +134,10 @@ fn new_parser(session::session sess,
132134
ret rdr.get_filemap();
133135
}
134136

137+
fn get_bad_expr_words() -> std::map::hashmap[str, ()] {
138+
ret bad_words;
139+
}
140+
135141
fn get_chpos() -> uint {ret rdr.get_chpos();}
136142

137143
fn get_ann() -> ast::ann {
@@ -156,7 +162,50 @@ fn new_parser(session::session sess,
156162
auto npos = rdr.get_chpos();
157163
ret stdio_parser(sess, env, ftype, lexer::next_token(rdr),
158164
npos, npos, npos, initial_def._1, UNRESTRICTED,
159-
initial_def._0, rdr, prec_table(), next_ann);
165+
initial_def._0, rdr, prec_table(), next_ann,
166+
bad_expr_word_table());
167+
}
168+
169+
// These are the words that shouldn't be allowed as value identifiers,
170+
// because, if used at the start of a line, they will cause the line to be
171+
// interpreted as a specific kind of statement, which would be confusing.
172+
fn bad_expr_word_table() -> std::map::hashmap[str, ()] {
173+
auto words = new_str_hash[()]();
174+
words.insert("mod", ());
175+
words.insert("if", ());
176+
words.insert("else", ());
177+
words.insert("while", ());
178+
words.insert("do", ());
179+
words.insert("alt", ());
180+
words.insert("for", ());
181+
words.insert("break", ());
182+
words.insert("cont", ());
183+
words.insert("put", ());
184+
words.insert("ret", ());
185+
words.insert("be", ());
186+
words.insert("fail", ());
187+
words.insert("type", ());
188+
words.insert("check", ());
189+
words.insert("assert", ());
190+
words.insert("claim", ());
191+
words.insert("prove", ());
192+
words.insert("state", ());
193+
words.insert("gc", ());
194+
words.insert("native", ());
195+
words.insert("auto", ());
196+
words.insert("fn", ());
197+
words.insert("pred", ());
198+
words.insert("iter", ());
199+
words.insert("import", ());
200+
words.insert("export", ());
201+
words.insert("let", ());
202+
words.insert("const", ());
203+
words.insert("log", ());
204+
words.insert("log_err", ());
205+
words.insert("yield", ());
206+
words.insert("tag", ());
207+
words.insert("obj", ());
208+
ret words;
160209
}
161210

162211
fn unexpected(parser p, token::token t) {
@@ -190,6 +239,10 @@ fn parse_ident(parser p) -> ast::ident {
190239
}
191240
}
192241
}
242+
fn parse_value_ident(parser p) -> ast::ident {
243+
check_bad_word(p);
244+
ret parse_ident(p);
245+
}
193246

194247

195248
/* FIXME: gross hack copied from rustboot to make certain configuration-based
@@ -240,6 +293,17 @@ fn expect_word(&parser p, &str word) {
240293
token::to_str(p.get_reader(), p.peek()));
241294
}
242295
}
296+
fn check_bad_word(&parser p) {
297+
alt (p.peek()) {
298+
case (token::IDENT(?sid)) {
299+
auto w = p.get_str(sid);
300+
if (p.get_bad_expr_words().contains_key(w)) {
301+
p.err("found " + w + " in expression position");
302+
}
303+
}
304+
case (_) {}
305+
}
306+
}
243307

244308
fn parse_ty_fn(ast::proto proto, parser p, uint lo)
245309
-> ast::ty_ {
@@ -299,7 +363,7 @@ fn parse_ty_obj(parser p, &mutable uint hi) -> ast::ty_ {
299363
auto flo = p.get_lo_pos();
300364

301365
let ast::proto proto = parse_proto(p);
302-
auto ident = parse_ident(p);
366+
auto ident = parse_value_ident(p);
303367
auto f = parse_ty_fn(proto, p, flo);
304368
expect(p, token::SEMI);
305369
alt (f) {
@@ -338,7 +402,7 @@ fn parse_constr_arg(parser p) -> @ast::constr_arg {
338402
if (p.peek() == token::BINOP(token::STAR)) {
339403
p.bump();
340404
} else {
341-
carg = ast::carg_ident(parse_ident(p));
405+
carg = ast::carg_ident(parse_value_ident(p));
342406
}
343407
ret @rec(node=carg, span=sp);
344408
}
@@ -504,7 +568,7 @@ fn parse_arg(parser p) -> ast::arg {
504568
eat_word(p, "mutable");
505569
}
506570
let @ast::ty t = parse_ty(p);
507-
let ast::ident i = parse_ident(p);
571+
let ast::ident i = parse_value_ident(p);
508572
ret rec(mode=m, ty=t, ident=i, id=p.next_def_id());
509573
}
510574

@@ -851,6 +915,7 @@ fn parse_bottom_expr(parser p) -> @ast::expr {
851915
ex = ast::expr_call(f, es.node, p.get_ann());
852916
} else if (is_ident(p.peek()) && !is_word(p, "true") &&
853917
!is_word(p, "false")) {
918+
check_bad_word(p);
854919
auto pth = parse_path(p);
855920
hi = pth.span.hi;
856921
ex = ast::expr_path(pth, p.get_ann());
@@ -1376,7 +1441,7 @@ fn parse_pat(parser p) -> @ast::pat {
13761441

13771442
fn parse_local_full(&option::t[@ast::ty] tyopt,
13781443
parser p) -> @ast::local {
1379-
auto ident = parse_ident(p);
1444+
auto ident = parse_value_ident(p);
13801445
auto init = parse_initializer(p);
13811446
ret @rec(ty = tyopt,
13821447
infer = false,
@@ -1622,7 +1687,7 @@ fn parse_fn(parser p, ast::proto proto, ast::purity purity) -> ast::_fn {
16221687

16231688
fn parse_fn_header(parser p)
16241689
-> tup(ast::ident, vec[ast::ty_param]) {
1625-
auto id = parse_ident(p);
1690+
auto id = parse_value_ident(p);
16261691
auto ty_params = parse_ty_params(p);
16271692
ret tup(id, ty_params);
16281693
}
@@ -1641,14 +1706,14 @@ fn parse_item_fn_or_iter(parser p, ast::purity purity, ast::proto proto)
16411706
fn parse_obj_field(parser p) -> ast::obj_field {
16421707
auto mut = parse_mutability(p); // TODO: store this, use it in typeck
16431708
auto ty = parse_ty(p);
1644-
auto ident = parse_ident(p);
1709+
auto ident = parse_value_ident(p);
16451710
ret rec(ty=ty, ident=ident, id=p.next_def_id(), ann=p.get_ann());
16461711
}
16471712

16481713
fn parse_method(parser p) -> @ast::method {
16491714
auto lo = p.get_lo_pos();
16501715
auto proto = parse_proto(p);
1651-
auto ident = parse_ident(p);
1716+
auto ident = parse_value_ident(p);
16521717
auto f = parse_fn(p, proto, ast::impure_fn);
16531718
auto meth = rec(ident=ident, meth=f,
16541719
id=p.next_def_id(), ann=p.get_ann());
@@ -1675,7 +1740,7 @@ fn parse_dtor(parser p) -> @ast::method {
16751740

16761741
fn parse_item_obj(parser p, ast::layer lyr) -> @ast::item {
16771742
auto lo = p.get_last_lo_pos();
1678-
auto ident = parse_ident(p);
1743+
auto ident = parse_value_ident(p);
16791744
auto ty_params = parse_ty_params(p);
16801745
auto pf = parse_obj_field;
16811746
let util::common::spanned[vec[ast::obj_field]] fields =
@@ -1722,7 +1787,7 @@ fn parse_mod_items(parser p, token::token term) -> ast::_mod {
17221787
fn parse_item_const(parser p) -> @ast::item {
17231788
auto lo = p.get_last_lo_pos();
17241789
auto ty = parse_ty(p);
1725-
auto id = parse_ident(p);
1790+
auto id = parse_value_ident(p);
17261791
expect(p, token::EQ);
17271792
auto e = parse_expr(p);
17281793
auto hi = p.get_hi_pos();
@@ -1871,6 +1936,7 @@ fn parse_item_tag(parser p) -> @ast::item {
18711936
auto tok = p.peek();
18721937
alt (tok) {
18731938
case (token::IDENT(?name)) {
1939+
check_bad_word(p);
18741940
auto vlo = p.get_lo_pos();
18751941
p.bump();
18761942

@@ -2215,7 +2281,7 @@ fn parse_crate_directive(parser p) -> ast::crate_directive
22152281
}
22162282
} else if (eat_word(p, "let")) {
22172283
expect(p, token::LPAREN);
2218-
auto id = parse_ident(p);
2284+
auto id = parse_value_ident(p);
22192285
expect(p, token::EQ);
22202286
auto x = parse_expr(p);
22212287
expect(p, token::RPAREN);

0 commit comments

Comments
 (0)