Skip to content

Commit 9d37d03

Browse files
committed
auto merge of #6737 : dotdash/rust/static_keywords, r=pcwalton
Currently, keywords are stored in hashsets that are recreated for every Parser instance, which is quite expensive since macro expansion creates lots of them. Additionally, the parser functions that look for a keyword currently accept a string and have a runtime check to validate that they actually received a keyword. By creating an enum for the keywords and inserting them into the ident interner, we can avoid the creation of the hashsets and get static checks for the keywords. For libstd, this cuts the parse+expansion part from ~2.6s to ~1.6s.
2 parents 6e65a3f + 6c62d77 commit 9d37d03

File tree

5 files changed

+280
-245
lines changed

5 files changed

+280
-245
lines changed

src/libsyntax/ext/trace_macros.rs

+3-2
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ use ext::base::ExtCtxt;
1616
use ext::base;
1717
use parse::lexer::{new_tt_reader, reader};
1818
use parse::parser::Parser;
19+
use parse::token::keywords;
1920

2021
pub fn expand_trace_macros(cx: @ExtCtxt,
2122
sp: span,
@@ -36,9 +37,9 @@ pub fn expand_trace_macros(cx: @ExtCtxt,
3637
rdr.dup()
3738
);
3839

39-
if rust_parser.is_keyword("true") {
40+
if rust_parser.is_keyword(keywords::True) {
4041
cx.set_trace_macros(true);
41-
} else if rust_parser.is_keyword("false") {
42+
} else if rust_parser.is_keyword(keywords::False) {
4243
cx.set_trace_macros(false);
4344
} else {
4445
cx.span_fatal(sp, "trace_macros! only accepts `true` or `false`")

src/libsyntax/parse/common.rs

+13-84
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ use ast;
1414
use codemap::{BytePos, spanned};
1515
use parse::lexer::reader;
1616
use parse::parser::Parser;
17+
use parse::token::keywords;
1718
use parse::token;
1819

1920
use opt_vec;
@@ -133,54 +134,15 @@ pub impl Parser {
133134
return if *self.token == *tok { self.bump(); true } else { false };
134135
}
135136

136-
// Storing keywords as interned idents instead of strings would be nifty.
137-
138-
// A sanity check that the word we are asking for is a known keyword
139-
// NOTE: this could be done statically....
140-
fn require_keyword(&self, word: &str) {
141-
if !self.keywords.contains_equiv(&word) {
142-
self.bug(fmt!("unknown keyword: %s", word));
143-
}
144-
}
145-
146-
// return true when this token represents the given string, and is not
147-
// followed immediately by :: .
148-
fn token_is_word(&self, word: &str, tok: &token::Token) -> bool {
149-
match *tok {
150-
token::IDENT(sid, false) => { word == *self.id_to_str(sid) }
151-
_ => { false }
152-
}
153-
}
154-
155-
fn token_is_keyword(&self, word: &str, tok: &token::Token) -> bool {
156-
self.require_keyword(word);
157-
self.token_is_word(word, tok)
158-
}
159-
160-
fn is_keyword(&self, word: &str) -> bool {
161-
self.token_is_keyword(word, &copy *self.token)
162-
}
163-
164-
fn id_is_any_keyword(&self, id: ast::ident) -> bool {
165-
self.keywords.contains(self.id_to_str(id))
166-
}
167-
168-
fn is_any_keyword(&self, tok: &token::Token) -> bool {
169-
match *tok {
170-
token::IDENT(sid, false) => {
171-
self.keywords.contains(self.id_to_str(sid))
172-
}
173-
_ => false
174-
}
137+
fn is_keyword(&self, kw: keywords::Keyword) -> bool {
138+
token::is_keyword(kw, self.token)
175139
}
176140

177-
// if the given word is not a keyword, signal an error.
178141
// if the next token is the given keyword, eat it and return
179142
// true. Otherwise, return false.
180-
fn eat_keyword(&self, word: &str) -> bool {
181-
self.require_keyword(word);
143+
fn eat_keyword(&self, kw: keywords::Keyword) -> bool {
182144
let is_kw = match *self.token {
183-
token::IDENT(sid, false) => word == *self.id_to_str(sid),
145+
token::IDENT(sid, false) => kw.to_ident().repr == sid.repr,
184146
_ => false
185147
};
186148
if is_kw { self.bump() }
@@ -190,63 +152,30 @@ pub impl Parser {
190152
// if the given word is not a keyword, signal an error.
191153
// if the next token is not the given word, signal an error.
192154
// otherwise, eat it.
193-
fn expect_keyword(&self, word: &str) {
194-
self.require_keyword(word);
195-
if !self.eat_keyword(word) {
155+
fn expect_keyword(&self, kw: keywords::Keyword) {
156+
if !self.eat_keyword(kw) {
196157
self.fatal(
197158
fmt!(
198159
"expected `%s`, found `%s`",
199-
word,
160+
*self.id_to_str(kw.to_ident()),
200161
self.this_token_to_str()
201162
)
202163
);
203164
}
204165
}
205166

206-
// return true if the given string is a strict keyword
207-
fn is_strict_keyword(&self, word: &str) -> bool {
208-
self.strict_keywords.contains_equiv(&word)
209-
}
210-
211-
// signal an error if the current token is a strict keyword
212-
fn check_strict_keywords(&self) {
213-
match *self.token {
214-
token::IDENT(_, false) => {
215-
let w = token_to_str(self.reader, &copy *self.token);
216-
self.check_strict_keywords_(w);
217-
}
218-
_ => ()
219-
}
220-
}
221-
222167
// signal an error if the given string is a strict keyword
223-
fn check_strict_keywords_(&self, w: &str) {
224-
if self.is_strict_keyword(w) {
168+
fn check_strict_keywords(&self) {
169+
if token::is_strict_keyword(self.token) {
225170
self.span_err(*self.last_span,
226-
fmt!("found `%s` in ident position", w));
171+
fmt!("found `%s` in ident position", self.this_token_to_str()));
227172
}
228173
}
229174

230-
// return true if this is a reserved keyword
231-
fn is_reserved_keyword(&self, word: &str) -> bool {
232-
self.reserved_keywords.contains_equiv(&word)
233-
}
234-
235175
// signal an error if the current token is a reserved keyword
236176
fn check_reserved_keywords(&self) {
237-
match *self.token {
238-
token::IDENT(_, false) => {
239-
let w = token_to_str(self.reader, &copy *self.token);
240-
self.check_reserved_keywords_(w);
241-
}
242-
_ => ()
243-
}
244-
}
245-
246-
// signal an error if the given string is a reserved keyword
247-
fn check_reserved_keywords_(&self, w: &str) {
248-
if self.is_reserved_keyword(w) {
249-
self.fatal(fmt!("`%s` is a reserved keyword", w));
177+
if token::is_reserved_keyword(self.token) {
178+
self.fatal(fmt!("`%s` is a reserved keyword", self.this_token_to_str()));
250179
}
251180
}
252181

src/libsyntax/parse/obsolete.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ use ast::{expr, expr_lit, lit_nil, attribute};
2323
use ast;
2424
use codemap::{span, respan};
2525
use parse::parser::Parser;
26-
use parse::token::Token;
26+
use parse::token::{keywords, Token};
2727
use parse::token;
2828

2929
use core::to_bytes;
@@ -295,9 +295,9 @@ pub impl Parser {
295295
}
296296

297297
fn try_parse_obsolete_priv_section(&self, attrs: &[attribute]) -> bool {
298-
if self.is_keyword("priv") && self.look_ahead(1) == token::LBRACE {
298+
if self.is_keyword(keywords::Priv) && self.look_ahead(1) == token::LBRACE {
299299
self.obsolete(copy *self.span, ObsoletePrivSection);
300-
self.eat_keyword("priv");
300+
self.eat_keyword(keywords::Priv);
301301
self.bump();
302302
while *self.token != token::RBRACE {
303303
self.parse_single_struct_field(ast::private, attrs.to_owned());

0 commit comments

Comments
 (0)