remove the rusti command

Closes #9818
Closes #9567
Closes #8924
Closes #8910
Closes #8392
Closes #7692
Closes #7499
Closes #7220
This commit is contained in:
Daniel Micay 2013-10-16 22:23:12 -04:00
parent c92f2168d4
commit 7c92435f8f
16 changed files with 15 additions and 1417 deletions

View File

@ -221,7 +221,6 @@ CFG_LIBRUSTC_$(1) :=$(call CFG_LIB_NAME_$(1),rustc)
CFG_LIBSYNTAX_$(1) :=$(call CFG_LIB_NAME_$(1),syntax)
CFG_LIBRUSTPKG_$(1) :=$(call CFG_LIB_NAME_$(1),rustpkg)
CFG_LIBRUSTDOC_$(1) :=$(call CFG_LIB_NAME_$(1),rustdoc)
CFG_LIBRUSTI_$(1) :=$(call CFG_LIB_NAME_$(1),rusti)
EXTRALIB_GLOB_$(1) :=$(call CFG_LIB_GLOB_$(1),extra)
STDLIB_GLOB_$(1) :=$(call CFG_LIB_GLOB_$(1),std)
@ -229,14 +228,12 @@ LIBRUSTC_GLOB_$(1) :=$(call CFG_LIB_GLOB_$(1),rustc)
LIBSYNTAX_GLOB_$(1) :=$(call CFG_LIB_GLOB_$(1),syntax)
LIBRUSTPKG_GLOB_$(1) :=$(call CFG_LIB_GLOB_$(1),rustpkg)
LIBRUSTDOC_GLOB_$(1) :=$(call CFG_LIB_GLOB_$(1),rustdoc)
LIBRUSTI_GLOB_$(1) :=$(call CFG_LIB_GLOB_$(1),rusti)
EXTRALIB_DSYM_GLOB_$(1) :=$(call CFG_LIB_DSYM_GLOB_$(1),extra)
STDLIB_DSYM_GLOB_$(1) :=$(call CFG_LIB_DSYM_GLOB_$(1),std)
LIBRUSTC_DSYM_GLOB_$(1) :=$(call CFG_LIB_DSYM_GLOB_$(1),rustc)
LIBSYNTAX_DSYM_GLOB_$(1) :=$(call CFG_LIB_DSYM_GLOB_$(1),syntax)
LIBRUSTPKG_DSYM_GLOB_$(1) :=$(call CFG_LIB_DSYM_GLOB_$(1),rustpkg)
LIBRUSTDOC_DSYM_GLOB_$(1) :=$(call CFG_LIB_DSYM_GLOB_$(1),rustdoc)
LIBRUSTI_DSYM_GLOB_$(1) :=$(call CFG_LIB_DSYM_GLOB_$(1),rusti)
endef
@ -446,14 +443,12 @@ CSREQ$(1)_T_$(2)_H_$(3) = \
$$(HBIN$(1)_H_$(3))/rusti$$(X_$(3)) \
$$(HLIB$(1)_H_$(3))/$(CFG_LIBRUSTPKG_$(3)) \
$$(HLIB$(1)_H_$(3))/$(CFG_LIBRUSTDOC_$(3)) \
$$(HLIB$(1)_H_$(3))/$(CFG_LIBRUSTI_$(3)) \
$$(TLIB$(1)_T_$(2)_H_$(3))/$(CFG_STDLIB_$(2)) \
$$(TLIB$(1)_T_$(2)_H_$(3))/$(CFG_EXTRALIB_$(2)) \
$$(TLIB$(1)_T_$(2)_H_$(3))/$(CFG_LIBSYNTAX_$(2)) \
$$(TLIB$(1)_T_$(2)_H_$(3))/$(CFG_LIBRUSTC_$(2)) \
$$(TLIB$(1)_T_$(2)_H_$(3))/$(CFG_LIBRUSTPKG_$(2)) \
$$(TLIB$(1)_T_$(2)_H_$(3))/$(CFG_LIBRUSTDOC_$(2)) \
$$(TLIB$(1)_T_$(2)_H_$(3))/$(CFG_LIBRUSTI_$(2)) \
$$(TLIB$(1)_T_$(2)_H_$(3))/$(CFG_LIBRUSTDOC_$(2))
ifeq ($(1),0)
# Don't run the the stage0 compiler under valgrind - that ship has sailed

View File

@ -1,3 +1,11 @@
Version 0.9 (XXX 2013)
--------------------------
* ~XXX changes, numerous bugfixes
* Tooling
* The `rust` and `rusti` commands have been removed, due to lack of maintenance.
Version 0.8 (September 2013)
--------------------------

View File

@ -113,9 +113,7 @@ for more information on them.
When complete, `make install` will place several programs into
`/usr/local/bin`: `rustc`, the Rust compiler; `rustdoc`, the
API-documentation tool; `rustpkg`, the Rust package manager;
`rusti`, the Rust REPL; and `rust`, a tool which acts both as a unified
interface for them, and for a few common command line scenarios.
API-documentation tool; and `rustpkg`, the Rust package manager.
[tarball]: http://static.rust-lang.org/dist/rust-0.8.tar.gz
[win-exe]: http://static.rust-lang.org/dist/rust-0.8-install.exe

View File

@ -130,7 +130,7 @@ To build an executable with debug info (experimental):
.SH "SEE ALSO"
rust, rustdoc, rustpkg, rusti
rustdoc, rustpkg
.SH "BUGS"
See <\fBhttps://github.com/mozilla/rust/issues\fR> for issues.

View File

@ -84,7 +84,7 @@ The generated HTML can be viewed with any standard web browser.
.SH "SEE ALSO"
rust, rustc, rustpkg, rusti
rustc, rustpkg
.SH "BUGS"
See <\fBhttps://github.com/mozilla/rust/issues\fR> for issues.

View File

@ -1,82 +0,0 @@
.TH RUSTI "1" "July 2013" "rusti 0.7" "User Commands"
\" Macros
..
.de Vb \" Begin verbatim text
.ft CW
.nf
.ne \\$1
..
.de Ve \" End verbatim text
.ft R
.fi
..
.SH NAME
rusti \- Rust interactive shell
.SH SYNOPSIS
.B rusti
.SH DESCRIPTION
This program is a REPL (Read-Eval-Print Loop) for the Rust language, available
at <\fBhttps://www.rust-lang.org\fR>. It provides an interactive shell to
evaluate Rust expressions, functions and code snippets, and to experiment with
Rust code.
.B WARNING:
The Rust REPL is experimental and may be unstable. If you encounter problems,
please use the compiler instead.
.SH OPTIONS
Currently none.
.SH SPECIAL COMMANDS
The interactive shell evaluates all input as a sequence of Rust expressions,
except for a set of special commands prefixed by a colon ':'. These special
commands are described below:
.TP
\fB:help\fR
Display a summary of available commands.
.TP
\fB:{\\n ..lines.. \\n:}\\n\fR
execute multiline command
.TP
\fB:load <crate> ...\fR
loads given crates as dynamic libraries
.TP
\fB:clear\fR
clear the bindings
.TP
\fB:exit\fR
exit from the repl
.SH "EXAMPLES"
A simple example session, declaring a variable, defining a function,
evaluating an expression and printing the result:
.PP
.Vb
\& \fBrusti>\fR let x = 42;
\& \fBrusti>\fR fn square(n: int) -> int { n*n }
\& \fBrusti>\fR println(fmt!("%d squared is %d", x, square(x)));
\& 42 squared is 1764
.Ve
.SH "SEE ALSO"
rust, rustc, rustdoc, rustpkg
.SH "BUGS"
See <\fBhttps://github.com/mozilla/rust/issues\fR> for issues.
.SH "AUTHOR"
See \fBAUTHORS.txt\fR in the rust source distribution. Graydon Hoare
<\fIgraydon@mozilla.com\fR> is the project leader.
.SH "COPYRIGHT"
This work is dual-licensed under Apache 2.0 and MIT terms. See \fBCOPYRIGHT\fR
file in the rust source distribution.

