Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
Add :load command to REPL that can compile and load external libraries
  • Loading branch information
bleibig authored and brson committed Dec 7, 2012
1 parent bbc04db commit 28027d3
Showing 1 changed file with 96 additions and 5 deletions.
101 changes: 96 additions & 5 deletions src/librusti/rusti.rc
Expand Up @@ -51,6 +51,7 @@ struct Repl {
binary: ~str,
running: bool,
view_items: ~str,
lib_search_paths: ~[~str],
stmts: ~str
}

Expand Down Expand Up @@ -132,7 +133,7 @@ fn run(repl: Repl, input: ~str) -> Repl {
let options: @session::options = @{
crate_type: session::unknown_crate,
binary: repl.binary,
addl_lib_search_paths: ~[os::getcwd()],
addl_lib_search_paths: repl.lib_search_paths.map(|p| Path(*p)),
.. *session::basic_options()
};

Expand Down Expand Up @@ -284,6 +285,63 @@ fn run(repl: Repl, input: ~str) -> Repl {
record(repl, blk, sess.parse_sess.interner)
}

// Compiles a crate given by the filename as a library if the compiled
// version doesn't exist or is older than the source file. Binary is
// the name of the compiling executable. Returns Some(true) if it
// successfully compiled, Some(false) if the crate wasn't compiled
// because it already exists and is newer than the source file, or
// None if there were compile errors.
fn compile_crate(src_filename: ~str, binary: ~str) -> Option<bool> {
match do task::try {
let src_path = Path(src_filename);
let options: @session::options = @{
binary: binary,
addl_lib_search_paths: ~[os::getcwd()],
.. *session::basic_options()
};
let input = driver::file_input(src_path);
let sess = driver::build_session(options, diagnostic::emit);
sess.building_library = true;
let cfg = driver::build_configuration(sess, binary, input);
let outputs = driver::build_output_filenames(input, &None, &None, sess);
// If the library already exists and is newer than the source
// file, skip compilation and return None.
let mut should_compile = true;
let dir = os::list_dir_path(&Path(outputs.out_filename.dirname()));
let maybe_lib_path = do dir.find |file| {
// The actual file's name has a hash value and version
// number in it which is unknown at this time, so looking
// for a file that matches out_filename won't work,
// instead we guess which file is the library by matching
// the prefix and suffix of out_filename to files in the
// directory.
let file_str = file.filename().get();
file_str.starts_with(outputs.out_filename.filestem().get())
&& file_str.ends_with(outputs.out_filename.filetype().get())
};
match maybe_lib_path {
Some(lib_path) => {
let (src_mtime, _) = src_path.get_mtime().get();
let (lib_mtime, _) = lib_path.get_mtime().get();
if lib_mtime >= src_mtime {
should_compile = false;
}
},
None => { },
}
if (should_compile) {
io::println(fmt!("compiling %s...", src_filename));
driver::compile_upto(sess, cfg, input, driver::cu_everything,
Some(outputs));
true
} else { false }
} {
Ok(true) => Some(true),
Ok(false) => Some(false),
Err(_) => None,
}
}

/// Tries to get a line from rl after outputting a prompt. Returns
/// None if no input was read (e.g. EOF was reached).
fn get_line(prompt: ~str) -> Option<~str> {
Expand All @@ -302,7 +360,7 @@ fn get_line(prompt: ~str) -> Option<~str> {

/// Run a command, e.g. :clear, :exit, etc.
fn run_cmd(repl: &mut Repl, _in: io::Reader, _out: io::Writer,
cmd: ~str, _args: ~[~str]) -> CmdAction {
cmd: ~str, args: ~[~str]) -> CmdAction {
let mut action = action_none;
match cmd {
~"exit" => repl.running = false,
Expand All @@ -316,10 +374,43 @@ fn run_cmd(repl: &mut Repl, _in: io::Reader, _out: io::Writer,
~"help" => {
io::println(
~":{\\n ..lines.. \\n:}\\n - execute multiline command\n" +
~":load <crate> ... - loads given crates as dynamic libraries" +
~":clear - clear the screen\n" +
~":exit - exit from the repl\n" +
~":help - show this message");
}
~"load" => {
let mut loaded_crates: ~[~str] = ~[];
for args.each |arg| {
let (crate, filename) =
if arg.ends_with(".rs") || arg.ends_with(".rc") {
(arg.substr(0, arg.len() - 3), *arg)
} else {
(*arg, arg + ~".rs")
};
match compile_crate(filename, repl.binary) {
Some(_) => loaded_crates.push(crate),
None => { }
}
}
for loaded_crates.each |crate| {
let crate_path = Path(*crate);
let crate_dir = crate_path.dirname();
let crate_name = crate_path.filename().get();
if !repl.view_items.contains(*crate) {
repl.view_items += fmt!("extern mod %s;\n", crate_name);
if !repl.lib_search_paths.contains(&crate_dir) {
repl.lib_search_paths.push(crate_dir);
}
}
}
if loaded_crates.is_empty() {
io::println("no crates loaded");
} else {
io::println(fmt!("crates loaded: %s",
str::connect(loaded_crates, ", ")));
}
}
~"{" => {
let mut multiline_cmd = ~"";
let mut end_multiline = false;
Expand Down Expand Up @@ -356,9 +447,7 @@ fn run_line(repl: &mut Repl, in: io::Reader, out: io::Writer, line: ~str)

if !cmd.is_empty() {
let args = if len > 1 {
do vec::view(split, 1, len - 1).map |arg| {
*arg
}
vec::slice(split, 1, len)
} else { ~[] };

match run_cmd(repl, in, out, cmd, args) {
Expand Down Expand Up @@ -394,6 +483,7 @@ pub fn main() {
binary: args[0],
running: true,
view_items: ~"",
lib_search_paths: ~[],
stmts: ~""
};

Expand All @@ -403,6 +493,7 @@ pub fn main() {
suggest(~":clear");
suggest(~":exit");
suggest(~":help");
suggest(~":load");
}
}
}
Expand Down

0 comments on commit 28027d3

Please sign in to comment.