Skip to content

Commit a256630

Browse files
author
Nick Cameron
committed
Add an option to the parser to avoid parsing out of line modules
This is useful if parsing from stdin or a String and don't want to try and read in a module from another file. Instead we just leave a stub in the AST.
1 parent 7b5c3d2 commit a256630

File tree

6 files changed

+46
-10
lines changed

6 files changed

+46
-10
lines changed

‎src/libsyntax/attr.rs‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -320,7 +320,7 @@ impl Attribute {
320320
pub fn parse<'a, T, F>(&self, sess: &'a ParseSess, mut f: F) -> PResult<'a, T>
321321
where F: FnMut(&mut Parser<'a>) -> PResult<'a, T>,
322322
{
323-
let mut parser = Parser::new(sess, self.tokens.clone(), None, false);
323+
let mut parser = Parser::new(sess, self.tokens.clone(), None, false, false);
324324
let result = f(&mut parser)?;
325325
if parser.token != token::Eof {
326326
parser.unexpected()?;

‎src/libsyntax/ext/tt/macro_parser.rs‎

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -418,9 +418,13 @@ fn inner_parse_loop(sess: &ParseSess,
418418
Success(())
419419
}
420420

421-
pub fn parse(sess: &ParseSess, tts: TokenStream, ms: &[TokenTree], directory: Option<Directory>)
421+
pub fn parse(sess: &ParseSess,
422+
tts: TokenStream,
423+
ms: &[TokenTree],
424+
directory: Option<Directory>,
425+
recurse_into_modules: bool)
422426
-> NamedParseResult {
423-
let mut parser = Parser::new(sess, tts, directory, true);
427+
let mut parser = Parser::new(sess, tts, directory, recurse_into_modules, true);
424428
let mut cur_eis = SmallVector::one(initial_matcher_pos(ms.to_owned(), parser.span.lo));
425429
let mut next_eis = Vec::new(); // or proceed normally
426430

‎src/libsyntax/ext/tt/macro_rules.rs‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -121,7 +121,7 @@ fn generic_extension<'cx>(cx: &'cx mut ExtCtxt,
121121
path: cx.current_expansion.module.directory.clone(),
122122
ownership: cx.current_expansion.directory_ownership,
123123
};
124-
let mut p = Parser::new(cx.parse_sess(), tts, Some(directory), false);
124+
let mut p = Parser::new(cx.parse_sess(), tts, Some(directory), true, false);
125125
p.root_module_name = cx.current_expansion.module.mod_path.last()
126126
.map(|id| id.name.as_str().to_string());
127127

@@ -192,7 +192,7 @@ pub fn compile(sess: &ParseSess, features: &RefCell<Features>, def: &ast::Item)
192192
ast::ItemKind::MacroDef(ref body) => body.clone().into(),
193193
_ => unreachable!(),
194194
};
195-
let argument_map = match parse(sess, body, &argument_gram, None) {
195+
let argument_map = match parse(sess, body, &argument_gram, None, true) {
196196
Success(m) => m,
197197
Failure(sp, tok) => {
198198
let s = parse_failure_msg(tok);

‎src/libsyntax/parse/mod.rs‎

Lines changed: 23 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -149,7 +149,9 @@ pub fn parse_stream_from_source_str(name: String, source: String, sess: &ParseSe
149149
// Create a new parser from a source string
150150
pub fn new_parser_from_source_str(sess: &ParseSess, name: String, source: String)
151151
-> Parser {
152-
filemap_to_parser(sess, sess.codemap().new_filemap(name, source))
152+
let mut parser = filemap_to_parser(sess, sess.codemap().new_filemap(name, source));
153+
parser.recurse_into_file_modules = false;
154+
parser
153155
}
154156

155157
/// Create a new parser, handling errors as appropriate
@@ -218,7 +220,7 @@ pub fn filemap_to_stream(sess: &ParseSess, filemap: Rc<FileMap>) -> TokenStream
218220

219221
/// Given stream and the `ParseSess`, produce a parser
220222
pub fn stream_to_parser(sess: &ParseSess, stream: TokenStream) -> Parser {
221-
Parser::new(sess, stream, None, false)
223+
Parser::new(sess, stream, None, true, false)
222224
}
223225

224226
/// Parse a string representing a character literal into its final form.
@@ -1032,4 +1034,23 @@ mod tests {
10321034
Err(_) => panic!("could not get snippet"),
10331035
}
10341036
}
1037+
1038+
// This tests that when parsing a string (rather than a file) we don't try
1039+
// and read in a file for a module declaration and just parse a stub.
1040+
// See `recurse_into_file_modules` in the parser.
1041+
#[test]
1042+
fn out_of_line_mod() {
1043+
let sess = ParseSess::new(FilePathMapping::empty());
1044+
let item = parse_item_from_source_str(
1045+
"foo".to_owned(),
1046+
"mod foo { struct S; mod this_does_not_exist; }".to_owned(),
1047+
&sess,
1048+
).unwrap().unwrap();
1049+
1050+
if let ast::ItemKind::Mod(ref m) = item.node {
1051+
assert!(m.items.len() == 2);
1052+
} else {
1053+
panic!();
1054+
}
1055+
}
10351056
}

‎src/libsyntax/parse/parser.rs‎

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -179,6 +179,8 @@ pub struct Parser<'a> {
179179
pub obsolete_set: HashSet<ObsoleteSyntax>,
180180
/// Used to determine the path to externally loaded source files
181181
pub directory: Directory,
182+
/// Whether to parse sub-modules in other files.
183+
pub recurse_into_file_modules: bool,
182184
/// Name of the root module this parser originated from. If `None`, then the
183185
/// name is not known. This does not change while the parser is descending
184186
/// into modules, and sub-parsers have new values for this name.
@@ -190,6 +192,7 @@ pub struct Parser<'a> {
190192
pub cfg_mods: bool,
191193
}
192194

195+
193196
struct TokenCursor {
194197
frame: TokenCursorFrame,
195198
stack: Vec<TokenCursorFrame>,
@@ -439,6 +442,7 @@ impl<'a> Parser<'a> {
439442
pub fn new(sess: &'a ParseSess,
440443
tokens: TokenStream,
441444
directory: Option<Directory>,
445+
recurse_into_file_modules: bool,
442446
desugar_doc_comments: bool)
443447
-> Self {
444448
let mut parser = Parser {
@@ -450,6 +454,7 @@ impl<'a> Parser<'a> {
450454
prev_token_kind: PrevTokenKind::Other,
451455
restrictions: Restrictions::empty(),
452456
obsolete_set: HashSet::new(),
457+
recurse_into_file_modules: recurse_into_file_modules,
453458
directory: Directory { path: PathBuf::new(), ownership: DirectoryOwnership::Owned },
454459
root_module_name: None,
455460
expected_tokens: Vec::new(),
@@ -467,12 +472,14 @@ impl<'a> Parser<'a> {
467472
let tok = parser.next_tok();
468473
parser.token = tok.tok;
469474
parser.span = tok.sp;
475+
470476
if let Some(directory) = directory {
471477
parser.directory = directory;
472478
} else if parser.span != syntax_pos::DUMMY_SP {
473479
parser.directory.path = PathBuf::from(sess.codemap().span_to_filename(parser.span));
474480
parser.directory.path.pop();
475481
}
482+
476483
parser.process_potential_macro_variable();
477484
parser
478485
}
@@ -3921,6 +3928,7 @@ impl<'a> Parser<'a> {
39213928
mem::replace(&mut self.directory.ownership, DirectoryOwnership::UnownedViaBlock);
39223929
let item = self.parse_item_(attrs.clone(), false, true)?;
39233930
self.directory.ownership = old_directory_ownership;
3931+
39243932
match item {
39253933
Some(i) => Stmt {
39263934
id: ast::DUMMY_NODE_ID,
@@ -5254,7 +5262,7 @@ impl<'a> Parser<'a> {
52545262
let id = self.parse_ident()?;
52555263
if self.check(&token::Semi) {
52565264
self.bump();
5257-
if in_cfg {
5265+
if in_cfg && self.recurse_into_file_modules {
52585266
// This mod is in an external file. Let's go get it!
52595267
let ModulePathSuccess { path, directory_ownership, warn } =
52605268
self.submod_path(id, &outer_attrs, id_span)?;
@@ -5281,10 +5289,12 @@ impl<'a> Parser<'a> {
52815289
} else {
52825290
let old_directory = self.directory.clone();
52835291
self.push_directory(id, &outer_attrs);
5292+
52845293
self.expect(&token::OpenDelim(token::Brace))?;
52855294
let mod_inner_lo = self.span;
52865295
let attrs = self.parse_inner_attributes()?;
52875296
let module = self.parse_mod_items(&token::CloseDelim(token::Brace), mod_inner_lo)?;
5297+
52885298
self.directory = old_directory;
52895299
Ok((id, ItemKind::Mod(module), Some(attrs)))
52905300
}
@@ -5347,7 +5357,8 @@ impl<'a> Parser<'a> {
53475357
fn submod_path(&mut self,
53485358
id: ast::Ident,
53495359
outer_attrs: &[ast::Attribute],
5350-
id_sp: Span) -> PResult<'a, ModulePathSuccess> {
5360+
id_sp: Span)
5361+
-> PResult<'a, ModulePathSuccess> {
53515362
if let Some(path) = Parser::submod_path_from_attr(outer_attrs, &self.directory.path) {
53525363
return Ok(ModulePathSuccess {
53535364
directory_ownership: match path.file_name().and_then(|s| s.to_str()) {

‎src/libsyntax/tokenstream.rs‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -109,7 +109,7 @@ impl TokenTree {
109109
path: cx.current_expansion.module.directory.clone(),
110110
ownership: cx.current_expansion.directory_ownership,
111111
};
112-
macro_parser::parse(cx.parse_sess(), tts, mtch, Some(directory))
112+
macro_parser::parse(cx.parse_sess(), tts, mtch, Some(directory), true)
113113
}
114114

115115
/// Check if this TokenTree is equal to the other, regardless of span information.

0 commit comments

Comments
 (0)