mirror of
https://github.com/rust-lang/rust.git
synced 2024-11-22 10:25:09 +01:00
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:
parent
c92f2168d4
commit
7c92435f8f
@ -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
|
||||
|
@ -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)
|
||||
--------------------------
|
||||
|
||||
|
@ -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
|
||||
|
@ -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.
|
||||
|
@ -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.
|
||||
|
82
man/rusti.1
82
man/rusti.1
@ -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.
|
@ -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.
|
||||
|
@ -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
|
||||
|
@ -29,7 +29,6 @@ PKG_FILES := \
|
||||
README.txt \
|
||||
driver \
|
||||
librustpkg \
|
||||
librusti \
|
||||
librustc \
|
||||
compiletest \
|
||||
etc \
|
||||
|
@ -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
|
||||
|
12
mk/tests.mk
12
mk/tests.mk
@ -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)) \
|
||||
|
43
mk/tools.mk
43
mk/tools.mk
@ -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), \
|
||||
|
@ -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
|
||||
|
@ -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 {""}
|
||||
}
|
||||
}
|
@ -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);
|
||||
}
|
||||
}
|
@ -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);
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user