View File

@ -181,7 +181,7 @@ custom build logic.
.SH "SEE ALSO"
rust, rustc, rustdoc, rusti
rustc, rustdoc
.SH "BUGS"
See <\fBhttps://github.com/mozilla/rust/issues\fR> for issues.

View File

@ -67,7 +67,6 @@ clean$(1)_H_$(2):
$(Q)rm -f $$(HBIN$(1)_H_$(2))/rustpkg$(X_$(2))
$(Q)rm -f $$(HBIN$(1)_H_$(2))/serializer$(X_$(2))
$(Q)rm -f $$(HBIN$(1)_H_$(2))/rustdoc$(X_$(2))
$(Q)rm -f $$(HBIN$(1)_H_$(2))/rusti$(X_$(2))
$(Q)rm -f $$(HBIN$(1)_H_$(2))/rust$(X_$(2))
$(Q)rm -f $$(HLIB$(1)_H_$(2))/$(CFG_LIBRUSTPKG_$(2))
$(Q)rm -f $$(HLIB$(1)_H_$(2))/$(CFG_LIBRUSTDOC_$(2))
@ -76,14 +75,12 @@ clean$(1)_H_$(2):
$(Q)rm -f $$(HLIB$(1)_H_$(2))/$(CFG_EXTRALIB_$(2))
$(Q)rm -f $$(HLIB$(1)_H_$(2))/$(CFG_LIBRUSTC_$(2))
$(Q)rm -f $$(HLIB$(1)_H_$(2))/$(CFG_LIBSYNTAX_$(2))
$(Q)rm -f $$(HLIB$(1)_H_$(2))/$(CFG_LIBRUSTI_$(2))
$(Q)rm -f $$(HLIB$(1)_H_$(2))/$(STDLIB_GLOB_$(2))
$(Q)rm -f $$(HLIB$(1)_H_$(2))/$(EXTRALIB_GLOB_$(2))
$(Q)rm -f $$(HLIB$(1)_H_$(2))/$(LIBRUSTC_GLOB_$(2))
$(Q)rm -f $$(HLIB$(1)_H_$(2))/$(LIBSYNTAX_GLOB_$(2))
$(Q)rm -f $$(HLIB$(1)_H_$(2))/$(LIBRUSTPKG_GLOB_$(2))
$(Q)rm -f $$(HLIB$(1)_H_$(2))/$(LIBRUSTDOC_GLOB_$(2))
$(Q)rm -f $$(HLIB$(1)_H_$(2))/$(LIBRUSTI_GLOB_$(2))
$(Q)rm -f $$(HLIB$(1)_H_$(2))/$(CFG_RUSTLLVM_$(2))
$(Q)rm -f $$(HLIB$(1)_H_$(2))/libstd.rlib
@ -100,7 +97,6 @@ clean$(1)_T_$(2)_H_$(3):
$(Q)rm -f $$(TBIN$(1)_T_$(2)_H_$(3))/rustpkg$(X_$(2))
$(Q)rm -f $$(TBIN$(1)_T_$(2)_H_$(3))/serializer$(X_$(2))
$(Q)rm -f $$(TBIN$(1)_T_$(2)_H_$(3))/rustdoc$(X_$(2))
$(Q)rm -f $$(TBIN$(1)_T_$(2)_H_$(3))/rusti$(X_$(2))
$(Q)rm -f $$(TBIN$(1)_T_$(2)_H_$(3))/rust$(X_$(2))
$(Q)rm -f $$(TLIB$(1)_T_$(2)_H_$(3))/$(CFG_LIBRUSTPKG_$(2))
$(Q)rm -f $$(TLIB$(1)_T_$(2)_H_$(3))/$(CFG_LIBRUSTDOC_$(2))
@ -109,14 +105,12 @@ clean$(1)_T_$(2)_H_$(3):
$(Q)rm -f $$(TLIB$(1)_T_$(2)_H_$(3))/$(CFG_EXTRALIB_$(2))
$(Q)rm -f $$(TLIB$(1)_T_$(2)_H_$(3))/$(CFG_LIBRUSTC_$(2))
$(Q)rm -f $$(TLIB$(1)_T_$(2)_H_$(3))/$(CFG_LIBSYNTAX_$(2))
$(Q)rm -f $$(TLIB$(1)_T_$(2)_H_$(3))/$(CFG_LIBRUSTI_$(2))
$(Q)rm -f $$(TLIB$(1)_T_$(2)_H_$(3))/$(STDLIB_GLOB_$(2))
$(Q)rm -f $$(TLIB$(1)_T_$(2)_H_$(3))/$(EXTRALIB_GLOB_$(2))
$(Q)rm -f $$(TLIB$(1)_T_$(2)_H_$(3))/$(LIBRUSTC_GLOB_$(2))
$(Q)rm -f $$(TLIB$(1)_T_$(2)_H_$(3))/$(LIBSYNTAX_GLOB_$(2))
$(Q)rm -f $$(TLIB$(1)_T_$(2)_H_$(3))/$(LIBRUSTPKG_GLOB_$(2))
$(Q)rm -f $$(TLIB$(1)_T_$(2)_H_$(3))/$(LIBRUSTDOC_GLOB_$(2))
$(Q)rm -f $$(TLIB$(1)_T_$(2)_H_$(3))/$(LIBRUSTI_GLOB_$(2))
$(Q)rm -f $$(TLIB$(1)_T_$(2)_H_$(3))/$(CFG_RUSTLLVM_$(2))
$(Q)rm -f $$(TLIB$(1)_T_$(2)_H_$(3))/libstd.rlib
$(Q)rm -f $$(TLIB$(1)_T_$(2)_H_$(3))/libmorestack.a

View File

@ -29,7 +29,6 @@ PKG_FILES := \
README.txt \
driver \
librustpkg \
librusti \
librustc \
compiletest \
etc \

View File

