@@ -51,6 +51,7 @@ struct Repl {
51
51
binary: ~str,
52
52
running: bool,
53
53
view_items: ~str,
54
+ lib_search_paths: ~[~str],
54
55
stmts: ~str
55
56
}
56
57
@@ -132,7 +133,7 @@ fn run(repl: Repl, input: ~str) -> Repl {
132
133
let options: @session::options = @{
133
134
crate_type: session::unknown_crate,
134
135
binary: repl.binary,
135
- addl_lib_search_paths: ~[os::getcwd()] ,
136
+ addl_lib_search_paths: repl.lib_search_paths.map(|p| Path(*p)) ,
136
137
.. *session::basic_options()
137
138
};
138
139
@@ -284,6 +285,63 @@ fn run(repl: Repl, input: ~str) -> Repl {
284
285
record(repl, blk, sess.parse_sess.interner)
285
286
}
286
287
288
+ // Compiles a crate given by the filename as a library if the compiled
289
+ // version doesn't exist or is older than the source file. Binary is
290
+ // the name of the compiling executable. Returns Some(true) if it
291
+ // successfully compiled, Some(false) if the crate wasn't compiled
292
+ // because it already exists and is newer than the source file, or
293
+ // None if there were compile errors.
294
+ fn compile_crate(src_filename: ~str, binary: ~str) -> Option<bool> {
295
+ match do task::try {
296
+ let src_path = Path(src_filename);
297
+ let options: @session::options = @{
298
+ binary: binary,
299
+ addl_lib_search_paths: ~[os::getcwd()],
300
+ .. *session::basic_options()
301
+ };
302
+ let input = driver::file_input(src_path);
303
+ let sess = driver::build_session(options, diagnostic::emit);
304
+ sess.building_library = true;
305
+ let cfg = driver::build_configuration(sess, binary, input);
306
+ let outputs = driver::build_output_filenames(input, &None, &None, sess);
307
+ // If the library already exists and is newer than the source
308
+ // file, skip compilation and return None.
309
+ let mut should_compile = true;
310
+ let dir = os::list_dir_path(&Path(outputs.out_filename.dirname()));
311
+ let maybe_lib_path = do dir.find |file| {
312
+ // The actual file's name has a hash value and version
313
+ // number in it which is unknown at this time, so looking
314
+ // for a file that matches out_filename won't work,
315
+ // instead we guess which file is the library by matching
316
+ // the prefix and suffix of out_filename to files in the
317
+ // directory.
318
+ let file_str = file.filename().get();
319
+ file_str.starts_with(outputs.out_filename.filestem().get())
320
+ && file_str.ends_with(outputs.out_filename.filetype().get())
321
+ };
322
+ match maybe_lib_path {
323
+ Some(lib_path) => {
324
+ let (src_mtime, _) = src_path.get_mtime().get();
325
+ let (lib_mtime, _) = lib_path.get_mtime().get();
326
+ if lib_mtime >= src_mtime {
327
+ should_compile = false;
328
+ }
329
+ },
330
+ None => { },
331
+ }
332
+ if (should_compile) {
333
+ io::println(fmt!("compiling %s...", src_filename));
334
+ driver::compile_upto(sess, cfg, input, driver::cu_everything,
335
+ Some(outputs));
336
+ true
337
+ } else { false }
338
+ } {
339
+ Ok(true) => Some(true),
340
+ Ok(false) => Some(false),
341
+ Err(_) => None,
342
+ }
343
+ }
344
+
287
345
/// Tries to get a line from rl after outputting a prompt. Returns
288
346
/// None if no input was read (e.g. EOF was reached).
289
347
fn get_line(prompt: ~str) -> Option<~str> {
@@ -302,7 +360,7 @@ fn get_line(prompt: ~str) -> Option<~str> {
302
360
303
361
/// Run a command, e.g. :clear, :exit, etc.
304
362
fn run_cmd(repl: &mut Repl, _in: io::Reader, _out: io::Writer,
305
- cmd: ~str, _args : ~[~str]) -> CmdAction {
363
+ cmd: ~str, args : ~[~str]) -> CmdAction {
306
364
let mut action = action_none;
307
365
match cmd {
308
366
~"exit" => repl.running = false,
@@ -316,10 +374,43 @@ fn run_cmd(repl: &mut Repl, _in: io::Reader, _out: io::Writer,
316
374
~"help" => {
317
375
io::println(
318
376
~":{\\n ..lines.. \\n:}\\n - execute multiline command\n" +
377
+ ~":load <crate> ... - loads given crates as dynamic libraries" +
319
378
~":clear - clear the screen\n" +
320
379
~":exit - exit from the repl\n" +
321
380
~":help - show this message");
322
381
}
382
+ ~"load" => {
383
+ let mut loaded_crates: ~[~str] = ~[];
384
+ for args.each |arg| {
385
+ let (crate, filename) =
386
+ if arg.ends_with(".rs") || arg.ends_with(".rc") {
387
+ (arg.substr(0, arg.len() - 3), *arg)
388
+ } else {
389
+ (*arg, arg + ~".rs")
390
+ };
391
+ match compile_crate(filename, repl.binary) {
392
+ Some(_) => loaded_crates.push(crate),
393
+ None => { }
394
+ }
395
+ }
396
+ for loaded_crates.each |crate| {
397
+ let crate_path = Path(*crate);
398
+ let crate_dir = crate_path.dirname();
399
+ let crate_name = crate_path.filename().get();
400
+ if !repl.view_items.contains(*crate) {
401
+ repl.view_items += fmt!("extern mod %s;\n", crate_name);
402
+ if !repl.lib_search_paths.contains(&crate_dir) {
403
+ repl.lib_search_paths.push(crate_dir);
404
+ }
405
+ }
406
+ }
407
+ if loaded_crates.is_empty() {
408
+ io::println("no crates loaded");
409
+ } else {
410
+ io::println(fmt!("crates loaded: %s",
411
+ str::connect(loaded_crates, ", ")));
412
+ }
413
+ }
323
414
~"{" => {
324
415
let mut multiline_cmd = ~"";
325
416
let mut end_multiline = false;
@@ -356,9 +447,7 @@ fn run_line(repl: &mut Repl, in: io::Reader, out: io::Writer, line: ~str)
356
447
357
448
if !cmd.is_empty() {
358
449
let args = if len > 1 {
359
- do vec::view(split, 1, len - 1).map |arg| {
360
- *arg
361
- }
450
+ vec::slice(split, 1, len)
362
451
} else { ~[] };
363
452
364
453
match run_cmd(repl, in, out, cmd, args) {
@@ -394,6 +483,7 @@ pub fn main() {
394
483
binary: args[0],
395
484
running: true,
396
485
view_items: ~"",
486
+ lib_search_paths: ~[],
397
487
stmts: ~""
398
488
};
399
489
@@ -403,6 +493,7 @@ pub fn main() {
403
493
suggest(~":clear");
404
494
suggest(~":exit");
405
495
suggest(~":help");
496
+ suggest(~":load");
406
497
}
407
498
}
408
499
}
0 commit comments