Merge branch 'master' into recursive-elseif
Conflicts: src/Makefile src/comp/front/ast.rs src/comp/front/parser.rs src/comp/middle/fold.rs src/comp/middle/trans.rs
This commit is contained in:
@@ -15,6 +15,7 @@ Jason Orendorff <jorendorff@mozilla.com>
|
||||
Jeff Balogh <jbalogh@mozilla.com>
|
||||
Jeff Mulzelaar <jmuizelaar@mozilla.com>
|
||||
Jeffrey Yasskin <jyasskin@gmail.com>
|
||||
Marijn Haverbeke <marijnh@gmail.com>
|
||||
Matt Brubeck <mbrubeck@limpet.net>
|
||||
Michael Bebenita <mbebenita@mozilla.com>
|
||||
Or Brostovski <tohava@gmail.com>
|
||||
|
||||
@@ -592,10 +592,12 @@ or interrupted by ignored characters.
|
||||
|
||||
Most tokens in Rust follow rules similar to the C family.
|
||||
|
||||
Most tokens (including identifiers, whitespace, keywords, operators and
|
||||
structural symbols) are drawn from the ASCII-compatible range of
|
||||
Unicode. String and character literals, however, may include the full range of
|
||||
Unicode characters.
|
||||
Most tokens (including whitespace, keywords, operators and structural symbols)
|
||||
are drawn from the ASCII-compatible range of Unicode. Identifiers are drawn
|
||||
from Unicode characters specified by the @code{XID_start} and
|
||||
@code{XID_continue} rules given by UAX #31@footnote{Unicode Standard Annex
|
||||
#31: Unicode Identifier and Pattern Syntax}. String and character literals may
|
||||
include the full range of Unicode characters.
|
||||
|
||||
@emph{TODO: formalize this section much more}.
|
||||
|
||||
@@ -638,18 +640,22 @@ token or a syntactic extension token. Multi-line comments may be nested.
|
||||
@c * Ref.Lex.Ident:: Identifier tokens.
|
||||
@cindex Identifier token
|
||||
|
||||
Identifiers follow the pattern of C identifiers: they begin with a
|
||||
@emph{letter} or @emph{underscore}, and continue with any combination of
|
||||
@emph{letters}, @emph{decimal digits} and underscores, and must not be equal
|
||||
to any keyword or reserved token. @xref{Ref.Lex.Key}. @xref{Ref.Lex.Res}.
|
||||
Identifiers follow the rules given by Unicode Standard Annex #31, in the form
|
||||
closed under NFKC normalization, @emph{excluding} those tokens that are
|
||||
otherwise defined as keywords or reserved
|
||||
tokens. @xref{Ref.Lex.Key}. @xref{Ref.Lex.Res}.
|
||||
|
||||
A @emph{letter} is a Unicode character in the ranges U+0061-U+007A and
|
||||
U+0041-U+005A (@code{'a'}-@code{'z'} and @code{'A'}-@code{'Z'}).
|
||||
That is: an identifier starts with any character having derived property
|
||||
@code{XID_Start} and continues with zero or more characters having derived
|
||||
property @code{XID_Continue}; and such an identifier is NFKC-normalized during
|
||||
lexing, such that all subsequent comparison of identifiers is performed on the
|
||||
NFKC-normalized forms.
|
||||
|
||||
An @dfn{underscore} is the character U+005F ('_').
|
||||
@emph{TODO: define relationship between Unicode and Rust versions}.
|
||||
|
||||
A @dfn{decimal digit} is a character in the range U+0030-U+0039
|
||||
(@code{'0'}-@code{'9'}).
|
||||
@footnote{This identifier syntax is a superset of the identifier syntaxes of C
|
||||
and Java, and is modeled on Python PEP #3131, which formed the definition of
|
||||
identifiers in Python 3.0 and later.}
|
||||
|
||||
@node Ref.Lex.Key
|
||||
@subsection Ref.Lex.Key
|
||||
@@ -1984,22 +1990,22 @@ module system).
|
||||
An example of a @code{tag} item and its use:
|
||||
@example
|
||||
tag animal @{
|
||||
dog();
|
||||
cat();
|
||||
dog;
|
||||
cat;
|
||||
@}
|
||||
|
||||
let animal a = dog();
|
||||
a = cat();
|
||||
let animal a = dog;
|
||||
a = cat;
|
||||
@end example
|
||||
|
||||
An example of a @emph{recursive} @code{tag} item and its use:
|
||||
@example
|
||||
tag list[T] @{
|
||||
nil();
|
||||
nil;
|
||||
cons(T, @@list[T]);
|
||||
@}
|
||||
|
||||
let list[int] a = cons(7, cons(13, nil()));
|
||||
let list[int] a = cons(7, cons(13, nil));
|
||||
@end example
|
||||
|
||||
|
||||
@@ -3395,9 +3401,9 @@ control enters the block.
|
||||
An example of a pattern @code{alt} statement:
|
||||
|
||||
@example
|
||||
type list[X] = tag(nil(), cons(X, @@list[X]));
|
||||
type list[X] = tag(nil, cons(X, @@list[X]));
|
||||
|
||||
let list[int] x = cons(10, cons(11, nil()));
|
||||
let list[int] x = cons(10, cons(11, nil));
|
||||
|
||||
alt (x) @{
|
||||
case (cons(a, cons(b, _))) @{
|
||||
|
||||
229
src/Makefile
229
src/Makefile
@@ -32,6 +32,19 @@ CFG_RUSTC_FLAGS := -nowarn
|
||||
# embedded into the executable, so use a no-op command.
|
||||
DSYMUTIL := true
|
||||
|
||||
ifeq ($(CFG_OSTYPE), FreeBSD)
|
||||
CFG_RUNTIME := librustrt.so
|
||||
CFG_STDLIB := libstd.so
|
||||
CFG_GCC_CFLAGS += -fPIC -march=i686 -I/usr/local/include
|
||||
CFG_GCC_LINK_FLAGS += -shared -fPIC -lpthread -lrt
|
||||
ifeq ($(CFG_CPUTYPE), x86_64)
|
||||
CFG_GCC_CFLAGS += -m32
|
||||
CFG_GCC_LINK_FLAGS += -m32
|
||||
endif
|
||||
CFG_NATIVE := 1
|
||||
CFG_UNIXY := 1
|
||||
endif
|
||||
|
||||
ifeq ($(CFG_OSTYPE), Linux)
|
||||
CFG_RUNTIME := librustrt.so
|
||||
CFG_STDLIB := libstd.so
|
||||
@@ -43,13 +56,6 @@ ifeq ($(CFG_OSTYPE), Linux)
|
||||
endif
|
||||
CFG_NATIVE := 1
|
||||
CFG_UNIXY := 1
|
||||
CFG_VALGRIND := $(shell which valgrind)
|
||||
ifdef CFG_VALGRIND
|
||||
CFG_VALGRIND += --leak-check=full \
|
||||
--error-exitcode=1 \
|
||||
--quiet --vex-iropt-level=0 \
|
||||
--suppressions=etc/x86.supp
|
||||
endif
|
||||
endif
|
||||
|
||||
ifeq ($(CFG_OSTYPE), Darwin)
|
||||
@@ -117,6 +123,13 @@ ifdef CFG_UNIXY
|
||||
CFG_GCC_LINK_FLAGS += -m32
|
||||
endif
|
||||
endif
|
||||
CFG_VALGRIND := $(shell which valgrind)
|
||||
ifdef CFG_VALGRIND
|
||||
CFG_VALGRIND += --leak-check=full \
|
||||
--error-exitcode=1 \
|
||||
--quiet --vex-iropt-level=0 \
|
||||
--suppressions=etc/x86.supp
|
||||
endif
|
||||
endif
|
||||
|
||||
ifdef CFG_GCC
|
||||
@@ -388,6 +401,7 @@ TASK_XFAILS := test/run-pass/task-comm-8.rs \
|
||||
TEST_XFAILS_BOOT := $(TASK_XFAILS) \
|
||||
$(NOMINAL_TAG_XFAILS) \
|
||||
$(CONST_TAG_XFAILS) \
|
||||
test/run-pass/arith-unsigned.rs \
|
||||
test/run-pass/child-outlives-parent.rs \
|
||||
test/run-pass/clone-with-exterior.rs \
|
||||
test/run-pass/constrained-type.rs \
|
||||
@@ -395,7 +409,7 @@ TEST_XFAILS_BOOT := $(TASK_XFAILS) \
|
||||
test/run-pass/obj-as.rs \
|
||||
test/run-pass/vec-slice.rs \
|
||||
test/run-pass/fn-lval.rs \
|
||||
test/run-pass/generic-recursive-tag.rs \
|
||||
test/run-pass/generic-fn-box.rs \
|
||||
test/run-pass/generic-tup.rs \
|
||||
test/run-pass/iter-ret.rs \
|
||||
test/run-pass/lib-io.rs \
|
||||
@@ -414,101 +428,104 @@ TEST_XFAILS_BOOT := $(TASK_XFAILS) \
|
||||
test/compile-fail/bad-recv.rs \
|
||||
test/compile-fail/bad-send.rs \
|
||||
test/compile-fail/infinite-vec-type-recursion.rs \
|
||||
test/compile-fail/tail-non-call.rs \
|
||||
test/compile-fail/writing-through-read-alias.rs
|
||||
|
||||
# Same strategy here for the time being: just list the ones that
|
||||
# work and assume the others don't. Invert this when we're closer
|
||||
# to actually bootstrapping.
|
||||
|
||||
TEST_XFAILS_RUSTC := $(filter-out \
|
||||
$(addprefix test/run-pass/, \
|
||||
alt-path.rs \
|
||||
alt-pattern-simple.rs \
|
||||
alt-tag.rs \
|
||||
arith-0.rs \
|
||||
arith-1.rs \
|
||||
arith-2.rs \
|
||||
autoderef-full-lval.rs \
|
||||
bind-exterior.rs \
|
||||
bind-interior.rs \
|
||||
bind-thunk.rs \
|
||||
bind-trivial.rs \
|
||||
bitwise.rs \
|
||||
bool-not.rs \
|
||||
box.rs \
|
||||
box-in-tup.rs \
|
||||
cast.rs \
|
||||
char.rs \
|
||||
complex.rs \
|
||||
const.rs \
|
||||
dead-code-one-arm-if.rs \
|
||||
deep.rs \
|
||||
deref.rs \
|
||||
div-mod.rs \
|
||||
drop-bind-thunk-args.rs \
|
||||
drop-on-ret.rs \
|
||||
else-if.rs \
|
||||
fact.rs \
|
||||
fn-lval.rs \
|
||||
fun-call-variants.rs \
|
||||
fun-indirect-call.rs \
|
||||
generic-fn.rs \
|
||||
generic-fn-infer.rs \
|
||||
generic-drop-glue.rs \
|
||||
generic-tup.rs \
|
||||
generic-type.rs \
|
||||
hello.rs \
|
||||
int.rs \
|
||||
i32-sub.rs \
|
||||
i8-incr.rs \
|
||||
import2.rs \
|
||||
import3.rs \
|
||||
import4.rs \
|
||||
import5.rs \
|
||||
import6.rs \
|
||||
import7.rs \
|
||||
import8.rs \
|
||||
item-name-overload.rs \
|
||||
large-records.rs \
|
||||
lazy-init.rs \
|
||||
lazy-and-or.rs \
|
||||
leak-box-as-tydesc.rs \
|
||||
linear-for-loop.rs \
|
||||
multiline-comment.rs \
|
||||
mutual-recursion-group.rs \
|
||||
obj-drop.rs \
|
||||
obj-recursion.rs \
|
||||
obj-with-vec.rs \
|
||||
operator-associativity.rs \
|
||||
opeq.rs \
|
||||
output-slot-variants.rs \
|
||||
over-constrained-vregs.rs \
|
||||
readalias.rs \
|
||||
rec.rs \
|
||||
rec-auto.rs \
|
||||
rec-tup.rs \
|
||||
return-nil.rs \
|
||||
simple-obj.rs \
|
||||
stateful-obj.rs \
|
||||
str-idx.rs \
|
||||
type-in-nested-module.rs \
|
||||
type-param.rs \
|
||||
tup.rs \
|
||||
u32-decr.rs \
|
||||
u8-incr.rs \
|
||||
u8-incr-decr.rs \
|
||||
uint.rs \
|
||||
unit.rs \
|
||||
use.rs \
|
||||
tag.rs \
|
||||
vec.rs \
|
||||
vec-drop.rs \
|
||||
vec-in-tup.rs \
|
||||
vec-late-init.rs \
|
||||
while-and-do-while.rs \
|
||||
while-flow-graph.rs \
|
||||
writealias.rs \
|
||||
TEST_XFAILS_RUSTC := $(addprefix test/run-pass/, \
|
||||
acyclic-unwind.rs \
|
||||
alt-pattern-drop.rs \
|
||||
alt-type-simple.rs \
|
||||
append-units.rs \
|
||||
basic-1.rs \
|
||||
basic-2.rs \
|
||||
basic.rs \
|
||||
bind-obj-ctor.rs \
|
||||
child-outlives-parent.rs \
|
||||
clone-with-exterior.rs \
|
||||
comm.rs \
|
||||
constrained-type.rs \
|
||||
destructor-ordering.rs \
|
||||
drop-parametric-closure-with-bound-box.rs \
|
||||
export-non-interference.rs \
|
||||
foreach-nested-2.rs \
|
||||
foreach-nested.rs \
|
||||
foreach-put-structured.rs \
|
||||
foreach-simple-outer-slot.rs \
|
||||
generic-fn-twice.rs \
|
||||
generic-iter-frame.rs \
|
||||
generic-recursive-tag.rs \
|
||||
generic-tag-alt.rs \
|
||||
generic-tag-values.rs \
|
||||
iter-range.rs \
|
||||
iter-ret.rs \
|
||||
lazychan.rs \
|
||||
lib-bitv.rs \
|
||||
lib-deque.rs \
|
||||
lib-int.rs \
|
||||
lib-io.rs \
|
||||
lib-map.rs \
|
||||
lib-rand.rs \
|
||||
lib-sha1.rs \
|
||||
lib-sort.rs \
|
||||
lib-str.rs \
|
||||
lib-task.rs \
|
||||
lib-uint.rs \
|
||||
lib-vec-str-conversions.rs \
|
||||
lib-vec.rs \
|
||||
many.rs \
|
||||
mlist-cycle.rs \
|
||||
mlist.rs \
|
||||
mutable-alias-vec.rs \
|
||||
obj-as.rs \
|
||||
obj-dtor.rs \
|
||||
obj-return-polytypes.rs \
|
||||
pred.rs \
|
||||
preempt.rs \
|
||||
rt-circular-buffer.rs \
|
||||
size-and-align.rs \
|
||||
spawn-fn.rs \
|
||||
spawn-module-qualified.rs \
|
||||
spawn.rs \
|
||||
str-append.rs \
|
||||
syntax-extension-fmt.rs \
|
||||
syntax-extension-shell.rs \
|
||||
task-comm-0.rs \
|
||||
task-comm-1.rs \
|
||||
task-comm-10.rs \
|
||||
task-comm-11.rs \
|
||||
task-comm-12.rs \
|
||||
task-comm-13-thread.rs \
|
||||
task-comm-13.rs \
|
||||
task-comm-15.rs \
|
||||
task-comm-2.rs \
|
||||
task-comm-3.rs \
|
||||
task-comm-4.rs \
|
||||
task-comm-5.rs \
|
||||
task-comm-6.rs \
|
||||
task-comm-7.rs \
|
||||
task-comm-8.rs \
|
||||
task-comm-9.rs \
|
||||
task-comm.rs \
|
||||
task-killjoin.rs \
|
||||
task-life-0.rs \
|
||||
threads.rs \
|
||||
type-sizes.rs \
|
||||
typestate-cfg-nesting.rs \
|
||||
use-import-export.rs \
|
||||
user.rs \
|
||||
utf8.rs \
|
||||
vec-alloc-append.rs \
|
||||
vec-append.rs \
|
||||
vec-slice.rs \
|
||||
while-prelude-drop.rs \
|
||||
while-with-break.rs \
|
||||
yield.rs \
|
||||
yield2.rs \
|
||||
multi.rc \
|
||||
native-mod.rc \
|
||||
native.rc \
|
||||
) \
|
||||
$(filter-out \
|
||||
$(addprefix test/compile-fail/, \
|
||||
alt-tag-nullary.rs \
|
||||
alt-tag-unary.rs \
|
||||
@@ -517,6 +534,7 @@ TEST_XFAILS_RUSTC := $(filter-out \
|
||||
bad-expr-path.rs \
|
||||
bad-expr-path2.rs \
|
||||
bogus-tag.rs \
|
||||
fru-extra-field.rs \
|
||||
import.rs \
|
||||
import2.rs \
|
||||
import3.rs \
|
||||
@@ -526,11 +544,20 @@ TEST_XFAILS_RUSTC := $(filter-out \
|
||||
multiline-comment-line-tracking.rs \
|
||||
output-type-mismatch.rs \
|
||||
rec-missing-fields.rs \
|
||||
reserved-dec.rs \
|
||||
reserved-f128.rs \
|
||||
reserved-f16.rs \
|
||||
reserved-f80.rs \
|
||||
reserved-m128.rs \
|
||||
reserved-m32.rs \
|
||||
reserved-m64.rs \
|
||||
tail-non-call.rs \
|
||||
tail-typeck.rs \
|
||||
type-shadow.rs \
|
||||
while-type-error.rs \
|
||||
wrong-ret-type.rs \
|
||||
), \
|
||||
$(wildcard test/*/*.rs test/*/*.rc))
|
||||
$(wildcard test/*fail/*.rs test/*fail/*.rc))
|
||||
|
||||
|
||||
ifdef MINGW_CROSS
|
||||
|
||||
@@ -8,7 +8,6 @@ boot/fe - Front end (lexer, parser, AST)
|
||||
boot/me - Middle end (resolve, check, layout, trans)
|
||||
boot/be - Back end (IL, RA, insns, asm, objfiles)
|
||||
boot/util - Ubiquitous helpers
|
||||
boot/llvm - LLVM-based alternative back end
|
||||
boot/driver - Compiler driver
|
||||
|
||||
comp/ The self-hosted compiler ("rustc": incomplete)
|
||||
|
||||
@@ -110,12 +110,22 @@ let indirect_args_elt_closure = 0;;
|
||||
(* Current worst case is by vec grow glue *)
|
||||
let worst_case_glue_call_args = 8;;
|
||||
|
||||
(*
|
||||
* ABI tags used to inform the runtime which sort of frame to set up for new
|
||||
* spawned functions. FIXME: There is almost certainly a better abstraction to
|
||||
* use.
|
||||
*)
|
||||
let abi_x86_rustboot_cdecl = 1;;
|
||||
let abi_x86_rustc_fastcall = 2;;
|
||||
|
||||
type abi =
|
||||
{
|
||||
abi_word_sz: int64;
|
||||
abi_word_bits: Il.bits;
|
||||
abi_word_ty: Common.ty_mach;
|
||||
|
||||
abi_tag: int;
|
||||
|
||||
abi_has_pcrel_data: bool;
|
||||
abi_has_pcrel_code: bool;
|
||||
|
||||
|
||||
@@ -44,7 +44,7 @@ type ei_data =
|
||||
;;
|
||||
|
||||
|
||||
let elf_identification ei_class ei_data =
|
||||
let elf_identification sess ei_class ei_data =
|
||||
SEQ
|
||||
[|
|
||||
STRING "\x7fELF";
|
||||
@@ -58,9 +58,16 @@ let elf_identification ei_class ei_data =
|
||||
ELFDATANONE -> 0
|
||||
| ELFDATA2LSB -> 1
|
||||
| ELFDATA2MSB -> 2);
|
||||
|
||||
1; (* EI_VERSION = EV_CURRENT *)
|
||||
0; (* EI_PAD #7 *)
|
||||
0; (* EI_PAD #8 *)
|
||||
|
||||
(* EI_OSABI *)
|
||||
(match sess.Session.sess_targ with
|
||||
FreeBSD_x86_elf -> 9
|
||||
| _ -> 0);
|
||||
|
||||
0; (* EI_ABIVERSION *)
|
||||
|
||||
0; (* EI_PAD #9 *)
|
||||
0; (* EI_PAD #A *)
|
||||
0; (* EI_PAD #B *)
|
||||
@@ -117,7 +124,7 @@ let elf32_header
|
||||
in
|
||||
DEF
|
||||
(elf_header_fixup,
|
||||
SEQ [| elf_identification ELFCLASS32 ei_data;
|
||||
SEQ [| elf_identification sess ELFCLASS32 ei_data;
|
||||
WORD (TY_u16, (IMM (match e_type with
|
||||
ET_NONE -> 0L
|
||||
| ET_REL -> 1L
|
||||
@@ -480,6 +487,7 @@ let elf32_linux_x86_file
|
||||
~(entry_name:string)
|
||||
~(text_frags:(string option, frag) Hashtbl.t)
|
||||
~(data_frags:(string option, frag) Hashtbl.t)
|
||||
~(bss_frags:(string option, frag) Hashtbl.t)
|
||||
~(rodata_frags:(string option, frag) Hashtbl.t)
|
||||
~(required_fixups:(string, fixup) Hashtbl.t)
|
||||
~(dwarf:Dwarf.debug_records)
|
||||
@@ -644,7 +652,7 @@ let elf32_linux_x86_file
|
||||
(* let gotpltndx = 8L in *) (* Section index of .got.plt *)
|
||||
(* let relapltndx = 9L in *) (* Section index of .rela.plt *)
|
||||
let datandx = 10L in (* Section index of .data *)
|
||||
(* let bssndx = 11L in *) (* Section index of .bss *)
|
||||
let bssndx = 11L in (* Section index of .bss *)
|
||||
(* let dynamicndx = 12L in *) (* Section index of .dynamic *)
|
||||
let shstrtabndx = 13L in (* Section index of .shstrtab *)
|
||||
|
||||
@@ -991,6 +999,22 @@ let elf32_linux_x86_file
|
||||
(strtab_entry, symtab_entry)
|
||||
in
|
||||
|
||||
let bss_sym name st_bind fixup =
|
||||
let name_fixup = new_fixup ("bss symbol name fixup: '" ^ name ^ "'") in
|
||||
let strtab_entry = DEF (name_fixup, ZSTRING name) in
|
||||
let symtab_entry =
|
||||
symbol
|
||||
~string_table_fixup: dynstr_section_fixup
|
||||
~name_string_fixup: name_fixup
|
||||
~sym_target_fixup: (Some fixup)
|
||||
~st_bind
|
||||
~st_type: STT_OBJECT
|
||||
~st_shndx: bssndx
|
||||
in
|
||||
incr n_syms;
|
||||
(strtab_entry, symtab_entry)
|
||||
in
|
||||
|
||||
let rodata_sym name st_bind fixup =
|
||||
let name_fixup = new_fixup ("rodata symbol name fixup: '" ^ name ^ "'") in
|
||||
let strtab_entry = DEF (name_fixup, ZSTRING name) in
|
||||
@@ -1212,6 +1236,12 @@ let elf32_linux_x86_file
|
||||
Hashtbl.fold (frags_of_symbol data_sym STB_GLOBAL) data_frags ([],[],[])
|
||||
in
|
||||
|
||||
let (bss_strtab_frags,
|
||||
bss_symtab_frags,
|
||||
bss_body_frags) =
|
||||
Hashtbl.fold (frags_of_symbol bss_sym STB_GLOBAL) bss_frags ([],[],[])
|
||||
in
|
||||
|
||||
let (_,
|
||||
require_strtab_frags,
|
||||
require_symtab_frags,
|
||||
@@ -1277,7 +1307,8 @@ let elf32_linux_x86_file
|
||||
global_text_symtab_frags @
|
||||
local_text_symtab_frags @
|
||||
rodata_symtab_frags @
|
||||
data_symtab_frags))
|
||||
data_symtab_frags @
|
||||
bss_symtab_frags))
|
||||
in
|
||||
|
||||
let dynstr_frags = (null_strtab_frag ::
|
||||
@@ -1286,11 +1317,16 @@ let elf32_linux_x86_file
|
||||
local_text_strtab_frags @
|
||||
rodata_strtab_frags @
|
||||
data_strtab_frags @
|
||||
bss_strtab_frags @
|
||||
(Array.to_list dynamic_needed_strtab_frags)))
|
||||
in
|
||||
|
||||
let interp_section =
|
||||
DEF (interp_section_fixup, ZSTRING "/lib/ld-linux.so.2")
|
||||
|
||||
DEF (interp_section_fixup, ZSTRING
|
||||
(if sess.Session.sess_targ = FreeBSD_x86_elf
|
||||
then "/libexec/ld-elf.so.1"
|
||||
else "/lib/ld-linux.so.2"))
|
||||
in
|
||||
|
||||
let text_section =
|
||||
@@ -1307,7 +1343,7 @@ let elf32_linux_x86_file
|
||||
in
|
||||
let bss_section =
|
||||
DEF (bss_section_fixup,
|
||||
SEQ [| |])
|
||||
SEQ (Array.of_list bss_body_frags))
|
||||
in
|
||||
let dynsym_section =
|
||||
DEF (dynsym_section_fixup,
|
||||
@@ -1486,6 +1522,7 @@ let emit_file
|
||||
let text_frags = Hashtbl.create 4 in
|
||||
let rodata_frags = Hashtbl.create 4 in
|
||||
let data_frags = Hashtbl.create 4 in
|
||||
let bss_frags = Hashtbl.create 4 in
|
||||
let required_fixups = Hashtbl.create 4 in
|
||||
|
||||
(*
|
||||
@@ -1584,7 +1621,9 @@ let emit_file
|
||||
|
||||
let needed_libs =
|
||||
[|
|
||||
"libc.so.6";
|
||||
if sess.Session.sess_targ = FreeBSD_x86_elf
|
||||
then "libc.so.7"
|
||||
else "libc.so.6";
|
||||
"librustrt.so"
|
||||
|]
|
||||
in
|
||||
@@ -1604,6 +1643,27 @@ let emit_file
|
||||
htab_put text_frags None code;
|
||||
htab_put rodata_frags None data;
|
||||
|
||||
if sess.Session.sess_targ = FreeBSD_x86_elf
|
||||
then
|
||||
(*
|
||||
* FreeBSD wants some extra symbols in .bss so its libc can fill
|
||||
* them in, I think.
|
||||
*)
|
||||
List.iter
|
||||
(fun x -> htab_put bss_frags (Some x) (WORD (TY_u32, (IMM 0L))))
|
||||
[
|
||||
"environ";
|
||||
"optind";
|
||||
"optarg";
|
||||
"_CurrentRuneLocale";
|
||||
"__stack_chk_guard";
|
||||
"__mb_sb_limit";
|
||||
"__isthreaded";
|
||||
"__stdinp";
|
||||
"__stderrp";
|
||||
"__stdoutp";
|
||||
];
|
||||
|
||||
Hashtbl.iter
|
||||
begin
|
||||
fun _ tab ->
|
||||
@@ -1616,6 +1676,7 @@ let emit_file
|
||||
end
|
||||
sem.Semant.ctxt_native_required
|
||||
in
|
||||
|
||||
let all_frags =
|
||||
elf32_linux_x86_file
|
||||
~sess
|
||||
@@ -1623,6 +1684,7 @@ let emit_file
|
||||
~entry_name: "_start"
|
||||
~text_frags
|
||||
~data_frags
|
||||
~bss_frags
|
||||
~dwarf
|
||||
~sem
|
||||
~rodata_frags
|
||||
|
||||
@@ -1851,6 +1851,8 @@ let (abi:Abi.abi) =
|
||||
Abi.abi_word_bits = word_bits;
|
||||
Abi.abi_word_ty = word_ty;
|
||||
|
||||
Abi.abi_tag = Abi.abi_x86_rustboot_cdecl;
|
||||
|
||||
Abi.abi_has_pcrel_data = false;
|
||||
Abi.abi_has_pcrel_code = true;
|
||||
|
||||
|
||||
@@ -249,6 +249,7 @@ let get_ar
|
||||
Win32_x86_pe -> Pe.sniff
|
||||
| MacOS_x86_macho -> Macho.sniff
|
||||
| Linux_x86_elf -> Elf.sniff
|
||||
| FreeBSD_x86_elf -> Elf.sniff
|
||||
in
|
||||
sniff sess filename
|
||||
end
|
||||
@@ -270,6 +271,7 @@ let get_sects
|
||||
Win32_x86_pe -> Pe.get_sections
|
||||
| MacOS_x86_macho -> Macho.get_sections
|
||||
| Linux_x86_elf -> Elf.get_sections
|
||||
| FreeBSD_x86_elf -> Elf.get_sections
|
||||
in
|
||||
Some (ar, (get_sections sess ar))
|
||||
end
|
||||
@@ -350,6 +352,7 @@ let get_mod
|
||||
Win32_x86_pe -> ".dll"
|
||||
| MacOS_x86_macho -> ".dylib"
|
||||
| Linux_x86_elf -> ".so"
|
||||
| FreeBSD_x86_elf -> ".so"
|
||||
in
|
||||
let rec meta_matches i f_meta =
|
||||
if i >= (Array.length meta)
|
||||
@@ -447,6 +450,7 @@ let infer_lib_name
|
||||
Win32_x86_pe -> ident ^ ".dll"
|
||||
| MacOS_x86_macho -> "lib" ^ ident ^ ".dylib"
|
||||
| Linux_x86_elf -> "lib" ^ ident ^ ".so"
|
||||
| FreeBSD_x86_elf -> "lib" ^ ident ^ ".so"
|
||||
;;
|
||||
|
||||
|
||||
|
||||
@@ -8,12 +8,21 @@ let _ =
|
||||
|
||||
let (targ:Common.target) =
|
||||
match Sys.os_type with
|
||||
"Unix" when Unix.system "test `uname -s` = 'Darwin'" = Unix.WEXITED 0 ->
|
||||
MacOS_x86_macho
|
||||
| "Unix" -> Linux_x86_elf
|
||||
| "Win32" -> Win32_x86_pe
|
||||
|
||||
| "Win32"
|
||||
| "Cygwin" -> Win32_x86_pe
|
||||
| _ -> Linux_x86_elf
|
||||
|
||||
| "Unix"
|
||||
when Unix.system "test `uname -s` = 'Linux'" = Unix.WEXITED 0 ->
|
||||
Linux_x86_elf
|
||||
| "Unix"
|
||||
when Unix.system "test `uname -s` = 'Darwin'" = Unix.WEXITED 0 ->
|
||||
MacOS_x86_macho
|
||||
| "Unix"
|
||||
when Unix.system "test `uname -s` = 'FreeBSD'" = Unix.WEXITED 0 ->
|
||||
FreeBSD_x86_elf
|
||||
| _ ->
|
||||
Linux_x86_elf
|
||||
;;
|
||||
|
||||
let (abi:Abi.abi) = X86.abi;;
|
||||
@@ -96,6 +105,7 @@ let default_output_filename (sess:Session.sess) : filename option =
|
||||
else
|
||||
base ^ (match sess.Session.sess_targ with
|
||||
Linux_x86_elf -> ""
|
||||
| FreeBSD_x86_elf -> ""
|
||||
| MacOS_x86_macho -> ""
|
||||
| Win32_x86_pe -> ".exe")
|
||||
in
|
||||
@@ -144,16 +154,21 @@ let flag f opt desc =
|
||||
|
||||
let argspecs =
|
||||
[
|
||||
("-t", Arg.Symbol (["linux-x86-elf"; "win32-x86-pe"; "macos-x86-macho"],
|
||||
("-t", Arg.Symbol (["linux-x86-elf";
|
||||
"win32-x86-pe";
|
||||
"macos-x86-macho";
|
||||
"freebsd-x86-elf"],
|
||||
fun s -> (sess.Session.sess_targ <-
|
||||
(match s with
|
||||
"win32-x86-pe" -> Win32_x86_pe
|
||||
| "macos-x86-macho" -> MacOS_x86_macho
|
||||
| "freebsd-x86-elf" -> FreeBSD_x86_elf
|
||||
| _ -> Linux_x86_elf))),
|
||||
(" target (default: " ^ (match sess.Session.sess_targ with
|
||||
Win32_x86_pe -> "win32-x86-pe"
|
||||
| Linux_x86_elf -> "linux-x86-elf"
|
||||
| MacOS_x86_macho -> "macos-x86-macho"
|
||||
| FreeBSD_x86_elf -> "freebsd-x86-elf"
|
||||
) ^ ")"));
|
||||
("-o", Arg.String (fun s -> sess.Session.sess_out <- Some s),
|
||||
"file to output (default: "
|
||||
@@ -320,6 +335,7 @@ let parse_input_crate
|
||||
let depfile =
|
||||
match sess.Session.sess_targ with
|
||||
Linux_x86_elf
|
||||
| FreeBSD_x86_elf
|
||||
| MacOS_x86_macho -> outfile ^ ".d"
|
||||
| Win32_x86_pe -> (Filename.chop_extension outfile) ^ ".d"
|
||||
in
|
||||
@@ -473,6 +489,7 @@ let main_pipeline _ =
|
||||
Win32_x86_pe -> Pe.emit_file
|
||||
| MacOS_x86_macho -> Macho.emit_file
|
||||
| Linux_x86_elf -> Elf.emit_file
|
||||
| FreeBSD_x86_elf -> Elf.emit_file
|
||||
in
|
||||
Session.time_inner "emit" sess
|
||||
(fun _ -> emitter sess crate code data sem_cx dwarf);
|
||||
|
||||
@@ -628,6 +628,7 @@ let parse_crate_file
|
||||
let (os, arch, libc) =
|
||||
match sess.Session.sess_targ with
|
||||
Linux_x86_elf -> ("linux", "x86", "libc.so.6")
|
||||
| FreeBSD_x86_elf -> ("freebsd", "x86", "libc.so.7")
|
||||
| Win32_x86_pe -> ("win32", "x86", "msvcrt.dll")
|
||||
| MacOS_x86_macho -> ("macos", "x86", "libc.dylib")
|
||||
in
|
||||
|
||||
@@ -2727,6 +2727,7 @@ let trans_visitor
|
||||
[|
|
||||
Il.Cell new_task;
|
||||
exit_task_glue_fptr;
|
||||
(imm (Int64.of_int abi.Abi.abi_tag));
|
||||
fptr_operand;
|
||||
callsz
|
||||
|];
|
||||
@@ -2739,6 +2740,7 @@ let trans_visitor
|
||||
[|
|
||||
Il.Cell new_task;
|
||||
exit_task_glue_fptr;
|
||||
(imm (Int64.of_int abi.Abi.abi_tag));
|
||||
fptr_operand;
|
||||
callsz
|
||||
|];
|
||||
@@ -6183,6 +6185,8 @@ let trans_visitor
|
||||
tab_sz cx.ctxt_required_rust_sym_num;
|
||||
tab_sz cx.ctxt_required_c_sym_num;
|
||||
tab_sz cx.ctxt_required_lib_num;
|
||||
|
||||
Asm.WORD (word_ty_mach, Asm.IMM (Int64.of_int abi.Abi.abi_tag));
|
||||
|]))
|
||||
in
|
||||
|
||||
|
||||
@@ -24,7 +24,6 @@ type typestate_tables =
|
||||
ts_prestates: (node_id,Bits.t) Hashtbl.t;
|
||||
ts_poststates: (node_id,Bits.t) Hashtbl.t;
|
||||
ts_graph: node_graph;
|
||||
ts_siblings: sibling_map;
|
||||
ts_stmts: Ast.stmt Stack.t;
|
||||
ts_maxid: int ref;
|
||||
}
|
||||
@@ -38,7 +37,6 @@ let new_tables _ =
|
||||
ts_poststates = Hashtbl.create 0;
|
||||
ts_prestates = Hashtbl.create 0;
|
||||
ts_graph = Hashtbl.create 0;
|
||||
ts_siblings = Hashtbl.create 0;
|
||||
ts_stmts = Stack.create ();
|
||||
ts_maxid = ref 0 }
|
||||
;;
|
||||
@@ -790,279 +788,148 @@ let show_node cx graph s i =
|
||||
s (int_of_node i) (lset_fmt (Hashtbl.find graph i)))
|
||||
;;
|
||||
|
||||
let graph_sequence_building_visitor
|
||||
(cx:ctxt)
|
||||
(tables_stack:typestate_tables Stack.t)
|
||||
(inner:Walk.visitor)
|
||||
: Walk.visitor =
|
||||
|
||||
let tables _ = Stack.top tables_stack in
|
||||
|
||||
(* Flow each stmt to its sequence-successor. *)
|
||||
let visit_stmts stmts =
|
||||
let ts = tables () in
|
||||
let graph = ts.ts_graph in
|
||||
let sibs = ts.ts_siblings in
|
||||
let len = Array.length stmts in
|
||||
for i = 0 to len - 2
|
||||
do
|
||||
let stmt = stmts.(i) in
|
||||
let next = stmts.(i+1) in
|
||||
log cx "sequential stmt edge %d -> %d"
|
||||
(int_of_node stmt.id) (int_of_node next.id);
|
||||
htab_put graph stmt.id [next.id];
|
||||
htab_put sibs stmt.id next.id;
|
||||
done;
|
||||
(* Flow last node to nowhere. *)
|
||||
if len > 0
|
||||
then htab_put graph stmts.(len-1).id []
|
||||
in
|
||||
|
||||
let visit_stmt_pre s =
|
||||
(* Sequence the prelude nodes on special stmts. *)
|
||||
begin
|
||||
match s.node with
|
||||
Ast.STMT_while sw ->
|
||||
let (stmts, _) = sw.Ast.while_lval in
|
||||
visit_stmts stmts
|
||||
| _ -> ()
|
||||
end;
|
||||
inner.Walk.visit_stmt_pre s
|
||||
in
|
||||
|
||||
let visit_block_pre b =
|
||||
visit_stmts b.node;
|
||||
inner.Walk.visit_block_pre b
|
||||
in
|
||||
|
||||
{ inner with
|
||||
Walk.visit_stmt_pre = visit_stmt_pre;
|
||||
Walk.visit_block_pre = visit_block_pre }
|
||||
;;
|
||||
|
||||
let add_flow_edges (graph:node_graph) (n:node_id) (dsts:node_id list) : unit =
|
||||
if Hashtbl.mem graph n
|
||||
then
|
||||
let existing = Hashtbl.find graph n in
|
||||
Hashtbl.replace graph n (lset_union existing dsts)
|
||||
else
|
||||
Hashtbl.add graph n dsts
|
||||
;;
|
||||
|
||||
let remove_flow_edges
|
||||
let rec build_flow_graph_for_stmt
|
||||
(graph:node_graph)
|
||||
(n:node_id)
|
||||
(dsts:node_id list)
|
||||
: unit =
|
||||
let existing = Hashtbl.find graph n in
|
||||
Hashtbl.replace graph n (lset_diff existing dsts)
|
||||
(predecessors:node_id list)
|
||||
(s:Ast.stmt)
|
||||
: node_id list =
|
||||
|
||||
let connect ps qs =
|
||||
List.iter
|
||||
(fun pred -> add_flow_edges graph pred qs)
|
||||
ps
|
||||
in
|
||||
|
||||
let seq ps (ss:Ast.stmt array) =
|
||||
build_flow_graph_for_stmts graph ps ss
|
||||
in
|
||||
|
||||
let blk ps b =
|
||||
connect ps [b.id];
|
||||
seq [b.id] b.node
|
||||
in
|
||||
|
||||
let first ss =
|
||||
if Array.length ss = 0
|
||||
then []
|
||||
else [ss.(0).id]
|
||||
in
|
||||
|
||||
connect [s.id] [];
|
||||
let outs =
|
||||
match s.node with
|
||||
|
||||
| Ast.STMT_while sw ->
|
||||
let (pre_loop_stmts, _) = sw.Ast.while_lval in
|
||||
let body = sw.Ast.while_body in
|
||||
let preloop_end = seq [s.id] pre_loop_stmts in
|
||||
connect predecessors [s.id];
|
||||
connect (blk preloop_end body) (first pre_loop_stmts);
|
||||
preloop_end
|
||||
|
||||
| Ast.STMT_for sf ->
|
||||
let body_end = blk [s.id] sf.Ast.for_body in
|
||||
connect predecessors [s.id];
|
||||
connect body_end (first sf.Ast.for_body.node);
|
||||
body_end
|
||||
|
||||
| Ast.STMT_for_each sfe ->
|
||||
let head_end = blk [s.id] sfe.Ast.for_each_head in
|
||||
let body_end = blk head_end sfe.Ast.for_each_body in
|
||||
connect predecessors [s.id];
|
||||
connect body_end (first sfe.Ast.for_each_head.node);
|
||||
body_end
|
||||
|
||||
| Ast.STMT_if sif ->
|
||||
connect predecessors [s.id];
|
||||
(blk [s.id] sif.Ast.if_then) @
|
||||
(match sif.Ast.if_else with
|
||||
None -> [s.id]
|
||||
| Some els -> blk [s.id] els)
|
||||
|
||||
| Ast.STMT_alt_tag sat ->
|
||||
connect predecessors [s.id];
|
||||
Array.fold_left
|
||||
(fun ends {node=(_, b); id=_} -> (blk [s.id] b) @ ends)
|
||||
[] sat.Ast.alt_tag_arms
|
||||
|
||||
| Ast.STMT_block b ->
|
||||
blk predecessors b
|
||||
|
||||
| Ast.STMT_fail
|
||||
| Ast.STMT_ret _ ->
|
||||
connect predecessors [s.id];
|
||||
[]
|
||||
|
||||
| _ ->
|
||||
connect predecessors [s.id];
|
||||
[s.id]
|
||||
in
|
||||
connect outs [];
|
||||
outs
|
||||
|
||||
and build_flow_graph_for_stmts
|
||||
(graph:node_graph)
|
||||
(predecessors:node_id list)
|
||||
(ss:Ast.stmt array)
|
||||
: node_id list =
|
||||
Array.fold_left (build_flow_graph_for_stmt graph) predecessors ss
|
||||
;;
|
||||
|
||||
|
||||
let last_id (nodes:('a identified) array) : node_id =
|
||||
let len = Array.length nodes in
|
||||
nodes.(len-1).id
|
||||
;;
|
||||
|
||||
let last_id_or_block_id (block:Ast.block) : node_id =
|
||||
let len = Array.length block.node in
|
||||
if len = 0
|
||||
then block.id
|
||||
else last_id block.node
|
||||
;;
|
||||
|
||||
let graph_general_block_structure_building_visitor
|
||||
let graph_building_visitor
|
||||
(cx:ctxt)
|
||||
(tables_stack:typestate_tables Stack.t)
|
||||
(inner:Walk.visitor)
|
||||
: Walk.visitor =
|
||||
|
||||
let tables _ = Stack.top tables_stack in
|
||||
|
||||
let visit_stmt_pre s =
|
||||
let ts = tables () in
|
||||
let stmts = ts.ts_stmts in
|
||||
Stack.push s stmts;
|
||||
inner.Walk.visit_stmt_pre s
|
||||
let graph _ = (tables()).ts_graph in
|
||||
let blk b =
|
||||
add_flow_edges (graph()) b.id [];
|
||||
ignore (build_flow_graph_for_stmts (graph()) [b.id] b.node)
|
||||
in
|
||||
|
||||
let visit_stmt_post s =
|
||||
let ts = tables () in
|
||||
let stmts = ts.ts_stmts in
|
||||
inner.Walk.visit_stmt_post s;
|
||||
ignore (Stack.pop stmts)
|
||||
let visit_mod_item_pre n p i =
|
||||
begin
|
||||
match i.node.Ast.decl_item with
|
||||
Ast.MOD_ITEM_fn fn -> blk fn.Ast.fn_body
|
||||
| _ -> ()
|
||||
end;
|
||||
inner.Walk.visit_mod_item_pre n p i
|
||||
in
|
||||
|
||||
let show_node =
|
||||
fun n id -> show_node cx (tables()).ts_graph n id
|
||||
let visit_obj_fn_pre obj ident fn =
|
||||
blk fn.node.Ast.fn_body;
|
||||
inner.Walk.visit_obj_fn_pre obj ident fn
|
||||
in
|
||||
|
||||
let visit_obj_drop_pre obj b =
|
||||
blk b;
|
||||
inner.Walk.visit_obj_drop_pre obj b
|
||||
in
|
||||
|
||||
let visit_block_pre b =
|
||||
begin
|
||||
let ts = tables () in
|
||||
let graph = ts.ts_graph in
|
||||
let sibs = ts.ts_siblings in
|
||||
let stmts = ts.ts_stmts in
|
||||
let len = Array.length b.node in
|
||||
let _ = htab_put graph b.id
|
||||
(if len > 0 then [b.node.(0).id] else [])
|
||||
in
|
||||
|
||||
(*
|
||||
* If block has len,
|
||||
* then flow block to block.node.(0) and block.node.(len-1) to dsts
|
||||
* else flow block to dsts
|
||||
*
|
||||
* so AST:
|
||||
*
|
||||
* block#n{ stmt#0 ... stmt#k };
|
||||
* stmt#j;
|
||||
*
|
||||
* turns into graph:
|
||||
*
|
||||
* block#n -> stmt#0 -> ... -> stmt#k -> stmt#j
|
||||
*
|
||||
*)
|
||||
if Stack.is_empty stmts
|
||||
then ()
|
||||
else
|
||||
let s = Stack.top stmts in
|
||||
add_flow_edges graph s.id [b.id];
|
||||
match htab_search sibs s.id with
|
||||
None -> ()
|
||||
| Some sib_id ->
|
||||
if len > 0
|
||||
then
|
||||
add_flow_edges graph (last_id b.node) [sib_id]
|
||||
else
|
||||
add_flow_edges graph b.id [sib_id]
|
||||
end;
|
||||
show_node "block" b.id;
|
||||
if Hashtbl.mem cx.ctxt_block_is_loop_body b.id
|
||||
then blk b;
|
||||
inner.Walk.visit_block_pre b
|
||||
in
|
||||
|
||||
{ inner with
|
||||
Walk.visit_stmt_pre = visit_stmt_pre;
|
||||
Walk.visit_stmt_post = visit_stmt_post;
|
||||
Walk.visit_mod_item_pre = visit_mod_item_pre;
|
||||
Walk.visit_obj_fn_pre = visit_obj_fn_pre;
|
||||
Walk.visit_obj_drop_pre = visit_obj_drop_pre;
|
||||
Walk.visit_block_pre = visit_block_pre }
|
||||
;;
|
||||
|
||||
|
||||
let graph_special_block_structure_building_visitor
|
||||
(cx:ctxt)
|
||||
(tables_stack:typestate_tables Stack.t)
|
||||
(inner:Walk.visitor)
|
||||
: Walk.visitor =
|
||||
|
||||
let tables _ = Stack.top tables_stack in
|
||||
|
||||
let visit_stmt_pre s =
|
||||
begin
|
||||
match s.node with
|
||||
|
||||
Ast.STMT_if sif ->
|
||||
let ts = tables () in
|
||||
let graph = ts.ts_graph in
|
||||
let cond_id = s.id in
|
||||
let succ = Hashtbl.find graph cond_id in
|
||||
let then_id = sif.Ast.if_then.id in
|
||||
let then_end_id = last_id_or_block_id sif.Ast.if_then in
|
||||
let show_node = show_node cx graph in
|
||||
let succ = List.filter (fun x -> not (x = then_id)) succ in
|
||||
show_node "initial cond" cond_id;
|
||||
show_node "initial then" then_id;
|
||||
show_node "initial then_end" then_end_id;
|
||||
begin
|
||||
match sif.Ast.if_else with
|
||||
None ->
|
||||
Hashtbl.replace graph cond_id (then_id :: succ);
|
||||
(* Kill residual messed-up block wiring.*)
|
||||
remove_flow_edges graph then_end_id [then_id];
|
||||
show_node "cond" cond_id;
|
||||
show_node "then" then_id;
|
||||
show_node "then_end" then_end_id;
|
||||
|
||||
| Some e ->
|
||||
let else_id = e.id in
|
||||
let succ =
|
||||
List.filter (fun x -> not (x = else_id)) succ
|
||||
in
|
||||
let else_end_id = last_id_or_block_id e in
|
||||
show_node "initial else" else_id;
|
||||
show_node "initial else_end" else_end_id;
|
||||
Hashtbl.replace graph cond_id [then_id; else_id];
|
||||
Hashtbl.replace graph then_end_id succ;
|
||||
Hashtbl.replace graph else_end_id succ;
|
||||
|
||||
(* Kill residual messed-up block wiring.*)
|
||||
remove_flow_edges graph then_end_id [then_id];
|
||||
remove_flow_edges graph else_id [then_id];
|
||||
remove_flow_edges graph else_end_id [then_id];
|
||||
show_node "cond" cond_id;
|
||||
show_node "then" then_id;
|
||||
show_node "then_end" then_end_id;
|
||||
show_node "else" else_id;
|
||||
show_node "else_end" else_end_id;
|
||||
end;
|
||||
|
||||
| Ast.STMT_while sw ->
|
||||
(* There are a bunch of rewirings to do on 'while' nodes. *)
|
||||
|
||||
begin
|
||||
let ts = tables () in
|
||||
let graph = ts.ts_graph in
|
||||
let dsts = Hashtbl.find graph s.id in
|
||||
let body = sw.Ast.while_body in
|
||||
let succ_stmts =
|
||||
List.filter (fun x -> not (x = body.id)) dsts
|
||||
in
|
||||
|
||||
let (pre_loop_stmts, _) = sw.Ast.while_lval in
|
||||
let loop_head_id =
|
||||
(* Splice loop prelude into flow graph, save loop-head
|
||||
* node.
|
||||
*)
|
||||
let slen = Array.length pre_loop_stmts in
|
||||
if slen > 0
|
||||
then
|
||||
begin
|
||||
let pre_loop_begin = pre_loop_stmts.(0).id in
|
||||
let pre_loop_end = last_id pre_loop_stmts in
|
||||
remove_flow_edges graph s.id [body.id];
|
||||
add_flow_edges graph s.id [pre_loop_begin];
|
||||
add_flow_edges graph pre_loop_end [body.id];
|
||||
pre_loop_end
|
||||
end
|
||||
else
|
||||
body.id
|
||||
in
|
||||
|
||||
(* Always flow s into the loop prelude; prelude may end
|
||||
* loop.
|
||||
*)
|
||||
remove_flow_edges graph s.id succ_stmts;
|
||||
add_flow_edges graph loop_head_id succ_stmts;
|
||||
|
||||
(* Flow loop-end to loop-head. *)
|
||||
let loop_end = last_id_or_block_id body in
|
||||
add_flow_edges graph loop_end [loop_head_id]
|
||||
end
|
||||
|
||||
| Ast.STMT_alt_tag at ->
|
||||
let ts = tables () in
|
||||
let graph = ts.ts_graph in
|
||||
let dsts = Hashtbl.find graph s.id in
|
||||
let arm_blocks =
|
||||
let arm_block_id { node = (_, block); id = _ } = block.id in
|
||||
Array.to_list (Array.map arm_block_id at.Ast.alt_tag_arms)
|
||||
in
|
||||
let succ_stmts =
|
||||
List.filter (fun x -> not (List.mem x arm_blocks)) dsts
|
||||
in
|
||||
remove_flow_edges graph s.id succ_stmts
|
||||
|
||||
| _ -> ()
|
||||
end;
|
||||
inner.Walk.visit_stmt_post s
|
||||
in
|
||||
{ inner with
|
||||
Walk.visit_stmt_pre = visit_stmt_pre }
|
||||
;;
|
||||
|
||||
let find_roots
|
||||
@@ -1631,13 +1498,7 @@ let process_crate
|
||||
(condition_assigning_visitor cx tables_stack scopes
|
||||
Walk.empty_visitor)));
|
||||
(table_managed
|
||||
(graph_sequence_building_visitor cx tables_stack
|
||||
Walk.empty_visitor));
|
||||
(table_managed
|
||||
(graph_general_block_structure_building_visitor cx tables_stack
|
||||
Walk.empty_visitor));
|
||||
(table_managed
|
||||
(graph_special_block_structure_building_visitor cx tables_stack
|
||||
(graph_building_visitor cx tables_stack
|
||||
Walk.empty_visitor));
|
||||
|]
|
||||
in
|
||||
|
||||
@@ -56,6 +56,7 @@ type target =
|
||||
Linux_x86_elf
|
||||
| Win32_x86_pe
|
||||
| MacOS_x86_macho
|
||||
| FreeBSD_x86_elf
|
||||
;;
|
||||
|
||||
type ty_mach =
|
||||
|
||||
@@ -44,7 +44,8 @@ const int obj_field_vtbl = 0;
|
||||
const int obj_field_box = 1;
|
||||
|
||||
const int obj_body_elt_tydesc = 0;
|
||||
const int obj_body_elt_fields = 1;
|
||||
const int obj_body_elt_typarams = 1;
|
||||
const int obj_body_elt_fields = 2;
|
||||
|
||||
const int fn_field_code = 0;
|
||||
const int fn_field_box = 1;
|
||||
@@ -59,6 +60,9 @@ const int worst_case_glue_call_args = 7;
|
||||
|
||||
const int n_upcall_glues = 7;
|
||||
|
||||
const int abi_x86_rustboot_cdecl = 1;
|
||||
const int abi_x86_rustc_fastcall = 2;
|
||||
|
||||
fn memcpy_glue_name() -> str {
|
||||
ret "rust_memcpy_glue";
|
||||
}
|
||||
@@ -67,6 +71,10 @@ fn bzero_glue_name() -> str {
|
||||
ret "rust_bzero_glue";
|
||||
}
|
||||
|
||||
fn vec_append_glue_name() -> str {
|
||||
ret "rust_vec_append_glue";
|
||||
}
|
||||
|
||||
fn upcall_glue_name(int n) -> str {
|
||||
ret "rust_upcall_" + util.common.istr(n);
|
||||
}
|
||||
|
||||
@@ -41,20 +41,117 @@ fn store_esp_to_runtime_sp() -> vec[str] {
|
||||
ret vec("movl %esp, " + wstr(abi.task_field_runtime_sp) + "(%ecx)");
|
||||
}
|
||||
|
||||
/*
|
||||
* This is a bit of glue-code. It should be emitted once per
|
||||
* compilation unit.
|
||||
*
|
||||
* - save regs on C stack
|
||||
* - align sp on a 16-byte boundary
|
||||
* - save sp to task.runtime_sp (runtime_sp is thus always aligned)
|
||||
* - load saved task sp (switch stack)
|
||||
* - restore saved task regs
|
||||
* - return to saved task pc
|
||||
*
|
||||
* Our incoming stack looks like this:
|
||||
*
|
||||
* *esp+4 = [arg1 ] = task ptr
|
||||
* *esp = [retpc ]
|
||||
*/
|
||||
|
||||
fn rust_activate_glue() -> vec[str] {
|
||||
ret vec("movl 4(%esp), %ecx # ecx = rust_task")
|
||||
+ save_callee_saves()
|
||||
+ store_esp_to_runtime_sp()
|
||||
+ load_esp_from_rust_sp()
|
||||
|
||||
// This 'add' instruction is a bit surprising.
|
||||
// See lengthy comment in boot/be/x86.ml activate_glue.
|
||||
/*
|
||||
* There are two paths we can arrive at this code from:
|
||||
*
|
||||
*
|
||||
* 1. We are activating a task for the first time. When we switch
|
||||
* into the task stack and 'ret' to its first instruction, we'll
|
||||
* start doing whatever the first instruction says. Probably
|
||||
* saving registers and starting to establish a frame. Harmless
|
||||
* stuff, doesn't look at task->rust_sp again except when it
|
||||
* clobbers it during a later upcall.
|
||||
*
|
||||
*
|
||||
* 2. We are resuming a task that was descheduled by the yield glue
|
||||
* below. When we switch into the task stack and 'ret', we'll be
|
||||
* ret'ing to a very particular instruction:
|
||||
*
|
||||
* "esp <- task->rust_sp"
|
||||
*
|
||||
* this is the first instruction we 'ret' to after this glue,
|
||||
* because it is the first instruction following *any* upcall,
|
||||
* and the task we are activating was descheduled mid-upcall.
|
||||
*
|
||||
* Unfortunately for us, we have already restored esp from
|
||||
* task->rust_sp and are about to eat the 5 words off the top of
|
||||
* it.
|
||||
*
|
||||
*
|
||||
* | ... | <-- where esp will be once we restore + ret, below,
|
||||
* | retpc | and where we'd *like* task->rust_sp to wind up.
|
||||
* | ebp |
|
||||
* | edi |
|
||||
* | esi |
|
||||
* | ebx | <-- current task->rust_sp == current esp
|
||||
*
|
||||
*
|
||||
* This is a problem. If we return to "esp <- task->rust_sp" it
|
||||
* will push esp back down by 5 words. This manifests as a rust
|
||||
* stack that grows by 5 words on each yield/reactivate. Not
|
||||
* good.
|
||||
*
|
||||
* So what we do here is just adjust task->rust_sp up 5 words as
|
||||
* well, to mirror the movement in esp we're about to
|
||||
* perform. That way the "esp <- task->rust_sp" we 'ret' to below
|
||||
* will be a no-op. Esp won't move, and the task's stack won't
|
||||
* grow.
|
||||
*/
|
||||
+ vec("addl $20, " + wstr(abi.task_field_rust_sp) + "(%ecx)")
|
||||
|
||||
|
||||
/*
|
||||
* In most cases, the function we're returning to (activating)
|
||||
* will have saved any caller-saves before it yielded via upcalling,
|
||||
* so no work to do here. With one exception: when we're initially
|
||||
* activating, the task needs to be in the fastcall 2nd parameter
|
||||
* expected by the rust main function. That's edx.
|
||||
*/
|
||||
+ vec("mov %ecx, %edx")
|
||||
|
||||
+ restore_callee_saves()
|
||||
+ vec("ret");
|
||||
}
|
||||
|
||||
/* More glue code, this time the 'bottom half' of yielding.
|
||||
*
|
||||
* We arrived here because an upcall decided to deschedule the
|
||||
* running task. So the upcall's return address got patched to the
|
||||
* first instruction of this glue code.
|
||||
*
|
||||
* When the upcall does 'ret' it will come here, and its esp will be
|
||||
* pointing to the last argument pushed on the C stack before making
|
||||
* the upcall: the 0th argument to the upcall, which is always the
|
||||
* task ptr performing the upcall. That's where we take over.
|
||||
*
|
||||
* Our goal is to complete the descheduling
|
||||
*
|
||||
* - Switch over to the task stack temporarily.
|
||||
*
|
||||
* - Save the task's callee-saves onto the task stack.
|
||||
* (the task is now 'descheduled', safe to set aside)
|
||||
*
|
||||
* - Switch *back* to the C stack.
|
||||
*
|
||||
* - Restore the C-stack callee-saves.
|
||||
*
|
||||
* - Return to the caller on the C stack that activated the task.
|
||||
*
|
||||
*/
|
||||
|
||||
fn rust_yield_glue() -> vec[str] {
|
||||
ret vec("movl 0(%esp), %ecx # ecx = rust_task")
|
||||
+ load_esp_from_rust_sp()
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
import front.parser;
|
||||
import front.token;
|
||||
import front.eval;
|
||||
import middle.trans;
|
||||
import middle.resolve;
|
||||
import middle.typeck;
|
||||
@@ -13,6 +14,30 @@ import std.option.none;
|
||||
import std._str;
|
||||
import std._vec;
|
||||
|
||||
fn default_environment(session.session sess,
|
||||
str argv0,
|
||||
str input) -> eval.env {
|
||||
|
||||
auto libc = "libc.so";
|
||||
alt (sess.get_targ_cfg().os) {
|
||||
case (session.os_win32) { libc = "msvcrt.dll"; }
|
||||
case (session.os_macos) { libc = "libc.dylib"; }
|
||||
case (session.os_linux) { libc = "libc.so.6"; }
|
||||
}
|
||||
|
||||
ret
|
||||
vec(
|
||||
// Target bindings.
|
||||
tup("target_os", eval.val_str(std.os.target_os())),
|
||||
tup("target_arch", eval.val_str("x86")),
|
||||
tup("target_libc", eval.val_str(libc)),
|
||||
|
||||
// Build bindings.
|
||||
tup("build_compiler", eval.val_str(argv0)),
|
||||
tup("build_input", eval.val_str(input))
|
||||
);
|
||||
}
|
||||
|
||||
impure fn parse_input(session.session sess,
|
||||
parser.parser p,
|
||||
str input) -> @front.ast.crate {
|
||||
@@ -25,20 +50,30 @@ impure fn parse_input(session.session sess,
|
||||
fail;
|
||||
}
|
||||
|
||||
impure fn compile_input(session.session sess, str input, str output,
|
||||
impure fn compile_input(session.session sess,
|
||||
eval.env env,
|
||||
str input, str output,
|
||||
bool shared) {
|
||||
auto p = parser.new_parser(sess, 0, input);
|
||||
auto p = parser.new_parser(sess, env, 0, input);
|
||||
auto crate = parse_input(sess, p, input);
|
||||
crate = resolve.resolve_crate(sess, crate);
|
||||
crate = typeck.check_crate(sess, crate);
|
||||
trans.trans_crate(sess, crate, output, shared);
|
||||
}
|
||||
|
||||
impure fn pretty_print_input(session.session sess,
|
||||
eval.env env,
|
||||
str input) {
|
||||
auto p = front.parser.new_parser(sess, env, 0, input);
|
||||
auto crate = front.parser.parse_crate_from_source_file(p);
|
||||
pretty.pprust.print_ast(crate.node.module);
|
||||
}
|
||||
|
||||
fn warn_wrong_compiler() {
|
||||
log "This is the rust 'self-hosted' compiler.";
|
||||
log "The one written in rust.";
|
||||
log "It is currently incomplete.";
|
||||
log "You may want rustboot insteaad, the compiler next door.";
|
||||
log "You may want rustboot instead, the compiler next door.";
|
||||
}
|
||||
|
||||
fn usage(session.session sess, str argv0) {
|
||||
@@ -48,6 +83,7 @@ fn usage(session.session sess, str argv0) {
|
||||
log " -o <filename> write output to <filename>";
|
||||
log " -nowarn suppress wrong-compiler warning";
|
||||
log " -shared compile a shared-library crate";
|
||||
log " -pp pretty-print the input instead of compiling";
|
||||
log " -h display this message";
|
||||
log "";
|
||||
log "";
|
||||
@@ -74,6 +110,7 @@ impure fn main(vec[str] args) {
|
||||
let option.t[str] output_file = none[str];
|
||||
let bool do_warn = true;
|
||||
let bool shared = false;
|
||||
let bool pretty = false;
|
||||
|
||||
auto i = 1u;
|
||||
auto len = _vec.len[str](args);
|
||||
@@ -86,9 +123,9 @@ impure fn main(vec[str] args) {
|
||||
do_warn = false;
|
||||
} else if (_str.eq(arg, "-shared")) {
|
||||
shared = true;
|
||||
} else {
|
||||
// FIXME: rust could use an elif construct.
|
||||
if (_str.eq(arg, "-o")) {
|
||||
} else if (_str.eq(arg, "-pp")) {
|
||||
pretty = true;
|
||||
} else if (_str.eq(arg, "-o")) {
|
||||
if (i+1u < len) {
|
||||
output_file = some(args.(i+1u));
|
||||
i += 1u;
|
||||
@@ -96,15 +133,12 @@ impure fn main(vec[str] args) {
|
||||
usage(sess, args.(0));
|
||||
sess.err("-o requires an argument");
|
||||
}
|
||||
} else {
|
||||
if (_str.eq(arg, "-h")) {
|
||||
} else if (_str.eq(arg, "-h")) {
|
||||
usage(sess, args.(0));
|
||||
} else {
|
||||
usage(sess, args.(0));
|
||||
sess.err("unrecognized option: " + arg);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
alt (input_file) {
|
||||
case (some[str](_)) {
|
||||
@@ -115,8 +149,6 @@ impure fn main(vec[str] args) {
|
||||
input_file = some[str](arg);
|
||||
}
|
||||
}
|
||||
// FIXME: dummy node to work around typestate mis-wiring bug.
|
||||
i = i;
|
||||
}
|
||||
i += 1u;
|
||||
}
|
||||
@@ -131,23 +163,29 @@ impure fn main(vec[str] args) {
|
||||
sess.err("no input filename");
|
||||
}
|
||||
case (some[str](?ifile)) {
|
||||
|
||||
auto env = default_environment(sess, args.(0), ifile);
|
||||
if (pretty) {
|
||||
pretty_print_input(sess, env, ifile);
|
||||
}
|
||||
else {
|
||||
alt (output_file) {
|
||||
case (none[str]) {
|
||||
let vec[str] parts = _str.split(ifile, '.' as u8);
|
||||
parts = _vec.pop[str](parts);
|
||||
parts += ".bc";
|
||||
auto ofile = _str.concat(parts);
|
||||
compile_input(sess, ifile, ofile, shared);
|
||||
compile_input(sess, env, ifile, ofile, shared);
|
||||
}
|
||||
case (some[str](?ofile)) {
|
||||
compile_input(sess, ifile, ofile, shared);
|
||||
compile_input(sess, env, ifile, ofile, shared);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Local Variables:
|
||||
// mode: rust
|
||||
// fill-column: 78;
|
||||
|
||||
@@ -5,6 +5,7 @@ import std._vec;
|
||||
import util.common.span;
|
||||
import util.common.spanned;
|
||||
import util.common.ty_mach;
|
||||
import util.common.filename;
|
||||
|
||||
type ident = str;
|
||||
|
||||
@@ -36,11 +37,29 @@ tag def {
|
||||
def_ty_arg(def_id);
|
||||
def_binding(def_id);
|
||||
def_use(def_id);
|
||||
def_native_ty(def_id);
|
||||
def_native_fn(def_id);
|
||||
}
|
||||
|
||||
type crate = spanned[crate_];
|
||||
type crate_ = rec(_mod module);
|
||||
|
||||
tag crate_directive_ {
|
||||
cdir_expr(@expr);
|
||||
// FIXME: cdir_let should be eliminated
|
||||
// and redirected to the use of const stmt_decls inside
|
||||
// crate directive blocks.
|
||||
cdir_let(ident, @expr, vec[@crate_directive]);
|
||||
cdir_src_mod(ident, option.t[filename]);
|
||||
cdir_dir_mod(ident, option.t[filename], vec[@crate_directive]);
|
||||
cdir_view_item(@view_item);
|
||||
cdir_meta(vec[@meta_item]);
|
||||
cdir_syntax(path);
|
||||
cdir_auth(path, effect);
|
||||
}
|
||||
type crate_directive = spanned[crate_directive_];
|
||||
|
||||
|
||||
type meta_item = spanned[meta_item_];
|
||||
type meta_item_ = rec(ident name, str value);
|
||||
|
||||
@@ -55,6 +74,7 @@ type pat = spanned[pat_];
|
||||
tag pat_ {
|
||||
pat_wild(ann);
|
||||
pat_bind(ident, def_id, ann);
|
||||
pat_lit(@lit, ann);
|
||||
pat_tag(path, vec[@pat], option.t[variant_def], ann);
|
||||
}
|
||||
|
||||
@@ -63,6 +83,11 @@ tag mutability {
|
||||
imm;
|
||||
}
|
||||
|
||||
tag opacity {
|
||||
op_abstract;
|
||||
op_transparent;
|
||||
}
|
||||
|
||||
tag layer {
|
||||
layer_value;
|
||||
layer_state;
|
||||
@@ -75,6 +100,11 @@ tag effect {
|
||||
eff_unsafe;
|
||||
}
|
||||
|
||||
tag proto {
|
||||
proto_iter;
|
||||
proto_fn;
|
||||
}
|
||||
|
||||
tag binop {
|
||||
add;
|
||||
sub;
|
||||
@@ -97,12 +127,49 @@ tag binop {
|
||||
gt;
|
||||
}
|
||||
|
||||
fn binop_to_str(binop op) -> str {
|
||||
alt (op) {
|
||||
case (add) {ret "+";}
|
||||
case (sub) {ret "-";}
|
||||
case (mul) {ret "*";}
|
||||
case (div) {ret "/";}
|
||||
case (rem) {ret "%";}
|
||||
case (and) {ret "&&";}
|
||||
case (or) {ret "||";}
|
||||
case (bitxor) {ret "^";}
|
||||
case (bitand) {ret "&";}
|
||||
case (bitor) {ret "|";}
|
||||
case (lsl) {ret "<<";}
|
||||
case (lsr) {ret ">>";}
|
||||
case (asr) {ret ">>>";}
|
||||
case (eq) {ret "==";}
|
||||
case (lt) {ret "<";}
|
||||
case (le) {ret "<=";}
|
||||
case (ne) {ret "!=";}
|
||||
case (ge) {ret ">=";}
|
||||
case (gt) {ret ">";}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
tag unop {
|
||||
box;
|
||||
deref;
|
||||
bitnot;
|
||||
not;
|
||||
neg;
|
||||
_mutable;
|
||||
}
|
||||
|
||||
fn unop_to_str(unop op) -> str {
|
||||
alt (op) {
|
||||
case (box) {ret "@";}
|
||||
case (deref) {ret "*";}
|
||||
case (bitnot) {ret "~";}
|
||||
case (not) {ret "!";}
|
||||
case (neg) {ret "-";}
|
||||
case (_mutable) {ret "mutable";}
|
||||
}
|
||||
}
|
||||
|
||||
tag mode {
|
||||
@@ -113,11 +180,9 @@ tag mode {
|
||||
type stmt = spanned[stmt_];
|
||||
tag stmt_ {
|
||||
stmt_decl(@decl);
|
||||
stmt_ret(option.t[@expr]);
|
||||
stmt_log(@expr);
|
||||
stmt_check_expr(@expr);
|
||||
stmt_fail;
|
||||
stmt_expr(@expr);
|
||||
// These only exist in crate-level blocks.
|
||||
stmt_crate_directive(@crate_directive);
|
||||
}
|
||||
|
||||
type local = rec(option.t[@ty] ty,
|
||||
@@ -142,7 +207,7 @@ type expr = spanned[expr_];
|
||||
tag expr_ {
|
||||
expr_vec(vec[@expr], ann);
|
||||
expr_tup(vec[elt], ann);
|
||||
expr_rec(vec[field], ann);
|
||||
expr_rec(vec[field], option.t[@expr], ann);
|
||||
expr_call(@expr, vec[@expr], ann);
|
||||
expr_bind(@expr, vec[option.t[@expr]], ann);
|
||||
expr_binary(binop, @expr, @expr, ann);
|
||||
@@ -152,6 +217,7 @@ tag expr_ {
|
||||
expr_if(@expr, block, option.t[@expr], ann);
|
||||
expr_while(@expr, block, ann);
|
||||
expr_for(@decl, @expr, block, ann);
|
||||
expr_for_each(@decl, @expr, block, ann);
|
||||
expr_do_while(block, @expr, ann);
|
||||
expr_alt(@expr, vec[arm], ann);
|
||||
expr_block(block, ann);
|
||||
@@ -160,6 +226,13 @@ tag expr_ {
|
||||
expr_field(@expr, ident, ann);
|
||||
expr_index(@expr, @expr, ann);
|
||||
expr_path(path, option.t[def], ann);
|
||||
expr_ext(path, vec[@expr], option.t[@expr], @expr, ann);
|
||||
expr_fail;
|
||||
expr_ret(option.t[@expr]);
|
||||
expr_put(option.t[@expr]);
|
||||
expr_be(@expr);
|
||||
expr_log(@expr);
|
||||
expr_check_expr(@expr);
|
||||
}
|
||||
|
||||
type lit = spanned[lit_];
|
||||
@@ -179,7 +252,8 @@ tag lit_ {
|
||||
type ty_field = rec(ident ident, @ty ty);
|
||||
type ty_arg = rec(mode mode, @ty ty);
|
||||
// TODO: effect
|
||||
type ty_method = rec(ident ident, vec[ty_arg] inputs, @ty output);
|
||||
type ty_method = rec(proto proto, ident ident,
|
||||
vec[ty_arg] inputs, @ty output);
|
||||
type ty = spanned[ty_];
|
||||
tag ty_ {
|
||||
ty_nil;
|
||||
@@ -193,17 +267,28 @@ tag ty_ {
|
||||
ty_vec(@ty);
|
||||
ty_tup(vec[@ty]);
|
||||
ty_rec(vec[ty_field]);
|
||||
ty_fn(vec[ty_arg], @ty); // TODO: effect
|
||||
ty_fn(proto, vec[ty_arg], @ty); // TODO: effect
|
||||
ty_obj(vec[ty_method]);
|
||||
ty_path(path, option.t[def]);
|
||||
ty_mutable(@ty);
|
||||
ty_type;
|
||||
ty_constr(@ty, vec[@constr]);
|
||||
}
|
||||
|
||||
tag constr_arg_ {
|
||||
carg_base;
|
||||
carg_ident(ident);
|
||||
}
|
||||
type constr_arg = spanned[constr_arg_];
|
||||
type constr_ = rec(path path, vec[@constr_arg] args);
|
||||
type constr = spanned[constr_];
|
||||
|
||||
type arg = rec(mode mode, @ty ty, ident ident, def_id id);
|
||||
type _fn = rec(effect effect,
|
||||
bool is_iter,
|
||||
type fn_decl = rec(effect effect,
|
||||
vec[arg] inputs,
|
||||
@ty output,
|
||||
@ty output);
|
||||
type _fn = rec(fn_decl decl,
|
||||
proto proto,
|
||||
block body);
|
||||
|
||||
|
||||
@@ -212,8 +297,8 @@ type method = spanned[method_];
|
||||
|
||||
type obj_field = rec(@ty ty, ident ident, def_id id, ann ann);
|
||||
type _obj = rec(vec[obj_field] fields,
|
||||
vec[@method] methods);
|
||||
|
||||
vec[@method] methods,
|
||||
option.t[block] dtor);
|
||||
|
||||
tag mod_index_entry {
|
||||
mie_view_item(@view_item);
|
||||
@@ -221,11 +306,28 @@ tag mod_index_entry {
|
||||
mie_tag_variant(@item /* tag item */, uint /* variant index */);
|
||||
}
|
||||
|
||||
tag native_mod_index_entry {
|
||||
nmie_view_item(@view_item);
|
||||
nmie_item(@native_item);
|
||||
}
|
||||
|
||||
type mod_index = hashmap[ident,mod_index_entry];
|
||||
type _mod = rec(vec[@view_item] view_items,
|
||||
vec[@item] items,
|
||||
mod_index index);
|
||||
|
||||
tag native_abi {
|
||||
native_abi_rust;
|
||||
native_abi_cdecl;
|
||||
}
|
||||
|
||||
type native_mod = rec(str native_name,
|
||||
native_abi abi,
|
||||
vec[@view_item] view_items,
|
||||
vec[@native_item] items,
|
||||
native_mod_index index);
|
||||
type native_mod_index = hashmap[ident,native_mod_index_entry];
|
||||
|
||||
type variant_arg = rec(@ty ty, def_id id);
|
||||
type variant = rec(str name, vec[variant_arg] args, def_id id, ann ann);
|
||||
|
||||
@@ -233,6 +335,7 @@ type view_item = spanned[view_item_];
|
||||
tag view_item_ {
|
||||
view_item_use(ident, vec[@meta_item], def_id);
|
||||
view_item_import(ident, vec[ident], def_id, option.t[def]);
|
||||
view_item_export(ident);
|
||||
}
|
||||
|
||||
type item = spanned[item_];
|
||||
@@ -240,11 +343,18 @@ tag item_ {
|
||||
item_const(ident, @ty, @expr, def_id, ann);
|
||||
item_fn(ident, _fn, vec[ty_param], def_id, ann);
|
||||
item_mod(ident, _mod, def_id);
|
||||
item_native_mod(ident, native_mod, def_id);
|
||||
item_ty(ident, @ty, vec[ty_param], def_id, ann);
|
||||
item_tag(ident, vec[variant], vec[ty_param], def_id);
|
||||
item_obj(ident, _obj, vec[ty_param], def_id, ann);
|
||||
}
|
||||
|
||||
type native_item = spanned[native_item_];
|
||||
tag native_item_ {
|
||||
native_item_ty(ident, def_id);
|
||||
native_item_fn(ident, fn_decl, vec[ty_param], def_id, ann);
|
||||
}
|
||||
|
||||
fn index_view_item(mod_index index, @view_item it) {
|
||||
alt (it.node) {
|
||||
case(ast.view_item_use(?id, _, _)) {
|
||||
@@ -253,6 +363,11 @@ fn index_view_item(mod_index index, @view_item it) {
|
||||
case(ast.view_item_import(?def_ident,_,_,_)) {
|
||||
index.insert(def_ident, ast.mie_view_item(it));
|
||||
}
|
||||
case(ast.view_item_export(_)) {
|
||||
// NB: don't index these, they might collide with
|
||||
// the import or use that they're exporting. Have
|
||||
// to do linear search for exports.
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -267,6 +382,9 @@ fn index_item(mod_index index, @item it) {
|
||||
case (ast.item_mod(?id, _, _)) {
|
||||
index.insert(id, ast.mie_item(it));
|
||||
}
|
||||
case (ast.item_native_mod(?id, _, _)) {
|
||||
index.insert(id, ast.mie_item(it));
|
||||
}
|
||||
case (ast.item_ty(?id, _, _, _, _)) {
|
||||
index.insert(id, ast.mie_item(it));
|
||||
}
|
||||
@@ -285,6 +403,41 @@ fn index_item(mod_index index, @item it) {
|
||||
}
|
||||
}
|
||||
|
||||
fn index_native_item(native_mod_index index, @native_item it) {
|
||||
alt (it.node) {
|
||||
case (ast.native_item_ty(?id, _)) {
|
||||
index.insert(id, ast.nmie_item(it));
|
||||
}
|
||||
case (ast.native_item_fn(?id, _, _, _, _)) {
|
||||
index.insert(id, ast.nmie_item(it));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn index_native_view_item(native_mod_index index, @view_item it) {
|
||||
alt (it.node) {
|
||||
case(ast.view_item_import(?def_ident,_,_,_)) {
|
||||
index.insert(def_ident, ast.nmie_view_item(it));
|
||||
}
|
||||
case(ast.view_item_export(_)) {
|
||||
// NB: don't index these, they might collide with
|
||||
// the import or use that they're exporting. Have
|
||||
// to do linear search for exports.
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn is_call_expr(@expr e) -> bool {
|
||||
alt (e.node) {
|
||||
case (expr_call(_, _, _)) {
|
||||
ret true;
|
||||
}
|
||||
case (_) {
|
||||
ret false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Local Variables:
|
||||
// mode: rust
|
||||
|
||||
436
src/comp/front/eval.rs
Normal file
436
src/comp/front/eval.rs
Normal file
@@ -0,0 +1,436 @@
|
||||
import std._vec;
|
||||
import std._str;
|
||||
import std.option;
|
||||
import std.option.some;
|
||||
import std.option.none;
|
||||
import std.map.hashmap;
|
||||
|
||||
import driver.session;
|
||||
import ast.ident;
|
||||
import front.parser.parser;
|
||||
import front.parser.spanned;
|
||||
import front.parser.new_parser;
|
||||
import front.parser.parse_mod_items;
|
||||
import util.common;
|
||||
import util.common.filename;
|
||||
import util.common.append;
|
||||
import util.common.span;
|
||||
import util.common.new_str_hash;
|
||||
|
||||
|
||||
// Simple dynamic-typed value type for eval_expr.
|
||||
tag val {
|
||||
val_bool(bool);
|
||||
val_int(int);
|
||||
val_str(str);
|
||||
}
|
||||
|
||||
type env = vec[tup(ident, val)];
|
||||
|
||||
fn mk_env() -> env {
|
||||
let env e = vec();
|
||||
ret e;
|
||||
}
|
||||
|
||||
fn val_is_bool(val v) -> bool {
|
||||
alt (v) {
|
||||
case (val_bool(_)) { ret true; }
|
||||
case (_) { }
|
||||
}
|
||||
ret false;
|
||||
}
|
||||
|
||||
fn val_is_int(val v) -> bool {
|
||||
alt (v) {
|
||||
case (val_bool(_)) { ret true; }
|
||||
case (_) { }
|
||||
}
|
||||
ret false;
|
||||
}
|
||||
|
||||
fn val_is_str(val v) -> bool {
|
||||
alt (v) {
|
||||
case (val_str(_)) { ret true; }
|
||||
case (_) { }
|
||||
}
|
||||
ret false;
|
||||
}
|
||||
|
||||
fn val_as_bool(val v) -> bool {
|
||||
alt (v) {
|
||||
case (val_bool(?b)) { ret b; }
|
||||
case (_) { }
|
||||
}
|
||||
fail;
|
||||
}
|
||||
|
||||
fn val_as_int(val v) -> int {
|
||||
alt (v) {
|
||||
case (val_int(?i)) { ret i; }
|
||||
case (_) { }
|
||||
}
|
||||
fail;
|
||||
}
|
||||
|
||||
fn val_as_str(val v) -> str {
|
||||
alt (v) {
|
||||
case (val_str(?s)) { ret s; }
|
||||
case (_) { }
|
||||
}
|
||||
fail;
|
||||
}
|
||||
|
||||
fn lookup(session.session sess, env e, span sp, ident i) -> val {
|
||||
for (tup(ident, val) pair in e) {
|
||||
if (_str.eq(i, pair._0)) {
|
||||
ret pair._1;
|
||||
}
|
||||
}
|
||||
sess.span_err(sp, "unknown variable: " + i);
|
||||
fail;
|
||||
}
|
||||
|
||||
fn eval_lit(session.session sess, env e, span sp, @ast.lit lit) -> val {
|
||||
alt (lit.node) {
|
||||
case (ast.lit_bool(?b)) { ret val_bool(b); }
|
||||
case (ast.lit_int(?i)) { ret val_int(i); }
|
||||
case (ast.lit_str(?s)) { ret val_str(s); }
|
||||
case (_) {
|
||||
sess.span_err(sp, "evaluating unsupported literal");
|
||||
}
|
||||
}
|
||||
fail;
|
||||
}
|
||||
|
||||
fn eval_expr(session.session sess, env e, @ast.expr x) -> val {
|
||||
alt (x.node) {
|
||||
case (ast.expr_path(?pth, _, _)) {
|
||||
if (_vec.len[ident](pth.node.idents) == 1u &&
|
||||
_vec.len[@ast.ty](pth.node.types) == 0u) {
|
||||
ret lookup(sess, e, x.span, pth.node.idents.(0));
|
||||
}
|
||||
sess.span_err(x.span, "evaluating structured path-name");
|
||||
}
|
||||
|
||||
case (ast.expr_lit(?lit, _)) {
|
||||
ret eval_lit(sess, e, x.span, lit);
|
||||
}
|
||||
|
||||
case (ast.expr_unary(?op, ?a, _)) {
|
||||
auto av = eval_expr(sess, e, a);
|
||||
alt (op) {
|
||||
case (ast.not) {
|
||||
if (val_is_bool(av)) {
|
||||
ret val_bool(!val_as_bool(av));
|
||||
}
|
||||
sess.span_err(x.span, "bad types in '!' expression");
|
||||
}
|
||||
case (_) {
|
||||
sess.span_err(x.span, "evaluating unsupported unop");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
case (ast.expr_binary(?op, ?a, ?b, _)) {
|
||||
auto av = eval_expr(sess, e, a);
|
||||
auto bv = eval_expr(sess, e, b);
|
||||
alt (op) {
|
||||
case (ast.add) {
|
||||
if (val_is_int(av) && val_is_int(bv)) {
|
||||
ret val_int(val_as_int(av) + val_as_int(bv));
|
||||
}
|
||||
if (val_is_str(av) && val_is_str(bv)) {
|
||||
ret val_str(val_as_str(av) + val_as_str(bv));
|
||||
}
|
||||
sess.span_err(x.span, "bad types in '+' expression");
|
||||
}
|
||||
|
||||
case (ast.sub) {
|
||||
if (val_is_int(av) && val_is_int(bv)) {
|
||||
ret val_int(val_as_int(av) - val_as_int(bv));
|
||||
}
|
||||
sess.span_err(x.span, "bad types in '-' expression");
|
||||
}
|
||||
|
||||
case (ast.mul) {
|
||||
if (val_is_int(av) && val_is_int(bv)) {
|
||||
ret val_int(val_as_int(av) * val_as_int(bv));
|
||||
}
|
||||
sess.span_err(x.span, "bad types in '*' expression");
|
||||
}
|
||||
|
||||
case (ast.div) {
|
||||
if (val_is_int(av) && val_is_int(bv)) {
|
||||
ret val_int(val_as_int(av) / val_as_int(bv));
|
||||
}
|
||||
sess.span_err(x.span, "bad types in '/' expression");
|
||||
}
|
||||
|
||||
case (ast.rem) {
|
||||
if (val_is_int(av) && val_is_int(bv)) {
|
||||
ret val_int(val_as_int(av) % val_as_int(bv));
|
||||
}
|
||||
sess.span_err(x.span, "bad types in '%' expression");
|
||||
}
|
||||
|
||||
case (ast.and) {
|
||||
if (val_is_bool(av) && val_is_bool(bv)) {
|
||||
ret val_bool(val_as_bool(av) && val_as_bool(bv));
|
||||
}
|
||||
sess.span_err(x.span, "bad types in '&&' expression");
|
||||
}
|
||||
|
||||
case (ast.or) {
|
||||
if (val_is_bool(av) && val_is_bool(bv)) {
|
||||
ret val_bool(val_as_bool(av) || val_as_bool(bv));
|
||||
}
|
||||
sess.span_err(x.span, "bad types in '||' expression");
|
||||
}
|
||||
|
||||
case (ast.eq) {
|
||||
ret val_bool(val_eq(sess, x.span, av, bv));
|
||||
}
|
||||
|
||||
case (ast.ne) {
|
||||
ret val_bool(! val_eq(sess, x.span, av, bv));
|
||||
}
|
||||
|
||||
case (_) {
|
||||
sess.span_err(x.span, "evaluating unsupported binop");
|
||||
}
|
||||
}
|
||||
}
|
||||
case (_) {
|
||||
sess.span_err(x.span, "evaluating unsupported expression");
|
||||
}
|
||||
}
|
||||
fail;
|
||||
}
|
||||
|
||||
fn val_eq(session.session sess, span sp, val av, val bv) -> bool {
|
||||
if (val_is_bool(av) && val_is_bool(bv)) {
|
||||
ret val_as_bool(av) == val_as_bool(bv);
|
||||
}
|
||||
if (val_is_int(av) && val_is_int(bv)) {
|
||||
ret val_as_int(av) == val_as_int(bv);
|
||||
}
|
||||
if (val_is_str(av) && val_is_str(bv)) {
|
||||
ret _str.eq(val_as_str(av),
|
||||
val_as_str(bv));
|
||||
}
|
||||
sess.span_err(sp, "bad types in comparison");
|
||||
fail;
|
||||
}
|
||||
|
||||
impure fn eval_crate_directives(parser p,
|
||||
env e,
|
||||
vec[@ast.crate_directive] cdirs,
|
||||
str prefix,
|
||||
&mutable vec[@ast.view_item] view_items,
|
||||
&mutable vec[@ast.item] items,
|
||||
hashmap[ast.ident,
|
||||
ast.mod_index_entry] index) {
|
||||
|
||||
for (@ast.crate_directive sub_cdir in cdirs) {
|
||||
eval_crate_directive(p, e, sub_cdir, prefix,
|
||||
view_items, items, index);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
impure fn eval_crate_directives_to_mod(parser p,
|
||||
env e,
|
||||
vec[@ast.crate_directive] cdirs,
|
||||
str prefix) -> ast._mod {
|
||||
let vec[@ast.view_item] view_items = vec();
|
||||
let vec[@ast.item] items = vec();
|
||||
auto index = new_str_hash[ast.mod_index_entry]();
|
||||
|
||||
eval_crate_directives(p, e, cdirs, prefix,
|
||||
view_items, items, index);
|
||||
|
||||
ret rec(view_items=view_items, items=items, index=index);
|
||||
}
|
||||
|
||||
|
||||
impure fn eval_crate_directive_block(parser p,
|
||||
env e,
|
||||
&ast.block blk,
|
||||
str prefix,
|
||||
&mutable vec[@ast.view_item] view_items,
|
||||
&mutable vec[@ast.item] items,
|
||||
hashmap[ast.ident,
|
||||
ast.mod_index_entry] index) {
|
||||
|
||||
for (@ast.stmt s in blk.node.stmts) {
|
||||
alt (s.node) {
|
||||
case (ast.stmt_crate_directive(?cdir)) {
|
||||
eval_crate_directive(p, e, cdir, prefix,
|
||||
view_items, items, index);
|
||||
}
|
||||
case (_) {
|
||||
auto sess = p.get_session();
|
||||
sess.span_err(s.span,
|
||||
"unsupported stmt in crate-directive block");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impure fn eval_crate_directive_expr(parser p,
|
||||
env e,
|
||||
@ast.expr x,
|
||||
str prefix,
|
||||
&mutable vec[@ast.view_item] view_items,
|
||||
&mutable vec[@ast.item] items,
|
||||
hashmap[ast.ident,
|
||||
ast.mod_index_entry] index) {
|
||||
auto sess = p.get_session();
|
||||
|
||||
alt (x.node) {
|
||||
|
||||
case (ast.expr_if(?cond, ?thn, ?elopt, _)) {
|
||||
auto cv = eval_expr(sess, e, cond);
|
||||
if (!val_is_bool(cv)) {
|
||||
sess.span_err(x.span, "bad cond type in 'if'");
|
||||
}
|
||||
|
||||
if (val_as_bool(cv)) {
|
||||
ret eval_crate_directive_block(p, e, thn, prefix,
|
||||
view_items, items,
|
||||
index);
|
||||
}
|
||||
|
||||
alt (elopt) {
|
||||
case (some[@ast.expr](?els)) {
|
||||
ret eval_crate_directive_expr(p, e, els, prefix,
|
||||
view_items, items,
|
||||
index);
|
||||
}
|
||||
case (_) {
|
||||
// Absent-else is ok.
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
case (ast.expr_alt(?v, ?arms, _)) {
|
||||
auto vv = eval_expr(sess, e, v);
|
||||
for (ast.arm arm in arms) {
|
||||
alt (arm.pat.node) {
|
||||
case (ast.pat_lit(?lit, _)) {
|
||||
auto pv = eval_lit(sess, e,
|
||||
arm.pat.span, lit);
|
||||
if (val_eq(sess, arm.pat.span, vv, pv)) {
|
||||
ret eval_crate_directive_block
|
||||
(p, e, arm.block, prefix,
|
||||
view_items, items, index);
|
||||
}
|
||||
}
|
||||
case (ast.pat_wild(_)) {
|
||||
ret eval_crate_directive_block
|
||||
(p, e, arm.block, prefix,
|
||||
view_items, items, index);
|
||||
}
|
||||
case (_) {
|
||||
sess.span_err(arm.pat.span,
|
||||
"bad pattern type in 'alt'");
|
||||
}
|
||||
}
|
||||
}
|
||||
sess.span_err(x.span, "no cases matched in 'alt'");
|
||||
}
|
||||
|
||||
case (ast.expr_block(?block, _)) {
|
||||
ret eval_crate_directive_block(p, e, block, prefix,
|
||||
view_items, items,
|
||||
index);
|
||||
}
|
||||
|
||||
case (_) {
|
||||
sess.span_err(x.span, "unsupported expr type");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impure fn eval_crate_directive(parser p,
|
||||
env e,
|
||||
@ast.crate_directive cdir,
|
||||
str prefix,
|
||||
&mutable vec[@ast.view_item] view_items,
|
||||
&mutable vec[@ast.item] items,
|
||||
hashmap[ast.ident,
|
||||
ast.mod_index_entry] index) {
|
||||
alt (cdir.node) {
|
||||
|
||||
case (ast.cdir_let(?id, ?x, ?cdirs)) {
|
||||
auto v = eval_expr(p.get_session(), e, x);
|
||||
auto e0 = vec(tup(id, v)) + e;
|
||||
eval_crate_directives(p, e0, cdirs, prefix,
|
||||
view_items, items, index);
|
||||
}
|
||||
|
||||
case (ast.cdir_expr(?x)) {
|
||||
eval_crate_directive_expr(p, e, x, prefix,
|
||||
view_items, items, index);
|
||||
}
|
||||
|
||||
case (ast.cdir_src_mod(?id, ?file_opt)) {
|
||||
|
||||
auto file_path = id + ".rs";
|
||||
alt (file_opt) {
|
||||
case (some[filename](?f)) {
|
||||
file_path = f;
|
||||
}
|
||||
case (none[filename]) {}
|
||||
}
|
||||
|
||||
auto full_path = prefix + std.os.path_sep() + file_path;
|
||||
|
||||
auto p0 = new_parser(p.get_session(), e, 0, full_path);
|
||||
auto m0 = parse_mod_items(p0, token.EOF);
|
||||
auto im = ast.item_mod(id, m0, p.next_def_id());
|
||||
auto i = @spanned(cdir.span, cdir.span, im);
|
||||
ast.index_item(index, i);
|
||||
append[@ast.item](items, i);
|
||||
}
|
||||
|
||||
case (ast.cdir_dir_mod(?id, ?dir_opt, ?cdirs)) {
|
||||
|
||||
auto path = id;
|
||||
alt (dir_opt) {
|
||||
case (some[filename](?d)) {
|
||||
path = d;
|
||||
}
|
||||
case (none[filename]) {}
|
||||
}
|
||||
|
||||
auto full_path = prefix + std.os.path_sep() + path;
|
||||
auto m0 = eval_crate_directives_to_mod(p, e, cdirs, full_path);
|
||||
auto im = ast.item_mod(id, m0, p.next_def_id());
|
||||
auto i = @spanned(cdir.span, cdir.span, im);
|
||||
ast.index_item(index, i);
|
||||
append[@ast.item](items, i);
|
||||
}
|
||||
|
||||
case (ast.cdir_view_item(?vi)) {
|
||||
append[@ast.view_item](view_items, vi);
|
||||
ast.index_view_item(index, vi);
|
||||
}
|
||||
|
||||
case (ast.cdir_meta(?mi)) {}
|
||||
case (ast.cdir_syntax(?pth)) {}
|
||||
case (ast.cdir_auth(?pth, ?eff)) {}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// Local Variables:
|
||||
// mode: rust
|
||||
// fill-column: 78;
|
||||
// indent-tabs-mode: nil
|
||||
// c-basic-offset: 4
|
||||
// buffer-file-coding-system: utf-8-unix
|
||||
// compile-command: "make -k -C ../.. 2>&1 | sed -e 's/\\/x\\//x:\\//g'";
|
||||
// End:
|
||||
//
|
||||
553
src/comp/front/extfmt.rs
Normal file
553
src/comp/front/extfmt.rs
Normal file
@@ -0,0 +1,553 @@
|
||||
/* The 'fmt' extension is modeled on the posix printf system.
|
||||
*
|
||||
* A posix conversion ostensibly looks like this:
|
||||
*
|
||||
* %[parameter][flags][width][.precision][length]type
|
||||
*
|
||||
* Given the different numeric type bestiary we have, we omit the 'length'
|
||||
* parameter and support slightly different conversions for 'type':
|
||||
*
|
||||
* %[parameter][flags][width][.precision]type
|
||||
*
|
||||
* we also only support translating-to-rust a tiny subset of the possible
|
||||
* combinations at the moment.
|
||||
*/
|
||||
|
||||
import util.common;
|
||||
|
||||
import std._str;
|
||||
import std._vec;
|
||||
import std.option;
|
||||
import std.option.none;
|
||||
import std.option.some;
|
||||
|
||||
export expand_syntax_ext;
|
||||
|
||||
tag signedness {
|
||||
signed;
|
||||
unsigned;
|
||||
}
|
||||
|
||||
tag caseness {
|
||||
case_upper;
|
||||
case_lower;
|
||||
}
|
||||
|
||||
tag ty {
|
||||
ty_bool;
|
||||
ty_str;
|
||||
ty_char;
|
||||
ty_int(signedness);
|
||||
ty_bits;
|
||||
ty_hex(caseness);
|
||||
// FIXME: More types
|
||||
}
|
||||
|
||||
tag flag {
|
||||
flag_left_justify;
|
||||
flag_left_zero_pad;
|
||||
flag_left_space_pad;
|
||||
flag_plus_if_positive;
|
||||
flag_alternate;
|
||||
}
|
||||
|
||||
tag count {
|
||||
count_is(int);
|
||||
count_is_param(int);
|
||||
count_is_next_param;
|
||||
count_implied;
|
||||
}
|
||||
|
||||
// A formatted conversion from an expression to a string
|
||||
type conv = rec(option.t[int] param,
|
||||
vec[flag] flags,
|
||||
count width,
|
||||
count precision,
|
||||
ty ty);
|
||||
|
||||
// A fragment of the output sequence
|
||||
tag piece {
|
||||
piece_string(str);
|
||||
piece_conv(conv);
|
||||
}
|
||||
|
||||
// TODO: Need to thread parser through here to handle errors correctly
|
||||
fn expand_syntax_ext(vec[@ast.expr] args,
|
||||
option.t[@ast.expr] body) -> @ast.expr {
|
||||
|
||||
if (_vec.len[@ast.expr](args) == 0u) {
|
||||
log "malformed #fmt call";
|
||||
fail;
|
||||
}
|
||||
|
||||
auto fmt = expr_to_str(args.(0));
|
||||
|
||||
// log "Format string:";
|
||||
// log fmt;
|
||||
|
||||
auto pieces = parse_fmt_string(fmt);
|
||||
auto args_len = _vec.len[@ast.expr](args);
|
||||
auto fmt_args = _vec.slice[@ast.expr](args, 1u, args_len - 1u);
|
||||
ret pieces_to_expr(pieces, args);
|
||||
}
|
||||
|
||||
fn expr_to_str(@ast.expr expr) -> str {
|
||||
alt (expr.node) {
|
||||
case (ast.expr_lit(?l, _)) {
|
||||
alt (l.node) {
|
||||
case (ast.lit_str(?s)) {
|
||||
ret s;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
log "malformed #fmt call";
|
||||
fail;
|
||||
}
|
||||
|
||||
fn parse_fmt_string(str s) -> vec[piece] {
|
||||
let vec[piece] pieces = vec();
|
||||
auto lim = _str.byte_len(s);
|
||||
auto buf = "";
|
||||
|
||||
fn flush_buf(str buf, &vec[piece] pieces) -> str {
|
||||
if (_str.byte_len(buf) > 0u) {
|
||||
auto piece = piece_string(buf);
|
||||
pieces += piece;
|
||||
}
|
||||
ret "";
|
||||
}
|
||||
|
||||
auto i = 0u;
|
||||
while (i < lim) {
|
||||
auto curr = _str.substr(s, i, 1u);
|
||||
if (_str.eq(curr, "%")) {
|
||||
i += 1u;
|
||||
if (i >= lim) {
|
||||
log "unterminated conversion at end of string";
|
||||
fail;
|
||||
}
|
||||
auto curr2 = _str.substr(s, i, 1u);
|
||||
if (_str.eq(curr2, "%")) {
|
||||
i += 1u;
|
||||
} else {
|
||||
buf = flush_buf(buf, pieces);
|
||||
auto res = parse_conversion(s, i, lim);
|
||||
pieces += res._0;
|
||||
i = res._1;
|
||||
}
|
||||
} else {
|
||||
buf += curr;
|
||||
i += 1u;
|
||||
}
|
||||
}
|
||||
buf = flush_buf(buf, pieces);
|
||||
ret pieces;
|
||||
}
|
||||
|
||||
fn peek_num(str s, uint i, uint lim) -> option.t[tup(uint, uint)] {
|
||||
if (i >= lim) {
|
||||
ret none[tup(uint, uint)];
|
||||
}
|
||||
|
||||
auto c = s.(i);
|
||||
if (!('0' as u8 <= c && c <= '9' as u8)) {
|
||||
ret option.none[tup(uint, uint)];
|
||||
}
|
||||
|
||||
auto n = (c - ('0' as u8)) as uint;
|
||||
alt (peek_num(s, i + 1u, lim)) {
|
||||
case (none[tup(uint, uint)]) {
|
||||
ret some[tup(uint, uint)](tup(n, i + 1u));
|
||||
}
|
||||
case (some[tup(uint, uint)](?next)) {
|
||||
auto m = next._0;
|
||||
auto j = next._1;
|
||||
ret some[tup(uint, uint)](tup(n * 10u + m, j));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
fn parse_conversion(str s, uint i, uint lim) -> tup(piece, uint) {
|
||||
auto parm = parse_parameter(s, i, lim);
|
||||
auto flags = parse_flags(s, parm._1, lim);
|
||||
auto width = parse_count(s, flags._1, lim);
|
||||
auto prec = parse_precision(s, width._1, lim);
|
||||
auto ty = parse_type(s, prec._1, lim);
|
||||
ret tup(piece_conv(rec(param = parm._0,
|
||||
flags = flags._0,
|
||||
width = width._0,
|
||||
precision = prec._0,
|
||||
ty = ty._0)),
|
||||
ty._1);
|
||||
}
|
||||
|
||||
fn parse_parameter(str s, uint i, uint lim) -> tup(option.t[int], uint) {
|
||||
if (i >= lim) {
|
||||
ret tup(none[int], i);
|
||||
}
|
||||
|
||||
auto num = peek_num(s, i, lim);
|
||||
alt (num) {
|
||||
case (none[tup(uint, uint)]) {
|
||||
ret tup(none[int], i);
|
||||
}
|
||||
case (some[tup(uint, uint)](?t)) {
|
||||
auto n = t._0;
|
||||
auto j = t._1;
|
||||
if (j < lim && s.(j) == '$' as u8) {
|
||||
ret tup(some[int](n as int), j + 1u);
|
||||
}
|
||||
else {
|
||||
ret tup(none[int], i);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn parse_flags(str s, uint i, uint lim) -> tup(vec[flag], uint) {
|
||||
let vec[flag] noflags = vec();
|
||||
|
||||
if (i >= lim) {
|
||||
ret tup(noflags, i);
|
||||
}
|
||||
|
||||
fn more_(flag f, str s, uint i, uint lim) -> tup(vec[flag], uint) {
|
||||
auto next = parse_flags(s, i + 1u, lim);
|
||||
auto rest = next._0;
|
||||
auto j = next._1;
|
||||
let vec[flag] curr = vec(f);
|
||||
ret tup(curr + rest, j);
|
||||
}
|
||||
|
||||
auto more = bind more_(_, s, i, lim);
|
||||
|
||||
auto f = s.(i);
|
||||
if (f == ('-' as u8)) {
|
||||
ret more(flag_left_justify);
|
||||
} else if (f == ('0' as u8)) {
|
||||
ret more(flag_left_zero_pad);
|
||||
} else if (f == (' ' as u8)) {
|
||||
ret more(flag_left_space_pad);
|
||||
} else if (f == ('+' as u8)) {
|
||||
ret more(flag_plus_if_positive);
|
||||
} else if (f == ('#' as u8)) {
|
||||
ret more(flag_alternate);
|
||||
} else {
|
||||
ret tup(noflags, i);
|
||||
}
|
||||
}
|
||||
|
||||
fn parse_count(str s, uint i, uint lim) -> tup(count, uint) {
|
||||
if (i >= lim) {
|
||||
ret tup(count_implied, i);
|
||||
}
|
||||
|
||||
if (s.(i) == ('*' as u8)) {
|
||||
auto param = parse_parameter(s, i + 1u, lim);
|
||||
auto j = param._1;
|
||||
alt (param._0) {
|
||||
case (none[int]) {
|
||||
ret tup(count_is_next_param, j);
|
||||
}
|
||||
case (some[int](?n)) {
|
||||
ret tup(count_is_param(n), j);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
auto num = peek_num(s, i, lim);
|
||||
alt (num) {
|
||||
case (none[tup(uint, uint)]) {
|
||||
ret tup(count_implied, i);
|
||||
}
|
||||
case (some[tup(uint, uint)](?num)) {
|
||||
ret tup(count_is(num._0 as int), num._1);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn parse_precision(str s, uint i, uint lim) -> tup(count, uint) {
|
||||
if (i >= lim) {
|
||||
ret tup(count_implied, i);
|
||||
}
|
||||
|
||||
if (s.(i) == '.' as u8) {
|
||||
ret parse_count(s, i + 1u, lim);
|
||||
} else {
|
||||
ret tup(count_implied, i);
|
||||
}
|
||||
}
|
||||
|
||||
fn parse_type(str s, uint i, uint lim) -> tup(ty, uint) {
|
||||
if (i >= lim) {
|
||||
log "missing type in conversion";
|
||||
fail;
|
||||
}
|
||||
|
||||
auto t;
|
||||
auto tstr = _str.substr(s, i, 1u);
|
||||
if (_str.eq(tstr, "b")) {
|
||||
t = ty_bool;
|
||||
} else if (_str.eq(tstr, "s")) {
|
||||
t = ty_str;
|
||||
} else if (_str.eq(tstr, "c")) {
|
||||
t = ty_char;
|
||||
} else if (_str.eq(tstr, "d")
|
||||
|| _str.eq(tstr, "i")) {
|
||||
// TODO: Do we really want two signed types here?
|
||||
// How important is it to be printf compatible?
|
||||
t = ty_int(signed);
|
||||
} else if (_str.eq(tstr, "u")) {
|
||||
t = ty_int(unsigned);
|
||||
} else if (_str.eq(tstr, "x")) {
|
||||
t = ty_hex(case_lower);
|
||||
} else if (_str.eq(tstr, "X")) {
|
||||
t = ty_hex(case_upper);
|
||||
} else if (_str.eq(tstr, "t")) {
|
||||
t = ty_bits;
|
||||
} else {
|
||||
log "unknown type in conversion";
|
||||
fail;
|
||||
}
|
||||
|
||||
ret tup(t, i + 1u);
|
||||
}
|
||||
|
||||
fn pieces_to_expr(vec[piece] pieces, vec[@ast.expr] args) -> @ast.expr {
|
||||
|
||||
fn make_new_lit(common.span sp, ast.lit_ lit) -> @ast.expr {
|
||||
auto sp_lit = @parser.spanned[ast.lit_](sp, sp, lit);
|
||||
auto expr = ast.expr_lit(sp_lit, ast.ann_none);
|
||||
ret @parser.spanned[ast.expr_](sp, sp, expr);
|
||||
}
|
||||
|
||||
fn make_new_str(common.span sp, str s) -> @ast.expr {
|
||||
auto lit = ast.lit_str(s);
|
||||
ret make_new_lit(sp, lit);
|
||||
}
|
||||
|
||||
fn make_new_uint(common.span sp, uint u) -> @ast.expr {
|
||||
auto lit = ast.lit_uint(u);
|
||||
ret make_new_lit(sp, lit);
|
||||
}
|
||||
|
||||
fn make_add_expr(common.span sp,
|
||||
@ast.expr lhs, @ast.expr rhs) -> @ast.expr {
|
||||
auto binexpr = ast.expr_binary(ast.add, lhs, rhs, ast.ann_none);
|
||||
ret @parser.spanned[ast.expr_](sp, sp, binexpr);
|
||||
}
|
||||
|
||||
fn make_call(common.span sp, vec[ast.ident] fn_path,
|
||||
vec[@ast.expr] args) -> @ast.expr {
|
||||
let vec[ast.ident] path_idents = fn_path;
|
||||
let vec[@ast.ty] path_types = vec();
|
||||
auto path = rec(idents = path_idents, types = path_types);
|
||||
auto sp_path = parser.spanned[ast.path_](sp, sp, path);
|
||||
auto pathexpr = ast.expr_path(sp_path, none[ast.def], ast.ann_none);
|
||||
auto sp_pathexpr = @parser.spanned[ast.expr_](sp, sp, pathexpr);
|
||||
auto callexpr = ast.expr_call(sp_pathexpr, args, ast.ann_none);
|
||||
auto sp_callexpr = @parser.spanned[ast.expr_](sp, sp, callexpr);
|
||||
ret sp_callexpr;
|
||||
}
|
||||
|
||||
fn make_new_conv(conv cnv, @ast.expr arg) -> @ast.expr {
|
||||
|
||||
auto unsupported = "conversion not supported in #fmt string";
|
||||
|
||||
alt (cnv.param) {
|
||||
case (option.none[int]) {
|
||||
}
|
||||
case (_) {
|
||||
log unsupported;
|
||||
fail;
|
||||
}
|
||||
}
|
||||
|
||||
if (_vec.len[flag](cnv.flags) != 0u) {
|
||||
log unsupported;
|
||||
fail;
|
||||
}
|
||||
|
||||
alt (cnv.width) {
|
||||
case (count_implied) {
|
||||
}
|
||||
case (_) {
|
||||
log unsupported;
|
||||
fail;
|
||||
}
|
||||
}
|
||||
|
||||
alt (cnv.precision) {
|
||||
case (count_implied) {
|
||||
}
|
||||
case (_) {
|
||||
log unsupported;
|
||||
fail;
|
||||
}
|
||||
}
|
||||
|
||||
alt (cnv.ty) {
|
||||
case (ty_str) {
|
||||
ret arg;
|
||||
}
|
||||
case (ty_int(?sign)) {
|
||||
alt (sign) {
|
||||
case (signed) {
|
||||
let vec[str] path = vec("std", "_int", "to_str");
|
||||
auto radix_expr = make_new_uint(arg.span, 10u);
|
||||
let vec[@ast.expr] args = vec(arg, radix_expr);
|
||||
ret make_call(arg.span, path, args);
|
||||
}
|
||||
case (unsigned) {
|
||||
let vec[str] path = vec("std", "_uint", "to_str");
|
||||
auto radix_expr = make_new_uint(arg.span, 10u);
|
||||
let vec[@ast.expr] args = vec(arg, radix_expr);
|
||||
ret make_call(arg.span, path, args);
|
||||
}
|
||||
}
|
||||
}
|
||||
case (_) {
|
||||
log unsupported;
|
||||
fail;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn log_conv(conv c) {
|
||||
alt (c.param) {
|
||||
case (some[int](?p)) {
|
||||
log "param: " + std._int.to_str(p, 10u);
|
||||
}
|
||||
case (_) {
|
||||
log "param: none";
|
||||
}
|
||||
}
|
||||
for (flag f in c.flags) {
|
||||
alt (f) {
|
||||
case (flag_left_justify) {
|
||||
log "flag: left justify";
|
||||
}
|
||||
case (flag_left_zero_pad) {
|
||||
log "flag: left zero pad";
|
||||
}
|
||||
case (flag_left_space_pad) {
|
||||
log "flag: left space pad";
|
||||
}
|
||||
case (flag_plus_if_positive) {
|
||||
log "flag: plus if positive";
|
||||
}
|
||||
case (flag_alternate) {
|
||||
log "flag: alternate";
|
||||
}
|
||||
}
|
||||
}
|
||||
alt (c.width) {
|
||||
case (count_is(?i)) {
|
||||
log "width: count is " + std._int.to_str(i, 10u);
|
||||
}
|
||||
case (count_is_param(?i)) {
|
||||
log "width: count is param " + std._int.to_str(i, 10u);
|
||||
}
|
||||
case (count_is_next_param) {
|
||||
log "width: count is next param";
|
||||
}
|
||||
case (count_implied) {
|
||||
log "width: count is implied";
|
||||
}
|
||||
}
|
||||
alt (c.precision) {
|
||||
case (count_is(?i)) {
|
||||
log "prec: count is " + std._int.to_str(i, 10u);
|
||||
}
|
||||
case (count_is_param(?i)) {
|
||||
log "prec: count is param " + std._int.to_str(i, 10u);
|
||||
}
|
||||
case (count_is_next_param) {
|
||||
log "prec: count is next param";
|
||||
}
|
||||
case (count_implied) {
|
||||
log "prec: count is implied";
|
||||
}
|
||||
}
|
||||
alt (c.ty) {
|
||||
case (ty_bool) {
|
||||
log "type: bool";
|
||||
}
|
||||
case (ty_str) {
|
||||
log "type: str";
|
||||
}
|
||||
case (ty_char) {
|
||||
log "type: char";
|
||||
}
|
||||
case (ty_int(?s)) {
|
||||
alt (s) {
|
||||
case (signed) {
|
||||
log "type: signed";
|
||||
}
|
||||
case (unsigned) {
|
||||
log "type: unsigned";
|
||||
}
|
||||
}
|
||||
}
|
||||
case (ty_bits) {
|
||||
log "type: bits";
|
||||
}
|
||||
case (ty_hex(?cs)) {
|
||||
alt (cs) {
|
||||
case (case_upper) {
|
||||
log "type: uhex";
|
||||
}
|
||||
case (case_lower) {
|
||||
log "type: lhex";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
auto sp = args.(0).span;
|
||||
auto n = 0u;
|
||||
auto tmp_expr = make_new_str(sp, "");
|
||||
|
||||
for (piece p in pieces) {
|
||||
alt (p) {
|
||||
case (piece_string(?s)) {
|
||||
auto s_expr = make_new_str(sp, s);
|
||||
tmp_expr = make_add_expr(sp, tmp_expr, s_expr);
|
||||
}
|
||||
case (piece_conv(?conv)) {
|
||||
if (n >= _vec.len[@ast.expr](args)) {
|
||||
log "too many conversions in #fmt string";
|
||||
fail;
|
||||
}
|
||||
|
||||
// TODO: Remove debug logging
|
||||
// log "Building conversion:";
|
||||
// log_conv(conv);
|
||||
|
||||
n += 1u;
|
||||
auto arg_expr = args.(n);
|
||||
auto c_expr = make_new_conv(conv, arg_expr);
|
||||
tmp_expr = make_add_expr(sp, tmp_expr, c_expr);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: Remove this debug logging
|
||||
// log "dumping expanded ast:";
|
||||
// log pretty.print_expr(tmp_expr);
|
||||
ret tmp_expr;
|
||||
}
|
||||
|
||||
//
|
||||
// Local Variables:
|
||||
// mode: rust
|
||||
// fill-column: 78;
|
||||
// indent-tabs-mode: nil
|
||||
// c-basic-offset: 4
|
||||
// buffer-file-coding-system: utf-8-unix
|
||||
// compile-command: "make -k -C ../.. 2>&1 | sed -e 's/\\/x\\//x:\\//g'";
|
||||
// End:
|
||||
//
|
||||
@@ -1,4 +1,4 @@
|
||||
import std._io.stdio_reader;
|
||||
import std.io.stdio_reader;
|
||||
import std._str;
|
||||
import std.map;
|
||||
import std.map.hashmap;
|
||||
@@ -90,7 +90,6 @@ fn new_reader(stdio_reader rdr, str filename) -> reader
|
||||
}
|
||||
|
||||
auto keywords = new_str_hash[token.token]();
|
||||
auto reserved = new_str_hash[()]();
|
||||
|
||||
keywords.insert("mod", token.MOD);
|
||||
keywords.insert("use", token.USE);
|
||||
@@ -191,6 +190,16 @@ fn new_reader(stdio_reader rdr, str filename) -> reader
|
||||
keywords.insert("f32", token.MACH(common.ty_f32));
|
||||
keywords.insert("f64", token.MACH(common.ty_f64));
|
||||
|
||||
auto reserved = new_str_hash[()]();
|
||||
|
||||
reserved.insert("f16", ()); // IEEE 754-2008 'binary16' interchange fmt
|
||||
reserved.insert("f80", ()); // IEEE 754-1985 'extended'
|
||||
reserved.insert("f128", ()); // IEEE 754-2008 'binary128'
|
||||
reserved.insert("m32", ()); // IEEE 754-2008 'decimal32'
|
||||
reserved.insert("m64", ()); // IEEE 754-2008 'decimal64'
|
||||
reserved.insert("m128", ()); // IEEE 754-2008 'decimal128'
|
||||
reserved.insert("dec", ()); // One of m32, m64, m128
|
||||
|
||||
ret reader(rdr, filename, rdr.getc() as char, rdr.getc() as char,
|
||||
1u, 0u, 1u, 0u, keywords, reserved);
|
||||
}
|
||||
@@ -425,6 +434,12 @@ impure fn next_token(reader rdr) -> token.token {
|
||||
ret kwds.get(accum_str);
|
||||
}
|
||||
|
||||
auto rsvd = rdr.get_reserved();
|
||||
if (rsvd.contains_key(accum_str)) {
|
||||
log "reserved keyword";
|
||||
fail;
|
||||
}
|
||||
|
||||
ret token.IDENT(accum_str);
|
||||
}
|
||||
|
||||
@@ -650,12 +665,9 @@ impure fn next_token(reader rdr) -> token.token {
|
||||
case ('%') {
|
||||
ret binop(rdr, token.PERCENT);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
log "lexer stopping at ";
|
||||
log c;
|
||||
ret token.EOF;
|
||||
fail;
|
||||
}
|
||||
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
87
src/comp/front/pretty.rs
Normal file
87
src/comp/front/pretty.rs
Normal file
@@ -0,0 +1,87 @@
|
||||
import std._int;
|
||||
import std._str;
|
||||
import std._uint;
|
||||
import std._vec;
|
||||
|
||||
export print_expr;
|
||||
|
||||
// FIXME this is superseded by ../pretty/pprust.rs. can it be dropped?
|
||||
|
||||
fn unknown() -> str {
|
||||
ret "<unknown ast node>";
|
||||
}
|
||||
|
||||
fn print_expr(@ast.expr expr) -> str {
|
||||
alt (expr.node) {
|
||||
case (ast.expr_lit(?lit, _)) {
|
||||
ret print_lit(lit);
|
||||
}
|
||||
case (ast.expr_binary(?op, ?lhs, ?rhs, _)) {
|
||||
ret print_expr_binary(op, lhs, rhs);
|
||||
}
|
||||
case (ast.expr_call(?path, ?args, _)) {
|
||||
ret print_expr_call(path, args);
|
||||
}
|
||||
case (ast.expr_path(?path, _, _)) {
|
||||
ret print_path(path);
|
||||
}
|
||||
case (_) {
|
||||
ret unknown();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn print_lit(@ast.lit lit) -> str {
|
||||
alt (lit.node) {
|
||||
case (ast.lit_str(?s)) {
|
||||
ret "\"" + s + "\"";
|
||||
}
|
||||
case (ast.lit_int(?i)) {
|
||||
ret _int.to_str(i, 10u);
|
||||
}
|
||||
case (ast.lit_uint(?u)) {
|
||||
ret _uint.to_str(u, 10u);
|
||||
}
|
||||
case (_) {
|
||||
ret unknown();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn print_expr_binary(ast.binop op, @ast.expr lhs, @ast.expr rhs) -> str {
|
||||
alt (op) {
|
||||
case (ast.add) {
|
||||
auto l = print_expr(lhs);
|
||||
auto r = print_expr(rhs);
|
||||
ret l + " + " + r;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn print_expr_call(@ast.expr path_expr, vec[@ast.expr] args) -> str {
|
||||
auto s = print_expr(path_expr);
|
||||
|
||||
s += "(";
|
||||
fn print_expr_ref(&@ast.expr e) -> str { ret print_expr(e); }
|
||||
auto mapfn = print_expr_ref;
|
||||
auto argstrs = _vec.map[@ast.expr, str](mapfn, args);
|
||||
s += _str.connect(argstrs, ", ");
|
||||
s += ")";
|
||||
|
||||
ret s;
|
||||
}
|
||||
|
||||
fn print_path(ast.path path) -> str {
|
||||
ret _str.connect(path.node.idents, ".");
|
||||
}
|
||||
|
||||
//
|
||||
// Local Variables:
|
||||
// mode: rust
|
||||
// fill-column: 78;
|
||||
// indent-tabs-mode: nil
|
||||
// c-basic-offset: 4
|
||||
// buffer-file-coding-system: utf-8-unix
|
||||
// compile-command: "make -k -C ../.. 2>&1 | sed -e 's/\\/x\\//x:\\//g'";
|
||||
// End:
|
||||
//
|
||||
@@ -76,6 +76,25 @@ const uint LLVMIntSLT = 40u;
|
||||
const uint LLVMIntSLE = 41u;
|
||||
|
||||
|
||||
// Consts for the LLVM RealPredicate type, pre-case to uint.
|
||||
// FIXME: as above.
|
||||
|
||||
const uint LLVMRealOEQ = 1u;
|
||||
const uint LLVMRealOGT = 2u;
|
||||
const uint LLVMRealOGE = 3u;
|
||||
const uint LLVMRealOLT = 4u;
|
||||
const uint LLVMRealOLE = 5u;
|
||||
const uint LLVMRealONE = 6u;
|
||||
|
||||
const uint LLVMRealORD = 7u;
|
||||
const uint LLVMRealUNO = 8u;
|
||||
const uint LLVMRealUEQ = 9u;
|
||||
const uint LLVMRealUGT = 10u;
|
||||
const uint LLVMRealUGE = 11u;
|
||||
const uint LLVMRealULT = 12u;
|
||||
const uint LLVMRealULE = 13u;
|
||||
const uint LLVMRealUNE = 14u;
|
||||
|
||||
native mod llvm = llvm_lib {
|
||||
|
||||
type ModuleRef;
|
||||
@@ -657,7 +676,7 @@ native mod llvm = llvm_lib {
|
||||
fn LLVMBuildICmp(BuilderRef B, uint Op,
|
||||
ValueRef LHS, ValueRef RHS,
|
||||
sbuf Name) -> ValueRef;
|
||||
fn LLVMBuildFCmp(BuilderRef B, RealPredicate Op,
|
||||
fn LLVMBuildFCmp(BuilderRef B, uint Op,
|
||||
ValueRef LHS, ValueRef RHS,
|
||||
sbuf Name) -> ValueRef;
|
||||
|
||||
@@ -1034,7 +1053,7 @@ obj builder(BuilderRef B) {
|
||||
ret llvm.LLVMBuildICmp(B, Op, LHS, RHS, _str.buf(""));
|
||||
}
|
||||
|
||||
fn FCmp(RealPredicate Op, ValueRef LHS, ValueRef RHS) -> ValueRef {
|
||||
fn FCmp(uint Op, ValueRef LHS, ValueRef RHS) -> ValueRef {
|
||||
ret llvm.LLVMBuildFCmp(B, Op, LHS, RHS, _str.buf(""));
|
||||
}
|
||||
|
||||
@@ -1151,18 +1170,70 @@ fn mk_type_handle() -> type_handle {
|
||||
ret rec(llth=th, dtor=type_handle_dtor(th));
|
||||
}
|
||||
|
||||
fn type_to_str(TypeRef ty) -> str {
|
||||
let vec[TypeRef] v = vec();
|
||||
ret type_to_str_inner(v, ty);
|
||||
|
||||
state obj type_names(std.map.hashmap[TypeRef, str] type_names,
|
||||
std.map.hashmap[str, TypeRef] named_types) {
|
||||
|
||||
fn associate(str s, TypeRef t) {
|
||||
check (!named_types.contains_key(s));
|
||||
check (!type_names.contains_key(t));
|
||||
type_names.insert(t, s);
|
||||
named_types.insert(s, t);
|
||||
}
|
||||
|
||||
fn type_has_name(TypeRef t) -> bool {
|
||||
ret type_names.contains_key(t);
|
||||
}
|
||||
|
||||
fn get_name(TypeRef t) -> str {
|
||||
ret type_names.get(t);
|
||||
}
|
||||
|
||||
fn name_has_type(str s) -> bool {
|
||||
ret named_types.contains_key(s);
|
||||
}
|
||||
|
||||
fn get_type(str s) -> TypeRef {
|
||||
ret named_types.get(s);
|
||||
}
|
||||
}
|
||||
|
||||
fn type_to_str_inner(vec[TypeRef] outer0, TypeRef ty) -> str {
|
||||
fn mk_type_names() -> type_names {
|
||||
auto nt = util.common.new_str_hash[TypeRef]();
|
||||
|
||||
fn hash(&TypeRef t) -> uint {
|
||||
ret t as uint;
|
||||
}
|
||||
|
||||
fn eq(&TypeRef a, &TypeRef b) -> bool {
|
||||
ret (a as uint) == (b as uint);
|
||||
}
|
||||
|
||||
let std.map.hashfn[TypeRef] hasher = hash;
|
||||
let std.map.eqfn[TypeRef] eqer = eq;
|
||||
auto tn = std.map.mk_hashmap[TypeRef,str](hasher, eqer);
|
||||
|
||||
ret type_names(tn, nt);
|
||||
}
|
||||
|
||||
fn type_to_str(type_names names, TypeRef ty) -> str {
|
||||
let vec[TypeRef] v = vec();
|
||||
ret type_to_str_inner(names, v, ty);
|
||||
}
|
||||
|
||||
fn type_to_str_inner(type_names names,
|
||||
vec[TypeRef] outer0, TypeRef ty) -> str {
|
||||
|
||||
if (names.type_has_name(ty)) {
|
||||
ret names.get_name(ty);
|
||||
}
|
||||
|
||||
auto outer = outer0 + vec(ty);
|
||||
|
||||
let int kind = llvm.LLVMGetTypeKind(ty);
|
||||
|
||||
fn tys_str(vec[TypeRef] outer, vec[TypeRef] tys) -> str {
|
||||
fn tys_str(type_names names,
|
||||
vec[TypeRef] outer, vec[TypeRef] tys) -> str {
|
||||
let str s = "";
|
||||
let bool first = true;
|
||||
for (TypeRef t in tys) {
|
||||
@@ -1171,7 +1242,7 @@ fn type_to_str_inner(vec[TypeRef] outer0, TypeRef ty) -> str {
|
||||
} else {
|
||||
s += ", ";
|
||||
}
|
||||
s += type_to_str_inner(outer, t);
|
||||
s += type_to_str_inner(names, outer, t);
|
||||
}
|
||||
ret s;
|
||||
}
|
||||
@@ -1200,9 +1271,9 @@ fn type_to_str_inner(vec[TypeRef] outer0, TypeRef ty) -> str {
|
||||
let vec[TypeRef] args =
|
||||
_vec.init_elt[TypeRef](0 as TypeRef, n_args);
|
||||
llvm.LLVMGetParamTypes(ty, _vec.buf[TypeRef](args));
|
||||
s += tys_str(outer, args);
|
||||
s += tys_str(names, outer, args);
|
||||
s += ") -> ";
|
||||
s += type_to_str_inner(outer, out_ty);
|
||||
s += type_to_str_inner(names, outer, out_ty);
|
||||
ret s;
|
||||
}
|
||||
|
||||
@@ -1212,7 +1283,7 @@ fn type_to_str_inner(vec[TypeRef] outer0, TypeRef ty) -> str {
|
||||
let vec[TypeRef] elts =
|
||||
_vec.init_elt[TypeRef](0 as TypeRef, n_elts);
|
||||
llvm.LLVMGetStructElementTypes(ty, _vec.buf[TypeRef](elts));
|
||||
s += tys_str(outer, elts);
|
||||
s += tys_str(names, outer, elts);
|
||||
s += "}";
|
||||
ret s;
|
||||
}
|
||||
@@ -1228,7 +1299,8 @@ fn type_to_str_inner(vec[TypeRef] outer0, TypeRef ty) -> str {
|
||||
ret "*\\" + util.common.istr(n as int);
|
||||
}
|
||||
}
|
||||
ret "*" + type_to_str_inner(outer, llvm.LLVMGetElementType(ty));
|
||||
ret "*" + type_to_str_inner(names, outer,
|
||||
llvm.LLVMGetElementType(ty));
|
||||
}
|
||||
|
||||
case (12) { ret "Opaque"; }
|
||||
|
||||
@@ -10,6 +10,7 @@ import util.common.ty_mach;
|
||||
import util.common.append;
|
||||
|
||||
import front.ast;
|
||||
import front.ast.fn_decl;
|
||||
import front.ast.ident;
|
||||
import front.ast.path;
|
||||
import front.ast.mutability;
|
||||
@@ -20,6 +21,7 @@ import front.ast.block;
|
||||
import front.ast.item;
|
||||
import front.ast.view_item;
|
||||
import front.ast.meta_item;
|
||||
import front.ast.native_item;
|
||||
import front.ast.arg;
|
||||
import front.ast.pat;
|
||||
import front.ast.decl;
|
||||
@@ -28,6 +30,7 @@ import front.ast.def;
|
||||
import front.ast.def_id;
|
||||
import front.ast.ann;
|
||||
|
||||
import std._uint;
|
||||
import std._vec;
|
||||
|
||||
type ast_fold[ENV] =
|
||||
@@ -56,6 +59,7 @@ type ast_fold[ENV] =
|
||||
vec[ast.ty_method] meths) -> @ty) fold_ty_obj,
|
||||
|
||||
(fn(&ENV e, &span sp,
|
||||
ast.proto proto,
|
||||
vec[rec(ast.mode mode, @ty ty)] inputs,
|
||||
@ty output) -> @ty) fold_ty_fn,
|
||||
|
||||
@@ -72,7 +76,8 @@ type ast_fold[ENV] =
|
||||
vec[ast.elt] es, ann a) -> @expr) fold_expr_tup,
|
||||
|
||||
(fn(&ENV e, &span sp,
|
||||
vec[ast.field] fields, ann a) -> @expr) fold_expr_rec,
|
||||
vec[ast.field] fields,
|
||||
option.t[@expr] base, ann a) -> @expr) fold_expr_rec,
|
||||
|
||||
(fn(&ENV e, &span sp,
|
||||
@expr f, vec[@expr] args,
|
||||
@@ -107,6 +112,10 @@ type ast_fold[ENV] =
|
||||
@decl decl, @expr seq, &block body,
|
||||
ann a) -> @expr) fold_expr_for,
|
||||
|
||||
(fn(&ENV e, &span sp,
|
||||
@decl decl, @expr seq, &block body,
|
||||
ann a) -> @expr) fold_expr_for_each,
|
||||
|
||||
(fn(&ENV e, &span sp,
|
||||
@expr cond, &block body,
|
||||
ann a) -> @expr) fold_expr_while,
|
||||
@@ -144,6 +153,29 @@ type ast_fold[ENV] =
|
||||
&option.t[def] d,
|
||||
ann a) -> @expr) fold_expr_path,
|
||||
|
||||
(fn(&ENV e, &span sp,
|
||||
&path p, vec[@expr] args,
|
||||
option.t[@expr] body,
|
||||
@expr expanded,
|
||||
ann a) -> @expr) fold_expr_ext,
|
||||
|
||||
(fn(&ENV e, &span sp) -> @expr) fold_expr_fail,
|
||||
|
||||
(fn(&ENV e, &span sp,
|
||||
&option.t[@expr] rv) -> @expr) fold_expr_ret,
|
||||
|
||||
(fn(&ENV e, &span sp,
|
||||
&option.t[@expr] rv) -> @expr) fold_expr_put,
|
||||
|
||||
(fn(&ENV e, &span sp,
|
||||
@expr e) -> @expr) fold_expr_be,
|
||||
|
||||
(fn(&ENV e, &span sp,
|
||||
@expr e) -> @expr) fold_expr_log,
|
||||
|
||||
(fn(&ENV e, &span sp,
|
||||
@expr e) -> @expr) fold_expr_check_expr,
|
||||
|
||||
// Decl folds.
|
||||
(fn(&ENV e, &span sp,
|
||||
@ast.local local) -> @decl) fold_decl_local,
|
||||
@@ -156,6 +188,9 @@ type ast_fold[ENV] =
|
||||
(fn(&ENV e, &span sp,
|
||||
ann a) -> @pat) fold_pat_wild,
|
||||
|
||||
(fn(&ENV e, &span sp,
|
||||
@ast.lit lit, ann a) -> @pat) fold_pat_lit,
|
||||
|
||||
(fn(&ENV e, &span sp,
|
||||
ident i, def_id did, ann a) -> @pat) fold_pat_bind,
|
||||
|
||||
@@ -169,15 +204,6 @@ type ast_fold[ENV] =
|
||||
(fn(&ENV e, &span sp,
|
||||
@decl decl) -> @stmt) fold_stmt_decl,
|
||||
|
||||
(fn(&ENV e, &span sp,
|
||||
&option.t[@expr] rv) -> @stmt) fold_stmt_ret,
|
||||
|
||||
(fn(&ENV e, &span sp,
|
||||
@expr e) -> @stmt) fold_stmt_log,
|
||||
|
||||
(fn(&ENV e, &span sp,
|
||||
@expr e) -> @stmt) fold_stmt_check_expr,
|
||||
|
||||
(fn(&ENV e, &span sp,
|
||||
@expr e) -> @stmt) fold_stmt_expr,
|
||||
|
||||
@@ -191,13 +217,24 @@ type ast_fold[ENV] =
|
||||
vec[ast.ty_param] ty_params,
|
||||
def_id id, ann a) -> @item) fold_item_fn,
|
||||
|
||||
(fn(&ENV e, &span sp, ident ident,
|
||||
&ast.fn_decl decl,
|
||||
vec[ast.ty_param] ty_params,
|
||||
def_id id, ann a) -> @native_item) fold_native_item_fn,
|
||||
|
||||
(fn(&ENV e, &span sp, ident ident,
|
||||
&ast._mod m, def_id id) -> @item) fold_item_mod,
|
||||
|
||||
(fn(&ENV e, &span sp, ident ident,
|
||||
&ast.native_mod m, def_id id) -> @item) fold_item_native_mod,
|
||||
|
||||
(fn(&ENV e, &span sp, ident ident,
|
||||
@ty t, vec[ast.ty_param] ty_params,
|
||||
def_id id, ann a) -> @item) fold_item_ty,
|
||||
|
||||
(fn(&ENV e, &span sp, ident ident,
|
||||
def_id id) -> @native_item) fold_native_item_ty,
|
||||
|
||||
(fn(&ENV e, &span sp, ident ident,
|
||||
vec[ast.variant] variants,
|
||||
vec[ast.ty_param] ty_params,
|
||||
@@ -220,23 +257,30 @@ type ast_fold[ENV] =
|
||||
(fn(&ENV e, &span sp,
|
||||
&ast.block_) -> block) fold_block,
|
||||
|
||||
(fn(&ENV e, &fn_decl decl,
|
||||
ast.proto proto,
|
||||
&block body) -> ast._fn) fold_fn,
|
||||
|
||||
(fn(&ENV e, ast.effect effect,
|
||||
bool is_iter,
|
||||
vec[arg] inputs,
|
||||
@ty output, &block body) -> ast._fn) fold_fn,
|
||||
@ty output) -> ast.fn_decl) fold_fn_decl,
|
||||
|
||||
(fn(&ENV e, &ast._mod m) -> ast._mod) fold_mod,
|
||||
|
||||
(fn(&ENV e, &ast.native_mod m) -> ast.native_mod) fold_native_mod,
|
||||
|
||||
(fn(&ENV e, &span sp,
|
||||
&ast._mod m) -> @ast.crate) fold_crate,
|
||||
|
||||
(fn(&ENV e,
|
||||
vec[ast.obj_field] fields,
|
||||
vec[@ast.method] methods) -> ast._obj) fold_obj,
|
||||
vec[@ast.method] methods,
|
||||
option.t[block] dtor) -> ast._obj) fold_obj,
|
||||
|
||||
// Env updates.
|
||||
(fn(&ENV e, @ast.crate c) -> ENV) update_env_for_crate,
|
||||
(fn(&ENV e, @item i) -> ENV) update_env_for_item,
|
||||
(fn(&ENV e, @native_item i) -> ENV) update_env_for_native_item,
|
||||
(fn(&ENV e, @view_item i) -> ENV) update_env_for_view_item,
|
||||
(fn(&ENV e, &block b) -> ENV) update_env_for_block,
|
||||
(fn(&ENV e, @stmt s) -> ENV) update_env_for_stmt,
|
||||
@@ -312,11 +356,13 @@ fn fold_ty[ENV](&ENV env, ast_fold[ENV] fld, @ty t) -> @ty {
|
||||
case (ast.ty_obj(?meths)) {
|
||||
let vec[ast.ty_method] meths_ = vec();
|
||||
for (ast.ty_method m in meths) {
|
||||
auto tfn = fold_ty_fn(env_, fld, t.span, m.inputs, m.output);
|
||||
auto tfn = fold_ty_fn(env_, fld, t.span, m.proto,
|
||||
m.inputs, m.output);
|
||||
alt (tfn.node) {
|
||||
case (ast.ty_fn(?ins, ?out)) {
|
||||
case (ast.ty_fn(?p, ?ins, ?out)) {
|
||||
append[ast.ty_method]
|
||||
(meths_, rec(inputs=ins, output=out with m));
|
||||
(meths_, rec(proto=p, inputs=ins, output=out
|
||||
with m));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -333,13 +379,14 @@ fn fold_ty[ENV](&ENV env, ast_fold[ENV] fld, @ty t) -> @ty {
|
||||
ret fld.fold_ty_mutable(env_, t.span, ty_);
|
||||
}
|
||||
|
||||
case (ast.ty_fn(?inputs, ?output)) {
|
||||
ret fold_ty_fn(env_, fld, t.span, inputs, output);
|
||||
case (ast.ty_fn(?proto, ?inputs, ?output)) {
|
||||
ret fold_ty_fn(env_, fld, t.span, proto, inputs, output);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn fold_ty_fn[ENV](&ENV env, ast_fold[ENV] fld, &span sp,
|
||||
ast.proto proto,
|
||||
vec[rec(ast.mode mode, @ty ty)] inputs,
|
||||
@ty output) -> @ty {
|
||||
auto output_ = fold_ty(env, fld, output);
|
||||
@@ -349,7 +396,7 @@ fn fold_ty_fn[ENV](&ENV env, ast_fold[ENV] fld, &span sp,
|
||||
auto input_ = rec(ty=ty_ with input);
|
||||
inputs_ += vec(input_);
|
||||
}
|
||||
ret fld.fold_ty_fn(env, sp, inputs_, output_);
|
||||
ret fld.fold_ty_fn(env, sp, proto, inputs_, output_);
|
||||
}
|
||||
|
||||
fn fold_decl[ENV](&ENV env, ast_fold[ENV] fld, @decl d) -> @decl {
|
||||
@@ -397,6 +444,9 @@ fn fold_pat[ENV](&ENV env, ast_fold[ENV] fld, @ast.pat p) -> @ast.pat {
|
||||
|
||||
alt (p.node) {
|
||||
case (ast.pat_wild(?t)) { ret fld.fold_pat_wild(env_, p.span, t); }
|
||||
case (ast.pat_lit(?lt, ?t)) {
|
||||
ret fld.fold_pat_lit(env_, p.span, lt, t);
|
||||
}
|
||||
case (ast.pat_bind(?id, ?did, ?t)) {
|
||||
ret fld.fold_pat_bind(env_, p.span, id, did, t);
|
||||
}
|
||||
@@ -449,12 +499,19 @@ fn fold_expr[ENV](&ENV env, ast_fold[ENV] fld, &@expr e) -> @expr {
|
||||
ret fld.fold_expr_tup(env_, e.span, elts, t);
|
||||
}
|
||||
|
||||
case (ast.expr_rec(?fs, ?t)) {
|
||||
case (ast.expr_rec(?fs, ?base, ?t)) {
|
||||
let vec[ast.field] fields = vec();
|
||||
let option.t[@expr] b = none[@expr];
|
||||
for (ast.field f in fs) {
|
||||
fields += fold_rec_field(env, fld, f);
|
||||
}
|
||||
ret fld.fold_expr_rec(env_, e.span, fields, t);
|
||||
alt (base) {
|
||||
case (none[@ast.expr]) { }
|
||||
case (some[@ast.expr](?eb)) {
|
||||
b = some[@expr](fold_expr(env_, fld, eb));
|
||||
}
|
||||
}
|
||||
ret fld.fold_expr_rec(env_, e.span, fields, b, t);
|
||||
}
|
||||
|
||||
case (ast.expr_call(?f, ?args, ?t)) {
|
||||
@@ -521,6 +578,13 @@ fn fold_expr[ENV](&ENV env, ast_fold[ENV] fld, &@expr e) -> @expr {
|
||||
ret fld.fold_expr_for(env_, e.span, ddecl, sseq, bbody, t);
|
||||
}
|
||||
|
||||
case (ast.expr_for_each(?decl, ?seq, ?body, ?t)) {
|
||||
auto ddecl = fold_decl(env_, fld, decl);
|
||||
auto sseq = fold_expr(env_, fld, seq);
|
||||
auto bbody = fold_block(env_, fld, body);
|
||||
ret fld.fold_expr_for_each(env_, e.span, ddecl, sseq, bbody, t);
|
||||
}
|
||||
|
||||
case (ast.expr_while(?cnd, ?body, ?t)) {
|
||||
auto ccnd = fold_expr(env_, fld, cnd);
|
||||
auto bbody = fold_block(env_, fld, body);
|
||||
@@ -574,9 +638,59 @@ fn fold_expr[ENV](&ENV env, ast_fold[ENV] fld, &@expr e) -> @expr {
|
||||
auto p_ = fold_path(env_, fld, p);
|
||||
ret fld.fold_expr_path(env_, e.span, p_, r, t);
|
||||
}
|
||||
|
||||
case (ast.expr_ext(?p, ?args, ?body, ?expanded, ?t)) {
|
||||
// Only fold the expanded expression, not the
|
||||
// expressions involved in syntax extension
|
||||
auto exp = fold_expr(env_, fld, expanded);
|
||||
ret fld.fold_expr_ext(env_, e.span, p, args, body,
|
||||
exp, t);
|
||||
}
|
||||
|
||||
ret e;
|
||||
case (ast.expr_fail) {
|
||||
ret fld.fold_expr_fail(env_, e.span);
|
||||
}
|
||||
|
||||
case (ast.expr_ret(?oe)) {
|
||||
auto oee = none[@expr];
|
||||
alt (oe) {
|
||||
case (some[@expr](?x)) {
|
||||
oee = some(fold_expr(env_, fld, x));
|
||||
}
|
||||
case (_) { /* fall through */ }
|
||||
}
|
||||
ret fld.fold_expr_ret(env_, e.span, oee);
|
||||
}
|
||||
|
||||
case (ast.expr_put(?oe)) {
|
||||
auto oee = none[@expr];
|
||||
alt (oe) {
|
||||
case (some[@expr](?x)) {
|
||||
oee = some(fold_expr(env_, fld, x));
|
||||
}
|
||||
case (_) { /* fall through */ }
|
||||
}
|
||||
ret fld.fold_expr_put(env_, e.span, oee);
|
||||
}
|
||||
|
||||
case (ast.expr_be(?x)) {
|
||||
auto ee = fold_expr(env_, fld, x);
|
||||
ret fld.fold_expr_be(env_, e.span, ee);
|
||||
}
|
||||
|
||||
case (ast.expr_log(?x)) {
|
||||
auto ee = fold_expr(env_, fld, x);
|
||||
ret fld.fold_expr_log(env_, e.span, ee);
|
||||
}
|
||||
|
||||
case (ast.expr_check_expr(?x)) {
|
||||
auto ee = fold_expr(env_, fld, x);
|
||||
ret fld.fold_expr_check_expr(env_, e.span, ee);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
fail;
|
||||
}
|
||||
|
||||
|
||||
@@ -594,37 +708,12 @@ fn fold_stmt[ENV](&ENV env, ast_fold[ENV] fld, &@stmt s) -> @stmt {
|
||||
ret fld.fold_stmt_decl(env_, s.span, dd);
|
||||
}
|
||||
|
||||
case (ast.stmt_ret(?oe)) {
|
||||
auto oee = none[@expr];
|
||||
alt (oe) {
|
||||
case (some[@expr](?e)) {
|
||||
oee = some(fold_expr(env_, fld, e));
|
||||
}
|
||||
case (_) { /* fall through */ }
|
||||
}
|
||||
ret fld.fold_stmt_ret(env_, s.span, oee);
|
||||
}
|
||||
|
||||
case (ast.stmt_log(?e)) {
|
||||
auto ee = fold_expr(env_, fld, e);
|
||||
ret fld.fold_stmt_log(env_, s.span, ee);
|
||||
}
|
||||
|
||||
case (ast.stmt_check_expr(?e)) {
|
||||
auto ee = fold_expr(env_, fld, e);
|
||||
ret fld.fold_stmt_check_expr(env_, s.span, ee);
|
||||
}
|
||||
|
||||
case (ast.stmt_fail) {
|
||||
ret s;
|
||||
}
|
||||
|
||||
case (ast.stmt_expr(?e)) {
|
||||
auto ee = fold_expr(env_, fld, e);
|
||||
ret fld.fold_stmt_expr(env_, s.span, ee);
|
||||
}
|
||||
}
|
||||
ret s;
|
||||
fail;
|
||||
}
|
||||
|
||||
fn fold_block[ENV](&ENV env, ast_fold[ENV] fld, &block blk) -> block {
|
||||
@@ -666,17 +755,22 @@ fn fold_arg[ENV](&ENV env, ast_fold[ENV] fld, &arg a) -> arg {
|
||||
ret rec(ty=ty with a);
|
||||
}
|
||||
|
||||
|
||||
fn fold_fn[ENV](&ENV env, ast_fold[ENV] fld, &ast._fn f) -> ast._fn {
|
||||
|
||||
fn fold_fn_decl[ENV](&ENV env, ast_fold[ENV] fld,
|
||||
&ast.fn_decl decl) -> ast.fn_decl {
|
||||
let vec[ast.arg] inputs = vec();
|
||||
for (ast.arg a in f.inputs) {
|
||||
for (ast.arg a in decl.inputs) {
|
||||
inputs += fold_arg(env, fld, a);
|
||||
}
|
||||
auto output = fold_ty[ENV](env, fld, f.output);
|
||||
auto output = fold_ty[ENV](env, fld, decl.output);
|
||||
ret fld.fold_fn_decl(env, decl.effect, inputs, output);
|
||||
}
|
||||
|
||||
fn fold_fn[ENV](&ENV env, ast_fold[ENV] fld, &ast._fn f) -> ast._fn {
|
||||
auto decl = fold_fn_decl(env, fld, f.decl);
|
||||
|
||||
auto body = fold_block[ENV](env, fld, f.body);
|
||||
|
||||
ret fld.fold_fn(env, f.effect, f.is_iter, inputs, output, body);
|
||||
ret fld.fold_fn(env, decl, f.proto, body);
|
||||
}
|
||||
|
||||
|
||||
@@ -701,6 +795,13 @@ fn fold_obj[ENV](&ENV env, ast_fold[ENV] fld, &ast._obj ob) -> ast._obj {
|
||||
for (ast.obj_field f in ob.fields) {
|
||||
fields += fold_obj_field(env, fld, f);
|
||||
}
|
||||
let option.t[block] dtor = none[block];
|
||||
alt (ob.dtor) {
|
||||
case (none[block]) { }
|
||||
case (some[block](?b)) {
|
||||
dtor = some[block](fold_block[ENV](env, fld, b));
|
||||
}
|
||||
}
|
||||
let vec[ast.ty_param] tp = vec();
|
||||
for (@ast.method m in ob.methods) {
|
||||
// Fake-up an ast.item for this method.
|
||||
@@ -715,7 +816,7 @@ fn fold_obj[ENV](&ENV env, ast_fold[ENV] fld, &ast._obj ob) -> ast._obj {
|
||||
let ENV _env = fld.update_env_for_item(env, i);
|
||||
append[@ast.method](meths, fold_method(_env, fld, m));
|
||||
}
|
||||
ret fld.fold_obj(env, fields, meths);
|
||||
ret fld.fold_obj(env, fields, meths, dtor);
|
||||
}
|
||||
|
||||
fn fold_view_item[ENV](&ENV env, ast_fold[ENV] fld, @view_item vi)
|
||||
@@ -768,6 +869,11 @@ fn fold_item[ENV](&ENV env, ast_fold[ENV] fld, @item i) -> @item {
|
||||
ret fld.fold_item_mod(env_, i.span, ident, mm_, id);
|
||||
}
|
||||
|
||||
case (ast.item_native_mod(?ident, ?mm, ?id)) {
|
||||
let ast.native_mod mm_ = fold_native_mod[ENV](env_, fld, mm);
|
||||
ret fld.fold_item_native_mod(env_, i.span, ident, mm_, id);
|
||||
}
|
||||
|
||||
case (ast.item_ty(?ident, ?ty, ?params, ?id, ?ann)) {
|
||||
let @ast.ty ty_ = fold_ty[ENV](env_, fld, ty);
|
||||
ret fld.fold_item_ty(env_, i.span, ident, ty_, params, id, ann);
|
||||
@@ -798,7 +904,6 @@ fn fold_item[ENV](&ENV env, ast_fold[ENV] fld, @item i) -> @item {
|
||||
fail;
|
||||
}
|
||||
|
||||
|
||||
fn fold_mod[ENV](&ENV e, ast_fold[ENV] fld, &ast._mod m) -> ast._mod {
|
||||
|
||||
let vec[@view_item] view_items = vec();
|
||||
@@ -818,7 +923,50 @@ fn fold_mod[ENV](&ENV e, ast_fold[ENV] fld, &ast._mod m) -> ast._mod {
|
||||
}
|
||||
|
||||
ret fld.fold_mod(e, rec(view_items=view_items, items=items, index=index));
|
||||
}
|
||||
|
||||
fn fold_native_item[ENV](&ENV env, ast_fold[ENV] fld,
|
||||
@native_item i) -> @native_item {
|
||||
let ENV env_ = fld.update_env_for_native_item(env, i);
|
||||
|
||||
if (!fld.keep_going(env_)) {
|
||||
ret i;
|
||||
}
|
||||
alt (i.node) {
|
||||
case (ast.native_item_ty(?ident, ?id)) {
|
||||
ret fld.fold_native_item_ty(env_, i.span, ident, id);
|
||||
}
|
||||
case (ast.native_item_fn(?ident, ?fn_decl, ?ty_params, ?id, ?ann)) {
|
||||
auto d = fold_fn_decl[ENV](env_, fld, fn_decl);
|
||||
ret fld.fold_native_item_fn(env_, i.span, ident, d,
|
||||
ty_params, id, ann);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn fold_native_mod[ENV](&ENV e, ast_fold[ENV] fld,
|
||||
&ast.native_mod m) -> ast.native_mod {
|
||||
let vec[@view_item] view_items = vec();
|
||||
let vec[@native_item] items = vec();
|
||||
auto index = new_str_hash[ast.native_mod_index_entry]();
|
||||
|
||||
for (@view_item vi in m.view_items) {
|
||||
auto new_vi = fold_view_item[ENV](e, fld, vi);
|
||||
append[@view_item](view_items, new_vi);
|
||||
}
|
||||
|
||||
for (@native_item i in m.items) {
|
||||
auto new_item = fold_native_item[ENV](e, fld, i);
|
||||
append[@native_item](items, new_item);
|
||||
ast.index_native_item(index, new_item);
|
||||
}
|
||||
|
||||
ret fld.fold_native_mod(e, rec(native_name=m.native_name,
|
||||
abi=m.abi,
|
||||
view_items=view_items,
|
||||
items=items,
|
||||
index=index));
|
||||
}
|
||||
|
||||
fn fold_crate[ENV](&ENV env, ast_fold[ENV] fld, @ast.crate c) -> @ast.crate {
|
||||
let ENV env_ = fld.update_env_for_crate(env, c);
|
||||
@@ -894,9 +1042,10 @@ fn identity_fold_ty_obj[ENV](&ENV env, &span sp,
|
||||
}
|
||||
|
||||
fn identity_fold_ty_fn[ENV](&ENV env, &span sp,
|
||||
ast.proto proto,
|
||||
vec[rec(ast.mode mode, @ty ty)] inputs,
|
||||
@ty output) -> @ty {
|
||||
ret @respan(sp, ast.ty_fn(inputs, output));
|
||||
ret @respan(sp, ast.ty_fn(proto, inputs, output));
|
||||
}
|
||||
|
||||
fn identity_fold_ty_path[ENV](&ENV env, &span sp, ast.path p,
|
||||
@@ -922,8 +1071,9 @@ fn identity_fold_expr_tup[ENV](&ENV env, &span sp,
|
||||
}
|
||||
|
||||
fn identity_fold_expr_rec[ENV](&ENV env, &span sp,
|
||||
vec[ast.field] fields, ann a) -> @expr {
|
||||
ret @respan(sp, ast.expr_rec(fields, a));
|
||||
vec[ast.field] fields,
|
||||
option.t[@expr] base, ann a) -> @expr {
|
||||
ret @respan(sp, ast.expr_rec(fields, base, a));
|
||||
}
|
||||
|
||||
fn identity_fold_expr_call[ENV](&ENV env, &span sp, @expr f,
|
||||
@@ -971,6 +1121,12 @@ fn identity_fold_expr_for[ENV](&ENV env, &span sp,
|
||||
ret @respan(sp, ast.expr_for(d, seq, body, a));
|
||||
}
|
||||
|
||||
fn identity_fold_expr_for_each[ENV](&ENV env, &span sp,
|
||||
@decl d, @expr seq,
|
||||
&block body, ann a) -> @expr {
|
||||
ret @respan(sp, ast.expr_for_each(d, seq, body, a));
|
||||
}
|
||||
|
||||
fn identity_fold_expr_while[ENV](&ENV env, &span sp,
|
||||
@expr cond, &block body, ann a) -> @expr {
|
||||
ret @respan(sp, ast.expr_while(cond, body, a));
|
||||
@@ -1019,6 +1175,40 @@ fn identity_fold_expr_path[ENV](&ENV env, &span sp,
|
||||
ret @respan(sp, ast.expr_path(p, d, a));
|
||||
}
|
||||
|
||||
fn identity_fold_expr_ext[ENV](&ENV env, &span sp,
|
||||
&path p, vec[@expr] args,
|
||||
option.t[@expr] body,
|
||||
@expr expanded,
|
||||
ann a) -> @expr {
|
||||
ret @respan(sp, ast.expr_ext(p, args, body, expanded, a));
|
||||
}
|
||||
|
||||
fn identity_fold_expr_fail[ENV](&ENV env, &span sp) -> @expr {
|
||||
ret @respan(sp, ast.expr_fail);
|
||||
}
|
||||
|
||||
fn identity_fold_expr_ret[ENV](&ENV env, &span sp,
|
||||
&option.t[@expr] rv) -> @expr {
|
||||
ret @respan(sp, ast.expr_ret(rv));
|
||||
}
|
||||
|
||||
fn identity_fold_expr_put[ENV](&ENV env, &span sp,
|
||||
&option.t[@expr] rv) -> @expr {
|
||||
ret @respan(sp, ast.expr_put(rv));
|
||||
}
|
||||
|
||||
fn identity_fold_expr_be[ENV](&ENV env, &span sp, @expr x) -> @expr {
|
||||
ret @respan(sp, ast.expr_be(x));
|
||||
}
|
||||
|
||||
fn identity_fold_expr_log[ENV](&ENV e, &span sp, @expr x) -> @expr {
|
||||
ret @respan(sp, ast.expr_log(x));
|
||||
}
|
||||
|
||||
fn identity_fold_expr_check_expr[ENV](&ENV e, &span sp, @expr x) -> @expr {
|
||||
ret @respan(sp, ast.expr_check_expr(x));
|
||||
}
|
||||
|
||||
|
||||
// Decl identities.
|
||||
|
||||
@@ -1038,6 +1228,10 @@ fn identity_fold_pat_wild[ENV](&ENV e, &span sp, ann a) -> @pat {
|
||||
ret @respan(sp, ast.pat_wild(a));
|
||||
}
|
||||
|
||||
fn identity_fold_pat_lit[ENV](&ENV e, &span sp, @ast.lit lit, ann a) -> @pat {
|
||||
ret @respan(sp, ast.pat_lit(lit, a));
|
||||
}
|
||||
|
||||
fn identity_fold_pat_bind[ENV](&ENV e, &span sp, ident i, def_id did, ann a)
|
||||
-> @pat {
|
||||
ret @respan(sp, ast.pat_bind(i, did, a));
|
||||
@@ -1055,19 +1249,6 @@ fn identity_fold_stmt_decl[ENV](&ENV env, &span sp, @decl d) -> @stmt {
|
||||
ret @respan(sp, ast.stmt_decl(d));
|
||||
}
|
||||
|
||||
fn identity_fold_stmt_ret[ENV](&ENV env, &span sp,
|
||||
&option.t[@expr] rv) -> @stmt {
|
||||
ret @respan(sp, ast.stmt_ret(rv));
|
||||
}
|
||||
|
||||
fn identity_fold_stmt_log[ENV](&ENV e, &span sp, @expr x) -> @stmt {
|
||||
ret @respan(sp, ast.stmt_log(x));
|
||||
}
|
||||
|
||||
fn identity_fold_stmt_check_expr[ENV](&ENV e, &span sp, @expr x) -> @stmt {
|
||||
ret @respan(sp, ast.stmt_check_expr(x));
|
||||
}
|
||||
|
||||
fn identity_fold_stmt_expr[ENV](&ENV e, &span sp, @expr x) -> @stmt {
|
||||
ret @respan(sp, ast.stmt_expr(x));
|
||||
}
|
||||
@@ -1087,17 +1268,34 @@ fn identity_fold_item_fn[ENV](&ENV e, &span sp, ident i,
|
||||
ret @respan(sp, ast.item_fn(i, f, ty_params, id, a));
|
||||
}
|
||||
|
||||
fn identity_fold_native_item_fn[ENV](&ENV e, &span sp, ident i,
|
||||
&ast.fn_decl decl,
|
||||
vec[ast.ty_param] ty_params,
|
||||
def_id id, ann a) -> @native_item {
|
||||
ret @respan(sp, ast.native_item_fn(i, decl, ty_params, id, a));
|
||||
}
|
||||
|
||||
fn identity_fold_item_mod[ENV](&ENV e, &span sp, ident i,
|
||||
&ast._mod m, def_id id) -> @item {
|
||||
ret @respan(sp, ast.item_mod(i, m, id));
|
||||
}
|
||||
|
||||
fn identity_fold_item_native_mod[ENV](&ENV e, &span sp, ident i,
|
||||
&ast.native_mod m, def_id id) -> @item {
|
||||
ret @respan(sp, ast.item_native_mod(i, m, id));
|
||||
}
|
||||
|
||||
fn identity_fold_item_ty[ENV](&ENV e, &span sp, ident i,
|
||||
@ty t, vec[ast.ty_param] ty_params,
|
||||
def_id id, ann a) -> @item {
|
||||
ret @respan(sp, ast.item_ty(i, t, ty_params, id, a));
|
||||
}
|
||||
|
||||
fn identity_fold_native_item_ty[ENV](&ENV e, &span sp, ident i,
|
||||
def_id id) -> @native_item {
|
||||
ret @respan(sp, ast.native_item_ty(i, id));
|
||||
}
|
||||
|
||||
fn identity_fold_item_tag[ENV](&ENV e, &span sp, ident i,
|
||||
vec[ast.variant] variants,
|
||||
vec[ast.ty_param] ty_params,
|
||||
@@ -1132,28 +1330,38 @@ fn identity_fold_block[ENV](&ENV e, &span sp, &ast.block_ blk) -> block {
|
||||
ret respan(sp, blk);
|
||||
}
|
||||
|
||||
fn identity_fold_fn[ENV](&ENV e,
|
||||
fn identity_fold_fn_decl[ENV](&ENV e,
|
||||
ast.effect effect,
|
||||
bool is_iter,
|
||||
vec[arg] inputs,
|
||||
@ast.ty output,
|
||||
@ty output) -> ast.fn_decl {
|
||||
ret rec(effect=effect, inputs=inputs, output=output);
|
||||
}
|
||||
|
||||
fn identity_fold_fn[ENV](&ENV e,
|
||||
&fn_decl decl,
|
||||
ast.proto proto,
|
||||
&block body) -> ast._fn {
|
||||
ret rec(effect=effect, is_iter=is_iter, inputs=inputs,
|
||||
output=output, body=body);
|
||||
ret rec(decl=decl, proto=proto, body=body);
|
||||
}
|
||||
|
||||
fn identity_fold_mod[ENV](&ENV e, &ast._mod m) -> ast._mod {
|
||||
ret m;
|
||||
}
|
||||
|
||||
fn identity_fold_native_mod[ENV](&ENV e,
|
||||
&ast.native_mod m) -> ast.native_mod {
|
||||
ret m;
|
||||
}
|
||||
|
||||
fn identity_fold_crate[ENV](&ENV e, &span sp, &ast._mod m) -> @ast.crate {
|
||||
ret @respan(sp, rec(module=m));
|
||||
}
|
||||
|
||||
fn identity_fold_obj[ENV](&ENV e,
|
||||
vec[ast.obj_field] fields,
|
||||
vec[@ast.method] methods) -> ast._obj {
|
||||
ret rec(fields=fields, methods=methods);
|
||||
vec[@ast.method] methods,
|
||||
option.t[block] dtor) -> ast._obj {
|
||||
ret rec(fields=fields, methods=methods, dtor=dtor);
|
||||
}
|
||||
|
||||
|
||||
@@ -1167,6 +1375,10 @@ fn identity_update_env_for_item[ENV](&ENV e, @item i) -> ENV {
|
||||
ret e;
|
||||
}
|
||||
|
||||
fn identity_update_env_for_native_item[ENV](&ENV e, @native_item i) -> ENV {
|
||||
ret e;
|
||||
}
|
||||
|
||||
fn identity_update_env_for_view_item[ENV](&ENV e, @view_item i) -> ENV {
|
||||
ret e;
|
||||
}
|
||||
@@ -1224,13 +1436,13 @@ fn new_identity_fold[ENV]() -> ast_fold[ENV] {
|
||||
fold_ty_tup = bind identity_fold_ty_tup[ENV](_,_,_),
|
||||
fold_ty_rec = bind identity_fold_ty_rec[ENV](_,_,_),
|
||||
fold_ty_obj = bind identity_fold_ty_obj[ENV](_,_,_),
|
||||
fold_ty_fn = bind identity_fold_ty_fn[ENV](_,_,_,_),
|
||||
fold_ty_fn = bind identity_fold_ty_fn[ENV](_,_,_,_,_),
|
||||
fold_ty_path = bind identity_fold_ty_path[ENV](_,_,_,_),
|
||||
fold_ty_mutable = bind identity_fold_ty_mutable[ENV](_,_,_),
|
||||
|
||||
fold_expr_vec = bind identity_fold_expr_vec[ENV](_,_,_,_),
|
||||
fold_expr_tup = bind identity_fold_expr_tup[ENV](_,_,_,_),
|
||||
fold_expr_rec = bind identity_fold_expr_rec[ENV](_,_,_,_),
|
||||
fold_expr_rec = bind identity_fold_expr_rec[ENV](_,_,_,_,_),
|
||||
fold_expr_call = bind identity_fold_expr_call[ENV](_,_,_,_,_),
|
||||
fold_expr_bind = bind identity_fold_expr_bind[ENV](_,_,_,_,_),
|
||||
fold_expr_binary = bind identity_fold_expr_binary[ENV](_,_,_,_,_,_),
|
||||
@@ -1239,6 +1451,8 @@ fn new_identity_fold[ENV]() -> ast_fold[ENV] {
|
||||
fold_expr_cast = bind identity_fold_expr_cast[ENV](_,_,_,_,_),
|
||||
fold_expr_if = bind identity_fold_expr_if[ENV](_,_,_,_,_,_),
|
||||
fold_expr_for = bind identity_fold_expr_for[ENV](_,_,_,_,_,_),
|
||||
fold_expr_for_each
|
||||
= bind identity_fold_expr_for_each[ENV](_,_,_,_,_,_),
|
||||
fold_expr_while = bind identity_fold_expr_while[ENV](_,_,_,_,_),
|
||||
fold_expr_do_while
|
||||
= bind identity_fold_expr_do_while[ENV](_,_,_,_,_),
|
||||
@@ -1250,25 +1464,36 @@ fn new_identity_fold[ENV]() -> ast_fold[ENV] {
|
||||
fold_expr_field = bind identity_fold_expr_field[ENV](_,_,_,_,_),
|
||||
fold_expr_index = bind identity_fold_expr_index[ENV](_,_,_,_,_),
|
||||
fold_expr_path = bind identity_fold_expr_path[ENV](_,_,_,_,_),
|
||||
fold_expr_ext = bind identity_fold_expr_ext[ENV](_,_,_,_,_,_,_),
|
||||
fold_expr_fail = bind identity_fold_expr_fail[ENV](_,_),
|
||||
fold_expr_ret = bind identity_fold_expr_ret[ENV](_,_,_),
|
||||
fold_expr_put = bind identity_fold_expr_put[ENV](_,_,_),
|
||||
fold_expr_be = bind identity_fold_expr_be[ENV](_,_,_),
|
||||
fold_expr_log = bind identity_fold_expr_log[ENV](_,_,_),
|
||||
fold_expr_check_expr
|
||||
= bind identity_fold_expr_check_expr[ENV](_,_,_),
|
||||
|
||||
fold_decl_local = bind identity_fold_decl_local[ENV](_,_,_),
|
||||
fold_decl_item = bind identity_fold_decl_item[ENV](_,_,_),
|
||||
|
||||
fold_pat_wild = bind identity_fold_pat_wild[ENV](_,_,_),
|
||||
fold_pat_lit = bind identity_fold_pat_lit[ENV](_,_,_,_),
|
||||
fold_pat_bind = bind identity_fold_pat_bind[ENV](_,_,_,_,_),
|
||||
fold_pat_tag = bind identity_fold_pat_tag[ENV](_,_,_,_,_,_),
|
||||
|
||||
fold_stmt_decl = bind identity_fold_stmt_decl[ENV](_,_,_),
|
||||
fold_stmt_ret = bind identity_fold_stmt_ret[ENV](_,_,_),
|
||||
fold_stmt_log = bind identity_fold_stmt_log[ENV](_,_,_),
|
||||
fold_stmt_check_expr
|
||||
= bind identity_fold_stmt_check_expr[ENV](_,_,_),
|
||||
fold_stmt_expr = bind identity_fold_stmt_expr[ENV](_,_,_),
|
||||
|
||||
fold_item_const= bind identity_fold_item_const[ENV](_,_,_,_,_,_,_),
|
||||
fold_item_fn = bind identity_fold_item_fn[ENV](_,_,_,_,_,_,_),
|
||||
fold_native_item_fn =
|
||||
bind identity_fold_native_item_fn[ENV](_,_,_,_,_,_,_),
|
||||
fold_item_mod = bind identity_fold_item_mod[ENV](_,_,_,_,_),
|
||||
fold_item_native_mod =
|
||||
bind identity_fold_item_native_mod[ENV](_,_,_,_,_),
|
||||
fold_item_ty = bind identity_fold_item_ty[ENV](_,_,_,_,_,_,_),
|
||||
fold_native_item_ty =
|
||||
bind identity_fold_native_item_ty[ENV](_,_,_,_),
|
||||
fold_item_tag = bind identity_fold_item_tag[ENV](_,_,_,_,_,_),
|
||||
fold_item_obj = bind identity_fold_item_obj[ENV](_,_,_,_,_,_,_),
|
||||
|
||||
@@ -1278,13 +1503,17 @@ fn new_identity_fold[ENV]() -> ast_fold[ENV] {
|
||||
bind identity_fold_view_item_import[ENV](_,_,_,_,_,_),
|
||||
|
||||
fold_block = bind identity_fold_block[ENV](_,_,_),
|
||||
fold_fn = bind identity_fold_fn[ENV](_,_,_,_,_,_),
|
||||
fold_fn = bind identity_fold_fn[ENV](_,_,_,_),
|
||||
fold_fn_decl = bind identity_fold_fn_decl[ENV](_,_,_,_),
|
||||
fold_mod = bind identity_fold_mod[ENV](_,_),
|
||||
fold_native_mod = bind identity_fold_native_mod[ENV](_,_),
|
||||
fold_crate = bind identity_fold_crate[ENV](_,_,_),
|
||||
fold_obj = bind identity_fold_obj[ENV](_,_,_),
|
||||
fold_obj = bind identity_fold_obj[ENV](_,_,_,_),
|
||||
|
||||
update_env_for_crate = bind identity_update_env_for_crate[ENV](_,_),
|
||||
update_env_for_item = bind identity_update_env_for_item[ENV](_,_),
|
||||
update_env_for_native_item =
|
||||
bind identity_update_env_for_native_item[ENV](_,_),
|
||||
update_env_for_view_item =
|
||||
bind identity_update_env_for_view_item[ENV](_,_),
|
||||
update_env_for_block = bind identity_update_env_for_block[ENV](_,_),
|
||||
|
||||
@@ -18,6 +18,7 @@ import std._vec;
|
||||
tag scope {
|
||||
scope_crate(@ast.crate);
|
||||
scope_item(@ast.item);
|
||||
scope_native_item(@ast.native_item);
|
||||
scope_loop(@ast.decl); // there's only 1 decl per loop.
|
||||
scope_block(ast.block);
|
||||
scope_arm(ast.arm);
|
||||
@@ -34,6 +35,7 @@ tag def_wrap {
|
||||
def_wrap_use(@ast.view_item);
|
||||
def_wrap_import(@ast.view_item);
|
||||
def_wrap_mod(@ast.item);
|
||||
def_wrap_native_mod(@ast.item);
|
||||
def_wrap_other(def);
|
||||
def_wrap_expr_field(uint, def);
|
||||
def_wrap_resolving;
|
||||
@@ -103,6 +105,29 @@ fn find_final_def(&env e, import_map index,
|
||||
// should return what a.b.c.d points to in the end.
|
||||
fn found_something(&env e, import_map index,
|
||||
&span sp, vec[ident] idents, def_wrap d) -> def_wrap {
|
||||
|
||||
fn found_mod(&env e, &import_map index, &span sp,
|
||||
vec[ident] idents, @ast.item i) -> def_wrap {
|
||||
auto len = _vec.len[ident](idents);
|
||||
auto rest_idents = _vec.slice[ident](idents, 1u, len);
|
||||
auto empty_e = rec(scopes = nil[scope],
|
||||
sess = e.sess);
|
||||
auto tmp_e = update_env_for_item(empty_e, i);
|
||||
auto next_i = rest_idents.(0);
|
||||
auto next_ = lookup_name_wrapped(tmp_e, next_i);
|
||||
alt (next_) {
|
||||
case (none[tup(@env, def_wrap)]) {
|
||||
e.sess.span_err(sp, "unresolved name: " + next_i);
|
||||
fail;
|
||||
}
|
||||
case (some[tup(@env, def_wrap)](?next)) {
|
||||
auto combined_e = update_env_for_item(e, i);
|
||||
ret found_something(combined_e, index, sp,
|
||||
rest_idents, next._1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
alt (d) {
|
||||
case (def_wrap_import(?imp)) {
|
||||
alt (imp.node) {
|
||||
@@ -122,23 +147,10 @@ fn find_final_def(&env e, import_map index,
|
||||
}
|
||||
alt (d) {
|
||||
case (def_wrap_mod(?i)) {
|
||||
auto rest_idents = _vec.slice[ident](idents, 1u, len);
|
||||
auto empty_e = rec(scopes = nil[scope],
|
||||
sess = e.sess);
|
||||
auto tmp_e = update_env_for_item(empty_e, i);
|
||||
auto next_i = rest_idents.(0);
|
||||
auto next_ = lookup_name_wrapped(tmp_e, next_i);
|
||||
alt (next_) {
|
||||
case (none[tup(@env, def_wrap)]) {
|
||||
e.sess.span_err(sp, "unresolved name: " + next_i);
|
||||
fail;
|
||||
}
|
||||
case (some[tup(@env, def_wrap)](?next)) {
|
||||
auto combined_e = update_env_for_item(e, i);
|
||||
ret found_something(combined_e, index, sp,
|
||||
rest_idents, next._1);
|
||||
}
|
||||
ret found_mod(e, index, sp, idents, i);
|
||||
}
|
||||
case (def_wrap_native_mod(?i)) {
|
||||
ret found_mod(e, index, sp, idents, i);
|
||||
}
|
||||
case (def_wrap_use(?c)) {
|
||||
e.sess.span_err(sp, "Crate access is not implemented");
|
||||
@@ -201,6 +213,9 @@ fn lookup_name_wrapped(&env e, ast.ident i) -> option.t[tup(@env, def_wrap)] {
|
||||
case (ast.item_mod(_, _, ?id)) {
|
||||
ret def_wrap_mod(i);
|
||||
}
|
||||
case (ast.item_native_mod(_, _, ?id)) {
|
||||
ret def_wrap_native_mod(i);
|
||||
}
|
||||
case (ast.item_ty(_, _, _, ?id, _)) {
|
||||
ret def_wrap_other(ast.def_ty(id));
|
||||
}
|
||||
@@ -213,6 +228,17 @@ fn lookup_name_wrapped(&env e, ast.ident i) -> option.t[tup(@env, def_wrap)] {
|
||||
}
|
||||
}
|
||||
|
||||
fn found_def_native_item(@ast.native_item i) -> def_wrap {
|
||||
alt (i.node) {
|
||||
case (ast.native_item_ty(_, ?id)) {
|
||||
ret def_wrap_other(ast.def_native_ty(id));
|
||||
}
|
||||
case (ast.native_item_fn(_, _, _, ?id, _)) {
|
||||
ret def_wrap_other(ast.def_native_fn(id));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn found_decl_stmt(@ast.stmt s) -> def_wrap {
|
||||
alt (s.node) {
|
||||
case (ast.stmt_decl(?d)) {
|
||||
@@ -267,23 +293,34 @@ fn lookup_name_wrapped(&env e, ast.ident i) -> option.t[tup(@env, def_wrap)] {
|
||||
}
|
||||
}
|
||||
}
|
||||
case (none[ast.mod_index_entry]) { /* fall through */ }
|
||||
}
|
||||
case (none[ast.mod_index_entry]) {
|
||||
ret none[def_wrap];
|
||||
}
|
||||
|
||||
|
||||
fn in_scope(ast.ident i, &scope s) -> option.t[def_wrap] {
|
||||
alt (s) {
|
||||
|
||||
case (scope_crate(?c)) {
|
||||
ret check_mod(i, c.node.module);
|
||||
}
|
||||
}
|
||||
|
||||
case (scope_item(?it)) {
|
||||
alt (it.node) {
|
||||
case (ast.item_fn(_, ?f, ?ty_params, _, _)) {
|
||||
for (ast.arg a in f.inputs) {
|
||||
fn check_native_mod(ast.ident i, ast.native_mod m) -> option.t[def_wrap] {
|
||||
|
||||
alt (m.index.find(i)) {
|
||||
case (some[ast.native_mod_index_entry](?ent)) {
|
||||
alt (ent) {
|
||||
case (ast.nmie_view_item(?view_item)) {
|
||||
ret some(found_def_view(view_item));
|
||||
}
|
||||
case (ast.nmie_item(?item)) {
|
||||
ret some(found_def_native_item(item));
|
||||
}
|
||||
}
|
||||
}
|
||||
case (none[ast.native_mod_index_entry]) {
|
||||
ret none[def_wrap];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn handle_fn_decl(ast.ident i, &ast.fn_decl decl,
|
||||
&vec[ast.ty_param] ty_params) -> option.t[def_wrap] {
|
||||
for (ast.arg a in decl.inputs) {
|
||||
if (_str.eq(a.ident, i)) {
|
||||
auto t = ast.def_arg(a.id);
|
||||
ret some(def_wrap_other(t));
|
||||
@@ -295,6 +332,20 @@ fn lookup_name_wrapped(&env e, ast.ident i) -> option.t[tup(@env, def_wrap)] {
|
||||
ret some(def_wrap_other(t));
|
||||
}
|
||||
}
|
||||
ret none[def_wrap];
|
||||
}
|
||||
|
||||
fn in_scope(ast.ident i, &scope s) -> option.t[def_wrap] {
|
||||
alt (s) {
|
||||
|
||||
case (scope_crate(?c)) {
|
||||
ret check_mod(i, c.node.module);
|
||||
}
|
||||
|
||||
case (scope_item(?it)) {
|
||||
alt (it.node) {
|
||||
case (ast.item_fn(_, ?f, ?ty_params, _, _)) {
|
||||
ret handle_fn_decl(i, f.decl, ty_params);
|
||||
}
|
||||
case (ast.item_obj(_, ?ob, ?ty_params, _, _)) {
|
||||
for (ast.obj_field f in ob.fields) {
|
||||
@@ -310,9 +361,20 @@ fn lookup_name_wrapped(&env e, ast.ident i) -> option.t[tup(@env, def_wrap)] {
|
||||
}
|
||||
}
|
||||
}
|
||||
case (ast.item_tag(_, _, ?ty_params, _)) {
|
||||
for (ast.ty_param tp in ty_params) {
|
||||
if (_str.eq(tp.ident, i)) {
|
||||
auto t = ast.def_ty_arg(tp.id);
|
||||
ret some(def_wrap_other(t));
|
||||
}
|
||||
}
|
||||
}
|
||||
case (ast.item_mod(_, ?m, _)) {
|
||||
ret check_mod(i, m);
|
||||
}
|
||||
case (ast.item_native_mod(_, ?m, _)) {
|
||||
ret check_native_mod(i, m);
|
||||
}
|
||||
case (ast.item_ty(_, _, ?ty_params, _, _)) {
|
||||
for (ast.ty_param tp in ty_params) {
|
||||
if (_str.eq(tp.ident, i)) {
|
||||
@@ -325,6 +387,14 @@ fn lookup_name_wrapped(&env e, ast.ident i) -> option.t[tup(@env, def_wrap)] {
|
||||
}
|
||||
}
|
||||
|
||||
case (scope_native_item(?it)) {
|
||||
alt (it.node) {
|
||||
case (ast.native_item_fn(_, ?decl, ?ty_params, _, _)) {
|
||||
ret handle_fn_decl(i, decl, ty_params);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
case (scope_loop(?d)) {
|
||||
alt (d.node) {
|
||||
case (ast.decl_local(?local)) {
|
||||
@@ -432,8 +502,7 @@ fn fold_expr_path(&env e, &span sp, &ast.path p, &option.t[def] d,
|
||||
path_len = n_idents - remaining + 1u;
|
||||
}
|
||||
case (def_wrap_other(_)) {
|
||||
check (n_idents == 1u);
|
||||
path_len = 1u;
|
||||
path_len = n_idents;
|
||||
}
|
||||
case (def_wrap_mod(?m)) {
|
||||
e.sess.span_err(sp,
|
||||
@@ -491,6 +560,10 @@ fn update_env_for_item(&env e, @ast.item i) -> env {
|
||||
ret rec(scopes = cons[scope](scope_item(i), @e.scopes) with e);
|
||||
}
|
||||
|
||||
fn update_env_for_native_item(&env e, @ast.native_item i) -> env {
|
||||
ret rec(scopes = cons[scope](scope_native_item(i), @e.scopes) with e);
|
||||
}
|
||||
|
||||
fn update_env_for_block(&env e, &ast.block b) -> env {
|
||||
ret rec(scopes = cons[scope](scope_block(b), @e.scopes) with e);
|
||||
}
|
||||
@@ -500,6 +573,9 @@ fn update_env_for_expr(&env e, @ast.expr x) -> env {
|
||||
case (ast.expr_for(?d, _, _, _)) {
|
||||
ret rec(scopes = cons[scope](scope_loop(d), @e.scopes) with e);
|
||||
}
|
||||
case (ast.expr_for_each(?d, _, _, _)) {
|
||||
ret rec(scopes = cons[scope](scope_loop(d), @e.scopes) with e);
|
||||
}
|
||||
case (_) { }
|
||||
}
|
||||
ret e;
|
||||
@@ -517,6 +593,8 @@ fn resolve_imports(session.session sess, @ast.crate crate) -> @ast.crate {
|
||||
= bind fold_view_item_import(_,_,import_index,_,_,_,_),
|
||||
update_env_for_crate = bind update_env_for_crate(_,_),
|
||||
update_env_for_item = bind update_env_for_item(_,_),
|
||||
update_env_for_native_item =
|
||||
bind update_env_for_native_item(_,_),
|
||||
update_env_for_block = bind update_env_for_block(_,_),
|
||||
update_env_for_arm = bind update_env_for_arm(_,_),
|
||||
update_env_for_expr = bind update_env_for_expr(_,_)
|
||||
@@ -539,6 +617,8 @@ fn resolve_crate(session.session sess, @ast.crate crate) -> @ast.crate {
|
||||
fold_ty_path = bind fold_ty_path(_,_,_,_),
|
||||
update_env_for_crate = bind update_env_for_crate(_,_),
|
||||
update_env_for_item = bind update_env_for_item(_,_),
|
||||
update_env_for_native_item =
|
||||
bind update_env_for_native_item(_,_),
|
||||
update_env_for_block = bind update_env_for_block(_,_),
|
||||
update_env_for_arm = bind update_env_for_arm(_,_),
|
||||
update_env_for_expr = bind update_env_for_expr(_,_)
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -19,7 +19,10 @@ import util.common.span;
|
||||
|
||||
type arg = rec(ast.mode mode, @t ty);
|
||||
type field = rec(ast.ident ident, @t ty);
|
||||
type method = rec(ast.ident ident, vec[arg] inputs, @t output);
|
||||
type method = rec(ast.proto proto,
|
||||
ast.ident ident,
|
||||
vec[arg] inputs,
|
||||
@t output);
|
||||
|
||||
// NB: If you change this, you'll probably want to change the corresponding
|
||||
// AST structure in front/ast.rs as well.
|
||||
@@ -32,16 +35,19 @@ tag sty {
|
||||
ty_machine(util.common.ty_mach);
|
||||
ty_char;
|
||||
ty_str;
|
||||
ty_tag(ast.def_id);
|
||||
ty_tag(ast.def_id, vec[@t]);
|
||||
ty_box(@t);
|
||||
ty_vec(@t);
|
||||
ty_tup(vec[@t]);
|
||||
ty_rec(vec[field]);
|
||||
ty_fn(vec[arg], @t); // TODO: effect
|
||||
ty_fn(ast.proto, vec[arg], @t); // TODO: effect
|
||||
ty_native_fn(ast.native_abi, vec[arg], @t); // TODO: effect
|
||||
ty_obj(vec[method]);
|
||||
ty_var(int); // ephemeral type var
|
||||
ty_local(ast.def_id); // type of a local var
|
||||
ty_param(ast.def_id); // fn type param
|
||||
ty_param(ast.def_id); // fn/tag type param
|
||||
ty_type;
|
||||
ty_native;
|
||||
// TODO: ty_fn_arg(@t), for a possibly-aliased function argument
|
||||
}
|
||||
|
||||
@@ -103,6 +109,7 @@ fn ast_ty_to_str(&@ast.ty ty) -> str {
|
||||
case (ast.ty_str) { s = "str"; }
|
||||
case (ast.ty_box(?t)) { s = "@" + ast_ty_to_str(t); }
|
||||
case (ast.ty_vec(?t)) { s = "vec[" + ast_ty_to_str(t) + "]"; }
|
||||
case (ast.ty_type) { s = "type"; }
|
||||
|
||||
case (ast.ty_tup(?elts)) {
|
||||
auto f = ast_ty_to_str;
|
||||
@@ -118,9 +125,13 @@ fn ast_ty_to_str(&@ast.ty ty) -> str {
|
||||
s += ")";
|
||||
}
|
||||
|
||||
case (ast.ty_fn(?inputs, ?output)) {
|
||||
case (ast.ty_fn(?proto, ?inputs, ?output)) {
|
||||
auto f = ast_fn_input_to_str;
|
||||
if (proto == ast.proto_fn) {
|
||||
s = "fn(";
|
||||
} else {
|
||||
s = "iter(";
|
||||
}
|
||||
auto is = _vec.map[rec(ast.mode mode, @ast.ty ty),str](f, inputs);
|
||||
s += _str.connect(is, ", ");
|
||||
s += ")";
|
||||
@@ -138,6 +149,7 @@ fn ast_ty_to_str(&@ast.ty ty) -> str {
|
||||
s = "mutable " + ast_ty_to_str(t);
|
||||
}
|
||||
|
||||
|
||||
case (_) {
|
||||
fail; // FIXME: typestate bug
|
||||
}
|
||||
@@ -157,6 +169,8 @@ fn path_to_str(&ast.path pth) -> str {
|
||||
ret result;
|
||||
}
|
||||
|
||||
// FIXME use the pretty-printer for this once it has a concept of an
|
||||
// abstract stream
|
||||
fn ty_to_str(&@t typ) -> str {
|
||||
|
||||
fn fn_input_to_str(&rec(ast.mode mode, @t ty) input) -> str {
|
||||
@@ -170,10 +184,14 @@ fn ty_to_str(&@t typ) -> str {
|
||||
ret s + ty_to_str(input.ty);
|
||||
}
|
||||
|
||||
fn fn_to_str(option.t[ast.ident] ident,
|
||||
fn fn_to_str(ast.proto proto,
|
||||
option.t[ast.ident] ident,
|
||||
vec[arg] inputs, @t output) -> str {
|
||||
auto f = fn_input_to_str;
|
||||
auto s = "fn";
|
||||
if (proto == ast.proto_iter) {
|
||||
s = "iter";
|
||||
}
|
||||
alt (ident) {
|
||||
case (some[ast.ident](?i)) {
|
||||
s += " ";
|
||||
@@ -193,7 +211,8 @@ fn ty_to_str(&@t typ) -> str {
|
||||
}
|
||||
|
||||
fn method_to_str(&method m) -> str {
|
||||
ret fn_to_str(some[ast.ident](m.ident), m.inputs, m.output) + ";";
|
||||
ret fn_to_str(m.proto, some[ast.ident](m.ident),
|
||||
m.inputs, m.output) + ";";
|
||||
}
|
||||
|
||||
fn field_to_str(&field f) -> str {
|
||||
@@ -206,6 +225,7 @@ fn ty_to_str(&@t typ) -> str {
|
||||
}
|
||||
|
||||
alt (typ.struct) {
|
||||
case (ty_native) { s = "native"; }
|
||||
case (ty_nil) { s = "()"; }
|
||||
case (ty_bool) { s = "bool"; }
|
||||
case (ty_int) { s = "int"; }
|
||||
@@ -215,6 +235,7 @@ fn ty_to_str(&@t typ) -> str {
|
||||
case (ty_str) { s = "str"; }
|
||||
case (ty_box(?t)) { s = "@" + ty_to_str(t); }
|
||||
case (ty_vec(?t)) { s = "vec[" + ty_to_str(t) + "]"; }
|
||||
case (ty_type) { s = "type"; }
|
||||
|
||||
case (ty_tup(?elems)) {
|
||||
auto f = ty_to_str;
|
||||
@@ -228,13 +249,23 @@ fn ty_to_str(&@t typ) -> str {
|
||||
s = "rec(" + _str.connect(strs, ",") + ")";
|
||||
}
|
||||
|
||||
case (ty_tag(_)) {
|
||||
case (ty_tag(?id, ?tps)) {
|
||||
// The user should never see this if the cname is set properly!
|
||||
s = "<tag>";
|
||||
s = "<tag#" + util.common.istr(id._0) + ":" +
|
||||
util.common.istr(id._1) + ">";
|
||||
if (_vec.len[@t](tps) > 0u) {
|
||||
auto f = ty_to_str;
|
||||
auto strs = _vec.map[@t,str](f, tps);
|
||||
s += "[" + _str.connect(strs, ",") + "]";
|
||||
}
|
||||
}
|
||||
|
||||
case (ty_fn(?inputs, ?output)) {
|
||||
s = fn_to_str(none[ast.ident], inputs, output);
|
||||
case (ty_fn(?proto, ?inputs, ?output)) {
|
||||
s = fn_to_str(proto, none[ast.ident], inputs, output);
|
||||
}
|
||||
|
||||
case (ty_native_fn(_, ?inputs, ?output)) {
|
||||
s = fn_to_str(ast.proto_fn, none[ast.ident], inputs, output);
|
||||
}
|
||||
|
||||
case (ty_obj(?meths)) {
|
||||
@@ -280,13 +311,21 @@ fn fold_ty(ty_fold fld, @t ty) -> @t {
|
||||
case (ty_machine(_)) { ret fld.fold_simple_ty(ty); }
|
||||
case (ty_char) { ret fld.fold_simple_ty(ty); }
|
||||
case (ty_str) { ret fld.fold_simple_ty(ty); }
|
||||
case (ty_tag(_)) { ret fld.fold_simple_ty(ty); }
|
||||
case (ty_type) { ret fld.fold_simple_ty(ty); }
|
||||
case (ty_native) { ret fld.fold_simple_ty(ty); }
|
||||
case (ty_box(?subty)) {
|
||||
ret rewrap(ty, ty_box(fold_ty(fld, subty)));
|
||||
}
|
||||
case (ty_vec(?subty)) {
|
||||
ret rewrap(ty, ty_vec(fold_ty(fld, subty)));
|
||||
}
|
||||
case (ty_tag(?tid, ?subtys)) {
|
||||
let vec[@t] new_subtys = vec();
|
||||
for (@t subty in subtys) {
|
||||
new_subtys += vec(fold_ty(fld, subty));
|
||||
}
|
||||
ret rewrap(ty, ty_tag(tid, new_subtys));
|
||||
}
|
||||
case (ty_tup(?subtys)) {
|
||||
let vec[@t] new_subtys = vec();
|
||||
for (@t subty in subtys) {
|
||||
@@ -302,13 +341,21 @@ fn fold_ty(ty_fold fld, @t ty) -> @t {
|
||||
}
|
||||
ret rewrap(ty, ty_rec(new_fields));
|
||||
}
|
||||
case (ty_fn(?args, ?ret_ty)) {
|
||||
case (ty_fn(?proto, ?args, ?ret_ty)) {
|
||||
let vec[arg] new_args = vec();
|
||||
for (arg a in args) {
|
||||
auto new_ty = fold_ty(fld, a.ty);
|
||||
new_args += vec(rec(mode=a.mode, ty=new_ty));
|
||||
}
|
||||
ret rewrap(ty, ty_fn(new_args, fold_ty(fld, ret_ty)));
|
||||
ret rewrap(ty, ty_fn(proto, new_args, fold_ty(fld, ret_ty)));
|
||||
}
|
||||
case (ty_native_fn(?abi, ?args, ?ret_ty)) {
|
||||
let vec[arg] new_args = vec();
|
||||
for (arg a in args) {
|
||||
auto new_ty = fold_ty(fld, a.ty);
|
||||
new_args += vec(rec(mode=a.mode, ty=new_ty));
|
||||
}
|
||||
ret rewrap(ty, ty_native_fn(abi, new_args, fold_ty(fld, ret_ty)));
|
||||
}
|
||||
case (ty_obj(?methods)) {
|
||||
let vec[method] new_methods = vec();
|
||||
@@ -317,7 +364,8 @@ fn fold_ty(ty_fold fld, @t ty) -> @t {
|
||||
for (arg a in m.inputs) {
|
||||
new_args += vec(rec(mode=a.mode, ty=fold_ty(fld, a.ty)));
|
||||
}
|
||||
new_methods += vec(rec(ident=m.ident, inputs=new_args,
|
||||
new_methods += vec(rec(proto=m.proto, ident=m.ident,
|
||||
inputs=new_args,
|
||||
output=fold_ty(fld, m.output)));
|
||||
}
|
||||
ret rewrap(ty, ty_obj(new_methods));
|
||||
@@ -327,7 +375,7 @@ fn fold_ty(ty_fold fld, @t ty) -> @t {
|
||||
case (ty_param(_)) { ret fld.fold_simple_ty(ty); }
|
||||
}
|
||||
|
||||
ret ty;
|
||||
fail;
|
||||
}
|
||||
|
||||
// Type utilities
|
||||
@@ -349,23 +397,43 @@ fn type_is_nil(@t ty) -> bool {
|
||||
fail;
|
||||
}
|
||||
|
||||
|
||||
fn type_is_structural(@t ty) -> bool {
|
||||
alt (ty.struct) {
|
||||
case (ty_tup(_)) { ret true; }
|
||||
case (ty_rec(_)) { ret true; }
|
||||
case (ty_tag(_)) { ret true; }
|
||||
case (ty_fn(_,_)) { ret true; }
|
||||
case (ty_tag(_,_)) { ret true; }
|
||||
case (ty_fn(_,_,_)) { ret true; }
|
||||
case (ty_obj(_)) { ret true; }
|
||||
case (_) { ret false; }
|
||||
}
|
||||
fail;
|
||||
}
|
||||
|
||||
fn type_is_sequence(@t ty) -> bool {
|
||||
alt (ty.struct) {
|
||||
case (ty_str) { ret true; }
|
||||
case (ty_vec(_)) { ret true; }
|
||||
case (_) { ret false; }
|
||||
}
|
||||
fail;
|
||||
}
|
||||
|
||||
fn sequence_element_type(@t ty) -> @t {
|
||||
alt (ty.struct) {
|
||||
case (ty_str) { ret plain_ty(ty_machine(common.ty_u8)); }
|
||||
case (ty_vec(?e)) { ret e; }
|
||||
}
|
||||
fail;
|
||||
}
|
||||
|
||||
|
||||
fn type_is_tup_like(@t ty) -> bool {
|
||||
alt (ty.struct) {
|
||||
case (ty_box(_)) { ret true; }
|
||||
case (ty_tup(_)) { ret true; }
|
||||
case (ty_rec(_)) { ret true; }
|
||||
case (ty_tag(_)) { ret true; }
|
||||
case (ty_tag(_,_)) { ret true; }
|
||||
case (_) { ret false; }
|
||||
}
|
||||
fail;
|
||||
@@ -402,6 +470,17 @@ fn type_is_scalar(@t ty) -> bool {
|
||||
case (ty_uint) { ret true; }
|
||||
case (ty_machine(_)) { ret true; }
|
||||
case (ty_char) { ret true; }
|
||||
case (ty_type) { ret true; }
|
||||
case (_) { ret false; }
|
||||
}
|
||||
fail;
|
||||
}
|
||||
|
||||
// FIXME: should we just return true for native types in
|
||||
// type_is_scalar?
|
||||
fn type_is_native(@t ty) -> bool {
|
||||
alt (ty.struct) {
|
||||
case (ty_native) { ret true; }
|
||||
case (_) { ret false; }
|
||||
}
|
||||
fail;
|
||||
@@ -423,6 +502,13 @@ fn type_has_dynamic_size(@t ty) -> bool {
|
||||
i += 1u;
|
||||
}
|
||||
}
|
||||
case (ty_tag(_, ?subtys)) {
|
||||
auto i = 0u;
|
||||
while (i < _vec.len[@t](subtys)) {
|
||||
if (type_has_dynamic_size(subtys.(i))) { ret true; }
|
||||
i += 1u;
|
||||
}
|
||||
}
|
||||
case (ty_param(_)) { ret true; }
|
||||
case (_) { /* fall through */ }
|
||||
}
|
||||
@@ -548,19 +634,38 @@ fn count_ty_params(@t ty) -> uint {
|
||||
|
||||
fn ty_fn_args(@t fty) -> vec[arg] {
|
||||
alt (fty.struct) {
|
||||
case (ty.ty_fn(?a, _)) { ret a; }
|
||||
case (ty.ty_fn(_, ?a, _)) { ret a; }
|
||||
case (ty.ty_native_fn(_, ?a, _)) { ret a; }
|
||||
}
|
||||
fail;
|
||||
}
|
||||
|
||||
fn ty_fn_proto(@t fty) -> ast.proto {
|
||||
alt (fty.struct) {
|
||||
case (ty.ty_fn(?p, _, _)) { ret p; }
|
||||
}
|
||||
fail;
|
||||
}
|
||||
|
||||
fn ty_fn_abi(@t fty) -> ast.native_abi {
|
||||
alt (fty.struct) {
|
||||
case (ty.ty_native_fn(?a, _, _)) { ret a; }
|
||||
}
|
||||
fail;
|
||||
}
|
||||
|
||||
fn ty_fn_ret(@t fty) -> @t {
|
||||
alt (fty.struct) {
|
||||
case (ty.ty_fn(_, ?r)) { ret r; }
|
||||
case (ty.ty_fn(_, _, ?r)) { ret r; }
|
||||
case (ty.ty_native_fn(_, _, ?r)) { ret r; }
|
||||
}
|
||||
fail;
|
||||
}
|
||||
|
||||
fn is_fn_ty(@t fty) -> bool {
|
||||
alt (fty.struct) {
|
||||
case (ty.ty_fn(_, _)) { ret true; }
|
||||
case (ty.ty_fn(_, _, _)) { ret true; }
|
||||
case (ty.ty_native_fn(_, _, _)) { ret true; }
|
||||
case (_) { ret false; }
|
||||
}
|
||||
ret false;
|
||||
@@ -571,7 +676,24 @@ fn is_fn_ty(@t fty) -> bool {
|
||||
|
||||
// Given an item, returns the associated type as well as a list of the IDs of
|
||||
// its type parameters.
|
||||
fn item_ty(@ast.item it) -> tup(vec[ast.def_id], @t) {
|
||||
type ty_params_and_ty = tup(vec[ast.def_id], @t);
|
||||
fn native_item_ty(@ast.native_item it) -> ty_params_and_ty {
|
||||
auto ty_params;
|
||||
auto result_ty;
|
||||
alt (it.node) {
|
||||
case (ast.native_item_fn(_, _, ?tps, _, ?ann)) {
|
||||
ty_params = tps;
|
||||
result_ty = ann_to_type(ann);
|
||||
}
|
||||
}
|
||||
let vec[ast.def_id] ty_param_ids = vec();
|
||||
for (ast.ty_param tp in ty_params) {
|
||||
ty_param_ids += vec(tp.id);
|
||||
}
|
||||
ret tup(ty_param_ids, result_ty);
|
||||
}
|
||||
|
||||
fn item_ty(@ast.item it) -> ty_params_and_ty {
|
||||
let vec[ast.ty_param] ty_params;
|
||||
auto result_ty;
|
||||
alt (it.node) {
|
||||
@@ -591,8 +713,13 @@ fn item_ty(@ast.item it) -> tup(vec[ast.def_id], @t) {
|
||||
result_ty = ann_to_type(ann);
|
||||
}
|
||||
case (ast.item_tag(_, _, ?tps, ?did)) {
|
||||
// Create a new generic polytype.
|
||||
ty_params = tps;
|
||||
result_ty = plain_ty(ty_tag(did));
|
||||
let vec[@t] subtys = vec();
|
||||
for (ast.ty_param tp in tps) {
|
||||
subtys += vec(plain_ty(ty_param(tp.id)));
|
||||
}
|
||||
result_ty = plain_ty(ty_tag(did, subtys));
|
||||
}
|
||||
case (ast.item_obj(_, _, ?tps, _, ?ann)) {
|
||||
ty_params = tps;
|
||||
@@ -628,6 +755,7 @@ fn block_ty(&ast.block b) -> @t {
|
||||
fn pat_ty(@ast.pat pat) -> @t {
|
||||
alt (pat.node) {
|
||||
case (ast.pat_wild(?ann)) { ret ann_to_type(ann); }
|
||||
case (ast.pat_lit(_, ?ann)) { ret ann_to_type(ann); }
|
||||
case (ast.pat_bind(_, _, ?ann)) { ret ann_to_type(ann); }
|
||||
case (ast.pat_tag(_, _, _, ?ann)) { ret ann_to_type(ann); }
|
||||
}
|
||||
@@ -638,7 +766,7 @@ fn expr_ty(@ast.expr expr) -> @t {
|
||||
alt (expr.node) {
|
||||
case (ast.expr_vec(_, ?ann)) { ret ann_to_type(ann); }
|
||||
case (ast.expr_tup(_, ?ann)) { ret ann_to_type(ann); }
|
||||
case (ast.expr_rec(_, ?ann)) { ret ann_to_type(ann); }
|
||||
case (ast.expr_rec(_, _, ?ann)) { ret ann_to_type(ann); }
|
||||
case (ast.expr_bind(_, _, ?ann)) { ret ann_to_type(ann); }
|
||||
case (ast.expr_call(_, _, ?ann)) { ret ann_to_type(ann); }
|
||||
case (ast.expr_binary(_, _, _, ?ann)) { ret ann_to_type(ann); }
|
||||
@@ -647,6 +775,8 @@ fn expr_ty(@ast.expr expr) -> @t {
|
||||
case (ast.expr_cast(_, _, ?ann)) { ret ann_to_type(ann); }
|
||||
case (ast.expr_if(_, _, _, ?ann)) { ret ann_to_type(ann); }
|
||||
case (ast.expr_for(_, _, _, ?ann)) { ret ann_to_type(ann); }
|
||||
case (ast.expr_for_each(_, _, _, ?ann))
|
||||
{ ret ann_to_type(ann); }
|
||||
case (ast.expr_while(_, _, ?ann)) { ret ann_to_type(ann); }
|
||||
case (ast.expr_do_while(_, _, ?ann)) { ret ann_to_type(ann); }
|
||||
case (ast.expr_alt(_, _, ?ann)) { ret ann_to_type(ann); }
|
||||
@@ -657,6 +787,14 @@ fn expr_ty(@ast.expr expr) -> @t {
|
||||
case (ast.expr_field(_, _, ?ann)) { ret ann_to_type(ann); }
|
||||
case (ast.expr_index(_, _, ?ann)) { ret ann_to_type(ann); }
|
||||
case (ast.expr_path(_, _, ?ann)) { ret ann_to_type(ann); }
|
||||
case (ast.expr_ext(_, _, _, _, ?ann)) { ret ann_to_type(ann); }
|
||||
|
||||
case (ast.expr_fail) { ret plain_ty(ty_nil); }
|
||||
case (ast.expr_log(_)) { ret plain_ty(ty_nil); }
|
||||
case (ast.expr_check_expr(_)) { ret plain_ty(ty_nil); }
|
||||
case (ast.expr_ret(_)) { ret plain_ty(ty_nil); }
|
||||
case (ast.expr_put(_)) { ret plain_ty(ty_nil); }
|
||||
case (ast.expr_be(_)) { ret plain_ty(ty_nil); }
|
||||
}
|
||||
fail;
|
||||
}
|
||||
@@ -726,7 +864,10 @@ fn is_lval(@ast.expr expr) -> bool {
|
||||
}
|
||||
}
|
||||
|
||||
// Type unification
|
||||
// Type unification via Robinson's algorithm (Robinson 1965). Implemented as
|
||||
// described in Hoder and Voronkov:
|
||||
//
|
||||
// http://www.cs.man.ac.uk/~hoderk/ubench/unification_full.pdf
|
||||
|
||||
fn unify(@ty.t expected, @ty.t actual, &unify_handler handler)
|
||||
-> unify_result {
|
||||
@@ -746,17 +887,23 @@ fn unify(@ty.t expected, @ty.t actual, &unify_handler handler)
|
||||
ret ures_err(terr_mismatch, expected, actual);
|
||||
}
|
||||
|
||||
fn unify_fn(&hashmap[int,@ty.t] bindings,
|
||||
tag fn_common_res {
|
||||
fn_common_res_err(unify_result);
|
||||
fn_common_res_ok(vec[arg], @t);
|
||||
}
|
||||
|
||||
fn unify_fn_common(@hashmap[int,@ty.t] bindings,
|
||||
@ty.t expected,
|
||||
@ty.t actual,
|
||||
&unify_handler handler,
|
||||
vec[arg] expected_inputs, @t expected_output,
|
||||
vec[arg] actual_inputs, @t actual_output)
|
||||
-> unify_result {
|
||||
-> fn_common_res {
|
||||
auto expected_len = _vec.len[arg](expected_inputs);
|
||||
auto actual_len = _vec.len[arg](actual_inputs);
|
||||
if (expected_len != actual_len) {
|
||||
ret ures_err(terr_arg_count, expected, actual);
|
||||
ret fn_common_res_err(ures_err(terr_arg_count,
|
||||
expected, actual));
|
||||
}
|
||||
|
||||
// TODO: as above, we should have an iter2 iterator.
|
||||
@@ -787,7 +934,7 @@ fn unify(@ty.t expected, @ty.t actual, &unify_handler handler)
|
||||
}
|
||||
|
||||
case (_) {
|
||||
ret result;
|
||||
ret fn_common_res_err(result);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -795,27 +942,77 @@ fn unify(@ty.t expected, @ty.t actual, &unify_handler handler)
|
||||
}
|
||||
|
||||
// Check the output.
|
||||
auto result_out;
|
||||
auto result = unify_step(bindings,
|
||||
expected_output,
|
||||
actual_output,
|
||||
handler);
|
||||
alt (result) {
|
||||
case (ures_ok(?rty)) {
|
||||
result_out = rty;
|
||||
ret fn_common_res_ok(result_ins, rty);
|
||||
}
|
||||
|
||||
case (_) {
|
||||
ret result;
|
||||
ret fn_common_res_err(result);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
auto t = plain_ty(ty.ty_fn(result_ins, result_out));
|
||||
ret ures_ok(t);
|
||||
fn unify_fn(@hashmap[int,@ty.t] bindings,
|
||||
ast.proto e_proto,
|
||||
ast.proto a_proto,
|
||||
@ty.t expected,
|
||||
@ty.t actual,
|
||||
&unify_handler handler,
|
||||
vec[arg] expected_inputs, @t expected_output,
|
||||
vec[arg] actual_inputs, @t actual_output)
|
||||
-> unify_result {
|
||||
|
||||
if (e_proto != a_proto) {
|
||||
ret ures_err(terr_mismatch, expected, actual);
|
||||
}
|
||||
auto t = unify_fn_common(bindings, expected, actual,
|
||||
handler, expected_inputs, expected_output,
|
||||
actual_inputs, actual_output);
|
||||
alt (t) {
|
||||
case (fn_common_res_err(?r)) {
|
||||
ret r;
|
||||
}
|
||||
case (fn_common_res_ok(?result_ins, ?result_out)) {
|
||||
auto t2 = plain_ty(ty.ty_fn(e_proto, result_ins, result_out));
|
||||
ret ures_ok(t2);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn unify_obj(&hashmap[int,@ty.t] bindings,
|
||||
fn unify_native_fn(@hashmap[int,@ty.t] bindings,
|
||||
ast.native_abi e_abi,
|
||||
ast.native_abi a_abi,
|
||||
@ty.t expected,
|
||||
@ty.t actual,
|
||||
&unify_handler handler,
|
||||
vec[arg] expected_inputs, @t expected_output,
|
||||
vec[arg] actual_inputs, @t actual_output)
|
||||
-> unify_result {
|
||||
if (e_abi != a_abi) {
|
||||
ret ures_err(terr_mismatch, expected, actual);
|
||||
}
|
||||
|
||||
auto t = unify_fn_common(bindings, expected, actual,
|
||||
handler, expected_inputs, expected_output,
|
||||
actual_inputs, actual_output);
|
||||
alt (t) {
|
||||
case (fn_common_res_err(?r)) {
|
||||
ret r;
|
||||
}
|
||||
case (fn_common_res_ok(?result_ins, ?result_out)) {
|
||||
auto t2 = plain_ty(ty.ty_native_fn(e_abi, result_ins,
|
||||
result_out));
|
||||
ret ures_ok(t2);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn unify_obj(@hashmap[int,@ty.t] bindings,
|
||||
@ty.t expected,
|
||||
@ty.t actual,
|
||||
&unify_handler handler,
|
||||
@@ -830,32 +1027,6 @@ fn unify(@ty.t expected, @ty.t actual, &unify_handler handler)
|
||||
ret ures_err(terr_meth_count, expected, actual);
|
||||
}
|
||||
|
||||
// FIXME: work around buggy typestate logic for 'alt', sigh.
|
||||
fn is_ok(&unify_result r) -> bool {
|
||||
alt (r) {
|
||||
case (ures_ok(?tfn)) {
|
||||
ret true;
|
||||
}
|
||||
case (_) {}
|
||||
}
|
||||
ret false;
|
||||
}
|
||||
|
||||
fn append_if_ok(&method e_meth,
|
||||
&unify_result r, &mutable vec[method] result_meths) {
|
||||
alt (r) {
|
||||
case (ures_ok(?tfn)) {
|
||||
alt (tfn.struct) {
|
||||
case (ty_fn(?ins, ?out)) {
|
||||
result_meths += vec(rec(inputs = ins,
|
||||
output = out
|
||||
with e_meth));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
while (i < expected_len) {
|
||||
auto e_meth = expected_meths.(i);
|
||||
auto a_meth = actual_meths.(i);
|
||||
@@ -863,41 +1034,70 @@ fn unify(@ty.t expected, @ty.t actual, &unify_handler handler)
|
||||
ret ures_err(terr_obj_meths(e_meth.ident, a_meth.ident),
|
||||
expected, actual);
|
||||
}
|
||||
auto r = unify_fn(bindings, expected, actual, handler,
|
||||
auto r = unify_fn(bindings,
|
||||
e_meth.proto, a_meth.proto,
|
||||
expected, actual, handler,
|
||||
e_meth.inputs, e_meth.output,
|
||||
a_meth.inputs, a_meth.output);
|
||||
if (!is_ok(r)) {
|
||||
alt (r) {
|
||||
case (ures_ok(?tfn)) {
|
||||
alt (tfn.struct) {
|
||||
case (ty_fn(?proto, ?ins, ?out)) {
|
||||
result_meths += vec(rec(inputs = ins,
|
||||
output = out
|
||||
with e_meth));
|
||||
}
|
||||
}
|
||||
}
|
||||
case (_) {
|
||||
ret r;
|
||||
}
|
||||
append_if_ok(e_meth, r, result_meths);
|
||||
}
|
||||
i += 1u;
|
||||
}
|
||||
auto t = plain_ty(ty_obj(result_meths));
|
||||
ret ures_ok(t);
|
||||
}
|
||||
|
||||
fn unify_step(&hashmap[int,@ty.t] bindings, @ty.t expected, @ty.t actual,
|
||||
&unify_handler handler) -> unify_result {
|
||||
fn resolve(@hashmap[int,@t] bindings, @t typ) -> @t {
|
||||
alt (typ.struct) {
|
||||
case (ty_var(?id)) {
|
||||
alt (bindings.find(id)) {
|
||||
case (some[@t](?typ2)) {
|
||||
ret resolve(bindings, typ2);
|
||||
}
|
||||
case (none[@t]) {
|
||||
// fall through
|
||||
}
|
||||
}
|
||||
}
|
||||
case (_) {
|
||||
// fall through
|
||||
}
|
||||
}
|
||||
ret typ;
|
||||
}
|
||||
|
||||
fn unify_step(@hashmap[int,@ty.t] bindings, @ty.t in_expected,
|
||||
@ty.t in_actual, &unify_handler handler) -> unify_result {
|
||||
|
||||
// Resolve any bindings.
|
||||
auto expected = resolve(bindings, in_expected);
|
||||
auto actual = resolve(bindings, in_actual);
|
||||
|
||||
// TODO: rewrite this using tuple pattern matching when available, to
|
||||
// avoid all this rightward drift and spikiness.
|
||||
|
||||
// TODO: occurs check, to make sure we don't loop forever when
|
||||
// unifying e.g. 'a and option['a]
|
||||
|
||||
alt (actual.struct) {
|
||||
// If the RHS is a variable type, then just do the appropriate
|
||||
// binding.
|
||||
case (ty.ty_var(?actual_id)) {
|
||||
alt (bindings.find(actual_id)) {
|
||||
case (some[@ty.t](?actual_ty)) {
|
||||
// FIXME: change the binding here?
|
||||
// FIXME: "be"
|
||||
ret unify_step(bindings, expected, actual_ty,
|
||||
handler);
|
||||
}
|
||||
case (none[@ty.t]) {
|
||||
bindings.insert(actual_id, expected);
|
||||
ret ures_ok(expected);
|
||||
}
|
||||
}
|
||||
}
|
||||
case (ty.ty_local(?actual_id)) {
|
||||
auto actual_ty = handler.resolve_local(actual_id);
|
||||
auto result = unify_step(bindings,
|
||||
@@ -938,14 +1138,45 @@ fn unify(@ty.t expected, @ty.t actual, &unify_handler handler)
|
||||
case (ty.ty_machine(_)) { ret struct_cmp(expected, actual); }
|
||||
case (ty.ty_char) { ret struct_cmp(expected, actual); }
|
||||
case (ty.ty_str) { ret struct_cmp(expected, actual); }
|
||||
case (ty.ty_type) { ret struct_cmp(expected, actual); }
|
||||
case (ty.ty_native) { ret struct_cmp(expected, actual); }
|
||||
|
||||
case (ty.ty_tag(?expected_id)) {
|
||||
case (ty.ty_tag(?expected_id, ?expected_tps)) {
|
||||
alt (actual.struct) {
|
||||
case (ty.ty_tag(?actual_id)) {
|
||||
if (expected_id._0 == actual_id._0 &&
|
||||
expected_id._1 == actual_id._1) {
|
||||
ret ures_ok(expected);
|
||||
case (ty.ty_tag(?actual_id, ?actual_tps)) {
|
||||
if (expected_id._0 != actual_id._0 ||
|
||||
expected_id._1 != actual_id._1) {
|
||||
ret ures_err(terr_mismatch, expected, actual);
|
||||
}
|
||||
|
||||
// TODO: factor this cruft out, see the TODO in the
|
||||
// ty.ty_tup case
|
||||
let vec[@ty.t] result_tps = vec();
|
||||
auto i = 0u;
|
||||
auto expected_len = _vec.len[@ty.t](expected_tps);
|
||||
while (i < expected_len) {
|
||||
auto expected_tp = expected_tps.(i);
|
||||
auto actual_tp = actual_tps.(i);
|
||||
|
||||
auto result = unify_step(bindings,
|
||||
expected_tp,
|
||||
actual_tp,
|
||||
handler);
|
||||
|
||||
alt (result) {
|
||||
case (ures_ok(?rty)) {
|
||||
append[@ty.t](result_tps, rty);
|
||||
}
|
||||
case (_) {
|
||||
ret result;
|
||||
}
|
||||
}
|
||||
|
||||
i += 1u;
|
||||
}
|
||||
|
||||
ret ures_ok(plain_ty(ty.ty_tag(expected_id,
|
||||
result_tps)));
|
||||
}
|
||||
case (_) { /* fall through */ }
|
||||
}
|
||||
@@ -970,8 +1201,6 @@ fn unify(@ty.t expected, @ty.t actual, &unify_handler handler)
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: ty_var
|
||||
|
||||
case (_) {
|
||||
ret ures_err(terr_mismatch, expected, actual);
|
||||
}
|
||||
@@ -995,8 +1224,6 @@ fn unify(@ty.t expected, @ty.t actual, &unify_handler handler)
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: ty_var
|
||||
|
||||
case (_) {
|
||||
ret ures_err(terr_mismatch, expected, actual);
|
||||
}
|
||||
@@ -1045,8 +1272,6 @@ fn unify(@ty.t expected, @ty.t actual, &unify_handler handler)
|
||||
ret ures_ok(plain_ty(ty.ty_tup(result_elems)));
|
||||
}
|
||||
|
||||
// TODO: ty_var
|
||||
|
||||
case (_) {
|
||||
ret ures_err(terr_mismatch, expected, actual);
|
||||
}
|
||||
@@ -1106,7 +1331,20 @@ fn unify(@ty.t expected, @ty.t actual, &unify_handler handler)
|
||||
ret ures_ok(plain_ty(ty.ty_rec(result_fields)));
|
||||
}
|
||||
|
||||
// TODO: ty_var
|
||||
case (_) {
|
||||
ret ures_err(terr_mismatch, expected, actual);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
case (ty.ty_fn(?ep, ?expected_inputs, ?expected_output)) {
|
||||
alt (actual.struct) {
|
||||
case (ty.ty_fn(?ap, ?actual_inputs, ?actual_output)) {
|
||||
ret unify_fn(bindings, ep, ap,
|
||||
expected, actual, handler,
|
||||
expected_inputs, expected_output,
|
||||
actual_inputs, actual_output);
|
||||
}
|
||||
|
||||
case (_) {
|
||||
ret ures_err(terr_mismatch, expected, actual);
|
||||
@@ -1114,14 +1352,16 @@ fn unify(@ty.t expected, @ty.t actual, &unify_handler handler)
|
||||
}
|
||||
}
|
||||
|
||||
case (ty.ty_fn(?expected_inputs, ?expected_output)) {
|
||||
case (ty.ty_native_fn(?e_abi, ?expected_inputs,
|
||||
?expected_output)) {
|
||||
alt (actual.struct) {
|
||||
case (ty.ty_fn(?actual_inputs, ?actual_output)) {
|
||||
ret unify_fn(bindings, expected, actual, handler,
|
||||
case (ty.ty_native_fn(?a_abi, ?actual_inputs,
|
||||
?actual_output)) {
|
||||
ret unify_native_fn(bindings, e_abi, a_abi,
|
||||
expected, actual, handler,
|
||||
expected_inputs, expected_output,
|
||||
actual_inputs, actual_output);
|
||||
}
|
||||
|
||||
case (_) {
|
||||
ret ures_err(terr_mismatch, expected, actual);
|
||||
}
|
||||
@@ -1141,21 +1381,10 @@ fn unify(@ty.t expected, @ty.t actual, &unify_handler handler)
|
||||
}
|
||||
|
||||
case (ty.ty_var(?expected_id)) {
|
||||
alt (bindings.find(expected_id)) {
|
||||
case (some[@ty.t](?expected_ty)) {
|
||||
// FIXME: change the binding here?
|
||||
// FIXME: "be"
|
||||
ret unify_step(bindings,
|
||||
expected_ty,
|
||||
actual,
|
||||
handler);
|
||||
}
|
||||
case (none[@ty.t]) {
|
||||
// Add a binding.
|
||||
bindings.insert(expected_id, actual);
|
||||
ret ures_ok(actual);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
case (ty.ty_local(?expected_id)) {
|
||||
auto expected_ty = handler.resolve_local(expected_id);
|
||||
@@ -1182,13 +1411,43 @@ fn unify(@ty.t expected, @ty.t actual, &unify_handler handler)
|
||||
fail;
|
||||
}
|
||||
|
||||
// Performs type binding substitution.
|
||||
fn substitute(@hashmap[int,@t] bindings, @t typ) -> @t {
|
||||
state obj folder(@hashmap[int,@t] bindings) {
|
||||
fn fold_simple_ty(@t typ) -> @t {
|
||||
alt (typ.struct) {
|
||||
case (ty_var(?id)) {
|
||||
alt (bindings.find(id)) {
|
||||
case (some[@t](?typ2)) {
|
||||
ret substitute(bindings, typ2);
|
||||
}
|
||||
case (none[@t]) {
|
||||
ret typ;
|
||||
}
|
||||
}
|
||||
}
|
||||
case (_) {
|
||||
ret typ;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ret ty.fold_ty(folder(bindings), typ);
|
||||
}
|
||||
|
||||
fn hash_int(&int x) -> uint { ret x as uint; }
|
||||
fn eq_int(&int a, &int b) -> bool { ret a == b; }
|
||||
auto hasher = hash_int;
|
||||
auto eqer = eq_int;
|
||||
auto bindings = map.mk_hashmap[int,@ty.t](hasher, eqer);
|
||||
auto bindings = @map.mk_hashmap[int,@ty.t](hasher, eqer);
|
||||
|
||||
ret unify_step(bindings, expected, actual, handler);
|
||||
auto ures = unify_step(bindings, expected, actual, handler);
|
||||
alt (ures) {
|
||||
case (ures_ok(?t)) { ret ures_ok(substitute(bindings, t)); }
|
||||
case (_) { ret ures; }
|
||||
}
|
||||
fail; // not reached
|
||||
}
|
||||
|
||||
fn type_err_to_str(&ty.type_err err) -> str {
|
||||
@@ -1231,9 +1490,10 @@ fn type_err_to_str(&ty.type_err err) -> str {
|
||||
}
|
||||
}
|
||||
|
||||
// Type parameter resolution, used in translation
|
||||
// Type parameter resolution, used in translation and typechecking
|
||||
|
||||
fn resolve_ty_params(@ast.item item, @t monoty) -> vec[@t] {
|
||||
fn resolve_ty_params(ty_params_and_ty ty_params_and_polyty,
|
||||
@t monoty) -> vec[@t] {
|
||||
obj resolve_ty_params_handler(@hashmap[ast.def_id,@t] bindings) {
|
||||
fn resolve_local(ast.def_id id) -> @t { log "resolve local"; fail; }
|
||||
fn record_local(ast.def_id id, @t ty) { log "record local"; fail; }
|
||||
@@ -1249,8 +1509,6 @@ fn resolve_ty_params(@ast.item item, @t monoty) -> vec[@t] {
|
||||
}
|
||||
}
|
||||
|
||||
auto ty_params_and_polyty = item_ty(item);
|
||||
|
||||
auto bindings = @new_def_hash[@t]();
|
||||
auto handler = resolve_ty_params_handler(bindings);
|
||||
|
||||
@@ -1274,6 +1532,47 @@ fn resolve_ty_params(@ast.item item, @t monoty) -> vec[@t] {
|
||||
ret result_tys;
|
||||
}
|
||||
|
||||
// Performs type parameter replacement using the supplied mapping from
|
||||
// parameter IDs to types.
|
||||
fn replace_type_params(@t typ, hashmap[ast.def_id,@t] param_map) -> @t {
|
||||
state obj param_replacer(hashmap[ast.def_id,@t] param_map) {
|
||||
fn fold_simple_ty(@t typ) -> @t {
|
||||
alt (typ.struct) {
|
||||
case (ty_param(?param_def)) {
|
||||
if (param_map.contains_key(param_def)) {
|
||||
ret param_map.get(param_def);
|
||||
} else {
|
||||
ret typ;
|
||||
}
|
||||
}
|
||||
case (_) {
|
||||
ret typ;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
auto replacer = param_replacer(param_map);
|
||||
ret fold_ty(replacer, typ);
|
||||
}
|
||||
|
||||
// Substitutes the type parameters specified by @ty_params with the
|
||||
// corresponding types in @bound in the given type. The two vectors must have
|
||||
// the same length.
|
||||
fn substitute_ty_params(vec[ast.ty_param] ty_params, vec[@t] bound, @t ty)
|
||||
-> @t {
|
||||
auto ty_param_len = _vec.len[ast.ty_param](ty_params);
|
||||
check (ty_param_len == _vec.len[@t](bound));
|
||||
|
||||
auto bindings = common.new_def_hash[@t]();
|
||||
auto i = 0u;
|
||||
while (i < ty_param_len) {
|
||||
bindings.insert(ty_params.(i).id, bound.(i));
|
||||
i += 1u;
|
||||
}
|
||||
|
||||
ret replace_type_params(ty, bindings);
|
||||
}
|
||||
|
||||
// Local Variables:
|
||||
// mode: rust
|
||||
// fill-column: 78;
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
207
src/comp/pretty/pp.rs
Normal file
207
src/comp/pretty/pp.rs
Normal file
@@ -0,0 +1,207 @@
|
||||
import std.io;
|
||||
import std._vec;
|
||||
import std._str;
|
||||
|
||||
tag boxtype {box_h; box_v; box_hv; box_align;}
|
||||
tag contexttype {cx_h; cx_v;}
|
||||
|
||||
tag token {
|
||||
brk(uint);
|
||||
word(str);
|
||||
cword(str); // closing token
|
||||
open(boxtype, uint);
|
||||
close;
|
||||
}
|
||||
|
||||
type context = rec(contexttype tp, uint indent);
|
||||
|
||||
type ps = @rec(mutable vec[context] context,
|
||||
uint width,
|
||||
mutable vec[token] buffered,
|
||||
mutable uint scandepth,
|
||||
mutable uint bufferedcol,
|
||||
mutable uint col,
|
||||
mutable bool start_of_line);
|
||||
|
||||
fn mkstate(uint width) -> ps {
|
||||
let vec[context] stack = vec(rec(tp=cx_v, indent=0u));
|
||||
let vec[token] buff = vec();
|
||||
ret @rec(mutable context=stack,
|
||||
width=width,
|
||||
mutable buffered=buff,
|
||||
mutable scandepth=0u,
|
||||
mutable bufferedcol=0u,
|
||||
mutable col=0u,
|
||||
mutable start_of_line=true);
|
||||
}
|
||||
|
||||
impure fn push_context(ps p, contexttype tp, uint indent) {
|
||||
before_print(p, false);
|
||||
p.context = _vec.push[context](p.context, rec(tp=tp, indent=base_indent(p)
|
||||
+ indent));
|
||||
}
|
||||
|
||||
impure fn pop_context(ps p) {
|
||||
p.context = _vec.pop[context](p.context);
|
||||
}
|
||||
|
||||
impure fn add_token(ps p, token tok) {
|
||||
if (p.scandepth == 0u) {do_token(p, tok);}
|
||||
else {buffer_token(p, tok);}
|
||||
}
|
||||
|
||||
impure fn buffer_token(ps p, token tok) {
|
||||
p.buffered += vec(tok);
|
||||
p.bufferedcol += token_size(tok);
|
||||
alt (p.buffered.(0)) {
|
||||
case (brk(_)) {
|
||||
alt (tok) {
|
||||
case (brk(_)) {
|
||||
if (p.scandepth == 1u) {finish_break_scan(p);}
|
||||
}
|
||||
case (open(box_h,_)) {p.scandepth += 1u;}
|
||||
case (open(_,_)) {finish_break_scan(p);}
|
||||
case (close) {
|
||||
p.scandepth -= 1u;
|
||||
if (p.scandepth == 0u) {finish_break_scan(p);}
|
||||
}
|
||||
case (_) {}
|
||||
}
|
||||
}
|
||||
case (open(_,_)) {
|
||||
if (p.bufferedcol > p.width) {finish_block_scan(p, cx_v);}
|
||||
else {
|
||||
alt (tok) {
|
||||
case (open(_,_)) {p.scandepth += 1u;}
|
||||
case (close) {
|
||||
p.scandepth -= 1u;
|
||||
if (p.scandepth == 0u) {finish_block_scan(p, cx_h);}
|
||||
}
|
||||
case (_) {}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impure fn finish_block_scan(ps p, contexttype tp) {
|
||||
auto indent;
|
||||
alt (p.buffered.(0)){
|
||||
case (open(box_hv,?ind)) {
|
||||
indent = ind;
|
||||
}
|
||||
case (open(box_align, _)) {
|
||||
indent = p.col - base_indent(p);
|
||||
}
|
||||
}
|
||||
p.scandepth = 0u;
|
||||
push_context(p, tp, indent);
|
||||
for (token t in _vec.shift[token](p.buffered)) {add_token(p, t);}
|
||||
}
|
||||
|
||||
impure fn finish_break_scan(ps p) {
|
||||
if (p.bufferedcol > p.width) {
|
||||
write_str("\n");
|
||||
p.col = 0u;
|
||||
}
|
||||
else {
|
||||
auto width;
|
||||
alt (p.buffered.(0)) {case(brk(?w)) {width = w;}}
|
||||
auto i = 0u;
|
||||
while (i < width) {write_str(" "); i+=1u;}
|
||||
p.col += width;
|
||||
}
|
||||
p.scandepth = 0u;
|
||||
for (token t in _vec.shift[token](p.buffered)) {add_token(p, t);}
|
||||
}
|
||||
|
||||
impure fn start_scan(ps p, token tok) {
|
||||
p.buffered = vec(tok);
|
||||
p.scandepth = 1u;
|
||||
p.bufferedcol = p.col;
|
||||
}
|
||||
|
||||
fn cur_context(ps p) -> context {
|
||||
ret p.context.(_vec.len[context](p.context)-1u);
|
||||
}
|
||||
fn base_indent(ps p) -> uint {
|
||||
auto i = _vec.len[context](p.context);
|
||||
while (i > 0u) {
|
||||
i -= 1u;
|
||||
auto cx = p.context.(i);
|
||||
if (cx.tp == cx_v) {ret cx.indent;}
|
||||
}
|
||||
}
|
||||
|
||||
impure fn do_token(ps p, token tok) {
|
||||
alt (tok) {
|
||||
case (brk(?sz)) {
|
||||
alt (cur_context(p).tp) {
|
||||
case (cx_h) {
|
||||
before_print(p, false);
|
||||
start_scan(p, tok);
|
||||
}
|
||||
case (cx_v) {
|
||||
write_str("\n");
|
||||
p.col = 0u;
|
||||
p.start_of_line = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
case (word(?w)) {
|
||||
before_print(p, false);
|
||||
write_str(w);
|
||||
p.col += _str.byte_len(w); // TODO char_len
|
||||
}
|
||||
case (cword(?w)) {
|
||||
before_print(p, true);
|
||||
write_str(w);
|
||||
p.col += _str.byte_len(w); // TODO char_len
|
||||
}
|
||||
case (open(?tp, ?indent)) {
|
||||
alt (tp) {
|
||||
case (box_hv) {start_scan(p, tok);}
|
||||
case (box_align) {start_scan(p, tok);}
|
||||
case (box_h) {push_context(p, cx_h, indent);}
|
||||
case (box_v) {push_context(p, cx_v, indent);}
|
||||
}
|
||||
}
|
||||
case (close) {pop_context(p);}
|
||||
}
|
||||
}
|
||||
|
||||
impure fn before_print(ps p, bool closing) {
|
||||
if (p.start_of_line) {
|
||||
p.start_of_line = false;
|
||||
auto ind;
|
||||
if (closing) {ind = base_indent(p);}
|
||||
else {ind = cur_context(p).indent;}
|
||||
p.col = ind;
|
||||
while (ind > 0u) {write_str(" "); ind -= 1u;}
|
||||
}
|
||||
}
|
||||
|
||||
fn write_str(str s) {
|
||||
io.writefd(1, _str.bytes(s));
|
||||
}
|
||||
|
||||
fn token_size(token tok) -> uint {
|
||||
alt (tok) {
|
||||
case (brk(?sz)) {ret sz;}
|
||||
case (word(?w)) {ret _str.byte_len(w);}
|
||||
case (cword(?w)) {ret _str.byte_len(w);}
|
||||
case (open(_, _)) {ret 0u;} // TODO exception for V blocks?
|
||||
case (close) {ret 0u;}
|
||||
}
|
||||
}
|
||||
|
||||
impure fn box(ps p, uint indent) {add_token(p, open(box_hv, indent));}
|
||||
impure fn abox(ps p) {add_token(p, open(box_align, 0u));}
|
||||
impure fn vbox(ps p, uint indent) {add_token(p, open(box_v, indent));}
|
||||
impure fn hbox(ps p, uint indent) {add_token(p, open(box_h, indent));}
|
||||
impure fn end(ps p) {add_token(p, close);}
|
||||
impure fn wrd(ps p, str wrd) {add_token(p, word(wrd));}
|
||||
impure fn cwrd(ps p, str wrd) {add_token(p, cword(wrd));}
|
||||
impure fn space(ps p) {add_token(p, brk(1u));}
|
||||
impure fn spaces(ps p, uint n) {add_token(p, brk(n));}
|
||||
impure fn line(ps p) {add_token(p, brk(0u));}
|
||||
708
src/comp/pretty/pprust.rs
Normal file
708
src/comp/pretty/pprust.rs
Normal file
@@ -0,0 +1,708 @@
|
||||
import std._vec;
|
||||
import std._str;
|
||||
import std.option;
|
||||
import front.ast;
|
||||
import pp.box; import pp.abox; import pp.vbox;
|
||||
import pp.end; import pp.wrd; import pp.space; import pp.line;
|
||||
import pp.ps;
|
||||
|
||||
import foo = std.io;
|
||||
|
||||
const uint indent_unit = 2u;
|
||||
const int as_prec = 5;
|
||||
|
||||
impure fn print_ast(ast._mod _mod) {
|
||||
auto s = pp.mkstate(80u);
|
||||
for (@ast.view_item vitem in _mod.view_items) {print_view_item(s, vitem);}
|
||||
line(s);
|
||||
for (@ast.item item in _mod.items) {print_item(s, item);}
|
||||
}
|
||||
|
||||
impure fn hbox(ps s) {
|
||||
pp.hbox(s, indent_unit);
|
||||
}
|
||||
impure fn wrd1(ps s, str word) {
|
||||
wrd(s, word);
|
||||
space(s);
|
||||
}
|
||||
impure fn popen(ps s) {
|
||||
wrd(s, "(");
|
||||
abox(s);
|
||||
}
|
||||
impure fn pclose(ps s) {
|
||||
end(s);
|
||||
wrd(s, ")");
|
||||
}
|
||||
impure fn bopen(ps s) {
|
||||
wrd1(s, "{");
|
||||
vbox(s, indent_unit);
|
||||
line(s);
|
||||
}
|
||||
impure fn bclose(ps s) {
|
||||
end(s);
|
||||
pp.cwrd(s, "}");
|
||||
}
|
||||
impure fn commasep[IN](ps s, vec[IN] elts, impure fn (ps, IN) op) {
|
||||
auto first = true;
|
||||
for (IN elt in elts) {
|
||||
if (first) {first = false;}
|
||||
else {wrd1(s, ",");}
|
||||
op(s, elt);
|
||||
}
|
||||
}
|
||||
|
||||
impure fn print_type(ps s, @ast.ty ty) {
|
||||
hbox(s);
|
||||
alt (ty.node) {
|
||||
case (ast.ty_nil) {wrd(s, "()");}
|
||||
case (ast.ty_bool) {wrd(s, "bool");}
|
||||
case (ast.ty_int) {wrd(s, "int");}
|
||||
case (ast.ty_uint) {wrd(s, "uint");}
|
||||
case (ast.ty_machine(?tm)) {wrd(s, util.common.ty_mach_to_str(tm));}
|
||||
case (ast.ty_char) {wrd(s, "char");}
|
||||
case (ast.ty_str) {wrd(s, "str");}
|
||||
case (ast.ty_box(?t)) {wrd(s, "@"); print_type(s, t);}
|
||||
case (ast.ty_vec(?t)) {wrd(s, "vec["); print_type(s, t); wrd(s, "]");}
|
||||
case (ast.ty_type) {wrd(s, "type");}
|
||||
case (ast.ty_tup(?elts)) {
|
||||
wrd(s, "tup");
|
||||
popen(s);
|
||||
auto f = print_type;
|
||||
commasep[@ast.ty](s, elts, f);
|
||||
pclose(s);
|
||||
}
|
||||
case (ast.ty_rec(?fields)) {
|
||||
wrd(s, "rec");
|
||||
popen(s);
|
||||
impure fn print_field(ps s, ast.ty_field f) {
|
||||
hbox(s);
|
||||
print_type(s, f.ty);
|
||||
space(s);
|
||||
wrd(s, f.ident);
|
||||
end(s);
|
||||
}
|
||||
auto f = print_field;
|
||||
commasep[ast.ty_field](s, fields, f);
|
||||
pclose(s);
|
||||
}
|
||||
case (ast.ty_fn(?proto,?inputs,?output)) {
|
||||
if (proto == ast.proto_fn) {wrd(s, "fn");}
|
||||
else {wrd(s, "iter");}
|
||||
popen(s);
|
||||
impure fn print_arg(ps s, ast.ty_arg input) {
|
||||
if (middle.ty.mode_is_alias(input.mode)) {wrd(s, "&");}
|
||||
print_type(s, input.ty);
|
||||
}
|
||||
auto f = print_arg;
|
||||
commasep[ast.ty_arg](s, inputs, f);
|
||||
pclose(s);
|
||||
if (output.node != ast.ty_nil) {
|
||||
space(s);
|
||||
hbox(s);
|
||||
wrd1(s, "->");
|
||||
print_type(s, output);
|
||||
end(s);
|
||||
}
|
||||
}
|
||||
case (ast.ty_path(?path,_)) {
|
||||
print_path(s, path);
|
||||
}
|
||||
case (ast.ty_mutable(?t)) {
|
||||
wrd1(s, "mutable");
|
||||
print_type(s, t);
|
||||
}
|
||||
}
|
||||
end(s);
|
||||
}
|
||||
|
||||
impure fn print_item(ps s, @ast.item item) {
|
||||
hbox(s);
|
||||
alt (item.node) {
|
||||
case (ast.item_const(?id, ?ty, ?expr, _, _)) {
|
||||
wrd1(s, "const");
|
||||
print_type(s, ty);
|
||||
space(s);
|
||||
wrd1(s, id);
|
||||
wrd1(s, "=");
|
||||
print_expr(s, expr);
|
||||
wrd(s, ";");
|
||||
}
|
||||
case (ast.item_fn(?name,?_fn,?typarams,_,_)) {
|
||||
print_fn(s, _fn.decl, name, typarams);
|
||||
space(s);
|
||||
print_block(s, _fn.body);
|
||||
}
|
||||
case (ast.item_mod(?id,?_mod,_)) {
|
||||
wrd1(s, "mod");
|
||||
wrd1(s, id);
|
||||
bopen(s);
|
||||
for (@ast.item itm in _mod.items) {print_item(s, itm);}
|
||||
bclose(s);
|
||||
}
|
||||
case (ast.item_native_mod(?id,?nmod,_)) {
|
||||
wrd1(s, "native");
|
||||
alt (nmod.abi) {
|
||||
case (ast.native_abi_rust) {wrd1(s, "\"rust\"");}
|
||||
case (ast.native_abi_cdecl) {wrd1(s, "\"cdecl\"");}
|
||||
}
|
||||
wrd1(s, "mod");
|
||||
wrd1(s, id);
|
||||
bopen(s);
|
||||
for (@ast.native_item item in nmod.items) {
|
||||
hbox(s);
|
||||
alt (item.node) {
|
||||
case (ast.native_item_ty(?id,_)) {
|
||||
wrd1(s, "type");
|
||||
wrd(s, id);
|
||||
}
|
||||
case (ast.native_item_fn(?id,?decl,?typarams,_,_)) {
|
||||
print_fn(s, decl, id, typarams);
|
||||
}
|
||||
}
|
||||
wrd(s, ";");
|
||||
end(s);
|
||||
}
|
||||
bclose(s);
|
||||
}
|
||||
case (ast.item_ty(?id,?ty,?params,_,_)) {
|
||||
wrd1(s, "type");
|
||||
wrd(s, id);
|
||||
print_type_params(s, params);
|
||||
space(s);
|
||||
wrd1(s, "=");
|
||||
print_type(s, ty);
|
||||
wrd(s, ";");
|
||||
}
|
||||
case (ast.item_tag(?id,?variants,?params,_)) {
|
||||
wrd1(s, "tag");
|
||||
wrd(s, id);
|
||||
print_type_params(s, params);
|
||||
space(s);
|
||||
bopen(s);
|
||||
for (ast.variant v in variants) {
|
||||
wrd(s, v.name);
|
||||
if (_vec.len[ast.variant_arg](v.args) > 0u) {
|
||||
popen(s);
|
||||
impure fn print_variant_arg(ps s, ast.variant_arg arg) {
|
||||
print_type(s, arg.ty);
|
||||
}
|
||||
auto f = print_variant_arg;
|
||||
commasep[ast.variant_arg](s, v.args, f);
|
||||
pclose(s);
|
||||
}
|
||||
wrd(s, ";");
|
||||
line(s);
|
||||
}
|
||||
bclose(s);
|
||||
}
|
||||
case (ast.item_obj(?id,?_obj,?params,_,_)) {
|
||||
wrd1(s, "obj");
|
||||
wrd(s, id);
|
||||
print_type_params(s, params);
|
||||
popen(s);
|
||||
impure fn print_field(ps s, ast.obj_field field) {
|
||||
hbox(s);
|
||||
print_type(s, field.ty);
|
||||
space(s);
|
||||
wrd(s, field.ident);
|
||||
end(s);
|
||||
}
|
||||
auto f = print_field;
|
||||
commasep[ast.obj_field](s, _obj.fields, f);
|
||||
pclose(s);
|
||||
space(s);
|
||||
bopen(s);
|
||||
for (@ast.method meth in _obj.methods) {
|
||||
hbox(s);
|
||||
let vec[ast.ty_param] typarams = vec();
|
||||
print_fn(s, meth.node.meth.decl, meth.node.ident, typarams);
|
||||
space(s);
|
||||
print_block(s, meth.node.meth.body);
|
||||
end(s);
|
||||
line(s);
|
||||
}
|
||||
alt (_obj.dtor) {
|
||||
case (option.some[ast.block](?dtor)) {
|
||||
hbox(s);
|
||||
wrd1(s, "close");
|
||||
print_block(s, dtor);
|
||||
end(s);
|
||||
line(s);
|
||||
}
|
||||
case (_) {}
|
||||
}
|
||||
bclose(s);
|
||||
}
|
||||
}
|
||||
end(s);
|
||||
line(s);
|
||||
line(s);
|
||||
}
|
||||
|
||||
impure fn print_block(ps s, ast.block blk) {
|
||||
bopen(s);
|
||||
for (@ast.stmt st in blk.node.stmts) {
|
||||
alt (st.node) {
|
||||
case (ast.stmt_decl(?decl)) {print_decl(s, decl);}
|
||||
case (ast.stmt_expr(?expr)) {print_expr(s, expr);}
|
||||
}
|
||||
if (front.parser.stmt_ends_with_semi(st)) {wrd(s, ";");}
|
||||
line(s);
|
||||
}
|
||||
alt (blk.node.expr) {
|
||||
case (option.some[@ast.expr](?expr)) {
|
||||
print_expr(s, expr);
|
||||
line(s);
|
||||
}
|
||||
case (_) {}
|
||||
}
|
||||
bclose(s);
|
||||
}
|
||||
|
||||
impure fn print_literal(ps s, @ast.lit lit) {
|
||||
alt (lit.node) {
|
||||
case (ast.lit_str(?st)) {print_string(s, st);}
|
||||
case (ast.lit_char(?ch)) {
|
||||
wrd(s, "'" + escape_str(_str.from_bytes(vec(ch as u8)), '\'') + "'");
|
||||
}
|
||||
case (ast.lit_int(?val)) {
|
||||
wrd(s, util.common.istr(val));
|
||||
}
|
||||
case (ast.lit_uint(?val)) { // TODO clipping? uistr?
|
||||
wrd(s, util.common.istr(val as int) + "u");
|
||||
}
|
||||
case (ast.lit_mach_int(?mach,?val)) {
|
||||
wrd(s, util.common.istr(val as int));
|
||||
wrd(s, util.common.ty_mach_to_str(mach));
|
||||
}
|
||||
case (ast.lit_nil) {wrd(s, "()");}
|
||||
case (ast.lit_bool(?val)) {
|
||||
if (val) {wrd(s, "true");} else {wrd(s, "false");}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impure fn print_expr(ps s, @ast.expr expr) {
|
||||
auto pe = print_expr;
|
||||
hbox(s);
|
||||
alt (expr.node) {
|
||||
case (ast.expr_vec(?exprs,_)) {
|
||||
wrd(s, "vec");
|
||||
popen(s);
|
||||
commasep[@ast.expr](s, exprs, pe);
|
||||
pclose(s);
|
||||
}
|
||||
case (ast.expr_tup(?exprs,_)) {
|
||||
impure fn printElt(ps s, ast.elt elt) {
|
||||
hbox(s);
|
||||
if (elt.mut == ast.mut) {wrd1(s, "mutable");}
|
||||
print_expr(s, elt.expr);
|
||||
end(s);
|
||||
}
|
||||
wrd(s, "tup");
|
||||
popen(s);
|
||||
auto f = printElt;
|
||||
commasep[ast.elt](s, exprs, f);
|
||||
pclose(s);
|
||||
}
|
||||
case (ast.expr_rec(?fields,_,_)) {
|
||||
impure fn print_field(ps s, ast.field field) {
|
||||
hbox(s);
|
||||
if (field.mut == ast.mut) {wrd1(s, "mutable");}
|
||||
wrd(s, field.ident);
|
||||
wrd(s, "=");
|
||||
print_expr(s, field.expr);
|
||||
end(s);
|
||||
}
|
||||
wrd(s, "rec");
|
||||
popen(s);
|
||||
auto f = print_field;
|
||||
commasep[ast.field](s, fields, f);
|
||||
pclose(s);
|
||||
}
|
||||
case (ast.expr_call(?func,?args,_)) {
|
||||
print_expr(s, func);
|
||||
popen(s);
|
||||
commasep[@ast.expr](s, args, pe);
|
||||
pclose(s);
|
||||
}
|
||||
case (ast.expr_bind(?func,?args,_)) {
|
||||
impure fn print_opt(ps s, option.t[@ast.expr] expr) {
|
||||
alt (expr) {
|
||||
case (option.some[@ast.expr](?expr)) {
|
||||
print_expr(s, expr);
|
||||
}
|
||||
case (_) {wrd(s, "_");}
|
||||
}
|
||||
}
|
||||
wrd1(s, "bind");
|
||||
print_expr(s, func);
|
||||
popen(s);
|
||||
auto f = print_opt;
|
||||
commasep[option.t[@ast.expr]](s, args, f);
|
||||
pclose(s);
|
||||
}
|
||||
case (ast.expr_binary(?op,?lhs,?rhs,_)) {
|
||||
auto prec = operator_prec(op);
|
||||
print_maybe_parens(s, lhs, prec);
|
||||
space(s);
|
||||
wrd1(s, ast.binop_to_str(op));
|
||||
print_maybe_parens(s, rhs, prec + 1);
|
||||
}
|
||||
case (ast.expr_unary(?op,?expr,_)) {
|
||||
wrd(s, ast.unop_to_str(op));
|
||||
if (op == ast._mutable) {space(s);}
|
||||
print_expr(s, expr);
|
||||
}
|
||||
case (ast.expr_lit(?lit,_)) {
|
||||
print_literal(s, lit);
|
||||
}
|
||||
case (ast.expr_cast(?expr,?ty,_)) {
|
||||
print_maybe_parens(s, expr, as_prec);
|
||||
space(s);
|
||||
wrd1(s, "as");
|
||||
print_type(s, ty);
|
||||
}
|
||||
case (ast.expr_if(?test,?block,?elseopt,_)) {
|
||||
wrd1(s, "if");
|
||||
popen(s);
|
||||
print_expr(s, test);
|
||||
pclose(s);
|
||||
space(s);
|
||||
print_block(s, block);
|
||||
alt (elseopt) {
|
||||
case (option.some[@ast.expr](?_else)) {
|
||||
space(s);
|
||||
wrd1(s, "else");
|
||||
print_expr(s, _else);
|
||||
}
|
||||
}
|
||||
}
|
||||
case (ast.expr_while(?test,?block,_)) {
|
||||
wrd1(s, "while");
|
||||
popen(s);
|
||||
print_expr(s, test);
|
||||
pclose(s);
|
||||
space(s);
|
||||
print_block(s, block);
|
||||
}
|
||||
case (ast.expr_for(?decl,?expr,?block,_)) {
|
||||
wrd1(s, "for");
|
||||
popen(s);
|
||||
print_decl(s, decl);
|
||||
space(s);
|
||||
wrd1(s, "in");
|
||||
print_expr(s, expr);
|
||||
pclose(s);
|
||||
space(s);
|
||||
print_block(s, block);
|
||||
}
|
||||
case (ast.expr_for_each(?decl,?expr,?block,_)) {
|
||||
wrd1(s, "for each");
|
||||
popen(s);
|
||||
print_decl(s, decl);
|
||||
space(s);
|
||||
wrd1(s, "in");
|
||||
print_expr(s, expr);
|
||||
space(s);
|
||||
print_block(s, block);
|
||||
}
|
||||
case (ast.expr_do_while(?block,?expr,_)) {
|
||||
wrd1(s, "do");
|
||||
space(s);
|
||||
print_block(s, block);
|
||||
space(s);
|
||||
wrd1(s, "while");
|
||||
popen(s);
|
||||
print_expr(s, expr);
|
||||
pclose(s);
|
||||
}
|
||||
case (ast.expr_alt(?expr,?arms,_)) {
|
||||
wrd1(s, "alt");
|
||||
popen(s);
|
||||
print_expr(s, expr);
|
||||
pclose(s);
|
||||
space(s);
|
||||
bopen(s);
|
||||
for (ast.arm arm in arms) {
|
||||
hbox(s);
|
||||
wrd1(s, "case");
|
||||
popen(s);
|
||||
print_pat(s, arm.pat);
|
||||
pclose(s);
|
||||
space(s);
|
||||
print_block(s, arm.block);
|
||||
end(s);
|
||||
line(s);
|
||||
}
|
||||
bclose(s);
|
||||
}
|
||||
case (ast.expr_block(?block,_)) {
|
||||
print_block(s, block);
|
||||
}
|
||||
case (ast.expr_assign(?lhs,?rhs,_)) {
|
||||
print_expr(s, lhs);
|
||||
space(s);
|
||||
wrd1(s, "=");
|
||||
print_expr(s, rhs);
|
||||
}
|
||||
case (ast.expr_assign_op(?op,?lhs,?rhs,_)) {
|
||||
print_expr(s, lhs);
|
||||
space(s);
|
||||
wrd(s, ast.binop_to_str(op));
|
||||
wrd1(s, "=");
|
||||
print_expr(s, rhs);
|
||||
}
|
||||
case (ast.expr_field(?expr,?id,_)) {
|
||||
print_expr(s, expr);
|
||||
wrd(s, ".");
|
||||
wrd(s, id);
|
||||
}
|
||||
case (ast.expr_index(?expr,?index,_)) {
|
||||
print_expr(s, expr);
|
||||
wrd(s, ".");
|
||||
popen(s);
|
||||
print_expr(s, index);
|
||||
pclose(s);
|
||||
}
|
||||
case (ast.expr_path(?path,_,_)) {
|
||||
print_path(s, path);
|
||||
}
|
||||
case (ast.expr_fail) {
|
||||
wrd(s, "fail");
|
||||
}
|
||||
case (ast.expr_ret(?result)) {
|
||||
wrd(s, "ret");
|
||||
alt (result) {
|
||||
case (option.some[@ast.expr](?expr)) {
|
||||
space(s);
|
||||
print_expr(s, expr);
|
||||
}
|
||||
case (_) {}
|
||||
}
|
||||
}
|
||||
case (ast.expr_put(?result)) {
|
||||
wrd(s, "put");
|
||||
alt (result) {
|
||||
case (option.some[@ast.expr](?expr)) {
|
||||
space(s);
|
||||
print_expr(s, expr);
|
||||
}
|
||||
case (_) {}
|
||||
}
|
||||
}
|
||||
case (ast.expr_be(?result)) {
|
||||
wrd1(s, "be");
|
||||
print_expr(s, result);
|
||||
}
|
||||
case (ast.expr_log(?expr)) {
|
||||
wrd1(s, "log");
|
||||
print_expr(s, expr);
|
||||
}
|
||||
case (ast.expr_check_expr(?expr)) {
|
||||
wrd1(s, "check");
|
||||
print_expr(s, expr);
|
||||
}
|
||||
case (_) {wrd(s, "X");}
|
||||
// TODO expr_ext(path, vec[@expr], option.t[@expr], @expr, ann);
|
||||
}
|
||||
end(s);
|
||||
}
|
||||
|
||||
impure fn print_decl(ps s, @ast.decl decl) {
|
||||
hbox(s);
|
||||
alt (decl.node) {
|
||||
case (ast.decl_local(?loc)) {
|
||||
alt (loc.ty) {
|
||||
case (option.some[@ast.ty](?ty)) {
|
||||
wrd1(s, "let");
|
||||
print_type(s, ty);
|
||||
space(s);
|
||||
}
|
||||
case (_) {
|
||||
wrd1(s, "auto");
|
||||
}
|
||||
}
|
||||
wrd(s, loc.ident);
|
||||
alt (loc.init) {
|
||||
case (option.some[@ast.expr](?init)) {
|
||||
space(s);
|
||||
wrd1(s, "=");
|
||||
print_expr(s, init);
|
||||
}
|
||||
case (_) {}
|
||||
}
|
||||
}
|
||||
case (ast.decl_item(?item)) {
|
||||
print_item(s, item);
|
||||
}
|
||||
}
|
||||
end(s);
|
||||
}
|
||||
|
||||
impure fn print_path(ps s, ast.path path) {
|
||||
auto first = true;
|
||||
for (str id in path.node.idents) {
|
||||
if (first) {first = false;}
|
||||
else {wrd(s, ".");}
|
||||
wrd(s, id);
|
||||
}
|
||||
if (_vec.len[@ast.ty](path.node.types) > 0u) {
|
||||
wrd(s, "[");
|
||||
auto f = print_type;
|
||||
commasep[@ast.ty](s, path.node.types, f);
|
||||
wrd(s, "]");
|
||||
}
|
||||
}
|
||||
|
||||
impure fn print_pat(ps s, @ast.pat pat) {
|
||||
alt (pat.node) {
|
||||
case (ast.pat_wild(_)) {wrd(s, "_");}
|
||||
case (ast.pat_bind(?id,_,_)) {wrd(s, "?" + id);}
|
||||
case (ast.pat_lit(?lit,_)) {print_literal(s, lit);}
|
||||
case (ast.pat_tag(?path,?args,_,_)) {
|
||||
print_path(s, path);
|
||||
if (_vec.len[@ast.pat](args) > 0u) {
|
||||
popen(s);
|
||||
auto f = print_pat;
|
||||
commasep[@ast.pat](s, args, f);
|
||||
pclose(s);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impure fn print_fn(ps s, ast.fn_decl decl, str name,
|
||||
vec[ast.ty_param] typarams) {
|
||||
alt (decl.effect) {
|
||||
case (ast.eff_impure) {wrd1(s, "impure");}
|
||||
case (ast.eff_unsafe) {wrd1(s, "unsafe");}
|
||||
case (_) {}
|
||||
}
|
||||
wrd1(s, "fn");
|
||||
wrd(s, name);
|
||||
print_type_params(s, typarams);
|
||||
popen(s);
|
||||
impure fn print_arg(ps s, ast.arg x) {
|
||||
hbox(s);
|
||||
print_type(s, x.ty);
|
||||
space(s);
|
||||
wrd(s, x.ident);
|
||||
end(s);
|
||||
}
|
||||
auto f = print_arg;
|
||||
commasep[ast.arg](s, decl.inputs, f);
|
||||
pclose(s);
|
||||
if (decl.output.node != ast.ty_nil) {
|
||||
space(s);
|
||||
hbox(s);
|
||||
wrd1(s, "->");
|
||||
print_type(s, decl.output);
|
||||
end(s);
|
||||
}
|
||||
}
|
||||
|
||||
impure fn print_type_params(ps s, vec[ast.ty_param] params) {
|
||||
if (_vec.len[ast.ty_param](params) > 0u) {
|
||||
wrd(s, "[");
|
||||
impure fn printParam(ps s, ast.ty_param param) {wrd(s, param.ident);}
|
||||
auto f = printParam;
|
||||
commasep[ast.ty_param](s, params, f);
|
||||
wrd(s, "]");
|
||||
}
|
||||
}
|
||||
|
||||
impure fn print_view_item(ps s, @ast.view_item item) {
|
||||
hbox(s);
|
||||
alt (item.node) {
|
||||
case (ast.view_item_use(?id,?mta,_)) {
|
||||
wrd1(s, "use");
|
||||
wrd(s, id);
|
||||
if (_vec.len[@ast.meta_item](mta) > 0u) {
|
||||
popen(s);
|
||||
impure fn print_meta(ps s, @ast.meta_item item) {
|
||||
hbox(s);
|
||||
wrd1(s, item.node.name);
|
||||
wrd1(s, "=");
|
||||
print_string(s, item.node.value);
|
||||
end(s);
|
||||
}
|
||||
auto f = print_meta;
|
||||
commasep[@ast.meta_item](s, mta, f);
|
||||
pclose(s);
|
||||
}
|
||||
}
|
||||
case (ast.view_item_import(?id,?ids,_,_)) {
|
||||
wrd1(s, "import");
|
||||
if (!_str.eq(id, ids.(_vec.len[str](ids)-1u))) {
|
||||
wrd1(s, id);
|
||||
wrd1(s, "=");
|
||||
}
|
||||
auto first = true;
|
||||
for (str elt in ids) {
|
||||
if (first) {first = false;}
|
||||
else {wrd(s, ".");}
|
||||
wrd(s, elt);
|
||||
}
|
||||
}
|
||||
case (ast.view_item_export(?id)) {
|
||||
wrd1(s, "export");
|
||||
wrd(s, id);
|
||||
}
|
||||
}
|
||||
end(s);
|
||||
wrd(s, ";");
|
||||
line(s);
|
||||
}
|
||||
|
||||
// FIXME: The fact that this builds up the table anew for every call is
|
||||
// not good. Eventually, table should be a const.
|
||||
fn operator_prec(ast.binop op) -> int {
|
||||
for (front.parser.op_spec spec in front.parser.prec_table()) {
|
||||
if (spec.op == op) {ret spec.prec;}
|
||||
}
|
||||
fail;
|
||||
}
|
||||
|
||||
impure fn print_maybe_parens(ps s, @ast.expr expr, int outer_prec) {
|
||||
auto add_them;
|
||||
alt (expr.node) {
|
||||
case (ast.expr_binary(?op,_,_,_)) {
|
||||
add_them = operator_prec(op) < outer_prec;
|
||||
}
|
||||
case (ast.expr_cast(_,_,_)) {
|
||||
add_them = as_prec < outer_prec;
|
||||
}
|
||||
case (_) {
|
||||
add_them = false;
|
||||
}
|
||||
}
|
||||
if (add_them) {popen(s);}
|
||||
print_expr(s, expr);
|
||||
if (add_them) {pclose(s);}
|
||||
}
|
||||
|
||||
// TODO non-ascii
|
||||
fn escape_str(str st, char to_escape) -> str {
|
||||
let str out = "";
|
||||
auto len = _str.byte_len(st);
|
||||
auto i = 0u;
|
||||
while (i < len) {
|
||||
alt (st.(i) as char) {
|
||||
case ('\n') {out += "\\n";}
|
||||
case ('\t') {out += "\\t";}
|
||||
case ('\r') {out += "\\r";}
|
||||
case ('\\') {out += "\\\\";}
|
||||
case (?cur) {
|
||||
if (cur == to_escape) {out += "\\";}
|
||||
out += cur as u8;
|
||||
}
|
||||
}
|
||||
i += 1u;
|
||||
}
|
||||
ret out;
|
||||
}
|
||||
|
||||
impure fn print_string(ps s, str st) {
|
||||
wrd(s, "\""); wrd(s, escape_str(st, '"')); wrd(s, "\"");
|
||||
}
|
||||
@@ -5,9 +5,12 @@ use std;
|
||||
|
||||
mod front {
|
||||
mod ast;
|
||||
mod extfmt;
|
||||
mod lexer;
|
||||
mod parser;
|
||||
mod pretty;
|
||||
mod token;
|
||||
mod eval;
|
||||
}
|
||||
|
||||
mod middle {
|
||||
@@ -28,6 +31,11 @@ mod driver {
|
||||
mod session;
|
||||
}
|
||||
|
||||
mod pretty {
|
||||
mod pp;
|
||||
mod pprust;
|
||||
}
|
||||
|
||||
mod util {
|
||||
mod common;
|
||||
}
|
||||
@@ -38,7 +46,6 @@ auth middle.trans.copy_args_to_allocas = impure;
|
||||
auth middle.trans.trans_block = impure;
|
||||
auth lib.llvm = unsafe;
|
||||
|
||||
|
||||
mod lib {
|
||||
alt (target_os) {
|
||||
case ("win32") {
|
||||
|
||||
@@ -2,8 +2,10 @@ import std._uint;
|
||||
import std._int;
|
||||
import front.ast;
|
||||
|
||||
|
||||
type filename = str;
|
||||
type pos = rec(uint line, uint col);
|
||||
type span = rec(str filename, pos lo, pos hi);
|
||||
type span = rec(filename filename, pos lo, pos hi);
|
||||
type spanned[T] = rec(T node, span span);
|
||||
|
||||
tag ty_mach {
|
||||
|
||||
@@ -96,25 +96,10 @@ fn buf(str s) -> sbuf {
|
||||
}
|
||||
|
||||
fn bytes(str s) -> vec[u8] {
|
||||
/* FIXME (issue #58):
|
||||
* Should be...
|
||||
*
|
||||
* fn ith(str s, uint i) -> u8 {
|
||||
* ret s.(i);
|
||||
* }
|
||||
* ret _vec.init_fn[u8](bind ith(s, _), byte_len(s));
|
||||
*
|
||||
* but we do not correctly decrement refcount of s when
|
||||
* the binding dies, so we have to do this manually.
|
||||
*/
|
||||
let uint n = _str.byte_len(s);
|
||||
let vec[u8] v = _vec.alloc[u8](n);
|
||||
let uint i = 0u;
|
||||
while (i < n) {
|
||||
v += vec(s.(i));
|
||||
i += 1u;
|
||||
fn ith(str s, uint i) -> u8 {
|
||||
ret s.(i);
|
||||
}
|
||||
ret v;
|
||||
ret _vec.init_fn[u8](bind ith(s, _), byte_len(s));
|
||||
}
|
||||
|
||||
fn from_bytes(vec[u8] v) : is_utf8(v) -> str {
|
||||
|
||||
@@ -85,24 +85,13 @@ fn new_buf_reader(str path) -> buf_reader {
|
||||
ret fd_buf_reader(fd, new_buf());
|
||||
}
|
||||
|
||||
/**
|
||||
* FIXME (issue #150): This should be
|
||||
*
|
||||
* type fileflag = tag(append(), create(), truncate());
|
||||
*
|
||||
* but then the tag value ctors are not found from crate-importers of std, so
|
||||
* we manually simulate the enum below.
|
||||
*/
|
||||
type fileflag = uint;
|
||||
fn append() -> uint { ret 0u; }
|
||||
fn create() -> uint { ret 1u; }
|
||||
fn truncate() -> uint { ret 2u; }
|
||||
tag fileflag {
|
||||
append;
|
||||
create;
|
||||
truncate;
|
||||
}
|
||||
|
||||
fn new_buf_writer(str path, vec[fileflag] flags) -> buf_writer {
|
||||
|
||||
state obj fd_buf_writer(int fd) {
|
||||
|
||||
fn write(vec[u8] v) {
|
||||
fn writefd(int fd, vec[u8] v) {
|
||||
auto len = _vec.len[u8](v);
|
||||
auto count = 0u;
|
||||
auto vbuf;
|
||||
@@ -116,6 +105,14 @@ fn new_buf_writer(str path, vec[fileflag] flags) -> buf_writer {
|
||||
}
|
||||
count += nout as uint;
|
||||
}
|
||||
}
|
||||
|
||||
fn new_buf_writer(str path, vec[fileflag] flags) -> buf_writer {
|
||||
|
||||
state obj fd_buf_writer(int fd) {
|
||||
|
||||
fn write(vec[u8] v) {
|
||||
writefd(fd, v);
|
||||
}
|
||||
|
||||
drop {
|
||||
@@ -129,13 +126,9 @@ fn new_buf_writer(str path, vec[fileflag] flags) -> buf_writer {
|
||||
|
||||
for (fileflag f in flags) {
|
||||
alt (f) {
|
||||
// FIXME (issue #150): cf comment above defn of fileflag type
|
||||
//case (append()) { fflags |= os.libc_constants.O_APPEND(); }
|
||||
//case (create()) { fflags |= os.libc_constants.O_CREAT(); }
|
||||
//case (truncate()) { fflags |= os.libc_constants.O_TRUNC(); }
|
||||
case (0u) { fflags |= os.libc_constants.O_APPEND(); }
|
||||
case (1u) { fflags |= os.libc_constants.O_CREAT(); }
|
||||
case (2u) { fflags |= os.libc_constants.O_TRUNC(); }
|
||||
case (append) { fflags |= os.libc_constants.O_APPEND(); }
|
||||
case (create) { fflags |= os.libc_constants.O_CREAT(); }
|
||||
case (truncate) { fflags |= os.libc_constants.O_TRUNC(); }
|
||||
}
|
||||
}
|
||||
|
||||
284
src/lib/sha1.rs
Normal file
284
src/lib/sha1.rs
Normal file
@@ -0,0 +1,284 @@
|
||||
/*
|
||||
* A SHA-1 implementation derived from Paul E. Jones's reference
|
||||
* implementation, which is written for clarity, not speed. At some
|
||||
* point this will want to be rewritten.
|
||||
*/
|
||||
|
||||
import std._vec;
|
||||
import std._str;
|
||||
|
||||
export sha1;
|
||||
export mk_sha1;
|
||||
|
||||
state type sha1 = state obj {
|
||||
// Provide message input as bytes
|
||||
fn input(&vec[u8]);
|
||||
|
||||
// Provide message input as string
|
||||
fn input_str(&str);
|
||||
|
||||
// Read the digest as a vector of 20 bytes. After
|
||||
// calling this no further input may provided
|
||||
// until reset is called
|
||||
fn result() -> vec[u8];
|
||||
|
||||
// Reset the sha1 state for reuse. This is called
|
||||
// automatically during construction
|
||||
fn reset();
|
||||
};
|
||||
|
||||
// Some unexported constants
|
||||
const uint digest_buf_len = 5;
|
||||
const uint msg_block_len = 64;
|
||||
|
||||
// Builds a sha1 object
|
||||
fn mk_sha1() -> sha1 {
|
||||
|
||||
state type sha1state = rec(vec[mutable u32] h,
|
||||
mutable u32 len_low,
|
||||
mutable u32 len_high,
|
||||
vec[mutable u8] msg_block,
|
||||
mutable uint msg_block_idx,
|
||||
mutable bool computed);
|
||||
|
||||
impure fn add_input(&sha1state st, &vec[u8] msg) {
|
||||
// FIXME: Should be typestate precondition
|
||||
check (!st.computed);
|
||||
|
||||
for (u8 element in msg) {
|
||||
st.msg_block.(st.msg_block_idx) = element;
|
||||
st.msg_block_idx += 1u;
|
||||
|
||||
st.len_low += 8u32;
|
||||
if (st.len_low == 0u32) {
|
||||
st.len_high += 1u32;
|
||||
if (st.len_high == 0u32) {
|
||||
// FIXME: Need better failure mode
|
||||
fail;
|
||||
}
|
||||
}
|
||||
|
||||
if (st.msg_block_idx == msg_block_len) {
|
||||
process_msg_block(st);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impure fn process_msg_block(&sha1state st) {
|
||||
|
||||
// FIXME: Make precondition
|
||||
check (_vec.len[mutable u32](st.h) == digest_buf_len);
|
||||
|
||||
// Constants
|
||||
auto k = vec(0x5A827999u32,
|
||||
0x6ED9EBA1u32,
|
||||
0x8F1BBCDCu32,
|
||||
0xCA62C1D6u32);
|
||||
|
||||
let int t; // Loop counter
|
||||
let vec[mutable u32] w = _vec.init_elt[mutable u32](0u32, 80u);
|
||||
|
||||
// Initialize the first 16 words of the vector w
|
||||
t = 0;
|
||||
while (t < 16) {
|
||||
w.(t) = (st.msg_block.(t * 4) as u32) << 24u32;
|
||||
w.(t) = w.(t) | ((st.msg_block.(t * 4 + 1) as u32) << 16u32);
|
||||
w.(t) = w.(t) | ((st.msg_block.(t * 4 + 2) as u32) << 8u32);
|
||||
w.(t) = w.(t) | (st.msg_block.(t * 4 + 3) as u32);
|
||||
t += 1;
|
||||
}
|
||||
|
||||
// Initialize the rest of vector w
|
||||
while (t < 80) {
|
||||
auto val = w.(t-3) ^ w.(t-8) ^ w.(t-14) ^ w.(t-16);
|
||||
w.(t) = circular_shift(1u32, val);
|
||||
t += 1;
|
||||
}
|
||||
|
||||
auto a = st.h.(0);
|
||||
auto b = st.h.(1);
|
||||
auto c = st.h.(2);
|
||||
auto d = st.h.(3);
|
||||
auto e = st.h.(4);
|
||||
|
||||
let u32 temp;
|
||||
|
||||
t = 0;
|
||||
while (t < 20) {
|
||||
temp = circular_shift(5u32, a)
|
||||
+ ((b & c) | ((~b) & d)) + e + w.(t) + k.(0);
|
||||
e = d;
|
||||
d = c;
|
||||
c = circular_shift(30u32, b);
|
||||
b = a;
|
||||
a = temp;
|
||||
t += 1;
|
||||
}
|
||||
|
||||
while (t < 40) {
|
||||
temp = circular_shift(5u32, a)
|
||||
+ (b ^ c ^ d) + e + w.(t) + k.(1);
|
||||
e = d;
|
||||
d = c;
|
||||
c = circular_shift(30u32, b);
|
||||
b = a;
|
||||
a = temp;
|
||||
t += 1;
|
||||
}
|
||||
|
||||
while (t < 60) {
|
||||
temp = circular_shift(5u32, a)
|
||||
+ ((b & c) | (b & d) | (c & d)) + e + w.(t) + k.(2);
|
||||
e = d;
|
||||
d = c;
|
||||
c = circular_shift(30u32, b);
|
||||
b = a;
|
||||
a = temp;
|
||||
t += 1;
|
||||
}
|
||||
|
||||
while (t < 80) {
|
||||
temp = circular_shift(5u32, a)
|
||||
+ (b ^ c ^ d) + e + w.(t) + k.(3);
|
||||
e = d;
|
||||
d = c;
|
||||
c = circular_shift(30u32, b);
|
||||
b = a;
|
||||
a = temp;
|
||||
t += 1;
|
||||
}
|
||||
|
||||
st.h.(0) = st.h.(0) + a;
|
||||
st.h.(1) = st.h.(1) + b;
|
||||
st.h.(2) = st.h.(2) + c;
|
||||
st.h.(3) = st.h.(3) + d;
|
||||
st.h.(4) = st.h.(4) + e;
|
||||
|
||||
st.msg_block_idx = 0u;
|
||||
}
|
||||
|
||||
fn circular_shift(u32 bits, u32 word) -> u32 {
|
||||
// FIXME: This is a workaround for a rustboot
|
||||
// "unrecognized quads" codegen bug
|
||||
auto bits_hack = bits;
|
||||
ret (word << bits_hack) | (word >> (32u32 - bits));
|
||||
}
|
||||
|
||||
impure fn mk_result(&sha1state st) -> vec[u8] {
|
||||
if (!st.computed) {
|
||||
pad_msg(st);
|
||||
st.computed = true;
|
||||
}
|
||||
|
||||
let vec[u8] res = vec();
|
||||
for (u32 hpart in st.h) {
|
||||
res += (hpart >> 24u32) & 0xFFu32 as u8;
|
||||
res += (hpart >> 16u32) & 0xFFu32 as u8;
|
||||
res += (hpart >> 8u32) & 0xFFu32 as u8;
|
||||
res += hpart & 0xFFu32 as u8;
|
||||
}
|
||||
ret res;
|
||||
}
|
||||
|
||||
/*
|
||||
* According to the standard, the message must be padded to an even
|
||||
* 512 bits. The first padding bit must be a '1'. The last 64 bits
|
||||
* represent the length of the original message. All bits in between
|
||||
* should be 0. This function will pad the message according to those
|
||||
* rules by filling the msg_block vector accordingly. It will also
|
||||
* call process_msg_block() appropriately. When it returns, it
|
||||
* can be assumed that the message digest has been computed.
|
||||
*/
|
||||
impure fn pad_msg(&sha1state st) {
|
||||
// FIXME: Should be a precondition
|
||||
check (_vec.len[mutable u8](st.msg_block) == msg_block_len);
|
||||
|
||||
/*
|
||||
* Check to see if the current message block is too small to hold
|
||||
* the initial padding bits and length. If so, we will pad the
|
||||
* block, process it, and then continue padding into a second block.
|
||||
*/
|
||||
if (st.msg_block_idx > 55u) {
|
||||
st.msg_block.(st.msg_block_idx) = 0x80u8;
|
||||
st.msg_block_idx += 1u;
|
||||
|
||||
while (st.msg_block_idx < msg_block_len) {
|
||||
st.msg_block.(st.msg_block_idx) = 0u8;
|
||||
st.msg_block_idx += 1u;
|
||||
}
|
||||
|
||||
process_msg_block(st);
|
||||
} else {
|
||||
st.msg_block.(st.msg_block_idx) = 0x80u8;
|
||||
st.msg_block_idx += 1u;
|
||||
}
|
||||
|
||||
while (st.msg_block_idx < 56u) {
|
||||
st.msg_block.(st.msg_block_idx) = 0u8;
|
||||
st.msg_block_idx += 1u;
|
||||
}
|
||||
|
||||
// Store the message length as the last 8 octets
|
||||
st.msg_block.(56) = (st.len_high >> 24u32) & 0xFFu32 as u8;
|
||||
st.msg_block.(57) = (st.len_high >> 16u32) & 0xFFu32 as u8;
|
||||
st.msg_block.(58) = (st.len_high >> 8u32) & 0xFFu32 as u8;
|
||||
st.msg_block.(59) = st.len_high & 0xFFu32 as u8;
|
||||
st.msg_block.(60) = (st.len_low >> 24u32) & 0xFFu32 as u8;
|
||||
st.msg_block.(61) = (st.len_low >> 16u32) & 0xFFu32 as u8;
|
||||
st.msg_block.(62) = (st.len_low >> 8u32) & 0xFFu32 as u8;
|
||||
st.msg_block.(63) = st.len_low & 0xFFu32 as u8;
|
||||
|
||||
process_msg_block(st);
|
||||
}
|
||||
|
||||
state obj sha1(sha1state st) {
|
||||
|
||||
fn reset() {
|
||||
// FIXME: Should be typestate precondition
|
||||
check (_vec.len[mutable u32](st.h) == digest_buf_len);
|
||||
|
||||
st.len_low = 0u32;
|
||||
st.len_high = 0u32;
|
||||
st.msg_block_idx = 0u;
|
||||
|
||||
st.h.(0) = 0x67452301u32;
|
||||
st.h.(1) = 0xEFCDAB89u32;
|
||||
st.h.(2) = 0x98BADCFEu32;
|
||||
st.h.(3) = 0x10325476u32;
|
||||
st.h.(4) = 0xC3D2E1F0u32;
|
||||
|
||||
st.computed = false;
|
||||
}
|
||||
|
||||
fn input(&vec[u8] msg) {
|
||||
add_input(st, msg);
|
||||
}
|
||||
|
||||
fn input_str(&str msg) {
|
||||
add_input(st, _str.bytes(msg));
|
||||
}
|
||||
|
||||
fn result() -> vec[u8] {
|
||||
ret mk_result(st);
|
||||
}
|
||||
}
|
||||
|
||||
auto st = rec(h = _vec.init_elt[mutable u32](0u32, digest_buf_len),
|
||||
mutable len_low = 0u32,
|
||||
mutable len_high = 0u32,
|
||||
msg_block = _vec.init_elt[mutable u8](0u8, msg_block_len),
|
||||
mutable msg_block_idx = 0u,
|
||||
mutable computed = false);
|
||||
auto sh = sha1(st);
|
||||
sh.reset();
|
||||
ret sh;
|
||||
}
|
||||
|
||||
// Local Variables:
|
||||
// mode: rust;
|
||||
// fill-column: 78;
|
||||
// indent-tabs-mode: nil
|
||||
// c-basic-offset: 4
|
||||
// buffer-file-coding-system: utf-8-unix
|
||||
// compile-command: "make -k -C .. 2>&1 | sed -e 's/\\/x\\//x:\\//g'";
|
||||
// End:
|
||||
@@ -14,7 +14,7 @@ mod _str;
|
||||
|
||||
// General IO and system-services modules.
|
||||
|
||||
mod _io;
|
||||
mod io;
|
||||
mod sys;
|
||||
mod _task;
|
||||
|
||||
@@ -25,7 +25,7 @@ mod util;
|
||||
|
||||
// Authorize various rule-bendings.
|
||||
|
||||
auth _io = unsafe;
|
||||
auth io = unsafe;
|
||||
auth _str = unsafe;
|
||||
auth _vec = unsafe;
|
||||
auth _task = unsafe;
|
||||
@@ -57,6 +57,7 @@ mod dbg;
|
||||
mod bitv;
|
||||
mod sort;
|
||||
mod path;
|
||||
mod sha1;
|
||||
|
||||
// Local Variables:
|
||||
// mode: rust;
|
||||
|
||||
@@ -1,7 +1,10 @@
|
||||
#include "rust_internal.h"
|
||||
#include "memory_region.h"
|
||||
|
||||
#define TRACK_ALLOCATIONS
|
||||
// NB: please do not commit code with this uncommented. It's
|
||||
// hugely expensive and should only be used as a last resort.
|
||||
//
|
||||
// #define TRACK_ALLOCATIONS
|
||||
|
||||
memory_region::memory_region(rust_srv *srv, bool synchronized) :
|
||||
_srv(srv), _parent(NULL), _live_allocations(0),
|
||||
|
||||
@@ -87,7 +87,8 @@ rust_start(uintptr_t main_fn, rust_crate const *crate, int argc,
|
||||
rust_dom *dom = handle->referent();
|
||||
command_line_args *args = new (dom) command_line_args(dom, argc, argv);
|
||||
|
||||
dom->log(rust_log::DOM, "startup: %d args", args->argc);
|
||||
dom->log(rust_log::DOM, "startup: %d args in 0x%" PRIxPTR,
|
||||
args->argc, (uintptr_t)args->args);
|
||||
for (int i = 0; i < args->argc; i++) {
|
||||
dom->log(rust_log::DOM,
|
||||
"startup: arg[%d] = '%s'", i, args->argv[i]);
|
||||
@@ -99,7 +100,8 @@ rust_start(uintptr_t main_fn, rust_crate const *crate, int argc,
|
||||
|
||||
uintptr_t main_args[4] = {0, 0, 0, (uintptr_t)args->args};
|
||||
dom->root_task->start(crate->get_exit_task_glue(),
|
||||
main_fn, (uintptr_t)&main_args, sizeof(main_args));
|
||||
crate->abi_tag, main_fn,
|
||||
(uintptr_t)&main_args, sizeof(main_args));
|
||||
int ret = dom->start_main_loop();
|
||||
delete args;
|
||||
kernel->destroy_domain(dom);
|
||||
|
||||
@@ -49,7 +49,8 @@ rust_crate_cache::c_sym::c_sym(rust_dom *dom, lib *library, char const *name)
|
||||
dom->log(rust_log::CACHE, "resolved symbol '%s' to 0x%" PRIxPTR,
|
||||
name, val);
|
||||
} else {
|
||||
dom->log(rust_log::CACHE, "unresolved symbol '%s', null lib handle",
|
||||
dom->log(rust_log::CACHE | rust_log::ERR,
|
||||
"unresolved symbol '%s', null lib handle",
|
||||
name);
|
||||
}
|
||||
}
|
||||
@@ -79,7 +80,7 @@ rust_crate_cache::rust_sym::rust_sym(rust_dom *dom,
|
||||
typedef rust_crate_reader::die die;
|
||||
rust_crate const *crate = (rust_crate*)crate_sym->get_val();
|
||||
if (!crate) {
|
||||
dom->log(rust_log::CACHE,
|
||||
dom->log(rust_log::CACHE | rust_log::ERR,
|
||||
"failed to resolve symbol, null crate symbol");
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -88,6 +88,10 @@ static size_t const TIME_SLICE_IN_MS = 10;
|
||||
|
||||
static intptr_t const CONST_REFCOUNT = 0x7badface;
|
||||
|
||||
// ABI tags for rust_start, rust_task::start and friends.
|
||||
static uintptr_t const ABI_X86_RUSTBOOT_CDECL = 1;
|
||||
static uintptr_t const ABI_X86_RUSTC_FASTCALL = 2;
|
||||
|
||||
// This accounts for logging buffers.
|
||||
|
||||
static size_t const BUF_BYTES = 2048;
|
||||
@@ -241,6 +245,8 @@ public:
|
||||
size_t n_c_syms;
|
||||
size_t n_libs;
|
||||
|
||||
uintptr_t abi_tag;
|
||||
|
||||
// Crates are immutable, constructed by the compiler.
|
||||
|
||||
uintptr_t get_image_base() const;
|
||||
|
||||
@@ -123,6 +123,7 @@ rust_task::~rust_task()
|
||||
|
||||
void
|
||||
rust_task::start(uintptr_t exit_task_glue,
|
||||
uintptr_t spawnee_abi,
|
||||
uintptr_t spawnee_fn,
|
||||
uintptr_t args,
|
||||
size_t callsz)
|
||||
@@ -147,18 +148,20 @@ rust_task::start(uintptr_t exit_task_glue,
|
||||
// The exit_task_glue frame we synthesize above the frame we activate:
|
||||
*spp-- = (uintptr_t) 0; // closure-or-obj
|
||||
*spp-- = (uintptr_t) this; // task
|
||||
*spp-- = (uintptr_t) 0; // output
|
||||
*spp-- = (uintptr_t) 0; // retpc
|
||||
*spp-- = (uintptr_t) 0x0; // output
|
||||
*spp-- = (uintptr_t) 0x0; // retpc
|
||||
|
||||
uintptr_t exit_task_frame_base;
|
||||
|
||||
if (spawnee_abi == ABI_X86_RUSTBOOT_CDECL) {
|
||||
for (size_t j = 0; j < n_callee_saves; ++j) {
|
||||
|
||||
// We want 'frame_base' to point to the old fp in this (exit-task)
|
||||
// frame, because we're going to inject this frame-pointer into the
|
||||
// callee-save frame pointer value in the *next* (spawnee) frame. A
|
||||
// cheap trick, but this means the spawnee frame will restore the
|
||||
// proper frame pointer of the glue frame as it runs its epilogue.
|
||||
// frame, because we're going to inject this frame-pointer into
|
||||
// the callee-save frame pointer value in the *next* (spawnee)
|
||||
// frame. A cheap trick, but this means the spawnee frame will
|
||||
// restore the proper frame pointer of the glue frame as it runs
|
||||
// its epilogue.
|
||||
if (j == callee_save_fp)
|
||||
exit_task_frame_base = (uintptr_t)spp;
|
||||
|
||||
@@ -167,6 +170,7 @@ rust_task::start(uintptr_t exit_task_glue,
|
||||
|
||||
*spp-- = (uintptr_t) dom->root_crate; // crate ptr
|
||||
*spp-- = (uintptr_t) 0; // frame_glue_fns
|
||||
}
|
||||
|
||||
// Copy args from spawner to spawnee.
|
||||
if (args) {
|
||||
@@ -174,12 +178,16 @@ rust_task::start(uintptr_t exit_task_glue,
|
||||
src += 1; // spawn-call output slot
|
||||
src += 1; // spawn-call task slot
|
||||
src += 1; // spawn-call closure-or-obj slot
|
||||
// Memcpy all but the task and output pointers
|
||||
callsz -= (2 * sizeof(uintptr_t));
|
||||
|
||||
// Undo previous sp-- so we're pointing at the last word pushed.
|
||||
++spp;
|
||||
|
||||
// Memcpy all but the task, output and env pointers
|
||||
callsz -= (3 * sizeof(uintptr_t));
|
||||
spp = (uintptr_t*) (((uintptr_t)spp) - callsz);
|
||||
memcpy(spp, src, callsz);
|
||||
|
||||
// Move sp down to point to task cell.
|
||||
// Move sp down to point to last implicit-arg cell (env).
|
||||
spp--;
|
||||
} else {
|
||||
// We're at root, starting up.
|
||||
@@ -188,10 +196,18 @@ rust_task::start(uintptr_t exit_task_glue,
|
||||
|
||||
// The *implicit* incoming args to the spawnee frame we're
|
||||
// activating:
|
||||
*spp-- = (uintptr_t) 0x0; // closure-or-obj
|
||||
|
||||
*spp-- = (uintptr_t) 0; // closure-or-obj
|
||||
if (spawnee_abi == ABI_X86_RUSTBOOT_CDECL) {
|
||||
// in CDECL mode we write the task + outptr to the spawnee stack.
|
||||
*spp-- = (uintptr_t) this; // task
|
||||
*spp-- = (uintptr_t) 0; // output addr
|
||||
} else {
|
||||
// in FASTCALL mode we don't, the outptr will be in ecx and the task
|
||||
// in edx, and the activate_glue will make sure to set that up.
|
||||
I(dom, spawnee_abi == ABI_X86_RUSTC_FASTCALL);
|
||||
}
|
||||
|
||||
*spp-- = (uintptr_t) exit_task_glue; // retpc
|
||||
|
||||
// The context the activate_glue needs to switch stack.
|
||||
|
||||
@@ -56,6 +56,7 @@ rust_task : public maybe_proxy<rust_task>,
|
||||
~rust_task();
|
||||
|
||||
void start(uintptr_t exit_task_glue,
|
||||
uintptr_t spawnee_abi,
|
||||
uintptr_t spawnee_fn,
|
||||
uintptr_t args,
|
||||
size_t callsz);
|
||||
|
||||
@@ -253,6 +253,10 @@ upcall_fail(rust_task *task,
|
||||
task->log(rust_log::UPCALL | rust_log::ERR,
|
||||
"upcall fail '%s', %s:%" PRIdPTR, expr, file, line);
|
||||
task->fail(4);
|
||||
if (getenv("RUST_TRAP_FAILURE")) {
|
||||
// FIXME: x86-ism.
|
||||
__asm__("int3");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -555,6 +559,7 @@ extern "C" CDECL rust_task *
|
||||
upcall_start_task(rust_task *spawner,
|
||||
rust_task *task,
|
||||
uintptr_t exit_task_glue,
|
||||
uintptr_t spawnee_abi,
|
||||
uintptr_t spawnee_fn,
|
||||
size_t callsz) {
|
||||
LOG_UPCALL_ENTRY(spawner);
|
||||
@@ -566,7 +571,8 @@ upcall_start_task(rust_task *spawner,
|
||||
", spawnee 0x%" PRIxPTR
|
||||
", callsz %" PRIdPTR ")", task->name, task, exit_task_glue,
|
||||
spawnee_fn, callsz);
|
||||
task->start(exit_task_glue, spawnee_fn, spawner->rust_sp, callsz);
|
||||
task->start(exit_task_glue, spawnee_abi, spawnee_fn,
|
||||
spawner->rust_sp, callsz);
|
||||
return task;
|
||||
}
|
||||
|
||||
@@ -619,6 +625,7 @@ extern "C" CDECL maybe_proxy<rust_task> *
|
||||
upcall_start_thread(rust_task *task,
|
||||
rust_proxy<rust_task> *child_task_proxy,
|
||||
uintptr_t exit_task_glue,
|
||||
uintptr_t spawnee_abi,
|
||||
uintptr_t spawnee_fn,
|
||||
size_t callsz) {
|
||||
LOG_UPCALL_ENTRY(task);
|
||||
@@ -626,9 +633,11 @@ upcall_start_thread(rust_task *task,
|
||||
rust_handle<rust_task> *child_task_handle = child_task_proxy->handle();
|
||||
task->log(rust_log::UPCALL | rust_log::MEM | rust_log::TASK,
|
||||
"exit_task_glue: " PTR ", spawnee_fn " PTR
|
||||
", callsz %" PRIdPTR ")", exit_task_glue, spawnee_fn, callsz);
|
||||
", callsz %" PRIdPTR ")",
|
||||
exit_task_glue, spawnee_fn, callsz);
|
||||
rust_task *child_task = child_task_handle->referent();
|
||||
child_task->start(exit_task_glue, spawnee_fn, task->rust_sp, callsz);
|
||||
child_task->start(exit_task_glue, spawnee_abi, spawnee_fn,
|
||||
task->rust_sp, callsz);
|
||||
#if defined(__WIN32__)
|
||||
HANDLE thread;
|
||||
thread = CreateThread(NULL, 0, rust_thread_start, child_task->dom, 0,
|
||||
|
||||
@@ -54,6 +54,7 @@ rust_task_test::worker::run() {
|
||||
kernel->create_domain(crate, "test");
|
||||
rust_dom *domain = handle->referent();
|
||||
domain->root_task->start(crate->get_exit_task_glue(),
|
||||
ABI_X86_RUSTBOOT_CDECL,
|
||||
(uintptr_t)&task_entry, (uintptr_t)NULL, 0);
|
||||
domain->start_main_loop();
|
||||
kernel->destroy_domain(domain);
|
||||
|
||||
5
src/test/compile-fail/reserved-dec.rs
Normal file
5
src/test/compile-fail/reserved-dec.rs
Normal file
@@ -0,0 +1,5 @@
|
||||
// error-pattern:reserved keyword
|
||||
|
||||
fn main() {
|
||||
let int dec = 0;
|
||||
}
|
||||
5
src/test/compile-fail/reserved-f128.rs
Normal file
5
src/test/compile-fail/reserved-f128.rs
Normal file
@@ -0,0 +1,5 @@
|
||||
// error-pattern:reserved keyword
|
||||
|
||||
fn main() {
|
||||
let int f128 = 0;
|
||||
}
|
||||
5
src/test/compile-fail/reserved-f16.rs
Normal file
5
src/test/compile-fail/reserved-f16.rs
Normal file
@@ -0,0 +1,5 @@
|
||||
// error-pattern:reserved keyword
|
||||
|
||||
fn main() {
|
||||
let int f16 = 0;
|
||||
}
|
||||
5
src/test/compile-fail/reserved-f80.rs
Normal file
5
src/test/compile-fail/reserved-f80.rs
Normal file
@@ -0,0 +1,5 @@
|
||||
// error-pattern:reserved keyword
|
||||
|
||||
fn main() {
|
||||
let int f80 = 0;
|
||||
}
|
||||
5
src/test/compile-fail/reserved-m128.rs
Normal file
5
src/test/compile-fail/reserved-m128.rs
Normal file
@@ -0,0 +1,5 @@
|
||||
// error-pattern:reserved keyword
|
||||
|
||||
fn main() {
|
||||
let int m128 = 0;
|
||||
}
|
||||
5
src/test/compile-fail/reserved-m32.rs
Normal file
5
src/test/compile-fail/reserved-m32.rs
Normal file
@@ -0,0 +1,5 @@
|
||||
// error-pattern:reserved keyword
|
||||
|
||||
fn main() {
|
||||
let int m32 = 0;
|
||||
}
|
||||
5
src/test/compile-fail/reserved-m64.rs
Normal file
5
src/test/compile-fail/reserved-m64.rs
Normal file
@@ -0,0 +1,5 @@
|
||||
// error-pattern:reserved keyword
|
||||
|
||||
fn main() {
|
||||
let int m64 = 0;
|
||||
}
|
||||
10
src/test/compile-fail/tail-non-call.rs
Normal file
10
src/test/compile-fail/tail-non-call.rs
Normal file
@@ -0,0 +1,10 @@
|
||||
// error-pattern: Non-call expression in tail call
|
||||
|
||||
fn f() -> int {
|
||||
auto x = 1;
|
||||
be x;
|
||||
}
|
||||
|
||||
fn main() {
|
||||
auto y = f();
|
||||
}
|
||||
13
src/test/compile-fail/tail-typeck.rs
Normal file
13
src/test/compile-fail/tail-typeck.rs
Normal file
@@ -0,0 +1,13 @@
|
||||
// error-pattern: mismatched types
|
||||
|
||||
fn f() -> int {
|
||||
be g();
|
||||
}
|
||||
|
||||
fn g() -> uint {
|
||||
ret 0u;
|
||||
}
|
||||
|
||||
fn main() {
|
||||
auto y = f();
|
||||
}
|
||||
17
src/test/run-pass/alt-pattern-lit.rs
Normal file
17
src/test/run-pass/alt-pattern-lit.rs
Normal file
@@ -0,0 +1,17 @@
|
||||
fn altlit(int f) -> int {
|
||||
alt (f) {
|
||||
case (10) {
|
||||
log "case 10";
|
||||
ret 20;
|
||||
}
|
||||
case (11) {
|
||||
log "case 11";
|
||||
ret 22;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
check (altlit(10) == 20);
|
||||
check (altlit(11) == 22);
|
||||
}
|
||||
24
src/test/run-pass/arith-unsigned.rs
Normal file
24
src/test/run-pass/arith-unsigned.rs
Normal file
@@ -0,0 +1,24 @@
|
||||
// Unsigned integer operations
|
||||
|
||||
fn main() {
|
||||
check (0u8 < 255u8);
|
||||
check (0u8 <= 255u8);
|
||||
check (255u8 > 0u8);
|
||||
check (255u8 >= 0u8);
|
||||
check (250u8 / 10u8 == 25u8);
|
||||
check (255u8 % 10u8 == 5u8);
|
||||
check (0u16 < 60000u16);
|
||||
check (0u16 <= 60000u16);
|
||||
check (60000u16 > 0u16);
|
||||
check (60000u16 >= 0u16);
|
||||
check (60000u16 / 10u16 == 6000u16);
|
||||
check (60005u16 % 10u16 == 5u16);
|
||||
check (0u32 < 4000000000u32);
|
||||
check (0u32 <= 4000000000u32);
|
||||
check (4000000000u32 > 0u32);
|
||||
check (4000000000u32 >= 0u32);
|
||||
check (4000000000u32 / 10u32 == 400000000u32);
|
||||
check (4000000005u32 % 10u32 == 5u32);
|
||||
|
||||
// 64-bit numbers have some flakiness yet. Not tested
|
||||
}
|
||||
8
src/test/run-pass/generic-box.rs
Normal file
8
src/test/run-pass/generic-box.rs
Normal file
@@ -0,0 +1,8 @@
|
||||
fn box[T](&tup(T,T,T) x) -> @tup(T,T,T) {
|
||||
ret @x;
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let @tup(int,int,int) x = box[int](tup(1,2,3));
|
||||
check (x._1 == 2);
|
||||
}
|
||||
9
src/test/run-pass/generic-fn-box.rs
Normal file
9
src/test/run-pass/generic-fn-box.rs
Normal file
@@ -0,0 +1,9 @@
|
||||
fn f[T](@T x) -> @T {
|
||||
ret x;
|
||||
}
|
||||
|
||||
fn main() {
|
||||
auto x = f(@3);
|
||||
log *x;
|
||||
}
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
tag list[T] {
|
||||
cons(@T, @list[T]);
|
||||
nil();
|
||||
nil;
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let list[int] a = cons[int](10, cons[int](12, cons[int](13, nil[int]())));
|
||||
let list[int] a = cons[int](@10, @cons[int](@12, @cons[int](@13,
|
||||
@nil[int])));
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
type foo[T] = tup(T);
|
||||
type bar[T] = foo[T];
|
||||
fn takebar[T](bar[T] b) {}
|
||||
fn takebar[T](&bar[T] b) {}
|
||||
fn main() {}
|
||||
@@ -1,7 +1,7 @@
|
||||
// -*- rust -*-
|
||||
|
||||
use std;
|
||||
import std._io;
|
||||
import std.io;
|
||||
import std._str;
|
||||
|
||||
fn test_simple(str tmpfilebase) {
|
||||
@@ -11,11 +11,11 @@ fn test_simple(str tmpfilebase) {
|
||||
log frood;
|
||||
|
||||
{
|
||||
let _io.buf_writer out = _io.new_buf_writer(tmpfile, vec(_io.create()));
|
||||
let io.buf_writer out = io.new_buf_writer(tmpfile, vec(io.create));
|
||||
out.write(_str.bytes(frood));
|
||||
}
|
||||
|
||||
let _io.buf_reader inp = _io.new_buf_reader(tmpfile);
|
||||
let io.buf_reader inp = io.new_buf_reader(tmpfile);
|
||||
let str frood2 = _str.from_bytes(inp.read());
|
||||
log frood2;
|
||||
check (_str.eq(frood, frood2));
|
||||
|
||||
115
src/test/run-pass/lib-sha1.rs
Normal file
115
src/test/run-pass/lib-sha1.rs
Normal file
@@ -0,0 +1,115 @@
|
||||
// -*- rust -*-
|
||||
|
||||
use std;
|
||||
|
||||
import std.sha1;
|
||||
import std._vec;
|
||||
import std._str;
|
||||
|
||||
fn main() {
|
||||
|
||||
type test = rec(str input, vec[u8] output);
|
||||
|
||||
fn a_million_letter_a() -> str {
|
||||
auto i = 0;
|
||||
auto res = "";
|
||||
while (i < 100000) {
|
||||
res += "aaaaaaaaaa";
|
||||
i += 1;
|
||||
}
|
||||
ret res;
|
||||
}
|
||||
|
||||
// Test messages from FIPS 180-1
|
||||
let vec[test] fips_180_1_tests =
|
||||
vec(
|
||||
rec(input = "abc",
|
||||
output = vec(0xA9u8, 0x99u8, 0x3Eu8, 0x36u8, 0x47u8,
|
||||
0x06u8, 0x81u8, 0x6Au8, 0xBAu8, 0x3Eu8,
|
||||
0x25u8, 0x71u8, 0x78u8, 0x50u8, 0xC2u8,
|
||||
0x6Cu8, 0x9Cu8, 0xD0u8, 0xD8u8, 0x9Du8)
|
||||
),
|
||||
rec(input = "abcdbcdecdefdefgefghfghighij"
|
||||
+ "hijkijkljklmklmnlmnomnopnopq",
|
||||
output = vec(0x84u8, 0x98u8, 0x3Eu8, 0x44u8, 0x1Cu8,
|
||||
0x3Bu8, 0xD2u8, 0x6Eu8, 0xBAu8, 0xAEu8,
|
||||
0x4Au8, 0xA1u8, 0xF9u8, 0x51u8, 0x29u8,
|
||||
0xE5u8, 0xE5u8, 0x46u8, 0x70u8, 0xF1u8)
|
||||
)
|
||||
// FIXME: This test is disabled because it takes some
|
||||
// minutes to run under rustboot+valgrind. It may be
|
||||
// possible to reenable once things are more optimized.
|
||||
/*,
|
||||
rec(input = a_million_letter_a(),
|
||||
output = vec(0x34u8, 0xAAu8, 0x97u8, 0x3Cu8, 0xD4u8,
|
||||
0xC4u8, 0xDAu8, 0xA4u8, 0xF6u8, 0x1Eu8,
|
||||
0xEBu8, 0x2Bu8, 0xDBu8, 0xADu8, 0x27u8,
|
||||
0x31u8, 0x65u8, 0x34u8, 0x01u8, 0x6Fu8)
|
||||
)
|
||||
*/
|
||||
);
|
||||
|
||||
// Examples from wikipedia
|
||||
let vec[test] wikipedia_tests =
|
||||
vec(
|
||||
rec(input = "The quick brown fox jumps over the lazy dog",
|
||||
output = vec(0x2fu8, 0xd4u8, 0xe1u8, 0xc6u8, 0x7au8,
|
||||
0x2du8, 0x28u8, 0xfcu8, 0xedu8, 0x84u8,
|
||||
0x9eu8, 0xe1u8, 0xbbu8, 0x76u8, 0xe7u8,
|
||||
0x39u8, 0x1bu8, 0x93u8, 0xebu8, 0x12u8)
|
||||
),
|
||||
rec(input = "The quick brown fox jumps over the lazy cog",
|
||||
output = vec(0xdeu8, 0x9fu8, 0x2cu8, 0x7fu8, 0xd2u8,
|
||||
0x5eu8, 0x1bu8, 0x3au8, 0xfau8, 0xd3u8,
|
||||
0xe8u8, 0x5au8, 0x0bu8, 0xd1u8, 0x7du8,
|
||||
0x9bu8, 0x10u8, 0x0du8, 0xb4u8, 0xb3u8)
|
||||
)
|
||||
);
|
||||
|
||||
auto tests = fips_180_1_tests + wikipedia_tests;
|
||||
|
||||
fn check_vec_eq(vec[u8] v0, vec[u8] v1) {
|
||||
check (_vec.len[u8](v0) == _vec.len[u8](v1));
|
||||
auto len = _vec.len[u8](v0);
|
||||
auto i = 0u;
|
||||
while (i < len) {
|
||||
auto a = v0.(i);
|
||||
auto b = v1.(i);
|
||||
check (a == b);
|
||||
i += 1u;
|
||||
}
|
||||
}
|
||||
|
||||
// Test that it works when accepting the message all at once
|
||||
auto sh = sha1.mk_sha1();
|
||||
for (test t in tests) {
|
||||
sh.input_str(t.input);
|
||||
auto out = sh.result();
|
||||
check_vec_eq(t.output, out);
|
||||
sh.reset();
|
||||
}
|
||||
|
||||
// Test that it works when accepting the message in pieces
|
||||
for (test t in tests) {
|
||||
auto len = _str.byte_len(t.input);
|
||||
auto left = len;
|
||||
while (left > 0u) {
|
||||
auto take = (left + 1u) / 2u;
|
||||
sh.input_str(_str.substr(t.input, len - left, take));
|
||||
left = left - take;
|
||||
}
|
||||
auto out = sh.result();
|
||||
check_vec_eq(t.output, out);
|
||||
sh.reset();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Local Variables:
|
||||
// mode: rust;
|
||||
// fill-column: 78;
|
||||
// indent-tabs-mode: nil
|
||||
// c-basic-offset: 4
|
||||
// buffer-file-coding-system: utf-8-unix
|
||||
// compile-command: "make -k -C .. 2>&1 | sed -e 's/\\/x\\//x:\\//g'";
|
||||
// End:
|
||||
20
src/test/run-pass/native2.rs
Normal file
20
src/test/run-pass/native2.rs
Normal file
@@ -0,0 +1,20 @@
|
||||
native "rust" mod rustrt {
|
||||
type vbuf;
|
||||
fn vec_buf[T](vec[T] v, uint offset) -> vbuf;
|
||||
}
|
||||
|
||||
native "rust" mod bar = "foo" {
|
||||
}
|
||||
|
||||
native mod zed {
|
||||
}
|
||||
|
||||
native mod libc = "libc.dylib" {
|
||||
fn write(int fd, rustrt.vbuf buf, uint count) -> int;
|
||||
}
|
||||
|
||||
native "cdecl" mod baz {
|
||||
}
|
||||
|
||||
fn main(vec[str] args) {
|
||||
}
|
||||
8
src/test/run-pass/path.rs
Normal file
8
src/test/run-pass/path.rs
Normal file
@@ -0,0 +1,8 @@
|
||||
mod foo {
|
||||
fn bar(uint offset) {
|
||||
}
|
||||
}
|
||||
|
||||
fn main(vec[str] args) {
|
||||
foo.bar(0u);
|
||||
}
|
||||
@@ -1,5 +1,16 @@
|
||||
use std;
|
||||
fn main() {
|
||||
auto s = #fmt("hello %d friends and %s things", 10, "formatted");
|
||||
log s;
|
||||
import std._str;
|
||||
|
||||
fn test(str actual, str expected) {
|
||||
log actual;
|
||||
log expected;
|
||||
check (_str.eq(actual, expected));
|
||||
}
|
||||
|
||||
fn main() {
|
||||
test(#fmt("hello %d friends and %s things", 10, "formatted"),
|
||||
"hello 10 friends and formatted things");
|
||||
test(#fmt("d: %d", 1), "d: 1");
|
||||
test(#fmt("i: %i", 2), "i: 2");
|
||||
test(#fmt("s: %s", "test"), "s: test");
|
||||
}
|
||||
|
||||
26
src/test/run-pass/typestate-cfg-nesting.rs
Normal file
26
src/test/run-pass/typestate-cfg-nesting.rs
Normal file
@@ -0,0 +1,26 @@
|
||||
|
||||
fn f() {
|
||||
|
||||
auto x = 10;
|
||||
auto y = 11;
|
||||
if (true) {
|
||||
alt (x) {
|
||||
case (_) {
|
||||
y = x;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
|
||||
auto x = 10;
|
||||
auto y = 11;
|
||||
if (true) {
|
||||
while (false) {
|
||||
y = x;
|
||||
}
|
||||
} else {
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user