@ -104,7 +104,6 @@ install-target-$(1)-host-$(2): $$(CSREQ$$(ISTAGE)_T_$(1)_H_$(2))
$$(Q)$$(call INSTALL_LIB,$$(LIBSYNTAX_GLOB_$(1)))
$$(Q)$$(call INSTALL_LIB,$$(LIBRUSTPKG_GLOB_$(1)))
$$(Q)$$(call INSTALL_LIB,$$(LIBRUSTDOC_GLOB_$(1)))
$$(Q)$$(call INSTALL_LIB,$$(LIBRUSTI_GLOB_$(1)))
$$(Q)$$(call INSTALL_LIB,libmorestack.a)
endef
@ -138,19 +137,16 @@ install-host: $(CSREQ$(ISTAGE)_T_$(CFG_BUILD_TRIPLE)_H_$(CFG_BUILD_TRIPLE))
$(Q)$(call INSTALL,$(HB2),$(PHB),rustc$(X_$(CFG_BUILD_TRIPLE)))
$(Q)$(call INSTALL,$(HB2),$(PHB),rustpkg$(X_$(CFG_BUILD_TRIPLE)))
$(Q)$(call INSTALL,$(HB2),$(PHB),rustdoc$(X_$(CFG_BUILD_TRIPLE)))
$(Q)$(call INSTALL,$(HB2),$(PHB),rusti$(X_$(CFG_BUILD_TRIPLE)))
$(Q)$(call INSTALL_LIB,$(STDLIB_GLOB_$(CFG_BUILD_TRIPLE)))
$(Q)$(call INSTALL_LIB,$(EXTRALIB_GLOB_$(CFG_BUILD_TRIPLE)))
$(Q)$(call INSTALL_LIB,$(LIBRUSTC_GLOB_$(CFG_BUILD_TRIPLE)))
$(Q)$(call INSTALL_LIB,$(LIBSYNTAX_GLOB_$(CFG_BUILD_TRIPLE)))
$(Q)$(call INSTALL_LIB,$(LIBRUSTI_GLOB_$(CFG_BUILD_TRIPLE)))
$(Q)$(call INSTALL_LIB,$(LIBRUSTPKG_GLOB_$(CFG_BUILD_TRIPLE)))
$(Q)$(call INSTALL_LIB,$(LIBRUSTDOC_GLOB_$(CFG_BUILD_TRIPLE)))
$(Q)$(call INSTALL,$(HL),$(PHL),$(CFG_RUNTIME_$(CFG_BUILD_TRIPLE)))
$(Q)$(call INSTALL,$(HL),$(PHL),$(CFG_RUSTLLVM_$(CFG_BUILD_TRIPLE)))
$(Q)$(call INSTALL,$(S)/man, $(PREFIX_ROOT)/share/man/man1,rustc.1)
$(Q)$(call INSTALL,$(S)/man, $(PREFIX_ROOT)/share/man/man1,rustdoc.1)
$(Q)$(call INSTALL,$(S)/man, $(PREFIX_ROOT)/share/man/man1,rusti.1)
$(Q)$(call INSTALL,$(S)/man, $(PREFIX_ROOT)/share/man/man1,rustpkg.1)
install-targets: $(INSTALL_TARGET_RULES)
@ -162,7 +158,6 @@ HOST_LIB_FROM_HL_GLOB = \
uninstall:
$(Q)rm -f $(PHB)/rustc$(X_$(CFG_BUILD_TRIPLE))
$(Q)rm -f $(PHB)/rustpkg$(X_$(CFG_BUILD_TRIPLE))
$(Q)rm -f $(PHB)/rusti$(X_$(CFG_BUILD_TRIPLE))
$(Q)rm -f $(PHB)/rustdoc$(X_$(CFG_BUILD_TRIPLE))
$(Q)rm -f $(PHL)/$(CFG_RUSTLLVM_$(CFG_BUILD_TRIPLE))
$(Q)rm -f $(PHL)/$(CFG_RUNTIME_$(CFG_BUILD_TRIPLE))
@ -173,14 +168,12 @@ uninstall:
$(call HOST_LIB_FROM_HL_GLOB,$(LIBSYNTAX_GLOB_$(CFG_BUILD_TRIPLE))) \
$(call HOST_LIB_FROM_HL_GLOB,$(LIBRUSTPKG_GLOB_$(CFG_BUILD_TRIPLE))) \
$(call HOST_LIB_FROM_HL_GLOB,$(LIBRUSTDOC_GLOB_$(CFG_BUILD_TRIPLE))) \
$(call HOST_LIB_FROM_HL_GLOB,$(LIBRUSTI_GLOB_$(CFG_BUILD_TRIPLE))) \
; \
do rm -f $$i ; \
done
$(Q)rm -Rf $(PHL)/rustc
$(Q)rm -f $(PREFIX_ROOT)/share/man/man1/rustc.1
$(Q)rm -f $(PREFIX_ROOT)/share/man/man1/rustdoc.1
$(Q)rm -f $(PREFIX_ROOT)/share/man/man1/rusti.1
$(Q)rm -f $(PREFIX_ROOT)/share/man/man1/rustpkg.1
# target platform specific variables

View File

