diff --git a/src/libsyntax/parse/eval.rs b/src/libsyntax/parse/eval.rs index 9a81d646306..660e88c7101 100644 --- a/src/libsyntax/parse/eval.rs +++ b/src/libsyntax/parse/eval.rs @@ -1,7 +1,9 @@ use parser::{Parser, SOURCE_FILE}; use attr::parser_attr; +use ast_util::mk_sp; export eval_crate_directives_to_mod; +export eval_src_mod; type ctx = @{sess: parse::parse_sess, @@ -79,29 +81,46 @@ fn cdir_path_opt(default: ~str, attrs: ~[ast::attribute]) -> ~str { } } +fn eval_src_mod(cx: ctx, prefix: &Path, id: ast::ident, + outer_attrs: ~[ast::attribute]) -> (ast::item_, ~[ast::attribute]) { + let file_path = Path(cdir_path_opt( + cx.sess.interner.get(id) + ~".rs", outer_attrs)); + let full_path = if file_path.is_absolute { + copy file_path + } else { + prefix.push_many(file_path.components) + }; + let p0 = + new_parser_from_file(cx.sess, cx.cfg, + &full_path, SOURCE_FILE); + let inner_attrs = p0.parse_inner_attrs_and_next(); + let mod_attrs = vec::append(outer_attrs, inner_attrs.inner); + let first_item_outer_attrs = inner_attrs.next; + let m0 = p0.parse_mod_items(token::EOF, first_item_outer_attrs); + return (ast::item_mod(m0), mod_attrs); +} + +// XXX: Duplicated from parser.rs +fn mk_item(ctx: ctx, lo: BytePos, hi: BytePos, +ident: ast::ident, + +node: ast::item_, vis: ast::visibility, + +attrs: ~[ast::attribute]) -> @ast::item { + return @{ident: ident, + attrs: attrs, + id: next_node_id(ctx.sess), + node: node, + vis: vis, + span: mk_sp(lo, hi)}; +} + fn eval_crate_directive(cx: ctx, cdir: @ast::crate_directive, prefix: &Path, view_items: &mut ~[@ast::view_item], items: &mut ~[@ast::item]) { match cdir.node { ast::cdir_src_mod(vis, id, attrs) => { - let file_path = Path(cdir_path_opt( - cx.sess.interner.get(id) + ~".rs", attrs)); - let full_path = if file_path.is_absolute { - copy file_path - } else { - prefix.push_many(file_path.components) - }; - let p0 = - new_parser_from_file(cx.sess, cx.cfg, - &full_path, SOURCE_FILE); - let inner_attrs = p0.parse_inner_attrs_and_next(); - let mod_attrs = vec::append(attrs, inner_attrs.inner); - let first_item_outer_attrs = inner_attrs.next; - let m0 = p0.parse_mod_items(token::EOF, first_item_outer_attrs); - - let i = p0.mk_item(cdir.span.lo, cdir.span.hi, + let (m, mod_attrs) = eval_src_mod(cx, prefix, id, attrs); + let i = mk_item(cx, cdir.span.lo, cdir.span.hi, /* FIXME (#2543) */ copy id, - ast::item_mod(m0), vis, mod_attrs); + m, vis, mod_attrs); items.push(i); } ast::cdir_dir_mod(vis, id, cdirs, attrs) => { diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index 2f96f6ba0a0..12ae135e525 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -2958,13 +2958,26 @@ impl Parser { (id, item_const(ty, e), None) } - fn parse_item_mod() -> item_info { + fn parse_item_mod(outer_attrs: ~[ast::attribute]) -> item_info { let id = self.parse_ident(); - self.expect(token::LBRACE); - let inner_attrs = self.parse_inner_attrs_and_next(); - let m = self.parse_mod_items(token::RBRACE, inner_attrs.next); - self.expect(token::RBRACE); - (id, item_mod(m), Some(inner_attrs.inner)) + if self.token == token::SEMI { + self.bump(); + // This mod is in an external file. Let's go get it! + let eval_ctx = @{ + sess: self.sess, + cfg: self.cfg + }; + let prefix = Path(self.sess.cm.span_to_filename(copy self.span)); + let prefix = prefix.dir_path(); + let (m, attrs) = eval::eval_src_mod(eval_ctx, &prefix, id, outer_attrs); + (id, m, Some(move attrs)) + } else { + self.expect(token::LBRACE); + let inner_attrs = self.parse_inner_attrs_and_next(); + let m = self.parse_mod_items(token::RBRACE, inner_attrs.next); + self.expect(token::RBRACE); + (id, item_mod(m), Some(inner_attrs.inner)) + } } fn parse_item_foreign_fn( +attrs: ~[attribute]) -> @foreign_item { @@ -3360,7 +3373,7 @@ impl Parser { return self.parse_item_foreign_mod(lo, visibility, attrs, items_allowed); } else if items_allowed && self.eat_keyword(~"mod") { - let (ident, item_, extra_attrs) = self.parse_item_mod(); + let (ident, item_, extra_attrs) = self.parse_item_mod(attrs); return iovi_item(self.mk_item(lo, self.last_span.hi, ident, item_, visibility, maybe_append(attrs, extra_attrs))); diff --git a/src/test/compile-fail/mod_file_aux.rs b/src/test/compile-fail/mod_file_aux.rs new file mode 100644 index 00000000000..313efe558de --- /dev/null +++ b/src/test/compile-fail/mod_file_aux.rs @@ -0,0 +1,3 @@ +// xfail-test Not a test. Used by other tests + +pub fn foo() -> int { 10 } diff --git a/src/test/compile-fail/mod_file_correct_spans.rs b/src/test/compile-fail/mod_file_correct_spans.rs new file mode 100644 index 00000000000..b34c11a07ac --- /dev/null +++ b/src/test/compile-fail/mod_file_correct_spans.rs @@ -0,0 +1,7 @@ +// Testing that the codemap is maintained correctly when parsing mods from external files + +mod mod_file_aux; + +fn main() { + assert mod_file_aux::bar() == 10; //~ ERROR unresolved name +} \ No newline at end of file diff --git a/src/test/run-pass/mod_file.rs b/src/test/run-pass/mod_file.rs new file mode 100644 index 00000000000..6e8cb220dc0 --- /dev/null +++ b/src/test/run-pass/mod_file.rs @@ -0,0 +1,9 @@ +// xfail-pretty + +// Testing that a plain .rs file can load modules from other source files + +mod mod_file_aux; + +fn main() { + assert mod_file_aux::foo() == 10; +} \ No newline at end of file diff --git a/src/test/run-pass/mod_file_aux.rs b/src/test/run-pass/mod_file_aux.rs new file mode 100644 index 00000000000..313efe558de --- /dev/null +++ b/src/test/run-pass/mod_file_aux.rs @@ -0,0 +1,3 @@ +// xfail-test Not a test. Used by other tests + +pub fn foo() -> int { 10 } diff --git a/src/test/run-pass/mod_file_with_path_attr.rs b/src/test/run-pass/mod_file_with_path_attr.rs new file mode 100644 index 00000000000..e7191099e4c --- /dev/null +++ b/src/test/run-pass/mod_file_with_path_attr.rs @@ -0,0 +1,10 @@ +// xfail-pretty + +// Testing that a plain .rs file can load modules from other source files + +#[path = "mod_file_aux.rs"] +mod m; + +fn main() { + assert m::foo() == 10; +} \ No newline at end of file