url = git://github.com/brson/llvm.git
[submodule "src/libuv"]
path = src/libuv
- url = git://github.com/joyent/libuv
+ url = git://github.com/graydon/libuv.git
startling <tdixon51793@gmail.com>
Stefan Plantikow <stefan.plantikow@googlemail.com>
Taras Shpot <mrshpot@gmail.com>
+Ted Horst <ted.horst@earthlink.net>
Tim Chevalier <chevalier@alum.wellesley.edu>
Tycho Sci <tychosci@gmail.com>
Wade Mealing <wmealing@gmail.com>
opt clang 0 "prefer clang to gcc for building the runtime"
valopt prefix "/usr/local" "set installation prefix"
valopt llvm-root "" "set LLVM root"
-valopt host-triple "$DEFAULT_HOST_TRIPLE" "primary LLVM host triple"
-valopt target-triples "" "LLVM target triples (defaults to host if unset)"
+valopt host-triple "${DEFAULT_HOST_TRIPLE}" "LLVM host triple"
+valopt target-triples "${CFG_HOST_TRIPLE}" "LLVM target triples"
if [ $HELP -eq 1 ]
then
CFG_C_COMPILER="gcc"
fi
-if [ -z "$CFG_PREFIX" ]
-then
- CFG_PREFIX=/usr/local
-fi
-
-if [ -z "$CFG_HOST_TRIPLE" ]
-then
- CFG_HOST_TRIPLE="$DEFAULT_HOST_TRIPLE"
-fi
-
-if [ -z "$CFG_TARGET_TRIPLES" ]
-then
- CFG_TARGET_TRIPLES="${CFG_HOST_TRIPLE}"
-else
- CFG_TARGET_TRIPLES="$(echo $CFG_TARGET_TRIPLES | tr ',' ' ')"
-fi
+# a little post-processing of various config values
+CFG_PREFIX=${CFG_PREFIX%/}
+CFG_TARGET_TRIPLES="$(echo $CFG_TARGET_TRIPLES | tr ',' ' ')"
case $CFG_TARGET_TRIPLES in
(*$CFG_HOST_TRIPLE*) ;;
(*) err "Host triple is not among the target triples." ;;
if [ -z $CFG_DISABLE_MANAGE_SUBMODULES ]
then
+msg "git: submodule sync"
+"${CFG_GIT}" submodule sync --quiet
SUBMODULE_STATUS=$("${CFG_GIT}" submodule status)
NEED_INIT_COUNT=$(echo "$SUBMODULE_STATUS" | grep -c "^-")
NEED_UPDATE_COUNT=$(echo "$SUBMODULE_STATUS" | grep -c "^+")
putvar CFG_OSTYPE
putvar CFG_CPUTYPE
putvar CFG_CONFIGURE_ARGS
-putvar CFG_HOST_TRIPLE
+putvar CFG_PREFIX
putvar CFG_TARGET_TRIPLES
putvar CFG_C_COMPILER
-putvar CFG_PREFIX
putvar CFG_LIBDIR
# Setting this again because it may have been changed
`<=`, and `>=`. Short-circuiting (lazy) boolean operators are written
`&&` (and) and `||` (or).
-Rust has a ternary conditional operator `?:`, as in:
-
-~~~~
-let badness = 12;
-let message = badness < 10 ? "error" : "FATAL ERROR";
-~~~~
-
For type casting, Rust uses the binary `as` operator, which has a
precedence between the bitwise combination operators (`&`, `|`, `^`)
and the comparison operators. It takes an expression on the left side,
~~~~
## ignore
// main.rs
+use std;
use mylib;
fn main() { std::io::println("hello " + mylib::world()); }
~~~~
-.TH RUSTC "1" "October 2011" "Rust" "User Commands"
+.TH RUSTC "1" "January 2012" "Rust" "User Commands"
+
.SH NAME
rustc \- rust compiler
+
.SH SYNOPSIS
rustc [\fB-h\fR] [\fB-v\fR] [\fB-o\fR \fIoutfile\fR]
[\fB--lib\fR] [\fB--static\fR] [\fB-L\fR \fIpath\fR]
.PP
Only the most commonly-used options are listed here. All options are listed and
described below.
+
.SH DESCRIPTION
This program is a compiler for the Rust language, available at
<\fBhttps://www.rust-lang.org\fR>.
+
.SH OPTIONS
.TP
-\fB-h, --help\fR:
-Display help.
+\fB--bin\fR
+Compile an executable crate (default)
.TP
-\fB-v, --version\fR:
-Display version information.
+\fB-c\fR
+Compile and assemble, but do not link
.TP
-\fB-o\fR \fIfilename\fR:
-Write output to \fIfilename\fR. The default
-output filename for \fBfoo.rs\fR is otherwise \fBfoo\fR plus any
-platform-specific extension (when compiling a binary), a
-platform-specific name, e.g. \fBlibfoo.so\fR (when compiling a
-library), \fBfoo.o\fR (when using \fB-c\fR), \fBfoo.s\fR (when using
-\fB-S\fR) or \fBfoo.bc\fR (when using \fB--emit-llvm\fR), and \fBfoo.ll\fR
-(when using both \fB-S\fR and \fB--emit-llvm\fR).
+\fB--cfg <cfgspec>\fR
+Configure the compilation environment
.TP
-\fB--lib\fR:
-Compile and link a library crate into a shared object.
+\fB--emit-llvm\fR
+Produce an LLVM bitcode file
.TP
-\fB--static\fR:
-Produce a statically-linked binary, or generate a static
-library.
+\fB-g\fR
+Produce debug info
.TP
-\fB--pretty\fR \fI[type]\fR:
-Pretty-print the input. Valid \fItype\fRs are:
-.RS
+\fB--gc\fR
+Garbage collect shared data (experimental/temporary)
.TP
-\fBnormal\fR: Un-annotated source (default).
+\fB-h --help\fR
+Display this message
.TP
-\fBexpanded\fR: Crates expanded.
+\fB-L <path>\fR
+Add a directory to the library search path
.TP
-\fBtyped\fR: Crates expanded, all expressions annotated with types.
+\fB--lib\fR
+Compile a library crate
.TP
-\fBidentified\fR: Fully parenthesized, ast nodes and blocks annotated with IDs.
-.RE
+\fB--ls\fR
+List the symbols defined by a compiled librar crate
.TP
-\fB--ls\fR:
-Lists symbols defined by the specified \fBcompiled\fR library.
+\fB--no-asm-comments\fR
+Do not add comments into the assembly source
.TP
-\fB-L\fR \fIpath\fR:
-Adds \fIpath\fR to the library search path.
+\fB--no-lint-ctypes\fR
+Suppress warnings for possibly incorrect ctype usage
.TP
-\fB--noverify\fR:
-Disables LLVM verification pass, which does sanity checking of
-bitcode generated by rustc. Using this option gives a slight speedup, at the
-cost of vastly reduced ability to catch rustc bugs. See
-<\fBhttp://llvm.org/docs/Passes.html\fR> for a list of properties checked.
+\fB--no-trans\fR
+Run all passes except translation; no output
.TP
-\fB--parse-only\fR:
-Run the parse phase only. If parsing succeeds, produces no
-output.
+\fB--no-verify\fR
+Suppress LLVM verification step (slight speedup)
+(see http://llvm.org/docs/Passes.html for detail)
.TP
-\fB--no-trans\fR:
-Run all passes except translation. Produces no output.
+\fB-O\fR
+Equivalent to --opt-level=2
.TP
-\fB-g\fR:
-Produce debug info.
+\fB-o <filename>\fR
+Write output to <filename>
.TP
-\fB--opt-level\fR \fIlevel\fR:
-Set optimization level to \fIlevel\fR.
+\fB--opt-level <lvl>\fR
+Optimize with possible levels 0-3
.TP
-\fB-O\fR:
-Equal to --opt-level=2
+\fB--out-dir <dir>\fR
+Write output to compiler-chosen filename in <dir>
.TP
-\fB-S\fR:
-Compile to assembly, but do not assemble or link.
+\fB--parse-only\fR
+Parse only; do not compile, assemble, or link
.TP
-\fB-c\fR:
-Compile and assemble, but do not link.
+\fB--pretty [type]\fR
+Pretty-print the input instead of compiling; valid types are: \fBnormal\fR (un-annotated source), \fBexpanded\fR (crates expanded), \fBtyped\fR (crates expanded, with type annotations), or \fBidentified\fR (fully parenthesized, AST nodes and blocks with IDs)
.TP
-\fB--emit-llvm\fR:
-Generate output files in LLVM format. When used with \fB-S\fR this generate LLVM
-intermediate language assembly files, otherwise this generates LLVM bitcode
-format object files.
+\fB-S\fR
+Compile only; do not assemble or link
.TP
-\fB--save-temps\fR:
-For foo.rs, save generated bitcode before optimization to
-\fBfoo.bc\fR, bitcode after optimization to \fBfoo.opt.bc\fR, and the generated
-object file to \fBfoo.o\fR.
+\fB--save-temps\fR
+Write intermediate files (.bc, .opt.bc, .o) in addition to normal output
.TP
-\fB--stats\fR:
-Print statistics about compilation.
+\fB--static\fR
+Use or produce static libraries or binaries
.TP
-\fB--cfg\fR \fIcfgspec\fR:
-Provide a crate config spec.
+\fB--stats\fR
+Print compilation statistics
.TP
-\fB--time-passes\fR:
-Print runtimes of compilation phases.
+\fB--sysroot <path>\fR
+Override the system root
.TP
-\fB--time-llvm-passes\fR:
-Print runtimes of llvm phases.
+\fB--test\fR
+Build test harness
.TP
-\fB--sysroot\fR \fIpath\fR:
-Set the system root. Default is the directory above
-rustc's.
+\fB--target <triple>\fR
+Target cpu-manufacturer-kernel[-os] to compile for (default: host triple)
+(see http://sources.redhat.com/autobook/autobook/autobook_17.html for detail)
.TP
-\fB--target\fR \fIgnu-config-name\fR:
-Set the compilation target, which is a
-string of the form \fBcpu\fR-\fBmanufacturer\fR-\fBkernel\fR[-\fBos\fR]. Example
-values include "i686-unknown-linux-gnu" and "mips-idt-ecoff"; see
-<\fBhttp://sources.redhat.com/autobook/autobook/autobook_17.html\fR>. If not
-supplied, the host triple is used (see \fB--version\fR output).
+\fB--time-passes\fR
+Time the individual phases of the compiler
.TP
-\fB--test\fR:
-Build a test harness.
+\fB--time-llvm-passes\fR
+Time the individual phases of the LLVM backend
.TP
-\fB--gc\fR:
-\fBEXPERIMENTAL\fR. Garbage-collect shared data.
+\fB-v --version\fR
+Print version info and exit
.TP
-\fB--warn-unused-imports\fR:
-Warn about unnecessary imports.
-.TP
-\fB--no-lint-ctypes\fR:
-Disables checking of possibly incorrect usage of Rust int or uint types in
-native function declarations, where types defined in libcore::ctypes should be
-used instead. Ctypes check emits warnings by default.
+\fB--warn-unused-imports\fR
+Warn about unnecessary imports
+
+.SH "EXAMPLES"
+To build an executable from a source file with a main function:
+ $ rustc -o hello hello.rs
+
+To build a library from a source file:
+ $ rustc --lib hello-lib.rs
+
+To build either with a crate (.rc) file:
+ $ rustc hello.rc
+
.SH "BUGS"
See \fBhttps://github.com/mozilla/rust/issues\fR for a list of known bugs.
+
.SH "AUTHOR"
See \fBAUTHORS.txt\fR in the rust source distribution. Graydon Hoare
<\fIgraydon@mozilla.com\fR> is the project leader.
+
.SH "COPYRIGHT"
See \fBLICENSE.txt\fR in the rust source distribution.
+
# Installation macro. Call with source directory as arg 1,
# destination directory as arg 2, and filename/libname-glob as arg 3
ifdef VERBOSE
- INSTALL = install -m755 -T $(1)/$(3) $(2)/$(3)
+ INSTALL = install -m755 $(1)/$(3) $(2)/$(3)
INSTALL_LIB = install -m644 `ls -rt1 $(1)/$(3) | tail -1` $(2)/
else
- INSTALL = $(Q)$(call E, install: $(2)/$(3)) && install -m755 -T $(1)/$(3) $(2)/$(3)
+ INSTALL = $(Q)$(call E, install: $(2)/$(3)) && install -m755 $(1)/$(3) $(2)/$(3)
INSTALL_LIB = $(Q)$(call E, install_lib: $(2)/$(3)) && \
install -m644 `ls -rt1 $(1)/$(3) | tail -1` $(2)/
endif
$$(TL$(1)$(2)),$$(PTL$(1)$(2)),$$(LIBRUSTC_GLOB))
$$(Q)$$(call INSTALL,$$(TL$(1)$(2)),$$(PTL$(1)$(2)),intrinsics.bc)
$$(Q)$$(call INSTALL,$$(TL$(1)$(2)),$$(PTL$(1)$(2)),libmorestack.a)
+
endef
$(foreach target,$(CFG_TARGET_TRIPLES), \
$(PREFIX_ROOT)/share/man/man1,rustc.1)
install-targets: $(INSTALL_TARGET_RULES)
+
+
+HOST_LIB_FROM_HL_GLOB = \
+ $(patsubst $(HL)/%,$(PHL)/%,$(wildcard $(HL)/$(1)))
+
+uninstall:
+ $(Q)rm -f $(PHB)/rustc$(X)
+ $(Q)rm -f $(PHB)/cargo$(X)
+ $(Q)rm -f $(PHB)/rustdoc$(X)
+ $(Q)rm -f $(PHL)/$(CFG_RUSTLLVM)
+ $(Q)rm -f $(PHL)/$(CFG_RUNTIME)
+ $(Q)for i in \
+ $(call HOST_LIB_FROM_HL_GLOB,$(CORELIB_GLOB)) \
+ $(call HOST_LIB_FROM_HL_GLOB,$(STDLIB_GLOB)) \
+ $(call HOST_LIB_FROM_HL_GLOB,$(LIBRUSTC_GLOB)) \
+ ; \
+ do rm -f $$i ; \
+ done
+ $(Q)rm -Rf $(PHL)/rustc
+ $(Q)rm -f $(PREFIX_ROOT)/share/man/man1/rustc.1
# The source directory tree.
srcdir := ../../../..
+abs_srcdir := $(abspath $(srcdir))
# The name of the builddir.
builddir_name ?= out
endif
# Specify BUILDTYPE=Release on the command line for a release build.
-BUILDTYPE ?= Default
+BUILDTYPE ?= Debug
# Directory all our build output goes into.
# Note that this must be two directories beneath src/ for unit tests to pass,
quiet_cmd_pch_c = CXX($(TOOLSET)) $@
cmd_pch_c = $(CC.$(TOOLSET)) $(GYP_PCH_CFLAGS) $(DEPFLAGS) $(CXXFLAGS.$(TOOLSET)) -c -o $@ $<
quiet_cmd_pch_cc = CXX($(TOOLSET)) $@
-cmd_pch_cc = $(CC.$(TOOLSET)) $(GYP_PCH_CCFLAGS) $(DEPFLAGS) $(CXXFLAGS.$(TOOLSET)) -c -o $@ $<
+cmd_pch_cc = $(CC.$(TOOLSET)) $(GYP_PCH_CXXFLAGS) $(DEPFLAGS) $(CXXFLAGS.$(TOOLSET)) -c -o $@ $<
quiet_cmd_pch_m = CXX($(TOOLSET)) $@
cmd_pch_m = $(CC.$(TOOLSET)) $(GYP_PCH_OBJCFLAGS) $(DEPFLAGS) -c -o $@ $<
quiet_cmd_pch_mm = CXX($(TOOLSET)) $@
quiet_cmd_mac_package_framework = PACKAGE FRAMEWORK $@
cmd_mac_package_framework = ./gyp-mac-tool package-framework "$@" $(4)
+quiet_cmd_infoplist = INFOPLIST $@
+cmd_infoplist = $(CC.$(TOOLSET)) -E -P -Wno-trigraphs -x c $(INFOPLIST_DEFINES) "$<" -o "$@"
+
quiet_cmd_touch = TOUCH $@
cmd_touch = touch $@
)
endef
-# Declare "all" target first so it is the default, even though we don't have the
-# deps yet.
+# Declare the "all" target first so it is the default,
+# even though we don't have the deps yet.
.PHONY: all
all:
include src/libuv/uv.target.mk
endif
-quiet_cmd_regen_makefile = ACTION Regenerating $@
-cmd_regen_makefile = ./src/libuv/build/gyp/gyp -fmake --ignore-environment "--toplevel-dir=." "--depth=." "--generator-output=mk/libuv/ia32/mac" "-Dlibrary=static_library" "-Dtarget_arch=ia32" "-DOS=mac" src/libuv/uv.gyp
-Makefile: $(srcdir)/src/libuv/uv.gyp
+#quiet_cmd_regen_makefile = ACTION Regenerating $@
+#cmd_regen_makefile = ./src/libuv/build/gyp/gyp -fmake --ignore-environment "--toplevel-dir=." -Isrc/libuv/common.gypi "--depth=." "--generator-output=mk/libuv/ia32/mac" "-Ddefault_configuration=Default" "-Dcomponent=static_library" "-Dlibrary=static_library" "-Dtarget_arch=ia32" "-DOS=mac" src/libuv/uv.gyp
+#Makefile: $(srcdir)/src/libuv/uv.gyp $(srcdir)/src/libuv/common.gypi
# $(call do_cmd,regen_makefile)
# "all" is a concatenation of the "all" targets from all the included
+++ /dev/null
-# We borrow heavily from the kernel build setup, though we are simpler since
-# we don't have Kconfig tweaking settings on us.
-
-# The implicit make rules have it looking for RCS files, among other things.
-# We instead explicitly write all the rules we care about.
-# It's even quicker (saves ~200ms) to pass -r on the command line.
-MAKEFLAGS=-r
-
-# The source directory tree.
-srcdir := ../../../..
-
-# The name of the builddir.
-builddir_name ?= out
-
-# The V=1 flag on command line makes us verbosely print command lines.
-ifdef V
- quiet=
-else
- quiet=quiet_
-endif
-
-# Specify BUILDTYPE=Release on the command line for a release build.
-BUILDTYPE ?= Default
-
-# Directory all our build output goes into.
-# Note that this must be two directories beneath src/ for unit tests to pass,
-# as they reach into the src/ directory for data with relative paths.
-builddir ?= $(builddir_name)/$(BUILDTYPE)
-abs_builddir := $(abspath $(builddir))
-depsdir := $(builddir)/.deps
-
-# Object output directory.
-obj := $(builddir)/obj
-abs_obj := $(abspath $(obj))
-
-# We build up a list of every single one of the targets so we can slurp in the
-# generated dependency rule Makefiles in one pass.
-all_deps :=
-
-
-
-# C++ apps need to be linked with g++.
-#
-# Note: flock is used to seralize linking. Linking is a memory-intensive
-# process so running parallel links can often lead to thrashing. To disable
-# the serialization, override LINK via an envrionment variable as follows:
-#
-# export LINK=g++
-#
-# This will allow make to invoke N linker processes as specified in -jN.
-LINK ?= ./gyp-mac-tool flock $(builddir)/linker.lock $(CXX)
-
-CC.target ?= $(CC)
-CFLAGS.target ?= $(CFLAGS)
-CXX.target ?= $(CXX)
-CXXFLAGS.target ?= $(CXXFLAGS)
-LINK.target ?= $(LINK)
-LDFLAGS.target ?= $(LDFLAGS)
-AR.target ?= $(AR)
-ARFLAGS.target ?= crs
-
-# N.B.: the logic of which commands to run should match the computation done
-# in gyp's make.py where ARFLAGS.host etc. is computed.
-# TODO(evan): move all cross-compilation logic to gyp-time so we don't need
-# to replicate this environment fallback in make as well.
-CC.host ?= gcc
-CFLAGS.host ?=
-CXX.host ?= g++
-CXXFLAGS.host ?=
-LINK.host ?= g++
-LDFLAGS.host ?=
-AR.host ?= ar
-ARFLAGS.host := crs
-
-# Define a dir function that can handle spaces.
-# http://www.gnu.org/software/make/manual/make.html#Syntax-of-Functions
-# "leading spaces cannot appear in the text of the first argument as written.
-# These characters can be put into the argument value by variable substitution."
-empty :=
-space := $(empty) $(empty)
-
-# http://stackoverflow.com/questions/1189781/using-make-dir-or-notdir-on-a-path-with-spaces
-replace_spaces = $(subst $(space),?,$1)
-unreplace_spaces = $(subst ?,$(space),$1)
-dirx = $(call unreplace_spaces,$(dir $(call replace_spaces,$1)))
-
-# Flags to make gcc output dependency info. Note that you need to be
-# careful here to use the flags that ccache and distcc can understand.
-# We write to a dep file on the side first and then rename at the end
-# so we can't end up with a broken dep file.
-depfile = $(depsdir)/$(call replace_spaces,$@).d
-DEPFLAGS = -MMD -MF $(depfile).raw
-
-# We have to fixup the deps output in a few ways.
-# (1) the file output should mention the proper .o file.
-# ccache or distcc lose the path to the target, so we convert a rule of
-# the form:
-# foobar.o: DEP1 DEP2
-# into
-# path/to/foobar.o: DEP1 DEP2
-# (2) we want missing files not to cause us to fail to build.
-# We want to rewrite
-# foobar.o: DEP1 DEP2 \
-# DEP3
-# to
-# DEP1:
-# DEP2:
-# DEP3:
-# so if the files are missing, they're just considered phony rules.
-# We have to do some pretty insane escaping to get those backslashes
-# and dollar signs past make, the shell, and sed at the same time.
-# Doesn't work with spaces, but that's fine: .d files have spaces in
-# their names replaced with other characters.
-define fixup_dep
-# The depfile may not exist if the input file didn't have any #includes.
-touch $(depfile).raw
-# Fixup path as in (1).
-sed -e "s|^$(notdir $@)|$@|" $(depfile).raw >> $(depfile)
-# Add extra rules as in (2).
-# We remove slashes and replace spaces with new lines;
-# remove blank lines;
-# delete the first line and append a colon to the remaining lines.
-sed -e 's|\\||' -e 'y| |\n|' $(depfile).raw |\
- grep -v '^$$' |\
- sed -e 1d -e 's|$$|:|' \
- >> $(depfile)
-rm $(depfile).raw
-endef
-
-# Command definitions:
-# - cmd_foo is the actual command to run;
-# - quiet_cmd_foo is the brief-output summary of the command.
-
-quiet_cmd_cc = CC($(TOOLSET)) $@
-cmd_cc = $(CC.$(TOOLSET)) $(GYP_CFLAGS) $(DEPFLAGS) $(CFLAGS.$(TOOLSET)) -c -o $@ $<
-
-quiet_cmd_cxx = CXX($(TOOLSET)) $@
-cmd_cxx = $(CXX.$(TOOLSET)) $(GYP_CXXFLAGS) $(DEPFLAGS) $(CXXFLAGS.$(TOOLSET)) -c -o $@ $<
-
-quiet_cmd_objc = CXX($(TOOLSET)) $@
-cmd_objc = $(CC.$(TOOLSET)) $(GYP_OBJCFLAGS) $(DEPFLAGS) -c -o $@ $<
-
-quiet_cmd_objcxx = CXX($(TOOLSET)) $@
-cmd_objcxx = $(CXX.$(TOOLSET)) $(GYP_OBJCXXFLAGS) $(DEPFLAGS) -c -o $@ $<
-
-# Commands for precompiled header files.
-quiet_cmd_pch_c = CXX($(TOOLSET)) $@
-cmd_pch_c = $(CC.$(TOOLSET)) $(GYP_PCH_CFLAGS) $(DEPFLAGS) $(CXXFLAGS.$(TOOLSET)) -c -o $@ $<
-quiet_cmd_pch_cc = CXX($(TOOLSET)) $@
-cmd_pch_cc = $(CC.$(TOOLSET)) $(GYP_PCH_CCFLAGS) $(DEPFLAGS) $(CXXFLAGS.$(TOOLSET)) -c -o $@ $<
-quiet_cmd_pch_m = CXX($(TOOLSET)) $@
-cmd_pch_m = $(CC.$(TOOLSET)) $(GYP_PCH_OBJCFLAGS) $(DEPFLAGS) -c -o $@ $<
-quiet_cmd_pch_mm = CXX($(TOOLSET)) $@
-cmd_pch_mm = $(CC.$(TOOLSET)) $(GYP_PCH_OBJCXXFLAGS) $(DEPFLAGS) -c -o $@ $<
-
-# gyp-mac-tool is written next to the root Makefile by gyp.
-# Use $(4) for the command, since $(2) and $(3) are used as flag by do_cmd
-# already.
-quiet_cmd_mac_tool = MACTOOL $(4) $<
-cmd_mac_tool = ./gyp-mac-tool $(4) $< "$@"
-
-quiet_cmd_mac_package_framework = PACKAGE FRAMEWORK $@
-cmd_mac_package_framework = ./gyp-mac-tool package-framework "$@" $(4)
-
-quiet_cmd_touch = TOUCH $@
-cmd_touch = touch $@
-
-quiet_cmd_copy = COPY $@
-# send stderr to /dev/null to ignore messages when linking directories.
-cmd_copy = ln -f "$<" "$@" 2>/dev/null || (rm -rf "$@" && cp -af "$<" "$@")
-
-quiet_cmd_alink = LIBTOOL-STATIC $@
-cmd_alink = rm -f $@ && libtool -static -o $@ $(filter %.o,$^)
-
-quiet_cmd_link = LINK($(TOOLSET)) $@
-cmd_link = $(LINK.$(TOOLSET)) $(GYP_LDFLAGS) $(LDFLAGS.$(TOOLSET)) -o "$@" $(LD_INPUTS) $(LIBS)
-
-# TODO(thakis): Find out and document the difference between shared_library and
-# loadable_module on mac.
-quiet_cmd_solink = SOLINK($(TOOLSET)) $@
-cmd_solink = $(LINK.$(TOOLSET)) -shared $(GYP_LDFLAGS) $(LDFLAGS.$(TOOLSET)) -o "$@" $(LD_INPUTS) $(LIBS)
-
-# TODO(thakis): The solink_module rule is likely wrong. Xcode seems to pass
-# -bundle -single_module here (for osmesa.so).
-quiet_cmd_solink_module = SOLINK_MODULE($(TOOLSET)) $@
-cmd_solink_module = $(LINK.$(TOOLSET)) -shared $(GYP_LDFLAGS) $(LDFLAGS.$(TOOLSET)) -o $@ $(filter-out FORCE_DO_CMD, $^) $(LIBS)
-
-
-# Define an escape_quotes function to escape single quotes.
-# This allows us to handle quotes properly as long as we always use
-# use single quotes and escape_quotes.
-escape_quotes = $(subst ','\'',$(1))
-# This comment is here just to include a ' to unconfuse syntax highlighting.
-# Define an escape_vars function to escape '$' variable syntax.
-# This allows us to read/write command lines with shell variables (e.g.
-# $LD_LIBRARY_PATH), without triggering make substitution.
-escape_vars = $(subst $$,$$$$,$(1))
-# Helper that expands to a shell command to echo a string exactly as it is in
-# make. This uses printf instead of echo because printf's behaviour with respect
-# to escape sequences is more portable than echo's across different shells
-# (e.g., dash, bash).
-exact_echo = printf '%s\n' '$(call escape_quotes,$(1))'
-
-# Helper to compare the command we're about to run against the command
-# we logged the last time we ran the command. Produces an empty
-# string (false) when the commands match.
-# Tricky point: Make has no string-equality test function.
-# The kernel uses the following, but it seems like it would have false
-# positives, where one string reordered its arguments.
-# arg_check = $(strip $(filter-out $(cmd_$(1)), $(cmd_$@)) \
-# $(filter-out $(cmd_$@), $(cmd_$(1))))
-# We instead substitute each for the empty string into the other, and
-# say they're equal if both substitutions produce the empty string.
-# .d files contain ? instead of spaces, take that into account.
-command_changed = $(or $(subst $(cmd_$(1)),,$(cmd_$(call replace_spaces,$@))),\
- $(subst $(cmd_$(call replace_spaces,$@)),,$(cmd_$(1))))
-
-# Helper that is non-empty when a prerequisite changes.
-# Normally make does this implicitly, but we force rules to always run
-# so we can check their command lines.
-# $? -- new prerequisites
-# $| -- order-only dependencies
-prereq_changed = $(filter-out FORCE_DO_CMD,$(filter-out $|,$?))
-
-# Helper that executes all postbuilds, and deletes the output file when done
-# if any of the postbuilds failed.
-define do_postbuilds
- @E=0;\
- for p in $(POSTBUILDS); do\
- eval $$p;\
- F=$$?;\
- if [ $$F -ne 0 ]; then\
- E=$$F;\
- fi;\
- done;\
- if [ $$E -ne 0 ]; then\
- rm -rf "$@";\
- exit $$E;\
- fi
-endef
-
-# do_cmd: run a command via the above cmd_foo names, if necessary.
-# Should always run for a given target to handle command-line changes.
-# Second argument, if non-zero, makes it do asm/C/C++ dependency munging.
-# Third argument, if non-zero, makes it do POSTBUILDS processing.
-# Note: We intentionally do NOT call dirx for depfile, since it contains ? for
-# spaces already and dirx strips the ? characters.
-define do_cmd
-$(if $(or $(command_changed),$(prereq_changed)),
- @$(call exact_echo, $($(quiet)cmd_$(1)))
- @mkdir -p "$(call dirx,$@)" "$(dir $(depfile))"
- $(if $(findstring flock,$(word 2,$(cmd_$1))),
- @$(cmd_$(1))
- @echo " $(quiet_cmd_$(1)): Finished",
- @$(cmd_$(1))
- )
- @$(call exact_echo,$(call escape_vars,cmd_$(call replace_spaces,$@) := $(cmd_$(1)))) > $(depfile)
- @$(if $(2),$(fixup_dep))
- $(if $(and $(3), $(POSTBUILDS)),
- $(call do_postbuilds)
- )
-)
-endef
-
-# Declare "all" target first so it is the default, even though we don't have the
-# deps yet.
-.PHONY: all
-all:
-
-# Use FORCE_DO_CMD to force a target to run. Should be coupled with
-# do_cmd.
-.PHONY: FORCE_DO_CMD
-FORCE_DO_CMD:
-
-TOOLSET := target
-# Suffix rules, putting all outputs into $(obj).
-$(obj).$(TOOLSET)/%.o: $(srcdir)/%.c FORCE_DO_CMD
- @$(call do_cmd,cc,1)
-$(obj).$(TOOLSET)/%.o: $(srcdir)/%.cc FORCE_DO_CMD
- @$(call do_cmd,cxx,1)
-$(obj).$(TOOLSET)/%.o: $(srcdir)/%.cpp FORCE_DO_CMD
- @$(call do_cmd,cxx,1)
-$(obj).$(TOOLSET)/%.o: $(srcdir)/%.cxx FORCE_DO_CMD
- @$(call do_cmd,cxx,1)
-$(obj).$(TOOLSET)/%.o: $(srcdir)/%.m FORCE_DO_CMD
- @$(call do_cmd,objc,1)
-$(obj).$(TOOLSET)/%.o: $(srcdir)/%.mm FORCE_DO_CMD
- @$(call do_cmd,objcxx,1)
-$(obj).$(TOOLSET)/%.o: $(srcdir)/%.S FORCE_DO_CMD
- @$(call do_cmd,cc,1)
-$(obj).$(TOOLSET)/%.o: $(srcdir)/%.s FORCE_DO_CMD
- @$(call do_cmd,cc,1)
-
-# Try building from generated source, too.
-$(obj).$(TOOLSET)/%.o: $(obj).$(TOOLSET)/%.c FORCE_DO_CMD
- @$(call do_cmd,cc,1)
-$(obj).$(TOOLSET)/%.o: $(obj).$(TOOLSET)/%.cc FORCE_DO_CMD
- @$(call do_cmd,cxx,1)
-$(obj).$(TOOLSET)/%.o: $(obj).$(TOOLSET)/%.cpp FORCE_DO_CMD
- @$(call do_cmd,cxx,1)
-$(obj).$(TOOLSET)/%.o: $(obj).$(TOOLSET)/%.cxx FORCE_DO_CMD
- @$(call do_cmd,cxx,1)
-$(obj).$(TOOLSET)/%.o: $(obj).$(TOOLSET)/%.m FORCE_DO_CMD
- @$(call do_cmd,objc,1)
-$(obj).$(TOOLSET)/%.o: $(obj).$(TOOLSET)/%.mm FORCE_DO_CMD
- @$(call do_cmd,objcxx,1)
-$(obj).$(TOOLSET)/%.o: $(obj).$(TOOLSET)/%.S FORCE_DO_CMD
- @$(call do_cmd,cc,1)
-$(obj).$(TOOLSET)/%.o: $(obj).$(TOOLSET)/%.s FORCE_DO_CMD
- @$(call do_cmd,cc,1)
-
-$(obj).$(TOOLSET)/%.o: $(obj)/%.c FORCE_DO_CMD
- @$(call do_cmd,cc,1)
-$(obj).$(TOOLSET)/%.o: $(obj)/%.cc FORCE_DO_CMD
- @$(call do_cmd,cxx,1)
-$(obj).$(TOOLSET)/%.o: $(obj)/%.cpp FORCE_DO_CMD
- @$(call do_cmd,cxx,1)
-$(obj).$(TOOLSET)/%.o: $(obj)/%.cxx FORCE_DO_CMD
- @$(call do_cmd,cxx,1)
-$(obj).$(TOOLSET)/%.o: $(obj)/%.m FORCE_DO_CMD
- @$(call do_cmd,objc,1)
-$(obj).$(TOOLSET)/%.o: $(obj)/%.mm FORCE_DO_CMD
- @$(call do_cmd,objcxx,1)
-$(obj).$(TOOLSET)/%.o: $(obj)/%.S FORCE_DO_CMD
- @$(call do_cmd,cc,1)
-$(obj).$(TOOLSET)/%.o: $(obj)/%.s FORCE_DO_CMD
- @$(call do_cmd,cc,1)
-
-
-ifeq ($(strip $(foreach prefix,$(NO_LOAD),\
- $(findstring $(join ^,$(prefix)),\
- $(join ^,src/libuv/run-benchmarks.target.mk)))),)
- include src/libuv/run-benchmarks.target.mk
-endif
-ifeq ($(strip $(foreach prefix,$(NO_LOAD),\
- $(findstring $(join ^,$(prefix)),\
- $(join ^,src/libuv/run-tests.target.mk)))),)
- include src/libuv/run-tests.target.mk
-endif
-ifeq ($(strip $(foreach prefix,$(NO_LOAD),\
- $(findstring $(join ^,$(prefix)),\
- $(join ^,src/libuv/uv.target.mk)))),)
- include src/libuv/uv.target.mk
-endif
-
-quiet_cmd_regen_makefile = ACTION Regenerating $@
-cmd_regen_makefile = ./src/libuv/build/gyp/gyp -fmake --ignore-environment "--toplevel-dir=." "--depth=." "--generator-output=mk/libuv/ia32/mac" "-Dlibrary=static_library" "-Dtarget_arch=ia32" "-DOS=mac" src/libuv/uv.gyp
-Makefile: $(srcdir)/src/libuv/uv.gyp
- $(call do_cmd,regen_makefile)
-
-# "all" is a concatenation of the "all" targets from all the included
-# sub-makefiles. This is just here to clarify.
-all:
-
-# Add in dependency-tracking rules. $(all_deps) is the list of every single
-# target in our tree. Only consider the ones with .d (dependency) info:
-d_files := $(wildcard $(foreach f,$(all_deps),$(depsdir)/$(f).d))
-ifneq ($(d_files),)
- # Rather than include each individual .d file, concatenate them into a
- # single file which make is able to load faster. We split this into
- # commands that take 1000 files at a time to avoid overflowing the
- # command line.
- $(shell cat $(wordlist 1,1000,$(d_files)) > $(depsdir)/all.deps)
-
- ifneq ($(word 1001,$(d_files)),)
- $(error Found unprocessed dependency files (gyp didn't generate enough rules!))
- endif
-
- # make looks for ways to re-generate included makefiles, but in our case, we
- # don't have a direct way. Explicitly telling make that it has nothing to do
- # for them makes it go faster.
- $(depsdir)/all.deps: ;
-
- include $(depsdir)/all.deps
-endif
-#!/usr/bin/python
+#!/usr/bin/env python
# Generated by gyp. Do not edit.
# Copyright (c) 2011 Google Inc. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
import subprocess
import sys
+
def main(args):
executor = MacTool()
executor.Dispatch(args)
+
class MacTool(object):
"""This class performs all the Mac tooling steps. The methods can either be
executed directly, or dispatched from an argument list."""
if not plist:
return
+ # Only create PkgInfo for executable types.
+ package_type = plist['CFBundlePackageType']
+ if package_type != 'APPL':
+ return
+
# The format of PkgInfo is eight characters, representing the bundle type
- # and bundle signature, each four characters. If either is missing, four
+ # and bundle signature, each four characters. If that is missing, four
# '?' characters are used instead.
- package_type = plist['CFBundlePackageType']
- if len(package_type) != 4:
- package_type = '?' * 4
signature_code = plist['CFBundleSignature']
if len(signature_code) != 4:
signature_code = '?' * 4
else:
return None
+
if __name__ == '__main__':
sys.exit(main(sys.argv[1:]))
TOOLSET := target
TARGET := run-benchmarks
-DEFS_Default := '-D_LARGEFILE_SOURCE' \
+DEFS_Debug := '-D_LARGEFILE_SOURCE' \
'-D_FILE_OFFSET_BITS=64' \
'-D_GNU_SOURCE' \
- '-DEIO_STACKSIZE=262144'
+ '-DEIO_STACKSIZE=262144' \
+ '-DDEBUG' \
+ '-D_DEBUG' \
+ '-DEV_VERIFY=2'
# Flags passed to all source files.
-CFLAGS_Default := -fasm-blocks \
- -mpascal-strings \
- -Os \
+CFLAGS_Debug := -Os \
-gdwarf-2 \
- -arch i386
+ -fvisibility=hidden \
+ -Wnewline-eof \
+ -arch i386 \
+ -fno-strict-aliasing \
+ -Wall \
+ -Wendif-labels \
+ -W \
+ -Wno-unused-parameter
# Flags passed to only C files.
-CFLAGS_C_Default :=
+CFLAGS_C_Debug :=
# Flags passed to only C++ files.
-CFLAGS_CC_Default :=
+CFLAGS_CC_Debug := -fno-rtti \
+ -fno-exceptions \
+ -fvisibility-inlines-hidden \
+ -fno-threadsafe-statics
# Flags passed to only ObjC files.
-CFLAGS_OBJC_Default :=
+CFLAGS_OBJC_Debug :=
# Flags passed to only ObjC++ files.
-CFLAGS_OBJCC_Default :=
+CFLAGS_OBJCC_Debug :=
-INCS_Default := -I$(srcdir)/src/libuv/include
+INCS_Debug := -I$(srcdir)/src/libuv/include
+
+DEFS_Release := '-D_LARGEFILE_SOURCE' \
+ '-D_FILE_OFFSET_BITS=64' \
+ '-D_GNU_SOURCE' \
+ '-DEIO_STACKSIZE=262144' \
+ '-DNDEBUG'
+
+# Flags passed to all source files.
+CFLAGS_Release := -Os \
+ -gdwarf-2 \
+ -fvisibility=hidden \
+ -Wnewline-eof \
+ -arch i386 \
+ -fno-strict-aliasing \
+ -Wall \
+ -Wendif-labels \
+ -W \
+ -Wno-unused-parameter
+
+# Flags passed to only C files.
+CFLAGS_C_Release :=
+
+# Flags passed to only C++ files.
+CFLAGS_CC_Release := -fno-rtti \
+ -fno-exceptions \
+ -fvisibility-inlines-hidden \
+ -fno-threadsafe-statics
+
+# Flags passed to only ObjC files.
+CFLAGS_OBJC_Release :=
+
+# Flags passed to only ObjC++ files.
+CFLAGS_OBJCC_Release :=
+
+INCS_Release := -I$(srcdir)/src/libuv/include
OBJS := $(obj).target/$(TARGET)/src/libuv/test/benchmark-ares.o \
$(obj).target/$(TARGET)/src/libuv/test/benchmark-getaddrinfo.o \
$(obj).target/$(TARGET)/src/libuv/test/benchmark-pump.o \
$(obj).target/$(TARGET)/src/libuv/test/benchmark-sizes.o \
$(obj).target/$(TARGET)/src/libuv/test/benchmark-spawn.o \
+ $(obj).target/$(TARGET)/src/libuv/test/benchmark-thread.o \
$(obj).target/$(TARGET)/src/libuv/test/benchmark-tcp-write-batch.o \
$(obj).target/$(TARGET)/src/libuv/test/benchmark-udp-packet-storm.o \
$(obj).target/$(TARGET)/src/libuv/test/dns-server.o \
# CFLAGS et al overrides must be target-local.
# See "Target-specific Variable Values" in the GNU Make manual.
$(OBJS): TOOLSET := $(TOOLSET)
-$(OBJS): GYP_CFLAGS := $(DEFS_$(BUILDTYPE)) $(INCS_$(BUILDTYPE)) $(CFLAGS_$(BUILDTYPE)) $(CFLAGS_C_$(BUILDTYPE))
-$(OBJS): GYP_CXXFLAGS := $(DEFS_$(BUILDTYPE)) $(INCS_$(BUILDTYPE)) $(CFLAGS_$(BUILDTYPE)) $(CFLAGS_CC_$(BUILDTYPE))
-$(OBJS): GYP_OBJCFLAGS := $(DEFS_$(BUILDTYPE)) $(INCS_$(BUILDTYPE)) $(CFLAGS_$(BUILDTYPE)) $(CFLAGS_C_$(BUILDTYPE)) $(CFLAGS_OBJC_$(BUILDTYPE))
-$(OBJS): GYP_OBJCXXFLAGS := $(DEFS_$(BUILDTYPE)) $(INCS_$(BUILDTYPE)) $(CFLAGS_$(BUILDTYPE)) $(CFLAGS_CC_$(BUILDTYPE)) $(CFLAGS_OBJCC_$(BUILDTYPE))
+$(OBJS): GYP_CFLAGS := $(DEFS_$(BUILDTYPE)) $(INCS_$(BUILDTYPE)) $(CFLAGS_$(BUILDTYPE)) $(CFLAGS_C_$(BUILDTYPE))
+$(OBJS): GYP_CXXFLAGS := $(DEFS_$(BUILDTYPE)) $(INCS_$(BUILDTYPE)) $(CFLAGS_$(BUILDTYPE)) $(CFLAGS_CC_$(BUILDTYPE))
+$(OBJS): GYP_OBJCFLAGS := $(DEFS_$(BUILDTYPE)) $(INCS_$(BUILDTYPE)) $(CFLAGS_$(BUILDTYPE)) $(CFLAGS_C_$(BUILDTYPE)) $(CFLAGS_OBJC_$(BUILDTYPE))
+$(OBJS): GYP_OBJCXXFLAGS := $(DEFS_$(BUILDTYPE)) $(INCS_$(BUILDTYPE)) $(CFLAGS_$(BUILDTYPE)) $(CFLAGS_CC_$(BUILDTYPE)) $(CFLAGS_OBJCC_$(BUILDTYPE))
# Suffix rules, putting all outputs into $(obj).
# End of this set of suffix rules
### Rules for final target.
-LDFLAGS_Default := -arch i386 \
+LDFLAGS_Debug := -Wl,-search_paths_first \
+ -arch i386 \
+ -L$(builddir)
+
+LDFLAGS_Release := -Wl,-search_paths_first \
+ -arch i386 \
-L$(builddir)
LIBS := -framework Carbon \
TOOLSET := target
TARGET := run-tests
-DEFS_Default := '-D_LARGEFILE_SOURCE' \
+DEFS_Debug := '-D_LARGEFILE_SOURCE' \
'-D_FILE_OFFSET_BITS=64' \
'-D_GNU_SOURCE' \
- '-DEIO_STACKSIZE=262144'
+ '-DEIO_STACKSIZE=262144' \
+ '-DDEBUG' \
+ '-D_DEBUG' \
+ '-DEV_VERIFY=2'
# Flags passed to all source files.
-CFLAGS_Default := -fasm-blocks \
- -mpascal-strings \
- -Os \
+CFLAGS_Debug := -Os \
-gdwarf-2 \
- -arch i386
+ -fvisibility=hidden \
+ -Wnewline-eof \
+ -arch i386 \
+ -fno-strict-aliasing \
+ -Wall \
+ -Wendif-labels \
+ -W \
+ -Wno-unused-parameter
# Flags passed to only C files.
-CFLAGS_C_Default :=
+CFLAGS_C_Debug :=
# Flags passed to only C++ files.
-CFLAGS_CC_Default :=
+CFLAGS_CC_Debug := -fno-rtti \
+ -fno-exceptions \
+ -fvisibility-inlines-hidden \
+ -fno-threadsafe-statics
# Flags passed to only ObjC files.
-CFLAGS_OBJC_Default :=
+CFLAGS_OBJC_Debug :=
# Flags passed to only ObjC++ files.
-CFLAGS_OBJCC_Default :=
+CFLAGS_OBJCC_Debug :=
-INCS_Default := -I$(srcdir)/src/libuv/include
+INCS_Debug := -I$(srcdir)/src/libuv/include
+
+DEFS_Release := '-D_LARGEFILE_SOURCE' \
+ '-D_FILE_OFFSET_BITS=64' \
+ '-D_GNU_SOURCE' \
+ '-DEIO_STACKSIZE=262144' \
+ '-DNDEBUG'
+
+# Flags passed to all source files.
+CFLAGS_Release := -Os \
+ -gdwarf-2 \
+ -fvisibility=hidden \
+ -Wnewline-eof \
+ -arch i386 \
+ -fno-strict-aliasing \
+ -Wall \
+ -Wendif-labels \
+ -W \
+ -Wno-unused-parameter
+
+# Flags passed to only C files.
+CFLAGS_C_Release :=
+
+# Flags passed to only C++ files.
+CFLAGS_CC_Release := -fno-rtti \
+ -fno-exceptions \
+ -fvisibility-inlines-hidden \
+ -fno-threadsafe-statics
+
+# Flags passed to only ObjC files.
+CFLAGS_OBJC_Release :=
+
+# Flags passed to only ObjC++ files.
+CFLAGS_OBJCC_Release :=
+
+INCS_Release := -I$(srcdir)/src/libuv/include
OBJS := $(obj).target/$(TARGET)/src/libuv/test/blackhole-server.o \
$(obj).target/$(TARGET)/src/libuv/test/echo-server.o \
$(obj).target/$(TARGET)/src/libuv/test/run-tests.o \
$(obj).target/$(TARGET)/src/libuv/test/runner.o \
$(obj).target/$(TARGET)/src/libuv/test/test-get-loadavg.o \
+ $(obj).target/$(TARGET)/src/libuv/test/test-util.o \
$(obj).target/$(TARGET)/src/libuv/test/test-async.o \
$(obj).target/$(TARGET)/src/libuv/test/test-error.o \
$(obj).target/$(TARGET)/src/libuv/test/test-callback-stack.o \
$(obj).target/$(TARGET)/src/libuv/test/test-connection-fail.o \
+ $(obj).target/$(TARGET)/src/libuv/test/test-cwd-and-chdir.o \
$(obj).target/$(TARGET)/src/libuv/test/test-delayed-accept.o \
+ $(obj).target/$(TARGET)/src/libuv/test/test-eio-overflow.o \
$(obj).target/$(TARGET)/src/libuv/test/test-fail-always.o \
$(obj).target/$(TARGET)/src/libuv/test/test-fs.o \
$(obj).target/$(TARGET)/src/libuv/test/test-fs-event.o \
$(obj).target/$(TARGET)/src/libuv/test/test-hrtime.o \
$(obj).target/$(TARGET)/src/libuv/test/test-idle.o \
$(obj).target/$(TARGET)/src/libuv/test/test-ipc.o \
+ $(obj).target/$(TARGET)/src/libuv/test/test-ipc-threads.o \
$(obj).target/$(TARGET)/src/libuv/test/test-loop-handles.o \
$(obj).target/$(TARGET)/src/libuv/test/test-multiple-listen.o \
$(obj).target/$(TARGET)/src/libuv/test/test-pass-always.o \
$(obj).target/$(TARGET)/src/libuv/test/test-ping-pong.o \
$(obj).target/$(TARGET)/src/libuv/test/test-pipe-bind-error.o \
$(obj).target/$(TARGET)/src/libuv/test/test-pipe-connect-error.o \
+ $(obj).target/$(TARGET)/src/libuv/test/test-platform-output.o \
+ $(obj).target/$(TARGET)/src/libuv/test/test-process-title.o \
$(obj).target/$(TARGET)/src/libuv/test/test-ref.o \
$(obj).target/$(TARGET)/src/libuv/test/test-shutdown-eof.o \
$(obj).target/$(TARGET)/src/libuv/test/test-spawn.o \
$(obj).target/$(TARGET)/src/libuv/test/test-tcp-write-to-half-open-connection.o \
$(obj).target/$(TARGET)/src/libuv/test/test-tcp-writealot.o \
$(obj).target/$(TARGET)/src/libuv/test/test-threadpool.o \
+ $(obj).target/$(TARGET)/src/libuv/test/test-mutexes.o \
+ $(obj).target/$(TARGET)/src/libuv/test/test-thread.o \
$(obj).target/$(TARGET)/src/libuv/test/test-timer-again.o \
$(obj).target/$(TARGET)/src/libuv/test/test-timer.o \
$(obj).target/$(TARGET)/src/libuv/test/test-tty.o \
$(obj).target/$(TARGET)/src/libuv/test/test-udp-dgram-too-big.o \
$(obj).target/$(TARGET)/src/libuv/test/test-udp-ipv6.o \
+ $(obj).target/$(TARGET)/src/libuv/test/test-udp-options.o \
$(obj).target/$(TARGET)/src/libuv/test/test-udp-send-and-recv.o \
$(obj).target/$(TARGET)/src/libuv/test/test-udp-multicast-join.o \
+ $(obj).target/$(TARGET)/src/libuv/test/test-counters-init.o \
$(obj).target/$(TARGET)/src/libuv/test/runner-unix.o
# Add to the list of files we specially track dependencies for.
# CFLAGS et al overrides must be target-local.
# See "Target-specific Variable Values" in the GNU Make manual.
$(OBJS): TOOLSET := $(TOOLSET)
-$(OBJS): GYP_CFLAGS := $(DEFS_$(BUILDTYPE)) $(INCS_$(BUILDTYPE)) $(CFLAGS_$(BUILDTYPE)) $(CFLAGS_C_$(BUILDTYPE))
-$(OBJS): GYP_CXXFLAGS := $(DEFS_$(BUILDTYPE)) $(INCS_$(BUILDTYPE)) $(CFLAGS_$(BUILDTYPE)) $(CFLAGS_CC_$(BUILDTYPE))
-$(OBJS): GYP_OBJCFLAGS := $(DEFS_$(BUILDTYPE)) $(INCS_$(BUILDTYPE)) $(CFLAGS_$(BUILDTYPE)) $(CFLAGS_C_$(BUILDTYPE)) $(CFLAGS_OBJC_$(BUILDTYPE))
-$(OBJS): GYP_OBJCXXFLAGS := $(DEFS_$(BUILDTYPE)) $(INCS_$(BUILDTYPE)) $(CFLAGS_$(BUILDTYPE)) $(CFLAGS_CC_$(BUILDTYPE)) $(CFLAGS_OBJCC_$(BUILDTYPE))
+$(OBJS): GYP_CFLAGS := $(DEFS_$(BUILDTYPE)) $(INCS_$(BUILDTYPE)) $(CFLAGS_$(BUILDTYPE)) $(CFLAGS_C_$(BUILDTYPE))
+$(OBJS): GYP_CXXFLAGS := $(DEFS_$(BUILDTYPE)) $(INCS_$(BUILDTYPE)) $(CFLAGS_$(BUILDTYPE)) $(CFLAGS_CC_$(BUILDTYPE))
+$(OBJS): GYP_OBJCFLAGS := $(DEFS_$(BUILDTYPE)) $(INCS_$(BUILDTYPE)) $(CFLAGS_$(BUILDTYPE)) $(CFLAGS_C_$(BUILDTYPE)) $(CFLAGS_OBJC_$(BUILDTYPE))
+$(OBJS): GYP_OBJCXXFLAGS := $(DEFS_$(BUILDTYPE)) $(INCS_$(BUILDTYPE)) $(CFLAGS_$(BUILDTYPE)) $(CFLAGS_CC_$(BUILDTYPE)) $(CFLAGS_OBJCC_$(BUILDTYPE))
# Suffix rules, putting all outputs into $(obj).
# End of this set of suffix rules
### Rules for final target.
-LDFLAGS_Default := -arch i386 \
+LDFLAGS_Debug := -Wl,-search_paths_first \
+ -arch i386 \
+ -L$(builddir)
+
+LDFLAGS_Release := -Wl,-search_paths_first \
+ -arch i386 \
-L$(builddir)
LIBS := -framework Carbon \
TOOLSET := target
TARGET := uv
-DEFS_Default := '-D_LARGEFILE_SOURCE' \
+DEFS_Debug := '-D_LARGEFILE_SOURCE' \
'-D_FILE_OFFSET_BITS=64' \
'-D_GNU_SOURCE' \
'-DEIO_STACKSIZE=262144' \
'-DHAVE_CONFIG_H' \
'-DEV_CONFIG_H="config_darwin.h"' \
- '-DEIO_CONFIG_H="config_darwin.h"'
+ '-DEIO_CONFIG_H="config_darwin.h"' \
+ '-DDEBUG' \
+ '-D_DEBUG' \
+ '-DEV_VERIFY=2'
# Flags passed to all source files.
-CFLAGS_Default := -fasm-blocks \
- -mpascal-strings \
- -Os \
+CFLAGS_Debug := -Os \
-gdwarf-2 \
- -arch i386
+ -fvisibility=hidden \
+ -Wnewline-eof \
+ -arch i386 \
+ -fno-strict-aliasing \
+ -Wall \
+ -Wendif-labels \
+ -W \
+ -Wno-unused-parameter
# Flags passed to only C files.
-CFLAGS_C_Default :=
+CFLAGS_C_Debug :=
# Flags passed to only C++ files.
-CFLAGS_CC_Default :=
+CFLAGS_CC_Debug := -fno-rtti \
+ -fno-exceptions \
+ -fvisibility-inlines-hidden \
+ -fno-threadsafe-statics
# Flags passed to only ObjC files.
-CFLAGS_OBJC_Default :=
+CFLAGS_OBJC_Debug :=
# Flags passed to only ObjC++ files.
-CFLAGS_OBJCC_Default :=
+CFLAGS_OBJCC_Debug :=
-INCS_Default := -I$(srcdir)/src/libuv/include \
+INCS_Debug := -I$(srcdir)/src/libuv/include \
+ -I$(srcdir)/src/libuv/include/uv-private \
+ -I$(srcdir)/src/libuv/src \
+ -I$(srcdir)/src/libuv/src/unix/ev \
+ -I$(srcdir)/src/libuv/src/ares/config_darwin
+
+DEFS_Release := '-D_LARGEFILE_SOURCE' \
+ '-D_FILE_OFFSET_BITS=64' \
+ '-D_GNU_SOURCE' \
+ '-DEIO_STACKSIZE=262144' \
+ '-DHAVE_CONFIG_H' \
+ '-DEV_CONFIG_H="config_darwin.h"' \
+ '-DEIO_CONFIG_H="config_darwin.h"' \
+ '-DNDEBUG'
+
+# Flags passed to all source files.
+CFLAGS_Release := -Os \
+ -gdwarf-2 \
+ -fvisibility=hidden \
+ -Wnewline-eof \
+ -arch i386 \
+ -fno-strict-aliasing \
+ -Wall \
+ -Wendif-labels \
+ -W \
+ -Wno-unused-parameter
+
+# Flags passed to only C files.
+CFLAGS_C_Release :=
+
+# Flags passed to only C++ files.
+CFLAGS_CC_Release := -fno-rtti \
+ -fno-exceptions \
+ -fvisibility-inlines-hidden \
+ -fno-threadsafe-statics
+
+# Flags passed to only ObjC files.
+CFLAGS_OBJC_Release :=
+
+# Flags passed to only ObjC++ files.
+CFLAGS_OBJCC_Release :=
+
+INCS_Release := -I$(srcdir)/src/libuv/include \
-I$(srcdir)/src/libuv/include/uv-private \
-I$(srcdir)/src/libuv/src \
-I$(srcdir)/src/libuv/src/unix/ev \
$(obj).target/$(TARGET)/src/libuv/src/unix/cares.o \
$(obj).target/$(TARGET)/src/libuv/src/unix/dl.o \
$(obj).target/$(TARGET)/src/libuv/src/unix/error.o \
+ $(obj).target/$(TARGET)/src/libuv/src/unix/thread.o \
$(obj).target/$(TARGET)/src/libuv/src/unix/process.o \
$(obj).target/$(TARGET)/src/libuv/src/unix/eio/eio.o \
$(obj).target/$(TARGET)/src/libuv/src/unix/ev/ev.o \
# CFLAGS et al overrides must be target-local.
# See "Target-specific Variable Values" in the GNU Make manual.
$(OBJS): TOOLSET := $(TOOLSET)
-$(OBJS): GYP_CFLAGS := $(DEFS_$(BUILDTYPE)) $(INCS_$(BUILDTYPE)) $(CFLAGS_$(BUILDTYPE)) $(CFLAGS_C_$(BUILDTYPE))
-$(OBJS): GYP_CXXFLAGS := $(DEFS_$(BUILDTYPE)) $(INCS_$(BUILDTYPE)) $(CFLAGS_$(BUILDTYPE)) $(CFLAGS_CC_$(BUILDTYPE))
-$(OBJS): GYP_OBJCFLAGS := $(DEFS_$(BUILDTYPE)) $(INCS_$(BUILDTYPE)) $(CFLAGS_$(BUILDTYPE)) $(CFLAGS_C_$(BUILDTYPE)) $(CFLAGS_OBJC_$(BUILDTYPE))
-$(OBJS): GYP_OBJCXXFLAGS := $(DEFS_$(BUILDTYPE)) $(INCS_$(BUILDTYPE)) $(CFLAGS_$(BUILDTYPE)) $(CFLAGS_CC_$(BUILDTYPE)) $(CFLAGS_OBJCC_$(BUILDTYPE))
+$(OBJS): GYP_CFLAGS := $(DEFS_$(BUILDTYPE)) $(INCS_$(BUILDTYPE)) $(CFLAGS_$(BUILDTYPE)) $(CFLAGS_C_$(BUILDTYPE))
+$(OBJS): GYP_CXXFLAGS := $(DEFS_$(BUILDTYPE)) $(INCS_$(BUILDTYPE)) $(CFLAGS_$(BUILDTYPE)) $(CFLAGS_CC_$(BUILDTYPE))
+$(OBJS): GYP_OBJCFLAGS := $(DEFS_$(BUILDTYPE)) $(INCS_$(BUILDTYPE)) $(CFLAGS_$(BUILDTYPE)) $(CFLAGS_C_$(BUILDTYPE)) $(CFLAGS_OBJC_$(BUILDTYPE))
+$(OBJS): GYP_OBJCXXFLAGS := $(DEFS_$(BUILDTYPE)) $(INCS_$(BUILDTYPE)) $(CFLAGS_$(BUILDTYPE)) $(CFLAGS_CC_$(BUILDTYPE)) $(CFLAGS_OBJCC_$(BUILDTYPE))
# Suffix rules, putting all outputs into $(obj).
# End of this set of suffix rules
### Rules for final target.
-LDFLAGS_Default := -arch i386 \
+LDFLAGS_Debug := -arch i386 \
+ -L$(builddir)
+
+LDFLAGS_Release := -arch i386 \
-L$(builddir)
LIBS := -lm
# The source directory tree.
srcdir := ../../../..
+abs_srcdir := $(abspath $(srcdir))
# The name of the builddir.
builddir_name ?= out
endif
# Specify BUILDTYPE=Release on the command line for a release build.
-BUILDTYPE ?= Default
+BUILDTYPE ?= Debug
# Directory all our build output goes into.
# Note that this must be two directories beneath src/ for unit tests to pass,
)
endef
-# Declare "all" target first so it is the default, even though we don't have the
-# deps yet.
+# Declare the "all" target first so it is the default,
+# even though we don't have the deps yet.
.PHONY: all
all:
include src/libuv/uv.target.mk
endif
-quiet_cmd_regen_makefile = ACTION Regenerating $@
-cmd_regen_makefile = ./src/libuv/build/gyp/gyp -fmake --ignore-environment "--toplevel-dir=." "--depth=." "--generator-output=mk/libuv/ia32/unix" "-Dlibrary=static_library" "-Dtarget_arch=ia32" "-DOS=linux" src/libuv/uv.gyp
-Makefile: $(srcdir)/src/libuv/uv.gyp
+#quiet_cmd_regen_makefile = ACTION Regenerating $@
+#cmd_regen_makefile = ./src/libuv/build/gyp/gyp -fmake --ignore-environment "--toplevel-dir=." -Isrc/libuv/common.gypi "--depth=." "--generator-output=mk/libuv/ia32/unix" "-Ddefault_configuration=Default" "-Dcomponent=static_library" "-Dlibrary=static_library" "-Dtarget_arch=ia32" "-DOS=linux" src/libuv/uv.gyp
+#Makefile: $(srcdir)/src/libuv/uv.gyp $(srcdir)/src/libuv/common.gypi
# $(call do_cmd,regen_makefile)
# "all" is a concatenation of the "all" targets from all the included
+++ /dev/null
-# We borrow heavily from the kernel build setup, though we are simpler since
-# we don't have Kconfig tweaking settings on us.
-
-# The implicit make rules have it looking for RCS files, among other things.
-# We instead explicitly write all the rules we care about.
-# It's even quicker (saves ~200ms) to pass -r on the command line.
-MAKEFLAGS=-r
-
-# The source directory tree.
-srcdir := ../../../..
-
-# The name of the builddir.
-builddir_name ?= out
-
-# The V=1 flag on command line makes us verbosely print command lines.
-ifdef V
- quiet=
-else
- quiet=quiet_
-endif
-
-# Specify BUILDTYPE=Release on the command line for a release build.
-BUILDTYPE ?= Default
-
-# Directory all our build output goes into.
-# Note that this must be two directories beneath src/ for unit tests to pass,
-# as they reach into the src/ directory for data with relative paths.
-builddir ?= $(builddir_name)/$(BUILDTYPE)
-abs_builddir := $(abspath $(builddir))
-depsdir := $(builddir)/.deps
-
-# Object output directory.
-obj := $(builddir)/obj
-abs_obj := $(abspath $(obj))
-
-# We build up a list of every single one of the targets so we can slurp in the
-# generated dependency rule Makefiles in one pass.
-all_deps :=
-
-
-
-# C++ apps need to be linked with g++.
-#
-# Note: flock is used to seralize linking. Linking is a memory-intensive
-# process so running parallel links can often lead to thrashing. To disable
-# the serialization, override LINK via an envrionment variable as follows:
-#
-# export LINK=g++
-#
-# This will allow make to invoke N linker processes as specified in -jN.
-LINK ?= flock $(builddir)/linker.lock $(CXX)
-
-CC.target ?= $(CC)
-CFLAGS.target ?= $(CFLAGS)
-CXX.target ?= $(CXX)
-CXXFLAGS.target ?= $(CXXFLAGS)
-LINK.target ?= $(LINK)
-LDFLAGS.target ?= $(LDFLAGS)
-AR.target ?= $(AR)
-ARFLAGS.target ?= crsT
-
-# N.B.: the logic of which commands to run should match the computation done
-# in gyp's make.py where ARFLAGS.host etc. is computed.
-# TODO(evan): move all cross-compilation logic to gyp-time so we don't need
-# to replicate this environment fallback in make as well.
-CC.host ?= gcc
-CFLAGS.host ?=
-CXX.host ?= g++
-CXXFLAGS.host ?=
-LINK.host ?= g++
-LDFLAGS.host ?=
-AR.host ?= ar
-ARFLAGS.host := crsT
-
-# Define a dir function that can handle spaces.
-# http://www.gnu.org/software/make/manual/make.html#Syntax-of-Functions
-# "leading spaces cannot appear in the text of the first argument as written.
-# These characters can be put into the argument value by variable substitution."
-empty :=
-space := $(empty) $(empty)
-
-# http://stackoverflow.com/questions/1189781/using-make-dir-or-notdir-on-a-path-with-spaces
-replace_spaces = $(subst $(space),?,$1)
-unreplace_spaces = $(subst ?,$(space),$1)
-dirx = $(call unreplace_spaces,$(dir $(call replace_spaces,$1)))
-
-# Flags to make gcc output dependency info. Note that you need to be
-# careful here to use the flags that ccache and distcc can understand.
-# We write to a dep file on the side first and then rename at the end
-# so we can't end up with a broken dep file.
-depfile = $(depsdir)/$(call replace_spaces,$@).d
-DEPFLAGS = -MMD -MF $(depfile).raw
-
-# We have to fixup the deps output in a few ways.
-# (1) the file output should mention the proper .o file.
-# ccache or distcc lose the path to the target, so we convert a rule of
-# the form:
-# foobar.o: DEP1 DEP2
-# into
-# path/to/foobar.o: DEP1 DEP2
-# (2) we want missing files not to cause us to fail to build.
-# We want to rewrite
-# foobar.o: DEP1 DEP2 \
-# DEP3
-# to
-# DEP1:
-# DEP2:
-# DEP3:
-# so if the files are missing, they're just considered phony rules.
-# We have to do some pretty insane escaping to get those backslashes
-# and dollar signs past make, the shell, and sed at the same time.
-# Doesn't work with spaces, but that's fine: .d files have spaces in
-# their names replaced with other characters.
-define fixup_dep
-# The depfile may not exist if the input file didn't have any #includes.
-touch $(depfile).raw
-# Fixup path as in (1).
-sed -e "s|^$(notdir $@)|$@|" $(depfile).raw >> $(depfile)
-# Add extra rules as in (2).
-# We remove slashes and replace spaces with new lines;
-# remove blank lines;
-# delete the first line and append a colon to the remaining lines.
-sed -e 's|\\||' -e 'y| |\n|' $(depfile).raw |\
- grep -v '^$$' |\
- sed -e 1d -e 's|$$|:|' \
- >> $(depfile)
-rm $(depfile).raw
-endef
-
-# Command definitions:
-# - cmd_foo is the actual command to run;
-# - quiet_cmd_foo is the brief-output summary of the command.
-
-quiet_cmd_cc = CC($(TOOLSET)) $@
-cmd_cc = $(CC.$(TOOLSET)) $(GYP_CFLAGS) $(DEPFLAGS) $(CFLAGS.$(TOOLSET)) -c -o $@ $<
-
-quiet_cmd_cxx = CXX($(TOOLSET)) $@
-cmd_cxx = $(CXX.$(TOOLSET)) $(GYP_CXXFLAGS) $(DEPFLAGS) $(CXXFLAGS.$(TOOLSET)) -c -o $@ $<
-
-quiet_cmd_touch = TOUCH $@
-cmd_touch = touch $@
-
-quiet_cmd_copy = COPY $@
-# send stderr to /dev/null to ignore messages when linking directories.
-cmd_copy = ln -f "$<" "$@" 2>/dev/null || (rm -rf "$@" && cp -af "$<" "$@")
-
-quiet_cmd_alink = AR($(TOOLSET)) $@
-cmd_alink = rm -f $@ && $(AR.$(TOOLSET)) $(ARFLAGS.$(TOOLSET)) $@ $(filter %.o,$^)
-
-# Due to circular dependencies between libraries :(, we wrap the
-# special "figure out circular dependencies" flags around the entire
-# input list during linking.
-quiet_cmd_link = LINK($(TOOLSET)) $@
-cmd_link = $(LINK.$(TOOLSET)) $(GYP_LDFLAGS) $(LDFLAGS.$(TOOLSET)) -o $@ -Wl,--start-group $(LD_INPUTS) -Wl,--end-group $(LIBS)
-
-# We support two kinds of shared objects (.so):
-# 1) shared_library, which is just bundling together many dependent libraries
-# into a link line.
-# 2) loadable_module, which is generating a module intended for dlopen().
-#
-# They differ only slightly:
-# In the former case, we want to package all dependent code into the .so.
-# In the latter case, we want to package just the API exposed by the
-# outermost module.
-# This means shared_library uses --whole-archive, while loadable_module doesn't.
-# (Note that --whole-archive is incompatible with the --start-group used in
-# normal linking.)
-
-# Other shared-object link notes:
-# - Set SONAME to the library filename so our binaries don't reference
-# the local, absolute paths used on the link command-line.
-quiet_cmd_solink = SOLINK($(TOOLSET)) $@
-cmd_solink = $(LINK.$(TOOLSET)) -shared $(GYP_LDFLAGS) $(LDFLAGS.$(TOOLSET)) -Wl,-soname=$(@F) -o $@ -Wl,--whole-archive $(LD_INPUTS) -Wl,--no-whole-archive $(LIBS)
-
-quiet_cmd_solink_module = SOLINK_MODULE($(TOOLSET)) $@
-cmd_solink_module = $(LINK.$(TOOLSET)) -shared $(GYP_LDFLAGS) $(LDFLAGS.$(TOOLSET)) -Wl,-soname=$(@F) -o $@ -Wl,--start-group $(filter-out FORCE_DO_CMD, $^) -Wl,--end-group $(LIBS)
-
-
-# Define an escape_quotes function to escape single quotes.
-# This allows us to handle quotes properly as long as we always use
-# use single quotes and escape_quotes.
-escape_quotes = $(subst ','\'',$(1))
-# This comment is here just to include a ' to unconfuse syntax highlighting.
-# Define an escape_vars function to escape '$' variable syntax.
-# This allows us to read/write command lines with shell variables (e.g.
-# $LD_LIBRARY_PATH), without triggering make substitution.
-escape_vars = $(subst $$,$$$$,$(1))
-# Helper that expands to a shell command to echo a string exactly as it is in
-# make. This uses printf instead of echo because printf's behaviour with respect
-# to escape sequences is more portable than echo's across different shells
-# (e.g., dash, bash).
-exact_echo = printf '%s\n' '$(call escape_quotes,$(1))'
-
-# Helper to compare the command we're about to run against the command
-# we logged the last time we ran the command. Produces an empty
-# string (false) when the commands match.
-# Tricky point: Make has no string-equality test function.
-# The kernel uses the following, but it seems like it would have false
-# positives, where one string reordered its arguments.
-# arg_check = $(strip $(filter-out $(cmd_$(1)), $(cmd_$@)) \
-# $(filter-out $(cmd_$@), $(cmd_$(1))))
-# We instead substitute each for the empty string into the other, and
-# say they're equal if both substitutions produce the empty string.
-# .d files contain ? instead of spaces, take that into account.
-command_changed = $(or $(subst $(cmd_$(1)),,$(cmd_$(call replace_spaces,$@))),\
- $(subst $(cmd_$(call replace_spaces,$@)),,$(cmd_$(1))))
-
-# Helper that is non-empty when a prerequisite changes.
-# Normally make does this implicitly, but we force rules to always run
-# so we can check their command lines.
-# $? -- new prerequisites
-# $| -- order-only dependencies
-prereq_changed = $(filter-out FORCE_DO_CMD,$(filter-out $|,$?))
-
-# Helper that executes all postbuilds, and deletes the output file when done
-# if any of the postbuilds failed.
-define do_postbuilds
- @E=0;\
- for p in $(POSTBUILDS); do\
- eval $$p;\
- F=$$?;\
- if [ $$F -ne 0 ]; then\
- E=$$F;\
- fi;\
- done;\
- if [ $$E -ne 0 ]; then\
- rm -rf "$@";\
- exit $$E;\
- fi
-endef
-
-# do_cmd: run a command via the above cmd_foo names, if necessary.
-# Should always run for a given target to handle command-line changes.
-# Second argument, if non-zero, makes it do asm/C/C++ dependency munging.
-# Third argument, if non-zero, makes it do POSTBUILDS processing.
-# Note: We intentionally do NOT call dirx for depfile, since it contains ? for
-# spaces already and dirx strips the ? characters.
-define do_cmd
-$(if $(or $(command_changed),$(prereq_changed)),
- @$(call exact_echo, $($(quiet)cmd_$(1)))
- @mkdir -p "$(call dirx,$@)" "$(dir $(depfile))"
- $(if $(findstring flock,$(word 1,$(cmd_$1))),
- @$(cmd_$(1))
- @echo " $(quiet_cmd_$(1)): Finished",
- @$(cmd_$(1))
- )
- @$(call exact_echo,$(call escape_vars,cmd_$(call replace_spaces,$@) := $(cmd_$(1)))) > $(depfile)
- @$(if $(2),$(fixup_dep))
- $(if $(and $(3), $(POSTBUILDS)),
- $(call do_postbuilds)
- )
-)
-endef
-
-# Declare "all" target first so it is the default, even though we don't have the
-# deps yet.
-.PHONY: all
-all:
-
-# Use FORCE_DO_CMD to force a target to run. Should be coupled with
-# do_cmd.
-.PHONY: FORCE_DO_CMD
-FORCE_DO_CMD:
-
-TOOLSET := target
-# Suffix rules, putting all outputs into $(obj).
-$(obj).$(TOOLSET)/%.o: $(srcdir)/%.c FORCE_DO_CMD
- @$(call do_cmd,cc,1)
-$(obj).$(TOOLSET)/%.o: $(srcdir)/%.cc FORCE_DO_CMD
- @$(call do_cmd,cxx,1)
-$(obj).$(TOOLSET)/%.o: $(srcdir)/%.cpp FORCE_DO_CMD
- @$(call do_cmd,cxx,1)
-$(obj).$(TOOLSET)/%.o: $(srcdir)/%.cxx FORCE_DO_CMD
- @$(call do_cmd,cxx,1)
-$(obj).$(TOOLSET)/%.o: $(srcdir)/%.S FORCE_DO_CMD
- @$(call do_cmd,cc,1)
-$(obj).$(TOOLSET)/%.o: $(srcdir)/%.s FORCE_DO_CMD
- @$(call do_cmd,cc,1)
-
-# Try building from generated source, too.
-$(obj).$(TOOLSET)/%.o: $(obj).$(TOOLSET)/%.c FORCE_DO_CMD
- @$(call do_cmd,cc,1)
-$(obj).$(TOOLSET)/%.o: $(obj).$(TOOLSET)/%.cc FORCE_DO_CMD
- @$(call do_cmd,cxx,1)
-$(obj).$(TOOLSET)/%.o: $(obj).$(TOOLSET)/%.cpp FORCE_DO_CMD
- @$(call do_cmd,cxx,1)
-$(obj).$(TOOLSET)/%.o: $(obj).$(TOOLSET)/%.cxx FORCE_DO_CMD
- @$(call do_cmd,cxx,1)
-$(obj).$(TOOLSET)/%.o: $(obj).$(TOOLSET)/%.S FORCE_DO_CMD
- @$(call do_cmd,cc,1)
-$(obj).$(TOOLSET)/%.o: $(obj).$(TOOLSET)/%.s FORCE_DO_CMD
- @$(call do_cmd,cc,1)
-
-$(obj).$(TOOLSET)/%.o: $(obj)/%.c FORCE_DO_CMD
- @$(call do_cmd,cc,1)
-$(obj).$(TOOLSET)/%.o: $(obj)/%.cc FORCE_DO_CMD
- @$(call do_cmd,cxx,1)
-$(obj).$(TOOLSET)/%.o: $(obj)/%.cpp FORCE_DO_CMD
- @$(call do_cmd,cxx,1)
-$(obj).$(TOOLSET)/%.o: $(obj)/%.cxx FORCE_DO_CMD
- @$(call do_cmd,cxx,1)
-$(obj).$(TOOLSET)/%.o: $(obj)/%.S FORCE_DO_CMD
- @$(call do_cmd,cc,1)
-$(obj).$(TOOLSET)/%.o: $(obj)/%.s FORCE_DO_CMD
- @$(call do_cmd,cc,1)
-
-
-ifeq ($(strip $(foreach prefix,$(NO_LOAD),\
- $(findstring $(join ^,$(prefix)),\
- $(join ^,src/libuv/run-benchmarks.target.mk)))),)
- include src/libuv/run-benchmarks.target.mk
-endif
-ifeq ($(strip $(foreach prefix,$(NO_LOAD),\
- $(findstring $(join ^,$(prefix)),\
- $(join ^,src/libuv/run-tests.target.mk)))),)
- include src/libuv/run-tests.target.mk
-endif
-ifeq ($(strip $(foreach prefix,$(NO_LOAD),\
- $(findstring $(join ^,$(prefix)),\
- $(join ^,src/libuv/uv.target.mk)))),)
- include src/libuv/uv.target.mk
-endif
-
-quiet_cmd_regen_makefile = ACTION Regenerating $@
-cmd_regen_makefile = ./src/libuv/build/gyp/gyp -fmake --ignore-environment "--toplevel-dir=." "--depth=." "--generator-output=mk/libuv/ia32/unix" "-Dlibrary=static_library" "-Dtarget_arch=ia32" "-DOS=linux" src/libuv/uv.gyp
-Makefile: $(srcdir)/src/libuv/uv.gyp
- $(call do_cmd,regen_makefile)
-
-# "all" is a concatenation of the "all" targets from all the included
-# sub-makefiles. This is just here to clarify.
-all:
-
-# Add in dependency-tracking rules. $(all_deps) is the list of every single
-# target in our tree. Only consider the ones with .d (dependency) info:
-d_files := $(wildcard $(foreach f,$(all_deps),$(depsdir)/$(f).d))
-ifneq ($(d_files),)
- # Rather than include each individual .d file, concatenate them into a
- # single file which make is able to load faster. We split this into
- # commands that take 1000 files at a time to avoid overflowing the
- # command line.
- $(shell cat $(wordlist 1,1000,$(d_files)) > $(depsdir)/all.deps)
-
- ifneq ($(word 1001,$(d_files)),)
- $(error Found unprocessed dependency files (gyp didn't generate enough rules!))
- endif
-
- # make looks for ways to re-generate included makefiles, but in our case, we
- # don't have a direct way. Explicitly telling make that it has nothing to do
- # for them makes it go faster.
- $(depsdir)/all.deps: ;
-
- include $(depsdir)/all.deps
-endif
TOOLSET := target
TARGET := run-benchmarks
-DEFS_Default := '-D_LARGEFILE_SOURCE' \
+DEFS_Debug := '-D_LARGEFILE_SOURCE' \
'-D_FILE_OFFSET_BITS=64' \
'-D_GNU_SOURCE' \
- '-DEIO_STACKSIZE=262144'
+ '-DEIO_STACKSIZE=262144' \
+ '-DDEBUG' \
+ '-D_DEBUG' \
+ '-DEV_VERIFY=2'
# Flags passed to all source files.
-CFLAGS_Default := -pthread
+CFLAGS_Debug := -pthread \
+ -Wall \
+ -ansi \
+ -pthread \
+ -fvisibility=hidden \
+ -g \
+ -O0
# Flags passed to only C files.
-CFLAGS_C_Default :=
+CFLAGS_C_Debug :=
# Flags passed to only C++ files.
-CFLAGS_CC_Default :=
+CFLAGS_CC_Debug := -fno-rtti \
+ -fno-exceptions
-INCS_Default := -I$(srcdir)/src/libuv/include
+INCS_Debug := -I$(srcdir)/src/libuv/include
+
+DEFS_Release := '-D_LARGEFILE_SOURCE' \
+ '-D_FILE_OFFSET_BITS=64' \
+ '-D_GNU_SOURCE' \
+ '-DEIO_STACKSIZE=262144' \
+ '-DNDEBUG'
+
+# Flags passed to all source files.
+CFLAGS_Release := -pthread \
+ -Wall \
+ -ansi \
+ -pthread \
+ -fvisibility=hidden \
+ -O3 \
+ -fomit-frame-pointer \
+ -fdata-sections \
+ -ffunction-sections
+
+# Flags passed to only C files.
+CFLAGS_C_Release :=
+
+# Flags passed to only C++ files.
+CFLAGS_CC_Release := -fno-rtti \
+ -fno-exceptions
+
+INCS_Release := -I$(srcdir)/src/libuv/include
OBJS := $(obj).target/$(TARGET)/src/libuv/test/benchmark-ares.o \
$(obj).target/$(TARGET)/src/libuv/test/benchmark-getaddrinfo.o \
$(obj).target/$(TARGET)/src/libuv/test/benchmark-pump.o \
$(obj).target/$(TARGET)/src/libuv/test/benchmark-sizes.o \
$(obj).target/$(TARGET)/src/libuv/test/benchmark-spawn.o \
+ $(obj).target/$(TARGET)/src/libuv/test/benchmark-thread.o \
$(obj).target/$(TARGET)/src/libuv/test/benchmark-tcp-write-batch.o \
$(obj).target/$(TARGET)/src/libuv/test/benchmark-udp-packet-storm.o \
$(obj).target/$(TARGET)/src/libuv/test/dns-server.o \
# CFLAGS et al overrides must be target-local.
# See "Target-specific Variable Values" in the GNU Make manual.
$(OBJS): TOOLSET := $(TOOLSET)
-$(OBJS): GYP_CFLAGS := $(DEFS_$(BUILDTYPE)) $(INCS_$(BUILDTYPE)) $(CFLAGS_$(BUILDTYPE)) $(CFLAGS_C_$(BUILDTYPE))
-$(OBJS): GYP_CXXFLAGS := $(DEFS_$(BUILDTYPE)) $(INCS_$(BUILDTYPE)) $(CFLAGS_$(BUILDTYPE)) $(CFLAGS_CC_$(BUILDTYPE))
+$(OBJS): GYP_CFLAGS := $(DEFS_$(BUILDTYPE)) $(INCS_$(BUILDTYPE)) $(CFLAGS_$(BUILDTYPE)) $(CFLAGS_C_$(BUILDTYPE))
+$(OBJS): GYP_CXXFLAGS := $(DEFS_$(BUILDTYPE)) $(INCS_$(BUILDTYPE)) $(CFLAGS_$(BUILDTYPE)) $(CFLAGS_CC_$(BUILDTYPE))
# Suffix rules, putting all outputs into $(obj).
# End of this set of suffix rules
### Rules for final target.
-LDFLAGS_Default :=
+LDFLAGS_Debug := -pthread
+
+LDFLAGS_Release := -pthread
LIBS := -lrt
TOOLSET := target
TARGET := run-tests
-DEFS_Default := '-D_LARGEFILE_SOURCE' \
+DEFS_Debug := '-D_LARGEFILE_SOURCE' \
'-D_FILE_OFFSET_BITS=64' \
'-D_GNU_SOURCE' \
- '-DEIO_STACKSIZE=262144'
+ '-DEIO_STACKSIZE=262144' \
+ '-DDEBUG' \
+ '-D_DEBUG' \
+ '-DEV_VERIFY=2'
# Flags passed to all source files.
-CFLAGS_Default := -pthread
+CFLAGS_Debug := -pthread \
+ -Wall \
+ -ansi \
+ -pthread \
+ -fvisibility=hidden \
+ -g \
+ -O0
# Flags passed to only C files.
-CFLAGS_C_Default :=
+CFLAGS_C_Debug :=
# Flags passed to only C++ files.
-CFLAGS_CC_Default :=
+CFLAGS_CC_Debug := -fno-rtti \
+ -fno-exceptions
-INCS_Default := -I$(srcdir)/src/libuv/include
+INCS_Debug := -I$(srcdir)/src/libuv/include
+
+DEFS_Release := '-D_LARGEFILE_SOURCE' \
+ '-D_FILE_OFFSET_BITS=64' \
+ '-D_GNU_SOURCE' \
+ '-DEIO_STACKSIZE=262144' \
+ '-DNDEBUG'
+
+# Flags passed to all source files.
+CFLAGS_Release := -pthread \
+ -Wall \
+ -ansi \
+ -pthread \
+ -fvisibility=hidden \
+ -O3 \
+ -fomit-frame-pointer \
+ -fdata-sections \
+ -ffunction-sections
+
+# Flags passed to only C files.
+CFLAGS_C_Release :=
+
+# Flags passed to only C++ files.
+CFLAGS_CC_Release := -fno-rtti \
+ -fno-exceptions
+
+INCS_Release := -I$(srcdir)/src/libuv/include
OBJS := $(obj).target/$(TARGET)/src/libuv/test/blackhole-server.o \
$(obj).target/$(TARGET)/src/libuv/test/echo-server.o \
$(obj).target/$(TARGET)/src/libuv/test/run-tests.o \
$(obj).target/$(TARGET)/src/libuv/test/runner.o \
$(obj).target/$(TARGET)/src/libuv/test/test-get-loadavg.o \
+ $(obj).target/$(TARGET)/src/libuv/test/test-util.o \
$(obj).target/$(TARGET)/src/libuv/test/test-async.o \
$(obj).target/$(TARGET)/src/libuv/test/test-error.o \
$(obj).target/$(TARGET)/src/libuv/test/test-callback-stack.o \
$(obj).target/$(TARGET)/src/libuv/test/test-connection-fail.o \
+ $(obj).target/$(TARGET)/src/libuv/test/test-cwd-and-chdir.o \
$(obj).target/$(TARGET)/src/libuv/test/test-delayed-accept.o \
+ $(obj).target/$(TARGET)/src/libuv/test/test-eio-overflow.o \
$(obj).target/$(TARGET)/src/libuv/test/test-fail-always.o \
$(obj).target/$(TARGET)/src/libuv/test/test-fs.o \
$(obj).target/$(TARGET)/src/libuv/test/test-fs-event.o \
$(obj).target/$(TARGET)/src/libuv/test/test-hrtime.o \
$(obj).target/$(TARGET)/src/libuv/test/test-idle.o \
$(obj).target/$(TARGET)/src/libuv/test/test-ipc.o \
+ $(obj).target/$(TARGET)/src/libuv/test/test-ipc-threads.o \
$(obj).target/$(TARGET)/src/libuv/test/test-loop-handles.o \
$(obj).target/$(TARGET)/src/libuv/test/test-multiple-listen.o \
$(obj).target/$(TARGET)/src/libuv/test/test-pass-always.o \
$(obj).target/$(TARGET)/src/libuv/test/test-ping-pong.o \
$(obj).target/$(TARGET)/src/libuv/test/test-pipe-bind-error.o \
$(obj).target/$(TARGET)/src/libuv/test/test-pipe-connect-error.o \
+ $(obj).target/$(TARGET)/src/libuv/test/test-platform-output.o \
+ $(obj).target/$(TARGET)/src/libuv/test/test-process-title.o \
$(obj).target/$(TARGET)/src/libuv/test/test-ref.o \
$(obj).target/$(TARGET)/src/libuv/test/test-shutdown-eof.o \
$(obj).target/$(TARGET)/src/libuv/test/test-spawn.o \
$(obj).target/$(TARGET)/src/libuv/test/test-tcp-write-to-half-open-connection.o \
$(obj).target/$(TARGET)/src/libuv/test/test-tcp-writealot.o \
$(obj).target/$(TARGET)/src/libuv/test/test-threadpool.o \
+ $(obj).target/$(TARGET)/src/libuv/test/test-mutexes.o \
+ $(obj).target/$(TARGET)/src/libuv/test/test-thread.o \
$(obj).target/$(TARGET)/src/libuv/test/test-timer-again.o \
$(obj).target/$(TARGET)/src/libuv/test/test-timer.o \
$(obj).target/$(TARGET)/src/libuv/test/test-tty.o \
$(obj).target/$(TARGET)/src/libuv/test/test-udp-dgram-too-big.o \
$(obj).target/$(TARGET)/src/libuv/test/test-udp-ipv6.o \
+ $(obj).target/$(TARGET)/src/libuv/test/test-udp-options.o \
$(obj).target/$(TARGET)/src/libuv/test/test-udp-send-and-recv.o \
$(obj).target/$(TARGET)/src/libuv/test/test-udp-multicast-join.o \
+ $(obj).target/$(TARGET)/src/libuv/test/test-counters-init.o \
$(obj).target/$(TARGET)/src/libuv/test/runner-unix.o
# Add to the list of files we specially track dependencies for.
# CFLAGS et al overrides must be target-local.
# See "Target-specific Variable Values" in the GNU Make manual.
$(OBJS): TOOLSET := $(TOOLSET)
-$(OBJS): GYP_CFLAGS := $(DEFS_$(BUILDTYPE)) $(INCS_$(BUILDTYPE)) $(CFLAGS_$(BUILDTYPE)) $(CFLAGS_C_$(BUILDTYPE))
-$(OBJS): GYP_CXXFLAGS := $(DEFS_$(BUILDTYPE)) $(INCS_$(BUILDTYPE)) $(CFLAGS_$(BUILDTYPE)) $(CFLAGS_CC_$(BUILDTYPE))
+$(OBJS): GYP_CFLAGS := $(DEFS_$(BUILDTYPE)) $(INCS_$(BUILDTYPE)) $(CFLAGS_$(BUILDTYPE)) $(CFLAGS_C_$(BUILDTYPE))
+$(OBJS): GYP_CXXFLAGS := $(DEFS_$(BUILDTYPE)) $(INCS_$(BUILDTYPE)) $(CFLAGS_$(BUILDTYPE)) $(CFLAGS_CC_$(BUILDTYPE))
# Suffix rules, putting all outputs into $(obj).
# End of this set of suffix rules
### Rules for final target.
-LDFLAGS_Default :=
+LDFLAGS_Debug := -pthread
+
+LDFLAGS_Release := -pthread
LIBS := -lrt
TOOLSET := target
TARGET := uv
-DEFS_Default := '-D_LARGEFILE_SOURCE' \
+DEFS_Debug := '-D_LARGEFILE_SOURCE' \
'-D_FILE_OFFSET_BITS=64' \
'-D_GNU_SOURCE' \
'-DEIO_STACKSIZE=262144' \
'-DHAVE_CONFIG_H' \
'-DEV_CONFIG_H="config_linux.h"' \
- '-DEIO_CONFIG_H="config_linux.h"'
+ '-DEIO_CONFIG_H="config_linux.h"' \
+ '-DDEBUG' \
+ '-D_DEBUG' \
+ '-DEV_VERIFY=2'
# Flags passed to all source files.
-CFLAGS_Default := -pthread \
+CFLAGS_Debug := -pthread \
+ -Wall \
+ -ansi \
+ -pthread \
+ -fvisibility=hidden \
+ -g \
+ --std=gnu89 \
+ -pedantic \
+ -Wall \
+ -Wextra \
+ -Wno-unused-parameter \
+ -g \
+ -O0
+
+# Flags passed to only C files.
+CFLAGS_C_Debug :=
+
+# Flags passed to only C++ files.
+CFLAGS_CC_Debug := -fno-rtti \
+ -fno-exceptions
+
+INCS_Debug := -I$(srcdir)/src/libuv/include \
+ -I$(srcdir)/src/libuv/include/uv-private \
+ -I$(srcdir)/src/libuv/src \
+ -I$(srcdir)/src/libuv/src/unix/ev \
+ -I$(srcdir)/src/libuv/src/ares/config_linux
+
+DEFS_Release := '-D_LARGEFILE_SOURCE' \
+ '-D_FILE_OFFSET_BITS=64' \
+ '-D_GNU_SOURCE' \
+ '-DEIO_STACKSIZE=262144' \
+ '-DHAVE_CONFIG_H' \
+ '-DEV_CONFIG_H="config_linux.h"' \
+ '-DEIO_CONFIG_H="config_linux.h"' \
+ '-DNDEBUG'
+
+# Flags passed to all source files.
+CFLAGS_Release := -pthread \
+ -Wall \
+ -ansi \
+ -pthread \
+ -fvisibility=hidden \
-g \
--std=gnu89 \
-pedantic \
-Wall \
-Wextra \
- -Wno-unused-parameter
+ -Wno-unused-parameter \
+ -O3 \
+ -fomit-frame-pointer \
+ -fdata-sections \
+ -ffunction-sections
# Flags passed to only C files.
-CFLAGS_C_Default :=
+CFLAGS_C_Release :=
# Flags passed to only C++ files.
-CFLAGS_CC_Default :=
+CFLAGS_CC_Release := -fno-rtti \
+ -fno-exceptions
-INCS_Default := -I$(srcdir)/src/libuv/include \
+INCS_Release := -I$(srcdir)/src/libuv/include \
-I$(srcdir)/src/libuv/include/uv-private \
-I$(srcdir)/src/libuv/src \
-I$(srcdir)/src/libuv/src/unix/ev \
$(obj).target/$(TARGET)/src/libuv/src/unix/cares.o \
$(obj).target/$(TARGET)/src/libuv/src/unix/dl.o \
$(obj).target/$(TARGET)/src/libuv/src/unix/error.o \
+ $(obj).target/$(TARGET)/src/libuv/src/unix/thread.o \
$(obj).target/$(TARGET)/src/libuv/src/unix/process.o \
$(obj).target/$(TARGET)/src/libuv/src/unix/eio/eio.o \
$(obj).target/$(TARGET)/src/libuv/src/unix/ev/ev.o \
# CFLAGS et al overrides must be target-local.
# See "Target-specific Variable Values" in the GNU Make manual.
$(OBJS): TOOLSET := $(TOOLSET)
-$(OBJS): GYP_CFLAGS := $(DEFS_$(BUILDTYPE)) $(INCS_$(BUILDTYPE)) $(CFLAGS_$(BUILDTYPE)) $(CFLAGS_C_$(BUILDTYPE))
-$(OBJS): GYP_CXXFLAGS := $(DEFS_$(BUILDTYPE)) $(INCS_$(BUILDTYPE)) $(CFLAGS_$(BUILDTYPE)) $(CFLAGS_CC_$(BUILDTYPE))
+$(OBJS): GYP_CFLAGS := $(DEFS_$(BUILDTYPE)) $(INCS_$(BUILDTYPE)) $(CFLAGS_$(BUILDTYPE)) $(CFLAGS_C_$(BUILDTYPE))
+$(OBJS): GYP_CXXFLAGS := $(DEFS_$(BUILDTYPE)) $(INCS_$(BUILDTYPE)) $(CFLAGS_$(BUILDTYPE)) $(CFLAGS_CC_$(BUILDTYPE))
# Suffix rules, putting all outputs into $(obj).
# End of this set of suffix rules
### Rules for final target.
-LDFLAGS_Default :=
+LDFLAGS_Debug := -pthread
+
+LDFLAGS_Release := -pthread
LIBS := -lm
# The source directory tree.
srcdir := ../../../..
+abs_srcdir := $(abspath $(srcdir))
# The name of the builddir.
builddir_name ?= out
endif
# Specify BUILDTYPE=Release on the command line for a release build.
-BUILDTYPE ?= Default
+BUILDTYPE ?= Debug
# Directory all our build output goes into.
# Note that this must be two directories beneath src/ for unit tests to pass,
)
endef
-# Declare "all" target first so it is the default, even though we don't have the
-# deps yet.
+# Declare the "all" target first so it is the default,
+# even though we don't have the deps yet.
.PHONY: all
all:
include src/libuv/uv.target.mk
endif
-quiet_cmd_regen_makefile = ACTION Regenerating $@
-cmd_regen_makefile = ./src/libuv/build/gyp/gyp -fmake --ignore-environment "--toplevel-dir=." "--depth=." "--generator-output=mk/libuv/ia32/win" "-Dlibrary=static_library" "-Dtarget_arch=ia32" "-DOS=win" src/libuv/uv.gyp
-Makefile: $(srcdir)/src/libuv/uv.gyp
+#quiet_cmd_regen_makefile = ACTION Regenerating $@
+#cmd_regen_makefile = ./src/libuv/build/gyp/gyp -fmake --ignore-environment "--toplevel-dir=." -Isrc/libuv/common.gypi "--depth=." "--generator-output=mk/libuv/ia32/win" "-Ddefault_configuration=Default" "-Dcomponent=static_library" "-Dlibrary=static_library" "-Dtarget_arch=ia32" "-DOS=win" src/libuv/uv.gyp
+#Makefile: $(srcdir)/src/libuv/uv.gyp $(srcdir)/src/libuv/common.gypi
# $(call do_cmd,regen_makefile)
# "all" is a concatenation of the "all" targets from all the included
+++ /dev/null
-# We borrow heavily from the kernel build setup, though we are simpler since
-# we don't have Kconfig tweaking settings on us.
-
-# The implicit make rules have it looking for RCS files, among other things.
-# We instead explicitly write all the rules we care about.
-# It's even quicker (saves ~200ms) to pass -r on the command line.
-MAKEFLAGS=-r
-
-# The source directory tree.
-srcdir := ../../../..
-
-# The name of the builddir.
-builddir_name ?= out
-
-# The V=1 flag on command line makes us verbosely print command lines.
-ifdef V
- quiet=
-else
- quiet=quiet_
-endif
-
-# Specify BUILDTYPE=Release on the command line for a release build.
-BUILDTYPE ?= Default
-
-# Directory all our build output goes into.
-# Note that this must be two directories beneath src/ for unit tests to pass,
-# as they reach into the src/ directory for data with relative paths.
-builddir ?= $(builddir_name)/$(BUILDTYPE)
-abs_builddir := $(abspath $(builddir))
-depsdir := $(builddir)/.deps
-
-# Object output directory.
-obj := $(builddir)/obj
-abs_obj := $(abspath $(obj))
-
-# We build up a list of every single one of the targets so we can slurp in the
-# generated dependency rule Makefiles in one pass.
-all_deps :=
-
-
-
-# C++ apps need to be linked with g++.
-#
-# Note: flock is used to seralize linking. Linking is a memory-intensive
-# process so running parallel links can often lead to thrashing. To disable
-# the serialization, override LINK via an envrionment variable as follows:
-#
-# export LINK=g++
-#
-# This will allow make to invoke N linker processes as specified in -jN.
-LINK ?= flock $(builddir)/linker.lock $(CXX)
-
-CC.target ?= $(CC)
-CFLAGS.target ?= $(CFLAGS)
-CXX.target ?= $(CXX)
-CXXFLAGS.target ?= $(CXXFLAGS)
-LINK.target ?= $(LINK)
-LDFLAGS.target ?= $(LDFLAGS)
-AR.target ?= $(AR)
-ARFLAGS.target ?= crsT
-
-# N.B.: the logic of which commands to run should match the computation done
-# in gyp's make.py where ARFLAGS.host etc. is computed.
-# TODO(evan): move all cross-compilation logic to gyp-time so we don't need
-# to replicate this environment fallback in make as well.
-CC.host ?= gcc
-CFLAGS.host ?=
-CXX.host ?= g++
-CXXFLAGS.host ?=
-LINK.host ?= g++
-LDFLAGS.host ?=
-AR.host ?= ar
-ARFLAGS.host := crsT
-
-# Define a dir function that can handle spaces.
-# http://www.gnu.org/software/make/manual/make.html#Syntax-of-Functions
-# "leading spaces cannot appear in the text of the first argument as written.
-# These characters can be put into the argument value by variable substitution."
-empty :=
-space := $(empty) $(empty)
-
-# http://stackoverflow.com/questions/1189781/using-make-dir-or-notdir-on-a-path-with-spaces
-replace_spaces = $(subst $(space),?,$1)
-unreplace_spaces = $(subst ?,$(space),$1)
-dirx = $(call unreplace_spaces,$(dir $(call replace_spaces,$1)))
-
-# Flags to make gcc output dependency info. Note that you need to be
-# careful here to use the flags that ccache and distcc can understand.
-# We write to a dep file on the side first and then rename at the end
-# so we can't end up with a broken dep file.
-depfile = $(depsdir)/$(call replace_spaces,$@).d
-DEPFLAGS = -MMD -MF $(depfile).raw
-
-# We have to fixup the deps output in a few ways.
-# (1) the file output should mention the proper .o file.
-# ccache or distcc lose the path to the target, so we convert a rule of
-# the form:
-# foobar.o: DEP1 DEP2
-# into
-# path/to/foobar.o: DEP1 DEP2
-# (2) we want missing files not to cause us to fail to build.
-# We want to rewrite
-# foobar.o: DEP1 DEP2 \
-# DEP3
-# to
-# DEP1:
-# DEP2:
-# DEP3:
-# so if the files are missing, they're just considered phony rules.
-# We have to do some pretty insane escaping to get those backslashes
-# and dollar signs past make, the shell, and sed at the same time.
-# Doesn't work with spaces, but that's fine: .d files have spaces in
-# their names replaced with other characters.
-define fixup_dep
-# The depfile may not exist if the input file didn't have any #includes.
-touch $(depfile).raw
-# Fixup path as in (1).
-sed -e "s|^$(notdir $@)|$@|" $(depfile).raw >> $(depfile)
-# Add extra rules as in (2).
-# We remove slashes and replace spaces with new lines;
-# remove blank lines;
-# delete the first line and append a colon to the remaining lines.
-sed -e 's|\\||' -e 'y| |\n|' $(depfile).raw |\
- grep -v '^$$' |\
- sed -e 1d -e 's|$$|:|' \
- >> $(depfile)
-rm $(depfile).raw
-endef
-
-# Command definitions:
-# - cmd_foo is the actual command to run;
-# - quiet_cmd_foo is the brief-output summary of the command.
-
-quiet_cmd_cc = CC($(TOOLSET)) $@
-cmd_cc = $(CC.$(TOOLSET)) $(GYP_CFLAGS) $(DEPFLAGS) $(CFLAGS.$(TOOLSET)) -c -o $@ $<
-
-quiet_cmd_cxx = CXX($(TOOLSET)) $@
-cmd_cxx = $(CXX.$(TOOLSET)) $(GYP_CXXFLAGS) $(DEPFLAGS) $(CXXFLAGS.$(TOOLSET)) -c -o $@ $<
-
-quiet_cmd_touch = TOUCH $@
-cmd_touch = touch $@
-
-quiet_cmd_copy = COPY $@
-# send stderr to /dev/null to ignore messages when linking directories.
-cmd_copy = ln -f "$<" "$@" 2>/dev/null || (rm -rf "$@" && cp -af "$<" "$@")
-
-quiet_cmd_alink = AR($(TOOLSET)) $@
-cmd_alink = rm -f $@ && $(AR.$(TOOLSET)) $(ARFLAGS.$(TOOLSET)) $@ $(filter %.o,$^)
-
-# Due to circular dependencies between libraries :(, we wrap the
-# special "figure out circular dependencies" flags around the entire
-# input list during linking.
-quiet_cmd_link = LINK($(TOOLSET)) $@
-cmd_link = $(LINK.$(TOOLSET)) $(GYP_LDFLAGS) $(LDFLAGS.$(TOOLSET)) -o $@ -Wl,--start-group $(LD_INPUTS) -Wl,--end-group $(LIBS)
-
-# We support two kinds of shared objects (.so):
-# 1) shared_library, which is just bundling together many dependent libraries
-# into a link line.
-# 2) loadable_module, which is generating a module intended for dlopen().
-#
-# They differ only slightly:
-# In the former case, we want to package all dependent code into the .so.
-# In the latter case, we want to package just the API exposed by the
-# outermost module.
-# This means shared_library uses --whole-archive, while loadable_module doesn't.
-# (Note that --whole-archive is incompatible with the --start-group used in
-# normal linking.)
-
-# Other shared-object link notes:
-# - Set SONAME to the library filename so our binaries don't reference
-# the local, absolute paths used on the link command-line.
-quiet_cmd_solink = SOLINK($(TOOLSET)) $@
-cmd_solink = $(LINK.$(TOOLSET)) -shared $(GYP_LDFLAGS) $(LDFLAGS.$(TOOLSET)) -Wl,-soname=$(@F) -o $@ -Wl,--whole-archive $(LD_INPUTS) -Wl,--no-whole-archive $(LIBS)
-
-quiet_cmd_solink_module = SOLINK_MODULE($(TOOLSET)) $@
-cmd_solink_module = $(LINK.$(TOOLSET)) -shared $(GYP_LDFLAGS) $(LDFLAGS.$(TOOLSET)) -Wl,-soname=$(@F) -o $@ -Wl,--start-group $(filter-out FORCE_DO_CMD, $^) -Wl,--end-group $(LIBS)
-
-
-# Define an escape_quotes function to escape single quotes.
-# This allows us to handle quotes properly as long as we always use
-# use single quotes and escape_quotes.
-escape_quotes = $(subst ','\'',$(1))
-# This comment is here just to include a ' to unconfuse syntax highlighting.
-# Define an escape_vars function to escape '$' variable syntax.
-# This allows us to read/write command lines with shell variables (e.g.
-# $LD_LIBRARY_PATH), without triggering make substitution.
-escape_vars = $(subst $$,$$$$,$(1))
-# Helper that expands to a shell command to echo a string exactly as it is in
-# make. This uses printf instead of echo because printf's behaviour with respect
-# to escape sequences is more portable than echo's across different shells
-# (e.g., dash, bash).
-exact_echo = printf '%s\n' '$(call escape_quotes,$(1))'
-
-# Helper to compare the command we're about to run against the command
-# we logged the last time we ran the command. Produces an empty
-# string (false) when the commands match.
-# Tricky point: Make has no string-equality test function.
-# The kernel uses the following, but it seems like it would have false
-# positives, where one string reordered its arguments.
-# arg_check = $(strip $(filter-out $(cmd_$(1)), $(cmd_$@)) \
-# $(filter-out $(cmd_$@), $(cmd_$(1))))
-# We instead substitute each for the empty string into the other, and
-# say they're equal if both substitutions produce the empty string.
-# .d files contain ? instead of spaces, take that into account.
-command_changed = $(or $(subst $(cmd_$(1)),,$(cmd_$(call replace_spaces,$@))),\
- $(subst $(cmd_$(call replace_spaces,$@)),,$(cmd_$(1))))
-
-# Helper that is non-empty when a prerequisite changes.
-# Normally make does this implicitly, but we force rules to always run
-# so we can check their command lines.
-# $? -- new prerequisites
-# $| -- order-only dependencies
-prereq_changed = $(filter-out FORCE_DO_CMD,$(filter-out $|,$?))
-
-# Helper that executes all postbuilds, and deletes the output file when done
-# if any of the postbuilds failed.
-define do_postbuilds
- @E=0;\
- for p in $(POSTBUILDS); do\
- eval $$p;\
- F=$$?;\
- if [ $$F -ne 0 ]; then\
- E=$$F;\
- fi;\
- done;\
- if [ $$E -ne 0 ]; then\
- rm -rf "$@";\
- exit $$E;\
- fi
-endef
-
-# do_cmd: run a command via the above cmd_foo names, if necessary.
-# Should always run for a given target to handle command-line changes.
-# Second argument, if non-zero, makes it do asm/C/C++ dependency munging.
-# Third argument, if non-zero, makes it do POSTBUILDS processing.
-# Note: We intentionally do NOT call dirx for depfile, since it contains ? for
-# spaces already and dirx strips the ? characters.
-define do_cmd
-$(if $(or $(command_changed),$(prereq_changed)),
- @$(call exact_echo, $($(quiet)cmd_$(1)))
- @mkdir -p "$(call dirx,$@)" "$(dir $(depfile))"
- $(if $(findstring flock,$(word 1,$(cmd_$1))),
- @$(cmd_$(1))
- @echo " $(quiet_cmd_$(1)): Finished",
- @$(cmd_$(1))
- )
- @$(call exact_echo,$(call escape_vars,cmd_$(call replace_spaces,$@) := $(cmd_$(1)))) > $(depfile)
- @$(if $(2),$(fixup_dep))
- $(if $(and $(3), $(POSTBUILDS)),
- $(call do_postbuilds)
- )
-)
-endef
-
-# Declare "all" target first so it is the default, even though we don't have the
-# deps yet.
-.PHONY: all
-all:
-
-# Use FORCE_DO_CMD to force a target to run. Should be coupled with
-# do_cmd.
-.PHONY: FORCE_DO_CMD
-FORCE_DO_CMD:
-
-TOOLSET := target
-# Suffix rules, putting all outputs into $(obj).
-$(obj).$(TOOLSET)/%.o: $(srcdir)/%.c FORCE_DO_CMD
- @$(call do_cmd,cc,1)
-$(obj).$(TOOLSET)/%.o: $(srcdir)/%.cc FORCE_DO_CMD
- @$(call do_cmd,cxx,1)
-$(obj).$(TOOLSET)/%.o: $(srcdir)/%.cpp FORCE_DO_CMD
- @$(call do_cmd,cxx,1)
-$(obj).$(TOOLSET)/%.o: $(srcdir)/%.cxx FORCE_DO_CMD
- @$(call do_cmd,cxx,1)
-$(obj).$(TOOLSET)/%.o: $(srcdir)/%.S FORCE_DO_CMD
- @$(call do_cmd,cc,1)
-$(obj).$(TOOLSET)/%.o: $(srcdir)/%.s FORCE_DO_CMD
- @$(call do_cmd,cc,1)
-
-# Try building from generated source, too.
-$(obj).$(TOOLSET)/%.o: $(obj).$(TOOLSET)/%.c FORCE_DO_CMD
- @$(call do_cmd,cc,1)
-$(obj).$(TOOLSET)/%.o: $(obj).$(TOOLSET)/%.cc FORCE_DO_CMD
- @$(call do_cmd,cxx,1)
-$(obj).$(TOOLSET)/%.o: $(obj).$(TOOLSET)/%.cpp FORCE_DO_CMD
- @$(call do_cmd,cxx,1)
-$(obj).$(TOOLSET)/%.o: $(obj).$(TOOLSET)/%.cxx FORCE_DO_CMD
- @$(call do_cmd,cxx,1)
-$(obj).$(TOOLSET)/%.o: $(obj).$(TOOLSET)/%.S FORCE_DO_CMD
- @$(call do_cmd,cc,1)
-$(obj).$(TOOLSET)/%.o: $(obj).$(TOOLSET)/%.s FORCE_DO_CMD
- @$(call do_cmd,cc,1)
-
-$(obj).$(TOOLSET)/%.o: $(obj)/%.c FORCE_DO_CMD
- @$(call do_cmd,cc,1)
-$(obj).$(TOOLSET)/%.o: $(obj)/%.cc FORCE_DO_CMD
- @$(call do_cmd,cxx,1)
-$(obj).$(TOOLSET)/%.o: $(obj)/%.cpp FORCE_DO_CMD
- @$(call do_cmd,cxx,1)
-$(obj).$(TOOLSET)/%.o: $(obj)/%.cxx FORCE_DO_CMD
- @$(call do_cmd,cxx,1)
-$(obj).$(TOOLSET)/%.o: $(obj)/%.S FORCE_DO_CMD
- @$(call do_cmd,cc,1)
-$(obj).$(TOOLSET)/%.o: $(obj)/%.s FORCE_DO_CMD
- @$(call do_cmd,cc,1)
-
-
-ifeq ($(strip $(foreach prefix,$(NO_LOAD),\
- $(findstring $(join ^,$(prefix)),\
- $(join ^,src/libuv/run-benchmarks.target.mk)))),)
- include src/libuv/run-benchmarks.target.mk
-endif
-ifeq ($(strip $(foreach prefix,$(NO_LOAD),\
- $(findstring $(join ^,$(prefix)),\
- $(join ^,src/libuv/run-tests.target.mk)))),)
- include src/libuv/run-tests.target.mk
-endif
-ifeq ($(strip $(foreach prefix,$(NO_LOAD),\
- $(findstring $(join ^,$(prefix)),\
- $(join ^,src/libuv/uv.target.mk)))),)
- include src/libuv/uv.target.mk
-endif
-
-quiet_cmd_regen_makefile = ACTION Regenerating $@
-cmd_regen_makefile = ./src/libuv/build/gyp/gyp -fmake --ignore-environment "--toplevel-dir=." "--depth=." "--generator-output=mk/libuv/ia32/win" "-Dlibrary=static_library" "-Dtarget_arch=ia32" "-DOS=win" src/libuv/uv.gyp
-Makefile: $(srcdir)/src/libuv/uv.gyp
- $(call do_cmd,regen_makefile)
-
-# "all" is a concatenation of the "all" targets from all the included
-# sub-makefiles. This is just here to clarify.
-all:
-
-# Add in dependency-tracking rules. $(all_deps) is the list of every single
-# target in our tree. Only consider the ones with .d (dependency) info:
-d_files := $(wildcard $(foreach f,$(all_deps),$(depsdir)/$(f).d))
-ifneq ($(d_files),)
- # Rather than include each individual .d file, concatenate them into a
- # single file which make is able to load faster. We split this into
- # commands that take 1000 files at a time to avoid overflowing the
- # command line.
- $(shell cat $(wordlist 1,1000,$(d_files)) > $(depsdir)/all.deps)
-
- ifneq ($(word 1001,$(d_files)),)
- $(error Found unprocessed dependency files (gyp didn't generate enough rules!))
- endif
-
- # make looks for ways to re-generate included makefiles, but in our case, we
- # don't have a direct way. Explicitly telling make that it has nothing to do
- # for them makes it go faster.
- $(depsdir)/all.deps: ;
-
- include $(depsdir)/all.deps
-endif
TOOLSET := target
TARGET := run-benchmarks
-DEFS_Default :=
+DEFS_Debug := '-DWIN32' \
+ '-D_CRT_SECURE_NO_DEPRECATE' \
+ '-D_CRT_NONSTDC_NO_DEPRECATE' \
+ '-DDEBUG' \
+ '-D_DEBUG'
# Flags passed to all source files.
-CFLAGS_Default :=
+CFLAGS_Debug := -g \
+ -O0
# Flags passed to only C files.
-CFLAGS_C_Default :=
+CFLAGS_C_Debug :=
# Flags passed to only C++ files.
-CFLAGS_CC_Default :=
+CFLAGS_CC_Debug :=
-INCS_Default := -I$(srcdir)/src/libuv/include
+INCS_Debug := -I$(srcdir)/src/libuv/include
+
+DEFS_Release := '-DWIN32' \
+ '-D_CRT_SECURE_NO_DEPRECATE' \
+ '-D_CRT_NONSTDC_NO_DEPRECATE' \
+ '-DNDEBUG'
+
+# Flags passed to all source files.
+CFLAGS_Release := -O3 \
+ -fomit-frame-pointer \
+ -fdata-sections \
+ -ffunction-sections
+
+# Flags passed to only C files.
+CFLAGS_C_Release :=
+
+# Flags passed to only C++ files.
+CFLAGS_CC_Release :=
+
+INCS_Release := -I$(srcdir)/src/libuv/include
OBJS := $(obj).target/$(TARGET)/src/libuv/test/benchmark-ares.o \
$(obj).target/$(TARGET)/src/libuv/test/benchmark-getaddrinfo.o \
$(obj).target/$(TARGET)/src/libuv/test/benchmark-pump.o \
$(obj).target/$(TARGET)/src/libuv/test/benchmark-sizes.o \
$(obj).target/$(TARGET)/src/libuv/test/benchmark-spawn.o \
+ $(obj).target/$(TARGET)/src/libuv/test/benchmark-thread.o \
$(obj).target/$(TARGET)/src/libuv/test/benchmark-tcp-write-batch.o \
$(obj).target/$(TARGET)/src/libuv/test/benchmark-udp-packet-storm.o \
$(obj).target/$(TARGET)/src/libuv/test/dns-server.o \
# CFLAGS et al overrides must be target-local.
# See "Target-specific Variable Values" in the GNU Make manual.
$(OBJS): TOOLSET := $(TOOLSET)
-$(OBJS): GYP_CFLAGS := $(DEFS_$(BUILDTYPE)) $(INCS_$(BUILDTYPE)) $(CFLAGS_$(BUILDTYPE)) $(CFLAGS_C_$(BUILDTYPE))
-$(OBJS): GYP_CXXFLAGS := $(DEFS_$(BUILDTYPE)) $(INCS_$(BUILDTYPE)) $(CFLAGS_$(BUILDTYPE)) $(CFLAGS_CC_$(BUILDTYPE))
+$(OBJS): GYP_CFLAGS := $(DEFS_$(BUILDTYPE)) $(INCS_$(BUILDTYPE)) $(CFLAGS_$(BUILDTYPE)) $(CFLAGS_C_$(BUILDTYPE))
+$(OBJS): GYP_CXXFLAGS := $(DEFS_$(BUILDTYPE)) $(INCS_$(BUILDTYPE)) $(CFLAGS_$(BUILDTYPE)) $(CFLAGS_CC_$(BUILDTYPE))
# Suffix rules, putting all outputs into $(obj).
# End of this set of suffix rules
### Rules for final target.
-LDFLAGS_Default :=
+LDFLAGS_Debug :=
+
+LDFLAGS_Release :=
LIBS := ws2_32.lib \
- -lws2_32.lib
+ -lws2_32.lib \
+ -lpsapi.lib \
+ -liphlpapi.lib
$(builddir)/run-benchmarks: GYP_LDFLAGS := $(LDFLAGS_$(BUILDTYPE))
$(builddir)/run-benchmarks: LIBS := $(LIBS)
TOOLSET := target
TARGET := run-tests
-DEFS_Default :=
+DEFS_Debug := '-DWIN32' \
+ '-D_CRT_SECURE_NO_DEPRECATE' \
+ '-D_CRT_NONSTDC_NO_DEPRECATE' \
+ '-DDEBUG' \
+ '-D_DEBUG'
# Flags passed to all source files.
-CFLAGS_Default :=
+CFLAGS_Debug := -g \
+ -O0
# Flags passed to only C files.
-CFLAGS_C_Default :=
+CFLAGS_C_Debug :=
# Flags passed to only C++ files.
-CFLAGS_CC_Default :=
+CFLAGS_CC_Debug :=
-INCS_Default := -I$(srcdir)/src/libuv/include
+INCS_Debug := -I$(srcdir)/src/libuv/include
+
+DEFS_Release := '-DWIN32' \
+ '-D_CRT_SECURE_NO_DEPRECATE' \
+ '-D_CRT_NONSTDC_NO_DEPRECATE' \
+ '-DNDEBUG'
+
+# Flags passed to all source files.
+CFLAGS_Release := -O3 \
+ -fomit-frame-pointer \
+ -fdata-sections \
+ -ffunction-sections
+
+# Flags passed to only C files.
+CFLAGS_C_Release :=
+
+# Flags passed to only C++ files.
+CFLAGS_CC_Release :=
+
+INCS_Release := -I$(srcdir)/src/libuv/include
OBJS := $(obj).target/$(TARGET)/src/libuv/test/blackhole-server.o \
$(obj).target/$(TARGET)/src/libuv/test/echo-server.o \
$(obj).target/$(TARGET)/src/libuv/test/run-tests.o \
$(obj).target/$(TARGET)/src/libuv/test/runner.o \
$(obj).target/$(TARGET)/src/libuv/test/test-get-loadavg.o \
+ $(obj).target/$(TARGET)/src/libuv/test/test-util.o \
$(obj).target/$(TARGET)/src/libuv/test/test-async.o \
$(obj).target/$(TARGET)/src/libuv/test/test-error.o \
$(obj).target/$(TARGET)/src/libuv/test/test-callback-stack.o \
$(obj).target/$(TARGET)/src/libuv/test/test-connection-fail.o \
+ $(obj).target/$(TARGET)/src/libuv/test/test-cwd-and-chdir.o \
$(obj).target/$(TARGET)/src/libuv/test/test-delayed-accept.o \
+ $(obj).target/$(TARGET)/src/libuv/test/test-eio-overflow.o \
$(obj).target/$(TARGET)/src/libuv/test/test-fail-always.o \
$(obj).target/$(TARGET)/src/libuv/test/test-fs.o \
$(obj).target/$(TARGET)/src/libuv/test/test-fs-event.o \
$(obj).target/$(TARGET)/src/libuv/test/test-hrtime.o \
$(obj).target/$(TARGET)/src/libuv/test/test-idle.o \
$(obj).target/$(TARGET)/src/libuv/test/test-ipc.o \
+ $(obj).target/$(TARGET)/src/libuv/test/test-ipc-threads.o \
$(obj).target/$(TARGET)/src/libuv/test/test-loop-handles.o \
$(obj).target/$(TARGET)/src/libuv/test/test-multiple-listen.o \
$(obj).target/$(TARGET)/src/libuv/test/test-pass-always.o \
$(obj).target/$(TARGET)/src/libuv/test/test-ping-pong.o \
$(obj).target/$(TARGET)/src/libuv/test/test-pipe-bind-error.o \
$(obj).target/$(TARGET)/src/libuv/test/test-pipe-connect-error.o \
+ $(obj).target/$(TARGET)/src/libuv/test/test-platform-output.o \
+ $(obj).target/$(TARGET)/src/libuv/test/test-process-title.o \
$(obj).target/$(TARGET)/src/libuv/test/test-ref.o \
$(obj).target/$(TARGET)/src/libuv/test/test-shutdown-eof.o \
$(obj).target/$(TARGET)/src/libuv/test/test-spawn.o \
$(obj).target/$(TARGET)/src/libuv/test/test-tcp-write-to-half-open-connection.o \
$(obj).target/$(TARGET)/src/libuv/test/test-tcp-writealot.o \
$(obj).target/$(TARGET)/src/libuv/test/test-threadpool.o \
+ $(obj).target/$(TARGET)/src/libuv/test/test-mutexes.o \
+ $(obj).target/$(TARGET)/src/libuv/test/test-thread.o \
$(obj).target/$(TARGET)/src/libuv/test/test-timer-again.o \
$(obj).target/$(TARGET)/src/libuv/test/test-timer.o \
$(obj).target/$(TARGET)/src/libuv/test/test-tty.o \
$(obj).target/$(TARGET)/src/libuv/test/test-udp-dgram-too-big.o \
$(obj).target/$(TARGET)/src/libuv/test/test-udp-ipv6.o \
+ $(obj).target/$(TARGET)/src/libuv/test/test-udp-options.o \
$(obj).target/$(TARGET)/src/libuv/test/test-udp-send-and-recv.o \
$(obj).target/$(TARGET)/src/libuv/test/test-udp-multicast-join.o \
+ $(obj).target/$(TARGET)/src/libuv/test/test-counters-init.o \
$(obj).target/$(TARGET)/src/libuv/test/runner-win.o
# Add to the list of files we specially track dependencies for.
# CFLAGS et al overrides must be target-local.
# See "Target-specific Variable Values" in the GNU Make manual.
$(OBJS): TOOLSET := $(TOOLSET)
-$(OBJS): GYP_CFLAGS := $(DEFS_$(BUILDTYPE)) $(INCS_$(BUILDTYPE)) $(CFLAGS_$(BUILDTYPE)) $(CFLAGS_C_$(BUILDTYPE))
-$(OBJS): GYP_CXXFLAGS := $(DEFS_$(BUILDTYPE)) $(INCS_$(BUILDTYPE)) $(CFLAGS_$(BUILDTYPE)) $(CFLAGS_CC_$(BUILDTYPE))
+$(OBJS): GYP_CFLAGS := $(DEFS_$(BUILDTYPE)) $(INCS_$(BUILDTYPE)) $(CFLAGS_$(BUILDTYPE)) $(CFLAGS_C_$(BUILDTYPE))
+$(OBJS): GYP_CXXFLAGS := $(DEFS_$(BUILDTYPE)) $(INCS_$(BUILDTYPE)) $(CFLAGS_$(BUILDTYPE)) $(CFLAGS_CC_$(BUILDTYPE))
# Suffix rules, putting all outputs into $(obj).
# End of this set of suffix rules
### Rules for final target.
-LDFLAGS_Default :=
+LDFLAGS_Debug :=
+
+LDFLAGS_Release :=
LIBS := ws2_32.lib \
- -lws2_32.lib
+ -lws2_32.lib \
+ -lpsapi.lib \
+ -liphlpapi.lib
$(builddir)/run-tests: GYP_LDFLAGS := $(LDFLAGS_$(BUILDTYPE))
$(builddir)/run-tests: LIBS := $(LIBS)
TOOLSET := target
TARGET := uv
-DEFS_Default := '-DHAVE_CONFIG_H' \
- '-D_WIN32_WINNT=0x0502' \
+DEFS_Debug := '-DWIN32' \
+ '-D_CRT_SECURE_NO_DEPRECATE' \
+ '-D_CRT_NONSTDC_NO_DEPRECATE' \
+ '-DHAVE_CONFIG_H' \
+ '-D_WIN32_WINNT=0x0600' \
'-DEIO_STACKSIZE=262144' \
- '-D_GNU_SOURCE'
+ '-D_GNU_SOURCE' \
+ '-DDEBUG' \
+ '-D_DEBUG'
# Flags passed to all source files.
-CFLAGS_Default :=
+CFLAGS_Debug := -g \
+ -O0
# Flags passed to only C files.
-CFLAGS_C_Default :=
+CFLAGS_C_Debug :=
# Flags passed to only C++ files.
-CFLAGS_CC_Default :=
+CFLAGS_CC_Debug :=
-INCS_Default := -I$(srcdir)/src/libuv/include \
+INCS_Debug := -I$(srcdir)/src/libuv/include \
+ -I$(srcdir)/src/libuv/include/uv-private \
+ -I$(srcdir)/src/libuv/src \
+ -I$(srcdir)/src/libuv/src/ares/config_win32
+
+DEFS_Release := '-DWIN32' \
+ '-D_CRT_SECURE_NO_DEPRECATE' \
+ '-D_CRT_NONSTDC_NO_DEPRECATE' \
+ '-DHAVE_CONFIG_H' \
+ '-D_WIN32_WINNT=0x0600' \
+ '-DEIO_STACKSIZE=262144' \
+ '-D_GNU_SOURCE' \
+ '-DNDEBUG'
+
+# Flags passed to all source files.
+CFLAGS_Release := -O3 \
+ -fomit-frame-pointer \
+ -fdata-sections \
+ -ffunction-sections
+
+# Flags passed to only C files.
+CFLAGS_C_Release :=
+
+# Flags passed to only C++ files.
+CFLAGS_CC_Release :=
+
+INCS_Release := -I$(srcdir)/src/libuv/include \
-I$(srcdir)/src/libuv/include/uv-private \
-I$(srcdir)/src/libuv/src \
-I$(srcdir)/src/libuv/src/ares/config_win32
$(obj).target/$(TARGET)/src/libuv/src/win/handle.o \
$(obj).target/$(TARGET)/src/libuv/src/win/loop-watcher.o \
$(obj).target/$(TARGET)/src/libuv/src/win/pipe.o \
+ $(obj).target/$(TARGET)/src/libuv/src/win/thread.o \
$(obj).target/$(TARGET)/src/libuv/src/win/process.o \
$(obj).target/$(TARGET)/src/libuv/src/win/req.o \
$(obj).target/$(TARGET)/src/libuv/src/win/stream.o \
$(obj).target/$(TARGET)/src/libuv/src/win/tcp.o \
$(obj).target/$(TARGET)/src/libuv/src/win/tty.o \
$(obj).target/$(TARGET)/src/libuv/src/win/threadpool.o \
- $(obj).target/$(TARGET)/src/libuv/src/win/threads.o \
$(obj).target/$(TARGET)/src/libuv/src/win/timer.o \
$(obj).target/$(TARGET)/src/libuv/src/win/udp.o \
$(obj).target/$(TARGET)/src/libuv/src/win/util.o \
# CFLAGS et al overrides must be target-local.
# See "Target-specific Variable Values" in the GNU Make manual.
$(OBJS): TOOLSET := $(TOOLSET)
-$(OBJS): GYP_CFLAGS := $(DEFS_$(BUILDTYPE)) $(INCS_$(BUILDTYPE)) $(CFLAGS_$(BUILDTYPE)) $(CFLAGS_C_$(BUILDTYPE))
-$(OBJS): GYP_CXXFLAGS := $(DEFS_$(BUILDTYPE)) $(INCS_$(BUILDTYPE)) $(CFLAGS_$(BUILDTYPE)) $(CFLAGS_CC_$(BUILDTYPE))
+$(OBJS): GYP_CFLAGS := $(DEFS_$(BUILDTYPE)) $(INCS_$(BUILDTYPE)) $(CFLAGS_$(BUILDTYPE)) $(CFLAGS_C_$(BUILDTYPE))
+$(OBJS): GYP_CXXFLAGS := $(DEFS_$(BUILDTYPE)) $(INCS_$(BUILDTYPE)) $(CFLAGS_$(BUILDTYPE)) $(CFLAGS_CC_$(BUILDTYPE))
# Suffix rules, putting all outputs into $(obj).
# End of this set of suffix rules
### Rules for final target.
-LDFLAGS_Default :=
+LDFLAGS_Debug :=
+
+LDFLAGS_Release :=
LIBS :=
--- /dev/null
+# This file is generated by gyp; do not edit.
+
+TOOLSET := target
+TARGET := uv
+DEFS_Debug := '-DWIN32' \
+ '-D_CRT_SECURE_NO_DEPRECATE' \
+ '-D_CRT_NONSTDC_NO_DEPRECATE' \
+ '-DHAVE_CONFIG_H' \
+ '-D_WIN32_WINNT=0x0600' \
+ '-DEIO_STACKSIZE=262144' \
+ '-D_GNU_SOURCE' \
+ '-DDEBUG' \
+ '-D_DEBUG'
+
+# Flags passed to all source files.
+CFLAGS_Debug := -g \
+ -O0
+
+# Flags passed to only C files.
+CFLAGS_C_Debug :=
+
+# Flags passed to only C++ files.
+CFLAGS_CC_Debug :=
+
+INCS_Debug := -I$(srcdir)\src\libuv\include \
+ -I$(srcdir)\src\libuv\include\uv-private \
+ -I$(srcdir)\src\libuv\src \
+ -I$(srcdir)\src\libuv\src\ares\config_win32
+
+DEFS_Release := '-DWIN32' \
+ '-D_CRT_SECURE_NO_DEPRECATE' \
+ '-D_CRT_NONSTDC_NO_DEPRECATE' \
+ '-DHAVE_CONFIG_H' \
+ '-D_WIN32_WINNT=0x0600' \
+ '-DEIO_STACKSIZE=262144' \
+ '-D_GNU_SOURCE' \
+ '-DNDEBUG'
+
+# Flags passed to all source files.
+CFLAGS_Release := -O3 \
+ -fomit-frame-pointer \
+ -fdata-sections \
+ -ffunction-sections
+
+# Flags passed to only C files.
+CFLAGS_C_Release :=
+
+# Flags passed to only C++ files.
+CFLAGS_CC_Release :=
+
+INCS_Release := -I$(srcdir)\src\libuv\include \
+ -I$(srcdir)\src\libuv\include\uv-private \
+ -I$(srcdir)\src\libuv\src \
+ -I$(srcdir)\src\libuv\src\ares\config_win32
+
+OBJS := $(obj).target\$(TARGET)\src\libuv\src\uv-common.o \
+ $(obj).target\$(TARGET)\src\libuv\src\ares\ares_cancel.o \
+ $(obj).target\$(TARGET)\src\libuv\src\ares\ares__close_sockets.o \
+ $(obj).target\$(TARGET)\src\libuv\src\ares\ares_data.o \
+ $(obj).target\$(TARGET)\src\libuv\src\ares\ares_destroy.o \
+ $(obj).target\$(TARGET)\src\libuv\src\ares\ares_expand_name.o \
+ $(obj).target\$(TARGET)\src\libuv\src\ares\ares_expand_string.o \
+ $(obj).target\$(TARGET)\src\libuv\src\ares\ares_fds.o \
+ $(obj).target\$(TARGET)\src\libuv\src\ares\ares_free_hostent.o \
+ $(obj).target\$(TARGET)\src\libuv\src\ares\ares_free_string.o \
+ $(obj).target\$(TARGET)\src\libuv\src\ares\ares_gethostbyaddr.o \
+ $(obj).target\$(TARGET)\src\libuv\src\ares\ares_gethostbyname.o \
+ $(obj).target\$(TARGET)\src\libuv\src\ares\ares__get_hostent.o \
+ $(obj).target\$(TARGET)\src\libuv\src\ares\ares_getnameinfo.o \
+ $(obj).target\$(TARGET)\src\libuv\src\ares\ares_getopt.o \
+ $(obj).target\$(TARGET)\src\libuv\src\ares\ares_getsock.o \
+ $(obj).target\$(TARGET)\src\libuv\src\ares\ares_init.o \
+ $(obj).target\$(TARGET)\src\libuv\src\ares\ares_library_init.o \
+ $(obj).target\$(TARGET)\src\libuv\src\ares\ares_llist.o \
+ $(obj).target\$(TARGET)\src\libuv\src\ares\ares_mkquery.o \
+ $(obj).target\$(TARGET)\src\libuv\src\ares\ares_nowarn.o \
+ $(obj).target\$(TARGET)\src\libuv\src\ares\ares_options.o \
+ $(obj).target\$(TARGET)\src\libuv\src\ares\ares_parse_aaaa_reply.o \
+ $(obj).target\$(TARGET)\src\libuv\src\ares\ares_parse_a_reply.o \
+ $(obj).target\$(TARGET)\src\libuv\src\ares\ares_parse_mx_reply.o \
+ $(obj).target\$(TARGET)\src\libuv\src\ares\ares_parse_ns_reply.o \
+ $(obj).target\$(TARGET)\src\libuv\src\ares\ares_parse_ptr_reply.o \
+ $(obj).target\$(TARGET)\src\libuv\src\ares\ares_parse_srv_reply.o \
+ $(obj).target\$(TARGET)\src\libuv\src\ares\ares_parse_txt_reply.o \
+ $(obj).target\$(TARGET)\src\libuv\src\ares\ares_process.o \
+ $(obj).target\$(TARGET)\src\libuv\src\ares\ares_query.o \
+ $(obj).target\$(TARGET)\src\libuv\src\ares\ares__read_line.o \
+ $(obj).target\$(TARGET)\src\libuv\src\ares\ares_search.o \
+ $(obj).target\$(TARGET)\src\libuv\src\ares\ares_send.o \
+ $(obj).target\$(TARGET)\src\libuv\src\ares\ares_strcasecmp.o \
+ $(obj).target\$(TARGET)\src\libuv\src\ares\ares_strdup.o \
+ $(obj).target\$(TARGET)\src\libuv\src\ares\ares_strerror.o \
+ $(obj).target\$(TARGET)\src\libuv\src\ares\ares_timeout.o \
+ $(obj).target\$(TARGET)\src\libuv\src\ares\ares__timeval.o \
+ $(obj).target\$(TARGET)\src\libuv\src\ares\ares_version.o \
+ $(obj).target\$(TARGET)\src\libuv\src\ares\ares_writev.o \
+ $(obj).target\$(TARGET)\src\libuv\src\ares\bitncmp.o \
+ $(obj).target\$(TARGET)\src\libuv\src\ares\inet_net_pton.o \
+ $(obj).target\$(TARGET)\src\libuv\src\ares\inet_ntop.o \
+ $(obj).target\$(TARGET)\src\libuv\src\ares\windows_port.o \
+ $(obj).target\$(TARGET)\src\libuv\src\ares\ares_getenv.o \
+ $(obj).target\$(TARGET)\src\libuv\src\ares\ares_platform.o \
+ $(obj).target\$(TARGET)\src\libuv\src\win\async.o \
+ $(obj).target\$(TARGET)\src\libuv\src\win\cares.o \
+ $(obj).target\$(TARGET)\src\libuv\src\win\core.o \
+ $(obj).target\$(TARGET)\src\libuv\src\win\dl.o \
+ $(obj).target\$(TARGET)\src\libuv\src\win\error.o \
+ $(obj).target\$(TARGET)\src\libuv\src\win\fs.o \
+ $(obj).target\$(TARGET)\src\libuv\src\win\fs-event.o \
+ $(obj).target\$(TARGET)\src\libuv\src\win\getaddrinfo.o \
+ $(obj).target\$(TARGET)\src\libuv\src\win\handle.o \
+ $(obj).target\$(TARGET)\src\libuv\src\win\loop-watcher.o \
+ $(obj).target\$(TARGET)\src\libuv\src\win\pipe.o \
+ $(obj).target\$(TARGET)\src\libuv\src\win\thread.o \
+ $(obj).target\$(TARGET)\src\libuv\src\win\process.o \
+ $(obj).target\$(TARGET)\src\libuv\src\win\req.o \
+ $(obj).target\$(TARGET)\src\libuv\src\win\stream.o \
+ $(obj).target\$(TARGET)\src\libuv\src\win\tcp.o \
+ $(obj).target\$(TARGET)\src\libuv\src\win\tty.o \
+ $(obj).target\$(TARGET)\src\libuv\src\win\threadpool.o \
+ $(obj).target\$(TARGET)\src\libuv\src\win\timer.o \
+ $(obj).target\$(TARGET)\src\libuv\src\win\udp.o \
+ $(obj).target\$(TARGET)\src\libuv\src\win\util.o \
+ $(obj).target\$(TARGET)\src\libuv\src\win\winapi.o \
+ $(obj).target\$(TARGET)\src\libuv\src\win\winsock.o
+
+# Add to the list of files we specially track dependencies for.
+all_deps += $(OBJS)
+
+# CFLAGS et al overrides must be target-local.
+# See "Target-specific Variable Values" in the GNU Make manual.
+$(OBJS): TOOLSET := $(TOOLSET)
+$(OBJS): GYP_CFLAGS := $(DEFS_$(BUILDTYPE)) $(INCS_$(BUILDTYPE)) $(CFLAGS_$(BUILDTYPE)) $(CFLAGS_C_$(BUILDTYPE))
+$(OBJS): GYP_CXXFLAGS := $(DEFS_$(BUILDTYPE)) $(INCS_$(BUILDTYPE)) $(CFLAGS_$(BUILDTYPE)) $(CFLAGS_CC_$(BUILDTYPE))
+
+# Suffix rules, putting all outputs into $(obj).
+
+$(obj).$(TOOLSET)\$(TARGET)\%.o: $(srcdir)\%.c FORCE_DO_CMD
+ @$(call do_cmd,cc,1)
+
+# Try building from generated source, too.
+
+$(obj).$(TOOLSET)\$(TARGET)\%.o: $(obj).$(TOOLSET)\%.c FORCE_DO_CMD
+ @$(call do_cmd,cc,1)
+
+$(obj).$(TOOLSET)\$(TARGET)\%.o: $(obj)\%.c FORCE_DO_CMD
+ @$(call do_cmd,cc,1)
+
+# End of this set of suffix rules
+### Rules for final target.
+LDFLAGS_Debug :=
+
+LDFLAGS_Release :=
+
+LIBS :=
+
+$(obj).target\src\libuv\libuv.a: GYP_LDFLAGS := $(LDFLAGS_$(BUILDTYPE))
+$(obj).target\src\libuv\libuv.a: LIBS := $(LIBS)
+$(obj).target\src\libuv\libuv.a: TOOLSET := $(TOOLSET)
+$(obj).target\src\libuv\libuv.a: $(OBJS) FORCE_DO_CMD
+ $(call do_cmd,alink)
+
+all_deps += $(obj).target\src\libuv\libuv.a
+# Add target alias
+.PHONY: uv
+uv: $(obj).target\src\libuv\libuv.a
+
+++ /dev/null
-# We borrow heavily from the kernel build setup, though we are simpler since
-# we don't have Kconfig tweaking settings on us.
-
-# The implicit make rules have it looking for RCS files, among other things.
-# We instead explicitly write all the rules we care about.
-# It's even quicker (saves ~200ms) to pass -r on the command line.
-MAKEFLAGS=-r
-
-# The source directory tree.
-srcdir := ../../../..
-
-# The name of the builddir.
-builddir_name ?= out
-
-# The V=1 flag on command line makes us verbosely print command lines.
-ifdef V
- quiet=
-else
- quiet=quiet_
-endif
-
-# Specify BUILDTYPE=Release on the command line for a release build.
-BUILDTYPE ?= Default
-
-# Directory all our build output goes into.
-# Note that this must be two directories beneath src/ for unit tests to pass,
-# as they reach into the src/ directory for data with relative paths.
-builddir ?= $(builddir_name)/$(BUILDTYPE)
-abs_builddir := $(abspath $(builddir))
-depsdir := $(builddir)/.deps
-
-# Object output directory.
-obj := $(builddir)/obj
-abs_obj := $(abspath $(obj))
-
-# We build up a list of every single one of the targets so we can slurp in the
-# generated dependency rule Makefiles in one pass.
-all_deps :=
-
-
-
-# C++ apps need to be linked with g++.
-#
-# Note: flock is used to seralize linking. Linking is a memory-intensive
-# process so running parallel links can often lead to thrashing. To disable
-# the serialization, override LINK via an envrionment variable as follows:
-#
-# export LINK=g++
-#
-# This will allow make to invoke N linker processes as specified in -jN.
-LINK ?= lockf $(builddir)/linker.lock $(CXX)
-
-CC.target ?= $(CC)
-CFLAGS.target ?= $(CFLAGS)
-CXX.target ?= $(CXX)
-CXXFLAGS.target ?= $(CXXFLAGS)
-LINK.target ?= $(LINK)
-LDFLAGS.target ?= $(LDFLAGS)
-AR.target ?= $(AR)
-ARFLAGS.target ?= crs
-
-# N.B.: the logic of which commands to run should match the computation done
-# in gyp's make.py where ARFLAGS.host etc. is computed.
-# TODO(evan): move all cross-compilation logic to gyp-time so we don't need
-# to replicate this environment fallback in make as well.
-CC.host ?= gcc
-CFLAGS.host ?=
-CXX.host ?= g++
-CXXFLAGS.host ?=
-LINK.host ?= g++
-LDFLAGS.host ?=
-AR.host ?= ar
-ARFLAGS.host := crs
-
-# Define a dir function that can handle spaces.
-# http://www.gnu.org/software/make/manual/make.html#Syntax-of-Functions
-# "leading spaces cannot appear in the text of the first argument as written.
-# These characters can be put into the argument value by variable substitution."
-empty :=
-space := $(empty) $(empty)
-
-# http://stackoverflow.com/questions/1189781/using-make-dir-or-notdir-on-a-path-with-spaces
-replace_spaces = $(subst $(space),?,$1)
-unreplace_spaces = $(subst ?,$(space),$1)
-dirx = $(call unreplace_spaces,$(dir $(call replace_spaces,$1)))
-
-# Flags to make gcc output dependency info. Note that you need to be
-# careful here to use the flags that ccache and distcc can understand.
-# We write to a dep file on the side first and then rename at the end
-# so we can't end up with a broken dep file.
-depfile = $(depsdir)/$(call replace_spaces,$@).d
-DEPFLAGS = -MMD -MF $(depfile).raw
-
-# We have to fixup the deps output in a few ways.
-# (1) the file output should mention the proper .o file.
-# ccache or distcc lose the path to the target, so we convert a rule of
-# the form:
-# foobar.o: DEP1 DEP2
-# into
-# path/to/foobar.o: DEP1 DEP2
-# (2) we want missing files not to cause us to fail to build.
-# We want to rewrite
-# foobar.o: DEP1 DEP2 \
-# DEP3
-# to
-# DEP1:
-# DEP2:
-# DEP3:
-# so if the files are missing, they're just considered phony rules.
-# We have to do some pretty insane escaping to get those backslashes
-# and dollar signs past make, the shell, and sed at the same time.
-# Doesn't work with spaces, but that's fine: .d files have spaces in
-# their names replaced with other characters.
-define fixup_dep
-# The depfile may not exist if the input file didn't have any #includes.
-touch $(depfile).raw
-# Fixup path as in (1).
-sed -e "s|^$(notdir $@)|$@|" $(depfile).raw >> $(depfile)
-# Add extra rules as in (2).
-# We remove slashes and replace spaces with new lines;
-# remove blank lines;
-# delete the first line and append a colon to the remaining lines.
-sed -e 's|\\||' -e 'y| |\n|' $(depfile).raw |\
- grep -v '^$$' |\
- sed -e 1d -e 's|$$|:|' \
- >> $(depfile)
-rm $(depfile).raw
-endef
-
-# Command definitions:
-# - cmd_foo is the actual command to run;
-# - quiet_cmd_foo is the brief-output summary of the command.
-
-quiet_cmd_cc = CC($(TOOLSET)) $@
-cmd_cc = $(CC.$(TOOLSET)) $(GYP_CFLAGS) $(DEPFLAGS) $(CFLAGS.$(TOOLSET)) -c -o $@ $<
-
-quiet_cmd_cxx = CXX($(TOOLSET)) $@
-cmd_cxx = $(CXX.$(TOOLSET)) $(GYP_CXXFLAGS) $(DEPFLAGS) $(CXXFLAGS.$(TOOLSET)) -c -o $@ $<
-
-quiet_cmd_touch = TOUCH $@
-cmd_touch = touch $@
-
-quiet_cmd_copy = COPY $@
-# send stderr to /dev/null to ignore messages when linking directories.
-cmd_copy = ln -f "$<" "$@" 2>/dev/null || (rm -rf "$@" && cp -af "$<" "$@")
-
-quiet_cmd_alink = AR($(TOOLSET)) $@
-cmd_alink = rm -f $@ && $(AR.$(TOOLSET)) $(ARFLAGS.$(TOOLSET)) $@ $(filter %.o,$^)
-
-# Due to circular dependencies between libraries :(, we wrap the
-# special "figure out circular dependencies" flags around the entire
-# input list during linking.
-quiet_cmd_link = LINK($(TOOLSET)) $@
-cmd_link = $(LINK.$(TOOLSET)) $(GYP_LDFLAGS) $(LDFLAGS.$(TOOLSET)) -o $@ -Wl,--start-group $(LD_INPUTS) -Wl,--end-group $(LIBS)
-
-# We support two kinds of shared objects (.so):
-# 1) shared_library, which is just bundling together many dependent libraries
-# into a link line.
-# 2) loadable_module, which is generating a module intended for dlopen().
-#
-# They differ only slightly:
-# In the former case, we want to package all dependent code into the .so.
-# In the latter case, we want to package just the API exposed by the
-# outermost module.
-# This means shared_library uses --whole-archive, while loadable_module doesn't.
-# (Note that --whole-archive is incompatible with the --start-group used in
-# normal linking.)
-
-# Other shared-object link notes:
-# - Set SONAME to the library filename so our binaries don't reference
-# the local, absolute paths used on the link command-line.
-quiet_cmd_solink = SOLINK($(TOOLSET)) $@
-cmd_solink = $(LINK.$(TOOLSET)) -shared $(GYP_LDFLAGS) $(LDFLAGS.$(TOOLSET)) -Wl,-soname=$(@F) -o $@ -Wl,--whole-archive $(LD_INPUTS) -Wl,--no-whole-archive $(LIBS)
-
-quiet_cmd_solink_module = SOLINK_MODULE($(TOOLSET)) $@
-cmd_solink_module = $(LINK.$(TOOLSET)) -shared $(GYP_LDFLAGS) $(LDFLAGS.$(TOOLSET)) -Wl,-soname=$(@F) -o $@ -Wl,--start-group $(filter-out FORCE_DO_CMD, $^) -Wl,--end-group $(LIBS)
-
-
-# Define an escape_quotes function to escape single quotes.
-# This allows us to handle quotes properly as long as we always use
-# use single quotes and escape_quotes.
-escape_quotes = $(subst ','\'',$(1))
-# This comment is here just to include a ' to unconfuse syntax highlighting.
-# Define an escape_vars function to escape '$' variable syntax.
-# This allows us to read/write command lines with shell variables (e.g.
-# $LD_LIBRARY_PATH), without triggering make substitution.
-escape_vars = $(subst $$,$$$$,$(1))
-# Helper that expands to a shell command to echo a string exactly as it is in
-# make. This uses printf instead of echo because printf's behaviour with respect
-# to escape sequences is more portable than echo's across different shells
-# (e.g., dash, bash).
-exact_echo = printf '%s\n' '$(call escape_quotes,$(1))'
-
-# Helper to compare the command we're about to run against the command
-# we logged the last time we ran the command. Produces an empty
-# string (false) when the commands match.
-# Tricky point: Make has no string-equality test function.
-# The kernel uses the following, but it seems like it would have false
-# positives, where one string reordered its arguments.
-# arg_check = $(strip $(filter-out $(cmd_$(1)), $(cmd_$@)) \
-# $(filter-out $(cmd_$@), $(cmd_$(1))))
-# We instead substitute each for the empty string into the other, and
-# say they're equal if both substitutions produce the empty string.
-# .d files contain ? instead of spaces, take that into account.
-command_changed = $(or $(subst $(cmd_$(1)),,$(cmd_$(call replace_spaces,$@))),\
- $(subst $(cmd_$(call replace_spaces,$@)),,$(cmd_$(1))))
-
-# Helper that is non-empty when a prerequisite changes.
-# Normally make does this implicitly, but we force rules to always run
-# so we can check their command lines.
-# $? -- new prerequisites
-# $| -- order-only dependencies
-prereq_changed = $(filter-out FORCE_DO_CMD,$(filter-out $|,$?))
-
-# Helper that executes all postbuilds, and deletes the output file when done
-# if any of the postbuilds failed.
-define do_postbuilds
- @E=0;\
- for p in $(POSTBUILDS); do\
- eval $$p;\
- F=$$?;\
- if [ $$F -ne 0 ]; then\
- E=$$F;\
- fi;\
- done;\
- if [ $$E -ne 0 ]; then\
- rm -rf "$@";\
- exit $$E;\
- fi
-endef
-
-# do_cmd: run a command via the above cmd_foo names, if necessary.
-# Should always run for a given target to handle command-line changes.
-# Second argument, if non-zero, makes it do asm/C/C++ dependency munging.
-# Third argument, if non-zero, makes it do POSTBUILDS processing.
-# Note: We intentionally do NOT call dirx for depfile, since it contains ? for
-# spaces already and dirx strips the ? characters.
-define do_cmd
-$(if $(or $(command_changed),$(prereq_changed)),
- @$(call exact_echo, $($(quiet)cmd_$(1)))
- @mkdir -p "$(call dirx,$@)" "$(dir $(depfile))"
- $(if $(findstring flock,$(word 1,$(cmd_$1))),
- @$(cmd_$(1))
- @echo " $(quiet_cmd_$(1)): Finished",
- @$(cmd_$(1))
- )
- @$(call exact_echo,$(call escape_vars,cmd_$(call replace_spaces,$@) := $(cmd_$(1)))) > $(depfile)
- @$(if $(2),$(fixup_dep))
- $(if $(and $(3), $(POSTBUILDS)),
- $(call do_postbuilds)
- )
-)
-endef
-
-# Declare the "all" target first so it is the default,
-# even though we don't have the deps yet.
-.PHONY: all
-all:
-
-# Use FORCE_DO_CMD to force a target to run. Should be coupled with
-# do_cmd.
-.PHONY: FORCE_DO_CMD
-FORCE_DO_CMD:
-
-TOOLSET := target
-# Suffix rules, putting all outputs into $(obj).
-$(obj).$(TOOLSET)/%.o: $(srcdir)/%.c FORCE_DO_CMD
- @$(call do_cmd,cc,1)
-$(obj).$(TOOLSET)/%.o: $(srcdir)/%.cc FORCE_DO_CMD
- @$(call do_cmd,cxx,1)
-$(obj).$(TOOLSET)/%.o: $(srcdir)/%.cpp FORCE_DO_CMD
- @$(call do_cmd,cxx,1)
-$(obj).$(TOOLSET)/%.o: $(srcdir)/%.cxx FORCE_DO_CMD
- @$(call do_cmd,cxx,1)
-$(obj).$(TOOLSET)/%.o: $(srcdir)/%.S FORCE_DO_CMD
- @$(call do_cmd,cc,1)
-$(obj).$(TOOLSET)/%.o: $(srcdir)/%.s FORCE_DO_CMD
- @$(call do_cmd,cc,1)
-
-# Try building from generated source, too.
-$(obj).$(TOOLSET)/%.o: $(obj).$(TOOLSET)/%.c FORCE_DO_CMD
- @$(call do_cmd,cc,1)
-$(obj).$(TOOLSET)/%.o: $(obj).$(TOOLSET)/%.cc FORCE_DO_CMD
- @$(call do_cmd,cxx,1)
-$(obj).$(TOOLSET)/%.o: $(obj).$(TOOLSET)/%.cpp FORCE_DO_CMD
- @$(call do_cmd,cxx,1)
-$(obj).$(TOOLSET)/%.o: $(obj).$(TOOLSET)/%.cxx FORCE_DO_CMD
- @$(call do_cmd,cxx,1)
-$(obj).$(TOOLSET)/%.o: $(obj).$(TOOLSET)/%.S FORCE_DO_CMD
- @$(call do_cmd,cc,1)
-$(obj).$(TOOLSET)/%.o: $(obj).$(TOOLSET)/%.s FORCE_DO_CMD
- @$(call do_cmd,cc,1)
-
-$(obj).$(TOOLSET)/%.o: $(obj)/%.c FORCE_DO_CMD
- @$(call do_cmd,cc,1)
-$(obj).$(TOOLSET)/%.o: $(obj)/%.cc FORCE_DO_CMD
- @$(call do_cmd,cxx,1)
-$(obj).$(TOOLSET)/%.o: $(obj)/%.cpp FORCE_DO_CMD
- @$(call do_cmd,cxx,1)
-$(obj).$(TOOLSET)/%.o: $(obj)/%.cxx FORCE_DO_CMD
- @$(call do_cmd,cxx,1)
-$(obj).$(TOOLSET)/%.o: $(obj)/%.S FORCE_DO_CMD
- @$(call do_cmd,cc,1)
-$(obj).$(TOOLSET)/%.o: $(obj)/%.s FORCE_DO_CMD
- @$(call do_cmd,cc,1)
-
-
-ifeq ($(strip $(foreach prefix,$(NO_LOAD),\
- $(findstring $(join ^,$(prefix)),\
- $(join ^,src/libuv/run-benchmarks.target.mk)))),)
- include src/libuv/run-benchmarks.target.mk
-endif
-ifeq ($(strip $(foreach prefix,$(NO_LOAD),\
- $(findstring $(join ^,$(prefix)),\
- $(join ^,src/libuv/run-tests.target.mk)))),)
- include src/libuv/run-tests.target.mk
-endif
-ifeq ($(strip $(foreach prefix,$(NO_LOAD),\
- $(findstring $(join ^,$(prefix)),\
- $(join ^,src/libuv/uv.target.mk)))),)
- include src/libuv/uv.target.mk
-endif
-
-quiet_cmd_regen_makefile = ACTION Regenerating $@
-cmd_regen_makefile = ./src/libuv/build/gyp/gyp -fmake --ignore-environment "--toplevel-dir=." "--depth=." "--generator-output=mk/libuv/x86_64/unix" "-Dlibrary=static_library" "-Dtarget_arch=x86_64" "-DOS=freebsd" src/libuv/uv.gyp
-Makefile: $(srcdir)/src/libuv/uv.gyp
-# $(call do_cmd,regen_makefile)
-
-# "all" is a concatenation of the "all" targets from all the included
-# sub-makefiles. This is just here to clarify.
-all:
-
-# Add in dependency-tracking rules. $(all_deps) is the list of every single
-# target in our tree. Only consider the ones with .d (dependency) info:
-d_files := $(wildcard $(foreach f,$(all_deps),$(depsdir)/$(f).d))
-ifneq ($(d_files),)
- # Rather than include each individual .d file, concatenate them into a
- # single file which make is able to load faster. We split this into
- # commands that take 1000 files at a time to avoid overflowing the
- # command line.
- $(shell cat $(wordlist 1,1000,$(d_files)) > $(depsdir)/all.deps)
-
- ifneq ($(word 1001,$(d_files)),)
- $(error Found unprocessed dependency files (gyp didn't generate enough rules!))
- endif
-
- # make looks for ways to re-generate included makefiles, but in our case, we
- # don't have a direct way. Explicitly telling make that it has nothing to do
- # for them makes it go faster.
- $(depsdir)/all.deps: ;
-
- include $(depsdir)/all.deps
-endif
+++ /dev/null
-# This file is generated by gyp; do not edit.
-
-TOOLSET := target
-TARGET := run-benchmarks
-DEFS_Default := '-D_LARGEFILE_SOURCE' \
- '-D_FILE_OFFSET_BITS=64' \
- '-D_GNU_SOURCE' \
- '-DEIO_STACKSIZE=262144'
-
-# Flags passed to all source files.
-CFLAGS_Default := -pthread
-
-# Flags passed to only C files.
-CFLAGS_C_Default :=
-
-# Flags passed to only C++ files.
-CFLAGS_CC_Default :=
-
-INCS_Default := -I$(srcdir)/src/libuv/include
-
-OBJS := $(obj).target/$(TARGET)/src/libuv/test/benchmark-ares.o \
- $(obj).target/$(TARGET)/src/libuv/test/benchmark-getaddrinfo.o \
- $(obj).target/$(TARGET)/src/libuv/test/benchmark-ping-pongs.o \
- $(obj).target/$(TARGET)/src/libuv/test/benchmark-pound.o \
- $(obj).target/$(TARGET)/src/libuv/test/benchmark-pump.o \
- $(obj).target/$(TARGET)/src/libuv/test/benchmark-sizes.o \
- $(obj).target/$(TARGET)/src/libuv/test/benchmark-spawn.o \
- $(obj).target/$(TARGET)/src/libuv/test/benchmark-tcp-write-batch.o \
- $(obj).target/$(TARGET)/src/libuv/test/benchmark-udp-packet-storm.o \
- $(obj).target/$(TARGET)/src/libuv/test/dns-server.o \
- $(obj).target/$(TARGET)/src/libuv/test/echo-server.o \
- $(obj).target/$(TARGET)/src/libuv/test/blackhole-server.o \
- $(obj).target/$(TARGET)/src/libuv/test/run-benchmarks.o \
- $(obj).target/$(TARGET)/src/libuv/test/runner.o \
- $(obj).target/$(TARGET)/src/libuv/test/runner-unix.o
-
-# Add to the list of files we specially track dependencies for.
-all_deps += $(OBJS)
-
-# Make sure our dependencies are built before any of us.
-$(OBJS): | $(obj).target/src/libuv/libuv.a
-
-# CFLAGS et al overrides must be target-local.
-# See "Target-specific Variable Values" in the GNU Make manual.
-$(OBJS): TOOLSET := $(TOOLSET)
-$(OBJS): GYP_CFLAGS := $(DEFS_$(BUILDTYPE)) $(INCS_$(BUILDTYPE)) $(CFLAGS_$(BUILDTYPE)) $(CFLAGS_C_$(BUILDTYPE))
-$(OBJS): GYP_CXXFLAGS := $(DEFS_$(BUILDTYPE)) $(INCS_$(BUILDTYPE)) $(CFLAGS_$(BUILDTYPE)) $(CFLAGS_CC_$(BUILDTYPE))
-
-# Suffix rules, putting all outputs into $(obj).
-
-$(obj).$(TOOLSET)/$(TARGET)/%.o: $(srcdir)/%.c FORCE_DO_CMD
- @$(call do_cmd,cc,1)
-
-# Try building from generated source, too.
-
-$(obj).$(TOOLSET)/$(TARGET)/%.o: $(obj).$(TOOLSET)/%.c FORCE_DO_CMD
- @$(call do_cmd,cc,1)
-
-$(obj).$(TOOLSET)/$(TARGET)/%.o: $(obj)/%.c FORCE_DO_CMD
- @$(call do_cmd,cc,1)
-
-# End of this set of suffix rules
-### Rules for final target.
-LDFLAGS_Default :=
-
-LIBS :=
-
-$(builddir)/run-benchmarks: GYP_LDFLAGS := $(LDFLAGS_$(BUILDTYPE))
-$(builddir)/run-benchmarks: LIBS := $(LIBS)
-$(builddir)/run-benchmarks: LD_INPUTS := $(OBJS) $(obj).target/src/libuv/libuv.a
-$(builddir)/run-benchmarks: TOOLSET := $(TOOLSET)
-$(builddir)/run-benchmarks: $(OBJS) $(obj).target/src/libuv/libuv.a FORCE_DO_CMD
- $(call do_cmd,link)
-
-all_deps += $(builddir)/run-benchmarks
-# Add target alias
-.PHONY: run-benchmarks
-run-benchmarks: $(builddir)/run-benchmarks
-
-# Add executable to "all" target.
-.PHONY: all
-all: $(builddir)/run-benchmarks
-
+++ /dev/null
-# This file is generated by gyp; do not edit.
-
-TOOLSET := target
-TARGET := run-tests
-DEFS_Default := '-D_LARGEFILE_SOURCE' \
- '-D_FILE_OFFSET_BITS=64' \
- '-D_GNU_SOURCE' \
- '-DEIO_STACKSIZE=262144'
-
-# Flags passed to all source files.
-CFLAGS_Default := -pthread
-
-# Flags passed to only C files.
-CFLAGS_C_Default :=
-
-# Flags passed to only C++ files.
-CFLAGS_CC_Default :=
-
-INCS_Default := -I$(srcdir)/src/libuv/include
-
-OBJS := $(obj).target/$(TARGET)/src/libuv/test/blackhole-server.o \
- $(obj).target/$(TARGET)/src/libuv/test/echo-server.o \
- $(obj).target/$(TARGET)/src/libuv/test/run-tests.o \
- $(obj).target/$(TARGET)/src/libuv/test/runner.o \
- $(obj).target/$(TARGET)/src/libuv/test/test-get-loadavg.o \
- $(obj).target/$(TARGET)/src/libuv/test/test-async.o \
- $(obj).target/$(TARGET)/src/libuv/test/test-error.o \
- $(obj).target/$(TARGET)/src/libuv/test/test-callback-stack.o \
- $(obj).target/$(TARGET)/src/libuv/test/test-connection-fail.o \
- $(obj).target/$(TARGET)/src/libuv/test/test-delayed-accept.o \
- $(obj).target/$(TARGET)/src/libuv/test/test-fail-always.o \
- $(obj).target/$(TARGET)/src/libuv/test/test-fs.o \
- $(obj).target/$(TARGET)/src/libuv/test/test-fs-event.o \
- $(obj).target/$(TARGET)/src/libuv/test/test-get-currentexe.o \
- $(obj).target/$(TARGET)/src/libuv/test/test-get-memory.o \
- $(obj).target/$(TARGET)/src/libuv/test/test-getaddrinfo.o \
- $(obj).target/$(TARGET)/src/libuv/test/test-gethostbyname.o \
- $(obj).target/$(TARGET)/src/libuv/test/test-getsockname.o \
- $(obj).target/$(TARGET)/src/libuv/test/test-hrtime.o \
- $(obj).target/$(TARGET)/src/libuv/test/test-idle.o \
- $(obj).target/$(TARGET)/src/libuv/test/test-ipc.o \
- $(obj).target/$(TARGET)/src/libuv/test/test-loop-handles.o \
- $(obj).target/$(TARGET)/src/libuv/test/test-multiple-listen.o \
- $(obj).target/$(TARGET)/src/libuv/test/test-pass-always.o \
- $(obj).target/$(TARGET)/src/libuv/test/test-ping-pong.o \
- $(obj).target/$(TARGET)/src/libuv/test/test-pipe-bind-error.o \
- $(obj).target/$(TARGET)/src/libuv/test/test-pipe-connect-error.o \
- $(obj).target/$(TARGET)/src/libuv/test/test-ref.o \
- $(obj).target/$(TARGET)/src/libuv/test/test-shutdown-eof.o \
- $(obj).target/$(TARGET)/src/libuv/test/test-spawn.o \
- $(obj).target/$(TARGET)/src/libuv/test/test-stdio-over-pipes.o \
- $(obj).target/$(TARGET)/src/libuv/test/test-tcp-bind-error.o \
- $(obj).target/$(TARGET)/src/libuv/test/test-tcp-bind6-error.o \
- $(obj).target/$(TARGET)/src/libuv/test/test-tcp-close.o \
- $(obj).target/$(TARGET)/src/libuv/test/test-tcp-flags.o \
- $(obj).target/$(TARGET)/src/libuv/test/test-tcp-connect-error.o \
- $(obj).target/$(TARGET)/src/libuv/test/test-tcp-connect6-error.o \
- $(obj).target/$(TARGET)/src/libuv/test/test-tcp-write-error.o \
- $(obj).target/$(TARGET)/src/libuv/test/test-tcp-write-to-half-open-connection.o \
- $(obj).target/$(TARGET)/src/libuv/test/test-tcp-writealot.o \
- $(obj).target/$(TARGET)/src/libuv/test/test-threadpool.o \
- $(obj).target/$(TARGET)/src/libuv/test/test-timer-again.o \
- $(obj).target/$(TARGET)/src/libuv/test/test-timer.o \
- $(obj).target/$(TARGET)/src/libuv/test/test-tty.o \
- $(obj).target/$(TARGET)/src/libuv/test/test-udp-dgram-too-big.o \
- $(obj).target/$(TARGET)/src/libuv/test/test-udp-ipv6.o \
- $(obj).target/$(TARGET)/src/libuv/test/test-udp-send-and-recv.o \
- $(obj).target/$(TARGET)/src/libuv/test/test-udp-multicast-join.o \
- $(obj).target/$(TARGET)/src/libuv/test/runner-unix.o
-
-# Add to the list of files we specially track dependencies for.
-all_deps += $(OBJS)
-
-# Make sure our dependencies are built before any of us.
-$(OBJS): | $(obj).target/src/libuv/libuv.a
-
-# CFLAGS et al overrides must be target-local.
-# See "Target-specific Variable Values" in the GNU Make manual.
-$(OBJS): TOOLSET := $(TOOLSET)
-$(OBJS): GYP_CFLAGS := $(DEFS_$(BUILDTYPE)) $(INCS_$(BUILDTYPE)) $(CFLAGS_$(BUILDTYPE)) $(CFLAGS_C_$(BUILDTYPE))
-$(OBJS): GYP_CXXFLAGS := $(DEFS_$(BUILDTYPE)) $(INCS_$(BUILDTYPE)) $(CFLAGS_$(BUILDTYPE)) $(CFLAGS_CC_$(BUILDTYPE))
-
-# Suffix rules, putting all outputs into $(obj).
-
-$(obj).$(TOOLSET)/$(TARGET)/%.o: $(srcdir)/%.c FORCE_DO_CMD
- @$(call do_cmd,cc,1)
-
-# Try building from generated source, too.
-
-$(obj).$(TOOLSET)/$(TARGET)/%.o: $(obj).$(TOOLSET)/%.c FORCE_DO_CMD
- @$(call do_cmd,cc,1)
-
-$(obj).$(TOOLSET)/$(TARGET)/%.o: $(obj)/%.c FORCE_DO_CMD
- @$(call do_cmd,cc,1)
-
-# End of this set of suffix rules
-### Rules for final target.
-LDFLAGS_Default :=
-
-LIBS :=
-
-$(builddir)/run-tests: GYP_LDFLAGS := $(LDFLAGS_$(BUILDTYPE))
-$(builddir)/run-tests: LIBS := $(LIBS)
-$(builddir)/run-tests: LD_INPUTS := $(OBJS) $(obj).target/src/libuv/libuv.a
-$(builddir)/run-tests: TOOLSET := $(TOOLSET)
-$(builddir)/run-tests: $(OBJS) $(obj).target/src/libuv/libuv.a FORCE_DO_CMD
- $(call do_cmd,link)
-
-all_deps += $(builddir)/run-tests
-# Add target alias
-.PHONY: run-tests
-run-tests: $(builddir)/run-tests
-
-# Add executable to "all" target.
-.PHONY: all
-all: $(builddir)/run-tests
-
+++ /dev/null
-# This file is generated by gyp; do not edit.
-
-export builddir_name ?= mk/libuv/x86_64/unix/./src/libuv/out
-.PHONY: all
-all:
- $(MAKE) -C ../.. uv run-benchmarks run-tests
+++ /dev/null
-# This file is generated by gyp; do not edit.
-
-TOOLSET := target
-TARGET := uv
-DEFS_Default := '-D_LARGEFILE_SOURCE' \
- '-D_FILE_OFFSET_BITS=64' \
- '-D_GNU_SOURCE' \
- '-DEIO_STACKSIZE=262144' \
- '-DHAVE_CONFIG_H' \
- '-DEV_CONFIG_H="config_freebsd.h"' \
- '-DEIO_CONFIG_H="config_freebsd.h"'
-
-# Flags passed to all source files.
-CFLAGS_Default := -pthread \
- -g \
- --std=gnu89 \
- -pedantic \
- -Wall \
- -Wextra \
- -Wno-unused-parameter
-
-# Flags passed to only C files.
-CFLAGS_C_Default :=
-
-# Flags passed to only C++ files.
-CFLAGS_CC_Default :=
-
-INCS_Default := -I$(srcdir)/src/libuv/include \
- -I$(srcdir)/src/libuv/include/uv-private \
- -I$(srcdir)/src/libuv/src \
- -I$(srcdir)/src/libuv/src/unix/ev \
- -I$(srcdir)/src/libuv/src/ares/config_freebsd
-
-OBJS := $(obj).target/$(TARGET)/src/libuv/src/uv-common.o \
- $(obj).target/$(TARGET)/src/libuv/src/ares/ares_cancel.o \
- $(obj).target/$(TARGET)/src/libuv/src/ares/ares__close_sockets.o \
- $(obj).target/$(TARGET)/src/libuv/src/ares/ares_data.o \
- $(obj).target/$(TARGET)/src/libuv/src/ares/ares_destroy.o \
- $(obj).target/$(TARGET)/src/libuv/src/ares/ares_expand_name.o \
- $(obj).target/$(TARGET)/src/libuv/src/ares/ares_expand_string.o \
- $(obj).target/$(TARGET)/src/libuv/src/ares/ares_fds.o \
- $(obj).target/$(TARGET)/src/libuv/src/ares/ares_free_hostent.o \
- $(obj).target/$(TARGET)/src/libuv/src/ares/ares_free_string.o \
- $(obj).target/$(TARGET)/src/libuv/src/ares/ares_gethostbyaddr.o \
- $(obj).target/$(TARGET)/src/libuv/src/ares/ares_gethostbyname.o \
- $(obj).target/$(TARGET)/src/libuv/src/ares/ares__get_hostent.o \
- $(obj).target/$(TARGET)/src/libuv/src/ares/ares_getnameinfo.o \
- $(obj).target/$(TARGET)/src/libuv/src/ares/ares_getopt.o \
- $(obj).target/$(TARGET)/src/libuv/src/ares/ares_getsock.o \
- $(obj).target/$(TARGET)/src/libuv/src/ares/ares_init.o \
- $(obj).target/$(TARGET)/src/libuv/src/ares/ares_library_init.o \
- $(obj).target/$(TARGET)/src/libuv/src/ares/ares_llist.o \
- $(obj).target/$(TARGET)/src/libuv/src/ares/ares_mkquery.o \
- $(obj).target/$(TARGET)/src/libuv/src/ares/ares_nowarn.o \
- $(obj).target/$(TARGET)/src/libuv/src/ares/ares_options.o \
- $(obj).target/$(TARGET)/src/libuv/src/ares/ares_parse_aaaa_reply.o \
- $(obj).target/$(TARGET)/src/libuv/src/ares/ares_parse_a_reply.o \
- $(obj).target/$(TARGET)/src/libuv/src/ares/ares_parse_mx_reply.o \
- $(obj).target/$(TARGET)/src/libuv/src/ares/ares_parse_ns_reply.o \
- $(obj).target/$(TARGET)/src/libuv/src/ares/ares_parse_ptr_reply.o \
- $(obj).target/$(TARGET)/src/libuv/src/ares/ares_parse_srv_reply.o \
- $(obj).target/$(TARGET)/src/libuv/src/ares/ares_parse_txt_reply.o \
- $(obj).target/$(TARGET)/src/libuv/src/ares/ares_process.o \
- $(obj).target/$(TARGET)/src/libuv/src/ares/ares_query.o \
- $(obj).target/$(TARGET)/src/libuv/src/ares/ares__read_line.o \
- $(obj).target/$(TARGET)/src/libuv/src/ares/ares_search.o \
- $(obj).target/$(TARGET)/src/libuv/src/ares/ares_send.o \
- $(obj).target/$(TARGET)/src/libuv/src/ares/ares_strcasecmp.o \
- $(obj).target/$(TARGET)/src/libuv/src/ares/ares_strdup.o \
- $(obj).target/$(TARGET)/src/libuv/src/ares/ares_strerror.o \
- $(obj).target/$(TARGET)/src/libuv/src/ares/ares_timeout.o \
- $(obj).target/$(TARGET)/src/libuv/src/ares/ares__timeval.o \
- $(obj).target/$(TARGET)/src/libuv/src/ares/ares_version.o \
- $(obj).target/$(TARGET)/src/libuv/src/ares/ares_writev.o \
- $(obj).target/$(TARGET)/src/libuv/src/ares/bitncmp.o \
- $(obj).target/$(TARGET)/src/libuv/src/ares/inet_net_pton.o \
- $(obj).target/$(TARGET)/src/libuv/src/ares/inet_ntop.o \
- $(obj).target/$(TARGET)/src/libuv/src/ares/windows_port.o \
- $(obj).target/$(TARGET)/src/libuv/src/unix/core.o \
- $(obj).target/$(TARGET)/src/libuv/src/unix/uv-eio.o \
- $(obj).target/$(TARGET)/src/libuv/src/unix/fs.o \
- $(obj).target/$(TARGET)/src/libuv/src/unix/udp.o \
- $(obj).target/$(TARGET)/src/libuv/src/unix/tcp.o \
- $(obj).target/$(TARGET)/src/libuv/src/unix/pipe.o \
- $(obj).target/$(TARGET)/src/libuv/src/unix/tty.o \
- $(obj).target/$(TARGET)/src/libuv/src/unix/stream.o \
- $(obj).target/$(TARGET)/src/libuv/src/unix/cares.o \
- $(obj).target/$(TARGET)/src/libuv/src/unix/dl.o \
- $(obj).target/$(TARGET)/src/libuv/src/unix/error.o \
- $(obj).target/$(TARGET)/src/libuv/src/unix/process.o \
- $(obj).target/$(TARGET)/src/libuv/src/unix/eio/eio.o \
- $(obj).target/$(TARGET)/src/libuv/src/unix/ev/ev.o \
- $(obj).target/$(TARGET)/src/libuv/src/unix/freebsd.o \
- $(obj).target/$(TARGET)/src/libuv/src/unix/kqueue.o
-
-# Add to the list of files we specially track dependencies for.
-all_deps += $(OBJS)
-
-# CFLAGS et al overrides must be target-local.
-# See "Target-specific Variable Values" in the GNU Make manual.
-$(OBJS): TOOLSET := $(TOOLSET)
-$(OBJS): GYP_CFLAGS := $(DEFS_$(BUILDTYPE)) $(INCS_$(BUILDTYPE)) $(CFLAGS_$(BUILDTYPE)) $(CFLAGS_C_$(BUILDTYPE))
-$(OBJS): GYP_CXXFLAGS := $(DEFS_$(BUILDTYPE)) $(INCS_$(BUILDTYPE)) $(CFLAGS_$(BUILDTYPE)) $(CFLAGS_CC_$(BUILDTYPE))
-
-# Suffix rules, putting all outputs into $(obj).
-
-$(obj).$(TOOLSET)/$(TARGET)/%.o: $(srcdir)/%.c FORCE_DO_CMD
- @$(call do_cmd,cc,1)
-
-# Try building from generated source, too.
-
-$(obj).$(TOOLSET)/$(TARGET)/%.o: $(obj).$(TOOLSET)/%.c FORCE_DO_CMD
- @$(call do_cmd,cc,1)
-
-$(obj).$(TOOLSET)/$(TARGET)/%.o: $(obj)/%.c FORCE_DO_CMD
- @$(call do_cmd,cc,1)
-
-# End of this set of suffix rules
-### Rules for final target.
-LDFLAGS_Default :=
-
-LIBS := -lm
-
-$(obj).target/src/libuv/libuv.a: GYP_LDFLAGS := $(LDFLAGS_$(BUILDTYPE))
-$(obj).target/src/libuv/libuv.a: LIBS := $(LIBS)
-$(obj).target/src/libuv/libuv.a: TOOLSET := $(TOOLSET)
-$(obj).target/src/libuv/libuv.a: $(OBJS) FORCE_DO_CMD
- $(call do_cmd,alink)
-
-all_deps += $(obj).target/src/libuv/libuv.a
-# Add target alias
-.PHONY: uv
-uv: $(obj).target/src/libuv/libuv.a
-
-# Add target alias to "all" target.
-.PHONY: all
-all: uv
-
# The source directory tree.
srcdir := ../../../..
+abs_srcdir := $(abspath $(srcdir))
# The name of the builddir.
builddir_name ?= out
endif
# Specify BUILDTYPE=Release on the command line for a release build.
-BUILDTYPE ?= Default
+BUILDTYPE ?= Debug
# Directory all our build output goes into.
# Note that this must be two directories beneath src/ for unit tests to pass,
quiet_cmd_pch_c = CXX($(TOOLSET)) $@
cmd_pch_c = $(CC.$(TOOLSET)) $(GYP_PCH_CFLAGS) $(DEPFLAGS) $(CXXFLAGS.$(TOOLSET)) -c -o $@ $<
quiet_cmd_pch_cc = CXX($(TOOLSET)) $@
-cmd_pch_cc = $(CC.$(TOOLSET)) $(GYP_PCH_CCFLAGS) $(DEPFLAGS) $(CXXFLAGS.$(TOOLSET)) -c -o $@ $<
+cmd_pch_cc = $(CC.$(TOOLSET)) $(GYP_PCH_CXXFLAGS) $(DEPFLAGS) $(CXXFLAGS.$(TOOLSET)) -c -o $@ $<
quiet_cmd_pch_m = CXX($(TOOLSET)) $@
cmd_pch_m = $(CC.$(TOOLSET)) $(GYP_PCH_OBJCFLAGS) $(DEPFLAGS) -c -o $@ $<
quiet_cmd_pch_mm = CXX($(TOOLSET)) $@
quiet_cmd_mac_package_framework = PACKAGE FRAMEWORK $@
cmd_mac_package_framework = ./gyp-mac-tool package-framework "$@" $(4)
+quiet_cmd_infoplist = INFOPLIST $@
+cmd_infoplist = $(CC.$(TOOLSET)) -E -P -Wno-trigraphs -x c $(INFOPLIST_DEFINES) "$<" -o "$@"
+
quiet_cmd_touch = TOUCH $@
cmd_touch = touch $@
)
endef
-# Declare "all" target first so it is the default, even though we don't have the
-# deps yet.
+# Declare the "all" target first so it is the default,
+# even though we don't have the deps yet.
.PHONY: all
all:
include src/libuv/uv.target.mk
endif
-quiet_cmd_regen_makefile = ACTION Regenerating $@
-cmd_regen_makefile = ./src/libuv/build/gyp/gyp -fmake --ignore-environment "--toplevel-dir=." "--depth=." "--generator-output=mk/libuv/x86_64/mac" "-Dlibrary=static_library" "-Dtarget_arch=x86_64" "-DOS=mac" src/libuv/uv.gyp
-Makefile: $(srcdir)/src/libuv/uv.gyp
+#quiet_cmd_regen_makefile = ACTION Regenerating $@
+#cmd_regen_makefile = ./src/libuv/build/gyp/gyp -fmake --ignore-environment "--toplevel-dir=." -Isrc/libuv/common.gypi "--depth=." "--generator-output=mk/libuv/x86_64/mac" "-Ddefault_configuration=Default" "-Dcomponent=static_library" "-Dlibrary=static_library" "-Dtarget_arch=x86_64" "-DOS=mac" src/libuv/uv.gyp
+#Makefile: $(srcdir)/src/libuv/uv.gyp $(srcdir)/src/libuv/common.gypi
# $(call do_cmd,regen_makefile)
# "all" is a concatenation of the "all" targets from all the included
+++ /dev/null
-# We borrow heavily from the kernel build setup, though we are simpler since
-# we don't have Kconfig tweaking settings on us.
-
-# The implicit make rules have it looking for RCS files, among other things.
-# We instead explicitly write all the rules we care about.
-# It's even quicker (saves ~200ms) to pass -r on the command line.
-MAKEFLAGS=-r
-
-# The source directory tree.
-srcdir := ../../../..
-
-# The name of the builddir.
-builddir_name ?= out
-
-# The V=1 flag on command line makes us verbosely print command lines.
-ifdef V
- quiet=
-else
- quiet=quiet_
-endif
-
-# Specify BUILDTYPE=Release on the command line for a release build.
-BUILDTYPE ?= Default
-
-# Directory all our build output goes into.
-# Note that this must be two directories beneath src/ for unit tests to pass,
-# as they reach into the src/ directory for data with relative paths.
-builddir ?= $(builddir_name)/$(BUILDTYPE)
-abs_builddir := $(abspath $(builddir))
-depsdir := $(builddir)/.deps
-
-# Object output directory.
-obj := $(builddir)/obj
-abs_obj := $(abspath $(obj))
-
-# We build up a list of every single one of the targets so we can slurp in the
-# generated dependency rule Makefiles in one pass.
-all_deps :=
-
-
-
-# C++ apps need to be linked with g++.
-#
-# Note: flock is used to seralize linking. Linking is a memory-intensive
-# process so running parallel links can often lead to thrashing. To disable
-# the serialization, override LINK via an envrionment variable as follows:
-#
-# export LINK=g++
-#
-# This will allow make to invoke N linker processes as specified in -jN.
-LINK ?= ./gyp-mac-tool flock $(builddir)/linker.lock $(CXX)
-
-CC.target ?= $(CC)
-CFLAGS.target ?= $(CFLAGS)
-CXX.target ?= $(CXX)
-CXXFLAGS.target ?= $(CXXFLAGS)
-LINK.target ?= $(LINK)
-LDFLAGS.target ?= $(LDFLAGS)
-AR.target ?= $(AR)
-ARFLAGS.target ?= crs
-
-# N.B.: the logic of which commands to run should match the computation done
-# in gyp's make.py where ARFLAGS.host etc. is computed.
-# TODO(evan): move all cross-compilation logic to gyp-time so we don't need
-# to replicate this environment fallback in make as well.
-CC.host ?= gcc
-CFLAGS.host ?=
-CXX.host ?= g++
-CXXFLAGS.host ?=
-LINK.host ?= g++
-LDFLAGS.host ?=
-AR.host ?= ar
-ARFLAGS.host := crs
-
-# Define a dir function that can handle spaces.
-# http://www.gnu.org/software/make/manual/make.html#Syntax-of-Functions
-# "leading spaces cannot appear in the text of the first argument as written.
-# These characters can be put into the argument value by variable substitution."
-empty :=
-space := $(empty) $(empty)
-
-# http://stackoverflow.com/questions/1189781/using-make-dir-or-notdir-on-a-path-with-spaces
-replace_spaces = $(subst $(space),?,$1)
-unreplace_spaces = $(subst ?,$(space),$1)
-dirx = $(call unreplace_spaces,$(dir $(call replace_spaces,$1)))
-
-# Flags to make gcc output dependency info. Note that you need to be
-# careful here to use the flags that ccache and distcc can understand.
-# We write to a dep file on the side first and then rename at the end
-# so we can't end up with a broken dep file.
-depfile = $(depsdir)/$(call replace_spaces,$@).d
-DEPFLAGS = -MMD -MF $(depfile).raw
-
-# We have to fixup the deps output in a few ways.
-# (1) the file output should mention the proper .o file.
-# ccache or distcc lose the path to the target, so we convert a rule of
-# the form:
-# foobar.o: DEP1 DEP2
-# into
-# path/to/foobar.o: DEP1 DEP2
-# (2) we want missing files not to cause us to fail to build.
-# We want to rewrite
-# foobar.o: DEP1 DEP2 \
-# DEP3
-# to
-# DEP1:
-# DEP2:
-# DEP3:
-# so if the files are missing, they're just considered phony rules.
-# We have to do some pretty insane escaping to get those backslashes
-# and dollar signs past make, the shell, and sed at the same time.
-# Doesn't work with spaces, but that's fine: .d files have spaces in
-# their names replaced with other characters.
-define fixup_dep
-# The depfile may not exist if the input file didn't have any #includes.
-touch $(depfile).raw
-# Fixup path as in (1).
-sed -e "s|^$(notdir $@)|$@|" $(depfile).raw >> $(depfile)
-# Add extra rules as in (2).
-# We remove slashes and replace spaces with new lines;
-# remove blank lines;
-# delete the first line and append a colon to the remaining lines.
-sed -e 's|\\||' -e 'y| |\n|' $(depfile).raw |\
- grep -v '^$$' |\
- sed -e 1d -e 's|$$|:|' \
- >> $(depfile)
-rm $(depfile).raw
-endef
-
-# Command definitions:
-# - cmd_foo is the actual command to run;
-# - quiet_cmd_foo is the brief-output summary of the command.
-
-quiet_cmd_cc = CC($(TOOLSET)) $@
-cmd_cc = $(CC.$(TOOLSET)) $(GYP_CFLAGS) $(DEPFLAGS) $(CFLAGS.$(TOOLSET)) -c -o $@ $<
-
-quiet_cmd_cxx = CXX($(TOOLSET)) $@
-cmd_cxx = $(CXX.$(TOOLSET)) $(GYP_CXXFLAGS) $(DEPFLAGS) $(CXXFLAGS.$(TOOLSET)) -c -o $@ $<
-
-quiet_cmd_objc = CXX($(TOOLSET)) $@
-cmd_objc = $(CC.$(TOOLSET)) $(GYP_OBJCFLAGS) $(DEPFLAGS) -c -o $@ $<
-
-quiet_cmd_objcxx = CXX($(TOOLSET)) $@
-cmd_objcxx = $(CXX.$(TOOLSET)) $(GYP_OBJCXXFLAGS) $(DEPFLAGS) -c -o $@ $<
-
-# Commands for precompiled header files.
-quiet_cmd_pch_c = CXX($(TOOLSET)) $@
-cmd_pch_c = $(CC.$(TOOLSET)) $(GYP_PCH_CFLAGS) $(DEPFLAGS) $(CXXFLAGS.$(TOOLSET)) -c -o $@ $<
-quiet_cmd_pch_cc = CXX($(TOOLSET)) $@
-cmd_pch_cc = $(CC.$(TOOLSET)) $(GYP_PCH_CCFLAGS) $(DEPFLAGS) $(CXXFLAGS.$(TOOLSET)) -c -o $@ $<
-quiet_cmd_pch_m = CXX($(TOOLSET)) $@
-cmd_pch_m = $(CC.$(TOOLSET)) $(GYP_PCH_OBJCFLAGS) $(DEPFLAGS) -c -o $@ $<
-quiet_cmd_pch_mm = CXX($(TOOLSET)) $@
-cmd_pch_mm = $(CC.$(TOOLSET)) $(GYP_PCH_OBJCXXFLAGS) $(DEPFLAGS) -c -o $@ $<
-
-# gyp-mac-tool is written next to the root Makefile by gyp.
-# Use $(4) for the command, since $(2) and $(3) are used as flag by do_cmd
-# already.
-quiet_cmd_mac_tool = MACTOOL $(4) $<
-cmd_mac_tool = ./gyp-mac-tool $(4) $< "$@"
-
-quiet_cmd_mac_package_framework = PACKAGE FRAMEWORK $@
-cmd_mac_package_framework = ./gyp-mac-tool package-framework "$@" $(4)
-
-quiet_cmd_touch = TOUCH $@
-cmd_touch = touch $@
-
-quiet_cmd_copy = COPY $@
-# send stderr to /dev/null to ignore messages when linking directories.
-cmd_copy = ln -f "$<" "$@" 2>/dev/null || (rm -rf "$@" && cp -af "$<" "$@")
-
-quiet_cmd_alink = LIBTOOL-STATIC $@
-cmd_alink = rm -f $@ && libtool -static -o $@ $(filter %.o,$^)
-
-quiet_cmd_link = LINK($(TOOLSET)) $@
-cmd_link = $(LINK.$(TOOLSET)) $(GYP_LDFLAGS) $(LDFLAGS.$(TOOLSET)) -o "$@" $(LD_INPUTS) $(LIBS)
-
-# TODO(thakis): Find out and document the difference between shared_library and
-# loadable_module on mac.
-quiet_cmd_solink = SOLINK($(TOOLSET)) $@
-cmd_solink = $(LINK.$(TOOLSET)) -shared $(GYP_LDFLAGS) $(LDFLAGS.$(TOOLSET)) -o "$@" $(LD_INPUTS) $(LIBS)
-
-# TODO(thakis): The solink_module rule is likely wrong. Xcode seems to pass
-# -bundle -single_module here (for osmesa.so).
-quiet_cmd_solink_module = SOLINK_MODULE($(TOOLSET)) $@
-cmd_solink_module = $(LINK.$(TOOLSET)) -shared $(GYP_LDFLAGS) $(LDFLAGS.$(TOOLSET)) -o $@ $(filter-out FORCE_DO_CMD, $^) $(LIBS)
-
-
-# Define an escape_quotes function to escape single quotes.
-# This allows us to handle quotes properly as long as we always use
-# use single quotes and escape_quotes.
-escape_quotes = $(subst ','\'',$(1))
-# This comment is here just to include a ' to unconfuse syntax highlighting.
-# Define an escape_vars function to escape '$' variable syntax.
-# This allows us to read/write command lines with shell variables (e.g.
-# $LD_LIBRARY_PATH), without triggering make substitution.
-escape_vars = $(subst $$,$$$$,$(1))
-# Helper that expands to a shell command to echo a string exactly as it is in
-# make. This uses printf instead of echo because printf's behaviour with respect
-# to escape sequences is more portable than echo's across different shells
-# (e.g., dash, bash).
-exact_echo = printf '%s\n' '$(call escape_quotes,$(1))'
-
-# Helper to compare the command we're about to run against the command
-# we logged the last time we ran the command. Produces an empty
-# string (false) when the commands match.
-# Tricky point: Make has no string-equality test function.
-# The kernel uses the following, but it seems like it would have false
-# positives, where one string reordered its arguments.
-# arg_check = $(strip $(filter-out $(cmd_$(1)), $(cmd_$@)) \
-# $(filter-out $(cmd_$@), $(cmd_$(1))))
-# We instead substitute each for the empty string into the other, and
-# say they're equal if both substitutions produce the empty string.
-# .d files contain ? instead of spaces, take that into account.
-command_changed = $(or $(subst $(cmd_$(1)),,$(cmd_$(call replace_spaces,$@))),\
- $(subst $(cmd_$(call replace_spaces,$@)),,$(cmd_$(1))))
-
-# Helper that is non-empty when a prerequisite changes.
-# Normally make does this implicitly, but we force rules to always run
-# so we can check their command lines.
-# $? -- new prerequisites
-# $| -- order-only dependencies
-prereq_changed = $(filter-out FORCE_DO_CMD,$(filter-out $|,$?))
-
-# Helper that executes all postbuilds, and deletes the output file when done
-# if any of the postbuilds failed.
-define do_postbuilds
- @E=0;\
- for p in $(POSTBUILDS); do\
- eval $$p;\
- F=$$?;\
- if [ $$F -ne 0 ]; then\
- E=$$F;\
- fi;\
- done;\
- if [ $$E -ne 0 ]; then\
- rm -rf "$@";\
- exit $$E;\
- fi
-endef
-
-# do_cmd: run a command via the above cmd_foo names, if necessary.
-# Should always run for a given target to handle command-line changes.
-# Second argument, if non-zero, makes it do asm/C/C++ dependency munging.
-# Third argument, if non-zero, makes it do POSTBUILDS processing.
-# Note: We intentionally do NOT call dirx for depfile, since it contains ? for
-# spaces already and dirx strips the ? characters.
-define do_cmd
-$(if $(or $(command_changed),$(prereq_changed)),
- @$(call exact_echo, $($(quiet)cmd_$(1)))
- @mkdir -p "$(call dirx,$@)" "$(dir $(depfile))"
- $(if $(findstring flock,$(word 2,$(cmd_$1))),
- @$(cmd_$(1))
- @echo " $(quiet_cmd_$(1)): Finished",
- @$(cmd_$(1))
- )
- @$(call exact_echo,$(call escape_vars,cmd_$(call replace_spaces,$@) := $(cmd_$(1)))) > $(depfile)
- @$(if $(2),$(fixup_dep))
- $(if $(and $(3), $(POSTBUILDS)),
- $(call do_postbuilds)
- )
-)
-endef
-
-# Declare "all" target first so it is the default, even though we don't have the
-# deps yet.
-.PHONY: all
-all:
-
-# Use FORCE_DO_CMD to force a target to run. Should be coupled with
-# do_cmd.
-.PHONY: FORCE_DO_CMD
-FORCE_DO_CMD:
-
-TOOLSET := target
-# Suffix rules, putting all outputs into $(obj).
-$(obj).$(TOOLSET)/%.o: $(srcdir)/%.c FORCE_DO_CMD
- @$(call do_cmd,cc,1)
-$(obj).$(TOOLSET)/%.o: $(srcdir)/%.cc FORCE_DO_CMD
- @$(call do_cmd,cxx,1)
-$(obj).$(TOOLSET)/%.o: $(srcdir)/%.cpp FORCE_DO_CMD
- @$(call do_cmd,cxx,1)
-$(obj).$(TOOLSET)/%.o: $(srcdir)/%.cxx FORCE_DO_CMD
- @$(call do_cmd,cxx,1)
-$(obj).$(TOOLSET)/%.o: $(srcdir)/%.m FORCE_DO_CMD
- @$(call do_cmd,objc,1)
-$(obj).$(TOOLSET)/%.o: $(srcdir)/%.mm FORCE_DO_CMD
- @$(call do_cmd,objcxx,1)
-$(obj).$(TOOLSET)/%.o: $(srcdir)/%.S FORCE_DO_CMD
- @$(call do_cmd,cc,1)
-$(obj).$(TOOLSET)/%.o: $(srcdir)/%.s FORCE_DO_CMD
- @$(call do_cmd,cc,1)
-
-# Try building from generated source, too.
-$(obj).$(TOOLSET)/%.o: $(obj).$(TOOLSET)/%.c FORCE_DO_CMD
- @$(call do_cmd,cc,1)
-$(obj).$(TOOLSET)/%.o: $(obj).$(TOOLSET)/%.cc FORCE_DO_CMD
- @$(call do_cmd,cxx,1)
-$(obj).$(TOOLSET)/%.o: $(obj).$(TOOLSET)/%.cpp FORCE_DO_CMD
- @$(call do_cmd,cxx,1)
-$(obj).$(TOOLSET)/%.o: $(obj).$(TOOLSET)/%.cxx FORCE_DO_CMD
- @$(call do_cmd,cxx,1)
-$(obj).$(TOOLSET)/%.o: $(obj).$(TOOLSET)/%.m FORCE_DO_CMD
- @$(call do_cmd,objc,1)
-$(obj).$(TOOLSET)/%.o: $(obj).$(TOOLSET)/%.mm FORCE_DO_CMD
- @$(call do_cmd,objcxx,1)
-$(obj).$(TOOLSET)/%.o: $(obj).$(TOOLSET)/%.S FORCE_DO_CMD
- @$(call do_cmd,cc,1)
-$(obj).$(TOOLSET)/%.o: $(obj).$(TOOLSET)/%.s FORCE_DO_CMD
- @$(call do_cmd,cc,1)
-
-$(obj).$(TOOLSET)/%.o: $(obj)/%.c FORCE_DO_CMD
- @$(call do_cmd,cc,1)
-$(obj).$(TOOLSET)/%.o: $(obj)/%.cc FORCE_DO_CMD
- @$(call do_cmd,cxx,1)
-$(obj).$(TOOLSET)/%.o: $(obj)/%.cpp FORCE_DO_CMD
- @$(call do_cmd,cxx,1)
-$(obj).$(TOOLSET)/%.o: $(obj)/%.cxx FORCE_DO_CMD
- @$(call do_cmd,cxx,1)
-$(obj).$(TOOLSET)/%.o: $(obj)/%.m FORCE_DO_CMD
- @$(call do_cmd,objc,1)
-$(obj).$(TOOLSET)/%.o: $(obj)/%.mm FORCE_DO_CMD
- @$(call do_cmd,objcxx,1)
-$(obj).$(TOOLSET)/%.o: $(obj)/%.S FORCE_DO_CMD
- @$(call do_cmd,cc,1)
-$(obj).$(TOOLSET)/%.o: $(obj)/%.s FORCE_DO_CMD
- @$(call do_cmd,cc,1)
-
-
-ifeq ($(strip $(foreach prefix,$(NO_LOAD),\
- $(findstring $(join ^,$(prefix)),\
- $(join ^,src/libuv/run-benchmarks.target.mk)))),)
- include src/libuv/run-benchmarks.target.mk
-endif
-ifeq ($(strip $(foreach prefix,$(NO_LOAD),\
- $(findstring $(join ^,$(prefix)),\
- $(join ^,src/libuv/run-tests.target.mk)))),)
- include src/libuv/run-tests.target.mk
-endif
-ifeq ($(strip $(foreach prefix,$(NO_LOAD),\
- $(findstring $(join ^,$(prefix)),\
- $(join ^,src/libuv/uv.target.mk)))),)
- include src/libuv/uv.target.mk
-endif
-
-quiet_cmd_regen_makefile = ACTION Regenerating $@
-cmd_regen_makefile = ./src/libuv/build/gyp/gyp -fmake --ignore-environment "--toplevel-dir=." "--depth=." "--generator-output=mk/libuv/x86_64/mac" "-Dlibrary=static_library" "-Dtarget_arch=x86_64" "-DOS=mac" src/libuv/uv.gyp
-Makefile: $(srcdir)/src/libuv/uv.gyp
- $(call do_cmd,regen_makefile)
-
-# "all" is a concatenation of the "all" targets from all the included
-# sub-makefiles. This is just here to clarify.
-all:
-
-# Add in dependency-tracking rules. $(all_deps) is the list of every single
-# target in our tree. Only consider the ones with .d (dependency) info:
-d_files := $(wildcard $(foreach f,$(all_deps),$(depsdir)/$(f).d))
-ifneq ($(d_files),)
- # Rather than include each individual .d file, concatenate them into a
- # single file which make is able to load faster. We split this into
- # commands that take 1000 files at a time to avoid overflowing the
- # command line.
- $(shell cat $(wordlist 1,1000,$(d_files)) > $(depsdir)/all.deps)
-
- ifneq ($(word 1001,$(d_files)),)
- $(error Found unprocessed dependency files (gyp didn't generate enough rules!))
- endif
-
- # make looks for ways to re-generate included makefiles, but in our case, we
- # don't have a direct way. Explicitly telling make that it has nothing to do
- # for them makes it go faster.
- $(depsdir)/all.deps: ;
-
- include $(depsdir)/all.deps
-endif
-#!/usr/bin/python
+#!/usr/bin/env python
# Generated by gyp. Do not edit.
# Copyright (c) 2011 Google Inc. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
import subprocess
import sys
+
def main(args):
executor = MacTool()
executor.Dispatch(args)
+
class MacTool(object):
"""This class performs all the Mac tooling steps. The methods can either be
executed directly, or dispatched from an argument list."""
if not plist:
return
+ # Only create PkgInfo for executable types.
+ package_type = plist['CFBundlePackageType']
+ if package_type != 'APPL':
+ return
+
# The format of PkgInfo is eight characters, representing the bundle type
- # and bundle signature, each four characters. If either is missing, four
+ # and bundle signature, each four characters. If that is missing, four
# '?' characters are used instead.
- package_type = plist['CFBundlePackageType']
- if len(package_type) != 4:
- package_type = '?' * 4
signature_code = plist['CFBundleSignature']
if len(signature_code) != 4:
signature_code = '?' * 4
else:
return None
+
if __name__ == '__main__':
sys.exit(main(sys.argv[1:]))
TOOLSET := target
TARGET := run-benchmarks
-DEFS_Default := '-D_LARGEFILE_SOURCE' \
+DEFS_Debug := '-D_LARGEFILE_SOURCE' \
'-D_FILE_OFFSET_BITS=64' \
'-D_GNU_SOURCE' \
- '-DEIO_STACKSIZE=262144'
+ '-DEIO_STACKSIZE=262144' \
+ '-DDEBUG' \
+ '-D_DEBUG' \
+ '-DEV_VERIFY=2'
# Flags passed to all source files.
-CFLAGS_Default := -fasm-blocks \
- -mpascal-strings \
- -Os \
+CFLAGS_Debug := -Os \
-gdwarf-2 \
- -arch x86_64
+ -fvisibility=hidden \
+ -Wnewline-eof \
+ -arch x86_64 \
+ -fno-strict-aliasing \
+ -Wall \
+ -Wendif-labels \
+ -W \
+ -Wno-unused-parameter
# Flags passed to only C files.
-CFLAGS_C_Default :=
+CFLAGS_C_Debug :=
# Flags passed to only C++ files.
-CFLAGS_CC_Default :=
+CFLAGS_CC_Debug := -fno-rtti \
+ -fno-exceptions \
+ -fvisibility-inlines-hidden \
+ -fno-threadsafe-statics
# Flags passed to only ObjC files.
-CFLAGS_OBJC_Default :=
+CFLAGS_OBJC_Debug :=
# Flags passed to only ObjC++ files.
-CFLAGS_OBJCC_Default :=
+CFLAGS_OBJCC_Debug :=
-INCS_Default := -I$(srcdir)/src/libuv/include
+INCS_Debug := -I$(srcdir)/src/libuv/include
+
+DEFS_Release := '-D_LARGEFILE_SOURCE' \
+ '-D_FILE_OFFSET_BITS=64' \
+ '-D_GNU_SOURCE' \
+ '-DEIO_STACKSIZE=262144' \
+ '-DNDEBUG'
+
+# Flags passed to all source files.
+CFLAGS_Release := -Os \
+ -gdwarf-2 \
+ -fvisibility=hidden \
+ -Wnewline-eof \
+ -arch x86_64 \
+ -fno-strict-aliasing \
+ -Wall \
+ -Wendif-labels \
+ -W \
+ -Wno-unused-parameter
+
+# Flags passed to only C files.
+CFLAGS_C_Release :=
+
+# Flags passed to only C++ files.
+CFLAGS_CC_Release := -fno-rtti \
+ -fno-exceptions \
+ -fvisibility-inlines-hidden \
+ -fno-threadsafe-statics
+
+# Flags passed to only ObjC files.
+CFLAGS_OBJC_Release :=
+
+# Flags passed to only ObjC++ files.
+CFLAGS_OBJCC_Release :=
+
+INCS_Release := -I$(srcdir)/src/libuv/include
OBJS := $(obj).target/$(TARGET)/src/libuv/test/benchmark-ares.o \
$(obj).target/$(TARGET)/src/libuv/test/benchmark-getaddrinfo.o \
$(obj).target/$(TARGET)/src/libuv/test/benchmark-pump.o \
$(obj).target/$(TARGET)/src/libuv/test/benchmark-sizes.o \
$(obj).target/$(TARGET)/src/libuv/test/benchmark-spawn.o \
+ $(obj).target/$(TARGET)/src/libuv/test/benchmark-thread.o \
$(obj).target/$(TARGET)/src/libuv/test/benchmark-tcp-write-batch.o \
$(obj).target/$(TARGET)/src/libuv/test/benchmark-udp-packet-storm.o \
$(obj).target/$(TARGET)/src/libuv/test/dns-server.o \
# CFLAGS et al overrides must be target-local.
# See "Target-specific Variable Values" in the GNU Make manual.
$(OBJS): TOOLSET := $(TOOLSET)
-$(OBJS): GYP_CFLAGS := $(DEFS_$(BUILDTYPE)) $(INCS_$(BUILDTYPE)) $(CFLAGS_$(BUILDTYPE)) $(CFLAGS_C_$(BUILDTYPE))
-$(OBJS): GYP_CXXFLAGS := $(DEFS_$(BUILDTYPE)) $(INCS_$(BUILDTYPE)) $(CFLAGS_$(BUILDTYPE)) $(CFLAGS_CC_$(BUILDTYPE))
-$(OBJS): GYP_OBJCFLAGS := $(DEFS_$(BUILDTYPE)) $(INCS_$(BUILDTYPE)) $(CFLAGS_$(BUILDTYPE)) $(CFLAGS_C_$(BUILDTYPE)) $(CFLAGS_OBJC_$(BUILDTYPE))
-$(OBJS): GYP_OBJCXXFLAGS := $(DEFS_$(BUILDTYPE)) $(INCS_$(BUILDTYPE)) $(CFLAGS_$(BUILDTYPE)) $(CFLAGS_CC_$(BUILDTYPE)) $(CFLAGS_OBJCC_$(BUILDTYPE))
+$(OBJS): GYP_CFLAGS := $(DEFS_$(BUILDTYPE)) $(INCS_$(BUILDTYPE)) $(CFLAGS_$(BUILDTYPE)) $(CFLAGS_C_$(BUILDTYPE))
+$(OBJS): GYP_CXXFLAGS := $(DEFS_$(BUILDTYPE)) $(INCS_$(BUILDTYPE)) $(CFLAGS_$(BUILDTYPE)) $(CFLAGS_CC_$(BUILDTYPE))
+$(OBJS): GYP_OBJCFLAGS := $(DEFS_$(BUILDTYPE)) $(INCS_$(BUILDTYPE)) $(CFLAGS_$(BUILDTYPE)) $(CFLAGS_C_$(BUILDTYPE)) $(CFLAGS_OBJC_$(BUILDTYPE))
+$(OBJS): GYP_OBJCXXFLAGS := $(DEFS_$(BUILDTYPE)) $(INCS_$(BUILDTYPE)) $(CFLAGS_$(BUILDTYPE)) $(CFLAGS_CC_$(BUILDTYPE)) $(CFLAGS_OBJCC_$(BUILDTYPE))
# Suffix rules, putting all outputs into $(obj).
# End of this set of suffix rules
### Rules for final target.
-LDFLAGS_Default := -arch x86_64 \
+LDFLAGS_Debug := -Wl,-search_paths_first \
+ -arch x86_64 \
+ -L$(builddir)
+
+LDFLAGS_Release := -Wl,-search_paths_first \
+ -arch x86_64 \
-L$(builddir)
LIBS := -framework Carbon \
+++ /dev/null
-# This file is generated by gyp; do not edit.
-
-TOOLSET := target
-TARGET := run-benchmarks
-DEFS_Default := '-D_LARGEFILE_SOURCE' \
- '-D_FILE_OFFSET_BITS=64' \
- '-D_GNU_SOURCE' \
- '-DEIO_STACKSIZE=262144'
-
-# Flags passed to all source files.
-CFLAGS_Default := -fasm-blocks \
- -mpascal-strings \
- -Os \
- -gdwarf-2 \
- -arch i386
-
-# Flags passed to only C files.
-CFLAGS_C_Default :=
-
-# Flags passed to only C++ files.
-CFLAGS_CC_Default :=
-
-# Flags passed to only ObjC files.
-CFLAGS_OBJC_Default :=
-
-# Flags passed to only ObjC++ files.
-CFLAGS_OBJCC_Default :=
-
-INCS_Default := -I$(srcdir)/src/libuv/include
-
-OBJS := $(obj).target/$(TARGET)/src/libuv/test/benchmark-ares.o \
- $(obj).target/$(TARGET)/src/libuv/test/benchmark-getaddrinfo.o \
- $(obj).target/$(TARGET)/src/libuv/test/benchmark-ping-pongs.o \
- $(obj).target/$(TARGET)/src/libuv/test/benchmark-pound.o \
- $(obj).target/$(TARGET)/src/libuv/test/benchmark-pump.o \
- $(obj).target/$(TARGET)/src/libuv/test/benchmark-sizes.o \
- $(obj).target/$(TARGET)/src/libuv/test/benchmark-spawn.o \
- $(obj).target/$(TARGET)/src/libuv/test/benchmark-tcp-write-batch.o \
- $(obj).target/$(TARGET)/src/libuv/test/benchmark-udp-packet-storm.o \
- $(obj).target/$(TARGET)/src/libuv/test/dns-server.o \
- $(obj).target/$(TARGET)/src/libuv/test/echo-server.o \
- $(obj).target/$(TARGET)/src/libuv/test/blackhole-server.o \
- $(obj).target/$(TARGET)/src/libuv/test/run-benchmarks.o \
- $(obj).target/$(TARGET)/src/libuv/test/runner.o \
- $(obj).target/$(TARGET)/src/libuv/test/runner-unix.o
-
-# Add to the list of files we specially track dependencies for.
-all_deps += $(OBJS)
-
-# Make sure our dependencies are built before any of us.
-$(OBJS): | $(builddir)/libuv.a
-
-# CFLAGS et al overrides must be target-local.
-# See "Target-specific Variable Values" in the GNU Make manual.
-$(OBJS): TOOLSET := $(TOOLSET)
-$(OBJS): GYP_CFLAGS := $(DEFS_$(BUILDTYPE)) $(INCS_$(BUILDTYPE)) $(CFLAGS_$(BUILDTYPE)) $(CFLAGS_C_$(BUILDTYPE))
-$(OBJS): GYP_CXXFLAGS := $(DEFS_$(BUILDTYPE)) $(INCS_$(BUILDTYPE)) $(CFLAGS_$(BUILDTYPE)) $(CFLAGS_CC_$(BUILDTYPE))
-$(OBJS): GYP_OBJCFLAGS := $(DEFS_$(BUILDTYPE)) $(INCS_$(BUILDTYPE)) $(CFLAGS_$(BUILDTYPE)) $(CFLAGS_C_$(BUILDTYPE)) $(CFLAGS_OBJC_$(BUILDTYPE))
-$(OBJS): GYP_OBJCXXFLAGS := $(DEFS_$(BUILDTYPE)) $(INCS_$(BUILDTYPE)) $(CFLAGS_$(BUILDTYPE)) $(CFLAGS_CC_$(BUILDTYPE)) $(CFLAGS_OBJCC_$(BUILDTYPE))
-
-# Suffix rules, putting all outputs into $(obj).
-
-$(obj).$(TOOLSET)/$(TARGET)/%.o: $(srcdir)/%.c FORCE_DO_CMD
- @$(call do_cmd,cc,1)
-
-# Try building from generated source, too.
-
-$(obj).$(TOOLSET)/$(TARGET)/%.o: $(obj).$(TOOLSET)/%.c FORCE_DO_CMD
- @$(call do_cmd,cc,1)
-
-$(obj).$(TOOLSET)/$(TARGET)/%.o: $(obj)/%.c FORCE_DO_CMD
- @$(call do_cmd,cc,1)
-
-# End of this set of suffix rules
-### Rules for final target.
-LDFLAGS_Default := -arch i386 \
- -L$(builddir)
-
-LIBS := -framework Carbon \
- -framework CoreServices
-
-$(builddir)/run-benchmarks: GYP_LDFLAGS := $(LDFLAGS_$(BUILDTYPE))
-$(builddir)/run-benchmarks: LIBS := $(LIBS)
-$(builddir)/run-benchmarks: LD_INPUTS := $(OBJS) $(builddir)/libuv.a
-$(builddir)/run-benchmarks: TOOLSET := $(TOOLSET)
-$(builddir)/run-benchmarks: $(OBJS) $(builddir)/libuv.a FORCE_DO_CMD
- $(call do_cmd,link)
-
-all_deps += $(builddir)/run-benchmarks
-# Add target alias
-.PHONY: run-benchmarks
-run-benchmarks: $(builddir)/run-benchmarks
-
-# Add executable to "all" target.
-.PHONY: all
-all: $(builddir)/run-benchmarks
-
TOOLSET := target
TARGET := run-tests
-DEFS_Default := '-D_LARGEFILE_SOURCE' \
+DEFS_Debug := '-D_LARGEFILE_SOURCE' \
'-D_FILE_OFFSET_BITS=64' \
'-D_GNU_SOURCE' \
- '-DEIO_STACKSIZE=262144'
+ '-DEIO_STACKSIZE=262144' \
+ '-DDEBUG' \
+ '-D_DEBUG' \
+ '-DEV_VERIFY=2'
# Flags passed to all source files.
-CFLAGS_Default := -fasm-blocks \
- -mpascal-strings \
- -Os \
+CFLAGS_Debug := -Os \
-gdwarf-2 \
- -arch x86_64
+ -fvisibility=hidden \
+ -Wnewline-eof \
+ -arch x86_64 \
+ -fno-strict-aliasing \
+ -Wall \
+ -Wendif-labels \
+ -W \
+ -Wno-unused-parameter
# Flags passed to only C files.
-CFLAGS_C_Default :=
+CFLAGS_C_Debug :=
# Flags passed to only C++ files.
-CFLAGS_CC_Default :=
+CFLAGS_CC_Debug := -fno-rtti \
+ -fno-exceptions \
+ -fvisibility-inlines-hidden \
+ -fno-threadsafe-statics
# Flags passed to only ObjC files.
-CFLAGS_OBJC_Default :=
+CFLAGS_OBJC_Debug :=
# Flags passed to only ObjC++ files.
-CFLAGS_OBJCC_Default :=
+CFLAGS_OBJCC_Debug :=
-INCS_Default := -I$(srcdir)/src/libuv/include
+INCS_Debug := -I$(srcdir)/src/libuv/include
+
+DEFS_Release := '-D_LARGEFILE_SOURCE' \
+ '-D_FILE_OFFSET_BITS=64' \
+ '-D_GNU_SOURCE' \
+ '-DEIO_STACKSIZE=262144' \
+ '-DNDEBUG'
+
+# Flags passed to all source files.
+CFLAGS_Release := -Os \
+ -gdwarf-2 \
+ -fvisibility=hidden \
+ -Wnewline-eof \
+ -arch x86_64 \
+ -fno-strict-aliasing \
+ -Wall \
+ -Wendif-labels \
+ -W \
+ -Wno-unused-parameter
+
+# Flags passed to only C files.
+CFLAGS_C_Release :=
+
+# Flags passed to only C++ files.
+CFLAGS_CC_Release := -fno-rtti \
+ -fno-exceptions \
+ -fvisibility-inlines-hidden \
+ -fno-threadsafe-statics
+
+# Flags passed to only ObjC files.
+CFLAGS_OBJC_Release :=
+
+# Flags passed to only ObjC++ files.
+CFLAGS_OBJCC_Release :=
+
+INCS_Release := -I$(srcdir)/src/libuv/include
OBJS := $(obj).target/$(TARGET)/src/libuv/test/blackhole-server.o \
$(obj).target/$(TARGET)/src/libuv/test/echo-server.o \
$(obj).target/$(TARGET)/src/libuv/test/run-tests.o \
$(obj).target/$(TARGET)/src/libuv/test/runner.o \
$(obj).target/$(TARGET)/src/libuv/test/test-get-loadavg.o \
+ $(obj).target/$(TARGET)/src/libuv/test/test-util.o \
$(obj).target/$(TARGET)/src/libuv/test/test-async.o \
$(obj).target/$(TARGET)/src/libuv/test/test-error.o \
$(obj).target/$(TARGET)/src/libuv/test/test-callback-stack.o \
$(obj).target/$(TARGET)/src/libuv/test/test-connection-fail.o \
+ $(obj).target/$(TARGET)/src/libuv/test/test-cwd-and-chdir.o \
$(obj).target/$(TARGET)/src/libuv/test/test-delayed-accept.o \
+ $(obj).target/$(TARGET)/src/libuv/test/test-eio-overflow.o \
$(obj).target/$(TARGET)/src/libuv/test/test-fail-always.o \
$(obj).target/$(TARGET)/src/libuv/test/test-fs.o \
$(obj).target/$(TARGET)/src/libuv/test/test-fs-event.o \
$(obj).target/$(TARGET)/src/libuv/test/test-hrtime.o \
$(obj).target/$(TARGET)/src/libuv/test/test-idle.o \
$(obj).target/$(TARGET)/src/libuv/test/test-ipc.o \
+ $(obj).target/$(TARGET)/src/libuv/test/test-ipc-threads.o \
$(obj).target/$(TARGET)/src/libuv/test/test-loop-handles.o \
$(obj).target/$(TARGET)/src/libuv/test/test-multiple-listen.o \
$(obj).target/$(TARGET)/src/libuv/test/test-pass-always.o \
$(obj).target/$(TARGET)/src/libuv/test/test-ping-pong.o \
$(obj).target/$(TARGET)/src/libuv/test/test-pipe-bind-error.o \
$(obj).target/$(TARGET)/src/libuv/test/test-pipe-connect-error.o \
+ $(obj).target/$(TARGET)/src/libuv/test/test-platform-output.o \
+ $(obj).target/$(TARGET)/src/libuv/test/test-process-title.o \
$(obj).target/$(TARGET)/src/libuv/test/test-ref.o \
$(obj).target/$(TARGET)/src/libuv/test/test-shutdown-eof.o \
$(obj).target/$(TARGET)/src/libuv/test/test-spawn.o \
$(obj).target/$(TARGET)/src/libuv/test/test-tcp-write-to-half-open-connection.o \
$(obj).target/$(TARGET)/src/libuv/test/test-tcp-writealot.o \
$(obj).target/$(TARGET)/src/libuv/test/test-threadpool.o \
+ $(obj).target/$(TARGET)/src/libuv/test/test-mutexes.o \
+ $(obj).target/$(TARGET)/src/libuv/test/test-thread.o \
$(obj).target/$(TARGET)/src/libuv/test/test-timer-again.o \
$(obj).target/$(TARGET)/src/libuv/test/test-timer.o \
$(obj).target/$(TARGET)/src/libuv/test/test-tty.o \
$(obj).target/$(TARGET)/src/libuv/test/test-udp-dgram-too-big.o \
$(obj).target/$(TARGET)/src/libuv/test/test-udp-ipv6.o \
+ $(obj).target/$(TARGET)/src/libuv/test/test-udp-options.o \
$(obj).target/$(TARGET)/src/libuv/test/test-udp-send-and-recv.o \
$(obj).target/$(TARGET)/src/libuv/test/test-udp-multicast-join.o \
+ $(obj).target/$(TARGET)/src/libuv/test/test-counters-init.o \
$(obj).target/$(TARGET)/src/libuv/test/runner-unix.o
# Add to the list of files we specially track dependencies for.
# CFLAGS et al overrides must be target-local.
# See "Target-specific Variable Values" in the GNU Make manual.
$(OBJS): TOOLSET := $(TOOLSET)
-$(OBJS): GYP_CFLAGS := $(DEFS_$(BUILDTYPE)) $(INCS_$(BUILDTYPE)) $(CFLAGS_$(BUILDTYPE)) $(CFLAGS_C_$(BUILDTYPE))
-$(OBJS): GYP_CXXFLAGS := $(DEFS_$(BUILDTYPE)) $(INCS_$(BUILDTYPE)) $(CFLAGS_$(BUILDTYPE)) $(CFLAGS_CC_$(BUILDTYPE))
-$(OBJS): GYP_OBJCFLAGS := $(DEFS_$(BUILDTYPE)) $(INCS_$(BUILDTYPE)) $(CFLAGS_$(BUILDTYPE)) $(CFLAGS_C_$(BUILDTYPE)) $(CFLAGS_OBJC_$(BUILDTYPE))
-$(OBJS): GYP_OBJCXXFLAGS := $(DEFS_$(BUILDTYPE)) $(INCS_$(BUILDTYPE)) $(CFLAGS_$(BUILDTYPE)) $(CFLAGS_CC_$(BUILDTYPE)) $(CFLAGS_OBJCC_$(BUILDTYPE))
+$(OBJS): GYP_CFLAGS := $(DEFS_$(BUILDTYPE)) $(INCS_$(BUILDTYPE)) $(CFLAGS_$(BUILDTYPE)) $(CFLAGS_C_$(BUILDTYPE))
+$(OBJS): GYP_CXXFLAGS := $(DEFS_$(BUILDTYPE)) $(INCS_$(BUILDTYPE)) $(CFLAGS_$(BUILDTYPE)) $(CFLAGS_CC_$(BUILDTYPE))
+$(OBJS): GYP_OBJCFLAGS := $(DEFS_$(BUILDTYPE)) $(INCS_$(BUILDTYPE)) $(CFLAGS_$(BUILDTYPE)) $(CFLAGS_C_$(BUILDTYPE)) $(CFLAGS_OBJC_$(BUILDTYPE))
+$(OBJS): GYP_OBJCXXFLAGS := $(DEFS_$(BUILDTYPE)) $(INCS_$(BUILDTYPE)) $(CFLAGS_$(BUILDTYPE)) $(CFLAGS_CC_$(BUILDTYPE)) $(CFLAGS_OBJCC_$(BUILDTYPE))
# Suffix rules, putting all outputs into $(obj).
# End of this set of suffix rules
### Rules for final target.
-LDFLAGS_Default := -arch x86_64 \
+LDFLAGS_Debug := -Wl,-search_paths_first \
+ -arch x86_64 \
+ -L$(builddir)
+
+LDFLAGS_Release := -Wl,-search_paths_first \
+ -arch x86_64 \
-L$(builddir)
LIBS := -framework Carbon \
+++ /dev/null
-# This file is generated by gyp; do not edit.
-
-TOOLSET := target
-TARGET := run-tests
-DEFS_Default := '-D_LARGEFILE_SOURCE' \
- '-D_FILE_OFFSET_BITS=64' \
- '-D_GNU_SOURCE' \
- '-DEIO_STACKSIZE=262144'
-
-# Flags passed to all source files.
-CFLAGS_Default := -fasm-blocks \
- -mpascal-strings \
- -Os \
- -gdwarf-2 \
- -arch i386
-
-# Flags passed to only C files.
-CFLAGS_C_Default :=
-
-# Flags passed to only C++ files.
-CFLAGS_CC_Default :=
-
-# Flags passed to only ObjC files.
-CFLAGS_OBJC_Default :=
-
-# Flags passed to only ObjC++ files.
-CFLAGS_OBJCC_Default :=
-
-INCS_Default := -I$(srcdir)/src/libuv/include
-
-OBJS := $(obj).target/$(TARGET)/src/libuv/test/blackhole-server.o \
- $(obj).target/$(TARGET)/src/libuv/test/echo-server.o \
- $(obj).target/$(TARGET)/src/libuv/test/run-tests.o \
- $(obj).target/$(TARGET)/src/libuv/test/runner.o \
- $(obj).target/$(TARGET)/src/libuv/test/test-get-loadavg.o \
- $(obj).target/$(TARGET)/src/libuv/test/test-async.o \
- $(obj).target/$(TARGET)/src/libuv/test/test-error.o \
- $(obj).target/$(TARGET)/src/libuv/test/test-callback-stack.o \
- $(obj).target/$(TARGET)/src/libuv/test/test-connection-fail.o \
- $(obj).target/$(TARGET)/src/libuv/test/test-delayed-accept.o \
- $(obj).target/$(TARGET)/src/libuv/test/test-fail-always.o \
- $(obj).target/$(TARGET)/src/libuv/test/test-fs.o \
- $(obj).target/$(TARGET)/src/libuv/test/test-fs-event.o \
- $(obj).target/$(TARGET)/src/libuv/test/test-get-currentexe.o \
- $(obj).target/$(TARGET)/src/libuv/test/test-get-memory.o \
- $(obj).target/$(TARGET)/src/libuv/test/test-getaddrinfo.o \
- $(obj).target/$(TARGET)/src/libuv/test/test-gethostbyname.o \
- $(obj).target/$(TARGET)/src/libuv/test/test-getsockname.o \
- $(obj).target/$(TARGET)/src/libuv/test/test-hrtime.o \
- $(obj).target/$(TARGET)/src/libuv/test/test-idle.o \
- $(obj).target/$(TARGET)/src/libuv/test/test-ipc.o \
- $(obj).target/$(TARGET)/src/libuv/test/test-loop-handles.o \
- $(obj).target/$(TARGET)/src/libuv/test/test-multiple-listen.o \
- $(obj).target/$(TARGET)/src/libuv/test/test-pass-always.o \
- $(obj).target/$(TARGET)/src/libuv/test/test-ping-pong.o \
- $(obj).target/$(TARGET)/src/libuv/test/test-pipe-bind-error.o \
- $(obj).target/$(TARGET)/src/libuv/test/test-pipe-connect-error.o \
- $(obj).target/$(TARGET)/src/libuv/test/test-ref.o \
- $(obj).target/$(TARGET)/src/libuv/test/test-shutdown-eof.o \
- $(obj).target/$(TARGET)/src/libuv/test/test-spawn.o \
- $(obj).target/$(TARGET)/src/libuv/test/test-stdio-over-pipes.o \
- $(obj).target/$(TARGET)/src/libuv/test/test-tcp-bind-error.o \
- $(obj).target/$(TARGET)/src/libuv/test/test-tcp-bind6-error.o \
- $(obj).target/$(TARGET)/src/libuv/test/test-tcp-close.o \
- $(obj).target/$(TARGET)/src/libuv/test/test-tcp-flags.o \
- $(obj).target/$(TARGET)/src/libuv/test/test-tcp-connect-error.o \
- $(obj).target/$(TARGET)/src/libuv/test/test-tcp-connect6-error.o \
- $(obj).target/$(TARGET)/src/libuv/test/test-tcp-write-error.o \
- $(obj).target/$(TARGET)/src/libuv/test/test-tcp-write-to-half-open-connection.o \
- $(obj).target/$(TARGET)/src/libuv/test/test-tcp-writealot.o \
- $(obj).target/$(TARGET)/src/libuv/test/test-threadpool.o \
- $(obj).target/$(TARGET)/src/libuv/test/test-timer-again.o \
- $(obj).target/$(TARGET)/src/libuv/test/test-timer.o \
- $(obj).target/$(TARGET)/src/libuv/test/test-tty.o \
- $(obj).target/$(TARGET)/src/libuv/test/test-udp-dgram-too-big.o \
- $(obj).target/$(TARGET)/src/libuv/test/test-udp-ipv6.o \
- $(obj).target/$(TARGET)/src/libuv/test/test-udp-send-and-recv.o \
- $(obj).target/$(TARGET)/src/libuv/test/test-udp-multicast-join.o \
- $(obj).target/$(TARGET)/src/libuv/test/runner-unix.o
-
-# Add to the list of files we specially track dependencies for.
-all_deps += $(OBJS)
-
-# Make sure our dependencies are built before any of us.
-$(OBJS): | $(builddir)/libuv.a
-
-# CFLAGS et al overrides must be target-local.
-# See "Target-specific Variable Values" in the GNU Make manual.
-$(OBJS): TOOLSET := $(TOOLSET)
-$(OBJS): GYP_CFLAGS := $(DEFS_$(BUILDTYPE)) $(INCS_$(BUILDTYPE)) $(CFLAGS_$(BUILDTYPE)) $(CFLAGS_C_$(BUILDTYPE))
-$(OBJS): GYP_CXXFLAGS := $(DEFS_$(BUILDTYPE)) $(INCS_$(BUILDTYPE)) $(CFLAGS_$(BUILDTYPE)) $(CFLAGS_CC_$(BUILDTYPE))
-$(OBJS): GYP_OBJCFLAGS := $(DEFS_$(BUILDTYPE)) $(INCS_$(BUILDTYPE)) $(CFLAGS_$(BUILDTYPE)) $(CFLAGS_C_$(BUILDTYPE)) $(CFLAGS_OBJC_$(BUILDTYPE))
-$(OBJS): GYP_OBJCXXFLAGS := $(DEFS_$(BUILDTYPE)) $(INCS_$(BUILDTYPE)) $(CFLAGS_$(BUILDTYPE)) $(CFLAGS_CC_$(BUILDTYPE)) $(CFLAGS_OBJCC_$(BUILDTYPE))
-
-# Suffix rules, putting all outputs into $(obj).
-
-$(obj).$(TOOLSET)/$(TARGET)/%.o: $(srcdir)/%.c FORCE_DO_CMD
- @$(call do_cmd,cc,1)
-
-# Try building from generated source, too.
-
-$(obj).$(TOOLSET)/$(TARGET)/%.o: $(obj).$(TOOLSET)/%.c FORCE_DO_CMD
- @$(call do_cmd,cc,1)
-
-$(obj).$(TOOLSET)/$(TARGET)/%.o: $(obj)/%.c FORCE_DO_CMD
- @$(call do_cmd,cc,1)
-
-# End of this set of suffix rules
-### Rules for final target.
-LDFLAGS_Default := -arch i386 \
- -L$(builddir)
-
-LIBS := -framework Carbon \
- -framework CoreServices
-
-$(builddir)/run-tests: GYP_LDFLAGS := $(LDFLAGS_$(BUILDTYPE))
-$(builddir)/run-tests: LIBS := $(LIBS)
-$(builddir)/run-tests: LD_INPUTS := $(OBJS) $(builddir)/libuv.a
-$(builddir)/run-tests: TOOLSET := $(TOOLSET)
-$(builddir)/run-tests: $(OBJS) $(builddir)/libuv.a FORCE_DO_CMD
- $(call do_cmd,link)
-
-all_deps += $(builddir)/run-tests
-# Add target alias
-.PHONY: run-tests
-run-tests: $(builddir)/run-tests
-
-# Add executable to "all" target.
-.PHONY: all
-all: $(builddir)/run-tests
-
TOOLSET := target
TARGET := uv
-DEFS_Default := '-D_LARGEFILE_SOURCE' \
+DEFS_Debug := '-D_LARGEFILE_SOURCE' \
'-D_FILE_OFFSET_BITS=64' \
'-D_GNU_SOURCE' \
'-DEIO_STACKSIZE=262144' \
'-DHAVE_CONFIG_H' \
'-DEV_CONFIG_H="config_darwin.h"' \
- '-DEIO_CONFIG_H="config_darwin.h"'
+ '-DEIO_CONFIG_H="config_darwin.h"' \
+ '-DDEBUG' \
+ '-D_DEBUG' \
+ '-DEV_VERIFY=2'
# Flags passed to all source files.
-CFLAGS_Default := -fasm-blocks \
- -mpascal-strings \
- -Os \
+CFLAGS_Debug := -Os \
-gdwarf-2 \
- -arch x86_64
+ -fvisibility=hidden \
+ -Wnewline-eof \
+ -arch x86_64 \
+ -fno-strict-aliasing \
+ -Wall \
+ -Wendif-labels \
+ -W \
+ -Wno-unused-parameter
# Flags passed to only C files.
-CFLAGS_C_Default :=
+CFLAGS_C_Debug :=
# Flags passed to only C++ files.
-CFLAGS_CC_Default :=
+CFLAGS_CC_Debug := -fno-rtti \
+ -fno-exceptions \
+ -fvisibility-inlines-hidden \
+ -fno-threadsafe-statics
# Flags passed to only ObjC files.
-CFLAGS_OBJC_Default :=
+CFLAGS_OBJC_Debug :=
# Flags passed to only ObjC++ files.
-CFLAGS_OBJCC_Default :=
+CFLAGS_OBJCC_Debug :=
-INCS_Default := -I$(srcdir)/src/libuv/include \
+INCS_Debug := -I$(srcdir)/src/libuv/include \
+ -I$(srcdir)/src/libuv/include/uv-private \
+ -I$(srcdir)/src/libuv/src \
+ -I$(srcdir)/src/libuv/src/unix/ev \
+ -I$(srcdir)/src/libuv/src/ares/config_darwin
+
+DEFS_Release := '-D_LARGEFILE_SOURCE' \
+ '-D_FILE_OFFSET_BITS=64' \
+ '-D_GNU_SOURCE' \
+ '-DEIO_STACKSIZE=262144' \
+ '-DHAVE_CONFIG_H' \
+ '-DEV_CONFIG_H="config_darwin.h"' \
+ '-DEIO_CONFIG_H="config_darwin.h"' \
+ '-DNDEBUG'
+
+# Flags passed to all source files.
+CFLAGS_Release := -Os \
+ -gdwarf-2 \
+ -fvisibility=hidden \
+ -Wnewline-eof \
+ -arch x86_64 \
+ -fno-strict-aliasing \
+ -Wall \
+ -Wendif-labels \
+ -W \
+ -Wno-unused-parameter
+
+# Flags passed to only C files.
+CFLAGS_C_Release :=
+
+# Flags passed to only C++ files.
+CFLAGS_CC_Release := -fno-rtti \
+ -fno-exceptions \
+ -fvisibility-inlines-hidden \
+ -fno-threadsafe-statics
+
+# Flags passed to only ObjC files.
+CFLAGS_OBJC_Release :=
+
+# Flags passed to only ObjC++ files.
+CFLAGS_OBJCC_Release :=
+
+INCS_Release := -I$(srcdir)/src/libuv/include \
-I$(srcdir)/src/libuv/include/uv-private \
-I$(srcdir)/src/libuv/src \
-I$(srcdir)/src/libuv/src/unix/ev \
$(obj).target/$(TARGET)/src/libuv/src/unix/cares.o \
$(obj).target/$(TARGET)/src/libuv/src/unix/dl.o \
$(obj).target/$(TARGET)/src/libuv/src/unix/error.o \
+ $(obj).target/$(TARGET)/src/libuv/src/unix/thread.o \
$(obj).target/$(TARGET)/src/libuv/src/unix/process.o \
$(obj).target/$(TARGET)/src/libuv/src/unix/eio/eio.o \
$(obj).target/$(TARGET)/src/libuv/src/unix/ev/ev.o \
# CFLAGS et al overrides must be target-local.
# See "Target-specific Variable Values" in the GNU Make manual.
$(OBJS): TOOLSET := $(TOOLSET)
-$(OBJS): GYP_CFLAGS := $(DEFS_$(BUILDTYPE)) $(INCS_$(BUILDTYPE)) $(CFLAGS_$(BUILDTYPE)) $(CFLAGS_C_$(BUILDTYPE))
-$(OBJS): GYP_CXXFLAGS := $(DEFS_$(BUILDTYPE)) $(INCS_$(BUILDTYPE)) $(CFLAGS_$(BUILDTYPE)) $(CFLAGS_CC_$(BUILDTYPE))
-$(OBJS): GYP_OBJCFLAGS := $(DEFS_$(BUILDTYPE)) $(INCS_$(BUILDTYPE)) $(CFLAGS_$(BUILDTYPE)) $(CFLAGS_C_$(BUILDTYPE)) $(CFLAGS_OBJC_$(BUILDTYPE))
-$(OBJS): GYP_OBJCXXFLAGS := $(DEFS_$(BUILDTYPE)) $(INCS_$(BUILDTYPE)) $(CFLAGS_$(BUILDTYPE)) $(CFLAGS_CC_$(BUILDTYPE)) $(CFLAGS_OBJCC_$(BUILDTYPE))
+$(OBJS): GYP_CFLAGS := $(DEFS_$(BUILDTYPE)) $(INCS_$(BUILDTYPE)) $(CFLAGS_$(BUILDTYPE)) $(CFLAGS_C_$(BUILDTYPE))
+$(OBJS): GYP_CXXFLAGS := $(DEFS_$(BUILDTYPE)) $(INCS_$(BUILDTYPE)) $(CFLAGS_$(BUILDTYPE)) $(CFLAGS_CC_$(BUILDTYPE))
+$(OBJS): GYP_OBJCFLAGS := $(DEFS_$(BUILDTYPE)) $(INCS_$(BUILDTYPE)) $(CFLAGS_$(BUILDTYPE)) $(CFLAGS_C_$(BUILDTYPE)) $(CFLAGS_OBJC_$(BUILDTYPE))
+$(OBJS): GYP_OBJCXXFLAGS := $(DEFS_$(BUILDTYPE)) $(INCS_$(BUILDTYPE)) $(CFLAGS_$(BUILDTYPE)) $(CFLAGS_CC_$(BUILDTYPE)) $(CFLAGS_OBJCC_$(BUILDTYPE))
# Suffix rules, putting all outputs into $(obj).
# End of this set of suffix rules
### Rules for final target.
-LDFLAGS_Default := -arch x86_64 \
+LDFLAGS_Debug := -arch x86_64 \
+ -L$(builddir)
+
+LDFLAGS_Release := -arch x86_64 \
-L$(builddir)
LIBS := -lm
+++ /dev/null
-# This file is generated by gyp; do not edit.
-
-TOOLSET := target
-TARGET := uv
-DEFS_Default := '-D_LARGEFILE_SOURCE' \
- '-D_FILE_OFFSET_BITS=64' \
- '-D_GNU_SOURCE' \
- '-DEIO_STACKSIZE=262144' \
- '-DHAVE_CONFIG_H' \
- '-DEV_CONFIG_H="config_darwin.h"' \
- '-DEIO_CONFIG_H="config_darwin.h"'
-
-# Flags passed to all source files.
-CFLAGS_Default := -fasm-blocks \
- -mpascal-strings \
- -Os \
- -gdwarf-2 \
- -arch i386
-
-# Flags passed to only C files.
-CFLAGS_C_Default :=
-
-# Flags passed to only C++ files.
-CFLAGS_CC_Default :=
-
-# Flags passed to only ObjC files.
-CFLAGS_OBJC_Default :=
-
-# Flags passed to only ObjC++ files.
-CFLAGS_OBJCC_Default :=
-
-INCS_Default := -I$(srcdir)/src/libuv/include \
- -I$(srcdir)/src/libuv/include/uv-private \
- -I$(srcdir)/src/libuv/src \
- -I$(srcdir)/src/libuv/src/unix/ev \
- -I$(srcdir)/src/libuv/src/ares/config_darwin
-
-OBJS := $(obj).target/$(TARGET)/src/libuv/src/uv-common.o \
- $(obj).target/$(TARGET)/src/libuv/src/ares/ares_cancel.o \
- $(obj).target/$(TARGET)/src/libuv/src/ares/ares__close_sockets.o \
- $(obj).target/$(TARGET)/src/libuv/src/ares/ares_data.o \
- $(obj).target/$(TARGET)/src/libuv/src/ares/ares_destroy.o \
- $(obj).target/$(TARGET)/src/libuv/src/ares/ares_expand_name.o \
- $(obj).target/$(TARGET)/src/libuv/src/ares/ares_expand_string.o \
- $(obj).target/$(TARGET)/src/libuv/src/ares/ares_fds.o \
- $(obj).target/$(TARGET)/src/libuv/src/ares/ares_free_hostent.o \
- $(obj).target/$(TARGET)/src/libuv/src/ares/ares_free_string.o \
- $(obj).target/$(TARGET)/src/libuv/src/ares/ares_gethostbyaddr.o \
- $(obj).target/$(TARGET)/src/libuv/src/ares/ares_gethostbyname.o \
- $(obj).target/$(TARGET)/src/libuv/src/ares/ares__get_hostent.o \
- $(obj).target/$(TARGET)/src/libuv/src/ares/ares_getnameinfo.o \
- $(obj).target/$(TARGET)/src/libuv/src/ares/ares_getopt.o \
- $(obj).target/$(TARGET)/src/libuv/src/ares/ares_getsock.o \
- $(obj).target/$(TARGET)/src/libuv/src/ares/ares_init.o \
- $(obj).target/$(TARGET)/src/libuv/src/ares/ares_library_init.o \
- $(obj).target/$(TARGET)/src/libuv/src/ares/ares_llist.o \
- $(obj).target/$(TARGET)/src/libuv/src/ares/ares_mkquery.o \
- $(obj).target/$(TARGET)/src/libuv/src/ares/ares_nowarn.o \
- $(obj).target/$(TARGET)/src/libuv/src/ares/ares_options.o \
- $(obj).target/$(TARGET)/src/libuv/src/ares/ares_parse_aaaa_reply.o \
- $(obj).target/$(TARGET)/src/libuv/src/ares/ares_parse_a_reply.o \
- $(obj).target/$(TARGET)/src/libuv/src/ares/ares_parse_mx_reply.o \
- $(obj).target/$(TARGET)/src/libuv/src/ares/ares_parse_ns_reply.o \
- $(obj).target/$(TARGET)/src/libuv/src/ares/ares_parse_ptr_reply.o \
- $(obj).target/$(TARGET)/src/libuv/src/ares/ares_parse_srv_reply.o \
- $(obj).target/$(TARGET)/src/libuv/src/ares/ares_parse_txt_reply.o \
- $(obj).target/$(TARGET)/src/libuv/src/ares/ares_process.o \
- $(obj).target/$(TARGET)/src/libuv/src/ares/ares_query.o \
- $(obj).target/$(TARGET)/src/libuv/src/ares/ares__read_line.o \
- $(obj).target/$(TARGET)/src/libuv/src/ares/ares_search.o \
- $(obj).target/$(TARGET)/src/libuv/src/ares/ares_send.o \
- $(obj).target/$(TARGET)/src/libuv/src/ares/ares_strcasecmp.o \
- $(obj).target/$(TARGET)/src/libuv/src/ares/ares_strdup.o \
- $(obj).target/$(TARGET)/src/libuv/src/ares/ares_strerror.o \
- $(obj).target/$(TARGET)/src/libuv/src/ares/ares_timeout.o \
- $(obj).target/$(TARGET)/src/libuv/src/ares/ares__timeval.o \
- $(obj).target/$(TARGET)/src/libuv/src/ares/ares_version.o \
- $(obj).target/$(TARGET)/src/libuv/src/ares/ares_writev.o \
- $(obj).target/$(TARGET)/src/libuv/src/ares/bitncmp.o \
- $(obj).target/$(TARGET)/src/libuv/src/ares/inet_net_pton.o \
- $(obj).target/$(TARGET)/src/libuv/src/ares/inet_ntop.o \
- $(obj).target/$(TARGET)/src/libuv/src/ares/windows_port.o \
- $(obj).target/$(TARGET)/src/libuv/src/unix/core.o \
- $(obj).target/$(TARGET)/src/libuv/src/unix/uv-eio.o \
- $(obj).target/$(TARGET)/src/libuv/src/unix/fs.o \
- $(obj).target/$(TARGET)/src/libuv/src/unix/udp.o \
- $(obj).target/$(TARGET)/src/libuv/src/unix/tcp.o \
- $(obj).target/$(TARGET)/src/libuv/src/unix/pipe.o \
- $(obj).target/$(TARGET)/src/libuv/src/unix/tty.o \
- $(obj).target/$(TARGET)/src/libuv/src/unix/stream.o \
- $(obj).target/$(TARGET)/src/libuv/src/unix/cares.o \
- $(obj).target/$(TARGET)/src/libuv/src/unix/dl.o \
- $(obj).target/$(TARGET)/src/libuv/src/unix/error.o \
- $(obj).target/$(TARGET)/src/libuv/src/unix/process.o \
- $(obj).target/$(TARGET)/src/libuv/src/unix/eio/eio.o \
- $(obj).target/$(TARGET)/src/libuv/src/unix/ev/ev.o \
- $(obj).target/$(TARGET)/src/libuv/src/unix/darwin.o \
- $(obj).target/$(TARGET)/src/libuv/src/unix/kqueue.o
-
-# Add to the list of files we specially track dependencies for.
-all_deps += $(OBJS)
-
-# CFLAGS et al overrides must be target-local.
-# See "Target-specific Variable Values" in the GNU Make manual.
-$(OBJS): TOOLSET := $(TOOLSET)
-$(OBJS): GYP_CFLAGS := $(DEFS_$(BUILDTYPE)) $(INCS_$(BUILDTYPE)) $(CFLAGS_$(BUILDTYPE)) $(CFLAGS_C_$(BUILDTYPE))
-$(OBJS): GYP_CXXFLAGS := $(DEFS_$(BUILDTYPE)) $(INCS_$(BUILDTYPE)) $(CFLAGS_$(BUILDTYPE)) $(CFLAGS_CC_$(BUILDTYPE))
-$(OBJS): GYP_OBJCFLAGS := $(DEFS_$(BUILDTYPE)) $(INCS_$(BUILDTYPE)) $(CFLAGS_$(BUILDTYPE)) $(CFLAGS_C_$(BUILDTYPE)) $(CFLAGS_OBJC_$(BUILDTYPE))
-$(OBJS): GYP_OBJCXXFLAGS := $(DEFS_$(BUILDTYPE)) $(INCS_$(BUILDTYPE)) $(CFLAGS_$(BUILDTYPE)) $(CFLAGS_CC_$(BUILDTYPE)) $(CFLAGS_OBJCC_$(BUILDTYPE))
-
-# Suffix rules, putting all outputs into $(obj).
-
-$(obj).$(TOOLSET)/$(TARGET)/%.o: $(srcdir)/%.c FORCE_DO_CMD
- @$(call do_cmd,cc,1)
-
-# Try building from generated source, too.
-
-$(obj).$(TOOLSET)/$(TARGET)/%.o: $(obj).$(TOOLSET)/%.c FORCE_DO_CMD
- @$(call do_cmd,cc,1)
-
-$(obj).$(TOOLSET)/$(TARGET)/%.o: $(obj)/%.c FORCE_DO_CMD
- @$(call do_cmd,cc,1)
-
-# End of this set of suffix rules
-### Rules for final target.
-LDFLAGS_Default := -arch i386 \
- -L$(builddir)
-
-LIBS := -lm
-
-$(builddir)/libuv.a: GYP_LDFLAGS := $(LDFLAGS_$(BUILDTYPE))
-$(builddir)/libuv.a: LIBS := $(LIBS)
-$(builddir)/libuv.a: TOOLSET := $(TOOLSET)
-$(builddir)/libuv.a: $(OBJS) FORCE_DO_CMD
- $(call do_cmd,alink)
-
-all_deps += $(builddir)/libuv.a
-# Add target alias
-.PHONY: uv
-uv: $(builddir)/libuv.a
-
-# Add target alias to "all" target.
-.PHONY: all
-all: uv
-
# The source directory tree.
srcdir := ../../../..
+abs_srcdir := $(abspath $(srcdir))
# The name of the builddir.
builddir_name ?= out
endif
# Specify BUILDTYPE=Release on the command line for a release build.
-BUILDTYPE ?= Default
+BUILDTYPE ?= Debug
# Directory all our build output goes into.
# Note that this must be two directories beneath src/ for unit tests to pass,
)
endef
-# Declare "all" target first so it is the default, even though we don't have the
-# deps yet.
+# Declare the "all" target first so it is the default,
+# even though we don't have the deps yet.
.PHONY: all
all:
include src/libuv/uv.target.mk
endif
-quiet_cmd_regen_makefile = ACTION Regenerating $@
-cmd_regen_makefile = ./src/libuv/build/gyp/gyp -fmake --ignore-environment "--toplevel-dir=." "--depth=." "--generator-output=mk/libuv/x86_64/unix" "-Dlibrary=static_library" "-Dtarget_arch=x86_64" "-DOS=linux" src/libuv/uv.gyp
-Makefile: $(srcdir)/src/libuv/uv.gyp
+#quiet_cmd_regen_makefile = ACTION Regenerating $@
+#cmd_regen_makefile = ./src/libuv/build/gyp/gyp -fmake --ignore-environment "--toplevel-dir=." -Isrc/libuv/common.gypi "--depth=." "--generator-output=mk/libuv/x86_64/unix" "-Ddefault_configuration=Default" "-Dcomponent=static_library" "-Dlibrary=static_library" "-Dtarget_arch=x86_64" "-DOS=linux" src/libuv/uv.gyp
+#Makefile: $(srcdir)/src/libuv/uv.gyp $(srcdir)/src/libuv/common.gypi
# $(call do_cmd,regen_makefile)
# "all" is a concatenation of the "all" targets from all the included
+++ /dev/null
-# We borrow heavily from the kernel build setup, though we are simpler since
-# we don't have Kconfig tweaking settings on us.
-
-# The implicit make rules have it looking for RCS files, among other things.
-# We instead explicitly write all the rules we care about.
-# It's even quicker (saves ~200ms) to pass -r on the command line.
-MAKEFLAGS=-r
-
-# The source directory tree.
-srcdir := ../../../..
-
-# The name of the builddir.
-builddir_name ?= out
-
-# The V=1 flag on command line makes us verbosely print command lines.
-ifdef V
- quiet=
-else
- quiet=quiet_
-endif
-
-# Specify BUILDTYPE=Release on the command line for a release build.
-BUILDTYPE ?= Default
-
-# Directory all our build output goes into.
-# Note that this must be two directories beneath src/ for unit tests to pass,
-# as they reach into the src/ directory for data with relative paths.
-builddir ?= $(builddir_name)/$(BUILDTYPE)
-abs_builddir := $(abspath $(builddir))
-depsdir := $(builddir)/.deps
-
-# Object output directory.
-obj := $(builddir)/obj
-abs_obj := $(abspath $(obj))
-
-# We build up a list of every single one of the targets so we can slurp in the
-# generated dependency rule Makefiles in one pass.
-all_deps :=
-
-
-
-# C++ apps need to be linked with g++.
-#
-# Note: flock is used to seralize linking. Linking is a memory-intensive
-# process so running parallel links can often lead to thrashing. To disable
-# the serialization, override LINK via an envrionment variable as follows:
-#
-# export LINK=g++
-#
-# This will allow make to invoke N linker processes as specified in -jN.
-LINK ?= flock $(builddir)/linker.lock $(CXX)
-
-CC.target ?= $(CC)
-CFLAGS.target ?= $(CFLAGS)
-CXX.target ?= $(CXX)
-CXXFLAGS.target ?= $(CXXFLAGS)
-LINK.target ?= $(LINK)
-LDFLAGS.target ?= $(LDFLAGS)
-AR.target ?= $(AR)
-ARFLAGS.target ?= crsT
-
-# N.B.: the logic of which commands to run should match the computation done
-# in gyp's make.py where ARFLAGS.host etc. is computed.
-# TODO(evan): move all cross-compilation logic to gyp-time so we don't need
-# to replicate this environment fallback in make as well.
-CC.host ?= gcc
-CFLAGS.host ?=
-CXX.host ?= g++
-CXXFLAGS.host ?=
-LINK.host ?= g++
-LDFLAGS.host ?=
-AR.host ?= ar
-ARFLAGS.host := crsT
-
-# Define a dir function that can handle spaces.
-# http://www.gnu.org/software/make/manual/make.html#Syntax-of-Functions
-# "leading spaces cannot appear in the text of the first argument as written.
-# These characters can be put into the argument value by variable substitution."
-empty :=
-space := $(empty) $(empty)
-
-# http://stackoverflow.com/questions/1189781/using-make-dir-or-notdir-on-a-path-with-spaces
-replace_spaces = $(subst $(space),?,$1)
-unreplace_spaces = $(subst ?,$(space),$1)
-dirx = $(call unreplace_spaces,$(dir $(call replace_spaces,$1)))
-
-# Flags to make gcc output dependency info. Note that you need to be
-# careful here to use the flags that ccache and distcc can understand.
-# We write to a dep file on the side first and then rename at the end
-# so we can't end up with a broken dep file.
-depfile = $(depsdir)/$(call replace_spaces,$@).d
-DEPFLAGS = -MMD -MF $(depfile).raw
-
-# We have to fixup the deps output in a few ways.
-# (1) the file output should mention the proper .o file.
-# ccache or distcc lose the path to the target, so we convert a rule of
-# the form:
-# foobar.o: DEP1 DEP2
-# into
-# path/to/foobar.o: DEP1 DEP2
-# (2) we want missing files not to cause us to fail to build.
-# We want to rewrite
-# foobar.o: DEP1 DEP2 \
-# DEP3
-# to
-# DEP1:
-# DEP2:
-# DEP3:
-# so if the files are missing, they're just considered phony rules.
-# We have to do some pretty insane escaping to get those backslashes
-# and dollar signs past make, the shell, and sed at the same time.
-# Doesn't work with spaces, but that's fine: .d files have spaces in
-# their names replaced with other characters.
-define fixup_dep
-# The depfile may not exist if the input file didn't have any #includes.
-touch $(depfile).raw
-# Fixup path as in (1).
-sed -e "s|^$(notdir $@)|$@|" $(depfile).raw >> $(depfile)
-# Add extra rules as in (2).
-# We remove slashes and replace spaces with new lines;
-# remove blank lines;
-# delete the first line and append a colon to the remaining lines.
-sed -e 's|\\||' -e 'y| |\n|' $(depfile).raw |\
- grep -v '^$$' |\
- sed -e 1d -e 's|$$|:|' \
- >> $(depfile)
-rm $(depfile).raw
-endef
-
-# Command definitions:
-# - cmd_foo is the actual command to run;
-# - quiet_cmd_foo is the brief-output summary of the command.
-
-quiet_cmd_cc = CC($(TOOLSET)) $@
-cmd_cc = $(CC.$(TOOLSET)) $(GYP_CFLAGS) $(DEPFLAGS) $(CFLAGS.$(TOOLSET)) -c -o $@ $<
-
-quiet_cmd_cxx = CXX($(TOOLSET)) $@
-cmd_cxx = $(CXX.$(TOOLSET)) $(GYP_CXXFLAGS) $(DEPFLAGS) $(CXXFLAGS.$(TOOLSET)) -c -o $@ $<
-
-quiet_cmd_touch = TOUCH $@
-cmd_touch = touch $@
-
-quiet_cmd_copy = COPY $@
-# send stderr to /dev/null to ignore messages when linking directories.
-cmd_copy = ln -f "$<" "$@" 2>/dev/null || (rm -rf "$@" && cp -af "$<" "$@")
-
-quiet_cmd_alink = AR($(TOOLSET)) $@
-cmd_alink = rm -f $@ && $(AR.$(TOOLSET)) $(ARFLAGS.$(TOOLSET)) $@ $(filter %.o,$^)
-
-# Due to circular dependencies between libraries :(, we wrap the
-# special "figure out circular dependencies" flags around the entire
-# input list during linking.
-quiet_cmd_link = LINK($(TOOLSET)) $@
-cmd_link = $(LINK.$(TOOLSET)) $(GYP_LDFLAGS) $(LDFLAGS.$(TOOLSET)) -o $@ -Wl,--start-group $(LD_INPUTS) -Wl,--end-group $(LIBS)
-
-# We support two kinds of shared objects (.so):
-# 1) shared_library, which is just bundling together many dependent libraries
-# into a link line.
-# 2) loadable_module, which is generating a module intended for dlopen().
-#
-# They differ only slightly:
-# In the former case, we want to package all dependent code into the .so.
-# In the latter case, we want to package just the API exposed by the
-# outermost module.
-# This means shared_library uses --whole-archive, while loadable_module doesn't.
-# (Note that --whole-archive is incompatible with the --start-group used in
-# normal linking.)
-
-# Other shared-object link notes:
-# - Set SONAME to the library filename so our binaries don't reference
-# the local, absolute paths used on the link command-line.
-quiet_cmd_solink = SOLINK($(TOOLSET)) $@
-cmd_solink = $(LINK.$(TOOLSET)) -shared $(GYP_LDFLAGS) $(LDFLAGS.$(TOOLSET)) -Wl,-soname=$(@F) -o $@ -Wl,--whole-archive $(LD_INPUTS) -Wl,--no-whole-archive $(LIBS)
-
-quiet_cmd_solink_module = SOLINK_MODULE($(TOOLSET)) $@
-cmd_solink_module = $(LINK.$(TOOLSET)) -shared $(GYP_LDFLAGS) $(LDFLAGS.$(TOOLSET)) -Wl,-soname=$(@F) -o $@ -Wl,--start-group $(filter-out FORCE_DO_CMD, $^) -Wl,--end-group $(LIBS)
-
-
-# Define an escape_quotes function to escape single quotes.
-# This allows us to handle quotes properly as long as we always use
-# use single quotes and escape_quotes.
-escape_quotes = $(subst ','\'',$(1))
-# This comment is here just to include a ' to unconfuse syntax highlighting.
-# Define an escape_vars function to escape '$' variable syntax.
-# This allows us to read/write command lines with shell variables (e.g.
-# $LD_LIBRARY_PATH), without triggering make substitution.
-escape_vars = $(subst $$,$$$$,$(1))
-# Helper that expands to a shell command to echo a string exactly as it is in
-# make. This uses printf instead of echo because printf's behaviour with respect
-# to escape sequences is more portable than echo's across different shells
-# (e.g., dash, bash).
-exact_echo = printf '%s\n' '$(call escape_quotes,$(1))'
-
-# Helper to compare the command we're about to run against the command
-# we logged the last time we ran the command. Produces an empty
-# string (false) when the commands match.
-# Tricky point: Make has no string-equality test function.
-# The kernel uses the following, but it seems like it would have false
-# positives, where one string reordered its arguments.
-# arg_check = $(strip $(filter-out $(cmd_$(1)), $(cmd_$@)) \
-# $(filter-out $(cmd_$@), $(cmd_$(1))))
-# We instead substitute each for the empty string into the other, and
-# say they're equal if both substitutions produce the empty string.
-# .d files contain ? instead of spaces, take that into account.
-command_changed = $(or $(subst $(cmd_$(1)),,$(cmd_$(call replace_spaces,$@))),\
- $(subst $(cmd_$(call replace_spaces,$@)),,$(cmd_$(1))))
-
-# Helper that is non-empty when a prerequisite changes.
-# Normally make does this implicitly, but we force rules to always run
-# so we can check their command lines.
-# $? -- new prerequisites
-# $| -- order-only dependencies
-prereq_changed = $(filter-out FORCE_DO_CMD,$(filter-out $|,$?))
-
-# Helper that executes all postbuilds, and deletes the output file when done
-# if any of the postbuilds failed.
-define do_postbuilds
- @E=0;\
- for p in $(POSTBUILDS); do\
- eval $$p;\
- F=$$?;\
- if [ $$F -ne 0 ]; then\
- E=$$F;\
- fi;\
- done;\
- if [ $$E -ne 0 ]; then\
- rm -rf "$@";\
- exit $$E;\
- fi
-endef
-
-# do_cmd: run a command via the above cmd_foo names, if necessary.
-# Should always run for a given target to handle command-line changes.
-# Second argument, if non-zero, makes it do asm/C/C++ dependency munging.
-# Third argument, if non-zero, makes it do POSTBUILDS processing.
-# Note: We intentionally do NOT call dirx for depfile, since it contains ? for
-# spaces already and dirx strips the ? characters.
-define do_cmd
-$(if $(or $(command_changed),$(prereq_changed)),
- @$(call exact_echo, $($(quiet)cmd_$(1)))
- @mkdir -p "$(call dirx,$@)" "$(dir $(depfile))"
- $(if $(findstring flock,$(word 1,$(cmd_$1))),
- @$(cmd_$(1))
- @echo " $(quiet_cmd_$(1)): Finished",
- @$(cmd_$(1))
- )
- @$(call exact_echo,$(call escape_vars,cmd_$(call replace_spaces,$@) := $(cmd_$(1)))) > $(depfile)
- @$(if $(2),$(fixup_dep))
- $(if $(and $(3), $(POSTBUILDS)),
- $(call do_postbuilds)
- )
-)
-endef
-
-# Declare "all" target first so it is the default, even though we don't have the
-# deps yet.
-.PHONY: all
-all:
-
-# Use FORCE_DO_CMD to force a target to run. Should be coupled with
-# do_cmd.
-.PHONY: FORCE_DO_CMD
-FORCE_DO_CMD:
-
-TOOLSET := target
-# Suffix rules, putting all outputs into $(obj).
-$(obj).$(TOOLSET)/%.o: $(srcdir)/%.c FORCE_DO_CMD
- @$(call do_cmd,cc,1)
-$(obj).$(TOOLSET)/%.o: $(srcdir)/%.cc FORCE_DO_CMD
- @$(call do_cmd,cxx,1)
-$(obj).$(TOOLSET)/%.o: $(srcdir)/%.cpp FORCE_DO_CMD
- @$(call do_cmd,cxx,1)
-$(obj).$(TOOLSET)/%.o: $(srcdir)/%.cxx FORCE_DO_CMD
- @$(call do_cmd,cxx,1)
-$(obj).$(TOOLSET)/%.o: $(srcdir)/%.S FORCE_DO_CMD
- @$(call do_cmd,cc,1)
-$(obj).$(TOOLSET)/%.o: $(srcdir)/%.s FORCE_DO_CMD
- @$(call do_cmd,cc,1)
-
-# Try building from generated source, too.
-$(obj).$(TOOLSET)/%.o: $(obj).$(TOOLSET)/%.c FORCE_DO_CMD
- @$(call do_cmd,cc,1)
-$(obj).$(TOOLSET)/%.o: $(obj).$(TOOLSET)/%.cc FORCE_DO_CMD
- @$(call do_cmd,cxx,1)
-$(obj).$(TOOLSET)/%.o: $(obj).$(TOOLSET)/%.cpp FORCE_DO_CMD
- @$(call do_cmd,cxx,1)
-$(obj).$(TOOLSET)/%.o: $(obj).$(TOOLSET)/%.cxx FORCE_DO_CMD
- @$(call do_cmd,cxx,1)
-$(obj).$(TOOLSET)/%.o: $(obj).$(TOOLSET)/%.S FORCE_DO_CMD
- @$(call do_cmd,cc,1)
-$(obj).$(TOOLSET)/%.o: $(obj).$(TOOLSET)/%.s FORCE_DO_CMD
- @$(call do_cmd,cc,1)
-
-$(obj).$(TOOLSET)/%.o: $(obj)/%.c FORCE_DO_CMD
- @$(call do_cmd,cc,1)
-$(obj).$(TOOLSET)/%.o: $(obj)/%.cc FORCE_DO_CMD
- @$(call do_cmd,cxx,1)
-$(obj).$(TOOLSET)/%.o: $(obj)/%.cpp FORCE_DO_CMD
- @$(call do_cmd,cxx,1)
-$(obj).$(TOOLSET)/%.o: $(obj)/%.cxx FORCE_DO_CMD
- @$(call do_cmd,cxx,1)
-$(obj).$(TOOLSET)/%.o: $(obj)/%.S FORCE_DO_CMD
- @$(call do_cmd,cc,1)
-$(obj).$(TOOLSET)/%.o: $(obj)/%.s FORCE_DO_CMD
- @$(call do_cmd,cc,1)
-
-
-ifeq ($(strip $(foreach prefix,$(NO_LOAD),\
- $(findstring $(join ^,$(prefix)),\
- $(join ^,src/libuv/run-benchmarks.target.mk)))),)
- include src/libuv/run-benchmarks.target.mk
-endif
-ifeq ($(strip $(foreach prefix,$(NO_LOAD),\
- $(findstring $(join ^,$(prefix)),\
- $(join ^,src/libuv/run-tests.target.mk)))),)
- include src/libuv/run-tests.target.mk
-endif
-ifeq ($(strip $(foreach prefix,$(NO_LOAD),\
- $(findstring $(join ^,$(prefix)),\
- $(join ^,src/libuv/uv.target.mk)))),)
- include src/libuv/uv.target.mk
-endif
-
-quiet_cmd_regen_makefile = ACTION Regenerating $@
-cmd_regen_makefile = ./src/libuv/build/gyp/gyp -fmake --ignore-environment "--toplevel-dir=." "--depth=." "--generator-output=mk/libuv/x86_64/unix" "-Dlibrary=static_library" "-Dtarget_arch=x86_64" "-DOS=linux" src/libuv/uv.gyp
-Makefile: $(srcdir)/src/libuv/uv.gyp
- $(call do_cmd,regen_makefile)
-
-# "all" is a concatenation of the "all" targets from all the included
-# sub-makefiles. This is just here to clarify.
-all:
-
-# Add in dependency-tracking rules. $(all_deps) is the list of every single
-# target in our tree. Only consider the ones with .d (dependency) info:
-d_files := $(wildcard $(foreach f,$(all_deps),$(depsdir)/$(f).d))
-ifneq ($(d_files),)
- # Rather than include each individual .d file, concatenate them into a
- # single file which make is able to load faster. We split this into
- # commands that take 1000 files at a time to avoid overflowing the
- # command line.
- $(shell cat $(wordlist 1,1000,$(d_files)) > $(depsdir)/all.deps)
-
- ifneq ($(word 1001,$(d_files)),)
- $(error Found unprocessed dependency files (gyp didn't generate enough rules!))
- endif
-
- # make looks for ways to re-generate included makefiles, but in our case, we
- # don't have a direct way. Explicitly telling make that it has nothing to do
- # for them makes it go faster.
- $(depsdir)/all.deps: ;
-
- include $(depsdir)/all.deps
-endif
TOOLSET := target
TARGET := run-benchmarks
-DEFS_Default := '-D_LARGEFILE_SOURCE' \
+DEFS_Debug := '-D_LARGEFILE_SOURCE' \
'-D_FILE_OFFSET_BITS=64' \
'-D_GNU_SOURCE' \
- '-DEIO_STACKSIZE=262144'
+ '-DEIO_STACKSIZE=262144' \
+ '-DDEBUG' \
+ '-D_DEBUG' \
+ '-DEV_VERIFY=2'
# Flags passed to all source files.
-CFLAGS_Default := -pthread
+CFLAGS_Debug := -pthread \
+ -Wall \
+ -ansi \
+ -pthread \
+ -fvisibility=hidden \
+ -g \
+ -O0
# Flags passed to only C files.
-CFLAGS_C_Default :=
+CFLAGS_C_Debug :=
# Flags passed to only C++ files.
-CFLAGS_CC_Default :=
+CFLAGS_CC_Debug := -fno-rtti \
+ -fno-exceptions
-INCS_Default := -I$(srcdir)/src/libuv/include
+INCS_Debug := -I$(srcdir)/src/libuv/include
+
+DEFS_Release := '-D_LARGEFILE_SOURCE' \
+ '-D_FILE_OFFSET_BITS=64' \
+ '-D_GNU_SOURCE' \
+ '-DEIO_STACKSIZE=262144' \
+ '-DNDEBUG'
+
+# Flags passed to all source files.
+CFLAGS_Release := -pthread \
+ -Wall \
+ -ansi \
+ -pthread \
+ -fvisibility=hidden \
+ -O3 \
+ -fomit-frame-pointer \
+ -fdata-sections \
+ -ffunction-sections
+
+# Flags passed to only C files.
+CFLAGS_C_Release :=
+
+# Flags passed to only C++ files.
+CFLAGS_CC_Release := -fno-rtti \
+ -fno-exceptions
+
+INCS_Release := -I$(srcdir)/src/libuv/include
OBJS := $(obj).target/$(TARGET)/src/libuv/test/benchmark-ares.o \
$(obj).target/$(TARGET)/src/libuv/test/benchmark-getaddrinfo.o \
$(obj).target/$(TARGET)/src/libuv/test/benchmark-pump.o \
$(obj).target/$(TARGET)/src/libuv/test/benchmark-sizes.o \
$(obj).target/$(TARGET)/src/libuv/test/benchmark-spawn.o \
+ $(obj).target/$(TARGET)/src/libuv/test/benchmark-thread.o \
$(obj).target/$(TARGET)/src/libuv/test/benchmark-tcp-write-batch.o \
$(obj).target/$(TARGET)/src/libuv/test/benchmark-udp-packet-storm.o \
$(obj).target/$(TARGET)/src/libuv/test/dns-server.o \
# CFLAGS et al overrides must be target-local.
# See "Target-specific Variable Values" in the GNU Make manual.
$(OBJS): TOOLSET := $(TOOLSET)
-$(OBJS): GYP_CFLAGS := $(DEFS_$(BUILDTYPE)) $(INCS_$(BUILDTYPE)) $(CFLAGS_$(BUILDTYPE)) $(CFLAGS_C_$(BUILDTYPE))
-$(OBJS): GYP_CXXFLAGS := $(DEFS_$(BUILDTYPE)) $(INCS_$(BUILDTYPE)) $(CFLAGS_$(BUILDTYPE)) $(CFLAGS_CC_$(BUILDTYPE))
+$(OBJS): GYP_CFLAGS := $(DEFS_$(BUILDTYPE)) $(INCS_$(BUILDTYPE)) $(CFLAGS_$(BUILDTYPE)) $(CFLAGS_C_$(BUILDTYPE))
+$(OBJS): GYP_CXXFLAGS := $(DEFS_$(BUILDTYPE)) $(INCS_$(BUILDTYPE)) $(CFLAGS_$(BUILDTYPE)) $(CFLAGS_CC_$(BUILDTYPE))
# Suffix rules, putting all outputs into $(obj).
# End of this set of suffix rules
### Rules for final target.
-LDFLAGS_Default :=
+LDFLAGS_Debug := -pthread
+
+LDFLAGS_Release := -pthread
LIBS := -lrt
TOOLSET := target
TARGET := run-tests
-DEFS_Default := '-D_LARGEFILE_SOURCE' \
+DEFS_Debug := '-D_LARGEFILE_SOURCE' \
'-D_FILE_OFFSET_BITS=64' \
'-D_GNU_SOURCE' \
- '-DEIO_STACKSIZE=262144'
+ '-DEIO_STACKSIZE=262144' \
+ '-DDEBUG' \
+ '-D_DEBUG' \
+ '-DEV_VERIFY=2'
# Flags passed to all source files.
-CFLAGS_Default := -pthread
+CFLAGS_Debug := -pthread \
+ -Wall \
+ -ansi \
+ -pthread \
+ -fvisibility=hidden \
+ -g \
+ -O0
# Flags passed to only C files.
-CFLAGS_C_Default :=
+CFLAGS_C_Debug :=
# Flags passed to only C++ files.
-CFLAGS_CC_Default :=
+CFLAGS_CC_Debug := -fno-rtti \
+ -fno-exceptions
-INCS_Default := -I$(srcdir)/src/libuv/include
+INCS_Debug := -I$(srcdir)/src/libuv/include
+
+DEFS_Release := '-D_LARGEFILE_SOURCE' \
+ '-D_FILE_OFFSET_BITS=64' \
+ '-D_GNU_SOURCE' \
+ '-DEIO_STACKSIZE=262144' \
+ '-DNDEBUG'
+
+# Flags passed to all source files.
+CFLAGS_Release := -pthread \
+ -Wall \
+ -ansi \
+ -pthread \
+ -fvisibility=hidden \
+ -O3 \
+ -fomit-frame-pointer \
+ -fdata-sections \
+ -ffunction-sections
+
+# Flags passed to only C files.
+CFLAGS_C_Release :=
+
+# Flags passed to only C++ files.
+CFLAGS_CC_Release := -fno-rtti \
+ -fno-exceptions
+
+INCS_Release := -I$(srcdir)/src/libuv/include
OBJS := $(obj).target/$(TARGET)/src/libuv/test/blackhole-server.o \
$(obj).target/$(TARGET)/src/libuv/test/echo-server.o \
$(obj).target/$(TARGET)/src/libuv/test/run-tests.o \
$(obj).target/$(TARGET)/src/libuv/test/runner.o \
$(obj).target/$(TARGET)/src/libuv/test/test-get-loadavg.o \
+ $(obj).target/$(TARGET)/src/libuv/test/test-util.o \
$(obj).target/$(TARGET)/src/libuv/test/test-async.o \
$(obj).target/$(TARGET)/src/libuv/test/test-error.o \
$(obj).target/$(TARGET)/src/libuv/test/test-callback-stack.o \
$(obj).target/$(TARGET)/src/libuv/test/test-connection-fail.o \
+ $(obj).target/$(TARGET)/src/libuv/test/test-cwd-and-chdir.o \
$(obj).target/$(TARGET)/src/libuv/test/test-delayed-accept.o \
+ $(obj).target/$(TARGET)/src/libuv/test/test-eio-overflow.o \
$(obj).target/$(TARGET)/src/libuv/test/test-fail-always.o \
$(obj).target/$(TARGET)/src/libuv/test/test-fs.o \
$(obj).target/$(TARGET)/src/libuv/test/test-fs-event.o \
$(obj).target/$(TARGET)/src/libuv/test/test-hrtime.o \
$(obj).target/$(TARGET)/src/libuv/test/test-idle.o \
$(obj).target/$(TARGET)/src/libuv/test/test-ipc.o \
+ $(obj).target/$(TARGET)/src/libuv/test/test-ipc-threads.o \
$(obj).target/$(TARGET)/src/libuv/test/test-loop-handles.o \
$(obj).target/$(TARGET)/src/libuv/test/test-multiple-listen.o \
$(obj).target/$(TARGET)/src/libuv/test/test-pass-always.o \
$(obj).target/$(TARGET)/src/libuv/test/test-ping-pong.o \
$(obj).target/$(TARGET)/src/libuv/test/test-pipe-bind-error.o \
$(obj).target/$(TARGET)/src/libuv/test/test-pipe-connect-error.o \
+ $(obj).target/$(TARGET)/src/libuv/test/test-platform-output.o \
+ $(obj).target/$(TARGET)/src/libuv/test/test-process-title.o \
$(obj).target/$(TARGET)/src/libuv/test/test-ref.o \
$(obj).target/$(TARGET)/src/libuv/test/test-shutdown-eof.o \
$(obj).target/$(TARGET)/src/libuv/test/test-spawn.o \
$(obj).target/$(TARGET)/src/libuv/test/test-tcp-write-to-half-open-connection.o \
$(obj).target/$(TARGET)/src/libuv/test/test-tcp-writealot.o \
$(obj).target/$(TARGET)/src/libuv/test/test-threadpool.o \
+ $(obj).target/$(TARGET)/src/libuv/test/test-mutexes.o \
+ $(obj).target/$(TARGET)/src/libuv/test/test-thread.o \
$(obj).target/$(TARGET)/src/libuv/test/test-timer-again.o \
$(obj).target/$(TARGET)/src/libuv/test/test-timer.o \
$(obj).target/$(TARGET)/src/libuv/test/test-tty.o \
$(obj).target/$(TARGET)/src/libuv/test/test-udp-dgram-too-big.o \
$(obj).target/$(TARGET)/src/libuv/test/test-udp-ipv6.o \
+ $(obj).target/$(TARGET)/src/libuv/test/test-udp-options.o \
$(obj).target/$(TARGET)/src/libuv/test/test-udp-send-and-recv.o \
$(obj).target/$(TARGET)/src/libuv/test/test-udp-multicast-join.o \
+ $(obj).target/$(TARGET)/src/libuv/test/test-counters-init.o \
$(obj).target/$(TARGET)/src/libuv/test/runner-unix.o
# Add to the list of files we specially track dependencies for.
# CFLAGS et al overrides must be target-local.
# See "Target-specific Variable Values" in the GNU Make manual.
$(OBJS): TOOLSET := $(TOOLSET)
-$(OBJS): GYP_CFLAGS := $(DEFS_$(BUILDTYPE)) $(INCS_$(BUILDTYPE)) $(CFLAGS_$(BUILDTYPE)) $(CFLAGS_C_$(BUILDTYPE))
-$(OBJS): GYP_CXXFLAGS := $(DEFS_$(BUILDTYPE)) $(INCS_$(BUILDTYPE)) $(CFLAGS_$(BUILDTYPE)) $(CFLAGS_CC_$(BUILDTYPE))
+$(OBJS): GYP_CFLAGS := $(DEFS_$(BUILDTYPE)) $(INCS_$(BUILDTYPE)) $(CFLAGS_$(BUILDTYPE)) $(CFLAGS_C_$(BUILDTYPE))
+$(OBJS): GYP_CXXFLAGS := $(DEFS_$(BUILDTYPE)) $(INCS_$(BUILDTYPE)) $(CFLAGS_$(BUILDTYPE)) $(CFLAGS_CC_$(BUILDTYPE))
# Suffix rules, putting all outputs into $(obj).
# End of this set of suffix rules
### Rules for final target.
-LDFLAGS_Default :=
+LDFLAGS_Debug := -pthread
+
+LDFLAGS_Release := -pthread
LIBS := -lrt
TOOLSET := target
TARGET := uv
-DEFS_Default := '-D_LARGEFILE_SOURCE' \
+DEFS_Debug := '-D_LARGEFILE_SOURCE' \
'-D_FILE_OFFSET_BITS=64' \
'-D_GNU_SOURCE' \
'-DEIO_STACKSIZE=262144' \
'-DHAVE_CONFIG_H' \
'-DEV_CONFIG_H="config_linux.h"' \
- '-DEIO_CONFIG_H="config_linux.h"'
+ '-DEIO_CONFIG_H="config_linux.h"' \
+ '-DDEBUG' \
+ '-D_DEBUG' \
+ '-DEV_VERIFY=2'
# Flags passed to all source files.
-CFLAGS_Default := -pthread \
+CFLAGS_Debug := -pthread \
+ -Wall \
+ -ansi \
+ -pthread \
+ -fvisibility=hidden \
+ -g \
+ --std=gnu89 \
+ -pedantic \
+ -Wall \
+ -Wextra \
+ -Wno-unused-parameter \
+ -g \
+ -O0
+
+# Flags passed to only C files.
+CFLAGS_C_Debug :=
+
+# Flags passed to only C++ files.
+CFLAGS_CC_Debug := -fno-rtti \
+ -fno-exceptions
+
+INCS_Debug := -I$(srcdir)/src/libuv/include \
+ -I$(srcdir)/src/libuv/include/uv-private \
+ -I$(srcdir)/src/libuv/src \
+ -I$(srcdir)/src/libuv/src/unix/ev \
+ -I$(srcdir)/src/libuv/src/ares/config_linux
+
+DEFS_Release := '-D_LARGEFILE_SOURCE' \
+ '-D_FILE_OFFSET_BITS=64' \
+ '-D_GNU_SOURCE' \
+ '-DEIO_STACKSIZE=262144' \
+ '-DHAVE_CONFIG_H' \
+ '-DEV_CONFIG_H="config_linux.h"' \
+ '-DEIO_CONFIG_H="config_linux.h"' \
+ '-DNDEBUG'
+
+# Flags passed to all source files.
+CFLAGS_Release := -pthread \
+ -Wall \
+ -ansi \
+ -pthread \
+ -fvisibility=hidden \
-g \
--std=gnu89 \
-pedantic \
-Wall \
-Wextra \
- -Wno-unused-parameter
+ -Wno-unused-parameter \
+ -O3 \
+ -fomit-frame-pointer \
+ -fdata-sections \
+ -ffunction-sections
# Flags passed to only C files.
-CFLAGS_C_Default :=
+CFLAGS_C_Release :=
# Flags passed to only C++ files.
-CFLAGS_CC_Default :=
+CFLAGS_CC_Release := -fno-rtti \
+ -fno-exceptions
-INCS_Default := -I$(srcdir)/src/libuv/include \
+INCS_Release := -I$(srcdir)/src/libuv/include \
-I$(srcdir)/src/libuv/include/uv-private \
-I$(srcdir)/src/libuv/src \
-I$(srcdir)/src/libuv/src/unix/ev \
$(obj).target/$(TARGET)/src/libuv/src/unix/cares.o \
$(obj).target/$(TARGET)/src/libuv/src/unix/dl.o \
$(obj).target/$(TARGET)/src/libuv/src/unix/error.o \
+ $(obj).target/$(TARGET)/src/libuv/src/unix/thread.o \
$(obj).target/$(TARGET)/src/libuv/src/unix/process.o \
$(obj).target/$(TARGET)/src/libuv/src/unix/eio/eio.o \
$(obj).target/$(TARGET)/src/libuv/src/unix/ev/ev.o \
# CFLAGS et al overrides must be target-local.
# See "Target-specific Variable Values" in the GNU Make manual.
$(OBJS): TOOLSET := $(TOOLSET)
-$(OBJS): GYP_CFLAGS := $(DEFS_$(BUILDTYPE)) $(INCS_$(BUILDTYPE)) $(CFLAGS_$(BUILDTYPE)) $(CFLAGS_C_$(BUILDTYPE))
-$(OBJS): GYP_CXXFLAGS := $(DEFS_$(BUILDTYPE)) $(INCS_$(BUILDTYPE)) $(CFLAGS_$(BUILDTYPE)) $(CFLAGS_CC_$(BUILDTYPE))
+$(OBJS): GYP_CFLAGS := $(DEFS_$(BUILDTYPE)) $(INCS_$(BUILDTYPE)) $(CFLAGS_$(BUILDTYPE)) $(CFLAGS_C_$(BUILDTYPE))
+$(OBJS): GYP_CXXFLAGS := $(DEFS_$(BUILDTYPE)) $(INCS_$(BUILDTYPE)) $(CFLAGS_$(BUILDTYPE)) $(CFLAGS_CC_$(BUILDTYPE))
# Suffix rules, putting all outputs into $(obj).
# End of this set of suffix rules
### Rules for final target.
-LDFLAGS_Default :=
+LDFLAGS_Debug := -pthread
+
+LDFLAGS_Release := -pthread
LIBS := -lm
# The source directory tree.
srcdir := ../../../..
+abs_srcdir := $(abspath $(srcdir))
# The name of the builddir.
builddir_name ?= out
endif
# Specify BUILDTYPE=Release on the command line for a release build.
-BUILDTYPE ?= Default
+BUILDTYPE ?= Debug
# Directory all our build output goes into.
# Note that this must be two directories beneath src/ for unit tests to pass,
)
endef
-# Declare "all" target first so it is the default, even though we don't have the
-# deps yet.
+# Declare the "all" target first so it is the default,
+# even though we don't have the deps yet.
.PHONY: all
all:
include src/libuv/uv.target.mk
endif
-quiet_cmd_regen_makefile = ACTION Regenerating $@
-cmd_regen_makefile = ./src/libuv/build/gyp/gyp -fmake --ignore-environment "--toplevel-dir=." "--depth=." "--generator-output=mk/libuv/x86_64/win" "-Dlibrary=static_library" "-Dtarget_arch=x86_64" "-DOS=win" src/libuv/uv.gyp
-Makefile: $(srcdir)/src/libuv/uv.gyp
+#quiet_cmd_regen_makefile = ACTION Regenerating $@
+#cmd_regen_makefile = ./src/libuv/build/gyp/gyp -fmake --ignore-environment "--toplevel-dir=." -Isrc/libuv/common.gypi "--depth=." "--generator-output=mk/libuv/x86_64/win" "-Ddefault_configuration=Default" "-Dcomponent=static_library" "-Dlibrary=static_library" "-Dtarget_arch=x86_64" "-DOS=win" src/libuv/uv.gyp
+#Makefile: $(srcdir)/src/libuv/uv.gyp $(srcdir)/src/libuv/common.gypi
# $(call do_cmd,regen_makefile)
# "all" is a concatenation of the "all" targets from all the included
+++ /dev/null
-# We borrow heavily from the kernel build setup, though we are simpler since
-# we don't have Kconfig tweaking settings on us.
-
-# The implicit make rules have it looking for RCS files, among other things.
-# We instead explicitly write all the rules we care about.
-# It's even quicker (saves ~200ms) to pass -r on the command line.
-MAKEFLAGS=-r
-
-# The source directory tree.
-srcdir := ../../../..
-
-# The name of the builddir.
-builddir_name ?= out
-
-# The V=1 flag on command line makes us verbosely print command lines.
-ifdef V
- quiet=
-else
- quiet=quiet_
-endif
-
-# Specify BUILDTYPE=Release on the command line for a release build.
-BUILDTYPE ?= Default
-
-# Directory all our build output goes into.
-# Note that this must be two directories beneath src/ for unit tests to pass,
-# as they reach into the src/ directory for data with relative paths.
-builddir ?= $(builddir_name)/$(BUILDTYPE)
-abs_builddir := $(abspath $(builddir))
-depsdir := $(builddir)/.deps
-
-# Object output directory.
-obj := $(builddir)/obj
-abs_obj := $(abspath $(obj))
-
-# We build up a list of every single one of the targets so we can slurp in the
-# generated dependency rule Makefiles in one pass.
-all_deps :=
-
-
-
-# C++ apps need to be linked with g++.
-#
-# Note: flock is used to seralize linking. Linking is a memory-intensive
-# process so running parallel links can often lead to thrashing. To disable
-# the serialization, override LINK via an envrionment variable as follows:
-#
-# export LINK=g++
-#
-# This will allow make to invoke N linker processes as specified in -jN.
-LINK ?= flock $(builddir)/linker.lock $(CXX)
-
-CC.target ?= $(CC)
-CFLAGS.target ?= $(CFLAGS)
-CXX.target ?= $(CXX)
-CXXFLAGS.target ?= $(CXXFLAGS)
-LINK.target ?= $(LINK)
-LDFLAGS.target ?= $(LDFLAGS)
-AR.target ?= $(AR)
-ARFLAGS.target ?= crsT
-
-# N.B.: the logic of which commands to run should match the computation done
-# in gyp's make.py where ARFLAGS.host etc. is computed.
-# TODO(evan): move all cross-compilation logic to gyp-time so we don't need
-# to replicate this environment fallback in make as well.
-CC.host ?= gcc
-CFLAGS.host ?=
-CXX.host ?= g++
-CXXFLAGS.host ?=
-LINK.host ?= g++
-LDFLAGS.host ?=
-AR.host ?= ar
-ARFLAGS.host := crsT
-
-# Define a dir function that can handle spaces.
-# http://www.gnu.org/software/make/manual/make.html#Syntax-of-Functions
-# "leading spaces cannot appear in the text of the first argument as written.
-# These characters can be put into the argument value by variable substitution."
-empty :=
-space := $(empty) $(empty)
-
-# http://stackoverflow.com/questions/1189781/using-make-dir-or-notdir-on-a-path-with-spaces
-replace_spaces = $(subst $(space),?,$1)
-unreplace_spaces = $(subst ?,$(space),$1)
-dirx = $(call unreplace_spaces,$(dir $(call replace_spaces,$1)))
-
-# Flags to make gcc output dependency info. Note that you need to be
-# careful here to use the flags that ccache and distcc can understand.
-# We write to a dep file on the side first and then rename at the end
-# so we can't end up with a broken dep file.
-depfile = $(depsdir)/$(call replace_spaces,$@).d
-DEPFLAGS = -MMD -MF $(depfile).raw
-
-# We have to fixup the deps output in a few ways.
-# (1) the file output should mention the proper .o file.
-# ccache or distcc lose the path to the target, so we convert a rule of
-# the form:
-# foobar.o: DEP1 DEP2
-# into
-# path/to/foobar.o: DEP1 DEP2
-# (2) we want missing files not to cause us to fail to build.
-# We want to rewrite
-# foobar.o: DEP1 DEP2 \
-# DEP3
-# to
-# DEP1:
-# DEP2:
-# DEP3:
-# so if the files are missing, they're just considered phony rules.
-# We have to do some pretty insane escaping to get those backslashes
-# and dollar signs past make, the shell, and sed at the same time.
-# Doesn't work with spaces, but that's fine: .d files have spaces in
-# their names replaced with other characters.
-define fixup_dep
-# The depfile may not exist if the input file didn't have any #includes.
-touch $(depfile).raw
-# Fixup path as in (1).
-sed -e "s|^$(notdir $@)|$@|" $(depfile).raw >> $(depfile)
-# Add extra rules as in (2).
-# We remove slashes and replace spaces with new lines;
-# remove blank lines;
-# delete the first line and append a colon to the remaining lines.
-sed -e 's|\\||' -e 'y| |\n|' $(depfile).raw |\
- grep -v '^$$' |\
- sed -e 1d -e 's|$$|:|' \
- >> $(depfile)
-rm $(depfile).raw
-endef
-
-# Command definitions:
-# - cmd_foo is the actual command to run;
-# - quiet_cmd_foo is the brief-output summary of the command.
-
-quiet_cmd_cc = CC($(TOOLSET)) $@
-cmd_cc = $(CC.$(TOOLSET)) $(GYP_CFLAGS) $(DEPFLAGS) $(CFLAGS.$(TOOLSET)) -c -o $@ $<
-
-quiet_cmd_cxx = CXX($(TOOLSET)) $@
-cmd_cxx = $(CXX.$(TOOLSET)) $(GYP_CXXFLAGS) $(DEPFLAGS) $(CXXFLAGS.$(TOOLSET)) -c -o $@ $<
-
-quiet_cmd_touch = TOUCH $@
-cmd_touch = touch $@
-
-quiet_cmd_copy = COPY $@
-# send stderr to /dev/null to ignore messages when linking directories.
-cmd_copy = ln -f "$<" "$@" 2>/dev/null || (rm -rf "$@" && cp -af "$<" "$@")
-
-quiet_cmd_alink = AR($(TOOLSET)) $@
-cmd_alink = rm -f $@ && $(AR.$(TOOLSET)) $(ARFLAGS.$(TOOLSET)) $@ $(filter %.o,$^)
-
-# Due to circular dependencies between libraries :(, we wrap the
-# special "figure out circular dependencies" flags around the entire
-# input list during linking.
-quiet_cmd_link = LINK($(TOOLSET)) $@
-cmd_link = $(LINK.$(TOOLSET)) $(GYP_LDFLAGS) $(LDFLAGS.$(TOOLSET)) -o $@ -Wl,--start-group $(LD_INPUTS) -Wl,--end-group $(LIBS)
-
-# We support two kinds of shared objects (.so):
-# 1) shared_library, which is just bundling together many dependent libraries
-# into a link line.
-# 2) loadable_module, which is generating a module intended for dlopen().
-#
-# They differ only slightly:
-# In the former case, we want to package all dependent code into the .so.
-# In the latter case, we want to package just the API exposed by the
-# outermost module.
-# This means shared_library uses --whole-archive, while loadable_module doesn't.
-# (Note that --whole-archive is incompatible with the --start-group used in
-# normal linking.)
-
-# Other shared-object link notes:
-# - Set SONAME to the library filename so our binaries don't reference
-# the local, absolute paths used on the link command-line.
-quiet_cmd_solink = SOLINK($(TOOLSET)) $@
-cmd_solink = $(LINK.$(TOOLSET)) -shared $(GYP_LDFLAGS) $(LDFLAGS.$(TOOLSET)) -Wl,-soname=$(@F) -o $@ -Wl,--whole-archive $(LD_INPUTS) -Wl,--no-whole-archive $(LIBS)
-
-quiet_cmd_solink_module = SOLINK_MODULE($(TOOLSET)) $@
-cmd_solink_module = $(LINK.$(TOOLSET)) -shared $(GYP_LDFLAGS) $(LDFLAGS.$(TOOLSET)) -Wl,-soname=$(@F) -o $@ -Wl,--start-group $(filter-out FORCE_DO_CMD, $^) -Wl,--end-group $(LIBS)
-
-
-# Define an escape_quotes function to escape single quotes.
-# This allows us to handle quotes properly as long as we always use
-# use single quotes and escape_quotes.
-escape_quotes = $(subst ','\'',$(1))
-# This comment is here just to include a ' to unconfuse syntax highlighting.
-# Define an escape_vars function to escape '$' variable syntax.
-# This allows us to read/write command lines with shell variables (e.g.
-# $LD_LIBRARY_PATH), without triggering make substitution.
-escape_vars = $(subst $$,$$$$,$(1))
-# Helper that expands to a shell command to echo a string exactly as it is in
-# make. This uses printf instead of echo because printf's behaviour with respect
-# to escape sequences is more portable than echo's across different shells
-# (e.g., dash, bash).
-exact_echo = printf '%s\n' '$(call escape_quotes,$(1))'
-
-# Helper to compare the command we're about to run against the command
-# we logged the last time we ran the command. Produces an empty
-# string (false) when the commands match.
-# Tricky point: Make has no string-equality test function.
-# The kernel uses the following, but it seems like it would have false
-# positives, where one string reordered its arguments.
-# arg_check = $(strip $(filter-out $(cmd_$(1)), $(cmd_$@)) \
-# $(filter-out $(cmd_$@), $(cmd_$(1))))
-# We instead substitute each for the empty string into the other, and
-# say they're equal if both substitutions produce the empty string.
-# .d files contain ? instead of spaces, take that into account.
-command_changed = $(or $(subst $(cmd_$(1)),,$(cmd_$(call replace_spaces,$@))),\
- $(subst $(cmd_$(call replace_spaces,$@)),,$(cmd_$(1))))
-
-# Helper that is non-empty when a prerequisite changes.
-# Normally make does this implicitly, but we force rules to always run
-# so we can check their command lines.
-# $? -- new prerequisites
-# $| -- order-only dependencies
-prereq_changed = $(filter-out FORCE_DO_CMD,$(filter-out $|,$?))
-
-# Helper that executes all postbuilds, and deletes the output file when done
-# if any of the postbuilds failed.
-define do_postbuilds
- @E=0;\
- for p in $(POSTBUILDS); do\
- eval $$p;\
- F=$$?;\
- if [ $$F -ne 0 ]; then\
- E=$$F;\
- fi;\
- done;\
- if [ $$E -ne 0 ]; then\
- rm -rf "$@";\
- exit $$E;\
- fi
-endef
-
-# do_cmd: run a command via the above cmd_foo names, if necessary.
-# Should always run for a given target to handle command-line changes.
-# Second argument, if non-zero, makes it do asm/C/C++ dependency munging.
-# Third argument, if non-zero, makes it do POSTBUILDS processing.
-# Note: We intentionally do NOT call dirx for depfile, since it contains ? for
-# spaces already and dirx strips the ? characters.
-define do_cmd
-$(if $(or $(command_changed),$(prereq_changed)),
- @$(call exact_echo, $($(quiet)cmd_$(1)))
- @mkdir -p "$(call dirx,$@)" "$(dir $(depfile))"
- $(if $(findstring flock,$(word 1,$(cmd_$1))),
- @$(cmd_$(1))
- @echo " $(quiet_cmd_$(1)): Finished",
- @$(cmd_$(1))
- )
- @$(call exact_echo,$(call escape_vars,cmd_$(call replace_spaces,$@) := $(cmd_$(1)))) > $(depfile)
- @$(if $(2),$(fixup_dep))
- $(if $(and $(3), $(POSTBUILDS)),
- $(call do_postbuilds)
- )
-)
-endef
-
-# Declare "all" target first so it is the default, even though we don't have the
-# deps yet.
-.PHONY: all
-all:
-
-# Use FORCE_DO_CMD to force a target to run. Should be coupled with
-# do_cmd.
-.PHONY: FORCE_DO_CMD
-FORCE_DO_CMD:
-
-TOOLSET := target
-# Suffix rules, putting all outputs into $(obj).
-$(obj).$(TOOLSET)/%.o: $(srcdir)/%.c FORCE_DO_CMD
- @$(call do_cmd,cc,1)
-$(obj).$(TOOLSET)/%.o: $(srcdir)/%.cc FORCE_DO_CMD
- @$(call do_cmd,cxx,1)
-$(obj).$(TOOLSET)/%.o: $(srcdir)/%.cpp FORCE_DO_CMD
- @$(call do_cmd,cxx,1)
-$(obj).$(TOOLSET)/%.o: $(srcdir)/%.cxx FORCE_DO_CMD
- @$(call do_cmd,cxx,1)
-$(obj).$(TOOLSET)/%.o: $(srcdir)/%.S FORCE_DO_CMD
- @$(call do_cmd,cc,1)
-$(obj).$(TOOLSET)/%.o: $(srcdir)/%.s FORCE_DO_CMD
- @$(call do_cmd,cc,1)
-
-# Try building from generated source, too.
-$(obj).$(TOOLSET)/%.o: $(obj).$(TOOLSET)/%.c FORCE_DO_CMD
- @$(call do_cmd,cc,1)
-$(obj).$(TOOLSET)/%.o: $(obj).$(TOOLSET)/%.cc FORCE_DO_CMD
- @$(call do_cmd,cxx,1)
-$(obj).$(TOOLSET)/%.o: $(obj).$(TOOLSET)/%.cpp FORCE_DO_CMD
- @$(call do_cmd,cxx,1)
-$(obj).$(TOOLSET)/%.o: $(obj).$(TOOLSET)/%.cxx FORCE_DO_CMD
- @$(call do_cmd,cxx,1)
-$(obj).$(TOOLSET)/%.o: $(obj).$(TOOLSET)/%.S FORCE_DO_CMD
- @$(call do_cmd,cc,1)
-$(obj).$(TOOLSET)/%.o: $(obj).$(TOOLSET)/%.s FORCE_DO_CMD
- @$(call do_cmd,cc,1)
-
-$(obj).$(TOOLSET)/%.o: $(obj)/%.c FORCE_DO_CMD
- @$(call do_cmd,cc,1)
-$(obj).$(TOOLSET)/%.o: $(obj)/%.cc FORCE_DO_CMD
- @$(call do_cmd,cxx,1)
-$(obj).$(TOOLSET)/%.o: $(obj)/%.cpp FORCE_DO_CMD
- @$(call do_cmd,cxx,1)
-$(obj).$(TOOLSET)/%.o: $(obj)/%.cxx FORCE_DO_CMD
- @$(call do_cmd,cxx,1)
-$(obj).$(TOOLSET)/%.o: $(obj)/%.S FORCE_DO_CMD
- @$(call do_cmd,cc,1)
-$(obj).$(TOOLSET)/%.o: $(obj)/%.s FORCE_DO_CMD
- @$(call do_cmd,cc,1)
-
-
-ifeq ($(strip $(foreach prefix,$(NO_LOAD),\
- $(findstring $(join ^,$(prefix)),\
- $(join ^,src/libuv/run-benchmarks.target.mk)))),)
- include src/libuv/run-benchmarks.target.mk
-endif
-ifeq ($(strip $(foreach prefix,$(NO_LOAD),\
- $(findstring $(join ^,$(prefix)),\
- $(join ^,src/libuv/run-tests.target.mk)))),)
- include src/libuv/run-tests.target.mk
-endif
-ifeq ($(strip $(foreach prefix,$(NO_LOAD),\
- $(findstring $(join ^,$(prefix)),\
- $(join ^,src/libuv/uv.target.mk)))),)
- include src/libuv/uv.target.mk
-endif
-
-quiet_cmd_regen_makefile = ACTION Regenerating $@
-cmd_regen_makefile = ./src/libuv/build/gyp/gyp -fmake --ignore-environment "--toplevel-dir=." "--depth=." "--generator-output=mk/libuv/x86_64/win" "-Dlibrary=static_library" "-Dtarget_arch=x86_64" "-DOS=win" src/libuv/uv.gyp
-Makefile: $(srcdir)/src/libuv/uv.gyp
- $(call do_cmd,regen_makefile)
-
-# "all" is a concatenation of the "all" targets from all the included
-# sub-makefiles. This is just here to clarify.
-all:
-
-# Add in dependency-tracking rules. $(all_deps) is the list of every single
-# target in our tree. Only consider the ones with .d (dependency) info:
-d_files := $(wildcard $(foreach f,$(all_deps),$(depsdir)/$(f).d))
-ifneq ($(d_files),)
- # Rather than include each individual .d file, concatenate them into a
- # single file which make is able to load faster. We split this into
- # commands that take 1000 files at a time to avoid overflowing the
- # command line.
- $(shell cat $(wordlist 1,1000,$(d_files)) > $(depsdir)/all.deps)
-
- ifneq ($(word 1001,$(d_files)),)
- $(error Found unprocessed dependency files (gyp didn't generate enough rules!))
- endif
-
- # make looks for ways to re-generate included makefiles, but in our case, we
- # don't have a direct way. Explicitly telling make that it has nothing to do
- # for them makes it go faster.
- $(depsdir)/all.deps: ;
-
- include $(depsdir)/all.deps
-endif
TOOLSET := target
TARGET := run-benchmarks
-DEFS_Default :=
+DEFS_Debug := '-DWIN32' \
+ '-D_CRT_SECURE_NO_DEPRECATE' \
+ '-D_CRT_NONSTDC_NO_DEPRECATE' \
+ '-DDEBUG' \
+ '-D_DEBUG'
# Flags passed to all source files.
-CFLAGS_Default :=
+CFLAGS_Debug := -g \
+ -O0
# Flags passed to only C files.
-CFLAGS_C_Default :=
+CFLAGS_C_Debug :=
# Flags passed to only C++ files.
-CFLAGS_CC_Default :=
+CFLAGS_CC_Debug :=
-INCS_Default := -I$(srcdir)/src/libuv/include
+INCS_Debug := -I$(srcdir)/src/libuv/include
+
+DEFS_Release := '-DWIN32' \
+ '-D_CRT_SECURE_NO_DEPRECATE' \
+ '-D_CRT_NONSTDC_NO_DEPRECATE' \
+ '-DNDEBUG'
+
+# Flags passed to all source files.
+CFLAGS_Release := -O3 \
+ -fomit-frame-pointer \
+ -fdata-sections \
+ -ffunction-sections
+
+# Flags passed to only C files.
+CFLAGS_C_Release :=
+
+# Flags passed to only C++ files.
+CFLAGS_CC_Release :=
+
+INCS_Release := -I$(srcdir)/src/libuv/include
OBJS := $(obj).target/$(TARGET)/src/libuv/test/benchmark-ares.o \
$(obj).target/$(TARGET)/src/libuv/test/benchmark-getaddrinfo.o \
$(obj).target/$(TARGET)/src/libuv/test/benchmark-pump.o \
$(obj).target/$(TARGET)/src/libuv/test/benchmark-sizes.o \
$(obj).target/$(TARGET)/src/libuv/test/benchmark-spawn.o \
+ $(obj).target/$(TARGET)/src/libuv/test/benchmark-thread.o \
$(obj).target/$(TARGET)/src/libuv/test/benchmark-tcp-write-batch.o \
$(obj).target/$(TARGET)/src/libuv/test/benchmark-udp-packet-storm.o \
$(obj).target/$(TARGET)/src/libuv/test/dns-server.o \
# CFLAGS et al overrides must be target-local.
# See "Target-specific Variable Values" in the GNU Make manual.
$(OBJS): TOOLSET := $(TOOLSET)
-$(OBJS): GYP_CFLAGS := $(DEFS_$(BUILDTYPE)) $(INCS_$(BUILDTYPE)) $(CFLAGS_$(BUILDTYPE)) $(CFLAGS_C_$(BUILDTYPE))
-$(OBJS): GYP_CXXFLAGS := $(DEFS_$(BUILDTYPE)) $(INCS_$(BUILDTYPE)) $(CFLAGS_$(BUILDTYPE)) $(CFLAGS_CC_$(BUILDTYPE))
+$(OBJS): GYP_CFLAGS := $(DEFS_$(BUILDTYPE)) $(INCS_$(BUILDTYPE)) $(CFLAGS_$(BUILDTYPE)) $(CFLAGS_C_$(BUILDTYPE))
+$(OBJS): GYP_CXXFLAGS := $(DEFS_$(BUILDTYPE)) $(INCS_$(BUILDTYPE)) $(CFLAGS_$(BUILDTYPE)) $(CFLAGS_CC_$(BUILDTYPE))
# Suffix rules, putting all outputs into $(obj).
# End of this set of suffix rules
### Rules for final target.
-LDFLAGS_Default :=
+LDFLAGS_Debug :=
+
+LDFLAGS_Release :=
LIBS := ws2_32.lib \
- -lws2_32.lib
+ -lws2_32.lib \
+ -lpsapi.lib \
+ -liphlpapi.lib
$(builddir)/run-benchmarks: GYP_LDFLAGS := $(LDFLAGS_$(BUILDTYPE))
$(builddir)/run-benchmarks: LIBS := $(LIBS)
TOOLSET := target
TARGET := run-tests
-DEFS_Default :=
+DEFS_Debug := '-DWIN32' \
+ '-D_CRT_SECURE_NO_DEPRECATE' \
+ '-D_CRT_NONSTDC_NO_DEPRECATE' \
+ '-DDEBUG' \
+ '-D_DEBUG'
# Flags passed to all source files.
-CFLAGS_Default :=
+CFLAGS_Debug := -g \
+ -O0
# Flags passed to only C files.
-CFLAGS_C_Default :=
+CFLAGS_C_Debug :=
# Flags passed to only C++ files.
-CFLAGS_CC_Default :=
+CFLAGS_CC_Debug :=
-INCS_Default := -I$(srcdir)/src/libuv/include
+INCS_Debug := -I$(srcdir)/src/libuv/include
+
+DEFS_Release := '-DWIN32' \
+ '-D_CRT_SECURE_NO_DEPRECATE' \
+ '-D_CRT_NONSTDC_NO_DEPRECATE' \
+ '-DNDEBUG'
+
+# Flags passed to all source files.
+CFLAGS_Release := -O3 \
+ -fomit-frame-pointer \
+ -fdata-sections \
+ -ffunction-sections
+
+# Flags passed to only C files.
+CFLAGS_C_Release :=
+
+# Flags passed to only C++ files.
+CFLAGS_CC_Release :=
+
+INCS_Release := -I$(srcdir)/src/libuv/include
OBJS := $(obj).target/$(TARGET)/src/libuv/test/blackhole-server.o \
$(obj).target/$(TARGET)/src/libuv/test/echo-server.o \
$(obj).target/$(TARGET)/src/libuv/test/run-tests.o \
$(obj).target/$(TARGET)/src/libuv/test/runner.o \
$(obj).target/$(TARGET)/src/libuv/test/test-get-loadavg.o \
+ $(obj).target/$(TARGET)/src/libuv/test/test-util.o \
$(obj).target/$(TARGET)/src/libuv/test/test-async.o \
$(obj).target/$(TARGET)/src/libuv/test/test-error.o \
$(obj).target/$(TARGET)/src/libuv/test/test-callback-stack.o \
$(obj).target/$(TARGET)/src/libuv/test/test-connection-fail.o \
+ $(obj).target/$(TARGET)/src/libuv/test/test-cwd-and-chdir.o \
$(obj).target/$(TARGET)/src/libuv/test/test-delayed-accept.o \
+ $(obj).target/$(TARGET)/src/libuv/test/test-eio-overflow.o \
$(obj).target/$(TARGET)/src/libuv/test/test-fail-always.o \
$(obj).target/$(TARGET)/src/libuv/test/test-fs.o \
$(obj).target/$(TARGET)/src/libuv/test/test-fs-event.o \
$(obj).target/$(TARGET)/src/libuv/test/test-hrtime.o \
$(obj).target/$(TARGET)/src/libuv/test/test-idle.o \
$(obj).target/$(TARGET)/src/libuv/test/test-ipc.o \
+ $(obj).target/$(TARGET)/src/libuv/test/test-ipc-threads.o \
$(obj).target/$(TARGET)/src/libuv/test/test-loop-handles.o \
$(obj).target/$(TARGET)/src/libuv/test/test-multiple-listen.o \
$(obj).target/$(TARGET)/src/libuv/test/test-pass-always.o \
$(obj).target/$(TARGET)/src/libuv/test/test-ping-pong.o \
$(obj).target/$(TARGET)/src/libuv/test/test-pipe-bind-error.o \
$(obj).target/$(TARGET)/src/libuv/test/test-pipe-connect-error.o \
+ $(obj).target/$(TARGET)/src/libuv/test/test-platform-output.o \
+ $(obj).target/$(TARGET)/src/libuv/test/test-process-title.o \
$(obj).target/$(TARGET)/src/libuv/test/test-ref.o \
$(obj).target/$(TARGET)/src/libuv/test/test-shutdown-eof.o \
$(obj).target/$(TARGET)/src/libuv/test/test-spawn.o \
$(obj).target/$(TARGET)/src/libuv/test/test-tcp-write-to-half-open-connection.o \
$(obj).target/$(TARGET)/src/libuv/test/test-tcp-writealot.o \
$(obj).target/$(TARGET)/src/libuv/test/test-threadpool.o \
+ $(obj).target/$(TARGET)/src/libuv/test/test-mutexes.o \
+ $(obj).target/$(TARGET)/src/libuv/test/test-thread.o \
$(obj).target/$(TARGET)/src/libuv/test/test-timer-again.o \
$(obj).target/$(TARGET)/src/libuv/test/test-timer.o \
$(obj).target/$(TARGET)/src/libuv/test/test-tty.o \
$(obj).target/$(TARGET)/src/libuv/test/test-udp-dgram-too-big.o \
$(obj).target/$(TARGET)/src/libuv/test/test-udp-ipv6.o \
+ $(obj).target/$(TARGET)/src/libuv/test/test-udp-options.o \
$(obj).target/$(TARGET)/src/libuv/test/test-udp-send-and-recv.o \
$(obj).target/$(TARGET)/src/libuv/test/test-udp-multicast-join.o \
+ $(obj).target/$(TARGET)/src/libuv/test/test-counters-init.o \
$(obj).target/$(TARGET)/src/libuv/test/runner-win.o
# Add to the list of files we specially track dependencies for.
# CFLAGS et al overrides must be target-local.
# See "Target-specific Variable Values" in the GNU Make manual.
$(OBJS): TOOLSET := $(TOOLSET)
-$(OBJS): GYP_CFLAGS := $(DEFS_$(BUILDTYPE)) $(INCS_$(BUILDTYPE)) $(CFLAGS_$(BUILDTYPE)) $(CFLAGS_C_$(BUILDTYPE))
-$(OBJS): GYP_CXXFLAGS := $(DEFS_$(BUILDTYPE)) $(INCS_$(BUILDTYPE)) $(CFLAGS_$(BUILDTYPE)) $(CFLAGS_CC_$(BUILDTYPE))
+$(OBJS): GYP_CFLAGS := $(DEFS_$(BUILDTYPE)) $(INCS_$(BUILDTYPE)) $(CFLAGS_$(BUILDTYPE)) $(CFLAGS_C_$(BUILDTYPE))
+$(OBJS): GYP_CXXFLAGS := $(DEFS_$(BUILDTYPE)) $(INCS_$(BUILDTYPE)) $(CFLAGS_$(BUILDTYPE)) $(CFLAGS_CC_$(BUILDTYPE))
# Suffix rules, putting all outputs into $(obj).
# End of this set of suffix rules
### Rules for final target.
-LDFLAGS_Default :=
+LDFLAGS_Debug :=
+
+LDFLAGS_Release :=
LIBS := ws2_32.lib \
- -lws2_32.lib
+ -lws2_32.lib \
+ -lpsapi.lib \
+ -liphlpapi.lib
$(builddir)/run-tests: GYP_LDFLAGS := $(LDFLAGS_$(BUILDTYPE))
$(builddir)/run-tests: LIBS := $(LIBS)
TOOLSET := target
TARGET := uv
-DEFS_Default := '-DHAVE_CONFIG_H' \
- '-D_WIN32_WINNT=0x0502' \
+DEFS_Debug := '-DWIN32' \
+ '-D_CRT_SECURE_NO_DEPRECATE' \
+ '-D_CRT_NONSTDC_NO_DEPRECATE' \
+ '-DHAVE_CONFIG_H' \
+ '-D_WIN32_WINNT=0x0600' \
'-DEIO_STACKSIZE=262144' \
- '-D_GNU_SOURCE'
+ '-D_GNU_SOURCE' \
+ '-DDEBUG' \
+ '-D_DEBUG'
# Flags passed to all source files.
-CFLAGS_Default :=
+CFLAGS_Debug := -g \
+ -O0
# Flags passed to only C files.
-CFLAGS_C_Default :=
+CFLAGS_C_Debug :=
# Flags passed to only C++ files.
-CFLAGS_CC_Default :=
+CFLAGS_CC_Debug :=
-INCS_Default := -I$(srcdir)/src/libuv/include \
+INCS_Debug := -I$(srcdir)/src/libuv/include \
+ -I$(srcdir)/src/libuv/include/uv-private \
+ -I$(srcdir)/src/libuv/src \
+ -I$(srcdir)/src/libuv/src/ares/config_win32
+
+DEFS_Release := '-DWIN32' \
+ '-D_CRT_SECURE_NO_DEPRECATE' \
+ '-D_CRT_NONSTDC_NO_DEPRECATE' \
+ '-DHAVE_CONFIG_H' \
+ '-D_WIN32_WINNT=0x0600' \
+ '-DEIO_STACKSIZE=262144' \
+ '-D_GNU_SOURCE' \
+ '-DNDEBUG'
+
+# Flags passed to all source files.
+CFLAGS_Release := -O3 \
+ -fomit-frame-pointer \
+ -fdata-sections \
+ -ffunction-sections
+
+# Flags passed to only C files.
+CFLAGS_C_Release :=
+
+# Flags passed to only C++ files.
+CFLAGS_CC_Release :=
+
+INCS_Release := -I$(srcdir)/src/libuv/include \
-I$(srcdir)/src/libuv/include/uv-private \
-I$(srcdir)/src/libuv/src \
-I$(srcdir)/src/libuv/src/ares/config_win32
$(obj).target/$(TARGET)/src/libuv/src/win/handle.o \
$(obj).target/$(TARGET)/src/libuv/src/win/loop-watcher.o \
$(obj).target/$(TARGET)/src/libuv/src/win/pipe.o \
+ $(obj).target/$(TARGET)/src/libuv/src/win/thread.o \
$(obj).target/$(TARGET)/src/libuv/src/win/process.o \
$(obj).target/$(TARGET)/src/libuv/src/win/req.o \
$(obj).target/$(TARGET)/src/libuv/src/win/stream.o \
$(obj).target/$(TARGET)/src/libuv/src/win/tcp.o \
$(obj).target/$(TARGET)/src/libuv/src/win/tty.o \
$(obj).target/$(TARGET)/src/libuv/src/win/threadpool.o \
- $(obj).target/$(TARGET)/src/libuv/src/win/threads.o \
$(obj).target/$(TARGET)/src/libuv/src/win/timer.o \
$(obj).target/$(TARGET)/src/libuv/src/win/udp.o \
$(obj).target/$(TARGET)/src/libuv/src/win/util.o \
# CFLAGS et al overrides must be target-local.
# See "Target-specific Variable Values" in the GNU Make manual.
$(OBJS): TOOLSET := $(TOOLSET)
-$(OBJS): GYP_CFLAGS := $(DEFS_$(BUILDTYPE)) $(INCS_$(BUILDTYPE)) $(CFLAGS_$(BUILDTYPE)) $(CFLAGS_C_$(BUILDTYPE))
-$(OBJS): GYP_CXXFLAGS := $(DEFS_$(BUILDTYPE)) $(INCS_$(BUILDTYPE)) $(CFLAGS_$(BUILDTYPE)) $(CFLAGS_CC_$(BUILDTYPE))
+$(OBJS): GYP_CFLAGS := $(DEFS_$(BUILDTYPE)) $(INCS_$(BUILDTYPE)) $(CFLAGS_$(BUILDTYPE)) $(CFLAGS_C_$(BUILDTYPE))
+$(OBJS): GYP_CXXFLAGS := $(DEFS_$(BUILDTYPE)) $(INCS_$(BUILDTYPE)) $(CFLAGS_$(BUILDTYPE)) $(CFLAGS_CC_$(BUILDTYPE))
# Suffix rules, putting all outputs into $(obj).
# End of this set of suffix rules
### Rules for final target.
-LDFLAGS_Default :=
+LDFLAGS_Debug :=
+
+LDFLAGS_Release :=
LIBS :=
CFG_INSTALL_NAME = -Wl,-install_name,@rpath/$(1)
endif
+# Hack: not sure how to test if a file exists in make other than this
+OS_SUPP = $(patsubst %,--suppressions=%,\
+ $(wildcard $(CFG_SRC_DIR)src/etc/$(CFG_OSTYPE).supp*))
+
ifneq ($(findstring mingw,$(CFG_OSTYPE)),)
CFG_WINDOWSY := 1
endif
ifdef CFG_VALGRIND
CFG_VALGRIND += --leak-check=full \
--error-exitcode=100 \
- --quiet --suppressions=$(CFG_SRC_DIR)src/etc/x86.supp
+ --quiet \
+ --suppressions=$(CFG_SRC_DIR)src/etc/x86.supp \
+ $(OS_SUPP)
endif
endif
rt/rust_run_program.cpp \
rt/rust_crate_cache.cpp \
rt/rust_env.cpp \
+ rt/rust_task_thread.cpp \
rt/rust_scheduler.cpp \
rt/rust_task.cpp \
rt/rust_task_list.cpp \
rt/rust_uv.cpp \
rt/rust_uvtmp.cpp \
rt/rust_log.cpp \
- rt/rust_timer.cpp \
rt/circular_buffer.cpp \
rt/isaac/randport.cpp \
rt/rust_srv.cpp \
rt/rust_kernel.cpp \
rt/rust_shape.cpp \
rt/rust_obstack.cpp \
- rt/rust_gc.cpp \
rt/rust_abi.cpp \
rt/rust_cc.cpp \
rt/rust_debug.cpp \
rt/memory_region.cpp \
- rt/test/rust_test_harness.cpp \
- rt/test/rust_test_runtime.cpp \
- rt/test/rust_test_util.cpp \
+ rt/boxed_region.cpp \
rt/arch/$$(HOST_$(1))/context.cpp
RUNTIME_S_$(1) := rt/arch/$$(HOST_$(1))/_context.S \
rt/rust_abi.h \
rt/rust_cc.h \
rt/rust_debug.h \
- rt/rust_gc.h \
rt/rust_internal.h \
rt/rust_util.h \
rt/rust_env.h \
rt/rust_unwind.h \
rt/rust_upcall.h \
rt/rust_port.h \
+ rt/rust_task_thread.h \
rt/rust_scheduler.h \
rt/rust_shape.h \
rt/rust_task.h \
rt/rust_kernel.h \
rt/memory_region.h \
rt/memory.h \
- rt/test/rust_test_harness.h \
- rt/test/rust_test_runtime.h \
- rt/test/rust_test_util.h \
rt/arch/$$(HOST_$(1))/context.h \
rt/arch/$$(HOST_$(1))/regs.h
ifeq ($$(CFG_WINDOWSY), 1)
LIBUV_OSTYPE_$(1) := win
- LIBUV_LIB_$(1) := rt/$(1)/libuv/Default/obj.target/src/libuv/libuv.a
+ LIBUV_LIB_$(1) := rt/$(1)/libuv/Release/obj.target/src/libuv/libuv.a
else ifeq ($(CFG_OSTYPE), apple-darwin)
LIBUV_OSTYPE_$(1) := mac
- LIBUV_LIB_$(1) := rt/$(1)/libuv/Default/libuv.a
+ LIBUV_LIB_$(1) := rt/$(1)/libuv/Release/libuv.a
else ifeq ($(CFG_OSTYPE), unknown-freebsd)
LIBUV_OSTYPE_$(1) := freebsd
- LIBUV_LIB_$(1) := rt/$(1)/libuv/Default/obj.target/src/libuv/libuv.a
+ LIBUV_LIB_$(1) := rt/$(1)/libuv/Release/obj.target/src/libuv/libuv.a
else
LIBUV_OSTYPE_$(1) := unix
- LIBUV_LIB_$(1) := rt/$(1)/libuv/Default/obj.target/src/libuv/libuv.a
+ LIBUV_LIB_$(1) := rt/$(1)/libuv/Release/obj.target/src/libuv/libuv.a
endif
RUNTIME_DEF_$(1) := rt/rustrt$$(CFG_DEF_SUFFIX)
CC="$$(CFG_GCCISH_CROSS)$$(CC)" \
CXX="$$(CFG_GCCISH_CROSS)$$(CXX)" \
AR="$$(CFG_GCCISH_CROSS)$$(AR)" \
+ BUILDTYPE=Release \
builddir_name="$$(CFG_BUILD_DIR)/rt/$(1)/libuv" \
V=$$(VERBOSE) FLOCK= uv
url: str,
method: str,
description: str,
- ref: option::t<str>,
+ ref: option<str>,
tags: [str]
};
type source = {
name: str,
url: str,
- sig: option::t<str>,
- key: option::t<str>,
- keyfp: option::t<str>,
+ sig: option<str>,
+ key: option<str>,
+ keyfp: option<str>,
mutable packages: [package]
};
name: str,
vers: str,
uuid: str,
- desc: option::t<str>,
- sigs: option::t<str>,
- crate_type: option::t<str>
+ desc: option<str>,
+ sigs: option<str>,
+ crate_type: option<str>
};
fn info(msg: str) {
io::stdout().write_line("error: " + msg);
}
-fn load_link(mis: [@ast::meta_item]) -> (option::t<str>,
- option::t<str>,
- option::t<str>) {
+fn load_link(mis: [@ast::meta_item]) -> (option<str>,
+ option<str>,
+ option<str>) {
let name = none;
let vers = none;
let uuid = none;
_ { }
}
}
+ _ { fail "load_link: meta items must be name-values"; }
}
}
(name, vers, uuid)
}
-fn load_pkg(filename: str) -> option::t<pkg> {
+fn load_pkg(filename: str) -> option<pkg> {
let cm = codemap::new_codemap();
let handler = diagnostic::mk_handler(none);
let sess = @{
uuid = u;
}
}
+ _ { fail "load_pkg: pkg attributes may not contain meta_words"; }
}
}
if (start >= str::char_len(s)) {
""
} else {
- str::char_slice(s, start, str::char_len(s))
+ str::slice(s, start, str::char_len(s))
}
}
}
}
-fn install_git(c: cargo, wd: str, url: str, ref: option::t<str>) {
+fn install_git(c: cargo, wd: str, url: str, ref: option<str>) {
run::run_program("git", ["clone", url, wd]);
if option::is_some::<str>(ref) {
let r = option::get::<str>(ref);
error("Can't find package " + src + "/" + name);
}
-fn cmd_install(c: cargo, argv: [str]) {
+fn cmd_install(c: cargo, argv: [str]) unsafe {
// cargo install <pkg>
if vec::len(argv) < 3u {
cmd_usage();
let uuid = rest(target, 5u);
let idx = str::index(uuid, '/' as u8);
if idx != -1 {
- let source = str::slice(uuid, 0u, idx as uint);
- uuid = str::slice(uuid, idx as uint + 1u, str::byte_len(uuid));
+ let source = str::unsafe::slice_bytes(uuid, 0u, idx as uint);
+ uuid = str::unsafe::slice_bytes(uuid, idx as uint + 1u,
+ str::byte_len(uuid));
install_uuid_specific(c, wd, source, uuid);
} else {
install_uuid(c, wd, uuid);
let name = target;
let idx = str::index(name, '/' as u8);
if idx != -1 {
- let source = str::slice(name, 0u, idx as uint);
- name = str::slice(name, idx as uint + 1u, str::byte_len(name));
+ let source = str::unsafe::slice_bytes(name, 0u, idx as uint);
+ name = str::unsafe::slice_bytes(name, idx as uint + 1u,
+ str::byte_len(name));
install_named_specific(c, wd, source, name);
} else {
install_named(c, wd, name);
const frame_glue_fns_field_reloc: int = 2;
-// n.b. must be same as cbox_elt_refcnt
-const box_rc_field_refcnt: int = 0;
-const box_rc_field_body: int = 1;
+const box_field_refcnt: int = 0;
+const box_field_tydesc: int = 1;
+const box_field_prev: int = 2;
+const box_field_next: int = 3;
+const box_field_body: int = 4;
const general_code_alignment: int = 16;
const fn_field_code: int = 0;
const fn_field_box: int = 1;
-// closure_box, see trans_closure.rs
-//
-// n.b. the refcnt must be compatible with a normal box
-const cbox_elt_refcnt: int = 0;
-const cbox_elt_tydesc: int = 1;
-const cbox_elt_ty_params: int = 2;
-const cbox_elt_bindings: int = 3;
+// closures, see trans_closure.rs
+const closure_body_ty_params: int = 0;
+const closure_body_bindings: int = 1;
const vec_elt_fill: int = 0;
import std::sha1::sha1;
import syntax::ast;
import syntax::print::pprust;
-import lib::llvm::llvm::ModuleRef;
-import lib::llvm::mk_pass_manager;
-import lib::llvm::mk_target_data;
-import lib::llvm::False;
+import lib::llvm::{ModuleRef, mk_pass_manager, mk_target_data, True, False};
import util::filesearch;
+import middle::ast_map::{path, path_mod, path_name};
enum output_type {
output_type_none,
} else { sess.fatal(msg + ": " + str::from_cstr(buf)); }
}
-fn load_intrinsics_bc(sess: session) -> option::t<ModuleRef> {
+fn load_intrinsics_bc(sess: session) -> option<ModuleRef> {
let path = alt filesearch::search(
sess.filesearch,
bind filesearch::pick_file("intrinsics.bc", _)) {
let MPMB = llvm::LLVMPassManagerBuilderCreate();
llvm::LLVMPassManagerBuilderSetOptLevel(MPMB,
opts.optimize as c_uint);
- llvm::LLVMPassManagerBuilderSetSizeLevel(MPMB, 0);
+ llvm::LLVMPassManagerBuilderSetSizeLevel(MPMB, False);
llvm::LLVMPassManagerBuilderSetDisableUnitAtATime(MPMB, False);
llvm::LLVMPassManagerBuilderSetDisableUnrollLoops(MPMB, False);
llvm::LLVMPassManagerBuilderSetDisableSimplifyLibCalls(MPMB,
sha: sha1) -> link_meta {
type provided_metas =
- {name: option::t<str>,
- vers: option::t<str>,
+ {name: option<str>,
+ vers: option<str>,
cmh_items: [@ast::meta_item]};
fn provided_link_metas(sess: session, c: ast::crate) ->
provided_metas {
- let name: option::t<str> = none;
- let vers: option::t<str> = none;
+ let name: option<str> = none;
+ let vers: option<str> = none;
let cmh_items: [@ast::meta_item] = [];
let linkage_metas = attr::find_linkage_metas(c.node.attrs);
attr::require_unique_names(sess, linkage_metas);
ret hash;
}
-fn mangle(ss: [str]) -> str {
+fn mangle(ss: path) -> str {
// Follow C++ namespace-mangling style
let n = "_ZN"; // Begin name-sequence.
- for s: str in ss { n += #fmt["%u%s", str::byte_len(s), s]; }
+ for s in ss {
+ alt s { path_name(s) | path_mod(s) {
+ n += #fmt["%u%s", str::byte_len(s), s];
+ } }
+ }
n += "E"; // End name-sequence.
-
- ret n;
+ n
}
-fn exported_name(path: [str], hash: str, _vers: str) -> str {
+fn exported_name(path: path, hash: str, _vers: str) -> str {
// FIXME: versioning isn't working yet
-
- ret mangle(path + [hash]); // + "@" + vers;
+ ret mangle(path + [path_name(hash)]); // + "@" + vers;
}
-fn mangle_exported_name(ccx: @crate_ctxt, path: [str], t: ty::t) -> str {
+fn mangle_exported_name(ccx: @crate_ctxt, path: path, t: ty::t) -> str {
let hash = get_symbol_hash(ccx, t);
ret exported_name(path, hash, ccx.link_meta.vers);
}
str {
let s = util::ppaux::ty_to_short_str(ccx.tcx, t);
let hash = get_symbol_hash(ccx, t);
- ret mangle([name, s, hash]);
+ ret mangle([path_name(name), path_name(s), path_name(hash)]);
}
-fn mangle_internal_name_by_path_and_seq(ccx: @crate_ctxt, path: [str],
+fn mangle_internal_name_by_path_and_seq(ccx: @crate_ctxt, path: path,
flav: str) -> str {
- ret mangle(path + [ccx.names(flav)]);
+ ret mangle(path + [path_name(ccx.names(flav))]);
}
-fn mangle_internal_name_by_path(_ccx: @crate_ctxt, path: [str]) -> str {
+fn mangle_internal_name_by_path(_ccx: @crate_ctxt, path: path) -> str {
ret mangle(path);
}
out_filename: str,
lm: link_meta) {
// Converts a library file name into a gcc -l argument
- fn unlib(config: @session::config, filename: str) -> str {
+ fn unlib(config: @session::config, filename: str) -> str unsafe {
let rmlib = fn@(filename: str) -> str {
if config.os == session::os_macos ||
(config.os == session::os_linux ||
config.os == session::os_freebsd) &&
str::find(filename, "lib") == 0 {
- ret str::slice(filename, 3u,
+ ret str::unsafe::slice_bytes(filename, 3u,
str::byte_len(filename));
} else { ret filename; }
};
export get_rpath_flags;
+pure fn not_win32(os: session::os) -> bool {
+ alt os {
+ session::os_win32 { false }
+ _ { true }
+ }
+}
+
fn get_rpath_flags(sess: session::session, out_filename: str) -> [str] {
let os = sess.targ_cfg.os;
fn get_rpath_relative_to_output(os: session::os,
cwd: fs::path,
output: fs::path,
- &&lib: fs::path) -> str {
+ &&lib: fs::path) : not_win32(os) -> str {
// Mac doesn't appear to support $ORIGIN
let prefix = alt os {
session::os_linux { "$ORIGIN" + fs::path_sep() }
session::os_freebsd { "$ORIGIN" + fs::path_sep() }
session::os_macos { "@executable_path" + fs::path_sep() }
+ session::os_win32 { std::util::unreachable(); }
};
prefix + get_relative_to(
#[test]
#[cfg(target_os = "linux")]
fn test_rpath_relative() {
- let res = get_rpath_relative_to_output(session::os_linux,
+ let o = session::os_linux;
+ check not_win32(o);
+ let res = get_rpath_relative_to_output(o,
"/usr", "bin/rustc", "lib/libstd.so");
- assert res == "$ORIGIN/../lib";
+ assert res == "$ORIGIN/../lib";
}
#[test]
#[cfg(target_os = "freebsd")]
fn test_rpath_relative() {
- let res = get_rpath_relative_to_output(session::os_freebsd,
+ let o = session::os_freebsd;
+ check not_win32(o);
+ let res = get_rpath_relative_to_output(o,
"/usr", "bin/rustc", "lib/libstd.so");
- assert res == "$ORIGIN/../lib";
+ assert res == "$ORIGIN/../lib";
}
#[test]
#[cfg(target_os = "macos")]
fn test_rpath_relative() {
- let res = get_rpath_relative_to_output(session::os_macos,
- "/usr", "bin/rustc", "lib/libstd.so");
+ // this is why refinements would be nice
+ let o = session::os_macos;
+ check not_win32(o);
+ let res = get_rpath_relative_to_output(o, "/usr", "bin/rustc",
+ "lib/libstd.so");
assert res == "@executable_path/../lib";
}
T_int, T_nil, T_dict,
T_opaque_vec, T_ptr,
T_size_t, T_void};
-import lib::llvm::type_names;
-import lib::llvm::llvm::ModuleRef;
-import lib::llvm::llvm::ValueRef;
-import lib::llvm::llvm::TypeRef;
+import lib::llvm::{type_names, ModuleRef, ValueRef, TypeRef};
type upcalls =
{_fail: ValueRef,
malloc: ValueRef,
free: ValueRef,
+ validate_box: ValueRef,
shared_malloc: ValueRef,
shared_free: ValueRef,
mark: ValueRef,
T_ptr(T_i8()),
size_t]),
malloc:
- d("malloc", [size_t, T_ptr(tydesc_type)],
+ d("malloc", [T_ptr(tydesc_type)],
T_ptr(T_i8())),
free:
- dv("free", [T_ptr(T_i8()), int_t]),
+ dv("free", [T_ptr(T_i8())]),
+ validate_box:
+ dv("validate_box", [T_ptr(T_i8())]),
shared_malloc:
d("shared_malloc", [size_t, T_ptr(tydesc_type)],
T_ptr(T_i8())),
fn print_diagnostic(topic: str, lvl: level, msg: str) {
if str::is_not_empty(topic) {
- io::stdout().write_str(#fmt["%s ", topic]);
+ io::stderr().write_str(#fmt["%s ", topic]);
}
if term::color_supported() {
- term::fg(io::stdout(), diagnosticcolor(lvl));
+ term::fg(io::stderr(), diagnosticcolor(lvl));
}
- io::stdout().write_str(#fmt["%s:", diagnosticstr(lvl)]);
+ io::stderr().write_str(#fmt["%s:", diagnosticstr(lvl)]);
if term::color_supported() {
- term::reset(io::stdout());
+ term::reset(io::stderr());
}
- io::stdout().write_str(#fmt[" %s\n", msg]);
+ io::stderr().write_str(#fmt[" %s\n", msg]);
}
fn emit(cmsp: option<(codemap::codemap, span)>,
fn highlight_lines(cm: codemap::codemap, sp: span,
lines: @codemap::file_lines) {
- // If we're not looking at a real file then we can't re-open it to
- // pull out the lines
- if lines.name == "-" { ret; }
-
- let fm = codemap::get_filemap(cm, lines.name);
+ let fm = lines.file;
// arbitrarily only print up to six lines of the error
let max_lines = 6u;
}
// Print the offending lines
for line: uint in display_lines {
- io::stdout().write_str(#fmt["%s:%u ", fm.name, line + 1u]);
+ io::stderr().write_str(#fmt["%s:%u ", fm.name, line + 1u]);
let s = codemap::get_line(fm, line as int);
if !str::ends_with(s, "\n") { s += "\n"; }
- io::stdout().write_str(s);
+ io::stderr().write_str(s);
}
if elided {
let last_line = display_lines[vec::len(display_lines) - 1u];
let out = "";
while indent > 0u { out += " "; indent -= 1u; }
out += "...\n";
- io::stdout().write_str(out);
+ io::stderr().write_str(out);
}
let width = hi.col - lo.col - 1u;
while width > 0u { str::push_char(s, '~'); width -= 1u; }
}
- io::stdout().write_str(s + "\n");
+ io::stderr().write_str(s + "\n");
}
}
if !input_is_stdin(input) {
parser::parse_crate_from_file(input, cfg, sess.parse_sess)
} else {
- let src = @str::unsafe_from_bytes(io::stdin().read_whole_stream());
+ let src = @str::from_bytes(io::stdin().read_whole_stream());
parser::parse_crate_from_source_str(input, src, cfg, sess.parse_sess)
}
}
fn compile_upto(sess: session, cfg: ast::crate_cfg,
input: str, upto: compile_upto,
- outputs: option::t<output_filenames>)
- -> {crate: @ast::crate, tcx: option::t<ty::ctxt>} {
+ outputs: option<output_filenames>)
+ -> {crate: @ast::crate, tcx: option<ty::ctxt>} {
let time_passes = sess.opts.time_passes;
let crate = time(time_passes, "parsing",
bind parse_input(sess, cfg, input));
}
fn compile_input(sess: session, cfg: ast::crate_cfg, input: str,
- outdir: option::t<str>, output: option::t<str>) {
+ outdir: option<str>, output: option<str>) {
let upto = if sess.opts.parse_only { cu_parse }
else if sess.opts.no_trans { cu_no_trans }
// grabbing (at compile time) the target triple that this rustc is
// built with and calling that (at runtime) the host triple.
let ht = #env("CFG_HOST_TRIPLE");
- ret ht != "" ? ht : fail "rustc built without CFG_HOST_TRIPLE";
+ ret if ht != "" {
+ ht
+ } else {
+ fail "rustc built without CFG_HOST_TRIPLE"
+ };
}
fn build_session_options(match: getopts::match,
if opt_present(match, "no-lint-ctypes") {
lint_opts += [(lint::ctypes, false)];
}
+ let monomorphize = opt_present(match, "monomorphize");
let output_type =
if parse_only || no_trans {
let addl_lib_search_paths = getopts::opt_strs(match, "L");
let cfg = parse_cfgspecs(getopts::opt_strs(match, "cfg"));
let test = opt_present(match, "test");
- let do_gc = opt_present(match, "gc");
let warn_unused_imports = opt_present(match, "warn-unused-imports");
let sopts: @session::options =
@{crate_type: crate_type,
test: test,
parse_only: parse_only,
no_trans: no_trans,
- do_gc: do_gc,
no_asm_comments: no_asm_comments,
+ monomorphize: monomorphize,
warn_unused_imports: warn_unused_imports};
ret sopts;
}
optflag("time-passes"), optflag("time-llvm-passes"),
optflag("no-verify"),
optflag("no-lint-ctypes"),
+ optflag("monomorphize"),
optmulti("cfg"), optflag("test"),
optflag("lib"), optflag("bin"), optflag("static"), optflag("gc"),
optflag("no-asm-comments"),
type output_filenames = @{out_filename: str, obj_filename:str};
fn build_output_filenames(ifile: str,
- odir: option::t<str>,
- ofile: option::t<str>,
+ odir: option<str>,
+ ofile: option<str>,
sess: session)
-> output_filenames {
let obj_path = "";
let match =
alt getopts::getopts(["--test"], opts()) {
ok(m) { m }
+ err(f) { fail "test_switch_implies_cfg_test: " +
+ getopts::fail_str(f); }
};
let sessopts = build_session_options(match, diagnostic::emit);
let sess = build_session(sessopts, "", diagnostic::emit);
let match =
alt getopts::getopts(["--test", "--cfg=test"], opts()) {
ok(m) { m }
+ err(f) { fail "test_switch_implies_cfg_test_unless_cfg_test: " +
+ getopts::fail_str(f); }
};
let sessopts = build_session_options(match, diagnostic::emit);
let sess = build_session(sessopts, "", diagnostic::emit);
}
fn usage(argv0: str) {
- io::stdout().write_str(#fmt["usage: %s [options] <input>\n", argv0] +
+ io::stdout().write_str(#fmt["Usage: %s [options] <input>\n", argv0] +
"
-options:
-
- -h --help display this message
- -v --version print version info and exit
-
- -o <filename> write output to <filename>
- --out-dir <dir> write output to compiler-chosen filename in <dir>
- --lib compile a library crate
- --bin compile an executable crate (default)
- --static use or produce static libraries
- --pretty [type] pretty-print the input instead of compiling
- --ls list the symbols defined by a crate file
- -L <path> add a directory to the library search path
- --no-verify suppress LLVM verification step (slight speedup)
- --parse-only parse only; do not compile, assemble, or link
- --no-trans run all passes except translation; no output
- -g produce debug info
- --opt-level <lvl> optimize with possible levels 0-3
- -O equivalent to --opt-level=2
- -S compile only; do not assemble or link
- --no-asm-comments do not add comments into the assembly source
- -c compile and assemble, but do not link
- --emit-llvm produce an LLVM bitcode file
- --save-temps write intermediate files in addition to normal output
- --stats gather and report various compilation statistics
- --cfg <cfgspec> configure the compilation environment
- --time-passes time the individual phases of the compiler
- --time-llvm-passes time the individual phases of the LLVM backend
- --sysroot <path> override the system root
- --target <triple> target to compile for (default: host triple)
- --test build test harness
- --gc garbage collect shared data (experimental/temporary)
+Options:
+
+ --bin Compile an executable crate (default)
+ -c Compile and assemble, but do not link
+ --cfg <cfgspec> Configure the compilation environment
+ --emit-llvm Produce an LLVM bitcode file
+ -g Produce debug info
+ --gc Garbage collect shared data (experimental/temporary)
+ -h --help Display this message
+ -L <path> Add a directory to the library search path
+ --lib Compile a library crate
+ --ls List the symbols defined by a compiled library crate
+ --no-asm-comments Do not add comments into the assembly source
+ --no-lint-ctypes Suppress warnings for possibly incorrect ctype usage
+ --no-trans Run all passes except translation; no output
+ --no-verify Suppress LLVM verification step (slight speedup)
+ (see http://llvm.org/docs/Passes.html for detail)
+ -O Equivalent to --opt-level=2
+ -o <filename> Write output to <filename>
+ --opt-level <lvl> Optimize with possible levels 0-3
+ --out-dir <dir> Write output to compiler-chosen filename in <dir>
+ --parse-only Parse only; do not compile, assemble, or link
+ --pretty [type] Pretty-print the input instead of compiling;
+ valid types are: normal (un-annotated source),
+ expanded (crates expanded), typed (crates expanded,
+ with type annotations), or identified (fully
+ parenthesized, AST nodes and blocks with IDs)
+ -S Compile only; do not assemble or link
+ --save-temps Write intermediate files (.bc, .opt.bc, .o)
+ in addition to normal output
+ --static Use or produce static libraries or binaries
+ --stats Print compilation statistics
+ --sysroot <path> Override the system root
+ --test Build a test harness
+ --target <triple> Target cpu-manufacturer-kernel[-os] to compile for
+ (default: host triple)
+ (see http://sources.redhat.com/autobook/autobook/
+ autobook_17.html for detail)
+
+ --time-passes Time the individual phases of the compiler
+ --time-llvm-passes Time the individual phases of the LLVM backend
+ -v --version Print version info and exit
--warn-unused-imports
- warn about unnecessary imports
- --no-lint-ctypes suppress lint-style ctypes usage check
+ Warn about unnecessary imports
");
}
time_llvm_passes: bool,
output_type: back::link::output_type,
addl_lib_search_paths: [str],
- maybe_sysroot: option::t<str>,
+ maybe_sysroot: option<str>,
target_triple: str,
cfg: ast::crate_cfg,
test: bool,
parse_only: bool,
no_trans: bool,
- do_gc: bool,
no_asm_comments: bool,
+ monomorphize: bool,
warn_unused_imports: bool};
type crate_metadata = {name: str, data: [u8]};
parse_sess: parse_sess,
codemap: codemap::codemap,
// For a library crate, this is always none
- mutable main_fn: option::t<node_id>,
+ mutable main_fn: option<(node_id, codemap::span)>,
span_diagnostic: diagnostic::span_handler,
filesearch: filesearch::filesearch,
mutable building_library: bool,
fn find_attrs_by_name(attrs: [ast::attribute], name: ast::ident) ->
[ast::attribute] {
let filter = (
- fn@(a: ast::attribute) -> option::t<ast::attribute> {
+ fn@(a: ast::attribute) -> option<ast::attribute> {
if get_attr_name(a) == name {
option::some(a)
} else { option::none }
fn find_meta_items_by_name(metas: [@ast::meta_item], name: ast::ident) ->
[@ast::meta_item] {
- let filter = fn@(&&m: @ast::meta_item) -> option::t<@ast::meta_item> {
+ let filter = fn@(&&m: @ast::meta_item) -> option<@ast::meta_item> {
if get_meta_item_name(m) == name {
option::some(m)
} else { option::none }
// Gets the string value if the meta_item is a meta_name_value variant
// containing a string, otherwise none
-fn get_meta_item_value_str(meta: @ast::meta_item) -> option::t<str> {
+fn get_meta_item_value_str(meta: @ast::meta_item) -> option<str> {
alt meta.node {
ast::meta_name_value(_, v) {
alt v.node { ast::lit_str(s) { option::some(s) } _ { option::none } }
}
fn get_meta_item_value_str_by_name(attrs: [ast::attribute], name: ast::ident)
- -> option::t<str> {
+ -> option<str> {
let mattrs = find_attrs_by_name(attrs, name);
if vec::len(mattrs) > 0u {
ret get_meta_item_value_str(attr_meta(mattrs[0]));
ret option::none;
}
-fn get_meta_item_list(meta: @ast::meta_item) -> option::t<[@ast::meta_item]> {
+fn get_meta_item_list(meta: @ast::meta_item) -> option<[@ast::meta_item]> {
alt meta.node {
ast::meta_list(_, l) { option::some(l) }
_ { option::none }
fn remove_meta_items_by_name(items: [@ast::meta_item], name: str) ->
[@ast::meta_item] {
- let filter = fn@(&&item: @ast::meta_item) -> option::t<@ast::meta_item> {
+ let filter = fn@(&&item: @ast::meta_item) -> option<@ast::meta_item> {
if get_meta_item_name(item) != name {
option::some(item)
} else { option::none }
}
fn filter_item(cx: ctxt, &&item: @ast::item) ->
- option::t<@ast::item> {
+ option<@ast::item> {
if item_in_cfg(cx, item) { option::some(item) } else { option::none }
}
}
fn filter_native_item(cx: ctxt, &&item: @ast::native_item) ->
- option::t<@ast::native_item> {
+ option<@ast::native_item> {
if native_item_in_cfg(cx, item) {
option::some(item)
} else { option::none }
}
fn filter_stmt(cx: ctxt, &&stmt: @ast::stmt) ->
- option::t<@ast::stmt> {
+ option<@ast::stmt> {
alt stmt.node {
ast::stmt_decl(decl, _) {
alt decl.node {
// the one we're going to add. FIXME: This is sloppy. Instead we should
// have some mechanism to indicate to the translation pass which function
// we want to be main.
- fn nomain(&&item: @ast::item) -> option::t<@ast::item> {
+ fn nomain(&&item: @ast::item) -> option<@ast::item> {
alt item.node {
ast::item_fn(_, _, _) {
if item.ident == "main" {
_ { false }
}
};
- (is_std ? [] : ["std"]) + path
+ (if is_std { [] } else { ["std"] }) + path
}
// The ast::ty of [std::test::test_desc]
let args_ty: ast::ty = nospan(ast::ty_vec(args_mt));
let args_arg: ast::arg =
- {mode: ast::by_val,
+ {mode: ast::expl(ast::by_val),
ty: @args_ty,
ident: "args",
id: cx.sess.next_node_id()};
import core::{vec, str, option};
import str::sbuf;
-import llvm::{TypeRef, MemoryBufferRef,
- PassManagerRef, TargetDataRef,
- ObjectFileRef, SectionIteratorRef};
import ctypes::{c_int, c_uint, unsigned, longlong, ulonglong};
-type Long = i32;
-type Bool = int;
+type Opcode = u32;
+type Bool = unsigned;
+const True: Bool = 1u32;
+const False: Bool = 0u32;
+// Consts for the LLVM CallConv type, pre-cast to uint.
-const True: Bool = 1;
-const False: Bool = 0;
+enum CallConv {
+ CCallConv = 0,
+ FastCallConv = 8,
+ ColdCallConv = 9,
+ X86StdcallCallConv = 64,
+ X86FastcallCallConv = 65,
+}
-// Consts for the LLVM CallConv type, pre-cast to uint.
-// FIXME: figure out a way to merge these with the native
-// typedef and/or a enum type in the native module below.
-
-const LLVMCCallConv: uint = 0u;
-const LLVMFastCallConv: uint = 8u;
-const LLVMColdCallConv: uint = 9u;
-const LLVMX86StdcallCallConv: uint = 64u;
-const LLVMX86FastcallCallConv: uint = 65u;
-
-const LLVMDefaultVisibility: uint = 0u;
-const LLVMHiddenVisibility: uint = 1u;
-const LLVMProtectedVisibility: uint = 2u;
-
-const LLVMExternalLinkage: uint = 0u;
-const LLVMAvailableExternallyLinkage: uint = 1u;
-const LLVMLinkOnceAnyLinkage: uint = 2u;
-const LLVMLinkOnceODRLinkage: uint = 3u;
-const LLVMWeakAnyLinkage: uint = 4u;
-const LLVMWeakODRLinkage: uint = 5u;
-const LLVMAppendingLinkage: uint = 6u;
-const LLVMInternalLinkage: uint = 7u;
-const LLVMPrivateLinkage: uint = 8u;
-const LLVMDLLImportLinkage: uint = 9u;
-const LLVMDLLExportLinkage: uint = 10u;
-const LLVMExternalWeakLinkage: uint = 11u;
-const LLVMGhostLinkage: uint = 12u;
-const LLVMCommonLinkage: uint = 13u;
-const LLVMLinkerPrivateLinkage: uint = 14u;
-const LLVMLinkerPrivateWeakLinkage: uint = 15u;
-
-const LLVMZExtAttribute: uint = 1u;
-const LLVMSExtAttribute: uint = 2u;
-const LLVMNoReturnAttribute: uint = 4u;
-const LLVMInRegAttribute: uint = 8u;
-const LLVMStructRetAttribute: uint = 16u;
-const LLVMNoUnwindAttribute: uint = 32u;
-const LLVMNoAliasAttribute: uint = 64u;
-const LLVMByValAttribute: uint = 128u;
-const LLVMNestAttribute: uint = 256u;
-const LLVMReadNoneAttribute: uint = 512u;
-const LLVMReadOnlyAttribute: uint = 1024u;
-const LLVMNoInlineAttribute: uint = 2048u;
-const LLVMAlwaysInlineAttribute: uint = 4096u;
-const LLVMOptimizeForSizeAttribute: uint = 8192u;
-const LLVMStackProtectAttribute: uint = 16384u;
-const LLVMStackProtectReqAttribute: uint = 32768u;
-const LLVMAlignmentAttribute: uint = 2031616u;
-// 31 << 16
-const LLVMNoCaptureAttribute: uint = 2097152u;
-const LLVMNoRedZoneAttribute: uint = 4194304u;
-const LLVMNoImplicitFloatAttribute: uint = 8388608u;
-const LLVMNakedAttribute: uint = 16777216u;
-const LLVMInlineHintAttribute: uint = 33554432u;
-const LLVMStackAttribute: uint = 469762048u;
-// 7 << 26
-const LLVMUWTableAttribute: uint = 1073741824u;
-// 1 << 30
+enum Visibility {
+ LLVMDefaultVisibility = 0,
+ HiddenVisibility = 1,
+ ProtectedVisibility = 2,
+}
+
+enum Linkage {
+ ExternalLinkage = 0,
+ AvailableExternallyLinkage = 1,
+ LinkOnceAnyLinkage = 2,
+ LinkOnceODRLinkage = 3,
+ WeakAnyLinkage = 4,
+ WeakODRLinkage = 5,
+ AppendingLinkage = 6,
+ InternalLinkage = 7,
+ PrivateLinkage = 8,
+ DLLImportLinkage = 9,
+ DLLExportLinkage = 10,
+ ExternalWeakLinkage = 11,
+ GhostLinkage = 12,
+ CommonLinkage = 13,
+ LinkerPrivateLinkage = 14,
+ LinkerPrivateWeakLinkage = 15,
+ LinkerPrivateWeakDefAutoLinkage = 16,
+}
+enum Attribute {
+ ZExtAttribute = 1,
+ SExtAttribute = 2,
+ NoReturnAttribute = 4,
+ InRegAttribute = 8,
+ StructRetAttribute = 16,
+ NoUnwindAttribute = 32,
+ NoAliasAttribute = 64,
+ ByValAttribute = 128,
+ NestAttribute = 256,
+ ReadNoneAttribute = 512,
+ ReadOnlyAttribute = 1024,
+ NoInlineAttribute = 2048,
+ AlwaysInlineAttribute = 4096,
+ OptimizeForSizeAttribute = 8192,
+ StackProtectAttribute = 16384,
+ StackProtectReqAttribute = 32768,
+ // 31 << 16
+ AlignmentAttribute = 2031616,
+ NoCaptureAttribute = 2097152,
+ NoRedZoneAttribute = 4194304,
+ NoImplicitFloatAttribute = 8388608,
+ NakedAttribute = 16777216,
+ InlineHintAttribute = 33554432,
+ // 7 << 26
+ StackAttribute = 469762048,
+ ReturnsTwiceAttribute = 536870912,
+ // 1 << 30
+ UWTableAttribute = 1073741824,
+ NonLazyBindAttribute = 2147483648,
+}
// Consts for the LLVM IntPredicate type, pre-cast to uint.
// FIXME: as above.
-
-const LLVMIntEQ: uint = 32u;
-const LLVMIntNE: uint = 33u;
-const LLVMIntUGT: uint = 34u;
-const LLVMIntUGE: uint = 35u;
-const LLVMIntULT: uint = 36u;
-const LLVMIntULE: uint = 37u;
-const LLVMIntSGT: uint = 38u;
-const LLVMIntSGE: uint = 39u;
-const LLVMIntSLT: uint = 40u;
-const LLVMIntSLE: uint = 41u;
-
+enum IntPredicate {
+ IntEQ = 32,
+ IntNE = 33,
+ IntUGT = 34,
+ IntUGE = 35,
+ IntULT = 36,
+ IntULE = 37,
+ IntSGT = 38,
+ IntSGE = 39,
+ IntSLT = 40,
+ IntSLE = 41,
+}
// Consts for the LLVM RealPredicate type, pre-case to uint.
// FIXME: as above.
-const LLVMRealOEQ: uint = 1u;
-const LLVMRealOGT: uint = 2u;
-const LLVMRealOGE: uint = 3u;
-const LLVMRealOLT: uint = 4u;
-const LLVMRealOLE: uint = 5u;
-const LLVMRealONE: uint = 6u;
-
-const LLVMRealORD: uint = 7u;
-const LLVMRealUNO: uint = 8u;
-const LLVMRealUEQ: uint = 9u;
-const LLVMRealUGT: uint = 10u;
-const LLVMRealUGE: uint = 11u;
-const LLVMRealULT: uint = 12u;
-const LLVMRealULE: uint = 13u;
-const LLVMRealUNE: uint = 14u;
+enum RealPredicate {
+ RealOEQ = 1,
+ RealOGT = 2,
+ RealOGE = 3,
+ RealOLT = 4,
+ RealOLE = 5,
+ RealONE = 6,
+ RealORD = 7,
+ RealUNO = 8,
+ RealUEQ = 9,
+ RealUGT = 10,
+ RealUGE = 11,
+ RealULT = 12,
+ RealULE = 13,
+ RealUNE = 14,
+}
+
+// Opaque pointer types
+enum Module_opaque {}
+type ModuleRef = *Module_opaque;
+enum Context_opaque {}
+type ContextRef = *Context_opaque;
+enum Type_opaque {}
+type TypeRef = *Type_opaque;
+enum Value_opaque {}
+type ValueRef = *Value_opaque;
+enum BasicBlock_opaque {}
+type BasicBlockRef = *BasicBlock_opaque;
+enum Builder_opaque {}
+type BuilderRef = *Builder_opaque;
+enum MemoryBuffer_opaque {}
+type MemoryBufferRef = *MemoryBuffer_opaque;
+enum PassManager_opaque {}
+type PassManagerRef = *PassManager_opaque;
+enum PassManagerBuilder_opaque {}
+type PassManagerBuilderRef = *PassManagerBuilder_opaque;
+enum Use_opaque {}
+type UseRef = *Use_opaque;
+enum TargetData_opaque {}
+type TargetDataRef = *TargetData_opaque;
+enum ObjectFile_opaque {}
+type ObjectFileRef = *ObjectFile_opaque;
+enum SectionIterator_opaque {}
+type SectionIteratorRef = *SectionIterator_opaque;
#[link_args = "-Lrustllvm"]
#[link_name = "rustllvm"]
#[abi = "cdecl"]
native mod llvm {
-
- type ModuleRef;
- type ContextRef;
- type TypeRef;
- type TypeHandleRef;
- type ValueRef;
- type BasicBlockRef;
- type BuilderRef;
- type ModuleProviderRef;
- type MemoryBufferRef;
- type PassManagerRef;
- type PassManagerBuilderRef;
- type UseRef;
- type TargetDataRef;
-
- /* FIXME: These are enums in the C header. Represent them how, in rust? */
- type Linkage;
- type Attribute;
- type Visibility;
- type CallConv;
- type IntPredicate;
- type RealPredicate;
- type Opcode;
-
/* Create and destroy contexts. */
fn LLVMContextCreate() -> ContextRef;
fn LLVMGetGlobalContext() -> ContextRef;
/* Operations on global variables, functions, and aliases (globals) */
fn LLVMGetGlobalParent(Global: ValueRef) -> ModuleRef;
fn LLVMIsDeclaration(Global: ValueRef) -> Bool;
- fn LLVMGetLinkage(Global: ValueRef) -> Linkage;
- fn LLVMSetLinkage(Global: ValueRef, Link: Linkage);
+ fn LLVMGetLinkage(Global: ValueRef) -> unsigned;
+ fn LLVMSetLinkage(Global: ValueRef, Link: unsigned);
fn LLVMGetSection(Global: ValueRef) -> sbuf;
fn LLVMSetSection(Global: ValueRef, Section: sbuf);
- fn LLVMGetVisibility(Global: ValueRef) -> Visibility;
- fn LLVMSetVisibility(Global: ValueRef, Viz: Visibility);
+ fn LLVMGetVisibility(Global: ValueRef) -> unsigned;
+ fn LLVMSetVisibility(Global: ValueRef, Viz: unsigned);
fn LLVMGetAlignment(Global: ValueRef) -> unsigned;
fn LLVMSetAlignment(Global: ValueRef, Bytes: unsigned);
fn LLVMSetFunctionCallConv(Fn: ValueRef, CC: unsigned);
fn LLVMGetGC(Fn: ValueRef) -> sbuf;
fn LLVMSetGC(Fn: ValueRef, Name: sbuf);
- fn LLVMAddFunctionAttr(Fn: ValueRef, PA: Attribute, HighPA: unsigned);
- fn LLVMGetFunctionAttr(Fn: ValueRef) -> Attribute;
- fn LLVMRemoveFunctionAttr(Fn: ValueRef, PA: Attribute, HighPA: unsigned);
+ fn LLVMAddFunctionAttr(Fn: ValueRef, PA: unsigned, HighPA: unsigned);
+ fn LLVMGetFunctionAttr(Fn: ValueRef) -> unsigned;
+ fn LLVMRemoveFunctionAttr(Fn: ValueRef, PA: unsigned, HighPA: unsigned);
/* Operations on parameters */
fn LLVMCountParams(Fn: ValueRef) -> unsigned;
fn LLVMGetLastParam(Fn: ValueRef) -> ValueRef;
fn LLVMGetNextParam(Arg: ValueRef) -> ValueRef;
fn LLVMGetPreviousParam(Arg: ValueRef) -> ValueRef;
- fn LLVMAddAttribute(Arg: ValueRef, PA: Attribute);
- fn LLVMRemoveAttribute(Arg: ValueRef, PA: Attribute);
- fn LLVMGetAttribute(Arg: ValueRef) -> Attribute;
+ fn LLVMAddAttribute(Arg: ValueRef, PA: unsigned);
+ fn LLVMRemoveAttribute(Arg: ValueRef, PA: unsigned);
+ fn LLVMGetAttribute(Arg: ValueRef) -> unsigned;
fn LLVMSetParamAlignment(Arg: ValueRef, align: unsigned);
/* Operations on basic blocks */
/* Operations on call sites */
fn LLVMSetInstructionCallConv(Instr: ValueRef, CC: unsigned);
fn LLVMGetInstructionCallConv(Instr: ValueRef) -> unsigned;
- fn LLVMAddInstrAttribute(Instr: ValueRef, index: unsigned, IA: Attribute);
+ fn LLVMAddInstrAttribute(Instr: ValueRef, index: unsigned, IA: unsigned);
fn LLVMRemoveInstrAttribute(Instr: ValueRef, index: unsigned,
- IA: Attribute);
+ IA: unsigned);
fn LLVMSetInstrParamAlignment(Instr: ValueRef, index: unsigned,
align: unsigned);
/* Stuff that's in rustllvm/ because it's not upstream yet. */
- type ObjectFileRef;
- type SectionIteratorRef;
-
/** Opens an object file. */
fn LLVMCreateObjectFile(MemBuf: MemoryBufferRef) -> ObjectFileRef;
/** Closes an object file. */
fn LLVMLinkModules(Dest: ModuleRef, Src: ModuleRef) -> Bool;
}
+fn SetInstructionCallConv(Instr: ValueRef, CC: CallConv) {
+ llvm::LLVMSetInstructionCallConv(Instr, CC as unsigned);
+}
+fn SetFunctionCallConv(Fn: ValueRef, CC: CallConv) {
+ llvm::LLVMSetFunctionCallConv(Fn, CC as unsigned);
+}
+fn SetLinkage(Global: ValueRef, Link: Linkage) {
+ llvm::LLVMSetLinkage(Global, Link as unsigned);
+}
+
/* Memory-managed object interface to type handles. */
type type_names = @{type_names: std::map::hashmap<TypeRef, str>,
assert tn.named_types.insert(s, t);
}
-fn type_has_name(tn: type_names, t: TypeRef) -> option::t<str> {
+fn type_has_name(tn: type_names, t: TypeRef) -> option<str> {
ret tn.type_names.find(t);
}
-fn name_has_type(tn: type_names, s: str) -> option::t<TypeRef> {
+fn name_has_type(tn: type_names, s: str) -> option<TypeRef> {
ret tn.named_types.find(s);
}
type object_file = {llof: ObjectFileRef, dtor: @object_file_res};
-fn mk_object_file(llmb: MemoryBufferRef) -> option::t<object_file> {
+fn mk_object_file(llmb: MemoryBufferRef) -> option<object_file> {
let llof = llvm::LLVMCreateObjectFile(llmb);
if llof as int == 0 { ret option::none::<object_file>; }
ret option::some({llof: llof, dtor: @object_file_res(llof)});
fn find_library_crate(sess: session::session, ident: ast::ident,
metas: [@ast::meta_item])
- -> option::t<{ident: str, data: @[u8]}> {
+ -> option<{ident: str, data: @[u8]}> {
attr::require_unique_names(sess, metas);
let metas = metas;
crate_name: str,
metas: [@ast::meta_item],
filesearch: filesearch::filesearch) ->
- option::t<{ident: str, data: @[u8]}> {
+ option<{ident: str, data: @[u8]}> {
let prefix: str = nn.prefix + crate_name + "-";
let suffix: str = nn.suffix;
}
fn get_metadata_section(sess: session::session,
- filename: str) -> option::t<@[u8]> unsafe {
+ filename: str) -> option<@[u8]> unsafe {
let mb = str::as_buf(filename, {|buf|
llvm::LLVMRustCreateMemoryBufferWithContentsOfFile(buf)
});
}
fn get_impls_for_mod(cstore: cstore::cstore, def: ast::def_id,
- name: option::t<ast::ident>)
+ name: option<ast::ident>)
-> @[@middle::resolve::_impl] {
let cdata = cstore::get_crate_data(cstore, def.crate);
decoder::get_impls_for_mod(cdata, def.node, name)
}
fn get_impl_iface(tcx: ty::ctxt, def: ast::def_id)
- -> option::t<ty::t> {
+ -> option<ty::t> {
let cstore = tcx.sess.cstore;
let cdata = cstore::get_crate_data(cstore, def.crate);
decoder::get_impl_iface(cdata, def.node, tcx)
import std::{ebml, map, io};
import io::writer_util;
import syntax::{ast, ast_util};
+import driver::session::session;
import front::attr;
import middle::ty;
import common::*;
ret result;
}
-fn maybe_find_item(item_id: int, items: ebml::doc) -> option::t<ebml::doc> {
+fn maybe_find_item(item_id: int, items: ebml::doc) -> option<ebml::doc> {
fn eq_item(bytes: [u8], item_id: int) -> bool {
ret ebml::be_uint_from_bytes(@bytes, 0u, 4u) as int == item_id;
}
ret parse_def_id(ebml::doc_data(tagdoc));
}
-fn variant_disr_val(d: ebml::doc) -> option::t<int> {
+fn variant_disr_val(d: ebml::doc) -> option<int> {
alt ebml::maybe_get_doc(d, tag_disr_val) {
some(val_doc) {
let val_buf = ebml::doc_data(val_doc);
}
fn item_impl_iface(item: ebml::doc, tcx: ty::ctxt, cdata: cmd)
- -> option::t<ty::t> {
+ -> option<ty::t> {
let result = none;
ebml::tagged_docs(item, tag_impl_iface) {|ity|
let t = parse_ty_data(ity.data, cdata.cnum, ity.start, tcx, {|did|
result
}
-fn item_ty_param_bounds(item: ebml::doc, tcx: ty::ctxt, cdata: cmd,
- skip: bool) -> @[ty::param_bounds] {
- let bounds = [], skip = skip;
+fn item_ty_param_bounds(item: ebml::doc, tcx: ty::ctxt, cdata: cmd)
+ -> @[ty::param_bounds] {
+ let bounds = [];
ebml::tagged_docs(item, tag_items_data_item_ty_param_bounds) {|p|
let bd = parse_bounds_data(p.data, p.start, cdata.cnum, tcx, {|did|
translate_def_id(cdata, did)
});
- if skip { skip = false; }
- else { bounds += [bd]; }
+ bounds += [bd];
}
@bounds
}
'f' { ast::def_fn(did, ast::impure_fn) }
'p' { ast::def_fn(did, ast::pure_fn) }
'y' { ast::def_ty(did) }
- 'T' { ast::def_native_ty(did) }
't' { ast::def_ty(did) }
'm' { ast::def_mod(did) }
'n' { ast::def_native_mod(did) }
-> ty::ty_param_bounds_and_ty {
let item = lookup_item(id, cdata.data);
let t = item_type(item, tcx, cdata);
- let family = item_family(item);
- let tp_bounds = if family_has_type_params(family) {
- item_ty_param_bounds(item, tcx, cdata, family == ('I' as u8))
+ let tp_bounds = if family_has_type_params(item_family(item)) {
+ item_ty_param_bounds(item, tcx, cdata)
} else { @[] };
ret {bounds: tp_bounds, ty: t};
}
}
fn get_impl_iface(cdata: cmd, id: ast::node_id, tcx: ty::ctxt)
- -> option::t<ty::t> {
+ -> option<ty::t> {
item_impl_iface(lookup_item(id, cdata.data), tcx, cdata)
}
}
fn get_impls_for_mod(cdata: cmd, m_id: ast::node_id,
- name: option::t<ast::ident>)
+ name: option<ast::ident>)
-> @[@middle::resolve::_impl] {
let data = cdata.data;
let mod_item = lookup_item(m_id, data), result = [];
let data = cdata.data;
let item = lookup_item(id, data), result = [];
ebml::tagged_docs(item, tag_item_method) {|mth|
- let bounds = item_ty_param_bounds(mth, tcx, cdata, false);
+ let bounds = item_ty_param_bounds(mth, tcx, cdata);
let name = item_name(mth);
let ty = doc_type(mth, tcx, cdata);
- let fty = alt ty::struct(tcx, ty) { ty::ty_fn(f) { f } };
+ let fty = alt ty::struct(tcx, ty) { ty::ty_fn(f) { f }
+ _ { tcx.sess.bug("get_iface_methods: id has non-function type");
+ } };
result += [{ident: name, tps: bounds, fty: fty}];
}
@result
import common::*;
import middle::trans::common::crate_ctxt;
import middle::ty;
-import middle::ty::node_id_to_monotype;
+import middle::ty::node_id_to_type;
import front::attr;
+import driver::session::session;
export encode_metadata;
export encoded_ty;
encode_def_id(ebml_w, local_def(it.id));
ebml::end_tag(ebml_w);
}
+ item_class(_,_,_,_) {
+ fail "encode: implement item_class";
+ }
item_enum(variants, tps) {
add_to_index(ebml_w, path, index, it.ident);
ebml::start_tag(ebml_w, tag_paths_data_item);
encode_name(ebml_w, variant.node.name);
encode_enum_id(ebml_w, local_def(id));
encode_type(ecx, ebml_w,
- node_id_to_monotype(ecx.ccx.tcx, variant.node.id));
+ node_id_to_type(ecx.ccx.tcx, variant.node.id));
if vec::len::<variant_arg>(variant.node.args) > 0u {
encode_symbol(ecx, ebml_w, variant.node.id);
}
}
}
}
+ _ { ecx.ccx.tcx.sess.bug("encode_info_for_mod: \
+ undocumented invariant"); }
}
ebml::end_tag(ebml_w);
}
ebml::start_tag(ebml_w, tag_items_data_item);
encode_def_id(ebml_w, local_def(item.id));
encode_family(ebml_w, 'c' as u8);
- encode_type(ecx, ebml_w, node_id_to_monotype(tcx, item.id));
+ encode_type(ecx, ebml_w, node_id_to_type(tcx, item.id));
encode_symbol(ecx, ebml_w, item.id);
ebml::end_tag(ebml_w);
}
impure_fn { 'f' }
} as u8);
encode_type_param_bounds(ebml_w, ecx, tps);
- encode_type(ecx, ebml_w, node_id_to_monotype(tcx, item.id));
+ encode_type(ecx, ebml_w, node_id_to_type(tcx, item.id));
encode_symbol(ecx, ebml_w, item.id);
ebml::end_tag(ebml_w);
}
encode_def_id(ebml_w, local_def(item.id));
encode_family(ebml_w, 'y' as u8);
encode_type_param_bounds(ebml_w, ecx, tps);
- encode_type(ecx, ebml_w, node_id_to_monotype(tcx, item.id));
+ encode_type(ecx, ebml_w, node_id_to_type(tcx, item.id));
encode_name(ebml_w, item.ident);
ebml::end_tag(ebml_w);
}
encode_def_id(ebml_w, local_def(item.id));
encode_family(ebml_w, 't' as u8);
encode_type_param_bounds(ebml_w, ecx, tps);
- encode_type(ecx, ebml_w, node_id_to_monotype(tcx, item.id));
+ encode_type(ecx, ebml_w, node_id_to_type(tcx, item.id));
encode_name(ebml_w, item.ident);
for v: variant in variants {
encode_variant_id(ebml_w, local_def(v.node.id));
ebml::end_tag(ebml_w);
encode_enum_variant_info(ecx, ebml_w, item.id, variants, index, tps);
}
+ item_class(_,_,_,_) {
+ fail "encode: implement item_class";
+ }
item_res(_, tps, _, _, ctor_id) {
- let fn_ty = node_id_to_monotype(tcx, ctor_id);
+ let fn_ty = node_id_to_type(tcx, ctor_id);
ebml::start_tag(ebml_w, tag_items_data_item);
encode_def_id(ebml_w, local_def(ctor_id));
encode_def_id(ebml_w, local_def(item.id));
encode_family(ebml_w, 'i' as u8);
encode_type_param_bounds(ebml_w, ecx, tps);
- encode_type(ecx, ebml_w, node_id_to_monotype(tcx, item.id));
+ encode_type(ecx, ebml_w, node_id_to_type(tcx, item.id));
encode_name(ebml_w, item.ident);
for m in methods {
ebml::start_tag(ebml_w, tag_item_method);
encode_family(ebml_w, 'f' as u8);
encode_type_param_bounds(ebml_w, ecx, tps + m.tps);
encode_type(ecx, ebml_w,
- node_id_to_monotype(tcx, m.id));
+ node_id_to_type(tcx, m.id));
encode_name(ebml_w, m.ident);
encode_symbol(ecx, ebml_w, m.id);
ebml::end_tag(ebml_w);
encode_def_id(ebml_w, local_def(item.id));
encode_family(ebml_w, 'I' as u8);
encode_type_param_bounds(ebml_w, ecx, tps);
- encode_type(ecx, ebml_w, node_id_to_monotype(tcx, item.id));
+ encode_type(ecx, ebml_w, node_id_to_type(tcx, item.id));
encode_name(ebml_w, item.ident);
let i = 0u;
for mty in *ty::iface_methods(tcx, local_def(item.id)) {
nitem: @native_item) {
ebml::start_tag(ebml_w, tag_items_data_item);
alt nitem.node {
- native_item_ty {
- encode_def_id(ebml_w, local_def(nitem.id));
- encode_family(ebml_w, 'T' as u8);
- encode_type(ecx, ebml_w,
- ty::mk_native(ecx.ccx.tcx, local_def(nitem.id)));
- }
native_item_fn(fn_decl, tps) {
let letter = alt fn_decl.purity {
unsafe_fn { 'u' }
encode_def_id(ebml_w, local_def(nitem.id));
encode_family(ebml_w, letter);
encode_type_param_bounds(ebml_w, ecx, tps);
- encode_type(ecx, ebml_w, node_id_to_monotype(ecx.ccx.tcx, nitem.id));
+ encode_type(ecx, ebml_w, node_id_to_type(ecx.ccx.tcx, nitem.id));
encode_symbol(ecx, ebml_w, nitem.id);
}
}
encode_info_for_mod(ecx, ebml_w, crate_mod, crate_node_id, "");
ecx.ccx.ast_map.items {|key, val|
alt val {
- middle::ast_map::node_item(i) {
+ middle::ast_map::node_item(i, _) {
index += [{val: key, pos: ebml_w.writer.tell()}];
encode_info_for_item(ecx, ebml_w, i, index);
}
- middle::ast_map::node_native_item(i) {
+ middle::ast_map::node_native_item(i, _) {
index += [{val: key, pos: ebml_w.writer.tell()}];
encode_info_for_native_item(ecx, ebml_w, i);
}
ret ty::mk_res(st.tcx, def, inner, params);
}
'X' { ret ty::mk_var(st.tcx, parse_int(st)); }
- 'E' { let def = parse_def(st, conv); ret ty::mk_native(st.tcx, def); }
'Y' { ret ty::mk_type(st.tcx); }
'y' { ret ty::mk_send_type(st.tcx); }
'C' {
'#' { ast::by_val }
};
st.pos += 1u;
- inputs += [{mode: mode, ty: parse_ty(st, conv)}];
+ inputs += [{mode: ast::expl(mode), ty: parse_ty(st, conv)}];
}
st.pos += 1u; // eat the ']'
let cs = parse_constrs(st, conv);
import std::map::hashmap;
import option::{some, none};
import syntax::ast::*;
+import driver::session::session;
import middle::ty;
import syntax::print::pprust::*;
w.write_char(']');
}
ty::ty_var(id) { w.write_char('X'); w.write_str(int::str(id)); }
- ty::ty_native(def) {
- w.write_char('E');
- w.write_str(cx.ds(def));
- w.write_char('|');
- }
ty::ty_param(id, did) {
w.write_char('p');
w.write_str(cx.ds(did));
fn enc_ty_fn(w: io::writer, cx: @ctxt, ft: ty::fn_ty) {
w.write_char('[');
for arg: ty::arg in ft.inputs {
- alt arg.mode {
+ alt ty::resolved_mode(cx.tcx, arg.mode) {
by_mut_ref { w.write_char('&'); }
by_move { w.write_char('-'); }
by_copy { w.write_char('+'); }
import visit::vt;
import core::{vec, option};
import std::list;
+import std::util::unreachable;
import option::{some, none, is_none};
import list::list;
import driver::session::session;
import pat_util::*;
+import util::ppaux::ty_to_str;
// This is not an alias-analyser (though it would merit from becoming one, or
// getting input from one, to be more precise). It is a pass that checks
type binding = @{node_id: node_id,
span: span,
- root_var: option::t<node_id>,
+ root_var: option<node_id>,
local_id: uint,
unsafe_tys: [unsafe_ty],
mutable copied: copied};
type scope = {bs: [binding],
invalid: @mutable list<@invalid>};
-fn mk_binding(cx: ctx, id: node_id, span: span, root_var: option::t<node_id>,
+fn mk_binding(cx: ctx, id: node_id, span: span, root_var: option<node_id>,
unsafe_tys: [unsafe_ty]) -> binding {
alt root_var {
some(r_id) { cx.ref_map.insert(id, r_id); }
let fty = ty::node_id_to_type(cx.tcx, id);
let args = ty::ty_fn_args(cx.tcx, fty);
for arg in args {
- if arg.mode == ast::by_val &&
- ty::type_has_dynamic_size(cx.tcx, arg.ty) {
+ alt ty::resolved_mode(cx.tcx, arg.mode) {
+ ast::by_val if ty::type_has_dynamic_size(cx.tcx, arg.ty) {
err(*cx, sp, "can not pass a dynamically-sized type by value");
+ }
+ _ { /* fallthrough */ }
}
}
for arg_t: ty::arg in arg_ts {
let arg = args[i];
let root = expr_root(cx, arg, false);
- if arg_t.mode == ast::by_mut_ref {
+ alt ty::resolved_mode(cx.tcx, arg_t.mode) {
+ ast::by_mut_ref {
alt path_def(cx, arg) {
some(def) {
let dnum = ast_util::def_id_of_def(def).node;
}
_ { }
}
+ }
+ ast::by_ref | ast::by_val | ast::by_move | ast::by_copy { }
}
let root_var = path_def_id(cx, root.ex);
+ let arg_copied = alt ty::resolved_mode(cx.tcx, arg_t.mode) {
+ ast::by_move | ast::by_copy { copied }
+ ast::by_mut_ref { not_allowed }
+ ast::by_ref | ast::by_val { not_copied }
+ };
bindings += [@{node_id: arg.id,
span: arg.span,
root_var: root_var,
local_id: 0u,
unsafe_tys: unsafe_set(root.mut),
- mutable copied: alt arg_t.mode {
- ast::by_move | ast::by_copy { copied }
- ast::by_mut_ref { not_allowed }
- _ { not_copied }
- }}];
+ mutable copied: arg_copied}];
i += 1u;
}
let f_may_close =
for unsafe_ty in b.unsafe_tys {
let i = 0u;
for arg_t: ty::arg in arg_ts {
- let mut_alias = arg_t.mode == ast::by_mut_ref;
+ let mut_alias =
+ (ast::by_mut_ref == ty::arg_mode(cx.tcx, arg_t));
if i != j &&
ty_can_unsafely_include(cx, unsafe_ty, arg_t.ty,
mut_alias) &&
check_lval(cx, dest, sc, v);
}
-fn check_if(c: @ast::expr, then: ast::blk, els: option::t<@ast::expr>,
+fn check_if(c: @ast::expr, then: ast::blk, els: option<@ast::expr>,
sc: scope, v: vt<scope>) {
v.visit_expr(c, sc, v);
let orig_invalid = *sc.invalid;
}
}
-fn path_def(cx: ctx, ex: @ast::expr) -> option::t<ast::def> {
+fn path_def(cx: ctx, ex: @ast::expr) -> option<ast::def> {
ret alt ex.node {
ast::expr_path(_) { some(cx.tcx.def_map.get(ex.id)) }
_ { none }
}
}
-fn path_def_id(cx: ctx, ex: @ast::expr) -> option::t<ast::node_id> {
+fn path_def_id(cx: ctx, ex: @ast::expr) -> option<ast::node_id> {
alt ex.node {
ast::expr_path(_) {
ret some(ast_util::def_id_of_def(cx.tcx.def_map.get(ex.id)).node);
fn score_ty(tcx: ty::ctxt, ty: ty::t) -> uint {
ret alt ty::struct(tcx, ty) {
ty::ty_nil | ty::ty_bot | ty::ty_bool | ty::ty_int(_) |
- ty::ty_uint(_) | ty::ty_float(_) | ty::ty_type | ty::ty_native(_) |
+ ty::ty_uint(_) | ty::ty_float(_) | ty::ty_type |
ty::ty_ptr(_) { 1u }
ty::ty_box(_) | ty::ty_iface(_, _) { 3u }
ty::ty_constr(t, _) | ty::ty_res(_, t, _) { score_ty(tcx, t) }
for f in fs { sum += score_ty(tcx, f.mt.ty); }
sum
}
+ _ {
+ tcx.sess.warn(#fmt("score_ty: unexpected type %s",
+ ty_to_str(tcx, ty)));
+ 1u // ???
+ }
};
}
ret score_ty(tcx, ty) > 8u;
type pattern_root = {id: node_id,
name: ident,
- mut: option::t<unsafe_ty>,
+ mut: option<unsafe_ty>,
span: span};
-fn pattern_roots(tcx: ty::ctxt, mut: option::t<unsafe_ty>, pat: @ast::pat)
+fn pattern_roots(tcx: ty::ctxt, mut: option<unsafe_ty>, pat: @ast::pat)
-> [pattern_root] {
- fn walk(tcx: ty::ctxt, mut: option::t<unsafe_ty>, pat: @ast::pat,
+ fn walk(tcx: ty::ctxt, mut: option<unsafe_ty>, pat: @ast::pat,
&set: [pattern_root]) {
alt normalize_pat(tcx, pat).node {
ast::pat_wild | ast::pat_lit(_) | ast::pat_range(_, _) {}
ast::pat_rec(fs, _) {
let ty = ty::node_id_to_type(tcx, pat.id);
for f in fs {
- let m = ty::get_field(tcx, ty, f.ident).mt.mut != ast::imm;
- walk(tcx, m ? some(contains(ty)) : mut, f.pat, set);
+ let m = ty::get_field(tcx, ty, f.ident).mt.mut != ast::imm,
+ c = if m { some(contains(ty)) } else { mut };
+ walk(tcx, c, f.pat, set);
}
}
ast::pat_box(p) {
let ty = ty::node_id_to_type(tcx, pat.id);
let m = alt ty::struct(tcx, ty) {
ty::ty_box(mt) { mt.mut != ast::imm }
- };
- walk(tcx, m ? some(contains(ty)) : mut, p, set);
+ _ { tcx.sess.span_bug(pat.span, "box pat has non-box type"); }
+ },
+ c = if m {some(contains(ty)) } else { mut };
+ walk(tcx, c, p, set);
}
ast::pat_uniq(p) {
let ty = ty::node_id_to_type(tcx, pat.id);
let m = alt ty::struct(tcx, ty) {
ty::ty_uniq(mt) { mt.mut != ast::imm }
- };
- walk(tcx, m ? some(contains(ty)) : mut, p, set);
+ _ { tcx.sess.span_bug(pat.span, "uniq pat has non-uniq type"); }
+ },
+ c = if m { some(contains(ty)) } else { mut };
+ walk(tcx, c, p, set);
}
}
}
// Wraps the expr_root in mut.rs to also handle roots that exist through
// return-by-reference
fn expr_root(cx: ctx, ex: @ast::expr, autoderef: bool)
- -> {ex: @ast::expr, mut: option::t<unsafe_ty>} {
+ -> {ex: @ast::expr, mut: option<unsafe_ty>} {
let base_root = mut::expr_root(cx.tcx, ex, autoderef);
let unsafe_ty = none;
for d in *base_root.ds {
ret {ex: base_root.ex, mut: unsafe_ty};
}
-fn unsafe_set(from: option::t<unsafe_ty>) -> [unsafe_ty] {
+fn unsafe_set(from: option<unsafe_ty>) -> [unsafe_ty] {
alt from { some(t) { [t] } _ { [] } }
}
fn find_invalid(id: node_id, lst: list<@invalid>)
- -> option::t<@invalid> {
+ -> option<@invalid> {
let cur = lst;
while true {
alt cur {
}
cur = *tail;
}
+ list::nil {
+ fail "append_invalid: stop doesn't appear to be \
+ a postfix of src";
+ }
}
}
ret dest;
if !is_none(p) { out = list::cons(head, @out); }
cur = *tail;
}
+ list::nil {
+ // typestate would help...
+ unreachable();
+ }
}
}
ret out;
import syntax::ast_util;
import syntax::{visit, codemap};
+enum path_elt { path_mod(str), path_name(str) }
+type path = [path_elt];
+
enum ast_node {
- node_item(@item),
- node_native_item(@native_item),
- node_method(@method),
+ node_item(@item, @path),
+ node_native_item(@native_item, @path),
+ node_method(@method, @path),
node_expr(@expr),
// Locals are numbered, because the alias analysis needs to know in which
// order they are introduced.
}
type map = std::map::map<node_id, ast_node>;
-type ctx = @{map: map, mutable local_id: uint};
+type ctx = {map: map, mutable path: path, mutable local_id: uint};
+type vt = visit::vt<ctx>;
fn map_crate(c: crate) -> map {
- let cx = @{map: std::map::new_int_hash(),
- mutable local_id: 0u};
-
- let v_map = visit::mk_simple_visitor
- (@{visit_item: bind map_item(cx, _),
- visit_native_item: bind map_native_item(cx, _),
- visit_expr: bind map_expr(cx, _),
- visit_fn: bind map_fn(cx, _, _, _, _, _),
- visit_local: bind map_local(cx, _),
- visit_arm: bind map_arm(cx, _)
- with *visit::default_simple_visitor()});
- visit::visit_crate(c, (), v_map);
+ let cx = {map: std::map::new_int_hash(),
+ mutable path: [],
+ mutable local_id: 0u};
+ visit::visit_crate(c, cx, visit::mk_vt(@{
+ visit_item: map_item,
+ visit_native_item: map_native_item,
+ visit_expr: map_expr,
+ visit_fn: map_fn,
+ visit_local: map_local,
+ visit_arm: map_arm
+ with *visit::default_visitor()
+ }));
ret cx.map;
}
-fn map_fn(cx: ctx, _fk: visit::fn_kind, decl: fn_decl, _body: blk,
- _sp: codemap::span, _id: node_id) {
+fn map_fn(fk: visit::fn_kind, decl: fn_decl, body: blk,
+ sp: codemap::span, id: node_id, cx: ctx, v: vt) {
for a in decl.inputs {
cx.map.insert(a.id, node_arg(a, cx.local_id));
cx.local_id += 1u;
}
+ visit::visit_fn(fk, decl, body, sp, id, cx, v);
}
-fn map_local(cx: ctx, loc: @local) {
- pat_util::pat_bindings(loc.node.pat) {|p|
- cx.map.insert(p.id, node_local(cx.local_id));
+fn map_local(loc: @local, cx: ctx, v: vt) {
+ pat_util::pat_bindings(loc.node.pat) {|p_id, _s, _p|
+ cx.map.insert(p_id, node_local(cx.local_id));
cx.local_id += 1u;
};
+ visit::visit_local(loc, cx, v);
}
-fn map_arm(cx: ctx, arm: arm) {
- pat_util::pat_bindings(arm.pats[0]) {|p|
- cx.map.insert(p.id, node_local(cx.local_id));
+fn map_arm(arm: arm, cx: ctx, v: vt) {
+ pat_util::pat_bindings(arm.pats[0]) {|p_id, _s, _p|
+ cx.map.insert(p_id, node_local(cx.local_id));
cx.local_id += 1u;
};
+ visit::visit_arm(arm, cx, v);
}
-fn map_item(cx: ctx, i: @item) {
- cx.map.insert(i.id, node_item(i));
+fn map_item(i: @item, cx: ctx, v: vt) {
+ cx.map.insert(i.id, node_item(i, @cx.path));
alt i.node {
item_impl(_, _, _, ms) {
- for m in ms { cx.map.insert(m.id, node_method(m)); }
+ for m in ms { cx.map.insert(m.id, node_method(m, @cx.path)); }
}
item_res(_, _, _, dtor_id, ctor_id) {
cx.map.insert(ctor_id, node_res_ctor(i));
- cx.map.insert(dtor_id, node_item(i));
+ cx.map.insert(dtor_id, node_item(i, @cx.path));
}
_ { }
}
+ alt i.node {
+ item_mod(_) | item_native_mod(_) { cx.path += [path_mod(i.ident)]; }
+ _ { cx.path += [path_name(i.ident)]; }
+ }
+ visit::visit_item(i, cx, v);
+ vec::pop(cx.path);
}
-fn map_native_item(cx: ctx, i: @native_item) {
- cx.map.insert(i.id, node_native_item(i));
+fn map_native_item(i: @native_item, cx: ctx, v: vt) {
+ cx.map.insert(i.id, node_native_item(i, @cx.path));
+ visit::visit_native_item(i, cx, v);
}
-fn map_expr(cx: ctx, ex: @expr) {
+fn map_expr(ex: @expr, cx: ctx, v: vt) {
cx.map.insert(ex.id, node_expr(ex));
-}
-
-fn node_span(node: ast_node) -> codemap::span {
- alt node {
- node_item(item) { item.span }
- node_native_item(nitem) { nitem.span }
- node_expr(expr) { expr.span }
- }
-}
-
-#[cfg(test)]
-mod test {
- import syntax::ast_util;
-
- #[test]
- fn test_node_span_item() {
- let expected: codemap::span = ast_util::mk_sp(20u, 30u);
- let node =
- node_item(@{ident: "test",
- attrs: [],
- id: 0,
- node: item_mod({view_items: [], items: []}),
- span: expected});
- assert (node_span(node) == expected);
- }
-
- #[test]
- fn test_node_span_native_item() {
- let expected: codemap::span = ast_util::mk_sp(20u, 30u);
- let node =
- node_native_item(@{ident: "test",
- attrs: [],
- node: native_item_ty,
- id: 0,
- span: expected});
- assert (node_span(node) == expected);
- }
-
- #[test]
- fn test_node_span_expr() {
- let expected: codemap::span = ast_util::mk_sp(20u, 30u);
- let node = node_expr(@{id: 0, node: expr_break, span: expected});
- assert (node_span(node) == expected);
- }
+ visit::visit_expr(ex, cx, v);
}
// Local Variables:
v.visit_expr(f, cx, v);
let i = 0u;
for arg_t in ty::ty_fn_args(cx.tcx, ty::expr_ty(cx.tcx, f)) {
- cx.allow_block = arg_t.mode == by_ref;
+ cx.allow_block = (ty::arg_mode(cx.tcx, arg_t) == by_ref);
v.visit_expr(args[i], cx, v);
i += 1u;
}
+
import syntax::ast::*;
import syntax::ast_util::{variant_def_ids, dummy_sp, compare_lit_exprs,
- lit_expr_eq};
+ lit_expr_eq, unguarded_pat};
+import syntax::codemap::span;
import pat_util::*;
import syntax::visit;
import option::{some, none};
import driver::session::session;
+import middle::ty;
+import middle::ty::*;
fn check_crate(tcx: ty::ctxt, crate: @crate) {
let v =
fn check_expr(tcx: ty::ctxt, ex: @expr, &&s: (), v: visit::vt<()>) {
visit::visit_expr(ex, s, v);
alt ex.node {
- expr_alt(_, arms) {
- check_arms(tcx, pat_util::normalize_arms(tcx, arms));
+ expr_alt(scrut, arms) {
+ check_arms(tcx, ex.span, scrut,
+ pat_util::normalize_arms(tcx, arms));
}
_ { }
}
}
-fn check_arms(tcx: ty::ctxt, arms: [arm]) {
+fn check_arms(tcx: ty::ctxt, sp:span, scrut: @expr, arms: [arm]) {
let i = 0;
+ let scrut_ty = expr_ty(tcx, scrut);
+ /* (Could both checks be done in a single pass?) */
+
+ /* Check for unreachable patterns */
for arm: arm in arms {
for arm_pat: @pat in arm.pats {
let reachable = true;
}
i += 1;
}
+
+ /* Check for exhaustiveness */
+
+ check_exhaustive(tcx, sp, scrut_ty,
+ vec::concat(vec::filter_map(arms, unguarded_pat)));
+}
+
+// Precondition: patterns have been normalized
+// (not checked statically yet)
+fn check_exhaustive(tcx: ty::ctxt, sp:span, scrut_ty:ty::t, pats:[@pat]) {
+ let represented : [def_id] = [];
+ /* Determine the type of the scrutinee */
+ /* If it's not an enum, exit (bailing out on checking non-enum alts
+ for now) */
+ /* Otherwise, get the list of variants and make sure each one is
+ represented. Then recurse on the columns. */
+
+ let ty_def_id = alt ty::struct(tcx, scrut_ty) {
+ ty_enum(id, _) { id }
+ _ { ret; } };
+
+ let variants = *enum_variants(tcx, ty_def_id);
+ for pat in pats {
+ if !is_refutable(tcx, pat) {
+ /* automatically makes this alt complete */ ret;
+ }
+ alt pat.node {
+ // want the def_id for the constructor
+ pat_enum(id,_) {
+ alt tcx.def_map.find(pat.id) {
+ some(def_variant(_, variant_def_id)) {
+ represented += [variant_def_id];
+ }
+ _ { tcx.sess.span_bug(pat.span, "check_exhaustive:
+ pat_tag not bound to a variant"); }
+ }
+ }
+ _ { tcx.sess.span_bug(pat.span, "check_exhaustive: ill-typed \
+ pattern"); // we know this has enum type,
+ } // so anything else should be impossible
+ }
+ }
+ fn not_represented(v: [def_id], &&vinfo: variant_info) -> bool {
+ !vec::member(vinfo.id, v)
+ }
+ // Could be more efficient (bitvectors?)
+ alt vec::find(variants, bind not_represented(represented,_)) {
+ some(bad) {
+ // complain
+ // TODO: give examples of cases that aren't covered
+ tcx.sess.note("Patterns not covered include:");
+ tcx.sess.note(bad.name);
+ tcx.sess.span_err(sp, "Non-exhaustive pattern");
+ }
+ _ {}
+ }
+ // Otherwise, check subpatterns
+ // inefficient
+ for variant in variants {
+ // rows consists of the argument list for each pat that's an enum
+ let rows : [[@pat]] = [];
+ for pat in pats {
+ alt pat.node {
+ pat_enum(id, args) {
+ alt tcx.def_map.find(pat.id) {
+ some(def_variant(_,variant_id))
+ if variant_id == variant.id { rows += [args]; }
+ _ { }
+ }
+ }
+ _ {}
+ }
+ }
+ if check vec::is_not_empty(rows) {
+ let i = 0u;
+ for it in rows[0] {
+ let column = [it];
+ // Annoying -- see comment in
+ // tstate::states::find_pre_post_state_loop
+ check vec::is_not_empty(rows);
+ for row in vec::tail(rows) {
+ column += [row[i]];
+ }
+ check_exhaustive(tcx, sp, pat_ty(tcx, it), column);
+ i += 1u;
+ }
+ }
+ // This shouldn't actually happen, since there were no
+ // irrefutable patterns if we got here.
+ else { cont; }
+ }
}
fn pattern_supersedes(tcx: ty::ctxt, a: @pat, b: @pat) -> bool {
pat_wild | pat_ident(_, none) { false }
pat_lit(_) { true }
pat_rec(fields, _) {
- for field: field_pat in fields {
- if is_refutable(tcx, field.pat) { ret true; }
+ for it: field_pat in fields {
+ if is_refutable(tcx, it.pat) { ret true; }
}
false
}
}
pat_enum(_, args) {
let vdef = variant_def_ids(tcx.def_map.get(pat.id));
- if vec::len(*ty::enum_variants(tcx, vdef.tg)) != 1u { ret true; }
+ if vec::len(*ty::enum_variants(tcx, vdef.enm)) != 1u { ret true; }
for p: @pat in args { if is_refutable(tcx, p) { ret true; } }
false
}
+ pat_range(_, _) { true }
}
}
expr_lit(@{node: lit_int(v, t), _}) {
if t != ty_char {
if (v as u64) > ast_util::int_ty_max(
- t == ty_i ? sess.targ_cfg.int_type : t) {
+ if t == ty_i { sess.targ_cfg.int_type } else { t }) {
sess.span_err(e.span, "literal out of range for its type");
}
}
}
expr_lit(@{node: lit_uint(v, t), _}) {
if v > ast_util::uint_ty_max(
- t == ty_u ? sess.targ_cfg.uint_type : t) {
+ if t == ty_u { sess.targ_cfg.uint_type } else { t }) {
sess.span_err(e.span, "literal out of range for its type");
}
}
import std::fs;
import std::map::hashmap;
import lib::llvm::llvm;
-import lib::llvm::llvm::ValueRef;
+import lib::llvm::ValueRef;
import trans::common::*;
import trans::base;
import trans::build::B;
import middle::ty;
-import syntax::{ast, codemap};
+import syntax::{ast, codemap, ast_util};
import codemap::span;
import ast::ty;
import pat_util::*;
import util::ppaux::ty_to_str;
+import driver::session::session;
export create_local_var;
export create_function;
}
fn cached_metadata<T: copy>(cache: metadata_cache, mdtag: int,
- eq: fn(md: T) -> bool) -> option::t<T> unsafe {
+ eq: fn(md: T) -> bool) -> option<T> unsafe {
if cache.contains_key(mdtag) {
let items = cache.get(mdtag);
for item in items {
}
fn create_compile_unit(cx: @crate_ctxt, full_path: str)
- -> @metadata<compile_unit_md> {
+ -> @metadata<compile_unit_md> unsafe {
let cache = get_cache(cx);
let tg = CompileUnitTag;
alt cached_metadata::<@metadata<compile_unit_md>>(cache, tg,
let work_dir = cx.sess.working_dir;
let file_path = if str::starts_with(full_path, work_dir) {
- str::slice(full_path, str::byte_len(work_dir),
+ str::unsafe::slice_bytes(full_path, str::byte_len(work_dir),
str::byte_len(full_path))
} else {
full_path
codemap::lookup_char_pos(cm, sp.lo).line
}
-fn create_block(cx: @block_ctxt, sp: span) -> @metadata<block_md> {
- //let cache = get_cache(bcx_ccx(cx));
+fn create_block(cx: @block_ctxt) -> @metadata<block_md> {
+ let cache = get_cache(bcx_ccx(cx));
+ let cx = cx;
+ while option::is_none(cx.block_span) {
+ alt cx.parent {
+ parent_none { fail "BAD"; /*break;*/ }
+ parent_some(b) { cx = b; }
+ }
+ }
+ let sp = option::get(cx.block_span);
+
let start = codemap::lookup_char_pos(bcx_ccx(cx).sess.codemap,
sp.lo);
- let fname = start.filename;
+ let fname = start.file.name;
let end = codemap::lookup_char_pos(bcx_ccx(cx).sess.codemap,
sp.hi);
let tg = LexicalBlockTag;
}*/
let parent = alt cx.parent {
- parent_none { create_function(cx.fcx, sp).node }
- parent_some(bcx) { create_block(bcx, sp).node }
+ parent_none { create_function(cx.fcx).node }
+ parent_some(bcx) { create_block(bcx).node }
};
let file_node = create_file(bcx_ccx(cx), fname);
- /*let unique_id = alt cache.find(LexicalBlockTag) {
+ let unique_id = alt cache.find(LexicalBlockTag) {
option::some(v) { vec::len(v) as int }
option::none { 0 }
- };*/
+ };
let lldata = [lltag(tg),
parent,
lli32(start.line as int),
lli32(start.col as int),
- file_node.node/*,
- lli32(unique_id)*/
+ file_node.node,
+ lli32(unique_id)
];
- let val = llmdnode(lldata);
- let mdval = @{node: val, data: {start: start, end: end}};
- //update_cache(cache, tg, block_metadata(mdval));
- ret mdval;
+ let val = llmdnode(lldata);
+ let mdval = @{node: val, data: {start: start, end: end}};
+ //update_cache(cache, tg, block_metadata(mdval));
+ ret mdval;
}
fn size_and_align_of<T>() -> (int, int) {
ast::ty_f32 {("f32", size_and_align_of::<f32>(), DW_ATE_float)}
ast::ty_f64 {("f64", size_and_align_of::<f64>(), DW_ATE_float)}
}}
+ _ { cx.tcx.sess.span_bug(ty.span,
+ "create_basic_type: unhandled type"); }
};
let fname = filename_from_span(cx, ty.span);
fn create_composite_type(type_tag: int, name: str, file: ValueRef, line: int,
size: int, align: int, offset: int,
- derived: option::t<ValueRef>,
- members: option::t<[ValueRef]>)
+ derived: option<ValueRef>,
+ members: option<[ValueRef]>)
-> ValueRef {
let lldata = [lltag(type_tag),
file,
lli64(align), // align
lli64(offset), // offset
lli32(0), // flags
- option::is_none(derived) ? llnull() : // derived from
- option::get(derived),
- option::is_none(members) ? llnull() : // members
- llmdnode(option::get(members)),
+ if option::is_none(derived) {
+ llnull()
+ } else { // derived from
+ option::get(derived)
+ },
+ if option::is_none(members) {
+ llnull()
+ } else { //members
+ llmdnode(option::get(members))
+ },
lli32(0), // runtime language
llnull()
];
ret llmdnode(lldata);
}
-fn create_vec(cx: @crate_ctxt, vec_t: ty::t, elem_t: ty::t, vec_ty: @ast::ty)
+fn create_vec(cx: @crate_ctxt, vec_t: ty::t, elem_t: ty::t,
+ vec_ty_span: codemap::span, elem_ty: @ast::ty)
-> @metadata<tydesc_md> {
- let fname = filename_from_span(cx, vec_ty.span);
+ let fname = filename_from_span(cx, vec_ty_span);
let file_node = create_file(cx, fname);
- let elem_ty = alt vec_ty.node { ast::ty_vec(mt) { mt.ty } };
let elem_ty_md = create_ty(cx, elem_t, elem_ty);
let tcx = ccx_tcx(cx);
let scx = create_structure(file_node, ty_to_str(tcx, vec_t), 0);
- let uint_ty = @{node: ast::ty_uint(ast::ty_u), span: vec_ty.span};
+ let uint_ty = @{node: ast::ty_uint(ast::ty_u), span: vec_ty_span};
let size_t_type = create_basic_type(cx, ty::mk_uint(tcx), uint_ty);
add_member(scx, "fill", 0, sys::size_of::<ctypes::size_t>() as int,
sys::align_of::<ctypes::size_t>() as int, size_t_type.node);
ast::ty_i8 { size_and_align_of::<i8>() }
ast::ty_i16 { size_and_align_of::<i16>() }
ast::ty_i32 { size_and_align_of::<i32>() }
+ ast::ty_i64 { size_and_align_of::<i64>() }
}}
ast::ty_uint(m) { alt m {
ast::ty_u { size_and_align_of::<uint>() }
ast::ty_u8 { size_and_align_of::<i8>() }
ast::ty_u16 { size_and_align_of::<u16>() }
ast::ty_u32 { size_and_align_of::<u32>() }
+ ast::ty_u64 { size_and_align_of::<u64>() }
}}
ast::ty_float(m) { alt m {
ast::ty_f { size_and_align_of::<float>() }
ast::ty_vec(_) {
size_and_align_of::<ctypes::uintptr_t>()
}
+ _ { fail "member_size_and_align: can't handle this type"; }
}
}
}
ty::ty_vec(mt) { ast::ty_vec({ty: t_to_ty(cx, mt.ty, span),
mut: mt.mut}) }
+ _ {
+ cx.tcx.sess.span_bug(span, "t_to_ty: Can't handle this type");
+ }
};
ret @{node: ty, span: span};
}
ast::ty_box(mt) {
let inner_t = alt ty::struct(ccx_tcx(cx), t) {
ty::ty_box(boxed) { boxed.ty }
+ _ { cx.tcx.sess.span_bug(ty.span, "t_to_ty was incoherent"); }
};
let md = create_ty(cx, inner_t, mt.ty);
let box = create_boxed_type(cx, t, inner_t, ty.span, md);
ast::ty_uniq(mt) {
let inner_t = alt ty::struct(ccx_tcx(cx), t) {
ty::ty_uniq(boxed) { boxed.ty }
+ // Hoping we'll have a way to eliminate this check soon.
+ _ { cx.tcx.sess.span_bug(ty.span, "t_to_ty was incoherent"); }
};
let md = create_ty(cx, inner_t, mt.ty);
ret create_pointer_type(cx, t, ty.span, md);
ast::ty_vec(mt) {
let inner_t = ty::sequence_element_type(ccx_tcx(cx), t);
- let v = create_vec(cx, t, inner_t, ty);
+ let inner_ast_t = t_to_ty(cx, inner_t, mt.ty.span);
+ let v = create_vec(cx, t, inner_t, ty.span, inner_ast_t);
ret create_pointer_type(cx, t, ty.span, v);
}
};
}
-fn filename_from_span(cx: @crate_ctxt, sp: span) -> str {
- codemap::lookup_char_pos(cx.sess.codemap, sp.lo).filename
+fn filename_from_span(cx: @crate_ctxt, sp: codemap::span) -> str {
+ codemap::lookup_char_pos(cx.sess.codemap, sp.lo).file.name
}
fn create_var(type_tag: int, context: ValueRef, name: str, file: ValueRef,
let name = path_to_ident(alt pat_util::normalize_pat(bcx_tcx(bcx),
local.node.pat).node {
ast::pat_ident(ident, _) { ident /*XXX deal w/ optional node binding*/ }
- });
+ _ { bcx_tcx(bcx).sess.span_bug(local.span, "create_local_var: \
+ weird pattern in local"); }
+ });
let loc = codemap::lookup_char_pos(cx.sess.codemap,
local.span.lo);
- let ty = base::node_id_type(cx, local.node.id);
+ let ty = node_id_type(bcx, local.node.id);
let tymd = create_ty(cx, ty, local.node.ty);
- let filemd = create_file(cx, loc.filename);
+ let filemd = create_file(cx, loc.file.name);
let context = alt bcx.parent {
- parent_none { create_function(bcx.fcx, local.span).node }
- parent_some(_) { create_block(bcx, local.span).node }
+ parent_none { create_function(bcx.fcx).node }
+ parent_some(_) { create_block(bcx).node }
};
let mdnode = create_var(tg, context, name, filemd.node,
loc.line as int, tymd.node);
let llptr = alt bcx.fcx.lllocals.find(local.node.id) {
option::some(local_mem(v)) { v }
+ option::some(_) {
+ bcx_tcx(bcx).sess.span_bug(local.span, "local is bound to \
+ something weird");
+ }
option::none {
alt bcx.fcx.lllocals.get(local.node.pat.id) {
local_imm(v) { v }
+ _ { bcx_tcx(bcx).sess.span_bug(local.span, "local is bound to \
+ something weird"); }
}
}
};
};*/
let loc = codemap::lookup_char_pos(cx.sess.codemap,
sp.lo);
- let ty = base::node_id_type(cx, arg.id);
+ let ty = node_id_type(bcx, arg.id);
let tymd = create_ty(cx, ty, arg.ty);
- let filemd = create_file(cx, loc.filename);
- let context = create_function(bcx.fcx, sp);
+ let filemd = create_file(cx, loc.file.name);
+ let context = create_function(bcx.fcx);
let mdnode = create_var(tg, context.node, arg.ident, filemd.node,
loc.line as int, tymd.node);
let mdval = @{node: mdnode, data: {id: arg.id}};
ret;
}
let cm = bcx_ccx(cx).sess.codemap;
- let blockmd = create_block(cx, s);
+ let blockmd = create_block(cx);
let loc = codemap::lookup_char_pos(cm, s.lo);
let scopedata = [lli32(loc.line as int),
lli32(loc.col as int),
llvm::LLVMSetCurrentDebugLocation(trans::build::B(cx), dbgscope);
}
-fn create_function(fcx: @fn_ctxt, sp: span) -> @metadata<subprogram_md> {
+fn create_function(fcx: @fn_ctxt) -> @metadata<subprogram_md> {
let cx = fcx_ccx(fcx);
let dbg_cx = option::get(cx.dbg_cx);
#debug("~~");
log(debug, fcx.id);
- //log(debug, codemap::span_to_str(sp, cx.sess.codemap));
+ let sp = option::get(fcx.span);
+ log(debug, codemap::span_to_str(sp, cx.sess.codemap));
let (ident, ret_ty, id) = alt cx.ast_map.get(fcx.id) {
- ast_map::node_item(item) {
+ ast_map::node_item(item, _) {
alt item.node {
ast::item_fn(decl, _, _) | ast::item_res(decl, _, _, _, _) {
(item.ident, decl.output, item.id)
}
+ _ { fcx_tcx(fcx).sess.span_bug(item.span, "create_function: item \
+ bound to non-function"); }
}
}
- ast_map::node_method(method) {
+ ast_map::node_method(method, _) {
(method.ident, method.decl.output, method.id)
}
ast_map::node_res_ctor(item) {
- alt item.node { ast::item_res(decl, _, _, _, ctor_id) {
- (item.ident, decl.output, ctor_id)
- }}
+ alt item.node {
+ ast::item_res(decl, _, _, _, ctor_id) {
+ (item.ident, decl.output, ctor_id)
+ }
+ _ { fcx_tcx(fcx).sess.span_bug(item.span, "create_function: \
+ expected an item_res here"); }
+ }
}
ast_map::node_expr(expr) {
alt expr.node {
ast::expr_fn_block(decl, _) {
(dbg_cx.names("fn"), decl.output, expr.id)
}
+ _ { fcx_tcx(fcx).sess.span_bug(expr.span, "create_function: \
+ expected an expr_fn or fn_block here"); }
}
}
+ _ { fcx_tcx(fcx).sess.bug("create_function: unexpected \
+ sort of node"); }
};
log(debug, ident);
log(debug, id);
- /*let cache = get_cache(cx);
+ let cache = get_cache(cx);
alt cached_metadata::<@metadata<subprogram_md>>(
cache, SubprogramTag, {|md| md.data.id == id}) {
option::some(md) { ret md; }
option::none {}
- }*/
+ }
- let path = str::connect(fcx.lcx.path + [ident], "::");
+ let path = path_str(fcx.path);
let loc = codemap::lookup_char_pos(cx.sess.codemap,
sp.lo);
- let file_node = create_file(cx, loc.filename).node;
- let key = cx.item_symbols.contains_key(fcx.id) ? fcx.id : id;
+ let file_node = create_file(cx, loc.file.name).node;
+ let key = if cx.item_symbols.contains_key(fcx.id) { fcx.id } else { id };
let mangled = cx.item_symbols.get(key);
let ty_node = if cx.sess.opts.extra_debuginfo {
alt ret_ty.node {
let val = llmdnode(fn_metadata);
add_named_metadata(cx, "llvm.dbg.sp", val);
let mdval = @{node: val, data: {id: id}};
- //update_cache(cache, SubprogramTag, subprogram_metadata(mdval));
+ update_cache(cache, SubprogramTag, subprogram_metadata(mdval));
ret mdval;
}
+++ /dev/null
-// Routines useful for garbage collection.
-
-import lib::llvm::True;
-import lib::llvm::llvm::ValueRef;
-import trans::base::get_tydesc;
-import trans::common::*;
-import trans::base;
-import option::none;
-import str;
-import driver::session::session;
-
-import lll = lib::llvm::llvm;
-import bld = trans::build;
-
-type ctxt = @{mutable next_tydesc_num: uint};
-
-fn mk_ctxt() -> ctxt { ret @{mutable next_tydesc_num: 0u}; }
-
-fn add_global(ccx: @crate_ctxt, llval: ValueRef, name: str) -> ValueRef {
- let llglobal =
- str::as_buf(name,
- {|buf|
- lll::LLVMAddGlobal(ccx.llmod, val_ty(llval), buf)
- });
- lll::LLVMSetInitializer(llglobal, llval);
- lll::LLVMSetGlobalConstant(llglobal, True);
- ret llglobal;
-}
-
-fn add_gc_root(cx: @block_ctxt, llval: ValueRef, ty: ty::t) -> @block_ctxt {
- let bcx = cx;
- let ccx = bcx_ccx(cx);
- if !type_is_gc_relevant(bcx_tcx(cx), ty) ||
- ty::type_has_dynamic_size(bcx_tcx(cx), ty) {
- ret bcx;
- }
-
- let gc_cx = bcx_ccx(cx).gc_cx;
-
- // FIXME (issue #839): For now, we are unconditionally zeroing out all
- // GC-relevant types. Eventually we should use typestate for this.
- bcx = base::zero_alloca(bcx, llval, ty);
-
- let ti = none;
- let td_r = get_tydesc(bcx, ty, false, ti);
- bcx = td_r.result.bcx;
- let lltydesc = td_r.result.val;
-
- let gcroot = bcx_ccx(bcx).intrinsics.get("llvm.gcroot");
- let llvalptr = bld::PointerCast(bcx, llval, T_ptr(T_ptr(T_i8())));
-
- alt td_r.kind {
- tk_derived {
- // It's a derived type descriptor. First, spill it.
- let lltydescptr = base::alloca(bcx, val_ty(lltydesc));
-
- let llderivedtydescs =
- base::llderivedtydescs_block_ctxt(bcx_fcx(bcx));
- bld::Store(llderivedtydescs, lltydesc, lltydescptr);
-
- let number = gc_cx.next_tydesc_num;
- gc_cx.next_tydesc_num += 1u;
-
- let lldestindex =
- add_global(bcx_ccx(bcx), C_struct([C_int(ccx, 0),
- C_uint(ccx, number)]),
- "rust_gc_tydesc_dest_index");
- let llsrcindex =
- add_global(bcx_ccx(bcx), C_struct([C_int(ccx, 1),
- C_uint(ccx, number)]),
- "rust_gc_tydesc_src_index");
-
- lldestindex = lll::LLVMConstPointerCast(lldestindex, T_ptr(T_i8()));
- llsrcindex = lll::LLVMConstPointerCast(llsrcindex, T_ptr(T_i8()));
-
- lltydescptr =
- bld::PointerCast(llderivedtydescs, lltydescptr,
- T_ptr(T_ptr(T_i8())));
-
- bld::Call(llderivedtydescs, gcroot, [lltydescptr, lldestindex]);
- bld::Call(bcx, gcroot, [llvalptr, llsrcindex]);
- }
- tk_param {
- bcx_tcx(cx).sess.bug("we should never be trying to root values " +
- "of a type parameter");
- }
- tk_static {
- // Static type descriptor.
-
- let llstaticgcmeta =
- add_global(bcx_ccx(bcx), C_struct([C_int(ccx, 2), lltydesc]),
- "rust_gc_tydesc_static_gc_meta");
- let llstaticgcmetaptr =
- lll::LLVMConstPointerCast(llstaticgcmeta, T_ptr(T_i8()));
-
- bld::Call(bcx, gcroot, [llvalptr, llstaticgcmetaptr]);
- }
- }
-
- ret bcx;
-}
-
-fn type_is_gc_relevant(cx: ty::ctxt, ty: ty::t) -> bool {
- alt ty::struct(cx, ty) {
- ty::ty_nil | ty::ty_bot | ty::ty_bool | ty::ty_int(_) |
- ty::ty_float(_) | ty::ty_uint(_) | ty::ty_str |
- ty::ty_type | ty::ty_ptr(_) | ty::ty_native(_) {
- ret false;
- }
- ty::ty_rec(fields) {
- for f in fields { if type_is_gc_relevant(cx, f.mt.ty) { ret true; } }
- ret false;
- }
- ty::ty_tup(elts) {
- for elt in elts { if type_is_gc_relevant(cx, elt) { ret true; } }
- ret false;
- }
- ty::ty_enum(did, tps) {
- let variants = ty::enum_variants(cx, did);
- for variant in *variants {
- for aty in variant.args {
- let arg_ty = ty::substitute_type_params(cx, tps, aty);
- if type_is_gc_relevant(cx, arg_ty) { ret true; }
- }
- }
- ret false;
- }
- ty::ty_vec(tm) {
- ret type_is_gc_relevant(cx, tm.ty);
- }
- ty::ty_constr(sub, _) { ret type_is_gc_relevant(cx, sub); }
- ty::ty_box(_) | ty::ty_uniq(_) | ty::ty_fn(_) |
- ty::ty_param(_, _) | ty::ty_res(_, _, _) { ret true; }
- ty::ty_var(_) {
- fail "ty_var in type_is_gc_relevant";
- }
- }
-}
-
// closure.
fn with_appropriate_checker(cx: ctx, id: node_id,
b: fn(fn@(ctx, ty::t, sp: span))) {
- let fty = ty::node_id_to_monotype(cx.tcx, id);
+ let fty = ty::node_id_to_type(cx.tcx, id);
alt ty::ty_fn_proto(cx.tcx, fty) {
proto_uniq { b(check_send); }
proto_box { b(check_copy); }
some(ex) {
// All noncopyable fields must be overridden
let t = ty::expr_ty(cx.tcx, ex);
- let ty_fields = alt ty::struct(cx.tcx, t) { ty::ty_rec(f) { f } };
+ let ty_fields = alt ty::struct(cx.tcx, t) { ty::ty_rec(f) { f }
+ _ { cx.tcx.sess.span_bug(ex.span,
+ "Bad expr type in record"); } };
for tf in ty_fields {
if !vec::any(fields, {|f| f.node.ident == tf.ident}) &&
!ty::kind_can_be_copied(ty::type_kind(cx.tcx, tf.mt.ty)) {
expr_call(f, args, _) {
let i = 0u;
for arg_t in ty::ty_fn_args(cx.tcx, ty::expr_ty(cx.tcx, f)) {
- alt arg_t.mode { by_copy { maybe_copy(cx, args[i]); } _ {} }
+ alt ty::arg_mode(cx.tcx, arg_t) {
+ by_copy { maybe_copy(cx, args[i]); }
+ by_ref | by_val | by_mut_ref | by_move { }
+ }
i += 1u;
}
}
expr_path(_) {
- let substs = ty::node_id_to_ty_param_substs_opt_and_ty(cx.tcx, e.id);
- alt substs.substs {
+ alt cx.tcx.node_type_substs.find(e.id) {
some(ts) {
let did = ast_util::def_id_of_def(cx.tcx.def_map.get(e.id));
let bounds = ty::lookup_item_type(cx.tcx, did).bounds;
none {}
}
}
- expr_ternary(_, a, b) { maybe_copy(cx, a); maybe_copy(cx, b); }
expr_fn(_, _, _, cap_clause) {
check_fn_cap_clause(cx, e.id, *cap_clause);
}
check_copy_ex(cx, ex, true);
}
+fn is_nullary_variant(cx: ctx, ex: @expr) -> bool {
+ alt ex.node {
+ expr_path(_) {
+ alt cx.tcx.def_map.get(ex.id) {
+ def_variant(edid, vdid) {
+ vec::len(ty::enum_variant_with_id(cx.tcx, edid, vdid).args) == 0u
+ }
+ _ { false }
+ }
+ }
+ _ { false }
+ }
+}
+
fn check_copy_ex(cx: ctx, ex: @expr, _warn: bool) {
if ty::expr_is_lval(cx.method_map, ex) &&
- !cx.last_uses.contains_key(ex.id) {
+ !cx.last_uses.contains_key(ex.id) &&
+ !is_nullary_variant(cx, ex) {
let ty = ty::expr_ty(cx.tcx, ex);
check_copy(cx, ty, ex.span);
// FIXME turn this on again once vector types are no longer unique.
import syntax::ast::*;
import syntax::codemap::span;
import std::list::{is_not_empty, list, nil, cons, tail};
+import std::util::unreachable;
import core::{vec, option};
import std::list;
}
fn ex_is_blockish(cx: ctx, id: node_id) -> bool {
- alt ty::struct(cx.tcx, ty::node_id_to_monotype(cx.tcx, id)) {
+ alt ty::struct(cx.tcx, ty::node_id_to_type(cx.tcx, id)) {
ty::ty_fn({proto: p, _}) if is_blockish(p) { true }
_ { false }
}
v.visit_expr(coll, cx, v);
visit_block(loop, cx) {|| visit::visit_block(blk, cx, v);}
}
- expr_ternary(_, _, _) {
- v.visit_expr(ast_util::ternary_to_if(ex), cx, v);
- }
expr_alt(input, arms) {
v.visit_expr(input, cx, v);
let before = cx.current, sets = [];
fns += [arg];
}
_ {
- alt arg_ts[i].mode {
+ alt ty::arg_mode(cx.tcx, arg_ts[i]) {
by_mut_ref { clear_if_path(cx, arg, v, false); }
_ { v.visit_expr(arg, cx, v); }
}
}
cur = *tail;
}
+ nil {
+ // typestate can't use the while loop condition --
+ // *sigh*
+ unreachable();
+ }
}
}
ret false;
fn clear_def_if_path(cx: ctx, d: def, to: bool)
-> option<node_id> {
alt d {
- def_local(def_id, let_copy) | def_arg(def_id, by_copy) |
- def_arg(def_id, by_move) {
+ def_local(def_id, let_copy) {
clear_in_current(cx, def_id.node, to);
some(def_id.node)
}
+ def_arg(def_id, m) {
+ alt ty::resolved_mode(cx.tcx, m) {
+ by_copy | by_move {
+ clear_in_current(cx, def_id.node, to);
+ some(def_id.node)
+ }
+ by_ref | by_val | by_mut_ref {
+ none
+ }
+ }
+ }
_ {
none
}
}
fn clear_if_path(cx: ctx, ex: @expr, v: visit::vt<ctx>, to: bool)
- -> option::t<node_id> {
+ -> option<node_id> {
alt ex.node {
expr_path(_) {
ret clear_def_if_path(cx, cx.def_map.get(ex.id), to);
ast::meta_word(name) {
str_to_option(name)
}
+ _ { fail "meta_to_option: meta_list contains a non-meta-word"; }
};
}
ty::ty_str {
ds += [@{mut: false, kind: index, outer_t: auto_unbox.t}];
}
+ _ { break; }
}
ds += auto_unbox.ds;
ex = base;
ty::ty_res(_, _, _) { }
ty::ty_enum(_, _) { }
ty::ty_ptr(mt) { is_mut = mt.mut == mut; ptr = true; }
+ _ { tcx.sess.span_bug(base.span, "Ill-typed base \
+ expression in deref"); }
}
ds += [@{mut: is_mut, kind: unbox(ptr && is_mut),
outer_t: base_t}];
let arg_ts = ty::ty_fn_args(cx.tcx, ty::expr_ty(cx.tcx, f));
let i = 0u;
for arg_t: ty::arg in arg_ts {
- alt arg_t.mode {
+ alt ty::resolved_mode(cx.tcx, arg_t.mode) {
by_mut_ref { check_lval(cx, args[i], msg_mut_ref); }
by_move { check_lval(cx, args[i], msg_move_out); }
- _ {}
+ by_ref | by_val | by_copy { }
}
i += 1u;
}
}
-fn check_bind(cx: @ctx, f: @expr, args: [option::t<@expr>]) {
+fn check_bind(cx: @ctx, f: @expr, args: [option<@expr>]) {
let arg_ts = ty::ty_fn_args(cx.tcx, ty::expr_ty(cx.tcx, f));
let i = 0u;
for arg in args {
alt arg {
some(expr) {
- alt (alt arg_ts[i].mode {
+ let o_msg = alt ty::resolved_mode(cx.tcx, arg_ts[i].mode) {
by_mut_ref { some("by mutable reference") }
by_move { some("by move") }
_ { none }
- }) {
+ };
+ alt o_msg {
some(name) {
cx.tcx.sess.span_err(
expr.span, "can not bind an argument passed " + name);
}
}
-fn is_immutable_def(cx: @ctx, def: def) -> option::t<str> {
+fn is_immutable_def(cx: @ctx, def: def) -> option<str> {
alt def {
def_fn(_, _) | def_mod(_) | def_native_mod(_) | def_const(_) |
def_use(_) {
some("static item")
}
- def_arg(_, by_ref) | def_arg(_, by_val) |
- def_arg(_, mode_infer) { some("argument") }
+ def_arg(_, m) {
+ alt ty::resolved_mode(cx.tcx, m) {
+ by_ref | by_val { some("argument") }
+ by_mut_ref | by_move | by_copy { none }
+ }
+ }
def_self(_) { some("self argument") }
def_upvar(_, inner, node_id) {
- let ty = ty::node_id_to_monotype(cx.tcx, node_id);
+ let ty = ty::node_id_to_type(cx.tcx, node_id);
let proto = ty::ty_fn_proto(cx.tcx, ty);
ret alt proto {
proto_any | proto_block { is_immutable_def(cx, *inner) }
import syntax::ast_util::respan;
import syntax::fold;
import syntax::fold::*;
+import syntax::codemap::span;
export normalize_arms;
export normalize_pat;
// use the node_id of their namesake in the first pattern.
fn pat_id_map(tcx: ty::ctxt, pat: @pat) -> pat_id_map {
let map = std::map::new_str_hash::<node_id>();
- pat_bindings(normalize_pat(tcx, pat)) {|bound|
- let name = path_to_ident(alt bound.node
- { pat_ident(n, _) { n } });
- map.insert(name, bound.id);
+ pat_bindings(normalize_pat(tcx, pat)) {|p_id, _s, n|
+ map.insert(path_to_ident(n), p_id);
};
ret map;
}
// This does *not* normalize. The pattern should be already normalized
// if you want to get a normalized pattern out of it.
// Could return a constrained type in order to express that (future work)
-fn pat_bindings(pat: @pat, it: fn(@pat)) {
+fn pat_bindings(pat: @pat, it: fn(node_id, span, @path)) {
alt pat.node {
- pat_ident(_, option::none) { it(pat); }
- pat_ident(_, option::some(sub)) { it(pat); pat_bindings(sub, it); }
+ pat_ident(pth, option::none) { it(pat.id, pat.span, pth); }
+ pat_ident(pth, option::some(sub)) { it(pat.id, pat.span, pth);
+ pat_bindings(sub, it); }
pat_enum(_, sub) { for p in sub { pat_bindings(p, it); } }
pat_rec(fields, _) { for f in fields { pat_bindings(f.pat, it); } }
pat_tup(elts) { for elt in elts { pat_bindings(elt, it); } }
fn pat_binding_ids(pat: @pat) -> [node_id] {
let found = [];
- pat_bindings(pat) {|b| found += [b.id]; };
+ pat_bindings(pat) {|b_id, _sp, _pt| found += [b_id]; };
ret found;
}
type scopes = list<scope>;
enum import_state {
- todo(ast::node_id, ast::ident, @[ast::ident], codemap::span, scopes),
- is_glob(@[ast::ident], scopes, codemap::span),
+ todo(ast::node_id, ast::ident, @[ast::ident], span, scopes),
+ is_glob(@[ast::ident], scopes, span),
resolving(span),
- resolved(option::t<def>, /* value */
- option::t<def>, /* type */
- option::t<def>, /* module */
+ resolved(option<def>, /* value */
+ option<def>, /* type */
+ option<def>, /* module */
@[@_impl], /* impls */
/* used for reporting unused import warning */
- ast::ident, codemap::span),
+ ast::ident, span),
}
enum glob_import_state {
glob_resolving(span),
- glob_resolved(option::t<def>, /* value */
- option::t<def>, /* type */
- option::t<def>), /* module */
+ glob_resolved(option<def>, /* value */
+ option<def>, /* type */
+ option<def>), /* module */
}
type ext_hash = hashmap<{did: def_id, ident: str, ns: namespace}, def>;
}
enum mod_index_entry {
- mie_view_item(@ast::view_item),
- mie_import_ident(node_id, codemap::span),
+ mie_view_item(ident, node_id, span),
+ mie_import_ident(node_id, span),
mie_item(@ast::item),
mie_native_item(@ast::native_item),
- mie_enum_variant(/* enum item */@ast::item, /* variant index */uint),
+ mie_enum_variant(/* variant index */uint,
+ /*parts of enum item*/ [variant],
+ node_id, span),
}
type mod_index = hashmap<ident, list<mod_index_entry>>;
type glob_imp_def = {def: def, item: @ast::view_item};
type indexed_mod = {
- m: option::t<ast::_mod>,
+ m: option<ast::_mod>,
index: mod_index,
mutable glob_imports: [glob_imp_def],
glob_imported_names: hashmap<str, glob_import_state>,
type ext_map = hashmap<def_id, [ident]>;
type exp_map = hashmap<str, @mutable [def]>;
type impl_map = hashmap<node_id, iscopes>;
-type impl_cache = hashmap<def_id, option::t<@[@_impl]>>;
+type impl_cache = hashmap<def_id, option<@[@_impl]>>;
type env =
{cstore: cstore::cstore,
mutable data: [ast::node_id]},
mutable reported: [{ident: str, sc: scope}],
mutable ignored_imports: [node_id],
- mutable current_tp: option::t<uint>,
+ mutable current_tp: option<uint>,
mutable resolve_unexported: bool,
sess: session};
scope_crate {
e.mod_map.get(ast::crate_node_id).glob_imports += [glob];
}
+ _ { e.sess.span_bug(vi.span, "Unexpected scope in a glob \
+ import"); }
}
}
}
resolve_import(e, local_def(node_id), name, *path, span, scopes);
}
resolved(_, _, _, _, _, _) | is_glob(_, _, _) { }
+ _ { e.sess.bug("Shouldn't see a resolving in resolve_imports"); }
}
};
e.used_imports.track = false;
maybe_insert(e, cap_item.id, dcur);
}
-fn maybe_insert(e: @env, id: node_id, def: option::t<def>) {
+fn maybe_insert(e: @env, id: node_id, def: option<def>) {
if option::is_some(def) { e.def_map.insert(id, option::get(def)); }
}
alt ifce { some(ty) { v.visit_ty(ty, sc, v); } _ {} }
v.visit_ty(sty, sc, v);
for m in methods {
+ v.visit_ty_params(m.tps, sc, v);
let msc = cons(scope_method(i.id, tps + m.tps), @sc);
v.visit_fn(visit::fk_method(m.ident, []),
m.decl, m.body, m.span, m.id, msc, v);
// is this a main fn declaration?
alt fk {
visit::fk_item_fn(nm, _) {
- if is_main_name([nm]) && !e.sess.building_library {
+ if is_main_name([ast_map::path_name(nm)]) &&
+ !e.sess.building_library {
// This is a main function -- set it in the session
// as the main ID
- e.sess.main_fn = some(id);
+ e.sess.main_fn = some((id, sp));
}
}
_ { /* fallthrough */ }
fn follow_import(e: env, sc: scopes, path: [ident], sp: span) ->
- option::t<def> {
+ option<def> {
let path_len = vec::len(path);
let dcur = lookup_in_scope_strict(e, sc, sp, path[0], ns_module);
let i = 1u;
fn resolve_import(e: env, defid: ast::def_id, name: ast::ident,
ids: [ast::ident], sp: codemap::span, sc: scopes) {
fn register(e: env, id: node_id, cx: ctxt, sp: codemap::span,
- name: ast::ident, lookup: fn(namespace) -> option::t<def>,
+ name: ast::ident, lookup: fn(namespace) -> option<def>,
impls: [@_impl]) {
let val = lookup(ns_val(ns_any_value)), typ = lookup(ns_type),
md = lookup(ns_module);
lst(id,
option::get(e.mod_map.get(ast::crate_node_id).m).view_items)
}
+ _ {
+ e.sess.bug("find_imports_after: nil or unexpected scope");
+ }
}
}
// This function has cleanup code at the end. Do not return without going
enum ctxt { in_mod(def), in_scope(scopes), }
fn unresolved_err(e: env, cx: ctxt, sp: span, name: ident, kind: str) {
- fn find_fn_or_mod_scope(sc: scopes) -> option::t<scope> {
+ fn find_fn_or_mod_scope(sc: scopes) -> option<scope> {
let sc = sc;
while true {
alt sc {
// Lookup helpers
fn lookup_path_strict(e: env, sc: scopes, sp: span, pth: ast::path_,
- ns: namespace) -> option::t<def> {
+ ns: namespace) -> option<def> {
let n_idents = vec::len(pth.idents);
let headns = if n_idents == 1u { ns } else { ns_module };
}
fn lookup_in_scope_strict(e: env, sc: scopes, sp: span, name: ident,
- ns: namespace) -> option::t<def> {
+ ns: namespace) -> option<def> {
alt lookup_in_scope(e, sc, sp, name, ns) {
none {
unresolved_err(e, in_scope(sc), sp, name, ns_name(ns));
// Returns:
// none - does not close
// some(node_id) - closes via the expr w/ node_id
-fn scope_closes(sc: scope) -> option::t<node_id> {
+fn scope_closes(sc: scope) -> option<node_id> {
alt sc {
scope_fn_expr(_, node_id, _) { some(node_id) }
_ { none }
}
fn lookup_in_scope(e: env, sc: scopes, sp: span, name: ident, ns: namespace)
- -> option::t<def> {
+ -> option<def> {
fn in_scope(e: env, sp: span, name: ident, s: scope, ns: namespace) ->
- option::t<def> {
+ option<def> {
alt s {
scope_crate {
ret lookup_in_local_mod(e, ast::crate_node_id, sp,
ast::native_item_fn(decl, ty_params) {
ret lookup_in_fn(e, name, decl, ty_params, ns);
}
+ _ {
+ e.sess.span_bug(it.span, "lookup_in_scope: \
+ scope_native_item doesn't refer to a native item");
+ }
}
}
scope_bare_fn(decl, _, ty_params) |
}
fn lookup_in_ty_params(e: env, name: ident, ty_params: [ast::ty_param])
- -> option::t<def> {
+ -> option<def> {
let n = 0u;
for tp: ast::ty_param in ty_params {
if str::eq(tp.ident, name) && alt e.current_tp {
} { ret some(ast::def_ty_param(local_def(tp.id), n)); }
n += 1u;
}
- ret none;
+ ret none::<def>;
}
-fn lookup_in_pat(e: env, name: ident, pat: @ast::pat) -> option::t<def_id> {
+fn lookup_in_pat(e: env, name: ident, pat: @ast::pat) -> option<def_id> {
let found = none;
- pat_util::pat_bindings(normalize_pat_def_map(e.def_map, pat)) {|bound|
- let p_name = alt bound.node { ast::pat_ident(n, _) { n } };
- if str::eq(path_to_ident(p_name), name)
- { found = some(local_def(bound.id)); }
+ pat_util::pat_bindings(normalize_pat_def_map(e.def_map, pat))
+ {|p_id, _sp, n|
+ if str::eq(path_to_ident(n), name)
+ { found = some(local_def(p_id)); }
};
ret found;
}
fn lookup_in_fn(e: env, name: ident, decl: ast::fn_decl,
ty_params: [ast::ty_param],
- ns: namespace) -> option::t<def> {
+ ns: namespace) -> option<def> {
alt ns {
ns_val(ns_any_value) {
for a: ast::arg in decl.inputs {
fn lookup_in_block(e: env, name: ident, sp: span, b: ast::blk_, pos: uint,
- loc_pos: uint, ns: namespace) -> option::t<def> {
+ loc_pos: uint, ns: namespace) -> option<def> {
let i = vec::len(b.stmts);
while i > 0u {
i -= 1u;
_ {}
}
}
+ _ { e.sess.span_bug(vi.span, "Unexpected view_item in block"); }
}
}
ret none;
}
-fn found_def_item(i: @ast::item, ns: namespace) -> option::t<def> {
+fn found_def_item(i: @ast::item, ns: namespace) -> option<def> {
alt i.node {
ast::item_const(_, _) {
if ns == ns_val(ns_any_value) {
}
fn lookup_in_mod_strict(e: env, m: def, sp: span, name: ident,
- ns: namespace, dr: dir) -> option::t<def> {
+ ns: namespace, dr: dir) -> option<def> {
alt lookup_in_mod(e, m, sp, name, ns, dr) {
none {
unresolved_err(e, in_mod(m), sp, name, ns_name(ns));
}
fn lookup_in_mod(e: env, m: def, sp: span, name: ident, ns: namespace,
- dr: dir) -> option::t<def> {
+ dr: dir) -> option<def> {
let defid = def_id_of_def(m);
if defid.crate != ast::local_crate {
// examining a module in an external crate
ast::def_native_mod(defid) {
ret lookup_in_local_native_mod(e, defid.node, sp, name, ns);
}
+ _ {
+ // Precondition
+ e.sess.span_bug(sp, "lookup_in_mod was passed a non-mod def");
+ }
}
}
-fn found_view_item(e: env, vi: @ast::view_item) -> option::t<def> {
- alt vi.node {
- ast::view_item_use(_, _, id) {
- let cnum = cstore::get_use_stmt_cnum(e.cstore, id);
- ret some(ast::def_mod({crate: cnum, node: ast::crate_node_id}));
- }
- }
+fn found_view_item(e: env, id: node_id) -> def {
+ let cnum = cstore::get_use_stmt_cnum(e.cstore, id);
+ ret ast::def_mod({crate: cnum, node: ast::crate_node_id});
}
-fn lookup_import(e: env, defid: def_id, ns: namespace) -> option::t<def> {
+fn lookup_import(e: env, defid: def_id, ns: namespace) -> option<def> {
// Imports are simply ignored when resolving themselves.
if vec::member(defid.node, e.ignored_imports) { ret none; }
alt e.imports.get(defid.node) {
ret alt ns { ns_val(_) { val } ns_type { typ }
ns_module { md } };
}
+ is_glob(_,_,_) {
+ e.sess.bug("lookup_import: can't handle is_glob");
+ }
}
}
fn lookup_in_local_native_mod(e: env, node_id: node_id, sp: span, id: ident,
- ns: namespace) -> option::t<def> {
+ ns: namespace) -> option<def> {
ret lookup_in_local_mod(e, node_id, sp, id, ns, inside);
}
}
fn lookup_in_local_mod(e: env, node_id: node_id, sp: span, id: ident,
- ns: namespace, dr: dir) -> option::t<def> {
+ ns: namespace, dr: dir) -> option<def> {
let info = e.mod_map.get(node_id);
if dr == outside && !is_exported(e, id, option::get(info.m)) {
// if we're in a native mod, then dr==inside, so info.m is some _mod
}
fn lookup_in_globs(e: env, globs: [glob_imp_def], sp: span, id: ident,
- ns: namespace, dr: dir) -> option::t<def> {
+ ns: namespace, dr: dir) -> option<def> {
fn lookup_in_mod_(e: env, def: glob_imp_def, sp: span, name: ident,
- ns: namespace, dr: dir) -> option::t<glob_imp_def> {
+ ns: namespace, dr: dir) -> option<glob_imp_def> {
alt def.item.node {
ast::view_item_import_glob(_, id) {
if vec::member(id, e.ignored_imports) { ret none; }
}
+ _ {
+ e.sess.span_bug(sp, "lookup_in_globs: not a glob");
+ }
}
alt lookup_in_mod(e, def.def, sp, name, ns, dr) {
some(d) { option::some({def: d, item: def.item}) }
}
fn lookup_glob_in_mod(e: env, info: @indexed_mod, sp: span, id: ident,
- wanted_ns: namespace, dr: dir) -> option::t<def> {
+ wanted_ns: namespace, dr: dir) -> option<def> {
// since we don't know what names we have in advance,
// absence takes the place of todo()
if !info.glob_imported_names.contains_key(id) {
}
fn lookup_in_mie(e: env, mie: mod_index_entry, ns: namespace) ->
- option::t<def> {
+ option<def> {
alt mie {
- mie_view_item(view_item) {
- if ns == ns_module { ret found_view_item(e, view_item); }
+ mie_view_item(_, id, _) {
+ if ns == ns_module { ret some(found_view_item(e, id)); }
}
mie_import_ident(id, _) { ret lookup_import(e, local_def(id), ns); }
mie_item(item) { ret found_def_item(item, ns); }
- mie_enum_variant(item, variant_idx) {
- alt item.node {
- ast::item_enum(variants, _) {
- alt ns {
- ns_val(_) {
- let vid = variants[variant_idx].node.id;
- ret some(ast::def_variant(local_def(item.id),
+ mie_enum_variant(variant_idx, variants, parent_id, parent_span) {
+ alt ns {
+ ns_val(_) {
+ let vid = variants[variant_idx].node.id;
+ ret some(ast::def_variant(local_def(parent_id),
local_def(vid)));
- }
- _ { ret none::<def>; }
- }
- }
- }
+ }
+ _ { ret none::<def>; }
+ }
}
mie_native_item(native_item) {
alt native_item.node {
- ast::native_item_ty {
- if ns == ns_type {
- ret some(ast::def_native_ty(local_def(native_item.id)));
- }
- }
ast::native_item_fn(decl, _) {
if ns == ns_val(ns_any_value) {
ret some(ast::def_fn(local_def(native_item.id),
let index = new_str_hash::<list<mod_index_entry>>();
for it: @ast::view_item in md.view_items {
alt it.node {
- ast::view_item_use(ident, _, _) {
- add_to_index(index, ident, mie_view_item(it));
+ ast::view_item_use(ident, _, id) {
+ add_to_index(index, ident, mie_view_item(ident, id, it.span));
}
ast::view_item_import(ident, _, id) {
add_to_index(index, ident, mie_import_ident(id, it.span));
let variant_idx: uint = 0u;
for v: ast::variant in variants {
add_to_index(index, v.node.name,
- mie_enum_variant(it, variant_idx));
+ mie_enum_variant(variant_idx, variants,
+ it.id, it.span));
variant_idx += 1u;
}
}
+ ast::item_class(_, items, ctor_decl, _) {
+ fail "resolve::index_mod: item_class";
+ }
}
}
ret index;
let index = new_str_hash::<list<mod_index_entry>>();
for it: @ast::view_item in md.view_items {
alt it.node {
- ast::view_item_use(ident, _, _) {
- add_to_index(index, ident, mie_view_item(it));
+ ast::view_item_use(ident, _, id) {
+ add_to_index(index, ident, mie_view_item(ident, id,
+ it.span));
}
ast::view_item_import(ident, _, id) {
add_to_index(index, ident, mie_import_ident(id, it.span));
}
}
ast::view_item_import_glob(_, _) | ast::view_item_export(_, _) { }
+ _ { /* tag exports */ }
}
}
for it: @ast::native_item in md.items {
ast::def_upvar(_, _, _) | ast::def_self(_) { ns_val(ns_any_value) }
ast::def_mod(_) | ast::def_native_mod(_) { ns_module }
ast::def_ty(_) | ast::def_binding(_) | ast::def_use(_) |
- ast::def_native_ty(_) { ns_type }
+ ast::def_ty_param(_, _) { ns_type }
}
}
}
fn lookup_external(e: env, cnum: int, ids: [ident], ns: namespace) ->
- option::t<def> {
+ option<def> {
for d: def in csearch::lookup_defs(e.sess.cstore, cnum, ids) {
e.ext_map.insert(def_id_of_def(d), ids);
if ns_ok(ns, ns_for_def(d)) { ret some(d); }
fn mie_span(mie: mod_index_entry) -> span {
ret alt mie {
- mie_view_item(item) { item.span }
+ mie_view_item(_, _, span) { span }
mie_import_ident(_, span) { span }
mie_item(item) { item.span }
- mie_enum_variant(item, _) { item.span }
+ mie_enum_variant(_, _, _, span) { span }
mie_native_item(item) { item.span }
};
}
}
fn check_pat(e: @env, ch: checker, p: @ast::pat) {
- pat_util::pat_bindings(normalize_pat_def_map(e.def_map, p)) {|p|
- let ident = path_to_ident(alt p.node { pat_ident(n, _) { n } });
- add_name(ch, p.span, ident);
+ pat_util::pat_bindings(normalize_pat_def_map(e.def_map, p)) {|_i, p_sp, n|
+ add_name(ch, p_sp, path_to_ident(n));
};
}
ast::decl_local(locs) {
let local_values = checker(*e, "value");
for (_, loc) in locs {
- pat_util::pat_bindings
- (normalize_pat_def_map(e.def_map, loc.node.pat))
- {|p|
- let ident = path_to_ident(alt p.node
- { pat_ident(n, _) { n } });
- add_name(local_values, p.span, ident);
- check_name(values, p.span, ident);
- };
+ pat_util::pat_bindings
+ (normalize_pat_def_map(e.def_map, loc.node.pat))
+ {|_i, p_sp, n|
+ let ident = path_to_ident(n);
+ add_name(local_values, p_sp, ident);
+ check_name(values, p_sp, ident);
+ };
}
}
ast::decl_item(it) {
is_some(m) || is_some(v) || is_some(t)
}
- fn maybe_add_reexport(e: @env, path: str, def: option::t<def>) {
+ fn maybe_add_reexport(e: @env, path: str, def: option<def>) {
alt def {
some(def) {
alt e.exp_map.find(path) {
some(ms) {
list::iter(ms) {|m|
alt m {
- mie_enum_variant(parent_item,_) {
- if parent_item.id != parent_id {
+ mie_enum_variant(_, _, actual_parent_id,
+ _) {
+ if actual_parent_id != parent_id {
e.sess.span_err(vi.span,
#fmt("variant %s \
doesn't belong to enum %s",
}
fn find_impls_in_view_item(e: env, vi: @ast::view_item,
- &impls: [@_impl], sc: option::t<iscopes>) {
+ &impls: [@_impl], sc: option<iscopes>) {
fn lookup_imported_impls(e: env, id: ast::node_id,
act: fn(@[@_impl])) {
alt e.imports.get(id) {
scopes);
alt e.imports.get(id) {
resolved(_, _, _, is, _, _) { act(is); }
+ _ {
+ e.sess.bug("Undocumented invariant in \
+ lookup_imported_impls");
+ }
}
}
_ {}
_ {}
}
}
+ _ { e.sess.span_bug(vi.span, "Undocumented invariant in \
+ find_impls_in_view_item"); }
}
}
_ {}
}
fn find_impls_in_item(e: env, i: @ast::item, &impls: [@_impl],
- name: option::t<ident>,
- ck_exports: option::t<ast::_mod>) {
+ name: option<ident>,
+ ck_exports: option<ast::_mod>) {
alt i.node {
ast::item_impl(_, ifce, _, mthds) {
if alt name { some(n) { n == i.ident } _ { true } } &&
}
fn find_impls_in_mod_by_id(e: env, defid: def_id, &impls: [@_impl],
- name: option::t<ident>) {
+ name: option<ident>) {
let cached;
alt e.impl_cache.find(defid) {
some(some(v)) { cached = v; }
}
fn find_impls_in_mod(e: env, m: def, &impls: [@_impl],
- name: option::t<ident>) {
+ name: option<ident>) {
alt m {
ast::def_mod(defid) {
find_impls_in_mod_by_id(e, defid, impls, name);
_ {}
}
}
- let sc = vec::len(impls) > 0u ? cons(@impls, @sc) : sc;
+ let sc = if vec::len(impls) > 0u { cons(@impls, @sc) } else { sc };
visit::visit_block(b, sc, v);
}
}
for i in m.items { find_impls_in_item(*e, i, impls, none, none); }
let impls = @impls;
- visit::visit_mod(m, s, id,
- vec::len(*impls) > 0u ? cons(impls, @sc) : sc, v);
+ visit::visit_mod(m, s, id, if vec::len(*impls) > 0u {
+ cons(impls, @sc)
+ } else {
+ sc
+ }, v);
e.impl_map.insert(id, cons(impls, @nil));
}
// This substitutes for the runtime tags used by e.g. MLs.
import lib::llvm::llvm;
-import lib::llvm::{True, False};
-import lib::llvm::llvm::{ModuleRef, TypeRef, ValueRef};
+import lib::llvm::{True, False, ModuleRef, TypeRef, ValueRef};
import driver::session;
import driver::session::session;
import trans::base;
lib::llvm::llvm::LLVMSetGlobalConstant(llglobal, True);
if internal {
- lib::llvm::llvm::LLVMSetLinkage(llglobal,
- lib::llvm::LLVMInternalLinkage as
- lib::llvm::llvm::Linkage);
+ lib::llvm::SetLinkage(llglobal, lib::llvm::InternalLinkage);
}
ret llglobal;
ty::ty_bot { s += [shape_u8]; }
ty::ty_int(ast::ty_i) { s += [s_int(ccx.tcx)]; }
ty::ty_float(ast::ty_f) { s += [s_float(ccx.tcx)]; }
- ty::ty_uint(ast::ty_u) | ty::ty_ptr(_) |
- ty::ty_native(_) { s += [s_uint(ccx.tcx)]; }
+ ty::ty_uint(ast::ty_u) | ty::ty_ptr(_) { s += [s_uint(ccx.tcx)]; }
ty::ty_type { s += [s_tydesc(ccx.tcx)]; }
ty::ty_send_type { s += [s_send_tydesc(ccx.tcx)]; }
ty::ty_int(ast::ty_i8) { s += [shape_i8]; }
ty::ty_opaque_closure_ptr(_) {
s += [shape_opaque_closure_ptr];
}
+ ty::ty_constr(inner_t, _) {
+ s += shape_of(ccx, inner_t, ty_param_map);
+ }
+ ty::ty_named(_, _) {
+ ccx.tcx.sess.bug("shape_of: shouldn't see a ty_named");
+ }
}
ret s;
ret s;
}
-//fn variant_names(ccx: @crate_ctxt, tag_id: ast::def_id) -> [str] {
-// assert ast::local_crate == tag_id.crate;
-// alt ccx.tcx.items.get(tag_id.node) {
-// ast_map::node_item(@{node: ast::item_tag(variants, _), _}) {
-// vec::map(variants) {|variant| variant.node.name}
-// }
-// }
-//}
-
fn gen_enum_shapes(ccx: @crate_ctxt) -> ValueRef {
// Loop over all the enum variants and write their shapes into a
// data buffer. As we do this, it's possible for us to discover
[lltagstable, llresourcestable]);
lib::llvm::llvm::LLVMSetInitializer(ccx.shape_cx.llshapetables, lltables);
lib::llvm::llvm::LLVMSetGlobalConstant(ccx.shape_cx.llshapetables, True);
- lib::llvm::llvm::LLVMSetLinkage(ccx.shape_cx.llshapetables,
- lib::llvm::LLVMInternalLinkage as
- lib::llvm::llvm::Linkage);
+ lib::llvm::SetLinkage(ccx.shape_cx.llshapetables,
+ lib::llvm::InternalLinkage);
}
// ______________________________________________________________________
cx.enum_sizes.insert(t, max_size);
ret max_size;
}
+ _ { cx.tcx.sess.bug("static_size_of_enum called on non-enum"); }
}
}
{ bcx: bcx, sz: sz, align: C_int(ccx, 1) }
}
+ _ {
+ // Precondition?
+ bcx_tcx(cx).sess.bug("dynamic_metrics: type has static \
+ size");
+ }
}
}
import driver::session::session;
import lib::llvm::llvm;
-import lib::llvm::llvm::{ValueRef, BasicBlockRef};
+import lib::llvm::{ValueRef, BasicBlockRef};
import pat_util::*;
import build::*;
-import base::{new_sub_block_ctxt, new_scope_block_ctxt, load_if_immediate};
+import base::{new_sub_block_ctxt, new_scope_block_ctxt,
+ new_real_block_ctxt, load_if_immediate};
import syntax::ast;
import syntax::ast_util;
import syntax::ast_util::{dummy_sp};
import syntax::ast::def_id;
import syntax::codemap::span;
import syntax::print::pprust::pat_to_str;
+import back::abi;
import common::*;
// range)
enum opt {
lit(@ast::expr),
- var(/* disr val */int, /* variant dids */{tg: def_id, var: def_id}),
+ var(/* disr val */int, /* variant dids */{enm: def_id, var: def_id}),
range(@ast::expr, @ast::expr)
}
fn opt_eq(a: opt, b: opt) -> bool {
// FIXME: invariant -- pat_id is bound in the def_map?
fn variant_opt(ccx: @crate_ctxt, pat_id: ast::node_id) -> opt {
let vdef = ast_util::variant_def_ids(ccx.tcx.def_map.get(pat_id));
- let variants = ty::enum_variants(ccx.tcx, vdef.tg);
+ let variants = ty::enum_variants(ccx.tcx, vdef.enm);
for v: ty::variant_info in *variants {
if vdef.var == v.id { ret var(v.disr_val, vdef); }
}
}
type bind_map = [{ident: ast::ident, val: ValueRef}];
-fn assoc(key: str, list: bind_map) -> option::t<ValueRef> {
+fn assoc(key: str, list: bind_map) -> option<ValueRef> {
for elt: {ident: ast::ident, val: ValueRef} in list {
if str::eq(elt.ident, key) { ret some(elt.val); }
}
@{pats: [@ast::pat],
bound: bind_map,
data: @{body: BasicBlockRef,
- guard: option::t<@ast::expr>,
+ guard: option<@ast::expr>,
id_map: pat_id_map}};
type match = [match_branch];
result
}
-type enter_pat = fn@(@ast::pat) -> option::t<[@ast::pat]>;
+type enter_pat = fn@(@ast::pat) -> option<[@ast::pat]>;
fn enter_match(m: match, col: uint, val: ValueRef, e: enter_pat) -> match {
let result = [];
_ { false }
}
}
- fn e(p: @ast::pat) -> option::t<[@ast::pat]> {
+ fn e(p: @ast::pat) -> option<[@ast::pat]> {
ret if matches_always(p) { some([]) } else { none };
}
ret enter_match(m, col, val, e);
val: ValueRef) -> match {
let dummy = @{id: 0, node: ast::pat_wild, span: dummy_sp()};
fn e(ccx: @crate_ctxt, dummy: @ast::pat, opt: opt, size: uint,
- p: @ast::pat) -> option::t<[@ast::pat]> {
+ p: @ast::pat) -> option<[@ast::pat]> {
alt p.node {
ast::pat_enum(ctor, subpats) {
ret if opt_eq(variant_opt(ccx, p.id), opt) {
match {
let dummy = @{id: 0, node: ast::pat_wild, span: dummy_sp()};
fn e(dummy: @ast::pat, fields: [ast::ident], p: @ast::pat) ->
- option::t<[@ast::pat]> {
+ option<[@ast::pat]> {
alt p.node {
ast::pat_rec(fpats, _) {
let pats = [];
fn enter_tup(m: match, col: uint, val: ValueRef, n_elts: uint) -> match {
let dummy = @{id: 0, node: ast::pat_wild, span: dummy_sp()};
fn e(dummy: @ast::pat, n_elts: uint, p: @ast::pat) ->
- option::t<[@ast::pat]> {
+ option<[@ast::pat]> {
alt p.node {
ast::pat_tup(elts) { ret some(elts); }
_ { ret some(vec::init_elt(n_elts, dummy)); }
fn enter_box(m: match, col: uint, val: ValueRef) -> match {
let dummy = @{id: 0, node: ast::pat_wild, span: dummy_sp()};
- fn e(dummy: @ast::pat, p: @ast::pat) -> option::t<[@ast::pat]> {
+ fn e(dummy: @ast::pat, p: @ast::pat) -> option<[@ast::pat]> {
alt p.node {
ast::pat_box(sub) { ret some([sub]); }
_ { ret some([dummy]); }
fn enter_uniq(m: match, col: uint, val: ValueRef) -> match {
let dummy = @{id: 0, node: ast::pat_wild, span: dummy_sp()};
- fn e(dummy: @ast::pat, p: @ast::pat) -> option::t<[@ast::pat]> {
+ fn e(dummy: @ast::pat, p: @ast::pat) -> option<[@ast::pat]> {
alt p.node {
ast::pat_uniq(sub) { ret some([sub]); }
_ { ret some([dummy]); }
}
fn extract_variant_args(bcx: @block_ctxt, pat_id: ast::node_id,
- vdefs: {tg: def_id, var: def_id}, val: ValueRef) ->
+ vdefs: {enm: def_id, var: def_id}, val: ValueRef) ->
{vals: [ValueRef], bcx: @block_ctxt} {
- let ccx = bcx.fcx.lcx.ccx, bcx = bcx;
+ let ccx = bcx.fcx.ccx, bcx = bcx;
// invariant:
// pat_id must have the same length ty_param_substs as vdefs?
let ty_param_substs = ty::node_id_to_type_params(ccx.tcx, pat_id);
let blobptr = val;
- let variants = ty::enum_variants(ccx.tcx, vdefs.tg);
+ let variants = ty::enum_variants(ccx.tcx, vdefs.enm);
let args = [];
let size =
- vec::len(ty::enum_variant_with_id(ccx.tcx, vdefs.tg, vdefs.var).args);
+ vec::len(ty::enum_variant_with_id(ccx.tcx, vdefs.enm, vdefs.var).args);
if size > 0u && vec::len(*variants) != 1u {
let enumptr =
PointerCast(bcx, val, T_opaque_enum_ptr(ccx));
blobptr = GEPi(bcx, enumptr, [0, 1]);
}
let i = 0u;
- let vdefs_tg = vdefs.tg;
+ let vdefs_tg = vdefs.enm;
let vdefs_var = vdefs.var;
while i < size {
check (valid_variant_index(i, bcx, vdefs_tg, vdefs_var));
let col = pick_col(m);
let val = vals[col];
- let m = has_nested_bindings(m, col) ?
- expand_nested_bindings(m, col, val) : m;
+ let m = if has_nested_bindings(m, col) {
+ expand_nested_bindings(m, col, val)
+ } else {
+ m
+ };
let vals_left =
vec::slice(vals, 0u, col) +
vec::slice(vals, col + 1u, vec::len(vals));
- let ccx = bcx.fcx.lcx.ccx;
+ let ccx = bcx.fcx.ccx;
let pat_id = 0;
for br: match_branch in m {
// Find a real id (we're adding placeholder wildcard patterns, but
let rec_fields = collect_record_fields(m, col);
// Separate path for extracting and binding record fields
if vec::len(rec_fields) > 0u {
- let rec_ty = ty::node_id_to_monotype(ccx.tcx, pat_id);
- let fields =
- alt ty::struct(ccx.tcx, rec_ty) { ty::ty_rec(fields) { fields } };
+ let rec_ty = ty::node_id_to_type(ccx.tcx, pat_id);
+ let fields = ty::get_fields(ccx.tcx, rec_ty);
let rec_vals = [];
for field_name: ast::ident in rec_fields {
let ix = option::get(ty::field_idx(field_name, fields));
}
if any_tup_pat(m, col) {
- let tup_ty = ty::node_id_to_monotype(ccx.tcx, pat_id);
+ let tup_ty = ty::node_id_to_type(ccx.tcx, pat_id);
let n_tup_elts =
alt ty::struct(ccx.tcx, tup_ty) {
ty::ty_tup(elts) { vec::len(elts) }
+ _ {
+ ccx.sess.bug("Non-tuple type in tuple\
+ pattern");
+ }
};
let tup_vals = [], i = 0u;
while i < n_tup_elts {
// Unbox in case of a box field
if any_box_pat(m, col) {
let box = Load(bcx, val);
- let unboxed = GEPi(bcx, box, [0, back::abi::box_rc_field_body]);
+ let unboxed = GEPi(bcx, box, [0, abi::box_field_body]);
compile_submatch(bcx, enter_box(m, col, val), [unboxed] + vals_left,
f, exits);
ret;
if vec::len(opts) > 0u {
alt opts[0] {
var(_, vdef) {
- if vec::len(*ty::enum_variants(ccx.tcx, vdef.tg)) == 1u {
+ if vec::len(*ty::enum_variants(ccx.tcx, vdef.enm)) == 1u {
kind = single;
} else {
let enumptr =
}
lit(l) {
test_val = Load(bcx, val);
- let pty = ty::node_id_to_monotype(ccx.tcx, pat_id);
- kind = ty::type_is_integral(ccx.tcx, pty) ? switch : compare;
+ let pty = ty::node_id_to_type(ccx.tcx, pat_id);
+ kind = if ty::type_is_integral(ccx.tcx, pty) {
+ switch
+ } else {
+ compare
+ };
}
range(_, _) {
test_val = Load(bcx, val);
llvm::LLVMAddCase(sw, r.val, opt_cx.llbb);
bcx = r.bcx;
}
+ _ { bcx_tcx(bcx).sess.bug("Someone forgot to\
+ document an invariant in compile_submatch"); }
}
}
compare {
// Copy references that the alias analysis considered unsafe
ids.values {|node_id|
if bcx_ccx(bcx).copy_map.contains_key(node_id) {
- let local = alt bcx.fcx.lllocals.get(node_id) {
- local_mem(x) { x }
+ let local = alt bcx.fcx.lllocals.find(node_id) {
+ some(local_mem(x)) { x }
+ _ { bcx_tcx(bcx).sess.bug("Someone \
+ forgot to document an invariant in \
+ make_phi_bindings"); }
};
let e_ty = ty::node_id_to_type(bcx_tcx(bcx), node_id);
let {bcx: abcx, val: alloc} = base::alloc_ty(bcx, e_ty);
let arms = normalize_arms(bcx_tcx(cx), arms_);
for a: ast::arm in arms {
- let body = new_scope_block_ctxt(er.bcx, "case_body");
+ let body = new_real_block_ctxt(er.bcx, "case_body",
+ a.body.span);
let id_map = pat_util::pat_id_map(bcx_tcx(cx), a.pats[0]);
bodies += [body];
for p: @ast::pat in a.pats {
// Cached fail-on-fallthrough block
let fail_cx = @mutable none;
fn mk_fail(cx: @block_ctxt, sp: span,
- done: @mutable option::t<BasicBlockRef>) -> BasicBlockRef {
+ done: @mutable option<BasicBlockRef>) -> BasicBlockRef {
alt *done { some(bb) { ret bb; } _ { } }
let fail_cx = new_sub_block_ctxt(cx, "case_fallthrough");
base::trans_fail(fail_cx, some(sp), "non-exhaustive match failure");;
}
let exit_map = [];
- let t = base::node_id_type(cx.fcx.lcx.ccx, expr.id);
+ let t = node_id_type(cx, expr.id);
let vr = base::spill_if_immediate(er.bcx, er.val, t);
compile_submatch(vr.bcx, match, [vr.val],
bind mk_fail(alt_cx, expr.span, fail_cx), exit_map);
// Not alt-related, but similar to the pattern-munging code above
fn bind_irrefutable_pat(bcx: @block_ctxt, pat: @ast::pat, val: ValueRef,
make_copy: bool) -> @block_ctxt {
- let ccx = bcx.fcx.lcx.ccx, bcx = bcx;
+ let ccx = bcx.fcx.ccx, bcx = bcx;
// Necessary since bind_irrefutable_pat is called outside trans_alt
alt normalize_pat(bcx_tcx(bcx), pat).node {
ast::pat_ident(_,inner) {
if make_copy || ccx.copy_map.contains_key(pat.id) {
- let ty = ty::node_id_to_monotype(ccx.tcx, pat.id);
+ let ty = node_id_type(bcx, pat.id);
// FIXME: Could constrain pat_bind to make this
// check unnecessary.
check (type_has_static_size(ccx, ty));
}
}
ast::pat_rec(fields, _) {
- let rec_ty = ty::node_id_to_monotype(ccx.tcx, pat.id);
- let rec_fields =
- alt ty::struct(ccx.tcx, rec_ty) { ty::ty_rec(fields) { fields } };
+ let rec_ty = node_id_type(bcx, pat.id);
+ let rec_fields = ty::get_fields(ccx.tcx, rec_ty);
for f: ast::field_pat in fields {
let ix = option::get(ty::field_idx(f.ident, rec_fields));
// how to get rid of this check?
}
}
ast::pat_tup(elems) {
- let tup_ty = ty::node_id_to_monotype(ccx.tcx, pat.id);
+ let tup_ty = node_id_type(bcx, pat.id);
let i = 0u;
for elem in elems {
// how to get rid of this check?
ast::pat_box(inner) {
let box = Load(bcx, val);
let unboxed =
- GEPi(bcx, box, [0, back::abi::box_rc_field_body]);
+ GEPi(bcx, box, [0, abi::box_field_body]);
bcx = bind_irrefutable_pat(bcx, inner, unboxed, true);
}
ast::pat_uniq(inner) {
import driver::session;
import session::session;
import front::attr;
-import middle::{ty, gc, resolve, debuginfo};
import middle::freevars::*;
import back::{link, abi, upcall};
import syntax::{ast, ast_util, codemap};
+import ast_util::local_def;
import syntax::visit;
import syntax::codemap::span;
import syntax::print::pprust::{expr_to_str, stmt_to_str, path_to_str};
import visit::vt;
import util::common::*;
import lib::llvm::{llvm, mk_target_data, mk_type_names};
-import lib::llvm::llvm::{ModuleRef, ValueRef, TypeRef, BasicBlockRef};
+import lib::llvm::{ModuleRef, ValueRef, TypeRef, BasicBlockRef};
import lib::llvm::{True, False};
import link::{mangle_internal_name_by_type_only,
mangle_internal_name_by_seq,
import metadata::{csearch, cstore};
import util::ppaux::{ty_to_str, ty_to_short_str};
+import shape::static_size_of_enum;
import common::*;
import build::*;
+import ast_map::{path, path_mod, path_name};
fn type_of_1(bcx: @block_ctxt, t: ty::t) -> TypeRef {
let cx = bcx_ccx(bcx);
fn type_of_explicit_args(cx: @crate_ctxt, inputs: [ty::arg]) ->
[TypeRef] {
- let atys = [];
- for arg in inputs {
+ let tcx = ccx_tcx(cx);
+ vec::map(inputs) {|arg|
let arg_ty = arg.ty;
// FIXME: would be nice to have a constraint on arg
// that would obviate the need for this check
check non_ty_var(cx, arg_ty);
let llty = type_of_inner(cx, arg_ty);
- atys += [arg.mode == ast::by_val ? llty : T_ptr(llty)];
+ alt ty::resolved_mode(tcx, arg.mode) {
+ ast::by_val { llty }
+ _ { T_ptr(llty) }
+ }
}
- ret atys;
}
atys += [out_ty];
// Arg 1: Environment
- atys += [T_opaque_cbox_ptr(cx)];
+ atys += [T_opaque_box_ptr(cx)];
// Args >2: ty params, if not acquired via capture...
for bounds in params {
// Given a function type and a count of ty params, construct an llvm type
fn type_of_fn_from_ty(cx: @crate_ctxt, fty: ty::t,
param_bounds: [ty::param_bounds]) -> TypeRef {
- // FIXME: Check should be unnecessary, b/c it's implied
- // by returns_non_ty_var(t). Make that a postcondition
- // (see Issue #586)
let ret_ty = ty::ty_fn_ret(cx.tcx, fty);
ret type_of_fn(cx, ty::ty_fn_args(cx.tcx, fty),
ret_ty, param_bounds);
if cx.lltypes.contains_key(t) { ret cx.lltypes.get(t); }
let llty = alt ty::struct(cx.tcx, t) {
- ty::ty_native(_) { T_ptr(T_i8()) }
ty::ty_nil { T_nil() }
ty::ty_bot {
T_nil() /* ...I guess? */
T_struct(tys)
}
ty::ty_opaque_closure_ptr(_) {
- T_opaque_cbox_ptr(cx)
+ T_opaque_box_ptr(cx)
}
ty::ty_constr(subt,_) {
// FIXME: could be a constraint on ty_fn
}
}
-fn type_of_ty_param_bounds_and_ty(lcx: @local_ctxt,
- tpt: ty::ty_param_bounds_and_ty) -> TypeRef {
- let cx = lcx.ccx;
+fn type_of_ty_param_bounds_and_ty
+ (ccx: @crate_ctxt, tpt: ty::ty_param_bounds_and_ty) -> TypeRef {
let t = tpt.ty;
- alt ty::struct(cx.tcx, t) {
+ alt ty::struct(ccx.tcx, t) {
ty::ty_fn(_) {
- ret type_of_fn_from_ty(cx, t, *tpt.bounds);
+ ret type_of_fn_from_ty(ccx, t, *tpt.bounds);
}
_ {
// fall through
// FIXME: could have a precondition on tpt, but that
// doesn't work right now because one predicate can't imply
// another
- check (type_has_static_size(cx, t));
- type_of(cx, t)
+ check type_has_static_size(ccx, t);
+ type_of(ccx, t)
}
fn type_of_or_i8(bcx: @block_ctxt, typ: ty::t) -> TypeRef {
}
-fn decl_fn(llmod: ModuleRef, name: str, cc: uint, llty: TypeRef) ->
- ValueRef {
- let llfn: ValueRef =
- str::as_buf(name, {|buf|
- llvm::LLVMGetOrInsertFunction(llmod, buf, llty) });
- llvm::LLVMSetFunctionCallConv(llfn, cc as c_uint);
+fn decl_fn(llmod: ModuleRef, name: str, cc: lib::llvm::CallConv,
+ llty: TypeRef) -> ValueRef {
+ let llfn: ValueRef = str::as_buf(name, {|buf|
+ llvm::LLVMGetOrInsertFunction(llmod, buf, llty)
+ });
+ lib::llvm::SetFunctionCallConv(llfn, cc);
ret llfn;
}
fn decl_cdecl_fn(llmod: ModuleRef, name: str, llty: TypeRef) -> ValueRef {
- ret decl_fn(llmod, name, lib::llvm::LLVMCCallConv, llty);
+ ret decl_fn(llmod, name, lib::llvm::CCallConv, llty);
}
fn decl_internal_cdecl_fn(llmod: ModuleRef, name: str, llty: TypeRef) ->
ValueRef {
let llfn = decl_cdecl_fn(llmod, name, llty);
- llvm::LLVMSetLinkage(llfn,
- lib::llvm::LLVMInternalLinkage as llvm::Linkage);
+ lib::llvm::SetLinkage(llfn, lib::llvm::InternalLinkage);
ret llfn;
}
fn get_extern_fn(externs: hashmap<str, ValueRef>, llmod: ModuleRef, name: str,
- cc: uint, ty: TypeRef) -> ValueRef {
+ cc: lib::llvm::CallConv, ty: TypeRef) -> ValueRef {
if externs.contains_key(name) { ret externs.get(name); }
let f = decl_fn(llmod, name, cc, ty);
externs.insert(name, f);
externs: hashmap<str, ValueRef>,
llmod: ModuleRef,
name: str, n_args: int) -> ValueRef {
- let ccx = cx.fcx.lcx.ccx;
+ let ccx = cx.fcx.ccx;
let inputs = vec::init_elt::<TypeRef>(n_args as uint, ccx.int_type);
let output = ccx.int_type;
let t = T_fn(inputs, output);
- ret get_extern_fn(externs, llmod, name,
- lib::llvm::LLVMCCallConv, t);
+ ret get_extern_fn(externs, llmod, name, lib::llvm::CCallConv, t);
}
fn trans_native_call(cx: @block_ctxt, externs: hashmap<str, ValueRef>,
ret Call(cx, llnative, call_args);
}
-fn trans_free_if_not_gc(cx: @block_ctxt, v: ValueRef) -> @block_ctxt {
- let ccx = bcx_ccx(cx);
- if !ccx.sess.opts.do_gc {
- Call(cx, ccx.upcalls.free,
- [PointerCast(cx, v, T_ptr(T_i8())),
- C_int(bcx_ccx(cx), 0)]);
- }
- ret cx;
+fn trans_free(cx: @block_ctxt, v: ValueRef) -> @block_ctxt {
+ Call(cx, bcx_ccx(cx).upcalls.free, [PointerCast(cx, v, T_ptr(T_i8()))]);
+ cx
}
fn trans_shared_free(cx: @block_ctxt, v: ValueRef) -> @block_ctxt {
}
fn umax(cx: @block_ctxt, a: ValueRef, b: ValueRef) -> ValueRef {
- let cond = ICmp(cx, lib::llvm::LLVMIntULT, a, b);
+ let cond = ICmp(cx, lib::llvm::IntULT, a, b);
ret Select(cx, cond, b, a);
}
fn umin(cx: @block_ctxt, a: ValueRef, b: ValueRef) -> ValueRef {
- let cond = ICmp(cx, lib::llvm::LLVMIntULT, a, b);
+ let cond = ICmp(cx, lib::llvm::IntULT, a, b);
ret Select(cx, cond, a, b);
}
-fn align_to(cx: @block_ctxt, off: ValueRef, align: ValueRef) -> ValueRef {
- let mask = Sub(cx, align, C_int(bcx_ccx(cx), 1));
- let bumped = Add(cx, off, mask);
- ret And(cx, bumped, Not(cx, mask));
-}
-
-
// Returns the real size of the given type for the current target.
fn llsize_of_real(cx: @crate_ctxt, t: TypeRef) -> uint {
ret llvm::LLVMStoreSizeOfType(cx.td.lltd, t) as uint;
ret ty::fold_ty(ccx.tcx, ty::fm_general(bind simplifier(ccx, _)), typ);
}
-
-// Computes the size of the data part of a non-dynamically-sized enum.
-fn static_size_of_enum(cx: @crate_ctxt, t: ty::t)
- : type_has_static_size(cx, t) -> uint {
- if cx.enum_sizes.contains_key(t) { ret cx.enum_sizes.get(t); }
- alt ty::struct(cx.tcx, t) {
- ty::ty_enum(tid, subtys) {
- // Compute max(variant sizes).
-
- let max_size = 0u;
- let variants = ty::enum_variants(cx.tcx, tid);
- for variant: ty::variant_info in *variants {
- let tup_ty = simplify_type(cx, ty::mk_tup(cx.tcx, variant.args));
- // Perform any type parameter substitutions.
-
- tup_ty = ty::substitute_type_params(cx.tcx, subtys, tup_ty);
- // Here we possibly do a recursive call.
-
- // FIXME: Avoid this check. Since the parent has static
- // size, any field must as well. There should be a way to
- // express that with constrained types.
- check (type_has_static_size(cx, tup_ty));
- let this_size = llsize_of_real(cx, type_of(cx, tup_ty));
- if max_size < this_size { max_size = this_size; }
- }
- cx.enum_sizes.insert(t, max_size);
- ret max_size;
- }
- }
-}
-
fn dynamic_size_of(cx: @block_ctxt, t: ty::t) -> result {
fn align_elements(cx: @block_ctxt, elts: [ty::t]) -> result {
//
} else { max_size_val };
ret rslt(bcx, total_size);
}
+ // Precondition?
+ _ { bcx_tcx(cx).sess.fatal("trans::dynamic_size_of alled on something \
+ with static size"); }
}
}
}
ret rslt(bcx, a);
}
+ _ { bcx_tcx(cx).sess.bug("trans::dynamic_align_of called on \
+ something with static size"); }
}
}
ret rslt(cx, PointerCast(cx, rval, llptr_ty));
}
-// trans_malloc_boxed_raw: expects an unboxed type and returns a pointer to
-// enough space for something of that type, along with space for a reference
-// count; in other words, it allocates a box for something of that type.
-fn trans_malloc_boxed_raw(cx: @block_ctxt, t: ty::t) -> result {
- let bcx = cx;
-
- // Synthesize a fake box type structurally so we have something
- // to measure the size of.
-
- // We synthesize two types here because we want both the type of the
- // pointer and the pointee. boxed_body is the type that we measure the
- // size of; box_ptr is the type that's converted to a TypeRef and used as
- // the pointer cast target in trans_raw_malloc.
+// Returns a pointer to the body for the box. The box may be an opaque
+// box. The result will be casted to the type of body_t, if it is statically
+// known.
+//
+// The runtime equivalent is box_body() in "rust_internal.h".
+fn opaque_box_body(bcx: @block_ctxt,
+ body_t: ty::t,
+ boxptr: ValueRef) -> ValueRef {
+ let ccx = bcx_ccx(bcx);
+ let boxptr = PointerCast(bcx, boxptr, T_ptr(T_box_header(ccx)));
+ let bodyptr = GEPi(bcx, boxptr, [1]);
+ if check type_has_static_size(ccx, body_t) {
+ PointerCast(bcx, bodyptr, T_ptr(type_of(ccx, body_t)))
+ } else {
+ PointerCast(bcx, bodyptr, T_ptr(T_i8()))
+ }
+}
- // The mk_int here is the space being
- // reserved for the refcount.
- let boxed_body = ty::mk_tup(bcx_tcx(bcx), [ty::mk_int(bcx_tcx(cx)), t]);
- let box_ptr = ty::mk_imm_box(bcx_tcx(bcx), t);
- let r = size_of(cx, boxed_body);
- let llsz = r.val; bcx = r.bcx;
+// trans_malloc_boxed_raw: expects an unboxed type and returns a pointer to
+// enough space for a box of that type. This includes a rust_opaque_box
+// header.
+fn trans_malloc_boxed_raw(bcx: @block_ctxt, t: ty::t,
+ &static_ti: option<@tydesc_info>) -> result {
+ let bcx = bcx;
+ let ccx = bcx_ccx(bcx);
// Grab the TypeRef type of box_ptr, because that's what trans_raw_malloc
// wants.
- // FIXME: Could avoid this check with a postcondition on mk_imm_box?
- // (requires Issue #586)
- let ccx = bcx_ccx(bcx);
+ let box_ptr = ty::mk_imm_box(bcx_tcx(bcx), t);
check (type_has_static_size(ccx, box_ptr));
let llty = type_of(ccx, box_ptr);
- let ti = none;
- let tydesc_result = get_tydesc(bcx, t, true, ti);
- let lltydesc = tydesc_result.result.val; bcx = tydesc_result.result.bcx;
+ // Get the tydesc for the body:
+ let {bcx, val: lltydesc} = get_tydesc(bcx, t, true, static_ti).result;
- let rval = Call(cx, ccx.upcalls.malloc,
- [llsz, lltydesc]);
- ret rslt(cx, PointerCast(cx, rval, llty));
+ // Allocate space:
+ let rval = Call(bcx, ccx.upcalls.malloc, [lltydesc]);
+ ret rslt(bcx, PointerCast(bcx, rval, llty));
}
// trans_malloc_boxed: usefully wraps trans_malloc_box_raw; allocates a box,
// initializes the reference count to 1, and pulls out the body and rc
-fn trans_malloc_boxed(cx: @block_ctxt, t: ty::t) ->
+fn trans_malloc_boxed(bcx: @block_ctxt, t: ty::t) ->
{bcx: @block_ctxt, box: ValueRef, body: ValueRef} {
- let res = trans_malloc_boxed_raw(cx, t);
- let box = res.val;
- let rc = GEPi(res.bcx, box, [0, abi::box_rc_field_refcnt]);
- Store(res.bcx, C_int(bcx_ccx(cx), 1), rc);
- let body = GEPi(res.bcx, box, [0, abi::box_rc_field_body]);
- ret {bcx: res.bcx, box: res.val, body: body};
+ let ti = none;
+ let {bcx, val:box} = trans_malloc_boxed_raw(bcx, t, ti);
+ let body = GEPi(bcx, box, [0, abi::box_field_body]);
+ ret {bcx: bcx, box: box, body: body};
}
// Type descriptor and type glue stuff
// constructing derived tydescs.
fn linearize_ty_params(cx: @block_ctxt, t: ty::t) ->
{params: [uint], descs: [ValueRef]} {
- let param_vals: [ValueRef] = [];
- let param_defs: [uint] = [];
- type rr =
- {cx: @block_ctxt, mutable vals: [ValueRef], mutable defs: [uint]};
-
- fn linearizer(r: @rr, t: ty::t) {
- alt ty::struct(bcx_tcx(r.cx), t) {
+ let param_vals = [], param_defs = [];
+ ty::walk_ty(bcx_tcx(cx), t) {|t|
+ alt ty::struct(bcx_tcx(cx), t) {
ty::ty_param(pid, _) {
- let seen: bool = false;
- for d: uint in r.defs { if d == pid { seen = true; } }
- if !seen {
- r.vals += [r.cx.fcx.lltyparams[pid].desc];
- r.defs += [pid];
+ if !vec::any(param_defs, {|d| d == pid}) {
+ param_vals += [cx.fcx.lltyparams[pid].desc];
+ param_defs += [pid];
}
}
_ { }
}
}
- let x = @{cx: cx, mutable vals: param_vals, mutable defs: param_defs};
- let f = bind linearizer(x, _);
- ty::walk_ty(bcx_tcx(cx), t, f);
- ret {params: x.defs, descs: x.vals};
+ ret {params: param_defs, descs: param_vals};
}
fn trans_stack_local_derived_tydesc(cx: @block_ctxt, llsz: ValueRef,
}
fn get_derived_tydesc(cx: @block_ctxt, t: ty::t, escapes: bool,
- &static_ti: option::t<@tydesc_info>) -> result {
+ &static_ti: option<@tydesc_info>) -> result {
alt cx.fcx.derived_tydescs.find(t) {
some(info) {
// If the tydesc escapes in this context, the cached derived
type get_tydesc_result = {kind: tydesc_kind, result: result};
fn get_tydesc(cx: @block_ctxt, t: ty::t, escapes: bool,
- &static_ti: option::t<@tydesc_info>)
+ &static_ti: option<@tydesc_info>)
-> get_tydesc_result {
// Is the supplied type a type param? If so, return the passed-in tydesc.
some(info) { ret info; }
none {
bcx_ccx(cx).stats.n_static_tydescs += 1u;
- let info = declare_tydesc(cx.fcx.lcx, t, ty_params);
+ let info = declare_tydesc(cx.fcx.ccx, t, ty_params);
bcx_ccx(cx).tydescs.insert(t, info);
ret info;
}
}
fn set_no_inline(f: ValueRef) {
- llvm::LLVMAddFunctionAttr(f,
- lib::llvm::LLVMNoInlineAttribute as
- lib::llvm::llvm::Attribute,
+ llvm::LLVMAddFunctionAttr(f, lib::llvm::NoInlineAttribute as c_uint,
0u as c_uint);
}
// Tell LLVM to emit the information necessary to unwind the stack for the
// function f.
fn set_uwtable(f: ValueRef) {
- llvm::LLVMAddFunctionAttr(f,
- lib::llvm::LLVMUWTableAttribute as
- lib::llvm::llvm::Attribute,
+ llvm::LLVMAddFunctionAttr(f, lib::llvm::UWTableAttribute as c_uint,
0u as c_uint);
}
fn set_always_inline(f: ValueRef) {
- llvm::LLVMAddFunctionAttr(f,
- lib::llvm::LLVMAlwaysInlineAttribute as
- lib::llvm::llvm::Attribute,
+ llvm::LLVMAddFunctionAttr(f, lib::llvm::AlwaysInlineAttribute as c_uint,
0u as c_uint);
}
fn set_custom_stack_growth_fn(f: ValueRef) {
// TODO: Remove this hack to work around the lack of u64 in the FFI.
- llvm::LLVMAddFunctionAttr(f, 0 as lib::llvm::llvm::Attribute,
- 1u as c_uint);
+ llvm::LLVMAddFunctionAttr(f, 0u as c_uint, 1u as c_uint);
}
-fn set_glue_inlining(cx: @local_ctxt, f: ValueRef, t: ty::t) {
- if ty::type_is_structural(cx.ccx.tcx, t) {
+fn set_glue_inlining(ccx: @crate_ctxt, f: ValueRef, t: ty::t) {
+ if ty::type_is_structural(ccx.tcx, t) {
set_no_inline(f);
} else { set_always_inline(f); }
}
// Generates the declaration for (but doesn't emit) a type descriptor.
-fn declare_tydesc(cx: @local_ctxt, t: ty::t, ty_params: [uint])
+fn declare_tydesc(ccx: @crate_ctxt, t: ty::t, ty_params: [uint])
-> @tydesc_info {
- log(debug, "+++ declare_tydesc " + ty_to_str(cx.ccx.tcx, t));
- let ccx = cx.ccx;
+ log(debug, "+++ declare_tydesc " + ty_to_str(ccx.tcx, t));
let llsize;
let llalign;
if check type_has_static_size(ccx, t) {
llalign = C_int(ccx, 0);
}
let name;
- if cx.ccx.sess.opts.debuginfo {
- name = mangle_internal_name_by_type_only(cx.ccx, t, "tydesc");
+ if ccx.sess.opts.debuginfo {
+ name = mangle_internal_name_by_type_only(ccx, t, "tydesc");
name = sanitize(name);
- } else { name = mangle_internal_name_by_seq(cx.ccx, "tydesc"); }
- let gvar =
- str::as_buf(name,
- {|buf|
- llvm::LLVMAddGlobal(ccx.llmod, ccx.tydesc_type, buf)
- });
+ } else { name = mangle_internal_name_by_seq(ccx, "tydesc"); }
+ let gvar = str::as_buf(name, {|buf|
+ llvm::LLVMAddGlobal(ccx.llmod, ccx.tydesc_type, buf)
+ });
let info =
@{ty: t,
tydesc: gvar,
size: llsize,
align: llalign,
- mutable take_glue: none::<ValueRef>,
- mutable drop_glue: none::<ValueRef>,
- mutable free_glue: none::<ValueRef>,
- mutable cmp_glue: none::<ValueRef>,
+ mutable take_glue: none,
+ mutable drop_glue: none,
+ mutable free_glue: none,
+ mutable cmp_glue: none,
ty_params: ty_params};
- log(debug, "--- declare_tydesc " + ty_to_str(cx.ccx.tcx, t));
+ log(debug, "--- declare_tydesc " + ty_to_str(ccx.tcx, t));
ret info;
}
type glue_helper = fn@(@block_ctxt, ValueRef, ty::t);
-fn declare_generic_glue(cx: @local_ctxt, t: ty::t, llfnty: TypeRef, name: str)
- -> ValueRef {
+fn declare_generic_glue(ccx: @crate_ctxt, t: ty::t, llfnty: TypeRef,
+ name: str) -> ValueRef {
let name = name;
let fn_nm;
- if cx.ccx.sess.opts.debuginfo {
- fn_nm = mangle_internal_name_by_type_only(cx.ccx, t, "glue_" + name);
+ if ccx.sess.opts.debuginfo {
+ fn_nm = mangle_internal_name_by_type_only(ccx, t, "glue_" + name);
fn_nm = sanitize(fn_nm);
- } else { fn_nm = mangle_internal_name_by_seq(cx.ccx, "glue_" + name); }
- let llfn = decl_cdecl_fn(cx.ccx.llmod, fn_nm, llfnty);
- set_glue_inlining(cx, llfn, t);
+ } else { fn_nm = mangle_internal_name_by_seq(ccx, "glue_" + name); }
+ let llfn = decl_cdecl_fn(ccx.llmod, fn_nm, llfnty);
+ set_glue_inlining(ccx, llfn, t);
ret llfn;
}
// FIXME: was this causing the leak?
-fn make_generic_glue_inner(cx: @local_ctxt, t: ty::t,
+fn make_generic_glue_inner(ccx: @crate_ctxt, t: ty::t,
llfn: ValueRef, helper: glue_helper,
ty_params: [uint]) -> ValueRef {
- let fcx = new_fn_ctxt(cx, llfn);
- llvm::LLVMSetLinkage(llfn,
- lib::llvm::LLVMInternalLinkage as llvm::Linkage);
- cx.ccx.stats.n_glues_created += 1u;
+ let fcx = new_fn_ctxt(ccx, [], llfn, none);
+ lib::llvm::SetLinkage(llfn, lib::llvm::InternalLinkage);
+ ccx.stats.n_glues_created += 1u;
// Any nontrivial glue is with values passed *by alias*; this is a
// requirement since in many contexts glue is invoked indirectly and
// the caller has no idea if it's dealing with something that can be
// passed by value.
- let ccx = cx.ccx;
- let llty =
- if check type_has_static_size(ccx, t) {
- T_ptr(type_of(ccx, t))
- } else { T_ptr(T_i8()) };
+ let llty = if check type_has_static_size(ccx, t) {
+ T_ptr(type_of(ccx, t))
+ } else { T_ptr(T_i8()) };
- let ty_param_count = vec::len::<uint>(ty_params);
+ let ty_param_count = vec::len(ty_params);
let lltyparams = llvm::LLVMGetParam(llfn, 2u as c_uint);
let load_env_bcx = new_raw_block_ctxt(fcx, fcx.llloadenv);
let lltydescs = [mutable];
fcx.lltyparams = vec::map_mut(lltydescs, {|d| {desc: d, dicts: none}});
- let bcx = new_top_block_ctxt(fcx);
+ let bcx = new_top_block_ctxt(fcx, none);
let lltop = bcx.llbb;
let llrawptr0 = llvm::LLVMGetParam(llfn, 3u as c_uint);
let llval0 = BitCast(bcx, llrawptr0, llty);
ret llfn;
}
-fn make_generic_glue(cx: @local_ctxt, t: ty::t, llfn: ValueRef,
- helper: glue_helper, ty_params: [uint], name: str) ->
- ValueRef {
- if !cx.ccx.sess.opts.stats {
- ret make_generic_glue_inner(cx, t, llfn, helper, ty_params);
+fn make_generic_glue(ccx: @crate_ctxt, t: ty::t, llfn: ValueRef,
+ helper: glue_helper, ty_params: [uint], name: str)
+ -> ValueRef {
+ if !ccx.sess.opts.stats {
+ ret make_generic_glue_inner(ccx, t, llfn, helper, ty_params);
}
let start = time::get_time();
- let llval = make_generic_glue_inner(cx, t, llfn, helper, ty_params);
+ let llval = make_generic_glue_inner(ccx, t, llfn, helper, ty_params);
let end = time::get_time();
- log_fn_time(cx.ccx, "glue " + name + " " + ty_to_short_str(cx.ccx.tcx, t),
+ log_fn_time(ccx, "glue " + name + " " + ty_to_short_str(ccx.tcx, t),
start, end);
ret llval;
}
let gvar = ti.tydesc;
llvm::LLVMSetInitializer(gvar, tydesc);
llvm::LLVMSetGlobalConstant(gvar, True);
- llvm::LLVMSetLinkage(gvar,
- lib::llvm::LLVMInternalLinkage as llvm::Linkage);
+ lib::llvm::SetLinkage(gvar, lib::llvm::InternalLinkage);
};
}
fn incr_refcnt_of_boxed(cx: @block_ctxt, box_ptr: ValueRef) -> @block_ctxt {
let ccx = bcx_ccx(cx);
- let rc_ptr =
- GEPi(cx, box_ptr, [0, abi::box_rc_field_refcnt]);
+ maybe_validate_box(cx, box_ptr);
+ let rc_ptr = GEPi(cx, box_ptr, [0, abi::box_field_refcnt]);
let rc = Load(cx, rc_ptr);
rc = Add(cx, rc, C_int(ccx, 1));
Store(cx, rc, rc_ptr);
ret alt ty::struct(bcx_tcx(bcx), t) {
ty::ty_box(body_mt) {
let v = PointerCast(bcx, v, type_of_1(bcx, t));
- let body = GEPi(bcx, v, [0, abi::box_rc_field_body]);
+ let body = GEPi(bcx, v, [0, abi::box_field_body]);
let bcx = drop_ty(bcx, body, body_mt.ty);
- trans_free_if_not_gc(bcx, v)
+ trans_free(bcx, v)
}
_ { fail "free_box invoked with non-box type"; }
let ccx = bcx_ccx(bcx);
let llbox_ty = T_opaque_iface_ptr(ccx);
let b = PointerCast(bcx, v, llbox_ty);
- let body = GEPi(bcx, b, [0, abi::box_rc_field_body]);
+ let body = GEPi(bcx, b, [0, abi::box_field_body]);
let tydescptr = GEPi(bcx, body, [0, 0]);
let tydesc = Load(bcx, tydescptr);
let ti = none;
call_tydesc_glue_full(bcx, body, tydesc,
abi::tydesc_field_drop_glue, ti);
- trans_free_if_not_gc(bcx, b)
+ trans_free(bcx, b)
}
ty::ty_send_type {
// sendable type descriptors are basically unique pointers,
let dtor_addr = common::get_res_dtor(ccx, did, inner_t);
let args = [cx.fcx.llretptr, null_env_ptr(cx)];
for tp: ty::t in tps {
- let ti: option::t<@tydesc_info> = none;
+ let ti: option<@tydesc_info> = none;
let td = get_tydesc(cx, tp, false, ti).result;
args += [td.val];
cx = td.bcx;
ret next_cx;
}
+fn maybe_validate_box(_cx: @block_ctxt, _box_ptr: ValueRef) {
+ // Uncomment this when debugging annoying use-after-free
+ // bugs. But do not commit with this uncommented! Big performance hit.
+
+ // let cx = _cx, box_ptr = _box_ptr;
+ // let ccx = bcx_ccx(cx);
+ // warn_not_to_commit(ccx, "validate_box() is uncommented");
+ // let raw_box_ptr = PointerCast(cx, box_ptr, T_ptr(T_i8()));
+ // Call(cx, ccx.upcalls.validate_box, [raw_box_ptr]);
+}
+
fn decr_refcnt_maybe_free(cx: @block_ctxt, box_ptr: ValueRef, t: ty::t)
-> @block_ctxt {
let ccx = bcx_ccx(cx);
+
+ maybe_validate_box(cx, box_ptr);
+
let rc_adj_cx = new_sub_block_ctxt(cx, "rc--");
let free_cx = new_sub_block_ctxt(cx, "free");
let next_cx = new_sub_block_ctxt(cx, "next");
let box_ptr = PointerCast(cx, box_ptr, llbox_ty);
let null_test = IsNull(cx, box_ptr);
CondBr(cx, null_test, next_cx.llbb, rc_adj_cx.llbb);
- let rc_ptr =
- GEPi(rc_adj_cx, box_ptr, [0, abi::box_rc_field_refcnt]);
+ let rc_ptr = GEPi(rc_adj_cx, box_ptr, [0, abi::box_field_refcnt]);
let rc = Load(rc_adj_cx, rc_ptr);
rc = Sub(rc_adj_cx, rc, C_int(ccx, 1));
Store(rc_adj_cx, rc, rc_ptr);
- let zero_test = ICmp(rc_adj_cx, lib::llvm::LLVMIntEQ, C_int(ccx, 0), rc);
+ let zero_test = ICmp(rc_adj_cx, lib::llvm::IntEQ, C_int(ccx, 0), rc);
CondBr(rc_adj_cx, zero_test, free_cx.llbb, next_cx.llbb);
let free_cx = free_ty(free_cx, box_ptr, t);
Br(free_cx, next_cx.llbb);
ret next_cx;
}
-
// Structural comparison: a rather involved form of glue.
fn maybe_name_value(cx: @crate_ctxt, v: ValueRef, s: str) {
if cx.sess.opts.save_temps {
"attempt to compare values of type type"),
C_nil());
}
- ty::ty_native(_) {
- let cx = trans_fail(cx, none,
- "attempt to compare values of type native");
- ret rslt(cx, C_nil());
- }
_ {
// Should never get here, because t is scalar.
bcx_ccx(cx).sess.bug("non-scalar type passed to \
// A helper function to do the actual comparison of scalar values.
fn compare_scalar_values(cx: @block_ctxt, lhs: ValueRef, rhs: ValueRef,
nt: scalar_type, op: ast::binop) -> ValueRef {
+ fn die_(cx: @block_ctxt) -> ! {
+ bcx_tcx(cx).sess.bug("compare_scalar_values: must be a\
+ comparison operator");
+ }
+ let die = bind die_(cx);
alt nt {
nil_type {
// We don't need to do actual comparisons for nil.
alt op {
ast::eq | ast::le | ast::ge { ret C_bool(true); }
ast::ne | ast::lt | ast::gt { ret C_bool(false); }
+ // refinements would be nice
+ _ { die(); }
}
}
floating_point {
let cmp = alt op {
- ast::eq { lib::llvm::LLVMRealOEQ }
- ast::ne { lib::llvm::LLVMRealUNE }
- ast::lt { lib::llvm::LLVMRealOLT }
- ast::le { lib::llvm::LLVMRealOLE }
- ast::gt { lib::llvm::LLVMRealOGT }
- ast::ge { lib::llvm::LLVMRealOGE }
+ ast::eq { lib::llvm::RealOEQ }
+ ast::ne { lib::llvm::RealUNE }
+ ast::lt { lib::llvm::RealOLT }
+ ast::le { lib::llvm::RealOLE }
+ ast::gt { lib::llvm::RealOGT }
+ ast::ge { lib::llvm::RealOGE }
+ _ { die(); }
};
ret FCmp(cx, cmp, lhs, rhs);
}
signed_int {
let cmp = alt op {
- ast::eq { lib::llvm::LLVMIntEQ }
- ast::ne { lib::llvm::LLVMIntNE }
- ast::lt { lib::llvm::LLVMIntSLT }
- ast::le { lib::llvm::LLVMIntSLE }
- ast::gt { lib::llvm::LLVMIntSGT }
- ast::ge { lib::llvm::LLVMIntSGE }
+ ast::eq { lib::llvm::IntEQ }
+ ast::ne { lib::llvm::IntNE }
+ ast::lt { lib::llvm::IntSLT }
+ ast::le { lib::llvm::IntSLE }
+ ast::gt { lib::llvm::IntSGT }
+ ast::ge { lib::llvm::IntSGE }
+ _ { die(); }
};
ret ICmp(cx, cmp, lhs, rhs);
}
unsigned_int {
let cmp = alt op {
- ast::eq { lib::llvm::LLVMIntEQ }
- ast::ne { lib::llvm::LLVMIntNE }
- ast::lt { lib::llvm::LLVMIntULT }
- ast::le { lib::llvm::LLVMIntULE }
- ast::gt { lib::llvm::LLVMIntUGT }
- ast::ge { lib::llvm::LLVMIntUGE }
+ ast::eq { lib::llvm::IntEQ }
+ ast::ne { lib::llvm::IntNE }
+ ast::lt { lib::llvm::IntULT }
+ ast::le { lib::llvm::IntULE }
+ ast::gt { lib::llvm::IntUGT }
+ ast::ge { lib::llvm::IntUGE }
+ _ { die(); }
};
ret ICmp(cx, cmp, lhs, rhs);
}
j += 1u;
}
}
+ // Precondition?
+ _ { bcx_tcx(cx).sess.bug("iter_variant: not a function type"); }
}
ret cx;
}
}
fn lazily_emit_all_tydesc_glue(cx: @block_ctxt,
- static_ti: option::t<@tydesc_info>) {
+ static_ti: option<@tydesc_info>) {
lazily_emit_tydesc_glue(cx, abi::tydesc_field_take_glue, static_ti);
lazily_emit_tydesc_glue(cx, abi::tydesc_field_drop_glue, static_ti);
lazily_emit_tydesc_glue(cx, abi::tydesc_field_free_glue, static_ti);
fn lazily_emit_all_generic_info_tydesc_glues(cx: @block_ctxt,
gi: generic_info) {
- for ti: option::t<@tydesc_info> in gi.static_tis {
+ for ti: option<@tydesc_info> in gi.static_tis {
lazily_emit_all_tydesc_glue(cx, ti);
}
}
fn lazily_emit_tydesc_glue(cx: @block_ctxt, field: int,
- static_ti: option::t<@tydesc_info>) {
+ static_ti: option<@tydesc_info>) {
+ let ccx = cx.fcx.ccx;
alt static_ti {
none { }
some(ti) {
none {
#debug("+++ lazily_emit_tydesc_glue TAKE %s",
ty_to_str(bcx_tcx(cx), ti.ty));
- let lcx = cx.fcx.lcx;
- let glue_fn =
- declare_generic_glue(lcx, ti.ty, T_glue_fn(lcx.ccx),
- "take");
- ti.take_glue = some::<ValueRef>(glue_fn);
- make_generic_glue(lcx, ti.ty, glue_fn,
+ let glue_fn = declare_generic_glue
+ (ccx, ti.ty, T_glue_fn(ccx), "take");
+ ti.take_glue = some(glue_fn);
+ make_generic_glue(ccx, ti.ty, glue_fn,
make_take_glue,
ti.ty_params, "take");
#debug("--- lazily_emit_tydesc_glue TAKE %s",
none {
#debug("+++ lazily_emit_tydesc_glue DROP %s",
ty_to_str(bcx_tcx(cx), ti.ty));
- let lcx = cx.fcx.lcx;
let glue_fn =
- declare_generic_glue(lcx, ti.ty, T_glue_fn(lcx.ccx),
- "drop");
- ti.drop_glue = some::<ValueRef>(glue_fn);
- make_generic_glue(lcx, ti.ty, glue_fn,
+ declare_generic_glue(ccx, ti.ty, T_glue_fn(ccx), "drop");
+ ti.drop_glue = some(glue_fn);
+ make_generic_glue(ccx, ti.ty, glue_fn,
make_drop_glue,
ti.ty_params, "drop");
#debug("--- lazily_emit_tydesc_glue DROP %s",
none {
#debug("+++ lazily_emit_tydesc_glue FREE %s",
ty_to_str(bcx_tcx(cx), ti.ty));
- let lcx = cx.fcx.lcx;
let glue_fn =
- declare_generic_glue(lcx, ti.ty, T_glue_fn(lcx.ccx),
- "free");
- ti.free_glue = some::<ValueRef>(glue_fn);
- make_generic_glue(lcx, ti.ty, glue_fn,
+ declare_generic_glue(ccx, ti.ty, T_glue_fn(ccx), "free");
+ ti.free_glue = some(glue_fn);
+ make_generic_glue(ccx, ti.ty, glue_fn,
make_free_glue,
ti.ty_params, "free");
#debug("--- lazily_emit_tydesc_glue FREE %s",
}
fn call_tydesc_glue_full(cx: @block_ctxt, v: ValueRef, tydesc: ValueRef,
- field: int, static_ti: option::t<@tydesc_info>) {
+ field: int, static_ti: option<@tydesc_info>) {
lazily_emit_tydesc_glue(cx, field, static_ti);
let static_glue_fn = none;
fn call_tydesc_glue(cx: @block_ctxt, v: ValueRef, t: ty::t, field: int) ->
@block_ctxt {
- let ti: option::t<@tydesc_info> = none::<@tydesc_info>;
+ let ti: option<@tydesc_info> = none::<@tydesc_info>;
let {bcx: bcx, val: td} = get_tydesc(cx, t, false, ti).result;
call_tydesc_glue_full(bcx, v, td, field, ti);
ret bcx;
alt ty::struct(bcx_tcx(bcx), t) {
ty::ty_uniq(_) | ty::ty_vec(_) | ty::ty_str { free_ty(bcx, v, t) }
ty::ty_box(_) | ty::ty_iface(_, _) { decr_refcnt_maybe_free(bcx, v, t) }
+ // Precondition?
+ _ { bcx_tcx(bcx).sess.bug("drop_ty_immediate: non-box ty"); }
}
}
let next_cx = new_sub_block_ctxt(cx, "next");
let dstcmp = load_if_immediate(cx, dst, t);
let self_assigning =
- ICmp(cx, lib::llvm::LLVMIntNE,
+ ICmp(cx, lib::llvm::IntNE,
PointerCast(cx, dstcmp, val_ty(src)), src);
CondBr(cx, self_assigning, do_copy_cx.llbb, next_cx.llbb);
do_copy_cx = copy_val_no_check(do_copy_cx, action, dst, src, t);
fn copy_val_no_check(bcx: @block_ctxt, action: copy_action, dst: ValueRef,
src: ValueRef, t: ty::t) -> @block_ctxt {
let ccx = bcx_ccx(bcx), bcx = bcx;
- if ty::type_is_scalar(ccx.tcx, t) || ty::type_is_native(ccx.tcx, t) {
+ if ty::type_is_scalar(ccx.tcx, t) {
Store(bcx, src, dst);
ret bcx;
}
src: lval_result, t: ty::t) -> @block_ctxt {
let src_val = src.val;
let tcx = bcx_tcx(cx), cx = cx;
- if ty::type_is_scalar(tcx, t) || ty::type_is_native(tcx, t) {
+ if ty::type_is_scalar(tcx, t) {
if src.kind == owned { src_val = Load(cx, src_val); }
Store(cx, src_val, dst);
ret cx;
-> @block_ctxt {
// Lvals in memory are not temporaries. Copy them.
if src.kind != temporary && !last_use {
- let v = src.kind == owned ? load_if_immediate(cx, src.val, t)
- : src.val;
+ let v = if src.kind == owned {
+ load_if_immediate(cx, src.val, t)
+ } else {
+ src.val
+ };
ret copy_val(cx, action, dst, v, t);
}
ret move_val(cx, action, dst, src, t);
}
}
-
-// Converts an annotation to a type
-fn node_id_type(cx: @crate_ctxt, id: ast::node_id) -> ty::t {
- ret ty::node_id_to_monotype(cx.tcx, id);
-}
-
fn trans_unary(bcx: @block_ctxt, op: ast::unop, e: @ast::expr,
un_expr: @ast::expr, dest: dest) -> @block_ctxt {
// Check for user-defined method call
alt bcx_ccx(bcx).method_map.find(un_expr.id) {
some(origin) {
let callee_id = ast_util::op_expr_callee_id(un_expr);
- let fty = ty::node_id_to_monotype(bcx_tcx(bcx), callee_id);
+ let fty = ty::node_id_to_type(bcx_tcx(bcx), callee_id);
ret trans_call_inner(bcx, fty, {|bcx|
impl::trans_method_callee(bcx, callee_id, e, origin)
}, [], un_expr.id, dest);
}
if dest == ignore { ret trans_expr(bcx, e, ignore); }
- let e_ty = ty::expr_ty(bcx_tcx(bcx), e);
+ let e_ty = expr_ty(bcx, e);
alt op {
ast::not {
let {bcx, val} = trans_temp_expr(bcx, e);
ast::eq | ast::ne { llop = C_u8(abi::cmp_glue_op_eq); }
ast::lt | ast::ge { llop = C_u8(abi::cmp_glue_op_lt); }
ast::le | ast::gt { llop = C_u8(abi::cmp_glue_op_le); }
+ // Precondition?
+ _ { bcx_tcx(cx).sess.bug("trans_compare got\
+ non-comparison-op"); }
}
let rs = call_cmp_glue(cx, lhs, rhs, rhs_t, llop);
ast::ne | ast::ge | ast::gt {
ret rslt(rs.bcx, Not(rs.bcx, rs.val));
}
+ _ { bcx_tcx(cx).sess.bug("trans_compare got\
+ non-comparison-op"); }
}
}
fn trans_assign_op(bcx: @block_ctxt, ex: @ast::expr, op: ast::binop,
dst: @ast::expr, src: @ast::expr) -> @block_ctxt {
let tcx = bcx_tcx(bcx);
- let t = ty::expr_ty(tcx, src);
+ let t = expr_ty(bcx, src);
let lhs_res = trans_lval(bcx, dst);
assert (lhs_res.kind == owned);
alt bcx_ccx(bcx).method_map.find(ex.id) {
some(origin) {
let callee_id = ast_util::op_expr_callee_id(ex);
- let fty = ty::node_id_to_monotype(bcx_tcx(bcx), callee_id);
+ let fty = ty::node_id_to_type(tcx, callee_id);
ret trans_call_inner(bcx, fty, {|bcx|
// FIXME provide the already-computed address, not the expr
impl::trans_method_callee(bcx, callee_id, dst, origin)
while true {
alt ty::struct(ccx.tcx, t1) {
ty::ty_box(mt) {
- let body = GEPi(cx, v1, [0, abi::box_rc_field_body]);
+ let body = GEPi(cx, v1, [0, abi::box_field_body]);
t1 = mt.ty;
// Since we're changing levels of box indirection, we may have
ret {bcx: cx, val: v1, ty: t1};
}
-fn trans_lazy_binop(bcx: @block_ctxt, op: ast::binop, a: @ast::expr,
+// refinement types would obviate the need for this
+enum lazy_binop_ty { lazy_and, lazy_or }
+
+fn trans_lazy_binop(bcx: @block_ctxt, op: lazy_binop_ty, a: @ast::expr,
b: @ast::expr, dest: dest) -> @block_ctxt {
- let is_and = alt op { ast::and { true } ast::or { false } };
+ let is_and = alt op { lazy_and { true } lazy_or { false } };
let lhs_res = trans_temp_expr(bcx, a);
if lhs_res.bcx.unreachable { ret lhs_res.bcx; }
let rhs_cx = new_scope_block_ctxt(lhs_res.bcx, "rhs");
alt bcx_ccx(bcx).method_map.find(ex.id) {
some(origin) {
let callee_id = ast_util::op_expr_callee_id(ex);
- let fty = ty::node_id_to_monotype(bcx_tcx(bcx), callee_id);
+ let fty = ty::node_id_to_type(bcx_tcx(bcx), callee_id);
ret trans_call_inner(bcx, fty, {|bcx|
impl::trans_method_callee(bcx, callee_id, lhs, origin)
}, [rhs], ex.id, dest);
// First couple cases are lazy:
alt op {
- ast::and | ast::or {
- ret trans_lazy_binop(bcx, op, lhs, rhs, dest);
+ ast::and {
+ ret trans_lazy_binop(bcx, lazy_and, lhs, rhs, dest);
+ }
+ ast::or {
+ ret trans_lazy_binop(bcx, lazy_or, lhs, rhs, dest);
}
_ {
// Remaining cases are eager:
let lhs_res = trans_temp_expr(bcx, lhs);
let rhs_res = trans_temp_expr(lhs_res.bcx, rhs);
ret trans_eager_binop(rhs_res.bcx, op, lhs_res.val,
- ty::expr_ty(bcx_tcx(bcx), lhs), rhs_res.val,
- ty::expr_ty(bcx_tcx(bcx), rhs), dest);
+ expr_ty(bcx, lhs), rhs_res.val,
+ expr_ty(bcx, rhs), dest);
}
}
}
}
fn get_dest_addr(dest: dest) -> ValueRef {
- alt dest { save_in(a) { a } }
+ alt dest {
+ save_in(a) { a }
+ // Precondition?
+ _ { fail "get_dest_addr: not a save_in"; }
+ }
}
fn trans_if(cx: @block_ctxt, cond: @ast::expr, thn: ast::blk,
- els: option::t<@ast::expr>, dest: dest)
+ els: option<@ast::expr>, dest: dest)
-> @block_ctxt {
let {bcx, val: cond_val} = trans_temp_expr(cx, cond);
let then_dest = dup_for_join(dest);
let else_dest = dup_for_join(dest);
- let then_cx = new_scope_block_ctxt(bcx, "then");
- let else_cx = new_scope_block_ctxt(bcx, "else");
+ let then_cx = new_real_block_ctxt(bcx, "then", thn.span);
+ let else_cx = new_real_block_ctxt(bcx, "else", alt els {
+ some(e) { e.span }
+ _ { ast_util::dummy_sp() }
+ });
CondBr(bcx, cond_val, then_cx.llbb, else_cx.llbb);
then_cx = trans_block_dps(then_cx, thn, then_dest);
// Calling trans_block directly instead of trans_expr
ast::expr_block(blk) {
else_cx = trans_block_dps(else_cx, blk, else_dest);
}
+ // would be nice to have a constraint on ifs
+ _ { bcx_tcx(cx).sess.bug("Strange alternative\
+ in if"); }
}
}
_ {}
let next_cx = new_sub_block_ctxt(bcx, "next");
let scope_cx =
new_loop_scope_block_ctxt(bcx, option::some(next_cx),
- outer_next_cx, "for loop scope");
+ outer_next_cx, "for loop scope",
+ body.span);
Br(bcx, scope_cx.llbb);
let curr = PointerCast(bcx, curr, T_ptr(type_of_or_i8(bcx, t)));
let bcx = alt::bind_irrefutable_pat(scope_cx, local.node.pat,
}
let ccx = bcx_ccx(cx);
let next_cx = new_sub_block_ctxt(cx, "next");
- let seq_ty = ty::expr_ty(bcx_tcx(cx), seq);
+ let seq_ty = expr_ty(cx, seq);
let {bcx: bcx, val: seq} = trans_temp_expr(cx, seq);
let seq = PointerCast(bcx, seq, T_ptr(ccx.opaque_vec_type));
let fill = tvec::get_fill(bcx, seq);
let next_cx = new_sub_block_ctxt(cx, "while next");
let cond_cx =
new_loop_scope_block_ctxt(cx, option::none::<@block_ctxt>, next_cx,
- "while cond");
+ "while cond", body.span);
let body_cx = new_scope_block_ctxt(cond_cx, "while loop body");
let body_end = trans_block(body_cx, body);
let cond_res = trans_temp_expr(cond_cx, cond);
let next_cx = new_sub_block_ctxt(cx, "next");
let body_cx =
new_loop_scope_block_ctxt(cx, option::none::<@block_ctxt>, next_cx,
- "do-while loop body");
+ "do-while loop body", body.span);
let body_end = trans_block(body_cx, body);
let cond_cx = new_scope_block_ctxt(body_cx, "do-while cond");
Br(body_end, cond_cx.llbb);
type generic_info = {
item_type: ty::t,
- static_tis: [option::t<@tydesc_info>],
+ static_tis: [option<@tydesc_info>],
tydescs: [ValueRef],
param_bounds: @[ty::param_bounds],
- origins: option::t<typeck::dict_res>
+ origins: option<typeck::dict_res>
};
enum lval_kind {
val: ValueRef,
kind: lval_kind,
env: callee_env,
- generic: option::t<generic_info>};
+ generic: option<generic_info>};
fn null_env_ptr(bcx: @block_ctxt) -> ValueRef {
- C_null(T_opaque_cbox_ptr(bcx_ccx(bcx)))
+ C_null(T_opaque_box_ptr(bcx_ccx(bcx)))
}
fn lval_from_local_var(bcx: @block_ctxt, r: local_var_result) -> lval_result {
fn trans_external_path(cx: @block_ctxt, did: ast::def_id,
tpt: ty::ty_param_bounds_and_ty) -> ValueRef {
- let lcx = cx.fcx.lcx;
- let name = csearch::get_symbol(lcx.ccx.sess.cstore, did);
- ret get_extern_const(lcx.ccx.externs, lcx.ccx.llmod, name,
- type_of_ty_param_bounds_and_ty(lcx, tpt));
+ let ccx = cx.fcx.ccx;
+ let name = csearch::get_symbol(ccx.sess.cstore, did);
+ ret get_extern_const(ccx.externs, ccx.llmod, name,
+ type_of_ty_param_bounds_and_ty(ccx, tpt));
+}
+
+fn monomorphic_fn(ccx: @crate_ctxt, fn_id: ast::def_id, substs: [ty::t],
+ dicts: option<typeck::dict_res>) -> ValueRef {
+ let hash_id = @{def: fn_id, substs: substs, dicts: alt dicts {
+ some(os) { vec::map(*os, {|o| impl::dict_id(ccx.tcx, o)}) }
+ none { [] }
+ }};
+ alt ccx.monomorphized.find(hash_id) {
+ some(val) { ret val; }
+ none {}
+ }
+ let tpt = ty::lookup_item_type(ccx.tcx, fn_id);
+ let mono_ty = ty::substitute_type_params(ccx.tcx, substs, tpt.ty);
+ let (item, pt) = alt ccx.tcx.items.get(fn_id.node) {
+ ast_map::node_item(i, p) { (i, p) } _ { fail; }
+ };
+ let pt = *pt + [path_name(item.ident)];
+ let result = alt item.node {
+ ast::item_fn(decl, _, body) {
+ let llfty = type_of_fn_from_ty(ccx, mono_ty, []);
+ let s = mangle_exported_name(ccx, pt, mono_ty);
+ let lldecl = decl_cdecl_fn(ccx.llmod, s, llfty);
+ trans_fn(ccx, pt, decl, body, lldecl, no_self, [],
+ some(substs), fn_id.node);
+ lldecl
+ }
+ _ { fail "FIXME[mono] handle other constructs"; }
+ };
+ ccx.monomorphized.insert(hash_id, result);
+ result
}
fn lval_static_fn(bcx: @block_ctxt, fn_id: ast::def_id, id: ast::node_id)
-> lval_maybe_callee {
let ccx = bcx_ccx(bcx);
+ let tys = ty::node_id_to_type_params(ccx.tcx, id);
let tpt = ty::lookup_item_type(ccx.tcx, fn_id);
+ if ccx.sess.opts.monomorphize && vec::len(tys) > 0u &&
+ fn_id.crate == ast::local_crate &&
+ !vec::any(tys, {|t| ty::type_contains_params(ccx.tcx, t)}) &&
+ vec::all(*tpt.bounds, {|bs| vec::all(*bs, {|b|
+ alt b { ty::bound_iface(_) { false } _ { true } }
+ })}) {
+ let dicts = ccx.dict_map.find(id);
+ ret {bcx: bcx, val: monomorphic_fn(ccx, fn_id, tys, dicts),
+ kind: owned, env: null_env, generic: none};
+ }
let val = if fn_id.crate == ast::local_crate {
// Internal reference.
assert (ccx.item_ids.contains_key(fn_id.node));
// External reference.
trans_external_path(bcx, fn_id, tpt)
};
- let tys = ty::node_id_to_type_params(ccx.tcx, id);
let gen = none, bcx = bcx;
- if vec::len(tys) != 0u {
+ if vec::len(tys) > 0u {
let tydescs = [], tis = [];
for t in tys {
// TODO: Doesn't always escape.
ret {bcx: bcx, val: val, kind: owned, env: null_env, generic: gen};
}
-fn lookup_discriminant(lcx: @local_ctxt, vid: ast::def_id) -> ValueRef {
- let ccx = lcx.ccx;
+fn lookup_discriminant(ccx: @crate_ctxt, vid: ast::def_id) -> ValueRef {
alt ccx.discrims.find(vid) {
none {
// It's an external discriminant that we haven't seen yet.
assert (vid.crate != ast::local_crate);
- let sym = csearch::get_symbol(lcx.ccx.sess.cstore, vid);
- let gvar =
- str::as_buf(sym,
- {|buf|
- llvm::LLVMAddGlobal(ccx.llmod, ccx.int_type, buf)
- });
- llvm::LLVMSetLinkage(gvar,
- lib::llvm::LLVMExternalLinkage as llvm::Linkage);
+ let sym = csearch::get_symbol(ccx.sess.cstore, vid);
+ let gvar = str::as_buf(sym, {|buf|
+ llvm::LLVMAddGlobal(ccx.llmod, ccx.int_type, buf)
+ });
+ lib::llvm::SetLinkage(gvar, lib::llvm::ExternalLinkage);
llvm::LLVMSetGlobalConstant(gvar, True);
- lcx.ccx.discrims.insert(vid, gvar);
+ ccx.discrims.insert(vid, gvar);
ret gvar;
}
some(llval) { ret llval; }
ret lval_static_fn(cx, vid, id);
} else {
// Nullary variant.
- let enum_ty = node_id_type(ccx, id);
+ let enum_ty = ty::node_id_to_type(ccx.tcx, id);
let alloc_result = alloc_ty(cx, enum_ty);
let llenumblob = alloc_result.val;
let llenumty = type_of_enum(ccx, tid, enum_ty);
let bcx = alloc_result.bcx;
let llenumptr = PointerCast(bcx, llenumblob, T_ptr(llenumty));
let lldiscrimptr = GEPi(bcx, llenumptr, [0, 0]);
- let lldiscrim_gv = lookup_discriminant(bcx.fcx.lcx, vid);
+ let lldiscrim_gv = lookup_discriminant(bcx.fcx.ccx, vid);
let lldiscrim = Load(bcx, lldiscrim_gv);
Store(bcx, lldiscrim, lldiscrimptr);
ret lval_no_env(bcx, llenumptr, temporary);
assert (ccx.consts.contains_key(did.node));
ret lval_no_env(cx, ccx.consts.get(did.node), owned);
} else {
- let tp = ty::node_id_to_monotype(ccx.tcx, id);
+ let tp = ty::node_id_to_type(ccx.tcx, id);
let val = trans_external_path(cx, did, {bounds: @[], ty: tp});
ret lval_no_env(cx, load_if_immediate(cx, val, tp), owned_imm);
}
fn trans_rec_field(bcx: @block_ctxt, base: @ast::expr,
field: ast::ident) -> lval_result {
let {bcx, val} = trans_temp_expr(bcx, base);
- let {bcx, val, ty} = autoderef(bcx, val, ty::expr_ty(bcx_tcx(bcx), base));
- let fields = alt ty::struct(bcx_tcx(bcx), ty) { ty::ty_rec(fs) { fs } };
+ let {bcx, val, ty} = autoderef(bcx, val, expr_ty(bcx, base));
+ let fields = alt ty::struct(bcx_tcx(bcx), ty) {
+ ty::ty_rec(fs) { fs }
+ // Constraint?
+ _ { bcx_tcx(bcx).sess.span_bug(base.span, "trans_rec_field:\
+ base expr has non-record type"); }
+ };
let ix = option::get(ty::field_idx(field, fields));
// Silly check
check type_is_tup_like(bcx, ty);
fn trans_index(cx: @block_ctxt, ex: @ast::expr, base: @ast::expr,
idx: @ast::expr) -> lval_result {
- let base_ty = ty::expr_ty(bcx_tcx(cx), base);
+ let base_ty = expr_ty(cx, base);
let exp = trans_temp_expr(cx, base);
let lv = autoderef(exp.bcx, exp.val, base_ty);
let ix = trans_temp_expr(lv.bcx, idx);
ix_val = Trunc(bcx, ix.val, ccx.int_type);
} else { ix_val = ix.val; }
- let unit_ty = node_id_type(bcx_ccx(cx), ex.id);
+ let unit_ty = node_id_type(cx, ex.id);
let unit_sz = size_of(bcx, unit_ty);
bcx = unit_sz.bcx;
maybe_name_value(bcx_ccx(cx), unit_sz.val, "unit_sz");
maybe_name_value(bcx_ccx(cx), scaled_ix, "scaled_ix");
let lim = tvec::get_fill(bcx, v);
let body = tvec::get_dataptr(bcx, v, type_of_or_i8(bcx, unit_ty));
- let bounds_check = ICmp(bcx, lib::llvm::LLVMIntULT, scaled_ix, lim);
+ let bounds_check = ICmp(bcx, lib::llvm::IntULT, scaled_ix, lim);
let fail_cx = new_sub_block_ctxt(bcx, "fail");
let next_cx = new_sub_block_ctxt(bcx, "next");
let ncx = bcx_ccx(next_cx);
some(origin) { // An impl method
ret impl::trans_method_callee(bcx, e.id, base, origin);
}
+ // Precondition?
+ _ { bcx_tcx(bcx).sess.span_bug(e.span, "trans_callee: weird\
+ expr"); }
}
}
}
alt e.node {
ast::expr_path(_) {
let v = trans_path(cx, e.id);
- ret lval_maybe_callee_to_lval(v, ty::expr_ty(bcx_tcx(cx), e));
+ ret lval_maybe_callee_to_lval(v, expr_ty(cx, e));
}
ast::expr_field(base, ident, _) {
ret trans_rec_field(cx, base, ident);
ast::expr_unary(ast::deref, base) {
let ccx = bcx_ccx(cx);
let sub = trans_temp_expr(cx, base);
- let t = ty::expr_ty(ccx.tcx, base);
+ let t = expr_ty(cx, base);
let val =
alt ty::struct(ccx.tcx, t) {
ty::ty_box(_) {
- GEPi(sub.bcx, sub.val, [0, abi::box_rc_field_body])
+ GEPi(sub.bcx, sub.val, [0, abi::box_field_body])
}
ty::ty_res(_, _, _) {
GEPi(sub.bcx, sub.val, [0, 1])
}
ty::ty_enum(_, _) {
- let ety = ty::expr_ty(ccx.tcx, e);
+ let ety = expr_ty(cx, e);
let ellty =
if check type_has_static_size(ccx, ety) {
T_ptr(type_of(ccx, ety))
PointerCast(sub.bcx, sub.val, ellty)
}
ty::ty_ptr(_) | ty::ty_uniq(_) { sub.val }
+ // Precondition?
+ _ {
+ bcx_tcx(cx).sess.span_bug(e.span, "trans_lval:\
+ Weird argument in deref");
+ }
};
ret lval_owned(sub.bcx, val);
}
- // This is a by-ref returning call. Regular calls are not lval
- ast::expr_call(f, args, _) {
- let cell = empty_dest_cell();
- let bcx = trans_call(cx, f, args, e.id, by_val(cell));
- ret lval_owned(bcx, *cell);
- }
_ { bcx_ccx(cx).sess.span_bug(e.span, "non-lval in trans_lval"); }
}
}
fn trans_cast(cx: @block_ctxt, e: @ast::expr, id: ast::node_id,
dest: dest) -> @block_ctxt {
let ccx = bcx_ccx(cx);
- let t_out = node_id_type(ccx, id);
- alt ty::struct(ccx.tcx, t_out) {
+ let t_out = node_id_type(cx, id);
+ alt ty::struct(bcx_tcx(cx), t_out) {
ty::ty_iface(_, _) { ret impl::trans_cast(cx, e, id, dest); }
_ {}
}
let e_res = trans_temp_expr(cx, e);
let ll_t_in = val_ty(e_res.val);
- let t_in = ty::expr_ty(ccx.tcx, e);
+ let t_in = expr_ty(cx, e);
// Check should be avoidable because it's a cast.
// FIXME: Constrain types so as to avoid this check.
check (type_has_static_size(ccx, t_out));
fn t_kind(tcx: ty::ctxt, t: ty::t) -> kind {
ret if ty::type_is_fp(tcx, t) {
float
- } else if ty::type_is_native(tcx, t) ||
- ty::type_is_unsafe_ptr(tcx, t) {
+ } else if ty::type_is_unsafe_ptr(tcx, t) {
pointer
} else if ty::type_is_integral(tcx, t) {
integral
integral {int_cast(e_res.bcx, ll_t_out,
val_ty(lldiscrim_a), lldiscrim_a, true)}
float {SIToFP(e_res.bcx, lldiscrim_a, ll_t_out)}
+ _ { ccx.sess.bug("Translating unsupported cast.") }
}
}
_ { ccx.sess.bug("Translating unsupported cast.") }
&to_revoke: [{v: ValueRef, t: ty::t}], e: @ast::expr) ->
result {
let ccx = bcx_ccx(cx);
- let e_ty = ty::expr_ty(ccx.tcx, e);
+ let e_ty = expr_ty(cx, e);
let is_bot = ty::type_is_bot(ccx.tcx, e_ty);
let lv = trans_temp_lval(cx, e);
let bcx = lv.bcx;
let val = lv.val;
+ let arg_mode = ty::resolved_mode(ccx.tcx, arg.mode);
if is_bot {
// For values of type _|_, we generate an
// "undef" value, as such a value should never
// be inspected. It's important for the value
// to have type lldestty (the callee's expected type).
val = llvm::LLVMGetUndef(lldestty);
- } else if arg.mode == ast::by_ref || arg.mode == ast::by_val {
+ } else if arg_mode == ast::by_ref || arg_mode == ast::by_val {
let copied = false, imm = ty::type_is_immediate(ccx.tcx, e_ty);
- if arg.mode == ast::by_ref && lv.kind != owned && imm {
+ if arg_mode == ast::by_ref && lv.kind != owned && imm {
val = do_spill_noroot(bcx, val);
copied = true;
}
} else { bcx = take_ty(bcx, val, e_ty); }
add_clean(bcx, val, e_ty);
}
- if arg.mode == ast::by_val && (lv.kind == owned || !imm) {
+ if arg_mode == ast::by_val && (lv.kind == owned || !imm) {
val = Load(bcx, val);
}
- } else if arg.mode == ast::by_copy {
+ } else if arg_mode == ast::by_copy {
let {bcx: cx, val: alloc} = alloc_ty(bcx, e_ty);
let last_use = ccx.last_uses.contains_key(e.id);
bcx = cx;
}
// Collect arg for later if it happens to be one we've moving out.
- if arg.mode == ast::by_move {
+ if arg_mode == ast::by_move {
if lv.kind == owned {
// Use actual ty, not declared ty -- anything else doesn't make
// sense if declared ty is a ty param
// - new_fn_ctxt
// - trans_args
fn trans_args(cx: @block_ctxt, llenv: ValueRef,
- gen: option::t<generic_info>, es: [@ast::expr], fn_ty: ty::t,
+ gen: option<generic_info>, es: [@ast::expr], fn_ty: ty::t,
dest: dest)
-> {bcx: @block_ctxt,
args: [ValueRef],
fn trans_call(in_cx: @block_ctxt, f: @ast::expr,
args: [@ast::expr], id: ast::node_id, dest: dest)
-> @block_ctxt {
- trans_call_inner(in_cx, ty::expr_ty(bcx_tcx(in_cx), f),
+ trans_call_inner(in_cx, expr_ty(in_cx, f),
{|cx| trans_callee(cx, f)}, args, id, dest)
}
let llenv, dict_param = none;
alt f_res.env {
null_env {
- llenv = llvm::LLVMGetUndef(T_opaque_cbox_ptr(bcx_ccx(cx)));
+ llenv = llvm::LLVMGetUndef(T_opaque_box_ptr(bcx_ccx(cx)));
}
self_env(e) { llenv = e; }
dict_env(dict, e) { llenv = e; dict_param = some(dict); }
fn trans_tup(bcx: @block_ctxt, elts: [@ast::expr], id: ast::node_id,
dest: dest) -> @block_ctxt {
- let t = node_id_type(bcx.fcx.lcx.ccx, id);
+ let t = node_id_type(bcx, id);
let bcx = bcx;
let addr = alt dest {
ignore {
ret bcx;
}
save_in(pos) { pos }
+ _ { bcx_tcx(bcx).sess.bug("trans_tup: weird dest"); }
};
let temp_cleanups = [], i = 0;
for e in elts {
let dst = GEP_tup_like_1(bcx, t, addr, [0, i]);
- let e_ty = ty::expr_ty(bcx_tcx(bcx), e);
+ let e_ty = expr_ty(bcx, e);
bcx = trans_expr_save_in(dst.bcx, e, dst.val);
add_clean_temp_mem(bcx, dst.val, e_ty);
temp_cleanups += [dst.val];
}
fn trans_rec(bcx: @block_ctxt, fields: [ast::field],
- base: option::t<@ast::expr>, id: ast::node_id,
+ base: option<@ast::expr>, id: ast::node_id,
dest: dest) -> @block_ctxt {
- let t = node_id_type(bcx_ccx(bcx), id);
+ let t = node_id_type(bcx, id);
let bcx = bcx;
let addr = alt dest {
ignore {
ret bcx;
}
save_in(pos) { pos }
+ _ { bcx_tcx(bcx).sess.bug("trans_rec: weird dest"); }
};
- let ty_fields = alt ty::struct(bcx_tcx(bcx), t) { ty::ty_rec(f) { f } };
+ let ty_fields = alt ty::struct(bcx_tcx(bcx), t) { ty::ty_rec(f) { f }
+ _ { bcx_tcx(bcx).sess.bug("trans_rec: id doesn't\
+ have a record type") } };
let temp_cleanups = [];
for fld in fields {
let ix = option::get(vec::position(ty_fields, {|ft|
// that nil or bot expressions get ignore rather than save_in as destination.
fn trans_expr_save_in(bcx: @block_ctxt, e: @ast::expr, dest: ValueRef)
-> @block_ctxt {
- let tcx = bcx_tcx(bcx), t = ty::expr_ty(tcx, e);
+ let tcx = bcx_tcx(bcx), t = expr_ty(bcx, e);
let do_ignore = ty::type_is_bot(tcx, t) || ty::type_is_nil(tcx, t);
- ret trans_expr(bcx, e, do_ignore ? ignore : save_in(dest));
+ ret trans_expr(bcx, e, if do_ignore { ignore } else { save_in(dest) });
}
// Call this to compile an expression that you need as an intermediate value,
ret trans_lval(bcx, e);
} else {
let tcx = bcx_tcx(bcx);
- let ty = ty::expr_ty(tcx, e);
+ let ty = expr_ty(bcx, e);
if ty::type_is_nil(tcx, ty) || ty::type_is_bot(tcx, ty) {
bcx = trans_expr(bcx, e, ignore);
ret {bcx: bcx, val: C_nil(), kind: temporary};
fn trans_temp_expr(bcx: @block_ctxt, e: @ast::expr) -> result {
let {bcx, val, kind} = trans_temp_lval(bcx, e);
if kind == owned {
- val = load_if_immediate(bcx, val, ty::expr_ty(bcx_tcx(bcx), e));
+ val = load_if_immediate(bcx, val, expr_ty(bcx, e));
}
ret {bcx: bcx, val: val};
}
let tcx = bcx_tcx(bcx);
debuginfo::update_source_pos(bcx, e.span);
+ #debug["trans_expr(%s,%?)", expr_to_str(e), dest];
+
if expr_is_lval(bcx, e) {
ret lval_to_dps(bcx, e, dest);
}
ast::expr_if(cond, thn, els) | ast::expr_if_check(cond, thn, els) {
ret trans_if(bcx, cond, thn, els, dest);
}
- ast::expr_ternary(_, _, _) {
- ret trans_expr(bcx, ast_util::ternary_to_if(e), dest);
- }
ast::expr_alt(expr, arms) {
// tcx.sess.span_note(e.span, "about to call trans_alt");
ret alt::trans_alt(bcx, expr, arms, dest);
}
ast::expr_block(blk) {
- let sub_cx = new_scope_block_ctxt(bcx, "block-expr body");
+ let sub_cx = new_real_block_ctxt(bcx, "block-expr body",
+ blk.span);
Br(bcx, sub_cx.llbb);
sub_cx = trans_block_dps(sub_cx, blk, dest);
let next_cx = new_sub_block_ctxt(bcx, "next");
bcx, proto, decl, body, e.span, e.id, *cap_clause, dest);
}
ast::expr_fn_block(decl, body) {
- alt ty::struct(tcx, ty::expr_ty(tcx, e)) {
+ alt ty::struct(tcx, expr_ty(bcx, e)) {
ty::ty_fn({proto, _}) {
#debug("translating fn_block %s with type %s",
- expr_to_str(e), ty_to_str(tcx, ty::expr_ty(tcx, e)));
+ expr_to_str(e), ty_to_str(tcx, expr_ty(bcx, e)));
let cap_clause = { copies: [], moves: [] };
ret closure::trans_expr_fn(
bcx, proto, decl, body, e.span, e.id, cap_clause, dest);
// If it is here, it's not an lval, so this is a user-defined index op
let origin = bcx_ccx(bcx).method_map.get(e.id);
let callee_id = ast_util::op_expr_callee_id(e);
- let fty = ty::node_id_to_monotype(tcx, callee_id);
+ let fty = ty::node_id_to_type(tcx, callee_id);
ret trans_call_inner(bcx, fty, {|bcx|
impl::trans_method_callee(bcx, callee_id, base, origin)
}, [idx], e.id, dest);
let {bcx, val: addr, kind} = trans_lval(src_r.bcx, dst);
assert kind == owned;
ret store_temp_expr(bcx, DROP_EXISTING, addr, src_r,
- ty::expr_ty(bcx_tcx(bcx), src),
+ expr_ty(bcx, src),
bcx_ccx(bcx).last_uses.contains_key(src.id));
}
ast::expr_move(dst, src) {
let {bcx, val: addr, kind} = trans_lval(src_r.bcx, dst);
assert kind == owned;
ret move_val(bcx, DROP_EXISTING, addr, src_r,
- ty::expr_ty(bcx_tcx(bcx), src));
+ expr_ty(bcx, src));
}
ast::expr_swap(dst, src) {
assert dest == ignore;
let lhs_res = trans_lval(bcx, dst);
assert lhs_res.kind == owned;
let rhs_res = trans_lval(lhs_res.bcx, src);
- let t = ty::expr_ty(tcx, src);
+ let t = expr_ty(bcx, src);
let {bcx: bcx, val: tmp_alloc} = alloc_ty(rhs_res.bcx, t);
// Swap through a temporary.
bcx = move_val(bcx, INIT, tmp_alloc, lhs_res, t);
assert dest == ignore;
ret trans_assign_op(bcx, e, op, dst, src);
}
+ _ { bcx_tcx(bcx).sess.span_bug(e.span, "trans_expr reached\
+ fall-through case"); }
+
}
}
let lv = trans_lval(bcx, e), ccx = bcx_ccx(bcx);
let {bcx, val, kind} = lv;
let last_use = kind == owned && ccx.last_uses.contains_key(e.id);
- let ty = ty::expr_ty(ccx.tcx, e);
+ let ty = expr_ty(bcx, e);
alt dest {
by_val(cell) {
if kind == temporary {
}
fn trans_log(lvl: @ast::expr, cx: @block_ctxt, e: @ast::expr) -> @block_ctxt {
- let ccx = bcx_ccx(cx);
- let lcx = cx.fcx.lcx;
- let tcx = ccx.tcx;
- let modname = str::connect(lcx.module_path, "::");
-
- if ty::type_is_bot(tcx, ty::expr_ty(tcx, lvl)) {
+ let ccx = bcx_ccx(cx), tcx = ccx.tcx;
+ if ty::type_is_bot(tcx, expr_ty(cx, lvl)) {
ret trans_expr(cx, lvl, ignore);
}
- let global = if lcx.ccx.module_data.contains_key(modname) {
- lcx.ccx.module_data.get(modname)
+ let modpath = [path_mod(ccx.link_meta.name)] +
+ vec::filter(cx.fcx.path, {|e|
+ alt e { path_mod(_) { true } _ { false } }
+ });
+ let modname = path_str(modpath);
+
+ let global = if ccx.module_data.contains_key(modname) {
+ ccx.module_data.get(modname)
} else {
let s = link::mangle_internal_name_by_path_and_seq(
- lcx.ccx, lcx.module_path, "loglevel");
+ ccx, modpath, "loglevel");
let global = str::as_buf(s, {|buf|
- llvm::LLVMAddGlobal(lcx.ccx.llmod, T_i32(), buf)
+ llvm::LLVMAddGlobal(ccx.llmod, T_i32(), buf)
});
llvm::LLVMSetGlobalConstant(global, False);
llvm::LLVMSetInitializer(global, C_null(T_i32()));
- llvm::LLVMSetLinkage(global,
- lib::llvm::LLVMInternalLinkage as llvm::Linkage);
- lcx.ccx.module_data.insert(modname, global);
+ lib::llvm::SetLinkage(global, lib::llvm::InternalLinkage);
+ ccx.module_data.insert(modname, global);
global
};
let level_cx = new_scope_block_ctxt(cx, "level");
Br(cx, level_cx.llbb);
let level_res = trans_temp_expr(level_cx, lvl);
- let test = ICmp(level_res.bcx, lib::llvm::LLVMIntUGE,
+ let test = ICmp(level_res.bcx, lib::llvm::IntUGE,
load, level_res.val);
CondBr(level_res.bcx, test, log_cx.llbb, after_cx.llbb);
let sub = trans_temp_expr(log_cx, e);
- let e_ty = ty::expr_ty(bcx_tcx(cx), e);
+ let e_ty = expr_ty(cx, e);
let log_bcx = sub.bcx;
let ti = none::<@tydesc_info>;
ret next_cx;
}
-fn trans_fail_expr(bcx: @block_ctxt, sp_opt: option::t<span>,
- fail_expr: option::t<@ast::expr>) -> @block_ctxt {
+fn trans_fail_expr(bcx: @block_ctxt, sp_opt: option<span>,
+ fail_expr: option<@ast::expr>) -> @block_ctxt {
let bcx = bcx;
alt fail_expr {
some(expr) {
let tcx = bcx_tcx(bcx);
let expr_res = trans_temp_expr(bcx, expr);
- let e_ty = ty::expr_ty(tcx, expr);
+ let e_ty = expr_ty(bcx, expr);
bcx = expr_res.bcx;
if ty::type_is_str(tcx, e_ty) {
}
}
-fn trans_fail(bcx: @block_ctxt, sp_opt: option::t<span>, fail_str: str) ->
+fn trans_fail(bcx: @block_ctxt, sp_opt: option<span>, fail_str: str) ->
@block_ctxt {
let V_fail_str = C_cstr(bcx_ccx(bcx), fail_str);
ret trans_fail_value(bcx, sp_opt, V_fail_str);
}
-fn trans_fail_value(bcx: @block_ctxt, sp_opt: option::t<span>,
+fn trans_fail_value(bcx: @block_ctxt, sp_opt: option<span>,
V_fail_str: ValueRef) -> @block_ctxt {
let ccx = bcx_ccx(bcx);
let V_filename;
some(sp) {
let sess = bcx_ccx(bcx).sess;
let loc = codemap::lookup_char_pos(sess.parse_sess.cm, sp.lo);
- V_filename = C_cstr(bcx_ccx(bcx), loc.filename);
+ V_filename = C_cstr(bcx_ccx(bcx), loc.file.name);
V_line = loc.line as int;
}
none { V_filename = C_cstr(bcx_ccx(bcx), "<runtime>"); V_line = 0; }
ret trans_break_cont(cx, false);
}
-fn trans_ret(bcx: @block_ctxt, e: option::t<@ast::expr>) -> @block_ctxt {
+fn trans_ret(bcx: @block_ctxt, e: option<@ast::expr>) -> @block_ctxt {
let cleanup_cx = bcx, bcx = bcx;
alt e {
some(x) { bcx = trans_expr_save_in(bcx, x, bcx.fcx.llretptr); }
}
fn init_local(bcx: @block_ctxt, local: @ast::local) -> @block_ctxt {
- let ty = node_id_type(bcx_ccx(bcx), local.node.id);
+ let ty = node_id_type(bcx, local.node.id);
let llptr = alt bcx.fcx.lllocals.find(local.node.id) {
some(local_mem(v)) { v }
+ some(_) { bcx_tcx(bcx).sess.span_bug(local.span,
+ "init_local: Someone forgot to document why it's\
+ safe to assume local.node.init must be local_mem!");
+ }
// This is a local that is kept immediate
none {
- let initexpr = alt local.node.init { some({expr, _}) { expr } };
+ let initexpr = alt local.node.init {
+ some({expr, _}) { expr }
+ none { bcx_tcx(bcx).sess.span_bug(local.span,
+ "init_local: Someone forgot to document why it's\
+ safe to assume local.node.init isn't none!"); }
+ };
let {bcx, val, kind} = trans_temp_lval(bcx, initexpr);
if kind != temporary {
if kind == owned { val = Load(bcx, val); }
alt kind {
owned_imm { val = do_spill_noroot(bcx, val); }
owned {}
+ _ { bcx_tcx(bcx).sess.span_bug(local.span,
+ "Someone forgot to document an invariant in init_ref_local!"); }
}
ret alt::bind_irrefutable_pat(bcx, local.node.pat, val, false);
}
}
fn trans_stmt(cx: @block_ctxt, s: ast::stmt) -> @block_ctxt {
+ #debug["trans_expr(%s)", stmt_to_str(s)];
+
if (!bcx_ccx(cx).sess.opts.no_asm_comments) {
add_span_comment(cx, s.span, stmt_to_str(s));
}
}
}
}
- ast::decl_item(i) { trans_item(cx.fcx.lcx, *i); }
+ ast::decl_item(i) { trans_item(cx.fcx.ccx, *i); }
}
}
_ { bcx_ccx(cx).sess.unimpl("stmt variant"); }
// You probably don't want to use this one. See the
// next three functions instead.
fn new_block_ctxt(cx: @fn_ctxt, parent: block_parent, kind: block_kind,
- name: str) -> @block_ctxt {
+ name: str, block_span: option<span>) -> @block_ctxt {
let s = "";
- if cx.lcx.ccx.sess.opts.save_temps ||
- cx.lcx.ccx.sess.opts.debuginfo {
- s = cx.lcx.ccx.names(name);
+ if cx.ccx.sess.opts.save_temps || cx.ccx.sess.opts.debuginfo {
+ s = cx.ccx.names(name);
}
let llbb: BasicBlockRef =
str::as_buf(s, {|buf| llvm::LLVMAppendBasicBlock(cx.llfn, buf) });
kind: kind,
mutable cleanups: [],
mutable lpad_dirty: true,
- mutable lpad: option::none,
+ mutable lpad: none,
+ block_span: block_span,
fcx: cx};
alt parent {
parent_some(cx) {
// Use this when you're at the top block of a function or the like.
-fn new_top_block_ctxt(fcx: @fn_ctxt) -> @block_ctxt {
- ret new_block_ctxt(fcx, parent_none, SCOPE_BLOCK, "function top level");
+fn new_top_block_ctxt(fcx: @fn_ctxt, sp: option<span>) -> @block_ctxt {
+ ret new_block_ctxt(fcx, parent_none, SCOPE_BLOCK, "function top level",
+ sp);
}
// Use this when you're at a curly-brace or similar lexical scope.
fn new_scope_block_ctxt(bcx: @block_ctxt, n: str) -> @block_ctxt {
- ret new_block_ctxt(bcx.fcx, parent_some(bcx), SCOPE_BLOCK, n);
+ ret new_block_ctxt(bcx.fcx, parent_some(bcx), SCOPE_BLOCK, n, none);
+}
+
+fn new_real_block_ctxt(bcx: @block_ctxt, n: str, sp: span) -> @block_ctxt {
+ ret new_block_ctxt(bcx.fcx, parent_some(bcx), SCOPE_BLOCK, n, some(sp));
}
-fn new_loop_scope_block_ctxt(bcx: @block_ctxt, _cont: option::t<@block_ctxt>,
- _break: @block_ctxt, n: str) -> @block_ctxt {
+fn new_loop_scope_block_ctxt(bcx: @block_ctxt, _cont: option<@block_ctxt>,
+ _break: @block_ctxt, n: str, sp: span)
+ -> @block_ctxt {
ret new_block_ctxt(bcx.fcx, parent_some(bcx),
- LOOP_SCOPE_BLOCK(_cont, _break), n);
+ LOOP_SCOPE_BLOCK(_cont, _break), n, some(sp));
}
// Use this when you're making a general CFG BB within a scope.
fn new_sub_block_ctxt(bcx: @block_ctxt, n: str) -> @block_ctxt {
- ret new_block_ctxt(bcx.fcx, parent_some(bcx), NON_SCOPE_BLOCK, n);
+ ret new_block_ctxt(bcx.fcx, parent_some(bcx), NON_SCOPE_BLOCK, n, none);
}
fn new_raw_block_ctxt(fcx: @fn_ctxt, llbb: BasicBlockRef) -> @block_ctxt {
kind: NON_SCOPE_BLOCK,
mutable cleanups: [],
mutable lpad_dirty: true,
- mutable lpad: option::none,
+ mutable lpad: none,
+ block_span: none,
fcx: fcx};
}
kind: SCOPE_BLOCK,
mutable cleanups: [],
mutable lpad_dirty: true,
- mutable lpad: option::none,
+ mutable lpad: none,
+ block_span: none,
fcx: fcx};
}
kind: SCOPE_BLOCK,
mutable cleanups: [],
mutable lpad_dirty: true,
- mutable lpad: option::none,
+ mutable lpad: none,
+ block_span: none,
fcx: fcx};
}
// past caller conventions and may well make sense again,
// so we leave it as-is.
- if bcx_tcx(cx).sess.opts.do_gc {
- bcx = gc::add_gc_root(bcx, val, t);
- }
-
ret rslt(cx, val);
}
fn alloc_local(cx: @block_ctxt, local: @ast::local) -> @block_ctxt {
- let t = node_id_type(bcx_ccx(cx), local.node.id);
+ let t = node_id_type(cx, local.node.id);
let p = normalize_pat(bcx_tcx(cx), local.node.pat);
let is_simple = alt p.node {
ast::pat_ident(_, none) { true } _ { false }
}
alt b.node.expr {
some(e) {
- let bt = ty::type_is_bot(bcx_tcx(bcx), ty::expr_ty(bcx_tcx(bcx), e));
+ let bt = ty::type_is_bot(bcx_tcx(bcx), expr_ty(bcx, e));
debuginfo::update_source_pos(bcx, e.span);
- bcx = trans_expr(bcx, e, bt ? ignore : dest);
+ bcx = trans_expr(bcx, e, if bt { ignore } else { dest });
}
_ { assert dest == ignore || bcx.unreachable; }
}
ret rv;
}
-fn new_local_ctxt(ccx: @crate_ctxt) -> @local_ctxt {
- let pth: [str] = [];
- ret @{path: pth,
- module_path: [ccx.link_meta.name],
- ccx: ccx};
-}
-
-
// Creates the standard quartet of basic blocks: static allocas, copy args,
// derived tydescs, and dynamic allocas.
fn mk_standard_basic_blocks(llfn: ValueRef) ->
// - create_llargs_for_fn_args.
// - new_fn_ctxt
// - trans_args
-fn new_fn_ctxt_w_id(cx: @local_ctxt, llfndecl: ValueRef,
- id: ast::node_id, rstyle: ast::ret_style)
- -> @fn_ctxt {
+fn new_fn_ctxt_w_id(ccx: @crate_ctxt, path: path,
+ llfndecl: ValueRef, id: ast::node_id,
+ param_substs: option<[ty::t]>,
+ sp: option<span>) -> @fn_ctxt {
let llbbs = mk_standard_basic_blocks(llfndecl);
ret @{llfn: llfndecl,
llenv: llvm::LLVMGetParam(llfndecl, 1u as c_uint),
mutable lltyparams: [],
derived_tydescs: ty::new_ty_hash(),
id: id,
- ret_style: rstyle,
- lcx: cx};
+ param_substs: param_substs,
+ span: sp,
+ path: path,
+ ccx: ccx};
}
-fn new_fn_ctxt(cx: @local_ctxt, llfndecl: ValueRef) -> @fn_ctxt {
- ret new_fn_ctxt_w_id(cx, llfndecl, -1, ast::return_val);
+fn new_fn_ctxt(ccx: @crate_ctxt, path: path, llfndecl: ValueRef,
+ sp: option<span>) -> @fn_ctxt {
+ ret new_fn_ctxt_w_id(ccx, path, llfndecl, -1, none, sp);
}
// NB: must keep 4 fns in sync:
fn copy_args_to_allocas(fcx: @fn_ctxt, bcx: @block_ctxt, args: [ast::arg],
arg_tys: [ty::arg]) -> @block_ctxt {
+ let tcx = bcx_tcx(bcx);
let arg_n: uint = 0u, bcx = bcx;
+ let epic_fail = fn@() -> ! {
+ tcx.sess.bug("Someone forgot\
+ to document an invariant in copy_args_to_allocas!");
+ };
for arg in arg_tys {
let id = args[arg_n].id;
- let argval = alt fcx.llargs.get(id) { local_mem(v) { v } };
- alt arg.mode {
+ let argval = alt fcx.llargs.get(id) { local_mem(v) { v }
+ _ { epic_fail() } };
+ alt ty::resolved_mode(tcx, arg.mode) {
ast::by_mut_ref { }
ast::by_move | ast::by_copy { add_clean(bcx, argval, arg.ty); }
ast::by_val {
ret bcx;
}
+// cries out for a precondition
fn arg_tys_of_fn(ccx: @crate_ctxt, id: ast::node_id) -> [ty::arg] {
- alt ty::struct(ccx.tcx, ty::node_id_to_type(ccx.tcx, id)) {
+ let tt = ty::node_id_to_type(ccx.tcx, id);
+ alt ty::struct(ccx.tcx, tt) {
ty::ty_fn({inputs, _}) { inputs }
+ _ { ccx.sess.bug(#fmt("arg_tys_of_fn called on non-function\
+ type %s", ty_to_str(ccx.tcx, tt)));}
}
}
// trans_closure: Builds an LLVM function out of a source function.
// If the function closes over its environment a closure will be
// returned.
-fn trans_closure(cx: @local_ctxt, decl: ast::fn_decl,
+fn trans_closure(ccx: @crate_ctxt, path: path, decl: ast::fn_decl,
body: ast::blk, llfndecl: ValueRef,
ty_self: self_arg, ty_params: [ast::ty_param],
+ param_substs: option<[ty::t]>,
id: ast::node_id, maybe_load_env: fn(@fn_ctxt)) {
set_uwtable(llfndecl);
// Set up arguments to the function.
- let fcx = new_fn_ctxt_w_id(cx, llfndecl, id, decl.cf);
+ let fcx = new_fn_ctxt_w_id(ccx, path, llfndecl, id, param_substs,
+ some(body.span));
create_llargs_for_fn_args(fcx, ty_self, decl.inputs, ty_params);
// Create the first basic block in the function and keep a handle on it to
// pass to finish_fn later.
- let bcx = new_top_block_ctxt(fcx);
+ let bcx = new_top_block_ctxt(fcx, some(body.span));
let lltop = bcx.llbb;
- let block_ty = node_id_type(cx.ccx, body.node.id);
+ let block_ty = node_id_type(bcx, body.node.id);
- let arg_tys = arg_tys_of_fn(fcx.lcx.ccx, id);
+ let arg_tys = arg_tys_of_fn(fcx.ccx, id);
bcx = copy_args_to_allocas(fcx, bcx, decl.inputs, arg_tys);
maybe_load_env(fcx);
// trans_mod, trans_item, et cetera) and those that do
// (trans_block, trans_expr, et cetera).
if option::is_none(body.node.expr) ||
- ty::type_is_bot(cx.ccx.tcx, block_ty) ||
- ty::type_is_nil(cx.ccx.tcx, block_ty) {
+ ty::type_is_bot(ccx.tcx, block_ty) ||
+ ty::type_is_nil(ccx.tcx, block_ty) {
bcx = trans_block(bcx, body);
} else {
bcx = trans_block_dps(bcx, body, save_in(fcx.llretptr));
}
- // FIXME: until LLVM has a unit type, we are moving around
- // C_nil values rather than their void type.
if !bcx.unreachable { build_return(bcx); }
// Insert the mandatory first few basic blocks before lltop.
finish_fn(fcx, lltop);
// trans_fn: creates an LLVM function corresponding to a source language
// function.
-fn trans_fn(cx: @local_ctxt, sp: span, decl: ast::fn_decl, body: ast::blk,
- llfndecl: ValueRef, ty_self: self_arg, ty_params: [ast::ty_param],
+fn trans_fn(ccx: @crate_ctxt, path: path, decl: ast::fn_decl,
+ body: ast::blk, llfndecl: ValueRef, ty_self: self_arg,
+ ty_params: [ast::ty_param], param_substs: option<[ty::t]>,
id: ast::node_id) {
- let do_time = cx.ccx.sess.opts.stats;
- let start = do_time ? time::get_time() : {sec: 0u32, usec: 0u32};
- let fcx = option::none;
- trans_closure(cx, decl, body, llfndecl, ty_self, ty_params, id,
- {|new_fcx| fcx = option::some(new_fcx);});
- if cx.ccx.sess.opts.extra_debuginfo {
- debuginfo::create_function(option::get(fcx), sp);
- }
+ let do_time = ccx.sess.opts.stats;
+ let start = if do_time { time::get_time() }
+ else { {sec: 0u32, usec: 0u32} };
+ trans_closure(ccx, path, decl, body, llfndecl, ty_self,
+ ty_params, param_substs, id, {|fcx|
+ if ccx.sess.opts.extra_debuginfo {
+ debuginfo::create_function(fcx);
+ }
+ });
if do_time {
let end = time::get_time();
- log_fn_time(cx.ccx, str::connect(cx.path, "::"), start, end);
+ log_fn_time(ccx, path_str(path), start, end);
}
}
-fn trans_res_ctor(cx: @local_ctxt, dtor: ast::fn_decl,
+fn trans_res_ctor(ccx: @crate_ctxt, path: path, dtor: ast::fn_decl,
ctor_id: ast::node_id, ty_params: [ast::ty_param]) {
- let ccx = cx.ccx;
-
// Create a function for the constructor
let llctor_decl = ccx.item_ids.get(ctor_id);
- let fcx = new_fn_ctxt(cx, llctor_decl);
- let ret_t = ty::ret_ty_of_fn(cx.ccx.tcx, ctor_id);
+ let fcx = new_fn_ctxt_w_id(ccx, path, llctor_decl, ctor_id, none, none);
+ let ret_t = ty::ret_ty_of_fn(ccx.tcx, ctor_id);
create_llargs_for_fn_args(fcx, no_self, dtor.inputs, ty_params);
- let bcx = new_top_block_ctxt(fcx);
+ let bcx = new_top_block_ctxt(fcx, none);
let lltop = bcx.llbb;
let arg_t = arg_tys_of_fn(ccx, ctor_id)[0].ty;
let tup_t = ty::mk_tup(ccx.tcx, [ty::mk_int(ccx.tcx), arg_t]);
let arg = alt fcx.llargs.find(dtor.inputs[0].id) {
some(local_mem(x)) { x }
+ _ { ccx.sess.bug("Someone forgot to document an invariant \
+ in trans_res_ctor"); }
};
let llretptr = fcx.llretptr;
if ty::type_has_dynamic_size(ccx.tcx, ret_t) {
}
-fn trans_enum_variant(cx: @local_ctxt, enum_id: ast::node_id,
- variant: ast::variant, disr: int, is_degen: bool,
- ty_params: [ast::ty_param]) {
- let ccx = cx.ccx;
-
- if vec::len::<ast::variant_arg>(variant.node.args) == 0u {
+fn trans_enum_variant(ccx: @crate_ctxt,
+ enum_id: ast::node_id,
+ variant: ast::variant, disr: int, is_degen: bool,
+ ty_params: [ast::ty_param]) {
+ if vec::len(variant.node.args) == 0u {
ret; // nullary constructors are just constants
-
}
- // Translate variant arguments to function arguments.
- let fn_args: [ast::arg] = [];
- let i = 0u;
- for varg: ast::variant_arg in variant.node.args {
- fn_args +=
- [{mode: ast::by_copy,
- ty: varg.ty,
- ident: "arg" + uint::to_str(i, 10u),
- id: varg.id}];
+ // Translate variant arguments to function arguments.
+ let fn_args = [], i = 0u;
+ for varg in variant.node.args {
+ fn_args += [{mode: ast::expl(ast::by_copy),
+ ty: varg.ty,
+ ident: "arg" + uint::to_str(i, 10u),
+ id: varg.id}];
}
assert (ccx.item_ids.contains_key(variant.node.id));
let llfndecl: ValueRef;
some(x) { llfndecl = x; }
_ {
ccx.sess.span_fatal(variant.span,
- "unbound variant id in trans_enum_variant");
+ "unbound variant id in trans_enum_variant");
}
}
- let fcx = new_fn_ctxt(cx, llfndecl);
+ let fcx = new_fn_ctxt_w_id(ccx, [], llfndecl, variant.node.id, none,
+ none);
create_llargs_for_fn_args(fcx, no_self, fn_args, ty_params);
- let ty_param_substs: [ty::t] = [];
- i = 0u;
+ let ty_param_substs = [], i = 0u;
for tp: ast::ty_param in ty_params {
ty_param_substs += [ty::mk_param(ccx.tcx, i,
- ast_util::local_def(tp.id))];
+ local_def(tp.id))];
i += 1u;
}
let arg_tys = arg_tys_of_fn(ccx, variant.node.id);
- let bcx = new_top_block_ctxt(fcx);
+ let bcx = new_top_block_ctxt(fcx, none);
let lltop = bcx.llbb;
bcx = copy_args_to_allocas(fcx, bcx, fn_args, arg_tys);
// Cast the enum to a type we can GEP into.
- let llblobptr =
- if is_degen {
- fcx.llretptr
- } else {
- let llenumptr =
- PointerCast(bcx, fcx.llretptr, T_opaque_enum_ptr(ccx));
- let lldiscrimptr = GEPi(bcx, llenumptr, [0, 0]);
- Store(bcx, C_int(ccx, disr), lldiscrimptr);
- GEPi(bcx, llenumptr, [0, 1])
- };
- i = 0u;
- let t_id = ast_util::local_def(enum_id);
- let v_id = ast_util::local_def(variant.node.id);
+ let llblobptr = if is_degen {
+ fcx.llretptr
+ } else {
+ let llenumptr =
+ PointerCast(bcx, fcx.llretptr, T_opaque_enum_ptr(ccx));
+ let lldiscrimptr = GEPi(bcx, llenumptr, [0, 0]);
+ Store(bcx, C_int(ccx, disr), lldiscrimptr);
+ GEPi(bcx, llenumptr, [0, 1])
+ };
+ let i = 0u;
+ let t_id = local_def(enum_id);
+ let v_id = local_def(variant.node.id);
for va: ast::variant_arg in variant.node.args {
check (valid_variant_index(i, bcx, t_id, v_id));
let rslt = GEP_enum(bcx, llblobptr, t_id, v_id, ty_param_substs, i);
// If this argument to this function is a enum, it'll have come in to
// this function as an opaque blob due to the way that type_of()
// works. So we have to cast to the destination's view of the type.
- let llarg = alt fcx.llargs.find(va.id) { some(local_mem(x)) { x } };
+ let llarg = alt fcx.llargs.find(va.id) { some(local_mem(x)) { x }
+ _ { bcx_tcx(bcx).sess.span_fatal(variant.span, "Someone forgot\
+ to document an invariant in trans_tag_variant"); } };
let arg_ty = arg_tys[i].ty;
if ty::type_contains_params(bcx_tcx(bcx), arg_ty) {
lldestptr = PointerCast(bcx, lldestptr, val_ty(llarg));
let te2 = trans_const_expr(cx, e2);
/* Neither type is bottom, and we expect them to be unified already,
* so the following is safe. */
- let ty = ty::expr_ty(ccx_tcx(cx), e1);
+ let ty = ty::expr_ty(cx.tcx, e1);
let is_float = ty::type_is_fp(ccx_tcx(cx), ty);
let signed = ty::type_is_signed(ccx_tcx(cx), ty);
ret alt b {
}
ast::expr_unary(u, e) {
let te = trans_const_expr(cx, e);
- let ty = ty::expr_ty(ccx_tcx(cx), e);
+ let ty = ty::expr_ty(cx.tcx, e);
let is_float = ty::type_is_fp(ccx_tcx(cx), ty);
ret alt u {
ast::box(_) |
shim_fn_ty: T_fn([T_ptr(bundle_ty)], T_void())
};
}
+ _ {
+ // Precondition?
+ ccx.tcx.sess.bug("c_stack_tys called on non-function type");
+ }
}
}
// stack pointer appropriately to avoid a round of copies. (In fact, the shim
// function itself is unnecessary). We used to do this, in fact, and will
// perhaps do so in the future.
-fn trans_native_mod(lcx: @local_ctxt, native_mod: ast::native_mod,
- abi: ast::native_abi) {
- fn build_shim_fn(lcx: @local_ctxt,
+fn trans_native_mod(ccx: @crate_ctxt,
+ native_mod: ast::native_mod, abi: ast::native_abi) {
+ fn build_shim_fn(ccx: @crate_ctxt,
native_item: @ast::native_item,
tys: @c_stack_tys,
- cc: uint) -> ValueRef {
+ cc: lib::llvm::CallConv) -> ValueRef {
let lname = link_name(native_item);
- let ccx = lcx_ccx(lcx);
// Declare the "prototype" for the base function F:
let llbasefn = decl_fn(ccx.llmod, lname, cc, tys.base_fn_ty);
ccx.llmod, shim_name, tys.shim_fn_ty);
// Declare the body of the shim function:
- let fcx = new_fn_ctxt(lcx, llshimfn);
- let bcx = new_top_block_ctxt(fcx);
+ let fcx = new_fn_ctxt(ccx, [], llshimfn, none);
+ let bcx = new_top_block_ctxt(fcx, none);
let lltop = bcx.llbb;
let llargbundle = llvm::LLVMGetParam(llshimfn, 0 as c_uint);
let i = 0u, n = vec::len(tys.arg_tys);
// Create the call itself and store the return value:
let llretval = CallWithConv(bcx, llbasefn,
- llargvals, cc as c_uint); // r
+ llargvals, cc); // r
if tys.ret_def {
// R** llretptr = &args->r;
let llretptr = GEPi(bcx, llargbundle, [0, n as int]);
ret llshimfn;
}
- fn build_wrap_fn(lcx: @local_ctxt,
+ fn build_wrap_fn(ccx: @crate_ctxt,
tys: @c_stack_tys,
num_tps: uint,
llshimfn: ValueRef,
llwrapfn: ValueRef) {
- let ccx = lcx_ccx(lcx);
- let fcx = new_fn_ctxt(lcx, llwrapfn);
- let bcx = new_top_block_ctxt(fcx);
+ let fcx = new_fn_ctxt(ccx, [], llwrapfn, none);
+ let bcx = new_top_block_ctxt(fcx, none);
let lltop = bcx.llbb;
// Allocate the struct and write the arguments into it.
finish_fn(fcx, lltop);
}
- let ccx = lcx_ccx(lcx);
- let cc = lib::llvm::LLVMCCallConv;
+ let cc = lib::llvm::CCallConv;
alt abi {
ast::native_abi_rust_intrinsic { ret; }
- ast::native_abi_cdecl { cc = lib::llvm::LLVMCCallConv; }
- ast::native_abi_stdcall { cc = lib::llvm::LLVMX86StdcallCallConv; }
+ ast::native_abi_cdecl { cc = lib::llvm::CCallConv; }
+ ast::native_abi_stdcall { cc = lib::llvm::X86StdcallCallConv; }
}
for native_item in native_mod.items {
alt native_item.node {
- ast::native_item_ty {}
ast::native_item_fn(fn_decl, tps) {
let id = native_item.id;
let tys = c_stack_tys(ccx, id);
alt ccx.item_ids.find(id) {
some(llwrapfn) {
- let llshimfn = build_shim_fn(lcx, native_item, tys, cc);
- build_wrap_fn(lcx, tys, vec::len(tps), llshimfn, llwrapfn);
+ let llshimfn = build_shim_fn(ccx, native_item, tys, cc);
+ build_wrap_fn(ccx, tys, vec::len(tps), llshimfn, llwrapfn);
}
-
none {
ccx.sess.span_fatal(
native_item.span,
}
}
-fn trans_item(cx: @local_ctxt, item: ast::item) {
+fn trans_item(ccx: @crate_ctxt, item: ast::item) {
+ let path = alt ccx.tcx.items.get(item.id) {
+ ast_map::node_item(_, p) { p }
+ _ { fail; }
+ };
alt item.node {
ast::item_fn(decl, tps, body) {
- let sub_cx = extend_path(cx, item.ident);
- alt cx.ccx.item_ids.find(item.id) {
+ alt ccx.item_ids.find(item.id) {
some(llfndecl) {
- trans_fn(sub_cx, item.span, decl, body, llfndecl, no_self, tps,
- item.id);
+ trans_fn(ccx, *path + [path_name(item.ident)], decl, body,
+ llfndecl, no_self, tps, none, item.id);
}
_ {
- cx.ccx.sess.span_fatal(item.span,
- "unbound function item in trans_item");
+ ccx.sess.span_fatal(item.span,
+ "unbound function item in trans_item");
}
}
}
ast::item_impl(tps, _, _, ms) {
- impl::trans_impl(cx, item.ident, ms, item.id, tps);
+ impl::trans_impl(ccx, *path, item.ident, ms, item.id, tps);
}
ast::item_res(decl, tps, body, dtor_id, ctor_id) {
- trans_res_ctor(cx, decl, ctor_id, tps);
+ trans_res_ctor(ccx, *path, decl, ctor_id, tps);
// Create a function for the destructor
- alt cx.ccx.item_ids.find(item.id) {
+ alt ccx.item_ids.find(item.id) {
some(lldtor_decl) {
- trans_fn(cx, item.span, decl, body, lldtor_decl, no_self,
- tps, dtor_id);
+ trans_fn(ccx, *path + [path_name(item.ident)], decl, body,
+ lldtor_decl, no_self, tps, none, dtor_id);
}
_ {
- cx.ccx.sess.span_fatal(item.span, "unbound dtor in trans_item");
+ ccx.sess.span_fatal(item.span, "unbound dtor in trans_item");
}
}
}
ast::item_mod(m) {
- let sub_cx =
- @{path: cx.path + [item.ident],
- module_path: cx.module_path + [item.ident] with *cx};
- trans_mod(sub_cx, m);
+ trans_mod(ccx, m);
}
ast::item_enum(variants, tps) {
- let sub_cx = extend_path(cx, item.ident);
let degen = vec::len(variants) == 1u;
- let vi = ty::enum_variants(cx.ccx.tcx, {crate: ast::local_crate,
- node: item.id});
+ let vi = ty::enum_variants(ccx.tcx, local_def(item.id));
let i = 0;
for variant: ast::variant in variants {
- trans_enum_variant(sub_cx, item.id, variant,
- vi[i].disr_val, degen, tps);
+ trans_enum_variant(ccx, item.id, variant,
+ vi[i].disr_val, degen, tps);
i += 1;
}
}
- ast::item_const(_, expr) { trans_const(cx.ccx, expr, item.id); }
+ ast::item_const(_, expr) { trans_const(ccx, expr, item.id); }
ast::item_native_mod(native_mod) {
let abi = alt attr::native_abi(item.attrs) {
either::right(abi_) { abi_ }
- either::left(msg) { cx.ccx.sess.span_fatal(item.span, msg) }
+ either::left(msg) { ccx.sess.span_fatal(item.span, msg) }
};
- trans_native_mod(cx, native_mod, abi);
+ trans_native_mod(ccx, native_mod, abi);
}
_ {/* fall through */ }
}
// separate modules in the compiled program. That's because modules exist
// only as a convenience for humans working with the code, to organize names
// and control visibility.
-fn trans_mod(cx: @local_ctxt, m: ast::_mod) {
- for item: @ast::item in m.items { trans_item(cx, *item); }
+fn trans_mod(ccx: @crate_ctxt, m: ast::_mod) {
+ for item in m.items { trans_item(ccx, *item); }
}
fn get_pair_fn_ty(llpairty: TypeRef) -> TypeRef {
ret struct_elt(llpairty, 0u);
}
-fn register_fn(ccx: @crate_ctxt, sp: span, path: [str], flav: str,
+fn register_fn(ccx: @crate_ctxt, sp: span, path: path, flav: str,
ty_params: [ast::ty_param], node_id: ast::node_id) {
// FIXME: pull this out
- let t = node_id_type(ccx, node_id);
- check returns_non_ty_var(ccx, t);
+ let t = ty::node_id_to_type(ccx.tcx, node_id);
register_fn_full(ccx, sp, path, flav, ty_params, node_id, t);
}
ccx.tcx.ty_param_bounds.get(tp.id)
}
-fn register_fn_full(ccx: @crate_ctxt, sp: span, path: [str], _flav: str,
+fn register_fn_full(ccx: @crate_ctxt, sp: span, path: path, _flav: str,
tps: [ast::ty_param], node_id: ast::node_id,
- node_type: ty::t)
- : returns_non_ty_var(ccx, node_type) {
- let path = path;
+ node_type: ty::t) {
let llfty = type_of_fn_from_ty(ccx, node_type,
vec::map(tps, {|p| param_bounds(ccx, p)}));
let ps: str = mangle_exported_name(ccx, path, node_type);
ccx.item_ids.insert(node_id, llfn);
ccx.item_symbols.insert(node_id, ps);
- let is_main: bool = is_main_name(path) && !ccx.sess.building_library;
+ let is_main = is_main_name(path) && !ccx.sess.building_library;
if is_main { create_main_wrapper(ccx, sp, llfn, node_type); }
}
}
let main_takes_argv =
+ // invariant!
alt ty::struct(ccx.tcx, main_node_type) {
ty::ty_fn({inputs, _}) { vec::len(inputs) != 0u }
+ _ { ccx.sess.span_fatal(sp, "main has a non-function type"); }
};
let llfn = create_main(ccx, main_llfn, main_takes_argv);
takes_argv: bool) -> ValueRef {
let unit_ty = ty::mk_str(ccx.tcx);
let vecarg_ty: ty::arg =
- {mode: ast::by_val,
+ {mode: ast::expl(ast::by_val),
ty: ty::mk_vec(ccx.tcx, {ty: unit_ty, mut: ast::imm})};
// FIXME: mk_nil should have a postcondition
let nt = ty::mk_nil(ccx.tcx);
let llfty = type_of_fn(ccx, [vecarg_ty], nt, []);
let llfdecl = decl_fn(ccx.llmod, "_rust_main",
- lib::llvm::LLVMCCallConv, llfty);
+ lib::llvm::CCallConv, llfty);
- let fcx = new_fn_ctxt(new_local_ctxt(ccx), llfdecl);
+ let fcx = new_fn_ctxt(ccx, [], llfdecl, none);
- let bcx = new_top_block_ctxt(fcx);
+ let bcx = new_top_block_ctxt(fcx, none);
let lltop = bcx.llbb;
let lloutputarg = llvm::LLVMGetParam(llfdecl, 0 as c_uint);
// on the stack).
fn create_real_fn_pair(cx: @block_ctxt, llfnty: TypeRef, llfn: ValueRef,
llenvptr: ValueRef) -> ValueRef {
- let lcx = cx.fcx.lcx;
-
- let pair = alloca(cx, T_fn_pair(lcx.ccx, llfnty));
+ let pair = alloca(cx, T_fn_pair(bcx_ccx(cx), llfnty));
fill_fn_pair(cx, pair, llfn, llenvptr);
ret pair;
}
let code_cell = GEPi(bcx, pair, [0, abi::fn_field_code]);
Store(bcx, llfn, code_cell);
let env_cell = GEPi(bcx, pair, [0, abi::fn_field_box]);
- let llenvblobptr =
- PointerCast(bcx, llenvptr, T_opaque_cbox_ptr(ccx));
+ let llenvblobptr = PointerCast(bcx, llenvptr, T_opaque_box_ptr(ccx));
Store(bcx, llenvblobptr, env_cell);
}
fn native_fn_ty_param_count(cx: @crate_ctxt, id: ast::node_id) -> uint {
let count;
let native_item =
- alt cx.ast_map.find(id) { some(ast_map::node_native_item(i)) { i } };
+ // invariant?!
+ alt cx.ast_map.find(id) {
+ some(ast_map::node_native_item(i, _)) { i }
+ _ { cx.sess.bug("native_fn_ty_param_count \
+ given a non-native item"); } };
alt native_item.node {
- ast::native_item_ty {
- cx.sess.bug("register_native_fn(): native fn isn't \
- actually a fn");
- }
ast::native_item_fn(_, tps) {
count = vec::len::<ast::ty_param>(tps);
}
ret count;
}
-fn native_fn_wrapper_type(cx: @crate_ctxt,
+
+// TODO: precondition
+fn native_fn_wrapper_type(cx: @crate_ctxt, sp: span,
param_bounds: [ty::param_bounds],
x: ty::t) -> TypeRef {
alt ty::struct(cx.tcx, x) {
ty::ty_fn({inputs: args, output: out, _}) {
ret type_of_fn(cx, args, out, param_bounds);
}
+ _ { cx.sess.span_bug(sp, "native_fn_wrapper_type got ill-typed\
+ thing"); }
}
}
}
fn collect_native_item(ccx: @crate_ctxt,
- abi: @mutable option::t<ast::native_abi>,
- i: @ast::native_item,
- &&pt: [str],
- _v: vt<[str]>) {
+ abi: @mutable option<ast::native_abi>,
+ i: @ast::native_item) {
alt i.node {
ast::native_item_fn(_, tps) {
let id = i.id;
- let node_type = node_id_type(ccx, id);
+ let node_type = ty::node_id_to_type(ccx.tcx, id);
let fn_abi =
alt attr::get_meta_item_value_str_by_name(i.attrs, "abi") {
option::none {
let ri_name = "rust_intrinsic_" + link_name(i);
let llnativefn = get_extern_fn(
ccx.externs, ccx.llmod, ri_name,
- lib::llvm::LLVMCCallConv, fn_type);
+ lib::llvm::CCallConv, fn_type);
ccx.item_ids.insert(id, llnativefn);
ccx.item_symbols.insert(id, ri_name);
}
// For true external functions: create a rust wrapper
// and link to that. The rust wrapper will handle
// switching to the C stack.
- let new_pt = pt + [i.ident];
- register_fn(ccx, i.span, new_pt, "native fn", tps, i.id);
+ let path = *alt ccx.tcx.items.get(i.id) {
+ ast_map::node_native_item(_, p) { p } _ { fail; }
+ } + [path_name(i.ident)];
+ register_fn(ccx, i.span, path, "native fn", tps, i.id);
}
}
}
}
}
-fn collect_item(ccx: @crate_ctxt, abi: @mutable option::t<ast::native_abi>,
- i: @ast::item, &&pt: [str], v: vt<[str]>) {
- let new_pt = pt + [i.ident];
+fn item_path(ccx: @crate_ctxt, i: @ast::item) -> path {
+ *alt ccx.tcx.items.get(i.id) {
+ ast_map::node_item(_, p) { p } _ { fail; }
+ } + [path_name(i.ident)]
+}
+
+fn collect_item(ccx: @crate_ctxt, abi: @mutable option<ast::native_abi>,
+ i: @ast::item) {
+ let my_path = item_path(ccx, i);
alt i.node {
ast::item_const(_, _) {
- let typ = node_id_type(ccx, i.id);
- let s =
- mangle_exported_name(ccx, pt + [i.ident],
- node_id_type(ccx, i.id));
+ let typ = ty::node_id_to_type(ccx.tcx, i.id);
+ let s = mangle_exported_name(ccx, my_path, typ);
// FIXME: Could follow from a constraint on types of const
// items
let g = str::as_buf(s, {|buf|
// Propagate the native ABI down to collect_native_item(),
alt attr::native_abi(i.attrs) {
either::left(msg) { ccx.sess.span_fatal(i.span, msg); }
- either::right(abi_) {
- *abi = option::some(abi_);
- }
+ either::right(abi_) { *abi = option::some(abi_); }
}
}
ast::item_fn(_, tps, _) {
- register_fn(ccx, i.span, new_pt, "fn", tps, i.id);
+ register_fn(ccx, i.span, my_path, "fn", tps,
+ i.id);
}
ast::item_impl(tps, _, _, methods) {
- let name = i.ident + int::str(i.id);
+ let path = my_path + [path_name(int::str(i.id))];
for m in methods {
- register_fn(ccx, i.span, pt + [name, m.ident],
+ register_fn(ccx, i.span,
+ path + [path_name(m.ident)],
"impl_method", tps + m.tps, m.id);
}
}
ast::item_res(_, tps, _, dtor_id, ctor_id) {
- register_fn(ccx, i.span, new_pt, "res_ctor", tps, ctor_id);
+ register_fn(ccx, i.span, my_path, "res_ctor", tps, ctor_id);
// Note that the destructor is associated with the item's id, not
// the dtor_id. This is a bit counter-intuitive, but simplifies
// ty_res, which would have to carry around two def_ids otherwise
// -- one to identify the type, and one to find the dtor symbol.
- let t = node_id_type(ccx, dtor_id);
+ let t = ty::node_id_to_type(ccx.tcx, dtor_id);
// FIXME: how to get rid of this check?
- check returns_non_ty_var(ccx, t);
- register_fn_full(ccx, i.span, new_pt, "res_dtor", tps, i.id, t);
+ register_fn_full(ccx, i.span, my_path + [path_name("dtor")],
+ "res_dtor", tps, i.id, t);
}
ast::item_enum(variants, tps) {
for variant in variants {
if vec::len(variant.node.args) != 0u {
- register_fn(ccx, i.span, new_pt + [variant.node.name],
+ register_fn(ccx, i.span,
+ my_path + [path_name(variant.node.name)],
"enum", tps, variant.node.id);
}
}
}
_ { }
}
- visit::visit_item(i, new_pt, v);
}
fn collect_items(ccx: @crate_ctxt, crate: @ast::crate) {
let abi = @mutable none::<ast::native_abi>;
- visit::visit_crate(*crate, [], visit::mk_vt(@{
- visit_native_item: bind collect_native_item(ccx, abi, _, _, _),
- visit_item: bind collect_item(ccx, abi, _, _, _)
- with *visit::default_visitor()
+ visit::visit_crate(*crate, (), visit::mk_simple_visitor(@{
+ visit_native_item: bind collect_native_item(ccx, abi, _),
+ visit_item: bind collect_item(ccx, abi, _)
+ with *visit::default_simple_visitor()
}));
}
// The constant translation pass.
-fn trans_constant(ccx: @crate_ctxt, it: @ast::item, &&pt: [str],
- v: vt<[str]>) {
- let new_pt = pt + [it.ident];
- visit::visit_item(it, new_pt, v);
+fn trans_constant(ccx: @crate_ctxt, it: @ast::item) {
alt it.node {
ast::item_enum(variants, _) {
let vi = ty::enum_variants(ccx.tcx, {crate: ast::local_crate,
- node: it.id});
- let i = 0;
+ node: it.id});
+ let i = 0, path = item_path(ccx, it);
for variant in variants {
- let p = new_pt + [variant.node.name, "discrim"];
+ let p = path + [path_name(variant.node.name),
+ path_name("discrim")];
let s = mangle_exported_name(ccx, p, ty::mk_int(ccx.tcx));
let disr_val = vi[i].disr_val;
let discrim_gvar = str::as_buf(s, {|buf|
llvm::LLVMSetInitializer(discrim_gvar, C_int(ccx, disr_val));
llvm::LLVMSetGlobalConstant(discrim_gvar, True);
ccx.discrims.insert(
- ast_util::local_def(variant.node.id), discrim_gvar);
+ local_def(variant.node.id), discrim_gvar);
ccx.discrim_symbols.insert(variant.node.id, s);
i += 1;
}
}
ast::item_impl(tps, some(@{node: ast::ty_path(_, id), _}), _, ms) {
let i_did = ast_util::def_id_of_def(ccx.tcx.def_map.get(id));
- impl::trans_impl_vtable(ccx, pt, i_did, ms, tps, it);
+ impl::trans_impl_vtable(ccx, item_path(ccx, it), i_did, ms, tps, it);
}
ast::item_iface(_, _) {
- impl::trans_iface_vtable(ccx, pt, it);
+ impl::trans_iface_vtable(ccx, item_path(ccx, it), it);
}
_ { }
}
}
fn trans_constants(ccx: @crate_ctxt, crate: @ast::crate) {
- let visitor =
- @{visit_item: bind trans_constant(ccx, _, _, _)
- with *visit::default_visitor()};
- visit::visit_crate(*crate, [], visit::mk_vt(visitor));
+ visit::visit_crate(*crate, (), visit::mk_simple_visitor(@{
+ visit_item: bind trans_constant(ccx, _)
+ with *visit::default_simple_visitor()
+ }));
}
fn vp2i(cx: @block_ctxt, v: ValueRef) -> ValueRef {
fn create_module_map(ccx: @crate_ctxt) -> ValueRef {
let elttype = T_struct([ccx.int_type, ccx.int_type]);
let maptype = T_array(elttype, ccx.module_data.size() + 1u);
- let map =
- str::as_buf("_rust_mod_map",
- {|buf| llvm::LLVMAddGlobal(ccx.llmod, maptype, buf) });
- llvm::LLVMSetLinkage(map,
- lib::llvm::LLVMInternalLinkage as llvm::Linkage);
+ let map = str::as_buf("_rust_mod_map", {|buf|
+ llvm::LLVMAddGlobal(ccx.llmod, maptype, buf)
+ });
+ lib::llvm::SetLinkage(map, lib::llvm::InternalLinkage);
let elts: [ValueRef] = [];
ccx.module_data.items {|key, val|
let elt = C_struct([p2i(ccx, C_cstr(ccx, key)),
let n_subcrates = 1;
let cstore = sess.cstore;
while cstore::have_crate_data(cstore, n_subcrates) { n_subcrates += 1; }
- let mapname = sess.building_library ? mapname : "toplevel";
+ let mapname = if sess.building_library { mapname } else { "toplevel" };
let sym_name = "_rust_crate_map_" + mapname;
let arrtype = T_array(int_type, n_subcrates as uint);
let maptype = T_struct([int_type, arrtype]);
let map = str::as_buf(sym_name, {|buf|
llvm::LLVMAddGlobal(llmod, maptype, buf)
});
- llvm::LLVMSetLinkage(map, lib::llvm::LLVMExternalLinkage
- as llvm::Linkage);
+ lib::llvm::SetLinkage(map, lib::llvm::ExternalLinkage);
ret map;
}
str::as_buf(cx.sess.targ_cfg.target_strs.meta_sect_name, {|buf|
llvm::LLVMSetSection(llglobal, buf)
});
- llvm::LLVMSetLinkage(llglobal,
- lib::llvm::LLVMInternalLinkage as llvm::Linkage);
+ lib::llvm::SetLinkage(llglobal, lib::llvm::InternalLinkage);
let t_ptr_i8 = T_ptr(T_i8());
llglobal = llvm::LLVMConstBitCast(llglobal, t_ptr_i8);
- let llvm_used =
- str::as_buf("llvm.used",
- {|buf|
- llvm::LLVMAddGlobal(cx.llmod, T_array(t_ptr_i8, 1u),
- buf)
- });
- llvm::LLVMSetLinkage(llvm_used,
- lib::llvm::LLVMAppendingLinkage as llvm::Linkage);
+ let llvm_used = str::as_buf("llvm.used", {|buf|
+ llvm::LLVMAddGlobal(cx.llmod, T_array(t_ptr_i8, 1u), buf)
+ });
+ lib::llvm::SetLinkage(llvm_used, lib::llvm::AppendingLinkage);
llvm::LLVMSetInitializer(llvm_used, C_array(t_ptr_i8, [llglobal]));
}
consts: new_int_hash::<ValueRef>(),
tydescs: ty::new_ty_hash(),
dicts: map::mk_hashmap(hash_dict_id, {|a, b| a == b}),
+ monomorphized: map::mk_hashmap(hash_mono_id, {|a, b| a == b}),
module_data: new_str_hash::<ValueRef>(),
lltypes: ty::new_ty_hash(),
names: new_namegen(),
opaque_vec_type: T_opaque_vec(targ_cfg),
builder: BuilderRef_res(llvm::LLVMCreateBuilder()),
shape_cx: shape::mk_ctxt(llmod),
- gc_cx: gc::mk_ctxt(),
crate_map: crate_map,
- dbg_cx: dbg_cx};
- let cx = new_local_ctxt(ccx);
+ dbg_cx: dbg_cx,
+ mutable do_not_commit_warning_issued: false};
collect_items(ccx, crate);
trans_constants(ccx, crate);
- trans_mod(cx, crate.node.module);
+ trans_mod(ccx, crate.node.module);
fill_crate_map(ccx, crate_map);
emit_tydescs(ccx);
shape::gen_shape_tables(ccx);
write_abi_version(ccx);
// Translate the metadata.
- write_metadata(cx.ccx, crate);
+ write_metadata(ccx, crate);
if ccx.sess.opts.stats {
#error("--- trans stats ---");
#error("n_static_tydescs: %u", ccx.stats.n_static_tydescs);
import lib::llvm::llvm;
import syntax::codemap;
import codemap::span;
-import llvm::{ValueRef, TypeRef, BasicBlockRef, BuilderRef, Opcode,
- ModuleRef};
+import lib::llvm::{ValueRef, TypeRef, BasicBlockRef, BuilderRef, ModuleRef};
+import lib::llvm::{Opcode, IntPredicate, RealPredicate, True, False,
+ CallConv};
import common::{block_ctxt, T_ptr, T_nil, T_i8, T_i1, T_void,
- T_fn, val_ty, bcx_ccx, C_i32};
+ T_fn, val_ty, bcx_ccx, C_i32, val_str};
fn B(cx: @block_ctxt) -> BuilderRef {
- let b = *cx.fcx.lcx.ccx.builder;
+ let b = *cx.fcx.ccx.builder;
llvm::LLVMPositionBuilderAtEnd(b, cx.llbb);
ret b;
}
if cx.unreachable { ret; }
assert (!cx.terminated);
cx.terminated = true;
+ #debug["Invoke(%s with arguments (%s))",
+ val_str(bcx_ccx(cx).tn, Fn),
+ str::connect(vec::map(Args, {|a|val_str(bcx_ccx(cx).tn, a)}),
+ ", ")];
unsafe {
llvm::LLVMBuildInvoke(B(cx), Fn, vec::to_ptr(Args),
vec::len(Args) as c_uint, Then, Catch,
let v = llvm::LLVMBuildInvoke(B(cx), Fn, vec::to_ptr(Args),
vec::len(Args) as c_uint,
Then, Catch, noname());
- llvm::LLVMSetInstructionCallConv(
- v, lib::llvm::LLVMFastCallConv as c_uint);
+ lib::llvm::SetInstructionCallConv(v, lib::llvm::FastCallConv);
}
}
}
fn Load(cx: @block_ctxt, PointerVal: ValueRef) -> ValueRef {
- let ccx = cx.fcx.lcx.ccx;
+ let ccx = cx.fcx.ccx;
if cx.unreachable {
let ty = val_ty(PointerVal);
let eltty = if llvm::LLVMGetTypeKind(ty) == 11 as c_int {
/* Comparisons */
-fn ICmp(cx: @block_ctxt, Op: uint, LHS: ValueRef, RHS: ValueRef) -> ValueRef {
+fn ICmp(cx: @block_ctxt, Op: IntPredicate, LHS: ValueRef, RHS: ValueRef)
+ -> ValueRef {
if cx.unreachable { ret llvm::LLVMGetUndef(T_i1()); }
ret llvm::LLVMBuildICmp(B(cx), Op as c_uint, LHS, RHS, noname());
}
-fn FCmp(cx: @block_ctxt, Op: uint, LHS: ValueRef, RHS: ValueRef) -> ValueRef {
+fn FCmp(cx: @block_ctxt, Op: RealPredicate, LHS: ValueRef, RHS: ValueRef)
+ -> ValueRef {
if cx.unreachable { ret llvm::LLVMGetUndef(T_i1()); }
ret llvm::LLVMBuildFCmp(B(cx), Op as c_uint, LHS, RHS, noname());
}
}
fn _UndefReturn(cx: @block_ctxt, Fn: ValueRef) -> ValueRef {
- let ccx = cx.fcx.lcx.ccx;
+ let ccx = cx.fcx.ccx;
let ty = val_ty(Fn);
let retty = if llvm::LLVMGetTypeKind(ty) == 8 as c_int {
llvm::LLVMGetReturnType(ty) } else { ccx.int_type };
check str::is_not_empty("$");
let sanitized = str::replace(text, "$", "");
let comment_text = "; " + sanitized;
- let asm = str::as_buf(comment_text, { |c|
- str::as_buf("", { |e|
- llvm::LLVMConstInlineAsm(T_fn([], T_void()), c, e, 0, 0)})});
+ let asm = str::as_buf(comment_text, {|c|
+ str::as_buf("", {|e|
+ llvm::LLVMConstInlineAsm(T_fn([], T_void()), c, e,
+ False, False)
+ })
+ });
Call(bcx, asm, []);
}
}
unsafe {
let v = llvm::LLVMBuildCall(B(cx), Fn, vec::to_ptr(Args),
vec::len(Args) as c_uint, noname());
- llvm::LLVMSetInstructionCallConv(
- v, lib::llvm::LLVMFastCallConv as c_uint);
+ lib::llvm::SetInstructionCallConv(v, lib::llvm::FastCallConv);
ret v;
}
}
fn CallWithConv(cx: @block_ctxt, Fn: ValueRef, Args: [ValueRef],
- Conv: c_uint) -> ValueRef {
+ Conv: CallConv) -> ValueRef {
if cx.unreachable { ret _UndefReturn(cx, Fn); }
unsafe {
let v = llvm::LLVMBuildCall(B(cx), Fn, vec::to_ptr(Args),
vec::len(Args) as c_uint, noname());
- llvm::LLVMSetInstructionCallConv(v, Conv);
+ lib::llvm::SetInstructionCallConv(v, Conv);
ret v;
}
}
}
fn PtrDiff(cx: @block_ctxt, LHS: ValueRef, RHS: ValueRef) -> ValueRef {
- let ccx = cx.fcx.lcx.ccx;
+ let ccx = cx.fcx.ccx;
if cx.unreachable { ret llvm::LLVMGetUndef(ccx.int_type); }
ret llvm::LLVMBuildPtrDiff(B(cx), LHS, RHS, noname());
}
import syntax::ast;
import syntax::ast_util;
import lib::llvm::llvm;
-import llvm::{ValueRef, TypeRef};
+import lib::llvm::{ValueRef, TypeRef};
import common::*;
import build::*;
import base::*;
mangle_internal_name_by_path,
mangle_internal_name_by_path_and_seq};
import util::ppaux::ty_to_str;
-import base::{
- trans_shared_malloc,
- type_of_inner,
- node_id_type,
- INIT,
- trans_shared_free,
- drop_ty,
- new_sub_block_ctxt,
- load_if_immediate,
- dest
-};
import shape::{size_of};
+import ast_map::{path, path_mod, path_name};
// ___Good to know (tm)__________________________________________________
//
// The layout of a closure environment in memory is
// roughly as follows:
//
-// struct closure_box {
-// unsigned ref_count; // only used for shared environments
-// type_desc *tydesc; // descriptor for the "struct closure_box" type
-// type_desc *bound_tdescs[]; // bound descriptors
-// struct {
-// upvar1_t upvar1;
-// ...
-// upvarN_t upvarN;
-// } bound_data;
+// struct rust_opaque_box { // see rust_internal.h
+// unsigned ref_count; // only used for fn@()
+// type_desc *tydesc; // describes closure_data struct
+// rust_opaque_box *prev; // (used internally by memory alloc)
+// rust_opaque_box *next; // (used internally by memory alloc)
+// struct closure_data {
+// type_desc *bound_tdescs[]; // bound descriptors
+// struct {
+// upvar1_t upvar1;
+// ...
+// upvarN_t upvarN;
+// } bound_data;
+// }
// };
//
-// Note that the closure carries a type descriptor that describes the
-// closure itself. Trippy. This is needed because the precise types
-// of the closed over data are lost in the closure type (`fn(T)->U`),
-// so if we need to take/drop, we must know what data is in the upvars
-// and so forth. This struct is defined in the code in mk_closure_tys()
-// below.
-//
-// The allocation strategy for this closure depends on the closure
-// type. For a sendfn, the closure (and the referenced type
-// descriptors) will be allocated in the exchange heap. For a fn, the
-// closure is allocated in the task heap and is reference counted.
-// For a block, the closure is allocated on the stack. Note that in
-// all cases we allocate space for a ref count just to make our lives
-// easier when upcasting to fn(T)->U, in the shape code, and so
-// forth.
+// Note that the closure is itself a rust_opaque_box. This is true
+// even for fn~ and fn&, because we wish to keep binary compatibility
+// between all kinds of closures. The allocation strategy for this
+// closure depends on the closure type. For a sendfn, the closure
+// (and the referenced type descriptors) will be allocated in the
+// exchange heap. For a fn, the closure is allocated in the task heap
+// and is reference counted. For a block, the closure is allocated on
+// the stack.
//
-// ## Opaque Closures ##
+// ## Opaque closures and the embedded type descriptor ##
//
// One interesting part of closures is that they encapsulate the data
// that they close over. So when I have a ptr to a closure, I do not
// nor where its fields are located. This is called an "opaque
// closure".
//
-// Typically an opaque closure suffices because I only manipulate it
-// by ptr. The routine common::T_opaque_cbox_ptr() returns an
-// appropriate type for such an opaque closure; it allows access to the
-// first two fields, but not the others.
+// Typically an opaque closure suffices because we only manipulate it
+// by ptr. The routine common::T_opaque_box_ptr() returns an
+// appropriate type for such an opaque closure; it allows access to
+// the box fields, but not the closure_data itself.
//
// But sometimes, such as when cloning or freeing a closure, we need
// to know the full information. That is where the type descriptor
//
// ## Subtleties concerning alignment ##
//
-// You'll note that the closure_box structure is a flat structure with
-// four fields. In some ways, it would be more convenient to use a nested
-// structure like so:
-//
-// struct {
-// int;
-// struct {
-// type_desc*;
-// type_desc*[];
-// bound_data;
-// } }
+// It is important that we be able to locate the closure data *without
+// knowing the kind of data that is being bound*. This can be tricky
+// because the alignment requirements of the bound data affects the
+// alignment requires of the closure_data struct as a whole. However,
+// right now this is a non-issue in any case, because the size of the
+// rust_opaque_box header is always a mutiple of 16-bytes, which is
+// the maximum alignment requirement we ever have to worry about.
//
-// This would be more convenient because it would allow us to use more
-// of the existing infrastructure: we could treat the inner struct as
-// a type and then hvae a boxed variant (which would add the int) etc.
-// However, there is one subtle problem with this: grouping the latter
-// 3 fields into an inner struct causes the alignment of the entire
-// struct to be the max alignment of the bound_data. This will
-// therefore vary from closure to closure. That would mean that we
-// cannot reliably locate the initial type_desc* in an opaque closure!
-// That's definitely a bad thing. Therefore, I have elected to create
-// a flat structure, even though it means some mild amount of code
-// duplication (however, we used to do it the other way, and we were
-// jumping through about as many hoops just trying to wedge a ref
-// count into a unique pointer, so it's kind of a wash in the end).
+// The only reason alignment matters is that, in order to learn what data
+// is bound, we would normally first load the type descriptors: but their
+// location is ultimately depend on their content! There is, however, a
+// workaround. We can load the tydesc from the rust_opaque_box, which
+// describes the closure_data struct and has self-contained derived type
+// descriptors, and read the alignment from there. It's just annoying to
+// do. Hopefully should this ever become an issue we'll have monomorphized
+// and type descriptors will all be a bad dream.
//
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
enum environment_value {
// Evaluate expr and store result in env (used for bind).
- env_expr(@ast::expr),
+ env_expr(@ast::expr, ty::t),
// Copy the value from this llvm ValueRef into the environment.
env_copy(ValueRef, ty::t, lval_kind),
fn ev_to_str(ccx: @crate_ctxt, ev: environment_value) -> str {
alt ev {
- env_expr(ex) { expr_to_str(ex) }
+ env_expr(ex, _) { expr_to_str(ex) }
env_copy(v, t, lk) { #fmt("copy(%s,%s)", val_str(ccx.tn, v),
ty_to_str(ccx.tcx, t)) }
env_move(v, t, lk) { #fmt("move(%s,%s)", val_str(ccx.tn, v),
};
}
+fn mk_tuplified_uniq_cbox_ty(tcx: ty::ctxt, cdata_ty: ty::t) -> ty::t {
+ let tydesc_ty = mk_tydesc_ty(tcx, ty::ck_uniq);
+ let cbox_ty = tuplify_cbox_ty(tcx, cdata_ty, tydesc_ty);
+ ret ty::mk_imm_uniq(tcx, cbox_ty);
+}
+
// Given a closure ty, emits a corresponding tuple ty
fn mk_closure_tys(tcx: ty::ctxt,
ck: ty::closure_kind,
ty_params: [fn_ty_param],
bound_values: [environment_value])
- -> (ty::t, ty::t, [ty::t]) {
+ -> (ty::t, [ty::t]) {
let bound_tys = [];
- let tydesc_ty =
- mk_tydesc_ty(tcx, ck);
+ let tydesc_ty = mk_tydesc_ty(tcx, ck);
// Compute the closed over tydescs
let param_ptrs = [];
env_copy(_, t, _) { t }
env_move(_, t, _) { t }
env_ref(_, t, _) { t }
- env_expr(e) { ty::expr_ty(tcx, e) }
+ env_expr(_, t) { t }
}];
}
let bound_data_ty = ty::mk_tup(tcx, bound_tys);
- let norc_tys = [tydesc_ty, ty::mk_tup(tcx, param_ptrs), bound_data_ty];
-
- // closure_norc_ty == everything but ref count
- //
- // This is a hack to integrate with the cycle coll. When you
- // allocate memory in the task-local space, you are expected to
- // provide a descriptor for that memory which excludes the ref
- // count. That's what this represents. However, this really
- // assumes a type setup like [uint, data] where data can be a
- // struct. We don't use that structure here because we don't want
- // to alignment of the first few fields being bound up in the
- // alignment of the bound data, as would happen if we laid out
- // that way. For now this should be fine but ultimately we need
- // to modify CC code or else modify box allocation interface to be
- // a bit more flexible, perhaps taking a vec of tys in the box
- // (which for normal rust code is always of length 1).
- let closure_norc_ty = ty::mk_tup(tcx, norc_tys);
-
- #debug["closure_norc_ty=%s", ty_to_str(tcx, closure_norc_ty)];
-
- // closure_ty == ref count, data tydesc, typarams, bound data
- let closure_ty = ty::mk_tup(tcx, [ty::mk_int(tcx)] + norc_tys);
-
- #debug["closure_ty=%s", ty_to_str(tcx, closure_norc_ty)];
-
- ret (closure_ty, closure_norc_ty, bound_tys);
+ let cdata_ty = ty::mk_tup(tcx, [ty::mk_tup(tcx, param_ptrs),
+ bound_data_ty]);
+ #debug["cdata_ty=%s", ty_to_str(tcx, cdata_ty)];
+ ret (cdata_ty, bound_tys);
}
fn allocate_cbox(bcx: @block_ctxt,
ck: ty::closure_kind,
- cbox_ty: ty::t,
- cbox_norc_ty: ty::t)
+ cdata_ty: ty::t)
-> (@block_ctxt, ValueRef, [ValueRef]) {
- let ccx = bcx_ccx(bcx);
-
- let alloc_in_heap = fn@(bcx: @block_ctxt,
- xchgheap: bool,
- &temp_cleanups: [ValueRef])
- -> (@block_ctxt, ValueRef) {
+ // let ccx = bcx_ccx(bcx);
+ let tcx = bcx_tcx(bcx);
- // n.b. If you are wondering why we don't use
- // trans_malloc_boxed() or alloc_uniq(), see the section about
- // "Subtleties concerning alignment" in the big comment at the
- // top of the file.
+ fn nuke_ref_count(bcx: @block_ctxt, box: ValueRef) {
+ // Initialize ref count to arbitrary value for debugging:
+ let ccx = bcx_ccx(bcx);
+ let box = PointerCast(bcx, box, T_opaque_box_ptr(ccx));
+ let ref_cnt = GEPi(bcx, box, [0, abi::box_field_refcnt]);
+ let rc = C_int(ccx, 0x12345678);
+ Store(bcx, rc, ref_cnt);
+ }
- let {bcx, val:llsz} = size_of(bcx, cbox_ty);
- let ti = none;
- let tydesc_ty = if xchgheap { cbox_ty } else { cbox_norc_ty };
- let {bcx, val:lltydesc} =
- get_tydesc(bcx, tydesc_ty, true, ti).result;
- let malloc = {
- if xchgheap { ccx.upcalls.shared_malloc}
- else { ccx.upcalls.malloc }
- };
- let box = Call(bcx, malloc, [llsz, lltydesc]);
- add_clean_free(bcx, box, xchgheap);
- temp_cleanups += [box];
- (bcx, box)
- };
+ fn store_uniq_tydesc(bcx: @block_ctxt,
+ cdata_ty: ty::t,
+ box: ValueRef,
+ &ti: option::t<@tydesc_info>) -> @block_ctxt {
+ let ccx = bcx_ccx(bcx);
+ let bound_tydesc = GEPi(bcx, box, [0, abi::box_field_tydesc]);
+ let {bcx, val: td} =
+ base::get_tydesc(bcx, cdata_ty, true, ti).result;
+ let td = Call(bcx, ccx.upcalls.create_shared_type_desc, [td]);
+ Store(bcx, td, bound_tydesc);
+ bcx
+ }
- // Allocate the box:
+ // Allocate and initialize the box:
+ let ti = none;
let temp_cleanups = [];
- let (bcx, box, rc) = alt ck {
+ let (bcx, box) = alt ck {
ty::ck_box {
- let (bcx, box) = alloc_in_heap(bcx, false, temp_cleanups);
- (bcx, box, 1)
+ let {bcx, val: box} = trans_malloc_boxed_raw(bcx, cdata_ty, ti);
+ (bcx, box)
}
ty::ck_uniq {
- let (bcx, box) = alloc_in_heap(bcx, true, temp_cleanups);
- (bcx, box, 0x12345678) // use arbitrary value for debugging
+ let uniq_cbox_ty = mk_tuplified_uniq_cbox_ty(tcx, cdata_ty);
+ check uniq::type_is_unique_box(bcx, uniq_cbox_ty);
+ let {bcx, val: box} = uniq::alloc_uniq(bcx, uniq_cbox_ty);
+ nuke_ref_count(bcx, box);
+ let bcx = store_uniq_tydesc(bcx, cdata_ty, box, ti);
+ (bcx, box)
}
ty::ck_block {
+ let cbox_ty = tuplify_box_ty(tcx, cdata_ty);
let {bcx, val: box} = base::alloc_ty(bcx, cbox_ty);
- (bcx, box, 0x12345678) // use arbitrary value for debugging
+ nuke_ref_count(bcx, box);
+ (bcx, box)
}
};
- // Initialize ref count
- let box = PointerCast(bcx, box, T_opaque_cbox_ptr(ccx));
- let ref_cnt = GEPi(bcx, box, [0, abi::box_rc_field_refcnt]);
- Store(bcx, C_int(ccx, rc), ref_cnt);
+ base::lazily_emit_tydesc_glue(bcx, abi::tydesc_field_take_glue, ti);
+ base::lazily_emit_tydesc_glue(bcx, abi::tydesc_field_drop_glue, ti);
+ base::lazily_emit_tydesc_glue(bcx, abi::tydesc_field_free_glue, ti);
ret (bcx, box, temp_cleanups);
}
type closure_result = {
llbox: ValueRef, // llvalue of ptr to closure
- cbox_ty: ty::t, // type of the closure data
+ cdata_ty: ty::t, // type of the closure data
bcx: @block_ctxt // final bcx
};
let tcx = bcx_tcx(bcx);
// compute the shape of the closure
- let (cbox_ty, cbox_norc_ty, bound_tys) =
+ let (cdata_ty, bound_tys) =
mk_closure_tys(tcx, ck, lltyparams, bound_values);
// allocate closure in the heap
let (bcx, llbox, temp_cleanups) =
- allocate_cbox(bcx, ck, cbox_ty, cbox_norc_ty);
-
- // store data tydesc.
- alt ck {
- ty::ck_box | ty::ck_uniq {
- let bound_tydesc = GEPi(bcx, llbox, [0, abi::cbox_elt_tydesc]);
- let ti = none;
-
- let {result:closure_td, _} =
- base::get_tydesc(bcx, cbox_ty, true, ti);
- base::lazily_emit_tydesc_glue(bcx, abi::tydesc_field_take_glue, ti);
- base::lazily_emit_tydesc_glue(bcx, abi::tydesc_field_drop_glue, ti);
- base::lazily_emit_tydesc_glue(bcx, abi::tydesc_field_free_glue, ti);
- bcx = closure_td.bcx;
- let td = maybe_clone_tydesc(bcx, ck, closure_td.val);
- Store(bcx, td, bound_tydesc);
- }
- ty::ck_block { /* skip this for blocks, not really relevant */ }
- }
+ allocate_cbox(bcx, ck, cdata_ty);
// cbox_ty has the form of a tuple: (a, b, c) we want a ptr to a
// tuple. This could be a ptr in uniq or a box or on stack,
// whatever.
+ let cbox_ty = tuplify_box_ty(tcx, cdata_ty);
let cboxptr_ty = ty::mk_ptr(tcx, {ty:cbox_ty, mut:ast::imm});
let llbox = cast_if_we_can(bcx, llbox, cboxptr_ty);
check type_is_tup_like(bcx, cbox_ty);
// If necessary, copy tydescs describing type parameters into the
// appropriate slot in the closure.
let {bcx:bcx, val:ty_params_slot} =
- GEP_tup_like(bcx, cbox_ty, llbox, [0, abi::cbox_elt_ty_params]);
+ GEP_tup_like(bcx, cbox_ty, llbox,
+ [0, abi::box_field_body, abi::closure_body_ty_params]);
let off = 0;
for tp in lltyparams {
let cloned_td = maybe_clone_tydesc(bcx, ck, tp.desc);
}
let bound_data = GEP_tup_like_1(bcx, cbox_ty, llbox,
- [0, abi::cbox_elt_bindings,
+ [0,
+ abi::box_field_body,
+ abi::closure_body_bindings,
i as int]);
bcx = bound_data.bcx;
let bound_data = bound_data.val;
alt bv {
- env_expr(e) {
+ env_expr(e, _) {
bcx = base::trans_expr_save_in(bcx, e, bound_data);
add_clean_temp_mem(bcx, bound_data, bound_tys[i]);
temp_cleanups += [bound_data];
}
for cleanup in temp_cleanups { revoke_clean(bcx, cleanup); }
- ret {llbox: llbox, cbox_ty: cbox_ty, bcx: bcx};
+ ret {llbox: llbox, cdata_ty: cdata_ty, bcx: bcx};
}
// Given a context and a list of upvars, build a closure. This just
vec::iter(cap_vars) { |cap_var|
let lv = trans_local_var(bcx, cap_var.def);
let nid = ast_util::def_id_of_def(cap_var.def).node;
- let ty = ty::node_id_to_monotype(tcx, nid);
+ let ty = ty::node_id_to_type(tcx, nid);
alt cap_var.mode {
capture::cap_ref {
assert ck == ty::ck_block;
// with the upvars and type descriptors.
fn load_environment(enclosing_cx: @block_ctxt,
fcx: @fn_ctxt,
- cbox_ty: ty::t,
+ cdata_ty: ty::t,
cap_vars: [capture::capture_var],
ck: ty::closure_kind) {
let bcx = new_raw_block_ctxt(fcx, fcx.llloadenv);
- let ccx = bcx_ccx(bcx);
- let tcx = bcx_tcx(bcx);
- let cboxptr_ty = ty::mk_ptr(tcx, {ty:cbox_ty, mut:ast::imm});
- check (type_has_static_size(ccx, cboxptr_ty));
- let llty = type_of(ccx, cboxptr_ty);
- let llclosure = PointerCast(bcx, fcx.llenv, llty);
+ // Load a pointer to the closure data, skipping over the box header:
+ let llcdata = base::opaque_box_body(bcx, cdata_ty, fcx.llenv);
// Populate the type parameters from the environment. We need to
// do this first because the tydescs are needed to index into
// the bindings if they are dynamically sized.
- let lltydescs = GEPi(bcx, llclosure, [0, abi::cbox_elt_ty_params]);
+ check type_is_tup_like(bcx, cdata_ty);
+ let {bcx, val: lltydescs} = GEP_tup_like(bcx, cdata_ty, llcdata,
+ [0, abi::closure_body_ty_params]);
let off = 0;
for tp in copy enclosing_cx.fcx.lltyparams {
let tydesc = Load(bcx, GEPi(bcx, lltydescs, [0, off]));
}
// Populate the upvars from the environment.
- let path = [0, abi::cbox_elt_bindings];
let i = 0u;
vec::iter(cap_vars) { |cap_var|
alt cap_var.mode {
capture::cap_drop { /* ignore */ }
_ {
- check type_is_tup_like(bcx, cbox_ty);
- let upvarptr = GEP_tup_like(
- bcx, cbox_ty, llclosure, path + [i as int]);
+ check type_is_tup_like(bcx, cdata_ty);
+ let upvarptr =
+ GEP_tup_like(bcx, cdata_ty, llcdata,
+ [0, abi::closure_body_bindings, i as int]);
bcx = upvarptr.bcx;
let llupvarptr = upvarptr.val;
alt ck {
dest: dest) -> @block_ctxt {
if dest == ignore { ret bcx; }
let ccx = bcx_ccx(bcx), bcx = bcx;
- let fty = node_id_type(ccx, id);
+ let fty = node_id_type(bcx, id);
let llfnty = type_of_fn_from_ty(ccx, fty, []);
- let sub_cx = extend_path(bcx.fcx.lcx, ccx.names("anon"));
- let s = mangle_internal_name_by_path(ccx, sub_cx.path);
+ let sub_path = bcx.fcx.path + [path_name("anon")];
+ let s = mangle_internal_name_by_path(ccx, sub_path);
let llfn = decl_internal_cdecl_fn(ccx.llmod, s, llfnty);
- register_fn(ccx, sp, sub_cx.path, "anon fn", [], id);
+ register_fn(ccx, sp, sub_path, "anon fn", [], id);
let trans_closure_env = fn@(ck: ty::closure_kind) -> ValueRef {
let cap_vars = capture::compute_capture_vars(
ccx.tcx, id, proto, cap_clause);
- let {llbox, cbox_ty, bcx} = build_closure(bcx, cap_vars, ck);
- trans_closure(sub_cx, decl, body, llfn, no_self, [], id, {|fcx|
- load_environment(bcx, fcx, cbox_ty, cap_vars, ck);
+ let {llbox, cdata_ty, bcx} = build_closure(bcx, cap_vars, ck);
+ trans_closure(ccx, sub_path, decl, body, llfn, no_self, [],
+ bcx.fcx.param_substs, id, {|fcx|
+ load_environment(bcx, fcx, cdata_ty, cap_vars, ck);
});
llbox
};
ast::proto_box { trans_closure_env(ty::ck_box) }
ast::proto_uniq { trans_closure_env(ty::ck_uniq) }
ast::proto_bare {
- let closure = C_null(T_opaque_cbox_ptr(ccx));
- trans_closure(sub_cx, decl, body, llfn, no_self, [],
+ trans_closure(ccx, sub_path, decl, body, llfn, no_self, [], none,
id, {|_fcx|});
- closure
+ C_null(T_opaque_box_ptr(ccx))
}
};
fill_fn_pair(bcx, get_dest_addr(dest), llfn, closure);
ret bcx;
}
-fn trans_bind(cx: @block_ctxt, f: @ast::expr, args: [option::t<@ast::expr>],
+fn trans_bind(cx: @block_ctxt, f: @ast::expr, args: [option<@ast::expr>],
id: ast::node_id, dest: dest) -> @block_ctxt {
let f_res = trans_callee(cx, f);
- ret trans_bind_1(cx, ty::expr_ty(bcx_tcx(cx), f), f_res, args,
+ ret trans_bind_1(cx, expr_ty(cx, f), f_res, args,
ty::node_id_to_type(bcx_tcx(cx), id), dest);
}
fn trans_bind_1(cx: @block_ctxt, outgoing_fty: ty::t,
f_res: lval_maybe_callee,
- args: [option::t<@ast::expr>], pair_ty: ty::t,
+ args: [option<@ast::expr>], pair_ty: ty::t,
dest: dest) -> @block_ctxt {
let bound: [@ast::expr] = [];
- for argopt: option::t<@ast::expr> in args {
+ for argopt: option<@ast::expr> in args {
alt argopt { none { } some(e) { bound += [e]; } }
}
let bcx = f_res.bcx;
};
// Actually construct the closure
- let {llbox, cbox_ty, bcx} = store_environment(
+ let {llbox, cdata_ty, bcx} = store_environment(
bcx, vec::map(lltydescs, {|d| {desc: d, dicts: none}}),
- env_vals + vec::map(bound, {|x| env_expr(x)}),
+ env_vals + vec::map(bound, {|x| env_expr(x, expr_ty(bcx, x))}),
ty::ck_box);
// Make thunk
- let llthunk =
- trans_bind_thunk(cx.fcx.lcx, pair_ty, outgoing_fty_real, args,
- cbox_ty, *param_bounds, target_res);
+ let llthunk = trans_bind_thunk(
+ cx.fcx.ccx, cx.fcx.path, pair_ty, outgoing_fty_real, args,
+ cdata_ty, *param_bounds, target_res);
// Fill the function pair
fill_fn_pair(bcx, get_dest_addr(dest), llthunk.val, llbox);
// Hard case, a deep copy:
let ccx = bcx_ccx(bcx);
- let llopaquecboxty = T_opaque_cbox_ptr(ccx);
+ let tcx = bcx_tcx(bcx);
+ let llopaquecboxty = T_opaque_box_ptr(ccx);
let cbox_in = Load(bcx, cboxptr);
make_null_test(bcx, cbox_in) {|bcx|
// Load the size from the type descr found in the cbox
let cbox_in = PointerCast(bcx, cbox_in, llopaquecboxty);
- let tydescptr = GEPi(bcx, cbox_in, [0, abi::cbox_elt_tydesc]);
+ let tydescptr = GEPi(bcx, cbox_in, [0, abi::box_field_tydesc]);
let tydesc = Load(bcx, tydescptr);
let tydesc = PointerCast(bcx, tydesc, T_ptr(ccx.tydesc_type));
let sz = Load(bcx, GEPi(bcx, tydesc, [0, abi::tydesc_field_size]));
+ // Adjust sz to account for the rust_opaque_box header fields
+ let sz = Add(bcx, sz, base::llsize_of(ccx, T_box_header(ccx)));
+
// Allocate memory, update original ptr, and copy existing data
let malloc = ccx.upcalls.shared_malloc;
let cbox_out = Call(bcx, malloc, [sz, tydesc]);
let {bcx, val: _} = call_memmove(bcx, cbox_out, cbox_in, sz);
Store(bcx, cbox_out, cboxptr);
+ // Take the (deeply cloned) type descriptor
+ let tydesc_out = GEPi(bcx, cbox_out, [0, abi::box_field_tydesc]);
+ let bcx = take_ty(bcx, tydesc_out, mk_tydesc_ty(tcx, ty::ck_uniq));
+
// Take the data in the tuple
let ti = none;
- call_tydesc_glue_full(bcx, cbox_out, tydesc,
+ let cdata_out = GEPi(bcx, cbox_out, [0, abi::box_field_body]);
+ call_tydesc_glue_full(bcx, cdata_out, tydesc,
abi::tydesc_field_take_glue, ti);
bcx
}
// Load the type descr found in the cbox
let lltydescty = T_ptr(ccx.tydesc_type);
let cbox = PointerCast(bcx, cbox, T_opaque_cbox_ptr(ccx));
- let tydescptr = GEPi(bcx, cbox, [0, abi::cbox_elt_tydesc]);
+ let tydescptr = GEPi(bcx, cbox, [0, abi::box_field_tydesc]);
let tydesc = Load(bcx, tydescptr);
let tydesc = PointerCast(bcx, tydesc, lltydescty);
- // Null out the type descr in the cbox. This is subtle:
- // we will be freeing the data in the cbox, and we may need the
- // information in the type descr to guide the GEP_tup_like process
- // etc if generic types are involved. So we null it out at first
- // then free it manually below.
- Store(bcx, C_null(lltydescty), tydescptr);
-
// Drop the tuple data then free the descriptor
let ti = none;
- call_tydesc_glue_full(bcx, cbox, tydesc,
+ let cdata = GEPi(bcx, cbox, [0, abi::box_field_body]);
+ call_tydesc_glue_full(bcx, cdata, tydesc,
abi::tydesc_field_drop_glue, ti);
// Free the ty descr (if necc) and the box itself
alt ck {
ty::ck_block { fail "Impossible"; }
ty::ck_box {
- trans_free_if_not_gc(bcx, cbox)
+ trans_free(bcx, cbox)
}
ty::ck_uniq {
let bcx = free_ty(bcx, tydesc, mk_tydesc_ty(tcx, ck));
}
// pth is cx.path
-fn trans_bind_thunk(cx: @local_ctxt,
+fn trans_bind_thunk(ccx: @crate_ctxt,
+ path: path,
incoming_fty: ty::t,
outgoing_fty: ty::t,
- args: [option::t<@ast::expr>],
- cbox_ty: ty::t,
+ args: [option<@ast::expr>],
+ cdata_ty: ty::t,
param_bounds: [ty::param_bounds],
- target_fn: option::t<ValueRef>)
+ target_fn: option<ValueRef>)
-> {val: ValueRef, ty: TypeRef} {
+
// If we supported constraints on record fields, we could make the
// constraints for this function:
/*
type_has_static_size(ccx, incoming_fty) ->
*/
// but since we don't, we have to do the checks at the beginning.
- let ccx = cx.ccx;
- let tcx = ccx_tcx(ccx);
+ let tcx = ccx.tcx;
check type_has_static_size(ccx, incoming_fty);
+ #debug["trans_bind_thunk[incoming_fty=%s,outgoing_fty=%s,\
+ cdata_ty=%s,param_bounds=%?]",
+ ty_to_str(tcx, incoming_fty),
+ ty_to_str(tcx, outgoing_fty),
+ ty_to_str(tcx, cdata_ty),
+ param_bounds];
+
// Here we're not necessarily constructing a thunk in the sense of
// "function with no arguments". The result of compiling 'bind f(foo,
// bar, baz)' would be a thunk that, when called, applies f to those
// construct and return that thunk.
// Give the thunk a name, type, and value.
- let s: str = mangle_internal_name_by_path_and_seq(ccx, cx.path, "thunk");
- let llthunk_ty: TypeRef = get_pair_fn_ty(type_of(ccx, incoming_fty));
- let llthunk: ValueRef = decl_internal_cdecl_fn(ccx.llmod, s, llthunk_ty);
+ let s = mangle_internal_name_by_path_and_seq(ccx, path, "thunk");
+ let llthunk_ty = get_pair_fn_ty(type_of(ccx, incoming_fty));
+ let llthunk = decl_internal_cdecl_fn(ccx.llmod, s, llthunk_ty);
// Create a new function context and block context for the thunk, and hold
// onto a pointer to the first block in the function for later use.
- let fcx = new_fn_ctxt(cx, llthunk);
- let bcx = new_top_block_ctxt(fcx);
+ let fcx = new_fn_ctxt(ccx, path, llthunk, none);
+ let bcx = new_top_block_ctxt(fcx, none);
let lltop = bcx.llbb;
// Since we might need to construct derived tydescs that depend on
// our bound tydescs, we need to load tydescs out of the environment
let l_bcx = new_raw_block_ctxt(fcx, fcx.llloadenv);
// The 'llenv' that will arrive in the thunk we're creating is an
- // environment that will contain the values of its arguments and a pointer
- // to the original function. So, let's create one of those:
-
- // The llenv pointer needs to be the correct size. That size is
- // 'cbox_ty', which was determined by trans_bind.
- let cboxptr_ty = ty::mk_ptr(tcx, {ty:cbox_ty, mut:ast::imm});
- check type_has_static_size(ccx, cboxptr_ty);
- let llclosure_ptr_ty = type_of(ccx, cboxptr_ty);
- let llclosure = PointerCast(l_bcx, fcx.llenv, llclosure_ptr_ty);
+ // environment that will contain the values of its arguments and a
+ // pointer to the original function. This environment is always
+ // stored like an opaque box (see big comment at the header of the
+ // file), so we load the body body, which contains the type descr
+ // and cached data.
+ let llcdata = base::opaque_box_body(l_bcx, cdata_ty, fcx.llenv);
// "target", in this context, means the function that's having some of its
// arguments bound and that will be called inside the thunk we're
}
none {
// Silly check
- check type_is_tup_like(bcx, cbox_ty);
+ check type_is_tup_like(bcx, cdata_ty);
let {bcx: cx, val: pair} =
- GEP_tup_like(bcx, cbox_ty, llclosure,
- [0, abi::cbox_elt_bindings, 0]);
+ GEP_tup_like(bcx, cdata_ty, llcdata,
+ [0, abi::closure_body_bindings, 0]);
let lltargetenv =
Load(cx, GEPi(cx, pair, [0, abi::fn_field_box]));
let lltargetfn = Load
// Get f's return type, which will also be the return type of the entire
// bind expression.
- let outgoing_ret_ty = ty::ty_fn_ret(cx.ccx.tcx, outgoing_fty);
+ let outgoing_ret_ty = ty::ty_fn_ret(ccx.tcx, outgoing_fty);
// Get the types of the arguments to f.
- let outgoing_args = ty::ty_fn_args(cx.ccx.tcx, outgoing_fty);
+ let outgoing_args = ty::ty_fn_args(ccx.tcx, outgoing_fty);
// The 'llretptr' that will arrive in the thunk we're creating also needs
// to be the correct type. Cast it to f's return type, if necessary.
let llretptr = fcx.llretptr;
- let ccx = cx.ccx;
if ty::type_contains_params(ccx.tcx, outgoing_ret_ty) {
check non_ty_var(ccx, outgoing_ret_ty);
let llretty = type_of_inner(ccx, outgoing_ret_ty);
let llargs: [ValueRef] = [llretptr, lltargetenv];
// Copy in the type parameters.
- check type_is_tup_like(l_bcx, cbox_ty);
+ check type_is_tup_like(l_bcx, cdata_ty);
let {bcx: l_bcx, val: param_record} =
- GEP_tup_like(l_bcx, cbox_ty, llclosure,
- [0, abi::cbox_elt_ty_params]);
+ GEP_tup_like(l_bcx, cdata_ty, llcdata,
+ [0, abi::closure_body_ty_params]);
let off = 0;
for param in param_bounds {
let dsc = Load(l_bcx, GEPi(l_bcx, param_record, [0, off])),
let b: int = starting_idx;
let outgoing_arg_index: uint = 0u;
let llout_arg_tys: [TypeRef] =
- type_of_explicit_args(cx.ccx, outgoing_args);
- for arg: option::t<@ast::expr> in args {
+ type_of_explicit_args(ccx, outgoing_args);
+ for arg: option<@ast::expr> in args {
let out_arg = outgoing_args[outgoing_arg_index];
let llout_arg_ty = llout_arg_tys[outgoing_arg_index];
alt arg {
// closure.
some(e) {
// Silly check
- check type_is_tup_like(bcx, cbox_ty);
+ check type_is_tup_like(bcx, cdata_ty);
let bound_arg =
- GEP_tup_like(bcx, cbox_ty, llclosure,
- [0, abi::cbox_elt_bindings, b]);
+ GEP_tup_like(bcx, cdata_ty, llcdata,
+ [0, abi::closure_body_bindings, b]);
bcx = bound_arg.bcx;
let val = bound_arg.val;
- if out_arg.mode == ast::by_val { val = Load(bcx, val); }
- if out_arg.mode == ast::by_copy {
+
+ alt ty::resolved_mode(tcx, out_arg.mode) {
+ ast::by_val {
+ val = Load(bcx, val);
+ }
+ ast::by_copy {
let {bcx: cx, val: alloc} = alloc_ty(bcx, out_arg.ty);
bcx = memmove_ty(cx, alloc, val, out_arg.ty);
bcx = take_ty(bcx, alloc, out_arg.ty);
val = alloc;
+ }
+ ast::by_ref | ast::by_mut_ref | ast::by_move { }
}
+
// If the type is parameterized, then we need to cast the
// type we actually have to the parameterized out type.
- if ty::type_contains_params(cx.ccx.tcx, out_arg.ty) {
+ if ty::type_contains_params(ccx.tcx, out_arg.ty) {
val = PointerCast(bcx, val, llout_arg_ty);
}
llargs += [val];
// Arg will be provided when the thunk is invoked.
none {
let arg: ValueRef = llvm::LLVMGetParam(llthunk, a as c_uint);
- if ty::type_contains_params(cx.ccx.tcx, out_arg.ty) {
+ if ty::type_contains_params(ccx.tcx, out_arg.ty) {
arg = PointerCast(bcx, arg, llout_arg_ty);
}
llargs += [arg];
// This is necessary because the type of the function that we have
// in the closure does not know how many type descriptors the function
// needs to take.
- let ccx = bcx_ccx(bcx);
-
let lltargetty =
type_of_fn_from_ty(ccx, outgoing_fty, param_bounds);
lltargetfn = PointerCast(bcx, lltargetfn, T_ptr(lltargetty));
import syntax::codemap::span;
import lib::llvm::{llvm, target_data, type_names, associate_type,
name_has_type};
-import lib::llvm::llvm::{ModuleRef, ValueRef, TypeRef, BasicBlockRef};
+import lib::llvm::{ModuleRef, ValueRef, TypeRef, BasicBlockRef, BuilderRef};
import lib::llvm::{True, False, Bool};
-import metadata::{csearch};
+import metadata::csearch;
+import ast_map::path;
// FIXME: These should probably be pulled in here too.
import base::{type_of_fn, drop_ty};
tydesc: ValueRef,
size: ValueRef,
align: ValueRef,
- mutable take_glue: option::t<ValueRef>,
- mutable drop_glue: option::t<ValueRef>,
- mutable free_glue: option::t<ValueRef>,
- mutable cmp_glue: option::t<ValueRef>,
+ mutable take_glue: option<ValueRef>,
+ mutable drop_glue: option<ValueRef>,
+ mutable free_glue: option<ValueRef>,
+ mutable cmp_glue: option<ValueRef>,
ty_params: [uint]};
/*
mutable n_real_glues: uint,
fn_times: @mutable [{ident: str, time: int}]};
-resource BuilderRef_res(B: llvm::BuilderRef) { llvm::LLVMDisposeBuilder(B); }
+resource BuilderRef_res(B: BuilderRef) { llvm::LLVMDisposeBuilder(B); }
// Crate context. Every crate we compile has one of these.
type crate_ctxt =
ast_map: ast_map::map,
exp_map: resolve::exp_map,
item_symbols: hashmap<ast::node_id, str>,
- mutable main_fn: option::t<ValueRef>,
+ mutable main_fn: option<ValueRef>,
link_meta: link::link_meta,
enum_sizes: hashmap<ty::t, uint>,
discrims: hashmap<ast::def_id, ValueRef>,
consts: hashmap<ast::node_id, ValueRef>,
tydescs: hashmap<ty::t, @tydesc_info>,
dicts: hashmap<dict_id, ValueRef>,
+ monomorphized: hashmap<mono_id, ValueRef>,
module_data: hashmap<str, ValueRef>,
lltypes: hashmap<ty::t, TypeRef>,
names: namegen,
opaque_vec_type: TypeRef,
builder: BuilderRef_res,
shape_cx: shape::ctxt,
- gc_cx: gc::ctxt,
crate_map: ValueRef,
- dbg_cx: option::t<@debuginfo::debug_ctxt>};
-
-type local_ctxt =
- {path: [str],
- module_path: [str],
- ccx: @crate_ctxt};
+ dbg_cx: option<@debuginfo::debug_ctxt>,
+ mutable do_not_commit_warning_issued: bool};
// Types used for llself.
type val_self_pair = {v: ValueRef, t: ty::t};
enum local_val { local_mem(ValueRef), local_imm(ValueRef), }
-type fn_ty_param = {desc: ValueRef, dicts: option::t<[ValueRef]>};
+type fn_ty_param = {desc: ValueRef, dicts: option<[ValueRef]>};
// Function context. Every LLVM function we create will have one of
// these.
-type fn_ctxt =
+type fn_ctxt = {
// The ValueRef returned from a call to llvm::LLVMAddFunction; the
// address of the first instruction in the sequence of
// instructions for this function that will go in the .text
// section of the executable we're generating.
+ llfn: ValueRef,
- // The three implicit arguments that arrive in the function we're
- // creating. For instance, foo(int, int) is really foo(ret*,
- // task*, env*, int, int). These are also available via
- // llvm::LLVMGetParam(llfn, uint) where uint = 1, 2, 0
- // respectively, but we unpack them into these fields for
- // convenience.
-
- // Points to the current task.
-
- // Points to the current environment (bindings of variables to
- // values), if this is a regular function
-
- // Points to where the return value of this function should end
- // up.
+ // The two implicit arguments that arrive in the function we're creating.
+ // For instance, foo(int, int) is really foo(ret*, env*, int, int).
+ llenv: ValueRef,
+ llretptr: ValueRef,
- // The next three elements: "hoisted basic blocks" containing
+ // These elements: "hoisted basic blocks" containing
// administrative activities that have to happen in only one place in
// the function, due to LLVM's quirks.
-
// A block for all the function's static allocas, so that LLVM
// will coalesce them into a single alloca call.
-
+ mutable llstaticallocas: BasicBlockRef,
// A block containing code that copies incoming arguments to space
// already allocated by code in one of the llallocas blocks.
// (LLVM requires that arguments be copied to local allocas before
// allowing most any operation to be performed on them.)
-
- // The first block containing derived tydescs received from the
- // runtime. See description of derived_tydescs, below.
-
- // The last block of the llderivedtydescs group.
-
+ mutable llloadenv: BasicBlockRef,
+ // The first and last block containing derived tydescs received from the
+ // runtime. See description of derived_tydescs, below.
+ mutable llderivedtydescs_first: BasicBlockRef,
+ mutable llderivedtydescs: BasicBlockRef,
// A block for all of the dynamically sized allocas. This must be
// after llderivedtydescs, because these sometimes depend on
// information computed from derived tydescs.
-
+ mutable lldynamicallocas: BasicBlockRef,
+ mutable llreturn: BasicBlockRef,
// The token used to clear the dynamic allocas at the end of this frame.
-
+ mutable llobstacktoken: option<ValueRef>,
// The 'self' value currently in use in this function, if there
// is one.
-
- // If this function is actually a iter, a block containing the
- // code called whenever the iter calls 'put'.
-
- // The next four items: hash tables mapping from AST def_ids to
- // LLVM-stuff-in-the-frame.
+ mutable llself: option<val_self_pair>,
// Maps arguments to allocas created for them in llallocas.
-
+ llargs: hashmap<ast::node_id, local_val>,
// Maps the def_ids for local variables to the allocas created for
// them in llallocas.
+ lllocals: hashmap<ast::node_id, local_val>,
+ // Same as above, but for closure upvars
+ llupvars: hashmap<ast::node_id, ValueRef>,
- // The same as above, but for variables accessed via the frame
- // pointer we pass into an iter, for access to the static
- // environment of the iter-calling frame.
-
- // For convenience, a vector of the incoming tydescs for each of
- // this functions type parameters, fetched via llvm::LLVMGetParam.
- // For example, for a function foo::<A, B, C>(), lltydescs contains
- // the ValueRefs for the tydescs for A, B, and C.
+ // A vector of incoming type descriptors and their associated iface dicts.
+ mutable lltyparams: [fn_ty_param],
// Derived tydescs are tydescs created at runtime, for types that
// involve type parameters inside type constructors. For example,
// when information about both "[T]" and "T" are available. When
// such a tydesc is created, we cache it in the derived_tydescs
// table for the next time that such a tydesc is needed.
+ derived_tydescs: hashmap<ty::t, derived_tydesc_info>,
// The node_id of the function, or -1 if it doesn't correspond to
// a user-defined function.
+ id: ast::node_id,
+
+ // If this function is being monomorphized, this contains the type
+ // substitutions used.
+ param_substs: option<[ty::t]>,
- // The source span where this function comes from, for error
- // reporting.
-
- // This function's enclosing local context.
- {llfn: ValueRef,
- llenv: ValueRef,
- llretptr: ValueRef,
- mutable llstaticallocas: BasicBlockRef,
- mutable llloadenv: BasicBlockRef,
- mutable llderivedtydescs_first: BasicBlockRef,
- mutable llderivedtydescs: BasicBlockRef,
- mutable lldynamicallocas: BasicBlockRef,
- mutable llreturn: BasicBlockRef,
- mutable llobstacktoken: option::t<ValueRef>,
- mutable llself: option::t<val_self_pair>,
- llargs: hashmap<ast::node_id, local_val>,
- lllocals: hashmap<ast::node_id, local_val>,
- llupvars: hashmap<ast::node_id, ValueRef>,
- mutable lltyparams: [fn_ty_param],
- derived_tydescs: hashmap<ty::t, derived_tydesc_info>,
- id: ast::node_id,
- ret_style: ast::ret_style,
- lcx: @local_ctxt};
+ // The source span and nesting context where this function comes from, for
+ // error reporting and symbol generation.
+ span: option<span>,
+ path: path,
+
+ // This function's enclosing crate context.
+ ccx: @crate_ctxt
+};
+
+fn warn_not_to_commit(ccx: @crate_ctxt, msg: str) {
+ if !ccx.do_not_commit_warning_issued {
+ ccx.do_not_commit_warning_issued = true;
+ ccx.sess.warn(msg + " -- do not commit like this!");
+ }
+}
enum cleanup {
clean(fn@(@block_ctxt) -> @block_ctxt),
fn add_clean_free(cx: @block_ctxt, ptr: ValueRef, shared: bool) {
let scope_cx = find_scope_cx(cx);
let free_fn = if shared { bind base::trans_shared_free(_, ptr) }
- else { bind base::trans_free_if_not_gc(_, ptr) };
+ else { bind base::trans_free(_, ptr) };
scope_cx.cleanups += [clean_temp(ptr, free_fn)];
scope_cx.lpad_dirty = true;
}
let nil_res = ty::mk_nil(ccx.tcx);
// FIXME: Silly check -- mk_nil should have a postcondition
check non_ty_var(ccx, nil_res);
- let f_t = type_of_fn(ccx, [{mode: ast::by_ref, ty: inner_t}],
+ let fn_mode = ast::expl(ast::by_ref);
+ let f_t = type_of_fn(ccx, [{mode: fn_mode, ty: inner_t}],
nil_res, *param_bounds);
ret base::get_extern_const(ccx.externs, ccx.llmod,
csearch::get_symbol(ccx.sess.cstore,
}
enum block_kind {
-
-
- // A scope block is a basic block created by translating a block { ... }
- // in the source language. Since these blocks create variable scope, any
- // variables created in them that are still live at the end of the block
- // must be dropped and cleaned up when the block ends.
+ // A scope at the end of which temporary values created inside of it are
+ // cleaned up. May correspond to an actual block in the language, but also
+ // to an implicit scope, for example, calls introduce an implicit scope in
+ // which the arguments are evaluated and cleaned up.
SCOPE_BLOCK,
-
-
// A basic block created from the body of a loop. Contains pointers to
- // which block to jump to in the case of "continue" or "break", with the
- // "continue" block optional, because "while" and "do while" don't support
- // "continue" (TODO: is this intentional?)
- LOOP_SCOPE_BLOCK(option::t<@block_ctxt>, @block_ctxt),
-
-
+ // which block to jump to in the case of "continue" or "break".
+ LOOP_SCOPE_BLOCK(option<@block_ctxt>, @block_ctxt),
// A non-scope block is a basic block created as a translation artifact
// from translating code that expresses conditional logic rather than by
// explicit { ... } block structure in the source language. It's called a
kind: block_kind,
mutable cleanups: [cleanup],
mutable lpad_dirty: bool,
- mutable lpad: option::t<BasicBlockRef>,
+ mutable lpad: option<BasicBlockRef>,
+ block_span: option<span>,
fcx: @fn_ctxt};
-// FIXME: we should be able to use option::t<@block_parent> here but
+// FIXME: we should be able to use option<@block_parent> here but
// the infinite-enum check in rustboot gets upset.
enum block_parent { parent_none, parent_some(@block_ctxt), }
type result = {bcx: @block_ctxt, val: ValueRef};
type result_t = {bcx: @block_ctxt, val: ValueRef, ty: ty::t};
-fn extend_path(cx: @local_ctxt, name: str) -> @local_ctxt {
- ret @{path: cx.path + [name] with *cx};
-}
-
fn rslt(bcx: @block_ctxt, val: ValueRef) -> result {
{bcx: bcx, val: val}
}
if cx.kind != NON_SCOPE_BLOCK { ret cx; }
alt cx.parent {
parent_some(b) { ret find_scope_cx(b); }
+ _ {
+ bcx_tcx(cx).sess.bug("find_scope_cx: empty scope");
+ }
}
}
// Accessors
// TODO: When we have overloading, simplify these names!
-pure fn bcx_tcx(bcx: @block_ctxt) -> ty::ctxt { ret bcx.fcx.lcx.ccx.tcx; }
-pure fn bcx_ccx(bcx: @block_ctxt) -> @crate_ctxt { ret bcx.fcx.lcx.ccx; }
-pure fn bcx_lcx(bcx: @block_ctxt) -> @local_ctxt { ret bcx.fcx.lcx; }
+pure fn bcx_tcx(bcx: @block_ctxt) -> ty::ctxt { ret bcx.fcx.ccx.tcx; }
+pure fn bcx_ccx(bcx: @block_ctxt) -> @crate_ctxt { ret bcx.fcx.ccx; }
pure fn bcx_fcx(bcx: @block_ctxt) -> @fn_ctxt { ret bcx.fcx; }
-pure fn fcx_ccx(fcx: @fn_ctxt) -> @crate_ctxt { ret fcx.lcx.ccx; }
-pure fn fcx_tcx(fcx: @fn_ctxt) -> ty::ctxt { ret fcx.lcx.ccx.tcx; }
-pure fn lcx_ccx(lcx: @local_ctxt) -> @crate_ctxt { ret lcx.ccx; }
+pure fn fcx_ccx(fcx: @fn_ctxt) -> @crate_ctxt { ret fcx.ccx; }
+pure fn fcx_tcx(fcx: @fn_ctxt) -> ty::ctxt { ret fcx.ccx.tcx; }
pure fn ccx_tcx(ccx: @crate_ctxt) -> ty::ctxt { ret ccx.tcx; }
// LLVM type constructors.
ret T_vec2(targ_cfg, T_i8());
}
+// Let T be the content of a box @T. tuplify_box_ty(t) returns the
+// representation of @T as a tuple (i.e., the ty::t version of what T_box()
+// returns).
+fn tuplify_box_ty(tcx: ty::ctxt, t: ty::t) -> ty::t {
+ ret tuplify_cbox_ty(tcx, t, ty::mk_type(tcx));
+}
+
+// As tuplify_box_ty(), but allows the caller to specify what type of type
+// descr is embedded in the box (ty::type vs ty::send_type). This is useful
+// for unique closure boxes, hence the name "cbox_ty" (closure box type).
+fn tuplify_cbox_ty(tcx: ty::ctxt, t: ty::t, tydesc_t: ty::t) -> ty::t {
+ let ptr = ty::mk_ptr(tcx, {ty: ty::mk_nil(tcx), mut: ast::imm});
+ ret ty::mk_tup(tcx, [ty::mk_uint(tcx), tydesc_t,
+ ptr, ptr,
+ t]);
+}
+
+fn T_box_header_fields(cx: @crate_ctxt) -> [TypeRef] {
+ let ptr = T_ptr(T_i8());
+ ret [cx.int_type, T_ptr(cx.tydesc_type), ptr, ptr];
+}
+
+fn T_box_header(cx: @crate_ctxt) -> TypeRef {
+ ret T_struct(T_box_header_fields(cx));
+}
+
fn T_box(cx: @crate_ctxt, t: TypeRef) -> TypeRef {
- ret T_struct([cx.int_type, t]);
+ ret T_struct(T_box_header_fields(cx) + [t]);
+}
+
+fn T_opaque_box(cx: @crate_ctxt) -> TypeRef {
+ ret T_box(cx, T_i8());
+}
+
+fn T_opaque_box_ptr(cx: @crate_ctxt) -> TypeRef {
+ ret T_ptr(T_opaque_box(cx));
}
fn T_port(cx: @crate_ctxt, _t: TypeRef) -> TypeRef {
fn T_typaram_ptr(tn: type_names) -> TypeRef { ret T_ptr(T_typaram(tn)); }
fn T_opaque_cbox_ptr(cx: @crate_ctxt) -> TypeRef {
- let s = "*cbox";
- alt name_has_type(cx.tn, s) { some(t) { ret t; } _ {} }
- let t = T_ptr(T_struct([cx.int_type,
- T_ptr(cx.tydesc_type),
- T_i8() /* represents closed over tydescs
- and data go here; see trans_closure.rs*/
- ]));
- associate_type(cx.tn, s, t);
- ret t;
+ // closures look like boxes (even when they are fn~ or fn&)
+ // see trans_closure.rs
+ ret T_opaque_box_ptr(cx);
}
fn T_enum_variant(cx: @crate_ctxt) -> TypeRef {
{|buf| llvm::LLVMAddGlobal(cx.llmod, val_ty(sc), buf) });
llvm::LLVMSetInitializer(g, sc);
llvm::LLVMSetGlobalConstant(g, True);
- llvm::LLVMSetLinkage(g, lib::llvm::LLVMInternalLinkage as llvm::Linkage);
+ lib::llvm::SetLinkage(g, lib::llvm::InternalLinkage);
ret g;
}
});
llvm::LLVMSetInitializer(llglobal, llshape);
llvm::LLVMSetGlobalConstant(llglobal, True);
- llvm::LLVMSetLinkage(llglobal,
- lib::llvm::LLVMInternalLinkage as llvm::Linkage);
+ lib::llvm::SetLinkage(llglobal, lib::llvm::InternalLinkage);
ret llvm::LLVMConstPointerCast(llglobal, T_ptr(T_i8()));
}
h
}
+// Used to identify cached monomorphized functions
+// FIXME[mono] don't count different boxes as different types
+type mono_id = @{def: ast::def_id, substs: [ty::t], dicts: [dict_id]};
+fn hash_mono_id(&&mi: mono_id) -> uint {
+ let h = syntax::ast_util::hash_def_id(mi.def);
+ for ty in mi.substs { h = (h << 2u) + ty; }
+ for dict in mi.dicts { h = (h << 2u) + hash_dict_id(dict); }
+ h
+}
+
fn umax(cx: @block_ctxt, a: ValueRef, b: ValueRef) -> ValueRef {
- let cond = build::ICmp(cx, lib::llvm::LLVMIntULT, a, b);
+ let cond = build::ICmp(cx, lib::llvm::IntULT, a, b);
ret build::Select(cx, cond, b, a);
}
fn umin(cx: @block_ctxt, a: ValueRef, b: ValueRef) -> ValueRef {
- let cond = build::ICmp(cx, lib::llvm::LLVMIntULT, a, b);
+ let cond = build::ICmp(cx, lib::llvm::IntULT, a, b);
ret build::Select(cx, cond, a, b);
}
ret build::And(cx, bumped, build::Not(cx, mask));
}
+fn path_str(p: path) -> str {
+ let r = "", first = true;
+ for e in p {
+ alt e { ast_map::path_name(s) | ast_map::path_mod(s) {
+ if first { first = false; }
+ else { r += "::"; }
+ r += s;
+ } }
+ }
+ r
+}
+
+fn node_id_type(bcx: @block_ctxt, id: ast::node_id) -> ty::t {
+ let tcx = bcx_tcx(bcx);
+ let t = ty::node_id_to_type(tcx, id);
+ alt bcx.fcx.param_substs {
+ some(s) { ty::substitute_type_params(tcx, s, t) }
+ _ { t }
+ }
+}
+fn expr_ty(bcx: @block_ctxt, ex: @ast::expr) -> ty::t {
+ node_id_type(bcx, ex.id)
+}
+
//
// Local Variables:
// mode: rust
import base::*;
import common::*;
import build::*;
+import driver::session::session;
import option::{some, none};
import syntax::{ast, ast_util};
import metadata::csearch;
import back::{link, abi};
import lib::llvm::llvm;
-import llvm::{ValueRef, TypeRef, LLVMGetParam};
+import lib::llvm::{ValueRef, TypeRef};
+import lib::llvm::llvm::LLVMGetParam;
+import ast_map::{path, path_mod, path_name};
// Translation functionality related to impls and ifaces
//
// annotates notes with information about the methods and dicts that
// are referenced (ccx.method_map and ccx.dict_map).
-fn trans_impl(cx: @local_ctxt, name: ast::ident, methods: [@ast::method],
- id: ast::node_id, tps: [ast::ty_param]) {
- let sub_cx = extend_path(cx, name);
+fn trans_impl(ccx: @crate_ctxt, path: path, name: ast::ident,
+ methods: [@ast::method], id: ast::node_id,
+ tps: [ast::ty_param]) {
+ let sub_path = path + [path_name(name)];
for m in methods {
- alt cx.ccx.item_ids.find(m.id) {
+ alt ccx.item_ids.find(m.id) {
some(llfn) {
- trans_fn(extend_path(sub_cx, m.ident), m.span, m.decl, m.body,
- llfn, impl_self(ty::node_id_to_monotype(cx.ccx.tcx, id)),
- tps + m.tps, m.id);
+ trans_fn(ccx, sub_path + [path_name(m.ident)], m.decl, m.body,
+ llfn, impl_self(ty::node_id_to_type(ccx.tcx, id)),
+ tps + m.tps, none, m.id);
+ }
+ _ {
+ ccx.tcx.sess.bug("Unbound id in trans_impl");
}
}
}
fn trans_self_arg(bcx: @block_ctxt, base: @ast::expr) -> result {
let tz = [], tr = [];
- let basety = ty::expr_ty(bcx_tcx(bcx), base);
- let {bcx, val} = trans_arg_expr(bcx, {mode: ast::by_ref, ty: basety},
+ let basety = expr_ty(bcx, base);
+ let m_by_ref = ast::expl(ast::by_ref);
+ let {bcx, val} = trans_arg_expr(bcx, {mode: m_by_ref, ty: basety},
T_ptr(type_of_or_i8(bcx, basety)), tz,
tr, base);
rslt(bcx, PointerCast(bcx, val, T_opaque_cbox_ptr(bcx_ccx(bcx))))
-> lval_maybe_callee {
let tcx = bcx_tcx(bcx);
let {bcx, val} = trans_temp_expr(bcx, base);
- let box_body = GEPi(bcx, val, [0, abi::box_rc_field_body]);
+ let box_body = GEPi(bcx, val, [0, abi::box_field_body]);
let dict = Load(bcx, PointerCast(bcx, GEPi(bcx, box_body, [0, 1]),
T_ptr(T_ptr(T_dict()))));
// FIXME[impl] I doubt this is alignment-safe
let self = PointerCast(bcx, GEPi(bcx, box_body, [0, 2]),
T_opaque_cbox_ptr(bcx_ccx(bcx)));
- let iface_id = alt ty::struct(tcx, ty::expr_ty(tcx, base)) {
+ let iface_id = alt ty::struct(tcx, expr_ty(bcx, base)) {
ty::ty_iface(did, _) { did }
+ // precondition
+ _ { bcx_tcx(bcx).sess.span_bug(base.span, "base has non-iface type \
+ in trans_iface_callee"); }
};
trans_vtable_callee(bcx, self, dict, callee_id, iface_id, n_method)
}
ccx.item_symbols.insert(id, name);
}
-fn trans_wrapper(ccx: @crate_ctxt, pt: [ast::ident], llfty: TypeRef,
+fn trans_wrapper(ccx: @crate_ctxt, pt: path, llfty: TypeRef,
fill: fn(ValueRef, @block_ctxt) -> @block_ctxt)
-> ValueRef {
- let lcx = @{path: pt, module_path: [], ccx: ccx};
let name = link::mangle_internal_name_by_path(ccx, pt);
let llfn = decl_internal_cdecl_fn(ccx.llmod, name, llfty);
- let fcx = new_fn_ctxt(lcx, llfn);
- let bcx = new_top_block_ctxt(fcx), lltop = bcx.llbb;
+ let fcx = new_fn_ctxt(ccx, [], llfn, none);
+ let bcx = new_top_block_ctxt(fcx, none), lltop = bcx.llbb;
let bcx = fill(llfn, bcx);
build_return(bcx);
finish_fn(fcx, lltop);
ret llfn;
}
-fn trans_impl_wrapper(ccx: @crate_ctxt, pt: [ast::ident],
+fn trans_impl_wrapper(ccx: @crate_ctxt, pt: path,
extra_tps: [ty::param_bounds], real_fn: ValueRef)
-> ValueRef {
let {inputs: real_args, output: real_ret} =
})
}
-fn trans_impl_vtable(ccx: @crate_ctxt, pt: [ast::ident],
+fn trans_impl_vtable(ccx: @crate_ctxt, pt: path,
iface_id: ast::def_id, ms: [@ast::method],
tps: [ast::ty_param], it: @ast::item) {
- let new_pt = pt + [it.ident + int::str(it.id), "wrap"];
+ let new_pt = pt + [path_name(it.ident), path_name(int::str(it.id)),
+ path_name("wrap")];
let extra_tps = vec::map(tps, {|p| param_bounds(ccx, p)});
let ptrs = vec::map(*ty::iface_methods(ccx.tcx, iface_id), {|im|
alt vec::find(ms, {|m| m.ident == im.ident}) {
some(m) {
let target = ccx.item_ids.get(m.id);
- trans_impl_wrapper(ccx, new_pt + [m.ident], extra_tps, target)
+ trans_impl_wrapper(ccx, new_pt + [path_name(m.ident)], extra_tps,
+ target)
+ }
+ _ {
+ ccx.tcx.sess.span_bug(it.span, "No matching method \
+ in trans_impl_vtable");
}
}
});
- let s = link::mangle_internal_name_by_path(ccx, new_pt + ["!vtable"]);
+ let s = link::mangle_internal_name_by_path(
+ ccx, new_pt + [path_name("!vtable")]);
trans_vtable(ccx, it.id, s, ptrs);
}
-fn trans_iface_wrapper(ccx: @crate_ctxt, pt: [ast::ident], m: ty::method,
+fn trans_iface_wrapper(ccx: @crate_ctxt, pt: path, m: ty::method,
n: uint) -> ValueRef {
let {llty: llfty, _} = wrapper_fn_ty(ccx, T_ptr(T_i8()), m);
trans_wrapper(ccx, pt, llfty, {|llfn, bcx|
let self = Load(bcx, PointerCast(bcx,
LLVMGetParam(llfn, 2u as c_uint),
T_ptr(T_opaque_iface_ptr(ccx))));
- let boxed = GEPi(bcx, self, [0, abi::box_rc_field_body]);
+ let boxed = GEPi(bcx, self, [0, abi::box_field_body]);
let dict = Load(bcx, PointerCast(bcx, GEPi(bcx, boxed, [0, 1]),
T_ptr(T_ptr(T_dict()))));
let vtable = PointerCast(bcx, Load(bcx, GEPi(bcx, dict, [0, 0])),
})
}
-fn trans_iface_vtable(ccx: @crate_ctxt, pt: [ast::ident], it: @ast::item) {
- let new_pt = pt + [it.ident + int::str(it.id)];
+fn trans_iface_vtable(ccx: @crate_ctxt, pt: path, it: @ast::item) {
+ let new_pt = pt + [path_name(it.ident), path_name(int::str(it.id))];
let i_did = ast_util::local_def(it.id), i = 0u;
let ptrs = vec::map(*ty::iface_methods(ccx.tcx, i_did), {|m|
- let w = trans_iface_wrapper(ccx, new_pt + [m.ident], m, i);
+ let w = trans_iface_wrapper(ccx, new_pt + [path_name(m.ident)], m, i);
i += 1u;
w
});
- let s = link::mangle_internal_name_by_path(ccx, new_pt + ["!vtable"]);
+ let s = link::mangle_internal_name_by_path(
+ ccx, new_pt + [path_name("!vtable")]);
trans_vtable(ccx, it.id, s, ptrs);
}
d_params += [dict_param_dict(dict_id(tcx, origs[orig]))];
orig += 1u;
}
+ _ {
+ tcx.sess.bug("Someone forgot to document an invariant in \
+ dict_id");
+ }
}
}
}
typeck::dict_iface(did) {
@{def: did, params: []}
}
+ _ {
+ tcx.sess.bug("Unexpected dict_param in dict_id");
+ }
}
}
});
llvm::LLVMSetGlobalConstant(gvar, lib::llvm::True);
llvm::LLVMSetInitializer(gvar, ptrs);
- llvm::LLVMSetLinkage(gvar,
- lib::llvm::LLVMInternalLinkage as llvm::Linkage);
+ lib::llvm::SetLinkage(gvar, lib::llvm::InternalLinkage);
let cast = llvm::LLVMConstPointerCast(gvar, T_ptr(T_dict()));
ccx.dicts.insert(id, cast);
cast
typeck::dict_iface(did) {
{bcx: bcx, ptrs: [get_vtable(ccx, did)]}
}
+ _ {
+ bcx_tcx(bcx).sess.bug("Unexpected dict_param in get_dict_ptrs");
+ }
}
}
fn trans_cast(bcx: @block_ctxt, val: @ast::expr, id: ast::node_id, dest: dest)
-> @block_ctxt {
let ccx = bcx_ccx(bcx), tcx = ccx.tcx;
- let val_ty = ty::expr_ty(tcx, val);
+ let val_ty = expr_ty(bcx, val);
let {bcx, val: dict} = get_dict(bcx, ccx.dict_map.get(id)[0]);
let body_ty = ty::mk_tup(tcx, [ty::mk_type(tcx), ty::mk_type(tcx),
val_ty]);
import vec;
import option::none;
import syntax::ast;
-import lib::llvm::llvm::{ValueRef, TypeRef};
+import driver::session::session;
+import lib::llvm::{ValueRef, TypeRef};
import back::abi;
import base::{call_memmove, trans_shared_malloc, type_of_or_i8,
INIT, copy_val, load_if_immediate, get_tydesc,
- node_id_type, new_sub_block_ctxt, do_spill_noroot,
+ new_sub_block_ctxt, do_spill_noroot,
dest};
import shape::{llsize_of, size_of};
import build::*;
}
ret bcx;
}
- let vec_ty = node_id_type(bcx_ccx(bcx), id);
+ let vec_ty = node_id_type(bcx, id);
let {bcx: bcx,
val: vptr,
llunitsz: llunitsz,
let ccx = bcx_ccx(cx);
let unit_ty = ty::sequence_element_type(bcx_tcx(cx), vec_ty);
let dynamic = ty::type_has_dynamic_size(bcx_tcx(cx), unit_ty);
- let (lhsptr, rhs) = !dynamic ? (lhsptr, rhs) :
- (PointerCast(cx, lhsptr, T_ptr(T_ptr(ccx.opaque_vec_type))),
- PointerCast(cx, rhs, T_ptr(ccx.opaque_vec_type)));
+ let (lhsptr, rhs) =
+ if !dynamic {
+ (lhsptr, rhs)
+ } else {
+ (PointerCast(cx, lhsptr, T_ptr(T_ptr(ccx.opaque_vec_type))),
+ PointerCast(cx, rhs, T_ptr(ccx.opaque_vec_type)))
+ };
let strings = alt ty::struct(bcx_tcx(cx), vec_ty) {
ty::ty_str { true }
ty::ty_vec(_) { false }
+ _ {
+ // precondition?
+ bcx_tcx(cx).sess.bug("Bad argument type in trans_append");
+ }
};
let {bcx: bcx, val: unit_sz} = size_of(cx, unit_ty);
let llunitty = type_of_or_i8(cx, unit_ty);
let lhs = Load(bcx, lhsptr);
- let self_append = ICmp(bcx, lib::llvm::LLVMIntEQ, lhs, rhs);
+ let self_append = ICmp(bcx, lib::llvm::IntEQ, lhs, rhs);
let lfill = get_fill(bcx, lhs);
let rfill = get_fill(bcx, rhs);
let new_fill = Add(bcx, lfill, rfill);
copy_val(bcx, INIT, write_ptr,
load_if_immediate(bcx, addr, unit_ty),
unit_ty);
- let incr = dynamic ? unit_sz : C_int(ccx, 1);
+ let incr = if dynamic {
+ unit_sz
+ } else {
+ C_int(ccx, 1)
+ };
Store(bcx, InBoundsGEP(bcx, write_ptr, [incr]),
write_ptr_ptr);
ret bcx;
let ccx = bcx_ccx(bcx);
let strings = alt ty::struct(bcx_tcx(bcx), vec_ty) {
ty::ty_str { true }
- ty::ty_vec(_) { false }
+ _ { false }
};
let unit_ty = ty::sequence_element_type(bcx_tcx(bcx), vec_ty);
let llunitty = type_of_or_i8(bcx, unit_ty);
let bcx = copy_val(bcx, INIT, write_ptr,
load_if_immediate(bcx, addr, unit_ty), unit_ty);
let incr =
- ty::type_has_dynamic_size(bcx_tcx(bcx), unit_ty) ?
- llunitsz : C_int(ccx, 1);
+ if ty::type_has_dynamic_size(bcx_tcx(bcx), unit_ty) {
+ llunitsz
+ } else {
+ C_int(ccx, 1)
+ };
Store(bcx, InBoundsGEP(bcx, write_ptr, [incr]),
write_ptr_ptr);
ret bcx;
Br(bcx, header_cx.llbb);
let data_ptr = Phi(header_cx, val_ty(data_ptr), [data_ptr], [bcx.llbb]);
let not_yet_at_end =
- ICmp(header_cx, lib::llvm::LLVMIntULT, data_ptr, data_end_ptr);
+ ICmp(header_cx, lib::llvm::IntULT, data_ptr, data_end_ptr);
let body_cx = new_sub_block_ctxt(header_cx, "iter_vec_loop_body");
let next_cx = new_sub_block_ctxt(header_cx, "iter_vec_next");
CondBr(header_cx, not_yet_at_end, body_cx.llbb, next_cx.llbb);
import syntax::ast;
-import lib::llvm::llvm::ValueRef;
+import lib::llvm::ValueRef;
import common::*;
import build::*;
import base::{
trans_shared_malloc,
type_of_inner,
- node_id_type,
INIT,
trans_shared_free,
drop_ty,
fn trans_uniq(bcx: @block_ctxt, contents: @ast::expr,
node_id: ast::node_id, dest: dest) -> @block_ctxt {
- let uniq_ty = node_id_type(bcx_ccx(bcx), node_id);
+ let uniq_ty = node_id_type(bcx, node_id);
check type_is_unique_box(bcx, uniq_ty);
let {bcx, val: llptr} = alloc_uniq(bcx, uniq_ty);
add_clean_free(bcx, llptr, true);
alt ty::struct(bcx_tcx(bcx), t) {
ty::ty_uniq({ty: ct, _}) { ct }
+ _ { std::util::unreachable(); }
}
}
ccx.node_anns[i] = a;
}
-fn get_ts_ann(ccx: crate_ctxt, i: node_id) -> option::t<ts_ann> {
+fn get_ts_ann(ccx: crate_ctxt, i: node_id) -> option<ts_ann> {
if i as uint < vec::len(*ccx.node_anns) {
ret some::<ts_ann>(ccx.node_anns[i]);
} else { ret none::<ts_ann>; }
}
}
-fn node_id_to_def(ccx: crate_ctxt, id: node_id) -> option::t<def> {
+fn node_id_to_def(ccx: crate_ctxt, id: node_id) -> option<def> {
ret ccx.tcx.def_map.find(id);
}
ret @respan(p.span,
carg_ident({ident: p.node.idents[0], node: id.node}));
}
- some(_) {
- tcx.sess.bug("exprs_to_constr_args: non-local variable " +
- "as pred arg");
+ some(what) {
+ tcx.sess.span_bug(e.span,
+ #fmt("exprs_to_constr_args: non-local variable %? \
+ as pred arg", what));
}
none {
- tcx.sess.bug("exprs_to_constr_args: NONE " + "as pred arg");
+ tcx.sess.span_bug(e.span,
+ "exprs_to_constr_args: unbound id as pred arg");
}
}
}
fn find_instance_(pattern: [constr_arg_general_<inst>], descs: [pred_args]) ->
- option::t<uint> {
+ option<uint> {
for d: pred_args in descs {
if pred_args_matches(pattern, d) { ret some(d.node.bit_num); }
}
rslt
}
-fn find_in_subst(id: node_id, s: subst) -> option::t<inst> {
+fn find_in_subst(id: node_id, s: subst) -> option<inst> {
for p: {from: inst, to: inst} in s {
if id == p.from.node { ret some(p.to); }
}
}
}
-fn local_node_id_to_def(fcx: fn_ctxt, i: node_id) -> option::t<def> {
+fn local_node_id_to_def(fcx: fn_ctxt, i: node_id) -> option<def> {
fcx.ccx.tcx.def_map.find(i)
}
-fn local_node_id_to_def_id(fcx: fn_ctxt, i: node_id) -> option::t<def_id> {
+fn local_node_id_to_def_id(fcx: fn_ctxt, i: node_id) -> option<def_id> {
alt local_node_id_to_def(fcx, i) {
some(def_local(id, _)) | some(def_arg(id, _)) | some(def_binding(id)) |
some(def_upvar(id, _, _)) {
}
fn local_node_id_to_local_def_id(fcx: fn_ctxt, i: node_id) ->
- option::t<node_id> {
+ option<node_id> {
alt local_node_id_to_def_id(fcx, i) {
some(did) { some(did.node) }
_ { none }
ret respan(c.span, tconstr);
}
-type binding = {lhs: [inst], rhs: option::t<initializer>};
+type binding = {lhs: [inst], rhs: option<initializer>};
fn local_to_bindings(tcx: ty::ctxt, loc: @local) -> binding {
let lhs = [];
- pat_bindings(pat_util::normalize_pat(tcx, loc.node.pat)) {|p|
- let ident = alt p.node
- { pat_ident(name, _) { path_to_ident(name) } };
- lhs += [{ident: ident, node: p.id}];
+ pat_bindings(pat_util::normalize_pat(tcx, loc.node.pat)) {|p_id, _s, name|
+ lhs += [{ident: path_to_ident(name), node: p_id}];
};
{lhs: lhs, rhs: loc.node.init}
}
ret rslt;
}
-fn callee_modes(fcx: fn_ctxt, callee: node_id) -> [ty::mode] {
+fn callee_modes(fcx: fn_ctxt, callee: node_id) -> [mode] {
let ty =
ty::type_autoderef(fcx.ccx.tcx,
ty::node_id_to_type(fcx.ccx.tcx, callee));
}
fn callee_arg_init_ops(fcx: fn_ctxt, callee: node_id) -> [init_op] {
- fn mode_to_op(m: ty::mode) -> init_op {
- alt m { by_move { init_move } _ { init_assign } }
+ vec::map(callee_modes(fcx, callee)) {|m|
+ alt ty::resolved_mode(fcx.ccx.tcx, m) {
+ by_move { init_move }
+ by_copy | by_ref | by_val | by_mut_ref { init_assign }
+ }
}
- vec::map(callee_modes(fcx, callee), mode_to_op)
}
fn anon_bindings(ops: [init_op], es: [@expr]) -> [binding] {
type ctxt = {cs: @mutable [sp_constr], tcx: ty::ctxt};
fn collect_local(loc: @local, cx: ctxt, v: visit::vt<ctxt>) {
- pat_bindings(pat_util::normalize_pat(cx.tcx, loc.node.pat)) {|p|
- let ident = alt p.node
- { pat_ident(id, _) { path_to_ident(id) } };
- log(debug, "collect_local: pushing " + ident);;
- *cx.cs += [respan(loc.span, ninit(p.id, ident))];
+ pat_bindings(pat_util::normalize_pat(cx.tcx, loc.node.pat))
+ {|p_id, _s, id|
+ *cx.cs += [respan(loc.span, ninit(p_id, path_to_ident(id)))];
};
visit::visit_local(loc, cx, v);
}
expr_check(_, ch) { *cx.cs += [expr_to_constr(cx.tcx, ch)]; }
expr_if_check(ex, _, _) { *cx.cs += [expr_to_constr(cx.tcx, ex)]; }
-
-
-
-
// If it's a call, generate appropriate instances of the
// call's constraints.
expr_call(operator, operands, _) {
import syntax::codemap::span;
import driver::session::session;
-
fn find_pre_post_mod(_m: _mod) -> _mod {
#debug("implement find_pre_post_mod!");
fail;
fn find_pre_post_item(ccx: crate_ctxt, i: item) {
alt i.node {
item_const(_, e) {
- // make a fake fcx
- let v: @mutable [node_id] = @mutable [];
- let fake_fcx =
- {
- // just bogus
- enclosing:
- {constrs: new_def_hash::<constraint>(),
- num_constraints: 0u,
- cf: return_val,
- i_return: ninit(0, ""),
- i_diverge: ninit(0, ""),
- used_vars: v},
- id: 0,
- name: "",
- ccx: ccx};
- find_pre_post_expr(fake_fcx, e);
+ // do nothing -- item_consts don't refer to local vars
}
item_fn(_, _, body) {
assert (ccx.fm.contains_key(i.id));
ccx: ccx};
find_pre_post_fn(fcx, body);
}
+ item_class(_,_,_,_) {
+ fail "find_pre_post_item: implement item_class";
+ }
item_impl(_, _, _, ms) { for m in ms { find_pre_post_method(ccx, m); } }
}
}
id: node_id) {
find_pre_post_expr(fcx, index);
find_pre_post_block(fcx, body);
- pat_bindings(normalize_pat(fcx.ccx.tcx, l.node.pat)) {|p|
- let ident = alt p.node
- { pat_ident(id, _) { path_to_ident(id) } };
- let v_init = ninit(p.id, ident);
+ pat_bindings(normalize_pat(fcx.ccx.tcx, l.node.pat)) {|p_id, _s, n|
+ let v_init = ninit(p_id, path_to_ident(n));
relax_precond_block(fcx, bit_num(fcx, v_init) as node_id, body);
// Hack: for-loop index variables are frequently ignored,
// so we pretend they're used
- use_var(fcx, p.id);
+ use_var(fcx, p_id);
};
let loop_precond =
// annotation for an if-expression with consequent conseq
// and alternative maybe_alt
fn join_then_else(fcx: fn_ctxt, antec: @expr, conseq: blk,
- maybe_alt: option::t<@expr>, id: node_id, chck: if_ty) {
+ maybe_alt: option<@expr>, id: node_id, chck: if_ty) {
find_pre_post_expr(fcx, antec);
find_pre_post_block(fcx, conseq);
alt maybe_alt {
}
}
-fn forget_args_moved_in(fcx: fn_ctxt, parent: @expr, modes: [ty::mode],
+fn forget_args_moved_in(fcx: fn_ctxt, parent: @expr, modes: [mode],
operands: [@expr]) {
- let i = 0u;
- for mode: ty::mode in modes {
- if mode == by_move {
- forget_in_postcond(fcx, parent.id, operands[i].id);
+ vec::iteri(modes) {|i,mode|
+ alt ty::resolved_mode(fcx.ccx.tcx, mode) {
+ by_move { forget_in_postcond(fcx, parent.id, operands[i].id); }
+ by_ref | by_val | by_mut_ref | by_copy { }
}
- i += 1u;
}
}
expr_if(antec, conseq, maybe_alt) {
join_then_else(fcx, antec, conseq, maybe_alt, e.id, plain_if);
}
- expr_ternary(_, _, _) { find_pre_post_expr(fcx, ternary_to_if(e)); }
expr_binary(bop, l, r) {
if lazy_binop(bop) {
find_pre_post_expr(fcx, l);
let cmodes = callee_modes(fcx, operator.id);
let modes = [];
let i = 0;
- for expr_opt: option::t<@expr> in maybe_args {
+ for expr_opt: option<@expr> in maybe_args {
alt expr_opt {
none {/* no-op */ }
some(expr) { modes += [cmodes[i]]; args += [expr]; }
/* LHS always becomes initialized,
whether or not this is a move */
find_pre_post_expr(fcx, an_init.expr);
- pat_bindings(alocal.node.pat) {|p|
- copy_pre_post(fcx.ccx, p.id, an_init.expr);
+ pat_bindings(alocal.node.pat) {|p_id, _s, _n|
+ copy_pre_post(fcx.ccx, p_id, an_init.expr);
};
/* Inherit ann from initializer, and add var being
initialized to the postcondition */
}
pat_bindings(normalize_pat(fcx.ccx.tcx, alocal.node.pat))
- {|pat|
- /* FIXME: This won't be necessary when typestate
- works well enough for pat_bindings to return a
- refinement-typed thing. */
- let ident = alt pat.node
- { pat_ident(n, _) { path_to_ident(n) } };
+ {|p_id, _s, n|
+ let ident = path_to_ident(n);
alt p {
some(p) {
copy_in_postcond(fcx, id,
- {ident: ident, node: pat.id},
+ {ident: ident, node: p_id},
{ident:
path_to_ident(p),
node: an_init.expr.id},
}
none { }
}
- gen(fcx, id, ninit(pat.id, ident));
+ gen(fcx, id, ninit(p_id, ident));
};
if an_init.op == init_move && is_path(an_init.expr) {
/* Include the LHSs too, since those aren't in the
postconds of the RHSs themselves */
pat_bindings(normalize_pat(fcx.ccx.tcx, alocal.node.pat))
- {|pat|
- // FIXME
- // Generalize this pattern? map_if_ident...
- alt pat.node {
- pat_ident(n, _) {
+ {|pat_id, _s, n|
set_in_postcond(bit_num(fcx,
- ninit(pat.id, path_to_ident(n))), prev_pp);
- }
- }
- };
+ ninit(pat_id, path_to_ident(n))), prev_pp);
+ };
copy_pre_post_(fcx.ccx, id, prev_pp.precondition,
prev_pp.postcondition);
}
none {
- pat_bindings(alocal.node.pat) {|p|
- clear_pp(node_id_to_ts_ann(fcx.ccx, p.id).conditions);
+ pat_bindings(alocal.node.pat) {|p_id, _s, _n|
+ clear_pp(node_id_to_ts_ann(fcx.ccx, p_id).conditions);
};
clear_pp(node_id_to_ts_ann(fcx.ccx, id).conditions);
}
}
fn find_pre_post_state_sub(fcx: fn_ctxt, pres: prestate, e: @expr,
- parent: node_id, c: option::t<tsconstr>) -> bool {
+ parent: node_id, c: option<tsconstr>) -> bool {
let changed = find_pre_post_state_expr(fcx, pres, e);
changed = set_prestate_ann(fcx.ccx, parent, pres) || changed;
fn find_pre_post_state_loop(fcx: fn_ctxt, pres: prestate, l: @local,
index: @expr, body: blk, id: node_id) -> bool {
+ // I'm confused about this -- how does the poststate for the body
+ // ever grow larger? It seems like it can't?
let loop_pres = intersect_states(pres, block_poststate(fcx.ccx, body));
let changed =
// Make sure the index vars are considered initialized
// in the body
let index_post = tritv_clone(expr_poststate(fcx.ccx, index));
- pat_bindings(pat_util::normalize_pat(fcx.ccx.tcx, l.node.pat)) {|p|
- let ident = alt p.node
- { pat_ident(name, _) { path_to_ident(name) } };
- set_in_poststate_ident(fcx, p.id, ident, index_post);
+ pat_bindings(pat_util::normalize_pat(fcx.ccx.tcx, l.node.pat))
+ {|p_id, _s, n|
+ set_in_poststate_ident(fcx, p_id, path_to_ident(n), index_post);
};
changed |= find_pre_post_state_block(fcx, index_post, body);
}
fn join_then_else(fcx: fn_ctxt, antec: @expr, conseq: blk,
- maybe_alt: option::t<@expr>, id: node_id, chk: if_ty,
+ maybe_alt: option<@expr>, id: node_id, chk: if_ty,
pres: prestate) -> bool {
let changed =
set_prestate_ann(fcx.ccx, id, pres) |
let callee_ops = callee_arg_init_ops(fcx, operator.id);
let ops = [];
let i = 0;
- for a_opt: option::t<@expr> in maybe_args {
+ for a_opt: option<@expr> in maybe_args {
alt a_opt {
none {/* no-op */ }
some(a) { ops += [callee_ops[i]]; args += [a]; }
ret join_then_else(fcx, antec, conseq, maybe_alt, e.id, plain_if,
pres);
}
- expr_ternary(_, _, _) {
- ret find_pre_post_state_expr(fcx, pres, ternary_to_if(e));
- }
expr_binary(bop, l, r) {
if lazy_binop(bop) {
let changed = find_pre_post_state_expr(fcx, pres, l);
import syntax::util::interner;
import util::ppaux::ty_to_str;
import util::ppaux::ty_constr_to_str;
-import util::ppaux::mode_str;
import syntax::print::pprust::*;
-export node_id_to_monotype;
export node_id_to_type;
export node_id_to_type_params;
-export node_id_to_ty_param_substs_opt_and_ty;
export arg;
export args_eq;
export ast_constr_to_constr;
export field;
export field_idx;
export get_field;
+export get_fields;
export fm_general;
export get_element_type;
export idx_nil;
export mk_mach_int;
export mk_mach_uint;
export mk_mach_float;
-export mk_native;
export mk_nil;
export mk_iface;
export mk_res;
export mk_opaque_closure_ptr;
export mk_named;
export gen_ty;
-export mode;
export mt;
export node_type_table;
export pat_ty;
export enum_variants;
export iface_methods, store_iface_methods, impl_iface;
export enum_variant_with_id;
-export ty_param_substs_opt_and_ty;
export ty_param_bounds_and_ty;
export ty_bool;
export ty_bot;
export ty_int;
export ty_str;
export ty_vec;
-export ty_native;
export ty_nil;
export ty_iface;
export ty_res;
export ty_rec;
export ty_enum;
export ty_tup;
-export ty_type;
export ty_send_type;
export ty_uint;
export ty_uniq;
export ty_named;
export same_type;
export ty_var_id;
-export ty_param_substs_opt_and_ty_to_monotype;
export ty_fn_args;
export type_constr;
export type_contains_params;
export type_allows_implicit_copy;
export type_is_integral;
export type_is_numeric;
-export type_is_native;
export type_is_nil;
export type_is_pod;
export type_is_scalar;
export type_structurally_contains_uniques;
export type_autoderef;
export type_param;
+export canon_mode;
+export resolved_mode;
+export arg_mode;
+export unify_mode;
+export set_default_mode;
export unify;
export variant_info;
export walk_ty;
export occurs_check_fails;
export closure_kind;
-export ck_any;
export ck_block;
export ck_box;
export ck_uniq;
export param_bound, param_bounds, bound_copy, bound_send, bound_iface;
export param_bounds_to_kind;
+export default_arg_mode_for_ty;
// Data types
-type arg = {mode: mode, ty: t};
+// Note: after typeck, you should use resolved_mode() to convert this mode
+// into an rmode, which will take into account the results of mode inference.
+type arg = {mode: ast::mode, ty: t};
type field = {ident: ast::ident, mt: mt};
sess: session::session,
def_map: resolve::def_map,
node_types: node_type_table,
+ node_type_substs: hashmap<node_id, [t]>,
items: ast_map::map,
freevars: freevars::freevar_map,
tcache: type_cache,
short_names_cache: hashmap<t, @str>,
needs_drop_cache: hashmap<t, bool>,
kind_cache: hashmap<t, kind>,
- ast_ty_to_ty_cache: hashmap<@ast::ty, option::t<t>>,
+ ast_ty_to_ty_cache: hashmap<@ast::ty, option<t>>,
enum_var_cache: hashmap<def_id, @[variant_info]>,
iface_method_cache: hashmap<def_id, @[method]>,
- ty_param_bounds: hashmap<ast::node_id, param_bounds>};
+ ty_param_bounds: hashmap<ast::node_id, param_bounds>,
+ inferred_modes: hashmap<ast::node_id, ast::mode>};
type ty_ctxt = ctxt;
type t = uint;
enum closure_kind {
- ck_any,
ck_block,
ck_box,
ck_uniq,
ty_type, // type_desc*
ty_send_type, // type_desc* that has been cloned into exchange heap
- ty_native(def_id),
ty_constr(t, [@type_constr]),
ty_opaque_closure_ptr(closure_kind), // ptr to env for fn, fn@, fn~
ty_named(t, @str),
type type_store = interner::interner<@raw_t>;
-// substs is a list of actuals that correspond to ty's
-// formal parameters
-type ty_param_substs_opt_and_ty = {substs: option::t<[ty::t]>, ty: ty::t};
-
-type node_type_table =
- @smallintmap::smallintmap<ty::ty_param_substs_opt_and_ty>;
+type node_type_table = @smallintmap::smallintmap<t>;
fn populate_type_store(cx: ctxt) {
intern(cx, ty_nil);
fn mk_ctxt(s: session::session, dm: resolve::def_map, amap: ast_map::map,
freevars: freevars::freevar_map) -> ctxt {
- let ntt: node_type_table =
- @smallintmap::mk::<ty::ty_param_substs_opt_and_ty>();
fn eq_raw_ty(&&a: @raw_t, &&b: @raw_t) -> bool {
ret a.hash == b.hash && a.struct == b.struct;
}
@{ts: ts,
sess: s,
def_map: dm,
- node_types: ntt,
+ node_types: @smallintmap::mk(),
+ node_type_substs: map::new_int_hash(),
items: amap,
freevars: freevars,
tcache: new_def_hash(),
map::mk_hashmap(ast_util::hash_ty, ast_util::eq_ty),
enum_var_cache: new_def_hash(),
iface_method_cache: new_def_hash(),
- ty_param_bounds: map::new_int_hash()};
+ ty_param_bounds: map::new_int_hash(),
+ inferred_modes: map::new_int_hash()};
populate_type_store(cx);
ret cx;
}
}
alt st {
ty_nil | ty_bot | ty_bool | ty_int(_) | ty_float(_) | ty_uint(_) |
- ty_str | ty_send_type | ty_type | ty_native(_) |
- ty_opaque_closure_ptr(_) {
- /* no-op */
- }
+ ty_str | ty_type | ty_send_type | ty_opaque_closure_ptr(_) {}
ty_param(_, _) { has_params = true; }
ty_var(_) { has_vars = true; }
ty_enum(_, tys) | ty_iface(_, tys) {
fn mk_send_type(_cx: ctxt) -> t { ret idx_send_type; }
-fn mk_native(cx: ctxt, did: def_id) -> t { ret gen_ty(cx, ty_native(did)); }
-
fn mk_opaque_closure_ptr(cx: ctxt, ck: closure_kind) -> t {
ret gen_ty(cx, ty_opaque_closure_ptr(ck));
}
interner::get(*cx.ts, typ).struct
}
-// Returns struact(cx, typ) but replaces all occurences of platform
+// Returns struct(cx, typ) but replaces all occurences of platform
// dependent primitive types with their machine type equivalent
pure fn mach_struct(cx: ctxt, cfg: @session::config, typ: t) -> sty {
alt interner::get(*cx.ts, typ).struct {
}
}
-pure fn ty_name(cx: ctxt, typ: t) -> option::t<@str> {
+pure fn ty_name(cx: ctxt, typ: t) -> option<@str> {
alt interner::get(*cx.ts, typ).struct {
ty_named(_, n) { some(n) }
_ { none }
}
}
-fn walk_ty(cx: ctxt, ty: t, walker: fn(t)) {
+fn default_arg_mode_for_ty(tcx: ty::ctxt, ty: ty::t) -> ast::rmode {
+ assert !ty::type_contains_vars(tcx, ty);
+ if ty::type_is_immediate(tcx, ty) { ast::by_val }
+ else { ast::by_ref }
+}
+
+fn walk_ty(cx: ctxt, ty: t, f: fn(t)) {
alt struct(cx, ty) {
ty_nil | ty_bot | ty_bool | ty_int(_) | ty_uint(_) | ty_float(_) |
- ty_str | ty_send_type | ty_type | ty_native(_) |
- ty_opaque_closure_ptr(_) {
- /* no-op */
- }
- ty_box(tm) | ty_vec(tm) | ty_ptr(tm) { walk_ty(cx, tm.ty, walker); }
+ ty_str | ty_send_type | ty_type |
+ ty_opaque_closure_ptr(_) | ty_var(_) | ty_param(_, _) {}
+ ty_box(tm) | ty_vec(tm) | ty_ptr(tm) { walk_ty(cx, tm.ty, f); }
ty_enum(_, subtys) | ty_iface(_, subtys) {
- for subty: t in subtys { walk_ty(cx, subty, walker); }
+ for subty: t in subtys { walk_ty(cx, subty, f); }
}
ty_rec(fields) {
- for fl: field in fields { walk_ty(cx, fl.mt.ty, walker); }
+ for fl: field in fields { walk_ty(cx, fl.mt.ty, f); }
}
- ty_tup(ts) { for tt in ts { walk_ty(cx, tt, walker); } }
- ty_fn(f) {
- for a: arg in f.inputs { walk_ty(cx, a.ty, walker); }
- walk_ty(cx, f.output, walker);
+ ty_tup(ts) { for tt in ts { walk_ty(cx, tt, f); } }
+ ty_fn(ft) {
+ for a: arg in ft.inputs { walk_ty(cx, a.ty, f); }
+ walk_ty(cx, ft.output, f);
}
ty_res(_, sub, tps) {
- walk_ty(cx, sub, walker);
- for tp: t in tps { walk_ty(cx, tp, walker); }
+ walk_ty(cx, sub, f);
+ for tp: t in tps { walk_ty(cx, tp, f); }
}
- ty_constr(sub, _) { walk_ty(cx, sub, walker); }
- ty_var(_) {/* no-op */ }
- ty_param(_, _) {/* no-op */ }
- ty_uniq(tm) { walk_ty(cx, tm.ty, walker); }
+ ty_constr(sub, _) { walk_ty(cx, sub, f); }
+ ty_uniq(tm) { walk_ty(cx, tm.ty, f); }
+ // precondition?
+ ty_named(_,_) { cx.sess.bug("walk_ty: should not see a ty_named \
+ here"); }
}
- walker(ty);
+ f(ty);
}
enum fold_mode {
fn fold_ty(cx: ctxt, fld: fold_mode, ty_0: t) -> t {
let ty = ty_0;
- // Fast paths.
+ // Fast paths.
alt fld {
fm_var(_) { if !type_contains_vars(cx, ty) { ret ty; } }
fm_param(_) { if !type_contains_params(cx, ty) { ret ty; } }
fm_general(_) {/* no fast path */ }
}
+
alt interner::get(*cx.ts, ty).struct {
ty_nil | ty_bot | ty_bool | ty_int(_) | ty_uint(_) | ty_float(_) |
- ty_str | ty_send_type | ty_type | ty_native(_) |
- ty_opaque_closure_ptr(_) {
- /* no-op */
- }
+ ty_str | ty_type | ty_send_type | ty_opaque_closure_ptr(_) {}
ty_box(tm) {
ty = mk_box(cx, {ty: fold_ty(cx, fld, tm.ty), mut: tm.mut});
}
pure fn type_is_scalar(cx: ctxt, ty: t) -> bool {
alt struct(cx, ty) {
ty_nil | ty_bool | ty_int(_) | ty_float(_) | ty_uint(_) |
- ty_send_type | ty_type | ty_native(_) | ty_ptr(_) { true }
+ ty_send_type | ty_type | ty_ptr(_) { true }
_ { false }
}
}
// FIXME maybe inline this for speed?
fn type_is_immediate(cx: ctxt, ty: t) -> bool {
ret type_is_scalar(cx, ty) || type_is_boxed(cx, ty) ||
- type_is_unique(cx, ty) || type_is_native(cx, ty);
+ type_is_unique(cx, ty);
}
fn type_needs_drop(cx: ctxt, ty: t) -> bool {
let result = alt struct(cx, ty) {
// scalar types
ty_nil | ty_bot | ty_bool | ty_int(_) | ty_float(_) | ty_uint(_) |
- ty_type | ty_native(_) | ty_ptr(_) { false }
+ ty_type | ty_ptr(_) { false }
ty_rec(flds) {
for f in flds { if type_needs_drop(cx, f.mt.ty) { accum = true; } }
accum
let result = alt struct(cx, ty) {
// Scalar and unique types are sendable
ty_nil | ty_bot | ty_bool | ty_int(_) | ty_uint(_) | ty_float(_) |
- ty_native(_) | ty_ptr(_) |
- ty_send_type | ty_str { kind_sendable }
+ ty_ptr(_) | ty_send_type | ty_str { kind_sendable }
ty_type { kind_copyable }
ty_fn(f) { proto_kind(f.proto) }
ty_opaque_closure_ptr(ck_block) { kind_noncopyable }
param_bounds_to_kind(cx.ty_param_bounds.get(did.node))
}
ty_constr(t, _) { type_kind(cx, t) }
+ _ { cx.sess.bug("Bad type in type_kind"); }
};
cx.kind_cache.insert(ty, result);
ret result;
}
-// FIXME: should we just return true for native types in
-// type_is_scalar?
-fn type_is_native(cx: ctxt, ty: t) -> bool {
- alt struct(cx, ty) { ty_native(_) { ret true; } _ { ret false; } }
-}
-
fn type_structurally_contains(cx: ctxt, ty: t, test: fn(sty) -> bool) ->
bool {
let sty = struct(cx, ty);
alt struct(cx, ty) {
// Scalar types
ty_nil | ty_bot | ty_bool | ty_int(_) | ty_float(_) | ty_uint(_) |
- ty_send_type | ty_type | ty_native(_) | ty_ptr(_) { result = true; }
+ ty_send_type | ty_type | ty_ptr(_) { result = true; }
// Boxed types
ty_str | ty_box(_) | ty_uniq(_) | ty_vec(_) | ty_fn(_) |
ty_iface(_, _) { result = false; }
}
ty_constr(subt, _) { result = type_is_pod(cx, subt); }
ty_var(_) {
- fail "ty_var in type_is_pod";
+ cx.sess.bug("ty_var in type_is_pod");
}
ty_param(_, _) { result = false; }
+ ty_opaque_closure_ptr(_) { result = true; }
+ ty_named(_,_) {
+ cx.sess.bug("ty_named in type_is_pod");
+ }
+
}
ret result;
}
}
-fn type_param(cx: ctxt, ty: t) -> option::t<uint> {
+fn type_param(cx: ctxt, ty: t) -> option<uint> {
alt struct(cx, ty) {
ty_param(id, _) { ret some(id); }
_ {/* fall through */ }
// Returns a vec of all the type variables
// occurring in t. It may contain duplicates.
fn vars_in_type(cx: ctxt, ty: t) -> [int] {
- fn collect_var(cx: ctxt, vars: @mutable [int], ty: t) {
- alt struct(cx, ty) { ty_var(v) { *vars += [v]; } _ { } }
+ let rslt = [];
+ walk_ty(cx, ty) {|ty|
+ alt struct(cx, ty) { ty_var(v) { rslt += [v]; } _ { } }
}
- let rslt: @mutable [int] = @mutable [];
- walk_ty(cx, ty) {|t| collect_var(cx, rslt, t)}
- // Works because of a "convenient" bug that lets us
- // return a mutable vec as if it's immutable
- ret *rslt;
+ rslt
}
fn type_autoderef(cx: ctxt, t: ty::t) -> ty::t {
ty_var(v) { ret hash_uint(30u, v as uint); }
ty_param(pid, _) { ret hash_uint(31u, pid); }
ty_type { ret 32u; }
- ty_native(did) { ret hash_def(33u, did); }
ty_bot { ret 34u; }
ty_ptr(mt) { ret hash_subty(35u, mt.ty); }
ty_res(did, sub, tps) {
ret true;
}
-// Type lookups
-fn node_id_to_ty_param_substs_opt_and_ty(cx: ctxt, id: ast::node_id) ->
- ty_param_substs_opt_and_ty {
- // Pull out the node type table.
- alt smallintmap::find(*cx.node_types, id as uint) {
- none {
- cx.sess.bug("node_id_to_ty_param_substs_opt_and_ty() called on " +
- "an untyped node (" + int::to_str(id, 10u) +
- ")");
- }
- some(tpot) { ret tpot; }
- }
-}
-
fn node_id_to_type(cx: ctxt, id: ast::node_id) -> t {
- ret node_id_to_ty_param_substs_opt_and_ty(cx, id).ty;
+ smallintmap::get(*cx.node_types, id as uint)
}
fn node_id_to_type_params(cx: ctxt, id: ast::node_id) -> [t] {
- alt node_id_to_ty_param_substs_opt_and_ty(cx, id).substs {
+ alt cx.node_type_substs.find(id) {
none { ret []; }
- some(tps) { ret tps; }
+ some(ts) { ret ts; }
}
}
fn node_id_has_type_params(cx: ctxt, id: ast::node_id) -> bool {
- ret vec::len(node_id_to_type_params(cx, id)) > 0u;
-}
-
-
-// Returns a type with type parameter substitutions performed if applicable
-fn ty_param_substs_opt_and_ty_to_monotype(cx: ctxt,
- tpot: ty_param_substs_opt_and_ty) ->
- t {
- alt tpot.substs {
- none { ret tpot.ty; }
- some(tps) { ret substitute_type_params(cx, tps, tpot.ty); }
- }
+ ret cx.node_type_substs.contains_key(id);
}
-
-// Returns the type of an annotation, with type parameter substitutions
-// performed if applicable
-fn node_id_to_monotype(cx: ctxt, id: ast::node_id) -> t {
- let tpot = node_id_to_ty_param_substs_opt_and_ty(cx, id);
- ret ty_param_substs_opt_and_ty_to_monotype(cx, tpot);
-}
-
-
// Returns the number of distinct type parameters in the given type.
fn count_ty_params(cx: ctxt, ty: t) -> uint {
- fn counter(cx: ctxt, param_indices: @mutable [uint], ty: t) {
- alt struct(cx, ty) {
+ let param_indices = [];
+ walk_ty(cx, ty) {|t|
+ alt struct(cx, t) {
ty_param(param_idx, _) {
- let seen = false;
- for other_param_idx: uint in *param_indices {
- if param_idx == other_param_idx { seen = true; }
+ if !vec::any(param_indices, {|i| i == param_idx}) {
+ param_indices += [param_idx];
}
- if !seen { *param_indices += [param_idx]; }
}
- _ {/* fall through */ }
+ _ {}
}
}
- let param_indices: @mutable [uint] = @mutable [];
- let f = bind counter(cx, param_indices, _);
- walk_ty(cx, ty, f);
- ret vec::len::<uint>(*param_indices);
+ vec::len(param_indices)
}
fn type_contains_vars(cx: ctxt, typ: t) -> bool {
// Returns the type of a pattern as a monotype. Like @expr_ty, this function
// doesn't provide type parameter substitutions.
fn pat_ty(cx: ctxt, pat: @ast::pat) -> t {
- ret node_id_to_monotype(cx, pat.id);
+ ret node_id_to_type(cx, pat.id);
}
// instead of "fn(t) -> T with T = int". If this isn't what you want, see
// expr_ty_params_and_ty() below.
fn expr_ty(cx: ctxt, expr: @ast::expr) -> t {
- ret node_id_to_monotype(cx, expr.id);
+ ret node_id_to_type(cx, expr.id);
}
fn expr_ty_params_and_ty(cx: ctxt, expr: @ast::expr) -> {params: [t], ty: t} {
}
}
-fn field_idx(id: ast::ident, fields: [field]) -> option::t<uint> {
+fn field_idx(id: ast::ident, fields: [field]) -> option<uint> {
let i = 0u;
for f in fields { if f.ident == id { ret some(i); } i += 1u; }
ret none;
}
fn get_field(tcx: ctxt, rec_ty: t, id: ast::ident) -> field {
+ alt vec::find(get_fields(tcx, rec_ty), {|f| str::eq(f.ident, id) }) {
+ some(f) { ret f; }
+ _ { tcx.sess.bug(#fmt("get_field: bad field id %s", id)); }
+ }
+}
+
+// TODO: could have a precondition instead of failing
+fn get_fields(tcx:ctxt, rec_ty:t) -> [field] {
alt struct(tcx, rec_ty) {
- ty_rec(fields) {
- alt vec::find(fields, {|f| str::eq(f.ident, id) }) {
- some(f) { ret f; }
- }
- }
+ ty::ty_rec(fields) { fields }
+ _ { tcx.sess.bug("get_fields called on non-record type"); }
}
}
-fn method_idx(id: ast::ident, meths: [method]) -> option::t<uint> {
+fn method_idx(id: ast::ident, meths: [method]) -> option<uint> {
let i = 0u;
for m in meths { if m.ident == id { ret some(i); } i += 1u; }
ret none;
fn sort_methods(meths: [method]) -> [method] {
fn method_lteq(a: method, b: method) -> bool {
- ret str::lteq(a.ident, b.ident);
+ ret str::le(a.ident, b.ident);
}
ret std::sort::merge_sort(bind method_lteq(_, _), meths);
}
-fn occurs_check_fails(tcx: ctxt, sp: option::t<span>, vid: int, rt: t) ->
+fn occurs_check_fails(tcx: ctxt, sp: option<span>, vid: int, rt: t) ->
bool {
if !type_contains_vars(tcx, rt) {
// Fast path
} else { ret false; }
}
+// Maintains a little union-set tree for inferred modes. `canon()` returns
+// the current head value for `m0`.
+fn canon<T:copy>(tbl: hashmap<ast::node_id, ast::inferable<T>>,
+ m0: ast::inferable<T>) -> ast::inferable<T> {
+ alt m0 {
+ ast::infer(id) {
+ alt tbl.find(id) {
+ none { m0 }
+ some(m1) {
+ let cm1 = canon(tbl, m1);
+ // path compression:
+ if cm1 != m1 { tbl.insert(id, cm1); }
+ cm1
+ }
+ }
+ }
+ _ { m0 }
+ }
+}
+
+// Maintains a little union-set tree for inferred modes. `resolve_mode()`
+// returns the current head value for `m0`.
+fn canon_mode(cx: ctxt, m0: ast::mode) -> ast::mode {
+ canon(cx.inferred_modes, m0)
+}
+
+// Returns the head value for mode, failing if `m` was a infer(_) that
+// was never inferred. This should be safe for use after typeck.
+fn resolved_mode(cx: ctxt, m: ast::mode) -> ast::rmode {
+ alt canon_mode(cx, m) {
+ ast::infer(_) {
+ cx.sess.bug(#fmt["mode %? was never resolved", m]);
+ }
+ ast::expl(m0) { m0 }
+ }
+}
+
+fn arg_mode(cx: ctxt, a: arg) -> ast::rmode { ty::resolved_mode(cx, a.mode) }
+
+// Unifies `m1` and `m2`. Returns unified value or failure code.
+fn unify_mode(cx: ctxt, m1: ast::mode, m2: ast::mode)
+ -> result::t<ast::mode, type_err> {
+ alt (canon_mode(cx, m1), canon_mode(cx, m2)) {
+ (m1, m2) if (m1 == m2) {
+ result::ok(m1)
+ }
+ (ast::infer(id1), ast::infer(id2)) {
+ cx.inferred_modes.insert(id2, m1);
+ result::ok(m1)
+ }
+ (ast::infer(id), m) | (m, ast::infer(id)) {
+ cx.inferred_modes.insert(id, m);
+ result::ok(m1)
+ }
+ (m1, m2) {
+ result::err(terr_mode_mismatch(m1, m2))
+ }
+ }
+}
+
+// If `m` was never unified, unifies it with `m_def`. Returns the final value
+// for `m`.
+fn set_default_mode(cx: ctxt, m: ast::mode, m_def: ast::rmode) {
+ alt canon_mode(cx, m) {
+ ast::infer(id) {
+ cx.inferred_modes.insert(id, ast::expl(m_def));
+ }
+ ast::expl(_) { }
+ }
+}
+
// Type unification via Robinson's algorithm (Robinson 1965). Implemented as
// described in Hoder and Voronkov:
//
variance: variance) -> union_result {
let vb = alt cx.st {
in_bindings(vb) { vb }
+ _ { cx.tcx.sess.bug("Someone forgot to document an invariant \
+ in union"); }
};
ufind::grow(vb.sets, math::max(set_a, set_b) + 1u);
let root_a = ufind::find(vb.sets, set_a);
}
);
-
alt smallintmap::find(vb.types, root_a) {
none {
alt smallintmap::find(vb.types, root_b) {
fn record_var_binding(
cx: @ctxt, key: int, typ: t, variance: variance) -> result {
- let vb = alt cx.st { in_bindings(vb) { vb } };
+ let vb = alt cx.st { in_bindings(vb) { vb }
+ _ { cx.tcx.sess.bug("Someone forgot to document an invariant \
+ in record_var_binding"); }
+ };
ufind::grow(vb.sets, (key as uint) + 1u);
let root = ufind::find(vb.sets, key as uint);
let result_type = typ;
// Unifies two mutability flags.
fn unify_mut(expected: ast::mutability, actual: ast::mutability,
variance: variance) ->
- option::t<(ast::mutability, variance)> {
+ option<(ast::mutability, variance)> {
// If you're unifying on something mutable then we have to
// be invariant on the inner type
ret none;
}
fn unify_fn_proto(e_proto: ast::proto, a_proto: ast::proto,
- variance: variance) -> option::t<result> {
+ variance: variance) -> option<result> {
// Prototypes form a diamond-shaped partial order:
//
// block
for expected_input in e_args {
let actual_input = a_args[i];
i += 1u;
+
// Unify the result modes.
- let result_mode = if expected_input.mode == ast::mode_infer {
- actual_input.mode
- } else if actual_input.mode == ast::mode_infer {
- expected_input.mode
- } else if expected_input.mode != actual_input.mode {
- ret either::left(ures_err(terr_mode_mismatch(
- expected_input.mode, actual_input.mode)));
- } else { expected_input.mode };
+ let result_mode =
+ alt unify_mode(cx.tcx, expected_input.mode,
+ actual_input.mode) {
+ result::err(err) { ret either::left(ures_err(err)); }
+ result::ok(m) { m }
+ };
alt unify_step(cx, expected_input.ty, actual_input.ty,
variance) {
ret ures_ok(actual);
}
ty::ty_bool | ty::ty_int(_) | ty_uint(_) | ty_float(_) |
- ty::ty_str | ty::ty_type | ty::ty_send_type {
+ ty::ty_str | ty::ty_send_type {
ret struct_cmp(cx, expected, actual);
}
- ty::ty_native(ex_id) {
- alt struct(cx.tcx, actual) {
- ty_native(act_id) {
- if ex_id.crate == act_id.crate && ex_id.node == act_id.node {
- ret ures_ok(actual);
- } else { ret ures_err(terr_mismatch); }
- }
- _ { ret ures_err(terr_mismatch); }
- }
- }
ty::ty_param(expected_n, _) {
alt struct(cx.tcx, actual) {
ty::ty_param(actual_n, _) if expected_n == actual_n {
}
}
}
+ _ { cx.tcx.sess.bug("unify: unexpected type"); }
}
}
fn unify(expected: t, actual: t, st: unify_style,
while i < vec::len::<ufind::node>(vb.sets.nodes) {
let sets = "";
let j = 0u;
- while j < vec::len::<option::t<uint>>(vb.sets.nodes) {
+ while j < vec::len::<option<uint>>(vb.sets.nodes) {
if ufind::find(vb.sets, j) == i { sets += #fmt[" %u", j]; }
j += 1u;
}
// Takes an optional span - complain about occurs check violations
// iff the span is present (so that if we already know we're going
// to error anyway, we don't complain)
- fn fixup_vars(tcx: ty_ctxt, sp: option::t<span>, vb: @var_bindings,
+ fn fixup_vars(tcx: ty_ctxt, sp: option<span>, vb: @var_bindings,
typ: t) -> fixup_result {
- fn subst_vars(tcx: ty_ctxt, sp: option::t<span>, vb: @var_bindings,
- unresolved: @mutable option::t<int>,
+ fn subst_vars(tcx: ty_ctxt, sp: option<span>, vb: @var_bindings,
+ unresolved: @mutable option<int>,
vars_seen: std::list::list<int>, vid: int) -> t {
// Should really return a fixup_result instead of a t, but fold_ty
// doesn't allow returning anything but a t.
some(var_id) { ret fix_err(var_id); }
}
}
- fn resolve_type_var(tcx: ty_ctxt, sp: option::t<span>, vb: @var_bindings,
+ fn resolve_type_var(tcx: ty_ctxt, sp: option<span>, vb: @var_bindings,
vid: int) -> fixup_result {
if vid as uint >= ufind::set_count(vb.sets) { ret fix_err(vid); }
let root_id = ufind::find(vb.sets, vid as uint);
}
terr_arg_count { ret "incorrect number of function parameters"; }
terr_mode_mismatch(e_mode, a_mode) {
- ret "expected argument mode " + mode_str(e_mode) + " but found " +
- mode_str(a_mode);
+ ret "expected argument mode " + mode_to_str(e_mode) + " but found " +
+ mode_to_str(a_mode);
}
terr_constr_len(e_len, a_len) {
ret "Expected a type with " + uint::str(e_len) +
// Replaces type parameters in the given type using the given list of
// substitions.
fn substitute_type_params(cx: ctxt, substs: [ty::t], typ: t) -> t {
-
if !type_contains_params(cx, typ) { ret typ; }
// Precondition? idx < vec::len(substs)
fn substituter(_cx: ctxt, substs: @[ty::t], idx: uint, _did: def_id)
ast::def_mod(_) | ast::def_const(_) |
ast::def_arg(_, _) | ast::def_local(_, _) | ast::def_upvar(_, _, _) |
ast::def_ty_param(_, _) | ast::def_binding(_) | ast::def_use(_) |
- ast::def_native_ty(_) | ast::def_self(_) | ast::def_ty(_) { false }
+ ast::def_self(_) | ast::def_ty(_) { false }
ast::def_fn(_, _) | ast::def_variant(_, _) { true }
+ _ { false } // ????
}
}
result
}
-fn impl_iface(cx: ctxt, id: ast::def_id) -> option::t<t> {
+fn impl_iface(cx: ctxt, id: ast::def_id) -> option<t> {
if id.crate == ast::local_crate {
option::map(cx.tcache.find(id), {|it| it.ty})
} else {
// check the disr_expr if it exists), this code should likely be
// moved there to avoid having to call eval_const_expr twice.
alt cx.items.get(id.node) {
- ast_map::node_item(@{node: ast::item_enum(variants, _), _}) {
+ ast_map::node_item(@{node: ast::item_enum(variants, _), _}, _) {
let disr_val = -1;
@vec::map(variants, {|variant|
- let ctor_ty = node_id_to_monotype(cx, variant.node.id);
+ let ctor_ty = node_id_to_type(cx, variant.node.id);
let arg_tys = if vec::len(variant.node.args) > 0u {
vec::map(ty_fn_args(cx, ctor_ty), {|a| a.ty})
} else { [] };
// FIXME: issue #1417
disr_val = alt syntax::ast_util::eval_const_expr(ex) {
ast_util::const_int(val) {val as int}
+ _ { cx.sess.bug("tag_variants: bad disr expr"); }
}
}
_ {disr_val += 1;}
}
})
}
+ _ { cx.sess.bug("tag_variants: id not bound to an enum"); }
}
};
cx.enum_var_cache.insert(id, result);
// If the given item is in an external crate, looks up its type and adds it to
// the type cache. Returns the type parameters and type.
fn lookup_item_type(cx: ctxt, did: ast::def_id) -> ty_param_bounds_and_ty {
- if did.crate == ast::local_crate {
- // The item is in this crate. The caller should have added it to the
- // type cache already; we simply return it.
- ret cx.tcache.get(did);
- }
alt cx.tcache.find(did) {
some(tpt) { ret tpt; }
none {
+ // The item is in this crate. The caller should have added it to the
+ // type cache already
+ assert did.crate != ast::local_crate;
let tyt = csearch::get_type(cx, did);
cx.tcache.insert(did, tyt);
ret tyt;
import middle::ty;
import middle::ty::{node_id_to_type, arg, block_ty,
expr_ty, field, node_type_table, mk_nil,
- ty_param_substs_opt_and_ty, ty_param_bounds_and_ty};
+ ty_param_bounds_and_ty};
import util::ppaux::ty_to_str;
import middle::ty::unify::{ures_ok, ures_err, fix_ok, fix_err};
import core::{int, vec, str, option};
var_bindings: @ty::unify::var_bindings,
locals: hashmap<ast::node_id, int>,
next_var_id: @mutable int,
- mutable fixups: [ast::node_id],
ccx: @crate_ctxt};
some(self_impl(impl_t)) {
ret {bounds: @[], ty: impl_t};
}
+ none {
+ fcx.ccx.tcx.sess.span_bug(sp, "def_self with no self_info");
+ }
}
}
ast::def_fn(id, _) | ast::def_const(id) |
// Instantiates the given path, which must refer to an item with the given
// number of type parameters and type.
fn instantiate_path(fcx: @fn_ctxt, pth: @ast::path,
- tpt: ty_param_bounds_and_ty, sp: span)
- -> ty_param_substs_opt_and_ty {
+ tpt: ty_param_bounds_and_ty, sp: span,
+ id: ast::node_id) {
let ty_param_count = vec::len(*tpt.bounds);
- let vars = vec::init_fn(ty_param_count, {|_i| next_ty_var(fcx)});
let ty_substs_len = vec::len(pth.node.types);
if ty_substs_len > 0u {
- let param_var_len = vec::len(vars);
- if param_var_len == 0u {
+ if ty_param_count == 0u {
fcx.ccx.tcx.sess.span_fatal
(sp, "this item does not take type parameters");
- } else if ty_substs_len > param_var_len {
+ } else if ty_substs_len > ty_param_count {
fcx.ccx.tcx.sess.span_fatal
(sp, "too many type parameter provided for this item");
- } else if ty_substs_len < param_var_len {
+ } else if ty_substs_len < ty_param_count {
fcx.ccx.tcx.sess.span_fatal
(sp, "not enough type parameters provided for this item");
}
- vec::iter2(pth.node.types, vars) {|sub, var|
- let ty_subst = ast_ty_to_ty_crate(fcx.ccx, sub);
- demand::simple(fcx, pth.span, var, ty_subst);
- }
if ty_param_count == 0u {
fcx.ccx.tcx.sess.span_fatal(
sp, "this item does not take type parameters");
}
+ let substs = vec::map(pth.node.types, {|aty|
+ ast_ty_to_ty_crate(fcx.ccx, aty)
+ });
+ write_ty_substs(fcx.ccx.tcx, id, tpt.ty, substs);
+ } else if ty_param_count > 0u {
+ let vars = vec::init_fn(ty_param_count, {|_i| next_ty_var(fcx)});
+ write_ty_substs(fcx.ccx.tcx, id, tpt.ty, vars);
+ } else {
+ write_ty(fcx.ccx.tcx, id, tpt.ty);
}
- {substs: some(vars), ty: tpt.ty}
}
// Type tests
// Returns the one-level-deep structure of the given type or none if it
// is not known yet.
fn structure_of_maybe(fcx: @fn_ctxt, _sp: span, typ: ty::t) ->
- option::t<ty::sty> {
+ option<ty::sty> {
let r =
ty::unify::resolve_type_structure(fcx.ccx.tcx, fcx.var_bindings, typ);
ret alt r {
ret ty::type_is_c_like_enum(fcx.ccx.tcx, typ_s);
}
-// Parses the programmer's textual representation of a type into our internal
-// notion of a type. `getter` is a function that returns the type
-// corresponding to a definition ID:
-fn default_arg_mode_for_ty(tcx: ty::ctxt, m: ast::mode,
- ty: ty::t) -> ast::mode {
- alt m {
- ast::mode_infer {
- alt ty::struct(tcx, ty) {
- ty::ty_var(_) { ast::mode_infer }
- _ {
- if ty::type_is_immediate(tcx, ty) { ast::by_val }
- else { ast::by_ref }
- }
- }
- }
- _ { m }
- }
-}
-
enum mode { m_collect, m_check, m_check_tyvar(@fn_ctxt), }
+// Parses the programmer's textual representation of a type into our
+// internal notion of a type. `getter` is a function that returns the type
+// corresponding to a definition ID:
fn ast_ty_to_ty(tcx: ty::ctxt, mode: mode, &&ast_ty: @ast::ty) -> ty::t {
fn getter(tcx: ty::ctxt, mode: mode, id: ast::def_id)
-> ty::ty_param_bounds_and_ty {
if id.crate != ast::local_crate { csearch::get_type(tcx, id) }
else {
alt tcx.items.find(id.node) {
- some(ast_map::node_item(item)) {
+ some(ast_map::node_item(item, _)) {
ty_of_item(tcx, mode, item)
}
- some(ast_map::node_native_item(native_item)) {
+ some(ast_map::node_native_item(native_item, _)) {
ty_of_native_item(tcx, mode, native_item)
}
+ _ {
+ tcx.sess.bug("Unexpected sort of item in ast_ty_to_ty");
+ }
}
}
}
}
}
- fn ast_arg_to_arg(tcx: ty::ctxt, mode: mode, arg: ast::arg)
- -> {mode: ty::mode, ty: ty::t} {
- let ty = ast_ty_to_ty(tcx, mode, arg.ty);
- ret {mode: default_arg_mode_for_ty(tcx, arg.mode, ty), ty: ty};
- }
alt tcx.ast_ty_to_ty_cache.find(ast_ty) {
some(some(ty)) { ret ty; }
some(none) {
some(ast::def_ty(id)) {
typ = instantiate(tcx, ast_ty.span, mode, id, path.node.types);
}
- some(ast::def_native_ty(id)) { typ = getter(tcx, mode, id).ty; }
some(ast::def_ty_param(id, n)) {
typ = ty::mk_param(tcx, n, id);
}
"found `ty_infer` in unexpected place"); }
}
}
+ ast::ty_mac(_) {
+ tcx.sess.span_bug(ast_ty.span,
+ "found `ty_mac` in unexpected place");
+ }
}
tcx.ast_ty_to_ty_cache.insert(ast_ty, some(typ));
ret typ;
ret tpt;
}
ast::item_iface(tps, ms) {
- let s_tp = vec::len(tps) - 1u;
- tcx.ty_param_bounds.insert(tps[s_tp].id, @[]);
- let {bounds, params} = mk_ty_params(tcx, vec::slice(tps, 0u, s_tp));
- let t = ty::mk_named(tcx, ty::mk_iface(tcx, local_def(it.id), params),
+ let {bounds, params} = mk_ty_params(tcx, tps);
+ let t = ty::mk_named(tcx, ty::mk_iface(tcx, local_def(it.id),
+ params),
@it.ident);
let tpt = {bounds: bounds, ty: t};
tcx.tcache.insert(local_def(it.id), tpt);
ret tpt;
}
+ ast::item_class(_,_,_,_) {
+ fail "ty_of_item: implement item_class";
+ }
+ ast::item_impl(_, _, _, _) | ast::item_mod(_) |
+ ast::item_native_mod(_) { fail; }
}
}
fn ty_of_native_item(tcx: ty::ctxt, mode: mode, it: @ast::native_item)
ret ty_of_native_fn_decl(tcx, mode, fn_decl, params,
local_def(it.id));
}
- ast::native_item_ty {
- alt tcx.tcache.find(local_def(it.id)) {
- some(tpt) { ret tpt; }
- none { }
- }
- let t = ty::mk_native(tcx, local_def(it.id));
- let t = ty::mk_named(tcx, t, @it.ident);
- let tpt = {bounds: @[], ty: t};
- tcx.tcache.insert(local_def(it.id), tpt);
- ret tpt;
- }
}
}
fn ty_of_arg(tcx: ty::ctxt, mode: mode, a: ast::arg) -> ty::arg {
+ fn arg_mode(tcx: ty::ctxt, m: ast::mode, ty: ty::t) -> ast::mode {
+ alt m {
+ ast::infer(_) {
+ alt ty::struct(tcx, ty) {
+ // If the type is not specified, then this must be a fn expr.
+ // Leave the mode as infer(_), it will get inferred based
+ // on constraints elsewhere.
+ ty::ty_var(_) { m }
+
+ // If the type is known, then use the default for that type.
+ // Here we unify m and the default. This should update the
+ // tables in tcx but should never fail, because nothing else
+ // will have been unified with m yet:
+ _ {
+ let m1 = ast::expl(ty::default_arg_mode_for_ty(tcx, ty));
+ result::get(ty::unify_mode(tcx, m, m1))
+ }
+ }
+ }
+ ast::expl(_) { m }
+ }
+ }
+
let ty = ast_ty_to_ty(tcx, mode, a.ty);
- {mode: default_arg_mode_for_ty(tcx, a.mode, ty), ty: ty}
-}
-fn ty_of_fn_decl(tcx: ty::ctxt, mode: mode,
- proto: ast::proto, decl: ast::fn_decl) -> ty::fn_ty {
- let input_tys = [];
- for a: ast::arg in decl.inputs { input_tys += [ty_of_arg(tcx, mode, a)]; }
+ let mode = arg_mode(tcx, a.mode, ty);
+ {mode: mode, ty: ty}
+}
+fn ty_of_fn_decl(tcx: ty::ctxt,
+ mode: mode,
+ proto: ast::proto,
+ decl: ast::fn_decl) -> ty::fn_ty {
+ let input_tys = vec::map(decl.inputs) {|a| ty_of_arg(tcx, mode, a) };
let output_ty = ast_ty_to_ty(tcx, mode, decl.output);
let out_constrs = [];
ty_params: [ast::ty_param], def_id: ast::def_id)
-> ty::ty_param_bounds_and_ty {
let input_tys = [], bounds = ty_param_bounds(tcx, mode, ty_params);
- for a: ast::arg in decl.inputs { input_tys += [ty_of_arg(tcx, mode, a)]; }
+ for a: ast::arg in decl.inputs {
+ input_tys += [ty_of_arg(tcx, mode, a)];
+ }
let output_ty = ast_ty_to_ty(tcx, mode, decl.output);
let t_fn = ty::mk_fn(tcx, {proto: ast::proto_bare,
// A wrapper around ast_ty_to_ty_crate that handles ty_infer.
fn ast_ty_to_ty_crate_infer(ccx: @crate_ctxt, &&ast_ty: @ast::ty) ->
- option::t<ty::t> {
+ option<ty::t> {
alt ast_ty.node {
ast::ty_infer { none }
_ { some(ast_ty_to_ty_crate(ccx, ast_ty)) }
// Functions that write types into the node type table
-mod write {
- fn inner(ntt: node_type_table, node_id: ast::node_id,
- tpot: ty_param_substs_opt_and_ty) {
- smallintmap::insert(*ntt, node_id as uint, tpot);
- }
-
- // Writes a type parameter count and type pair into the node type table.
- fn ty(tcx: ty::ctxt, node_id: ast::node_id,
- tpot: ty_param_substs_opt_and_ty) {
- assert (!ty::type_contains_vars(tcx, tpot.ty));
- inner(tcx.node_types, node_id, tpot);
- }
-
- // Writes a type parameter count and type pair into the node type table.
- // This function allows for the possibility of type variables, which will
- // be rewritten later during the fixup mode.
- fn ty_fixup(fcx: @fn_ctxt, node_id: ast::node_id,
- tpot: ty_param_substs_opt_and_ty) {
- inner(fcx.ccx.tcx.node_types, node_id, tpot);
- if ty::type_contains_vars(fcx.ccx.tcx, tpot.ty) {
- fcx.fixups += [node_id];
- }
- }
-
- // Writes a type with no type parameters into the node type table.
- fn ty_only(tcx: ty::ctxt, node_id: ast::node_id, typ: ty::t) {
- ty(tcx, node_id, {substs: none::<[ty::t]>, ty: typ});
- }
-
- // Writes a type with no type parameters into the node type table. This
- // function allows for the possibility of type variables.
- fn ty_only_fixup(fcx: @fn_ctxt, node_id: ast::node_id, typ: ty::t) {
- ret ty_fixup(fcx, node_id, {substs: none::<[ty::t]>, ty: typ});
- }
-
- // Writes a nil type into the node type table.
- fn nil_ty(tcx: ty::ctxt, node_id: ast::node_id) {
- ret ty(tcx, node_id, {substs: none::<[ty::t]>, ty: ty::mk_nil(tcx)});
- }
-
- // Writes the bottom type into the node type table.
- fn bot_ty(tcx: ty::ctxt, node_id: ast::node_id) {
- ret ty(tcx, node_id, {substs: none::<[ty::t]>, ty: ty::mk_bot(tcx)});
- }
+fn write_ty(tcx: ty::ctxt, node_id: ast::node_id, ty: ty::t) {
+ smallintmap::insert(*tcx.node_types, node_id as uint, ty);
+}
+fn write_substs(tcx: ty::ctxt, node_id: ast::node_id, +substs: [ty::t]) {
+ tcx.node_type_substs.insert(node_id, substs);
+}
+fn write_ty_substs(tcx: ty::ctxt, node_id: ast::node_id, ty: ty::t,
+ +substs: [ty::t]) {
+ let ty = if ty::type_contains_params(tcx, ty) {
+ ty::substitute_type_params(tcx, substs, ty)
+ } else { ty };
+ write_ty(tcx, node_id, ty);
+ write_substs(tcx, node_id, substs);
+}
+fn write_nil(tcx: ty::ctxt, node_id: ast::node_id) {
+ write_ty(tcx, node_id, ty::mk_nil(tcx));
+}
+fn write_bot(tcx: ty::ctxt, node_id: ast::node_id) {
+ write_ty(tcx, node_id, ty::mk_bot(tcx));
}
fn mk_ty_params(tcx: ty::ctxt, atps: [ast::ty_param])
}
fn compare_impl_method(tcx: ty::ctxt, sp: span, impl_m: ty::method,
- impl_tps: uint, if_m: ty::method, substs: [ty::t])
- -> ty::t {
+ impl_tps: uint, if_m: ty::method, substs: [ty::t]) {
if impl_m.tps != if_m.tps {
tcx.sess.span_err(sp, "method `" + if_m.ident +
"` has an incompatible set of type parameters");
- ty::mk_fn(tcx, impl_m.fty)
} else {
let auto_modes = vec::map2(impl_m.fty.inputs, if_m.fty.inputs, {|i, f|
alt ty::struct(tcx, f.ty) {
- ty::ty_param(0u, _) if i.mode == ast::mode_infer {
- {mode: ast::by_ref with i}
+ ty::ty_param(0u, _) {
+ {mode: ast::expl(ast::by_ref) with i}
}
_ { i }
}
tcx.sess.span_err(sp, "method `" + if_m.ident +
"` has an incompatible type: " +
ty::type_err_to_str(err));
- impl_fty
}
- ty::unify::ures_ok(tp) { tp }
+ _ {}
}
}
}
let args: [arg] = [];
for va: ast::variant_arg in variant.node.args {
let arg_ty = ast_ty_to_ty(cx.tcx, m_collect, va.ty);
- args += [{mode: ast::by_copy, ty: arg_ty}];
+ args += [{mode: ast::expl(ast::by_copy), ty: arg_ty}];
}
// FIXME: this will be different for constrained types
ty::mk_fn(cx.tcx,
let tpt = {bounds: ty_param_bounds(cx.tcx, m_collect, ty_params),
ty: result_ty};
cx.tcx.tcache.insert(local_def(variant.node.id), tpt);
- write::ty_only(cx.tcx, variant.node.id, result_ty);
+ write_ty(cx.tcx, variant.node.id, result_ty);
}
}
fn convert(cx: @ctxt, it: @ast::item) {
ast::item_mod(_) | ast::item_native_mod(_) {}
ast::item_enum(variants, ty_params) {
let tpt = ty_of_item(cx.tcx, m_collect, it);
- write::ty_only(cx.tcx, it.id, tpt.ty);
+ write_ty(cx.tcx, it.id, tpt.ty);
get_enum_variant_types(cx, tpt.ty, variants, ty_params);
}
ast::item_impl(tps, ifce, selfty, ms) {
for m in ms {
let bounds = ty_param_bounds(cx.tcx, m_collect, m.tps);
let mty = ty_of_method(cx.tcx, m_collect, m);
- my_methods += [{mty: mty, id: m.id}];
+ my_methods += [mty];
let fty = ty::mk_fn(cx.tcx, mty.fty);
cx.tcx.tcache.insert(local_def(m.id),
{bounds: @(*i_bounds + *bounds),
ty: fty});
- write::ty_only(cx.tcx, m.id, fty);
+ write_ty(cx.tcx, m.id, fty);
}
- let selfty = ast_ty_to_ty(cx.tcx, m_collect, selfty);
- write::ty_only(cx.tcx, it.id, selfty);
+ write_ty(cx.tcx, it.id, ast_ty_to_ty(cx.tcx, m_collect,
+ selfty));
alt ifce {
some(t) {
let iface_ty = ast_ty_to_ty(cx.tcx, m_collect, t);
ty::ty_iface(did, tys) {
for if_m in *ty::iface_methods(cx.tcx, did) {
alt vec::find(my_methods,
- {|m| if_m.ident == m.mty.ident}) {
- some({mty: m, id}) {
- let mt = compare_impl_method(
- cx.tcx, t.span, m, vec::len(tps), if_m,
- tys + [selfty]);
- let old = cx.tcx.tcache.get(local_def(id));
- if old.ty != mt {
- cx.tcx.tcache.insert(local_def(id),
- {bounds: old.bounds,
- ty: mt});
- write::ty_only(cx.tcx, id, mt);
- }
+ {|m| if_m.ident == m.ident}) {
+ some(m) {
+ compare_impl_method(cx.tcx, t.span, m,
+ vec::len(tps), if_m, tys);
}
none {
cx.tcx.sess.span_err(t.span, "missing method `" +
params);
let t_ctor = ty::mk_fn(cx.tcx, {
proto: ast::proto_box,
- inputs: [{mode: ast::by_copy with t_arg}],
+ inputs: [{mode: ast::expl(ast::by_copy) with t_arg}],
output: t_res,
ret_style: ast::return_val, constraints: []
});
inputs: [t_arg], output: ty::mk_nil(cx.tcx),
ret_style: ast::return_val, constraints: []
});
- write::ty_only(cx.tcx, it.id, t_res);
- write::ty_only(cx.tcx, ctor_id, t_ctor);
+ write_ty(cx.tcx, it.id, t_res);
+ write_ty(cx.tcx, ctor_id, t_ctor);
cx.tcx.tcache.insert(local_def(ctor_id),
{bounds: bounds, ty: t_ctor});
- write::ty_only(cx.tcx, dtor_id, t_dtor);
+ write_ty(cx.tcx, dtor_id, t_dtor);
}
ast::item_iface(_, ms) {
let tpt = ty_of_item(cx.tcx, m_collect, it);
- write::ty_only(cx.tcx, it.id, tpt.ty);
+ write_ty(cx.tcx, it.id, tpt.ty);
ty::store_iface_methods(cx.tcx, it.id, @vec::map(ms, {|m|
ty_of_ty_method(cx.tcx, m_collect, m)
}));
// of the item in passing. All we have to do here is to write
// it into the node type table.
let tpt = ty_of_item(cx.tcx, m_collect, it);
- write::ty_only(cx.tcx, it.id, tpt.ty);
+ write_ty(cx.tcx, it.id, tpt.ty);
}
}
}
// table.
let tpt = ty_of_native_item(cx.tcx, m_collect, i);
alt i.node {
- ast::native_item_ty {
- // FIXME: Native types have no annotation. Should they? --pcw
- }
ast::native_item_fn(_, _) {
- write::ty_only(cx.tcx, i.id, tpt.ty);
+ write_ty(cx.tcx, i.id, tpt.ty);
}
}
}
// Type resolution: the phase that finds all the types in the AST with
// unresolved type variables and replaces "ty_var" types with their
// substitutions.
-//
-// TODO: inefficient since not all types have vars in them. It would be better
-// to maintain a list of fixups.
mod writeback {
export resolve_type_vars_in_block;
export resolve_type_vars_in_expr;
fn resolve_type_vars_in_type(fcx: @fn_ctxt, sp: span, typ: ty::t) ->
- option::t<ty::t> {
+ option<ty::t> {
if !ty::type_contains_vars(fcx.ccx.tcx, typ) { ret some(typ); }
alt ty::unify::fixup_vars(fcx.ccx.tcx, some(sp), fcx.var_bindings,
typ) {
}
}
}
- fn resolve_type_vars_for_node(wbcx: wb_ctxt, sp: span, id: ast::node_id) {
- let fcx = wbcx.fcx;
- let tpot = ty::node_id_to_ty_param_substs_opt_and_ty(fcx.ccx.tcx, id);
- let new_ty =
- alt resolve_type_vars_in_type(fcx, sp, tpot.ty) {
- some(t) { t }
- none { wbcx.success = false; ret }
- };
- let new_substs_opt;
- alt tpot.substs {
- none { new_substs_opt = none; }
- some(substs) {
- let new_substs: [ty::t] = [];
- for subst: ty::t in substs {
- alt resolve_type_vars_in_type(fcx, sp, subst) {
- some(t) { new_substs += [t]; }
- none { wbcx.success = false; ret; }
+ fn resolve_type_vars_for_node(wbcx: wb_ctxt, sp: span, id: ast::node_id)
+ -> option<ty::t> {
+ let fcx = wbcx.fcx, tcx = fcx.ccx.tcx;
+ alt resolve_type_vars_in_type(fcx, sp, ty::node_id_to_type(tcx, id)) {
+ none {
+ wbcx.success = false;
+ ret none;
+ }
+
+ some(t) {
+ write_ty(tcx, id, t);
+ alt tcx.node_type_substs.find(id) {
+ some(substs) {
+ let new_substs = [];
+ for subst: ty::t in substs {
+ alt resolve_type_vars_in_type(fcx, sp, subst) {
+ some(t) { new_substs += [t]; }
+ none { wbcx.success = false; ret none; }
+ }
}
+ write_substs(tcx, id, new_substs);
+ }
+ none {}
}
- new_substs_opt = some(new_substs);
+ ret some(t);
}
}
- write::ty(fcx.ccx.tcx, id, {substs: new_substs_opt, ty: new_ty});
}
type wb_ctxt =
alt e.node {
ast::expr_fn(_, decl, _, _) |
ast::expr_fn_block(decl, _) {
- for input in decl.inputs {
- resolve_type_vars_for_node(wbcx, e.span, input.id);
+ vec::iter(decl.inputs) {|input|
+ let r_ty = resolve_type_vars_for_node(wbcx, e.span, input.id);
+
+ // Just in case we never constrained the mode to anything,
+ // constrain it to the default for the type in question.
+ alt (r_ty, input.mode) {
+ (some(t), ast::infer(_)) {
+ let tcx = wbcx.fcx.ccx.tcx;
+ let m_def = ty::default_arg_mode_for_ty(tcx, t);
+ ty::set_default_mode(tcx, input.mode, m_def);
+ }
+ _ {}
+ }
}
}
_ { }
ty::unify::resolve_type_var(wbcx.fcx.ccx.tcx, some(l.span),
wbcx.fcx.var_bindings, var_id);
alt fix_rslt {
- fix_ok(lty) { write::ty_only(wbcx.fcx.ccx.tcx, l.node.id, lty); }
+ fix_ok(lty) { write_ty(wbcx.fcx.ccx.tcx, l.node.id, lty); }
fix_err(_) {
wbcx.fcx.ccx.tcx.sess.span_err(l.span,
"cannot determine a type \
decl: ast::fn_decl,
body: ast::blk,
id: ast::node_id,
- old_fcx: option::t<@fn_ctxt>) -> gather_result {
+ old_fcx: option<@fn_ctxt>) -> gather_result {
let {vb: vb, locals: locals, nvi: nvi} =
alt old_fcx {
none {
let tcx = ccx.tcx;
let next_var_id = fn@() -> int { let rv = *nvi; *nvi += 1; ret rv; };
- let assign = fn@(nid: ast::node_id, ty_opt: option::t<ty::t>) {
+ let assign = fn@(nid: ast::node_id, ty_opt: option<ty::t>) {
let var_id = next_var_id();
locals.insert(nid, var_id);
alt ty_opt {
// their types immediately.
fn check_pat(fcx: @fn_ctxt, map: pat_util::pat_id_map, pat: @ast::pat,
expected: ty::t) {
- alt normalize_pat(fcx.ccx.tcx, pat).node {
+ let tcx = fcx.ccx.tcx;
+ alt normalize_pat(tcx, pat).node {
ast::pat_wild {
alt structure_of(fcx, pat.span, expected) {
ty::ty_enum(_, expected_tps) {
- let path_tpt = {substs: some(expected_tps),
- ty: expected};
- write::ty_fixup(fcx, pat.id, path_tpt);
+ write_ty_substs(tcx, pat.id, expected,
+ expected_tps);
}
_ {
- write::ty_only_fixup(fcx, pat.id, expected);
+ write_ty(tcx, pat.id, expected);
}
}
}
ast::pat_lit(lt) {
check_expr_with(fcx, lt, expected);
- write::ty_only_fixup(fcx, pat.id, expr_ty(fcx.ccx.tcx, lt));
+ write_ty(tcx, pat.id, expr_ty(tcx, lt));
}
ast::pat_range(begin, end) {
check_expr_with(fcx, begin, expected);
check_expr_with(fcx, end, expected);
- let b_ty = resolve_type_vars_if_possible(fcx, expr_ty(fcx.ccx.tcx,
- begin));
- if !ty::same_type(fcx.ccx.tcx, b_ty, resolve_type_vars_if_possible(
- fcx, expr_ty(fcx.ccx.tcx, end))) {
- fcx.ccx.tcx.sess.span_err(pat.span, "mismatched types in range");
- } else if !ty::type_is_numeric(fcx.ccx.tcx, b_ty) {
- fcx.ccx.tcx.sess.span_err(pat.span,
- "non-numeric type used in range");
+ let b_ty = resolve_type_vars_if_possible(fcx, expr_ty(tcx, begin));
+ if !ty::same_type(tcx, b_ty, resolve_type_vars_if_possible(
+ fcx, expr_ty(tcx, end))) {
+ tcx.sess.span_err(pat.span, "mismatched types in range");
+ } else if !ty::type_is_numeric(tcx, b_ty) {
+ tcx.sess.span_err(pat.span, "non-numeric type used in range");
} else if !valid_range_bounds(begin, end) {
- fcx.ccx.tcx.sess.span_err(begin.span,
- "lower range bound must be less \
- than upper");
+ tcx.sess.span_err(begin.span, "lower range bound must be less \
+ than upper");
}
- write::ty_only_fixup(fcx, pat.id, b_ty);
+ write_ty(tcx, pat.id, b_ty);
}
ast::pat_ident(name, sub) {
let vid = lookup_local(fcx, pat.span, pat.id);
- let typ = ty::mk_var(fcx.ccx.tcx, vid);
+ let typ = ty::mk_var(tcx, vid);
typ = demand::simple(fcx, pat.span, expected, typ);
let canon_id = map.get(path_to_ident(name));
if canon_id != pat.id {
- let ct =
- ty::mk_var(fcx.ccx.tcx,
- lookup_local(fcx, pat.span, canon_id));
+ let ct = ty::mk_var(tcx, lookup_local(fcx, pat.span, canon_id));
typ = demand::simple(fcx, pat.span, ct, typ);
}
- write::ty_only_fixup(fcx, pat.id, typ);
+ write_ty(tcx, pat.id, typ);
alt sub {
some(p) { check_pat(fcx, map, p, expected); }
_ {}
// Typecheck the path.
let v_def = lookup_def(fcx, path.span, pat.id);
let v_def_ids = ast_util::variant_def_ids(v_def);
- let enum_tpt = ty::lookup_item_type(fcx.ccx.tcx, v_def_ids.tg);
- let path_tpot = instantiate_path(fcx, path, enum_tpt, pat.span);
+ let ctor_tpt = ty::lookup_item_type(tcx, v_def_ids.enm);
+ instantiate_path(fcx, path, ctor_tpt, pat.span, pat.id);
// Take the enum type params out of `expected`.
alt structure_of(fcx, pat.span, expected) {
ty::ty_enum(_, expected_tps) {
- // Unify with the expected enum type.
- let ctor_ty =
- ty::ty_param_substs_opt_and_ty_to_monotype(fcx.ccx.tcx,
- path_tpot);
-
- let path_tpt =
- demand::with_substs(fcx, pat.span, expected, ctor_ty,
- expected_tps);
- path_tpot =
- {substs: some::<[ty::t]>(path_tpt.substs), ty: path_tpt.ty};
-
+ let ctor_ty = ty::node_id_to_type(tcx, pat.id);
+ demand::with_substs(fcx, pat.span, expected, ctor_ty,
+ expected_tps);
// Get the number of arguments in this enum variant.
let arg_types =
variant_arg_types(fcx.ccx, pat.span, v_def_ids.var,
let subpats_len = vec::len::<@ast::pat>(subpats);
if vec::len::<ty::t>(arg_types) > 0u {
// N-ary variant.
-
let arg_len = vec::len::<ty::t>(arg_types);
if arg_len != subpats_len {
// TODO: note definition of enum variant
// TODO (issue #448): Wrap a #fmt string over multiple
// lines...
- let s =
- #fmt["this pattern has %u field%s, but the \
- corresponding variant has %u field%s",
- subpats_len,
- if subpats_len == 1u { "" } else { "s" },
- arg_len, if arg_len == 1u { "" } else { "s" }];
- fcx.ccx.tcx.sess.span_fatal(pat.span, s);
+ let s = #fmt["this pattern has %u field%s, but the \
+ corresponding variant has %u field%s",
+ subpats_len,
+ if subpats_len == 1u { "" } else { "s" },
+ arg_len,
+ if arg_len == 1u { "" } else { "s" }];
+ tcx.sess.span_err(pat.span, s);
}
- // TODO: vec::iter2
-
- let i = 0u;
- for subpat: @ast::pat in subpats {
- check_pat(fcx, map, subpat, arg_types[i]);
- i += 1u;
+ vec::iter2(subpats, arg_types) {|subpat, arg_ty|
+ check_pat(fcx, map, subpat, arg_ty);
}
} else if subpats_len > 0u {
// TODO: note definition of enum variant
- fcx.ccx.tcx.sess.span_fatal
- (pat.span,
- #fmt["this pattern has %u field%s, \
- but the corresponding \
- variant has no fields",
- subpats_len,
- if subpats_len == 1u {
- ""
- } else { "s" }]);
+ tcx.sess.span_err
+ (pat.span, #fmt["this pattern has %u field%s, \
+ but the corresponding \
+ variant has no fields",
+ subpats_len,
+ if subpats_len == 1u { "" }
+ else { "s" }]);
}
- write::ty_fixup(fcx, pat.id, path_tpot);
}
_ {
// FIXME: Switch expected and actual in this message? I
// can never tell.
- fcx.ccx.tcx.sess.span_fatal
+ tcx.sess.span_err
(pat.span,
#fmt["mismatched types: expected `%s` but found enum",
- ty_to_str(fcx.ccx.tcx, expected)]);
+ ty_to_str(tcx, expected)]);
}
}
- write::ty_fixup(fcx, pat.id, path_tpot);
}
ast::pat_rec(fields, etc) {
let ex_fields;
alt structure_of(fcx, pat.span, expected) {
ty::ty_rec(fields) { ex_fields = fields; }
_ {
- fcx.ccx.tcx.sess.span_fatal
+ tcx.sess.span_fatal
(pat.span,
#fmt["mismatched types: expected `%s` but found record",
- ty_to_str(fcx.ccx.tcx, expected)]);
+ ty_to_str(tcx, expected)]);
}
}
let f_count = vec::len(fields);
let ex_f_count = vec::len(ex_fields);
if ex_f_count < f_count || !etc && ex_f_count > f_count {
- fcx.ccx.tcx.sess.span_fatal
+ tcx.sess.span_fatal
(pat.span, #fmt["mismatched types: expected a record \
with %u fields, found one with %u \
fields",
alt vec::find(ex_fields, bind matches(f.ident, _)) {
some(field) { check_pat(fcx, map, f.pat, field.mt.ty); }
none {
- fcx.ccx.tcx.sess.span_fatal(pat.span,
- #fmt["mismatched types: did not \
- expect a record with a field `%s`",
- f.ident]);
+ tcx.sess.span_fatal(pat.span,
+ #fmt["mismatched types: did not \
+ expect a record with a field `%s`",
+ f.ident]);
}
}
}
- write::ty_only_fixup(fcx, pat.id, expected);
+ write_ty(tcx, pat.id, expected);
}
ast::pat_tup(elts) {
let ex_elts;
alt structure_of(fcx, pat.span, expected) {
ty::ty_tup(elts) { ex_elts = elts; }
_ {
- fcx.ccx.tcx.sess.span_fatal
+ tcx.sess.span_fatal
(pat.span,
#fmt["mismatched types: expected `%s`, found tuple",
- ty_to_str(fcx.ccx.tcx, expected)]);
+ ty_to_str(tcx, expected)]);
}
}
let e_count = vec::len(elts);
if e_count != vec::len(ex_elts) {
- fcx.ccx.tcx.sess.span_fatal
+ tcx.sess.span_fatal
(pat.span, #fmt["mismatched types: expected a tuple \
with %u fields, found one with %u \
fields", vec::len(ex_elts), e_count]);
}
let i = 0u;
for elt in elts { check_pat(fcx, map, elt, ex_elts[i]); i += 1u; }
- write::ty_only_fixup(fcx, pat.id, expected);
+ write_ty(tcx, pat.id, expected);
}
ast::pat_box(inner) {
alt structure_of(fcx, pat.span, expected) {
ty::ty_box(e_inner) {
check_pat(fcx, map, inner, e_inner.ty);
- write::ty_only_fixup(fcx, pat.id, expected);
+ write_ty(tcx, pat.id, expected);
}
_ {
- fcx.ccx.tcx.sess.span_fatal(pat.span,
+ tcx.sess.span_fatal(pat.span,
"mismatched types: expected `" +
- ty_to_str(fcx.ccx.tcx, expected) +
+ ty_to_str(tcx, expected) +
"` found box");
}
}
alt structure_of(fcx, pat.span, expected) {
ty::ty_uniq(e_inner) {
check_pat(fcx, map, inner, e_inner.ty);
- write::ty_only_fixup(fcx, pat.id, expected);
+ write_ty(tcx, pat.id, expected);
}
_ {
- fcx.ccx.tcx.sess.span_fatal(pat.span,
+ tcx.sess.span_fatal(pat.span,
"mismatched types: expected `" +
- ty_to_str(fcx.ccx.tcx, expected) +
+ ty_to_str(tcx, expected) +
"` found uniq");
}
}
if did.crate == ast::local_crate {
alt tcx.items.get(did.node) {
ast_map::node_item(@{node: ast::item_impl(ts, _, st, _),
- _}) {
+ _}, _) {
{n_tps: vec::len(ts), ty: ast_ty_to_ty(tcx, m_check, st)}
}
+ an_item {
+ tcx.sess.bug("Undocumented invariant in impl_self_ty");
+ }
}
} else {
let tpt = csearch::get_type(tcx, did);
fn lookup_method(fcx: @fn_ctxt, isc: resolve::iscopes,
name: ast::ident, ty: ty::t, sp: span)
- -> option::t<{method_ty: ty::t, n_tps: uint, substs: [ty::t],
+ -> option<{method_ty: ty::t, n_tps: uint, substs: [ty::t],
origin: method_origin}> {
let tcx = fcx.ccx.tcx;
ty::bound_iface(t) {
let (iid, tps) = alt ty::struct(tcx, t) {
ty::ty_iface(i, tps) { (i, tps) }
+ _ {
+ tcx.sess.span_bug(sp, "Undocument invariant in \
+ lookup_method");
+ }
};
let ifce_methods = ty::iface_methods(tcx, iid);
alt vec::position(*ifce_methods, {|m| m.ident == name}) {
let m = ifce_methods[pos];
ret some({method_ty: ty::mk_fn(tcx, m.fty),
n_tps: vec::len(*m.tps),
- substs: tps + [ty],
+ substs: tps,
origin: method_param(iid, pos, n, bound_n)});
}
_ {}
if m.ident == name {
ret some({method_ty: ty::mk_fn(tcx, m.fty),
n_tps: vec::len(*m.tps),
- substs: tps + [ty::mk_int(tcx)],
+ substs: tps,
origin: method_iface(i)});
}
i += 1u;
_ {}
}
+ fn ty_from_did(tcx: ty::ctxt, did: ast::def_id) -> ty::t {
+ if did.crate == ast::local_crate {
+ alt tcx.items.get(did.node) {
+ ast_map::node_method(m, _) {
+ let mt = ty_of_method(tcx, m_check, m);
+ ty::mk_fn(tcx, mt.fty)
+ }
+ _ {
+ tcx.sess.bug("Undocumented invariant in ty_from_did");
+ }
+ }
+ } else { csearch::get_type(tcx, did).ty }
+ }
+
let result = none;
std::list::iter(isc) {|impls|
if option::is_some(result) { ret; }
sp, "multiple applicable methods in scope");
} else {
result = some({
- method_ty: ty::lookup_item_type(tcx, m.did).ty,
+ method_ty: ty_from_did(tcx, m.did),
n_tps: m.n_tps,
substs: vars,
origin: method_static(m.did)
unify: unifier,
expected: ty::t) {
let tcx = fcx.ccx.tcx;
-
- let fty = ty::mk_fn(tcx, ty_of_fn_decl(tcx, m_check_tyvar(fcx),
- proto, decl));
+ let fty = ty::mk_fn(tcx,
+ ty_of_fn_decl(tcx, m_check_tyvar(fcx), proto, decl));
#debug("check_expr_fn_with_unifier %s fty=%s",
expr_to_str(expr),
ty_to_str(tcx, fty));
- write::ty_only_fixup(fcx, expr.id, fty);
+ write_ty(tcx, expr.id, fty);
// Unify the type of the function with the expected type before we
// typecheck the body so that we have more information about the
// A generic function to factor out common logic from call and bind
// expressions.
fn check_call_or_bind(fcx: @fn_ctxt, sp: span, fty: ty::t,
- args: [option::t<@ast::expr>]) -> bool {
+ args: [option<@ast::expr>]) -> bool {
let sty = structure_of(fcx, sp, fty);
// Grab the argument types
let arg_tys = alt sty {
fcx.ccx.tcx.sess.span_err(
sp, #fmt["this function takes %u parameter%s but %u \
parameter%s supplied", expected_arg_count,
- expected_arg_count == 1u ? "" : "s",
+ if expected_arg_count == 1u {
+ ""
+ } else {
+ "s"
+ },
supplied_arg_count,
- supplied_arg_count == 1u ? " was" : "s were"]);
+ if supplied_arg_count == 1u {
+ " was"
+ } else {
+ "s were"
+ }]);
// HACK: build an arguments list with dummy arguments to
// check against
- let dummy = {mode: ast::by_ref, ty: ty::mk_bot(fcx.ccx.tcx)};
+ let dummy = {mode: ast::expl(ast::by_ref),
+ ty: ty::mk_bot(fcx.ccx.tcx)};
arg_tys = vec::init_elt(supplied_arg_count, dummy);
}
rhs: @ast::expr, id: ast::node_id) -> bool {
let t = next_ty_var(fcx);
let bot = check_expr_with(fcx, lhs, t) | check_expr_with(fcx, rhs, t);
- write::ty_only_fixup(fcx, id, ty::mk_nil(fcx.ccx.tcx));
+ write_ty(fcx.ccx.tcx, id, ty::mk_nil(fcx.ccx.tcx));
ret bot;
}
// A generic function for checking call expressions
fn check_call(fcx: @fn_ctxt, sp: span, f: @ast::expr, args: [@ast::expr])
-> bool {
- let args_opt_0: [option::t<@ast::expr>] = [];
+ let args_opt_0: [option<@ast::expr>] = [];
for arg: @ast::expr in args {
args_opt_0 += [some::<@ast::expr>(arg)];
}
}
_ { fcx.ccx.tcx.sess.span_fatal(sp, "calling non-function"); }
};
- write::ty_only_fixup(fcx, id, rt_1);
+ write_ty(fcx.ccx.tcx, id, rt_1);
ret bot;
}
demand::simple(fcx, local.span,
ty::node_id_to_type(fcx.ccx.tcx, local.node.id),
element_ty);
- write::nil_ty(fcx.ccx.tcx, node_id);
+ write_nil(fcx.ccx.tcx, node_id);
ret bot;
}
// A generic function for checking the then and else in an if
// or if-check
fn check_then_else(fcx: @fn_ctxt, thn: ast::blk,
- elsopt: option::t<@ast::expr>, id: ast::node_id,
+ elsopt: option<@ast::expr>, id: ast::node_id,
_sp: span) -> bool {
let (if_t, if_bot) =
alt elsopt {
(ty::mk_nil(fcx.ccx.tcx), false)
}
};
- write::ty_only_fixup(fcx, id, if_t);
+ write_ty(fcx.ccx.tcx, id, if_t);
ret if_bot;
}
- fn binop_method(op: ast::binop) -> option::t<str> {
+ fn binop_method(op: ast::binop) -> option<str> {
alt op {
ast::add | ast::subtract | ast::mul | ast::div | ast::rem |
ast::bitxor | ast::bitand | ast::bitor | ast::lsl | ast::lsr |
}
fn lookup_op_method(fcx: @fn_ctxt, op_ex: @ast::expr, self_t: ty::t,
opname: str,
- args: [option::t<@ast::expr>]) -> option::t<ty::t> {
+ args: [option<@ast::expr>]) -> option<ty::t> {
let isc = fcx.ccx.impl_map.get(op_ex.id);
alt lookup_method(fcx, isc, opname, self_t, op_ex.span) {
some({method_ty, n_tps: 0u, substs, origin}) {
let callee_id = ast_util::op_expr_callee_id(op_ex);
- write::ty_fixup(fcx, callee_id, {substs: some(substs),
- ty: method_ty});
+ write_ty_substs(fcx.ccx.tcx, callee_id, method_ty, substs);
check_call_or_bind(fcx, op_ex.span, method_ty, args);
fcx.ccx.method_map.insert(op_ex.id, origin);
some(ty::ty_fn_ret(fcx.ccx.tcx, method_ty))
alt expr.node {
ast::expr_lit(lit) {
let typ = check_lit(fcx.ccx, lit);
- write::ty_only_fixup(fcx, id, typ);
+ write_ty(tcx, id, typ);
}
ast::expr_binary(binop, lhs, rhs) {
let lhs_t = next_ty_var(fcx);
let rhs_bot = check_expr_with(fcx, rhs, lhs_t);
if !ast_util::lazy_binop(binop) { bot |= rhs_bot; }
-
let result = check_binop(fcx, expr, lhs_t, binop, rhs);
- write::ty_only_fixup(fcx, id, result);
+ write_ty(tcx, id, result);
}
ast::expr_assign_op(op, lhs, rhs) {
require_impure(tcx.sess, fcx.purity, expr.span);
}
}
}
- write::ty_only_fixup(fcx, id, oper_t);
+ write_ty(tcx, id, oper_t);
}
ast::expr_path(pth) {
let defn = lookup_def(fcx, pth.span, id);
let tpt = ty_param_bounds_and_ty_for_def(fcx, expr.span, defn);
if ty::def_has_ty_params(defn) {
- let path_tpot = instantiate_path(fcx, pth, tpt, expr.span);
- write::ty_fixup(fcx, id, path_tpot);
+ instantiate_path(fcx, pth, tpt, expr.span, expr.id);
} else {
// The definition doesn't take type parameters. If the programmer
// supplied some, that's an error
"this kind of value does not \
take type parameters");
}
- write::ty_only_fixup(fcx, id, tpt.ty);
+ write_ty(tcx, id, tpt.ty);
}
}
ast::expr_mac(_) { tcx.sess.bug("unexpanded macro"); }
none {/* do nothing */ }
some(e) { check_expr_with(fcx, e, ty::mk_str(tcx)); }
}
- write::bot_ty(tcx, id);
+ write_bot(tcx, id);
}
- ast::expr_break { write::bot_ty(tcx, id); bot = true; }
- ast::expr_cont { write::bot_ty(tcx, id); bot = true; }
+ ast::expr_break { write_bot(tcx, id); bot = true; }
+ ast::expr_cont { write_bot(tcx, id); bot = true; }
ast::expr_ret(expr_opt) {
bot = true;
alt expr_opt {
}
some(e) { check_expr_with(fcx, e, fcx.ret_ty); }
}
- write::bot_ty(tcx, id);
+ write_bot(tcx, id);
}
ast::expr_be(e) {
// FIXME: prove instead of assert
assert (ast_util::is_call_expr(e));
check_expr_with(fcx, e, fcx.ret_ty);
bot = true;
- write::nil_ty(tcx, id);
+ write_nil(tcx, id);
}
ast::expr_log(_, lv, e) {
bot = check_expr_with(fcx, lv, ty::mk_mach_uint(tcx, ast::ty_u32));
bot |= check_expr(fcx, e);
- write::nil_ty(tcx, id);
+ write_nil(tcx, id);
}
ast::expr_check(_, e) {
bot = check_pred_expr(fcx, e);
- write::nil_ty(tcx, id);
+ write_nil(tcx, id);
}
ast::expr_if_check(cond, thn, elsopt) {
bot =
check_pred_expr(fcx, cond) |
check_then_else(fcx, thn, elsopt, id, expr.span);
}
- ast::expr_ternary(_, _, _) {
- bot = check_expr(fcx, ast_util::ternary_to_if(expr));
- }
ast::expr_assert(e) {
bot = check_expr_with(fcx, e, ty::mk_bool(tcx));
- write::nil_ty(tcx, id);
+ write_nil(tcx, id);
}
ast::expr_copy(a) {
bot = check_expr_with_unifier(fcx, a, unify, expected);
- let tpot =
- ty::node_id_to_ty_param_substs_opt_and_ty(tcx, a.id);
- write::ty_fixup(fcx, id, tpot);
-
+ write_ty(tcx, id, ty::node_id_to_type(tcx, a.id));
}
ast::expr_move(lhs, rhs) {
require_impure(tcx.sess, fcx.purity, expr.span);
ast::expr_while(cond, body) {
bot = check_expr_with(fcx, cond, ty::mk_bool(tcx));
check_block_no_value(fcx, body);
- write::ty_only_fixup(fcx, id, ty::mk_nil(tcx));
+ write_ty(tcx, id, ty::mk_nil(tcx));
}
ast::expr_do_while(body, cond) {
bot = check_expr_with(fcx, cond, ty::mk_bool(tcx)) |
check_block_no_value(fcx, body);
- write::ty_only_fixup(fcx, id, block_ty(tcx, body));
+ write_ty(tcx, id, block_ty(tcx, body));
}
ast::expr_alt(expr, arms) {
bot = check_expr(fcx, expr);
}
bot |= !arm_non_bot;
if !arm_non_bot { result_ty = ty::mk_bot(tcx); }
- write::ty_only_fixup(fcx, id, result_ty);
+ write_ty(tcx, id, result_ty);
}
ast::expr_fn(proto, decl, body, captures) {
check_expr_fn_with_unifier(fcx, expr, proto, decl, body,
// Take the prototype from the expected type, but default to block:
let proto = alt ty::struct(tcx, expected) {
ty::ty_fn({proto, _}) { proto }
- _ {
- tcx.sess.span_warn(expr.span, "unable to infer kind of closure, \
- defaulting to block");
- ast::proto_block
- }
+ _ { ast::proto_box }
};
#debug("checking expr_fn_block %s expected=%s",
expr_to_str(expr),
ty_to_str(tcx, expected));
check_expr_fn_with_unifier(fcx, expr, proto, decl, body,
unify, expected);
- write::ty_only_fixup(fcx, id, expected);
}
ast::expr_block(b) {
// If this is an unchecked block, turn off purity-checking
some(expr) { expr_ty(tcx, expr) }
none { ty::mk_nil(tcx) }
};
- write::ty_only_fixup(fcx, id, typ);
+ write_ty(tcx, id, typ);
}
ast::expr_bind(f, args) {
// Call the generic checker.
let ft = ty::mk_fn(tcx, {proto: lower_bound_proto(proto),
inputs: out_args, output: rt,
ret_style: cf, constraints: constrs});
- write::ty_only_fixup(fcx, id, ft);
+ write_ty(tcx, id, ft);
}
ast::expr_call(f, args, _) {
bot = check_call_full(fcx, expr.span, f, args, expr.id);
}
}
}
- write::ty_only_fixup(fcx, id, t_1);
+ write_ty(tcx, id, t_1);
}
ast::expr_vec(args, mut) {
let t: ty::t = next_ty_var(fcx);
for e: @ast::expr in args { bot |= check_expr_with(fcx, e, t); }
let typ = ty::mk_vec(tcx, {ty: t, mut: mut});
- write::ty_only_fixup(fcx, id, typ);
+ write_ty(tcx, id, typ);
}
ast::expr_tup(elts) {
let elt_ts = [];
elt_ts += [ety];
}
let typ = ty::mk_tup(tcx, elt_ts);
- write::ty_only_fixup(fcx, id, typ);
+ write_ty(tcx, id, typ);
}
ast::expr_rec(fields, base) {
alt base { none {/* no-op */ } some(b_0) { check_expr(fcx, b_0); } }
none {
fn get_node(f: spanned<field>) -> field { f.node }
let typ = ty::mk_rec(tcx, vec::map(fields_t, get_node));
- write::ty_only_fixup(fcx, id, typ);
+ write_ty(tcx, id, typ);
}
some(bexpr) {
bot |= check_expr(fcx, bexpr);
"record update has non-record base");
}
}
- write::ty_only_fixup(fcx, id, bexpr_t);
+ write_ty(tcx, id, bexpr_t);
for f: spanned<ty::field> in fields_t {
let found = false;
for bf: ty::field in base_fields {
"can't provide type parameters \
to a field access");
}
- write::ty_only_fixup(fcx, id, fields[ix].mt.ty);
+ write_ty(tcx, id, fields[ix].mt.ty);
handled = true;
}
_ {}
i += 1u;
}
}
- write::ty_fixup(fcx, id, {substs: some(substs), ty: fty});
+ write_ty_substs(fcx.ccx.tcx, id, fty, substs);
} else if n_tys > 0u {
tcx.sess.span_fatal(expr.span,
"this method does not take type \
parameters");
} else {
- write::ty_only_fixup(fcx, id, fty);
+ write_ty(tcx, id, fty);
}
fcx.ccx.method_map.insert(id, origin);
}
field, ty_to_str(tcx, t_err)];
tcx.sess.span_err(expr.span, msg);
// NB: Adding a bogus type to allow typechecking to continue
- write::ty_only_fixup(fcx, id, ty::mk_nil(tcx));
+ write_ty(tcx, id, ty::mk_nil(tcx));
}
}
}
alt structure_of(fcx, expr.span, base_t) {
ty::ty_vec(mt) {
require_integral(fcx, idx.span, idx_t);
- write::ty_only_fixup(fcx, id, mt.ty);
+ write_ty(tcx, id, mt.ty);
}
ty::ty_str {
require_integral(fcx, idx.span, idx_t);
let typ = ty::mk_mach_uint(tcx, ast::ty_u8);
- write::ty_only_fixup(fcx, id, typ);
+ write_ty(tcx, id, typ);
}
_ {
let resolved = structurally_resolved_type(fcx, expr.span,
raw_base_t);
alt lookup_op_method(fcx, expr, resolved, "[]",
[some(idx)]) {
- some(ret_ty) { write::ty_only_fixup(fcx, id, ret_ty); }
+ some(ret_ty) { write_ty(tcx, id, ret_ty); }
_ {
tcx.sess.span_fatal(
expr.span, "cannot index a value of type `" +
}
_ { tcx.sess.unimpl("expr type in typeck::check_expr"); }
}
- if bot { write::ty_only_fixup(fcx, expr.id, ty::mk_bot(tcx)); }
+ if bot { write_ty(tcx, expr.id, ty::mk_bot(tcx)); }
unify(fcx, expr.span, expected, expr_ty(tcx, expr));
ret bot;
{vars: vars, ty: ty::substitute_type_params(fcx.ccx.tcx, vars, tp)}
}
-fn get_self_info(ccx: @crate_ctxt) -> option::t<self_info> {
+fn get_self_info(ccx: @crate_ctxt) -> option<self_info> {
ret vec::last(ccx.self_infos);
}
alt fcx.locals.find(local.node.id) {
some(i) {
let t = ty::mk_var(fcx.ccx.tcx, i);
- write::ty_only_fixup(fcx, local.node.id, t);
+ write_ty(fcx.ccx.tcx, local.node.id, t);
alt local.node.init {
some(init) {
bot = check_decl_initializer(fcx, local.node.id, init);
let id_map = pat_util::pat_id_map(fcx.ccx.tcx, local.node.pat);
check_pat(fcx, id_map, local.node.pat, t);
}
+ _ { fcx.ccx.tcx.sess.span_bug(local.span, "Undocumented invariant \
+ in check_decl_local"); }
}
ret bot;
}
bot = check_expr(fcx, expr);
}
}
- write::nil_ty(fcx.ccx.tcx, node_id);
+ write_nil(fcx.ccx.tcx, node_id);
ret bot;
}
fn check_block_no_value(fcx: @fn_ctxt, blk: ast::blk) -> bool {
let bot = check_block(fcx, blk);
if !bot {
- let blkty = ty::node_id_to_monotype(fcx.ccx.tcx, blk.node.id);
+ let blkty = ty::node_id_to_type(fcx.ccx.tcx, blk.node.id);
let nilty = ty::mk_nil(fcx.ccx.tcx);
demand::simple(fcx, blk.span, nilty, blkty);
}
bot |= check_stmt(fcx, s);
}
alt blk.node.expr {
- none { write::nil_ty(fcx.ccx.tcx, blk.node.id); }
+ none { write_nil(fcx.ccx.tcx, blk.node.id); }
some(e) {
if bot && !warned {
fcx.ccx.tcx.sess.span_warn(e.span, "unreachable expression");
}
bot |= check_expr(fcx, e);
let ety = expr_ty(fcx.ccx.tcx, e);
- write::ty_only_fixup(fcx, blk.node.id, ety);
+ write_ty(fcx.ccx.tcx, blk.node.id, ety);
}
}
if bot {
- write::ty_only_fixup(fcx, blk.node.id, ty::mk_bot(fcx.ccx.tcx));
+ write_ty(fcx.ccx.tcx, blk.node.id, ty::mk_bot(fcx.ccx.tcx));
}
ret bot;
}
// FIXME: this is kinda a kludge; we manufacture a fake function context
// and statement context for checking the initializer expression.
let rty = node_id_to_type(ccx.tcx, id);
- let fixups: [ast::node_id] = [];
let fcx: @fn_ctxt =
@{ret_ty: rty,
purity: ast::pure_fn,
var_bindings: ty::unify::mk_var_bindings(),
locals: new_int_hash::<int>(),
next_var_id: @mutable 0,
- mutable fixups: fixups,
ccx: ccx};
check_expr(fcx, e);
let cty = expr_ty(fcx.ccx.tcx, e);
// FIXME: this is kinda a kludge; we manufacture a fake function context
// and statement context for checking the initializer expression.
let rty = node_id_to_type(ccx.tcx, id);
- let fixups: [ast::node_id] = [];
let fcx: @fn_ctxt =
@{ret_ty: rty,
purity: ast::pure_fn,
var_bindings: ty::unify::mk_var_bindings(),
locals: new_int_hash::<int>(),
next_var_id: @mutable 0,
- mutable fixups: fixups,
ccx: ccx};
let disr_vals: [int] = [];
let disr_val = 0;
decl: ast::fn_decl,
body: ast::blk,
id: ast::node_id,
- old_fcx: option::t<@fn_ctxt>) {
+ old_fcx: option<@fn_ctxt>) {
// If old_fcx is some(...), this is a block fn { |x| ... }.
// In that case, the purity is inherited from the context.
let purity = alt old_fcx {
};
let gather_result = gather_locals(ccx, decl, body, id, old_fcx);
- let fixups: [ast::node_id] = [];
let fcx: @fn_ctxt =
@{ret_ty: ty::ty_fn_ret(ccx.tcx, ty::node_id_to_type(ccx.tcx, id)),
purity: purity,
var_bindings: gather_result.var_bindings,
locals: gather_result.locals,
next_var_id: gather_result.next_var_id,
- mutable fixups: fixups,
ccx: ccx};
check_constraints(fcx, decl.constraints, decl.inputs);
let args = ty::ty_fn_args(ccx.tcx, ty::node_id_to_type(ccx.tcx, id));
let i = 0u;
for arg: ty::arg in args {
- write::ty_only_fixup(fcx, decl.inputs[i].id, arg.ty);
+ write_ty(ccx.tcx, decl.inputs[i].id, arg.ty);
i += 1u;
}
}
}
-fn check_main_fn_ty(tcx: ty::ctxt, main_id: ast::node_id) {
- let main_t = ty::node_id_to_monotype(tcx, main_id);
+fn check_main_fn_ty(tcx: ty::ctxt, main_id: ast::node_id, main_span: span) {
+ let main_t = ty::node_id_to_type(tcx, main_id);
alt ty::struct(tcx, main_t) {
ty::ty_fn({proto: ast::proto_bare, inputs, output,
ret_style: ast::return_val, constraints}) {
ok &= num_args == 0u || num_args == 1u &&
arg_is_argv_ty(tcx, inputs[0]);
if !ok {
- let span = ast_map::node_span(tcx.items.get(main_id));
- tcx.sess.span_err(span,
+ tcx.sess.span_err(main_span,
"wrong type in main function: found `" +
ty_to_str(tcx, main_t) + "`");
}
}
_ {
- let span = ast_map::node_span(tcx.items.get(main_id));
- tcx.sess.span_bug(span,
+ tcx.sess.span_bug(main_span,
"main has a non-function type: found `" +
ty_to_str(tcx, main_t) + "`");
}
fn check_for_main_fn(tcx: ty::ctxt, crate: @ast::crate) {
if !tcx.sess.building_library {
alt tcx.sess.main_fn {
- some(id) { check_main_fn_ty(tcx, id); }
+ some((id, sp)) { check_main_fn_ty(tcx, id, sp); }
none { tcx.sess.span_err(crate.span, "main function not found"); }
}
}
let tcx = fcx.ccx.tcx;
let (iface_id, iface_tps) = alt ty::struct(tcx, iface_ty) {
ty::ty_iface(did, tps) { (did, tps) }
+ _ { tcx.sess.span_bug(sp, "Undocumented invariant in lookup\
+ _dict"); }
};
let ty = fixup_ty(fcx, sp, ty);
alt ty::struct(tcx, ty) {
ty::ty_iface(idid, _) {
if iface_id == idid { ret dict_param(n, n_bound); }
}
+ _ { tcx.sess.span_bug(sp, "Undocumented invariant in \
+ lookup_dict"); }
}
n_bound += 1u;
}
some(ity) {
alt ty::struct(tcx, ity) {
ty::ty_iface(id, _) { id == iface_id }
+ // Bleah, abstract this
+ _ { tcx.sess.span_bug(sp, "Undocumented invariant \
+ in lookup_dict"); }
}
}
_ { false }
vec::iter2(tps, iface_tys,
{|a, b| demand::simple(fcx, sp, a, b);});
}
+ _ {
+ tcx.sess.span_bug(sp, "Undocumented invariant in \
+ connect_iface_tps");
+ }
}
}
let cx = fcx.ccx;
alt ex.node {
ast::expr_path(_) {
- let substs = ty::node_id_to_ty_param_substs_opt_and_ty(
- cx.tcx, ex.id);
- alt substs.substs {
+ alt cx.tcx.node_type_substs.find(ex.id) {
some(ts) {
let did = ast_util::def_id_of_def(cx.tcx.def_map.get(ex.id));
let item_ty = ty::lookup_item_type(cx.tcx, did);
}
}
ast::expr_cast(src, _) {
- // Ifaces that refer to a self type can not be cast to -- callers
- // wouldn't know what self refers to.
- fn type_refers_to_self(tcx: ty::ctxt, t: ty::t, s_param: uint)
- -> bool {
- let found = false;
- if ty::type_contains_params(tcx, t) {
- ty::walk_ty(tcx, t) {|t|
- alt ty::struct(tcx, t) {
- ty::ty_param(n, _) if n == s_param { found = true; }
- _ {}
- }
- }
- }
- found
- }
- fn method_refers_to_self(tcx: ty::ctxt, m: ty::method,
- s_param: uint) -> bool {
- vec::any(m.fty.inputs, {|in|
- type_refers_to_self(tcx, in.ty, s_param)
- }) || type_refers_to_self(tcx, m.fty.output, s_param)
- }
let target_ty = expr_ty(cx.tcx, ex);
alt ty::struct(cx.tcx, target_ty) {
- ty::ty_iface(id, tps) {
- for m in *ty::iface_methods(cx.tcx, id) {
- if method_refers_to_self(cx.tcx, m, vec::len(tps)) {
- cx.tcx.sess.span_err(
- ex.span, "can not cast to an iface type that \
- refers to `self` " + m.ident);
- break;
- }
- }
+ ty::ty_iface(_, _) {
let impls = cx.impl_map.get(ex.id);
let dict = lookup_dict(fcx, impls, ex.span,
expr_ty(cx.tcx, src), target_ty);
mod kind;
mod freevars;
mod shape;
- mod gc;
mod debuginfo;
mod capture;
mod pat_util;
mod ext {
mod base;
mod expand;
+ mod qquote;
+ mod build;
mod fmt;
mod env;
type ident = str;
// Functions may or may not have names.
-type fn_ident = option::t<ident>;
+type fn_ident = option<ident>;
// FIXME: with typestate constraint, could say
// idents and types are the same length, and are
def_ty_param(def_id, uint),
def_binding(def_id),
def_use(def_id),
- def_native_ty(def_id),
def_upvar(def_id, @def, node_id), // node_id == expr_fn or expr_fn_block
}
type blk = spanned<blk_>;
-type blk_ = {view_items: [@view_item], stmts: [@stmt], expr: option::t<@expr>,
+type blk_ = {view_items: [@view_item], stmts: [@stmt], expr: option<@expr>,
id: node_id, rules: blk_check_mode};
type pat = {id: node_id, node: pat_, span: span};
// After the resolution phase, code should never pattern-
// match on a pat directly! Always call pat_util::normalize_pat --
// it turns any pat_idents that refer to nullary enums into pat_enums.
- pat_ident(@path, option::t<@pat>),
+ pat_ident(@path, option<@pat>),
pat_enum(@path, [@pat]),
pat_rec([field_pat], bool),
pat_tup([@pat]),
deref, not, neg,
}
-enum mode { by_ref, by_val, by_mut_ref, by_move, by_copy, mode_infer, }
+// Generally, after typeck you can get the inferred value
+// using ty::resolved_T(...).
+enum inferable<T> {
+ expl(T), infer(node_id)
+}
+
+// "resolved" mode: the real modes.
+enum rmode { by_ref, by_val, by_mut_ref, by_move, by_copy }
+
+// inferable mode.
+type mode = inferable<rmode>;
type stmt = spanned<stmt_>;
type initializer = {op: init_op, expr: @expr};
type local_ = // FIXME: should really be a refinement on pat
- {ty: @ty, pat: @pat, init: option::t<initializer>, id: node_id};
+ {ty: @ty, pat: @pat, init: option<initializer>, id: node_id};
type local = spanned<local_>;
enum decl_ { decl_local([(let_style, @local)]), decl_item(@item), }
-type arm = {pats: [@pat], guard: option::t<@expr>, body: blk};
+type arm = {pats: [@pat], guard: option<@expr>, body: blk};
type field_ = {mut: mutability, ident: ident, expr: @expr};
enum expr_ {
expr_vec([@expr], mutability),
- expr_rec([field], option::t<@expr>),
+ expr_rec([field], option<@expr>),
expr_call(@expr, [@expr], bool),
expr_tup([@expr]),
- expr_bind(@expr, [option::t<@expr>]),
+ expr_bind(@expr, [option<@expr>]),
expr_binary(binop, @expr, @expr),
expr_unary(unop, @expr),
expr_lit(@lit),
expr_cast(@expr, @ty),
- expr_if(@expr, blk, option::t<@expr>),
- expr_ternary(@expr, @expr, @expr),
+ expr_if(@expr, blk, option<@expr>),
expr_while(@expr, blk),
expr_for(@local, @expr, blk),
expr_do_while(blk, @expr),
expr_field(@expr, ident, [@ty]),
expr_index(@expr, @expr),
expr_path(@path),
- expr_fail(option::t<@expr>),
+ expr_fail(option<@expr>),
expr_break,
expr_cont,
- expr_ret(option::t<@expr>),
+ expr_ret(option<@expr>),
expr_be(@expr),
expr_log(int, @expr, @expr),
/* FIXME Would be nice if expr_check desugared
to expr_if_check. */
- expr_if_check(@expr, blk, option::t<@expr>),
+ expr_if_check(@expr, blk, option<@expr>),
expr_mac(mac),
}
type mac = spanned<mac_>;
+type mac_arg = option::t<@expr>;
+
+type mac_body_ = {span: span};
+type mac_body = option::t<mac_body_>;
+
enum mac_ {
- mac_invoc(@path, @expr, option::t<str>),
+ mac_invoc(@path, mac_arg, mac_body),
mac_embed_type(@ty),
mac_embed_block(blk),
mac_ellipsis,
+ // the span is used by the quoter/anti-quoter ...
+ mac_qq(span /* span of expr */, @expr), // quasi-quote
+ mac_aq(span /* span of quote */, @expr), // anti-quote
+ mac_var(uint)
}
type lit = spanned<lit_>;
type ty_field = spanned<ty_field_>;
-type ty_method = {ident: ident, decl: fn_decl, tps: [ty_param], span: span};
+type ty_method = {ident: ident, attrs: [attribute],
+ decl: fn_decl, tps: [ty_param], span: span};
enum int_ty { ty_i, ty_char, ty_i8, ty_i16, ty_i32, ty_i64, }
ty_uniq(mt),
ty_vec(mt),
ty_ptr(mt),
- ty_task,
- ty_port(@ty),
- ty_chan(@ty),
ty_rec([ty_field]),
ty_fn(proto, fn_decl),
ty_tup([@ty]),
ty_path(@path, node_id),
- ty_type,
ty_constr(@ty, [@ty_constr]),
ty_mac(mac),
// ty_infer means the type should be inferred instead of it having been
return_val, // everything else
}
-type method = {ident: ident, tps: [ty_param], decl: fn_decl, body: blk,
+type method = {ident: ident, attrs: [attribute],
+ tps: [ty_param], decl: fn_decl, body: blk,
id: node_id, span: span};
type _mod = {view_items: [@view_item], items: [@item]};
type variant_arg = {ty: @ty, id: node_id};
type variant_ = {name: ident, attrs: [attribute], args: [variant_arg],
- id: node_id, disr_expr: option::t<@expr>};
+ id: node_id, disr_expr: option<@expr>};
type variant = spanned<variant_>;
item_enum([variant], [ty_param]),
item_res(fn_decl /* dtor */, [ty_param], blk,
node_id /* dtor id */, node_id /* ctor id */),
+ item_class([ty_param], /* ty params for class */
+ [@class_item], /* methods, etc. */
+ /* (not including ctor) */
+ fn_decl, /* ctor decl */
+ blk /* ctor body */
+ ),
item_iface([ty_param], [ty_method]),
- item_impl([ty_param], option::t<@ty> /* iface */,
+ item_impl([ty_param], option<@ty> /* iface */,
@ty /* self */, [@method]),
}
+type class_item_ = {privacy: privacy, decl: @class_member};
+type class_item = spanned<class_item_>;
+
+enum class_member {
+ instance_var(ident, @ty, class_mutability, node_id),
+ class_method(@item)
+}
+
+enum class_mutability { class_mutable, class_immutable }
+
+enum privacy { priv, pub }
+
type native_item =
{ident: ident,
attrs: [attribute],
span: span};
enum native_item_ {
- native_item_ty,
native_item_fn(fn_decl, [ty_param]),
}
fn local_def(id: node_id) -> def_id { ret {crate: local_crate, node: id}; }
-fn variant_def_ids(d: def) -> {tg: def_id, var: def_id} {
- alt d { def_variant(enum_id, var_id) { ret {tg: enum_id, var: var_id}; } }
+fn variant_def_ids(d: def) -> {enm: def_id, var: def_id} {
+ alt d { def_variant(enum_id, var_id) {
+ ret {enm: enum_id, var: var_id}; }
+ _ { fail "non-variant in variant_def_ids"; } }
}
fn def_id_of_def(d: def) -> def_id {
def_fn(id, _) | def_self(id) | def_mod(id) |
def_native_mod(id) | def_const(id) | def_arg(id, _) | def_local(id, _) |
def_variant(_, id) | def_ty(id) | def_ty_param(id, _) |
- def_binding(id) | def_use(id) | def_native_ty(id) |
- def_upvar(id, _, _) { id }
+ def_binding(id) | def_use(id) | def_upvar(id, _, _) { id }
}
}
fn int_ty_to_str(t: int_ty) -> str {
alt t {
+ ty_char { "u8" } // ???
ty_i { "" } ty_i8 { "i8" } ty_i16 { "i16" }
ty_i32 { "i32" } ty_i64 { "i64" }
}
alt t {
ty_i8 { 0x80u64 }
ty_i16 { 0x800u64 }
- ty_char | ty_i32 { 0x80000000u64 }
+ ty_i | ty_char | ty_i32 { 0x80000000u64 } // actually ni about ty_i
ty_i64 { 0x8000000000000000u64 }
}
}
alt t {
ty_u8 { 0xffu64 }
ty_u16 { 0xffffu64 }
- ty_u32 { 0xffffffffu64 }
+ ty_u | ty_u32 { 0xffffffffu64 } // actually ni about ty_u
ty_u64 { 0xffffffffffffffffu64 }
}
}
ret {node: blk_, span: e.span};
}
-fn default_block(stmts1: [@stmt], expr1: option::t<@expr>, id1: node_id) ->
+fn default_block(stmts1: [@stmt], expr1: option<@expr>, id1: node_id) ->
blk_ {
{view_items: [], stmts: stmts1, expr: expr1, id: id1, rules: default_blk}
}
-// This is a convenience function to transfor ternary expressions to if
-// expressions so that they can be treated the same
-fn ternary_to_if(e: @expr) -> @expr {
- alt e.node {
- expr_ternary(cond, then, els) {
- let then_blk = block_from_expr(then);
- let els_blk = block_from_expr(els);
- let els_expr =
- @{id: els.id, node: expr_block(els_blk), span: els.span};
- ret @{id: e.id,
- node: expr_if(cond, then_blk, option::some(els_expr)),
- span: e.span};
- }
- _ { fail; }
- }
-}
-
// FIXME this doesn't handle big integer/float literals correctly (nor does
// the rest of our literal handling)
enum const_val {
const_float(f) { const_float(-f) }
const_int(i) { const_int(-i) }
const_uint(i) { const_uint(-i) }
+ _ { fail "eval_const_expr: bad neg argument"; }
}
}
expr_unary(not, inner) {
alt eval_const_expr(inner) {
const_int(i) { const_int(!i) }
const_uint(i) { const_uint(!i) }
+ _ { fail "eval_const_expr: bad not argument"; }
}
}
expr_binary(op, a, b) {
rem { const_float(a % b) } eq { fromb(a == b) }
lt { fromb(a < b) } le { fromb(a <= b) } ne { fromb(a != b) }
ge { fromb(a >= b) } gt { fromb(a > b) }
+ _ { fail "eval_const_expr: can't apply this binop to floats"; }
}
}
(const_int(a), const_int(b)) {
eq { fromb(a == b) } lt { fromb(a < b) }
le { fromb(a <= b) } ne { fromb(a != b) }
ge { fromb(a >= b) } gt { fromb(a > b) }
+ _ { fail "eval_const_expr: can't apply this binop to ints"; }
}
}
(const_uint(a), const_uint(b)) {
eq { fromb(a == b) } lt { fromb(a < b) }
le { fromb(a <= b) } ne { fromb(a != b) }
ge { fromb(a >= b) } gt { fromb(a > b) }
+ _ { fail "eval_const_expr: can't apply this binop to uints"; }
}
}
+ _ { fail "eval_constr_expr: bad binary arguments"; }
}
}
expr_lit(lit) { lit_to_const(lit) }
+ // Precondition?
+ _ {
+ fail "eval_const_expr: non-constant expression";
+ }
}
}
fn compare_const_vals(a: const_val, b: const_val) -> int {
alt (a, b) {
- (const_int(a), const_int(b)) { a == b ? 0 : a < b ? -1 : 1 }
- (const_uint(a), const_uint(b)) { a == b ? 0 : a < b ? -1 : 1 }
- (const_float(a), const_float(b)) { a == b ? 0 : a < b ? -1 : 1 }
- (const_str(a), const_str(b)) { a == b ? 0 : a < b ? -1 : 1 }
+ (const_int(a), const_int(b)) {
+ if a == b {
+ 0
+ } else if a < b {
+ -1
+ } else {
+ 1
+ }
+ }
+ (const_uint(a), const_uint(b)) {
+ if a == b {
+ 0
+ } else if a < b {
+ -1
+ } else {
+ 1
+ }
+ }
+ (const_float(a), const_float(b)) {
+ if a == b {
+ 0
+ } else if a < b {
+ -1
+ } else {
+ 1
+ }
+ }
+ (const_str(a), const_str(b)) {
+ if a == b {
+ 0
+ } else if a < b {
+ -1
+ } else {
+ 1
+ }
+ }
+ _ {
+ fail "compare_const_vals: ill-typed comparison";
+ }
}
}
@respan(s, {global: false, idents: [i], types: []})
}
+pure fn is_unguarded(&&a: arm) -> bool {
+ alt a.guard {
+ none { true }
+ _ { false }
+ }
+}
+
+pure fn unguarded_pat(a: arm) -> option<[@pat]> {
+ if is_unguarded(a) { some(a.pats) } else { none }
+}
+
// Provides an extra node_id to hang callee information on, in case the
// operator is deferred to a user-supplied method. The parser is responsible
// for reserving this id.
* with single-word things, rather than passing records all over the
* compiler.
*/
+
+type file_substr_ = {lo: uint, hi: uint, col: uint, line: uint};
+type file_substr = option<file_substr_>;
+
type filemap =
- @{name: filename, src: @str,
+ @{name: filename, substr: file_substr, src: @str,
start_pos: file_pos, mutable lines: [file_pos]};
type codemap = @{mutable files: [filemap]};
-type loc = {filename: filename, line: uint, col: uint};
+type loc = {file: filemap, line: uint, col: uint};
-fn new_codemap() -> codemap { ret @{mutable files: []}; }
+fn new_codemap() -> codemap { @{mutable files: [] } }
-fn new_filemap(filename: filename, src: @str,
- start_pos_ch: uint, start_pos_byte: uint)
+fn new_filemap_w_substr(filename: filename, substr: file_substr,
+ src: @str,
+ start_pos_ch: uint, start_pos_byte: uint)
-> filemap {
- ret @{name: filename, src: src,
+ ret @{name: filename, substr: substr, src: src,
start_pos: {ch: start_pos_ch, byte: start_pos_byte},
mutable lines: [{ch: start_pos_ch, byte: start_pos_byte}]};
}
+fn new_filemap(filename: filename, src: @str,
+ start_pos_ch: uint, start_pos_byte: uint)
+ -> filemap {
+ ret new_filemap_w_substr(filename, none, src,
+ start_pos_ch, start_pos_byte);
+}
+
+fn get_substr_info(cm: codemap, lo: uint, hi: uint)
+ -> (filename, file_substr_)
+{
+ let pos = lookup_char_pos(cm, lo);
+ let name = #fmt("<%s:%u:%u>", pos.file.name, pos.line, pos.col);
+ ret (name, {lo: lo, hi: hi, col: pos.col, line: pos.line});
+}
+
fn next_line(file: filemap, chpos: uint, byte_pos: uint) {
file.lines += [{ch: chpos, byte: byte_pos}];
}
type lookup_fn = fn@(file_pos) -> uint;
-fn lookup_pos(map: codemap, pos: uint, lookup: lookup_fn) -> loc {
+fn lookup_line(map: codemap, pos: uint, lookup: lookup_fn)
+ -> {fm: filemap, line: uint}
+{
let len = vec::len(map.files);
let a = 0u;
let b = len;
if lookup(map.files[m].start_pos) > pos { b = m; } else { a = m; }
}
if (a >= len) {
- ret { filename: "-", line: 0u, col: 0u };
+ fail #fmt("position %u does not resolve to a source location", pos)
}
let f = map.files[a];
a = 0u;
let m = (a + b) / 2u;
if lookup(f.lines[m]) > pos { b = m; } else { a = m; }
}
- ret {filename: f.name, line: a + 1u, col: pos - lookup(f.lines[a])};
+ ret {fm: f, line: a};
+}
+
+fn lookup_pos(map: codemap, pos: uint, lookup: lookup_fn) -> loc {
+ let {fm: f, line: a} = lookup_line(map, pos, lookup);
+ ret {file: f, line: a + 1u, col: pos - lookup(f.lines[a])};
}
fn lookup_char_pos(map: codemap, pos: uint) -> loc {
enum opt_span {
- //hack (as opposed to option::t), to make `span` compile
+ //hack (as opposed to option), to make `span` compile
os_none,
os_some(@span),
}
fn span_to_str(sp: span, cm: codemap) -> str {
let cur = sp;
let res = "";
+ // FIXME: Should probably be doing pointer comparison on filemap
let prev_file = none;
while true {
let lo = lookup_char_pos(cm, cur.lo);
let hi = lookup_char_pos(cm, cur.hi);
res +=
#fmt["%s:%u:%u: %u:%u",
- if some(lo.filename) == prev_file {
+ if some(lo.file.name) == prev_file {
"-"
- } else { lo.filename }, lo.line, lo.col, hi.line, hi.col];
+ } else { lo.file.name }, lo.line, lo.col, hi.line, hi.col];
alt cur.expanded_from {
os_none { break; }
os_some(new_sp) {
cur = *new_sp;
- prev_file = some(lo.filename);
+ prev_file = some(lo.file.name);
res += "<<";
}
}
ret res;
}
-type file_lines = {name: str, lines: [uint]};
+type file_lines = {file: filemap, lines: [uint]};
fn span_to_lines(sp: span, cm: codemap::codemap) -> @file_lines {
let lo = lookup_char_pos(cm, sp.lo);
let hi = lookup_char_pos(cm, sp.hi);
+ // FIXME: Check for filemap?
let lines = [];
uint::range(lo.line - 1u, hi.line as uint) {|i| lines += [i]; };
- ret @{name: lo.filename, lines: lines};
+ ret @{file: lo.file, lines: lines};
}
-fn get_line(fm: filemap, line: int) -> str {
+fn get_line(fm: filemap, line: int) -> str unsafe {
let begin: uint = fm.lines[line].byte - fm.start_pos.byte;
let end: uint;
if line as uint < vec::len(fm.lines) - 1u {
// parsed. If we just slice the rest of the string, we'll print out
// the remainder of the file, which is undesirable.
end = str::byte_len(*fm.src);
- let rest = str::slice(*fm.src, begin, end);
+ let rest = str::unsafe::slice_bytes(*fm.src, begin, end);
let newline = str::index(rest, '\n' as u8);
if newline != -1 { end = begin + (newline as uint); }
}
- ret str::slice(*fm.src, begin, end);
+ ret str::unsafe::slice_bytes(*fm.src, begin, end);
+}
+
+fn lookup_byte_offset(cm: codemap::codemap, chpos: uint)
+ -> {fm: filemap, pos: uint}
+{
+ fn lookup(pos: file_pos) -> uint { ret pos.ch; }
+ let {fm,line} = lookup_line(cm,chpos,lookup);
+ let line_offset = fm.lines[line].byte - fm.start_pos.byte;
+ let col = chpos - fm.lines[line].ch;
+ let col_offset = str::byte_len_range(*fm.src, line_offset, col);
+ ret {fm: fm, pos: line_offset + col_offset};
+}
+
+fn span_to_snippet(sp: span, cm: codemap::codemap) -> str {
+ let begin = lookup_byte_offset(cm,sp.lo);
+ let end = lookup_byte_offset(cm,sp.hi);
+ assert begin.fm == end.fm;
+ ret str::slice(*begin.fm.src, begin.pos, end.pos);
+}
+
+fn get_snippet(cm: codemap::codemap, fidx: uint, lo: uint, hi: uint) -> str
+{
+ let fm = cm.files[fidx];
+ ret str::slice(*fm.src, lo, hi)
}
fn get_filemap(cm: codemap, filename: str) -> filemap {
import codemap;
type syntax_expander =
- fn@(ext_ctxt, span, @ast::expr, option::t<str>) -> @ast::expr;
+ fn@(ext_ctxt, span, ast::mac_arg, ast::mac_body) -> @ast::expr;
type macro_def = {ident: str, ext: syntax_extension};
type macro_definer =
- fn@(ext_ctxt, span, @ast::expr, option::t<str>) -> macro_def;
+ fn@(ext_ctxt, span, ast::mac_arg, ast::mac_body) -> macro_def;
enum syntax_extension {
normal(syntax_expander),
normal(ext::ident_to_str::expand_syntax_ext));
syntax_expanders.insert("log_syntax",
normal(ext::log_syntax::expand_syntax_ext));
+ syntax_expanders.insert("ast",
+ normal(ext::qquote::expand_ast));
ret syntax_expanders;
}
ret @{id: cx.next_id(), node: ast::expr_lit(sp_lit), span: sp};
}
+fn get_mac_arg(cx: ext_ctxt, sp: span, arg: ast::mac_arg) -> @ast::expr {
+ alt (arg) {
+ some(expr) {expr}
+ none {cx.span_fatal(sp, "missing macro args")}
+ }
+}
+fn get_mac_body(cx: ext_ctxt, sp: span, args: ast::mac_body)
+ -> ast::mac_body_
+{
+ alt (args) {
+ some(body) {body}
+ none {cx.span_fatal(sp, "missing macro body")}
+ }
+}
//
// Local Variables:
--- /dev/null
+import core::{vec, str, option};
+import option::{some};
+import codemap::span;
+import syntax::ext::base::ext_ctxt;
+
+// NOTE: Moved from fmt.rs which had this fixme:
+// FIXME: Cleanup the naming of these functions
+
+fn mk_lit(cx: ext_ctxt, sp: span, lit: ast::lit_) -> @ast::expr {
+ let sp_lit = @{node: lit, span: sp};
+ ret @{id: cx.next_id(), node: ast::expr_lit(sp_lit), span: sp};
+}
+fn mk_str(cx: ext_ctxt, sp: span, s: str) -> @ast::expr {
+ let lit = ast::lit_str(s);
+ ret mk_lit(cx, sp, lit);
+}
+fn mk_int(cx: ext_ctxt, sp: span, i: int) -> @ast::expr {
+ let lit = ast::lit_int(i as i64, ast::ty_i);
+ ret mk_lit(cx, sp, lit);
+}
+fn mk_uint(cx: ext_ctxt, sp: span, u: uint) -> @ast::expr {
+ let lit = ast::lit_uint(u as u64, ast::ty_u);
+ ret mk_lit(cx, sp, lit);
+}
+fn mk_binary(cx: ext_ctxt, sp: span, op: ast::binop,
+ lhs: @ast::expr, rhs: @ast::expr)
+ -> @ast::expr {
+ let binexpr = ast::expr_binary(op, lhs, rhs);
+ ret @{id: cx.next_id(), node: binexpr, span: sp};
+}
+fn mk_unary(cx: ext_ctxt, sp: span, op: ast::unop, e: @ast::expr)
+ -> @ast::expr {
+ let expr = ast::expr_unary(op, e);
+ ret @{id: cx.next_id(), node: expr, span: sp};
+}
+fn mk_path(cx: ext_ctxt, sp: span, idents: [ast::ident]) ->
+ @ast::expr {
+ let path = {global: false, idents: idents, types: []};
+ let sp_path = @{node: path, span: sp};
+ let pathexpr = ast::expr_path(sp_path);
+ ret @{id: cx.next_id(), node: pathexpr, span: sp};
+}
+fn mk_access_(cx: ext_ctxt, sp: span, p: @ast::expr, m: ast::ident)
+ -> @ast::expr {
+ let expr = ast::expr_field(p, m, []);
+ ret @{id: cx.next_id(), node: expr, span: sp};
+}
+fn mk_access(cx: ext_ctxt, sp: span, p: [ast::ident], m: ast::ident)
+ -> @ast::expr {
+ let pathexpr = mk_path(cx, sp, p);
+ ret mk_access_(cx, sp, pathexpr, m);
+}
+fn mk_call_(cx: ext_ctxt, sp: span, fn_expr: @ast::expr,
+ args: [@ast::expr]) -> @ast::expr {
+ let callexpr = ast::expr_call(fn_expr, args, false);
+ ret @{id: cx.next_id(), node: callexpr, span: sp};
+}
+fn mk_call(cx: ext_ctxt, sp: span, fn_path: [ast::ident],
+ args: [@ast::expr]) -> @ast::expr {
+ let pathexpr = mk_path(cx, sp, fn_path);
+ ret mk_call_(cx, sp, pathexpr, args);
+}
+// e = expr, t = type
+fn mk_vec_e(cx: ext_ctxt, sp: span, exprs: [@ast::expr]) ->
+ @ast::expr {
+ let vecexpr = ast::expr_vec(exprs, ast::imm);
+ ret @{id: cx.next_id(), node: vecexpr, span: sp};
+}
+fn mk_rec_e(cx: ext_ctxt, sp: span,
+ fields: [{ident: ast::ident, ex: @ast::expr}]) ->
+ @ast::expr {
+ let astfields: [ast::field] = [];
+ for field: {ident: ast::ident, ex: @ast::expr} in fields {
+ let ident = field.ident;
+ let val = field.ex;
+ let astfield =
+ {node: {mut: ast::imm, ident: ident, expr: val}, span: sp};
+ astfields += [astfield];
+ }
+ let recexpr = ast::expr_rec(astfields, option::none::<@ast::expr>);
+ ret @{id: cx.next_id(), node: recexpr, span: sp};
+}
+
import base::*;
import syntax::ast;
-fn expand_syntax_ext(cx: ext_ctxt, sp: codemap::span, arg: @ast::expr,
- _body: option::t<str>) -> @ast::expr {
+fn expand_syntax_ext(cx: ext_ctxt, sp: codemap::span, arg: ast::mac_arg,
+ _body: ast::mac_body) -> @ast::expr {
+ let arg = get_mac_arg(cx,sp,arg);
let args: [@ast::expr] =
alt arg.node {
ast::expr_vec(elts, _) { elts }
import base::*;
export expand_syntax_ext;
-fn expand_syntax_ext(cx: ext_ctxt, sp: codemap::span, arg: @ast::expr,
- _body: option::t<str>) -> @ast::expr {
+fn expand_syntax_ext(cx: ext_ctxt, sp: codemap::span, arg: ast::mac_arg,
+ _body: ast::mac_body) -> @ast::expr {
+ let arg = get_mac_arg(cx,sp,arg);
let args: [@ast::expr] =
alt arg.node {
ast::expr_vec(elts, _) { elts }
cx.span_fatal(sp, "malformed #env call");
}
// FIXME: if this was more thorough it would manufacture an
- // option::t<str> rather than just an maybe-empty string.
+ // option<str> rather than just an maybe-empty string.
let var = expr_to_str(cx, args[0], "#env requires a string");
alt generic_os::getenv(var) {
import std::map::hashmap;
import vec;
-import syntax::ast::{crate, expr_, expr_mac, mac_invoc};
+import syntax::ast::{crate, expr_, expr_mac, mac_invoc, mac_qq};
import syntax::fold::*;
import syntax::ext::base::*;
+import syntax::ext::qquote::{expand_qquote,qq_helper};
import syntax::parse::parser::parse_expr_from_source_str;
import codemap::span;
}
}
}
+ mac_qq(sp, exp) {
+ let r = expand_qquote(cx, sp, none, exp);
+ // need to keep going, resuls may contain embedded qquote or
+ // macro that need expanding
+ let r2 = fld.fold_expr(r);
+ (r2.node, s)
+ }
_ { cx.span_bug(mac.span, "naked syntactic bit") }
}
}
{fold_expr: bind expand_expr(exts, cx, _, _, _, afp.fold_expr)
with *afp};
let f = make_fold(f_pre);
- let cm = parse_expr_from_source_str("<anon>", @core_macros(),
+ let cm = parse_expr_from_source_str("<core-macros>",
+ @core_macros(),
sess.opts.cfg,
sess.parse_sess);
import extfmt::ct::*;
import base::*;
import codemap::span;
+import syntax::ext::build::*;
export expand_syntax_ext;
-fn expand_syntax_ext(cx: ext_ctxt, sp: span, arg: @ast::expr,
- _body: option::t<str>) -> @ast::expr {
+fn expand_syntax_ext(cx: ext_ctxt, sp: span, arg: ast::mac_arg,
+ _body: ast::mac_body) -> @ast::expr {
+ let arg = get_mac_arg(cx,sp,arg);
let args: [@ast::expr] =
alt arg.node {
ast::expr_vec(elts, _) { elts }
// FIXME: A lot of these functions for producing expressions can probably
// be factored out in common with other code that builds expressions.
// FIXME: Cleanup the naming of these functions
+// NOTE: Moved many of the common ones to build.rs --kevina
fn pieces_to_expr(cx: ext_ctxt, sp: span, pieces: [piece], args: [@ast::expr])
-> @ast::expr {
- fn make_new_lit(cx: ext_ctxt, sp: span, lit: ast::lit_) -> @ast::expr {
- let sp_lit = @{node: lit, span: sp};
- ret @{id: cx.next_id(), node: ast::expr_lit(sp_lit), span: sp};
- }
- fn make_new_str(cx: ext_ctxt, sp: span, s: str) -> @ast::expr {
- let lit = ast::lit_str(s);
- ret make_new_lit(cx, sp, lit);
- }
- fn make_new_int(cx: ext_ctxt, sp: span, i: int) -> @ast::expr {
- let lit = ast::lit_int(i as i64, ast::ty_i);
- ret make_new_lit(cx, sp, lit);
- }
- fn make_new_uint(cx: ext_ctxt, sp: span, u: uint) -> @ast::expr {
- let lit = ast::lit_uint(u as u64, ast::ty_u);
- ret make_new_lit(cx, sp, lit);
- }
- fn make_add_expr(cx: ext_ctxt, sp: span, lhs: @ast::expr, rhs: @ast::expr)
- -> @ast::expr {
- let binexpr = ast::expr_binary(ast::add, lhs, rhs);
- ret @{id: cx.next_id(), node: binexpr, span: sp};
- }
- fn make_path_expr(cx: ext_ctxt, sp: span, idents: [ast::ident]) ->
- @ast::expr {
- let path = {global: false, idents: idents, types: []};
- let sp_path = @{node: path, span: sp};
- let pathexpr = ast::expr_path(sp_path);
- ret @{id: cx.next_id(), node: pathexpr, span: sp};
- }
- fn make_vec_expr(cx: ext_ctxt, sp: span, exprs: [@ast::expr]) ->
- @ast::expr {
- let vecexpr = ast::expr_vec(exprs, ast::imm);
- ret @{id: cx.next_id(), node: vecexpr, span: sp};
- }
- fn make_call(cx: ext_ctxt, sp: span, fn_path: [ast::ident],
- args: [@ast::expr]) -> @ast::expr {
- let pathexpr = make_path_expr(cx, sp, fn_path);
- let callexpr = ast::expr_call(pathexpr, args, false);
- ret @{id: cx.next_id(), node: callexpr, span: sp};
- }
- fn make_rec_expr(cx: ext_ctxt, sp: span,
- fields: [{ident: ast::ident, ex: @ast::expr}]) ->
- @ast::expr {
- let astfields: [ast::field] = [];
- for field: {ident: ast::ident, ex: @ast::expr} in fields {
- let ident = field.ident;
- let val = field.ex;
- let astfield =
- {node: {mut: ast::imm, ident: ident, expr: val}, span: sp};
- astfields += [astfield];
- }
- let recexpr = ast::expr_rec(astfields, option::none::<@ast::expr>);
- ret @{id: cx.next_id(), node: recexpr, span: sp};
- }
fn make_path_vec(_cx: ext_ctxt, ident: ast::ident) -> [ast::ident] {
ret ["extfmt", "rt", ident];
}
fn make_rt_path_expr(cx: ext_ctxt, sp: span, ident: str) -> @ast::expr {
let path = make_path_vec(cx, ident);
- ret make_path_expr(cx, sp, path);
+ ret mk_path(cx, sp, path);
}
// Produces an AST expression that represents a RT::conv record,
// which tells the RT::conv* functions how to perform the conversion
if vec::len::<@ast::expr>(flagexprs) == 0u {
flagexprs += [make_rt_path_expr(cx, sp, "flag_none")];
}
- ret make_vec_expr(cx, sp, flagexprs);
+ ret mk_vec_e(cx, sp, flagexprs);
}
fn make_count(cx: ext_ctxt, sp: span, cnt: count) -> @ast::expr {
alt cnt {
ret make_rt_path_expr(cx, sp, "count_implied");
}
count_is(c) {
- let count_lit = make_new_int(cx, sp, c);
+ let count_lit = mk_int(cx, sp, c);
let count_is_path = make_path_vec(cx, "count_is");
let count_is_args = [count_lit];
- ret make_call(cx, sp, count_is_path, count_is_args);
+ ret mk_call(cx, sp, count_is_path, count_is_args);
}
_ { cx.span_unimpl(sp, "unimplemented #fmt conversion"); }
}
fn make_conv_rec(cx: ext_ctxt, sp: span, flags_expr: @ast::expr,
width_expr: @ast::expr, precision_expr: @ast::expr,
ty_expr: @ast::expr) -> @ast::expr {
- ret make_rec_expr(cx, sp,
- [{ident: "flags", ex: flags_expr},
- {ident: "width", ex: width_expr},
- {ident: "precision", ex: precision_expr},
- {ident: "ty", ex: ty_expr}]);
+ ret mk_rec_e(cx, sp,
+ [{ident: "flags", ex: flags_expr},
+ {ident: "width", ex: width_expr},
+ {ident: "precision", ex: precision_expr},
+ {ident: "ty", ex: ty_expr}]);
}
let rt_conv_flags = make_flags(cx, sp, cnv.flags);
let rt_conv_width = make_count(cx, sp, cnv.width);
let path = make_path_vec(cx, fname);
let cnv_expr = make_rt_conv_expr(cx, sp, cnv);
let args = [cnv_expr, arg];
- ret make_call(cx, arg.span, path, args);
+ ret mk_call(cx, arg.span, path, args);
}
fn make_new_conv(cx: ext_ctxt, sp: span, cnv: conv, arg: @ast::expr) ->
@ast::expr {
}
let fmt_sp = args[0].span;
let n = 0u;
- let tmp_expr = make_new_str(cx, sp, "");
+ let tmp_expr = mk_str(cx, sp, "");
let nargs = vec::len::<@ast::expr>(args);
for pc: piece in pieces {
alt pc {
piece_string(s) {
- let s_expr = make_new_str(cx, fmt_sp, s);
- tmp_expr = make_add_expr(cx, fmt_sp, tmp_expr, s_expr);
+ let s_expr = mk_str(cx, fmt_sp, s);
+ tmp_expr = mk_binary(cx, fmt_sp, ast::add, tmp_expr, s_expr);
}
piece_conv(conv) {
n += 1u;
log_conv(conv);
let arg_expr = args[n];
let c_expr = make_new_conv(cx, fmt_sp, conv, arg_expr);
- tmp_expr = make_add_expr(cx, fmt_sp, tmp_expr, c_expr);
+ tmp_expr = mk_binary(cx, fmt_sp, ast::add, tmp_expr, c_expr);
}
}
}
import base::*;
import syntax::ast;
-fn expand_syntax_ext(cx: ext_ctxt, sp: codemap::span, arg: @ast::expr,
- _body: option::t<str>) -> @ast::expr {
+fn expand_syntax_ext(cx: ext_ctxt, sp: codemap::span, arg: ast::mac_arg,
+ _body: ast::mac_body) -> @ast::expr {
+ let arg = get_mac_arg(cx,sp,arg);
let args: [@ast::expr] =
alt arg.node {
ast::expr_vec(elts, _) { elts }
import syntax::ast;
import std::io::writer_util;
-fn expand_syntax_ext(cx: ext_ctxt, sp: codemap::span, arg: @ast::expr,
- _body: option::t<str>) -> @ast::expr {
-
+fn expand_syntax_ext(cx: ext_ctxt, sp: codemap::span, arg: ast::mac_arg,
+ _body: ast::mac_body) -> @ast::expr {
+ let arg = get_mac_arg(cx,sp,arg);
cx.print_backtrace();
std::io::stdout().write_line(print::pprust::expr_to_str(arg));
--- /dev/null
+import driver::session;
+
+import option::{none, some};
+
+import syntax::ast::{crate, expr_, mac_invoc,
+ mac_qq, mac_aq, mac_var};
+import syntax::fold::*;
+import syntax::visit::*;
+import syntax::ext::base::*;
+import syntax::ext::build::*;
+import syntax::parse::parser;
+import syntax::parse::parser::{parser, parse_from_source_str};
+
+import syntax::print::*;
+import std::io::*;
+
+import codemap::span;
+
+type aq_ctxt = @{lo: uint,
+ mutable gather: [{lo: uint, hi: uint,
+ e: @ast::expr,
+ constr: str}]};
+enum fragment {
+ from_expr(@ast::expr),
+ from_ty(@ast::ty)
+}
+
+iface qq_helper {
+ fn span() -> span;
+ fn visit(aq_ctxt, vt<aq_ctxt>);
+ fn extract_mac() -> option<ast::mac_>;
+ fn mk_parse_fn(ext_ctxt,span) -> @ast::expr;
+ fn get_fold_fn() -> str;
+}
+impl of qq_helper for @ast::expr {
+ fn span() -> span {self.span}
+ fn visit(cx: aq_ctxt, v: vt<aq_ctxt>) {visit_expr(self, cx, v);}
+ fn extract_mac() -> option<ast::mac_> {
+ alt (self.node) {
+ ast::expr_mac({node: mac, _}) {some(mac)}
+ _ {none}
+ }
+ }
+ fn mk_parse_fn(cx: ext_ctxt, sp: span) -> @ast::expr {
+ mk_path(cx, sp, ["syntax", "parse", "parser", "parse_expr"])
+ }
+ fn get_fold_fn() -> str {"fold_expr"}
+}
+impl of qq_helper for @ast::ty {
+ fn span() -> span {self.span}
+ fn visit(cx: aq_ctxt, v: vt<aq_ctxt>) {visit_ty(self, cx, v);}
+ fn extract_mac() -> option<ast::mac_> {
+ alt (self.node) {
+ ast::ty_mac({node: mac, _}) {some(mac)}
+ _ {none}
+ }
+ }
+ fn mk_parse_fn(cx: ext_ctxt, sp: span) -> @ast::expr {
+ mk_path(cx, sp, ["syntax", "ext", "qquote", "parse_ty"])
+ }
+ fn get_fold_fn() -> str {"fold_ty"}
+}
+impl of qq_helper for @ast::item {
+ fn span() -> span {self.span}
+ fn visit(cx: aq_ctxt, v: vt<aq_ctxt>) {visit_item(self, cx, v);}
+ fn extract_mac() -> option<ast::mac_> {fail}
+ fn mk_parse_fn(cx: ext_ctxt, sp: span) -> @ast::expr {
+ mk_path(cx, sp, ["syntax", "ext", "qquote", "parse_item"])
+ }
+ fn get_fold_fn() -> str {"fold_item"}
+}
+impl of qq_helper for @ast::stmt {
+ fn span() -> span {self.span}
+ fn visit(cx: aq_ctxt, v: vt<aq_ctxt>) {visit_stmt(self, cx, v);}
+ fn extract_mac() -> option<ast::mac_> {fail}
+ fn mk_parse_fn(cx: ext_ctxt, sp: span) -> @ast::expr {
+ mk_path(cx, sp, ["syntax", "ext", "qquote", "parse_stmt"])
+ }
+ fn get_fold_fn() -> str {"fold_stmt"}
+}
+impl of qq_helper for @ast::pat {
+ fn span() -> span {self.span}
+ fn visit(cx: aq_ctxt, v: vt<aq_ctxt>) {visit_pat(self, cx, v);}
+ fn extract_mac() -> option<ast::mac_> {fail}
+ fn mk_parse_fn(cx: ext_ctxt, sp: span) -> @ast::expr {
+ mk_path(cx, sp, ["syntax", "parse", "parser", "parse_pat"])
+ }
+ fn get_fold_fn() -> str {"fold_pat"}
+}
+
+fn gather_anti_quotes<N: qq_helper>(lo: uint, node: N) -> aq_ctxt
+{
+ let v = @{visit_expr: visit_aq_expr,
+ visit_ty: visit_aq_ty
+ with *default_visitor()};
+ let cx = @{lo:lo, mutable gather: []};
+ node.visit(cx, mk_vt(v));
+ ret cx;
+}
+
+fn visit_aq<T:qq_helper>(node: T, constr: str, &&cx: aq_ctxt, v: vt<aq_ctxt>)
+{
+ alt (node.extract_mac()) {
+ some(mac_aq(sp, e)) {
+ cx.gather += [{lo: sp.lo - cx.lo, hi: sp.hi - cx.lo,
+ e: e, constr: constr}];
+ }
+ _ {node.visit(cx, v);}
+ }
+}
+// FIXME: these are only here because I (kevina) couldn't figure out how to
+// get bind to work in gather_anti_quotes
+fn visit_aq_expr(node: @ast::expr, &&cx: aq_ctxt, v: vt<aq_ctxt>) {
+ visit_aq(node,"from_expr",cx,v);
+}
+fn visit_aq_ty(node: @ast::ty, &&cx: aq_ctxt, v: vt<aq_ctxt>) {
+ visit_aq(node,"from_ty",cx,v);
+}
+
+fn is_space(c: char) -> bool {
+ syntax::parse::lexer::is_whitespace(c)
+}
+
+fn expand_ast(ecx: ext_ctxt, _sp: span,
+ arg: ast::mac_arg, body: ast::mac_body)
+ -> @ast::expr
+{
+ let what = "expr";
+ option::may(arg) {|arg|
+ let args: [@ast::expr] =
+ alt arg.node {
+ ast::expr_vec(elts, _) { elts }
+ _ {
+ ecx.span_fatal
+ (_sp, "#ast requires arguments of the form `[...]`.")
+ }
+ };
+ if vec::len::<@ast::expr>(args) != 1u {
+ ecx.span_fatal(_sp, "#ast requires exactly one arg");
+ }
+ alt (args[0].node) {
+ ast::expr_path(@{node: {idents: id, _},_}) if vec::len(id) == 1u
+ {what = id[0]}
+ _ {ecx.span_fatal(args[0].span, "expected an identifier");}
+ }
+ }
+ let body = get_mac_body(ecx,_sp,body);
+ fn finish<T: qq_helper>(ecx: ext_ctxt, body: ast::mac_body_,
+ f: fn (p: parser) -> T)
+ -> @ast::expr
+ {
+ let cm = ecx.session().parse_sess.cm;
+ let str = @codemap::span_to_snippet(body.span, cm);
+ let (fname, ss) = codemap::get_substr_info
+ (cm, body.span.lo, body.span.hi);
+ let node = parse_from_source_str
+ (f, fname, some(ss), str,
+ ecx.session().opts.cfg, ecx.session().parse_sess);
+ ret expand_qquote(ecx, node.span(), some(*str), node);
+ }
+
+ ret alt what {
+ "expr" {finish(ecx, body, parser::parse_expr)}
+ "ty" {finish(ecx, body, parse_ty)}
+ "item" {finish(ecx, body, parse_item)}
+ "stmt" {finish(ecx, body, parse_stmt)}
+ "pat" {finish(ecx, body, parser::parse_pat)}
+ _ {ecx.span_fatal(_sp, "unsupported ast type")}
+ };
+}
+
+fn parse_ty(p: parser) -> @ast::ty {
+ parser::parse_ty(p, false)
+}
+
+fn parse_stmt(p: parser) -> @ast::stmt {
+ parser::parse_stmt(p, [])
+}
+
+fn parse_item(p: parser) -> @ast::item {
+ alt (parser::parse_item(p, [])) {
+ some(item) {item}
+ none {fail; /* FIXME: Error message, somehow */}
+ }
+}
+
+fn expand_qquote<N: qq_helper>
+ (ecx: ext_ctxt, sp: span, maybe_str: option::t<str>, node: N)
+ -> @ast::expr
+{
+ let str = alt(maybe_str) {
+ some(s) {s}
+ none {codemap::span_to_snippet(sp, ecx.session().parse_sess.cm)}
+ };
+ let qcx = gather_anti_quotes(sp.lo, node);
+ let cx = qcx;
+ let prev = 0u;
+ for {lo: lo, _} in cx.gather {
+ assert lo > prev;
+ prev = lo;
+ }
+ let str2 = "";
+ enum state {active, skip(uint), blank};
+ let state = active;
+ let i = 0u, j = 0u;
+ let g_len = vec::len(cx.gather);
+ str::chars_iter(str) {|ch|
+ if (j < g_len && i == cx.gather[j].lo) {
+ assert ch == '$';
+ let repl = #fmt("$%u ", j);
+ state = skip(str::char_len(repl));
+ str2 += repl;
+ }
+ alt state {
+ active {str::push_char(str2, ch);}
+ skip(1u) {state = blank;}
+ skip(sk) {state = skip (sk-1u);}
+ blank if is_space(ch) {str::push_char(str2, ch);}
+ blank {str::push_char(str2, ' ');}
+ }
+ i += 1u;
+ if (j < g_len && i == cx.gather[j].hi) {
+ assert ch == ')';
+ state = active;
+ j += 1u;
+ }
+ }
+
+ let cx = ecx;
+ let session_call = bind mk_call_(cx,sp,
+ mk_access(cx,sp,["ext_cx"], "session"),
+ []);
+ let pcall = mk_call(cx,sp,
+ ["syntax", "parse", "parser",
+ "parse_from_source_str"],
+ [node.mk_parse_fn(cx,sp),
+ mk_str(cx,sp, "<anon>"),
+ mk_path(cx,sp, ["option","none"]),
+ mk_unary(cx,sp, ast::box(ast::imm),
+ mk_str(cx,sp, str2)),
+ mk_access_(cx,sp,
+ mk_access_(cx,sp, session_call(), "opts"),
+ "cfg"),
+ mk_access_(cx,sp, session_call(), "parse_sess")]
+ );
+ let rcall = pcall;
+ if (g_len > 0u) {
+ rcall = mk_call(cx,sp,
+ ["syntax", "ext", "qquote", "replace"],
+ [pcall,
+ mk_vec_e(cx,sp, vec::map(copy qcx.gather) {|g|
+ mk_call(cx,sp,
+ ["syntax", "ext", "qquote", g.constr],
+ [g.e])}),
+ mk_path(cx,sp,
+ ["syntax", "ext", "qquote",
+ node.get_fold_fn()])]);
+ }
+ ret rcall;
+}
+
+fn replace<T>(node: T, repls: [fragment], ff: fn (ast_fold, T) -> T)
+ -> T
+{
+ let aft = default_ast_fold();
+ let f_pre = {fold_expr: bind replace_expr(repls, _, _, _,
+ aft.fold_expr),
+ fold_ty: bind replace_ty(repls, _, _, _,
+ aft.fold_ty)
+ with *aft};
+ ret ff(make_fold(f_pre), node);
+}
+fn fold_expr(f: ast_fold, &&n: @ast::expr) -> @ast::expr {f.fold_expr(n)}
+fn fold_ty(f: ast_fold, &&n: @ast::ty) -> @ast::ty {f.fold_ty(n)}
+fn fold_item(f: ast_fold, &&n: @ast::item) -> @ast::item {f.fold_item(n)}
+fn fold_stmt(f: ast_fold, &&n: @ast::stmt) -> @ast::stmt {f.fold_stmt(n)}
+fn fold_pat(f: ast_fold, &&n: @ast::pat) -> @ast::pat {f.fold_pat(n)}
+
+fn replace_expr(repls: [fragment],
+ e: ast::expr_, s: span, fld: ast_fold,
+ orig: fn@(ast::expr_, span, ast_fold)->(ast::expr_, span))
+ -> (ast::expr_, span)
+{
+ alt e {
+ ast::expr_mac({node: mac_var(i), _}) {
+ alt (repls[i]) {
+ from_expr(r) {(r.node, r.span)}
+ _ {fail /* fixme error message */}}}
+ _ {orig(e,s,fld)}
+ }
+}
+
+fn replace_ty(repls: [fragment],
+ e: ast::ty_, s: span, fld: ast_fold,
+ orig: fn@(ast::ty_, span, ast_fold)->(ast::ty_, span))
+ -> (ast::ty_, span)
+{
+ alt e {
+ ast::ty_mac({node: mac_var(i), _}) {
+ alt (repls[i]) {
+ from_ty(r) {(r.node, r.span)}
+ _ {fail /* fixme error message */}}}
+ _ {orig(e,s,fld)}
+ }
+}
+
+fn print_expr(expr: @ast::expr) {
+ let stdout = std::io::stdout();
+ let pp = pprust::rust_printer(stdout);
+ pprust::print_expr(pp, expr);
+ pp::eof(pp.s);
+ stdout.write_str("\n");
+}
+
+// Local Variables:
+// mode: rust
+// fill-column: 78;
+// indent-tabs-mode: nil
+// c-basic-offset: 4
+// buffer-file-coding-system: utf-8-unix
+// End:
import core::{vec, option};
import std::map::{hashmap, new_str_hash};
import option::{some, none};
+import driver::session::session;
-import base::{ext_ctxt, normal};
+import base::*;
import fold::*;
import ast_util::respan;
export add_new_extension;
-fn path_to_ident(pth: @path) -> option::t<ident> {
+fn path_to_ident(pth: @path) -> option<ident> {
if vec::len(pth.node.idents) == 1u && vec::len(pth.node.types) == 0u {
ret some(pth.node.idents[0u]);
}
// If we want better match failure error messages (like in Fortifying Syntax),
// we'll want to return something indicating amount of progress and location
// of failure instead of `none`.
-type match_result = option::t<arb_depth<matchable>>;
+type match_result = option<arb_depth<matchable>>;
type selector = fn@(matchable) -> match_result;
fn elts_to_ell(cx: ext_ctxt, elts: [@expr]) ->
- {pre: [@expr], rep: option::t<@expr>, post: [@expr]} {
+ {pre: [@expr], rep: option<@expr>, post: [@expr]} {
let idx: uint = 0u;
let res = none;
for elt: @expr in elts {
}
}
-fn option_flatten_map<T: copy, U: copy>(f: fn@(T) -> option::t<U>, v: [T]) ->
- option::t<[U]> {
+fn option_flatten_map<T: copy, U: copy>(f: fn@(T) -> option<U>, v: [T]) ->
+ option<[U]> {
let res = [];
for elem: T in v {
alt f(elem) { none { ret none; } some(fv) { res += [fv]; } }
bindings. Most of the work is done in p_t_s, which generates the
selectors. */
-fn use_selectors_to_bind(b: binders, e: @expr) -> option::t<bindings> {
+fn use_selectors_to_bind(b: binders, e: @expr) -> option<bindings> {
let res = new_str_hash::<arb_depth<matchable>>();
//need to do this first, to check vec lengths.
for sel: selector in b.literal_ast_matchers {
ret res;
}
-fn follow_for_trans(cx: ext_ctxt, mmaybe: option::t<arb_depth<matchable>>,
- idx_path: @mutable [uint]) -> option::t<matchable> {
+fn follow_for_trans(cx: ext_ctxt, mmaybe: option<arb_depth<matchable>>,
+ idx_path: @mutable [uint]) -> option<matchable> {
alt mmaybe {
none { ret none }
some(m) {
alt repeat_me_maybe {
none { }
some(repeat_me) {
- let repeat: option::t<{rep_count: uint, name: ident}> = none;
+ let repeat: option<{rep_count: uint, name: ident}> = none;
/* we need to walk over all the free vars in lockstep, except for
the leaves, which are just duplicated */
free_vars(b, repeat_me) {|fv|
}
}
}
-
-
-
-
-
/* TODO: handle embedded types and blocks, at least */
expr_mac(mac) {
p_t_s_r_mac(cx, mac, s, b);
}
}
}
+ _ {
+ cx.session().bug("undocumented invariant in p_t_s_rec");
+ }
}
}
}
}
-fn block_to_ident(blk: blk_) -> option::t<ident> {
+fn block_to_ident(blk: blk_) -> option<ident> {
if vec::len(blk.stmts) != 0u { ret none; }
ret alt blk.expr {
some(expr) {
none { no_des(cx, blk.span, "under `#{}`"); }
}
}
+ ast::mac_qq(_,_) { no_des(cx, mac.span, "quasiquotes"); }
+ ast::mac_aq(_,_) { no_des(cx, mac.span, "antiquotes"); }
+ ast::mac_var(_) { no_des(cx, mac.span, "antiquote variables"); }
}
}
}
}
-fn add_new_extension(cx: ext_ctxt, sp: span, arg: @expr,
- _body: option::t<str>) -> base::macro_def {
+fn add_new_extension(cx: ext_ctxt, sp: span, arg: ast::mac_arg,
+ _body: ast::mac_body) -> base::macro_def {
+ let arg = get_mac_arg(cx,sp,arg);
let args: [@ast::expr] =
alt arg.node {
ast::expr_vec(elts, _) { elts }
}
};
- let macro_name: option::t<str> = none;
+ let macro_name: option<str> = none;
let clauses: [@clause] = [];
for arg: @expr in args {
alt arg.node {
}
}
clauses +=
- [@{params: pattern_to_selectors(cx, invoc_arg),
+ [@{params: pattern_to_selectors
+ (cx, get_mac_arg(cx,mac.span,invoc_arg)),
body: elts[1u]}];
+
// FIXME: check duplicates (or just simplify
// the macro arg situation)
}
+ _ {
+ cx.span_bug(mac.span, "undocumented invariant in \
+ add_extension");
+ }
}
}
_ {
},
ext: normal(ext)};
- fn generic_extension(cx: ext_ctxt, sp: span, arg: @expr,
- _body: option::t<str>, clauses: [@clause]) -> @expr {
+ fn generic_extension(cx: ext_ctxt, sp: span, arg: ast::mac_arg,
+ _body: ast::mac_body, clauses: [@clause]) -> @expr {
+ let arg = get_mac_arg(cx,sp,arg);
for c: @clause in clauses {
alt use_selectors_to_bind(c.params, arg) {
some(bindings) { ret transcribe(cx, bindings, c.body); }
fold_view_item: fn@(view_item_, ast_fold) -> view_item_,
fold_native_item: fn@(&&@native_item, ast_fold) -> @native_item,
fold_item: fn@(&&@item, ast_fold) -> @item,
+ fold_class_item: fn@(&&@class_item, ast_fold) -> @class_item,
fold_item_underscore: fn@(item_, ast_fold) -> item_,
fold_method: fn@(&&@method, ast_fold) -> @method,
fold_block: fn@(blk_, span, ast_fold) -> (blk_, span),
fold_view_item: fn@(&&@view_item) -> @view_item,
fold_native_item: fn@(&&@native_item) -> @native_item,
fold_item: fn@(&&@item) -> @item,
+ fold_class_item: fn@(&&@class_item) -> @class_item,
fold_item_underscore: fn@(item_) -> item_,
fold_method: fn@(&&@method) -> @method,
fold_block: fn@(blk) -> blk,
fn nf_view_item_dummy(&&_v: @view_item) -> @view_item { fail; }
fn nf_native_item_dummy(&&_n: @native_item) -> @native_item { fail; }
fn nf_item_dummy(&&_i: @item) -> @item { fail; }
+fn nf_class_item_dummy(&&_ci: @class_item) -> @class_item { fail; }
fn nf_item_underscore_dummy(_i: item_) -> item_ { fail; }
fn nf_method_dummy(&&_m: @method) -> @method { fail; }
fn nf_blk_dummy(_b: blk) -> blk { fail; }
ret {node:
alt m.node {
mac_invoc(pth, arg, body) {
- mac_invoc(fld.fold_path(pth), fld.fold_expr(arg), body)
+ mac_invoc(fld.fold_path(pth),
+ // FIXME: bind should work, but causes a crash
+ option::map(arg) {|arg| fld.fold_expr(arg)},
+ body)
}
mac_embed_type(ty) { mac_embed_type(fld.fold_ty(ty)) }
mac_embed_block(blk) { mac_embed_block(fld.fold_block(blk)) }
mac_ellipsis { mac_ellipsis }
+ mac_qq(_,_) { /* fixme */ m.node }
+ mac_aq(_,_) { /* fixme */ m.node }
+ mac_var(_) { /* fixme */ m.node }
},
span: m.span};
}
attrs: vec::map(ni.attrs, fold_attribute),
node:
alt ni.node {
- native_item_ty { native_item_ty }
native_item_fn(fdec, typms) {
native_item_fn({inputs: vec::map(fdec.inputs, fold_arg),
output: fld.fold_ty(fdec.output),
span: i.span};
}
+fn noop_fold_class_item(&&ci: @class_item, fld: ast_fold)
+ -> @class_item {
+ @{node: {
+ privacy:ci.node.privacy,
+ decl:
+ @alt *ci.node.decl {
+ instance_var(ident, t, cm, id) {
+ instance_var(ident, fld.fold_ty(t), cm, id)
+ }
+ class_method(i) { class_method(fld.fold_item(i)) }
+ }},
+ span: ci.span}
+}
+
fn noop_fold_item_underscore(i: item_, fld: ast_fold) -> item_ {
ret alt i {
item_const(t, e) { item_const(fld.fold_ty(t), fld.fold_expr(e)) }
item_enum(variants, typms) {
item_enum(vec::map(variants, fld.fold_variant), typms)
}
+ item_class(typms, items, ctor_decl, ctor_body) {
+ item_class(typms,
+ vec::map(items, fld.fold_class_item),
+ fold_fn_decl(ctor_decl, fld),
+ fld.fold_block(ctor_body))
+ }
item_impl(tps, ifce, ty, methods) {
item_impl(tps, option::map(ifce, fld.fold_ty), fld.fold_ty(ty),
vec::map(methods, fld.fold_method))
expr_if(fld.fold_expr(cond), fld.fold_block(tr),
option::map(fl, fld.fold_expr))
}
- expr_ternary(cond, tr, fl) {
- expr_ternary(fld.fold_expr(cond), fld.fold_expr(tr),
- fld.fold_expr(fl))
- }
expr_while(cond, body) {
expr_while(fld.fold_expr(cond), fld.fold_block(body))
}
}
}
-fn noop_fold_ty(t: ty_, _fld: ast_fold) -> ty_ {
- //drop in ty::fold_ty here if necessary
- ret t;
+fn noop_fold_ty(t: ty_, fld: ast_fold) -> ty_ {
+ let fold_mac = bind fold_mac_(_, fld);
+ fn fold_mt(mt: mt, fld: ast_fold) -> mt {
+ {ty: fld.fold_ty(mt.ty), mut: mt.mut}
+ }
+ fn fold_field(f: ty_field, fld: ast_fold) -> ty_field {
+ {node: {ident: fld.fold_ident(f.node.ident),
+ mt: fold_mt(f.node.mt, fld)},
+ span: fld.new_span(f.span)}
+ }
+ alt t {
+ ty_nil | ty_bot | ty_bool | ty_str {t}
+ ty_int(_) | ty_uint(_) | ty_float(_) {t}
+ ty_box(mt) {ty_box(fold_mt(mt, fld))}
+ ty_uniq(mt) {ty_uniq(fold_mt(mt, fld))}
+ ty_vec(mt) {ty_vec(fold_mt(mt, fld))}
+ ty_ptr(mt) {ty_ptr(fold_mt(mt, fld))}
+ ty_rec(fields) {ty_rec(vec::map(fields) {|f| fold_field(f, fld)})}
+ ty_fn(proto, decl) {ty_fn(proto, fold_fn_decl(decl, fld))}
+ ty_tup(tys) {ty_tup(vec::map(tys) {|ty| fld.fold_ty(ty)})}
+ ty_path(path, id) {ty_path(fld.fold_path(path), fld.new_id(id))}
+ // FIXME: constrs likely needs to be folded...
+ ty_constr(ty, constrs) {ty_constr(fld.fold_ty(ty), constrs)}
+ ty_mac(mac) {ty_mac(fold_mac(mac))}
+ ty_infer {t}
+ }
}
fn noop_fold_constr(c: constr_, fld: ast_fold) -> constr_ {
fold_view_item: noop_fold_view_item,
fold_native_item: noop_fold_native_item,
fold_item: noop_fold_item,
+ fold_class_item: noop_fold_class_item,
fold_item_underscore: noop_fold_item_underscore,
fold_method: noop_fold_method,
fold_block: wrap(noop_fold_block),
fold_view_item: bind nf_view_item_dummy(_),
fold_native_item: bind nf_native_item_dummy(_),
fold_item: bind nf_item_dummy(_),
+ fold_class_item: bind nf_class_item_dummy(_),
fold_item_underscore: bind nf_item_underscore_dummy(_),
fold_method: bind nf_method_dummy(_),
fold_block: bind nf_blk_dummy(_),
fn f_item(afp: ast_fold_precursor, f: ast_fold, &&i: @item) -> @item {
ret afp.fold_item(i, f);
}
+ fn f_class_item(afp: ast_fold_precursor, f: ast_fold,
+ &&ci: @class_item) -> @class_item {
+ @{node:
+ {privacy:ci.node.privacy,
+ decl:
+ @alt *ci.node.decl {
+ instance_var(nm, t, mt, id) {
+ instance_var(nm, f_ty(afp, f, t),
+ mt, id)
+ }
+ class_method(i) {
+ class_method(afp.fold_item(i, f))
+ }
+ }}, span: ci.span}
+ }
fn f_item_underscore(afp: ast_fold_precursor, f: ast_fold, i: item_) ->
item_ {
ret afp.fold_item_underscore(i, f);
fold_view_item: bind f_view_item(afp, result, _),
fold_native_item: bind f_native_item(afp, result, _),
fold_item: bind f_item(afp, result, _),
+ fold_class_item: bind f_class_item(afp, result, _),
fold_item_underscore: bind f_item_underscore(afp, result, _),
fold_method: bind f_method(afp, result, _),
fold_block: bind f_block(afp, result, _),
}
fn eval_crate_directives_to_mod(cx: ctx, cdirs: [@ast::crate_directive],
- prefix: str, suffix: option::t<str>)
+ prefix: str, suffix: option<str>)
-> (ast::_mod, [ast::attribute]) {
#debug("eval crate prefix: %s", prefix);
#debug("eval crate suffix: %s",
We build the path to the companion mod by combining the prefix and the
optional suffix then adding the .rs extension.
*/
-fn parse_companion_mod(cx: ctx, prefix: str, suffix: option::t<str>)
+fn parse_companion_mod(cx: ctx, prefix: str, suffix: option<str>)
-> ([@ast::view_item], [@ast::item], [ast::attribute]) {
- fn companion_file(prefix: str, suffix: option::t<str>) -> str {
+ fn companion_file(prefix: str, suffix: option<str>) -> str {
ret alt suffix {
option::some(s) { fs::connect(prefix, s) }
option::none { prefix }
impl reader for reader {
fn is_eof() -> bool { self.curr == -1 as char }
- fn get_str_from(start: uint) -> str {
+ fn get_str_from(start: uint) -> str unsafe {
// I'm pretty skeptical about this subtraction. What if there's a
// multi-byte character before the mark?
- ret str::slice(*self.src, start - 1u, self.pos - 1u);
+ ret str::unsafe::slice_bytes(*self.src, start - 1u, self.pos - 1u);
}
fn next() -> char {
if self.pos < self.len {
be consume_whitespace_and_comments(rdr);
}
-fn scan_exponent(rdr: reader) -> option::t<str> {
+fn scan_exponent(rdr: reader) -> option<str> {
let c = rdr.curr;
let rslt = "";
if c == 'e' || c == 'E' {
c = rdr.curr;
n = rdr.next();
if c == 'u' || c == 'i' {
- let signed = c == 'i', tp = signed ? either::left(ast::ty_i)
- : either::right(ast::ty_u);
+ let signed = c == 'i', tp = if signed { either::left(ast::ty_i) }
+ else { either::right(ast::ty_u) };
rdr.bump();
c = rdr.curr;
if c == '8' {
rdr.bump();
- tp = signed ? either::left(ast::ty_i8)
- : either::right(ast::ty_u8);
+ tp = if signed { either::left(ast::ty_i8) }
+ else { either::right(ast::ty_u8) };
}
n = rdr.next();
if c == '1' && n == '6' {
rdr.bump();
rdr.bump();
- tp = signed ? either::left(ast::ty_i16)
- : either::right(ast::ty_u16);
+ tp = if signed { either::left(ast::ty_i16) }
+ else { either::right(ast::ty_u16) };
} else if c == '3' && n == '2' {
rdr.bump();
rdr.bump();
- tp = signed ? either::left(ast::ty_i32)
- : either::right(ast::ty_u32);
+ tp = if signed { either::left(ast::ty_i32) }
+ else { either::right(ast::ty_u32) };
} else if c == '6' && n == '4' {
rdr.bump();
rdr.bump();
- tp = signed ? either::left(ast::ty_i64)
- : either::right(ast::ty_u64);
+ tp = if signed { either::left(ast::ty_i64) }
+ else { either::right(ast::ty_u64) };
}
let parsed = u64::from_str(num_str, base as u64);
alt tp {
// One-byte tokens.
- '?' {
- rdr.bump();
- ret token::QUES;
- }
';' { rdr.bump(); ret token::SEMI; }
',' { rdr.bump(); ret token::COMMA; }
'.' {
'#' {
rdr.bump();
if rdr.curr == '<' { rdr.bump(); ret token::POUND_LT; }
+ if rdr.curr == '(' { rdr.bump(); ret token::POUND_LPAREN; }
if rdr.curr == '{' { rdr.bump(); ret token::POUND_LBRACE; }
ret token::POUND;
}
} else { ret token::COLON; }
}
+ '$' {
+ rdr.bump();
+ if is_dec_digit(rdr.curr) {
+ let val = dec_digit_val(rdr.curr) as uint;
+ while is_dec_digit(rdr.next()) {
+ rdr.bump();
+ val = val * 10u + (dec_digit_val(rdr.curr) as uint);
+ }
+ rdr.bump();
+ ret token::DOLLAR_NUM(val);
+ } else if rdr.curr == '(' {
+ rdr.bump();
+ ret token::DOLLAR_LPAREN;
+ } else {
+ rdr.fatal("expected digit");
+ }
+ }
+
ret true;
}
-fn trim_whitespace_prefix_and_push_line(&lines: [str], s: str, col: uint) {
+fn trim_whitespace_prefix_and_push_line(&lines: [str],
+ s: str, col: uint) unsafe {
let s1;
if all_whitespace(s, 0u, col) {
if col < str::byte_len(s) {
- s1 = str::slice(s, col, str::byte_len(s));
+ s1 = str::unsafe::slice_bytes(s, col, str::byte_len(s));
} else { s1 = ""; }
} else { s1 = s; }
log(debug, "pushing line: " + s1);
}
let tok = next_token(rdr);
if is_lit(tok.tok) {
- literals += [{lit: rdr.get_str_from(tok.bpos), pos: tok.chpos}];
+ let s = rdr.get_str_from(tok.bpos);
+ literals += [{lit: s, pos: tok.chpos}];
+ log(debug, "tok lit: " + s);
+ } else {
+ log(debug, "tok: " + token::to_str(rdr, tok.tok));
}
- log(debug, "tok: " + token::to_str(rdr, tok.tok));
first_read = false;
}
ret {cmnts: comments, lits: literals};
}
fn new_parser_from_source_str(sess: parse_sess, cfg: ast::crate_cfg,
- name: str, source: @str) -> parser {
+ name: str, ss: codemap::file_substr,
+ source: @str) -> parser {
let ftype = SOURCE_FILE;
- let filemap = codemap::new_filemap(name, source,
- sess.chpos, sess.byte_pos);
+ let filemap = codemap::new_filemap_w_substr
+ (name, ss, source, sess.chpos, sess.byte_pos);
sess.cm.files += [filemap];
let itr = @interner::mk(str::hash, str::eq);
let rdr = lexer::new_reader(sess.cm, sess.span_diagnostic,
}
}
-fn parse_ty_fn(proto: ast::proto, p: parser) -> ast::ty_ {
+fn parse_ty_fn(p: parser) -> ast::fn_decl {
fn parse_fn_input_ty(p: parser) -> ast::arg {
let mode = parse_arg_mode(p);
let name = if is_plain_ident(p) && p.look_ahead(1u) == token::COLON {
// auto constrs = parse_constrs(~[], p);
let constrs: [@ast::constr] = [];
let (ret_style, ret_ty) = parse_ret_ty(p);
- ret ast::ty_fn(proto, {inputs: inputs.node, output: ret_ty,
+ ret {inputs: inputs.node, output: ret_ty,
purity: ast::impure_fn, cf: ret_style,
- constraints: constrs});
+ constraints: constrs};
}
fn parse_ty_methods(p: parser) -> [ast::ty_method] {
parse_seq(token::LBRACE, token::RBRACE, seq_sep_none(), {|p|
+ let attrs = parse_outer_attributes(p);
let flo = p.span.lo;
expect_word(p, "fn");
let ident = parse_method_name(p);
let tps = parse_ty_params(p);
- let f = parse_ty_fn(ast::proto_bare, p), fhi = p.last_span.hi;
+ let d = parse_ty_fn(p), fhi = p.last_span.hi;
expect(p, token::SEMI);
- alt f {
- ast::ty_fn(_, d) {
- {ident: ident, decl: d, tps: tps,
- span: ast_util::mk_sp(flo, fhi)}
- }
- }
- }, p).node
+ {ident: ident, attrs: attrs, decl: d, tps: tps,
+ span: ast_util::mk_sp(flo, fhi)}}, p).node
}
fn parse_mt(p: parser) -> ast::mt {
fn parse_ty(p: parser, colons_before_params: bool) -> @ast::ty {
let lo = p.span.lo;
+
+ alt have_dollar(p) {
+ some(e) {ret @spanned(lo, p.span.hi,
+ ast::ty_mac(spanned(lo, p.span.hi, e)))}
+ none {}
+ }
+
let t: ast::ty_;
// FIXME: do something with this
ast::proto_bare { p.warn("fn is deprecated, use native fn"); }
_ { /* fallthrough */ }
}
- t = parse_ty_fn(proto, p);
+ t = ast::ty_fn(proto, parse_ty_fn(p));
} else if eat_word(p, "native") {
expect_word(p, "fn");
- t = parse_ty_fn(ast::proto_bare, p);
+ t = ast::ty_fn(ast::proto_bare, parse_ty_fn(p));
} else if p.token == token::MOD_SEP || is_ident(p.token) {
let path = parse_path(p);
t = ast::ty_path(path, p.get_id());
}
fn parse_arg_mode(p: parser) -> ast::mode {
- if eat(p, token::BINOP(token::AND)) { ast::by_mut_ref }
- else if eat(p, token::BINOP(token::MINUS)) { ast::by_move }
- else if eat(p, token::ANDAND) { ast::by_ref }
- else if eat(p, token::BINOP(token::PLUS)) {
- if eat(p, token::BINOP(token::PLUS)) { ast::by_val }
- else { ast::by_copy }
- }
- else { ast::mode_infer }
+ if eat(p, token::BINOP(token::AND)) {
+ ast::expl(ast::by_mut_ref)
+ } else if eat(p, token::BINOP(token::MINUS)) {
+ ast::expl(ast::by_move)
+ } else if eat(p, token::ANDAND) {
+ ast::expl(ast::by_ref)
+ } else if eat(p, token::BINOP(token::PLUS)) {
+ if eat(p, token::BINOP(token::PLUS)) {
+ ast::expl(ast::by_val)
+ } else {
+ ast::expl(ast::by_copy)
+ }
+ } else { ast::infer(p.get_id()) }
}
fn parse_arg(p: parser) -> ast::arg {
fn parse_fn_block_arg(p: parser) -> ast::arg {
let m = parse_arg_mode(p);
let i = parse_value_ident(p);
- let t = eat(p, token::COLON) ? parse_ty(p, false) :
- @spanned(p.span.lo, p.span.hi, ast::ty_infer);
+ let t = if eat(p, token::COLON) {
+ parse_ty(p, false)
+ } else {
+ @spanned(p.span.lo, p.span.hi, ast::ty_infer)
+ };
ret {mode: m, ty: t, ident: i, id: p.get_id()};
}
-fn parse_seq_to_before_gt<T: copy>(sep: option::t<token::token>,
+fn parse_seq_to_before_gt<T: copy>(sep: option<token::token>,
f: fn(parser) -> T,
p: parser) -> [T] {
let first = true;
ret v;
}
-fn parse_seq_to_gt<T: copy>(sep: option::t<token::token>,
+fn parse_seq_to_gt<T: copy>(sep: option<token::token>,
f: fn(parser) -> T, p: parser) -> [T] {
let v = parse_seq_to_before_gt(sep, f, p);
expect_gt(p);
ret v;
}
-fn parse_seq_lt_gt<T: copy>(sep: option::t<token::token>,
+fn parse_seq_lt_gt<T: copy>(sep: option<token::token>,
f: fn(parser) -> T,
p: parser) -> spanned<[T]> {
let lo = p.span.lo;
}
type seq_sep = {
- sep: option::t<token::token>,
+ sep: option<token::token>,
trailing_opt: bool // is trailing separator optional?
};
ret spanned(lo, hi, result);
}
+fn have_dollar(p: parser) -> option::t<ast::mac_> {
+ alt p.token {
+ token::DOLLAR_NUM(num) {
+ p.bump();
+ some(ast::mac_var(num))
+ }
+ token::DOLLAR_LPAREN {
+ let lo = p.span.lo;
+ p.bump();
+ let e = parse_expr(p);
+ expect(p, token::RPAREN);
+ let hi = p.last_span.hi;
+ some(ast::mac_aq(ast_util::mk_sp(lo,hi), e))
+ }
+ _ {none}
+ }
+}
+
fn lit_from_token(p: parser, tok: token::token) -> ast::lit_ {
alt tok {
token::LIT_INT(i, it) { ast::lit_int(i, it) }
fn parse_path_and_ty_param_substs(p: parser, colons: bool) -> @ast::path {
let lo = p.span.lo;
let path = parse_path(p);
- if colons ? eat(p, token::MOD_SEP) : p.token == token::LT {
+ let b = if colons {
+ eat(p, token::MOD_SEP)
+ } else {
+ p.token == token::LT
+ };
+ if b {
let seq = parse_seq_lt_gt(some(token::COMMA),
{|p| parse_ty(p, false)}, p);
@spanned(lo, seq.span.hi, {types: seq.node with path.node})
let hi = p.span.hi;
let ex: ast::expr_;
+
+ alt have_dollar(p) {
+ some(x) {ret pexpr(mk_mac_expr(p, lo, p.span.hi, x));}
+ _ {}
+ }
+
if p.token == token::LPAREN {
p.bump();
if p.token == token::RPAREN {
} else if p.token == token::ELLIPSIS {
p.bump();
ret pexpr(mk_mac_expr(p, lo, p.span.hi, ast::mac_ellipsis));
+ } else if p.token == token::POUND_LPAREN {
+ p.bump();
+ let e = parse_expr(p);
+ expect(p, token::RPAREN);
+ ret pexpr(mk_mac_expr(p, lo, p.span.hi,
+ ast::mac_qq(e.span, e)));
} else if eat_word(p, "bind") {
let e = parse_expr_res(p, RESTRICT_NO_CALL_EXPRS);
- fn parse_expr_opt(p: parser) -> option::t<@ast::expr> {
+ fn parse_expr_opt(p: parser) -> option<@ast::expr> {
alt p.token {
token::UNDERSCORE { p.bump(); ret none; }
_ { ret some(parse_expr(p)); }
let pth = parse_path(p);
//temporary for a backwards-compatible cycle:
let sep = seq_sep(token::COMMA);
- let es =
- if p.token == token::LPAREN {
- parse_seq(token::LPAREN, token::RPAREN, sep, parse_expr, p)
- } else {
- parse_seq(token::LBRACKET, token::RBRACKET, sep, parse_expr, p)
- };
- let hi = es.span.hi;
- let e = mk_expr(p, es.span.lo, hi, ast::expr_vec(es.node, ast::imm));
- ret mk_mac_expr(p, lo, hi, ast::mac_invoc(pth, e, none));
+ let e = none;
+ if (p.token == token::LPAREN || p.token == token::LBRACKET) {
+ let es =
+ if p.token == token::LPAREN {
+ parse_seq(token::LPAREN, token::RPAREN,
+ sep, parse_expr, p)
+ } else {
+ parse_seq(token::LBRACKET, token::RBRACKET,
+ sep, parse_expr, p)
+ };
+ let hi = es.span.hi;
+ e = some(mk_expr(p, es.span.lo, hi,
+ ast::expr_vec(es.node, ast::imm)));
+ }
+ let b = none;
+ if p.token == token::LBRACE {
+ p.bump();
+ let lo = p.span.lo;
+ let depth = 1u;
+ while (depth > 0u) {
+ alt (p.token) {
+ token::LBRACE {depth += 1u;}
+ token::RBRACE {depth -= 1u;}
+ token::EOF {p.fatal("unexpected EOF in macro body");}
+ _ {}
+ }
+ p.bump();
+ }
+ let hi = p.last_span.lo;
+ b = some({span: mk_sp(lo,hi)});
+ }
+ ret mk_mac_expr(p, lo, p.span.hi, ast::mac_invoc(pth, e, b));
}
fn parse_dot_or_call_expr(p: parser) -> pexpr {
ret mk_pexpr(p, lo, hi, ex);
}
-fn parse_ternary(p: parser) -> @ast::expr {
- let cond_expr = parse_binops(p);
- if p.token == token::QUES {
- p.bump();
- let then_expr = parse_expr(p);
- expect(p, token::COLON);
- let else_expr = parse_expr(p);
- ret mk_expr(p, cond_expr.span.lo, else_expr.span.hi,
- ast::expr_ternary(cond_expr, then_expr, else_expr));
- } else { ret cond_expr; }
-}
-
type op_spec = {tok: token::token, op: ast::binop, prec: int};
const unop_prec: int = 100;
const as_prec: int = 5;
-const ternary_prec: int = 0;
fn parse_more_binops(p: parser, plhs: pexpr, min_prec: int) ->
@ast::expr {
fn parse_assign_expr(p: parser) -> @ast::expr {
let lo = p.span.lo;
- let lhs = parse_ternary(p);
+ let lhs = parse_binops(p);
alt p.token {
token::EQ {
p.bump();
fn parse_if_expr_1(p: parser) ->
{cond: @ast::expr,
then: ast::blk,
- els: option::t<@ast::expr>,
+ els: option<@ast::expr>,
lo: uint,
hi: uint} {
let lo = p.last_span.lo;
let cond = parse_expr(p);
let thn = parse_block(p);
- let els: option::t<@ast::expr> = none;
+ let els: option<@ast::expr> = none;
let hi = thn.span.hi;
if eat_word(p, "else") {
let elexpr = parse_else_expr(p);
ret e;
}
-fn parse_initializer(p: parser) -> option::t<ast::initializer> {
+fn parse_initializer(p: parser) -> option<ast::initializer> {
alt p.token {
token::EQ {
p.bump();
_ { true }
} {
let name = parse_path(p);
- let sub = eat(p, token::AT) ? some(parse_pat(p)) : none;
+ let sub = if eat(p, token::AT) {
+ some(parse_pat(p))
+ } else {
+ none
+ };
pat = ast::pat_ident(name, sub);
} else {
let enum_path = parse_path_and_ty_param_substs(p, true);
fn parse_let(p: parser) -> @ast::decl {
fn parse_let_style(p: parser) -> ast::let_style {
- eat(p, token::BINOP(token::AND)) ? ast::let_ref : ast::let_copy
+ if eat(p, token::BINOP(token::AND)) {
+ ast::let_ref
+ } else {
+ ast::let_copy
+ }
}
let lo = p.span.lo;
let locals = [(parse_let_style(p), parse_local(p, true))];
ret @spanned(lo, p.last_span.hi, ast::decl_local(locals));
}
+fn parse_instance_var(p:parser) -> @ast::class_member {
+ let is_mut = ast::class_immutable;
+ expect_word(p, "let");
+ if eat_word(p, "mutable") {
+ is_mut = ast::class_mutable;
+ }
+ if !is_plain_ident(p) {
+ p.fatal("expecting ident");
+ }
+ let name = parse_ident(p);
+ expect(p, token::COLON);
+ let ty = parse_ty(p, false);
+ ret @ast::instance_var(name, ty, is_mut, p.get_id());
+}
+
fn parse_stmt(p: parser, first_item_attrs: [ast::attribute]) -> @ast::stmt {
fn check_expected_item(p: parser, current_attrs: [ast::attribute]) {
// If we have attributes then we should have an item
}
fn parse_fn_block_decl(p: parser) -> ast::fn_decl {
- let inputs = eat(p, token::OROR) ? [] :
- parse_seq(token::BINOP(token::OR), token::BINOP(token::OR),
- seq_sep(token::COMMA), parse_fn_block_arg, p).node;
- let output = eat(p, token::RARROW) ? parse_ty(p, false) :
- @spanned(p.span.lo, p.span.hi, ast::ty_infer);
+ let inputs = if eat(p, token::OROR) {
+ []
+ } else {
+ parse_seq(token::BINOP(token::OR),
+ token::BINOP(token::OR),
+ seq_sep(token::COMMA),
+ parse_fn_block_arg, p).node
+ };
+ let output = if eat(p, token::RARROW) {
+ parse_ty(p, false)
+ } else {
+ @spanned(p.span.lo, p.span.hi, ast::ty_infer)
+ };
ret {inputs: inputs,
output: output,
purity: ast::impure_fn,
}
fn parse_method(p: parser) -> @ast::method {
+ let attrs = parse_outer_attributes(p);
let lo = p.span.lo;
expect_word(p, "fn");
let ident = parse_method_name(p);
let tps = parse_ty_params(p);
let decl = parse_fn_decl(p, ast::impure_fn);
- let body = parse_block(p);
- @{ident: ident, tps: tps, decl: decl, body: body,
+ let (inner_attrs, body) = parse_inner_attrs_and_block(p, true);
+ let attrs = attrs + inner_attrs;
+ @{ident: ident, attrs: attrs, tps: tps, decl: decl, body: body,
id: p.get_id(), span: ast_util::mk_sp(lo, body.span.hi)}
}
fn parse_item_iface(p: parser, attrs: [ast::attribute]) -> @ast::item {
let lo = p.last_span.lo, ident = parse_ident(p),
- tps = parse_ty_params(p), meths = parse_ty_methods(p),
- self_tp = {ident: "self", id: p.get_id(), bounds: @[]};
+ tps = parse_ty_params(p), meths = parse_ty_methods(p);
ret mk_item(p, lo, p.last_span.hi, ident,
- ast::item_iface(tps + [self_tp], meths), attrs);
+ ast::item_iface(tps, meths), attrs);
}
// Parses three variants (with the initial params always optional):
let dtor = parse_block_no_value(p);
let decl =
{inputs:
- [{mode: ast::by_ref, ty: t, ident: arg_ident,
- id: p.get_id()}],
+ [{mode: ast::expl(ast::by_ref), ty: t,
+ ident: arg_ident, id: p.get_id()}],
output: @spanned(lo, lo, ast::ty_nil),
purity: ast::impure_fn,
cf: ast::return_val,
attrs);
}
+fn parse_item_class(p: parser, attrs: [ast::attribute]) -> @ast::item {
+ let lo = p.last_span.lo;
+ let class_name = parse_value_ident(p);
+ let ty_params = parse_ty_params(p);
+ expect(p, token::LBRACE);
+ let items: [@ast::class_item] = [];
+ let the_ctor : option<(ast::fn_decl, ast::blk)> = none;
+ while p.token != token::RBRACE {
+ alt parse_class_item(p) {
+ ctor_decl(a_fn_decl, blk) {
+ the_ctor = some((a_fn_decl, blk));
+ }
+ plain_decl(a_decl) {
+ items += [@{node: {privacy: ast::pub, decl: a_decl},
+ span: p.last_span}];
+ }
+ priv_decls(some_decls) {
+ items += vec::map(some_decls, {|d|
+ @{node: {privacy: ast::priv, decl: d},
+ span: p.last_span}});
+ }
+ }
+ }
+ p.bump();
+ alt the_ctor {
+ some((ct_d, ct_b)) { ret mk_item(p, lo, p.last_span.hi, class_name,
+ ast::item_class(ty_params, items, ct_d, ct_b), attrs); }
+ /*
+ Is it strange for the parser to check this?
+ */
+ none { /* parse error */ fail "Class with no ctor"; }
+ }
+}
+
+// lets us identify the constructor declaration at
+// parse time
+// we don't really want just the fn_decl...
+enum class_contents { ctor_decl(ast::fn_decl, ast::blk),
+ // assumed to be public
+ plain_decl(@ast::class_member),
+ // contents of a priv section --
+ // parse_class_item ensures that
+ // none of these are a ctor decl
+ priv_decls([@ast::class_member])}
+
+fn parse_class_item(p:parser) -> class_contents {
+ if eat_word(p, "new") {
+ // Can ctors have attrs?
+ let decl = parse_fn_decl(p, ast::impure_fn);
+ let body = parse_block(p);
+ ret ctor_decl(decl, body);
+ }
+ // TODO: refactor
+ else if eat_word(p, "priv") {
+ expect(p, token::LBRACE);
+ let results = [];
+ while p.token != token::RBRACE {
+ alt parse_item(p, []) {
+ some(i) {
+ results += [@ast::class_method(i)];
+ }
+ _ {
+ let a_var = parse_instance_var(p);
+ expect(p, token::SEMI);
+ results += [a_var];
+ }
+ }
+ }
+ p.bump();
+ ret priv_decls(results);
+ }
+ else {
+ // Probably need to parse attrs
+ alt parse_item(p, []) {
+ some(i) {
+ ret plain_decl(@ast::class_method(i));
+ }
+ _ {
+ let a_var = parse_instance_var(p);
+ expect(p, token::SEMI);
+ ret plain_decl(a_var);
+ }
+ }
+ }
+}
+
fn parse_mod_items(p: parser, term: token::token,
first_item_attrs: [ast::attribute]) -> ast::_mod {
// Shouldn't be any view items since we've already parsed an item attr
while p.token != term {
let attrs = initial_attrs + parse_outer_attributes(p);
initial_attrs = [];
+ #debug["parse_mod_items: parse_item(attrs=%?)", attrs];
alt parse_item(p, attrs) {
some(i) { items += [i]; }
_ {
token::to_str(p.reader, p.token) + "'");
}
}
+ #debug["parse_mod_items: attrs=%?", attrs];
}
ret {view_items: view_items, items: items};
}
ret mk_item(p, lo, hi, id, ast::item_mod(m), attrs + inner_attrs.inner);
}
-fn parse_item_native_type(p: parser, attrs: [ast::attribute]) ->
- @ast::native_item {
- let t = parse_type_decl(p);
- let hi = p.span.hi;
- expect(p, token::SEMI);
- ret @{ident: t.ident,
- attrs: attrs,
- node: ast::native_item_ty,
- id: p.get_id(),
- span: ast_util::mk_sp(t.lo, hi)};
-}
-
fn parse_item_native_fn(p: parser, attrs: [ast::attribute],
purity: ast::purity) -> @ast::native_item {
let lo = p.last_span.lo;
fn parse_native_item(p: parser, attrs: [ast::attribute]) ->
@ast::native_item {
- if eat_word(p, "type") {
- ret parse_item_native_type(p, attrs);
- } else if eat_word(p, "fn") {
+ if eat_word(p, "fn") {
ret parse_item_native_fn(p, attrs, ast::impure_fn);
} else if eat_word(p, "pure") {
expect_word(p, "fn");
}
}
-fn parse_item(p: parser, attrs: [ast::attribute]) -> option::t<@ast::item> {
+fn parse_item(p: parser, attrs: [ast::attribute]) -> option<@ast::item> {
if eat_word(p, "const") {
ret some(parse_item_const(p, attrs));
} else if eat_word(p, "inline") {
ret some(parse_item_impl(p, attrs));
} else if eat_word(p, "resource") {
ret some(parse_item_res(p, attrs));
- } else { ret none; }
+ } else if eat_word(p, "class") {
+ ret some(parse_item_class(p, attrs));
+ }
+else { ret none; }
}
// A type to distingush between the parsing of item attributes or syntax
// extensions, which both begin with token.POUND
-type attr_or_ext = option::t<either::t<[ast::attribute], @ast::expr>>;
+type attr_or_ext = option<either::t<[ast::attribute], @ast::expr>>;
fn parse_outer_attrs_or_ext(
p: parser,
}
fn parse_rest_import_name(p: parser, first: ast::ident,
- def_ident: option::t<ast::ident>) ->
+ def_ident: option<ast::ident>) ->
ast::view_item_ {
let identifiers: [ast::ident] = [first];
let glob: bool = false;
fn parse_expr_from_source_str(name: str, source: @str, cfg: ast::crate_cfg,
sess: parse_sess) -> @ast::expr {
- let p = new_parser_from_source_str(sess, cfg, name, source);
+ let p = new_parser_from_source_str(sess, cfg, name, none, source);
let r = parse_expr(p);
sess.chpos = p.reader.chpos;
sess.byte_pos = sess.byte_pos + p.reader.pos;
ret r;
}
+fn parse_from_source_str<T>(f: fn (p: parser) -> T,
+ name: str, ss: codemap::file_substr,
+ source: @str, cfg: ast::crate_cfg,
+ sess: parse_sess)
+ -> T
+{
+ let p = new_parser_from_source_str(sess, cfg, name, ss, source);
+ let r = f(p);
+ sess.chpos = p.reader.chpos;
+ sess.byte_pos = sess.byte_pos + p.reader.pos;
+ ret r;
+}
+
fn parse_crate_from_source_str(name: str, source: @str, cfg: ast::crate_cfg,
sess: parse_sess) -> @ast::crate {
- let p = new_parser_from_source_str(sess, cfg, name, source);
+ let p = new_parser_from_source_str(sess, cfg, name, none, source);
let r = parse_crate_mod(p, cfg);
sess.chpos = p.reader.chpos;
sess.byte_pos = sess.byte_pos + p.reader.pos;
SEMI,
COLON,
MOD_SEP,
- QUES,
RARROW,
LARROW,
DARROW,
LBRACE,
RBRACE,
POUND,
+ POUND_LPAREN,
POUND_LBRACE,
POUND_LT,
+ DOLLAR_LPAREN,
+ DOLLAR_NUM(uint),
+
/* Literals */
LIT_INT(i64, ast::int_ty),
LIT_UINT(u64, ast::uint_ty),
UNDERSCORE,
BRACEQUOTE(str_num),
EOF,
+
}
fn binop_to_str(o: binop) -> str {
SEMI { ret ";"; }
COLON { ret ":"; }
MOD_SEP { ret "::"; }
- QUES { ret "?"; }
RARROW { ret "->"; }
LARROW { ret "<-"; }
DARROW { ret "<->"; }
LBRACE { ret "{"; }
RBRACE { ret "}"; }
POUND { ret "#"; }
+ POUND_LPAREN { ret "#("; }
POUND_LBRACE { ret "#{"; }
POUND_LT { ret "#<"; }
+ DOLLAR_LPAREN { ret "$("; }
+ DOLLAR_NUM(u) {
+ ret "$" + uint::to_str(u as uint, 10u);
+ }
+
/* Literals */
LIT_INT(c, ast::ty_char) {
// FIXME: escape.
type ps =
@{s: pp::printer,
- cm: option::t<codemap>,
- comments: option::t<[lexer::cmnt]>,
- literals: option::t<[lexer::lit]>,
+ cm: option<codemap>,
+ comments: option<[lexer::cmnt]>,
+ literals: option<[lexer::lit]>,
mutable cur_cmnt: uint,
mutable cur_lit: uint,
mutable boxes: [pp::breaks],
fn item_to_str(i: @ast::item) -> str { be to_str(i, print_item); }
+fn typarams_to_str(tps: [ast::ty_param]) -> str {
+ be to_str(tps, print_type_params)
+}
+
fn path_to_str(&&p: @ast::path) -> str {
be to_str(p, bind print_path(_, _, false));
}
fn test_res_to_str() {
let decl: ast::fn_decl = {
inputs: [{
- mode: ast::by_val,
+ mode: ast::expl(ast::by_val),
ty: @ast_util::respan(ast_util::dummy_sp(), ast::ty_bool),
ident: "b",
id: 0
word(s.s, "]");
}
ast::ty_ptr(mt) { word(s.s, "*"); print_mt(s, mt); }
- ast::ty_task { word(s.s, "task"); }
- ast::ty_port(t) {
- word(s.s, "port<");
- print_type(s, t);
- word(s.s, ">");
- }
- ast::ty_chan(t) {
- word(s.s, "chan<");
- print_type(s, t);
- word(s.s, ">");
- }
ast::ty_rec(fields) {
word(s.s, "{");
fn print_field(s: ps, f: ast::ty_field) {
print_ty_fn(s, some(proto), d, none, none);
}
ast::ty_path(path, _) { print_path(s, path, false); }
- ast::ty_type { word(s.s, "type"); }
ast::ty_constr(t, cs) {
print_type(s, t);
space(s.s);
word(s.s, ast_ty_constrs_str(cs));
}
+ ast::ty_mac(_) {
+ fail "print_type doesn't know how to print a ty_mac";
+ }
+ ast::ty_infer {
+ fail "print_type shouldn't see a ty_infer";
+ }
+
}
end(s);
}
maybe_print_comment(s, item.span.lo);
print_outer_attributes(s, item.attrs);
alt item.node {
- ast::native_item_ty {
- ibox(s, indent_unit);
- ibox(s, 0u);
- word_nbsp(s, "type");
- word(s.s, item.ident);
- end(s); // end the inner ibox
- word(s.s, ";");
- end(s); // end the outer ibox
-
- }
ast::native_item_fn(decl, typarams) {
print_fn(s, decl, item.ident, typarams);
end(s); // end head-ibox
bclose(s, item.span);
}
}
+ ast::item_class(tps,items,ctor_decl,ctor_body) {
+ head(s, "class");
+ word_nbsp(s, item.ident);
+ print_type_params(s, tps);
+ bopen(s);
+ hardbreak_if_not_bol(s);
+ head(s, "new");
+ print_fn_args_and_ret(s, ctor_decl);
+ space(s.s);
+ print_block(s, ctor_body);
+ for ci in items {
+ /*
+ TODO: collect all private items and print them
+ in a single "priv" section
+ */
+ hardbreak_if_not_bol(s);
+ alt ci.node.privacy {
+ ast::priv {
+ head(s, "priv");
+ bopen(s);
+ hardbreak_if_not_bol(s);
+ }
+ _ {}
+ }
+ alt *ci.node.decl {
+ ast::instance_var(nm, t, mt, _) {
+ word_nbsp(s, "let");
+ alt mt {
+ ast::class_mutable { word_nbsp(s, "mutable"); }
+ _ {}
+ }
+ word(s.s, nm);
+ word_nbsp(s, ":");
+ print_type(s, t);
+ word(s.s, ";");
+ }
+ ast::class_method(i) {
+ print_item(s, i);
+ }
+ }
+ alt ci.node.privacy {
+ ast::priv { bclose(s, ci.span); }
+ _ {}
+ }
+ }
+ }
ast::item_impl(tps, ifce, ty, methods) {
head(s, "impl");
word(s.s, item.ident);
for meth in methods {
hardbreak_if_not_bol(s);
maybe_print_comment(s, meth.span.lo);
+ print_outer_attributes(s, meth.attrs);
print_fn(s, meth.decl, meth.ident, meth.tps);
word(s.s, " ");
- print_block(s, meth.body);
+ print_block_with_attrs(s, meth.body, meth.attrs);
}
bclose(s, item.span);
}
ast::item_iface(tps, methods) {
head(s, "iface");
word(s.s, item.ident);
- print_type_params(s, vec::slice(tps, 0u, vec::len(tps) - 1u));
- nbsp(s);
+ print_type_params(s, tps);
+ word(s.s, " ");
bopen(s);
for meth in methods { print_ty_method(s, meth); }
bclose(s, item.span);
fn print_ty_method(s: ps, m: ast::ty_method) {
hardbreak_if_not_bol(s);
- cbox(s, indent_unit);
maybe_print_comment(s, m.span.lo);
+ print_outer_attributes(s, m.attrs);
print_ty_fn(s, none, m.decl, some(m.ident), some(m.tps));
word(s.s, ";");
- end(s);
}
fn print_outer_attributes(s: ps, attrs: [ast::attribute]) {
ast::unsafe_blk { word(s.s, "unsafe"); }
ast::default_blk { }
}
-
maybe_print_comment(s, blk.span.lo);
let ann_node = node_block(s, blk);
s.ann.pre(ann_node);
}
fn print_if(s: ps, test: @ast::expr, blk: ast::blk,
- elseopt: option::t<@ast::expr>, chk: bool) {
+ elseopt: option<@ast::expr>, chk: bool) {
head(s, "if");
if chk { word_nbsp(s, "check"); }
print_maybe_parens_discrim(s, test);
space(s.s);
print_block(s, blk);
- fn do_else(s: ps, els: option::t<@ast::expr>) {
+ fn do_else(s: ps, els: option<@ast::expr>) {
alt els {
some(_else) {
alt _else.node {
-
-
-
-
-
// "another else-if"
ast::expr_if(i, t, e) {
cbox(s, indent_unit - 1u);
print_block(s, t);
do_else(s, e);
}
-
-
-
-
-
// "final else"
ast::expr_block(b) {
cbox(s, indent_unit - 1u);
word(s.s, " else ");
print_block(s, b);
}
+ // BLEAH, constraints would be great here
+ _ {
+ fail "print_if saw if with weird alternative";
+ }
}
}
_ {/* fall through */ }
ast::mac_invoc(path, arg, body) {
word(s.s, "#");
print_path(s, path, false);
- alt arg.node { ast::expr_vec(_, _) { } _ { word(s.s, " "); } }
- print_expr(s, arg);
+ alt arg {
+ some(@{node: ast::expr_vec(_, _), _}) { }
+ _ { word(s.s, " "); }
+ }
+ option::may(arg, bind print_expr(s, _));
// FIXME: extension 'body'
}
ast::mac_embed_type(ty) {
print_possibly_embedded_block(s, blk, block_normal, indent_unit);
}
ast::mac_ellipsis { word(s.s, "..."); }
+ ast::mac_var(v) { word(s.s, #fmt("$%u", v)); }
+ _ { /* fixme */ }
}
}
}
}
ast::expr_bind(func, args) {
- fn print_opt(s: ps, expr: option::t<@ast::expr>) {
+ fn print_opt(s: ps, expr: option<@ast::expr>) {
alt expr {
some(expr) { print_expr(s, expr); }
_ { word(s.s, "_"); }
ast::expr_if_check(test, blk, elseopt) {
print_if(s, test, blk, elseopt, true);
}
- ast::expr_ternary(test, then, els) {
- print_expr(s, test);
- space(s.s);
- word_space(s, "?");
- print_expr(s, then);
- space(s.s);
- word_space(s, ":");
- print_expr(s, els);
- }
ast::expr_while(test, blk) {
head(s, "while");
print_maybe_parens_discrim(s, test);
}
ast::expr_assert(expr) {
word_nbsp(s, "assert");
- popen(s);
print_expr(s, expr);
- pclose(s);
}
ast::expr_mac(m) { print_mac(s, m); }
}
let parens = alt ex.node {
ast::expr_fail(_) | ast::expr_ret(_) |
ast::expr_binary(_, _, _) | ast::expr_unary(_, _) |
- ast::expr_ternary(_, _, _) | ast::expr_move(_, _) |
- ast::expr_copy(_) | ast::expr_assign(_, _) | ast::expr_be(_) |
+ ast::expr_move(_, _) | ast::expr_copy(_) |
+ ast::expr_assign(_, _) | ast::expr_be(_) |
ast::expr_assign_op(_, _, _) | ast::expr_swap(_, _) |
ast::expr_log(_, _, _) | ast::expr_assert(_) |
ast::expr_call(_, _, true) |
maybe_print_comment(s, decl.output.span.lo);
}
-fn print_arg_mode(s: ps, m: ast::mode) {
+fn mode_to_str(m: ast::mode) -> str {
alt m {
- ast::by_mut_ref { word(s.s, "&"); }
- ast::by_move { word(s.s, "-"); }
- ast::by_ref { word(s.s, "&&"); }
- ast::by_val { word(s.s, "++"); }
- ast::by_copy { word(s.s, "+"); }
- ast::mode_infer {}
+ ast::expl(ast::by_mut_ref) { "&" }
+ ast::expl(ast::by_move) { "-" }
+ ast::expl(ast::by_ref) { "&&" }
+ ast::expl(ast::by_val) { "++" }
+ ast::expl(ast::by_copy) { "+" }
+ ast::infer(_) { "" }
}
}
+fn print_arg_mode(s: ps, m: ast::mode) {
+ let ms = mode_to_str(m);
+ if ms != "" { word(s.s, ms); }
+}
+
fn print_bounds(s: ps, bounds: @[ast::ty_param_bound]) {
if vec::len(*bounds) > 0u {
word(s.s, ":");
}
}
-fn print_type_params(s: ps, params: [ast::ty_param]) {
+fn print_type_params(s: ps, &¶ms: [ast::ty_param]) {
if vec::len(params) > 0u {
word(s.s, "<");
fn printParam(s: ps, param: ast::ty_param) {
alt expr.node {
ast::expr_binary(op, _, _) { operator_prec(op) < outer_prec }
ast::expr_cast(_, _) { parse::parser::as_prec < outer_prec }
- ast::expr_ternary(_, _, _) { parse::parser::ternary_prec < outer_prec }
// This may be too conservative in some cases
ast::expr_assign(_, _) { true }
ast::expr_move(_, _) { true }
}
fn print_ty_fn(s: ps, opt_proto: option<ast::proto>,
- decl: ast::fn_decl, id: option::t<ast::ident>,
- tps: option::t<[ast::ty_param]>) {
+ decl: ast::fn_decl, id: option<ast::ident>,
+ tps: option<[ast::ty_param]>) {
ibox(s, indent_unit);
word(s.s, opt_proto_to_str(opt_proto));
alt id { some(id) { word(s.s, " "); word(s.s, id); } _ { } }
}
fn maybe_print_trailing_comment(s: ps, span: codemap::span,
- next_pos: option::t<uint>) {
+ next_pos: option<uint>) {
let cm;
alt s.cm { some(ccm) { cm = ccm; } _ { ret; } }
alt next_comment(s) {
word(s.s, "'" + escape_str(str::from_char(ch as char), '\'') + "'");
}
ast::lit_int(i, t) {
- word(s.s, int::str(i as int) + ast_util::int_ty_to_str(t));
+ if i < 0_i64 {
+ word(s.s,
+ "-" + u64::to_str(-i as u64, 10u)
+ + ast_util::int_ty_to_str(t));
+ } else {
+ word(s.s,
+ u64::to_str(i as u64, 10u)
+ + ast_util::int_ty_to_str(t));
+ }
}
ast::lit_uint(u, t) {
- word(s.s, uint::str(u as uint) + ast_util::uint_ty_to_str(t));
+ word(s.s,
+ u64::to_str(u, 10u)
+ + ast_util::uint_ty_to_str(t));
}
ast::lit_float(f, t) {
word(s.s, f + ast_util::float_ty_to_str(t));
fn lit_to_str(l: @ast::lit) -> str { be to_str(l, print_literal); }
-fn next_lit(s: ps, pos: uint) -> option::t<lexer::lit> {
+fn next_lit(s: ps, pos: uint) -> option<lexer::lit> {
alt s.literals {
some(lits) {
while s.cur_lit < vec::len(lits) {
io::mem_buffer_str(buffer)
}
-fn next_comment(s: ps) -> option::t<lexer::cmnt> {
+fn next_comment(s: ps) -> option<lexer::cmnt> {
alt s.comments {
some(cmnts) {
if s.cur_cmnt < vec::len(cmnts) {
alt ex.node {
ast::expr_lit(@{node: ast::lit_int(_, ast::ty_i), _}) { true }
ast::expr_binary(_, _, sub) | ast::expr_unary(_, sub) |
- ast::expr_ternary(_, _, sub) | ast::expr_move(_, sub) |
- ast::expr_copy(sub) | ast::expr_assign(_, sub) | ast::expr_be(sub) |
+ ast::expr_move(_, sub) | ast::expr_copy(sub) |
+ ast::expr_assign(_, sub) | ast::expr_be(sub) |
ast::expr_assign_op(_, _, sub) | ast::expr_swap(_, sub) |
ast::expr_log(_, _, sub) | ast::expr_assert(sub) |
ast::expr_check(_, sub) { ends_in_lit_int(sub) }
visit_ty: fn@(@ty, E, vt<E>),
visit_ty_params: fn@([ty_param], E, vt<E>),
visit_constr: fn@(@path, span, node_id, E, vt<E>),
- visit_fn: fn@(fn_kind, fn_decl, blk, span, node_id, E, vt<E>)};
+ visit_fn: fn@(fn_kind, fn_decl, blk, span, node_id, E, vt<E>),
+ visit_class_item: fn@(span, privacy, @class_member, E, vt<E>)};
fn default_visitor<E>() -> visitor<E> {
ret @{visit_mod: bind visit_mod::<E>(_, _, _, _, _),
visit_ty: bind skip_ty::<E>(_, _, _),
visit_ty_params: bind visit_ty_params::<E>(_, _, _),
visit_constr: bind visit_constr::<E>(_, _, _, _, _),
- visit_fn: bind visit_fn::<E>(_, _, _, _, _, _, _)};
+ visit_fn: bind visit_fn::<E>(_, _, _, _, _, _, _),
+ visit_class_item: bind visit_class_item::<E>(_,_,_,_,_)};
}
fn visit_crate<E>(c: crate, e: E, v: vt<E>) {
m.id, e, v);
}
}
+ item_class(tps, members, ctor_decl, ctor_blk) {
+ v.visit_ty_params(tps, e, v);
+ for m in members {
+ v.visit_class_item(m.span, m.node.privacy, m.node.decl, e, v);
+ }
+ visit_fn_decl(ctor_decl, e, v);
+ v.visit_block(ctor_blk, e, v);
+ }
item_iface(tps, methods) {
v.visit_ty_params(tps, e, v);
for m in methods {
}
}
+fn visit_class_item<E>(_s: span, _p: privacy, cm: @class_member,
+ e:E, v:vt<E>) {
+ alt *cm {
+ instance_var(ident, t, mt, id) {
+ v.visit_ty(t, e, v);
+ }
+ class_method(i) {
+ v.visit_item(i, e, v);
+ }
+ }
+}
+
fn skip_ty<E>(_t: @ty, _e: E, _v: vt<E>) {}
fn visit_ty<E>(t: @ty, e: E, v: vt<E>) {
v.visit_ty(decl.output, e, v);
}
ty_path(p, _) { visit_path(p, e, v); }
- ty_type {/* no-op */ }
ty_constr(t, cs) {
v.visit_ty(t, e, v);
for tc: @spanned<constr_general_<@path, node_id>> in cs {
v.visit_ty_params(tps, e, v);
visit_fn_decl(fd, e, v);
}
- native_item_ty { }
}
}
}
}
-fn visit_expr_opt<E>(eo: option::t<@expr>, e: E, v: vt<E>) {
+fn visit_expr_opt<E>(eo: option<@expr>, e: E, v: vt<E>) {
alt eo { none { } some(ex) { v.visit_expr(ex, e, v); } }
}
fn visit_mac<E>(m: mac, e: E, v: vt<E>) {
alt m.node {
- ast::mac_invoc(pth, arg, body) { visit_expr(arg, e, v); }
+ ast::mac_invoc(pth, arg, body) {
+ option::map(arg) {|arg| visit_expr(arg, e, v)}; }
ast::mac_embed_type(ty) { v.visit_ty(ty, e, v); }
ast::mac_embed_block(blk) { v.visit_block(blk, e, v); }
ast::mac_ellipsis { }
+ ast::mac_qq(_, e) { /* FIXME: maybe visit */ }
+ ast::mac_aq(_, e) { /* FIXME: maybe visit */ }
+ ast::mac_var(_) { }
}
}
}
expr_bind(callee, args) {
v.visit_expr(callee, e, v);
- for eo: option::t<@expr> in args { visit_expr_opt(eo, e, v); }
+ for eo: option<@expr> in args { visit_expr_opt(eo, e, v); }
}
expr_binary(_, a, b) { v.visit_expr(a, e, v); v.visit_expr(b, e, v); }
expr_unary(_, a) { v.visit_expr(a, e, v); }
v.visit_block(b, e, v);
visit_expr_opt(eo, e, v);
}
- expr_ternary(c, t, el) {
- v.visit_expr(c, e, v);
- v.visit_expr(t, e, v);
- v.visit_expr(el, e, v);
- }
expr_while(x, b) { v.visit_expr(x, e, v); v.visit_block(b, e, v); }
expr_for(dcl, x, b) {
v.visit_local(dcl, e, v);
visit_ty: fn@(@ty),
visit_ty_params: fn@([ty_param]),
visit_constr: fn@(@path, span, node_id),
- visit_fn: fn@(fn_kind, fn_decl, blk, span, node_id)};
+ visit_fn: fn@(fn_kind, fn_decl, blk, span, node_id),
+ visit_class_item: fn@(span, privacy, @class_member)};
fn simple_ignore_ty(_t: @ty) {}
visit_ty_params: fn@(_ps: [ty_param]) {},
visit_constr: fn@(_p: @path, _sp: span, _id: node_id) { },
visit_fn: fn@(_fk: fn_kind, _d: fn_decl, _b: blk, _sp: span,
- _id: node_id) { }
+ _id: node_id) { },
+ visit_class_item: fn@(_s: span, _p: privacy, _c: @class_member) {}
};
}
} else {
bind v_ty(v.visit_ty, _, _, _)
};
+ fn v_class_item(f: fn@(span, privacy, @class_member),
+ s:span, p:privacy, cm: @class_member, &&e: (),
+ v: vt<()>) {
+ f(s, p, cm);
+ visit_class_item(s, p, cm, e, v);
+ }
ret mk_vt(@{visit_mod: bind v_mod(v.visit_mod, _, _, _, _, _),
visit_view_item: bind v_view_item(v.visit_view_item, _, _, _),
visit_native_item:
visit_ty: visit_ty,
visit_ty_params: bind v_ty_params(v.visit_ty_params, _, _, _),
visit_constr: bind v_constr(v.visit_constr, _, _, _, _, _),
- visit_fn: bind v_fn(v.visit_fn, _, _, _, _, _, _, _)
+ visit_fn: bind v_fn(v.visit_fn, _, _, _, _, _, _, _),
+ visit_class_item: bind v_class_item(v.visit_class_item, _, _,
+ _, _, _)
});
}
alt l.node.init { some(i) { ret i.expr.span; } _ { ret def; } }
}
-fn is_main_name(path: [ast::ident]) -> bool {
- str::eq(option::get(vec::last(path)), "main")
+fn is_main_name(path: middle::ast_map::path) -> bool {
+ option::get(vec::last(path)) == middle::ast_map::path_name("main")
}
-
-
//
// Local Variables:
// mode: rust
export get_cargo_root;
export libdir;
-type pick<T> = fn(path: fs::path) -> option::t<T>;
+type pick<T> = fn(path: fs::path) -> option<T>;
-fn pick_file(file: fs::path, path: fs::path) -> option::t<fs::path> {
+fn pick_file(file: fs::path, path: fs::path) -> option<fs::path> {
if fs::basename(path) == file { option::some(path) }
else { option::none }
}
fn get_target_lib_file_path(file: fs::path) -> fs::path;
}
-fn mk_filesearch(maybe_sysroot: option::t<fs::path>,
+fn mk_filesearch(maybe_sysroot: option<fs::path>,
target_triple: str,
addl_lib_search_paths: [fs::path]) -> filesearch {
type filesearch_impl = {sysroot: fs::path,
}
// FIXME #1001: This can't be an obj method
-fn search<T: copy>(filesearch: filesearch, pick: pick<T>) -> option::t<T> {
+fn search<T: copy>(filesearch: filesearch, pick: pick<T>) -> option<T> {
for lib_search_path in filesearch.lib_search_paths() {
#debug("searching %s", lib_search_path);
for path in fs::list_dir(lib_search_path) {
}
}
-fn get_sysroot(maybe_sysroot: option::t<fs::path>) -> fs::path {
+fn get_sysroot(maybe_sysroot: option<fs::path>) -> fs::path {
alt maybe_sysroot {
option::some(sr) { sr }
option::none { get_default_sysroot() }
import middle::ty::*;
import metadata::encoder;
import syntax::print::pprust;
-import syntax::print::pprust::{path_to_str, constr_args_to_str, proto_to_str};
+import syntax::print::pprust::{path_to_str, constr_args_to_str, proto_to_str,
+ mode_to_str};
import syntax::{ast, ast_util};
import middle::ast_map;
-fn mode_str(m: ty::mode) -> str {
- alt m {
- ast::by_ref { "&&" }
- ast::by_val { "++" }
- ast::by_mut_ref { "&" }
- ast::by_move { "-" }
- ast::by_copy { "+" }
- _ { "" }
- }
-}
-
fn ty_to_str(cx: ctxt, typ: t) -> str {
- fn fn_input_to_str(cx: ctxt, input: {mode: middle::ty::mode, ty: t}) ->
+ fn fn_input_to_str(cx: ctxt, input: {mode: ast::mode, ty: t}) ->
str {
- let modestr = alt input.mode {
- ast::by_ref {
- ty::type_is_immediate(cx, input.ty) ? "&&" : ""
- }
- ast::by_val {
- ty::type_is_immediate(cx, input.ty) ? "" : "++"
+ let {mode, ty} = input;
+ let modestr = alt canon_mode(cx, mode) {
+ ast::infer(_) { "" }
+ ast::expl(m) {
+ if !ty::type_contains_vars(cx, ty) &&
+ m == ty::default_arg_mode_for_ty(cx, ty) {
+ ""
+ } else {
+ mode_to_str(ast::expl(m))
+ }
}
- _ { mode_str(input.mode) }
};
- modestr + ty_to_str(cx, input.ty)
+ modestr + ty_to_str(cx, ty)
}
- fn fn_to_str(cx: ctxt, proto: ast::proto, ident: option::t<ast::ident>,
+ fn fn_to_str(cx: ctxt, proto: ast::proto, ident: option<ast::ident>,
inputs: [arg], output: t, cf: ast::ret_style,
constrs: [@constr]) -> str {
let s = proto_to_str(proto);
_ { }
}
ret alt struct(cx, typ) {
- ty_native(_) { "native" }
ty_nil { "()" }
ty_bot { "_|_" }
ty_bool { "bool" }
stage_id: str,
mode: mode,
run_ignored: bool,
- filter: option::t<str>,
- runtool: option::t<str>,
- rustcflags: option::t<str>,
+ filter: option<str>,
+ runtool: option<str>,
+ rustcflags: option<str>,
verbose: bool};
type cx = {config: config, procsrv: procsrv::handle};
logv(c, #fmt["\n"]);
}
-fn opt_str(maybestr: option::t<str>) -> str {
+fn opt_str(maybestr: option<str>) -> str {
alt maybestr { option::some(s) { s } option::none { "(none)" } }
}
-fn str_opt(maybestr: str) -> option::t<str> {
+fn str_opt(maybestr: str) -> option<str> {
if maybestr != "(none)" { option::some(maybestr) } else { option::none }
}
ret error_patterns;
}
-fn parse_expected(line_num: uint, line: str) -> [expected_error] {
+fn parse_expected(line_num: uint, line: str) -> [expected_error] unsafe {
let error_tag = "//!";
let idx0 = str::find(line, error_tag);
if idx0 < 0 { ret []; }
while idx < len && line[idx] == (' ' as u8) { idx += 1u; }
let start_kind = idx;
while idx < len && line[idx] != (' ' as u8) { idx += 1u; }
- let kind = str::to_lower(str::slice(line, start_kind, idx));
+ let kind = str::to_lower(str::unsafe::slice_bytes(line, start_kind, idx));
// Extract msg:
while idx < len && line[idx] == (' ' as u8) { idx += 1u; }
- let msg = str::slice(line, idx, len);
+ let msg = str::unsafe::slice_bytes(line, idx, len);
#debug("line=%u kind=%s msg=%s", line_num - adjust_line, kind, msg);
// Lines that should be expected, in order, on standard out
error_patterns: [str],
// Extra flags to pass to the compiler
- compile_flags: option::t<str>,
+ compile_flags: option<str>,
// If present, the name of a file that this test should match when
// pretty-printed
- pp_exact: option::t<str>
+ pp_exact: option<str>
};
// Load any test directives embedded in the file
}
}
-fn parse_error_pattern(line: str) -> option::t<str> {
+fn parse_error_pattern(line: str) -> option<str> {
parse_name_value_directive(line, "error-pattern")
}
-fn parse_compile_flags(line: str) -> option::t<str> {
+fn parse_compile_flags(line: str) -> option<str> {
parse_name_value_directive(line, "compile-flags")
}
-fn parse_pp_exact(line: str, testfile: str) -> option::t<str> {
+fn parse_pp_exact(line: str, testfile: str) -> option<str> {
alt parse_name_value_directive(line, "pp-exact") {
option::some(s) { option::some(s) }
option::none {
}
fn parse_name_value_directive(line: str,
- directive: str) -> option::t<str> {
+ directive: str) -> option<str> unsafe {
let keycolon = directive + ":";
if str::find(line, keycolon) >= 0 {
let colon = str::find(line, keycolon) as uint;
let value =
- str::slice(line, colon + str::byte_len(keycolon),
+ str::unsafe::slice_bytes(line, colon + str::byte_len(keycolon),
str::byte_len(line));
#debug("%s: %s", directive, value);
option::some(value)
type reqchan = chan<request>;
type handle =
- {task: option::t<(task::task, port<task::task_notification>)>,
+ {task: option<(task::task, port<task::task_notification>)>,
chan: reqchan};
enum request { exec([u8], [u8], [[u8]], chan<response>), stop, }
}
fn run(handle: handle, lib_path: str, prog: str, args: [str],
- input: option::t<str>) -> {status: int, out: str, err: str} {
+ input: option<str>) -> {status: int, out: str, err: str} {
let p = port();
let ch = chan(p);
send(handle.chan,
ret {status: status, out: output, err: errput};
}
-fn writeclose(fd: fd_t, s: option::t<str>) {
+fn writeclose(fd: fd_t, s: option<str>) {
if option::is_some(s) {
let writer = io::fd_writer(fd, false);
writer.write_str(option::get(s));
let next_err_idx = 0u;
let next_err_pat = props.error_patterns[next_err_idx];
- for line: str in str::split(procres.stdout, '\n' as u8) {
+ for line: str in str::split(procres.stderr, '\n' as u8) {
if str::find(line, next_err_pat) > 0 {
#debug("found error pattern %s", next_err_pat);
next_err_idx += 1u;
// filename:line1:col1: line2:col2: *warning:* msg
// where line1:col1: is the starting point, line2:col2:
// is the ending point, and * represents ANSI color codes.
- for line: str in str::split(procres.stdout, '\n' as u8) {
+ for line: str in str::split(procres.stderr, '\n' as u8) {
let was_expected = false;
vec::iteri(expected_errors) {|i, ee|
if !found_flags[i] {
fn compose_and_run(cx: cx, testfile: str,
make_args: fn@(config, str) -> procargs, lib_path: str,
- input: option::t<str>) -> procres {
+ input: option<str>) -> procres {
let procargs = make_args(cx.config, testfile);
ret program_output(cx, testfile, lib_path, procargs.prog, procargs.args,
input);
ret {prog: args[0], args: vec::slice(args, 1u, vec::len(args))};
}
-fn split_maybe_args(argstr: option::t<str>) -> [str] {
+fn split_maybe_args(argstr: option<str>) -> [str] {
fn rm_whitespace(v: [str]) -> [str] {
- fn flt(&&s: str) -> option::t<str> {
+ fn flt(&&s: str) -> option<str> {
if !is_whitespace(s) { option::some(s) } else { option::none }
}
}
fn program_output(cx: cx, testfile: str, lib_path: str, prog: str,
- args: [str], input: option::t<str>) -> procres {
+ args: [str], input: option<str>) -> procres {
let cmdline =
{
let cmdline = make_cmdline(lib_path, prog, args);
--- /dev/null
+{
+ issue_1333_setenv_leak
+ Memcheck:Leak
+ fun:malloc_zone_malloc
+ ...
+ fun:setenv
+ fun:setenv__c_stack_shim
+ ...
+}
--langmap=rust:.rs
--regex-rust=/[ \t]*fn[ \t]+([a-zA-Z0-9_]+)/\1/f,function/
--regex-rust=/[ \t]*type[ \t]+([a-zA-Z0-9_]+)/\1/T,types/
---regex-rust=/[ \t]*tag[ \t]+([a-zA-Z0-9_]+)/\1/T,types/
+--regex-rust=/[ \t]*enum[ \t]+([a-zA-Z0-9_]+)/\1/T,types/
--regex-rust=/[ \t]*resource[ \t]+([a-zA-Z0-9_]+)/\1/T,types/
--regex-rust=/[ \t]*mod[ \t]+([a-zA-Z0-9_]+)/\1/m,modules/
fi
clang++ -emit-llvm -S -m$BITS -O3 -Isrc/rt/isaac -Isrc/rt/uthash \
- -Isrc/rt/arch/$ARCH -fno-stack-protector \
+ -Isrc/rt/arch/$ARCH -Isrc/rt -fno-stack-protector \
-o src/rt/intrinsics/intrinsics.$ARCH.ll.in \
src/rt/intrinsics/intrinsics.cpp
sed -i .orig \
# This script generates rust compatible makefiles from libuv. When upgrading
# libuv, do:
+#
# cd $RUST_DIR
-# rm -r mk/libuv
-# cd $LIBUV_DIR
-# git archive --prefix libuv/ $REVISION > libuv.tar.gz
-# cd $RUST_DIR/src/rt
-# rm -r libuv
-# tar -xvf $LIBUV_DIR/libuv.tar.gz
-# mkdir -p libuv/build
-# svn co http://gyp.googlecode.com/svn/trunk libuv/build/gyp
+# cd src/libuv
+# git checkout master
+# git pull
+# svn co http://gyp.googlecode.com/svn/trunk build/gyp
# cd ../..
-# ./src/etc/gyp_uv
+# rm -r mk/libuv
+# ./src/etc/gyp-uv
+#
+# Note: you must not run gyp on windows. It will get the backslashes
+# incorrect in its rules, and not work.
set -e
cd `dirname $0`
cd ../..
+GYPFILE=src/libuv/uv.gyp
+INCLUDES="-I src/libuv/common.gypi"
+
for ARCH in ia32 x86_64
do
- args="--depth . -Dlibrary=static_library -Dtarget_arch=$ARCH"
+ ARGS="$GYPFILE \
+ $INCLUDES \
+ --depth . \
+ -Dcomponent=static_library \
+ -Dlibrary=static_library \
+ -Dtarget_arch=$ARCH"
- ./src/libuv/build/gyp/gyp src/libuv/uv.gyp $args \
+ ./src/libuv/build/gyp/gyp $ARGS \
-f make-mac \
--generator-output mk/libuv/$ARCH/mac \
-DOS=mac
- ./src/libuv/build/gyp/gyp src/libuv/uv.gyp $args \
+ ./src/libuv/build/gyp/gyp $ARGS \
-f make-linux \
--generator-output mk/libuv/$ARCH/unix \
-DOS=linux
- ./src/libuv/build/gyp/gyp src/libuv/uv.gyp $args \
+ ./src/libuv/build/gyp/gyp $ARGS \
-f make-linux \
--generator-output mk/libuv/$ARCH/win \
-DOS=win
- # Comment out the gyp auto regeneration
- for os in mac unix win; do
- sed -i \
- -e 's/^\(Makefile: $(srcdir)\/src\/rt\/libuv\/uv\.gyp\)/#\1/' \
- mk/libuv/$ARCH/$os/Makefile
-
- sed -i \
- -e 's/^\( $(call do_cmd,regen_makefile)\)/#\1/' \
- mk/libuv/$ARCH/$os/Makefile
- done
done
# On Mac, GYP hardcodes a -arch i386 into the output. Fix that.
sed -i \
-e 's/-arch i386/-arch x86_64/' \
mk/libuv/x86_64/mac/src/libuv/*.mk
+
+MKFILES=$(find mk/libuv -name \*.mk -o -name Makefile)
+
+# Comment out the gyp auto regeneration
+perl -i -p -e 's@^(Makefile:.*)@#\1@go' $MKFILES
+perl -i -p -e 's@^(Makefile:.*)@#\1@go' $MKFILES
+perl -i -p -e 's@(.*regen_makefile.*)@#\1@go' $MKFILES
+++ /dev/null
-# -*- shell-script -*-
-# (not really, but syntax is similar)
-#
-# This is a NSIS win32 installer script the Rust toolchain.
-#
-
-# FIXME: EnvVarUpdate belongs in its own file but I'm having a hard time figuring
-# out how to make !include look in the directory I want it to.
-
-/**
- * EnvVarUpdate.nsh
- * : Environmental Variables: append, prepend, and remove entries
- *
- * WARNING: If you use StrFunc.nsh header then include it before this file
- * with all required definitions. This is to avoid conflicts
- *
- * Usage:
- * ${EnvVarUpdate} "ResultVar" "EnvVarName" "Action" "RegLoc" "PathString"
- *
- * Credits:
- * Version 1.0
- * * Cal Turney (turnec2)
- * * Amir Szekely (KiCHiK) and e-circ for developing the forerunners of this
- * function: AddToPath, un.RemoveFromPath, AddToEnvVar, un.RemoveFromEnvVar,
- * WriteEnvStr, and un.DeleteEnvStr
- * * Diego Pedroso (deguix) for StrTok
- * * Kevin English (kenglish_hi) for StrContains
- * * Hendri Adriaens (Smile2Me), Diego Pedroso (deguix), and Dan Fuhry
- * (dandaman32) for StrReplace
- *
- * Version 1.1 (compatibility with StrFunc.nsh)
- * * techtonik
- *
- * http://nsis.sourceforge.net/Environmental_Variables:_append%2C_prepend%2C_and_remove_entries
- *
- */
-
-
-!ifndef ENVVARUPDATE_FUNCTION
-!define ENVVARUPDATE_FUNCTION
-!verbose push
-!verbose 3
-!include "LogicLib.nsh"
-!include "WinMessages.NSH"
-!include "StrFunc.nsh"
-
-; ---- Fix for conflict if StrFunc.nsh is already includes in main file -----------------------
-!macro _IncludeStrFunction StrFuncName
- !ifndef ${StrFuncName}_INCLUDED
- ${${StrFuncName}}
- !endif
- !ifndef Un${StrFuncName}_INCLUDED
- ${Un${StrFuncName}}
- !endif
- !define un.${StrFuncName} "${Un${StrFuncName}}"
-!macroend
-
-!insertmacro _IncludeStrFunction StrTok
-!insertmacro _IncludeStrFunction StrStr
-!insertmacro _IncludeStrFunction StrRep
-
-; ---------------------------------- Macro Definitions ----------------------------------------
-!macro _EnvVarUpdateConstructor ResultVar EnvVarName Action Regloc PathString
- Push "${EnvVarName}"
- Push "${Action}"
- Push "${RegLoc}"
- Push "${PathString}"
- Call EnvVarUpdate
- Pop "${ResultVar}"
-!macroend
-!define EnvVarUpdate '!insertmacro "_EnvVarUpdateConstructor"'
-
-!macro _unEnvVarUpdateConstructor ResultVar EnvVarName Action Regloc PathString
- Push "${EnvVarName}"
- Push "${Action}"
- Push "${RegLoc}"
- Push "${PathString}"
- Call un.EnvVarUpdate
- Pop "${ResultVar}"
-!macroend
-!define un.EnvVarUpdate '!insertmacro "_unEnvVarUpdateConstructor"'
-; ---------------------------------- Macro Definitions end-------------------------------------
-
-;----------------------------------- EnvVarUpdate start----------------------------------------
-!define hklm_all_users 'HKLM "SYSTEM\CurrentControlSet\Control\Session Manager\Environment"'
-!define hkcu_current_user 'HKCU "Environment"'
-
-!macro EnvVarUpdate UN
-
-Function ${UN}EnvVarUpdate
-
- Push $0
- Exch 4
- Exch $1
- Exch 3
- Exch $2
- Exch 2
- Exch $3
- Exch
- Exch $4
- Push $5
- Push $6
- Push $7
- Push $8
- Push $9
- Push $R0
-
- /* After this point:
- -------------------------
- $0 = ResultVar (returned)
- $1 = EnvVarName (input)
- $2 = Action (input)
- $3 = RegLoc (input)
- $4 = PathString (input)
- $5 = Orig EnvVar (read from registry)
- $6 = Len of $0 (temp)
- $7 = tempstr1 (temp)
- $8 = Entry counter (temp)
- $9 = tempstr2 (temp)
- $R0 = tempChar (temp) */
-
- ; Step 1: Read contents of EnvVarName from RegLoc
- ;
- ; Check for empty EnvVarName
- ${If} $1 == ""
- SetErrors
- DetailPrint "ERROR: EnvVarName is blank"
- Goto EnvVarUpdate_Restore_Vars
- ${EndIf}
-
- ; Check for valid Action
- ${If} $2 != "A"
- ${AndIf} $2 != "P"
- ${AndIf} $2 != "R"
- SetErrors
- DetailPrint "ERROR: Invalid Action - must be A, P, or R"
- Goto EnvVarUpdate_Restore_Vars
- ${EndIf}
-
- ${If} $3 == HKLM
- ReadRegStr $5 ${hklm_all_users} $1 ; Get EnvVarName from all users into $5
- ${ElseIf} $3 == HKCU
- ReadRegStr $5 ${hkcu_current_user} $1 ; Read EnvVarName from current user into $5
- ${Else}
- SetErrors
- DetailPrint 'ERROR: Action is [$3] but must be "HKLM" or HKCU"'
- Goto EnvVarUpdate_Restore_Vars
- ${EndIf}
-
- ; Check for empty PathString
- ${If} $4 == ""
- SetErrors
- DetailPrint "ERROR: PathString is blank"
- Goto EnvVarUpdate_Restore_Vars
- ${EndIf}
-
- ; Make sure we've got some work to do
- ${If} $5 == ""
- ${AndIf} $2 == "R"
- SetErrors
- DetailPrint "$1 is empty - Nothing to remove"
- Goto EnvVarUpdate_Restore_Vars
- ${EndIf}
-
- ; Step 2: Scrub EnvVar
- ;
- StrCpy $0 $5 ; Copy the contents to $0
- ; Remove spaces around semicolons (NOTE: spaces before the 1st entry or
- ; after the last one are not removed here but instead in Step 3)
- ${If} $0 != "" ; If EnvVar is not empty ...
- ${Do}
- ${${UN}StrStr} $7 $0 " ;"
- ${If} $7 == ""
- ${ExitDo}
- ${EndIf}
- ${${UN}StrRep} $0 $0 " ;" ";" ; Remove '<space>;'
- ${Loop}
- ${Do}
- ${${UN}StrStr} $7 $0 "; "
- ${If} $7 == ""
- ${ExitDo}
- ${EndIf}
- ${${UN}StrRep} $0 $0 "; " ";" ; Remove ';<space>'
- ${Loop}
- ${Do}
- ${${UN}StrStr} $7 $0 ";;"
- ${If} $7 == ""
- ${ExitDo}
- ${EndIf}
- ${${UN}StrRep} $0 $0 ";;" ";"
- ${Loop}
-
- ; Remove a leading or trailing semicolon from EnvVar
- StrCpy $7 $0 1 0
- ${If} $7 == ";"
- StrCpy $0 $0 "" 1 ; Change ';<EnvVar>' to '<EnvVar>'
- ${EndIf}
- StrLen $6 $0
- IntOp $6 $6 - 1
- StrCpy $7 $0 1 $6
- ${If} $7 == ";"
- StrCpy $0 $0 $6 ; Change ';<EnvVar>' to '<EnvVar>'
- ${EndIf}
- ; DetailPrint "Scrubbed $1: [$0]" ; Uncomment to debug
- ${EndIf}
-
- /* Step 3. Remove all instances of the target path/string (even if "A" or "P")
- $6 = bool flag (1 = found and removed PathString)
- $7 = a string (e.g. path) delimited by semicolon(s)
- $8 = entry counter starting at 0
- $9 = copy of $0
- $R0 = tempChar */
-
- ${If} $5 != "" ; If EnvVar is not empty ...
- StrCpy $9 $0
- StrCpy $0 ""
- StrCpy $8 0
- StrCpy $6 0
-
- ${Do}
- ${${UN}StrTok} $7 $9 ";" $8 "0" ; $7 = next entry, $8 = entry counter
-
- ${If} $7 == "" ; If we've run out of entries,
- ${ExitDo} ; were done
- ${EndIf} ;
-
- ; Remove leading and trailing spaces from this entry (critical step for Action=Remove)
- ${Do}
- StrCpy $R0 $7 1
- ${If} $R0 != " "
- ${ExitDo}
- ${EndIf}
- StrCpy $7 $7 "" 1 ; Remove leading space
- ${Loop}
- ${Do}
- StrCpy $R0 $7 1 -1
- ${If} $R0 != " "
- ${ExitDo}
- ${EndIf}
- StrCpy $7 $7 -1 ; Remove trailing space
- ${Loop}
- ${If} $7 == $4 ; If string matches, remove it by not appending it
- StrCpy $6 1 ; Set 'found' flag
- ${ElseIf} $7 != $4 ; If string does NOT match
- ${AndIf} $0 == "" ; and the 1st string being added to $0,
- StrCpy $0 $7 ; copy it to $0 without a prepended semicolon
- ${ElseIf} $7 != $4 ; If string does NOT match
- ${AndIf} $0 != "" ; and this is NOT the 1st string to be added to $0,
- StrCpy $0 $0;$7 ; append path to $0 with a prepended semicolon
- ${EndIf} ;
-
- IntOp $8 $8 + 1 ; Bump counter
- ${Loop} ; Check for duplicates until we run out of paths
- ${EndIf}
-
- ; Step 4: Perform the requested Action
- ;
- ${If} $2 != "R" ; If Append or Prepend
- ${If} $6 == 1 ; And if we found the target
- DetailPrint "Target is already present in $1. It will be removed and"
- ${EndIf}
- ${If} $0 == "" ; If EnvVar is (now) empty
- StrCpy $0 $4 ; just copy PathString to EnvVar
- ${If} $6 == 0 ; If found flag is either 0
- ${OrIf} $6 == "" ; or blank (if EnvVarName is empty)
- DetailPrint "$1 was empty and has been updated with the target"
- ${EndIf}
- ${ElseIf} $2 == "A" ; If Append (and EnvVar is not empty),
- StrCpy $0 $0;$4 ; append PathString
- ${If} $6 == 1
- DetailPrint "appended to $1"
- ${Else}
- DetailPrint "Target was appended to $1"
- ${EndIf}
- ${Else} ; If Prepend (and EnvVar is not empty),
- StrCpy $0 $4;$0 ; prepend PathString
- ${If} $6 == 1
- DetailPrint "prepended to $1"
- ${Else}
- DetailPrint "Target was prepended to $1"
- ${EndIf}
- ${EndIf}
- ${Else} ; If Action = Remove
- ${If} $6 == 1 ; and we found the target
- DetailPrint "Target was found and removed from $1"
- ${Else}
- DetailPrint "Target was NOT found in $1 (nothing to remove)"
- ${EndIf}
- ${If} $0 == ""
- DetailPrint "$1 is now empty"
- ${EndIf}
- ${EndIf}
-
- ; Step 5: Update the registry at RegLoc with the updated EnvVar and announce the change
- ;
- ClearErrors
- ${If} $3 == HKLM
- WriteRegExpandStr ${hklm_all_users} $1 $0 ; Write it in all users section
- ${ElseIf} $3 == HKCU
- WriteRegExpandStr ${hkcu_current_user} $1 $0 ; Write it to current user section
- ${EndIf}
-
- IfErrors 0 +4
- MessageBox MB_OK|MB_ICONEXCLAMATION "Could not write updated $1 to $3"
- DetailPrint "Could not write updated $1 to $3"
- Goto EnvVarUpdate_Restore_Vars
-
- ; "Export" our change
- SendMessage ${HWND_BROADCAST} ${WM_WININICHANGE} 0 "STR:Environment" /TIMEOUT=5000
-
- EnvVarUpdate_Restore_Vars:
- ;
- ; Restore the user's variables and return ResultVar
- Pop $R0
- Pop $9
- Pop $8
- Pop $7
- Pop $6
- Pop $5
- Pop $4
- Pop $3
- Pop $2
- Pop $1
- Push $0 ; Push my $0 (ResultVar)
- Exch
- Pop $0 ; Restore his $0
-
-FunctionEnd
-
-!macroend ; EnvVarUpdate UN
-!insertmacro EnvVarUpdate ""
-!insertmacro EnvVarUpdate "un."
-;----------------------------------- EnvVarUpdate end----------------------------------------
-
-!verbose pop
-!endif
-
-
-Name "Rust"
-ShowInstDetails "show"
-ShowUninstDetails "show"
-SetCompressor "lzma"
-LicenseForceSelection checkbox
-
-InstallDir $PROGRAMFILES\Rust
-
-Page license
-Page directory
-Page instfiles
-UninstPage uninstConfirm
-UninstPage instfiles
-
-Section "Compiler"
- SetOutPath $INSTDIR
- File /nonfatal /r i686-pc-mingw32\stage3\*.*
-SectionEnd
-
-Section "Documentation"
- SetOutPath $INSTDIR\doc
- File /nonfatal /oname=rust.html doc\rust.html
- File /nonfatal /oname=rust.pdf doc\rust.pdf
-SectionEnd
-
-Section "SystemPath"
- ${EnvVarUpdate} $0 "PATH" "A" "HKLM" "$INSTDIR\bin"
-SectionEnd
-
-Section "Uninstall"
- Delete $INSTDIR\uninstall.exe
- Delete $INSTDIR\bin\*.*
- Delete $INSTDIR\bin\rustc\i686-pc-mingw32\bin\*.*
- Delete $INSTDIR\doc\rust.html
- Delete $INSTDIR\doc\rust.pdf
- RMDir $INSTDIR\bin\rustc\i686-pc-mingw32\bin
- RMDir $INSTDIR\bin\rustc\i686-pc-mingw32
- RMDir $INSTDIR\bin\rustc
- RMDir $INSTDIR\bin
- RMDir $INSTDIR\doc
- RMDir $INSTDIR
- DeleteRegKey HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\Rust"
- ${un.EnvVarUpdate} $0 "PATH" "R" "HKLM" "$INSTDIR\bin"
-SectionEnd
-
-Section
- WriteUninstaller $INSTDIR\uninstall.exe
- WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\Rust" \
- "DisplayName" "Rust"
- WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\Rust" \
- "Publisher" "Mozilla"
- WriteRegDWORD HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\Rust" \
- "NoModify" 1
- WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\Rust" \
- "UninstallString" "$\"$INSTDIR\uninstall.exe$\""
- WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\Rust" \
- "QuietUninstallString" "$\"$INSTDIR\uninstall.exe$\" /S"
-SectionEnd
libuv-0-byte-realloc1
Memcheck:Leak
fun:malloc
- fun:realloc
- fun:ev_realloc_emul
- fun:ev_realloc
- fun:epoll_destroy
- fun:ev_loop_destroy
+ ...
fun:uv_loop_delete
}
libuv-0-byte-realloc2
Memcheck:Leak
fun:malloc
- fun:realloc
- fun:ev_realloc_emul
- fun:ev_realloc
- fun:ev_loop_destroy
+ ...
fun:uv_loop_delete
}
}
}
-fn last_part(filename: str) -> str {
+fn last_part(filename: str) -> str unsafe {
let ix = str::rindex(filename, 47u8 /* '/' */);
assert ix >= 0;
- str::slice(filename, ix as uint + 1u, str::byte_len(filename) - 3u)
+ str::unsafe::slice_bytes(filename, ix as uint + 1u, str::byte_len(filename) - 3u)
}
enum happiness { passed, cleanly_rejected(str), known_bug(str), failed(str), }
brief = "Convert a char to the corresponding digit. Returns none when \
character is not a valid hexadecimal digit."
)]
-pure fn maybe_digit(c: char) -> option::t<u8> {
+pure fn maybe_digit(c: char) -> option<u8> {
alt c {
'0' to '9' { option::some(c as u8 - ('0' as u8)) }
'a' to 'z' { option::some(c as u8 + 10u8 - ('a' as u8)) }
export chan::{};
export port::{};
+enum rust_port {}
+
#[abi = "cdecl"]
native mod rustrt {
- type rust_port;
-
fn chan_id_send<T: send>(t: *sys::type_desc,
target_task: task::task, target_port: port_id,
data: T) -> ctypes::uintptr_t;
chan_t(task::task, port_id)
}
-resource port_ptr<T: send>(po: *rustrt::rust_port) {
+resource port_ptr<T: send>(po: *rust_port) {
// Once the port is detached it's guaranteed not to receive further
// messages
rustrt::rust_port_detach(po);
#[doc(
brief = "Receive on a raw port pointer"
)]
-fn recv_<T: send>(p: *rustrt::rust_port) -> T {
+fn recv_<T: send>(p: *rust_port) -> T {
// FIXME: Due to issue 1185 we can't use a return pointer when
// calling C code, and since we can't create our own return
// pointer on the stack, we're going to call a little intrinsic
// that will grab the value of the return pointer, then call this
// function, which we will then use to call the runtime.
- fn recv(dptr: *uint, port: *rustrt::rust_port,
+ fn recv(dptr: *uint, port: *rust_port,
yield: *ctypes::uintptr_t,
killed: *ctypes::uintptr_t) unsafe {
rustrt::port_recv(dptr, port, yield, killed);
export box, char, float, bessel, f32, f64, int, str, ptr;
export uint, u8, u32, u64, vec, bool;
-export either, option, result;
+export either, option, result, iter;
export ctypes, sys, unsafe, comm, task, logging;
export extfmt;
export math;
mod option;
mod result;
mod tuple;
-
+mod iter;
// Runtime and language-primitive support
// Top-level, visible-everywhere definitions.
-// Export type option as a synonym for option::t and export the some and none
+// Export type option as a synonym for option and export the some and none
// enum constructors.
import option::{some, none};
which are not obviously correct for all potential platforms.
*/
-export c_int, c_uint, long, longlong, unsigned, ulong, ulonglong;
+export c_char, c_int, c_uint, long, longlong, unsigned, ulong, ulonglong;
export intptr_t, uintptr_t;
export uint32_t;
export void::{};
// PORT adapt to architecture
+#[doc = "A signed integer with the same size as a C `char`."]
+type c_char = i8;
+
#[doc(
brief = "A signed integer with the same size as a C `int`."
)]
but using pointers to this type when interoperating \
with C void pointers can help in documentation."
)]
-enum void {
- // Making the only variant reference itself makes it impossible to
- // construct. Not exporting it makes it impossible to destructure.
- void_private(@void),
- // FIXME: #881
- void_private2(@void),
-}
+enum void {}
#[doc(
brief = "A float value with the same size as a C `float`."
// A formatted conversion from an expression to a string
type conv =
- {param: option::t<int>,
+ {param: option<int>,
flags: [flag],
width: count,
precision: count,
ret pieces;
}
fn peek_num(s: str, i: uint, lim: uint) ->
- option::t<{num: uint, next: uint}> {
+ option<{num: uint, next: uint}> {
if i >= lim { ret none; }
let c = s[i];
if !('0' as u8 <= c && c <= '9' as u8) { ret option::none; }
next: ty.next};
}
fn parse_parameter(s: str, i: uint, lim: uint) ->
- {param: option::t<int>, next: uint} {
+ {param: option<int>, next: uint} {
if i >= lim { ret {param: none, next: i}; }
let num = peek_num(s, i, lim);
ret alt num {
*/
fn to_str_common(num: float, digits: uint, exact: bool) -> str {
if is_NaN(num) { ret "NaN"; }
- let (num, accum) = num < 0.0 ? (-num, "-") : (num, "");
+ let (num, accum) = if num < 0.0 { (-num, "-") } else { (num, "") };
let trunc = num as uint;
let frac = num - (trunc as float);
accum += uint::str(trunc);
--- /dev/null
+iface iterable<A> {
+ fn iter(blk: fn(A));
+}
+
+impl<A> of iterable<A> for fn@(fn(A)) {
+ fn iter(blk: fn(A)) {
+ self(blk);
+ }
+}
+
+// accomodate the fact that int/uint are passed by value by default:
+impl of iterable<int> for fn@(fn(int)) {
+ fn iter(blk: fn(&&int)) {
+ self {|i| blk(i)}
+ }
+}
+
+impl of iterable<uint> for fn@(fn(uint)) {
+ fn iter(blk: fn(&&uint)) {
+ self {|i| blk(i)}
+ }
+}
+
+impl<A> of iterable<A> for [A] {
+ fn iter(blk: fn(A)) {
+ vec::iter(self, blk)
+ }
+}
+
+impl<A> of iterable<A> for option<A> {
+ fn iter(blk: fn(A)) {
+ option::may(self, blk)
+ }
+}
+
+fn enumerate<A,IA:iterable<A>>(self: IA, blk: fn(uint, A)) {
+ let i = 0u;
+ self.iter {|a|
+ blk(i, a);
+ i += 1u;
+ }
+}
+
+// Here: we have to use fn@ for predicates and map functions, because
+// we will be binding them up into a closure. Disappointing. A true
+// region type system might be able to do better than this.
+
+fn filter<A,IA:iterable<A>>(self: IA, prd: fn@(A) -> bool, blk: fn(A)) {
+ self.iter {|a|
+ if prd(a) { blk(a) }
+ }
+}
+
+fn map<A,B,IA:iterable<A>>(self: IA, cnv: fn@(A) -> B, blk: fn(B)) {
+ self.iter {|a|
+ let b = cnv(a);
+ blk(b);
+ }
+}
+
+fn flat_map<A,B,IA:iterable<A>,IB:iterable<B>>(
+ self: IA, cnv: fn@(A) -> IB, blk: fn(B)) {
+ self.iter {|a|
+ cnv(a).iter(blk)
+ }
+}
+
+fn foldl<A,B:copy,IA:iterable<A>>(self: IA, b0: B, blk: fn(B, A) -> B) -> B {
+ let b = b0;
+ self.iter {|a|
+ b = blk(b, a);
+ }
+ ret b;
+}
+
+fn to_list<A:copy,IA:iterable<A>>(self: IA) -> [A] {
+ foldl::<A,[A],IA>(self, [], {|r, a| r + [a]})
+}
+
+fn repeat(times: uint, blk: fn()) {
+ let i = 0u;
+ while i < times {
+ blk();
+ i += 1u;
+ }
+}
+
+
+#[test]
+fn test_enumerate() {
+ enumerate(["0", "1", "2"]) {|i,j|
+ assert #fmt["%u",i] == j;
+ }
+}
+
+#[test]
+fn test_map_and_to_list() {
+ let a = bind vec::iter([0, 1, 2], _);
+ let b = bind map(a, {|i| i*2}, _);
+ let c = to_list(b);
+ assert c == [0, 2, 4];
+}
+
+#[test]
+fn test_map_directly_on_vec() {
+ let b = bind map([0, 1, 2], {|i| i*2}, _);
+ let c = to_list(b);
+ assert c == [0, 2, 4];
+}
+
+#[test]
+fn test_filter_on_int_range() {
+ fn is_even(&&i: int) -> bool {
+ ret (i % 2) == 0;
+ }
+
+ let l = to_list(bind filter(bind int::range(0, 10, _), is_even, _));
+ assert l == [0, 2, 4, 6, 8];
+}
+
+#[test]
+fn test_filter_on_uint_range() {
+ fn is_even(&&i: uint) -> bool {
+ ret (i % 2u) == 0u;
+ }
+
+ let l = to_list(bind filter(bind uint::range(0u, 10u, _), is_even, _));
+ assert l == [0u, 2u, 4u, 6u, 8u];
+}
+
+#[test]
+fn test_flat_map_with_option() {
+ fn if_even(&&i: int) -> option<int> {
+ if (i % 2) == 0 { some(i) }
+ else { none }
+ }
+
+ let a = bind vec::iter([0, 1, 2], _);
+ let b = bind flat_map(a, if_even, _);
+ let c = to_list(b);
+ assert c == [0, 2];
+}
+
+#[test]
+fn test_flat_map_with_list() {
+ fn repeat(&&i: int) -> [int] {
+ let r = [];
+ int::range(0, i) {|_j| r += [i]; }
+ r
+ }
+
+ let a = bind vec::iter([0, 1, 2, 3], _);
+ let b = bind flat_map(a, repeat, _);
+ let c = to_list(b);
+ #debug["c = %?", c];
+ assert c == [1, 2, 2, 3, 3, 3];
+}
+
+#[test]
+fn test_repeat() {
+ let c = [],
+ i = 0u;
+ repeat(5u) {||
+ c += [(i * i)];
+ i += 1u;
+ };
+ #debug["c = %?", c];
+ assert c == [0u, 1u, 4u, 9u, 16u];
+}
+
+
Returns the minimum of two values
*/
-pure fn min<T: copy>(x: T, y: T) -> T { x < y ? x : y }
+pure fn min<T: copy>(x: T, y: T) -> T { if x < y { x } else { y} }
/*
Function: max
Returns the maximum of two values
*/
-pure fn max<T: copy>(x: T, y: T) -> T { x < y ? y : x }
+pure fn max<T: copy>(x: T, y: T) -> T { if x < y { y } else { x } }
#[test]
fn test_max_min() {
assert ln1p(float::infinity) == float::infinity;
}
-*/
\ No newline at end of file
+*/
export
// Creating a string
from_bytes,
- unsafe_from_bytes,
from_byte,
- unsafe_from_byte,
//push_utf8_bytes,
from_char,
from_chars,
// Transforming strings
bytes,
- to_chars,
+ chars,
substr,
- char_slice,
slice,
- safe_slice,
split,
splitn,
split_str,
// Comparing strings
eq,
- lteq,
+ le,
hash,
// Iterating through strings
- loop_chars,
all,
any,
map,
bytes_iter,
- iter_chars,
chars_iter,
+ split_chars_iter,
+ splitn_chars_iter,
words_iter,
lines_iter,
utf8_char_width,
char_range_at,
char_at,
- loop_chars_sub,
+ substr_all,
escape_char,
as_buf,
//buf,
- sbuf;
+ sbuf,
+ reserve,
+
+ unsafe;
#[abi = "cdecl"]
native mod rustrt {
fn rust_str_push(&s: str, ch: u8);
+ fn str_reserve_shared(&ss: str, nn: ctypes::size_t);
}
// FIXME: add pure to a lot of functions
Convert a vector of bytes to a UTF-8 string. Fails if invalid UTF-8.
*/
-fn from_bytes(vv: [u8]) -> str {
+fn from_bytes(vv: [u8]) -> str unsafe {
assert is_utf8(vv);
- ret unsafe_from_bytes(vv);
-}
-
-/*
-Function: unsafe_from_bytes
-
-Converts a vector of bytes to a string. Does not verify that the
-vector contains valid UTF-8.
-
-FIXME: stop exporting
-*/
-fn unsafe_from_bytes(v: [const u8]) -> str unsafe {
- let vcopy: [u8] = v + [0u8];
- let scopy: str = unsafe::reinterpret_cast(vcopy);
- unsafe::leak(vcopy);
- ret scopy;
+ ret unsafe::from_bytes(vv);
}
-/*
-Function: unsafe_from_byte
-
-Converts a byte to a string. Does not verify that the byte is
-valid UTF-8.
-
-FIXME: stop exporting
-*/
-fn unsafe_from_byte(u: u8) -> str { unsafe_from_bytes([u]) }
-
-
/*
Function: from_byte
}
ret i;
}
- let chars = to_chars(s);
+ let chars = chars(s);
let whities = count_whities(chars);
ret from_chars(vec::slice(chars, whities, vec::len(chars)));
}
}
ret i;
}
- let chars = to_chars(s);
+ let chars = chars(s);
let whities = count_whities(chars);
ret from_chars(vec::slice(chars, 0u, whities));
}
null-terminated.
*/
fn bytes(s: str) -> [u8] unsafe {
- let v = unsafe::reinterpret_cast(s);
+ let v = ::unsafe::reinterpret_cast(s);
let vcopy = vec::slice(v, 0u, vec::len(v) - 1u);
- unsafe::leak(v);
+ ::unsafe::leak(v);
ret vcopy;
}
/*
-Function: to_chars
+Function: chars
Convert a string to a vector of characters
FIXME: rename to 'chars'
*/
-fn to_chars(s: str) -> [char] {
+fn chars(s: str) -> [char] {
let buf: [char] = [];
let i = 0u;
let len = byte_len(s);
If `begin` + `len` is is greater than the byte length of the string
*/
-fn substr(s: str, begin: uint, len: uint) -> str {
- ret slice(s, begin, begin + len);
+fn substr(s: str, begin: uint, len: uint) -> str unsafe {
+ ret unsafe::slice_bytes(s, begin, begin + len);
}
/*
-Function: char_slice
+Function: slice
Unicode-safe slice. Returns a slice of the given string containing
the characters in the range [`begin`..`end`). `begin` and `end` are
- If begin is greater than end
- If end is greater than the character length of the string
-FIXME: rename to slice(), make faster by avoiding char conversion
-*/
-fn char_slice(s: str, begin: uint, end: uint) -> str {
- from_chars(vec::slice(to_chars(s), begin, end))
-}
-
-/*
-Function: slice
-
-Takes a bytewise slice from a string. Returns the substring from
-[`begin`..`end`).
-
-This function is not unicode-safe.
-
-Failure:
-
-- If begin is greater than end.
-- If end is greater than the length of the string.
-
-FIXME: rename to slice_byte or slice_byte_unsafe
-*/
-fn slice(s: str, begin: uint, end: uint) -> str unsafe {
- // FIXME: Typestate precondition
- assert (begin <= end);
- assert (end <= byte_len(s));
-
- let v: [u8] = unsafe::reinterpret_cast(s);
- let v2 = vec::slice(v, begin, end);
- unsafe::leak(v);
- v2 += [0u8];
- let s2: str = unsafe::reinterpret_cast(v2);
- unsafe::leak(v2);
- ret s2;
-}
-
-/*
-Function: safe_slice
-
-FIXME: make sure char_slice / slice / byte_slice
- have these preconditions and assertions
-FIXME: this shouldn't be mistaken for a UTF-8 safe slice
+FIXME: make faster by avoiding char conversion
*/
-fn safe_slice(s: str, begin: uint, end: uint) : uint::le(begin, end) -> str {
- // would need some magic to make this a precondition
- assert (end <= byte_len(s));
- ret slice(s, begin, end);
+fn slice(s: str, begin: uint, end: uint) -> str {
+ from_chars(vec::slice(chars(s), begin, end))
}
/*
let accum: str = "";
let ends_with_sep: bool = false;
- str::iter_chars(ss, {|cc| if sepfn(cc) {
+ chars_iter(ss, {|cc| if sepfn(cc) {
vv += [accum];
accum = "";
ends_with_sep = true;
let ii = 0u;
while ii+nn <= len {
- let w = char_slice( ss, ii, ii+nn );
+ let w = slice( ss, ii, ii+nn );
vec::push(ww,w);
ii += 1u;
}
Function: to_lower
Convert a string to lowercase
-
-FIXME: rewrite with map
*/
fn to_lower(s: str) -> str {
- let outstr = "";
- iter_chars(s) { |c|
- push_char(outstr, char::to_lower(c));
- }
- ret outstr;
+ map(s, char::to_lower)
}
/*
Function: to_upper
Convert a string to uppercase
-
-FIXME: rewrite with map
*/
fn to_upper(s: str) -> str {
- let outstr = "";
- iter_chars(s) { |c|
- push_char(outstr, char::to_upper(c));
- }
- ret outstr;
+ map(s, char::to_upper)
}
// FIXME: This is super-inefficient
The original string with all occurances of `from` replaced with `to`
*/
-fn replace(s: str, from: str, to: str) : is_not_empty(from) -> str {
+fn replace(s: str, from: str, to: str) : is_not_empty(from) -> str unsafe {
// FIXME (694): Shouldn't have to check this
check (is_not_empty(from));
if byte_len(s) == 0u {
ret "";
} else if starts_with(s, from) {
- ret to + replace(slice(s, byte_len(from), byte_len(s)), from, to);
+ ret to + replace(unsafe::slice_bytes(s, byte_len(from), byte_len(s)),
+ from, to);
} else {
let idx = find(s, from);
if idx == -1 {
ret s;
}
- ret char_slice(s, 0u, idx as uint) + to +
- replace(char_slice(s, idx as uint + char_len(from), char_len(s)),
+ ret slice(s, 0u, idx as uint) + to +
+ replace(slice(s, idx as uint + char_len(from), char_len(s)),
from, to);
}
}
*/
fn escape(s: str) -> str {
let r = "";
- loop_chars(s, { |c| r += escape_char(c); true });
+ all(s, { |c| r += escape_char(c); true });
r
}
pure fn eq(&&a: str, &&b: str) -> bool { a == b }
/*
-Function: lteq
+Function: le
Bytewise less than or equal
*/
-pure fn lteq(&&a: str, &&b: str) -> bool { a <= b }
+pure fn le(&&a: str, &&b: str) -> bool { a <= b }
/*
Function: hash
Section: Iterating through strings
*/
-/*
-Function: loop_chars
-
-Loop through a string, char by char
-
-Parameters:
-s - A string to traverse. It may be empty.
-it - A block to execute with each consecutive character of `s`.
-Return `true` to continue, `false` to stop.
-
-Returns:
-
-`true` If execution proceeded correctly, `false` if it was interrupted,
-that is if `it` returned `false` at any point.
-
-FIXME: rename to 'chars_loop' (change? currently a synonym to 'all')
- */
-fn loop_chars(s: str, it: fn(char) -> bool) -> bool{
- ret loop_chars_sub(s, 0u, byte_len(s), it);
-}
-
/*
Function: all
Return true if a predicate matches all characters or
if the string contains no characters
-
-// FIXME: a synonym to loop_chars
*/
-fn all(ss: str, ff: fn(char) -> bool) -> bool {
- str::loop_chars(ss, ff)
+fn all(s: str, it: fn(char) -> bool) -> bool{
+ ret substr_all(s, 0u, byte_len(s), it);
}
/*
*/
fn map(ss: str, ff: fn(char) -> char) -> str {
let result = "";
+ reserve(result, byte_len(ss));
- str::iter_chars(ss, {|cc|
+ chars_iter(ss, {|cc|
str::push_char(result, ff(cc));
});
Function: bytes_iter
Iterate over the bytes in a string
-
-FIXME: Should it really include the last byte '\0'?
*/
fn bytes_iter(ss: str, it: fn(u8)) {
let pos = 0u;
}
/*
-Function: iter_chars
+Function: chars_iter
Iterate over the characters in a string
-
-FIXME: rename to 'chars_iter'
*/
-fn iter_chars(s: str, it: fn(char)) {
+fn chars_iter(s: str, it: fn(char)) {
let pos = 0u, len = byte_len(s);
while (pos < len) {
let {ch, next} = char_range_at(s, pos);
}
/*
-Function: chars_iter
+Function: split_chars_iter
-Iterate over the characters in a string
+Apply a function to each substring after splitting
+by character
+*/
+fn split_chars_iter(ss: str, cc: char, ff: fn(&&str)) {
+ vec::iter(split_char(ss, cc), ff)
+}
+
+/*
+Function: splitn_chars_iter
-FIXME: A synonym to iter_chars
+Apply a function to each substring after splitting
+by character, up to nn times
+
+FIXME: make this use chars when splitn/splitn_char is fixed
*/
-fn chars_iter(ss: str, it: fn(char)) {
- iter_chars(ss, it)
+fn splitn_chars_iter(ss: str, sep: u8, count: uint, ff: fn(&&str)) {
+ vec::iter(splitn(ss, sep, count), ff)
}
/*
vec::iter(lines(ss), ff)
}
-// FIXME: ADD split_char_iter
-// FIXME: ADD splitn_char_iter
-
/*
Section: Searching
*/
Returns the index of the first matching byte. Returns -1 if
no match is found.
+
+FIXME: UTF-8
*/
fn index(s: str, c: u8) -> int {
let i: int = 0;
Returns the index of the last matching byte. Returns -1
if no match is found.
+
+FIXME: UTF-8
*/
fn rindex(s: str, c: u8) -> int {
let n: int = byte_len(s) as int;
Returns:
The index of the first occurance of `needle`, or -1 if not found.
+
+FIXME: UTF-8?
*/
fn find(haystack: str, needle: str) -> int {
let haystack_len: int = byte_len(haystack) as int;
Returns true if the string contains only whitespace
*/
fn is_whitespace(s: str) -> bool {
- ret loop_chars(s, char::is_whitespace);
+ ret all(s, char::is_whitespace);
}
/*
FIXME: rename to 'len_bytes'?
*/
pure fn byte_len(s: str) -> uint unsafe {
- let v: [u8] = unsafe::reinterpret_cast(s);
+ let v: [u8] = ::unsafe::reinterpret_cast(s);
let vlen = vec::len(v);
- unsafe::leak(v);
+ ::unsafe::leak(v);
// There should always be a null terminator
assert (vlen > 0u);
ret vlen - 1u;
FIXME: rename to 'substr_len_chars'
*/
fn char_len_range(s: str, byte_start: uint, byte_len: uint) -> uint {
- let i = byte_start;
+ let i = byte_start;
+ let byte_stop = i + byte_len;
let len = 0u;
- while i < byte_len {
+ while i < byte_stop {
let chsize = utf8_char_width(s[i]);
assert (chsize > 0u);
len += 1u;
i += chsize;
}
- assert (i == byte_len);
ret len;
}
fn char_at(s: str, i: uint) -> char { ret char_range_at(s, i).ch; }
/*
-Function: loop_chars_sub
+Function: substr_all
Loop through a substring, char by char
- This function does not check whether the substring is valid.
- This function fails if `byte_offset` or `byte_len` do not
represent valid positions inside `s`
-
-FIXME: rename to 'substr_all'
*/
-fn loop_chars_sub(s: str, byte_offset: uint, byte_len: uint,
+fn substr_all(s: str, byte_offset: uint, byte_len: uint,
it: fn(char) -> bool) -> bool {
let i = byte_offset;
let result = true;
// no guarantee that the string is rooted). Instead, use as_buf below.
unsafe fn buf(s: str) -> sbuf {
let saddr = ptr::addr_of(s);
- let vaddr: *[u8] = unsafe::reinterpret_cast(saddr);
+ let vaddr: *[u8] = ::unsafe::reinterpret_cast(saddr);
let buf = vec::to_ptr(*vaddr);
ret buf;
}
*/
type sbuf = *u8;
+// Function: reserve
+//
+// Allocate more memory for a string, up to `nn` + 1 bytes
+fn reserve(&ss: str, nn: uint) {
+ rustrt::str_reserve_shared(ss, nn);
+}
+
+// Module: unsafe
+//
+// These functions may create invalid UTF-8 strings and eat your baby.
+mod unsafe {
+ export
+ // UNSAFE
+ from_bytes,
+ from_byte,
+ slice_bytes,
+ slice_bytes_safe_range;
+
+ // Function: unsafe::from_bytes
+ //
+ // Converts a vector of bytes to a string. Does not verify that the
+ // vector contains valid UTF-8.
+ unsafe fn from_bytes(v: [const u8]) -> str unsafe {
+ let vcopy: [u8] = v + [0u8];
+ let scopy: str = ::unsafe::reinterpret_cast(vcopy);
+ ::unsafe::leak(vcopy);
+ ret scopy;
+ }
+
+ // Function: unsafe::from_byte
+ //
+ // Converts a byte to a string. Does not verify that the byte is
+ // valid UTF-8.
+ unsafe fn from_byte(u: u8) -> str { unsafe::from_bytes([u]) }
+
+ /*
+ Function: slice
+
+ Takes a bytewise (not UTF-8) slice from a string.
+ Returns the substring from [`begin`..`end`).
+
+ Failure:
+
+ - If begin is greater than end.
+ - If end is greater than the length of the string.
+ */
+ unsafe fn slice_bytes(s: str, begin: uint, end: uint) -> str unsafe {
+ // FIXME: Typestate precondition
+ assert (begin <= end);
+ assert (end <= byte_len(s));
+
+ let v: [u8] = ::unsafe::reinterpret_cast(s);
+ let v2 = vec::slice(v, begin, end);
+ ::unsafe::leak(v);
+ v2 += [0u8];
+ let s2: str = ::unsafe::reinterpret_cast(v2);
+ ::unsafe::leak(v2);
+ ret s2;
+ }
+
+ /*
+ Function: slice_bytes_safe_range
+
+ Like slice_bytes, with a precondition
+ */
+ unsafe fn slice_bytes_safe_range(s: str, begin: uint, end: uint)
+ : uint::le(begin, end) -> str {
+ // would need some magic to make this a precondition
+ assert (end <= byte_len(s));
+ ret slice_bytes(s, begin, end);
+ }
+
+}
+
#[cfg(test)]
mod tests {
}
#[test]
- fn test_lteq() {
- assert (lteq("", ""));
- assert (lteq("", "foo"));
- assert (lteq("foo", "foo"));
+ fn test_le() {
+ assert (le("", ""));
+ assert (le("", "foo"));
+ assert (le("foo", "foo"));
assert (!eq("foo", "bar"));
}
#[test]
fn test_to_upper() {
- // to_upper doesn't understand unicode yet,
- // but we need to at least preserve it
+ // char::to_upper, and hence str::to_upper
+ // are culturally insensitive: I'm not sure they
+ // really work for anything but English ASCII, but YMMV
let unicode = "\u65e5\u672c";
let input = "abcDEF" + unicode + "xyz:.;";
}
#[test]
- fn test_slice() {
- assert (eq("ab", slice("abc", 0u, 2u)));
- assert (eq("bc", slice("abc", 1u, 3u)));
- assert (eq("", slice("abc", 1u, 1u)));
+ fn test_to_lower() {
+ assert "" == map("", char::to_lower);
+ assert "ymca" == map("YMCA", char::to_lower);
+ }
+
+ #[test]
+ fn test_unsafe_slice() unsafe {
+ assert (eq("ab", unsafe::slice_bytes("abc", 0u, 2u)));
+ assert (eq("bc", unsafe::slice_bytes("abc", 1u, 3u)));
+ assert (eq("", unsafe::slice_bytes("abc", 1u, 1u)));
fn a_million_letter_a() -> str {
let i = 0;
let rs = "";
ret rs;
}
assert (eq(half_a_million_letter_a(),
- slice(a_million_letter_a(), 0u, 500000u)));
+ unsafe::slice_bytes(a_million_letter_a(), 0u, 500000u)));
}
#[test]
}
#[test]
- fn test_char_slice() {
- assert (eq("ab", char_slice("abc", 0u, 2u)));
- assert (eq("bc", char_slice("abc", 1u, 3u)));
- assert (eq("", char_slice("abc", 1u, 1u)));
- assert (eq("\u65e5", char_slice("\u65e5\u672c", 0u, 1u)));
+ fn test_slice() {
+ assert (eq("ab", slice("abc", 0u, 2u)));
+ assert (eq("bc", slice("abc", 1u, 3u)));
+ assert (eq("", slice("abc", 1u, 1u)));
+ assert (eq("\u65e5", slice("\u65e5\u672c", 0u, 1u)));
let data = "ประเทศไทย中华";
- assert (eq("ป", char_slice(data, 0u, 1u)));
- assert (eq("ร", char_slice(data, 1u, 2u)));
- assert (eq("华", char_slice(data, 10u, 11u)));
- assert (eq("", char_slice(data, 1u, 1u)));
+ assert (eq("ป", slice(data, 0u, 1u)));
+ assert (eq("ร", slice(data, 1u, 2u)));
+ assert (eq("华", slice(data, 10u, 11u)));
+ assert (eq("", slice(data, 1u, 1u)));
fn a_million_letter_X() -> str {
let i = 0;
ret rs;
}
assert (eq(half_a_million_letter_X(),
- char_slice(a_million_letter_X(), 0u, 500000u)));
+ slice(a_million_letter_X(), 0u, 500000u)));
}
#[test]
}
#[test]
- fn test_unsafe_from_bytes() {
+ fn test_unsafe_from_bytes() unsafe {
let a = [65u8, 65u8, 65u8, 65u8, 65u8, 65u8, 65u8];
- let b = unsafe_from_bytes(a);
+ let b = unsafe::from_bytes(a);
assert (b == "AAAAAAA");
}
#[test]
#[should_fail]
+ #[ignore(cfg(target_os = "win32"))]
fn test_from_bytes_fail() {
let bb = [0xff_u8, 0xb8_u8, 0xa8_u8,
0xe0_u8, 0xb9_u8, 0x84_u8,
assert !contains("", "a");
}
- #[test]
- fn test_iter_chars() {
- let i = 0;
- iter_chars("x\u03c0y") {|ch|
- alt i {
- 0 { assert ch == 'x'; }
- 1 { assert ch == '\u03c0'; }
- 2 { assert ch == 'y'; }
- }
- i += 1;
- }
-
- iter_chars("") {|_ch| fail; } // should not fail
- }
-
#[test]
fn test_chars_iter() {
let i = 0;
bytes_iter("") {|bb| assert bb == 0u8; }
}
+ #[test]
+ fn test_split_chars_iter() {
+ let data = "\nMary had a little lamb\nLittle lamb\n";
+
+ let ii = 0;
+
+ split_chars_iter(data, ' ') {|xx|
+ alt ii {
+ 0 { assert "\nMary" == xx; }
+ 1 { assert "had" == xx; }
+ 2 { assert "a" == xx; }
+ 3 { assert "little" == xx; }
+ _ { () }
+ }
+ ii += 1;
+ }
+ }
+
+ #[test]
+ fn test_splitn_chars_iter() {
+ let data = "\nMary had a little lamb\nLittle lamb\n";
+
+ let ii = 0;
+
+ splitn_chars_iter(data, ' ' as u8, 2u) {|xx|
+ alt ii {
+ 0 { assert "\nMary" == xx; }
+ 1 { assert "had" == xx; }
+ 2 { assert "a little lamb\nLittle lamb\n" == xx; }
+ _ { () }
+ }
+ ii += 1;
+ }
+ }
+
#[test]
fn test_words_iter() {
let data = "\nMary had a little lamb\nLittle lamb\n";
#[test]
#[should_fail]
+ #[ignore(cfg(target_os = "win32"))]
fn test_windowed_() {
let _x = windowed(0u, "abcd");
}
+
+ #[test]
+ fn test_chars() {
+ let ss = "ศไทย中华Việt Nam";
+ assert ['ศ','ไ','ท','ย','中','华','V','i','ệ','t',' ','N','a','m']
+ == chars(ss);
+ }
}
// visible-in-crate, but not re-exported.
fn last_os_error() -> str;
fn refcount<T>(t: @T) -> ctypes::intptr_t;
- fn do_gc();
fn unsupervise();
fn shape_log_str<T>(t: *sys::type_desc, data: T) -> str;
fn rust_set_exit_status(code: ctypes::intptr_t);
- fn set_min_stack(size: ctypes::uintptr_t);
}
#[abi = "rust-intrinsic"]
ret rustrt::refcount::<T>(t);
}
-/*
-Function: do_gc
-
-Force a garbage collection
-*/
-fn do_gc() -> () {
- ret rustrt::do_gc();
-}
-
// FIXME: There's a wrapper for this in the task module and this really
// just belongs there
fn unsupervise() -> () {
rustrt::rust_set_exit_status(code as ctypes::intptr_t);
}
-// FIXME: #1495 - This shouldn't exist
-#[doc(
- brief =
- "Globally set the minimum size, in bytes, of a stack segment",
- desc =
- "Rust tasks have segmented stacks that are connected in a linked list \
- allowing them to start very small and grow very large. In some \
- situations this can result in poor performance. Calling this function \
- will set the minimum size of all stack segments allocated in the \
- future, for all tasks."
-)]
-#[deprecated]
-fn set_min_stack(size: uint) {
- rustrt::set_min_stack(size);
-}
-
#[cfg(test)]
mod tests {
export task;
export joinable_task;
-export sleep;
export yield;
export task_notification;
export join;
export unsupervise;
-export pin;
-export unpin;
export task_result;
export tr_success;
export tr_failure;
#[abi = "rust-intrinsic"]
native mod rusti {
// these must run on the Rust stack so that they can swap stacks etc:
- fn task_sleep(task: *rust_task, time_in_us: c::size_t, &killed: bool);
+ fn task_yield(task: *rust_task, &killed: bool);
}
type rust_closure = {
#[link_name = "rustrt"]
#[abi = "cdecl"]
native mod rustrt {
- // these can run on the C stack:
- fn pin_task();
- fn unpin_task();
fn get_task_id() -> task_id;
fn rust_get_task() -> *rust_task;
fn drop_task(task_id: *rust_task);
fn get_task_pointer(id: task_id) -> *rust_task;
- fn migrate_alloc(alloc: *u8, target: task_id);
-
fn start_task(id: task, closure: *rust_closure);
fn rust_task_is_unwinding(rt: *rust_task) -> bool;
}
fn spawn_inner(-f: fn~(),
- notify: option<comm::chan<task_notification>>) -> task unsafe {
+ notify: option<comm::chan<task_notification>>) -> task unsafe {
let closure: *rust_closure = unsafe::reinterpret_cast(ptr::addr_of(f));
#debug("spawn: closure={%x,%x}", (*closure).fnptr, (*closure).envptr);
let id = rustrt::new_task();
fn get_task() -> task { rustrt::get_task_id() }
/*
-Function: sleep
-
-Hints the scheduler to yield this task for a specified ammount of time.
+Function: yield
-Parameters:
+Yield control to the task scheduler
-time_in_us - maximum number of microseconds to yield control for
+The scheduler may schedule another task to execute.
*/
-fn sleep(time_in_us: uint) {
+fn yield() {
let task = rustrt::rust_get_task();
let killed = false;
- // FIXME: uncomment this when extfmt is moved to core
- // in a snapshot.
- // #debug("yielding for %u us", time_in_us);
- rusti::task_sleep(task, time_in_us, killed);
+ rusti::task_yield(task, killed);
if killed && !currently_unwinding() {
fail "killed";
}
}
-/*
-Function: yield
-
-Yield control to the task scheduler
-
-The scheduler may schedule another task to execute.
-*/
-fn yield() { sleep(1u) }
-
/*
Function: join
*/
fn unsupervise() { ret sys::unsupervise(); }
-/*
-Function: pin
-
-Pins the current task and future child tasks to a single scheduler thread
-*/
-fn pin() { rustrt::pin_task(); }
-
-/*
-Function: unpin
-
-Unpin the current task and future child tasks
-*/
-fn unpin() { rustrt::unpin_task(); }
-
/*
Function: currently_unwinding()
#[cfg(test)]
mod tests {
- #[test]
- fn test_sleep() { sleep(1000000u); }
-
// FIXME: Leaks on windows
#[test]
#[ignore(cfg(target_os = "win32"))]
An option containing the last element of `v` if `v` is not empty, or
none if `v` is empty.
*/
-pure fn last<T: copy>(v: [const T]) -> option::t<T> {
+pure fn last<T: copy>(v: [const T]) -> option<T> {
if len(v) == 0u { ret none; }
ret some(v[len(v) - 1u]);
}
ret e;
}
-// TODO: Write this, unsafely, in a way that's not O(n).
/*
Function: pop
Remove the last element from a vector and return it
*/
-fn pop<T: copy>(&v: [const T]) -> T {
+fn pop<T>(&v: [const T]) -> T unsafe {
let ln = len(v);
- assert (ln > 0u);
- ln -= 1u;
- let e = v[ln];
- v = slice(v, 0u, ln);
- ret e;
-// FIXME use this implementation after the next snapshot (27.01.2012)
-/* let new_ln = len(v) - 1u;
- assert (new_ln > 0u);
- let valptr = ptr::mut_addr_of(v[new_ln]);
+ assert ln > 0u;
+ let valptr = ptr::mut_addr_of(v[ln - 1u]);
let val <- *valptr;
- unsafe::set_len(v, new_ln);
+ unsafe::set_len(v, ln - 1u);
val
-*/
}
/*
If function `f` returns `none` then that element is excluded from
the resulting vector.
*/
-fn filter_map<T: copy, U: copy>(v: [const T], f: fn(T) -> option::t<U>)
+fn filter_map<T: copy, U: copy>(v: [const T], f: fn(T) -> option<U>)
-> [U] {
let result = [];
for elem: T in v {
When function `f` returns true then an option containing the element
is returned. If `f` matches no elements then none is returned.
*/
-fn find<T: copy>(v: [T], f: fn(T) -> bool) -> option::t<T> {
+fn find<T: copy>(v: [T], f: fn(T) -> bool) -> option<T> {
find_from(v, 0u, len(v), f)
}
is returned. If `f` matches no elements then none is returned.
*/
fn find_from<T: copy>(v: [T], start: uint, end: uint, f: fn(T) -> bool) ->
- option::t<T> {
+ option<T> {
option::map(position_from(v, start, end, f)) { |i| v[i] }
}
returns true then an option containing the element is returned. If `f`
matches no elements then none is returned.
*/
-fn rfind<T: copy>(v: [T], f: fn(T) -> bool) -> option::t<T> {
+fn rfind<T: copy>(v: [T], f: fn(T) -> bool) -> option<T> {
rfind_from(v, 0u, len(v), f)
}
the element is returned. If `f` matches no elements then none is returned.
*/
fn rfind_from<T: copy>(v: [T], start: uint, end: uint, f: fn(T) -> bool) ->
- option::t<T> {
+ option<T> {
option::map(rposition_from(v, start, end, f)) { |i| v[i] }
}
option::some(uint) - The first index containing a matching value
option::none - No elements matched
*/
-fn position_elt<T>(v: [T], x: T) -> option::t<uint> {
+fn position_elt<T>(v: [T], x: T) -> option<uint> {
position(v) { |y| x == y }
}
then an option containing the index is returned. If `f` matches no elements
then none is returned.
*/
-fn position<T>(v: [T], f: fn(T) -> bool) -> option::t<uint> {
+fn position<T>(v: [T], f: fn(T) -> bool) -> option<uint> {
position_from(v, 0u, len(v), f)
}
returned. If `f` matches no elements then none is returned.
*/
fn position_from<T>(v: [T], start: uint, end: uint, f: fn(T) -> bool) ->
- option::t<uint> {
+ option<uint> {
assert start <= end;
assert end <= len(v);
let i = start;
option::some(uint) - The last index containing a matching value
option::none - No elements matched
*/
-fn rposition_elt<T>(v: [T], x: T) -> option::t<uint> {
+fn rposition_elt<T>(v: [T], x: T) -> option<uint> {
rposition(v) { |y| x == y }
}
`f` returns true then an option containing the index is returned. If `f`
matches no elements then none is returned.
*/
-fn rposition<T>(v: [T], f: fn(T) -> bool) -> option::t<uint> {
+fn rposition<T>(v: [T], f: fn(T) -> bool) -> option<uint> {
rposition_from(v, 0u, len(v), f)
}
the index is returned. If `f` matches no elements then none is returned.
*/
fn rposition_from<T>(v: [T], start: uint, end: uint, f: fn(T) -> bool) ->
- option::t<uint> {
+ option<uint> {
assert start <= end;
assert end <= len(v);
let i = end;
pure fn is_equal(&&x: uint, &&y:uint) -> bool { ret x == y; }
- fn square_if_odd(&&n: uint) -> option::t<uint> {
+ fn square_if_odd(&&n: uint) -> option<uint> {
ret if n % 2u == 1u { some(n * n) } else { none };
}
assert (w[1] == 9u);
assert (w[2] == 25u);
- fn halve(&&i: int) -> option::t<int> {
+ fn halve(&&i: int) -> option<int> {
if i % 2 == 0 {
ret option::some::<int>(i / 2);
} else { ret option::none::<int>; }
#[test]
#[should_fail]
+ #[ignore(cfg(target_os = "win32"))]
fn test_windowed_() {
let _x = windowed (0u, [1u,2u,3u,4u,5u,6u]);
}
t({ base: *mutable T, len: uint, rsrc: @dtor_res})
}
-resource dtor_res(dtor: option::t<fn@()>) {
+resource dtor_res(dtor: option<fn@()>) {
alt dtor {
option::none { }
option::some(f) { f(); }
// FIXME eventually, a proper datatype plus an exported impl would be
// preferrable
fn create<T: copy>() -> t<T> {
- type cell<T> = option::t<T>;
+ type cell<T> = option<T>;
let initial_capacity: uint = 32u; // 2^5
/**
ret {data: data, start: elt_size.next, end: end};
}
-fn maybe_get_doc(d: doc, tg: uint) -> option::t<doc> {
+fn maybe_get_doc(d: doc, tg: uint) -> option<doc> {
let pos = d.start;
while pos < d.end {
let elt_tag = vint_at(*d.data, pos);
export libc;
export libc_constants;
export pipe;
-export fd_FILE;
+export FILE, fd_FILE;
export close;
export fclose;
export waitpid;
// FIXME Somehow merge stuff duplicated here and macosx_os.rs. Made difficult
// by https://github.com/graydon/rust/issues#issue/268
+enum FILE_opaque {}
+type FILE = *FILE_opaque;
+enum dir {}
+enum dirent {}
+
#[nolink]
#[abi = "cdecl"]
native mod libc {
fn read(fd: fd_t, buf: *u8, count: size_t) -> ssize_t;
fn write(fd: fd_t, buf: *u8, count: size_t) -> ssize_t;
- fn fread(buf: *u8, size: size_t, n: size_t, f: libc::FILE) -> size_t;
- fn fwrite(buf: *u8, size: size_t, n: size_t, f: libc::FILE) -> size_t;
+ fn fread(buf: *u8, size: size_t, n: size_t, f: FILE) -> size_t;
+ fn fwrite(buf: *u8, size: size_t, n: size_t, f: FILE) -> size_t;
fn open(s: str::sbuf, flags: c_int, mode: unsigned) -> fd_t;
fn close(fd: fd_t) -> c_int;
- type FILE;
fn fopen(path: str::sbuf, mode: str::sbuf) -> FILE;
fn fdopen(fd: fd_t, mode: str::sbuf) -> FILE;
fn fclose(f: FILE);
fn feof(f: FILE) -> c_int;
fn fseek(f: FILE, offset: long, whence: c_int) -> c_int;
fn ftell(f: FILE) -> long;
- type dir;
- fn opendir(d: str::sbuf) -> dir;
- fn closedir(d: dir) -> c_int;
- type dirent;
- fn readdir(d: dir) -> dirent;
+ fn opendir(d: str::sbuf) -> *dir;
+ fn closedir(d: *dir) -> c_int;
+ fn readdir(d: *dir) -> *dirent;
fn getenv(n: str::sbuf) -> str::sbuf;
fn setenv(n: str::sbuf, v: str::sbuf, overwrite: c_int) -> c_int;
fn unsetenv(n: str::sbuf) -> c_int;
ret {in: fds.in, out: fds.out};
}
-fn fd_FILE(fd: fd_t) -> libc::FILE {
+fn fd_FILE(fd: fd_t) -> FILE {
ret str::as_buf("r", {|modebuf| libc::fdopen(fd, modebuf) });
}
libc::close(fd)
}
-fn fclose(file: libc::FILE) {
+fn fclose(file: FILE) {
libc::fclose(file)
}
/// Returns the directory containing the running program
/// followed by a path separator
-fn get_exe_path() -> option::t<fs::path> unsafe {
+fn get_exe_path() -> option<fs::path> unsafe {
let bufsize = 1023u;
// FIXME: path "strings" will likely need fixing...
let path = str::from_bytes(vec::init_elt(bufsize, 0u8));
the provided path. If an empty path is provided or the path ends
with a path separator then an empty path is returned.
*/
-fn basename(p: path) -> path {
+fn basename(p: path) -> path unsafe {
let i: int = str::rindex(p, os_fs::path_sep as u8);
if i == -1 {
i = str::rindex(p, os_fs::alt_path_sep as u8);
}
let len = str::byte_len(p);
if i + 1 as uint >= len { ret p; }
- ret str::slice(p, i + 1 as uint, len);
+ ret str::unsafe::slice_bytes(p, i + 1 as uint, len);
}
*/
import option::{some, none};
-import option = option::t;
+import option = option;
export treemap;
export init;
fn traverse<K, V: copy>(m: treemap<K, V>, f: fn(K, V)) {
alt *m {
empty { }
- node(@k, @v, _, _) {
+ /*
+ Previously, this had what looked like redundant
+ matches to me, so I changed it. but that may be a
+ de-optimization -- tjc
+ */
+ node(@k, @v, left, right) {
// copy v to make aliases work out
let v1 = v;
- alt *m { node(_, _, left, _) { traverse(left, f); } }
+ traverse(left, f);
f(k, v1);
- alt *m { node(_, _, _, right) { traverse(right, f); } }
+ traverse(right, f);
}
}
}
Get the value of an environment variable
*/
-fn getenv(n: str) -> option::t<str> { }
+fn getenv(n: str) -> option<str> { }
#[cfg(bogus)]
/*
#[cfg(target_os = "linux")]
#[cfg(target_os = "macos")]
#[cfg(target_os = "freebsd")]
-fn getenv(n: str) -> option::t<str> unsafe {
+fn getenv(n: str) -> option<str> unsafe {
let s = str::as_buf(n, {|buf| os::libc::getenv(buf) });
ret if unsafe::reinterpret_cast(s) == 0 {
option::none::<str>
}
#[cfg(target_os = "win32")]
-fn getenv(n: str) -> option::t<str> {
+fn getenv(n: str) -> option<str> {
let nsize = 256u;
while true {
let v: [u8] = [];
ret alt nm { short(ch) { str::from_char(ch) } long(s) { s } };
}
-fn find_opt(opts: [opt], nm: name) -> option::t<uint> {
+fn find_opt(opts: [opt], nm: name) -> option<uint> {
vec::position(opts, { |opt| opt.name == nm })
}
<opt_str>, etc. to interrogate results.
err(fail_) - On failure. Use <fail_str> to get an error message.
*/
-fn getopts(args: [str], opts: [opt]) -> result {
+fn getopts(args: [str], opts: [opt]) -> result unsafe {
let n_opts = vec::len::<opt>(opts);
fn f(_x: uint) -> [optval] { ret []; }
let vals = vec::init_fn_mut::<[optval]>(n_opts, f);
let names;
let i_arg = option::none::<str>;
if cur[1] == '-' as u8 {
- let tail = str::slice(cur, 2u, curlen);
+ let tail = str::unsafe::slice_bytes(cur, 2u, curlen);
let eq = str::index(tail, '=' as u8);
if eq == -1 {
names = [long(tail)];
} else {
- names = [long(str::slice(tail, 0u, eq as uint))];
+ names =
+ [long(str::unsafe::slice_bytes(tail,0u,eq as uint))];
i_arg =
- option::some::<str>(str::slice(tail,
+ option::some::<str>(str::unsafe::slice_bytes(tail,
(eq as uint) + 1u,
curlen - 2u));
}
Returns the string argument supplied to a matching option or none
*/
-fn opt_maybe_str(m: match, nm: str) -> option::t<str> {
+fn opt_maybe_str(m: match, nm: str) -> option<str> {
let vals = opt_vals(m, nm);
if vec::len::<optval>(vals) == 0u { ret none::<str>; }
ret alt vals[0] { val(s) { some::<str>(s) } _ { none::<str> } };
present but no argument was provided, and the argument if the option was
present and an argument was provided.
*/
-fn opt_default(m: match, nm: str, def: str) -> option::t<str> {
+fn opt_default(m: match, nm: str, def: str) -> option<str> {
let vals = opt_vals(m, nm);
if vec::len::<optval>(vals) == 0u { ret none::<str>; }
ret alt vals[0] { val(s) { some::<str>(s) } _ { some::<str>(def) } }
#[abi = "cdecl"]
native mod rustrt {
- fn rust_get_stdin() -> os::libc::FILE;
- fn rust_get_stdout() -> os::libc::FILE;
- fn rust_get_stderr() -> os::libc::FILE;
+ fn rust_get_stdin() -> os::FILE;
+ fn rust_get_stdout() -> os::FILE;
+ fn rust_get_stderr() -> os::FILE;
}
// Reading
};
}
-impl of reader for os::libc::FILE {
+impl of reader for os::FILE {
fn read_bytes(len: uint) -> [u8] unsafe {
let buf = [];
vec::reserve(buf, len);
fn tell() -> uint { self.base.tell() }
}
-resource FILE_res(f: os::libc::FILE) { os::libc::fclose(f); }
+resource FILE_res(f: os::FILE) { os::libc::fclose(f); }
-fn FILE_reader(f: os::libc::FILE, cleanup: bool) -> reader {
+fn FILE_reader(f: os::FILE, cleanup: bool) -> reader {
if cleanup {
{base: f, cleanup: FILE_res(f)} as reader
} else {
fn flush() -> int { self.base.flush() }
}
-impl of writer for os::libc::FILE {
+impl of writer for os::FILE {
fn write(v: [const u8]) unsafe {
let len = vec::len(v);
let vbuf = vec::unsafe::to_ptr(v);
fn flush() -> int { os::libc::fflush(self) as int }
}
-fn FILE_writer(f: os::libc::FILE, cleanup: bool) -> writer {
+fn FILE_writer(f: os::FILE, cleanup: bool) -> writer {
if cleanup {
{base: f, cleanup: FILE_res(f)} as writer
} else {
type arg<t> = {
val: t,
- opt_level: option::t<level>,
+ opt_level: option<level>,
fsync_fn: fn@(t, level) -> int
};
// fsync file after executing blk
// FIXME find better way to create resources within lifetime of outer res
- fn FILE_res_sync(&&file: FILE_res, opt_level: option::t<level>,
- blk: fn(&&res<os::libc::FILE>)) {
+ fn FILE_res_sync(&&file: FILE_res, opt_level: option<level>,
+ blk: fn(&&res<os::FILE>)) {
blk(res({
val: *file, opt_level: opt_level,
- fsync_fn: fn@(&&file: os::libc::FILE, l: level) -> int {
+ fsync_fn: fn@(&&file: os::FILE, l: level) -> int {
ret os::fsync_fd(os::libc::fileno(file), l) as int;
}
}));
}
// fsync fd after executing blk
- fn fd_res_sync(&&fd: fd_res, opt_level: option::t<level>,
+ fn fd_res_sync(&&fd: fd_res, opt_level: option<level>,
blk: fn(&&res<fd_t>)) {
blk(res({
val: *fd, opt_level: opt_level,
iface t { fn fsync(l: level) -> int; }
// Call o.fsync after executing blk
- fn obj_sync(&&o: t, opt_level: option::t<level>, blk: fn(&&res<t>)) {
+ fn obj_sync(&&o: t, opt_level: option<level>, blk: fn(&&res<t>)) {
blk(res({
val: o, opt_level: opt_level,
fsync_fn: fn@(&&o: t, l: level) -> int { ret o.fsync(l); }
fn rest(s: str) -> str {
assert(str::char_len(s) >= 1u);
- str::char_slice(s, 1u, str::char_len(s))
+ str::slice(s, 1u, str::char_len(s))
}
-fn from_str_str(s: str) -> (option::t<json>, str) {
+fn from_str_str(s: str) -> (option<json>, str) {
let pos = 0u;
let len = str::byte_len(s);
let escape = false;
cont;
} else if (c == '"') {
ret (some(string(res)),
- str::char_slice(s, pos, str::char_len(s)));
+ str::slice(s, pos, str::char_len(s)));
}
res = res + str::from_char(c);
}
ret (none, s);
}
-fn from_str_list(s: str) -> (option::t<json>, str) {
+fn from_str_list(s: str) -> (option<json>, str) {
if str::char_at(s, 0u) != '[' { ret (none, s); }
let s0 = str::trim_left(rest(s));
let vals = [];
ret (none, s0);
}
-fn from_str_dict(s: str) -> (option::t<json>, str) {
+fn from_str_dict(s: str) -> (option<json>, str) {
if str::char_at(s, 0u) != '{' { ret (none, s); }
let s0 = str::trim_left(rest(s));
let vals = map::new_str_hash::<json>();
(none, s)
}
-fn from_str_float(s: str) -> (option::t<json>, str) {
+fn from_str_float(s: str) -> (option<json>, str) {
let pos = 0u;
let len = str::byte_len(s);
let res = 0f;
}
'.' { break; }
_ { ret (some(num(neg * res)),
- str::char_slice(s, opos, str::char_len(s))); }
+ str::slice(s, opos, str::char_len(s))); }
}
}
if pos == len {
- ret (some(num(neg * res)), str::char_slice(s, pos, str::char_len(s)));
+ ret (some(num(neg * res)), str::slice(s, pos, str::char_len(s)));
}
let dec = 1f;
res += (((c as int) - ('0' as int)) as float) * dec;
}
_ { ret (some(num(neg * res)),
- str::char_slice(s, opos, str::char_len(s))); }
+ str::slice(s, opos, str::char_len(s))); }
}
}
- ret (some(num(neg * res)), str::char_slice(s, pos, str::char_len(s)));
+ ret (some(num(neg * res)), str::slice(s, pos, str::char_len(s)));
}
-fn from_str_bool(s: str) -> (option::t<json>, str) {
+fn from_str_bool(s: str) -> (option<json>, str) {
if (str::starts_with(s, "true")) {
- (some(boolean(true)), str::slice(s, 4u, str::byte_len(s)))
+ (some(boolean(true)), str::slice(s, 4u, str::char_len(s)))
} else if (str::starts_with(s, "false")) {
- (some(boolean(false)), str::slice(s, 5u, str::byte_len(s)))
+ (some(boolean(false)), str::slice(s, 5u, str::char_len(s)))
} else {
(none, s)
}
}
-fn from_str_null(s: str) -> (option::t<json>, str) {
+fn from_str_null(s: str) -> (option<json>, str) {
if (str::starts_with(s, "null")) {
- (some(null), str::slice(s, 4u, str::byte_len(s)))
+ (some(null), str::slice(s, 4u, str::char_len(s)))
} else {
(none, s)
}
}
-fn from_str_helper(s: str) -> (option::t<json>, str) {
+fn from_str_helper(s: str) -> (option<json>, str) {
let s = str::trim_left(s);
if str::is_empty(s) { ret (none, s); }
let start = str::char_at(s, 0u);
Deserializes a json value from a string.
*/
-fn from_str(s: str) -> option::t<json> {
+fn from_str(s: str) -> option<json> {
let (j, _) = from_str_helper(s);
j
}
export libc;
export libc_constants;
export pipe;
-export fd_FILE;
+export FILE, fd_FILE;
export close;
export fclose;
export waitpid;
// FIXME Somehow merge stuff duplicated here and macosx_os.rs. Made difficult
// by https://github.com/graydon/rust/issues#issue/268
+enum FILE_opaque {}
+type FILE = *FILE_opaque;
+enum dir {}
+enum dirent {}
+
#[nolink]
#[abi = "cdecl"]
native mod libc {
fn read(fd: fd_t, buf: *u8, count: size_t) -> ssize_t;
fn write(fd: fd_t, buf: *u8, count: size_t) -> ssize_t;
- fn fread(buf: *u8, size: size_t, n: size_t, f: libc::FILE) -> size_t;
- fn fwrite(buf: *u8, size: size_t, n: size_t, f: libc::FILE) -> size_t;
+ fn fread(buf: *u8, size: size_t, n: size_t, f: FILE) -> size_t;
+ fn fwrite(buf: *u8, size: size_t, n: size_t, f: FILE) -> size_t;
fn open(s: str::sbuf, flags: c_int, mode: unsigned) -> fd_t;
fn close(fd: fd_t) -> c_int;
- type FILE;
fn fopen(path: str::sbuf, mode: str::sbuf) -> FILE;
fn fdopen(fd: fd_t, mode: str::sbuf) -> FILE;
fn fclose(f: FILE);
fn feof(f: FILE) -> c_int;
fn fseek(f: FILE, offset: long, whence: c_int) -> c_int;
fn ftell(f: FILE) -> long;
- type dir;
- fn opendir(d: str::sbuf) -> dir;
- fn closedir(d: dir) -> c_int;
- type dirent;
- fn readdir(d: dir) -> dirent;
+ fn opendir(d: str::sbuf) -> *dir;
+ fn closedir(d: *dir) -> c_int;
+ fn readdir(d: *dir) -> *dirent;
fn getenv(n: str::sbuf) -> str::sbuf;
fn setenv(n: str::sbuf, v: str::sbuf, overwrite: c_int) -> c_int;
fn unsetenv(n: str::sbuf) -> c_int;
ret {in: fds.in, out: fds.out};
}
-fn fd_FILE(fd: fd_t) -> libc::FILE {
+fn fd_FILE(fd: fd_t) -> FILE {
ret str::as_buf("r", {|modebuf| libc::fdopen(fd, modebuf) });
}
libc::close(fd)
}
-fn fclose(file: libc::FILE) {
+fn fclose(file: FILE) {
libc::fclose(file)
}
/// Returns the directory containing the running program
/// followed by a path separator
-fn get_exe_path() -> option::t<fs::path> {
+fn get_exe_path() -> option<fs::path> {
let bufsize = 1023u;
// FIXME: path "strings" will likely need fixing...
let path = str::from_bytes(vec::init_elt(bufsize, 0u8));
When function `f` returns true then an option containing the element
is returned. If `f` matches no elements then none is returned.
*/
-fn find<T: copy, U: copy>(ls: list<T>, f: fn(T) -> option::t<U>)
- -> option::t<U> {
+fn find<T: copy, U: copy>(ls: list<T>, f: fn(T) -> option<U>)
+ -> option<U> {
let ls = ls;
while true {
alt ls {
#[test]
fn test_find_success() {
- fn match(&&i: int) -> option::t<int> {
+ fn match(&&i: int) -> option<int> {
ret if i == 2 { option::some(i) } else { option::none::<int> };
}
let l = from_vec([0, 1, 2]);
#[test]
fn test_find_fail() {
- fn match(&&_i: int) -> option::t<int> { ret option::none::<int>; }
+ fn match(&&_i: int) -> option<int> { ret option::none::<int>; }
let l = from_vec([0, 1, 2]);
let empty = list::nil::<int>;
assert (list::find(l, match) == option::none::<int>);
export libc;
export libc_constants;
export pipe;
-export fd_FILE;
+export FILE, fd_FILE;
export close;
export fclose;
export waitpid;
// FIXME Refactor into unix_os module or some such. Doesn't
// seem to work right now.
+enum FILE_opaque {}
+type FILE = *FILE_opaque;
+enum dir {}
+enum dirent {}
+
#[nolink]
#[abi = "cdecl"]
native mod libc {
fn read(fd: fd_t, buf: *u8, count: size_t) -> ssize_t;
fn write(fd: fd_t, buf: *u8, count: size_t) -> ssize_t;
- fn fread(buf: *u8, size: size_t, n: size_t, f: libc::FILE) -> size_t;
- fn fwrite(buf: *u8, size: size_t, n: size_t, f: libc::FILE) -> size_t;
+ fn fread(buf: *u8, size: size_t, n: size_t, f: FILE) -> size_t;
+ fn fwrite(buf: *u8, size: size_t, n: size_t, f: FILE) -> size_t;
fn open(s: str::sbuf, flags: c_int, mode: unsigned) -> fd_t;
fn close(fd: fd_t) -> c_int;
- type FILE;
fn fopen(path: str::sbuf, mode: str::sbuf) -> FILE;
fn fdopen(fd: fd_t, mode: str::sbuf) -> FILE;
fn fflush(f: FILE) -> c_int;
fn feof(f: FILE) -> c_int;
fn fseek(f: FILE, offset: long, whence: c_int) -> c_int;
fn ftell(f: FILE) -> long;
- type dir;
- fn opendir(d: str::sbuf) -> dir;
- fn closedir(d: dir) -> c_int;
- type dirent;
- fn readdir(d: dir) -> dirent;
+ fn opendir(d: str::sbuf) -> *dir;
+ fn closedir(d: *dir) -> c_int;
+ fn readdir(d: *dir) -> *dirent;
fn getenv(n: str::sbuf) -> str::sbuf;
fn setenv(n: str::sbuf, v: str::sbuf, overwrite: c_int) -> c_int;
fn unsetenv(n: str::sbuf) -> c_int;
ret {in: fds.in, out: fds.out};
}
-fn fd_FILE(fd: fd_t) -> libc::FILE {
+fn fd_FILE(fd: fd_t) -> FILE {
ret str::as_buf("r", {|modebuf| libc::fdopen(fd, modebuf) });
}
libc::close(fd)
}
-fn fclose(file: libc::FILE) {
+fn fclose(file: FILE) {
libc::fclose(file)
}
fn dylib_filename(base: str) -> str { ret "lib" + base + ".dylib"; }
-fn get_exe_path() -> option::t<fs::path> {
+fn get_exe_path() -> option<fs::path> {
// FIXME: This doesn't handle the case where the buffer is too small
// FIXME: path "strings" will likely need fixing...
let bufsize = 1023u32;
Get the value for the specified key. If the key does not exist
in the map then returns none.
*/
- fn find(K) -> option::t<V>;
+ fn find(K) -> option<V>;
/*
Method: remove
Remove and return a value from the map. If the key does not exist
in the map then returns none.
*/
- fn remove(K) -> option::t<V>;
+ fn remove(K) -> option<V>;
/*
Method: items
}
}
- fn get<K: copy, V: copy>(tbl: t<K,V>, k: K) -> core::option::t<V> {
+ fn get<K: copy, V: copy>(tbl: t<K,V>, k: K) -> core::option<V> {
alt search_tbl(tbl, k, tbl.hasher(k)) {
not_found {
ret core::option::none;
}
}
- fn remove<K: copy, V: copy>(tbl: t<K,V>, k: K) -> core::option::t<V> {
+ fn remove<K: copy, V: copy>(tbl: t<K,V>, k: K) -> core::option<V> {
alt search_tbl(tbl, k, tbl.hasher(k)) {
not_found {
ret core::option::none;
fn get(k: K) -> V { option::get(get(self, k)) }
- fn find(k: K) -> option::t<V> { get(self, k) }
+ fn find(k: K) -> option<V> { get(self, k) }
- fn remove(k: K) -> option::t<V> { remove(self, k) }
+ fn remove(k: K) -> option<V> { remove(self, k) }
fn items(blk: fn(K, V)) { items(self, blk); }
let j = 0u, q = 0x6ed9eba1u32;
while j < 8u {
- let jj = j > 2u ? j - 3u : j;
+ let jj = if j > 2u { j - 3u } else { j };
a = rot(3, a + (b ^ c ^ d) + x[jj] + q);
d = rot(9, d + (a ^ b ^ c) + x[jj + 8u] + q);
c = rot(11, c + (d ^ a ^ b) + x[jj + 4u] + q);
Random number generation
*/
+
+enum rctx {}
+
#[abi = "cdecl"]
native mod rustrt {
- type rctx;
- fn rand_new() -> rctx;
- fn rand_next(c: rctx) -> u32;
- fn rand_free(c: rctx);
+ fn rand_new() -> *rctx;
+ fn rand_next(c: *rctx) -> u32;
+ fn rand_free(c: *rctx);
}
/* Section: Types */
fn gen_bytes(len: uint) -> [u8];
}
-resource rand_res(c: rustrt::rctx) { rustrt::rand_free(c); }
+resource rand_res(c: *rctx) { rustrt::rand_free(c); }
/* Section: Operations */
node::content(x) { ret node::leaf_iterator::start(x) }
}
}
- fn next(it: node::leaf_iterator::t) -> option::t<node::leaf> {
+ fn next(it: node::leaf_iterator::t) -> option<node::leaf> {
ret node::leaf_iterator::next(it);
}
}
node::content(x) { ret node::char_iterator::start(x) }
}
}
- fn next(it: node::char_iterator::t) -> option::t<char> {
+ fn next(it: node::char_iterator::t) -> option<char> {
ret node::char_iterator::next(it)
}
}
- `option::some(x)` otherwise, in which case `x` has the same contents
as `node` bot lower height and/or fragmentation.
*/
- fn bal(node: @node) -> option::t<@node> {
+ fn bal(node: @node) -> option<@node> {
if height(node) < hint_max_node_height { ret option::none; }
//1. Gather all leaves as a forest
let forest = [mutable];
fn loop_chars(node: @node, it: fn(char) -> bool) -> bool {
ret loop_leaves(node, {|leaf|
- ret str::loop_chars_sub(*leaf.content,
+ ret str::substr_all(*leaf.content,
leaf.byte_offset,
leaf.byte_len, it)
})
}
}
- fn next(it: t) -> option::t<leaf> {
+ fn next(it: t) -> option<leaf> {
if it.stackpos < 0 { ret option::none; }
while true {
let current = it.stack[it.stackpos];
mod char_iterator {
type t = {
leaf_iterator: leaf_iterator::t,
- mutable leaf: option::t<leaf>,
+ mutable leaf: option<leaf>,
mutable leaf_byte_pos: uint
};
}
}
- fn next(it: t) -> option::t<char> {
+ fn next(it: t) -> option<char> {
while true {
alt(get_current_or_next_leaf(it)) {
option::none { ret option::none; }
fail;//unreachable
}
- fn get_current_or_next_leaf(it: t) -> option::t<leaf> {
+ fn get_current_or_next_leaf(it: t) -> option<leaf> {
alt(it.leaf) {
option::some(_) { ret it.leaf }
option::none {
}
}
- fn get_next_char_in_leaf(it: t) -> option::t<char> {
+ fn get_next_char_in_leaf(it: t) -> option<char> {
alt(it.leaf) {
option::none { ret option::none }
option::some(aleaf) {
assert eq(r, r2);
}
-}
\ No newline at end of file
+}
type prog_repr = {pid: pid_t,
mutable in_fd: fd_t,
- out_file: os::libc::FILE,
- err_file: os::libc::FILE,
+ out_file: os::FILE,
+ err_file: os::FILE,
mutable finished: bool};
fn close_repr_input(r: prog_repr) {
/*
Type: smallintmap
*/
-type smallintmap<T> = @{mutable v: [mutable option::t<T>]};
+type smallintmap<T> = @{mutable v: [mutable option<T>]};
/*
Function: mk
Create a smallintmap
*/
fn mk<T>() -> smallintmap<T> {
- let v: [mutable option::t<T>] = [mutable];
+ let v: [mutable option<T>] = [mutable];
ret @{mutable v: v};
}
the specified key then the original value is replaced.
*/
fn insert<T: copy>(m: smallintmap<T>, key: uint, val: T) {
- vec::grow_set::<option::t<T>>(m.v, key, none::<T>, some::<T>(val));
+ vec::grow_set::<option<T>>(m.v, key, none::<T>, some::<T>(val));
}
/*
Get the value for the specified key. If the key does not exist
in the map then returns none
*/
-fn find<T: copy>(m: smallintmap<T>, key: uint) -> option::t<T> {
- if key < vec::len::<option::t<T>>(m.v) { ret m.v[key]; }
+fn find<T: copy>(m: smallintmap<T>, key: uint) -> option<T> {
+ if key < vec::len::<option<T>>(m.v) { ret m.v[key]; }
ret none::<T>;
}
// FIXME: Are these really useful?
fn truncate<T: copy>(m: smallintmap<T>, len: uint) {
- m.v = vec::slice_mut::<option::t<T>>(m.v, 0u, len);
+ m.v = vec::slice_mut::<option<T>>(m.v, 0u, len);
}
fn max_key<T>(m: smallintmap<T>) -> uint {
- ret vec::len::<option::t<T>>(m.v);
+ ret vec::len::<option<T>>(m.v);
}
/*
insert(self, key, value);
ret !exists;
}
- fn remove(&&key: uint) -> option::t<V> {
+ fn remove(&&key: uint) -> option<V> {
if key >= vec::len(self.v) { ret none; }
let old = self.v[key];
self.v[key] = none;
contains_key(self, key)
}
fn get(&&key: uint) -> V { get(self, key) }
- fn find(&&key: uint) -> option::t<V> { find(self, key) }
+ fn find(&&key: uint) -> option<V> { find(self, key) }
fn rehash() { fail }
fn items(it: fn(&&uint, V)) {
let idx = 0u;
export quick_sort;
export quick_sort3;
-/* Type: lteq */
-type lteq<T> = fn(T, T) -> bool;
+/* Type: le */
+type le<T> = fn(T, T) -> bool;
/*
Function: merge_sort
Has worst case O(n log n) performance, best case O(n), but
is not space efficient. This is a stable sort.
*/
-fn merge_sort<T: copy>(le: lteq<T>, v: [const T]) -> [T] {
- fn merge<T: copy>(le: lteq<T>, a: [T], b: [T]) -> [T] {
+fn merge_sort<T: copy>(le: le<T>, v: [const T]) -> [T] {
+ fn merge<T: copy>(le: le<T>, a: [T], b: [T]) -> [T] {
let rs: [T] = [];
let a_len: uint = len::<T>(a);
let a_ix: uint = 0u;
ret merge::<T>(le, merge_sort::<T>(le, a), merge_sort::<T>(le, b));
}
-fn part<T: copy>(compare_func: lteq<T>, arr: [mutable T], left: uint,
+fn part<T: copy>(compare_func: le<T>, arr: [mutable T], left: uint,
right: uint, pivot: uint) -> uint {
let pivot_value = arr[pivot];
arr[pivot] <-> arr[right];
ret storage_index;
}
-fn qsort<T: copy>(compare_func: lteq<T>, arr: [mutable T], left: uint,
+fn qsort<T: copy>(compare_func: le<T>, arr: [mutable T], left: uint,
right: uint) {
if right > left {
let pivot = (left + right) / 2u;
Has worst case O(n^2) performance, average case O(n log n).
This is an unstable sort.
*/
-fn quick_sort<T: copy>(compare_func: lteq<T>, arr: [mutable T]) {
+fn quick_sort<T: copy>(compare_func: le<T>, arr: [mutable T]) {
if len::<T>(arr) == 0u { ret; }
qsort::<T>(compare_func, arr, 0u, len::<T>(arr) - 1u);
}
-fn qsort3<T: copy>(compare_func_lt: lteq<T>, compare_func_eq: lteq<T>,
+fn qsort3<T: copy>(compare_func_lt: le<T>, compare_func_eq: le<T>,
arr: [mutable T], left: int, right: int) {
if right <= left { ret; }
let v: T = arr[right];
This is an unstable sort.
*/
-fn quick_sort3<T: copy>(compare_func_lt: lteq<T>, compare_func_eq: lteq<T>,
+fn quick_sort3<T: copy>(compare_func_lt: le<T>, compare_func_eq: le<T>,
arr: [mutable T]) {
if len::<T>(arr) == 0u { ret; }
qsort3::<T>(compare_func_lt, compare_func_eq, arr, 0,
mod test_qsort {
fn check_sort(v1: [mutable int], v2: [mutable int]) {
let len = vec::len::<int>(v1);
- fn ltequal(&&a: int, &&b: int) -> bool { ret a <= b; }
- let f = ltequal;
+ fn leual(&&a: int, &&b: int) -> bool { ret a <= b; }
+ let f = leual;
quick_sort::<int>(f, v1);
let i = 0u;
while i < len {
let expected = [1, 2, 3];
- fn lteq(&&a: int, &&b: int) -> bool { int::le(a, b) }
- sort::quick_sort(lteq, names);
+ fn le(&&a: int, &&b: int) -> bool { int::le(a, b) }
+ sort::quick_sort(le, names);
let immut_names = vec::from_mut(names);
fn check_sort(v1: [int], v2: [int]) {
let len = vec::len::<int>(v1);
- fn lteq(&&a: int, &&b: int) -> bool { ret a <= b; }
- let f = lteq;
+ fn le(&&a: int, &&b: int) -> bool { ret a <= b; }
+ let f = le;
let v3 = merge_sort::<int>(f, v1);
let i = 0u;
while i < len {
#[test]
fn test_merge_sort_mutable() {
- fn lteq(&&a: int, &&b: int) -> bool { ret a <= b; }
+ fn le(&&a: int, &&b: int) -> bool { ret a <= b; }
let v1 = [mutable 3, 2, 1];
- let v2 = merge_sort(lteq, v1);
+ let v2 = merge_sort(le, v1);
assert v2 == [1, 2, 3];
}
}
/*
Function: mkdtemp
*/
-fn mkdtemp(prefix: str, suffix: str) -> option::t<str> {
+fn mkdtemp(prefix: str, suffix: str) -> option<str> {
let r = rand::mk_rng();
let i = 0u;
while (i < 1000u) {
if !run_tests_console(opts, tests) { fail "Some tests failed"; }
}
-type test_opts = {filter: option::t<str>, run_ignored: bool};
+type test_opts = {filter: option<str>, run_ignored: bool};
type opt_res = either::t<test_opts, str>;
};
fn filter_fn(test: test_desc, filter_str: str) ->
- option::t<test_desc> {
+ option<test_desc> {
if str::find(test.name, filter_str) >= 0 {
ret option::some(test);
} else { ret option::none; }
filtered = if !opts.run_ignored {
filtered
} else {
- fn filter(test: test_desc) -> option::t<test_desc> {
+ fn filter(test: test_desc) -> option<test_desc> {
if test.ignore {
ret option::some({name: test.name,
fn: test.fn,
filtered =
{
fn lteq(t1: test_desc, t2: test_desc) -> bool {
- str::lteq(t1.name, t2.name)
+ str::le(t1.name, t2.name)
}
sort::merge_sort(bind lteq(_, _), filtered)
};
fn first_free_arg_should_be_a_filter() {
let args = ["progname", "filter"];
check (vec::is_not_empty(args));
- let opts = alt parse_opts(args) { either::left(o) { o } };
+ let opts = alt parse_opts(args) { either::left(o) { o }
+ _ { fail "Malformed arg in first_free_arg_should_be_a_filter"; } };
assert (str::eq("filter", option::get(opts.filter)));
}
fn parse_ignored_flag() {
let args = ["progname", "filter", "--ignored"];
check (vec::is_not_empty(args));
- let opts = alt parse_opts(args) { either::left(o) { o } };
+ let opts = alt parse_opts(args) { either::left(o) { o }
+ _ { fail "Malformed arg in parse_ignored_flag"; } };
assert (opts.run_ignored);
}
*/
import core::option::{some, none};
-import option = core::option::t;
+import option = core::option;
export treemap;
export init;
fn find<K: copy, V: copy>(m: treemap<K, V>, k: K) -> option<V> {
alt *m {
empty { none }
- node(@kk, @v, _, _) {
+ // TODO: was that an optimization?
+ node(@kk, @v, left, right) {
if k == kk {
some(v)
} else if k < kk {
-
- // Again, ugliness to unpack left and right individually.
- alt *m { node(_, _, left, _) { find(left, k) } }
- } else { alt *m { node(_, _, _, right) { find(right, k) } } }
+ find(left, k)
+ } else { find(right, k) }
}
}
}
fn traverse<K, V>(m: treemap<K, V>, f: fn(K, V)) {
alt *m {
empty { }
- node(k, v, _, _) {
+ /*
+ Previously, this had what looked like redundant
+ matches to me, so I changed it. but that may be a
+ de-optimization -- tjc
+ */
+ node(k, v, left, right) {
let k1 = k, v1 = v;
- alt *m { node(_, _, left, _) { traverse(left, f); } }
+ traverse(left, f);
f(*k1, *v1);
- alt *m { node(_, _, _, right) { traverse(right, f); } }
+ traverse(right, f);
}
}
}
// A very naive implementation of union-find with unsigned integer nodes.
// Maintains the invariant that the root of a node is always equal to or less
// than the node itself.
-type node = option::t<uint>;
+type node = option<uint>;
type ufind = {mutable nodes: [mutable node]};
the C libuv API. Does very little right now pending scheduler improvements.
*/
-#[cfg(target_os = "linux")];
-#[cfg(target_os = "macos")];
-#[cfg(target_os = "freebsd")];
-
export sanity_check;
export loop_t, idle_t;
export loop_new, loop_delete, default_loop, run, unref;
type close_cb = opaque_cb;
type idle_cb = opaque_cb;
-#[cfg(target_os = "linux")]
-#[cfg(target_os = "macos")]
-#[cfg(target_os = "freebsd")]
type handle_private_fields = {
a00: ctypes::c_int,
a01: ctypes::c_int,
fn sanity_check() {
fn check_size(t: str, uv: ctypes::size_t, rust: ctypes::size_t) {
#debug("size of %s: uv: %u, rust: %u", t, uv, rust);
- assert uv == rust;
+ assert uv <= rust;
}
check_size("idle_t",
helpers::rust_uv_size_of_idle_t(),
sys::size_of::<idle_t>());
}
-#[cfg(target_os = "linux")]
-#[cfg(target_os = "macos")]
-#[cfg(target_os = "freebsd")]
fn handle_fields_new() -> handle_fields {
{
loop: ptr::null(),
}
}
}
-
// Some temporary libuv hacks for servo
-#[cfg(target_os = "linux")];
-#[cfg(target_os = "macos")];
-#[cfg(target_os = "freebsd")];
-
-
#[nolink]
native mod rustrt {
fn rust_uvtmp_create_thread() -> thread;
connected(cd) {
close_connection(thread, 0u32);
}
+ _ { fail "test_connect: port isn't connected"; }
}
join_thread(thread);
delete_thread(thread);
read(_, buf, len) {
unsafe {
log(error, len);
- let buf = vec::unsafe::from_buf(buf, len as uint);
+ let buf = vec::unsafe::from_buf(buf,
+ len as uint);
let str = str::from_bytes(buf);
#error("read something");
io::println(str);
}
delete_buf(buf);
}
+ _ { fail "test_http: protocol error"; }
}
}
close_connection(thread, 0u32);
}
+ _ { fail "test_http: expected `wrote`"; }
}
}
+ _ { fail "test_http: port not connected"; }
}
join_thread(thread);
delete_thread(thread);
import core::option;
import core::ctypes::*;
+enum FILE_opaque {}
+type FILE = *FILE_opaque;
+
#[abi = "cdecl"]
#[nolink]
native mod libc {
fn read(fd: fd_t, buf: *u8, count: size_t) -> ssize_t;
fn write(fd: fd_t, buf: *u8, count: size_t) -> ssize_t;
- fn fread(buf: *u8, size: size_t, n: size_t, f: libc::FILE) -> size_t;
- fn fwrite(buf: *u8, size: size_t, n: size_t, f: libc::FILE) -> size_t;
+ fn fread(buf: *u8, size: size_t, n: size_t, f: FILE) -> size_t;
+ fn fwrite(buf: *u8, size: size_t, n: size_t, f: FILE) -> size_t;
#[link_name = "_open"]
fn open(s: str::sbuf, flags: c_int, mode: unsigned) -> c_int;
#[link_name = "_close"]
fn close(fd: fd_t) -> c_int;
- type FILE;
fn fopen(path: str::sbuf, mode: str::sbuf) -> FILE;
fn _fdopen(fd: fd_t, mode: str::sbuf) -> FILE;
fn fclose(f: FILE);
}
type DWORD = u32;
-type HMODULE = uint;
+type HMODULE = c_uint;
type LPTSTR = str::sbuf;
type LPCTSTR = str::sbuf;
+type LPSECURITY_ATTRIBUTES = *ctypes::void;
+
#[abi = "stdcall"]
native mod kernel32 {
- type LPSECURITY_ATTRIBUTES;
- fn GetEnvironmentVariableA(n: str::sbuf, v: str::sbuf, nsize: uint) ->
- uint;
- fn SetEnvironmentVariableA(n: str::sbuf, v: str::sbuf) -> int;
+ fn GetEnvironmentVariableA(n: str::sbuf, v: str::sbuf, nsize: c_uint) ->
+ c_uint;
+ fn SetEnvironmentVariableA(n: str::sbuf, v: str::sbuf) -> c_int;
fn GetModuleFileNameA(hModule: HMODULE,
lpFilename: LPTSTR,
nSize: DWORD) -> DWORD;
ret {in: fds.in, out: fds.out};
}
-fn fd_FILE(fd: fd_t) -> libc::FILE {
+fn fd_FILE(fd: fd_t) -> FILE {
ret str::as_buf("r", {|modebuf| libc::_fdopen(fd, modebuf) });
}
libc::close(fd)
}
-fn fclose(file: libc::FILE) {
+fn fclose(file: FILE) {
libc::fclose(file)
}
-fn fsync_fd(fd: fd_t, level: io::fsync::level) -> c_int {
+fn fsync_fd(_fd: fd_t, _level: io::fsync::level) -> c_int {
// FIXME (1253)
fail;
}
fn getcwd() -> str { ret rustrt::rust_getcwd(); }
-fn get_exe_path() -> option::t<fs::path> {
+fn get_exe_path() -> option<fs::path> {
// FIXME: This doesn't handle the case where the buffer is too small
// FIXME: path "strings" will likely need fixing...
let bufsize = 1023u;
-Subproject commit f1859eb841be2fe48512bc10e64556383f408b01
+Subproject commit 1170ffba3ac5191930b40c897d4569a9d8a296a3
--- /dev/null
+#include <assert.h>
+#include "boxed_region.h"
+#include "rust_internal.h"
+
+// #define DUMP_BOXED_REGION
+
+rust_opaque_box *boxed_region::malloc(type_desc *td) {
+ size_t header_size = sizeof(rust_opaque_box);
+ size_t body_size = td->size;
+ size_t body_align = td->align;
+ size_t total_size = align_to(header_size, body_align) + body_size;
+ rust_opaque_box *box =
+ (rust_opaque_box*)backing_region->malloc(total_size, "@");
+ box->td = td;
+ box->ref_count = 1;
+ box->prev = NULL;
+ box->next = live_allocs;
+ if (live_allocs) live_allocs->prev = box;
+ live_allocs = box;
+
+# ifdef DUMP_BOXED_REGION
+ fprintf(stderr, "Allocated box %p with td %p,"
+ " size %lu==%lu+%lu, align %lu, prev %p, next %p\n",
+ box, td, total_size, header_size, body_size, body_align,
+ box->prev, box->next);
+# endif
+
+ return box;
+}
+
+rust_opaque_box *boxed_region::calloc(type_desc *td) {
+ rust_opaque_box *box = malloc(td);
+ memset(box_body(box), 0, td->size);
+ return box;
+}
+
+void boxed_region::free(rust_opaque_box *box) {
+ // This turns out to not be true in various situations,
+ // like when we are unwinding after a failure.
+ //
+ // assert(box->ref_count == 0);
+
+ // This however should always be true. Helps to detect
+ // double frees (kind of).
+ assert(box->td != NULL);
+
+# ifdef DUMP_BOXED_REGION
+ fprintf(stderr, "Freed box %p with td %p, prev %p, next %p\n",
+ box, box->td, box->prev, box->next);
+# endif
+
+ if (box->prev) box->prev->next = box->next;
+ if (box->next) box->next->prev = box->prev;
+ if (live_allocs == box) live_allocs = box->next;
+ box->prev = NULL;
+ box->next = NULL;
+ box->td = NULL;
+ backing_region->free(box);
+}
--- /dev/null
+#ifndef BOXED_REGION_H
+#define BOXED_REGION_H
+
+#include <stdlib.h>
+
+struct type_desc;
+class memory_region;
+struct rust_opaque_box;
+
+/* Tracks the data allocated by a particular task in the '@' region.
+ * Currently still relies on the standard malloc as a backing allocator, but
+ * this could be improved someday if necessary. Every allocation must provide
+ * a type descr which describes the payload (what follows the header). */
+class boxed_region {
+private:
+ memory_region *backing_region;
+ rust_opaque_box *live_allocs;
+
+ size_t align_to(size_t v, size_t align) {
+ size_t alignm1 = align - 1;
+ v += alignm1;
+ v &= ~alignm1;
+ return v;
+ }
+
+public:
+ boxed_region(memory_region *br)
+ : backing_region(br)
+ , live_allocs(NULL)
+ {}
+
+ rust_opaque_box *first_live_alloc() { return live_allocs; }
+
+ rust_opaque_box *malloc(type_desc *td);
+ rust_opaque_box *calloc(type_desc *td);
+ void free(rust_opaque_box *box);
+};
+
+#endif /* BOXED_REGION_H */
// Build with the script in src/etc/gen-intrinsics
#include "../rust_internal.h"
-#include "../rust_scheduler.h"
+#include "../rust_util.h"
#include <cstdlib>
#include <cstring>
extern "C" CDECL void
-rust_task_sleep(rust_task *task, size_t time_in_us, bool *killed);
+rust_task_yield(rust_task *task, bool *killed);
extern "C" void
rust_intrinsic_vec_len(size_t *retptr,
}
extern "C" void
-rust_intrinsic_task_sleep(void **retptr,
+rust_intrinsic_task_yield(void **retptr,
void *env,
rust_task *task,
- size_t time_in_us,
bool *killed) {
- rust_task_sleep(task, time_in_us, killed);
+ rust_task_yield(task, killed);
}
%struct.rust_vec = type { i32, i32, [0 x i8] }
%struct.rust_fn = type { i32*, %struct.rust_box* }
%struct.rust_box = type opaque
-%struct.rust_task = type { %struct.rust_task_user, i32, %class.context, %struct.stk_seg*, i32, %struct.rust_scheduler*, %class.rust_crate_cache*, %class.rust_kernel*, i8*, %class.rust_task_list*, %struct.rust_cond*, i8*, %struct.rust_task*, i32, i32, %class.timer, i32*, i32, i32, %class.memory_region, i8, i8, i8, %class.lock_and_signal, %class.hash_map.4, %class.rust_obstack, %"class.std::map", i32, %"class.debug::task_debug_info" }
+%struct.rust_task = type { %struct.rust_task_user, i32, [8 x i8], %class.context, %struct.stk_seg*, i32, %struct.rust_task_thread*, %class.rust_crate_cache*, %class.rust_kernel*, i8*, %class.rust_task_list*, %struct.rust_cond*, i8*, %struct.rust_task*, i32, i32, i32*, %class.memory_region, %class.boxed_region, i8, i8, i8, %class.lock_and_signal, %class.hash_map.4, %class.rust_obstack, i32, %"class.debug::task_debug_info", i32, [4 x i8] }
%struct.rust_task_user = type { i32, i32, %struct.chan_handle, i32 }
%struct.chan_handle = type { i32, i32 }
-%class.context = type { %struct.registers_t, %class.context* }
-%struct.registers_t = type { i32, i32, i32, i32, i32, i32, i32, i32, i16, i16, i16, i16, i16, i16, i32, i32 }
-%struct.stk_seg = type { %struct.stk_seg*, i32, i32, i32, [0 x i8] }
-%struct.rust_scheduler = type { %class.rust_thread, i32, i32, %class.rust_log, i32, %class.rust_srv*, i8*, %class.rust_task_list, %class.rust_task_list, %class.rust_task_list, %class.rust_task_list, %class.rust_crate_cache, %struct.randctx, %class.rust_kernel*, i32, i32, %class.lock_and_signal, i32, %union.pthread_attr_t, %struct.rust_env*, %class.context }
+%class.context = type { %struct.registers_t, %class.context*, [12 x i8] }
+%struct.registers_t = type { i32, i32, i32, i32, i32, i32, i32, i32, i16, i16, i16, i16, i16, i16, i32, i32, [12 x i8] }
+%struct.stk_seg = type { %struct.stk_seg*, %struct.stk_seg*, i32, i32, i32, [0 x i8] }
+%struct.rust_task_thread = type { %class.rust_thread, i32, %class.rust_log, i32, %class.rust_srv*, i8*, %class.rust_task_list, %class.rust_task_list, %class.rust_task_list, %class.rust_task_list, %class.rust_crate_cache, %struct.randctx, %class.rust_kernel*, i32, i32, %class.lock_and_signal, i32, %union.pthread_attr_t, %struct.rust_env*, [12 x i8], %class.context, i8, [15 x i8] }
%class.rust_thread = type { i32 (...)**, i8, i32 }
-%class.rust_log = type { i32 (...)**, %class.rust_srv*, %struct.rust_scheduler*, i8 }
+%class.rust_log = type { i32 (...)**, %class.rust_srv*, %struct.rust_task_thread*, i8 }
%class.rust_srv = type { i32 (...)**, %struct.rust_env*, %class.memory_region }
-%struct.rust_env = type { i32, i32, i8*, i8, i8, i8* }
+%struct.rust_env = type { i32, i32, i32, i8*, i8, i8, i8* }
%class.memory_region = type { i32 (...)**, %class.rust_srv*, %class.memory_region*, i32, %class.array_list, i8, i8, %class.lock_and_signal }
%class.array_list = type { i32, %"struct.memory_region::alloc_header"**, i32 }
%"struct.memory_region::alloc_header" = type { i8 }
-%class.lock_and_signal = type { i32 (...)**, %union.pthread_cond_t, %union.pthread_mutex_t, i32, i8, i8 }
+%class.lock_and_signal = type { i32 (...)**, %union.pthread_cond_t, %union.pthread_mutex_t, i32 }
%union.pthread_cond_t = type { %struct.anon, [4 x i8] }
%struct.anon = type { i32, i32, i64, i64, i64, i8*, i32, i32 }
%union.pthread_mutex_t = type { %"struct.<anonymous union>::__pthread_mutex_s" }
%"struct.<anonymous union>::__pthread_mutex_s" = type { i32, i32, i32, i32, i32, %union.anon }
%union.anon = type { i32 }
-%class.rust_task_list = type { %class.indexed_list, %struct.rust_scheduler*, i8* }
+%class.rust_task_list = type { %class.indexed_list, %struct.rust_task_thread*, i8* }
%class.indexed_list = type { i32 (...)**, %class.array_list.1 }
%class.array_list.1 = type { i32, %struct.rust_task**, i32 }
-%class.rust_crate_cache = type { %struct.type_desc*, %struct.rust_scheduler*, i32 }
+%class.rust_crate_cache = type { %struct.type_desc*, %struct.rust_hashable_dict*, %struct.rust_task_thread*, i32 }
+%struct.rust_hashable_dict = type { %struct.UT_hash_handle, [0 x i8*] }
%struct.randctx = type { i32, [256 x i32], [256 x i32], i32, i32, i32 }
%class.rust_kernel = type { i32 (...)**, %class.memory_region, %class.rust_log, %class.rust_srv*, %class.lock_and_signal, %class.array_list.3, %struct.randctx, i32, %class.hash_map, i32, i32, i32, %struct.rust_env* }
-%class.array_list.3 = type { i32, %struct.rust_scheduler**, i32 }
+%class.array_list.3 = type { i32, %struct.rust_task_thread**, i32 }
%class.hash_map = type { %"struct.hash_map<int, rust_task *>::map_entry"* }
%"struct.hash_map<int, rust_task *>::map_entry" = type opaque
%union.pthread_attr_t = type { i32, [32 x i8] }
%struct.rust_cond = type { i8 }
-%class.timer = type { i32 (...)**, i64, i64 }
+%class.boxed_region = type { %class.memory_region*, %struct.rust_opaque_box* }
+%struct.rust_opaque_box = type { i32, %struct.type_desc*, %struct.rust_opaque_box*, %struct.rust_opaque_box* }
%class.hash_map.4 = type { %"struct.hash_map<int, rust_port *>::map_entry"* }
%"struct.hash_map<int, rust_port *>::map_entry" = type opaque
%class.rust_obstack = type { %struct.rust_obstack_chunk*, %struct.rust_task* }
%struct.rust_obstack_chunk = type { %struct.rust_obstack_chunk*, i32, i32, i32, [0 x i8] }
+%"class.debug::task_debug_info" = type { %"class.std::map" }
%"class.std::map" = type { %"class.std::_Rb_tree" }
-%"class.std::_Rb_tree" = type { %"struct.std::_Rb_tree<void *, std::pair<void *const, const type_desc *>, std::_Select1st<std::pair<void *const, const type_desc *> >, std::less<void *>, std::allocator<std::pair<void *const, const type_desc *> > >::_Rb_tree_impl" }
-%"struct.std::_Rb_tree<void *, std::pair<void *const, const type_desc *>, std::_Select1st<std::pair<void *const, const type_desc *> >, std::less<void *>, std::allocator<std::pair<void *const, const type_desc *> > >::_Rb_tree_impl" = type { %"struct.std::less", %"struct.std::_Rb_tree_node_base", i32 }
+%"class.std::_Rb_tree" = type { %"struct.std::_Rb_tree<void *, std::pair<void *const, std::basic_string<char> >, std::_Select1st<std::pair<void *const, std::basic_string<char> > >, std::less<void *>, std::allocator<std::pair<void *const, std::basic_string<char> > > >::_Rb_tree_impl" }
+%"struct.std::_Rb_tree<void *, std::pair<void *const, std::basic_string<char> >, std::_Select1st<std::pair<void *const, std::basic_string<char> > >, std::less<void *>, std::allocator<std::pair<void *const, std::basic_string<char> > > >::_Rb_tree_impl" = type { %"struct.std::less", %"struct.std::_Rb_tree_node_base", i32 }
%"struct.std::less" = type { i8 }
%"struct.std::_Rb_tree_node_base" = type { i32, %"struct.std::_Rb_tree_node_base"*, %"struct.std::_Rb_tree_node_base"*, %"struct.std::_Rb_tree_node_base"* }
-%"class.debug::task_debug_info" = type { %"class.std::map.5" }
-%"class.std::map.5" = type { %"class.std::_Rb_tree.6" }
-%"class.std::_Rb_tree.6" = type { %"struct.std::_Rb_tree<void *, std::pair<void *const, std::basic_string<char> >, std::_Select1st<std::pair<void *const, std::basic_string<char> > >, std::less<void *>, std::allocator<std::pair<void *const, std::basic_string<char> > > >::_Rb_tree_impl" }
-%"struct.std::_Rb_tree<void *, std::pair<void *const, std::basic_string<char> >, std::_Select1st<std::pair<void *const, std::basic_string<char> > >, std::less<void *>, std::allocator<std::pair<void *const, std::basic_string<char> > > >::_Rb_tree_impl" = type { %"struct.std::less", %"struct.std::_Rb_tree_node_base", i32 }
define void @rust_intrinsic_vec_len(i32* nocapture %retptr, i8* nocapture %env, %struct.type_desc* nocapture %ty, %struct.rust_vec** nocapture %vp) nounwind {
- %1 = load %struct.rust_vec** %vp, align 4, !tbaa !0
- %2 = getelementptr inbounds %struct.rust_vec* %1, i32 0, i32 0
- %3 = load i32* %2, align 4, !tbaa !3
- %4 = getelementptr inbounds %struct.type_desc* %ty, i32 0, i32 1
- %5 = load i32* %4, align 4, !tbaa !3
- %6 = udiv i32 %3, %5
- store i32 %6, i32* %retptr, align 4, !tbaa !3
+entry:
+ %0 = load %struct.rust_vec** %vp, align 4, !tbaa !0
+ %fill = getelementptr inbounds %struct.rust_vec* %0, i32 0, i32 0
+ %1 = load i32* %fill, align 4, !tbaa !3
+ %size = getelementptr inbounds %struct.type_desc* %ty, i32 0, i32 1
+ %2 = load i32* %size, align 4, !tbaa !3
+ %div = udiv i32 %1, %2
+ store i32 %div, i32* %retptr, align 4, !tbaa !3
ret void
}
define void @rust_intrinsic_ptr_offset(i8** nocapture %retptr, i8* nocapture %env, %struct.type_desc* nocapture %ty, i8* %ptr, i32 %count) nounwind {
- %1 = getelementptr inbounds %struct.type_desc* %ty, i32 0, i32 1
- %2 = load i32* %1, align 4, !tbaa !3
- %3 = mul i32 %2, %count
- %4 = getelementptr inbounds i8* %ptr, i32 %3
- store i8* %4, i8** %retptr, align 4, !tbaa !0
+entry:
+ %size = getelementptr inbounds %struct.type_desc* %ty, i32 0, i32 1
+ %0 = load i32* %size, align 4, !tbaa !3
+ %mul = mul i32 %0, %count
+ %arrayidx = getelementptr inbounds i8* %ptr, i32 %mul
+ store i8* %arrayidx, i8** %retptr, align 4, !tbaa !0
ret void
}
define void @rust_intrinsic_cast(i8* nocapture %retptr, i8* nocapture %env, %struct.type_desc* nocapture %t1, %struct.type_desc* nocapture %t2, i8* nocapture %src) nounwind {
- %1 = getelementptr inbounds %struct.type_desc* %t1, i32 0, i32 1
- %2 = load i32* %1, align 4, !tbaa !3
- tail call void @llvm.memmove.p0i8.p0i8.i32(i8* %retptr, i8* %src, i32 %2, i32 1, i1 false)
+entry:
+ %size = getelementptr inbounds %struct.type_desc* %t1, i32 0, i32 1
+ %0 = load i32* %size, align 4, !tbaa !3
+ tail call void @llvm.memmove.p0i8.p0i8.i32(i8* %retptr, i8* %src, i32 %0, i32 1, i1 false)
ret void
}
declare void @llvm.memmove.p0i8.p0i8.i32(i8* nocapture, i8* nocapture, i32, i32, i1) nounwind
define void @rust_intrinsic_addr_of(i8** nocapture %retptr, i8* nocapture %env, %struct.type_desc* nocapture %ty, i8* %valptr) nounwind {
+entry:
store i8* %valptr, i8** %retptr, align 4, !tbaa !0
ret void
}
define void @rust_intrinsic_call_with_retptr(i8** %retptr, i8* nocapture %env, %struct.type_desc* nocapture %ty, %struct.rust_fn* nocapture %recvfn) {
- %1 = getelementptr inbounds %struct.rust_fn* %recvfn, i32 0, i32 0
- %2 = load i32** %1, align 4, !tbaa !0
- %3 = bitcast i32* %2 to void (i8**, i8*, i8**)*
- %4 = getelementptr inbounds %struct.rust_fn* %recvfn, i32 0, i32 1
- %5 = load %struct.rust_box** %4, align 4, !tbaa !0
- %6 = bitcast %struct.rust_box* %5 to i8*
- tail call void %3(i8** null, i8* %6, i8** %retptr)
+entry:
+ %fn1 = getelementptr inbounds %struct.rust_fn* %recvfn, i32 0, i32 0
+ %0 = load i32** %fn1, align 4, !tbaa !0
+ %1 = bitcast i32* %0 to void (i8**, i8*, i8**)*
+ %env2 = getelementptr inbounds %struct.rust_fn* %recvfn, i32 0, i32 1
+ %2 = load %struct.rust_box** %env2, align 4, !tbaa !0
+ %3 = bitcast %struct.rust_box* %2 to i8*
+ tail call void %1(i8** null, i8* %3, i8** %retptr)
ret void
}
define void @rust_intrinsic_get_type_desc(i8** nocapture %retptr, i8* nocapture %env, %struct.type_desc* %ty) nounwind {
+entry:
%ty.c = bitcast %struct.type_desc* %ty to i8*
store i8* %ty.c, i8** %retptr, align 4, !tbaa !0
ret void
}
-define void @rust_intrinsic_task_sleep(i8** nocapture %retptr, i8* nocapture %env, %struct.rust_task* %task, i32 %time_in_us, i8* %killed) {
- tail call void @rust_task_sleep(%struct.rust_task* %task, i32 %time_in_us, i8* %killed)
+define void @rust_intrinsic_task_yield(i8** nocapture %retptr, i8* nocapture %env, %struct.rust_task* %task, i8* %killed) {
+entry:
+ tail call void @rust_task_yield(%struct.rust_task* %task, i8* %killed)
ret void
}
-declare void @rust_task_sleep(%struct.rust_task*, i32, i8*)
+declare void @rust_task_yield(%struct.rust_task*, i8*)
!0 = metadata !{metadata !"any pointer", metadata !1}
!1 = metadata !{metadata !"omnipotent char", metadata !2}
%struct.rust_vec = type { i64, i64, [0 x i8] }
%struct.rust_fn = type { i64*, %struct.rust_box* }
%struct.rust_box = type opaque
-%struct.rust_task = type { %struct.rust_task_user, i64, %class.context, %struct.stk_seg*, i64, %struct.rust_scheduler*, %class.rust_crate_cache*, %class.rust_kernel*, i8*, %class.rust_task_list*, %struct.rust_cond*, i8*, %struct.rust_task*, i32, i64, %class.timer, i64*, i32, i32, %class.memory_region, i8, i8, i8, %class.lock_and_signal, %class.hash_map.4, %class.rust_obstack, %"class.std::map", i32, %"class.debug::task_debug_info" }
+%struct.rust_task = type { %struct.rust_task_user, i64, %class.context, %struct.stk_seg*, i64, %struct.rust_task_thread*, %class.rust_crate_cache*, %class.rust_kernel*, i8*, %class.rust_task_list*, %struct.rust_cond*, i8*, %struct.rust_task*, i32, i64, i64*, %class.memory_region, %class.boxed_region, i8, i8, i8, %class.lock_and_signal, %class.hash_map.4, %class.rust_obstack, i32, %"class.debug::task_debug_info", i64, [8 x i8] }
%struct.rust_task_user = type { i64, i64, %struct.chan_handle, i64 }
%struct.chan_handle = type { i64, i64 }
-%class.context = type { %struct.registers_t, %class.context* }
+%class.context = type { %struct.registers_t, %class.context*, [8 x i8] }
%struct.registers_t = type { [22 x i64] }
-%struct.stk_seg = type { %struct.stk_seg*, i64, i32, [0 x i8] }
-%struct.rust_scheduler = type { %class.rust_thread, i64, i64, %class.rust_log, i32, %class.rust_srv*, i8*, %class.rust_task_list, %class.rust_task_list, %class.rust_task_list, %class.rust_task_list, %class.rust_crate_cache, %struct.randctx, %class.rust_kernel*, i32, i32, %class.lock_and_signal, i64, %union.pthread_attr_t, %struct.rust_env*, %class.context }
+%struct.stk_seg = type { %struct.stk_seg*, %struct.stk_seg*, i64, i32, [0 x i8] }
+%struct.rust_task_thread = type { %class.rust_thread, i64, %class.rust_log, i32, %class.rust_srv*, i8*, %class.rust_task_list, %class.rust_task_list, %class.rust_task_list, %class.rust_task_list, %class.rust_crate_cache, %struct.randctx, %class.rust_kernel*, i32, i32, %class.lock_and_signal, i64, %union.pthread_attr_t, %struct.rust_env*, [8 x i8], %class.context, i8, [15 x i8] }
%class.rust_thread = type { i32 (...)**, i8, i64 }
-%class.rust_log = type { i32 (...)**, %class.rust_srv*, %struct.rust_scheduler*, i8 }
+%class.rust_log = type { i32 (...)**, %class.rust_srv*, %struct.rust_task_thread*, i8 }
%class.rust_srv = type { i32 (...)**, %struct.rust_env*, %class.memory_region }
-%struct.rust_env = type { i64, i64, i8*, i8, i8, i8* }
+%struct.rust_env = type { i64, i64, i64, i8*, i8, i8, i8* }
%class.memory_region = type { i32 (...)**, %class.rust_srv*, %class.memory_region*, i32, %class.array_list, i8, i8, %class.lock_and_signal }
%class.array_list = type { i64, %"struct.memory_region::alloc_header"**, i64 }
%"struct.memory_region::alloc_header" = type { i8 }
-%class.lock_and_signal = type { i32 (...)**, %union.pthread_cond_t, %union.pthread_mutex_t, i64, i8, i8 }
+%class.lock_and_signal = type { i32 (...)**, %union.pthread_cond_t, %union.pthread_mutex_t, i64 }
%union.pthread_cond_t = type { %struct.anon }
%struct.anon = type { i32, i32, i64, i64, i64, i8*, i32, i32 }
%union.pthread_mutex_t = type { %"struct.<anonymous union>::__pthread_mutex_s" }
%"struct.<anonymous union>::__pthread_mutex_s" = type { i32, i32, i32, i32, i32, i32, %struct.__pthread_internal_list }
%struct.__pthread_internal_list = type { %struct.__pthread_internal_list*, %struct.__pthread_internal_list* }
-%class.rust_task_list = type { %class.indexed_list, %struct.rust_scheduler*, i8* }
+%class.rust_task_list = type { %class.indexed_list, %struct.rust_task_thread*, i8* }
%class.indexed_list = type { i32 (...)**, %class.array_list.1 }
%class.array_list.1 = type { i64, %struct.rust_task**, i64 }
-%class.rust_crate_cache = type { %struct.type_desc*, %struct.rust_scheduler*, i64 }
+%class.rust_crate_cache = type { %struct.type_desc*, %struct.rust_hashable_dict*, %struct.rust_task_thread*, i64 }
+%struct.rust_hashable_dict = type { %struct.UT_hash_handle, [0 x i8*] }
%struct.randctx = type { i64, [256 x i64], [256 x i64], i64, i64, i64 }
-%class.rust_kernel = type { i32 (...)**, %class.memory_region, %class.rust_log, %class.rust_srv*, %class.lock_and_signal, %class.array_list.3, %struct.randctx, i64, %class.hash_map, i64, i32, i32, %struct.rust_env* }
-%class.array_list.3 = type { i64, %struct.rust_scheduler**, i64 }
+%class.rust_kernel = type { i32 (...)**, %class.memory_region, %class.rust_log, %class.rust_srv*, %class.lock_and_signal, %class.array_list.3, %struct.randctx, i64, %class.hash_map, i32, i64, i32, %struct.rust_env* }
+%class.array_list.3 = type { i64, %struct.rust_task_thread**, i64 }
%class.hash_map = type { %"struct.hash_map<long, rust_task *>::map_entry"* }
%"struct.hash_map<long, rust_task *>::map_entry" = type opaque
%union.pthread_attr_t = type { i64, [48 x i8] }
%struct.rust_cond = type { i8 }
-%class.timer = type { i32 (...)**, i64, i64 }
+%class.boxed_region = type { %class.memory_region*, %struct.rust_opaque_box* }
+%struct.rust_opaque_box = type { i64, %struct.type_desc*, %struct.rust_opaque_box*, %struct.rust_opaque_box* }
%class.hash_map.4 = type { %"struct.hash_map<long, rust_port *>::map_entry"* }
%"struct.hash_map<long, rust_port *>::map_entry" = type opaque
%class.rust_obstack = type { %struct.rust_obstack_chunk*, %struct.rust_task* }
%struct.rust_obstack_chunk = type { %struct.rust_obstack_chunk*, i64, i64, i64, [0 x i8] }
+%"class.debug::task_debug_info" = type { %"class.std::map" }
%"class.std::map" = type { %"class.std::_Rb_tree" }
-%"class.std::_Rb_tree" = type { %"struct.std::_Rb_tree<void *, std::pair<void *const, const type_desc *>, std::_Select1st<std::pair<void *const, const type_desc *> >, std::less<void *>, std::allocator<std::pair<void *const, const type_desc *> > >::_Rb_tree_impl" }
-%"struct.std::_Rb_tree<void *, std::pair<void *const, const type_desc *>, std::_Select1st<std::pair<void *const, const type_desc *> >, std::less<void *>, std::allocator<std::pair<void *const, const type_desc *> > >::_Rb_tree_impl" = type { %"struct.std::less", %"struct.std::_Rb_tree_node_base", i64 }
+%"class.std::_Rb_tree" = type { %"struct.std::_Rb_tree<void *, std::pair<void *const, std::basic_string<char> >, std::_Select1st<std::pair<void *const, std::basic_string<char> > >, std::less<void *>, std::allocator<std::pair<void *const, std::basic_string<char> > > >::_Rb_tree_impl" }
+%"struct.std::_Rb_tree<void *, std::pair<void *const, std::basic_string<char> >, std::_Select1st<std::pair<void *const, std::basic_string<char> > >, std::less<void *>, std::allocator<std::pair<void *const, std::basic_string<char> > > >::_Rb_tree_impl" = type { %"struct.std::less", %"struct.std::_Rb_tree_node_base", i64 }
%"struct.std::less" = type { i8 }
%"struct.std::_Rb_tree_node_base" = type { i32, %"struct.std::_Rb_tree_node_base"*, %"struct.std::_Rb_tree_node_base"*, %"struct.std::_Rb_tree_node_base"* }
-%"class.debug::task_debug_info" = type { %"class.std::map.5" }
-%"class.std::map.5" = type { %"class.std::_Rb_tree.6" }
-%"class.std::_Rb_tree.6" = type { %"struct.std::_Rb_tree<void *, std::pair<void *const, std::basic_string<char> >, std::_Select1st<std::pair<void *const, std::basic_string<char> > >, std::less<void *>, std::allocator<std::pair<void *const, std::basic_string<char> > > >::_Rb_tree_impl" }
-%"struct.std::_Rb_tree<void *, std::pair<void *const, std::basic_string<char> >, std::_Select1st<std::pair<void *const, std::basic_string<char> > >, std::less<void *>, std::allocator<std::pair<void *const, std::basic_string<char> > > >::_Rb_tree_impl" = type { %"struct.std::less", %"struct.std::_Rb_tree_node_base", i64 }
define void @rust_intrinsic_vec_len(i64* nocapture %retptr, i8* nocapture %env, %struct.type_desc* nocapture %ty, %struct.rust_vec** nocapture %vp) nounwind uwtable {
- %1 = load %struct.rust_vec** %vp, align 8, !tbaa !0
- %2 = getelementptr inbounds %struct.rust_vec* %1, i64 0, i32 0
- %3 = load i64* %2, align 8, !tbaa !3
- %4 = getelementptr inbounds %struct.type_desc* %ty, i64 0, i32 1
- %5 = load i64* %4, align 8, !tbaa !3
- %6 = udiv i64 %3, %5
- store i64 %6, i64* %retptr, align 8, !tbaa !3
+entry:
+ %0 = load %struct.rust_vec** %vp, align 8, !tbaa !0
+ %fill = getelementptr inbounds %struct.rust_vec* %0, i64 0, i32 0
+ %1 = load i64* %fill, align 8, !tbaa !3
+ %size = getelementptr inbounds %struct.type_desc* %ty, i64 0, i32 1
+ %2 = load i64* %size, align 8, !tbaa !3
+ %div = udiv i64 %1, %2
+ store i64 %div, i64* %retptr, align 8, !tbaa !3
ret void
}
define void @rust_intrinsic_ptr_offset(i8** nocapture %retptr, i8* nocapture %env, %struct.type_desc* nocapture %ty, i8* %ptr, i64 %count) nounwind uwtable {
- %1 = getelementptr inbounds %struct.type_desc* %ty, i64 0, i32 1
- %2 = load i64* %1, align 8, !tbaa !3
- %3 = mul i64 %2, %count
- %4 = getelementptr inbounds i8* %ptr, i64 %3
- store i8* %4, i8** %retptr, align 8, !tbaa !0
+entry:
+ %size = getelementptr inbounds %struct.type_desc* %ty, i64 0, i32 1
+ %0 = load i64* %size, align 8, !tbaa !3
+ %mul = mul i64 %0, %count
+ %arrayidx = getelementptr inbounds i8* %ptr, i64 %mul
+ store i8* %arrayidx, i8** %retptr, align 8, !tbaa !0
ret void
}
define void @rust_intrinsic_cast(i8* nocapture %retptr, i8* nocapture %env, %struct.type_desc* nocapture %t1, %struct.type_desc* nocapture %t2, i8* nocapture %src) nounwind uwtable {
- %1 = getelementptr inbounds %struct.type_desc* %t1, i64 0, i32 1
- %2 = load i64* %1, align 8, !tbaa !3
- tail call void @llvm.memmove.p0i8.p0i8.i64(i8* %retptr, i8* %src, i64 %2, i32 1, i1 false)
+entry:
+ %size = getelementptr inbounds %struct.type_desc* %t1, i64 0, i32 1
+ %0 = load i64* %size, align 8, !tbaa !3
+ tail call void @llvm.memmove.p0i8.p0i8.i64(i8* %retptr, i8* %src, i64 %0, i32 1, i1 false)
ret void
}
declare void @llvm.memmove.p0i8.p0i8.i64(i8* nocapture, i8* nocapture, i64, i32, i1) nounwind
define void @rust_intrinsic_addr_of(i8** nocapture %retptr, i8* nocapture %env, %struct.type_desc* nocapture %ty, i8* %valptr) nounwind uwtable {
+entry:
store i8* %valptr, i8** %retptr, align 8, !tbaa !0
ret void
}
define void @rust_intrinsic_call_with_retptr(i8** %retptr, i8* nocapture %env, %struct.type_desc* nocapture %ty, %struct.rust_fn* nocapture %recvfn) uwtable {
- %1 = getelementptr inbounds %struct.rust_fn* %recvfn, i64 0, i32 0
- %2 = load i64** %1, align 8, !tbaa !0
- %3 = bitcast i64* %2 to void (i8**, i8*, i8**)*
- %4 = getelementptr inbounds %struct.rust_fn* %recvfn, i64 0, i32 1
- %5 = load %struct.rust_box** %4, align 8, !tbaa !0
- %6 = bitcast %struct.rust_box* %5 to i8*
- tail call void %3(i8** null, i8* %6, i8** %retptr)
+entry:
+ %fn1 = getelementptr inbounds %struct.rust_fn* %recvfn, i64 0, i32 0
+ %0 = load i64** %fn1, align 8, !tbaa !0
+ %1 = bitcast i64* %0 to void (i8**, i8*, i8**)*
+ %env2 = getelementptr inbounds %struct.rust_fn* %recvfn, i64 0, i32 1
+ %2 = load %struct.rust_box** %env2, align 8, !tbaa !0
+ %3 = bitcast %struct.rust_box* %2 to i8*
+ tail call void %1(i8** null, i8* %3, i8** %retptr)
ret void
}
define void @rust_intrinsic_get_type_desc(i8** nocapture %retptr, i8* nocapture %env, %struct.type_desc* %ty) nounwind uwtable {
+entry:
%ty.c = bitcast %struct.type_desc* %ty to i8*
store i8* %ty.c, i8** %retptr, align 8, !tbaa !0
ret void
}
-define void @rust_intrinsic_task_sleep(i8** nocapture %retptr, i8* nocapture %env, %struct.rust_task* %task, i64 %time_in_us, i8* %killed) uwtable {
- tail call void @rust_task_sleep(%struct.rust_task* %task, i64 %time_in_us, i8* %killed)
+define void @rust_intrinsic_task_yield(i8** nocapture %retptr, i8* nocapture %env, %struct.rust_task* %task, i8* %killed) uwtable {
+entry:
+ tail call void @rust_task_yield(%struct.rust_task* %task, i8* %killed)
ret void
}
-declare void @rust_task_sleep(%struct.rust_task*, i64, i8*)
+declare void @rust_task_yield(%struct.rust_task*, i8*)
!0 = metadata !{metadata !"any pointer", metadata !1}
!1 = metadata !{metadata !"omnipotent char", metadata !2}
void dec_alloc();
void maybe_poison(void *mem);
+ void release_alloc(void *mem);
+ void claim_alloc(void *mem);
+
public:
memory_region(rust_srv *srv, bool synchronized);
memory_region(memory_region *parent);
void *realloc(void *mem, size_t size);
void free(void *mem);
virtual ~memory_region();
-
- void release_alloc(void *mem);
- void claim_alloc(void *mem);
-};
+ };
inline void *operator new(size_t size, memory_region ®ion,
const char *tag) {
#include "rust_internal.h"
#include "rust_util.h"
+#include "rust_scheduler.h"
#include <cstdio>
struct
int check_claims = 0;
+const size_t MAIN_STACK_SIZE = 1024*1024;
+
extern "C" CDECL int
rust_start(uintptr_t main_fn, int argc, char **argv, void* crate_map) {
rust_srv *srv = new rust_srv(env);
rust_kernel *kernel = new rust_kernel(srv, env->num_sched_threads);
- rust_task_id root_id = kernel->create_task(NULL, "main");
+ rust_scheduler *sched = kernel->get_default_scheduler();
+ rust_task_id root_id = sched->create_task(NULL, "main", MAIN_STACK_SIZE);
rust_task *root_task = kernel->get_task_by_id(root_id);
I(kernel, root_task != NULL);
- rust_scheduler *sched = root_task->sched;
+ rust_task_thread *thread = root_task->thread;
command_line_args *args
= new (kernel, "main command line args")
command_line_args(root_task, argc, argv);
- DLOG(sched, dom, "startup: %d args in 0x%" PRIxPTR,
+ DLOG(thread, dom, "startup: %d args in 0x%" PRIxPTR,
args->argc, (uintptr_t)args->args);
for (int i = 0; i < args->argc; i++) {
- DLOG(sched, dom, "startup: arg[%d] = '%s'", i, args->argv[i]);
+ DLOG(thread, dom, "startup: arg[%d] = '%s'", i, args->argv[i]);
}
root_task->start((spawn_fn)main_fn, NULL, args->args);
root_task->deref();
root_task = NULL;
- int ret = kernel->start_task_threads();
+ int ret = kernel->start_schedulers();
delete args;
delete kernel;
delete srv;
/* Native builtins. */
#include "rust_internal.h"
-#include "rust_scheduler.h"
+#include "rust_task_thread.h"
#include "rust_task.h"
#include "rust_util.h"
+#include "rust_scheduler.h"
+#include "sync/timer.h"
#if !defined(__WIN32__)
#include <sys/time.h>
extern "C" CDECL rust_str*
last_os_error() {
- rust_task *task = rust_scheduler::get_task();
+ rust_task *task = rust_task_thread::get_task();
LOG(task, task, "last_os_error()");
extern "C" CDECL rust_str *
rust_getcwd() {
- rust_task *task = rust_scheduler::get_task();
+ rust_task *task = rust_task_thread::get_task();
LOG(task, task, "rust_getcwd()");
char cbuf[BUF_BYTES];
return (*v) - 1;
}
-extern "C" CDECL void
-do_gc() {
- // TODO
-}
-
extern "C" CDECL void
unsupervise() {
- rust_task *task = rust_scheduler::get_task();
+ rust_task *task = rust_task_thread::get_task();
task->unsupervise();
}
extern "C" CDECL void
vec_reserve_shared(type_desc* ty, rust_vec** vp,
size_t n_elts) {
- rust_task *task = rust_scheduler::get_task();
- reserve_vec(task, vp, n_elts * ty->size);
+ rust_task *task = rust_task_thread::get_task();
+ reserve_vec_exact(task, vp, n_elts * ty->size);
+}
+
+extern "C" CDECL void
+str_reserve_shared(rust_vec** sp,
+ size_t n_elts) {
+ rust_task *task = rust_task_thread::get_task();
+ reserve_vec_exact(task, sp, n_elts + 1);
}
/**
*/
extern "C" CDECL rust_vec*
vec_from_buf_shared(type_desc *ty, void *ptr, size_t count) {
- rust_task *task = rust_scheduler::get_task();
+ rust_task *task = rust_task_thread::get_task();
size_t fill = ty->size * count;
rust_vec* v = (rust_vec*)task->kernel->malloc(fill + sizeof(rust_vec),
"vec_from_buf");
extern "C" CDECL void
rust_str_push(rust_vec** sp, uint8_t byte) {
- rust_task *task = rust_scheduler::get_task();
+ rust_task *task = rust_task_thread::get_task();
size_t fill = (*sp)->fill;
reserve_vec(task, sp, fill + 1);
(*sp)->data[fill-1] = byte;
extern "C" CDECL void *
rand_new() {
- rust_task *task = rust_scheduler::get_task();
- rust_scheduler *sched = task->sched;
+ rust_task *task = rust_task_thread::get_task();
+ rust_task_thread *thread = task->thread;
randctx *rctx = (randctx *) task->malloc(sizeof(randctx), "randctx");
if (!rctx) {
task->fail();
return NULL;
}
- isaac_init(sched, rctx);
+ isaac_init(thread->kernel, rctx);
return rctx;
}
extern "C" CDECL void
rand_free(randctx *rctx) {
- rust_task *task = rust_scheduler::get_task();
+ rust_task *task = rust_task_thread::get_task();
task->free(rctx);
}
static void
debug_tydesc_helper(type_desc *t)
{
- rust_task *task = rust_scheduler::get_task();
+ rust_task *task = rust_task_thread::get_task();
LOG(task, stdlib, " size %" PRIdPTR ", align %" PRIdPTR
", first_param 0x%" PRIxPTR,
t->size, t->align, t->first_param);
extern "C" CDECL void
debug_tydesc(type_desc *t) {
- rust_task *task = rust_scheduler::get_task();
+ rust_task *task = rust_task_thread::get_task();
LOG(task, stdlib, "debug_tydesc");
debug_tydesc_helper(t);
}
extern "C" CDECL void
debug_opaque(type_desc *t, uint8_t *front) {
- rust_task *task = rust_scheduler::get_task();
+ rust_task *task = rust_task_thread::get_task();
LOG(task, stdlib, "debug_opaque");
debug_tydesc_helper(t);
// FIXME may want to actually account for alignment. `front` may not
extern "C" CDECL void
debug_box(type_desc *t, rust_box *box) {
- rust_task *task = rust_scheduler::get_task();
+ rust_task *task = rust_task_thread::get_task();
LOG(task, stdlib, "debug_box(0x%" PRIxPTR ")", box);
debug_tydesc_helper(t);
LOG(task, stdlib, " refcount %" PRIdPTR,
extern "C" CDECL void
debug_tag(type_desc *t, rust_tag *tag) {
- rust_task *task = rust_scheduler::get_task();
+ rust_task *task = rust_task_thread::get_task();
LOG(task, stdlib, "debug_tag");
debug_tydesc_helper(t);
extern "C" CDECL void
debug_obj(type_desc *t, rust_obj *obj, size_t nmethods, size_t nbytes) {
- rust_task *task = rust_scheduler::get_task();
+ rust_task *task = rust_task_thread::get_task();
LOG(task, stdlib, "debug_obj with %" PRIdPTR " methods", nmethods);
debug_tydesc_helper(t);
extern "C" CDECL void
debug_fn(type_desc *t, rust_fn *fn) {
- rust_task *task = rust_scheduler::get_task();
+ rust_task *task = rust_task_thread::get_task();
LOG(task, stdlib, "debug_fn");
debug_tydesc_helper(t);
LOG(task, stdlib, " thunk at 0x%" PRIxPTR, fn->thunk);
debug_ptrcast(type_desc *from_ty,
type_desc *to_ty,
void *ptr) {
- rust_task *task = rust_scheduler::get_task();
+ rust_task *task = rust_task_thread::get_task();
LOG(task, stdlib, "debug_ptrcast from");
debug_tydesc_helper(from_ty);
LOG(task, stdlib, "to");
extern "C" CDECL void *
debug_get_stk_seg() {
- rust_task *task = rust_scheduler::get_task();
+ rust_task *task = rust_task_thread::get_task();
return task->stk;
}
extern "C" CDECL rust_vec*
rust_list_files(rust_str *path) {
- rust_task *task = rust_scheduler::get_task();
+ rust_task *task = rust_task_thread::get_task();
array_list<rust_str*> strings;
#if defined(__WIN32__)
WIN32_FIND_DATA FindFileData;
#if defined(__WIN32__)
extern "C" CDECL void
get_time(uint32_t *sec, uint32_t *usec) {
- rust_task *task = rust_scheduler::get_task();
+ rust_task *task = rust_task_thread::get_task();
SYSTEMTIME systemTime;
FILETIME fileTime;
GetSystemTime(&systemTime);
*ns = t.time_ns();
}
-extern "C" CDECL void
-pin_task() {
- rust_task *task = rust_scheduler::get_task();
- task->pin();
-}
-
-extern "C" CDECL void
-unpin_task() {
- rust_task *task = rust_scheduler::get_task();
- task->unpin();
-}
-
extern "C" CDECL rust_task_id
get_task_id() {
- rust_task *task = rust_scheduler::get_task();
+ rust_task *task = rust_task_thread::get_task();
return task->user.id;
}
extern "C" CDECL rust_task_id
new_task() {
- rust_task *task = rust_scheduler::get_task();
- return task->kernel->create_task(task, NULL);
+ rust_task *task = rust_task_thread::get_task();
+ return task->sched->create_task(task, NULL);
}
extern "C" CDECL void
extern "C" CDECL rust_task *
get_task_pointer(rust_task_id id) {
- rust_task *task = rust_scheduler::get_task();
+ rust_task *task = rust_task_thread::get_task();
return task->kernel->get_task_by_id(id);
}
extern "C" rust_task *
rust_get_task() {
- return rust_scheduler::get_task();
+ return rust_task_thread::get_task();
}
extern "C" CDECL void
start_task(rust_task_id id, fn_env_pair *f) {
- rust_task *task = rust_scheduler::get_task();
+ rust_task *task = rust_task_thread::get_task();
rust_task *target = task->kernel->get_task_by_id(id);
target->start(f->f, f->env, NULL);
target->deref();
}
-extern "C" CDECL void
-migrate_alloc(void *alloc, rust_task_id tid) {
- rust_task *task = rust_scheduler::get_task();
- if(!alloc) return;
- rust_task *target = task->kernel->get_task_by_id(tid);
- if(target) {
- const type_desc *tydesc = task->release_alloc(alloc);
- target->claim_alloc(alloc, tydesc);
- target->deref();
- }
- else {
- // We couldn't find the target. Maybe we should just free?
- task->fail();
- }
-}
-
-// defined in rust_task.cpp
-extern size_t g_custom_min_stack_size;
-extern "C" CDECL void
-set_min_stack(uintptr_t stack_size) {
- g_custom_min_stack_size = stack_size;
-}
-
extern "C" CDECL int
sched_threads() {
- rust_task *task = rust_scheduler::get_task();
- return task->kernel->num_threads;
+ rust_task *task = rust_task_thread::get_task();
+ return task->sched->number_of_threads();
}
extern "C" CDECL rust_port*
new_port(size_t unit_sz) {
- rust_task *task = rust_scheduler::get_task();
+ rust_task *task = rust_task_thread::get_task();
LOG(task, comm, "new_port(task=0x%" PRIxPTR " (%s), unit_sz=%d)",
(uintptr_t) task, task->name, unit_sz);
// port starts with refcount == 1
extern "C" CDECL void
rust_port_detach(rust_port *port) {
- rust_task *task = rust_scheduler::get_task();
+ rust_task *task = rust_task_thread::get_task();
LOG(task, comm, "rust_port_detach(0x%" PRIxPTR ")", (uintptr_t) port);
port->detach();
// FIXME: Busy waiting until we're the only ref
extern "C" CDECL void
del_port(rust_port *port) {
- rust_task *task = rust_scheduler::get_task();
+ rust_task *task = rust_task_thread::get_task();
LOG(task, comm, "del_port(0x%" PRIxPTR ")", (uintptr_t) port);
- A(task->sched, port->ref_count == 1, "Expected port ref_count == 1");
+ A(task->thread, port->ref_count == 1, "Expected port ref_count == 1");
port->deref();
}
rust_port_id target_port_id, void *sptr) {
// FIXME: make sure this is thread-safe
bool sent = false;
- rust_task *task = rust_scheduler::get_task();
+ rust_task *task = rust_task_thread::get_task();
rust_task *target_task = task->kernel->get_task_by_id(target_task_id);
if(target_task) {
rust_port *port = target_task->get_port_by_id(target_port_id);
// This is called by an intrinsic on the Rust stack and must run
// entirely in the red zone. Do not call on the C stack.
extern "C" CDECL void
-rust_task_sleep(rust_task *task, size_t time_in_us, bool *killed) {
- task->yield(time_in_us, killed);
+rust_task_yield(rust_task *task, bool *killed) {
+ task->yield(killed);
}
extern "C" CDECL void
uintptr_t *yield, uintptr_t *killed) {
*yield = false;
*killed = false;
- rust_task *task = rust_scheduler::get_task();
+ rust_task *task = rust_task_thread::get_task();
{
scoped_lock with(port->lock);
extern "C" CDECL void
rust_set_exit_status(intptr_t code) {
- rust_task *task = rust_scheduler::get_task();
+ rust_task *task = rust_task_thread::get_task();
task->kernel->set_exit_status((int)code);
}
extern "C" CDECL void
rust_log_console_off() {
- rust_task *task = rust_scheduler::get_task();
+ rust_task *task = rust_task_thread::get_task();
log_console_off(task->kernel->env);
}
// time until LLVM's GC infrastructure is more mature.
#include "rust_debug.h"
-#include "rust_gc.h"
#include "rust_internal.h"
#include "rust_shape.h"
#include "rust_task.h"
// Internal reference count computation
-typedef std::map<void *,uintptr_t> irc_map;
+typedef std::map<rust_opaque_box*,uintptr_t> irc_map;
class irc : public shape::data<irc,shape::ptr> {
friend class shape::data<irc,shape::ptr>;
}
}
- void walk_obj2() {
- dp += sizeof(void *); // skip vtable
- uint8_t *box_ptr = shape::bump_dp<uint8_t *>(dp);
- shape::ptr ref_count_dp(box_ptr);
- maybe_record_irc(ref_count_dp);
- }
-
void walk_iface2() {
walk_box2();
}
void walk_uniq_contents2(irc &sub) { sub.walk(); }
- void walk_box_contents2(irc &sub, shape::ptr &ref_count_dp) {
- maybe_record_irc(ref_count_dp);
+ void walk_box_contents2(irc &sub, shape::ptr &box_dp) {
+ maybe_record_irc(box_dp);
// Do not traverse the contents of this box; it's in the allocation
// somewhere, so we're guaranteed to come back to it (if we haven't
// traversed it already).
}
- void maybe_record_irc(shape::ptr &ref_count_dp) {
- if (!ref_count_dp)
+ void maybe_record_irc(shape::ptr &box_dp) {
+ if (!box_dp)
return;
+ rust_opaque_box *box_ptr = (rust_opaque_box *) box_dp;
+
// Bump the internal reference count of the box.
- if (ircs.find((void *)ref_count_dp) == ircs.end()) {
+ if (ircs.find(box_ptr) == ircs.end()) {
LOG(task, gc,
"setting internal reference count for %p to 1",
- (void *)ref_count_dp);
- ircs[(void *)ref_count_dp] = 1;
+ box_ptr);
+ ircs[box_ptr] = 1;
} else {
- uintptr_t newcount = ircs[(void *)ref_count_dp] + 1;
+ uintptr_t newcount = ircs[box_ptr] + 1;
LOG(task, gc,
"bumping internal reference count for %p to %lu",
- (void *)ref_count_dp, newcount);
- ircs[(void *)ref_count_dp] = newcount;
+ box_ptr, newcount);
+ ircs[box_ptr] = newcount;
}
}
void
irc::compute_ircs(rust_task *task, irc_map &ircs) {
- std::map<void *,const type_desc *>::iterator
- begin(task->local_allocs.begin()), end(task->local_allocs.end());
- while (begin != end) {
- uint8_t *p = reinterpret_cast<uint8_t *>(begin->first);
-
- const type_desc *tydesc = begin->second;
-
- LOG(task, gc, "determining internal ref counts: %p, tydesc=%p", p,
- tydesc);
-
+ boxed_region *boxed = &task->boxed;
+ for (rust_opaque_box *box = boxed->first_live_alloc();
+ box != NULL;
+ box = box->next) {
+ type_desc *tydesc = box->td;
+ uint8_t *body = (uint8_t*) box_body(box);
+
+ LOG(task, gc,
+ "determining internal ref counts: "
+ "box=%p tydesc=%p body=%p",
+ box, tydesc, body);
+
shape::arena arena;
shape::type_param *params =
- shape::type_param::from_tydesc_and_data(tydesc, p, arena);
-
-#if 0
- shape::print print(task, true, tydesc->shape, params,
- tydesc->shape_tables);
- print.walk();
-
- shape::log log(task, true, tydesc->shape, params,
- tydesc->shape_tables, p + sizeof(uintptr_t),
- std::cerr);
- log.walk();
-#endif
+ shape::type_param::from_tydesc_and_data(tydesc, body, arena);
irc irc(task, true, tydesc->shape, params, tydesc->shape_tables,
- p + sizeof(uintptr_t), ircs);
+ body, ircs);
irc.walk();
-
- ++begin;
}
}
// Root finding
void
-find_roots(rust_task *task, irc_map &ircs, std::vector<void *> &roots) {
- std::map<void *,const type_desc *>::iterator
- begin(task->local_allocs.begin()), end(task->local_allocs.end());
- while (begin != end) {
- void *alloc = begin->first;
- uintptr_t *ref_count_ptr = reinterpret_cast<uintptr_t *>(alloc);
- uintptr_t ref_count = *ref_count_ptr;
+find_roots(rust_task *task, irc_map &ircs,
+ std::vector<rust_opaque_box *> &roots) {
+ boxed_region *boxed = &task->boxed;
+ for (rust_opaque_box *box = boxed->first_live_alloc();
+ box != NULL;
+ box = box->next) {
+ uintptr_t ref_count = box->ref_count;
uintptr_t irc;
- if (ircs.find(alloc) != ircs.end())
- irc = ircs[alloc];
+ if (ircs.find(box) != ircs.end())
+ irc = ircs[box];
else
irc = 0;
// This allocation must be a root, because the internal reference
// count is smaller than the total reference count.
LOG(task, gc,"root found: %p, irc %lu, ref count %lu",
- alloc, irc, ref_count);
- roots.push_back(alloc);
+ box, irc, ref_count);
+ roots.push_back(box);
} else {
LOG(task, gc, "nonroot found: %p, irc %lu, ref count %lu",
- alloc, irc, ref_count);
+ box, irc, ref_count);
assert(irc == ref_count && "Internal reference count must be "
"less than or equal to the total reference count!");
}
-
- ++begin;
}
}
class mark : public shape::data<mark,shape::ptr> {
friend class shape::data<mark,shape::ptr>;
- std::set<void *> &marked;
+ std::set<rust_opaque_box *> &marked;
mark(const mark &other, const shape::ptr &in_dp)
: shape::data<mark,shape::ptr>(other.task, other.align, other.sp,
const shape::type_param *in_params,
const rust_shape_tables *in_tables,
uint8_t *in_data,
- std::set<void *> &in_marked)
+ std::set<rust_opaque_box*> &in_marked)
: shape::data<mark,shape::ptr>(in_task, in_align, in_sp, in_params,
in_tables, in_data),
marked(in_marked) {}
case shape::SHAPE_BOX_FN: {
// Record an irc for the environment box, but don't descend
// into it since it will be walked via the box's allocation
- shape::data<mark,shape::ptr>::walk_fn_contents1(dp, false);
+ shape::data<mark,shape::ptr>::walk_fn_contents1();
break;
}
case shape::SHAPE_BARE_FN: // Does not close over data.
}
}
- void walk_obj2() {
- shape::data<mark,shape::ptr>::walk_obj_contents1(dp);
- }
-
void walk_res2(const shape::rust_fn *dtor, unsigned n_params,
const shape::type_param *params, const uint8_t *end_sp,
bool live) {
void walk_uniq_contents2(mark &sub) { sub.walk(); }
- void walk_box_contents2(mark &sub, shape::ptr &ref_count_dp) {
- if (!ref_count_dp)
+ void walk_box_contents2(mark &sub, shape::ptr &box_dp) {
+ if (!box_dp)
return;
- if (marked.find((void *)ref_count_dp) != marked.end())
+ rust_opaque_box *box_ptr = (rust_opaque_box *) box_dp;
+
+ if (marked.find(box_ptr) != marked.end())
return; // Skip to avoid chasing cycles.
- marked.insert((void *)ref_count_dp);
+ marked.insert(box_ptr);
sub.walk();
}
inline void walk_number2() { /* no-op */ }
public:
- static void do_mark(rust_task *task, const std::vector<void *> &roots,
- std::set<void *> &marked);
+ static void do_mark(rust_task *task,
+ const std::vector<rust_opaque_box *> &roots,
+ std::set<rust_opaque_box*> &marked);
};
void
}
void
-mark::do_mark(rust_task *task, const std::vector<void *> &roots,
- std::set<void *> &marked) {
- std::vector<void *>::const_iterator begin(roots.begin()),
- end(roots.end());
+mark::do_mark(rust_task *task,
+ const std::vector<rust_opaque_box *> &roots,
+ std::set<rust_opaque_box *> &marked) {
+ std::vector<rust_opaque_box *>::const_iterator
+ begin(roots.begin()),
+ end(roots.end());
while (begin != end) {
- void *alloc = *begin;
- if (marked.find(alloc) == marked.end()) {
- marked.insert(alloc);
+ rust_opaque_box *box = *begin;
+ if (marked.find(box) == marked.end()) {
+ marked.insert(box);
- const type_desc *tydesc = task->local_allocs[alloc];
+ const type_desc *tydesc = box->td;
- LOG(task, gc, "marking: %p, tydesc=%p", alloc, tydesc);
+ LOG(task, gc, "marking: %p, tydesc=%p", box, tydesc);
- uint8_t *p = reinterpret_cast<uint8_t *>(alloc);
+ uint8_t *p = (uint8_t*) box_body(box);
shape::arena arena;
shape::type_param *params =
shape::type_param::from_tydesc_and_data(tydesc, p, arena);
-#if 0
- // We skip over the reference count here.
- shape::log log(task, true, tydesc->shape, params,
- tydesc->shape_tables, p + sizeof(uintptr_t),
- std::cerr);
- log.walk();
-#endif
-
- // We skip over the reference count here.
mark mark(task, true, tydesc->shape, params, tydesc->shape_tables,
- p + sizeof(uintptr_t), marked);
+ p, marked);
mark.walk();
}
fn_env_pair pair = *(fn_env_pair*)dp;
// free closed over data:
- shape::data<sweep,shape::ptr>::walk_fn_contents1(dp, true);
+ shape::data<sweep,shape::ptr>::walk_fn_contents1();
// now free the embedded type descr:
- //
- // see comment in walk_fn_contents1() concerning null_td
- // to understand why this does not occur during the normal
- // walk.
upcall_s_free_shared_type_desc((type_desc*)pair.env->td);
// now free the ptr:
void walk_uniq_contents2(sweep &sub) { sub.walk(); }
- void walk_box_contents2(sweep &sub, shape::ptr &ref_count_dp) {
+ void walk_box_contents2(sweep &sub, shape::ptr &box_dp) {
return;
}
inline void walk_number2() { /* no-op */ }
public:
- static void do_sweep(rust_task *task, const std::set<void *> &marked);
+ static void do_sweep(rust_task *task,
+ const std::set<rust_opaque_box*> &marked);
};
void
-sweep::do_sweep(rust_task *task, const std::set<void *> &marked) {
- std::map<void *,const type_desc *>::iterator
- begin(task->local_allocs.begin()), end(task->local_allocs.end());
- while (begin != end) {
- void *alloc = begin->first;
-
- if (marked.find(alloc) == marked.end()) {
- LOG(task, gc, "object is part of a cycle: %p", alloc);
-
- const type_desc *tydesc = begin->second;
- uint8_t *p = reinterpret_cast<uint8_t *>(alloc);
+sweep::do_sweep(rust_task *task,
+ const std::set<rust_opaque_box*> &marked) {
+ boxed_region *boxed = &task->boxed;
+ rust_opaque_box *box = boxed->first_live_alloc();
+ while (box != NULL) {
+ // save next ptr as we may be freeing box
+ rust_opaque_box *box_next = box->next;
+ if (marked.find(box) == marked.end()) {
+ LOG(task, gc, "object is part of a cycle: %p", box);
+
+ const type_desc *tydesc = box->td;
+ uint8_t *p = (uint8_t*) box_body(box);
shape::arena arena;
shape::type_param *params =
shape::type_param::from_tydesc_and_data(tydesc, p, arena);
sweep sweep(task, true, tydesc->shape,
params, tydesc->shape_tables,
- p + sizeof(uintptr_t));
+ p);
sweep.walk();
- // FIXME: Run the destructor, *if* it's a resource.
- task->free(alloc);
+ boxed->free(box);
}
- ++begin;
+ box = box_next;
}
}
void
do_cc(rust_task *task) {
- LOG(task, gc, "cc; n allocs = %lu",
- (long unsigned int)task->local_allocs.size());
+ LOG(task, gc, "cc");
irc_map ircs;
irc::compute_ircs(task, ircs);
- std::vector<void *> roots;
+ std::vector<rust_opaque_box*> roots;
find_roots(task, ircs, roots);
- std::set<void *> marked;
+ std::set<rust_opaque_box*> marked;
mark::do_mark(task, roots, marked);
sweep::do_sweep(task, marked);
type_desc const **descs,
uintptr_t n_obj_params)
{
- I(sched, n_descs > 1);
+ I(thread, n_descs > 1);
type_desc *td = NULL;
size_t keysz = n_descs * sizeof(type_desc*);
HASH_FIND(hh, this->type_descs, descs, keysz, td);
if (td) {
- DLOG(sched, cache, "rust_crate_cache::get_type_desc hit");
+ DLOG(thread, cache, "rust_crate_cache::get_type_desc hit");
// FIXME: This is a gross hack.
td->n_obj_params = std::max(td->n_obj_params, n_obj_params);
return td;
}
- DLOG(sched, cache, "rust_crate_cache::get_type_desc miss");
- td = (type_desc*) sched->kernel->malloc(sizeof(type_desc) + keysz,
+ DLOG(thread, cache, "rust_crate_cache::get_type_desc miss");
+ td = (type_desc*) thread->kernel->malloc(sizeof(type_desc) + keysz,
"crate cache typedesc");
if (!td)
return NULL;
td->size = size;
td->align = align;
for (size_t i = 0; i < n_descs; ++i) {
- DLOG(sched, cache,
+ DLOG(thread, cache,
"rust_crate_cache::descs[%" PRIdPTR "] = 0x%" PRIxPTR,
i, descs[i]);
td->descs[i] = descs[i];
HASH_FIND(hh, this->dicts, dict, dictsz, found);
if (found) return &(found->fields[0]);
found = (rust_hashable_dict*)
- sched->kernel->malloc(sizeof(UT_hash_handle) + dictsz,
+ thread->kernel->malloc(sizeof(UT_hash_handle) + dictsz,
"crate cache dict");
if (!found) return NULL;
void** retptr = &(found->fields[0]);
return retptr;
}
-rust_crate_cache::rust_crate_cache(rust_scheduler *sched)
+rust_crate_cache::rust_crate_cache(rust_task_thread *thread)
: type_descs(NULL),
dicts(NULL),
- sched(sched),
+ thread(thread),
idx(0)
{
}
void
rust_crate_cache::flush() {
- DLOG(sched, cache, "rust_crate_cache::flush()");
+ DLOG(thread, cache, "rust_crate_cache::flush()");
while (type_descs) {
type_desc *d = type_descs;
HASH_DEL(type_descs, d);
- DLOG(sched, mem, "rust_crate_cache::flush() tydesc %" PRIxPTR, d);
- sched->kernel->free(d);
+ DLOG(thread, mem, "rust_crate_cache::flush() tydesc %" PRIxPTR, d);
+ thread->kernel->free(d);
}
while (dicts) {
rust_hashable_dict *d = dicts;
HASH_DEL(dicts, d);
- sched->kernel->free(d);
+ thread->kernel->free(d);
}
}
+++ /dev/null
-// Rust garbage collection.
-
-#include <algorithm>
-#include <iostream>
-#include <utility>
-#include <vector>
-#include <stdint.h>
-
-#include "rust_abi.h"
-#include "rust_debug.h"
-#include "rust_gc.h"
-#include "rust_internal.h"
-#include "rust_shape.h"
-
-#ifdef __WIN32__
-#include <windows.h>
-#else
-#include <dlfcn.h>
-#endif
-
-using namespace stack_walk;
-
-namespace gc {
-
-weak_symbol<const uintptr_t> safe_point_data("rust_gc_safe_points");
-
-struct root_info {
- intptr_t frame_offset;
- uintptr_t dynamic; // 0 = static, 1 = dynamic
- const type_desc *tydesc;
-};
-
-struct root {
- const type_desc *tydesc;
- uint8_t *data;
-
- root(const root_info &info, const frame &frame)
- : tydesc(info.tydesc),
- data((uint8_t *)frame.bp + info.frame_offset) {}
-};
-
-struct safe_point {
- uintptr_t n_roots;
- root_info roots[0];
-};
-
-struct safe_point_index_entry {
- void (*ra)(); // The return address.
- const struct safe_point *safe_point; // The safe point.
-
- struct cmp {
- bool operator()(const safe_point_index_entry &entry, void (*ra)())
- const {
- return entry.ra < ra;
- }
- bool operator()(void (*ra)(), const safe_point_index_entry &entry)
- const {
- return ra < entry.ra;
- }
- };
-};
-
-class safe_point_map {
- uintptr_t n_safe_points;
- const safe_point_index_entry *index;
- const safe_point *safe_points;
-
-public:
- safe_point_map() {
- const uintptr_t *data = *safe_point_data;
- n_safe_points = *data++;
- index = (const safe_point_index_entry *)data;
- data += n_safe_points * 2;
- safe_points = (const safe_point *)data;
- }
-
- const safe_point *get_safe_point(void (*addr)());
-};
-
-class gc {
-private:
- rust_task *task;
-
- void mark(std::vector<root> &roots);
- void sweep();
-
-public:
- gc(rust_task *in_task) : task(in_task) {}
- void run();
-};
-
-const safe_point *
-safe_point_map::get_safe_point(void (*addr)()) {
- safe_point_index_entry::cmp cmp;
- const safe_point_index_entry *entry =
- std::lower_bound(index, index + n_safe_points, addr, cmp);
- return (entry && entry->ra == addr) ? entry->safe_point : NULL;
-}
-
-void
-gc::mark(std::vector<root> &roots) {
- std::vector<root>::iterator ri = roots.begin(), rend = roots.end();
- while (ri < rend) {
- DPRINT("root: %p\n", ri->data);
-
- shape::arena arena;
- shape::type_param *params =
- shape::type_param::from_tydesc_and_data(ri->tydesc, ri->data,
- arena);
- shape::log log(task, true, ri->tydesc->shape, params,
- ri->tydesc->shape_tables, ri->data, std::cerr);
- log.walk();
- DPRINT("\n");
-
- ++ri;
- }
- // TODO
-}
-
-void
-gc::sweep() {
- // TODO
-}
-
-void
-gc::run() {
- safe_point_map map;
-
- // Find roots.
- std::vector<root> roots;
- std::vector<frame> call_stack = backtrace();
- for (unsigned i = 0; i < call_stack.size(); i++) {
- frame f = call_stack[i];
- const safe_point *sp = map.get_safe_point(f.ra);
- if (!sp)
- continue;
-
- DPRINT("%u: ra %p, ebp %p\n", i, call_stack[i].ra, call_stack[i].bp);
- for (unsigned j = 0; j < sp->n_roots; j++) {
- root r(sp->roots[j], f);
- roots.push_back(r);
- }
- }
-
- // Mark and sweep.
- mark(roots);
- sweep();
-}
-
-void
-maybe_gc(rust_task *task) {
- if (*safe_point_data == NULL)
- return;
-
- static debug::flag zeal("RUST_GC_ZEAL");
-
- if (*zeal) {
- gc gc(task);
- gc.run();
- }
-}
-
-}
-
+++ /dev/null
-// Rust garbage collection.
-
-struct rust_task;
-
-namespace gc {
-
-void maybe_gc(rust_task *task);
-
-}
-
#include "util/synchronized_indexed_list.h"
#include "util/hash_map.h"
#include "sync/sync.h"
-#include "sync/timer.h"
#include "sync/lock_and_signal.h"
#include "sync/lock_free_queue.h"
-struct rust_scheduler;
+struct rust_task_thread;
struct rust_task;
class rust_log;
class rust_port;
#include "rust_srv.h"
#include "rust_log.h"
#include "rust_kernel.h"
-#include "rust_scheduler.h"
-
-struct rust_timer {
- // FIXME: This will probably eventually need replacement
- // with something more sophisticated and integrated with
- // an IO event-handling library, when we have such a thing.
- // For now it's just the most basic "thread that can interrupt
- // its associated domain-thread" device, so that we have
- // *some* form of task-preemption.
- rust_scheduler *sched;
- uintptr_t exit_flag;
-
-#if defined(__WIN32__)
- HANDLE thread;
-#else
- pthread_attr_t attr;
- pthread_t thread;
-#endif
-
- rust_timer(rust_scheduler *sched);
- ~rust_timer();
-};
+#include "rust_task_thread.h"
typedef void CDECL (glue_fn)(void *, void *,
const type_desc **, void *);
uint8_t *resources;
};
-struct rust_opaque_closure;
+typedef unsigned long ref_cnt_t;
+
+// Corresponds to the boxed data in the @ region. The body follows the
+// header; you can obtain a ptr via box_body() below.
+struct rust_opaque_box {
+ ref_cnt_t ref_count;
+ type_desc *td;
+ rust_opaque_box *prev;
+ rust_opaque_box *next;
+};
// The type of functions that we spawn, which fall into two categories:
// - the main function: has a NULL environment, but uses the void* arg
// - unique closures of type fn~(): have a non-NULL environment, but
// no arguments (and hence the final void*) is harmless
-typedef void (*CDECL spawn_fn)(void*, rust_opaque_closure*, void *);
+typedef void (*CDECL spawn_fn)(void*, rust_opaque_box*, void *);
// corresponds to the layout of a fn(), fn@(), fn~() etc
struct fn_env_pair {
spawn_fn f;
- rust_opaque_closure *env;
+ rust_opaque_box *env;
};
-// corresponds the closures generated in trans_closure.rs
-struct rust_opaque_closure {
- intptr_t ref_count;
- const type_desc *td;
- // The size/types of these will vary per closure, so they
- // cannot be statically expressed. See trans_closure.rs:
- const type_desc *captured_tds[0];
- // struct bound_data;
-};
+static inline void *box_body(rust_opaque_box *box) {
+ // Here we take advantage of the fact that the size of a box in 32
+ // (resp. 64) bit is 16 (resp. 32) bytes, and thus always 16-byte aligned.
+ // If this were to change, we would have to update the method
+ // rustc::middle::trans::base::opaque_box_body() as well.
+ return (void*)(box + 1);
+}
struct type_desc {
// First part of type_desc is known to compiler.
#include "rust_port.h"
#include "memory.h"
-#include "test/rust_test_harness.h"
-#include "test/rust_test_util.h"
-#include "test/rust_test_runtime.h"
-
//
// Local Variables:
// mode: C++
#include "rust_internal.h"
#include "rust_util.h"
+#include "rust_scheduler.h"
#define KLOG_(...) \
KLOG(this, kern, __VA_ARGS__)
_region(srv, true),
_log(srv, NULL),
srv(srv),
- max_id(0),
- rval(0),
- num_threads(num_threads),
live_tasks(0),
+ max_task_id(0),
+ rval(0),
env(srv->env)
{
- isaac_init(this, &rctx);
- create_schedulers();
-}
-
-rust_scheduler *
-rust_kernel::create_scheduler(int id) {
- _kernel_lock.lock();
- rust_srv *srv = this->srv->clone();
- rust_scheduler *sched =
- new (this, "rust_scheduler") rust_scheduler(this, srv, id);
- KLOG_("created scheduler: " PTR ", id: %d, index: %d",
- sched, id, sched->list_index);
- _kernel_lock.signal_all();
- _kernel_lock.unlock();
- return sched;
-}
-
-void
-rust_kernel::destroy_scheduler(rust_scheduler *sched) {
- _kernel_lock.lock();
- KLOG_("deleting scheduler: " PTR ", name: %s, index: %d",
- sched, sched->name, sched->list_index);
- rust_srv *srv = sched->srv;
- delete sched;
- delete srv;
- _kernel_lock.signal_all();
- _kernel_lock.unlock();
-}
-
-void rust_kernel::create_schedulers() {
- KLOG_("Using %d scheduler threads.", num_threads);
-
- for(size_t i = 0; i < num_threads; ++i) {
- threads.push(create_scheduler(i));
- }
-}
-
-void rust_kernel::destroy_schedulers() {
- for(size_t i = 0; i < num_threads; ++i) {
- destroy_scheduler(threads[i]);
- }
-}
-
-void
-rust_kernel::log_all_scheduler_state() {
- for(size_t i = 0; i < num_threads; ++i) {
- threads[i]->log_state();
- }
-}
-
-/**
- * Checks for simple deadlocks.
- */
-bool
-rust_kernel::is_deadlocked() {
- return false;
+ sched = new (this, "rust_scheduler")
+ rust_scheduler(this, srv, num_threads);
}
void
}
rust_kernel::~rust_kernel() {
- destroy_schedulers();
+ delete sched;
}
void *
_region.free(mem);
}
-void
-rust_kernel::signal_kernel_lock() {
- _kernel_lock.lock();
- _kernel_lock.signal_all();
- _kernel_lock.unlock();
-}
-
-int rust_kernel::start_task_threads()
+int rust_kernel::start_schedulers()
{
- for(size_t i = 0; i < num_threads; ++i) {
- rust_scheduler *thread = threads[i];
- thread->start();
- }
-
- for(size_t i = 0; i < num_threads; ++i) {
- rust_scheduler *thread = threads[i];
- thread->join();
- }
-
+ sched->start_task_threads();
return rval;
}
+rust_scheduler *
+rust_kernel::get_default_scheduler() {
+ return sched;
+}
+
void
rust_kernel::fail() {
// FIXME: On windows we're getting "Application has requested the
#if defined(__WIN32__)
exit(rval);
#endif
- for(size_t i = 0; i < num_threads; ++i) {
- rust_scheduler *thread = threads[i];
- thread->kill_all_tasks();
+ sched->kill_all_tasks();
+}
+
+void
+rust_kernel::register_task(rust_task *task) {
+ uintptr_t new_live_tasks;
+ {
+ scoped_lock with(task_lock);
+ task->user.id = max_task_id++;
+ task_table.put(task->user.id, task);
+ new_live_tasks = ++live_tasks;
}
+ K(srv, task->user.id != INTPTR_MAX, "Hit the maximum task id");
+ KLOG_("Registered task %" PRIdPTR, task->user.id);
+ KLOG_("Total outstanding tasks: %d", new_live_tasks);
}
-rust_task_id
-rust_kernel::create_task(rust_task *spawner, const char *name) {
- scoped_lock with(_kernel_lock);
- rust_scheduler *thread = threads[isaac_rand(&rctx) % num_threads];
- rust_task *t = thread->create_task(spawner, name);
- t->user.id = max_id++;
- task_table.put(t->user.id, t);
- return t->user.id;
+void
+rust_kernel::release_task_id(rust_task_id id) {
+ KLOG_("Releasing task %" PRIdPTR, id);
+ uintptr_t new_live_tasks;
+ {
+ scoped_lock with(task_lock);
+ task_table.remove(id);
+ new_live_tasks = --live_tasks;
+ }
+ KLOG_("Total outstanding tasks: %d", new_live_tasks);
+ if (new_live_tasks == 0) {
+ // There are no more tasks and there never will be.
+ // Tell all the schedulers to exit.
+ sched->exit();
+ }
}
rust_task *
rust_kernel::get_task_by_id(rust_task_id id) {
- scoped_lock with(_kernel_lock);
+ scoped_lock with(task_lock);
rust_task *task = NULL;
// get leaves task unchanged if not found.
task_table.get(id, &task);
return task;
}
-void
-rust_kernel::release_task_id(rust_task_id id) {
- scoped_lock with(_kernel_lock);
- task_table.remove(id);
-}
-
-void rust_kernel::wakeup_schedulers() {
- for(size_t i = 0; i < num_threads; ++i) {
- threads[i]->lock.signal_all();
- }
-}
-
#ifdef __WIN32__
void
rust_kernel::win32_require(LPCTSTR fn, BOOL ok) {
void
rust_kernel::set_exit_status(int code) {
- scoped_lock with(_kernel_lock);
+ scoped_lock with(rval_lock);
// If we've already failed then that's the code we're going to use
if (rval != PROC_FAIL_CODE) {
rval = code;
#include "memory_region.h"
#include "rust_log.h"
+struct rust_task_thread;
struct rust_scheduler;
/**
public:
rust_srv *srv;
private:
- lock_and_signal _kernel_lock;
-
- array_list<rust_scheduler *> threads;
-
- randctx rctx;
-
- rust_scheduler *create_scheduler(int id);
- void destroy_scheduler(rust_scheduler *sched);
-
- void create_schedulers();
- void destroy_schedulers();
-
- rust_task_id max_id;
+ rust_scheduler *sched;
+
+ // Protects live_tasks, max_task_id and task_table
+ lock_and_signal task_lock;
+ // Tracks the number of tasks that are being managed by
+ // schedulers. When this hits 0 we will tell all schedulers
+ // to exit.
+ uintptr_t live_tasks;
+ // The next task id
+ rust_task_id max_task_id;
hash_map<rust_task_id, rust_task *> task_table;
+ lock_and_signal rval_lock;
int rval;
public:
- const size_t num_threads;
- volatile int live_tasks;
struct rust_env *env;
rust_kernel(rust_srv *srv, size_t num_threads);
+ ~rust_kernel();
- bool is_deadlocked();
-
- void signal_kernel_lock();
- void wakeup_schedulers();
-
- void log_all_scheduler_state();
void log(uint32_t level, char const *fmt, ...);
void fatal(char const *fmt, ...);
- virtual ~rust_kernel();
void *malloc(size_t size, const char *tag);
void *realloc(void *mem, size_t size);
void fail();
- int start_task_threads();
+ int start_schedulers();
+ rust_scheduler* get_default_scheduler();
#ifdef __WIN32__
void win32_require(LPCTSTR fn, BOOL ok);
#endif
- rust_task_id create_task(rust_task *spawner, const char *name);
+ void register_task(rust_task *task);
rust_task *get_task_by_id(rust_task_id id);
void release_task_id(rust_task_id tid);
+
void set_exit_status(int code);
};
}
}
-rust_log::rust_log(rust_srv *srv, rust_scheduler *sched) :
+rust_log::rust_log(rust_srv *srv, rust_task_thread *thread) :
_srv(srv),
- _sched(sched) {
+ _thread(thread) {
}
rust_log::~rust_log() {
#endif
char prefix[BUF_BYTES] = "";
- if (_sched && _sched->name) {
+ if (_thread && _thread->name) {
append_string(prefix, "%04" PRIxPTR ":%.10s:",
- thread_id, _sched->name);
+ thread_id, _thread->name);
} else {
append_string(prefix, "%04" PRIxPTR ":0x%08" PRIxPTR ":",
- thread_id, (uintptr_t) _sched);
+ thread_id, (uintptr_t) _thread);
}
if (task) {
if (task->name) {
const uint32_t log_debug = 3;
#define LOG(task, field, ...) \
- DLOG_LVL(log_debug, task, task->sched, field, __VA_ARGS__)
+ DLOG_LVL(log_debug, task, task->thread, field, __VA_ARGS__)
#define LOG_ERR(task, field, ...) \
- DLOG_LVL(log_err, task, task->sched, field, __VA_ARGS__)
-#define DLOG(sched, field, ...) \
- DLOG_LVL(log_debug, NULL, sched, field, __VA_ARGS__)
-#define DLOG_ERR(sched, field, ...) \
- DLOG_LVL(log_err, NULL, sched, field, __VA_ARGS__)
-#define LOGPTR(sched, msg, ptrval) \
- DLOG_LVL(log_debug, NULL, sched, mem, "%s 0x%" PRIxPTR, msg, ptrval)
-#define DLOG_LVL(lvl, task, sched, field, ...) \
+ DLOG_LVL(log_err, task, task->thread, field, __VA_ARGS__)
+#define DLOG(thread, field, ...) \
+ DLOG_LVL(log_debug, NULL, thread, field, __VA_ARGS__)
+#define DLOG_ERR(thread, field, ...) \
+ DLOG_LVL(log_err, NULL, thread, field, __VA_ARGS__)
+#define LOGPTR(thread, msg, ptrval) \
+ DLOG_LVL(log_debug, NULL, thread, mem, "%s 0x%" PRIxPTR, msg, ptrval)
+#define DLOG_LVL(lvl, task, thread, field, ...) \
do { \
- rust_scheduler* _d_ = sched; \
+ rust_task_thread* _d_ = thread; \
if (log_rt_##field >= lvl && _d_->log_lvl >= lvl) { \
_d_->log(task, lvl, __VA_ARGS__); \
} \
} \
} while (0)
-struct rust_scheduler;
+struct rust_task_thread;
struct rust_task;
class rust_log {
public:
- rust_log(rust_srv *srv, rust_scheduler *sched);
+ rust_log(rust_srv *srv, rust_task_thread *thread);
virtual ~rust_log();
void trace_ln(rust_task *task, uint32_t level, char *message);
private:
rust_srv *_srv;
- rust_scheduler *_sched;
+ rust_task_thread *_thread;
bool _use_labels;
void trace_ln(rust_task *task, char *message);
};
}
void rust_port::detach() {
- I(task->sched, !task->lock.lock_held_by_current_thread());
+ I(task->thread, !task->lock.lock_held_by_current_thread());
scoped_lock with(task->lock);
{
task->release_port(id);
}
void rust_port::send(void *sptr) {
- I(task->sched, !lock.lock_held_by_current_thread());
+ I(task->thread, !lock.lock_held_by_current_thread());
scoped_lock with(lock);
buffer.enqueue(sptr);
}
bool rust_port::receive(void *dptr) {
- I(task->sched, lock.lock_held_by_current_thread());
+ I(task->thread, lock.lock_held_by_current_thread());
if (buffer.is_empty() == false) {
buffer.dequeue(dptr);
LOG(task, comm, "<=== read data ===");
}
size_t rust_port::size() {
- I(task->sched, !lock.lock_held_by_current_thread());
+ I(task->thread, !lock.lock_held_by_current_thread());
scoped_lock with(lock);
return buffer.size();
}
-
-#include <stdarg.h>
-#include <cassert>
-#include <pthread.h>
-#include "rust_internal.h"
+#include "rust_scheduler.h"
#include "rust_util.h"
-#include "globals.h"
-
-#ifndef _WIN32
-pthread_key_t rust_scheduler::task_key;
-#else
-DWORD rust_scheduler::task_key;
-#endif
-
-bool rust_scheduler::tls_initialized = false;
rust_scheduler::rust_scheduler(rust_kernel *kernel,
- rust_srv *srv,
- int id) :
- ref_count(1),
- interrupt_flag(0),
- _log(srv, this),
- log_lvl(log_debug),
- srv(srv),
- // TODO: calculate a per scheduler name.
- name("main"),
- newborn_tasks(this, "newborn"),
- running_tasks(this, "running"),
- blocked_tasks(this, "blocked"),
- dead_tasks(this, "dead"),
- cache(this),
+ rust_srv *srv,
+ size_t num_threads) :
kernel(kernel),
- id(id),
- min_stack_size(kernel->env->min_stack_size),
- env(kernel->env)
+ srv(srv),
+ env(srv->env),
+ num_threads(num_threads)
{
- LOGPTR(this, "new dom", (uintptr_t)this);
- isaac_init(this, &rctx);
-#ifndef __WIN32__
- pthread_attr_init(&attr);
- pthread_attr_setstacksize(&attr, 1024 * 1024);
- pthread_attr_setdetachstate(&attr, true);
-#endif
-
- if (!tls_initialized)
- init_tls();
+ isaac_init(kernel, &rctx);
+ create_task_threads();
}
rust_scheduler::~rust_scheduler() {
- DLOG(this, dom, "~rust_scheduler %s @0x%" PRIxPTR, name, (uintptr_t)this);
-
- newborn_tasks.delete_all();
- running_tasks.delete_all();
- blocked_tasks.delete_all();
- dead_tasks.delete_all();
-#ifndef __WIN32__
- pthread_attr_destroy(&attr);
-#endif
-}
-
-void
-rust_scheduler::activate(rust_task *task) {
- task->ctx.next = &c_context;
- DLOG(this, task, "descheduling...");
- lock.unlock();
- task->ctx.swap(c_context);
- lock.lock();
- DLOG(this, task, "task has returned");
+ destroy_task_threads();
}
-void
-rust_scheduler::log(rust_task* task, uint32_t level, char const *fmt, ...) {
- char buf[BUF_BYTES];
- va_list args;
- va_start(args, fmt);
- vsnprintf(buf, sizeof(buf), fmt, args);
- _log.trace_ln(task, level, buf);
- va_end(args);
+rust_task_thread *
+rust_scheduler::create_task_thread(int id) {
+ rust_srv *srv = this->srv->clone();
+ rust_task_thread *thread =
+ new (kernel, "rust_task_thread") rust_task_thread(this, srv, id);
+ KLOG(kernel, kern, "created task thread: " PTR ", id: %d, index: %d",
+ thread, id, thread->list_index);
+ return thread;
}
void
-rust_scheduler::fail() {
- log(NULL, log_err, "domain %s @0x%" PRIxPTR " root task failed",
- name, this);
- kernel->fail();
+rust_scheduler::destroy_task_thread(rust_task_thread *thread) {
+ KLOG(kernel, kern, "deleting task thread: " PTR ", name: %s, index: %d",
+ thread, thread->name, thread->list_index);
+ rust_srv *srv = thread->srv;
+ delete thread;
+ delete srv;
}
void
-rust_scheduler::kill_all_tasks() {
- I(this, !lock.lock_held_by_current_thread());
- scoped_lock with(lock);
+rust_scheduler::create_task_threads() {
+ KLOG(kernel, kern, "Using %d scheduler threads.", num_threads);
- for (size_t i = 0; i < running_tasks.length(); i++) {
- // We don't want the failure of these tasks to propagate back
- // to the kernel again since we're already failing everything
- running_tasks[i]->unsupervise();
- running_tasks[i]->kill();
+ for(size_t i = 0; i < num_threads; ++i) {
+ threads.push(create_task_thread(i));
}
-
- for (size_t i = 0; i < blocked_tasks.length(); i++) {
- blocked_tasks[i]->unsupervise();
- blocked_tasks[i]->kill();
- }
-}
-
-size_t
-rust_scheduler::number_of_live_tasks() {
- return running_tasks.length() + blocked_tasks.length();
}
-/**
- * Delete any dead tasks.
- */
void
-rust_scheduler::reap_dead_tasks(int id) {
- I(this, lock.lock_held_by_current_thread());
- if (dead_tasks.length() == 0) {
- return;
+rust_scheduler::destroy_task_threads() {
+ for(size_t i = 0; i < num_threads; ++i) {
+ destroy_task_thread(threads[i]);
}
-
- // First make a copy of the dead_task list with the lock held
- size_t dead_tasks_len = dead_tasks.length();
- rust_task **dead_tasks_copy = (rust_task**)
- srv->malloc(sizeof(rust_task*) * dead_tasks_len);
- for (size_t i = 0; i < dead_tasks_len; ++i) {
- rust_task *task = dead_tasks[i];
- dead_tasks_copy[i] = task;
- }
-
- // Now drop the lock and futz with the tasks. This avoids establishing
- // a sched->lock then task->lock locking order, which would be devestating
- // to performance.
- lock.unlock();
-
- for (size_t i = 0; i < dead_tasks_len; ++i) {
- rust_task *task = dead_tasks_copy[i];
- task->lock.lock();
- // Make sure this task isn't still running somewhere else...
- if (task->can_schedule(id)) {
- DLOG(this, task,
- "deleting unreferenced dead task %s @0x%" PRIxPTR,
- task->name, task);
- task->lock.unlock();
- } else {
- task->lock.unlock();
- dead_tasks_copy[i] = NULL;
- }
- }
-
- // Now grab the lock again and remove the tasks that were truly dead
- lock.lock();
-
- for (size_t i = 0; i < dead_tasks_len; ++i) {
- rust_task *task = dead_tasks_copy[i];
- if (task) {
- dead_tasks.remove(task);
- }
- }
-
- // Now unlock again because we have to actually free the dead tasks,
- // and that may end up wanting to lock the task and sched locks
- // again (via target->send)
- lock.unlock();
-
- for (size_t i = 0; i < dead_tasks_len; ++i) {
- rust_task *task = dead_tasks_copy[i];
- if (task) {
- task->deref();
- sync::decrement(kernel->live_tasks);
- kernel->wakeup_schedulers();
- }
- }
- srv->free(dead_tasks_copy);
-
- lock.lock();
-}
-
-/**
- * Schedules a running task for execution. Only running tasks can be
- * activated. Blocked tasks have to be unblocked before they can be
- * activated.
- *
- * Returns NULL if no tasks can be scheduled.
- */
-rust_task *
-rust_scheduler::schedule_task(int id) {
- I(this, this);
- // FIXME: in the face of failing tasks, this is not always right.
- // I(this, n_live_tasks() > 0);
- if (running_tasks.length() > 0) {
- size_t k = isaac_rand(&rctx);
- // Look around for a runnable task, starting at k.
- for(size_t j = 0; j < running_tasks.length(); ++j) {
- size_t i = (j + k) % running_tasks.length();
- if (running_tasks[i]->can_schedule(id)) {
- return (rust_task *)running_tasks[i];
- }
- }
- }
- return NULL;
}
void
-rust_scheduler::log_state() {
- if (log_rt_task < log_debug) return;
-
- if (!running_tasks.is_empty()) {
- log(NULL, log_debug, "running tasks:");
- for (size_t i = 0; i < running_tasks.length(); i++) {
- log(NULL, log_debug, "\t task: %s @0x%" PRIxPTR
- " remaining: %" PRId64 " us",
- running_tasks[i]->name,
- running_tasks[i],
- running_tasks[i]->yield_timer.remaining_us());
- }
- }
-
- if (!blocked_tasks.is_empty()) {
- log(NULL, log_debug, "blocked tasks:");
- for (size_t i = 0; i < blocked_tasks.length(); i++) {
- log(NULL, log_debug, "\t task: %s @0x%" PRIxPTR ", blocked on: 0x%"
- PRIxPTR " '%s'",
- blocked_tasks[i]->name, blocked_tasks[i],
- blocked_tasks[i]->cond, blocked_tasks[i]->cond_name);
- }
+rust_scheduler::start_task_threads()
+{
+ for(size_t i = 0; i < num_threads; ++i) {
+ rust_task_thread *thread = threads[i];
+ thread->start();
}
- if (!dead_tasks.is_empty()) {
- log(NULL, log_debug, "dead tasks:");
- for (size_t i = 0; i < dead_tasks.length(); i++) {
- log(NULL, log_debug, "\t task: %s 0x%" PRIxPTR,
- dead_tasks[i]->name, dead_tasks[i]);
- }
+ for(size_t i = 0; i < num_threads; ++i) {
+ rust_task_thread *thread = threads[i];
+ thread->join();
}
}
-/**
- * Starts the main scheduler loop which performs task scheduling for this
- * domain.
- *
- * Returns once no more tasks can be scheduled and all task ref_counts
- * drop to zero.
- */
-void
-rust_scheduler::start_main_loop() {
- lock.lock();
-
- // Make sure someone is watching, to pull us out of infinite loops.
- //
- // FIXME: time-based interruption is not presently working; worked
- // in rustboot and has been completely broken in rustc.
- //
- // rust_timer timer(this);
-
- DLOG(this, dom, "started domain loop %d", id);
- while (kernel->live_tasks > 0) {
- A(this, kernel->is_deadlocked() == false, "deadlock");
-
- DLOG(this, dom, "worker %d, number_of_live_tasks = %d, total = %d",
- id, number_of_live_tasks(), kernel->live_tasks);
-
- rust_task *scheduled_task = schedule_task(id);
-
- if (scheduled_task == NULL) {
- log_state();
- DLOG(this, task,
- "all tasks are blocked, scheduler id %d yielding ...",
- id);
- lock.timed_wait(10);
- reap_dead_tasks(id);
- DLOG(this, task,
- "scheduler %d resuming ...", id);
- continue;
- }
-
- I(this, scheduled_task->running());
-
- DLOG(this, task,
- "activating task %s 0x%" PRIxPTR
- ", sp=0x%" PRIxPTR
- ", state: %s",
- scheduled_task->name,
- (uintptr_t)scheduled_task,
- scheduled_task->user.rust_sp,
- scheduled_task->state->name);
-
- place_task_in_tls(scheduled_task);
-
- interrupt_flag = 0;
-
- DLOG(this, task,
- "Running task %p on worker %d",
- scheduled_task, id);
- scheduled_task->running_on = id;
- activate(scheduled_task);
- scheduled_task->running_on = -1;
-
- DLOG(this, task,
- "returned from task %s @0x%" PRIxPTR
- " in state '%s', sp=0x%x, worker id=%d" PRIxPTR,
- scheduled_task->name,
- (uintptr_t)scheduled_task,
- scheduled_task->state->name,
- scheduled_task->user.rust_sp,
- id);
-
- reap_dead_tasks(id);
- }
-
- DLOG(this, dom,
- "terminated scheduler loop, reaping dead tasks ...");
-
- while (dead_tasks.length() > 0) {
- DLOG(this, dom,
- "waiting for %d dead tasks to become dereferenced, "
- "scheduler yielding ...",
- dead_tasks.length());
- log_state();
- lock.unlock();
- sync::yield();
- lock.lock();
- reap_dead_tasks(id);
+void
+rust_scheduler::kill_all_tasks() {
+ for(size_t i = 0; i < num_threads; ++i) {
+ rust_task_thread *thread = threads[i];
+ thread->kill_all_tasks();
}
-
- DLOG(this, dom, "finished main-loop %d", id);
-
- lock.unlock();
-}
-
-rust_crate_cache *
-rust_scheduler::get_cache() {
- return &cache;
}
-rust_task *
-rust_scheduler::create_task(rust_task *spawner, const char *name) {
- rust_task *task =
- new (this->kernel, "rust_task")
- rust_task (this, &newborn_tasks, spawner, name);
- DLOG(this, task, "created task: " PTR ", spawner: %s, name: %s",
- task, spawner ? spawner->name : "null", name);
- if(spawner) {
- task->pin(spawner->pinned_on);
- }
-
+rust_task_id
+rust_scheduler::create_task(rust_task *spawner, const char *name,
+ size_t init_stack_sz) {
+ size_t thread_no;
{
- scoped_lock with(lock);
- newborn_tasks.append(task);
+ scoped_lock with(lock);
+ thread_no = isaac_rand(&rctx) % num_threads;
}
-
- sync::increment(kernel->live_tasks);
-
- return task;
-}
-
-void rust_scheduler::run() {
- this->start_main_loop();
-}
-
-#ifndef _WIN32
-void
-rust_scheduler::init_tls() {
- int result = pthread_key_create(&task_key, NULL);
- assert(!result && "Couldn't create the TLS key!");
- tls_initialized = true;
+ rust_task_thread *thread = threads[thread_no];
+ return thread->create_task(spawner, name, init_stack_sz);
}
-void
-rust_scheduler::place_task_in_tls(rust_task *task) {
- int result = pthread_setspecific(task_key, task);
- assert(!result && "Couldn't place the task in TLS!");
- task->record_stack_limit();
-}
-
-rust_task *
-rust_scheduler::get_task() {
- if (!tls_initialized)
- return NULL;
- rust_task *task = reinterpret_cast<rust_task *>
- (pthread_getspecific(task_key));
- assert(task && "Couldn't get the task from TLS!");
- return task;
-}
-#else
-void
-rust_scheduler::init_tls() {
- task_key = TlsAlloc();
- assert(task_key != TLS_OUT_OF_INDEXES && "Couldn't create the TLS key!");
- tls_initialized = true;
+rust_task_id
+rust_scheduler::create_task(rust_task *spawner, const char *name) {
+ return create_task(spawner, name, env->min_stack_size);
}
void
-rust_scheduler::place_task_in_tls(rust_task *task) {
- BOOL result = TlsSetValue(task_key, task);
- assert(result && "Couldn't place the task in TLS!");
- task->record_stack_limit();
+rust_scheduler::exit() {
+ for(size_t i = 0; i < num_threads; ++i) {
+ threads[i]->exit();
+ }
}
-rust_task *
-rust_scheduler::get_task() {
- if (!tls_initialized)
- return NULL;
- rust_task *task = reinterpret_cast<rust_task *>(TlsGetValue(task_key));
- assert(task && "Couldn't get the task from TLS!");
- return task;
+size_t
+rust_scheduler::number_of_threads() {
+ return num_threads;
}
-#endif
-
-//
-// Local Variables:
-// mode: C++
-// fill-column: 70;
-// indent-tabs-mode: nil
-// c-basic-offset: 4
-// buffer-file-coding-system: utf-8-unix
-// End:
-//
#ifndef RUST_SCHEDULER_H
#define RUST_SCHEDULER_H
-#include "context.h"
+#include "rust_internal.h"
-#ifndef _WIN32
-#include <pthread.h>
-#else
-#include <windows.h>
-#endif
-
-struct rust_scheduler;
-
-struct rust_hashable_dict {
- UT_hash_handle hh;
- void* fields[0];
-};
-
-class rust_crate_cache {
+class rust_scheduler : public kernel_owned<rust_scheduler> {
+ // FIXME: Make these private
public:
- type_desc *get_type_desc(size_t size,
- size_t align,
- size_t n_descs,
- type_desc const **descs,
- uintptr_t n_obj_params);
- void** get_dict(size_t n_fields, void** dict);
-
-private:
-
- type_desc *type_descs;
- rust_hashable_dict *dicts;
-
-public:
-
- rust_scheduler *sched;
- size_t idx;
-
- rust_crate_cache(rust_scheduler *sched);
- ~rust_crate_cache();
- void flush();
-};
-
-struct rust_scheduler : public kernel_owned<rust_scheduler>,
- rust_thread
-{
- RUST_REFCOUNTED(rust_scheduler)
-
- // Fields known to the compiler:
- uintptr_t interrupt_flag;
-
- // Fields known only by the runtime:
- rust_log _log;
-
- // NB: this is used to filter *runtime-originating* debug
- // logging, on a per-scheduler basis. It's not likely what
- // you want to expose to the user in terms of per-task
- // or per-module logging control. By default all schedulers
- // are set to debug-level logging here, and filtered by
- // runtime category using the pseudo-modules ::rt::foo.
- uint32_t log_lvl;
-
- rust_srv *srv;
- const char *const name;
-
- rust_task_list newborn_tasks;
- rust_task_list running_tasks;
- rust_task_list blocked_tasks;
- rust_task_list dead_tasks;
-
- rust_crate_cache cache;
-
- randctx rctx;
-
rust_kernel *kernel;
- int32_t list_index;
-
- const int id;
-
+ rust_srv *srv;
+ rust_env *env;
+private:
lock_and_signal lock;
- size_t min_stack_size;
-
-#ifndef __WIN32__
- pthread_attr_t attr;
- static pthread_key_t task_key;
-#else
- static DWORD task_key;
-#endif
+ array_list<rust_task_thread *> threads;
+ randctx rctx;
+ const size_t num_threads;
+ int rval;
- static bool tls_initialized;
+ void create_task_threads();
+ void destroy_task_threads();
- rust_env *env;
- context c_context;
+ rust_task_thread *create_task_thread(int id);
+ void destroy_task_thread(rust_task_thread *thread);
- // Only a pointer to 'name' is kept, so it must live as long as this
- // domain.
- rust_scheduler(rust_kernel *kernel, rust_srv *srv, int id);
+public:
+ rust_scheduler(rust_kernel *kernel, rust_srv *srv, size_t num_threads);
~rust_scheduler();
- void activate(rust_task *task);
- void log(rust_task *task, uint32_t level, char const *fmt, ...);
- rust_log & get_log();
- void fail();
-
- rust_crate_cache *get_cache();
- size_t number_of_live_tasks();
-
- void reap_dead_tasks(int id);
- rust_task *schedule_task(int id);
-
- void start_main_loop();
-
- void log_state();
+ void start_task_threads();
void kill_all_tasks();
-
- rust_task *create_task(rust_task *spawner, const char *name);
-
- virtual void run();
-
-#ifdef __WIN32__
- inline void win32_require(LPCTSTR fn, BOOL ok) {
- kernel->win32_require(fn, ok);
- }
-#endif
-
- void init_tls();
- void place_task_in_tls(rust_task *task);
-
- static rust_task *get_task();
+ rust_task_id create_task(rust_task *spawner,
+ const char *name,
+ size_t init_stack_sz);
+ rust_task_id create_task(rust_task *spawner, const char *name);
+ void exit();
+ size_t number_of_threads();
};
-inline rust_log &
-rust_scheduler::get_log() {
- return _log;
-}
-
-//
-// Local Variables:
-// mode: C++
-// fill-column: 78;
-// indent-tabs-mode: nil
-// c-basic-offset: 4
-// buffer-file-coding-system: utf-8-unix
-// compile-command: "make -k -C $RBUILD 2>&1 | sed -e 's/\\/x\\//x:\\//g'";
-// End:
-//
-
#endif /* RUST_SCHEDULER_H */
result = sub.result;
}
- inline void walk_box_contents2(cmp &sub, ptr_pair &ref_count_dp) {
+ inline void walk_box_contents2(cmp &sub, ptr_pair &box_dp) {
sub.align = true;
sub.walk();
result = sub.result;
shape_cmp_type(int8_t *result, const type_desc *tydesc,
const type_desc **subtydescs, uint8_t *data_0,
uint8_t *data_1, uint8_t cmp_type) {
- rust_task *task = rust_scheduler::get_task();
+ rust_task *task = rust_task_thread::get_task();
shape::arena arena;
// FIXME: This may well be broken when comparing two closures or objects
extern "C" rust_str *
shape_log_str(const type_desc *tydesc, uint8_t *data) {
- rust_task *task = rust_scheduler::get_task();
+ rust_task *task = rust_task_thread::get_task();
shape::arena arena;
shape::type_param *params =
extern "C" void
shape_log_type(const type_desc *tydesc, uint8_t *data, uint32_t level) {
- rust_task *task = rust_scheduler::get_task();
+ rust_task *task = rust_task_thread::get_task();
shape::arena arena;
shape::type_param *params =
log.walk();
- task->sched->log(task, level, "%s", ss.str().c_str());
+ task->thread->log(task, level, "%s", ss.str().c_str());
}
typedef unsigned long tag_variant_t;
typedef unsigned long tag_align_t;
-typedef unsigned long ref_cnt_t;
// Constants
case SHAPE_TAG: walk_tag0(); break;
case SHAPE_BOX: walk_box0(); break;
case SHAPE_STRUCT: walk_struct0(); break;
- case SHAPE_OBJ: WALK_SIMPLE(walk_obj1); break;
case SHAPE_RES: walk_res0(); break;
case SHAPE_VAR: walk_var0(); break;
case SHAPE_UNIQ: walk_uniq0(); break;
default: abort();
}
}
- void walk_obj1() { DPRINT("obj"); }
void walk_iface1() { DPRINT("iface"); }
void walk_tydesc1(char kind) {
void walk_uniq1() { sa.set(sizeof(void *), sizeof(void *)); }
void walk_box1() { sa.set(sizeof(void *), sizeof(void *)); }
void walk_fn1(char) { sa.set(sizeof(void *)*2, sizeof(void *)); }
- void walk_obj1() { sa.set(sizeof(void *)*2, sizeof(void *)); }
void walk_iface1() { sa.set(sizeof(void *), sizeof(void *)); }
void walk_tydesc1(char) { sa.set(sizeof(void *), sizeof(void *)); }
void walk_closure1();
void walk_box_contents1();
void walk_uniq_contents1();
- void walk_fn_contents1(ptr &dp, bool null_td);
- void walk_obj_contents1(ptr &dp);
- void walk_iface_contents1(ptr &dp);
+ void walk_fn_contents1();
+ void walk_iface_contents1();
void walk_variant1(tag_info &tinfo, tag_variant_t variant);
static std::pair<uint8_t *,uint8_t *> get_vec_data_range(ptr dp);
dp = next_dp;
}
- void walk_obj1() {
- ALIGN_TO(alignof<void *>());
- U next_dp = dp + sizeof(void *) * 2;
- static_cast<T *>(this)->walk_obj2();
- dp = next_dp;
- }
-
void walk_iface1() {
ALIGN_TO(alignof<void *>());
U next_dp = dp + sizeof(void *);
void
data<T,U>::walk_box_contents1() {
typename U::template data<uint8_t *>::t box_ptr = bump_dp<uint8_t *>(dp);
- U ref_count_dp(box_ptr);
- T sub(*static_cast<T *>(this), ref_count_dp + sizeof(ref_cnt_t));
- static_cast<T *>(this)->walk_box_contents2(sub, ref_count_dp);
+ U box_dp(box_ptr);
+
+ // No need to worry about alignment so long as the box header is
+ // a multiple of 16 bytes. We can just find the body by adding
+ // the size of header to box_dp.
+ assert ((sizeof(rust_opaque_box) % 16) == 0 ||
+ !"Must align to find the box body");
+
+ U body_dp = box_dp + sizeof(rust_opaque_box);
+ T sub(*static_cast<T *>(this), body_dp);
+ static_cast<T *>(this)->walk_box_contents2(sub, box_dp);
}
template<typename T,typename U>
template<typename T,typename U>
void
-data<T,U>::walk_fn_contents1(ptr &dp, bool null_td) {
+data<T,U>::walk_fn_contents1() {
fn_env_pair pair = bump_dp<fn_env_pair>(dp);
if (!pair.env)
return;
arena arena;
const type_desc *closure_td = pair.env->td;
- type_param *params =
- type_param::from_tydesc(closure_td, arena);
- ptr closure_dp((uintptr_t)pair.env);
+ type_param *params = type_param::from_tydesc(closure_td, arena);
+ ptr closure_dp((uintptr_t)box_body(pair.env));
T sub(*static_cast<T *>(this), closure_td->shape, params,
closure_td->shape_tables, closure_dp);
sub.align = true;
- if (null_td) {
- // if null_td flag is true, null out the type descr from
- // the data structure while we walk. This is used in cycle
- // collector when we are sweeping up data. The idea is that
- // we are using the information in the embedded type desc to
- // walk the contents, so we do not want to free it during that
- // walk. This is not *strictly* necessary today because
- // type_param::from_tydesc() actually pulls out the "shape"
- // string and other information and copies it into a new
- // location that is unaffected by the free. But it seems
- // safer, particularly as this pulling out of information will
- // not cope with nested, derived type descriptors.
- pair.env->td = NULL;
- }
-
- sub.walk();
-
- if (null_td) {
- pair.env->td = closure_td;
- }
-}
-
-template<typename T,typename U>
-void
-data<T,U>::walk_obj_contents1(ptr &dp) {
- dp += sizeof(void *); // Skip over the vtable.
-
- uint8_t *box_ptr = bump_dp<uint8_t *>(dp);
- type_desc *subtydesc =
- *reinterpret_cast<type_desc **>(box_ptr + sizeof(void *));
- ptr obj_closure_dp(box_ptr + sizeof(void *));
- if (!box_ptr) // Null check.
- return;
-
- arena arena;
- type_param *params = type_param::from_obj_shape(subtydesc->shape,
- obj_closure_dp, arena);
- T sub(*static_cast<T *>(this), subtydesc->shape, params,
- subtydesc->shape_tables, obj_closure_dp);
- sub.align = true;
sub.walk();
}
template<typename T,typename U>
void
-data<T,U>::walk_iface_contents1(ptr &dp) {
- uint8_t *box_ptr = bump_dp<uint8_t *>(dp);
- if (!box_ptr) return;
- U ref_count_dp(box_ptr);
- uint8_t *body_ptr = box_ptr + sizeof(void*);
- type_desc *valtydesc =
- *reinterpret_cast<type_desc **>(body_ptr);
- ptr value_dp(body_ptr + sizeof(void*) * 2);
- // FIXME The 5 is a hard-coded way to skip over a struct shape
- // header and the first two (number-typed) fields. This is too
- // fragile, but I didn't see a good way to properly encode it.
- T sub(*static_cast<T *>(this), valtydesc->shape + 5, NULL, NULL,
- value_dp);
- sub.align = true;
- static_cast<T *>(this)->walk_box_contents2(sub, ref_count_dp);
+data<T,U>::walk_iface_contents1() {
+ walk_box_contents1();
}
// Polymorphic logging, for convenience
void walk_fn2(char kind) {
out << prefix << "fn";
prefix = "";
- data<log,ptr>::walk_fn_contents1(dp, false);
- }
-
- void walk_obj2() {
- out << prefix << "obj";
- prefix = "";
- data<log,ptr>::walk_obj_contents1(dp);
+ data<log,ptr>::walk_fn_contents1();
}
void walk_iface2() {
out << prefix << "iface(";
prefix = "";
- data<log,ptr>::walk_iface_contents1(dp);
+ data<log,ptr>::walk_iface_contents1();
out << prefix << ")";
}
void
rust_srv::log(char const *msg) {
- printf("rust: %s\n", msg);
- // FIXME: flushing each time is expensive, but at the moment
- // necessary to get output through before a rust_task::fail
- // call. This should be changed.
- fflush(stdout);
+ fprintf(stderr, "rust: %s\n", msg);
}
void
#include <algorithm>
#include "globals.h"
+#include "rust_upcall.h"
// The amount of extra space at the end of each stack segment, available
// to the rt, compiler and dynamic linker for running small functions
0xAB, 0xCD, 0xAB, 0xCD,
0xAB, 0xCD, 0xAB, 0xCD};
-// Stack size
-size_t g_custom_min_stack_size = 0;
-
static size_t
-get_min_stk_size(size_t default_size) {
- if (g_custom_min_stack_size != 0) {
- return g_custom_min_stack_size;
- } else {
- return default_size;
- }
-}
-
-static size_t
-get_next_stk_size(rust_scheduler *sched, rust_task *task,
+get_next_stk_size(rust_task_thread *thread, rust_task *task,
size_t min, size_t current, size_t requested) {
LOG(task, mem, "calculating new stack size for 0x%" PRIxPTR, task);
LOG(task, mem,
sz = std::max(sz, next);
LOG(task, mem, "next stack size: %" PRIdPTR, sz);
- I(sched, requested <= sz);
+ I(thread, requested <= sz);
return sz;
}
static void
free_stk(rust_task *task, stk_seg *stk) {
- LOGPTR(task->sched, "freeing stk segment", (uintptr_t)stk);
+ LOGPTR(task->thread, "freeing stk segment", (uintptr_t)stk);
task->total_stack_sz -= user_stack_size(stk);
task->free(stk);
}
static stk_seg*
-new_stk(rust_scheduler *sched, rust_task *task, size_t requested_sz)
+new_stk(rust_task_thread *thread, rust_task *task, size_t requested_sz)
{
LOG(task, mem, "creating new stack for task %" PRIxPTR, task);
if (task->stk) {
}
// The minimum stack size, in bytes, of a Rust stack, excluding red zone
- size_t min_sz = get_min_stk_size(sched->min_stack_size);
+ size_t min_sz = thread->min_stack_size;
// Try to reuse an existing stack segment
if (task->stk != NULL && task->stk->prev != NULL) {
if (min_sz <= prev_sz && requested_sz <= prev_sz) {
LOG(task, mem, "reusing existing stack");
task->stk = task->stk->prev;
- A(sched, task->stk->prev == NULL, "Bogus stack ptr");
+ A(thread, task->stk->prev == NULL, "Bogus stack ptr");
config_valgrind_stack(task->stk);
return task->stk;
} else {
current_sz = user_stack_size(task->stk);
}
// The calculated size of the new stack, excluding red zone
- size_t rust_stk_sz = get_next_stk_size(sched, task, min_sz,
+ size_t rust_stk_sz = get_next_stk_size(thread, task, min_sz,
current_sz, requested_sz);
- if (task->total_stack_sz + rust_stk_sz > sched->env->max_stack_size) {
+ if (task->total_stack_sz + rust_stk_sz > thread->env->max_stack_size) {
LOG_ERR(task, task, "task %" PRIxPTR " ran out of stack", task);
task->fail();
}
size_t sz = sizeof(stk_seg) + rust_stk_sz + RED_ZONE_SIZE;
stk_seg *stk = (stk_seg *)task->malloc(sz, "stack");
- LOGPTR(task->sched, "new stk", (uintptr_t)stk);
+ LOGPTR(task->thread, "new stk", (uintptr_t)stk);
memset(stk, 0, sizeof(stk_seg));
add_stack_canary(stk);
stk->prev = NULL;
stk->next = task->stk;
stk->end = (uintptr_t) &stk->data[rust_stk_sz + RED_ZONE_SIZE];
- LOGPTR(task->sched, "stk end", stk->end);
+ LOGPTR(task->thread, "stk end", stk->end);
task->stk = stk;
config_valgrind_stack(task->stk);
unconfig_valgrind_stack(stk);
if (delete_stack) {
free_stk(task, stk);
- A(task->sched, task->total_stack_sz == 0, "Stack size should be 0");
+ A(task->thread, task->total_stack_sz == 0, "Stack size should be 0");
}
}
// Tasks
-rust_task::rust_task(rust_scheduler *sched, rust_task_list *state,
- rust_task *spawner, const char *name) :
+rust_task::rust_task(rust_task_thread *thread, rust_task_list *state,
+ rust_task *spawner, const char *name,
+ size_t init_stack_sz) :
ref_count(1),
stk(NULL),
runtime_sp(0),
- sched(sched),
+ sched(thread->sched),
+ thread(thread),
cache(NULL),
- kernel(sched->kernel),
+ kernel(thread->kernel),
name(name),
state(state),
cond(NULL),
list_index(-1),
next_port_id(0),
rendezvous_ptr(0),
- running_on(-1),
- pinned_on(-1),
- local_region(&sched->srv->local_region),
+ local_region(&thread->srv->local_region),
+ boxed(&local_region),
unwinding(false),
killed(false),
propagate_failure(true),
cc_counter(0),
total_stack_sz(0)
{
- LOGPTR(sched, "new task", (uintptr_t)this);
- DLOG(sched, task, "sizeof(task) = %d (0x%x)", sizeof *this, sizeof *this);
+ LOGPTR(thread, "new task", (uintptr_t)this);
+ DLOG(thread, task, "sizeof(task) = %d (0x%x)", sizeof *this, sizeof *this);
assert((void*)this == (void*)&user);
user.notify_enabled = 0;
- stk = new_stk(sched, this, 0);
+ stk = new_stk(thread, this, init_stack_sz);
user.rust_sp = stk->end;
if (supervisor) {
supervisor->ref();
rust_task::~rust_task()
{
- I(sched, !sched->lock.lock_held_by_current_thread());
- I(sched, port_table.is_empty());
- DLOG(sched, task, "~rust_task %s @0x%" PRIxPTR ", refcnt=%d",
+ I(thread, !thread->lock.lock_held_by_current_thread());
+ I(thread, port_table.is_empty());
+ DLOG(thread, task, "~rust_task %s @0x%" PRIxPTR ", refcnt=%d",
name, (uintptr_t)this, ref_count);
+ // FIXME: We should do this when the task exits, not in the destructor
if (supervisor) {
supervisor->deref();
}
- kernel->release_task_id(user.id);
-
/* FIXME: tighten this up, there are some more
assertions that hold at task-lifecycle events. */
- I(sched, ref_count == 0); // ||
+ I(thread, ref_count == 0); // ||
// (ref_count == 1 && this == sched->root_task));
// Delete all the stacks. There may be more than one if the task failed
// and no landing pads stopped to clean up.
+ // FIXME: We should do this when the task exits, not in the destructor
while (stk != NULL) {
del_stk(this, stk);
}
struct spawn_args {
rust_task *task;
spawn_fn f;
- rust_opaque_closure *envptr;
+ rust_opaque_box *envptr;
void *argptr;
};
#ifndef __WIN32__
task->conclude_failure();
#else
- A(task->sched, false, "Shouldn't happen");
+ A(task->thread, false, "Shouldn't happen");
#endif
}
}
-extern "C" void upcall_shared_free(void* ptr);
-
// This runs on the Rust stack
extern "C" CDECL
void task_start_wrapper(spawn_args *a)
// must have void return type, we can safely pass 0.
a->f(0, a->envptr, a->argptr);
} catch (rust_task *ex) {
- A(task->sched, ex == task,
+ A(task->thread, ex == task,
"Expected this task to be thrown for unwinding");
threw_exception = true;
}
- rust_opaque_closure* env = a->envptr;
+ rust_opaque_box* env = a->envptr;
if(env) {
- // free the environment.
+ // free the environment (which should be a unique closure).
const type_desc *td = env->td;
LOG(task, task, "Freeing env %p with td %p", env, td);
- td->drop_glue(NULL, NULL, td->first_param, env);
+ td->drop_glue(NULL, NULL, td->first_param, box_body(env));
+ upcall_free_shared_type_desc(env->td);
upcall_shared_free(env);
}
// The cleanup work needs lots of stack
cleanup_args ca = {a, threw_exception};
- task->sched->c_context.call_shim_on_c_stack(&ca, (void*)cleanup_task);
+ task->thread->c_context.call_shim_on_c_stack(&ca, (void*)cleanup_task);
task->ctx.next->swap(task->ctx);
}
void
rust_task::start(spawn_fn spawnee_fn,
- rust_opaque_closure *envptr,
+ rust_opaque_box *envptr,
void *argptr)
{
LOG(this, task, "starting task from fn 0x%" PRIxPTR
" with env 0x%" PRIxPTR " and arg 0x%" PRIxPTR,
spawnee_fn, envptr, argptr);
- I(sched, stk->data != NULL);
+ I(thread, stk->data != NULL);
char *sp = (char *)user.rust_sp;
void rust_task::start()
{
- yield_timer.reset_us(0);
- transition(&sched->newborn_tasks, &sched->running_tasks);
- sched->lock.signal();
+ transition(&thread->newborn_tasks, &thread->running_tasks);
}
// Only run this on the rust stack
void
-rust_task::yield(size_t time_in_us, bool *killed) {
+rust_task::yield(bool *killed) {
if (this->killed) {
*killed = true;
}
- yield_timer.reset_us(time_in_us);
-
// Return to the scheduler.
ctx.next->swap(ctx);
// Unblock the task so it can unwind.
unblock();
- sched->lock.signal();
-
LOG(this, task, "preparing to unwind task: 0x%" PRIxPTR, this);
// run_on_resume(rust_unwind_glue);
}
void
rust_task::fail() {
// See note in ::kill() regarding who should call this.
- DLOG(sched, task, "task %s @0x%" PRIxPTR " failing", name, this);
+ DLOG(thread, task, "task %s @0x%" PRIxPTR " failing", name, this);
backtrace();
unwinding = true;
#ifndef __WIN32__
die();
conclude_failure();
// FIXME: Need unwinding on windows. This will end up aborting
- sched->fail();
+ thread->fail();
#endif
}
void
rust_task::fail_parent() {
if (supervisor) {
- DLOG(sched, task,
+ DLOG(thread, task,
"task %s @0x%" PRIxPTR
" propagating failure to supervisor %s @0x%" PRIxPTR,
name, this, supervisor->name, supervisor);
}
// FIXME: implement unwinding again.
if (NULL == supervisor && propagate_failure)
- sched->fail();
+ thread->fail();
}
void
rust_task::unsupervise()
{
- DLOG(sched, task,
+ if (supervisor) {
+ DLOG(thread, task,
"task %s @0x%" PRIxPTR
" disconnecting from supervisor %s @0x%" PRIxPTR,
name, this, supervisor->name, supervisor);
- if (supervisor) {
supervisor->deref();
}
supervisor = NULL;
bool
rust_task::running()
{
- return state == &sched->running_tasks;
+ return state == &thread->running_tasks;
}
bool
rust_task::blocked()
{
- return state == &sched->blocked_tasks;
+ return state == &thread->blocked_tasks;
}
bool
bool
rust_task::dead()
{
- return state == &sched->dead_tasks;
+ return state == &thread->dead_tasks;
}
void *
}
void *
-rust_task::realloc(void *data, size_t sz, bool is_gc)
+rust_task::realloc(void *data, size_t sz)
{
return local_region.realloc(data, sz);
}
void
-rust_task::free(void *p, bool is_gc)
+rust_task::free(void *p)
{
local_region.free(p);
}
void
rust_task::transition(rust_task_list *src, rust_task_list *dst) {
bool unlock = false;
- if(!sched->lock.lock_held_by_current_thread()) {
+ if(!thread->lock.lock_held_by_current_thread()) {
unlock = true;
- sched->lock.lock();
+ thread->lock.lock();
}
- DLOG(sched, task,
+ DLOG(thread, task,
"task %s " PTR " state change '%s' -> '%s' while in '%s'",
name, (uintptr_t)this, src->name, dst->name, state->name);
- I(sched, state == src);
+ I(thread, state == src);
src->remove(this);
dst->append(this);
state = dst;
+ thread->lock.signal();
if(unlock)
- sched->lock.unlock();
+ thread->lock.unlock();
}
void
rust_task::block(rust_cond *on, const char* name) {
- I(sched, !lock.lock_held_by_current_thread());
+ I(thread, !lock.lock_held_by_current_thread());
scoped_lock with(lock);
LOG(this, task, "Blocking on 0x%" PRIxPTR ", cond: 0x%" PRIxPTR,
(uintptr_t) on, (uintptr_t) cond);
- A(sched, cond == NULL, "Cannot block an already blocked task.");
- A(sched, on != NULL, "Cannot block on a NULL object.");
+ A(thread, cond == NULL, "Cannot block an already blocked task.");
+ A(thread, on != NULL, "Cannot block on a NULL object.");
- transition(&sched->running_tasks, &sched->blocked_tasks);
+ transition(&thread->running_tasks, &thread->blocked_tasks);
cond = on;
cond_name = name;
}
void
rust_task::wakeup(rust_cond *from) {
- I(sched, !lock.lock_held_by_current_thread());
+ I(thread, !lock.lock_held_by_current_thread());
scoped_lock with(lock);
- A(sched, cond != NULL, "Cannot wake up unblocked task.");
+ A(thread, cond != NULL, "Cannot wake up unblocked task.");
LOG(this, task, "Blocked on 0x%" PRIxPTR " woken up on 0x%" PRIxPTR,
(uintptr_t) cond, (uintptr_t) from);
- A(sched, cond == from, "Cannot wake up blocked task on wrong condition.");
+ A(thread, cond == from, "Cannot wake up blocked task on wrong condition.");
- transition(&sched->blocked_tasks, &sched->running_tasks);
- I(sched, cond == from);
cond = NULL;
cond_name = "none";
-
- sched->lock.signal();
+ transition(&thread->blocked_tasks, &thread->running_tasks);
}
void
rust_task::die() {
- I(sched, !lock.lock_held_by_current_thread());
+ I(thread, !lock.lock_held_by_current_thread());
scoped_lock with(lock);
- transition(&sched->running_tasks, &sched->dead_tasks);
- sched->lock.signal();
+ transition(&thread->running_tasks, &thread->dead_tasks);
}
void
rust_task::get_crate_cache()
{
if (!cache) {
- DLOG(sched, task, "fetching cache for current crate");
- cache = sched->get_cache();
+ DLOG(thread, task, "fetching cache for current crate");
+ cache = thread->get_cache();
}
return cache;
}
#endif
}
-bool rust_task::can_schedule(int id)
-{
- return yield_timer.has_timed_out() &&
- running_on == -1 &&
- (pinned_on == -1 || pinned_on == id);
-}
-
void *
rust_task::calloc(size_t size, const char *tag) {
return local_region.calloc(size, tag);
}
-void rust_task::pin() {
- I(this->sched, running_on != -1);
- pinned_on = running_on;
-}
-
-void rust_task::pin(int id) {
- I(this->sched, running_on == -1);
- pinned_on = id;
-}
-
-void rust_task::unpin() {
- pinned_on = -1;
-}
-
rust_port_id rust_task::register_port(rust_port *port) {
- I(sched, !lock.lock_held_by_current_thread());
+ I(thread, !lock.lock_held_by_current_thread());
scoped_lock with(lock);
rust_port_id id = next_port_id++;
+ A(thread, id != INTPTR_MAX, "Hit the maximum port id");
port_table.put(id, port);
return id;
}
void rust_task::release_port(rust_port_id id) {
- I(sched, lock.lock_held_by_current_thread());
+ I(thread, lock.lock_held_by_current_thread());
port_table.remove(id);
}
rust_port *rust_task::get_port_by_id(rust_port_id id) {
- I(sched, !lock.lock_held_by_current_thread());
+ I(thread, !lock.lock_held_by_current_thread());
scoped_lock with(lock);
rust_port *port = NULL;
port_table.get(id, &port);
return port;
}
-
-// Temporary routine to allow boxes on one task's shared heap to be reparented
-// to another.
-const type_desc *
-rust_task::release_alloc(void *alloc) {
- I(sched, !lock.lock_held_by_current_thread());
- lock.lock();
-
- assert(local_allocs.find(alloc) != local_allocs.end());
- const type_desc *tydesc = local_allocs[alloc];
- local_allocs.erase(alloc);
-
- local_region.release_alloc(alloc);
-
- lock.unlock();
- return tydesc;
-}
-
-// Temporary routine to allow boxes from one task's shared heap to be
-// reparented to this one.
-void
-rust_task::claim_alloc(void *alloc, const type_desc *tydesc) {
- I(sched, !lock.lock_held_by_current_thread());
- lock.lock();
-
- assert(local_allocs.find(alloc) == local_allocs.end());
- local_allocs[alloc] = tydesc;
- local_region.claim_alloc(alloc);
-
- lock.unlock();
-}
-
void
rust_task::notify(bool success) {
// FIXME (1078) Do this in rust code
void *
rust_task::new_stack(size_t stk_sz, void *args_addr, size_t args_sz) {
- stk_seg *stk_seg = new_stk(sched, this, stk_sz + args_sz);
- A(sched, stk_seg->end - (uintptr_t)stk_seg->data >= stk_sz + args_sz,
+ stk_seg *stk_seg = new_stk(thread, this, stk_sz + args_sz);
+ A(thread, stk_seg->end - (uintptr_t)stk_seg->data >= stk_sz + args_sz,
"Did not receive enough stack");
uint8_t *new_sp = (uint8_t*)stk_seg->end;
// Push the function arguments to the new stack
// subtracting the frame size. As a result we need our stack limit to
// account for those 256 bytes.
const unsigned LIMIT_OFFSET = 256;
- A(sched,
+ A(thread,
(uintptr_t)stk->end - RED_ZONE_SIZE
- (uintptr_t)stk->data >= LIMIT_OFFSET,
"Stack size must be greater than LIMIT_OFFSET");
uintptr_t sp = get_sp();
while (!sp_in_stk_seg(sp, stk)) {
del_stk(this, stk);
- A(sched, stk != NULL, "Failed to find the current stack");
+ A(thread, stk != NULL, "Failed to find the current stack");
}
record_stack_limit();
}
#include "rust_internal.h"
#include "rust_kernel.h"
#include "rust_obstack.h"
+#include "boxed_region.h"
// Corresponds to the rust chan (currently _chan) type.
struct chan_handle {
RUST_ATOMIC_REFCOUNT();
- // Fields known to the compiler.
context ctx;
stk_seg *stk;
uintptr_t runtime_sp; // Runtime sp while task running.
rust_scheduler *sched;
+ rust_task_thread *thread;
rust_crate_cache *cache;
// Fields known only to the runtime.
rust_port_id next_port_id;
- // Keeps track of the last time this task yielded.
- timer yield_timer;
-
// Rendezvous pointer for receiving data when blocked on a port. If we're
// trying to read data and no data is available on any incoming channel,
// we block on the port, and yield control to the scheduler. Since, we
// that location before waking us up.
uintptr_t* rendezvous_ptr;
- // This flag indicates that a worker is either currently running the task
- // or is about to run this task.
- int running_on;
- int pinned_on;
-
memory_region local_region;
+ boxed_region boxed;
// Indicates that fail() has been called and we are cleaning up.
// We use this to suppress the "killed" flag during calls to yield.
rust_obstack dynastack;
- std::map<void *,const type_desc *> local_allocs;
uint32_t cc_counter;
debug::task_debug_info debug;
size_t total_stack_sz;
// Only a pointer to 'name' is kept, so it must live as long as this task.
- rust_task(rust_scheduler *sched,
+ rust_task(rust_task_thread *thread,
rust_task_list *state,
rust_task *spawner,
- const char *name);
+ const char *name,
+ size_t init_stack_sz);
~rust_task();
void start(spawn_fn spawnee_fn,
- rust_opaque_closure *env,
+ rust_opaque_box *env,
void *args);
void start();
bool running();
bool dead();
void *malloc(size_t sz, const char *tag, type_desc *td=0);
- void *realloc(void *data, size_t sz, bool gc_mem=false);
- void free(void *p, bool gc_mem=false);
+ void *realloc(void *data, size_t sz);
+ void free(void *p);
void transition(rust_task_list *src, rust_task_list *dst);
// Print a backtrace, if the "bt" logging option is on.
void backtrace();
- // Yields for a specified duration of time.
- void yield(size_t time_in_ms, bool *killed);
+ // Yields control to the scheduler. Called from the Rust stack
+ void yield(bool *killed);
// Fail this task (assuming caller-on-stack is different task).
void kill();
frame_glue_fns *get_frame_glue_fns(uintptr_t fp);
rust_crate_cache * get_crate_cache();
- bool can_schedule(int worker);
-
void *calloc(size_t size, const char *tag);
- void pin();
- void pin(int id);
- void unpin();
-
rust_port_id register_port(rust_port *port);
void release_port(rust_port_id id);
rust_port *get_port_by_id(rust_port_id id);
// not at all safe.
intptr_t get_ref_count() const { return ref_count; }
- // FIXME: These functions only exist to get the tasking system off the
- // ground. We should never be migrating shared boxes between tasks.
- const type_desc *release_alloc(void *alloc);
- void claim_alloc(void *alloc, const type_desc *tydesc);
-
void notify(bool success);
void *new_stack(size_t stk_sz, void *args_addr, size_t args_sz);
#include "rust_internal.h"
-rust_task_list::rust_task_list (rust_scheduler *sched, const char* name) :
- sched(sched), name(name) {
+rust_task_list::rust_task_list (rust_task_thread *thread, const char* name) :
+ thread(thread), name(name) {
}
void
rust_task_list::delete_all() {
- DLOG(sched, task, "deleting all %s tasks", name);
+ DLOG(thread, task, "deleting all %s tasks", name);
while (is_empty() == false) {
rust_task *task = pop_value();
- DLOG(sched, task, "deleting task " PTR, task);
+ DLOG(thread, task, "deleting task " PTR, task);
delete task;
}
}
class rust_task_list : public indexed_list<rust_task>,
public kernel_owned<rust_task_list> {
public:
- rust_scheduler *sched;
+ rust_task_thread *thread;
const char* name;
- rust_task_list (rust_scheduler *sched, const char* name);
+ rust_task_list (rust_task_thread *thread, const char* name);
void delete_all();
};
--- /dev/null
+
+#include <stdarg.h>
+#include <cassert>
+#include <pthread.h>
+#include "rust_internal.h"
+#include "rust_util.h"
+#include "globals.h"
+#include "rust_scheduler.h"
+
+#ifndef _WIN32
+pthread_key_t rust_task_thread::task_key;
+#else
+DWORD rust_task_thread::task_key;
+#endif
+
+bool rust_task_thread::tls_initialized = false;
+
+rust_task_thread::rust_task_thread(rust_scheduler *sched,
+ rust_srv *srv,
+ int id) :
+ ref_count(1),
+ _log(srv, this),
+ log_lvl(log_debug),
+ srv(srv),
+ // TODO: calculate a per scheduler name.
+ name("main"),
+ newborn_tasks(this, "newborn"),
+ running_tasks(this, "running"),
+ blocked_tasks(this, "blocked"),
+ dead_tasks(this, "dead"),
+ cache(this),
+ kernel(sched->kernel),
+ sched(sched),
+ id(id),
+ min_stack_size(kernel->env->min_stack_size),
+ env(kernel->env),
+ should_exit(false)
+{
+ LOGPTR(this, "new dom", (uintptr_t)this);
+ isaac_init(kernel, &rctx);
+#ifndef __WIN32__
+ pthread_attr_init(&attr);
+ pthread_attr_setstacksize(&attr, 1024 * 1024);
+ pthread_attr_setdetachstate(&attr, true);
+#endif
+
+ if (!tls_initialized)
+ init_tls();
+}
+
+rust_task_thread::~rust_task_thread() {
+ DLOG(this, dom, "~rust_task_thread %s @0x%" PRIxPTR, name, (uintptr_t)this);
+
+ newborn_tasks.delete_all();
+ running_tasks.delete_all();
+ blocked_tasks.delete_all();
+ dead_tasks.delete_all();
+#ifndef __WIN32__
+ pthread_attr_destroy(&attr);
+#endif
+}
+
+void
+rust_task_thread::activate(rust_task *task) {
+ task->ctx.next = &c_context;
+ DLOG(this, task, "descheduling...");
+ lock.unlock();
+ task->ctx.swap(c_context);
+ lock.lock();
+ DLOG(this, task, "task has returned");
+}
+
+void
+rust_task_thread::log(rust_task* task, uint32_t level, char const *fmt, ...) {
+ char buf[BUF_BYTES];
+ va_list args;
+ va_start(args, fmt);
+ vsnprintf(buf, sizeof(buf), fmt, args);
+ _log.trace_ln(task, level, buf);
+ va_end(args);
+}
+
+void
+rust_task_thread::fail() {
+ log(NULL, log_err, "domain %s @0x%" PRIxPTR " root task failed",
+ name, this);
+ kernel->fail();
+}
+
+void
+rust_task_thread::kill_all_tasks() {
+ I(this, !lock.lock_held_by_current_thread());
+ scoped_lock with(lock);
+
+ for (size_t i = 0; i < running_tasks.length(); i++) {
+ // We don't want the failure of these tasks to propagate back
+ // to the kernel again since we're already failing everything
+ running_tasks[i]->unsupervise();
+ running_tasks[i]->kill();
+ }
+
+ for (size_t i = 0; i < blocked_tasks.length(); i++) {
+ blocked_tasks[i]->unsupervise();
+ blocked_tasks[i]->kill();
+ }
+}
+
+size_t
+rust_task_thread::number_of_live_tasks() {
+ return running_tasks.length() + blocked_tasks.length();
+}
+
+/**
+ * Delete any dead tasks.
+ */
+void
+rust_task_thread::reap_dead_tasks() {
+ I(this, lock.lock_held_by_current_thread());
+ if (dead_tasks.length() == 0) {
+ return;
+ }
+
+ // First make a copy of the dead_task list with the lock held
+ size_t dead_tasks_len = dead_tasks.length();
+ rust_task **dead_tasks_copy = (rust_task**)
+ srv->malloc(sizeof(rust_task*) * dead_tasks_len);
+ for (size_t i = 0; i < dead_tasks_len; ++i) {
+ dead_tasks_copy[i] = dead_tasks.pop_value();
+ }
+
+ // Now unlock again because we have to actually free the dead tasks,
+ // and that may end up wanting to lock the kernel lock. We have
+ // a kernel lock -> scheduler lock locking order that we need
+ // to maintain.
+ lock.unlock();
+
+ for (size_t i = 0; i < dead_tasks_len; ++i) {
+ rust_task *task = dead_tasks_copy[i];
+ if (task) {
+ kernel->release_task_id(task->user.id);
+ task->deref();
+ }
+ }
+ srv->free(dead_tasks_copy);
+
+ lock.lock();
+}
+
+/**
+ * Schedules a running task for execution. Only running tasks can be
+ * activated. Blocked tasks have to be unblocked before they can be
+ * activated.
+ *
+ * Returns NULL if no tasks can be scheduled.
+ */
+rust_task *
+rust_task_thread::schedule_task() {
+ I(this, this);
+ // FIXME: in the face of failing tasks, this is not always right.
+ // I(this, n_live_tasks() > 0);
+ if (running_tasks.length() > 0) {
+ size_t k = isaac_rand(&rctx);
+ // Look around for a runnable task, starting at k.
+ for(size_t j = 0; j < running_tasks.length(); ++j) {
+ size_t i = (j + k) % running_tasks.length();
+ return (rust_task *)running_tasks[i];
+ }
+ }
+ return NULL;
+}
+
+void
+rust_task_thread::log_state() {
+ if (log_rt_task < log_debug) return;
+
+ if (!running_tasks.is_empty()) {
+ log(NULL, log_debug, "running tasks:");
+ for (size_t i = 0; i < running_tasks.length(); i++) {
+ log(NULL, log_debug, "\t task: %s @0x%" PRIxPTR,
+ running_tasks[i]->name,
+ running_tasks[i]);
+ }
+ }
+
+ if (!blocked_tasks.is_empty()) {
+ log(NULL, log_debug, "blocked tasks:");
+ for (size_t i = 0; i < blocked_tasks.length(); i++) {
+ log(NULL, log_debug, "\t task: %s @0x%" PRIxPTR ", blocked on: 0x%"
+ PRIxPTR " '%s'",
+ blocked_tasks[i]->name, blocked_tasks[i],
+ blocked_tasks[i]->cond, blocked_tasks[i]->cond_name);
+ }
+ }
+
+ if (!dead_tasks.is_empty()) {
+ log(NULL, log_debug, "dead tasks:");
+ for (size_t i = 0; i < dead_tasks.length(); i++) {
+ log(NULL, log_debug, "\t task: %s 0x%" PRIxPTR,
+ dead_tasks[i]->name, dead_tasks[i]);
+ }
+ }
+}
+/**
+ * Starts the main scheduler loop which performs task scheduling for this
+ * domain.
+ *
+ * Returns once no more tasks can be scheduled and all task ref_counts
+ * drop to zero.
+ */
+void
+rust_task_thread::start_main_loop() {
+ lock.lock();
+
+ DLOG(this, dom, "started domain loop %d", id);
+
+ while (!should_exit) {
+ DLOG(this, dom, "worker %d, number_of_live_tasks = %d",
+ id, number_of_live_tasks());
+
+ rust_task *scheduled_task = schedule_task();
+
+ if (scheduled_task == NULL) {
+ log_state();
+ DLOG(this, task,
+ "all tasks are blocked, scheduler id %d yielding ...",
+ id);
+ lock.wait();
+ reap_dead_tasks();
+ DLOG(this, task,
+ "scheduler %d resuming ...", id);
+ continue;
+ }
+
+ I(this, scheduled_task->running());
+
+ DLOG(this, task,
+ "activating task %s 0x%" PRIxPTR
+ ", sp=0x%" PRIxPTR
+ ", state: %s",
+ scheduled_task->name,
+ (uintptr_t)scheduled_task,
+ scheduled_task->user.rust_sp,
+ scheduled_task->state->name);
+
+ place_task_in_tls(scheduled_task);
+
+ DLOG(this, task,
+ "Running task %p on worker %d",
+ scheduled_task, id);
+ activate(scheduled_task);
+
+ DLOG(this, task,
+ "returned from task %s @0x%" PRIxPTR
+ " in state '%s', sp=0x%x, worker id=%d" PRIxPTR,
+ scheduled_task->name,
+ (uintptr_t)scheduled_task,
+ scheduled_task->state->name,
+ scheduled_task->user.rust_sp,
+ id);
+
+ reap_dead_tasks();
+ }
+
+ A(this, newborn_tasks.is_empty(), "Should have no newborn tasks");
+ A(this, running_tasks.is_empty(), "Should have no running tasks");
+ A(this, blocked_tasks.is_empty(), "Should have no blocked tasks");
+ A(this, dead_tasks.is_empty(), "Should have no dead tasks");
+
+ DLOG(this, dom, "finished main-loop %d", id);
+
+ lock.unlock();
+}
+
+rust_crate_cache *
+rust_task_thread::get_cache() {
+ return &cache;
+}
+
+rust_task_id
+rust_task_thread::create_task(rust_task *spawner, const char *name,
+ size_t init_stack_sz) {
+ rust_task *task =
+ new (this->kernel, "rust_task")
+ rust_task (this, &newborn_tasks, spawner, name, init_stack_sz);
+ DLOG(this, task, "created task: " PTR ", spawner: %s, name: %s",
+ task, spawner ? spawner->name : "null", name);
+
+ {
+ scoped_lock with(lock);
+ newborn_tasks.append(task);
+ }
+
+ kernel->register_task(task);
+ return task->user.id;
+}
+
+void rust_task_thread::run() {
+ this->start_main_loop();
+}
+
+#ifndef _WIN32
+void
+rust_task_thread::init_tls() {
+ int result = pthread_key_create(&task_key, NULL);
+ assert(!result && "Couldn't create the TLS key!");
+ tls_initialized = true;
+}
+
+void
+rust_task_thread::place_task_in_tls(rust_task *task) {
+ int result = pthread_setspecific(task_key, task);
+ assert(!result && "Couldn't place the task in TLS!");
+ task->record_stack_limit();
+}
+
+rust_task *
+rust_task_thread::get_task() {
+ if (!tls_initialized)
+ return NULL;
+ rust_task *task = reinterpret_cast<rust_task *>
+ (pthread_getspecific(task_key));
+ assert(task && "Couldn't get the task from TLS!");
+ return task;
+}
+#else
+void
+rust_task_thread::init_tls() {
+ task_key = TlsAlloc();
+ assert(task_key != TLS_OUT_OF_INDEXES && "Couldn't create the TLS key!");
+ tls_initialized = true;
+}
+
+void
+rust_task_thread::place_task_in_tls(rust_task *task) {
+ BOOL result = TlsSetValue(task_key, task);
+ assert(result && "Couldn't place the task in TLS!");
+ task->record_stack_limit();
+}
+
+rust_task *
+rust_task_thread::get_task() {
+ if (!tls_initialized)
+ return NULL;
+ rust_task *task = reinterpret_cast<rust_task *>(TlsGetValue(task_key));
+ assert(task && "Couldn't get the task from TLS!");
+ return task;
+}
+#endif
+
+void
+rust_task_thread::exit() {
+ A(this, !lock.lock_held_by_current_thread(), "Shouldn't have lock");
+ scoped_lock with(lock);
+ should_exit = true;
+ lock.signal();
+}
+
+//
+// Local Variables:
+// mode: C++
+// fill-column: 70;
+// indent-tabs-mode: nil
+// c-basic-offset: 4
+// buffer-file-coding-system: utf-8-unix
+// End:
+//
--- /dev/null
+#ifndef RUST_TASK_THREAD_H
+#define RUST_TASK_THREAD_H
+
+#include "context.h"
+
+#ifndef _WIN32
+#include <pthread.h>
+#else
+#include <windows.h>
+#endif
+
+struct rust_task_thread;
+
+struct rust_hashable_dict {
+ UT_hash_handle hh;
+ void* fields[0];
+};
+
+class rust_crate_cache {
+public:
+ type_desc *get_type_desc(size_t size,
+ size_t align,
+ size_t n_descs,
+ type_desc const **descs,
+ uintptr_t n_obj_params);
+ void** get_dict(size_t n_fields, void** dict);
+
+private:
+
+ type_desc *type_descs;
+ rust_hashable_dict *dicts;
+
+public:
+
+ rust_task_thread *thread;
+ size_t idx;
+
+ rust_crate_cache(rust_task_thread *thread);
+ ~rust_crate_cache();
+ void flush();
+};
+
+struct rust_task_thread : public kernel_owned<rust_task_thread>,
+ rust_thread
+{
+ RUST_REFCOUNTED(rust_task_thread)
+
+ // Fields known only by the runtime:
+ rust_log _log;
+
+ // NB: this is used to filter *runtime-originating* debug
+ // logging, on a per-scheduler basis. It's not likely what
+ // you want to expose to the user in terms of per-task
+ // or per-module logging control. By default all schedulers
+ // are set to debug-level logging here, and filtered by
+ // runtime category using the pseudo-modules ::rt::foo.
+ uint32_t log_lvl;
+
+ rust_srv *srv;
+ const char *const name;
+
+ rust_task_list newborn_tasks;
+ rust_task_list running_tasks;
+ rust_task_list blocked_tasks;
+ rust_task_list dead_tasks;
+
+ rust_crate_cache cache;
+
+ randctx rctx;
+
+ rust_kernel *kernel;
+ rust_scheduler *sched;
+ int32_t list_index;
+
+ const int id;
+
+ lock_and_signal lock;
+ size_t min_stack_size;
+
+#ifndef __WIN32__
+ pthread_attr_t attr;
+ static pthread_key_t task_key;
+#else
+ static DWORD task_key;
+#endif
+
+ static bool tls_initialized;
+
+ rust_env *env;
+ context c_context;
+
+ bool should_exit;
+
+ // Only a pointer to 'name' is kept, so it must live as long as this
+ // domain.
+ rust_task_thread(rust_scheduler *sched, rust_srv *srv, int id);
+ ~rust_task_thread();
+ void activate(rust_task *task);
+ void log(rust_task *task, uint32_t level, char const *fmt, ...);
+ rust_log & get_log();
+ void fail();
+
+ rust_crate_cache *get_cache();
+ size_t number_of_live_tasks();
+
+ void reap_dead_tasks();
+ rust_task *schedule_task();
+
+ void start_main_loop();
+
+ void log_state();
+
+ void kill_all_tasks();
+
+ rust_task_id create_task(rust_task *spawner, const char *name,
+ size_t init_stack_sz);
+
+ virtual void run();
+
+ void init_tls();
+ void place_task_in_tls(rust_task *task);
+
+ static rust_task *get_task();
+
+ // Tells the scheduler to exit it's scheduling loop and thread
+ void exit();
+};
+
+inline rust_log &
+rust_task_thread::get_log() {
+ return _log;
+}
+
+//
+// Local Variables:
+// mode: C++
+// fill-column: 78;
+// indent-tabs-mode: nil
+// c-basic-offset: 4
+// buffer-file-coding-system: utf-8-unix
+// compile-command: "make -k -C $RBUILD 2>&1 | sed -e 's/\\/x\\//x:\\//g'";
+// End:
+//
+
+#endif /* RUST_TASK_THREAD_H */
+++ /dev/null
-#include "rust_internal.h"
-#include "vg/valgrind.h"
-
-// The mechanism in this file is very crude; every domain (thread) spawns its
-// own secondary timer thread, and that timer thread *never idles*. It
-// sleep-loops interrupting the domain.
-//
-// This will need replacement, particularly in order to achieve an actual
-// state of idling when we're waiting on the outside world. Though that might
-// be as simple as making a secondary waitable start/stop-timer signalling
-// system between the domain and its timer thread. We'll see.
-//
-// On the other hand, we don't presently have the ability to idle domains *at
-// all*, and without the timer thread we're unable to otherwise preempt rust
-// tasks. So ... one step at a time.
-//
-// The implementation here is "lockless" in the sense that it only involves
-// one-directional signaling of one-shot events, so the event initiator just
-// writes a nonzero word to a prederermined location and waits for the
-// receiver to see it show up in their memory.
-
-#if defined(__WIN32__)
-static DWORD WINAPI
-#elif defined(__GNUC__)
-static void *
-#else
-#error "Platform not supported"
-#endif
-timer_loop(void *ptr) {
- // We were handed the rust_timer that owns us.
- rust_timer *timer = (rust_timer *)ptr;
- rust_scheduler *sched = timer->sched;
- DLOG(sched, timer, "in timer 0x%" PRIxPTR, (uintptr_t)timer);
- size_t ms = TIME_SLICE_IN_MS;
-
- while (!timer->exit_flag) {
-#if defined(__WIN32__)
- Sleep(ms);
-#else
- usleep(ms * 1000);
-#endif
- DLOG(sched, timer, "timer 0x%" PRIxPTR
- " interrupting schedain 0x%" PRIxPTR, (uintptr_t) timer,
- (uintptr_t) sched);
- sched->interrupt_flag = 1;
- }
-#if defined(__WIN32__)
- ExitThread(0);
-#else
- pthread_exit(NULL);
-#endif
- return 0;
-}
-
-rust_timer::rust_timer(rust_scheduler *sched) :
- sched(sched), exit_flag(0) {
- DLOG(sched, timer, "creating timer for domain 0x%" PRIxPTR, sched);
-#if defined(__WIN32__)
- thread = CreateThread(NULL, 0, timer_loop, this, 0, NULL);
- sched->kernel->win32_require("CreateThread", thread != NULL);
- if (RUNNING_ON_VALGRIND)
- Sleep(10);
-#else
- pthread_attr_init(&attr);
- pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
- pthread_create(&thread, &attr, timer_loop, (void *)this);
-#endif
-}
-
-rust_timer::~rust_timer() {
- exit_flag = 1;
-#if defined(__WIN32__)
- sched->kernel->win32_require("WaitForSingleObject",
- WaitForSingleObject(thread, INFINITE) ==
- WAIT_OBJECT_0);
-#else
- pthread_join(thread, NULL);
-#endif
-}
-
-//
-// Local Variables:
-// mode: C++
-// fill-column: 78;
-// indent-tabs-mode: nil
-// c-basic-offset: 4
-// buffer-file-coding-system: utf-8-unix
-// compile-command: "make -k -C $RBUILD 2>&1 | sed -e 's/\\/x\\//x:\\//g'";
-// End:
-//
*/
#include "rust_cc.h"
-#include "rust_gc.h"
#include "rust_internal.h"
-#include "rust_scheduler.h"
+#include "rust_task_thread.h"
#include "rust_unwind.h"
#include "rust_upcall.h"
#include "rust_util.h"
#include <stdint.h>
+#ifdef __GNUC__
+#define LOG_UPCALL_ENTRY(task) \
+ LOG(task, upcall, \
+ "> UPCALL %s - task: %s 0x%" PRIxPTR \
+ " retpc: x%" PRIxPTR, \
+ __FUNCTION__, \
+ (task)->name, (task), \
+ __builtin_return_address(0));
+#else
+#define LOG_UPCALL_ENTRY(task) \
+ LOG(task, upcall, "> UPCALL task: %s @x%" PRIxPTR, \
+ (task)->name, (task));
+#endif
+
// This is called to ensure we've set up our rust stacks
// correctly. Strategically placed at entry to upcalls because they begin on
// the rust stack and happen frequently enough to catch most stack changes,
inline void
call_upcall_on_c_stack(void *args, void *fn_ptr) {
check_stack_alignment();
- rust_task *task = rust_scheduler::get_task();
- rust_scheduler *sched = task->sched;
- sched->c_context.call_shim_on_c_stack(args, fn_ptr);
+ rust_task *task = rust_task_thread::get_task();
+ rust_task_thread *thread = task->thread;
+ thread->c_context.call_shim_on_c_stack(args, fn_ptr);
}
extern "C" void record_sp(void *limit);
*/
extern "C" CDECL void
upcall_call_shim_on_c_stack(void *args, void *fn_ptr) {
- rust_task *task = rust_scheduler::get_task();
+ rust_task *task = rust_task_thread::get_task();
// FIXME (1226) - The shim functions generated by rustc contain the
// morestack prologue, so we need to let them know they have enough
// stack.
record_sp(0);
- rust_scheduler *sched = task->sched;
+ rust_task_thread *thread = task->thread;
try {
- sched->c_context.call_shim_on_c_stack(args, fn_ptr);
+ thread->c_context.call_shim_on_c_stack(args, fn_ptr);
} catch (...) {
- A(sched, false, "Native code threw an exception");
+ A(thread, false, "Native code threw an exception");
}
- task = rust_scheduler::get_task();
+ task = rust_task_thread::get_task();
task->record_stack_limit();
}
extern "C" CDECL void
upcall_s_fail(s_fail_args *args) {
- rust_task *task = rust_scheduler::get_task();
+ rust_task *task = rust_task_thread::get_task();
LOG_UPCALL_ENTRY(task);
LOG_ERR(task, upcall, "upcall fail '%s', %s:%" PRIdPTR,
args->expr, args->file, args->line);
struct s_malloc_args {
uintptr_t retval;
- size_t nbytes;
type_desc *td;
};
extern "C" CDECL void
upcall_s_malloc(s_malloc_args *args) {
- rust_task *task = rust_scheduler::get_task();
+ rust_task *task = rust_task_thread::get_task();
LOG_UPCALL_ENTRY(task);
- LOG(task, mem,
- "upcall malloc(%" PRIdPTR ", 0x%" PRIxPTR ")",
- args->nbytes, args->td);
+ LOG(task, mem, "upcall malloc(0x%" PRIxPTR ")", args->td);
- gc::maybe_gc(task);
cc::maybe_cc(task);
- // TODO: Maybe use dladdr here to find a more useful name for the
- // type_desc.
-
- void *p = task->malloc(args->nbytes, "tdesc", args->td);
- memset(p, '\0', args->nbytes);
+ // FIXME--does this have to be calloc?
+ rust_opaque_box *box = task->boxed.calloc(args->td);
+ void *body = box_body(box);
- task->local_allocs[p] = args->td;
- debug::maybe_track_origin(task, p);
+ debug::maybe_track_origin(task, box);
LOG(task, mem,
- "upcall malloc(%" PRIdPTR ", 0x%" PRIxPTR ") = 0x%" PRIxPTR,
- args->nbytes, args->td, (uintptr_t)p);
- args->retval = (uintptr_t) p;
+ "upcall malloc(0x%" PRIxPTR ") = box 0x%" PRIxPTR
+ " with body 0x%" PRIxPTR,
+ args->td, (uintptr_t)box, (uintptr_t)body);
+ args->retval = (uintptr_t) box;
}
extern "C" CDECL uintptr_t
-upcall_malloc(size_t nbytes, type_desc *td) {
- s_malloc_args args = {0, nbytes, td};
+upcall_malloc(type_desc *td) {
+ s_malloc_args args = {0, td};
UPCALL_SWITCH_STACK(&args, upcall_s_malloc);
return args.retval;
}
struct s_free_args {
void *ptr;
- uintptr_t is_gc;
};
extern "C" CDECL void
upcall_s_free(s_free_args *args) {
- rust_task *task = rust_scheduler::get_task();
+ rust_task *task = rust_task_thread::get_task();
LOG_UPCALL_ENTRY(task);
- rust_scheduler *sched = task->sched;
- DLOG(sched, mem,
+ rust_task_thread *thread = task->thread;
+ DLOG(thread, mem,
"upcall free(0x%" PRIxPTR ", is_gc=%" PRIdPTR ")",
- (uintptr_t)args->ptr, args->is_gc);
+ (uintptr_t)args->ptr);
- task->local_allocs.erase(args->ptr);
debug::maybe_untrack_origin(task, args->ptr);
- task->free(args->ptr, (bool) args->is_gc);
+ rust_opaque_box *box = (rust_opaque_box*) args->ptr;
+ task->boxed.free(box);
}
extern "C" CDECL void
-upcall_free(void* ptr, uintptr_t is_gc) {
- s_free_args args = {ptr, is_gc};
+upcall_free(void* ptr) {
+ s_free_args args = {ptr};
UPCALL_SWITCH_STACK(&args, upcall_s_free);
}
+/**********************************************************************
+ * Sanity checks on boxes, insert when debugging possible
+ * use-after-free bugs. See maybe_validate_box() in trans.rs.
+ */
+
+extern "C" CDECL void
+upcall_validate_box(rust_opaque_box* ptr) {
+ if (ptr) {
+ assert(ptr->ref_count > 0);
+ assert(ptr->td != NULL);
+ assert(ptr->td->align <= 8);
+ assert(ptr->td->size <= 4096); // might not really be true...
+ }
+}
+
/**********************************************************************
* Allocate an object in the exchange heap.
*/
extern "C" CDECL void
upcall_s_shared_malloc(s_shared_malloc_args *args) {
- rust_task *task = rust_scheduler::get_task();
+ rust_task *task = rust_task_thread::get_task();
LOG_UPCALL_ENTRY(task);
LOG(task, mem,
extern "C" CDECL void
upcall_s_shared_free(s_shared_free_args *args) {
- rust_task *task = rust_scheduler::get_task();
+ rust_task *task = rust_task_thread::get_task();
LOG_UPCALL_ENTRY(task);
- rust_scheduler *sched = task->sched;
- DLOG(sched, mem,
+ rust_task_thread *thread = task->thread;
+ DLOG(thread, mem,
"upcall shared_free(0x%" PRIxPTR")",
(uintptr_t)args->ptr);
task->kernel->free(args->ptr);
void upcall_s_create_shared_type_desc(s_create_shared_type_desc_args *args)
{
- rust_task *task = rust_scheduler::get_task();
+ rust_task *task = rust_task_thread::get_task();
LOG_UPCALL_ENTRY(task);
// Copy the main part of the type descriptor:
void upcall_s_free_shared_type_desc(type_desc *td)
{ // n.b.: invoked from rust_cc.cpp as well as generated code
- rust_task *task = rust_scheduler::get_task();
+ rust_task *task = rust_task_thread::get_task();
LOG_UPCALL_ENTRY(task);
if (td) {
extern "C" CDECL void
upcall_s_get_type_desc(s_get_type_desc_args *args) {
- rust_task *task = rust_scheduler::get_task();
+ rust_task *task = rust_task_thread::get_task();
LOG_UPCALL_ENTRY(task);
LOG(task, cache, "upcall get_type_desc with size=%" PRIdPTR
extern "C" CDECL void
upcall_s_intern_dict(s_intern_dict_args *args) {
- rust_task *task = rust_scheduler::get_task();
+ rust_task *task = rust_task_thread::get_task();
LOG_UPCALL_ENTRY(task);
rust_crate_cache *cache = task->get_crate_cache();
args->res = cache->get_dict(args->n_fields, args->dict);
extern "C" CDECL void
upcall_s_vec_grow(s_vec_grow_args *args) {
- rust_task *task = rust_scheduler::get_task();
+ rust_task *task = rust_task_thread::get_task();
LOG_UPCALL_ENTRY(task);
reserve_vec(task, args->vp, args->new_sz);
(*args->vp)->fill = args->new_sz;
extern "C" CDECL void
upcall_s_vec_push(s_vec_push_args *args) {
- rust_task *task = rust_scheduler::get_task();
+ rust_task *task = rust_task_thread::get_task();
LOG_UPCALL_ENTRY(task);
size_t new_sz = (*args->vp)->fill + args->elt_ty->size;
reserve_vec(task, args->vp, new_sz);
upcall_s_vec_push(&args);
// Do the stack check to make sure this op, on the Rust stack, is behaving
- rust_task *task = rust_scheduler::get_task();
+ rust_task *task = rust_task_thread::get_task();
task->check_stack_canary();
}
extern "C" CDECL void
upcall_s_dynastack_mark(s_dynastack_mark_args *args) {
- args->retval = rust_scheduler::get_task()->dynastack.mark();
+ args->retval = rust_task_thread::get_task()->dynastack.mark();
}
extern "C" CDECL void *
upcall_s_dynastack_alloc(s_dynastack_alloc_args *args) {
size_t sz = args->sz;
args->retval = sz ?
- rust_scheduler::get_task()->dynastack.alloc(sz, NULL) : NULL;
+ rust_task_thread::get_task()->dynastack.alloc(sz, NULL) : NULL;
}
extern "C" CDECL void *
size_t sz = args->sz;
type_desc *ty = args->ty;
args->retval = sz ?
- rust_scheduler::get_task()->dynastack.alloc(sz, ty) : NULL;
+ rust_task_thread::get_task()->dynastack.alloc(sz, ty) : NULL;
}
extern "C" CDECL void *
extern "C" CDECL void
upcall_s_dynastack_free(s_dynastack_free_args *args) {
- return rust_scheduler::get_task()->dynastack.free(args->ptr);
+ return rust_task_thread::get_task()->dynastack.free(args->ptr);
}
/** Frees space in the dynamic stack. */
s_rust_personality_args args = {(_Unwind_Reason_Code)0,
version, actions, exception_class,
ue_header, context};
- rust_task *task = rust_scheduler::get_task();
+ rust_task *task = rust_task_thread::get_task();
// The personality function is run on the stack of the
// last function that threw or landed, which is going
extern "C" CDECL void
upcall_s_new_stack(struct s_new_stack_args *args) {
- rust_task *task = rust_scheduler::get_task();
+ rust_task *task = rust_task_thread::get_task();
args->result = task->new_stack(args->stk_sz,
args->args_addr,
args->args_sz);
extern "C" CDECL void
upcall_s_del_stack() {
- rust_task *task = rust_scheduler::get_task();
+ rust_task *task = rust_task_thread::get_task();
task->del_stack();
}
// needs to acquire the value of the stack pointer
extern "C" CDECL void
upcall_reset_stack_limit() {
- rust_task *task = rust_scheduler::get_task();
+ rust_task *task = rust_task_thread::get_task();
task->reset_stack_limit();
}
#pragma once
-#ifdef __GNUC__
-#define LOG_UPCALL_ENTRY(task) \
- LOG(task, upcall, \
- "> UPCALL %s - task: %s 0x%" PRIxPTR \
- " retpc: x%" PRIxPTR, \
- __FUNCTION__, \
- (task)->name, (task), \
- __builtin_return_address(0));
-#else
-#define LOG_UPCALL_ENTRY(task) \
- LOG(task, upcall, "> UPCALL task: %s @x%" PRIxPTR, \
- (task)->name, (task));
-#endif
+// Upcalls used from C code on occasion:
+extern "C" CDECL void upcall_shared_free(void* ptr);
+extern "C" CDECL void upcall_free_shared_type_desc(type_desc *td);
fill(0),
data(new (task, "ptr_vec<T>") T*[alloc])
{
- I(task->sched, data);
- DLOG(task->sched, mem, "new ptr_vec(data=0x%" PRIxPTR ") -> 0x%" PRIxPTR,
+ I(task->thread, data);
+ DLOG(task->thread, mem, "new ptr_vec(data=0x%" PRIxPTR ") -> 0x%" PRIxPTR,
(uintptr_t)data, (uintptr_t)this);
}
template <typename T>
ptr_vec<T>::~ptr_vec()
{
- I(task->sched, data);
- DLOG(task->sched, mem, "~ptr_vec 0x%" PRIxPTR ", data=0x%" PRIxPTR,
+ I(task->thread, data);
+ DLOG(task->thread, mem, "~ptr_vec 0x%" PRIxPTR ", data=0x%" PRIxPTR,
(uintptr_t)this, (uintptr_t)data);
- I(task->sched, fill == 0);
+ I(task->thread, fill == 0);
task->free(data);
}
template <typename T> T *&
ptr_vec<T>::operator[](size_t offset) {
- I(task->sched, data[offset]->idx == offset);
+ I(task->thread, data[offset]->idx == offset);
return data[offset];
}
void
ptr_vec<T>::push(T *p)
{
- I(task->sched, data);
- I(task->sched, fill <= alloc);
+ I(task->thread, data);
+ I(task->thread, fill <= alloc);
if (fill == alloc) {
alloc *= 2;
data = (T **)task->realloc(data, alloc * sizeof(T*));
- I(task->sched, data);
+ I(task->thread, data);
}
- I(task->sched, fill < alloc);
+ I(task->thread, fill < alloc);
p->idx = fill;
data[fill++] = p;
}
void
ptr_vec<T>::trim(size_t sz)
{
- I(task->sched, data);
+ I(task->thread, data);
if (sz <= (alloc / 4) &&
(alloc / 2) >= INIT_SIZE) {
alloc /= 2;
- I(task->sched, alloc >= fill);
+ I(task->thread, alloc >= fill);
data = (T **)task->realloc(data, alloc * sizeof(T*));
- I(task->sched, data);
+ I(task->thread, data);
}
}
ptr_vec<T>::swap_delete(T *item)
{
/* Swap the endpoint into i and decr fill. */
- I(task->sched, data);
- I(task->sched, fill > 0);
- I(task->sched, item->idx < fill);
+ I(task->thread, data);
+ I(task->thread, fill > 0);
+ I(task->thread, item->idx < fill);
fill--;
if (fill > 0) {
T *subst = data[fill];
// Initialization helper for ISAAC RNG
-template <typename sched_or_kernel>
-static inline void
-isaac_init(sched_or_kernel *sched, randctx *rctx)
+inline void
+isaac_init(rust_kernel *kernel, randctx *rctx)
{
memset(rctx, 0, sizeof(randctx));
- char *rust_seed = sched->env->rust_seed;
+ char *rust_seed = kernel->env->rust_seed;
if (rust_seed != NULL) {
ub4 seed = (ub4) atoi(rust_seed);
for (size_t i = 0; i < RANDSIZ; i ++) {
} else {
#ifdef __WIN32__
HCRYPTPROV hProv;
- sched->win32_require
+ kernel->win32_require
(_T("CryptAcquireContext"),
CryptAcquireContext(&hProv, NULL, NULL, PROV_RSA_FULL,
CRYPT_VERIFYCONTEXT|CRYPT_SILENT));
- sched->win32_require
+ kernel->win32_require
(_T("CryptGenRandom"),
CryptGenRandom(hProv, sizeof(rctx->randrsl),
(BYTE*)(&rctx->randrsl)));
- sched->win32_require
+ kernel->win32_require
(_T("CryptReleaseContext"),
CryptReleaseContext(hProv, 0));
#else
int fd = open("/dev/urandom", O_RDONLY);
- I(sched, fd > 0);
- I(sched,
+ I(kernel, fd > 0);
+ I(kernel,
read(fd, (void*) &rctx->randrsl, sizeof(rctx->randrsl))
== sizeof(rctx->randrsl));
- I(sched, close(fd) == 0);
+ I(kernel, close(fd) == 0);
#endif
}
return sizeof(rust_vec) + sizeof(T) * elems;
}
-inline void reserve_vec(rust_task* task, rust_vec** vpp, size_t size) {
+inline void reserve_vec_exact(rust_task* task, rust_vec** vpp, size_t size) {
if (size > (*vpp)->alloc) {
- size_t new_alloc = next_power_of_two(size);
- *vpp = (rust_vec*)task->kernel->realloc(*vpp, new_alloc +
- sizeof(rust_vec));
- (*vpp)->alloc = new_alloc;
+ *vpp = (rust_vec*)task->kernel->realloc(*vpp, size + sizeof(rust_vec));
+ (*vpp)->alloc = size;
}
}
+inline void reserve_vec(rust_task* task, rust_vec** vpp, size_t size) {
+ reserve_vec_exact(task, vpp, next_power_of_two(size));
+}
+
typedef rust_vec rust_str;
inline rust_str *
public:
rust_uvtmp_thread() {
- task = rust_scheduler::get_task();
+ task = rust_task_thread::get_task();
stop_flag = false;
loop = uv_loop_new();
uv_idle_init(loop, &idle);
debug_tag
debug_tydesc
debug_get_stk_seg
-do_gc
drop_task
get_port_id
get_task_id
get_time
last_os_error
leak
-migrate_alloc
nano_time
new_port
new_task
-pin_task
port_recv
-unpin_task
rand_free
rand_new
rand_next
rust_set_exit_status
rust_start
rust_getcwd
+rust_task_yield
rust_task_is_unwinding
-rust_task_sleep
rust_get_task
-set_min_stack
sched_threads
shape_log_str
squareroot
start_task
vec_reserve_shared
+str_reserve_shared
vec_from_buf_shared
unsupervise
upcall_cmp_type
upcall_dynastack_mark
upcall_fail
upcall_free
+upcall_validate_box
upcall_create_shared_type_desc
upcall_free_shared_type_desc
upcall_get_type_desc
rust_uvtmp_timer
rust_uvtmp_delete_buf
rust_uvtmp_get_req_id
-
+#include <assert.h>
#include "../globals.h"
/*
#include "lock_and_signal.h"
+// FIXME: This is not a portable way of specifying an invalid pthread_t
+#define INVALID_THREAD 0
+
+
#if defined(__WIN32__)
lock_and_signal::lock_and_signal()
- : alive(true)
+ : _holding_thread(INVALID_THREAD)
{
- // FIXME: In order to match the behavior of pthread_cond_broadcast on
- // Windows, we create manual reset events. This however breaks the
- // behavior of pthread_cond_signal, fixing this is quite involved:
- // refer to: http://www.cs.wustl.edu/~schmidt/win32-cv-1.html
-
- _event = CreateEvent(NULL, TRUE, FALSE, NULL);
+ _event = CreateEvent(NULL, FALSE, FALSE, NULL);
InitializeCriticalSection(&_cs);
}
#else
lock_and_signal::lock_and_signal()
- : _locked(false), alive(true)
+ : _holding_thread(INVALID_THREAD)
{
CHECKED(pthread_cond_init(&_cond, NULL));
CHECKED(pthread_mutex_init(&_mutex, NULL));
CHECKED(pthread_cond_destroy(&_cond));
CHECKED(pthread_mutex_destroy(&_mutex));
#endif
- alive = false;
}
void lock_and_signal::lock() {
CHECKED(pthread_mutex_lock(&_mutex));
_holding_thread = pthread_self();
#endif
- _locked = true;
}
void lock_and_signal::unlock() {
- _locked = false;
+ _holding_thread = INVALID_THREAD;
#if defined(__WIN32__)
LeaveCriticalSection(&_cs);
#else
* Wait indefinitely until condition is signaled.
*/
void lock_and_signal::wait() {
- timed_wait(0);
-}
-
-bool lock_and_signal::timed_wait(size_t timeout_in_ms) {
- _locked = false;
- bool rv = true;
+ assert(lock_held_by_current_thread());
+ _holding_thread = INVALID_THREAD;
#if defined(__WIN32__)
LeaveCriticalSection(&_cs);
- DWORD timeout = timeout_in_ms == 0 ? INFINITE : timeout_in_ms;
- rv = WaitForSingleObject(_event, timeout) != WAIT_TIMEOUT;
+ WaitForSingleObject(_event, INFINITE);
EnterCriticalSection(&_cs);
_holding_thread = GetCurrentThreadId();
#else
- if (timeout_in_ms == 0) {
- CHECKED(pthread_cond_wait(&_cond, &_mutex));
- } else {
- timeval time_val;
- gettimeofday(&time_val, NULL);
- timespec time_spec;
- time_spec.tv_sec = time_val.tv_sec + 0;
- time_spec.tv_nsec = time_val.tv_usec * 1000 + timeout_in_ms * 1000000;
- if(time_spec.tv_nsec >= 1000000000) {
- time_spec.tv_sec++;
- time_spec.tv_nsec -= 1000000000;
- }
- int cond_wait_status
- = pthread_cond_timedwait(&_cond, &_mutex, &time_spec);
- switch(cond_wait_status) {
- case 0:
- // successfully grabbed the lock.
- break;
- case ETIMEDOUT:
- // Oops, we timed out.
- rv = false;
- break;
- default:
- // Error
- CHECKED(cond_wait_status);
- }
- }
+ CHECKED(pthread_cond_wait(&_cond, &_mutex));
_holding_thread = pthread_self();
#endif
- _locked = true;
- return rv;
}
/**
#endif
}
-/**
- * Signal condition, and resume all waiting threads.
- */
-void lock_and_signal::signal_all() {
-#if defined(__WIN32__)
- SetEvent(_event);
-#else
- CHECKED(pthread_cond_broadcast(&_cond));
-#endif
-}
-
bool lock_and_signal::lock_held_by_current_thread()
{
#if defined(__WIN32__)
- return _locked && _holding_thread == GetCurrentThreadId();
+ return _holding_thread == GetCurrentThreadId();
#else
- return _locked && _holding_thread == pthread_self();
+ return pthread_equal(_holding_thread, pthread_self());
#endif
}
pthread_t _holding_thread;
#endif
- bool _locked;
-
- bool alive;
public:
lock_and_signal();
void lock();
void unlock();
void wait();
- bool timed_wait(size_t timeout_in_ns);
void signal();
- void signal_all();
bool lock_held_by_current_thread();
};
+++ /dev/null
-#include "../rust_internal.h"
-
-bool
-rust_test::run() {
- return false;
-}
-
-const char *
-rust_test::name() {
- return "untitled";
-}
-
-rust_test_suite::rust_test_suite() {
- tests.append(new rust_domain_test());
- tests.append(new rust_task_test(this));
- tests.append(new rust_array_list_test());
- tests.append(new rust_synchronized_indexed_list_test());
-}
-
-rust_test_suite::~rust_test_suite() {
-
-}
-
-bool
-rust_test_suite::run() {
- bool pass = true;
- for (size_t i = 0; i < tests.size(); i++) {
- rust_test *test = tests[i];
- printf("test: %s running ... \n", test->name());
- timer timer;
- bool result = tests[i]->run();
- printf("test: %s %s %.2f ms\n", test->name(),
- result ? "PASS" : "FAIL", timer.elapsed_ms());
- if (result == false) {
- pass = false;
- }
- }
- return pass;
-}
-
+++ /dev/null
-#ifndef RUST_TEST_HARNESS_H
-#define RUST_TEST_HARNESS_H
-
-#define CHECK(x) if ((x) == false) \
- { printf("condition: %s failed at file: %s, line: %d\n", #x, \
- __FILE__, __LINE__ ); return false; }
-
-class rust_test {
-public:
- virtual bool run();
- virtual const char *name();
-};
-
-class rust_test_suite : public rust_test {
-public:
- array_list<rust_test*> tests;
- rust_test_suite();
- virtual ~rust_test_suite();
- bool run();
-};
-
-#endif /* RUST_TEST_HARNESS_H */
+++ /dev/null
-#include "rust_test_runtime.h"
-
-rust_test_runtime::rust_test_runtime() {
-}
-
-rust_test_runtime::~rust_test_runtime() {
-}
-
-#define DOMAINS 32
-#define TASKS 32
-
-void
-rust_domain_test::worker::run() {
- for (int i = 0; i < TASKS; i++) {
- kernel->create_task(NULL, "child");
- }
- //sync::sleep(rand(&handle->rctx) % 1000);
-}
-
-bool
-rust_domain_test::run() {
- rust_env env;
- rust_srv srv(&env);
- rust_kernel kernel(&srv, 1);
-
- array_list<worker *> workers;
- for (int i = 0; i < DOMAINS; i++) {
- worker *worker = new rust_domain_test::worker (&kernel);
- workers.append(worker);
- worker->start();
- }
-
- // We don't join the worker threads here in order to simulate ad-hoc
- // termination of domains. If we join_all_domains before all domains
- // are actually spawned, this could crash, thus the reason for the
- // sleep below.
-
- sync::sleep(100);
- return true;
-}
-
-void task_entry(void *, rust_opaque_closure *, void *) {
- printf("task entry\n");
-}
-
-void
-rust_task_test::worker::run() {
- rust_task_id root_id = kernel->create_task(NULL, "main");
- rust_task *root_task = kernel->get_task_by_id(root_id);
- root_task->start(&task_entry, NULL, NULL);
- root_task->sched->start_main_loop();
-}
-
-bool
-rust_task_test::run() {
- rust_env env;
- rust_srv srv(&env);
- rust_kernel kernel(&srv, 1);
-
- array_list<worker *> workers;
- for (int i = 0; i < DOMAINS; i++) {
- worker *worker = new rust_task_test::worker (&kernel, this);
- workers.append(worker);
- worker->start();
- }
-
- //sync::sleep(rand(&kernel.sched->rctx) % 1000);
- return true;
-}
+++ /dev/null
-#include "../rust_internal.h"
-
-#ifndef RUST_TEST_RUNTIME_H
-#define RUST_TEST_RUNTIME_H
-
-class rust_test_runtime {
-public:
- rust_test_runtime();
- virtual ~rust_test_runtime();
-};
-
-
-class rust_domain_test : public rust_test {
-public:
- class worker : public rust_thread {
- public:
- rust_kernel *kernel;
- worker(rust_kernel *kernel) : kernel(kernel) {
- }
- void run();
- };
- bool run();
- const char *name() {
- return "rust_domain_test";
- }
-};
-
-class rust_task_test : public rust_test {
-public:
- rust_test_suite *suite;
- rust_task_test(rust_test_suite *suite) : suite(suite) {
- }
- class worker : public rust_thread {
- public:
- rust_kernel *kernel;
- rust_task_test *parent;
- worker(rust_kernel *kernel, rust_task_test *parent) :
- kernel(kernel), parent(parent) {
- }
- void run();
- };
- bool run();
- const char *name() {
- return "rust_task_test";
- }
-};
-
-#endif /* RUST_TEST_RUNTIME_H */
+++ /dev/null
-#include "../rust_internal.h"
-
-#define COUNT 1000
-#define LARGE_COUNT 10000
-#define THREADS 10
-
-bool
-rust_array_list_test::run() {
- array_list<int> list;
-
- for (int i = 0; i < COUNT; i++) {
- list.append(i);
- }
-
- for (int i = 0; i < COUNT; i++) {
- CHECK (list[i] == i);
- }
-
- for (int i = 0; i < COUNT; i++) {
- CHECK (list.index_of(i) == i);
- }
-
- for (int i = 0; i < COUNT; i++) {
- CHECK (list.replace(i, -i));
- CHECK (list.replace(-i, i));
- CHECK (list.index_of(i) == i);
- }
-
- for (int i = COUNT - 1; i >= 0; i--) {
- CHECK (list.pop(NULL));
- }
-
- return true;
-}
-
-bool
-rust_synchronized_indexed_list_test::run() {
- array_list<worker*> workers;
-
- for (int i = 0; i < THREADS; i++) {
- worker *worker =
- new rust_synchronized_indexed_list_test::worker(this);
- workers.append(worker);
- }
-
- for (uint32_t i = 0; i < workers.size(); i++) {
- workers[i]->start();
- }
-
- while(workers.is_empty() == false) {
- worker *worker;
- workers.pop(&worker);
- worker->join();
- delete worker;
- }
-
- size_t expected_items = LARGE_COUNT * THREADS;
-
- CHECK(list.length() == expected_items);
-
- long long sum = 0;
- for (size_t i = 0; i < list.length(); i++) {
- sum += list[i]->value;
- }
-
- long long expected_sum = LARGE_COUNT;
- expected_sum = expected_sum * (expected_sum - 1) / 2 * THREADS;
- CHECK (sum == expected_sum);
- return true;
-}
-
-void
-rust_synchronized_indexed_list_test::worker::run() {
- for (int i = 0; i < LARGE_COUNT; i++) {
- parent->list.append(new indexed_list_element<int>(i));
- }
- return;
-}
+++ /dev/null
-#ifndef RUST_TEST_UTIL_H
-#define RUST_TEST_UTIL_H
-
-class rust_test_util : public rust_test {
-public:
-
-};
-
-class rust_array_list_test : public rust_test {
-public:
- bool run();
- const char *name() {
- return "rust_array_list_test";
- }
-};
-
-
-class rust_synchronized_indexed_list_test : public rust_test {
-public:
- rust_env env;
- rust_srv srv;
- synchronized_indexed_list<indexed_list_element<int> > list;
-
- rust_synchronized_indexed_list_test() :
- srv(&env)
- {
- }
-
- class worker : public rust_thread {
- public:
- rust_synchronized_indexed_list_test *parent;
- worker(rust_synchronized_indexed_list_test *parent) : parent(parent) {
- }
- void run();
- };
- bool run();
- const char *name() {
- return "rust_synchronized_indexed_list_test";
- }
-};
-
-#endif /* RUST_TEST_UTIL_H */
}
}
+// FIXME: this whole structure should not be duplicated here. makes it
+// painful to add or remove options.
fn build_session() -> session::session {
let sopts: @session::options = @{
crate_type: session::lib_crate,
test: false,
parse_only: false,
no_trans: false,
- do_gc: false,
no_asm_comments: false,
+ monomorphize: false,
warn_unused_imports: false
};
driver::build_session(sopts, ".", diagnostic::emit)
}
#[test]
-#[ignore]
fn srv_should_build_ast_map() {
- // FIXME
- /*let source = "fn a() { }";
+ let source = "fn a() { }";
let srv = mk_srv_from_str(source);
exec(srv) {|ctxt|
assert ctxt.ast_map.size() != 0u
- };*/
+ };
}
#[test]
import core::tuple;
export crate_attrs, mod_attrs, fn_attrs, arg_attrs,
- const_attrs, enum_attrs, variant_attrs, res_attrs;
+ const_attrs, enum_attrs, variant_attrs, res_attrs,
+ iface_attrs, method_attrs, impl_attrs, type_attrs;
export parse_crate, parse_mod, parse_fn, parse_const,
- parse_enum, parse_variant, parse_res;
+ parse_enum, parse_variant, parse_res,
+ parse_iface, parse_method, parse_impl, parse_type;
type crate_attrs = {
name: option<str>
args: [arg_attrs]
};
+type iface_attrs = {
+ brief: option<str>,
+ desc: option<str>
+};
+
+type impl_attrs = {
+ brief: option<str>,
+ desc: option<str>
+};
+
+type method_attrs = fn_attrs;
+
+type type_attrs = {
+ brief: option<str>,
+ desc: option<str>
+};
+
#[cfg(test)]
mod test {
mutable byte_pos: 0u
};
let parser = parser::new_parser_from_source_str(
- parse_sess, [], "-", @source);
+ parse_sess, [], "-", none, @source);
parser::parse_outer_attributes(parser)
}
let attrs = parse_res(attrs);
assert attrs.args[0].name == "a";
assert attrs.args[0].desc == "b";
+}
+
+fn parse_iface(attrs: [ast::attribute]) -> iface_attrs {
+ parse_basic(attrs)
+}
+
+fn parse_method(attrs: [ast::attribute]) -> method_attrs {
+ parse_fn(attrs)
+}
+
+fn parse_impl(attrs: [ast::attribute]) -> impl_attrs {
+ parse_basic(attrs)
+}
+
+fn parse_type(attrs: [ast::attribute]) -> type_attrs {
+ parse_basic(attrs)
}
\ No newline at end of file
fold_fn: fold_fn,
fold_const: fold_const,
fold_enum: fold_enum,
- fold_res: fold_res
+ fold_res: fold_res,
+ fold_iface: fold_iface,
+ fold_impl: fold_impl,
+ fold_type: fold_type
with *fold::default_seq_fold(srv)
});
fold.fold_crate(fold, doc)
attr_parser::parse_crate(attrs)
};
- ~{
- topmod: ~{
+ {
+ topmod: {
name: option::from_maybe(doc.topmod.name, attrs.name)
- with *doc.topmod
+ with doc.topmod
}
}
}
#[test]
fn should_replace_top_module_name_with_crate_name() {
- let source = "#[link(name = \"bond\")];";
- let srv = astsrv::mk_srv_from_str(source);
- let doc = extract::from_srv(srv, "");
- let fold = fold::default_seq_fold(srv);
- let doc = fold_crate(fold, doc);
+ let doc = test::mk_doc("#[link(name = \"bond\")];");
assert doc.topmod.name == "bond";
}
parse_attrs: fn~([ast::attribute]) -> T) -> T {
astsrv::exec(srv) {|ctxt|
let attrs = alt ctxt.ast_map.get(id) {
- ast_map::node_item(item) { item.attrs }
+ ast_map::node_item(item, _) { item.attrs }
+ _ {
+ fail "parse_item_attrs: not an item";
+ }
};
parse_attrs(attrs)
}
doc: doc::moddoc,
attrs: attr_parser::mod_attrs
) -> doc::moddoc {
- ~{
+ {
brief: attrs.brief,
desc: attrs.desc
- with *doc
+ with doc
}
}
}
#[test]
fn fold_mod_should_extract_mod_attributes() {
- let source = "#[doc = \"test\"] mod a { }";
- let srv = astsrv::mk_srv_from_str(source);
- let doc = extract::from_srv(srv, "");
- let fold = fold::default_seq_fold(srv);
- let doc = fold_mod(fold, doc.topmod.mods[0]);
- assert doc.desc == some("test");
+ let doc = test::mk_doc("#[doc = \"test\"] mod a { }");
+ assert doc.topmod.mods()[0].desc == some("test");
}
#[test]
fn fold_mod_should_extract_top_mod_attributes() {
- let source = "#[doc = \"test\"];";
- let srv = astsrv::mk_srv_from_str(source);
- let doc = extract::from_srv(srv, "");
- let fold = fold::default_seq_fold(srv);
- let doc = fold_mod(fold, doc.topmod);
- assert doc.desc == some("test");
+ let doc = test::mk_doc("#[doc = \"test\"];");
+ assert doc.topmod.desc == some("test");
}
fn fold_fn(
doc: doc::fndoc,
attrs: attr_parser::fn_attrs
) -> doc::fndoc {
- ret ~{
+ ret {
brief: attrs.brief,
desc: attrs.desc,
args: merge_arg_attrs(doc.args, attrs.args),
return: merge_ret_attrs(doc.return, attrs.return),
failure: attrs.failure
- with *doc
+ with doc
};
}
+}
- fn merge_arg_attrs(
- docs: [doc::argdoc],
- attrs: [attr_parser::arg_attrs]
- ) -> [doc::argdoc] {
- vec::map(docs) {|doc|
- alt vec::find(attrs) {|attr|
- attr.name == doc.name
- } {
- some(attr) {
- ~{
- desc: some(attr.desc)
- with *doc
- }
+fn merge_arg_attrs(
+ docs: [doc::argdoc],
+ attrs: [attr_parser::arg_attrs]
+) -> [doc::argdoc] {
+ vec::map(docs) {|doc|
+ alt vec::find(attrs) {|attr|
+ attr.name == doc.name
+ } {
+ some(attr) {
+ {
+ desc: some(attr.desc)
+ with doc
}
- none { doc }
}
+ none { doc }
}
- // FIXME: Warning when documenting a non-existent arg
}
+ // FIXME: Warning when documenting a non-existent arg
+}
- fn merge_ret_attrs(
- doc: doc::retdoc,
- attrs: option<str>
- ) -> doc::retdoc {
- {
- desc: attrs
- with doc
- }
+
+fn merge_ret_attrs(
+ doc: doc::retdoc,
+ attrs: option<str>
+) -> doc::retdoc {
+ {
+ desc: attrs
+ with doc
}
}
#[test]
fn fold_fn_should_extract_fn_attributes() {
- let source = "#[doc = \"test\"] fn a() -> int { }";
- let srv = astsrv::mk_srv_from_str(source);
- let doc = extract::from_srv(srv, "");
- let fold = fold::default_seq_fold(srv);
- let doc = fold_fn(fold, doc.topmod.fns[0]);
- assert doc.desc == some("test");
+ let doc = test::mk_doc("#[doc = \"test\"] fn a() -> int { }");
+ assert doc.topmod.fns()[0].desc == some("test");
}
#[test]
fn fold_fn_should_extract_arg_attributes() {
- let source = "#[doc(args(a = \"b\"))] fn c(a: bool) { }";
- let srv = astsrv::mk_srv_from_str(source);
- let doc = extract::from_srv(srv, "");
- let fold = fold::default_seq_fold(srv);
- let doc = fold_fn(fold, doc.topmod.fns[0]);
- assert doc.args[0].desc == some("b");
+ let doc = test::mk_doc("#[doc(args(a = \"b\"))] fn c(a: bool) { }");
+ assert doc.topmod.fns()[0].args[0].desc == some("b");
}
#[test]
let doc = extract::from_srv(srv, "");
let doc = tystr_pass::mk_pass()(srv, doc);
let fold = fold::default_seq_fold(srv);
- let doc = fold_fn(fold, doc.topmod.fns[0]);
+ let doc = fold_fn(fold, doc.topmod.fns()[0]);
assert doc.return.desc == some("what");
}
let doc = extract::from_srv(srv, "");
let doc = tystr_pass::mk_pass()(srv, doc);
let fold = fold::default_seq_fold(srv);
- let doc = fold_fn(fold, doc.topmod.fns[0]);
+ let doc = fold_fn(fold, doc.topmod.fns()[0]);
assert doc.sig == some("fn a() -> int");
}
#[test]
fn fold_fn_should_extract_failure_conditions() {
- let source = "#[doc(failure = \"what\")] fn a() { }";
- let srv = astsrv::mk_srv_from_str(source);
- let doc = extract::from_srv(srv, "");
- let fold = fold::default_seq_fold(srv);
- let doc = fold_fn(fold, doc.topmod.fns[0]);
- assert doc.failure == some("what");
+ let doc = test::mk_doc("#[doc(failure = \"what\")] fn a() { }");
+ assert doc.topmod.fns()[0].failure == some("what");
}
fn fold_const(
doc: doc::constdoc
) -> doc::constdoc {
let srv = fold.ctxt;
- let attrs = parse_item_attrs(srv, doc.id, attr_parser::parse_mod);
+ let attrs = parse_item_attrs(srv, doc.id, attr_parser::parse_const);
- ~{
+ {
brief: attrs.brief,
desc: attrs.desc
- with *doc
+ with doc
}
}
#[test]
fn fold_const_should_extract_docs() {
- let source = "#[doc(brief = \"foo\", desc = \"bar\")]\
- const a: bool = true;";
- let srv = astsrv::mk_srv_from_str(source);
- let doc = extract::from_srv(srv, "");
- let fold = fold::default_seq_fold(srv);
- let doc = fold_const(fold, doc.topmod.consts[0]);
- assert doc.brief == some("foo");
- assert doc.desc == some("bar");
+ let doc = test::mk_doc("#[doc(brief = \"foo\", desc = \"bar\")]\
+ const a: bool = true;");
+ assert doc.topmod.consts()[0].brief == some("foo");
+ assert doc.topmod.consts()[0].desc == some("bar");
}
fn fold_enum(
let srv = fold.ctxt;
let attrs = parse_item_attrs(srv, doc.id, attr_parser::parse_enum);
- ~{
+ {
brief: attrs.brief,
desc: attrs.desc,
variants: vec::map(doc.variants) {|variant|
alt ctxt.ast_map.get(doc.id) {
ast_map::node_item(@{
node: ast::item_enum(ast_variants, _), _
- }) {
+ }, _) {
let ast_variant = option::get(
vec::find(ast_variants) {|v|
v.node.name == variant.name
attr_parser::parse_variant(ast_variant.node.attrs)
}
+ _ { fail "fold_enum: undocumented invariant"; }
}
};
- ~{
+ {
desc: attrs.desc
- with *variant
+ with variant
}
}
- with *doc
+ with doc
}
}
#[test]
fn fold_enum_should_extract_docs() {
- let source = "#[doc(brief = \"a\", desc = \"b\")]\
- enum a { v }";
- let srv = astsrv::mk_srv_from_str(source);
- let doc = extract::from_srv(srv, "");
- let fold = fold::default_seq_fold(srv);
- let doc = fold_enum(fold, doc.topmod.enums[0]);
- assert doc.brief == some("a");
- assert doc.desc == some("b");
+ let doc = test::mk_doc("#[doc(brief = \"a\", desc = \"b\")]\
+ enum a { v }");
+ assert doc.topmod.enums()[0].brief == some("a");
+ assert doc.topmod.enums()[0].desc == some("b");
}
#[test]
fn fold_enum_should_extract_variant_docs() {
- let source = "enum a { #[doc = \"c\"] v }";
- let srv = astsrv::mk_srv_from_str(source);
- let doc = extract::from_srv(srv, "");
- let fold = fold::default_seq_fold(srv);
- let doc = fold_enum(fold, doc.topmod.enums[0]);
- assert doc.variants[0].desc == some("c");
+ let doc = test::mk_doc("enum a { #[doc = \"c\"] v }");
+ assert doc.topmod.enums()[0].variants[0].desc == some("c");
}
fn fold_res(
let srv = fold.ctxt;
let attrs = parse_item_attrs(srv, doc.id, attr_parser::parse_fn);
- ~{
+ {
brief: attrs.brief,
desc: attrs.desc,
args: vec::map(doc.args) {|doc|
attr.name == doc.name
} {
some(attr) {
- ~{
+ {
desc: some(attr.desc)
- with *doc
+ with doc
}
}
none { doc }
}
}
- with *doc
+ with doc
}
}
#[test]
fn fold_res_should_extract_docs() {
- let source = "#[doc(brief = \"a\", desc = \"b\")]\
- resource r(b: bool) { }";
- let srv = astsrv::mk_srv_from_str(source);
- let doc = extract::from_srv(srv, "");
- let fold = fold::default_seq_fold(srv);
- let doc = fold_res(fold, doc.topmod.resources[0]);
- assert doc.brief == some("a");
- assert doc.desc == some("b");
+ let doc = test::mk_doc("#[doc(brief = \"a\", desc = \"b\")]\
+ resource r(b: bool) { }");
+ assert doc.topmod.resources()[0].brief == some("a");
+ assert doc.topmod.resources()[0].desc == some("b");
}
#[test]
fn fold_res_should_extract_arg_docs() {
- let source = "#[doc(args(a = \"b\"))]\
- resource r(a: bool) { }";
- let srv = astsrv::mk_srv_from_str(source);
- let doc = extract::from_srv(srv, "");
- let fold = fold::default_seq_fold(srv);
- let doc = fold_res(fold, doc.topmod.resources[0]);
- assert doc.args[0].name == "a";
- assert doc.args[0].desc == some("b");
+ let doc = test::mk_doc("#[doc(args(a = \"b\"))]\
+ resource r(a: bool) { }");
+ assert doc.topmod.resources()[0].args[0].name == "a";
+ assert doc.topmod.resources()[0].args[0].desc == some("b");
+}
+
+fn fold_iface(
+ fold: fold::fold<astsrv::srv>,
+ doc: doc::ifacedoc
+) -> doc::ifacedoc {
+ let srv = fold.ctxt;
+ let doc = fold::default_seq_fold_iface(fold, doc);
+ let attrs = parse_item_attrs(srv, doc.id, attr_parser::parse_iface);
+
+ {
+ brief: attrs.brief,
+ desc: attrs.desc,
+ methods: merge_method_attrs(srv, doc.id, doc.methods)
+ with doc
+ }
+}
+
+fn merge_method_attrs(
+ srv: astsrv::srv,
+ item_id: doc::ast_id,
+ docs: [doc::methoddoc]
+) -> [doc::methoddoc] {
+ // Create an assoc list from method name to attributes
+ let attrs = astsrv::exec(srv) {|ctxt|
+ alt ctxt.ast_map.get(item_id) {
+ ast_map::node_item(@{
+ node: ast::item_iface(_, methods), _
+ }, _) {
+ vec::map(methods) {|method|
+ (method.ident, attr_parser::parse_method(method.attrs))
+ }
+ }
+ ast_map::node_item(@{
+ node: ast::item_impl(_, _, _, methods), _
+ }, _) {
+ vec::map(methods) {|method|
+ (method.ident, attr_parser::parse_method(method.attrs))
+ }
+ }
+ _ { fail "unexpected item" }
+ }
+ };
+
+ vec::map2(docs, attrs) {|doc, attrs|
+ assert doc.name == tuple::first(attrs);
+ let attrs = tuple::second(attrs);
+
+ {
+ brief: attrs.brief,
+ desc: attrs.desc,
+ args: merge_arg_attrs(doc.args, attrs.args),
+ return: merge_ret_attrs(doc.return, attrs.return),
+ failure: attrs.failure
+ with doc
+ }
+ }
+}
+
+#[test]
+fn should_extract_iface_docs() {
+ let doc = test::mk_doc("#[doc = \"whatever\"] iface i { fn a(); }");
+ assert doc.topmod.ifaces()[0].desc == some("whatever");
+}
+
+#[test]
+fn should_extract_iface_method_docs() {
+ let doc = test::mk_doc(
+ "iface i {\
+ #[doc(\
+ brief = \"brief\",\
+ desc = \"desc\",\
+ args(a = \"a\"),\
+ return = \"return\",\
+ failure = \"failure\")]\
+ fn f(a: bool) -> bool;\
+ }");
+ assert doc.topmod.ifaces()[0].methods[0].brief == some("brief");
+ assert doc.topmod.ifaces()[0].methods[0].desc == some("desc");
+ assert doc.topmod.ifaces()[0].methods[0].args[0].desc == some("a");
+ assert doc.topmod.ifaces()[0].methods[0].return.desc == some("return");
+ assert doc.topmod.ifaces()[0].methods[0].failure == some("failure");
+}
+
+
+fn fold_impl(
+ fold: fold::fold<astsrv::srv>,
+ doc: doc::impldoc
+) -> doc::impldoc {
+ let srv = fold.ctxt;
+ let doc = fold::default_seq_fold_impl(fold, doc);
+ let attrs = parse_item_attrs(srv, doc.id, attr_parser::parse_impl);
+
+ {
+ brief: attrs.brief,
+ desc: attrs.desc,
+ methods: merge_method_attrs(srv, doc.id, doc.methods)
+ with doc
+ }
+}
+
+#[test]
+fn should_extract_impl_docs() {
+ let doc = test::mk_doc(
+ "#[doc = \"whatever\"] impl i for int { fn a() { } }");
+ assert doc.topmod.impls()[0].desc == some("whatever");
+}
+
+#[test]
+fn should_extract_impl_method_docs() {
+ let doc = test::mk_doc(
+ "impl i for int {\
+ #[doc(\
+ brief = \"brief\",\
+ desc = \"desc\",\
+ args(a = \"a\"),\
+ return = \"return\",\
+ failure = \"failure\")]\
+ fn f(a: bool) -> bool { }\
+ }");
+ assert doc.topmod.impls()[0].methods[0].brief == some("brief");
+ assert doc.topmod.impls()[0].methods[0].desc == some("desc");
+ assert doc.topmod.impls()[0].methods[0].args[0].desc == some("a");
+ assert doc.topmod.impls()[0].methods[0].return.desc == some("return");
+ assert doc.topmod.impls()[0].methods[0].failure == some("failure");
+}
+
+fn fold_type(
+ fold: fold::fold<astsrv::srv>,
+ doc: doc::tydoc
+) -> doc::tydoc {
+ let srv = fold.ctxt;
+ let doc = fold::default_seq_fold_type(fold, doc);
+ let attrs = parse_item_attrs(srv, doc.id, attr_parser::parse_type);
+
+ {
+ brief: attrs.brief,
+ desc: attrs.desc
+ with doc
+ }
+}
+
+#[test]
+fn should_extract_type_docs() {
+ let doc = test::mk_doc(
+ "#[doc(brief = \"brief\", desc = \"desc\")]\
+ type t = int;");
+ assert doc.topmod.types()[0].brief == some("brief");
+ assert doc.topmod.types()[0].desc == some("desc");
+}
+
+#[cfg(test)]
+mod test {
+ fn mk_doc(source: str) -> doc::cratedoc {
+ let srv = astsrv::mk_srv_from_str(source);
+ let doc = extract::from_srv(srv, "");
+ run(srv, doc)
+ }
}
\ No newline at end of file
")]
resource bored(bored: bool) {
log(error, bored);
+}
+
+#[doc(
+ brief = "The Shunned House",
+ desc = "
+
+From even the greatest of horrors irony is seldom absent. Sometimes it
+enters directly into the composition of the events, while sometimes it
+relates only to their fortuitous position among persons and
+places. The latter sort is splendidly exemplified by a case in the
+ancient city of Providence, where in the late forties Edgar Allan Poe
+used to sojourn often during his unsuccessful wooing of the gifted
+poetess, Mrs. Whitman. Poe generally stopped at the Mansion House in
+Benefit Street--the renamed Golden Ball Inn whose roof has sheltered
+Washington, Jefferson, and Lafayette--and his favorite walk led
+northward along the same street to Mrs. Whitman's home and the
+neighboring hillside churchyard of St. John's, whose hidden expanse of
+Eighteenth Century gravestones had for him a peculiar fascination.
+
+")]
+iface the_shunned_house {
+ #[doc(
+ desc = "
+
+ Now the irony is this. In this walk, so many times repeated, the
+ world's greatest master of the terrible and the bizarre was
+ obliged to pass a particular house on the eastern side of the
+ street; a dingy, antiquated structure perched on the abruptly
+ rising side hill, with a great unkempt yard dating from a time
+ when the region was partly open country. It does not appear that
+ he ever wrote or spoke of it, nor is there any evidence that he
+ even noticed it. And yet that house, to the two persons in
+ possession of certain information, equals or outranks in horror
+ the wildest fantasy of the genius who so often passed it
+ unknowingly, and stands starkly leering as a symbol of all that is
+ unutterably hideous.
+
+ ",
+ args(
+ a =
+ "A yard dating from a time when the region was partly
+ open country"
+ ))]
+ fn dingy_house(unkempt_yard: int);
+
+ #[doc(
+ desc = "
+
+ The house was--and for that matter still is--of a kind to attract
+ the attention of the curious. Originally a farm or semi-farm
+ building, it followed the average New England colonial lines of
+ the middle Eighteenth Century--the prosperous peaked-roof sort,
+ with two stories and dormerless attic, and with the Georgian
+ doorway and interior panelling dictated by the progress of taste
+ at that time. It faced south, with one gable end buried to the
+ lower windows in the eastward rising hill, and the other exposed
+ to the foundations toward the street. Its construction, over a
+ century and a half ago, had followed the grading and straightening
+ of the road in that especial vicinity; for Benefit Street--at
+ first called Back Street--was laid out as a lane winding amongst
+ the graveyards of the first settlers, and straightened only when
+ the removal of the bodies to the North Burial Ground made it
+ decently possible to cut through the old family plots.
+
+ ",
+ return = "A dingy house with an unkempt yard",
+ failure = "Will fail if bodies are removed from premises"
+ )]
+ fn construct() -> bool;
+}
+
+#[doc = "Whatever"]
+impl of the_shunned_house for omnomnomy {
+ #[doc(args(_unkempt_yard = "Whatever"))]
+ fn dingy_house(_unkempt_yard: int) {
+ }
+
+ fn construct() -> bool {
+ fail;
+ }
}
\ No newline at end of file
fold_const: fold_const,
fold_fn: fold_fn,
fold_enum: fold_enum,
- fold_res: fold_res
+ fold_res: fold_res,
+ fold_iface: fold_iface,
+ fold_impl: fold_impl,
+ fold_type: fold_type
with *fold::default_seq_fold(op)
});
fold.fold_crate(fold, doc)
fn fold_mod(fold: fold::fold<op>, doc: doc::moddoc) -> doc::moddoc {
let doc = fold::default_seq_fold_mod(fold, doc);
- ~{
+ {
brief: maybe_apply_op(fold.ctxt, doc.brief),
desc: maybe_apply_op(fold.ctxt, doc.desc)
- with *doc
+ with doc
}
}
fn fold_const(fold: fold::fold<op>, doc: doc::constdoc) -> doc::constdoc {
let doc = fold::default_seq_fold_const(fold, doc);
- ~{
+ {
brief: maybe_apply_op(fold.ctxt, doc.brief),
desc: maybe_apply_op(fold.ctxt, doc.desc)
- with *doc
+ with doc
}
}
fn fold_fn(fold: fold::fold<op>, doc: doc::fndoc) -> doc::fndoc {
let doc = fold::default_seq_fold_fn(fold, doc);
- ~{
+ {
brief: maybe_apply_op(fold.ctxt, doc.brief),
desc: maybe_apply_op(fold.ctxt, doc.desc),
args: vec::map(doc.args) {|doc|
- ~{
+ {
desc: maybe_apply_op(fold.ctxt, doc.desc)
- with *doc
+ with doc
}
},
return: {
with doc.return
},
failure: maybe_apply_op(fold.ctxt, doc.failure)
- with *doc
+ with doc
}
}
fn fold_enum(fold: fold::fold<op>, doc: doc::enumdoc) -> doc::enumdoc {
- ~{
+ {
brief: maybe_apply_op(fold.ctxt, doc.brief),
desc: maybe_apply_op(fold.ctxt, doc.desc),
variants: vec::map(doc.variants) {|variant|
- ~{
+ {
desc: maybe_apply_op(fold.ctxt, variant.desc)
- with *variant
+ with variant
}
}
- with *doc
+ with doc
}
}
fn fold_res(fold: fold::fold<op>, doc: doc::resdoc) -> doc::resdoc {
- ~{
+ {
brief: maybe_apply_op(fold.ctxt, doc.brief),
desc: maybe_apply_op(fold.ctxt, doc.desc),
args: vec::map(doc.args) {|arg|
- ~{
+ {
desc: maybe_apply_op(fold.ctxt, arg.desc)
- with *arg
+ with arg
}
}
- with *doc
+ with doc
+ }
+}
+
+fn fold_iface(fold: fold::fold<op>, doc: doc::ifacedoc) -> doc::ifacedoc {
+ {
+ brief: maybe_apply_op(fold.ctxt, doc.brief),
+ desc: maybe_apply_op(fold.ctxt, doc.desc),
+ methods: apply_to_methods(fold.ctxt, doc.methods)
+ with doc
+ }
+}
+
+fn apply_to_methods(op: op, docs: [doc::methoddoc]) -> [doc::methoddoc] {
+ vec::map(docs) {|doc|
+ {
+ brief: maybe_apply_op(op, doc.brief),
+ desc: maybe_apply_op(op, doc.desc),
+ args: vec::map(doc.args) {|doc|
+ {
+ desc: maybe_apply_op(op, doc.desc)
+ with doc
+ }
+ },
+ return: {
+ desc: maybe_apply_op(op, doc.return.desc)
+ with doc.return
+ },
+ failure: maybe_apply_op(op, doc.failure)
+ with doc
+ }
+ }
+}
+
+fn fold_impl(fold: fold::fold<op>, doc: doc::impldoc) -> doc::impldoc {
+ {
+ brief: maybe_apply_op(fold.ctxt, doc.brief),
+ desc: maybe_apply_op(fold.ctxt, doc.desc),
+ methods: apply_to_methods(fold.ctxt, doc.methods)
+ with doc
+ }
+}
+
+fn fold_type(fold: fold::fold<op>, doc: doc::tydoc) -> doc::tydoc {
+ {
+ brief: maybe_apply_op(fold.ctxt, doc.brief),
+ desc: maybe_apply_op(fold.ctxt, doc.desc)
+ with doc
}
}
#[test]
fn should_execute_op_on_enum_brief() {
- let source = "#[doc(brief = \" a \")] enum a { b }";
- let srv = astsrv::mk_srv_from_str(source);
- let doc = extract::from_srv(srv, "");
- let doc = attr_pass::mk_pass()(srv, doc);
- let doc = mk_pass(str::trim)(srv, doc);
- assert doc.topmod.enums[0].brief == some("a");
+ let doc = test::mk_doc("#[doc(brief = \" a \")] enum a { b }");
+ assert doc.topmod.enums()[0].brief == some("a");
}
#[test]
fn should_execute_op_on_enum_desc() {
- let source = "#[doc(desc = \" a \")] enum a { b }";
- let srv = astsrv::mk_srv_from_str(source);
- let doc = extract::from_srv(srv, "");
- let doc = attr_pass::mk_pass()(srv, doc);
- let doc = mk_pass(str::trim)(srv, doc);
- assert doc.topmod.enums[0].desc == some("a");
+ let doc = test::mk_doc("#[doc(desc = \" a \")] enum a { b }");
+ assert doc.topmod.enums()[0].desc == some("a");
}
#[test]
fn should_execute_op_on_variant_desc() {
- let source = "enum a { #[doc = \" a \"] b }";
- let srv = astsrv::mk_srv_from_str(source);
- let doc = extract::from_srv(srv, "");
- let doc = attr_pass::mk_pass()(srv, doc);
- let doc = mk_pass(str::trim)(srv, doc);
- assert doc.topmod.enums[0].variants[0].desc == some("a");
+ let doc = test::mk_doc("enum a { #[doc = \" a \"] b }");
+ assert doc.topmod.enums()[0].variants[0].desc == some("a");
}
#[test]
fn should_execute_op_on_resource_brief() {
- let source = "#[doc(brief = \" a \")] resource r(a: bool) { }";
- let srv = astsrv::mk_srv_from_str(source);
- let doc = extract::from_srv(srv, "");
- let doc = attr_pass::mk_pass()(srv, doc);
- let doc = mk_pass(str::trim)(srv, doc);
- assert doc.topmod.resources[0].brief == some("a");
+ let doc = test::mk_doc("#[doc(brief = \" a \")] resource r(a: bool) { }");
+ assert doc.topmod.resources()[0].brief == some("a");
}
#[test]
fn should_execute_op_on_resource_desc() {
- let source = "#[doc(desc = \" a \")] resource r(a: bool) { }";
- let srv = astsrv::mk_srv_from_str(source);
- let doc = extract::from_srv(srv, "");
- let doc = attr_pass::mk_pass()(srv, doc);
- let doc = mk_pass(str::trim)(srv, doc);
- assert doc.topmod.resources[0].desc == some("a");
+ let doc = test::mk_doc("#[doc(desc = \" a \")] resource r(a: bool) { }");
+ assert doc.topmod.resources()[0].desc == some("a");
}
#[test]
fn should_execute_op_on_resource_args() {
- let source = "#[doc(args(a = \" a \"))] resource r(a: bool) { }";
- let srv = astsrv::mk_srv_from_str(source);
- let doc = extract::from_srv(srv, "");
- let doc = attr_pass::mk_pass()(srv, doc);
- let doc = mk_pass(str::trim)(srv, doc);
- assert doc.topmod.resources[0].args[0].desc == some("a");
+ let doc = test::mk_doc(
+ "#[doc(args(a = \" a \"))] resource r(a: bool) { }");
+ assert doc.topmod.resources()[0].args[0].desc == some("a");
+}
+
+#[test]
+fn should_execute_op_on_iface_brief() {
+ let doc = test::mk_doc(
+ "#[doc(brief = \" a \")] iface i { fn a(); }");
+ assert doc.topmod.ifaces()[0].brief == some("a");
+}
+
+#[test]
+fn should_execute_op_on_iface_desc() {
+ let doc = test::mk_doc(
+ "#[doc(desc = \" a \")] iface i { fn a(); }");
+ assert doc.topmod.ifaces()[0].desc == some("a");
+}
+
+#[test]
+fn should_execute_op_on_iface_method_brief() {
+ let doc = test::mk_doc(
+ "iface i { #[doc(brief = \" a \")] fn a(); }");
+ assert doc.topmod.ifaces()[0].methods[0].brief == some("a");
+}
+
+#[test]
+fn should_execute_op_on_iface_method_desc() {
+ let doc = test::mk_doc(
+ "iface i { #[doc(desc = \" a \")] fn a(); }");
+ assert doc.topmod.ifaces()[0].methods[0].desc == some("a");
+}
+
+#[test]
+fn should_execute_op_on_iface_method_args() {
+ let doc = test::mk_doc(
+ "iface i { #[doc(args(a = \" a \"))] fn a(a: bool); }");
+ assert doc.topmod.ifaces()[0].methods[0].args[0].desc == some("a");
+}
+
+#[test]
+fn should_execute_op_on_iface_method_return() {
+ let doc = test::mk_doc(
+ "iface i { #[doc(return = \" a \")] fn a() -> int; }");
+ assert doc.topmod.ifaces()[0].methods[0].return.desc == some("a");
+}
+
+#[test]
+fn should_execute_op_on_iface_method_failure_condition() {
+ let doc = test::mk_doc("iface i { #[doc(failure = \" a \")] fn a(); }");
+ assert doc.topmod.ifaces()[0].methods[0].failure == some("a");
+}
+
+#[test]
+fn should_execute_op_on_impl_brief() {
+ let doc = test::mk_doc(
+ "#[doc(brief = \" a \")] impl i for int { fn a() { } }");
+ assert doc.topmod.impls()[0].brief == some("a");
+}
+
+#[test]
+fn should_execute_op_on_impl_desc() {
+ let doc = test::mk_doc(
+ "#[doc(desc = \" a \")] impl i for int { fn a() { } }");
+ assert doc.topmod.impls()[0].desc == some("a");
+}
+
+#[test]
+fn should_execute_op_on_impl_method_brief() {
+ let doc = test::mk_doc(
+ "impl i for int { #[doc(brief = \" a \")] fn a() { } }");
+ assert doc.topmod.impls()[0].methods[0].brief == some("a");
+}
+
+#[test]
+fn should_execute_op_on_impl_method_desc() {
+ let doc = test::mk_doc(
+ "impl i for int { #[doc(desc = \" a \")] fn a() { } }");
+ assert doc.topmod.impls()[0].methods[0].desc == some("a");
+}
+
+#[test]
+fn should_execute_op_on_impl_method_args() {
+ let doc = test::mk_doc(
+ "impl i for int { #[doc(args(a = \" a \"))] fn a(a: bool) { } }");
+ assert doc.topmod.impls()[0].methods[0].args[0].desc == some("a");
+}
+
+#[test]
+fn should_execute_op_on_impl_method_return() {
+ let doc = test::mk_doc(
+ "impl i for int { #[doc(return = \" a \")] fn a() -> int { fail } }");
+ assert doc.topmod.impls()[0].methods[0].return.desc == some("a");
+}
+
+#[test]
+fn should_execute_op_on_impl_method_failure_condition() {
+ let doc = test::mk_doc(
+ "impl i for int { #[doc(failure = \" a \")] fn a() { } }");
+ assert doc.topmod.impls()[0].methods[0].failure == some("a");
+}
+
+
+#[test]
+fn should_execute_op_on_type_brief() {
+ let doc = test::mk_doc(
+ "#[doc(brief = \" a \")] type t = int;");
+ assert doc.topmod.types()[0].brief == some("a");
+}
+
+#[test]
+fn should_execute_op_on_type_desc() {
+ let doc = test::mk_doc(
+ "#[doc(desc = \" a \")] type t = int;");
+ assert doc.topmod.types()[0].desc == some("a");
+}
+
+#[cfg(test)]
+mod test {
+ fn mk_doc(source: str) -> doc::cratedoc {
+ let srv = astsrv::mk_srv_from_str(source);
+ let doc = extract::from_srv(srv, "");
+ let doc = attr_pass::mk_pass()(srv, doc);
+ mk_pass(str::trim)(srv, doc)
+ }
}
\ No newline at end of file
fold_const: fold_const,
fold_fn: fold_fn,
fold_enum: fold_enum,
- fold_res: fold_res
+ fold_res: fold_res,
+ fold_iface: fold_iface,
+ fold_impl: fold_impl,
+ fold_type: fold_type
with *fold::default_seq_fold(())
});
fold.fold_crate(fold, doc)
let doc = fold::default_seq_fold_mod(fold, doc);
let (brief, desc) = modify(doc.brief, doc.desc);
- ~{
+ {
brief: brief,
desc: desc
- with *doc
+ with doc
}
}
let doc = fold::default_seq_fold_const(fold, doc);
let (brief, desc) = modify(doc.brief, doc.desc);
- ~{
+ {
brief: brief,
desc: desc
- with *doc
+ with doc
}
}
let doc = fold::default_seq_fold_fn(fold, doc);
let (brief, desc) = modify(doc.brief, doc.desc);
- ~{
+ {
brief: brief,
desc: desc
- with *doc
+ with doc
}
}
let doc = fold::default_seq_fold_enum(fold, doc);
let (brief, desc) = modify(doc.brief, doc.desc);
- ~{
+ {
brief: brief,
desc: desc
- with *doc
+ with doc
}
}
let doc = fold::default_seq_fold_res(fold, doc);
let (brief, desc) = modify(doc.brief, doc.desc);
- ~{
+ {
brief: brief,
desc: desc
- with *doc
+ with doc
+ }
+}
+
+fn fold_iface(fold: fold::fold<()>, doc: doc::ifacedoc) -> doc::ifacedoc {
+ let doc =fold::default_seq_fold_iface(fold, doc);
+ let (brief, desc) = modify(doc.brief, doc.desc);
+
+ {
+ brief: brief,
+ desc: desc,
+ methods: vec::map(doc.methods) {|doc|
+ let (brief, desc) = modify(doc.brief, doc.desc);
+
+ {
+ brief: brief,
+ desc: desc
+ with doc
+ }
+ }
+ with doc
+ }
+}
+
+fn fold_impl(fold: fold::fold<()>, doc: doc::impldoc) -> doc::impldoc {
+ let doc =fold::default_seq_fold_impl(fold, doc);
+ let (brief, desc) = modify(doc.brief, doc.desc);
+
+ {
+ brief: brief,
+ desc: desc,
+ methods: vec::map(doc.methods) {|doc|
+ let (brief, desc) = modify(doc.brief, doc.desc);
+
+ {
+ brief: brief,
+ desc: desc
+ with doc
+ }
+ }
+ with doc
+ }
+}
+
+fn fold_type(fold: fold::fold<()>, doc: doc::tydoc) -> doc::tydoc {
+ let doc = fold::default_seq_fold_type(fold, doc);
+ let (brief, desc) = modify(doc.brief, doc.desc);
+
+ {
+ brief: brief,
+ desc: desc
+ with doc
}
}
#[test]
fn should_promote_mod_desc() {
- let source = "#[doc(desc = \"desc\")] mod m { }";
- let srv = astsrv::mk_srv_from_str(source);
- let doc = extract::from_srv(srv, "");
- let doc = attr_pass::mk_pass()(srv, doc);
- let doc = run(srv, doc);
- assert doc.topmod.mods[0].brief == some("desc");
- assert doc.topmod.mods[0].desc == none;
+ let doc = test::mk_doc("#[doc(desc = \"desc\")] mod m { }");
+ assert doc.topmod.mods()[0].brief == some("desc");
+ assert doc.topmod.mods()[0].desc == none;
}
#[test]
fn should_promote_const_desc() {
- let source = "#[doc(desc = \"desc\")] const a: bool = true;";
- let srv = astsrv::mk_srv_from_str(source);
- let doc = extract::from_srv(srv, "");
- let doc = attr_pass::mk_pass()(srv, doc);
- let doc = run(srv, doc);
- assert doc.topmod.consts[0].brief == some("desc");
- assert doc.topmod.consts[0].desc == none;
+ let doc = test::mk_doc("#[doc(desc = \"desc\")] const a: bool = true;");
+ assert doc.topmod.consts()[0].brief == some("desc");
+ assert doc.topmod.consts()[0].desc == none;
}
#[test]
fn should_promote_fn_desc() {
- let source = "#[doc(desc = \"desc\")] fn a() { }";
- let srv = astsrv::mk_srv_from_str(source);
- let doc = extract::from_srv(srv, "");
- let doc = attr_pass::mk_pass()(srv, doc);
- let doc = run(srv, doc);
- assert doc.topmod.fns[0].brief == some("desc");
- assert doc.topmod.fns[0].desc == none;
+ let doc = test::mk_doc("#[doc(desc = \"desc\")] fn a() { }");
+ assert doc.topmod.fns()[0].brief == some("desc");
+ assert doc.topmod.fns()[0].desc == none;
}
#[test]
fn should_promote_enum_desc() {
- let source = "#[doc(desc = \"desc\")] enum a { b }";
- let srv = astsrv::mk_srv_from_str(source);
- let doc = extract::from_srv(srv, "");
- let doc = attr_pass::mk_pass()(srv, doc);
- let doc = run(srv, doc);
- assert doc.topmod.enums[0].brief == some("desc");
- assert doc.topmod.enums[0].desc == none;
+ let doc = test::mk_doc("#[doc(desc = \"desc\")] enum a { b }");
+ assert doc.topmod.enums()[0].brief == some("desc");
+ assert doc.topmod.enums()[0].desc == none;
}
#[test]
fn should_promote_resource_desc() {
- let source = "#[doc(desc = \"desc\")] resource r(a: bool) { }";
- let srv = astsrv::mk_srv_from_str(source);
- let doc = extract::from_srv(srv, "");
- let doc = attr_pass::mk_pass()(srv, doc);
- let doc = run(srv, doc);
- assert doc.topmod.resources[0].brief == some("desc");
- assert doc.topmod.resources[0].desc == none;
+ let doc = test::mk_doc(
+ "#[doc(desc = \"desc\")] resource r(a: bool) { }");
+ assert doc.topmod.resources()[0].brief == some("desc");
+ assert doc.topmod.resources()[0].desc == none;
+}
+
+#[test]
+fn should_promote_iface_desc() {
+ let doc = test::mk_doc("#[doc(desc = \"desc\")] iface i { fn a(); }");
+ assert doc.topmod.ifaces()[0].brief == some("desc");
+ assert doc.topmod.ifaces()[0].desc == none;
+}
+
+#[test]
+fn should_promote_iface_method_desc() {
+ let doc = test::mk_doc("iface i { #[doc(desc = \"desc\")] fn a(); }");
+ assert doc.topmod.ifaces()[0].methods[0].brief == some("desc");
+ assert doc.topmod.ifaces()[0].methods[0].desc == none;
+}
+
+#[test]
+fn should_promote_impl_desc() {
+ let doc = test::mk_doc(
+ "#[doc(desc = \"desc\")] impl i for int { fn a() { } }");
+ assert doc.topmod.impls()[0].brief == some("desc");
+ assert doc.topmod.impls()[0].desc == none;
+}
+
+#[test]
+fn should_promote_impl_method_desc() {
+ let doc = test::mk_doc(
+ "impl i for int { #[doc(desc = \"desc\")] fn a() { } }");
+ assert doc.topmod.impls()[0].methods[0].brief == some("desc");
+ assert doc.topmod.impls()[0].methods[0].desc == none;
+}
+
+#[test]
+fn should_promote_type_desc() {
+ let doc = test::mk_doc("#[doc(desc = \"desc\")] type t = int;");
+ assert doc.topmod.types()[0].brief == some("desc");
+ assert doc.topmod.types()[0].desc == none;
+}
+
+#[cfg(test)]
+mod test {
+ fn mk_doc(source: str) -> doc::cratedoc {
+ let srv = astsrv::mk_srv_from_str(source);
+ let doc = extract::from_srv(srv, "");
+ let doc = attr_pass::mk_pass()(srv, doc);
+ run(srv, doc)
+ }
}
fn modify(
type ast_id = int;
-type cratedoc = ~{
+type cratedoc = {
topmod: moddoc,
};
-type moddoc = ~{
+enum itemtag {
+ modtag(moddoc),
+ consttag(constdoc),
+ fntag(fndoc),
+ enumtag(enumdoc),
+ restag(resdoc),
+ ifacetag(ifacedoc),
+ impltag(impldoc),
+ tytag(tydoc)
+}
+
+type moddoc = {
id: ast_id,
name: str,
path: [str],
brief: option<str>,
desc: option<str>,
- mods: modlist,
- fns: fnlist,
- consts: constlist,
- enums: enumlist,
- resources: reslist
+ // This box exists to break the structural recursion
+ items: ~[itemtag]
};
-type constdoc = ~{
+type constdoc = {
id: ast_id,
name: str,
brief: option<str>,
ty: option<str>
};
-type fndoc = ~{
+type fndoc = {
id: ast_id,
name: str,
brief: option<str>,
sig: option<str>
};
-type argdoc = ~{
+type argdoc = {
name: str,
desc: option<str>,
ty: option<str>
ty: option<str>
};
-type enumdoc = ~{
+type enumdoc = {
id: ast_id,
name: str,
brief: option<str>,
variants: [variantdoc]
};
-type variantdoc = ~{
+type variantdoc = {
name: str,
desc: option<str>,
sig: option<str>
};
-type resdoc = ~{
+type resdoc = {
id: ast_id,
name: str,
brief: option<str>,
sig: option<str>
};
-// Just to break the structural recursive types
-enum modlist = [moddoc];
-enum constlist = [constdoc];
-enum fnlist = [fndoc];
-enum enumlist = [enumdoc];
-enum reslist = [resdoc];
+type ifacedoc = {
+ id: ast_id,
+ name: str,
+ brief: option<str>,
+ desc: option<str>,
+ methods: [methoddoc]
+};
+
+type methoddoc = {
+ name: str,
+ brief: option<str>,
+ desc: option<str>,
+ args: [argdoc],
+ return: retdoc,
+ failure: option<str>,
+ sig: option<str>
+};
+
+type impldoc = {
+ id: ast_id,
+ name: str,
+ brief: option<str>,
+ desc: option<str>,
+ iface_ty: option<str>,
+ self_ty: option<str>,
+ methods: [methoddoc]
+};
+
+type tydoc = {
+ id: ast_id,
+ name: str,
+ brief: option<str>,
+ desc: option<str>,
+ sig: option<str>
+};
+
+#[doc = "Some helper methods on moddoc, mostly for testing"]
+impl util for moddoc {
+
+ fn mods() -> [moddoc] {
+ vec::filter_map(*self.items) {|itemtag|
+ alt itemtag {
+ modtag(moddoc) { some(moddoc) }
+ _ { none }
+ }
+ }
+ }
+
+ fn fns() -> [fndoc] {
+ vec::filter_map(*self.items) {|itemtag|
+ alt itemtag {
+ fntag(fndoc) { some(fndoc) }
+ _ { none }
+ }
+ }
+ }
+
+ fn consts() -> [constdoc] {
+ vec::filter_map(*self.items) {|itemtag|
+ alt itemtag {
+ consttag(constdoc) { some(constdoc) }
+ _ { none }
+ }
+ }
+ }
+
+ fn enums() -> [enumdoc] {
+ vec::filter_map(*self.items) {|itemtag|
+ alt itemtag {
+ enumtag(enumdoc) { some(enumdoc) }
+ _ { none }
+ }
+ }
+ }
+
+ fn resources() -> [resdoc] {
+ vec::filter_map(*self.items) {|itemtag|
+ alt itemtag {
+ restag(resdoc) { some(resdoc) }
+ _ { none }
+ }
+ }
+ }
+
+ fn ifaces() -> [ifacedoc] {
+ vec::filter_map(*self.items) {|itemtag|
+ alt itemtag {
+ ifacetag(ifacedoc) { some(ifacedoc) }
+ _ { none }
+ }
+ }
+ }
+
+ fn impls() -> [impldoc] {
+ vec::filter_map(*self.items) {|itemtag|
+ alt itemtag {
+ impltag(impldoc) { some(impldoc) }
+ _ { none }
+ }
+ }
+ }
+
+ fn types() -> [tydoc] {
+ vec::filter_map(*self.items) {|itemtag|
+ alt itemtag {
+ tytag(tydoc) { some(tydoc) }
+ _ { none }
+ }
+ }
+ }
+}
+
+#[doc = "Helper methods on itemtag"]
+impl util for itemtag {
+ fn name() -> str {
+ alt self {
+ doc::modtag({name, _}) { name }
+ doc::fntag({name, _}) { name }
+ doc::consttag({name, _}) { name }
+ doc::enumtag({name, _}) { name }
+ doc::restag({name, _}) { name }
+ doc::ifacetag({name, _}) { name }
+ doc::impltag({name, _}) { name }
+ doc::tytag({name, _}) { name }
+ }
+ }
+}
crate: @ast::crate,
default_name: str
) -> doc::cratedoc {
- ~{
+ {
topmod: top_moddoc_from_crate(crate, default_name),
}
}
name: ast::ident,
id: ast::node_id
) -> doc::moddoc {
- ~{
+ {
id: id,
name: name,
path: [],
brief: none,
desc: none,
- mods: doc::modlist(
- vec::filter_map(module.items) {|item|
- alt item.node {
- ast::item_mod(m) {
- some(moddoc_from_mod(m, item.ident, item.id))
- }
- _ {
- none
- }
- }
- }),
- fns: doc::fnlist(
- vec::filter_map(module.items) {|item|
- alt item.node {
- ast::item_fn(decl, _, _) {
- some(fndoc_from_fn(
- decl, item.ident, item.id))
- }
- _ {
- none
- }
- }
- }),
- consts: doc::constlist(
- vec::filter_map(module.items) {|item|
- alt item.node {
- ast::item_const(_, _) {
- some(constdoc_from_const(item.ident, item.id))
- }
- _ {
- none
- }
- }
- }),
- enums: doc::enumlist(
- vec::filter_map(module.items) {|item|
- alt item.node {
- ast::item_enum(variants, _) {
- some(enumdoc_from_enum(item.ident, item.id, variants))
- }
- _ {
- none
- }
- }
- }),
- resources: doc::reslist(
- vec::filter_map(module.items) {|item|
- alt item.node {
- ast::item_res(decl, _, _, _, _) {
- some(resdoc_from_resource(decl, item.ident, item.id))
- }
- _ {
- none
- }
- }
- })
+ items: ~vec::filter_map(module.items) {|item|
+ alt item.node {
+ ast::item_mod(m) {
+ some(doc::modtag(
+ moddoc_from_mod(m, item.ident, item.id)
+ ))
+ }
+ ast::item_fn(decl, _, _) {
+ some(doc::fntag(
+ fndoc_from_fn(decl, item.ident, item.id)
+ ))
+ }
+ ast::item_const(_, _) {
+ some(doc::consttag(
+ constdoc_from_const(item.ident, item.id)
+ ))
+ }
+ ast::item_enum(variants, _) {
+ some(doc::enumtag(
+ enumdoc_from_enum(item.ident, item.id, variants)
+ ))
+ }
+ ast::item_res(decl, _, _, _, _) {
+ some(doc::restag(
+ resdoc_from_resource(decl, item.ident, item.id)
+ ))
+ }
+ ast::item_iface(_, methods) {
+ some(doc::ifacetag(
+ ifacedoc_from_iface(methods, item.ident, item.id)
+ ))
+ }
+ ast::item_impl(_, _, _, methods) {
+ some(doc::impltag(
+ impldoc_from_impl(methods, item.ident, item.id)
+ ))
+ }
+ ast::item_ty(_, _) {
+ some(doc::tytag(
+ tydoc_from_ty(item.ident, item.id)
+ ))
+ }
+ _ {
+ none
+ }
+ }
+ }
}
}
name: ast::ident,
id: ast::node_id
) -> doc::fndoc {
- ~{
+ {
id: id,
name: name,
brief: none,
let source = "fn a(b: int, c: int) { }";
let ast = parse::from_str(source);
let doc = extract(ast, "");
- let fn_ = doc.topmod.fns[0];
+ let fn_ = doc.topmod.fns()[0];
assert fn_.args[0].name == "b";
assert fn_.args[1].name == "c";
}
}
fn argdoc_from_arg(arg: ast::arg) -> doc::argdoc {
- ~{
+ {
name: arg.ident,
desc: none,
ty: none
name: ast::ident,
id: ast::node_id
) -> doc::constdoc {
- ~{
+ {
id: id,
name: name,
brief: none,
#[test]
fn should_extract_const_name_and_id() {
- let source = "const a: int = 0;";
- let ast = parse::from_str(source);
- let doc = extract(ast, "");
- assert doc.topmod.consts[0].id != 0;
- assert doc.topmod.consts[0].name == "a";
+ let doc = test::mk_doc("const a: int = 0;");
+ assert doc.topmod.consts()[0].id != 0;
+ assert doc.topmod.consts()[0].name == "a";
}
fn enumdoc_from_enum(
id: ast::node_id,
variants: [ast::variant]
) -> doc::enumdoc {
- ~{
+ {
id: id,
name: name,
brief: none,
}
fn variantdoc_from_variant(variant: ast::variant) -> doc::variantdoc {
- ~{
+ {
name: variant.node.name,
desc: none,
sig: none
#[test]
fn should_extract_enums() {
- let source = "enum e { v }";
- let ast = parse::from_str(source);
- let doc = extract(ast, "");
- assert doc.topmod.enums[0].id != 0;
- assert doc.topmod.enums[0].name == "e";
+ let doc = test::mk_doc("enum e { v }");
+ assert doc.topmod.enums()[0].id != 0;
+ assert doc.topmod.enums()[0].name == "e";
}
#[test]
fn should_extract_enum_variants() {
- let source = "enum e { v }";
- let ast = parse::from_str(source);
- let doc = extract(ast, "");
- assert doc.topmod.enums[0].variants[0].name == "v";
+ let doc = test::mk_doc("enum e { v }");
+ assert doc.topmod.enums()[0].variants[0].name == "v";
}
fn resdoc_from_resource(
name: str,
id: ast::node_id
) -> doc::resdoc {
- ~{
+ {
id: id,
name: name,
brief: none,
#[test]
fn should_extract_resources() {
- let source = "resource r(b: bool) { }";
- let ast = parse::from_str(source);
- let doc = extract(ast, "");
- assert doc.topmod.resources[0].id != 0;
- assert doc.topmod.resources[0].name == "r";
+ let doc = test::mk_doc("resource r(b: bool) { }");
+ assert doc.topmod.resources()[0].id != 0;
+ assert doc.topmod.resources()[0].name == "r";
}
#[test]
fn should_extract_resource_args() {
- let source = "resource r(b: bool) { }";
- let ast = parse::from_str(source);
- let doc = extract(ast, "");
- assert doc.topmod.resources[0].args[0].name == "b";
+ let doc = test::mk_doc("resource r(b: bool) { }");
+ assert doc.topmod.resources()[0].args[0].name == "b";
+}
+
+fn ifacedoc_from_iface(
+ methods: [ast::ty_method],
+ name: str,
+ id: ast::node_id
+) -> doc::ifacedoc {
+ {
+ id: id,
+ name: name,
+ brief: none,
+ desc: none,
+ methods: vec::map(methods) {|method|
+ {
+ name: method.ident,
+ brief: none,
+ desc: none,
+ args: argdocs_from_args(method.decl.inputs),
+ return: {
+ desc: none,
+ ty: none
+ },
+ failure: none,
+ sig: none
+ }
+ }
+ }
+}
+
+#[test]
+fn should_extract_ifaces() {
+ let doc = test::mk_doc("iface i { fn f(); }");
+ assert doc.topmod.ifaces()[0].name == "i";
+}
+
+#[test]
+fn should_extract_iface_methods() {
+ let doc = test::mk_doc("iface i { fn f(); }");
+ assert doc.topmod.ifaces()[0].methods[0].name == "f";
+}
+
+#[test]
+fn should_extract_iface_method_args() {
+ let doc = test::mk_doc("iface i { fn f(a: bool); }");
+ assert doc.topmod.ifaces()[0].methods[0].args[0].name == "a";
+}
+
+fn impldoc_from_impl(
+ methods: [@ast::method],
+ name: str,
+ id: ast::node_id
+) -> doc::impldoc {
+ {
+ id: id,
+ name: name,
+ brief: none,
+ desc: none,
+ iface_ty: none,
+ self_ty: none,
+ methods: vec::map(methods) {|method|
+ {
+ name: method.ident,
+ brief: none,
+ desc: none,
+ args: argdocs_from_args(method.decl.inputs),
+ return: {
+ desc: none,
+ ty: none
+ },
+ failure: none,
+ sig: none
+ }
+ }
+ }
+}
+
+#[test]
+fn should_extract_impls_with_names() {
+ let doc = test::mk_doc("impl i for int { fn a() { } }");
+ assert doc.topmod.impls()[0].name == "i";
+}
+
+#[test]
+fn should_extract_impls_without_names() {
+ let doc = test::mk_doc("impl of i for int { fn a() { } }");
+ assert doc.topmod.impls()[0].name == "i";
+}
+
+#[test]
+fn should_extract_impl_methods() {
+ let doc = test::mk_doc("impl i for int { fn f() { } }");
+ assert doc.topmod.impls()[0].methods[0].name == "f";
+}
+
+#[test]
+fn should_extract_impl_method_args() {
+ let doc = test::mk_doc("impl i for int { fn f(a: bool) { } }");
+ assert doc.topmod.impls()[0].methods[0].args[0].name == "a";
+}
+
+fn tydoc_from_ty(
+ name: str,
+ id: ast::node_id
+) -> doc::tydoc {
+ {
+ id: id,
+ name: name,
+ brief: none,
+ desc: none,
+ sig: none
+ }
+}
+
+#[test]
+fn should_extract_tys() {
+ let doc = test::mk_doc("type a = int;");
+ assert doc.topmod.types()[0].name == "a";
}
#[cfg(test)]
-mod tests {
+mod test {
+
+ fn mk_doc(source: str) -> doc::cratedoc {
+ let ast = parse::from_str(source);
+ extract(ast, "")
+ }
#[test]
fn extract_empty_crate() {
- let source = ""; // empty crate
- let ast = parse::from_str(source);
- let doc = extract(ast, "");
- // FIXME #1535: These are boxed to prevent a crash
- assert ~doc.topmod.mods == ~doc::modlist([]);
- assert ~doc.topmod.fns == ~doc::fnlist([]);
+ let doc = mk_doc("");
+ assert vec::is_empty(doc.topmod.mods());
+ assert vec::is_empty(doc.topmod.fns());
}
#[test]
fn extract_mods() {
- let source = "mod a { mod b { } mod c { } }";
- let ast = parse::from_str(source);
- let doc = extract(ast, "");
- assert doc.topmod.mods[0].name == "a";
- assert doc.topmod.mods[0].mods[0].name == "b";
- assert doc.topmod.mods[0].mods[1].name == "c";
+ let doc = mk_doc("mod a { mod b { } mod c { } }");
+ assert doc.topmod.mods()[0].name == "a";
+ assert doc.topmod.mods()[0].mods()[0].name == "b";
+ assert doc.topmod.mods()[0].mods()[1].name == "c";
}
#[test]
fn extract_mods_deep() {
- let source = "mod a { mod b { mod c { } } }";
- let ast = parse::from_str(source);
- let doc = extract(ast, "");
- assert doc.topmod.mods[0].mods[0].mods[0].name == "c";
+ let doc = mk_doc("mod a { mod b { mod c { } } }");
+ assert doc.topmod.mods()[0].mods()[0].mods()[0].name == "c";
}
#[test]
fn extract_should_set_mod_ast_id() {
- let source = "mod a { }";
- let ast = parse::from_str(source);
- let doc = extract(ast, "");
- assert doc.topmod.mods[0].id != 0;
+ let doc = mk_doc("mod a { }");
+ assert doc.topmod.mods()[0].id != 0;
}
#[test]
fn extract_fns() {
- let source =
+ let doc = mk_doc(
"fn a() { } \
- mod b { fn c() { } }";
- let ast = parse::from_str(source);
- let doc = extract(ast, "");
- assert doc.topmod.fns[0].name == "a";
- assert doc.topmod.mods[0].fns[0].name == "c";
+ mod b { fn c() { } }");
+ assert doc.topmod.fns()[0].name == "a";
+ assert doc.topmod.mods()[0].fns()[0].name == "c";
}
#[test]
fn extract_should_set_fn_ast_id() {
- let source = "fn a() { }";
- let ast = parse::from_str(source);
- let doc = extract(ast, "");
- assert doc.topmod.fns[0].id != 0;
+ let doc = mk_doc("fn a() { }");
+ assert doc.topmod.fns()[0].id != 0;
}
#[test]
import std;
export fold;
-export fold_crate, fold_mod, fold_fn, fold_modlist, fold_fnlist;
+export fold_crate, fold_mod, fold_fn;
export default_seq_fold;
export default_seq_fold_crate;
export default_seq_fold_mod;
export default_seq_fold_const;
export default_seq_fold_enum;
export default_seq_fold_res;
-export default_seq_fold_fnlist;
+export default_seq_fold_iface;
+export default_seq_fold_impl;
+export default_seq_fold_type;
enum fold<T> = t<T>;
type fold_const<T> = fn~(fold: fold<T>, doc: doc::constdoc) -> doc::constdoc;
type fold_enum<T> = fn~(fold: fold<T>, doc: doc::enumdoc) -> doc::enumdoc;
type fold_res<T> = fn~(fold: fold<T>, doc: doc::resdoc) -> doc::resdoc;
-type fold_modlist<T> = fn~(fold: fold<T>, list: doc::modlist) -> doc::modlist;
-type fold_fnlist<T> = fn~(fold: fold<T>, list: doc::fnlist) -> doc::fnlist;
-type fold_constlist<T> = fn~(
- fold: fold<T>, list: doc::constlist) -> doc::constlist;
-type fold_enumlist<T> = fn~(
- fold: fold<T>, list: doc::enumlist) -> doc::enumlist;
-type fold_reslist<T> = fn~(
- fold: fold<T>, list: doc::reslist) -> doc::reslist;
+type fold_iface<T> = fn~(fold: fold<T>, doc: doc::ifacedoc) -> doc::ifacedoc;
+type fold_impl<T> = fn~(fold: fold<T>, doc: doc::impldoc) -> doc::impldoc;
+type fold_type<T> = fn~(fold: fold<T>, doc: doc::tydoc) -> doc::tydoc;
type t<T> = {
ctxt: T,
fold_const: fold_const<T>,
fold_enum: fold_enum<T>,
fold_res: fold_res<T>,
- fold_modlist: fold_modlist<T>,
- fold_fnlist: fold_fnlist<T>,
- fold_constlist: fold_constlist<T>,
- fold_enumlist: fold_enumlist<T>,
- fold_reslist: fold_reslist<T>
+ fold_iface: fold_iface<T>,
+ fold_impl: fold_impl<T>,
+ fold_type: fold_type<T>
};
fold_const: fold_const<T>,
fold_enum: fold_enum<T>,
fold_res: fold_res<T>,
- fold_modlist: fold_modlist<T>,
- fold_fnlist: fold_fnlist<T>,
- fold_constlist: fold_constlist<T>,
- fold_enumlist: fold_enumlist<T>,
- fold_reslist: fold_reslist<T>
+ fold_iface: fold_iface<T>,
+ fold_impl: fold_impl<T>,
+ fold_type: fold_type<T>
) -> fold<T> {
fold({
ctxt: ctxt,
fold_const: fold_const,
fold_enum: fold_enum,
fold_res: fold_res,
- fold_modlist: fold_modlist,
- fold_fnlist: fold_fnlist,
- fold_constlist: fold_constlist,
- fold_enumlist: fold_enumlist,
- fold_reslist: fold_reslist
+ fold_iface: fold_iface,
+ fold_impl: fold_impl,
+ fold_type: fold_type
})
}
{|f, d| default_seq_fold_const(f, d)},
{|f, d| default_seq_fold_enum(f, d)},
{|f, d| default_seq_fold_res(f, d)},
- {|f, d| default_seq_fold_modlist(f, d)},
- {|f, d| default_seq_fold_fnlist(f, d)},
- {|f, d| default_seq_fold_constlist(f, d)},
- {|f, d| default_seq_fold_enumlist(f, d)},
- {|f, d| default_seq_fold_reslist(f, d)}
+ {|f, d| default_seq_fold_iface(f, d)},
+ {|f, d| default_seq_fold_impl(f, d)},
+ {|f, d| default_seq_fold_type(f, d)}
)
}
fold: fold<T>,
doc: doc::cratedoc
) -> doc::cratedoc {
- ~{
+ {
topmod: fold.fold_mod(fold, doc.topmod)
}
}
fold: fold<T>,
doc: doc::moddoc
) -> doc::moddoc {
- ~{
- mods: fold.fold_modlist(fold, doc.mods),
- fns: fold.fold_fnlist(fold, doc.fns),
- consts: fold.fold_constlist(fold, doc.consts),
- enums: fold.fold_enumlist(fold, doc.enums),
- resources: fold.fold_reslist(fold, doc.resources)
- with *doc
+ {
+ items: ~vec::map(*doc.items) {|itemtag|
+ alt itemtag {
+ doc::modtag(moddoc) {
+ doc::modtag(fold.fold_mod(fold, moddoc))
+ }
+ doc::fntag(fndoc) {
+ doc::fntag(fold.fold_fn(fold, fndoc))
+ }
+ doc::consttag(constdoc) {
+ doc::consttag(fold.fold_const(fold, constdoc))
+ }
+ doc::enumtag(enumdoc) {
+ doc::enumtag(fold.fold_enum(fold, enumdoc))
+ }
+ doc::restag(resdoc) {
+ doc::restag(fold.fold_res(fold, resdoc))
+ }
+ doc::ifacetag(ifacedoc) {
+ doc::ifacetag(fold.fold_iface(fold, ifacedoc))
+ }
+ doc::impltag(impldoc) {
+ doc::impltag(fold.fold_impl(fold, impldoc))
+ }
+ doc::tytag(tydoc) {
+ doc::tytag(fold.fold_type(fold, tydoc))
+ }
+ }
+ }
+ with doc
}
}
doc
}
-fn default_seq_fold_modlist<T>(
- fold: fold<T>,
- list: doc::modlist
-) -> doc::modlist {
- doc::modlist(vec::map(*list) {|doc|
- fold.fold_mod(fold, doc)
- })
-}
-
-fn default_seq_fold_fnlist<T>(
- fold: fold<T>,
- list: doc::fnlist
-) -> doc::fnlist {
- doc::fnlist(vec::map(*list) {|doc|
- fold.fold_fn(fold, doc)
- })
-}
-
-fn default_seq_fold_constlist<T>(
- fold: fold<T>,
- list: doc::constlist
-) -> doc::constlist {
- doc::constlist(vec::map(*list) {|doc|
- fold.fold_const(fold, doc)
- })
+fn default_seq_fold_iface<T>(
+ _fold: fold<T>,
+ doc: doc::ifacedoc
+) -> doc::ifacedoc {
+ doc
}
-fn default_seq_fold_enumlist<T>(
- fold: fold<T>,
- list: doc::enumlist
-) -> doc::enumlist {
- doc::enumlist(vec::map(*list) {|doc|
- fold.fold_enum(fold, doc)
- })
+fn default_seq_fold_impl<T>(
+ _fold: fold<T>,
+ doc: doc::impldoc
+) -> doc::impldoc {
+ doc
}
-fn default_seq_fold_reslist<T>(
- fold: fold<T>,
- list: doc::reslist
-) -> doc::reslist {
- doc::reslist(vec::map(*list) {|doc|
- fold.fold_res(fold, doc)
- })
+fn default_seq_fold_type<T>(
+ _fold: fold<T>,
+ doc: doc::tydoc
+) -> doc::tydoc {
+ doc
}
#[test]
export mk_pass;
+// FIXME: This is a really convoluted interface to work around trying
+// to get a writer into a unique closure and then being able to test
+// what was written afterward
fn mk_pass(
- writer: fn~() -> io::writer
+ give_writer: fn~(fn(io::writer))
) -> pass {
- ret fn~(
- _srv: astsrv::srv,
+ fn~(
+ srv: astsrv::srv,
doc: doc::cratedoc
) -> doc::cratedoc {
- write_markdown(doc, writer());
+
+ fn mods_last(item1: doc::itemtag, item2: doc::itemtag) -> bool {
+ fn is_mod(item: doc::itemtag) -> bool {
+ alt item {
+ doc::modtag(_) { true }
+ _ { false }
+ }
+ }
+
+ let lteq = !is_mod(item1) || is_mod(item2);
+ lteq
+ }
+
+ give_writer {|writer|
+ // Sort the items so mods come last. All mods will be
+ // output at the same header level so sorting mods last
+ // makes the headers come out nested correctly.
+ let sorted_doc = sort_pass::mk_pass(mods_last)(srv, doc);
+
+ write_markdown(sorted_doc, writer);
+ }
doc
- };
+ }
+}
+
+#[test]
+fn should_write_modules_last() {
+ /*
+ Because the markdown pass writes all modules at the same level of
+ indentation (it doesn't 'nest' them), we need to make sure that we
+ write all of the modules contained in each module after all other
+ types of items, or else the header nesting will end up wrong, with
+ modules appearing to contain items that they do not.
+ */
+ let markdown = test::render(
+ "mod a { }\
+ fn b() { }\
+ mod c { }\
+ fn d() { }"
+ );
+
+ let idx_a = str::find(markdown, "# Module `a`");
+ let idx_b = str::find(markdown, "## Function `b`");
+ let idx_c = str::find(markdown, "# Module `c`");
+ let idx_d = str::find(markdown, "## Function `d`");
+
+ assert idx_b < idx_d;
+ assert idx_d < idx_a;
+ assert idx_a < idx_c;
}
type ctxt = {
write_brief(ctxt, doc.brief);
write_desc(ctxt, doc.desc);
- for constdoc in *doc.consts {
- write_const(ctxt, constdoc);
- }
-
- for enumdoc in *doc.enums {
- write_enum(ctxt, enumdoc);
- }
-
- for fndoc in *doc.fns {
- write_fn(ctxt, fndoc);
- }
-
- for resdoc in *doc.resources {
- write_res(ctxt, resdoc);
- }
-
- for moddoc in *doc.mods {
- write_mod(ctxt, moddoc);
+ for itemtag in *doc.items {
+ alt itemtag {
+ doc::modtag(moddoc) { write_mod(ctxt, moddoc) }
+ doc::fntag(fndoc) { write_fn(ctxt, fndoc) }
+ doc::consttag(constdoc) { write_const(ctxt, constdoc) }
+ doc::enumtag(enumdoc) { write_enum(ctxt, enumdoc) }
+ doc::restag(resdoc) { write_res(ctxt, resdoc) }
+ doc::ifacetag(ifacedoc) { write_iface(ctxt, ifacedoc) }
+ doc::impltag(impldoc) { write_impl(ctxt, impldoc) }
+ doc::tytag(tydoc) { write_type(ctxt, tydoc) }
+ }
}
}
doc: doc::fndoc
) {
write_header(ctxt, h2, #fmt("Function `%s`", doc.name));
- write_sig(ctxt, doc.sig);
- write_brief(ctxt, doc.brief);
- write_desc(ctxt, doc.desc);
- write_args(ctxt, doc.args);
- write_return(ctxt, doc.return);
- write_failure(ctxt, doc.failure);
+ write_fnlike(
+ ctxt,
+ doc.sig,
+ doc.brief,
+ doc.desc,
+ doc.args,
+ doc.return,
+ doc.failure
+ );
+}
+
+fn write_fnlike(
+ ctxt: ctxt,
+ sig: option<str>,
+ brief: option<str>,
+ desc: option<str>,
+ args: [doc::argdoc],
+ return: doc::retdoc,
+ failure: option<str>
+) {
+ write_sig(ctxt, sig);
+ write_brief(ctxt, brief);
+ write_desc(ctxt, desc);
+ write_args(ctxt, args);
+ write_return(ctxt, return);
+ write_failure(ctxt, failure);
}
fn write_sig(ctxt: ctxt, sig: option<str>) {
#[test]
fn should_correctly_indent_fn_signature() {
let doc = test::create_doc("fn a() { }");
- let doc = ~{
- topmod: ~{
- fns: doc::fnlist([~{
+ let doc = {
+ topmod: {
+ items: ~[doc::fntag({
sig: some("line 1\nline 2")
- with *doc.topmod.fns[0]
- }])
- with *doc.topmod
+ with doc.topmod.fns()[0]
+ })]
+ with doc.topmod
}
- with *doc
+ with doc
};
let markdown = test::write_markdown_str(doc);
assert str::contains(markdown, " line 1\n line 2");
assert str::contains(markdown, "Arguments:\n\n* `a`: `bool` - b");
}
+fn write_iface(ctxt: ctxt, doc: doc::ifacedoc) {
+ write_header(ctxt, h2, #fmt("Interface `%s`", doc.name));
+ write_brief(ctxt, doc.brief);
+ write_desc(ctxt, doc.desc);
+ write_methods(ctxt, doc.methods);
+}
+
+fn write_methods(ctxt: ctxt, docs: [doc::methoddoc]) {
+ vec::iter(docs) {|doc| write_method(ctxt, doc) }
+}
+
+fn write_method(ctxt: ctxt, doc: doc::methoddoc) {
+ write_header(ctxt, h3, #fmt("Method `%s`", doc.name));
+ write_fnlike(
+ ctxt,
+ doc.sig,
+ doc.brief,
+ doc.desc,
+ doc.args,
+ doc.return,
+ doc.failure
+ );
+}
+
+#[test]
+fn should_write_iface_header() {
+ let markdown = test::render("iface i { fn a(); }");
+ assert str::contains(markdown, "## Interface `i`");
+}
+
+#[test]
+fn should_write_iface_brief() {
+ let markdown = test::render(
+ "#[doc(brief = \"brief\")] iface i { fn a(); }");
+ assert str::contains(markdown, "brief");
+}
+
+#[test]
+fn should_write_iface_desc() {
+ let markdown = test::render(
+ "#[doc(desc = \"desc\")] iface i { fn a(); }");
+ assert str::contains(markdown, "desc");
+}
+
+#[test]
+fn should_write_iface_method_header() {
+ let markdown = test::render(
+ "iface i { fn a(); }");
+ assert str::contains(markdown, "### Method `a`");
+}
+
+#[test]
+fn should_write_iface_method_signature() {
+ let markdown = test::render(
+ "iface i { fn a(); }");
+ assert str::contains(markdown, "\n fn a()");
+}
+
+#[test]
+fn should_write_iface_method_argument_header() {
+ let markdown = test::render(
+ "iface a { fn a(b: int); }");
+ assert str::contains(markdown, "\n\nArguments:\n\n");
+}
+
+#[test]
+fn should_write_iface_method_arguments() {
+ let markdown = test::render(
+ "iface a { fn a(b: int); }");
+ assert str::contains(markdown, "* `b`: `int`\n");
+}
+
+#[test]
+fn should_not_write_iface_method_arguments_if_none() {
+ let markdown = test::render(
+ "iface a { fn a(); }");
+ assert !str::contains(markdown, "Arguments");
+}
+
+#[test]
+fn should_write_iface_method_return_info() {
+ let markdown = test::render(
+ "iface a { fn a() -> int; }");
+ assert str::contains(markdown, "Returns `int`");
+}
+
+#[test]
+fn should_write_iface_method_failure_conditions() {
+ let markdown = test::render(
+ "iface a { #[doc(failure = \"nuked\")] fn a(); }");
+ assert str::contains(markdown, "Failure conditions: nuked");
+}
+
+fn write_impl(ctxt: ctxt, doc: doc::impldoc) {
+ assert option::is_some(doc.self_ty);
+ let self_ty = option::get(doc.self_ty);
+ alt doc.iface_ty {
+ some(iface_ty) {
+ write_header(ctxt, h2,
+ #fmt("Implementation `%s` of `%s` for `%s`",
+ doc.name, iface_ty, self_ty));
+ }
+ none {
+ write_header(ctxt, h2,
+ #fmt("Implementation `%s` for `%s`",
+ doc.name, self_ty));
+ }
+ }
+ write_brief(ctxt, doc.brief);
+ write_desc(ctxt, doc.desc);
+ write_methods(ctxt, doc.methods);
+}
+
+#[test]
+fn should_write_impl_header() {
+ let markdown = test::render("impl i for int { fn a() { } }");
+ assert str::contains(markdown, "## Implementation `i` for `int`");
+}
+
+#[test]
+fn should_write_impl_header_with_iface() {
+ let markdown = test::render("impl i of j for int { fn a() { } }");
+ assert str::contains(markdown, "## Implementation `i` of `j` for `int`");
+}
+
+#[test]
+fn should_write_impl_brief() {
+ let markdown = test::render(
+ "#[doc(brief = \"brief\")] impl i for int { fn a() { } }");
+ assert str::contains(markdown, "brief");
+}
+
+#[test]
+fn should_write_impl_desc() {
+ let markdown = test::render(
+ "#[doc(desc = \"desc\")] impl i for int { fn a() { } }");
+ assert str::contains(markdown, "desc");
+}
+
+#[test]
+fn should_write_impl_method_header() {
+ let markdown = test::render(
+ "impl i for int { fn a() { } }");
+ assert str::contains(markdown, "### Method `a`");
+}
+
+#[test]
+fn should_write_impl_method_signature() {
+ let markdown = test::render(
+ "impl i for int { fn a() { } }");
+ assert str::contains(markdown, "\n fn a()");
+}
+
+#[test]
+fn should_write_impl_method_argument_header() {
+ let markdown = test::render(
+ "impl a for int { fn a(b: int) { } }");
+ assert str::contains(markdown, "\n\nArguments:\n\n");
+}
+
+#[test]
+fn should_write_impl_method_arguments() {
+ let markdown = test::render(
+ "impl a for int { fn a(b: int) { } }");
+ assert str::contains(markdown, "* `b`: `int`\n");
+}
+
+#[test]
+fn should_not_write_impl_method_arguments_if_none() {
+ let markdown = test::render(
+ "impl a for int { fn a() { } }");
+ assert !str::contains(markdown, "Arguments");
+}
+
+#[test]
+fn should_write_impl_method_return_info() {
+ let markdown = test::render(
+ "impl a for int { fn a() -> int { } }");
+ assert str::contains(markdown, "Returns `int`");
+}
+
+#[test]
+fn should_write_impl_method_failure_conditions() {
+ let markdown = test::render(
+ "impl a for int { #[doc(failure = \"nuked\")] fn a() { } }");
+ assert str::contains(markdown, "Failure conditions: nuked");
+}
+
+fn write_type(
+ ctxt: ctxt,
+ doc: doc::tydoc
+) {
+ write_header(ctxt, h2, #fmt("Type `%s`", doc.name));
+ write_sig(ctxt, doc.sig);
+ write_brief(ctxt, doc.brief);
+ write_desc(ctxt, doc.desc);
+}
+
+#[test]
+fn should_write_type_header() {
+ let markdown = test::render("type t = int;");
+ assert str::contains(markdown, "## Type `t`");
+}
+
+#[test]
+fn should_write_type_brief() {
+ let markdown = test::render(
+ "#[doc(brief = \"brief\")] type t = int;");
+ assert str::contains(markdown, "\n\nbrief\n\n");
+}
+
+#[test]
+fn should_write_type_desc() {
+ let markdown = test::render(
+ "#[doc(desc = \"desc\")] type t = int;");
+ assert str::contains(markdown, "\n\ndesc\n\n");
+}
+
+#[test]
+fn should_write_type_signature() {
+ let markdown = test::render("type t = int;");
+ assert str::contains(markdown, "\n\n type t = int\n\n");
+}
+
#[cfg(test)]
mod test {
fn render(source: str) -> str {
- let doc = create_doc(source);
- let markdown = write_markdown_str(doc);
+ let (srv, doc) = create_doc_srv(source);
+ let markdown = write_markdown_str_srv(srv, doc);
#debug("markdown: %s", markdown);
markdown
}
- fn create_doc(source: str) -> doc::cratedoc {
+ fn create_doc_srv(source: str) -> (astsrv::srv, doc::cratedoc) {
let srv = astsrv::mk_srv_from_str(source);
let doc = extract::from_srv(srv, "");
#debug("doc (extract): %?", doc);
#debug("doc (path): %?", doc);
let doc = attr_pass::mk_pass()(srv, doc);
#debug("doc (attr): %?", doc);
+ (srv, doc)
+ }
+
+ fn create_doc(source: str) -> doc::cratedoc {
+ let (_, doc) = create_doc_srv(source);
doc
}
ret io::mem_buffer_str(buffer);
}
+ fn write_markdown_str_srv(
+ srv: astsrv::srv,
+ doc: doc::cratedoc
+ ) -> str {
+ let port = comm::port();
+ let chan = comm::chan(port);
+
+ let pass = mk_pass {|f|
+ let buffer = io::mk_mem_buffer();
+ let writer = io::mem_buffer_writer(buffer);
+ f(writer);
+ let result = io::mem_buffer_str(buffer);
+ comm::send(chan, result);
+ };
+ pass(srv, doc);
+ ret comm::recv(port);
+ }
+
#[test]
fn write_markdown_should_write_crate_header() {
let srv = astsrv::mk_srv_from_str("");
fn cfg(sess: session::session) -> ast::crate_cfg {
driver::default_configuration(sess, "rustdoc", "<anon>")
-}
\ No newline at end of file
+}
if !is_topmod { vec::push(fold.ctxt.path, doc.name); }
let doc = fold::default_seq_fold_mod(fold, doc);
if !is_topmod { vec::pop(fold.ctxt.path); }
- ~{
+ {
path: fold.ctxt.path
- with *doc
+ with doc
}
}
let srv = astsrv::mk_srv_from_str(source);
let doc = extract::from_srv(srv, "");
let doc = run(srv, doc);
- assert doc.topmod.mods[0].mods[0].mods[0].path == ["a", "b"];
- assert doc.topmod.mods[0].mods[1].mods[0].path == ["a", "d"];
+ assert doc.topmod.mods()[0].mods()[0].mods()[0].path == ["a", "b"];
+ assert doc.topmod.mods()[0].mods()[1].mods()[0].path == ["a", "d"];
}
\ No newline at end of file
--- /dev/null
+#[doc = "Prunes args, retvals of the document tree that \
+ contain no documentation"];
+
+export mk_pass;
+
+fn mk_pass() -> pass {
+ run
+}
+
+fn run(
+ _srv: astsrv::srv,
+ doc: doc::cratedoc
+) -> doc::cratedoc {
+ let fold = fold::fold({
+ fold_fn: fold_fn,
+ fold_res: fold_res,
+ fold_iface: fold_iface,
+ fold_impl: fold_impl
+ with *fold::default_seq_fold(())
+ });
+ fold.fold_crate(fold, doc)
+}
+
+fn fold_fn(
+ fold: fold::fold<()>,
+ doc: doc::fndoc
+) -> doc::fndoc {
+ let doc = fold::default_seq_fold_fn(fold, doc);
+
+ {
+ args: prune_args(doc.args),
+ return: prune_return(doc.return)
+ with doc
+ }
+}
+
+fn prune_args(docs: [doc::argdoc]) -> [doc::argdoc] {
+ vec::filter_map(docs) {|doc|
+ if option::is_some(doc.desc) {
+ some(doc)
+ } else {
+ none
+ }
+ }
+}
+
+fn prune_return(doc: doc::retdoc) -> doc::retdoc {
+ {
+ ty: if option::is_some(doc.desc) {
+ doc.ty
+ } else {
+ none
+ }
+ with doc
+ }
+}
+
+#[test]
+fn should_elide_undocumented_arguments() {
+ let doc = test::mk_doc("#[doc = \"hey\"] fn a(b: int) { }");
+ assert vec::is_empty(doc.topmod.fns()[0].args);
+}
+
+#[test]
+fn should_elide_undocumented_return_values() {
+ let source = "#[doc = \"fonz\"] fn a() -> int { }";
+ let srv = astsrv::mk_srv_from_str(source);
+ let doc = extract::from_srv(srv, "");
+ let doc = tystr_pass::mk_pass()(srv, doc);
+ let doc = attr_pass::mk_pass()(srv, doc);
+ let doc = run(srv, doc);
+ assert doc.topmod.fns()[0].return.ty == none;
+}
+
+fn fold_res(
+ fold: fold::fold<()>,
+ doc: doc::resdoc
+) -> doc::resdoc {
+ let doc = fold::default_seq_fold_res(fold, doc);
+
+ {
+ args: prune_args(doc.args)
+ with doc
+ }
+}
+
+#[test]
+fn should_elide_undocumented_resource_args() {
+ let doc = test::mk_doc("#[doc = \"drunk\"]\
+ resource r(a: bool) { }");
+ assert vec::is_empty(doc.topmod.resources()[0].args);
+}
+
+fn fold_iface(
+ fold: fold::fold<()>,
+ doc: doc::ifacedoc
+) -> doc::ifacedoc {
+ let doc = fold::default_seq_fold_iface(fold, doc);
+
+ {
+ methods: prune_methods(doc.methods)
+ with doc
+ }
+}
+
+fn prune_methods(docs: [doc::methoddoc]) -> [doc::methoddoc] {
+ vec::map(docs) {|doc|
+ {
+ args: prune_args(doc.args),
+ return: prune_return(doc.return)
+ with doc
+ }
+ }
+}
+
+#[test]
+fn should_elide_undocumented_iface_method_args() {
+ let doc = test::mk_doc("#[doc = \"hey\"] iface i { fn a(); }");
+ assert vec::is_empty(doc.topmod.ifaces()[0].methods[0].args);
+}
+
+#[test]
+fn should_elide_undocumented_iface_method_return_values() {
+ let doc = test::mk_doc("#[doc = \"hey\"] iface i { fn a() -> int; }");
+ assert doc.topmod.ifaces()[0].methods[0].return.ty == none;
+}
+
+fn fold_impl(
+ fold: fold::fold<()>,
+ doc: doc::impldoc
+) -> doc::impldoc {
+ let doc = fold::default_seq_fold_impl(fold, doc);
+
+ {
+ methods: prune_methods(doc.methods)
+ with doc
+ }
+}
+
+#[test]
+fn should_elide_undocumented_impl_method_args() {
+ let doc = test::mk_doc(
+ "#[doc = \"hey\"] impl i for int { fn a(b: bool) { } }");
+ assert vec::is_empty(doc.topmod.impls()[0].methods[0].args);
+}
+
+#[test]
+fn should_elide_undocumented_impl_method_return_values() {
+ let doc = test::mk_doc(
+ "#[doc = \"hey\"] impl i for int { fn a() -> int { } }");
+ assert doc.topmod.impls()[0].methods[0].return.ty == none;
+}
+
+#[cfg(test)]
+mod test {
+ fn mk_doc(source: str) -> doc::cratedoc {
+ let srv = astsrv::mk_srv_from_str(source);
+ let doc = extract::from_srv(srv, "");
+ let doc = attr_pass::mk_pass()(srv, doc);
+ run(srv, doc)
+ }
+}
--- /dev/null
+#[doc = "Prunes items of the document tree that contain no documentation"];
+
+export mk_pass;
+
+fn mk_pass() -> pass {
+ run
+}
+
+type ctxt = {
+ mutable have_docs: bool
+};
+
+fn run(
+ _srv: astsrv::srv,
+ doc: doc::cratedoc
+) -> doc::cratedoc {
+ let ctxt = {
+ mutable have_docs: true
+ };
+ let fold = fold::fold({
+ fold_mod: fold_mod,
+ fold_fn: fold_fn,
+ fold_const: fold_const,
+ fold_enum: fold_enum,
+ fold_res: fold_res,
+ fold_iface: fold_iface,
+ fold_impl: fold_impl,
+ fold_type: fold_type
+ with *fold::default_seq_fold(ctxt)
+ });
+ fold.fold_crate(fold, doc)
+}
+
+fn fold_mod(
+ fold: fold::fold<ctxt>,
+ doc: doc::moddoc
+) -> doc::moddoc {
+ let doc = {
+ items: ~vec::filter_map(*doc.items) {|itemtag|
+ alt itemtag {
+ doc::modtag(moddoc) {
+ let doc = fold.fold_mod(fold, moddoc);
+ if fold.ctxt.have_docs {
+ some(doc::modtag(doc))
+ } else {
+ none
+ }
+ }
+ doc::fntag(fndoc) {
+ let doc = fold.fold_fn(fold, fndoc);
+ if fold.ctxt.have_docs {
+ some(doc::fntag(doc))
+ } else {
+ none
+ }
+ }
+ doc::consttag(constdoc) {
+ let doc = fold.fold_const(fold, constdoc);
+ if fold.ctxt.have_docs {
+ some(doc::consttag(doc))
+ } else {
+ none
+ }
+ }
+ doc::enumtag(enumdoc) {
+ let doc = fold.fold_enum(fold, enumdoc);
+ if fold.ctxt.have_docs {
+ some(doc::enumtag(doc))
+ } else {
+ none
+ }
+ }
+ doc::restag(resdoc) {
+ let doc = fold.fold_res(fold, resdoc);
+ if fold.ctxt.have_docs {
+ some(doc::restag(doc))
+ } else {
+ none
+ }
+ }
+ doc::ifacetag(ifacedoc) {
+ let doc = fold.fold_iface(fold, ifacedoc);
+ if fold.ctxt.have_docs {
+ some(doc::ifacetag(doc))
+ } else {
+ none
+ }
+ }
+ doc::impltag(impldoc) {
+ let doc = fold.fold_impl(fold, impldoc);
+ if fold.ctxt.have_docs {
+ some(doc::impltag(doc))
+ } else {
+ none
+ }
+ }
+ doc::tytag(tydoc) {
+ let doc = fold.fold_type(fold, tydoc);
+ if fold.ctxt.have_docs {
+ some(doc::tytag(doc))
+ } else {
+ none
+ }
+ }
+ _ { some(itemtag) }
+ }
+ }
+ with fold::default_seq_fold_mod(fold, doc)
+ };
+ fold.ctxt.have_docs =
+ doc.brief != none
+ || doc.desc != none
+ || vec::is_not_empty(*doc.items);
+ ret doc;
+}
+
+fn fold_fn(
+ fold: fold::fold<ctxt>,
+ doc: doc::fndoc
+) -> doc::fndoc {
+ let doc = fold::default_seq_fold_fn(fold, doc);
+
+ fold.ctxt.have_docs =
+ doc.brief != none
+ || doc.desc != none
+ || args_have_docs(doc.args)
+ || doc.return.desc != none
+ || doc.failure != none;
+ ret doc;
+}
+
+fn args_have_docs(docs: [doc::argdoc]) -> bool {
+ vec::foldl(false, docs) {|accum, doc|
+ accum || doc.desc != none
+ }
+}
+
+#[test]
+fn should_elide_fns_with_undocumented_arguments() {
+ let doc = test::mk_doc("fn a(a: int) { }");
+ assert vec::is_empty(doc.topmod.fns());
+}
+
+#[test]
+fn should_not_elide_fns_with_documented_arguments() {
+ let doc = test::mk_doc("#[doc(args(a = \"b\"))] fn a(a: int) { }");
+ assert vec::is_not_empty(doc.topmod.fns());
+}
+
+#[test]
+fn should_not_elide_fns_with_documented_failure_conditions() {
+ let doc = test::mk_doc("#[doc(failure = \"yup\")] fn a() { }");
+ assert vec::is_not_empty(doc.topmod.fns());
+}
+
+#[test]
+fn should_elide_undocumented_mods() {
+ let doc = test::mk_doc("mod a { }");
+ assert vec::is_empty(doc.topmod.mods());
+}
+
+#[test]
+fn should_not_elide_undocument_mods_with_documented_mods() {
+ let doc = test::mk_doc("mod a { #[doc = \"b\"] mod b { } }");
+ assert vec::is_not_empty(doc.topmod.mods());
+}
+
+#[test]
+fn should_not_elide_undocument_mods_with_documented_fns() {
+ let doc = test::mk_doc("mod a { #[doc = \"b\"] fn b() { } }");
+ assert vec::is_not_empty(doc.topmod.mods());
+}
+
+#[test]
+fn should_elide_undocumented_fns() {
+ let doc = test::mk_doc("fn a() { }");
+ assert vec::is_empty(doc.topmod.fns());
+}
+
+fn fold_const(
+ fold: fold::fold<ctxt>,
+ doc: doc::constdoc
+) -> doc::constdoc {
+ let doc = fold::default_seq_fold_const(fold, doc);
+ fold.ctxt.have_docs =
+ doc.brief != none
+ || doc.desc != none;
+ ret doc;
+}
+
+#[test]
+fn should_elide_undocumented_consts() {
+ let doc = test::mk_doc("const a: bool = true;");
+ assert vec::is_empty(doc.topmod.consts());
+}
+
+fn fold_enum(fold: fold::fold<ctxt>, doc: doc::enumdoc) -> doc::enumdoc {
+ let doc = {
+ variants: vec::filter_map(doc.variants) {|variant|
+ if variant.desc != none {
+ some(variant)
+ } else {
+ none
+ }
+ }
+ with fold::default_seq_fold_enum(fold, doc)
+ };
+ fold.ctxt.have_docs =
+ doc.brief != none
+ || doc.desc != none
+ || vec::is_not_empty(doc.variants);
+ ret doc;
+}
+
+#[test]
+fn should_elide_undocumented_enums() {
+ let doc = test::mk_doc("enum a { b }");
+ assert vec::is_empty(doc.topmod.enums());
+}
+
+#[test]
+fn should_elide_undocumented_variants() {
+ let doc = test::mk_doc("#[doc = \"a\"] enum a { b }");
+ assert vec::is_empty(doc.topmod.enums()[0].variants);
+}
+
+#[test]
+fn should_not_elide_enums_with_documented_variants() {
+ let doc = test::mk_doc("enum a { #[doc = \"a\"] b }");
+ assert vec::is_not_empty(doc.topmod.enums());
+}
+
+fn fold_res(fold: fold::fold<ctxt>, doc: doc::resdoc) -> doc::resdoc {
+ let doc = fold::default_seq_fold_res(fold, doc);
+
+ fold.ctxt.have_docs =
+ doc.brief != none
+ || doc.desc != none
+ || args_have_docs(doc.args);
+ ret doc;
+}
+
+#[test]
+fn should_elide_undocumented_resources() {
+ let doc = test::mk_doc("resource r(a: bool) { }");
+ assert vec::is_empty(doc.topmod.resources());
+}
+
+#[test]
+fn should_not_elide_resources_with_documented_args() {
+ let doc = test::mk_doc("#[doc(args(a = \"drunk\"))]\
+ resource r(a: bool) { }");
+ assert vec::is_not_empty(doc.topmod.resources());
+}
+
+fn fold_iface(
+ fold: fold::fold<ctxt>,
+ doc: doc::ifacedoc
+) -> doc::ifacedoc {
+ let doc = fold::default_seq_fold_iface(fold, doc);
+
+ fold.ctxt.have_docs =
+ doc.brief != none
+ || doc.desc != none
+ || methods_have_docs(doc.methods);
+ ret doc;
+}
+
+fn methods_have_docs(docs: [doc::methoddoc]) -> bool {
+ vec::foldl(false, docs) {|accum, doc|
+ accum
+ || doc.brief != none
+ || doc.desc != none
+ || args_have_docs(doc.args)
+ || doc.return.desc != none
+ || doc.failure != none
+ }
+}
+
+#[test]
+fn should_elide_undocumented_ifaces() {
+ let doc = test::mk_doc("iface i { fn a(); }");
+ assert vec::is_empty(doc.topmod.ifaces());
+}
+
+#[test]
+fn should_not_elide_documented_ifaces() {
+ let doc = test::mk_doc("#[doc = \"hey\"] iface i { fn a(); }");
+ assert vec::is_not_empty(doc.topmod.ifaces());
+}
+
+#[test]
+fn should_elide_ifaces_with_undocumented_args() {
+ let doc = test::mk_doc("iface i { fn a(b: bool); }");
+ assert vec::is_empty(doc.topmod.ifaces());
+}
+
+#[test]
+fn should_not_elide_ifaces_with_documented_methods() {
+ let doc = test::mk_doc("iface i { #[doc = \"hey\"] fn a(); }");
+ assert vec::is_not_empty(doc.topmod.ifaces());
+}
+
+#[test]
+fn should_not_elide_undocumented_iface_methods() {
+ let doc = test::mk_doc("#[doc = \"hey\"] iface i { fn a(); }");
+ assert vec::is_not_empty(doc.topmod.ifaces()[0].methods);
+}
+
+fn fold_impl(
+ fold: fold::fold<ctxt>,
+ doc: doc::impldoc
+) -> doc::impldoc {
+ let doc = fold::default_seq_fold_impl(fold, doc);
+
+ fold.ctxt.have_docs =
+ doc.brief != none
+ || doc.desc != none
+ || methods_have_docs(doc.methods);
+ ret doc;
+}
+
+#[test]
+fn should_elide_undocumented_impls() {
+ let doc = test::mk_doc("impl i for int { fn a() { } }");
+ assert vec::is_empty(doc.topmod.impls());
+}
+
+#[test]
+fn should_not_elide_documented_impls() {
+ let doc = test::mk_doc("#[doc = \"hey\"] impl i for int { fn a() { } }");
+ assert vec::is_not_empty(doc.topmod.impls());
+}
+
+#[test]
+fn should_not_elide_impls_with_documented_methods() {
+ let doc = test::mk_doc("impl i for int { #[doc = \"hey\"] fn a() { } }");
+ assert vec::is_not_empty(doc.topmod.impls());
+}
+
+#[test]
+fn should_not_elide_undocumented_impl_methods() {
+ let doc = test::mk_doc("#[doc = \"hey\"] impl i for int { fn a() { } }");
+ assert vec::is_not_empty(doc.topmod.impls()[0].methods);
+}
+
+fn fold_type(
+ fold: fold::fold<ctxt>,
+ doc: doc::tydoc
+) -> doc::tydoc {
+ let doc = fold::default_seq_fold_type(fold, doc);
+
+ fold.ctxt.have_docs =
+ doc.brief != none
+ || doc.desc != none;
+ ret doc;
+}
+
+#[test]
+fn should_elide_undocumented_types() {
+ let doc = test::mk_doc("type t = int;");
+ assert vec::is_empty(doc.topmod.types());
+}
+
+#[cfg(test)]
+mod test {
+ fn mk_doc(source: str) -> doc::cratedoc {
+ let srv = astsrv::mk_srv_from_str(source);
+ let doc = extract::from_srv(srv, "");
+ let doc = attr_pass::mk_pass()(srv, doc);
+ run(srv, doc)
+ }
+}
+++ /dev/null
-#[doc = "Prunes branches of the document tree that contain no documentation"];
-
-export mk_pass;
-
-fn mk_pass() -> pass {
- run
-}
-
-type ctxt = {
- mutable have_docs: bool
-};
-
-fn run(
- _srv: astsrv::srv,
- doc: doc::cratedoc
-) -> doc::cratedoc {
- let ctxt = {
- mutable have_docs: true
- };
- let fold = fold::fold({
- fold_mod: fold_mod,
- fold_fn: fold_fn,
- fold_const: fold_const,
- fold_enum: fold_enum,
- fold_res: fold_res,
- fold_modlist: fold_modlist,
- fold_fnlist: fold_fnlist,
- fold_constlist: fold_constlist,
- fold_enumlist: fold_enumlist,
- fold_reslist: fold_reslist
- with *fold::default_seq_fold(ctxt)
- });
- fold.fold_crate(fold, doc)
-}
-
-fn fold_mod(
- fold: fold::fold<ctxt>,
- doc: doc::moddoc
-) -> doc::moddoc {
- let doc = fold::default_seq_fold_mod(fold, doc);
- fold.ctxt.have_docs =
- doc.brief != none
- || doc.desc != none
- || vec::is_not_empty(*doc.mods)
- || vec::is_not_empty(*doc.fns);
- ret doc;
-}
-
-fn fold_fn(
- fold: fold::fold<ctxt>,
- doc: doc::fndoc
-) -> doc::fndoc {
- let have_arg_docs = false;
- let doc = ~{
- args: vec::filter_map(doc.args) {|doc|
- if option::is_some(doc.desc) {
- have_arg_docs = true;
- some(doc)
- } else {
- none
- }
- },
- return: {
- ty: if option::is_some(doc.return.desc) {
- doc.return.ty
- } else {
- none
- }
- with doc.return
- }
- with *doc
- };
-
- fold.ctxt.have_docs =
- doc.brief != none
- || doc.desc != none
- || have_arg_docs
- || doc.return.desc != none
- || doc.failure != none;
- ret doc;
-}
-
-#[test]
-fn should_elide_undocumented_arguments() {
- let source = "#[doc = \"hey\"] fn a(b: int) { }";
- let srv = astsrv::mk_srv_from_str(source);
- let doc = extract::from_srv(srv, "");
- let doc = attr_pass::mk_pass()(srv, doc);
- let doc = run(srv, doc);
- assert vec::is_empty(doc.topmod.fns[0].args);
-}
-
-#[test]
-fn should_not_elide_fns_with_documented_arguments() {
- let source = "#[doc(args(a = \"b\"))] fn a(a: int) { }";
- let srv = astsrv::mk_srv_from_str(source);
- let doc = extract::from_srv(srv, "");
- let doc = attr_pass::mk_pass()(srv, doc);
- let doc = run(srv, doc);
- assert vec::is_not_empty(*doc.topmod.fns);
-}
-
-#[test]
-fn should_elide_undocumented_return_values() {
- let source = "#[doc = \"fonz\"] fn a() -> int { }";
- let srv = astsrv::mk_srv_from_str(source);
- let doc = extract::from_srv(srv, "");
- let doc = tystr_pass::mk_pass()(srv, doc);
- let doc = attr_pass::mk_pass()(srv, doc);
- let doc = run(srv, doc);
- assert doc.topmod.fns[0].return.ty == none;
-}
-
-#[test]
-fn should_not_elide_fns_with_documented_failure_conditions() {
- let source = "#[doc(failure = \"yup\")] fn a() { }";
- let srv = astsrv::mk_srv_from_str(source);
- let doc = extract::from_srv(srv, "");
- let doc = attr_pass::mk_pass()(srv, doc);
- let doc = run(srv, doc);
- assert vec::is_not_empty(*doc.topmod.fns);
-}
-
-fn fold_modlist(
- fold: fold::fold<ctxt>,
- list: doc::modlist
-) -> doc::modlist {
- doc::modlist(vec::filter_map(*list) {|doc|
- let doc = fold.fold_mod(fold, doc);
- if fold.ctxt.have_docs {
- some(doc)
- } else {
- none
- }
- })
-}
-
-#[test]
-fn should_elide_undocumented_mods() {
- let source = "mod a { }";
- let srv = astsrv::mk_srv_from_str(source);
- let doc = extract::from_srv(srv, "");
- let doc = run(srv, doc);
- assert vec::is_empty(*doc.topmod.mods);
-}
-
-#[test]
-fn should_not_elide_undocument_mods_with_documented_mods() {
- let source = "mod a { #[doc = \"b\"] mod b { } }";
- let srv = astsrv::mk_srv_from_str(source);
- let doc = extract::from_srv(srv, "");
- let doc = attr_pass::mk_pass()(srv, doc);
- let doc = run(srv, doc);
- assert vec::is_not_empty(*doc.topmod.mods);
-}
-
-#[test]
-fn should_not_elide_undocument_mods_with_documented_fns() {
- let source = "mod a { #[doc = \"b\"] fn b() { } }";
- let srv = astsrv::mk_srv_from_str(source);
- let doc = extract::from_srv(srv, "");
- let doc = attr_pass::mk_pass()(srv, doc);
- let doc = run(srv, doc);
- assert vec::is_not_empty(*doc.topmod.mods);
-}
-
-fn fold_fnlist(
- fold: fold::fold<ctxt>,
- list: doc::fnlist
-) -> doc::fnlist {
- doc::fnlist(vec::filter_map(*list) {|doc|
- let doc = fold.fold_fn(fold, doc);
- if fold.ctxt.have_docs {
- some(doc)
- } else {
- none
- }
- })
-}
-
-#[test]
-fn should_elide_undocumented_fns() {
- let source = "fn a() { }";
- let srv = astsrv::mk_srv_from_str(source);
- let doc = extract::from_srv(srv, "");
- let doc = run(srv, doc);
- assert vec::is_empty(*doc.topmod.fns);
-}
-
-fn fold_const(
- fold: fold::fold<ctxt>,
- doc: doc::constdoc
-) -> doc::constdoc {
- let doc = fold::default_seq_fold_const(fold, doc);
- fold.ctxt.have_docs =
- doc.brief != none
- || doc.desc != none;
- ret doc;
-}
-
-fn fold_constlist(
- fold: fold::fold<ctxt>,
- list: doc::constlist
-) -> doc::constlist {
- doc::constlist(vec::filter_map(*list) {|doc|
- let doc = fold.fold_const(fold, doc);
- if fold.ctxt.have_docs {
- some(doc)
- } else {
- none
- }
- })
-}
-
-#[test]
-fn should_elide_undocumented_consts() {
- let source = "const a: bool = true;";
- let srv = astsrv::mk_srv_from_str(source);
- let doc = extract::from_srv(srv, "");
- let doc = run(srv, doc);
- assert vec::is_empty(*doc.topmod.consts);
-}
-
-fn fold_enum(fold: fold::fold<ctxt>, doc: doc::enumdoc) -> doc::enumdoc {
- let doc = ~{
- variants: vec::filter_map(doc.variants) {|variant|
- if variant.desc != none {
- some(variant)
- } else {
- none
- }
- }
- with *fold::default_seq_fold_enum(fold, doc)
- };
- fold.ctxt.have_docs =
- doc.brief != none
- || doc.desc != none
- || vec::is_not_empty(doc.variants);
- ret doc;
-}
-
-fn fold_enumlist(
- fold: fold::fold<ctxt>,
- list: doc::enumlist
-) -> doc::enumlist {
- doc::enumlist(vec::filter_map(*list) {|doc|
- let doc = fold.fold_enum(fold, doc);
- if fold.ctxt.have_docs {
- some(doc)
- } else {
- none
- }
- })
-}
-
-#[test]
-fn should_elide_undocumented_enums() {
- let source = "enum a { b }";
- let srv = astsrv::mk_srv_from_str(source);
- let doc = extract::from_srv(srv, "");
- let doc = attr_pass::mk_pass()(srv, doc);
- let doc = run(srv, doc);
- assert vec::is_empty(*doc.topmod.enums);
-}
-
-#[test]
-fn should_elide_undocumented_variants() {
- let source = "#[doc = \"a\"] enum a { b }";
- let srv = astsrv::mk_srv_from_str(source);
- let doc = extract::from_srv(srv, "");
- let doc = attr_pass::mk_pass()(srv, doc);
- let doc = run(srv, doc);
- assert vec::is_empty(doc.topmod.enums[0].variants);
-}
-
-#[test]
-fn should_not_elide_enums_with_documented_variants() {
- let source = "enum a { #[doc = \"a\"] b }";
- let srv = astsrv::mk_srv_from_str(source);
- let doc = extract::from_srv(srv, "");
- let doc = attr_pass::mk_pass()(srv, doc);
- let doc = run(srv, doc);
- assert vec::is_not_empty(*doc.topmod.enums);
-}
-
-fn fold_res(fold: fold::fold<ctxt>, doc: doc::resdoc) -> doc::resdoc {
- let doc = ~{
- args: vec::filter_map(doc.args) {|arg|
- if arg.desc != none {
- some(arg)
- } else {
- none
- }
- }
- with *fold::default_seq_fold_res(fold, doc)
- };
- fold.ctxt.have_docs =
- doc.brief != none
- || doc.desc != none
- || vec::is_not_empty(doc.args);
- ret doc;
-}
-
-fn fold_reslist(
- fold: fold::fold<ctxt>,
- list: doc::reslist
-) -> doc::reslist {
- doc::reslist(vec::filter_map(*list) {|doc|
- let doc = fold.fold_res(fold, doc);
- if fold.ctxt.have_docs {
- some(doc)
- } else {
- none
- }
- })
-}
-
-#[test]
-fn should_elide_undocumented_resources() {
- let source = "resource r(a: bool) { }";
- let srv = astsrv::mk_srv_from_str(source);
- let doc = extract::from_srv(srv, "");
- let doc = run(srv, doc);
- assert vec::is_empty(*doc.topmod.resources);
-}
-
-#[test]
-fn should_elide_undocumented_resource_args() {
- let source = "#[doc = \"drunk\"]\
- resource r(a: bool) { }";
- let srv = astsrv::mk_srv_from_str(source);
- let doc = extract::from_srv(srv, "");
- let doc = attr_pass::mk_pass()(srv, doc);
- let doc = run(srv, doc);
- assert vec::is_empty(doc.topmod.resources[0].args);
-}
-
-#[test]
-fn should_not_elide_resources_with_documented_args() {
- let source = "#[doc(args(a = \"drunk\"))]\
- resource r(a: bool) { }";
- let srv = astsrv::mk_srv_from_str(source);
- let doc = extract::from_srv(srv, "");
- let doc = attr_pass::mk_pass()(srv, doc);
- let doc = run(srv, doc);
- assert vec::is_not_empty(*doc.topmod.resources);
-}
fn fold_mod(fold: fold::fold<astsrv::srv>, doc: doc::moddoc) -> doc::moddoc {
let doc = fold::default_seq_fold_mod(fold, doc);
- ~{
- mods: doc::modlist(exported_mods(fold.ctxt, doc)),
- fns: doc::fnlist(exported_fns(fold.ctxt, doc)),
- consts: doc::constlist(exported_consts(fold.ctxt, doc)),
- enums: doc::enumlist(exported_enums(fold.ctxt, doc))
- with *doc
+ {
+ items: ~exported_items(fold.ctxt, doc)
+ with doc
}
}
-fn exported_mods(srv: astsrv::srv, doc: doc::moddoc) -> [doc::moddoc] {
+fn exported_items(srv: astsrv::srv, doc: doc::moddoc) -> [doc::itemtag] {
exported_things(
srv, doc,
- exported_mods_from_crate,
- exported_mods_from_mod
- )
-}
-
-fn exported_fns(srv: astsrv::srv, doc: doc::moddoc) -> [doc::fndoc] {
- exported_things(
- srv, doc,
- exported_fns_from_crate,
- exported_fns_from_mod
- )
-}
-
-fn exported_consts(srv: astsrv::srv, doc: doc::moddoc) -> [doc::constdoc] {
- exported_things(
- srv, doc,
- exported_consts_from_crate,
- exported_consts_from_mod
- )
-}
-
-fn exported_enums(srv: astsrv::srv, doc: doc::moddoc) -> [doc::enumdoc] {
- exported_things(
- srv, doc,
- exported_enums_from_crate,
- exported_enums_from_mod
+ exported_items_from_crate,
+ exported_items_from_mod
)
}
}
}
-fn exported_mods_from_crate(
- srv: astsrv::srv,
- doc: doc::moddoc
-) -> [doc::moddoc] {
- exported_mods_from(srv, doc, is_exported_from_crate)
-}
-
-fn exported_mods_from_mod(
- srv: astsrv::srv,
- doc: doc::moddoc
-) -> [doc::moddoc] {
- exported_mods_from(srv, doc, bind is_exported_from_mod(_, doc.id, _))
-}
-
-fn exported_fns_from_crate(
+fn exported_items_from_crate(
srv: astsrv::srv,
doc: doc::moddoc
-) -> [doc::fndoc] {
- exported_fns_from(srv, doc, is_exported_from_crate)
+) -> [doc::itemtag] {
+ exported_items_from(srv, doc, is_exported_from_crate)
}
-fn exported_fns_from_mod(
+fn exported_items_from_mod(
srv: astsrv::srv,
doc: doc::moddoc
-) -> [doc::fndoc] {
- exported_fns_from(srv, doc, bind is_exported_from_mod(_, doc.id, _))
-}
-
-fn exported_consts_from_crate(
- srv: astsrv::srv,
- doc: doc::moddoc
-) -> [doc::constdoc] {
- exported_consts_from(srv, doc, is_exported_from_crate)
-}
-
-fn exported_consts_from_mod(
- srv: astsrv::srv,
- doc: doc::moddoc
-) -> [doc::constdoc] {
- exported_consts_from(srv, doc, bind is_exported_from_mod(_, doc.id, _))
-}
-
-fn exported_enums_from_crate(
- srv: astsrv::srv,
- doc: doc::moddoc
-) -> [doc::enumdoc] {
- exported_enums_from(srv, doc, is_exported_from_crate)
-}
-
-fn exported_enums_from_mod(
- srv: astsrv::srv,
- doc: doc::moddoc
-) -> [doc::enumdoc] {
- exported_enums_from(srv, doc, bind is_exported_from_mod(_, doc.id, _))
-}
-
-fn exported_fns_from(
- srv: astsrv::srv,
- doc: doc::moddoc,
- is_exported: fn(astsrv::srv, str) -> bool
-) -> [doc::fndoc] {
- vec::filter_map(*doc.fns) { |doc|
- if is_exported(srv, doc.name) {
- some(doc)
- } else {
- none
- }
- }
-}
-
-fn exported_mods_from(
- srv: astsrv::srv,
- doc: doc::moddoc,
- is_exported: fn(astsrv::srv, str) -> bool
-) -> [doc::moddoc] {
- vec::filter_map(*doc.mods) { |doc|
- if is_exported(srv, doc.name) {
- some(doc)
- } else {
- none
- }
- }
-}
-
-fn exported_consts_from(
- srv: astsrv::srv,
- doc: doc::moddoc,
- is_exported: fn(astsrv::srv, str) -> bool
-) -> [doc::constdoc] {
- vec::filter_map(*doc.consts) { |doc|
- if is_exported(srv, doc.name) {
- some(doc)
- } else {
- none
- }
- }
+) -> [doc::itemtag] {
+ exported_items_from(srv, doc, bind is_exported_from_mod(_, doc.id, _))
}
-fn exported_enums_from(
+fn exported_items_from(
srv: astsrv::srv,
doc: doc::moddoc,
is_exported: fn(astsrv::srv, str) -> bool
-) -> [doc::enumdoc] {
- vec::filter_map(*doc.enums) { |doc|
- if is_exported(srv, doc.name) {
- some(~{
- variants: exported_variants_from(
- srv, doc, is_exported)
- with *doc
+) -> [doc::itemtag] {
+ vec::filter_map(*doc.items) { |itemtag|
+ let itemtag = alt itemtag {
+ doc::enumtag(enumdoc) {
+ // Also need to check variant exportedness
+ doc::enumtag({
+ variants: exported_variants_from(srv, enumdoc, is_exported)
+ with enumdoc
})
+ }
+ _ { itemtag }
+ };
+ if is_exported(srv, itemtag.name()) {
+ some(itemtag)
} else {
none
}
) -> bool {
astsrv::exec(srv) {|ctxt|
alt ctxt.ast_map.get(mod_id) {
- ast_map::node_item(item) {
+ ast_map::node_item(item, _) {
alt item.node {
ast::item_mod(m) {
ast_util::is_exported(item_name, m)
}
+ _ {
+ fail "is_exported_from_mod: not a mod";
+ }
}
}
+ _ { fail "is_exported_from_mod: not an item"; }
}
}
}
#[test]
fn should_prune_unexported_fns() {
- let source = "mod b { export a; fn a() { } fn b() { } }";
- let srv = astsrv::mk_srv_from_str(source);
- let doc = extract::from_srv(srv, "");
- let doc = run(srv, doc);
- assert vec::len(*doc.topmod.mods[0].fns) == 1u;
+ let doc = test::mk_doc("mod b { export a; fn a() { } fn b() { } }");
+ assert vec::len(doc.topmod.mods()[0].fns()) == 1u;
}
#[test]
fn should_prune_unexported_fns_from_top_mod() {
- let source = "export a; fn a() { } fn b() { }";
- let srv = astsrv::mk_srv_from_str(source);
- let doc = extract::from_srv(srv, "");
- let doc = run(srv, doc);
- assert vec::len(*doc.topmod.fns) == 1u;
+ let doc = test::mk_doc("export a; fn a() { } fn b() { }");
+ assert vec::len(doc.topmod.fns()) == 1u;
}
#[test]
fn should_prune_unexported_modules() {
- let source = "mod a { export a; mod a { } mod b { } }";
- let srv = astsrv::mk_srv_from_str(source);
- let doc = extract::from_srv(srv, "");
- let doc = run(srv, doc);
- assert vec::len(*doc.topmod.mods[0].mods) == 1u;
+ let doc = test::mk_doc("mod a { export a; mod a { } mod b { } }");
+ assert vec::len(doc.topmod.mods()[0].mods()) == 1u;
}
#[test]
fn should_prune_unexported_modules_from_top_mod() {
- let source = "export a; mod a { } mod b { }";
- let srv = astsrv::mk_srv_from_str(source);
- let doc = extract::from_srv(srv, "");
- let doc = run(srv, doc);
- assert vec::len(*doc.topmod.mods) == 1u;
+ let doc = test::mk_doc("export a; mod a { } mod b { }");
+ assert vec::len(doc.topmod.mods()) == 1u;
}
#[test]
fn should_prune_unexported_consts() {
- let source = "mod a { export a; \
- const a: bool = true; \
- const b: bool = true; }";
- let srv = astsrv::mk_srv_from_str(source);
- let doc = extract::from_srv(srv, "");
- let doc = run(srv, doc);
- assert vec::len(*doc.topmod.mods[0].consts) == 1u;
+ let doc = test::mk_doc(
+ "mod a { export a; \
+ const a: bool = true; \
+ const b: bool = true; }");
+ assert vec::len(doc.topmod.mods()[0].consts()) == 1u;
}
#[test]
fn should_prune_unexported_consts_from_top_mod() {
- let source = "export a; const a: bool = true; const b: bool = true;";
- let srv = astsrv::mk_srv_from_str(source);
- let doc = extract::from_srv(srv, "");
- let doc = run(srv, doc);
- assert vec::len(*doc.topmod.consts) == 1u;
+ let doc = test::mk_doc(
+ "export a; const a: bool = true; const b: bool = true;");
+ assert vec::len(doc.topmod.consts()) == 1u;
}
#[test]
fn should_prune_unexported_enums_from_top_mod() {
- let source = "export a; mod a { } enum b { c }";
- let srv = astsrv::mk_srv_from_str(source);
- let doc = extract::from_srv(srv, "");
- let doc = run(srv, doc);
- assert vec::len(*doc.topmod.enums) == 0u;
+ let doc = test::mk_doc("export a; mod a { } enum b { c }");
+ assert vec::len(doc.topmod.enums()) == 0u;
}
#[test]
fn should_prune_unexported_enums() {
- let source = "mod a { export a; mod a { } enum b { c } }";
- let srv = astsrv::mk_srv_from_str(source);
- let doc = extract::from_srv(srv, "");
- let doc = run(srv, doc);
- assert vec::len(*doc.topmod.mods[0].enums) == 0u;
+ let doc = test::mk_doc("mod a { export a; mod a { } enum b { c } }");
+ assert vec::len(doc.topmod.mods()[0].enums()) == 0u;
}
#[test]
fn should_prune_unexported_variants_from_top_mod() {
- let source = "export b::{}; enum b { c }";
- let srv = astsrv::mk_srv_from_str(source);
- let doc = extract::from_srv(srv, "");
- let doc = run(srv, doc);
- assert vec::len(doc.topmod.enums[0].variants) == 0u;
+ let doc = test::mk_doc("export b::{}; enum b { c }");
+ assert vec::len(doc.topmod.enums()[0].variants) == 0u;
}
#[test]
fn should_prune_unexported_variants() {
- let source = "mod a { export b::{}; enum b { c } }";
- let srv = astsrv::mk_srv_from_str(source);
- let doc = extract::from_srv(srv, "");
- let doc = run(srv, doc);
- assert vec::len(doc.topmod.mods[0].enums[0].variants) == 0u;
+ let doc = test::mk_doc("mod a { export b::{}; enum b { c } }");
+ assert vec::len(doc.topmod.mods()[0].enums()[0].variants) == 0u;
+}
+
+#[test]
+fn should_prune_unexported_resources_from_top_mod() {
+ let doc = test::mk_doc("export a; mod a { } resource r(a: bool) { }");
+ assert vec::is_empty(doc.topmod.resources());
+}
+
+#[test]
+fn should_prune_unexported_resources() {
+ let doc = test::mk_doc(
+ "mod a { export a; mod a { } resource r(a: bool) { } }");
+ assert vec::is_empty(doc.topmod.mods()[0].resources());
}
+
+#[test]
+fn should_prune_unexported_ifaces_from_top_mod() {
+ let doc = test::mk_doc("export a; mod a { } iface b { fn c(); }");
+ assert vec::is_empty(doc.topmod.ifaces());
+}
+
+#[test]
+fn should_prune_unexported_impls_from_top_mod() {
+ let doc = test::mk_doc(
+ "export a; mod a { } impl b for int { fn c() { } }");
+ assert vec::is_empty(doc.topmod.impls())
+}
+
+#[test]
+fn should_prune_unexported_types() {
+ let doc = test::mk_doc("export a; mod a { } type b = int;");
+ assert vec::is_empty(doc.topmod.types());
+}
+
+#[cfg(test)]
+mod test {
+ fn mk_doc(source: str) -> doc::cratedoc {
+ let srv = astsrv::mk_srv_from_str(source);
+ let doc = extract::from_srv(srv, "");
+ run(srv, doc)
+ }
+}
\ No newline at end of file
mod path_pass;
mod attr_pass;
mod tystr_pass;
-mod prune_undoc_pass;
+mod prune_undoc_details_pass;
+mod prune_undoc_items_pass;
mod prune_unexported_pass;
mod desc_to_brief_pass;
mod desc_pass;
mod trim_pass;
mod astsrv;
mod demo;
+mod sort_pass;
+mod sort_item_name_pass;
+mod sort_item_type_pass;
\ No newline at end of file
* Copyright 2011 Google Inc.
*/
+import doc::util;
+
#[doc = "A single operation on the document model"]
type pass = fn~(srv: astsrv::srv, doc: doc::cratedoc) -> doc::cratedoc;
_srv: astsrv::srv,
doc: doc::cratedoc
) -> doc::cratedoc {
- ~{
- topmod: ~{
+ {
+ topmod: {
id: 0,
name: doc.topmod.name + "two",
path: [],
brief: none,
desc: none,
- mods: doc::modlist([]),
- fns: doc::fnlist([]),
- consts: doc::constlist([]),
- enums: doc::enumlist([]),
- resources: doc::reslist([])
+ items: ~[]
}
}
}
_srv: astsrv::srv,
doc: doc::cratedoc
) -> doc::cratedoc {
- ~{
- topmod: ~{
+ {
+ topmod: {
id: 0,
name: doc.topmod.name + "three",
path: [],
brief: none,
desc: none,
- mods: doc::modlist([]),
- fns: doc::fnlist([]),
- consts: doc::constlist([]),
- enums: doc::enumlist([]),
- resources: doc::reslist([])
+ items: ~[]
}
}
}
tystr_pass::mk_pass(),
path_pass::mk_pass(),
attr_pass::mk_pass(),
+ prune_undoc_details_pass::mk_pass(),
// FIXME: This pass should be optional
- prune_undoc_pass::mk_pass(),
+ // prune_undoc_items_pass::mk_pass(),
desc_to_brief_pass::mk_pass(),
trim_pass::mk_pass(),
unindent_pass::mk_pass(),
- markdown_pass::mk_pass {|| std::io:: stdout()}
+ sort_item_name_pass::mk_pass(),
+ sort_item_type_pass::mk_pass(),
+ markdown_pass::mk_pass {|f| f(std::io:: stdout()) }
]);
}
\ No newline at end of file
--- /dev/null
+#[doc = "Sorts items by name"];
+
+export mk_pass;
+
+fn mk_pass() -> pass {
+ sort_pass::mk_pass { |item1, item2|
+ str::le(item1.name(), item2.name())
+ }
+}
+
+#[test]
+fn test() {
+ let source = "mod z { } fn y() { }";
+ let srv = astsrv::mk_srv_from_str(source);
+ let doc = extract::from_srv(srv, "");
+ let doc = mk_pass()(srv, doc);
+ assert doc.topmod.items[0].name() == "y";
+ assert doc.topmod.items[1].name() == "z";
+}
--- /dev/null
+#[doc = "Sorts items by type"];
+
+export mk_pass;
+
+fn mk_pass() -> pass {
+ sort_pass::mk_pass { |item1, item2|
+ fn score(item: doc::itemtag) -> int {
+ alt item {
+ doc::consttag(_) { 0 }
+ doc::tytag(_) { 1 }
+ doc::enumtag(_) { 2 }
+ doc::restag(_) { 3 }
+ doc::ifacetag(_) { 4 }
+ doc::impltag(_) { 5 }
+ doc::fntag(_) { 6 }
+ doc::modtag(_) { 7 }
+ _ { fail }
+ }
+ }
+
+ score(item1) <= score(item2)
+ }
+}
+
+#[test]
+fn test() {
+ let source =
+ "mod imod { } \
+ const iconst: int = 0; \
+ fn ifn() { } \
+ enum ienum { ivar } \
+ resource ires(a: bool) { } \
+ iface iiface { fn a(); } \
+ impl iimpl for int { fn a() { } } \
+ type itype = int;";
+ let srv = astsrv::mk_srv_from_str(source);
+ let doc = extract::from_srv(srv, "");
+ let doc = mk_pass()(srv, doc);
+ assert doc.topmod.items[0].name() == "iconst";
+ assert doc.topmod.items[1].name() == "itype";
+ assert doc.topmod.items[2].name() == "ienum";
+ assert doc.topmod.items[3].name() == "ires";
+ assert doc.topmod.items[4].name() == "iiface";
+ assert doc.topmod.items[5].name() == "iimpl";
+ assert doc.topmod.items[6].name() == "ifn";
+ assert doc.topmod.items[7].name() == "imod";
+}
--- /dev/null
+#[doc = "A general sorting pass"];
+
+import std::sort;
+
+export item_lteq, mk_pass;
+
+type item_lteq = fn~(doc::itemtag, doc::itemtag) -> bool;
+
+fn mk_pass(lteq: item_lteq) -> pass {
+ fn~(srv: astsrv::srv, doc: doc::cratedoc) -> doc::cratedoc {
+ run(srv, doc, lteq)
+ }
+}
+
+fn run(
+ _srv: astsrv::srv,
+ doc: doc::cratedoc,
+ lteq: item_lteq
+) -> doc::cratedoc {
+ let fold = fold::fold({
+ fold_mod: fold_mod
+ with *fold::default_seq_fold(lteq)
+ });
+ fold.fold_crate(fold, doc)
+}
+
+fn fold_mod(
+ fold: fold::fold<item_lteq>,
+ doc: doc::moddoc
+) -> doc::moddoc {
+ let doc = fold::default_seq_fold_mod(fold, doc);
+ {
+ items: ~sort::merge_sort(fold.ctxt, *doc.items)
+ with doc
+ }
+}
+
+#[test]
+fn test() {
+ fn name_lteq(item1: doc::itemtag, item2: doc::itemtag) -> bool {
+ str::le(item1.name(), item2.name())
+ }
+
+ let source = "mod z { mod y { } fn x() { } } mod w { }";
+ let srv = astsrv::mk_srv_from_str(source);
+ let doc = extract::from_srv(srv, "");
+ let doc = mk_pass(name_lteq)(srv, doc);
+ assert doc.topmod.mods()[0].name == "w";
+ assert doc.topmod.mods()[1].items[0].name() == "x";
+ assert doc.topmod.mods()[1].items[1].name() == "y";
+ assert doc.topmod.mods()[1].name == "z";
+}
+
+#[test]
+fn should_be_stable() {
+ fn always_eq(_item1: doc::itemtag, _item2: doc::itemtag) -> bool {
+ true
+ }
+
+ let source = "mod a { mod b { } } mod c { mod d { } }";
+ let srv = astsrv::mk_srv_from_str(source);
+ let doc = extract::from_srv(srv, "");
+ let doc = mk_pass(always_eq)(srv, doc);
+ assert doc.topmod.mods()[0].items[0].name() == "b";
+ assert doc.topmod.mods()[1].items[0].name() == "d";
+ let doc = mk_pass(always_eq)(srv, doc);
+ assert doc.topmod.mods()[0].items[0].name() == "b";
+ assert doc.topmod.mods()[1].items[0].name() == "d";
+}
#[test]
fn should_trim_mod() {
- let source = "#[doc(brief = \"\nbrief\n\", \
- desc = \"\ndesc\n\")] \
- mod m { }";
- let srv = astsrv::mk_srv_from_str(source);
- let doc = extract::from_srv(srv, "");
- let doc = attr_pass::mk_pass()(srv, doc);
- let doc = mk_pass()(srv, doc);
- assert doc.topmod.mods[0].brief == some("brief");
- assert doc.topmod.mods[0].desc == some("desc");
+ let doc = test::mk_doc("#[doc(brief = \"\nbrief\n\", \
+ desc = \"\ndesc\n\")] \
+ mod m { }");
+ assert doc.topmod.mods()[0].brief == some("brief");
+ assert doc.topmod.mods()[0].desc == some("desc");
}
#[test]
fn should_trim_const() {
- let source = "#[doc(brief = \"\nbrief\n\", \
- desc = \"\ndesc\n\")] \
- const a: bool = true;";
- let srv = astsrv::mk_srv_from_str(source);
- let doc = extract::from_srv(srv, "");
- let doc = attr_pass::mk_pass()(srv, doc);
- let doc = mk_pass()(srv, doc);
- assert doc.topmod.consts[0].brief == some("brief");
- assert doc.topmod.consts[0].desc == some("desc");
+ let doc = test::mk_doc("#[doc(brief = \"\nbrief\n\", \
+ desc = \"\ndesc\n\")] \
+ const a: bool = true;");
+ assert doc.topmod.consts()[0].brief == some("brief");
+ assert doc.topmod.consts()[0].desc == some("desc");
}
#[test]
fn should_trim_fn() {
- let source = "#[doc(brief = \"\nbrief\n\", \
- desc = \"\ndesc\n\")] \
- fn a() { }";
- let srv = astsrv::mk_srv_from_str(source);
- let doc = extract::from_srv(srv, "");
- let doc = attr_pass::mk_pass()(srv, doc);
- let doc = mk_pass()(srv, doc);
- assert doc.topmod.fns[0].brief == some("brief");
- assert doc.topmod.fns[0].desc == some("desc");
+ let doc = test::mk_doc("#[doc(brief = \"\nbrief\n\", \
+ desc = \"\ndesc\n\")] \
+ fn a() { }");
+ assert doc.topmod.fns()[0].brief == some("brief");
+ assert doc.topmod.fns()[0].desc == some("desc");
}
#[test]
fn should_trim_args() {
- let source = "#[doc(args(a = \"\na\n\"))] fn a(a: int) { }";
- let srv = astsrv::mk_srv_from_str(source);
- let doc = extract::from_srv(srv, "");
- let doc = attr_pass::mk_pass()(srv, doc);
- let doc = mk_pass()(srv, doc);
- assert doc.topmod.fns[0].args[0].desc == some("a");
+ let doc = test::mk_doc("#[doc(args(a = \"\na\n\"))] fn a(a: int) { }");
+ assert doc.topmod.fns()[0].args[0].desc == some("a");
}
#[test]
fn should_trim_ret() {
- let source = "#[doc(return = \"\na\n\")] fn a() -> int { }";
- let srv = astsrv::mk_srv_from_str(source);
- let doc = extract::from_srv(srv, "");
- let doc = attr_pass::mk_pass()(srv, doc);
- let doc = mk_pass()(srv, doc);
- assert doc.topmod.fns[0].return.desc == some("a");
+ let doc = test::mk_doc("#[doc(return = \"\na\n\")] fn a() -> int { }");
+ assert doc.topmod.fns()[0].return.desc == some("a");
}
#[test]
fn should_trim_failure_conditions() {
- let source = "#[doc(failure = \"\na\n\")] fn a() -> int { }";
- let srv = astsrv::mk_srv_from_str(source);
- let doc = extract::from_srv(srv, "");
- let doc = attr_pass::mk_pass()(srv, doc);
- let doc = mk_pass()(srv, doc);
- assert doc.topmod.fns[0].failure == some("a");
+ let doc = test::mk_doc("#[doc(failure = \"\na\n\")] fn a() -> int { }");
+ assert doc.topmod.fns()[0].failure == some("a");
+}
+
+#[cfg(test)]
+mod test {
+ fn mk_doc(source: str) -> doc::cratedoc {
+ let srv = astsrv::mk_srv_from_str(source);
+ let doc = extract::from_srv(srv, "");
+ let doc = attr_pass::mk_pass()(srv, doc);
+ mk_pass()(srv, doc)
+ }
}
\ No newline at end of file
fold_fn: fold_fn,
fold_const: fold_const,
fold_enum: fold_enum,
- fold_res: fold_res
+ fold_res: fold_res,
+ fold_iface: fold_iface,
+ fold_impl: fold_impl,
+ fold_type: fold_type
with *fold::default_seq_fold(srv)
});
fold.fold_crate(fold, doc)
let srv = fold.ctxt;
- ~{
+ {
args: merge_arg_tys(srv, doc.id, doc.args),
return: merge_ret_ty(srv, doc.id, doc.return),
sig: get_fn_sig(srv, doc.id)
- with *doc
+ with doc
}
}
ast_map::node_item(@{
ident: ident,
node: ast::item_fn(decl, _, blk), _
- }) {
+ }, _) {
some(pprust::fun_to_str(decl, ident, []))
}
+ _ {
+ fail "get_fn_sig: undocumented invariant";
+ }
}
}
}
#[test]
fn should_add_fn_sig() {
- let source = "fn a() -> int { }";
- let srv = astsrv::mk_srv_from_str(source);
- let doc = extract::from_srv(srv, "");
- let doc = run(srv, doc);
- assert doc.topmod.fns[0].sig == some("fn a() -> int");
+ let doc = test::mk_doc("fn a() -> int { }");
+ assert doc.topmod.fns()[0].sig == some("fn a() -> int");
}
fn merge_ret_ty(
alt ctxt.ast_map.get(fn_id) {
ast_map::node_item(@{
node: ast::item_fn(decl, _, _), _
- }) {
- if decl.output.node != ast::ty_nil {
- some(pprust::ty_to_str(decl.output))
- } else {
- // Nil-typed return values are not interesting
- none
- }
+ }, _) {
+ ret_ty_to_str(decl)
}
+ _ { fail "get_ret_ty: undocumented invariant"; }
}
}
}
+fn ret_ty_to_str(decl: ast::fn_decl) -> option<str> {
+ if decl.output.node != ast::ty_nil {
+ some(pprust::ty_to_str(decl.output))
+ } else {
+ // Nil-typed return values are not interesting
+ none
+ }
+}
+
#[test]
fn should_add_fn_ret_types() {
- let source = "fn a() -> int { }";
- let srv = astsrv::mk_srv_from_str(source);
- let doc = extract::from_srv(srv, "");
- let doc = run(srv, doc);
- assert doc.topmod.fns[0].return.ty == some("int");
+ let doc = test::mk_doc("fn a() -> int { }");
+ assert doc.topmod.fns()[0].return.ty == some("int");
}
#[test]
fn should_not_add_nil_ret_type() {
- let source = "fn a() { }";
- let srv = astsrv::mk_srv_from_str(source);
- let doc = extract::from_srv(srv, "");
- let doc = run(srv, doc);
- assert doc.topmod.fns[0].return.ty == none;
+ let doc = test::mk_doc("fn a() { }");
+ assert doc.topmod.fns()[0].return.ty == none;
}
fn merge_arg_tys(
vec::map2(args, tys) {|arg, ty|
// Sanity check that we're talking about the same args
assert arg.name == tuple::first(ty);
- ~{
+ {
ty: some(tuple::second(ty))
- with *arg
+ with arg
}
}
}
alt ctxt.ast_map.get(fn_id) {
ast_map::node_item(@{
node: ast::item_fn(decl, _, _), _
- }) |
+ }, _) |
ast_map::node_item(@{
node: ast::item_res(decl, _, _, _, _), _
- }) {
- vec::map(decl.inputs) {|arg|
- (arg.ident, pprust::ty_to_str(arg.ty))
- }
+ }, _) {
+ decl_arg_tys(decl)
+ }
+ _ {
+ fail "get_arg_tys: undocumented invariant";
}
}
}
}
+fn decl_arg_tys(decl: ast::fn_decl) -> [(str, str)] {
+ vec::map(decl.inputs) {|arg|
+ (arg.ident, pprust::ty_to_str(arg.ty))
+ }
+}
+
#[test]
fn should_add_arg_types() {
- let source = "fn a(b: int, c: bool) { }";
- let srv = astsrv::mk_srv_from_str(source);
- let doc = extract::from_srv(srv, "");
- let doc = run(srv, doc);
- let fn_ = doc.topmod.fns[0];
+ let doc = test::mk_doc("fn a(b: int, c: bool) { }");
+ let fn_ = doc.topmod.fns()[0];
assert fn_.args[0].ty == some("int");
assert fn_.args[1].ty == some("bool");
}
) -> doc::constdoc {
let srv = fold.ctxt;
- ~{
+ {
ty: some(astsrv::exec(srv) {|ctxt|
alt ctxt.ast_map.get(doc.id) {
ast_map::node_item(@{
node: ast::item_const(ty, _), _
- }) {
+ }, _) {
pprust::ty_to_str(ty)
}
+ _ {
+ fail "fold_const: undocumented invariant";
+ }
}
})
- with *doc
+ with doc
}
}
#[test]
fn should_add_const_types() {
- let source = "const a: bool = true;";
- let srv = astsrv::mk_srv_from_str(source);
- let doc = extract::from_srv(srv, "");
- let doc = run(srv, doc);
- assert doc.topmod.consts[0].ty == some("bool");
+ let doc = test::mk_doc("const a: bool = true;");
+ assert doc.topmod.consts()[0].ty == some("bool");
}
fn fold_enum(
) -> doc::enumdoc {
let srv = fold.ctxt;
- ~{
+ {
variants: vec::map(doc.variants) {|variant|
let sig = astsrv::exec(srv) {|ctxt|
alt ctxt.ast_map.get(doc.id) {
ast_map::node_item(@{
node: ast::item_enum(ast_variants, _), _
- }) {
+ }, _) {
let ast_variant = option::get(
vec::find(ast_variants) {|v|
v.node.name == variant.name
pprust::variant_to_str(ast_variant)
}
+ _ { fail "fold_enum: undocumented invariant"; }
}
};
- ~{
+ {
sig: some(sig)
- with *variant
+ with variant
}
}
- with *doc
+ with doc
}
}
#[test]
fn should_add_variant_sigs() {
- let source = "enum a { b(int) }";
- let srv = astsrv::mk_srv_from_str(source);
- let doc = extract::from_srv(srv, "");
- let doc = run(srv, doc);
- assert doc.topmod.enums[0].variants[0].sig == some("b(int)");
+ let doc = test::mk_doc("enum a { b(int) }");
+ assert doc.topmod.enums()[0].variants[0].sig == some("b(int)");
}
fn fold_res(
) -> doc::resdoc {
let srv = fold.ctxt;
- ~{
+ {
args: merge_arg_tys(srv, doc.id, doc.args),
sig: some(astsrv::exec(srv) {|ctxt|
alt ctxt.ast_map.get(doc.id) {
ast_map::node_item(@{
node: ast::item_res(decl, _, _, _, _), _
- }) {
+ }, _) {
pprust::res_to_str(decl, doc.name, [])
}
+ _ { fail "fold_res: undocumented invariant"; }
}
})
- with *doc
+ with doc
}
}
#[test]
fn should_add_resource_sigs() {
- let source = "resource r(b: bool) { }";
- let srv = astsrv::mk_srv_from_str(source);
- let doc = extract::from_srv(srv, "");
- let doc = run(srv, doc);
- assert doc.topmod.resources[0].sig == some("resource r(b: bool)");
+ let doc = test::mk_doc("resource r(b: bool) { }");
+ assert doc.topmod.resources()[0].sig == some("resource r(b: bool)");
}
#[test]
fn should_add_resource_arg_tys() {
- let source = "resource r(a: bool) { }";
- let srv = astsrv::mk_srv_from_str(source);
- let doc = extract::from_srv(srv, "");
- let doc = run(srv, doc);
- assert doc.topmod.resources[0].args[0].ty == some("bool");
+ let doc = test::mk_doc("resource r(a: bool) { }");
+ assert doc.topmod.resources()[0].args[0].ty == some("bool");
+}
+
+fn fold_iface(
+ fold: fold::fold<astsrv::srv>,
+ doc: doc::ifacedoc
+) -> doc::ifacedoc {
+ {
+ methods: merge_methods(fold.ctxt, doc.id, doc.methods)
+ with doc
+ }
+}
+
+fn merge_methods(
+ srv: astsrv::srv,
+ item_id: doc::ast_id,
+ docs: [doc::methoddoc]
+) -> [doc::methoddoc] {
+ vec::map(docs) {|doc|
+ {
+ args: merge_method_arg_tys(
+ srv,
+ item_id,
+ doc.args,
+ doc.name),
+ return: merge_method_ret_ty(
+ srv,
+ item_id,
+ doc.return,
+ doc.name),
+ sig: get_method_sig(srv, item_id, doc.name)
+ with doc
+ }
+ }
+}
+
+fn merge_method_ret_ty(
+ srv: astsrv::srv,
+ item_id: doc::ast_id,
+ doc: doc::retdoc,
+ method_name: str
+) -> doc::retdoc {
+ alt get_method_ret_ty(srv, item_id, method_name) {
+ some(ty) {
+ {
+ ty: some(ty)
+ with doc
+ }
+ }
+ none { doc }
+ }
+}
+
+fn get_method_ret_ty(
+ srv: astsrv::srv,
+ item_id: doc::ast_id,
+ method_name: str
+) -> option<str> {
+ astsrv::exec(srv) {|ctxt|
+ alt ctxt.ast_map.get(item_id) {
+ ast_map::node_item(@{
+ node: ast::item_iface(_, methods), _
+ }, _) {
+ alt vec::find(methods) {|method|
+ method.ident == method_name
+ } {
+ some(method) {
+ ret_ty_to_str(method.decl)
+ }
+ _ { fail "get_method_ret_ty: undocumented invariant"; }
+ }
+ }
+ ast_map::node_item(@{
+ node: ast::item_impl(_, _, _, methods), _
+ }, _) {
+ alt vec::find(methods) {|method|
+ method.ident == method_name
+ } {
+ some(method) {
+ ret_ty_to_str(method.decl)
+ }
+ _ { fail "get_method_ret_ty: undocumented invariant"; }
+ }
+ }
+ _ { fail }
+ }
+ }
+}
+
+fn get_method_sig(
+ srv: astsrv::srv,
+ item_id: doc::ast_id,
+ method_name: str
+) -> option<str> {
+ astsrv::exec(srv) {|ctxt|
+ alt ctxt.ast_map.get(item_id) {
+ ast_map::node_item(@{
+ node: ast::item_iface(_, methods), _
+ }, _) {
+ alt vec::find(methods) {|method|
+ method.ident == method_name
+ } {
+ some(method) {
+ some(pprust::fun_to_str(method.decl, method.ident, []))
+ }
+ _ { fail "get_method_sig: undocumented invariant"; }
+ }
+ }
+ ast_map::node_item(@{
+ node: ast::item_impl(_, _, _, methods), _
+ }, _) {
+ alt vec::find(methods) {|method|
+ method.ident == method_name
+ } {
+ some(method) {
+ some(pprust::fun_to_str(method.decl, method.ident, []))
+ }
+ _ { fail "get_method_sig: undocumented invariant"; }
+ }
+ }
+ _ { fail "get_method_sig: undocumented invariant"; }
+ }
+ }
+}
+
+fn merge_method_arg_tys(
+ srv: astsrv::srv,
+ item_id: doc::ast_id,
+ args: [doc::argdoc],
+ method_name: str
+) -> [doc::argdoc] {
+ let tys = get_method_arg_tys(srv, item_id, method_name);
+ vec::map2(args, tys) {|arg, ty|
+ assert arg.name == tuple::first(ty);
+ {
+ ty: some(tuple::second(ty))
+ with arg
+ }
+ }
+}
+
+fn get_method_arg_tys(
+ srv: astsrv::srv,
+ item_id: doc::ast_id,
+ method_name: str
+) -> [(str, str)] {
+ astsrv::exec(srv) {|ctxt|
+ alt ctxt.ast_map.get(item_id) {
+ ast_map::node_item(@{
+ node: ast::item_iface(_, methods), _
+ }, _) {
+ alt vec::find(methods) {|method|
+ method.ident == method_name
+ } {
+ some(method) {
+ decl_arg_tys(method.decl)
+ }
+ _ { fail "get_method_arg_tys: expected method"; }
+ }
+ }
+ ast_map::node_item(@{
+ node: ast::item_impl(_, _, _, methods), _
+ }, _) {
+ alt vec::find(methods) {|method|
+ method.ident == method_name
+ } {
+ some(method) {
+ decl_arg_tys(method.decl)
+ }
+ _ { fail "get_method_arg_tys: expected method"; }
+ }
+ }
+ _ { fail }
+ }
+ }
+}
+
+#[test]
+fn should_add_iface_method_sigs() {
+ let doc = test::mk_doc("iface i { fn a() -> int; }");
+ assert doc.topmod.ifaces()[0].methods[0].sig == some("fn a() -> int");
+}
+
+#[test]
+fn should_add_iface_method_ret_types() {
+ let doc = test::mk_doc("iface i { fn a() -> int; }");
+ assert doc.topmod.ifaces()[0].methods[0].return.ty == some("int");
+}
+
+#[test]
+fn should_not_add_iface_method_nil_ret_type() {
+ let doc = test::mk_doc("iface i { fn a(); }");
+ assert doc.topmod.ifaces()[0].methods[0].return.ty == none;
+}
+
+#[test]
+fn should_add_iface_method_arg_types() {
+ let doc = test::mk_doc("iface i { fn a(b: int, c: bool); }");
+ let fn_ = doc.topmod.ifaces()[0].methods[0];
+ assert fn_.args[0].ty == some("int");
+ assert fn_.args[1].ty == some("bool");
+}
+
+fn fold_impl(
+ fold: fold::fold<astsrv::srv>,
+ doc: doc::impldoc
+) -> doc::impldoc {
+
+ let srv = fold.ctxt;
+
+ let (iface_ty, self_ty) = astsrv::exec(srv) {|ctxt|
+ alt ctxt.ast_map.get(doc.id) {
+ ast_map::node_item(@{
+ node: ast::item_impl(_, iface_ty, self_ty, _), _
+ }, _) {
+ let iface_ty = option::map(iface_ty) {|iface_ty|
+ pprust::ty_to_str(iface_ty)
+ };
+ (iface_ty, some(pprust::ty_to_str(self_ty)))
+ }
+ _ { fail "expected impl" }
+ }
+ };
+
+ {
+ iface_ty: iface_ty,
+ self_ty: self_ty,
+ methods: merge_methods(fold.ctxt, doc.id, doc.methods)
+ with doc
+ }
+}
+
+#[test]
+fn should_add_impl_iface_ty() {
+ let doc = test::mk_doc("impl i of j for int { fn a() { } }");
+ assert doc.topmod.impls()[0].iface_ty == some("j");
+}
+
+#[test]
+fn should_not_add_impl_iface_ty_if_none() {
+ let doc = test::mk_doc("impl i for int { fn a() { } }");
+ assert doc.topmod.impls()[0].iface_ty == none;
+}
+
+#[test]
+fn should_add_impl_self_ty() {
+ let doc = test::mk_doc("impl i for int { fn a() { } }");
+ assert doc.topmod.impls()[0].self_ty == some("int");
+}
+
+#[test]
+fn should_add_impl_method_sigs() {
+ let doc = test::mk_doc("impl i for int { fn a() -> int { fail } }");
+ assert doc.topmod.impls()[0].methods[0].sig == some("fn a() -> int");
+}
+
+#[test]
+fn should_add_impl_method_ret_types() {
+ let doc = test::mk_doc("impl i for int { fn a() -> int { fail } }");
+ assert doc.topmod.impls()[0].methods[0].return.ty == some("int");
+}
+
+#[test]
+fn should_not_add_impl_method_nil_ret_type() {
+ let doc = test::mk_doc("impl i for int { fn a() { } }");
+ assert doc.topmod.impls()[0].methods[0].return.ty == none;
+}
+
+#[test]
+fn should_add_impl_method_arg_types() {
+ let doc = test::mk_doc("impl i for int { fn a(b: int, c: bool) { } }");
+ let fn_ = doc.topmod.impls()[0].methods[0];
+ assert fn_.args[0].ty == some("int");
+ assert fn_.args[1].ty == some("bool");
+}
+
+fn fold_type(
+ fold: fold::fold<astsrv::srv>,
+ doc: doc::tydoc
+) -> doc::tydoc {
+
+ let srv = fold.ctxt;
+
+ {
+ sig: astsrv::exec(srv) {|ctxt|
+ alt ctxt.ast_map.get(doc.id) {
+ ast_map::node_item(@{
+ ident: ident,
+ node: ast::item_ty(ty, params), _
+ }, _) {
+ some(#fmt(
+ "type %s%s = %s",
+ ident,
+ pprust::typarams_to_str(params),
+ pprust::ty_to_str(ty)
+ ))
+ }
+ _ { fail "expected type" }
+ }
+ }
+ with doc
+ }
+}
+
+#[test]
+fn should_add_type_signatures() {
+ let doc = test::mk_doc("type t<T> = int;");
+ assert doc.topmod.types()[0].sig == some("type t<T> = int");
+}
+
+#[cfg(test)]
+mod test {
+ fn mk_doc(source: str) -> doc::cratedoc {
+ let srv = astsrv::mk_srv_from_str(source);
+ let doc = extract::from_srv(srv, "");
+ run(srv, doc)
+ }
}
\ No newline at end of file
} else {
saw_first_line = true;
let spaces = 0u;
- str::loop_chars(line) {|char|
+ str::all(line) {|char|
// Only comparing against space because I wouldn't
// know what to do with mixed whitespace chars
if char == ' ' {
line
} else {
assert str::byte_len(line) >= min_indent;
- str::char_slice(line, min_indent, str::char_len(line))
+ str::slice(line, min_indent, str::char_len(line))
}
};
str::connect(unindented, "\n")
let s = "line1\n\n line2";
let r = unindent(s);
assert r == "line1\n\n line2";
-}
\ No newline at end of file
+}
+S 2012-02-01 196d69b
+ winnt-i386 25f5906994ea01dc322a4b52b2b9a4b1264a6c2d
+ linux-i386 8d4aef1320b62043997a10d28005a2c0c592da6d
+ macos-i386 55d70915501a65e16588c1c2e73632a930c12092
+ linux-x86_64 9a030fc6a649127f55aace94152275c0ee7b1e69
+ macos-x86_64 0d0259cd6e52f30121044f36fd64167ced6d4f09
+
+S 2012-01-31 e5d095d
+ winnt-i386 4d80e3c51fa7bb0f8933eece86dc469016dc020a
+ linux-i386 9e2632c68104fd371b173f130472d6424394a957
+ macos-i386 c74a126bd8367779c2d5914c98f262fc095dab6d
+ linux-x86_64 91618dfd51cc7681854ffb5a0eb41d71b8283d4a
+ macos-x86_64 89c3d55bba1d7d25e2553e2f511afb6d81541ee9
+
S 2012-01-26 28fbb19
winnt-i386 34428e930722e75b1bc7a313ade232052cf95a5d
linux-i386 beefec8535c52d614df22664fd75165f6cec3034
}
fn main(args: [str]) {
- // FIXME: #1527
- sys::set_min_stack(1000000u);
let n = if vec::len(args) == 2u {
int::from_str(args[1])
} else {
}
fn main(args: [str]) {
- // FIXME: #1527
- sys::set_min_stack(1000000u);
let n = if vec::len(args) == 2u {
int::from_str(args[1])
} else {
--- /dev/null
+// based on:
+// http://shootout.alioth.debian.org/
+// u64q/program.php?test=mandelbrot&lang=python3&id=2
+//
+// takes 3 optional args:
+// square image size, defaults to 80_u
+// yield frequency, defaults to 10_u (yield every 10 spawns)
+// output path, default is "" (no output), "-" means stdout
+//
+// in the shootout, they use 16000 as image size
+// yield frequency doesn't seem to have much effect
+//
+// writes pbm image to output path
+
+use std;
+import std::io::writer_util;
+
+type cmplx = {re: f64, im: f64};
+type line = {i: uint, b: [u8]};
+
+impl arith for cmplx {
+ fn *(x: cmplx) -> cmplx {
+ {re: self.re*x.re - self.im*x.im, im: self.re*x.im + self.im*x.re}
+ }
+
+ fn +(x: cmplx) -> cmplx {
+ {re: self.re + x.re, im: self.im + x.im}
+ }
+}
+
+pure fn cabs(x: cmplx) -> f64
+{
+ x.re*x.re + x.im*x.im
+}
+
+fn mb(x: cmplx) -> bool
+{
+ let z = {re: 0., im: 0.};
+ let i = 0;
+ let in = true;
+ while i < 50 {
+ z = z*z + x;
+ if cabs(z) >= 4. {
+ in = false;
+ break;
+ }
+ i += 1;
+ }
+ in
+}
+
+fn fillbyte(x: cmplx, incr: f64) -> u8 {
+ let rv = 0_u8;
+ let i = 0_u8;
+ while i < 8_u8 {
+ let z = {re: x.re + (i as f64)*incr, im: x.im};
+ if mb(z) {
+ rv += 1_u8 << (7_u8 - i);
+ }
+ i += 1_u8;
+ }
+ rv
+}
+
+fn chanmb(i: uint, size: uint, ch: comm::chan<line>) -> ()
+{
+ let crv = [];
+ let incr = 2./(size as f64);
+ let y = incr*(i as f64) - 1.;
+ let xincr = 8.*incr;
+ uint::range(0_u, size/8_u) {
+ |j|
+ let x = {re: xincr*(j as f64) - 1.5, im: y};
+ crv += [fillbyte(x, incr)];
+ };
+ comm::send(ch, {i:i, b:crv});
+}
+
+type devnull = {dn: int};
+
+impl of std::io::writer for devnull {
+ fn write(_b: [const u8]) {}
+ fn seek(_i: int, _s: std::io::seek_style) {}
+ fn tell() -> uint {0_u}
+ fn flush() -> int {0}
+}
+
+fn writer(path: str, writech: comm::chan<comm::chan<line>>, size: uint)
+{
+ let p: comm::port<line> = comm::port();
+ let ch = comm::chan(p);
+ comm::send(writech, ch);
+ let cout: std::io::writer = alt path {
+ "" {
+ {dn: 0} as std::io::writer
+ }
+ "-" {
+ std::io::stdout()
+ }
+ _ {
+ result::get(
+ std::io::file_writer(path,
+ [std::io::create, std::io::truncate]))
+ }
+ };
+ cout.write_line("P4");
+ cout.write_line(#fmt("%u %u", size, size));
+ let lines = std::map::new_uint_hash();
+ let done = 0_u;
+ let i = 0_u;
+ while i < size {
+ let aline = comm::recv(p);
+ if aline.i == done {
+ #debug("W %u", aline.i);
+ cout.write(aline.b);
+ done += 1_u;
+ let prev = done;
+ while prev <= i {
+ if lines.contains_key(prev) {
+ #debug("WS %u", prev);
+ cout.write(lines.get(prev));
+ done += 1_u;
+ lines.remove(prev);
+ prev += 1_u;
+ }
+ else {
+ break
+ }
+ };
+ }
+ else {
+ #debug("S %u", aline.i);
+ lines.insert(aline.i, aline.b);
+ };
+ i += 1_u;
+ }
+}
+
+fn main(argv: [str])
+{
+ let size = if vec::len(argv) < 2_u {
+ 80u
+ }
+ else {
+ uint::from_str(argv[1])
+ };
+ let yieldevery = if vec::len(argv) < 3_u {
+ 10_u
+ }
+ else {
+ uint::from_str(argv[2])
+ };
+ let path = if vec::len(argv) < 4_u {
+ ""
+ }
+ else {
+ argv[3]
+ };
+ let writep = comm::port();
+ let writech = comm::chan(writep);
+ task::spawn {
+ || writer(path, writech, size);
+ };
+ let ch = comm::recv(writep);
+ uint::range(0_u, size) {
+ |j| task::spawn {
+ || chanmb(j, size, ch);
+ };
+ if j % yieldevery == 0_u {
+ #debug("Y %u", j);
+ task::yield();
+ };
+ };
+}
--- /dev/null
+// Based on threadring.erlang by Jira Isa
+use std;
+
+const n_threads: int = 503;
+
+fn start(+token: int) {
+ import iter::*;
+
+ let p = comm::port();
+ let ch = iter::foldl(bind int::range(2, n_threads + 1, _),
+ comm::chan(p)) { |ch, i|
+ let id = n_threads + 2 - i;
+ let {to_child, _} = task::spawn_connected::<int, int> {|p, _ch|
+ roundtrip(id, p, ch)
+ };
+ to_child
+ };
+ comm::send(ch, token);
+ roundtrip(1, p, ch);
+}
+
+fn roundtrip(id: int, p: comm::port<int>, ch: comm::chan<int>) {
+ while (true) {
+ alt comm::recv(p) {
+ 1 {
+ std::io::println(#fmt("%d\n", id));
+ ret;
+ }
+ token {
+ #debug("%d %d", id, token);
+ comm::send(ch, token - 1);
+ if token <= n_threads {
+ ret;
+ }
+ }
+ }
+ }
+}
+
+fn main(args: [str]) {
+ let token = if vec::len(args) < 2u {
+ 1000
+ } else {
+ int::from_str(args[1])
+ };
+
+ start(token);
+}
\ No newline at end of file
use std;
-import option = option::t;
+import option = option;
import option::some;
import option::none;
import str;
use std;
-import option = option::t;
+import option = option;
import option::{some, none};
import std::{map, io, time};
import io::reader_util;
+// xfail-test
// error-pattern:expected a syntax expander name
fn main() {
#();
-}
\ No newline at end of file
+}
use std;
import str::*;
-fn main() {
+fn main() unsafe {
let a: uint = 4u;
let b: uint = 1u;
- log(error, safe_slice("kitties", a, b));
+ log(error, str::unsafe::slice_bytes_safe_range("kitties", a, b));
}
--- /dev/null
+// In this test, the mode gets inferred to ++ due to the apply_int(),
+// but then we get a failure in the generic apply().
+
+fn apply<A>(f: fn(A) -> A, a: A) -> A { f(a) }
+fn apply_int(f: fn(int) -> int, a: int) -> int { f(a) }
+
+fn main() {
+ let f = {|i| i};
+ assert apply_int(f, 2) == 2;
+ assert apply(f, 2) == 2; //! ERROR expected argument mode ++
+}
+++ /dev/null
-// error-pattern:expected `sbuf` but found `FILE`
-use std;
-
-fn main() unsafe {
- let f: std::os::libc::FILE = std::io::rustrt::rust_get_stdin();
- std::os::libc::fopen(f, f);
-}
-// error-pattern:Unsatisfied precondition constraint (for example, le(b, d
-use std;
-import str::*;
-import uint::*;
+// error-pattern:Unsatisfied precondition constraint (for example, uint::le
-fn main() {
+fn main() unsafe {
let a: uint = 1u;
let b: uint = 4u;
let c: uint = 5u;
// make sure that the constraint le(b, a) exists...
- check (le(b, a));
+ check (uint::le(b, a));
// ...invalidate it...
b += 1u;
- check (le(c, a));
+ check (uint::le(c, a));
// ...and check that it doesn't get set in the poststate of
// the next statement, since it's not true in the
// prestate.
let d <- a;
- log(debug, safe_slice("kitties", b, d));
+ log(debug, str::unsafe::slice_bytes_safe_range("kitties", b, d));
}
--- /dev/null
+// -*- rust -*-
+// error-pattern: Non-exhaustive pattern
+enum t { a(u), b }
+enum u { c, d }
+
+fn main() {
+ let x = a(c);
+ alt x {
+ a(d) { fail "hello"; }
+ b { fail "goodbye"; }
+ }
+}
+
--- /dev/null
+// -*- rust -*-
+// error-pattern: Non-exhaustive pattern
+enum t { a, b, }
+
+fn main() { let x = a; alt x { b { } } }
// error-pattern: mismatched types
-enum bar { t1((), option::t<[int]>), t2, }
+enum bar { t1((), option<[int]>), t2, }
fn foo(t: bar) -> int { alt t { t1(_, some(x)) { ret x * 3; } _ { fail; } } }
// error-pattern: mismatched types
-enum bar { t1((), option::t<[int]>), t2, }
+enum bar { t1((), option<[int]>), t2, }
fn foo(t: bar) {
alt t {
// -*- rust -*-
// xfail-test
-// error-pattern:option::t
+// error-pattern:option
use std;
import vec::*;
import std::os;
fn main() {
- log(debug, 1.0 as os::libc::FILE); // Can't cast float to native.
+ log(debug, 1.0 as os::FILE); // Can't cast float to native.
}
(*regs < 2) as uint
}
-fn test8() -> int { let val = @0; alt true { true { } } *val < 1 ? 0 : 1 }
+fn test8() -> int {
+ let val = @0;
+ alt true {
+ true { }
+ }
+ if *val < 1 {
+ 0
+ } else {
+ 1
+ }
+}
fn test9() { let regs = @mutable 0; alt true { true { } } *regs += 1; }
fn main() {
let sth = {x: 0, y: 1,};
let sth2 = {y: 9 with sth};
- assert (sth.x + sth2.y == 9);
+ assert sth.x + sth2.y == 9;
}
-// error-pattern:Predicate le(a, b) failed
-use std;
-import str::*;
-import uint::le;
+// error-pattern:Predicate uint::le(a, b) failed
-fn main() {
+fn main() unsafe {
let a: uint = 4u;
let b: uint = 1u;
- check (le(a, b));
- log(error, safe_slice("kitties", a, b));
+ check (uint::le(a, b));
+ log(error, str::unsafe::slice_bytes_safe_range("kitties", a, b));
}
use std;
native mod rustrt {
- fn pin_task();
+ fn last_os_error() -> str;
}
fn getbig_call_c_and_fail(i: int) {
if i != 0 {
getbig_call_c_and_fail(i - 1);
} else {
- rustrt::pin_task();
+ rustrt::last_os_error();
fail;
}
}
use std;
-native mod rustrt {
- fn set_min_stack(size: uint);
-}
-
fn getbig_and_fail(&&i: int) {
let r = and_then_get_big_again(@0);
if i != 0 {
}
fn main() {
- rustrt::set_min_stack(256u);
task::spawn {||
getbig_and_fail(1);
};
+++ /dev/null
-
-
-
-// -*- rust -*-
-
-// error-pattern:non-exhaustive match failure
-enum t { a, b, }
-
-fn main() { let x = a; alt x { b { } } }
enum sty { ty_nil, }
-type raw_t = {struct: sty, cname: option::t<str>, hash: uint};
+type raw_t = {struct: sty, cname: option<str>, hash: uint};
-fn mk_raw_ty(st: sty, cname: option::t<str>) -> raw_t {
+fn mk_raw_ty(st: sty, cname: option<str>) -> raw_t {
ret {struct: st, cname: cname, hash: 0u};
}
use std;
import option;
-import option::t;
-import option::none;
-import option::some;
-fn foo<T>(y: option::t<T>) {
+fn foo<T>(y: option<T>) {
let x: int;
let rs: [int] = [];
/* tests that x doesn't get put in the precondition for the
enum foo { foo1, foo2, }
}
-fn bar(x: m1::foo) { alt x { m1::foo1 { } } }
+fn bar(x: m1::foo) { alt x { m1::foo1 { } m1::foo2 { } } }
fn main() { }
#[abi = "cdecl"]
native mod rustrt {
- fn pin_task();
+ fn rand_new() -> *ctypes::void;
}
-fn main() { bind rustrt::pin_task(); }
+fn main() { bind rustrt::rand_new(); }
#[abi = "cdecl"]
#[nolink]
native mod test {
- fn do_gc();
fn unsupervise();
}
// FIXME (#1058): comparison of native fns
fn test_native_fn() {
/*
- assert (native_mod::do_gc == native_mod::do_gc);
- assert (native_mod::do_gc != native_mod::unsupervise);
+ assert (native_mod::last_os_error != native_mod::unsupervise);
*/
}
+++ /dev/null
-// Allow block arguments with ternary... why not, no chance of ambig.
-fn main() {
- let v = [-1f, 1f];
- let foo = vec::any(v) { |e| float::is_negative(e) } ? true : false;
- assert foo;
-}
--- /dev/null
+// xfail-test
+class cat {
+ priv {
+ let mutable meows : uint;
+ fn meow() {
+ #error("Meow");
+ meows += 1;
+ if meows % 5 == 0 {
+ how_hungry += 1;
+ }
+ }
+ }
+
+ let how_hungry : int;
+
+ new(in_x : uint, in_y : int) { meows = in_x; how_hungry = in_y; }
+
+ fn speak() { meow(); }
+
+ fn eat() {
+ if how_hungry > 0 {
+ #error("OM NOM NOM");
+ how_hungry -= 2;
+ }
+ else {
+ #error("Not hungry!");
+ }
+ }
+}
\ No newline at end of file
--- /dev/null
+fn foo(i: int) -> int { i + 1 }
+
+fn apply<A>(f: fn(A) -> A, v: A) -> A { f(v) }
+
+fn main() {
+ let f = {|i| foo(i)};
+ assert apply(f, 2) == 3;
+}
--- /dev/null
+// Test a rather underspecified example:
+
+fn main() {
+ let f = {|i| i};
+ assert f(2) == 2;
+ assert f(5) == 5;
+}
-use std;
-import str::*;
-import uint::*;
-fn main() {
+fn main() unsafe {
let a: uint = 1u;
let b: uint = 4u;
let c: uint = 17u;
- check (le(a, b));
+ check (uint::le(a, b));
c <- a;
- log(debug, safe_slice("kitties", c, b));
+ log(debug, str::unsafe::slice_bytes_safe_range("kitties", c, b));
}
-use std;
-import str::*;
-import uint::*;
-
-fn main() {
+fn main() unsafe {
let a: uint = 1u;
let b: uint = 4u;
- check (le(a, b));
+ check (uint::le(a, b));
let c <- a;
- log(debug, safe_slice("kitties", c, b));
+ log(debug, str::unsafe::slice_bytes_safe_range("kitties", c, b));
}
-use std;
-import str::*;
-import uint::*;
-
-fn main() {
+fn main() unsafe {
let a: uint = 4u;
let b: uint = 1u;
- check (le(b, a));
+ check (uint::le(b, a));
b <-> a;
- log(debug, safe_slice("kitties", a, b));
+ log(debug, str::unsafe::slice_bytes_safe_range("kitties", a, b));
}
-use std;
-import str::*;
-import uint::*;
-
-fn main() {
+fn main() unsafe {
let a: uint = 1u;
let b: uint = 4u;
- check (le(a, b));
+ check (uint::le(a, b));
let c = b;
- log(debug, safe_slice("kitties", a, c));
+ log(debug, str::unsafe::slice_bytes_safe_range("kitties", a, c));
}
}
fn test_color(color: color, val: int, name: str) {
- assert (color as int == val);
- assert (color as float == val as float);
+ assert color as int == val;
+ assert color as float == val as float;
}
-use std;
-import str::*;
-import uint::*;
-
-fn main() {
+fn main() unsafe {
let a: uint = 1u;
let b: uint = 4u;
- check (le(a, b));
- log(debug, safe_slice("kitties", a, b));
+ check (uint::le(a, b));
+ log(debug, str::unsafe::slice_bytes_safe_range("kitties", a, b));
}
use std;
-import option = option::t;
+import option = option;
import option::some;
import option::none;
import str;
}
iface map<T> {
- fn iter(fn(T));
fn map<U>(f: fn(T) -> U) -> [U];
}
impl <T> of map<T> for [T] {
- fn iter(_f: fn(T)) {}
fn map<U>(f: fn(T) -> U) -> [U] {
let r = [];
for x in self { r += [f(x)]; }
--- /dev/null
+fn main() {
+ const _x: int = 1<<2;
+}
use std;
import option;
-fn f<T>(&o: option::t<T>) {
+fn f<T>(&o: option<T>) {
assert o == option::none;
}
native mod rustrt {
#[attr];
- #[attr]
- type sbuf;
-
#[attr]
fn unsupervise();
}
--- /dev/null
+// pp-exact - Make sure we print all the attributes
+
+#[frobable]
+iface frobable {
+ #[frob_attr]
+ fn frob();
+ #[defrob_attr]
+ fn defrob();
+}
+
+#[int_frobable]
+impl frobable for int {
+ #[frob_attr1]
+ fn frob() {
+ #[frob_attr2];
+ }
+
+ #[defrob_attr1]
+ fn defrob() {
+ #[defrob_attr2];
+ }
+}
+
+fn main() { }
use std;
import task;
-native mod rustrt {
- fn set_min_stack(size: uint);
-}
-
fn getbig(&&i: int) {
if i != 0 {
getbig(i - 1);
fn main() {
let sz = 400u;
while sz < 500u {
- rustrt::set_min_stack(sz);
task::join(task::spawn_joinable {|| getbig(200) });
sz += 1u;
}
import std::rand;
native mod rustrt {
- fn set_min_stack(size: uint);
fn debug_get_stk_seg() -> *u8;
fn unsupervise();
fn last_os_error() -> str;
fn rust_getcwd() -> str;
fn refcount(box: @int);
- fn do_gc();
- fn pin_task();
- fn unpin_task();
fn get_task_id();
fn sched_threads();
fn rust_get_task();
fn calllink02() { rustrt::last_os_error(); }
fn calllink03() { rustrt::rust_getcwd(); }
fn calllink04() { rustrt::refcount(@0); }
-fn calllink05() { rustrt::do_gc(); }
-fn calllink06() { rustrt::pin_task(); }
-fn calllink07() { rustrt::unpin_task(); }
fn calllink08() { rustrt::get_task_id(); }
fn calllink09() { rustrt::sched_threads(); }
fn calllink10() { rustrt::rust_get_task(); }
calllink02,
calllink03,
calllink04,
- calllink05,
- calllink06,
- calllink07,
calllink08,
calllink09,
calllink10
for f in fns {
let sz = rng.next() % 256u32 + 256u32;
let frame_backoff = rng.next() % 10u32 + 1u32;
- rustrt::set_min_stack(sz as uint);
task::join(task::spawn_joinable {|| runtest(f, frame_backoff);});
}
}
\ No newline at end of file
#[abi = "cdecl"]
#[link_name = "rustrt"]
native mod rustrt1 {
- fn pin_task();
+ fn last_os_error() -> str;
}
#[abi = "cdecl"]
#[link_name = "rustrt"]
native mod rustrt2 {
- fn pin_task();
+ fn last_os_error() -> str;
}
fn main() {
- rustrt1::pin_task();
- rustrt2::pin_task();
+ rustrt1::last_os_error();
+ rustrt2::last_os_error();
}
+++ /dev/null
-
-
-#[abi = "cdecl"]
-#[nolink]
-native mod libc {
- type file_handle;
-}
-
-fn main() { assert (true); }
import option::some;
import option::none;
-enum t { foo(int, uint), bar(int, option::t<int>), }
+enum t { foo(int, uint), bar(int, option<int>), }
fn nested(o: t) {
alt o {
{x: -self.x, y: -self.y}
}
fn [](x: bool) -> int {
- x ? self.x : self.y
+ if x { self.x } else { self.y }
}
}
assert -p == {x: -11, y: -22};
assert p[true] == 11;
assert p[false] == 22;
+ // Issue #1733
+ fn~(_x: int){}(p[true]);
}
--- /dev/null
+// xfail-pretty
+
+use std;
+use rustc;
+
+import rustc::*;
+import std::io::*;
+
+import rustc::driver::diagnostic;
+import rustc::syntax::ast;
+import rustc::syntax::codemap;
+import rustc::syntax::parse::parser;
+import rustc::syntax::print::*;
+
+fn new_parse_sess() -> parser::parse_sess {
+ let cm = codemap::new_codemap();
+ let handler = diagnostic::mk_handler(option::none);
+ let sess = @{
+ cm: cm,
+ mutable next_id: 1,
+ span_diagnostic: diagnostic::mk_span_handler(handler, cm),
+ mutable chpos: 0u,
+ mutable byte_pos: 0u
+ };
+ ret sess;
+}
+
+iface fake_ext_ctxt {
+ fn session() -> fake_session;
+}
+
+type fake_options = {cfg: ast::crate_cfg};
+
+type fake_session = {opts: @fake_options,
+ parse_sess: parser::parse_sess};
+
+impl of fake_ext_ctxt for fake_session {
+ fn session() -> fake_session {self}
+}
+
+fn mk_ctxt() -> fake_ext_ctxt {
+ let opts : fake_options = {cfg: []};
+ {opts: @opts, parse_sess: new_parse_sess()} as fake_ext_ctxt
+}
+
+
+fn main() {
+ let ext_cx = mk_ctxt();
+
+ let abc = #ast{23};
+ check_pp(abc, pprust::print_expr, "23");
+
+ let expr3 = #ast{2 - $(abc) + 7};
+ check_pp(expr3, pprust::print_expr, "2 - 23 + 7");
+
+ let expr4 = #ast{2 - $(#(3)) + 9};
+ check_pp(expr4, pprust::print_expr, "2 - 3 + 9");
+
+ let ty = #ast(ty){int};
+ check_pp(ty, pprust::print_type, "int");
+
+ let ty2 = #ast(ty){option<$(ty)>};
+ check_pp(ty2, pprust::print_type, "option<int>");
+
+ let item = #ast(item){const x : int = 10;};
+ check_pp(item, pprust::print_item, "const x: int = 10;");
+
+ let item2: @ast::item = #ast(item){const x : int = $(abc);};
+ check_pp(item2, pprust::print_item, "const x: int = 23;");
+
+ let stmt = #ast(stmt){let x = 20;};
+ check_pp(*stmt, pprust::print_stmt, "let x = 20;");
+
+ let stmt2 = #ast(stmt){let x : $(ty) = $(abc);};
+ check_pp(*stmt2, pprust::print_stmt, "let x: int = 23;");
+
+ let pat = #ast(pat){some(_)};
+ check_pp(pat, pprust::print_pat, "some(_)");
+}
+
+fn check_pp<T>(expr: T, f: fn(pprust::ps, T), expect: str) {
+ let buf = mk_mem_buffer();
+ let pp = pprust::rust_printer(buf as std::io::writer);
+ f(pp, expr);
+ pp::eof(pp.s);
+ let str = mem_buffer_str(buf);
+ stdout().write_line(str);
+ if expect != "" {
+ #error("expect: '%s', got: '%s'", expect, str);
+ assert str == expect;
+ }
+}
+
enum opt_span {
- //hack (as opposed to option::t), to make `span` compile
+ //hack (as opposed to option), to make `span` compile
os_none,
os_some(@span),
}
import std::os;
fn main() {
- let f = 1 as os::libc::FILE;
+ let f = 1 as os::FILE;
log(debug, f as int);
log(debug, f as uint);
log(debug, f as i8);
log(debug, 1 as uint);
log(debug, 1 as float);
log(debug, 1 as bool);
- log(debug, 1 as os::libc::FILE);
+ log(debug, 1 as os::FILE);
log(debug, 1 as i8);
log(debug, 1 as i16);
log(debug, 1 as i32);
log(debug, 1u as uint);
log(debug, 1u as float);
log(debug, 1u as bool);
- log(debug, 1u as os::libc::FILE);
+ log(debug, 1u as os::FILE);
log(debug, 1u as i8);
log(debug, 1u as i16);
log(debug, 1u as i32);
log(debug, 1i8 as uint);
log(debug, 1i8 as float);
log(debug, 1i8 as bool);
- log(debug, 1i8 as os::libc::FILE);
+ log(debug, 1i8 as os::FILE);
log(debug, 1i8 as i8);
log(debug, 1i8 as i16);
log(debug, 1i8 as i32);
log(debug, 1u8 as uint);
log(debug, 1u8 as float);
log(debug, 1u8 as bool);
- log(debug, 1u8 as os::libc::FILE);
+ log(debug, 1u8 as os::FILE);
log(debug, 1u8 as i8);
log(debug, 1u8 as i16);
log(debug, 1u8 as i32);
log(debug, 1i16 as uint);
log(debug, 1i16 as float);
log(debug, 1i16 as bool);
- log(debug, 1i16 as os::libc::FILE);
+ log(debug, 1i16 as os::FILE);
log(debug, 1i16 as i8);
log(debug, 1i16 as i16);
log(debug, 1i16 as i32);
log(debug, 1u16 as uint);
log(debug, 1u16 as float);
log(debug, 1u16 as bool);
- log(debug, 1u16 as os::libc::FILE);
+ log(debug, 1u16 as os::FILE);
log(debug, 1u16 as i8);
log(debug, 1u16 as i16);
log(debug, 1u16 as i32);
log(debug, 1i32 as uint);
log(debug, 1i32 as float);
log(debug, 1i32 as bool);
- log(debug, 1i32 as os::libc::FILE);
+ log(debug, 1i32 as os::FILE);
log(debug, 1i32 as i8);
log(debug, 1i32 as i16);
log(debug, 1i32 as i32);
log(debug, 1u32 as uint);
log(debug, 1u32 as float);
log(debug, 1u32 as bool);
- log(debug, 1u32 as os::libc::FILE);
+ log(debug, 1u32 as os::FILE);
log(debug, 1u32 as i8);
log(debug, 1u32 as i16);
log(debug, 1u32 as i32);
log(debug, 1i64 as uint);
log(debug, 1i64 as float);
log(debug, 1i64 as bool);
- log(debug, 1i64 as os::libc::FILE);
+ log(debug, 1i64 as os::FILE);
log(debug, 1i64 as i8);
log(debug, 1i64 as i16);
log(debug, 1i64 as i32);
log(debug, 1u64 as uint);
log(debug, 1u64 as float);
log(debug, 1u64 as bool);
- log(debug, 1u64 as os::libc::FILE);
+ log(debug, 1u64 as os::FILE);
log(debug, 1u64 as i8);
log(debug, 1u64 as i16);
log(debug, 1u64 as i32);
log(debug, 1u64 as uint);
log(debug, 1u64 as float);
log(debug, 1u64 as bool);
- log(debug, 1u64 as os::libc::FILE);
+ log(debug, 1u64 as os::FILE);
log(debug, 1u64 as i8);
log(debug, 1u64 as i16);
log(debug, 1u64 as i32);
log(debug, true as uint);
log(debug, true as float);
log(debug, true as bool);
- log(debug, true as os::libc::FILE);
+ log(debug, true as os::FILE);
log(debug, true as i8);
log(debug, true as i16);
log(debug, true as i32);
let t = task::spawn_joinable {|| start(i); };
// Sleep long enough for the task to finish.
- task::sleep(10000u);
+ let i = 0;
+ while i < 10000 {
+ task::yield();
+ i += 1;
+ }
// Try joining tasks that have already finished.
task::join(t);
+++ /dev/null
-/**
- Exercises task pinning and unpinning. Doesn't really ensure it
- works, just makes sure it runs.
-*/
-
-use std;
-
-import task;
-
-fn main() { task::pin(); task::unpin(); }
+++ /dev/null
-fn test_simple() { let x = true ? 10 : 11; assert (x == 10); }
-
-fn test_precedence() {
- let x;
-
- x = true || true ? 10 : 11;
- assert (x == 10);
-
- x = true == false ? 10 : 11;
- assert (x == 11);
-
- x = true ? false ? 10 : 11 : 12;
- assert (x == 11);
-
- let y = true ? 0xF0 : 0x0 | 0x0F;
- assert (y == 0xF0);
-
- y = true ? 0xF0 | 0x0F : 0x0;
- assert (y == 0xFF);
-}
-
-fn test_associativity() {
- // Ternary is right-associative
- let x = false ? 10 : false ? 11 : 12;
- assert (x == 12);
-}
-
-fn test_lval() {
- let box1: @mutable int = @mutable 10;
- let box2: @mutable int = @mutable 10;
- *(true ? box1 : box2) = 100;
- assert (*box1 == 100);
-}
-
-fn test_as_stmt() { let s; true ? s = 10 : s = 12; assert (s == 10); }
-
-fn main() {
- test_simple();
- test_precedence();
- test_associativity();
- test_lval();
- test_as_stmt();
-}
assert (str::byte_len(s) == 10u);
assert (str::char_len(s) == 4u);
- assert (vec::len::<char>(str::to_chars(s)) == 4u);
- assert (str::eq(str::from_chars(str::to_chars(s)), s));
+ assert (vec::len::<char>(str::chars(s)) == 4u);
+ assert (str::eq(str::from_chars(str::chars(s)), s));
assert (str::char_at(s, 0u) == 'e');
assert (str::char_at(s, 1u) == 'é');
do {
while (ret) {
if (ret) {
- alt (ret) { _ { ret ? ret : ret } };
+ alt (ret) {
+ _ {
+ if (ret) {
+ ret
+ } else {
+ ret
+ }
+ }
+ };
} else if (ret) {
ret;
}