@ -15,7 +15,7 @@
# The names of crates that must be tested
TEST_TARGET_CRATES = std extra
TEST_HOST_CRATES = rusti rustpkg rustc rustdoc syntax
TEST_HOST_CRATES = rustpkg rustc rustdoc syntax
TEST_CRATES = $(TEST_TARGET_CRATES) $(TEST_HOST_CRATES)
# Markdown files under doc/ that should have their code extracted and run
@ -189,7 +189,7 @@ check-test: cleantestlibs cleantmptestlogs all check-stage2-rfail
check-lite: cleantestlibs cleantmptestlogs \
check-stage2-std check-stage2-extra check-stage2-rpass \
check-stage2-rustpkg check-stage2-rusti \
check-stage2-rustpkg \
check-stage2-rfail check-stage2-cfail
$(Q)$(CFG_PYTHON) $(S)src/etc/check-summary.py tmp/*.log
@ -379,14 +379,6 @@ $(3)/stage$(1)/test/rustpkgtest-$(2)$$(X_$(2)): \
@$$(call E, compile_and_link: $$@)
$$(STAGE$(1)_T_$(2)_H_$(3)) -o $$@ $$< --test
$(3)/stage$(1)/test/rustitest-$(2)$$(X_$(2)): \
$$(RUSTI_LIB) $$(RUSTI_INPUTS) \
$$(SREQ$(1)_T_$(2)_H_$(3)) \
$$(TLIB$(1)_T_$(2)_H_$(3))/$$(CFG_LIBSYNTAX_$(2)) \
$$(TLIB$(1)_T_$(2)_H_$(3))/$$(CFG_LIBRUSTC_$(2))
@$$(call E, compile_and_link: $$@)
$$(STAGE$(1)_T_$(2)_H_$(3)) -o $$@ $$< --test
$(3)/stage$(1)/test/rustdoctest-$(2)$$(X_$(2)): \
$$(RUSTDOC_LIB) $$(RUSTDOC_INPUTS) \
$$(SREQ$(1)_T_$(2)_H_$(3)) \

View File

@ -24,10 +24,6 @@ RUSTDOC_LIB := $(S)src/librustdoc/rustdoc.rs
RUSTDOC_INPUTS := $(wildcard $(addprefix $(S)src/librustdoc/, \
*.rs */*.rs */*/*.rs))
# Rusti, the JIT REPL
RUSTI_LIB := $(S)src/librusti/rusti.rs
RUSTI_INPUTS := $(wildcard $(S)src/librusti/*.rs)
# FIXME: These are only built for the host arch. Eventually we'll
# have tools that need to built for other targets.
define TOOLS_STAGE_N_TARGET
@ -75,24 +71,6 @@ $$(TBIN$(1)_T_$(4)_H_$(3))/rustdoc$$(X_$(4)): \
@$$(call E, compile_and_link: $$@)
$$(STAGE$(1)_T_$(4)_H_$(3)) --cfg rustdoc -o $$@ $$<
$$(TLIB$(1)_T_$(4)_H_$(3))/$(CFG_LIBRUSTI_$(4)): \
$$(RUSTI_LIB) $$(RUSTI_INPUTS) \
$$(SREQ$(1)_T_$(4)_H_$(3)) \
$$(TLIB$(1)_T_$(4)_H_$(3))/$(CFG_LIBRUSTC_$(4)) \
| $$(TLIB$(1)_T_$(4)_H_$(3))/
@$$(call E, compile_and_link: $$@)
$$(call REMOVE_ALL_OLD_GLOB_MATCHES_EXCEPT,$$(dir $$@),$(LIBRUSTI_GLOB_$(4)),$$(notdir $$@))
$$(STAGE$(1)_T_$(4)_H_$(3)) $$(WFLAGS_ST$(1)) --out-dir $$(@D) $$< && touch $$@
$$(call LIST_ALL_OLD_GLOB_MATCHES_EXCEPT,$$(dir $$@),$(LIBRUSTI_GLOB_$(4)),$$(notdir $$@))
$$(TBIN$(1)_T_$(4)_H_$(3))/rusti$$(X_$(4)): \
$$(DRIVER_CRATE) \
$$(TSREQ$(1)_T_$(4)_H_$(3)) \
$$(TLIB$(1)_T_$(4)_H_$(4))/$(CFG_LIBRUSTI_$(4)) \
| $$(TBIN$(1)_T_$(4)_H_$(3))/
@$$(call E, compile_and_link: $$@)
$$(STAGE$(1)_T_$(4)_H_$(3)) --cfg rusti -o $$@ $$<
endef
define TOOLS_STAGE_N_HOST
@ -147,27 +125,6 @@ $$(HBIN$(2)_H_$(4))/rustdoc$$(X_$(4)): \
@$$(call E, cp: $$@)
$$(Q)cp $$< $$@
$$(HLIB$(2)_H_$(4))/$(CFG_LIBRUSTI_$(4)): \
$$(TLIB$(1)_T_$(4)_H_$(3))/$(CFG_LIBRUSTI_$(4)) \
$$(HLIB$(2)_H_$(4))/$(CFG_LIBRUSTC_$(4)) \
$$(HSREQ$(2)_H_$(4)) \
| $$(HLIB$(2)_H_$(4))/
@$$(call E, cp: $$@)
$$(call REMOVE_ALL_OLD_GLOB_MATCHES_EXCEPT,$$(dir $$@),$(LIBRUSTI_GLOB_$(4)),$$(notdir $$@))
$$(Q)cp $$< $$@
$$(call LIST_ALL_OLD_GLOB_MATCHES_EXCEPT,$$(dir $$@),$(LIBRUSTI_GLOB_$(4)),$$(notdir $$@))
$$(Q)cp -R $$(TLIB$(1)_T_$(4)_H_$(3))/$(LIBRUSTI_GLOB_$(4)) \
$$(wildcard $$(TLIB$(1)_T_$(4)_H_$(3))/$(LIBRUSTI_DSYM_GLOB_$(4))) \
$$(HLIB$(2)_H_$(4))
$$(HBIN$(2)_H_$(4))/rusti$$(X_$(4)): \
$$(TBIN$(1)_T_$(4)_H_$(3))/rusti$$(X_$(4)) \
$$(HLIB$(2)_H_$(4))/$(CFG_LIBRUSTI_$(4)) \
$$(HSREQ$(2)_H_$(4)) \
| $$(HBIN$(2)_H_$(4))/
@$$(call E, cp: $$@)
$$(Q)cp $$< $$@
endef
$(foreach host,$(CFG_HOST_TRIPLES), \

View File

@ -31,8 +31,6 @@ compiletest/ The test runner
librustpkg/ The package manager and build system
librusti/ The JIT REPL
librustdoc/ The Rust API documentation tool
llvm/ The LLVM submodule

View File

@ -1,416 +0,0 @@
// Copyright 2012-2013 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
use std::cast;
use std::util;
use std::hashmap::HashMap;
use std::local_data;
use syntax::ast;
use syntax::parse::token;
use syntax::print::pprust;
use rustc::middle::ty;
use rustc::util::ppaux;
use utils::*;
/// This structure keeps track of the state of the world for the code being
/// executed in rusti.
#[deriving(Clone)]
pub struct Program {
/// All known local variables
local_vars: HashMap<~str, LocalVariable>,
/// New variables which will be present (learned from typechecking)
newvars: HashMap<~str, LocalVariable>,
/// All known view items (use statements), distinct because these must
/// follow extern mods
view_items: ~str,
/// All known 'extern mod' statements (must always come first)
externs: ~str,
/// All known structs defined. These need to have
/// #[deriving(Encodable,Decodable)] to be at all useful in rusti
structs: HashMap<~str, ~str>,
/// All other items, can all be intermingled. Duplicate definitions of the
/// same name have the previous one overwritten.
items: HashMap<~str, ~str>,
}
/// Represents a local variable that the program is currently using.
#[deriving(Clone)]
struct LocalVariable {
/// Should this variable be locally declared as mutable?
mutable: bool,
/// This is the type of the serialized data below
ty: ~str,
/// This is the serialized version of the variable
data: ~[u8],
/// When taking borrowed pointers or slices, care must be taken to ensure
/// that the deserialization produces what we'd expect. If some magic is in
/// order, the first element of this pair is the actual type of the local
/// variable (which can be different from the deserialized type), and the
/// second element are the '&'s which need to be prepended.
alterations: Option<(~str, ~str)>,
}
type LocalCache = @mut HashMap<~str, @~[u8]>;
local_data_key!(tls_key: LocalCache)
impl Program {
pub fn new() -> Program {
Program {
local_vars: HashMap::new(),
newvars: HashMap::new(),
view_items: ~"",
externs: ~"",
structs: HashMap::new(),
items: HashMap::new(),
}
}
/// Clears all local bindings about variables, items, externs, etc.
pub fn clear(&mut self) {
*self = Program::new();
}
/// Creates a block of code to be fed to rustc. This code is not meant to
/// run, but rather it is meant to learn about the input given. This will
/// assert that the types of all bound local variables are encodable,
/// along with checking syntax and other rust-related things. The reason
/// that we only check for encodability is that some super-common types
/// (like &'static str) are not decodable, but are encodable. By doing some
/// mild approximation when decoding, we can emulate at least &str and &[T].
///
/// Once this code has been fed to rustc, it is intended that the code()
/// function is used to actually generate code to fully compile and run.
pub fn test_code(&self, user_input: &str, to_print: &Option<~str>,
new_locals: &[(~str, bool)]) -> ~str {
let mut code = self.program_header();
code.push_str("
fn assert_encodable<T: Encodable<::extra::ebml::writer::Encoder>>(t: &T) {}
");
code.push_str("fn main() {\n");
// It's easy to initialize things if we don't run things...
for (name, var) in self.local_vars.iter() {
let mt = var.mt();
code.push_str(format!("let{} {}: {} = fail!();\n", mt, *name, var.ty));
var.alter(*name, &mut code);
}
code.push_str("{\n");
code.push_str(user_input);
code.push_char('\n');
match *to_print {
Some(ref s) => {
code.push_str(*s);
code.push_str(";\n");
}
None => {}
}
for p in new_locals.iter() {
code.push_str(format!("assert_encodable(&{});\n", *p.first_ref()));
}
code.push_str("};}");
return code;
}
/// Creates a program to be fed into rustc. This program is structured to
/// deserialize all bindings into local variables, run the code input, and
/// then reserialize all the variables back out.
///
/// This program (unlike test_code) is meant to run to actually execute the
/// user's input
pub fn code(&mut self, user_input: &str, to_print: &Option<~str>) -> ~str {
let mut code = self.program_header();
code.push_str("
fn main() {
");
let key: uint= unsafe { cast::transmute(tls_key) };
// First, get a handle to the tls map which stores all the local
// variables. This works by totally legitimately using the 'code'
// pointer of the 'tls_key' function as a uint, and then casting it back
// up to a function
code.push_str(format!("
let __tls_map: @mut ::std::hashmap::HashMap<~str, @~[u8]> = unsafe \\{
let key = ::std::cast::transmute({});
::std::local_data::get(key, |k| k.map(|&x| *x)).unwrap()
\\};\n", key));
// Using this __tls_map handle, deserialize each variable binding that
// we know about
for (name, var) in self.local_vars.iter() {
let mt = var.mt();
code.push_str(format!("let{} {}: {} = \\{
let data = __tls_map.get_copy(&~\"{}\");
let doc = ::extra::ebml::reader::Doc(data);
let mut decoder = ::extra::ebml::reader::Decoder(doc);
::extra::serialize::Decodable::decode(&mut decoder)
\\};\n", mt, *name, var.ty, *name));
var.alter(*name, &mut code);
}
// After all that, actually run the user's code.
code.push_str(user_input);
code.push_char('\n');
match *to_print {
Some(ref s) => { code.push_str(format!("pp(\\{\n{}\n\\});", *s)); }
None => {}
}
let newvars = util::replace(&mut self.newvars, HashMap::new());
for (name, var) in newvars.move_iter() {
self.local_vars.insert(name, var);
}
// After the input code is run, we can re-serialize everything back out
// into tls map (to be read later on by this task)
for (name, var) in self.local_vars.iter() {
code.push_str(format!("\\{
let local: {} = {};
let bytes = do ::std::io::with_bytes_writer |io| \\{
let mut enc = ::extra::ebml::writer::Encoder(io);
local.encode(&mut enc);
\\};
__tls_map.insert(~\"{}\", @bytes);
\\}\n", var.real_ty(), *name, *name));
}
// Close things up, and we're done.
code.push_str("}");
return code;
}
/// Creates the header of the programs which are generated to send to rustc
fn program_header(&self) -> ~str {
// up front, disable lots of annoying lints, then include all global
// state such as items, view items, and extern mods.
let mut code = format!("
\\#[allow(warnings)];
extern mod extra;
{} // extern mods
use extra::serialize::*;
{} // view items
", self.externs, self.view_items);
for (_, s) in self.structs.iter() {
// The structs aren't really useful unless they're encodable
code.push_str("#[deriving(Encodable, Decodable)]");
code.push_str(*s);
code.push_str("\n");
}
for (_, s) in self.items.iter() {
code.push_str(*s);
code.push_str("\n");
}
code.push_str("fn pp<T>(t: T) { println(fmt!(\"%?\", t)); }\n");
return code;
}
/// Initializes the task-local cache of all local variables known to the
/// program. This will be used to read local variables out of once the
/// program starts
pub fn set_cache(&self) {
let map = @mut HashMap::new();
for (name, value) in self.local_vars.iter() {
map.insert((*name).clone(), @(value.data).clone());
}
local_data::set(tls_key, map);
}
/// Once the program has finished running, this function will consume the
/// task-local cache of local variables. After the program finishes running,
/// it updates this cache with the new values of each local variable.
pub fn consume_cache(&mut self) {
let map = local_data::pop(tls_key).expect("tls is empty");
let cons_map = util::replace(map, HashMap::new());
for (name, value) in cons_map.move_iter() {
match self.local_vars.find_mut(&name) {
Some(v) => { v.data = (*value).clone(); }
None => { fail2!("unknown variable {}", name) }
}
}
}
// Simple functions to record various global things (as strings)
pub fn record_view_item(&mut self, vi: &str) {
self.view_items.push_str(vi);
self.view_items.push_char('\n');
}
pub fn record_struct(&mut self, name: &str, s: ~str) {
let name = name.to_owned();
self.items.remove(&name);
self.structs.insert(name, s);
}
pub fn record_item(&mut self, name: &str, it: ~str) {
let name = name.to_owned();
self.structs.remove(&name);
self.items.insert(name, it);
}
pub fn record_extern(&mut self, name: &str) {
self.externs.push_str(name);
self.externs.push_char('\n');
}
/// This monster function is responsible for reading the main function
/// generated by test_code() to determine the type of each local binding
/// created by the user's input.
///
/// Once the types are known, they are inserted into the local_vars map in
/// this Program (to be deserialized later on
pub fn register_new_vars(&mut self, blk: &ast::Block, tcx: ty::ctxt) {
debug2!("looking for new variables");
let newvars = @mut HashMap::new();
do each_user_local(blk) |local| {
let mutable = local.is_mutbl;
do each_binding(local) |path, id| {
let name = do with_pp(token::get_ident_interner()) |pp, _| {
pprust::print_path(pp, path, false);
};
let mut t = ty::node_id_to_type(tcx, id);
let mut tystr = ~"";
let mut lvar = LocalVariable {
ty: ~"",
data: ~[],
mutable: mutable,
alterations: None,
};
// This loop is responsible for figuring out what "alterations"
// are necessary for this local variable.
loop {
match ty::get(t).sty {
// &T encoded will decode to T, so we need to be sure to
// re-take a loan after decoding
ty::ty_rptr(_, mt) => {
if mt.mutbl == ast::MutMutable {
tystr.push_str("&mut ");
} else {
tystr.push_str("&");
}
t = mt.ty;
}
// Literals like [1, 2, 3] and (~[0]).slice() will both
// be serialized to ~[T], whereas it's requested to be a
// &[T] instead.
ty::ty_evec(mt, ty::vstore_slice(*)) |
ty::ty_evec(mt, ty::vstore_fixed(*)) => {
let vty = ppaux::ty_to_str(tcx, mt.ty);
let derefs = tystr.clone();
lvar.ty = tystr + "~[" + vty + "]";
lvar.alterations = Some((tystr + "&[" + vty + "]",
derefs));
break;
}
// Similar to vectors, &str serializes to ~str, so a
// borrow must be taken
ty::ty_estr(ty::vstore_slice(*)) => {
let derefs = tystr.clone();
lvar.ty = tystr + "~str";
lvar.alterations = Some((tystr + "&str", derefs));
break;
}
// Don't generate extra stuff if there's no borrowing
// going on here
_ if "" == tystr => {
lvar.ty = ppaux::ty_to_str(tcx, t);
break;
}
// If we're just borrowing (no vectors or strings), then
// we just need to record how many borrows there were.
_ => {
let derefs = tystr.clone();
let tmptystr = ppaux::ty_to_str(tcx, t);
lvar.alterations = Some((tystr + tmptystr, derefs));
lvar.ty = tmptystr;
break;
}
}
}
newvars.insert(name, lvar);
}
}
// I'm not an @ pointer, so this has to be done outside.
let cons_newvars = util::replace(newvars, HashMap::new());
for (k, v) in cons_newvars.move_iter() {
self.newvars.insert(k, v);
}
// helper functions to perform ast iteration
fn each_user_local(blk: &ast::Block, f: &fn(@ast::Local)) {
do find_user_block(blk) |blk| {
for stmt in blk.stmts.iter() {
match stmt.node {
ast::StmtDecl(d, _) => {
match d.node {
ast::DeclLocal(l) => { f(l); }
_ => {}
}
}
_ => {}
}
}
}
}
fn find_user_block(blk: &ast::Block, f: &fn(&ast::Block)) {
for stmt in blk.stmts.iter() {
match stmt.node {
ast::StmtSemi(e, _) => {
match e.node {
ast::ExprBlock(ref blk) => { return f(blk); }
_ => {}
}
}
_ => {}
}
}
fail2!("couldn't find user block");
}
}
}
impl LocalVariable {
/// Performs alterations to the code provided, given the name of this
/// variable.
fn alter(&self, name: &str, code: &mut ~str) {
match self.alterations {
Some((ref real_ty, ref prefix)) => {
code.push_str(format!("let{} {}: {} = {}{};\n",
self.mt(), name,
*real_ty, *prefix, name));
}
None => {}
}
}
fn real_ty<'a>(&'a self) -> &'a str {
match self.alterations {
Some((ref real_ty, _)) => {
let ret: &'a str = *real_ty;
return ret;
}
None => {
let ret: &'a str = self.ty;
return ret;
}
}
}
fn mt(&self) -> &'static str {
if self.mutable {" mut"} else {""}
}
}

View File

@ -1,786 +0,0 @@
// Copyright 2012-2013 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
/*!
* rusti - A REPL using the JIT backend
*
* Rusti works by serializing state between lines of input. This means that each
* line can be run in a separate task, and the only limiting factor is that all
* local bound variables are encodable.
*
* This is accomplished by feeding in generated input to rustc for execution in
* the JIT compiler. Currently input actually gets fed in three times to get
* information about the program.
*
* - Pass #1
* In this pass, the input is simply thrown at the parser and the input comes
* back. This validates the structure of the program, and at this stage the
* global items (fns, structs, impls, traits, etc.) are filtered from the
* input into the "global namespace". These declarations shadow all previous
* declarations of an item by the same name.
*
* - Pass #2
* After items have been stripped, the remaining input is passed to rustc
* along with all local variables declared (initialized to nothing). This pass
* runs up to typechecking. From this, we can learn about the types of each
* bound variable, what variables are bound, and also ensure that all the
* types are encodable (the input can actually be run).
*
* - Pass #3
* Finally, a program is generated to deserialize the local variable state,
* run the code input, and then reserialize all bindings back into a local
* hash map. This code is then run in the JIT engine provided by the rust
* compiler.
*
* - Pass #4
* Once this code runs, the input has fully been run and the hash map of local
* variables from TLS is read back into the local store of variables. This is
* then used later to pass back along to the parent rusti task and then begin
* waiting for input again.
*
* - Pass #5
* When running rusti code, it's important to consume ownership of the LLVM
* jit contextual information to prevent code from being deallocated too soon
* (before drop glue runs, see #7732). For this reason, the jit context is
* consumed and also passed along to the parent task. The parent task then
* keeps around all contexts while rusti is running. This must be done because
* tasks could in theory be spawned off and running in the background (still
* using the code).
*
* Encoding/decoding is done with EBML, and there is simply a map of ~str ->
* ~[u8] maintaining the values of each local binding (by name).
*/
#[link(name = "rusti",
vers = "0.9-pre",
uuid = "7fb5bf52-7d45-4fee-8325-5ad3311149fc",
url = "https://github.com/mozilla/rust/tree/master/src/rusti")];
#[license = "MIT/ASL2"];
#[crate_type = "lib"];
#[feature(globs)];
extern mod extra;
extern mod rustc;
extern mod syntax;
use std::{libc, io, os, task};
use std::cell::Cell;
use extra::rl::CompletionCb;
use extra::rl;
use rustc::driver::{driver, session};
use rustc::back::link::jit;
use syntax::{ast, codemap, diagnostic};
use syntax::ast_util::*;
use syntax::diagnostic::Emitter;
use syntax::parse::token;
use syntax::print::pprust;
use program::Program;
use utils::*;
mod program;
pub mod utils;
/**
* A structure shared across REPL instances for storing history
* such as statements and view items. I wish the AST was sendable.
*/
pub struct Repl {
prompt: ~str,
binary: ~str,
running: bool,
lib_search_paths: ~[~str],
engines: ~[~jit::Engine],
program: ~Program,
}
// Action to do after reading a :command
enum CmdAction {
action_none,
action_run_line(~str),
}
struct EncodableWarningEmitter;
impl diagnostic::Emitter for EncodableWarningEmitter {
fn emit(&self,
cm: Option<(@codemap::CodeMap, codemap::Span)>,
msg: &str,
lvl: diagnostic::level) {
diagnostic::DefaultEmitter.emit(cm, msg, lvl);
if msg.contains("failed to find an implementation of trait") &&
msg.contains("extra::serialize::Encodable") {
diagnostic::DefaultEmitter.emit(cm,
"Currrently rusti serializes \
bound locals between different \
lines of input. This means that \
all values of local variables \
need to be encodable, and this \
type isn't encodable",
diagnostic::note);
}
}
}
/// Run an input string in a Repl, returning the new Repl.
fn run(mut program: ~Program, binary: ~str, lib_search_paths: ~[~str],
input: ~str) -> (~Program, Option<~jit::Engine>)
{
// Build some necessary rustc boilerplate for compiling things
let binary = binary.to_managed();
let options = @session::options {
crate_type: session::unknown_crate,
binary: binary,
addl_lib_search_paths: @mut lib_search_paths.map(|p| Path::new(p.as_slice())),
jit: true,
.. (*session::basic_options()).clone()
};
// Because we assume that everything is encodable (and assert so), add some
// extra helpful information if the error crops up. Otherwise people are
// bound to be very confused when they find out code is running that they
// never typed in...
let sess = driver::build_session(options,
@EncodableWarningEmitter as
@diagnostic::Emitter);
let intr = token::get_ident_interner();
//
// Stage 1: parse the input and filter it into the program (as necessary)
//
debug2!("parsing: {}", input);
let crate = parse_input(sess, input);
let mut to_run = ~[]; // statements to run (emitted back into code)
let new_locals = @mut ~[]; // new locals being defined
let mut result = None; // resultant expression (to print via pp)
do find_main(&crate, sess) |blk| {
// Fish out all the view items, be sure to record 'extern mod' items
// differently beause they must appear before all 'use' statements
for vi in blk.view_items.iter() {
let s = do with_pp(intr) |pp, _| {
pprust::print_view_item(pp, vi);
};
match vi.node {
ast::view_item_extern_mod(*) => {
program.record_extern(s);
}
ast::view_item_use(*) => { program.record_view_item(s); }
}
}
// Iterate through all of the block's statements, inserting them into
// the correct portions of the program
for stmt in blk.stmts.iter() {
let s = do with_pp(intr) |pp, _| { pprust::print_stmt(pp, *stmt); };
match stmt.node {
ast::StmtDecl(d, _) => {
match d.node {
ast::DeclItem(it) => {
let name = sess.str_of(it.ident);
match it.node {
// Structs are treated specially because to make
// them at all usable they need to be decorated
// with #[deriving(Encoable, Decodable)]
ast::item_struct(*) => {
program.record_struct(name, s);
}
// Item declarations are hoisted out of main()
_ => { program.record_item(name, s); }
}
}
// Local declarations must be specially dealt with,
// record all local declarations for use later on
ast::DeclLocal(l) => {
let mutbl = l.is_mutbl;
do each_binding(l) |path, _| {
let s = do with_pp(intr) |pp, _| {
pprust::print_path(pp, path, false);
};
new_locals.push((s, mutbl));
}
to_run.push(s);
}
}
}
// run statements with expressions (they have effects)
ast::StmtMac(*) | ast::StmtSemi(*) | ast::StmtExpr(*) => {
to_run.push(s);
}
}
}
result = do blk.expr.map |e| {
do with_pp(intr) |pp, _| { pprust::print_expr(pp, e); }
};
}
// return fast for empty inputs
if to_run.len() == 0 && result.is_none() {
return (program, None);
}
//
// Stage 2: run everything up to typeck to learn the types of the new
// variables introduced into the program
//
info2!("Learning about the new types in the program");
program.set_cache(); // before register_new_vars (which changes them)
let input = to_run.connect("\n");
let test = program.test_code(input, &result, *new_locals);
debug2!("testing with ^^^^^^ {:?}", (||{ println(test) })());
let dinput = driver::str_input(test.to_managed());
let cfg = driver::build_configuration(sess);
let crate = driver::phase_1_parse_input(sess, cfg.clone(), &dinput);
let expanded_crate = driver::phase_2_configure_and_expand(sess, cfg, crate);
let analysis = driver::phase_3_run_analysis_passes(sess, &expanded_crate);
// Once we're typechecked, record the types of all local variables defined
// in this input
do find_main(&expanded_crate, sess) |blk| {
program.register_new_vars(blk, analysis.ty_cx);
}
//
// Stage 3: Actually run the code in the JIT
//
info2!("actually running code");
let code = program.code(input, &result);
debug2!("actually running ^^^^^^ {:?}", (||{ println(code) })());
let input = driver::str_input(code.to_managed());
let cfg = driver::build_configuration(sess);
let outputs = driver::build_output_filenames(&input, &None, &None, [], sess);
let sess = driver::build_session(options,
@diagnostic::DefaultEmitter as
@diagnostic::Emitter);
let crate = driver::phase_1_parse_input(sess, cfg.clone(), &input);
let expanded_crate = driver::phase_2_configure_and_expand(sess, cfg, crate);
let analysis = driver::phase_3_run_analysis_passes(sess, &expanded_crate);
let trans = driver::phase_4_translate_to_llvm(sess, expanded_crate, &analysis, outputs);
driver::phase_5_run_llvm_passes(sess, &trans, outputs);
//
// Stage 4: Inform the program that computation is done so it can update all
// local variable bindings.
//
info2!("cleaning up after code");
program.consume_cache();
//
// Stage 5: Extract the LLVM execution engine to take ownership of the
// generated JIT code. This means that rusti can spawn parallel
// tasks and we won't deallocate the code emitted until rusti
// itself is destroyed.
//
return (program, jit::consume_engine());
fn parse_input(sess: session::Session, input: &str) -> ast::Crate {
let code = format!("fn main() \\{\n {} \n\\}", input);
let input = driver::str_input(code.to_managed());
let cfg = driver::build_configuration(sess);
driver::phase_1_parse_input(sess, cfg.clone(), &input)
}
fn find_main(crate: &ast::Crate, sess: session::Session,
f: &fn(&ast::Block)) {
for item in crate.module.items.iter() {
match item.node {
ast::item_fn(_, _, _, _, ref blk) => {
if item.ident == sess.ident_of("main") {
return f(blk);
}
}
_ => {}
}
}
fail2!("main function was expected somewhere...");
}
}
// 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> {
fn has_prefix(v: &[u8], pref: &[u8]) -> bool {
v.len() >= pref.len() && v.slice_to(pref.len()) == pref
}
fn has_extension(v: &[u8], ext: Option<&[u8]>) -> bool {
match ext {
None => true,
Some(ext) => {
v.len() > ext.len() && v[v.len()-ext.len()-1] == '.' as u8 &&
v.slice_from(v.len()-ext.len()) == ext
}
}
}
match do task::try {
let src_path = Path::new(src_filename.as_slice());
let binary = binary.to_managed();
let options = @session::options {
binary: binary,
addl_lib_search_paths: @mut ~[os::getcwd()],
.. (*session::basic_options()).clone()
};
let input = driver::file_input(src_path.clone());
let sess = driver::build_session(options,
@diagnostic::DefaultEmitter as
@diagnostic::Emitter);
*sess.building_library = true;
let cfg = driver::build_configuration(sess);
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(&outputs.out_filename.dir_path());
let maybe_lib_path = do dir.iter().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_vec = file.filename().unwrap();
has_prefix(file_vec, outputs.out_filename.filestem().unwrap()) &&
has_extension(file_vec, outputs.out_filename.extension())
};
match maybe_lib_path {
Some(lib_path) => {
let (src_mtime, _) = src_path.get_mtime().unwrap();
let (lib_mtime, _) = lib_path.get_mtime().unwrap();
if lib_mtime >= src_mtime {
should_compile = false;
}
},
None => { },
}
if (should_compile) {
println(format!("compiling {}...", src_filename));
let crate = driver::phase_1_parse_input(sess, cfg.clone(), &input);
let expanded_crate = driver::phase_2_configure_and_expand(sess, cfg, crate);
let analysis = driver::phase_3_run_analysis_passes(sess, &expanded_crate);
let trans = driver::phase_4_translate_to_llvm(sess, expanded_crate, &analysis, outputs);
driver::phase_5_run_llvm_passes(sess, &trans, 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(use_rl: bool, prompt: &str) -> Option<~str> {
if use_rl {
let result = rl::read(prompt);
match result {
None => None,
Some(line) => {
rl::add_history(line);
Some(line)
}
}
} else {
if io::stdin().eof() {
None
} else {
Some(io::stdin().read_line())
}
}
}
/// Run a command, e.g. :clear, :exit, etc.
fn run_cmd(repl: &mut Repl, _in: @io::Reader, _out: @io::Writer,
cmd: ~str, args: ~[~str], use_rl: bool) -> CmdAction {
let mut action = action_none;
match cmd {
~"exit" => repl.running = false,
~"clear" => {
repl.program.clear();
// XXX: Win32 version of linenoise can't do this
//rl::clear();
}
~"help" => {
println(
":{\\n ..lines.. \\n:}\\n - execute multiline command\n\
:load <crate> ... - loads given crates as dynamic libraries\n\
:clear - clear the bindings\n\
:exit - exit from the repl\n\
:help - show this message");
}
~"load" => {
let mut loaded_crates: ~[~str] = ~[];
for arg in args.iter() {
let (crate, filename) =
if arg.ends_with(".rs") || arg.ends_with(".rc") {
(arg.slice_to(arg.len() - 3).to_owned(), (*arg).clone())
} else {
((*arg).clone(), *arg + ".rs")
};
match compile_crate(filename, repl.binary.clone()) {
Some(_) => loaded_crates.push(crate),
None => { }
}
}
for crate in loaded_crates.iter() {
let crate_path = Path::new(crate.as_slice());
// FIXME (#9639): This needs to handle non-utf8 paths
let crate_dir = crate_path.dirname_str().unwrap();
repl.program.record_extern(format!("extern mod {};", *crate));
if !repl.lib_search_paths.iter().any(|x| crate_dir == *x) {
repl.lib_search_paths.push(crate_dir.to_owned());
}
}
if loaded_crates.is_empty() {
println("no crates loaded");
} else {
println!("crates loaded: {}", loaded_crates.connect(", "));
}
}
~"{" => {
let mut multiline_cmd = ~"";
let mut end_multiline = false;
while (!end_multiline) {
match get_line(use_rl, "rusti| ") {
None => fail2!("unterminated multiline command :\\{ .. :\\}"),
Some(line) => {
if line.trim() == ":}" {
end_multiline = true;
} else {
multiline_cmd.push_str(line);
multiline_cmd.push_char('\n');
}
}
}
}
action = action_run_line(multiline_cmd);
}
_ => println(~"unknown cmd: " + cmd)
}
return action;
}
/// Executes a line of input, which may either be rust code or a
/// :command. Returns a new Repl if it has changed.
pub fn run_line(repl: &mut Repl, input: @io::Reader, out: @io::Writer, line: ~str,
use_rl: bool) -> bool
{
if line.starts_with(":") {
// drop the : and the \n (one byte each)
let full = line.slice(1, line.len());
let split: ~[~str] = full.word_iter().map(|s| s.to_owned()).collect();
let len = split.len();
if len > 0 {
let cmd = split[0].clone();
if !cmd.is_empty() {
let args = if len > 1 {
split.slice(1, len).to_owned()
} else { ~[] };
match run_cmd(repl, input, out, cmd, args, use_rl) {
action_none => { }
action_run_line(multiline_cmd) => {
if !multiline_cmd.is_empty() {
return run_line(repl, input, out, multiline_cmd, use_rl);
}
}
}
return true;
}
}
}
let line = Cell::new(line);
let program = Cell::new(repl.program.clone());
let lib_search_paths = Cell::new(repl.lib_search_paths.clone());
let binary = Cell::new(repl.binary.clone());
let result = do task::try {
run(program.take(), binary.take(), lib_search_paths.take(), line.take())
};
match result {
Ok((program, engine)) => {
repl.program = program;
match engine {
Some(e) => { repl.engines.push(e); }
None => {}
}
return true;
}
Err(*) => { return false; }
}
}
pub fn main() {
os::set_exit_status(main_args(os::args()));
}
struct Completer;
impl CompletionCb for Completer {
fn complete(&self, line: ~str, suggest: &fn(~str)) {
if line.starts_with(":") {
suggest(~":clear");
suggest(~":exit");
suggest(~":help");
suggest(~":load");
}
}
}
pub fn main_args(args: &[~str]) -> int {
#[fixed_stack_segment]; #[inline(never)];
let input = io::stdin();
let out = io::stdout();
let mut repl = Repl {
prompt: ~"rusti> ",
binary: args[0].clone(),
running: true,
lib_search_paths: ~[],
engines: ~[],
program: ~Program::new(),
};
let istty = unsafe { libc::isatty(libc::STDIN_FILENO as i32) } != 0;
// only print this stuff if the user is actually typing into rusti
if istty {
println("WARNING: The Rust REPL is experimental and may be");
println("unstable. If you encounter problems, please use the");
println("compiler instead. Type :help for help.");
unsafe {
rl::complete(@Completer as @CompletionCb)
}
}
while repl.running {
match get_line(istty, repl.prompt) {
None => break,
Some(line) => {
if line.is_empty() {
if istty {
println("()");
}
continue;
}
run_line(&mut repl, input, out, line, istty);
}
}
}
return 0;
}
#[cfg(test)]
mod tests {
use std::io;
use program::Program;
use super::*;
fn repl() -> Repl {
Repl {
prompt: ~"rusti> ",
binary: ~"rusti",
running: true,
lib_search_paths: ~[],
engines: ~[],
program: ~Program::new(),
}
}
// FIXME: #7220 rusti on 32bit mac doesn't work.
// FIXME: #7641 rusti on 32bit linux cross compile doesn't work
// FIXME: #7115 re-enable once LLVM has been upgraded
#[cfg(thiswillneverbeacfgflag)]
fn run_program(prog: &str) {
let mut r = repl();
for cmd in prog.split_iter('\n') {
assert!(run_line(&mut r, io::stdin(), io::stdout(),
cmd.to_owned(), false),
"the command '%s' failed", cmd);
}
}
fn run_program(_: &str) {}
#[ignore]
#[test]
fn super_basic() {
run_program("");
}
#[ignore]
#[test]
fn regression_5937() {
run_program("use std::hashmap;");
}
#[ignore]
#[test]
fn regression_5784() {
run_program("let a = 3;");
}
#[test] #[ignore]
fn new_tasks() {
// XXX: can't spawn new tasks because the JIT code is cleaned up
// after the main function is done.
run_program("
spawn( || println(\"Please don't segfault\") );
do spawn { println(\"Please?\"); }
");
}
#[ignore]
#[test]
fn inferred_integers_usable() {
run_program("let a = 2;\n()\n");
run_program("
let a = 3;
let b = 4u;
assert!((a as uint) + b == 7)
");
}
#[ignore]
#[test]
fn local_variables_allow_shadowing() {
run_program("
let a = 3;
let a = 5;
assert!(a == 5)
");
}
#[ignore]
#[test]
fn string_usable() {
run_program("
let a = ~\"\";
let b = \"\";
let c = @\"\";
let d = a + b + c;
assert!(d.len() == 0);
");
}
#[ignore]
#[test]
fn vectors_usable() {
run_program("
let a = ~[1, 2, 3];
let b = &[1, 2, 3];
let c = @[1, 2, 3];
let d = a + b + c;
assert!(d.len() == 9);
let e: &[int] = [];
");
}
#[ignore]
#[test]
fn structs_usable() {
run_program("
struct A{ a: int }
let b = A{ a: 3 };
assert!(b.a == 3)
");
}
#[ignore]
#[test]
fn mutable_variables_work() {
run_program("
let mut a = 3;
a = 5;
let mut b = std::hashmap::HashSet::new::<int>();
b.insert(a);
assert!(b.contains(&5))
assert!(b.len() == 1)
");
}
#[ignore]
#[test]
fn functions_saved() {
run_program("
fn fib(x: int) -> int { if x < 2 {x} else { fib(x - 1) + fib(x - 2) } }
let a = fib(3);
let a = a + fib(4);
assert!(a == 5)
");
}
#[ignore]
#[test]
fn modules_saved() {
run_program("
mod b { pub fn foo() -> uint { 3 } }
assert!(b::foo() == 3)
");
}
#[ignore]
#[test]
fn multiple_functions() {
run_program("
fn f() {}
fn f() {}
f()
");
}
#[ignore]
#[test]
fn multiple_items_same_name() {
run_program("
fn f() {}
mod f {}
struct f;
enum f {}
fn f() {}
f()
");
}
#[ignore]
#[test]
fn simultaneous_definition_and_expression() {
run_program("
let a = 3; a as u8
");
}
#[ignore]
#[test]
fn exit_quits() {
let mut r = repl();
assert!(r.running);
let result = run_line(&mut r, io::stdin(), io::stdout(),
~":exit", false);
assert!(result);
assert!(!r.running);
}
}

View File

@ -1,52 +0,0 @@
// Copyright 2012-2013 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
use std::io;
use syntax::ast;
use syntax::print::pp;
use syntax::print::pprust;
use syntax::parse::token;
use syntax::visit;
struct EachBindingVisitor<'self> {
f: &'self fn(&ast::Path, ast::NodeId)
}
impl<'self> visit::Visitor<()> for EachBindingVisitor<'self> {
fn visit_pat(&mut self, pat:@ast::Pat, _:()) {
match pat.node {
ast::PatIdent(_, ref path, _) => {
(self.f)(path, pat.id);
}
_ => {}
}
visit::walk_pat(self, pat, ());
}
}
pub fn each_binding(l: @ast::Local, f: &fn(&ast::Path, ast::NodeId)) {
use syntax::visit::Visitor;
let mut vt = EachBindingVisitor{ f: f };
vt.visit_pat(l.pat, ());
}
/// A utility function that hands off a pretty printer to a callback.
pub fn with_pp(intr: @token::ident_interner,
cb: &fn(@pprust::ps, @io::Writer)) -> ~str {
do io::with_str_writer |writer| {
let pp = pprust::rust_printer(writer, intr);
cb(pp, writer);
pp::eof(pp.s);
}
}