From e0f44730e8dc75c17dc86fcb48769d62a4dbcaae Mon Sep 17 00:00:00 2001 From: Brian Anderson Date: Sat, 29 Oct 2011 01:21:43 -0700 Subject: [PATCH] rustc: Support 'companion mod's for crates and directory mods Under this scheme when parsing foo.rc the parser will also look for foo.rs to fill in the crate-level module, and when evaluating a directory module directive it will look for a .rs file with the same name as the directory. --- src/comp/syntax/parse/eval.rs | 65 +++++++++++++++++++++-- src/comp/syntax/parse/parser.rs | 8 +-- src/compiletest/compiletest.rc | 1 - src/fuzzer/fuzzer.rc | 2 - src/fuzzer/fuzzer.rs | 3 -- src/test/run-pass/companionmod-src/b.rs | 2 + src/test/run-pass/companionmod-src/b/x.rs | 1 + src/test/run-pass/companionmod-src/d.rs | 2 + src/test/run-pass/companionmod-src/d/x.rs | 1 + src/test/run-pass/companionmod.rc | 10 ++++ src/test/run-pass/companionmod.rs | 7 +++ 11 files changed, 88 insertions(+), 14 deletions(-) create mode 100644 src/test/run-pass/companionmod-src/b.rs create mode 100644 src/test/run-pass/companionmod-src/b/x.rs create mode 100644 src/test/run-pass/companionmod-src/d.rs create mode 100644 src/test/run-pass/companionmod-src/d/x.rs create mode 100644 src/test/run-pass/companionmod.rc create mode 100644 src/test/run-pass/companionmod.rs diff --git a/src/comp/syntax/parse/eval.rs b/src/comp/syntax/parse/eval.rs index 8a48a8ec2d15..e4b60c4c21e3 100644 --- a/src/comp/syntax/parse/eval.rs +++ b/src/comp/syntax/parse/eval.rs @@ -1,5 +1,5 @@ -import std::{str, option}; +import std::{str, option, result, io, fs}; import std::option::{some, none}; import syntax::ast; import syntax::parse::token; @@ -25,11 +25,65 @@ fn eval_crate_directives(cx: ctx, cdirs: [@ast::crate_directive], prefix: str, } fn eval_crate_directives_to_mod(cx: ctx, cdirs: [@ast::crate_directive], - prefix: str) -> ast::_mod { + prefix: str, suffix: option::t) + -> (ast::_mod, [ast::attribute]) { + log #fmt("eval crate prefix: %s", prefix); + log #fmt("eval crate suffix: %s", + option::from_maybe("none", suffix)); + let (cview_items, citems, cattrs) + = parse_companion_mod(cx, prefix, suffix); let view_items: [@ast::view_item] = []; let items: [@ast::item] = []; eval_crate_directives(cx, cdirs, prefix, view_items, items); - ret {view_items: view_items, items: items}; + ret ({view_items: view_items + cview_items, + items: items + citems}, + cattrs); +} + +/* +The 'companion mod'. So .rc crates and directory mod crate directives define +modules but not a .rs file to fill those mods with stuff. The companion mod is +a convention for location a .rs file to go with them. For .rc files the +companion mod is a .rs file with the same name; for directory mods the +companion mod is a .rs file with the same name as the directory. + +We build the path to the companion mod by combining the prefix and the +optional suffix then adding the .rs extension. +*/ +fn parse_companion_mod(cx: ctx, prefix: str, suffix: option::t) + -> ([@ast::view_item], [@ast::item], [ast::attribute]) { + + fn companion_file(prefix: str, suffix: option::t) -> str { + alt suffix { + option::some(s) { fs::connect(prefix, s) } + option::none. { prefix } + } + ".rs" + } + + fn file_exists(path: str) -> bool { + // Crude, but there's no lib function for this and I'm not + // up to writing it just now + alt io::file_reader(path) { + result::ok(_) { true } + result::err(_) { false } + } + } + + let modpath = companion_file(prefix, suffix); + log #fmt("looking for companion mod %s", modpath); + if file_exists(modpath) { + log "found companion mod"; + let p0 = new_parser_from_file(cx.sess, cx.cfg, modpath, + cx.chpos, cx.byte_pos, SOURCE_FILE); + let inner_attrs = parse_inner_attrs_and_next(p0); + let first_item_outer_attrs = inner_attrs.next; + let m0 = parse_mod_items(p0, token::EOF, first_item_outer_attrs); + cx.chpos = p0.get_chpos(); + cx.byte_pos = p0.get_byte_pos(); + ret (m0.view_items, m0.items, inner_attrs.inner); + } else { + ret ([], [], []); + } } fn eval_crate_directive(cx: ctx, cdir: @ast::crate_directive, prefix: str, @@ -66,10 +120,11 @@ fn eval_crate_directive(cx: ctx, cdir: @ast::crate_directive, prefix: str, if std::fs::path_is_absolute(path) { path } else { prefix + std::fs::path_sep() + path }; - let m0 = eval_crate_directives_to_mod(cx, cdirs, full_path); + let (m0, a0) = eval_crate_directives_to_mod( + cx, cdirs, full_path, none); let i = @{ident: id, - attrs: attrs, + attrs: attrs + a0, id: cx.sess.next_id, node: ast::item_mod(m0), span: cdir.span}; diff --git a/src/comp/syntax/parse/parser.rs b/src/comp/syntax/parse/parser.rs index f605a2fb6999..98dcb1411924 100644 --- a/src/comp/syntax/parse/parser.rs +++ b/src/comp/syntax/parse/parser.rs @@ -1,5 +1,5 @@ -import std::{io, vec, str, option, either, result}; +import std::{io, vec, str, option, either, result, fs}; import std::option::{some, none}; import std::either::{left, right}; import std::map::{hashmap, new_str_hash}; @@ -2599,13 +2599,15 @@ fn parse_crate_from_crate_file(input: str, cfg: ast::crate_cfg, mutable chpos: p.get_chpos(), mutable byte_pos: p.get_byte_pos(), cfg: p.get_cfg()}; - let m = eval::eval_crate_directives_to_mod(cx, cdirs, prefix); + let (companionmod, _) = fs::splitext(fs::basename(input)); + let (m, attrs) = eval::eval_crate_directives_to_mod( + cx, cdirs, prefix, option::some(companionmod)); let hi = p.get_hi_pos(); expect(p, token::EOF); ret @spanned(lo, hi, {directives: cdirs, module: m, - attrs: crate_attrs, + attrs: crate_attrs + attrs, config: p.get_cfg()}); } diff --git a/src/compiletest/compiletest.rc b/src/compiletest/compiletest.rc index 2f9ffe50f81e..703862076a5f 100644 --- a/src/compiletest/compiletest.rc +++ b/src/compiletest/compiletest.rc @@ -1,6 +1,5 @@ use std; -mod compiletest; mod procsrv; mod util; mod header; diff --git a/src/fuzzer/fuzzer.rc b/src/fuzzer/fuzzer.rc index 473a7b20615a..9793b9d21c71 100644 --- a/src/fuzzer/fuzzer.rc +++ b/src/fuzzer/fuzzer.rc @@ -3,8 +3,6 @@ use std; use rustc; -mod fuzzer; - // Local Variables: // fill-column: 78; // indent-tabs-mode: nil diff --git a/src/fuzzer/fuzzer.rs b/src/fuzzer/fuzzer.rs index 4a96877dfc12..480b45ae6b4b 100644 --- a/src/fuzzer/fuzzer.rs +++ b/src/fuzzer/fuzzer.rs @@ -1,6 +1,3 @@ -use std; -use rustc; - import std::{fs, io, getopts, math, vec, str, int, uint, option, result}; import std::getopts::{optopt, opt_present, opt_str}; import std::io::stdout; diff --git a/src/test/run-pass/companionmod-src/b.rs b/src/test/run-pass/companionmod-src/b.rs new file mode 100644 index 000000000000..e867ff713cd4 --- /dev/null +++ b/src/test/run-pass/companionmod-src/b.rs @@ -0,0 +1,2 @@ +import g = x::f; +export g; \ No newline at end of file diff --git a/src/test/run-pass/companionmod-src/b/x.rs b/src/test/run-pass/companionmod-src/b/x.rs new file mode 100644 index 000000000000..413b834fb110 --- /dev/null +++ b/src/test/run-pass/companionmod-src/b/x.rs @@ -0,0 +1 @@ +fn f() -> str { "ralph" } \ No newline at end of file diff --git a/src/test/run-pass/companionmod-src/d.rs b/src/test/run-pass/companionmod-src/d.rs new file mode 100644 index 000000000000..e867ff713cd4 --- /dev/null +++ b/src/test/run-pass/companionmod-src/d.rs @@ -0,0 +1,2 @@ +import g = x::f; +export g; \ No newline at end of file diff --git a/src/test/run-pass/companionmod-src/d/x.rs b/src/test/run-pass/companionmod-src/d/x.rs new file mode 100644 index 000000000000..94f006f9a1f7 --- /dev/null +++ b/src/test/run-pass/companionmod-src/d/x.rs @@ -0,0 +1 @@ +fn f() -> str { "nelson" } \ No newline at end of file diff --git a/src/test/run-pass/companionmod.rc b/src/test/run-pass/companionmod.rc new file mode 100644 index 000000000000..405e5efc846e --- /dev/null +++ b/src/test/run-pass/companionmod.rc @@ -0,0 +1,10 @@ +// Test that crates and directory modules can contain code + +mod a = "companionmod-src" { + mod b { + mod x; + } + mod c = "d" { + mod x; + } +} \ No newline at end of file diff --git a/src/test/run-pass/companionmod.rs b/src/test/run-pass/companionmod.rs new file mode 100644 index 000000000000..9b9d1a00f0f6 --- /dev/null +++ b/src/test/run-pass/companionmod.rs @@ -0,0 +1,7 @@ +// This isn't really xfailed; it's used by the companionmod.rc test +// xfail-test + +fn main() { + assert a::b::g() == "ralph"; + assert a::c::g() == "nelson"; +} \ No newline at end of file