mirror of
https://github.com/rust-lang/rust.git
synced 2024-11-27 09:14:20 +00:00
auto merge of #9897 : thestinger/rust/rusti, r=alexcrichton
Closes #9818 Closes #9567 Closes #8924 Closes #8910 Closes #8392 Closes #7692 Closes #7499 Closes #7220 Closes #5038
This commit is contained in:
commit
386fa1d818
1
.gitattributes
vendored
1
.gitattributes
vendored
@ -7,5 +7,4 @@
|
||||
src/etc/pkg/rust-logo.ico binary
|
||||
src/rt/msvc/* -whitespace
|
||||
src/rt/vg/* -whitespace
|
||||
src/rt/linenoise/* -whitespace
|
||||
src/rt/jemalloc/**/* -whitespace
|
||||
|
@ -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)
|
||||
--------------------------
|
||||
|
||||
|
2
configure
vendored
2
configure
vendored
@ -686,7 +686,7 @@ do
|
||||
make_dir $t/rt/libuv/src/ev
|
||||
make_dir $t/rt/jemalloc
|
||||
for i in \
|
||||
isaac linenoise sync test \
|
||||
isaac sync test \
|
||||
arch/i386 arch/x86_64 arch/arm arch/mips \
|
||||
sundown/src sundown/html
|
||||
do
|
||||
|
@ -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
|
||||
|
@ -29,7 +29,7 @@ $(foreach t,$(CFG_TARGET_TRIPLES),$(info cfg: os for $(t) is $(OSTYPE_$(t))))
|
||||
# FIXME: no-omit-frame-pointer is just so that task_start_wrapper
|
||||
# has a frame pointer and the stack walker can understand it. Turning off
|
||||
# frame pointers everywhere is overkill
|
||||
CFG_GCCISH_CFLAGS += -fno-omit-frame-pointer -DUSE_UTF8
|
||||
CFG_GCCISH_CFLAGS += -fno-omit-frame-pointer
|
||||
|
||||
# On Darwin, we need to run dsymutil so the debugging information ends
|
||||
# up in the right place. On other platforms, it automatically gets
|
||||
|
5
mk/rt.mk
5
mk/rt.mk
@ -96,9 +96,7 @@ RUNTIME_CXXS_$(1)_$(2) := \
|
||||
rt/rust_android_dummy.cpp \
|
||||
rt/rust_test_helpers.cpp
|
||||
|
||||
RUNTIME_CS_$(1)_$(2) := rt/linenoise/linenoise.c \
|
||||
rt/linenoise/utf8.c \
|
||||
rt/sundown/src/autolink.c \
|
||||
RUNTIME_CS_$(1)_$(2) := rt/sundown/src/autolink.c \
|
||||
rt/sundown/src/buffer.c \
|
||||
rt/sundown/src/stack.c \
|
||||
rt/sundown/src/markdown.c \
|
||||
@ -116,7 +114,6 @@ RT_BUILD_DIR_$(1)_$(2) := $$(RT_OUTPUT_DIR_$(1))/stage$(2)
|
||||
RUNTIME_DEF_$(1)_$(2) := $$(RT_OUTPUT_DIR_$(1))/rustrt$$(CFG_DEF_SUFFIX_$(1))
|
||||
RUNTIME_INCS_$(1)_$(2) := -I $$(S)src/rt -I $$(S)src/rt/isaac -I $$(S)src/rt/uthash \
|
||||
-I $$(S)src/rt/arch/$$(HOST_$(1)) \
|
||||
-I $$(S)src/rt/linenoise \
|
||||
-I $$(S)src/rt/sundown/src \
|
||||
-I $$(S)src/rt/sundown/html \
|
||||
-I $$(S)src/libuv/include
|
||||
|
15
mk/tests.mk
15
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
|
||||
|
||||
@ -227,7 +227,6 @@ ALL_CS := $(wildcard $(S)src/rt/*.cpp \
|
||||
$(S)src/rt/*/*/*.cpp \
|
||||
$(S)src/rustllvm/*.cpp)
|
||||
ALL_CS := $(filter-out $(S)src/rt/miniz.cpp \
|
||||
$(wildcard $(S)src/rt/linenoise/*.c) \
|
||||
$(wildcard $(S)src/rt/sundown/src/*.c) \
|
||||
$(wildcard $(S)src/rt/sundown/html/*.c) \
|
||||
,$(ALL_CS))
|
||||
@ -240,8 +239,6 @@ ALL_HS := $(filter-out $(S)src/rt/vg/valgrind.h \
|
||||
$(S)src/rt/msvc/typeof.h \
|
||||
$(S)src/rt/msvc/stdint.h \
|
||||
$(S)src/rt/msvc/inttypes.h \
|
||||
$(S)src/rt/linenoise/linenoise.h \
|
||||
$(S)src/rt/linenoise/utf8.h \
|
||||
$(wildcard $(S)src/rt/sundown/src/*.h) \
|
||||
$(wildcard $(S)src/rt/sundown/html/*.h) \
|
||||
,$(ALL_HS))
|
||||
@ -379,14 +376,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), \
|
||||
|
@ -17,7 +17,6 @@ rt/sync - Concurrency utils
|
||||
rt/util - Small utility classes for the runtime.
|
||||
rt/vg - Valgrind headers
|
||||
rt/msvc - MSVC support
|
||||
rt/linenoise - a readline-like line editing library
|
||||
|
||||
test/ Testsuite
|
||||
test/compile-fail - Tests that should fail to compile
|
||||
@ -31,8 +30,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
|
||||
|
@ -94,7 +94,6 @@ pub mod term;
|
||||
pub mod time;
|
||||
pub mod arena;
|
||||
pub mod base64;
|
||||
pub mod rl;
|
||||
pub mod workcache;
|
||||
pub mod enum_set;
|
||||
#[path="num/bigint.rs"]
|
||||
|
@ -1,143 +0,0 @@
|
||||
// Copyright 2012 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.
|
||||
|
||||
//! Bindings for the ability to read lines of input from the console
|
||||
|
||||
use std::c_str::ToCStr;
|
||||
use std::libc::{c_char, c_int};
|
||||
use std::{local_data, str, rt};
|
||||
use std::unstable::finally::Finally;
|
||||
|
||||
mod rustrt {
|
||||
use std::libc::{c_char, c_int};
|
||||
|
||||
externfn!(fn linenoise(prompt: *c_char) -> *c_char)
|
||||
externfn!(fn linenoiseHistoryAdd(line: *c_char) -> c_int)
|
||||
externfn!(fn linenoiseHistorySetMaxLen(len: c_int) -> c_int)
|
||||
externfn!(fn linenoiseHistorySave(file: *c_char) -> c_int)
|
||||
externfn!(fn linenoiseHistoryLoad(file: *c_char) -> c_int)
|
||||
externfn!(fn linenoiseSetCompletionCallback(callback: extern "C" fn(*i8, *())))
|
||||
externfn!(fn linenoiseAddCompletion(completions: *(), line: *c_char))
|
||||
|
||||
externfn!(fn rust_take_linenoise_lock())
|
||||
externfn!(fn rust_drop_linenoise_lock())
|
||||
}
|
||||
|
||||
macro_rules! locked {
|
||||
($expr:expr) => {
|
||||
{
|
||||
// FIXME #9105: can't use a static mutex in pure Rust yet.
|
||||
rustrt::rust_take_linenoise_lock();
|
||||
let x = $expr;
|
||||
rustrt::rust_drop_linenoise_lock();
|
||||
x
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Add a line to history
|
||||
pub fn add_history(line: &str) -> bool {
|
||||
do line.with_c_str |buf| {
|
||||
unsafe {
|
||||
(locked!(rustrt::linenoiseHistoryAdd(buf))) == 1 as c_int
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Set the maximum amount of lines stored
|
||||
pub fn set_history_max_len(len: int) -> bool {
|
||||
unsafe {
|
||||
(locked!(rustrt::linenoiseHistorySetMaxLen(len as c_int))) == 1
|
||||
as c_int
|
||||
}
|
||||
}
|
||||
|
||||
/// Save line history to a file
|
||||
pub fn save_history(file: &str) -> bool {
|
||||
do file.with_c_str |buf| {
|
||||
// 0 on success, -1 on failure
|
||||
unsafe {
|
||||
(locked!(rustrt::linenoiseHistorySave(buf))) == 0 as c_int
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Load line history from a file
|
||||
pub fn load_history(file: &str) -> bool {
|
||||
do file.with_c_str |buf| {
|
||||
// 0 on success, -1 on failure
|
||||
unsafe {
|
||||
(locked!(rustrt::linenoiseHistoryLoad(buf))) == 0 as c_int
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Print out a prompt and then wait for input and return it
|
||||
pub fn read(prompt: &str) -> Option<~str> {
|
||||
do prompt.with_c_str |buf| {
|
||||
let line = unsafe {
|
||||
locked!(rustrt::linenoise(buf))
|
||||
};
|
||||
|
||||
if line.is_null() { None }
|
||||
else {
|
||||
unsafe {
|
||||
do (|| {
|
||||
Some(str::raw::from_c_str(line))
|
||||
}).finally {
|
||||
// linenoise's return value is from strdup, so we
|
||||
// better not leak it.
|
||||
rt::global_heap::exchange_free(line);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// The callback used to perform completions.
|
||||
pub trait CompletionCb {
|
||||
/// Performs a completion.
|
||||
fn complete(&self, line: ~str, suggestion: &fn(~str));
|
||||
}
|
||||
|
||||
local_data_key!(complete_key: @CompletionCb)
|
||||
|
||||
/// Bind to the main completion callback in the current task.
|
||||
///
|
||||
/// The completion callback should not call any `extra::rl` functions
|
||||
/// other than the closure that it receives as its second
|
||||
/// argument. Calling such a function will deadlock on the mutex used
|
||||
/// to ensure that the calls are thread-safe.
|
||||
pub unsafe fn complete(cb: @CompletionCb) {
|
||||
local_data::set(complete_key, cb);
|
||||
|
||||
extern fn callback(line: *c_char, completions: *()) {
|
||||
do local_data::get(complete_key) |opt_cb| {
|
||||
// only fetch completions if a completion handler has been
|
||||
// registered in the current task.
|
||||
match opt_cb {
|
||||
None => {}
|
||||
Some(cb) => {
|
||||
unsafe {
|
||||
do cb.complete(str::raw::from_c_str(line))
|
||||
|suggestion| {
|
||||
do suggestion.with_c_str |buf| {
|
||||
rustrt::linenoiseAddCompletion(completions,
|
||||
buf);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
locked!(rustrt::linenoiseSetCompletionCallback(callback));
|
||||
}
|
@ -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);
|
||||
}
|
||||
}
|
@ -1,47 +0,0 @@
|
||||
# Linenoise
|
||||
|
||||
A minimal, zero-config, BSD licensed, readline replacement.
|
||||
|
||||
News: linenoise now includes minimal completion support, thanks to Pieter Noordhuis (@pnoordhuis).
|
||||
|
||||
News: linenoise is now part of [Android](http://android.git.kernel.org/?p=platform/system/core.git;a=tree;f=liblinenoise;h=56450eaed7f783760e5e6a5993ef75cde2e29dea;hb=HEAD Android)!
|
||||
|
||||
## Can a line editing library be 20k lines of code?
|
||||
|
||||
Line editing with some support for history is a really important feature for command line utilities. Instead of retyping almost the same stuff again and again it's just much better to hit the up arrow and edit on syntax errors, or in order to try a slightly different command. But apparently code dealing with terminals is some sort of Black Magic: readline is 30k lines of code, libedit 20k. Is it reasonable to link small utilities to huge libraries just to get a minimal support for line editing?
|
||||
|
||||
So what usually happens is either:
|
||||
|
||||
* Large programs with configure scripts disabling line editing if readline is not present in the system, or not supporting it at all since readline is GPL licensed and libedit (the BSD clone) is not as known and available as readline is (Real world example of this problem: Tclsh).
|
||||
* Smaller programs not using a configure script not supporting line editing at all (A problem we had with Redis-cli for instance).
|
||||
|
||||
The result is a pollution of binaries without line editing support.
|
||||
|
||||
So I spent more or less two hours doing a reality check resulting in this little library: is it *really* needed for a line editing library to be 20k lines of code? Apparently not, it is possibe to get a very small, zero configuration, trivial to embed library, that solves the problem. Smaller programs will just include this, supporing line editing out of the box. Larger programs may use this little library or just checking with configure if readline/libedit is available and resorting to linenoise if not.
|
||||
|
||||
## Terminals, in 2010.
|
||||
|
||||
Apparently almost every terminal you can happen to use today has some kind of support for VT100 alike escape sequences. So I tried to write a lib using just very basic VT100 features. The resulting library appears to work everywhere I tried to use it.
|
||||
|
||||
Since it's so young I guess there are a few bugs, or the lib may not compile or work with some operating system, but it's a matter of a few weeks and eventually we'll get it right, and there will be no excuses for not shipping command line tools without built-in line editing support.
|
||||
|
||||
The library is currently less than 400 lines of code. In order to use it in your project just look at the *example.c* file in the source distribution, it is trivial. Linenoise is BSD code, so you can use both in free software and commercial software.
|
||||
|
||||
## Tested with...
|
||||
|
||||
* Linux text only console ($TERM = linux)
|
||||
* Linux KDE terminal application ($TERM = xterm)
|
||||
* Linux xterm ($TERM = xterm)
|
||||
* Mac OS X iTerm ($TERM = xterm)
|
||||
* Mac OS X default Terminal.app ($TERM = xterm)
|
||||
* OpenBSD 4.5 through an OSX Terminal.app ($TERM = screen)
|
||||
* IBM AIX 6.1
|
||||
* FreeBSD xterm ($TERM = xterm)
|
||||
|
||||
Please test it everywhere you can and report back!
|
||||
|
||||
## Let's push this forward!
|
||||
|
||||
Please fork it and add something interesting and send me a pull request. What's especially interesting are fixes, new key bindings, completion.
|
||||
|
||||
Send feedbacks to antirez at gmail
|
@ -1,30 +0,0 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include "linenoise.h"
|
||||
|
||||
#ifndef NO_COMPLETION
|
||||
void completion(const char *buf, linenoiseCompletions *lc) {
|
||||
if (buf[0] == 'h') {
|
||||
linenoiseAddCompletion(lc,"hello");
|
||||
linenoiseAddCompletion(lc,"hello there");
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
int main(void) {
|
||||
char *line;
|
||||
|
||||
#ifndef NO_COMPLETION
|
||||
linenoiseSetCompletionCallback(completion);
|
||||
#endif
|
||||
linenoiseHistoryLoad("history.txt"); /* Load the history at startup */
|
||||
while((line = linenoise("hello> ")) != NULL) {
|
||||
if (line[0] != '\0') {
|
||||
printf("echo: '%s'\n", line);
|
||||
linenoiseHistoryAdd(line);
|
||||
linenoiseHistorySave("history.txt"); /* Save every new entry */
|
||||
}
|
||||
free(line);
|
||||
}
|
||||
return 0;
|
||||
}
|
File diff suppressed because it is too large
Load Diff
@ -1,61 +0,0 @@
|
||||
/* linenoise.h -- guerrilla line editing library against the idea that a
|
||||
* line editing lib needs to be 20,000 lines of C code.
|
||||
*
|
||||
* See linenoise.c for more information.
|
||||
*
|
||||
* ------------------------------------------------------------------------
|
||||
*
|
||||
* Copyright (c) 2010, Salvatore Sanfilippo <antirez at gmail dot com>
|
||||
* Copyright (c) 2010, Pieter Noordhuis <pcnoordhuis at gmail dot com>
|
||||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are
|
||||
* met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
*
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
* HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef __LINENOISE_H
|
||||
#define __LINENOISE_H
|
||||
|
||||
#ifndef NO_COMPLETION
|
||||
typedef struct linenoiseCompletions {
|
||||
size_t len;
|
||||
char **cvec;
|
||||
} linenoiseCompletions;
|
||||
|
||||
typedef void(linenoiseCompletionCallback)(const char *, linenoiseCompletions *);
|
||||
void linenoiseSetCompletionCallback(linenoiseCompletionCallback *);
|
||||
void linenoiseAddCompletion(linenoiseCompletions *, const char *);
|
||||
#endif
|
||||
|
||||
char *linenoise(const char *prompt);
|
||||
int linenoiseHistoryAdd(const char *line);
|
||||
int linenoiseHistorySetMaxLen(int len);
|
||||
int linenoiseHistoryGetMaxLen(void);
|
||||
int linenoiseHistorySave(const char *filename);
|
||||
int linenoiseHistoryLoad(const char *filename);
|
||||
void linenoiseHistoryFree(void);
|
||||
char **linenoiseHistory(int *len);
|
||||
int linenoiseColumns(void);
|
||||
|
||||
#endif /* __LINENOISE_H */
|
@ -1,115 +0,0 @@
|
||||
/**
|
||||
* UTF-8 utility functions
|
||||
*
|
||||
* (c) 2010 Steve Bennett <steveb@workware.net.au>
|
||||
*
|
||||
* See LICENCE for licence details.
|
||||
*/
|
||||
|
||||
#include <ctype.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include "utf8.h"
|
||||
|
||||
#ifdef USE_UTF8
|
||||
int utf8_fromunicode(char *p, unsigned short uc)
|
||||
{
|
||||
if (uc <= 0x7f) {
|
||||
*p = uc;
|
||||
return 1;
|
||||
}
|
||||
else if (uc <= 0x7ff) {
|
||||
*p++ = 0xc0 | ((uc & 0x7c0) >> 6);
|
||||
*p = 0x80 | (uc & 0x3f);
|
||||
return 2;
|
||||
}
|
||||
else {
|
||||
*p++ = 0xe0 | ((uc & 0xf000) >> 12);
|
||||
*p++ = 0x80 | ((uc & 0xfc0) >> 6);
|
||||
*p = 0x80 | (uc & 0x3f);
|
||||
return 3;
|
||||
}
|
||||
}
|
||||
|
||||
int utf8_charlen(int c)
|
||||
{
|
||||
if ((c & 0x80) == 0) {
|
||||
return 1;
|
||||
}
|
||||
if ((c & 0xe0) == 0xc0) {
|
||||
return 2;
|
||||
}
|
||||
if ((c & 0xf0) == 0xe0) {
|
||||
return 3;
|
||||
}
|
||||
if ((c & 0xf8) == 0xf0) {
|
||||
return 4;
|
||||
}
|
||||
/* Invalid sequence */
|
||||
return -1;
|
||||
}
|
||||
|
||||
int utf8_strlen(const char *str, int bytelen)
|
||||
{
|
||||
int charlen = 0;
|
||||
if (bytelen < 0) {
|
||||
bytelen = strlen(str);
|
||||
}
|
||||
while (bytelen) {
|
||||
int c;
|
||||
int l = utf8_tounicode(str, &c);
|
||||
charlen++;
|
||||
str += l;
|
||||
bytelen -= l;
|
||||
}
|
||||
return charlen;
|
||||
}
|
||||
|
||||
int utf8_index(const char *str, int index)
|
||||
{
|
||||
const char *s = str;
|
||||
while (index--) {
|
||||
int c;
|
||||
s += utf8_tounicode(s, &c);
|
||||
}
|
||||
return s - str;
|
||||
}
|
||||
|
||||
int utf8_charequal(const char *s1, const char *s2)
|
||||
{
|
||||
int c1, c2;
|
||||
|
||||
utf8_tounicode(s1, &c1);
|
||||
utf8_tounicode(s2, &c2);
|
||||
|
||||
return c1 == c2;
|
||||
}
|
||||
|
||||
int utf8_tounicode(const char *str, int *uc)
|
||||
{
|
||||
unsigned const char *s = (unsigned const char *)str;
|
||||
|
||||
if (s[0] < 0xc0) {
|
||||
*uc = s[0];
|
||||
return 1;
|
||||
}
|
||||
if (s[0] < 0xe0) {
|
||||
if ((s[1] & 0xc0) == 0x80) {
|
||||
*uc = ((s[0] & ~0xc0) << 6) | (s[1] & ~0x80);
|
||||
return 2;
|
||||
}
|
||||
}
|
||||
else if (s[0] < 0xf0) {
|
||||
if (((str[1] & 0xc0) == 0x80) && ((str[2] & 0xc0) == 0x80)) {
|
||||
*uc = ((s[0] & ~0xe0) << 12) | ((s[1] & ~0x80) << 6) | (s[2] & ~0x80);
|
||||
return 3;
|
||||
}
|
||||
}
|
||||
|
||||
/* Invalid sequence, so just return the byte */
|
||||
*uc = *s;
|
||||
return 1;
|
||||
}
|
||||
|
||||
#endif
|
@ -1,79 +0,0 @@
|
||||
#ifndef UTF8_UTIL_H
|
||||
#define UTF8_UTIL_H
|
||||
/**
|
||||
* UTF-8 utility functions
|
||||
*
|
||||
* (c) 2010 Steve Bennett <steveb@workware.net.au>
|
||||
*
|
||||
* See LICENCE for licence details.
|
||||
*/
|
||||
|
||||
#ifndef USE_UTF8
|
||||
#include <ctype.h>
|
||||
|
||||
/* No utf-8 support. 1 byte = 1 char */
|
||||
#define utf8_strlen(S, B) ((B) < 0 ? (int)strlen(S) : (B))
|
||||
#define utf8_tounicode(S, CP) (*(CP) = (unsigned char)*(S), 1)
|
||||
#define utf8_index(C, I) (I)
|
||||
#define utf8_charlen(C) 1
|
||||
|
||||
#else
|
||||
/**
|
||||
* Converts the given unicode codepoint (0 - 0xffff) to utf-8
|
||||
* and stores the result at 'p'.
|
||||
*
|
||||
* Returns the number of utf-8 characters (1-3).
|
||||
*/
|
||||
int utf8_fromunicode(char *p, unsigned short uc);
|
||||
|
||||
/**
|
||||
* Returns the length of the utf-8 sequence starting with 'c'.
|
||||
*
|
||||
* Returns 1-4, or -1 if this is not a valid start byte.
|
||||
*
|
||||
* Note that charlen=4 is not supported by the rest of the API.
|
||||
*/
|
||||
int utf8_charlen(int c);
|
||||
|
||||
/**
|
||||
* Returns the number of characters in the utf-8
|
||||
* string of the given byte length.
|
||||
*
|
||||
* Any bytes which are not part of an valid utf-8
|
||||
* sequence are treated as individual characters.
|
||||
*
|
||||
* The string *must* be null terminated.
|
||||
*
|
||||
* Does not support unicode code points > \uffff
|
||||
*/
|
||||
int utf8_strlen(const char *str, int bytelen);
|
||||
|
||||
/**
|
||||
* Returns the byte index of the given character in the utf-8 string.
|
||||
*
|
||||
* The string *must* be null terminated.
|
||||
*
|
||||
* This will return the byte length of a utf-8 string
|
||||
* if given the char length.
|
||||
*/
|
||||
int utf8_index(const char *str, int charindex);
|
||||
|
||||
/**
|
||||
* Returns the unicode codepoint corresponding to the
|
||||
* utf-8 sequence 'str'.
|
||||
*
|
||||
* Stores the result in *uc and returns the number of bytes
|
||||
* consumed.
|
||||
*
|
||||
* If 'str' is null terminated, then an invalid utf-8 sequence
|
||||
* at the end of the string will be returned as individual bytes.
|
||||
*
|
||||
* If it is not null terminated, the length *must* be checked first.
|
||||
*
|
||||
* Does not support unicode code points > \uffff
|
||||
*/
|
||||
int utf8_tounicode(const char *str, int *uc);
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
@ -570,18 +570,6 @@ rust_drop_env_lock() {
|
||||
env_lock.unlock();
|
||||
}
|
||||
|
||||
static lock_and_signal linenoise_lock;
|
||||
|
||||
extern "C" CDECL void
|
||||
rust_take_linenoise_lock() {
|
||||
linenoise_lock.lock();
|
||||
}
|
||||
|
||||
extern "C" CDECL void
|
||||
rust_drop_linenoise_lock() {
|
||||
linenoise_lock.unlock();
|
||||
}
|
||||
|
||||
static lock_and_signal dlerror_lock;
|
||||
|
||||
extern "C" CDECL void
|
||||
|
@ -133,13 +133,6 @@ tinfl_decompress_mem_to_heap
|
||||
rust_uv_ip4_port
|
||||
rust_uv_ip6_port
|
||||
rust_uv_tcp_getpeername
|
||||
linenoise
|
||||
linenoiseSetCompletionCallback
|
||||
linenoiseAddCompletion
|
||||
linenoiseHistoryAdd
|
||||
linenoiseHistorySetMaxLen
|
||||
linenoiseHistorySave
|
||||
linenoiseHistoryLoad
|
||||
rust_raw_thread_start
|
||||
rust_raw_thread_join
|
||||
rust_raw_thread_delete
|
||||
@ -187,8 +180,6 @@ rust_get_num_cpus
|
||||
rust_get_global_args_ptr
|
||||
rust_take_global_args_lock
|
||||
rust_drop_global_args_lock
|
||||
rust_take_linenoise_lock
|
||||
rust_drop_linenoise_lock
|
||||
rust_get_test_int
|
||||
rust_get_task
|
||||
rust_uv_get_loop_from_getaddrinfo_req
|
||||
|
@ -1,15 +0,0 @@
|
||||
// Copyright 2012 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.
|
||||
|
||||
#[link(name = "linenoise",
|
||||
vers = "0.1")];
|
||||
#[crate_type = "lib"];
|
||||
|
||||
pub mod issue_3882;
|
@ -1,21 +0,0 @@
|
||||
// Copyright 2012 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.
|
||||
|
||||
mod issue_3882 {
|
||||
struct Completions {
|
||||
len: libc::size_t,
|
||||
}
|
||||
|
||||
mod c {
|
||||
extern {
|
||||
fn linenoiseAddCompletion(lc: *mut Completions);
|
||||
}
|
||||
}
|
||||
}
|
@ -1,16 +0,0 @@
|
||||
// Copyright 2012 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.
|
||||
|
||||
// xfail-test
|
||||
// aux-build:issue_3882.rc
|
||||
extern mod linenoise;
|
||||
use linenoise::issue_3882::*;
|
||||
|
||||
pub fn main() {}
|
@ -1,83 +0,0 @@
|
||||
// Copyright 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.
|
||||
|
||||
// xfail-fast no compile flags for check-fast
|
||||
|
||||
// we want this to be compiled to avoid bitrot, but the actual test
|
||||
//has to be conducted by a human, i.e. someone (you?) compiling this
|
||||
//file with a plain rustc invocation and running it and checking it
|
||||
//works.
|
||||
|
||||
// compile-flags: --cfg robot_mode
|
||||
|
||||
extern mod extra;
|
||||
use extra::rl;
|
||||
|
||||
static HISTORY_FILE: &'static str = "rl-human-test-history.txt";
|
||||
|
||||
struct TestCompleter;
|
||||
|
||||
impl rl::CompletionCb for TestCompleter {
|
||||
fn complete(&self, line: ~str, suggest: &fn(~str)) {
|
||||
if line.is_empty() {
|
||||
suggest(~"empty")
|
||||
} else {
|
||||
for c in line.rev_iter().take(3) {
|
||||
suggest(format!("{0}{1}{1}{1}", line, c))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
// don't run this in robot mode, but still typecheck it.
|
||||
if !cfg!(robot_mode) {
|
||||
println("~~ Welcome to the rl test \"suite\". ~~");
|
||||
println!("Operations:
|
||||
- restrict the history to 2 lines,
|
||||
- set the tab-completion to suggest three copies of each of the last 3 letters (or 'empty'),
|
||||
- add 'one' and 'two' to the history,
|
||||
- save it to `{0}`,
|
||||
- add 'three',
|
||||
- prompt & save input (check the history & completion work and contains only 'two', 'three'),
|
||||
- load from `{0}`
|
||||
- prompt & save input (history should be 'one', 'two' again),
|
||||
- prompt once more.
|
||||
|
||||
The bool return values of each step are printed.",
|
||||
HISTORY_FILE);
|
||||
|
||||
println!("restricting history length: {}", rl::set_history_max_len(3));
|
||||
|
||||
unsafe {
|
||||
rl::complete(@TestCompleter as @rl::CompletionCb);
|
||||
}
|
||||
|
||||
println!("adding 'one': {}", rl::add_history("one"));
|
||||
println!("adding 'two': {}", rl::add_history("two"));
|
||||
|
||||
println!("saving history: {}", rl::save_history(HISTORY_FILE));
|
||||
|
||||
println!("adding 'three': {}", rl::add_history("three"));
|
||||
|
||||
match rl::read("> ") {
|
||||
Some(s) => println!("saving input: {}", rl::add_history(s)),
|
||||
None => return
|
||||
}
|
||||
println!("loading history: {}", rl::load_history(HISTORY_FILE));
|
||||
|
||||
match rl::read("> ") {
|
||||
Some(s) => println!("saving input: {}", rl::add_history(s)),
|
||||
None => return
|
||||
}
|
||||
|
||||
rl::read("> ");
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user