Skip to content

Commit 43d81a8

Browse files
Rollup merge of rust-lang#42071 - nrc:parse-mods, r=nikomatsakis
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.
2 parents f4780a3 + a256630 commit 43d81a8

File tree

6 files changed

+46
-10
lines changed

6 files changed

+46
-10
lines changed

src/libsyntax/attr.rs

+1-1
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

+6-2
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

+2-2
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

+23-2
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

+13-2
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

+1-1
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)