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:
Brian Anderson
2011-03-07 21:21:01 -05:00
66 changed files with 8303 additions and 2468 deletions

View File

@@ -15,6 +15,7 @@ Jason Orendorff <jorendorff@mozilla.com>
Jeff Balogh <jbalogh@mozilla.com> Jeff Balogh <jbalogh@mozilla.com>
Jeff Mulzelaar <jmuizelaar@mozilla.com> Jeff Mulzelaar <jmuizelaar@mozilla.com>
Jeffrey Yasskin <jyasskin@gmail.com> Jeffrey Yasskin <jyasskin@gmail.com>
Marijn Haverbeke <marijnh@gmail.com>
Matt Brubeck <mbrubeck@limpet.net> Matt Brubeck <mbrubeck@limpet.net>
Michael Bebenita <mbebenita@mozilla.com> Michael Bebenita <mbebenita@mozilla.com>
Or Brostovski <tohava@gmail.com> Or Brostovski <tohava@gmail.com>

View File

@@ -592,10 +592,12 @@ or interrupted by ignored characters.
Most tokens in Rust follow rules similar to the C family. Most tokens in Rust follow rules similar to the C family.
Most tokens (including identifiers, whitespace, keywords, operators and Most tokens (including whitespace, keywords, operators and structural symbols)
structural symbols) are drawn from the ASCII-compatible range of are drawn from the ASCII-compatible range of Unicode. Identifiers are drawn
Unicode. String and character literals, however, may include the full range of from Unicode characters specified by the @code{XID_start} and
Unicode characters. @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}. @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. @c * Ref.Lex.Ident:: Identifier tokens.
@cindex Identifier token @cindex Identifier token
Identifiers follow the pattern of C identifiers: they begin with a Identifiers follow the rules given by Unicode Standard Annex #31, in the form
@emph{letter} or @emph{underscore}, and continue with any combination of closed under NFKC normalization, @emph{excluding} those tokens that are
@emph{letters}, @emph{decimal digits} and underscores, and must not be equal otherwise defined as keywords or reserved
to any keyword or reserved token. @xref{Ref.Lex.Key}. @xref{Ref.Lex.Res}. tokens. @xref{Ref.Lex.Key}. @xref{Ref.Lex.Res}.
A @emph{letter} is a Unicode character in the ranges U+0061-U+007A and That is: an identifier starts with any character having derived property
U+0041-U+005A (@code{'a'}-@code{'z'} and @code{'A'}-@code{'Z'}). @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 @footnote{This identifier syntax is a superset of the identifier syntaxes of C
(@code{'0'}-@code{'9'}). 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 @node Ref.Lex.Key
@subsection Ref.Lex.Key @subsection Ref.Lex.Key
@@ -1984,22 +1990,22 @@ module system).
An example of a @code{tag} item and its use: An example of a @code{tag} item and its use:
@example @example
tag animal @{ tag animal @{
dog(); dog;
cat(); cat;
@} @}
let animal a = dog(); let animal a = dog;
a = cat(); a = cat;
@end example @end example
An example of a @emph{recursive} @code{tag} item and its use: An example of a @emph{recursive} @code{tag} item and its use:
@example @example
tag list[T] @{ tag list[T] @{
nil(); nil;
cons(T, @@list[T]); cons(T, @@list[T]);
@} @}
let list[int] a = cons(7, cons(13, nil())); let list[int] a = cons(7, cons(13, nil));
@end example @end example
@@ -3395,9 +3401,9 @@ control enters the block.
An example of a pattern @code{alt} statement: An example of a pattern @code{alt} statement:
@example @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) @{ alt (x) @{
case (cons(a, cons(b, _))) @{ case (cons(a, cons(b, _))) @{

View File

@@ -32,6 +32,19 @@ CFG_RUSTC_FLAGS := -nowarn
# embedded into the executable, so use a no-op command. # embedded into the executable, so use a no-op command.
DSYMUTIL := true 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) ifeq ($(CFG_OSTYPE), Linux)
CFG_RUNTIME := librustrt.so CFG_RUNTIME := librustrt.so
CFG_STDLIB := libstd.so CFG_STDLIB := libstd.so
@@ -43,13 +56,6 @@ ifeq ($(CFG_OSTYPE), Linux)
endif endif
CFG_NATIVE := 1 CFG_NATIVE := 1
CFG_UNIXY := 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 endif
ifeq ($(CFG_OSTYPE), Darwin) ifeq ($(CFG_OSTYPE), Darwin)
@@ -117,6 +123,13 @@ ifdef CFG_UNIXY
CFG_GCC_LINK_FLAGS += -m32 CFG_GCC_LINK_FLAGS += -m32
endif endif
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 endif
ifdef CFG_GCC ifdef CFG_GCC
@@ -388,6 +401,7 @@ TASK_XFAILS := test/run-pass/task-comm-8.rs \
TEST_XFAILS_BOOT := $(TASK_XFAILS) \ TEST_XFAILS_BOOT := $(TASK_XFAILS) \
$(NOMINAL_TAG_XFAILS) \ $(NOMINAL_TAG_XFAILS) \
$(CONST_TAG_XFAILS) \ $(CONST_TAG_XFAILS) \
test/run-pass/arith-unsigned.rs \
test/run-pass/child-outlives-parent.rs \ test/run-pass/child-outlives-parent.rs \
test/run-pass/clone-with-exterior.rs \ test/run-pass/clone-with-exterior.rs \
test/run-pass/constrained-type.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/obj-as.rs \
test/run-pass/vec-slice.rs \ test/run-pass/vec-slice.rs \
test/run-pass/fn-lval.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/generic-tup.rs \
test/run-pass/iter-ret.rs \ test/run-pass/iter-ret.rs \
test/run-pass/lib-io.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-recv.rs \
test/compile-fail/bad-send.rs \ test/compile-fail/bad-send.rs \
test/compile-fail/infinite-vec-type-recursion.rs \ test/compile-fail/infinite-vec-type-recursion.rs \
test/compile-fail/tail-non-call.rs \
test/compile-fail/writing-through-read-alias.rs test/compile-fail/writing-through-read-alias.rs
# Same strategy here for the time being: just list the ones that TEST_XFAILS_RUSTC := $(addprefix test/run-pass/, \
# work and assume the others don't. Invert this when we're closer acyclic-unwind.rs \
# to actually bootstrapping. alt-pattern-drop.rs \
alt-type-simple.rs \
TEST_XFAILS_RUSTC := $(filter-out \ append-units.rs \
$(addprefix test/run-pass/, \ basic-1.rs \
alt-path.rs \ basic-2.rs \
alt-pattern-simple.rs \ basic.rs \
alt-tag.rs \ bind-obj-ctor.rs \
arith-0.rs \ child-outlives-parent.rs \
arith-1.rs \ clone-with-exterior.rs \
arith-2.rs \ comm.rs \
autoderef-full-lval.rs \ constrained-type.rs \
bind-exterior.rs \ destructor-ordering.rs \
bind-interior.rs \ drop-parametric-closure-with-bound-box.rs \
bind-thunk.rs \ export-non-interference.rs \
bind-trivial.rs \ foreach-nested-2.rs \
bitwise.rs \ foreach-nested.rs \
bool-not.rs \ foreach-put-structured.rs \
box.rs \ foreach-simple-outer-slot.rs \
box-in-tup.rs \ generic-fn-twice.rs \
cast.rs \ generic-iter-frame.rs \
char.rs \ generic-recursive-tag.rs \
complex.rs \ generic-tag-alt.rs \
const.rs \ generic-tag-values.rs \
dead-code-one-arm-if.rs \ iter-range.rs \
deep.rs \ iter-ret.rs \
deref.rs \ lazychan.rs \
div-mod.rs \ lib-bitv.rs \
drop-bind-thunk-args.rs \ lib-deque.rs \
drop-on-ret.rs \ lib-int.rs \
else-if.rs \ lib-io.rs \
fact.rs \ lib-map.rs \
fn-lval.rs \ lib-rand.rs \
fun-call-variants.rs \ lib-sha1.rs \
fun-indirect-call.rs \ lib-sort.rs \
generic-fn.rs \ lib-str.rs \
generic-fn-infer.rs \ lib-task.rs \
generic-drop-glue.rs \ lib-uint.rs \
generic-tup.rs \ lib-vec-str-conversions.rs \
generic-type.rs \ lib-vec.rs \
hello.rs \ many.rs \
int.rs \ mlist-cycle.rs \
i32-sub.rs \ mlist.rs \
i8-incr.rs \ mutable-alias-vec.rs \
import2.rs \ obj-as.rs \
import3.rs \ obj-dtor.rs \
import4.rs \ obj-return-polytypes.rs \
import5.rs \ pred.rs \
import6.rs \ preempt.rs \
import7.rs \ rt-circular-buffer.rs \
import8.rs \ size-and-align.rs \
item-name-overload.rs \ spawn-fn.rs \
large-records.rs \ spawn-module-qualified.rs \
lazy-init.rs \ spawn.rs \
lazy-and-or.rs \ str-append.rs \
leak-box-as-tydesc.rs \ syntax-extension-fmt.rs \
linear-for-loop.rs \ syntax-extension-shell.rs \
multiline-comment.rs \ task-comm-0.rs \
mutual-recursion-group.rs \ task-comm-1.rs \
obj-drop.rs \ task-comm-10.rs \
obj-recursion.rs \ task-comm-11.rs \
obj-with-vec.rs \ task-comm-12.rs \
operator-associativity.rs \ task-comm-13-thread.rs \
opeq.rs \ task-comm-13.rs \
output-slot-variants.rs \ task-comm-15.rs \
over-constrained-vregs.rs \ task-comm-2.rs \
readalias.rs \ task-comm-3.rs \
rec.rs \ task-comm-4.rs \
rec-auto.rs \ task-comm-5.rs \
rec-tup.rs \ task-comm-6.rs \
return-nil.rs \ task-comm-7.rs \
simple-obj.rs \ task-comm-8.rs \
stateful-obj.rs \ task-comm-9.rs \
str-idx.rs \ task-comm.rs \
type-in-nested-module.rs \ task-killjoin.rs \
type-param.rs \ task-life-0.rs \
tup.rs \ threads.rs \
u32-decr.rs \ type-sizes.rs \
u8-incr.rs \ typestate-cfg-nesting.rs \
u8-incr-decr.rs \ use-import-export.rs \
uint.rs \ user.rs \
unit.rs \ utf8.rs \
use.rs \ vec-alloc-append.rs \
tag.rs \ vec-append.rs \
vec.rs \ vec-slice.rs \
vec-drop.rs \ while-prelude-drop.rs \
vec-in-tup.rs \ while-with-break.rs \
vec-late-init.rs \ yield.rs \
while-and-do-while.rs \ yield2.rs \
while-flow-graph.rs \ multi.rc \
writealias.rs \ native-mod.rc \
native.rc \
) \ ) \
$(filter-out \
$(addprefix test/compile-fail/, \ $(addprefix test/compile-fail/, \
alt-tag-nullary.rs \ alt-tag-nullary.rs \
alt-tag-unary.rs \ alt-tag-unary.rs \
@@ -517,6 +534,7 @@ TEST_XFAILS_RUSTC := $(filter-out \
bad-expr-path.rs \ bad-expr-path.rs \
bad-expr-path2.rs \ bad-expr-path2.rs \
bogus-tag.rs \ bogus-tag.rs \
fru-extra-field.rs \
import.rs \ import.rs \
import2.rs \ import2.rs \
import3.rs \ import3.rs \
@@ -526,11 +544,20 @@ TEST_XFAILS_RUSTC := $(filter-out \
multiline-comment-line-tracking.rs \ multiline-comment-line-tracking.rs \
output-type-mismatch.rs \ output-type-mismatch.rs \
rec-missing-fields.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 \ type-shadow.rs \
while-type-error.rs \ while-type-error.rs \
wrong-ret-type.rs \ wrong-ret-type.rs \
), \ ), \
$(wildcard test/*/*.rs test/*/*.rc)) $(wildcard test/*fail/*.rs test/*fail/*.rc))
ifdef MINGW_CROSS ifdef MINGW_CROSS

View File

@@ -8,7 +8,6 @@ boot/fe - Front end (lexer, parser, AST)
boot/me - Middle end (resolve, check, layout, trans) boot/me - Middle end (resolve, check, layout, trans)
boot/be - Back end (IL, RA, insns, asm, objfiles) boot/be - Back end (IL, RA, insns, asm, objfiles)
boot/util - Ubiquitous helpers boot/util - Ubiquitous helpers
boot/llvm - LLVM-based alternative back end
boot/driver - Compiler driver boot/driver - Compiler driver
comp/ The self-hosted compiler ("rustc": incomplete) comp/ The self-hosted compiler ("rustc": incomplete)

View File

@@ -110,12 +110,22 @@ let indirect_args_elt_closure = 0;;
(* Current worst case is by vec grow glue *) (* Current worst case is by vec grow glue *)
let worst_case_glue_call_args = 8;; 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 = type abi =
{ {
abi_word_sz: int64; abi_word_sz: int64;
abi_word_bits: Il.bits; abi_word_bits: Il.bits;
abi_word_ty: Common.ty_mach; abi_word_ty: Common.ty_mach;
abi_tag: int;
abi_has_pcrel_data: bool; abi_has_pcrel_data: bool;
abi_has_pcrel_code: bool; abi_has_pcrel_code: bool;

View File

@@ -44,7 +44,7 @@ type ei_data =
;; ;;
let elf_identification ei_class ei_data = let elf_identification sess ei_class ei_data =
SEQ SEQ
[| [|
STRING "\x7fELF"; STRING "\x7fELF";
@@ -58,9 +58,16 @@ let elf_identification ei_class ei_data =
ELFDATANONE -> 0 ELFDATANONE -> 0
| ELFDATA2LSB -> 1 | ELFDATA2LSB -> 1
| ELFDATA2MSB -> 2); | ELFDATA2MSB -> 2);
1; (* EI_VERSION = EV_CURRENT *) 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 #9 *)
0; (* EI_PAD #A *) 0; (* EI_PAD #A *)
0; (* EI_PAD #B *) 0; (* EI_PAD #B *)
@@ -117,7 +124,7 @@ let elf32_header
in in
DEF DEF
(elf_header_fixup, (elf_header_fixup,
SEQ [| elf_identification ELFCLASS32 ei_data; SEQ [| elf_identification sess ELFCLASS32 ei_data;
WORD (TY_u16, (IMM (match e_type with WORD (TY_u16, (IMM (match e_type with
ET_NONE -> 0L ET_NONE -> 0L
| ET_REL -> 1L | ET_REL -> 1L
@@ -480,6 +487,7 @@ let elf32_linux_x86_file
~(entry_name:string) ~(entry_name:string)
~(text_frags:(string option, frag) Hashtbl.t) ~(text_frags:(string option, frag) Hashtbl.t)
~(data_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) ~(rodata_frags:(string option, frag) Hashtbl.t)
~(required_fixups:(string, fixup) Hashtbl.t) ~(required_fixups:(string, fixup) Hashtbl.t)
~(dwarf:Dwarf.debug_records) ~(dwarf:Dwarf.debug_records)
@@ -644,7 +652,7 @@ let elf32_linux_x86_file
(* let gotpltndx = 8L in *) (* Section index of .got.plt *) (* let gotpltndx = 8L in *) (* Section index of .got.plt *)
(* let relapltndx = 9L in *) (* Section index of .rela.plt *) (* let relapltndx = 9L in *) (* Section index of .rela.plt *)
let datandx = 10L in (* Section index of .data *) 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 dynamicndx = 12L in *) (* Section index of .dynamic *)
let shstrtabndx = 13L in (* Section index of .shstrtab *) let shstrtabndx = 13L in (* Section index of .shstrtab *)
@@ -991,6 +999,22 @@ let elf32_linux_x86_file
(strtab_entry, symtab_entry) (strtab_entry, symtab_entry)
in 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 rodata_sym name st_bind fixup =
let name_fixup = new_fixup ("rodata symbol name fixup: '" ^ name ^ "'") in let name_fixup = new_fixup ("rodata symbol name fixup: '" ^ name ^ "'") in
let strtab_entry = DEF (name_fixup, ZSTRING 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 ([],[],[]) Hashtbl.fold (frags_of_symbol data_sym STB_GLOBAL) data_frags ([],[],[])
in in
let (bss_strtab_frags,
bss_symtab_frags,
bss_body_frags) =
Hashtbl.fold (frags_of_symbol bss_sym STB_GLOBAL) bss_frags ([],[],[])
in
let (_, let (_,
require_strtab_frags, require_strtab_frags,
require_symtab_frags, require_symtab_frags,
@@ -1277,7 +1307,8 @@ let elf32_linux_x86_file
global_text_symtab_frags @ global_text_symtab_frags @
local_text_symtab_frags @ local_text_symtab_frags @
rodata_symtab_frags @ rodata_symtab_frags @
data_symtab_frags)) data_symtab_frags @
bss_symtab_frags))
in in
let dynstr_frags = (null_strtab_frag :: let dynstr_frags = (null_strtab_frag ::
@@ -1286,11 +1317,16 @@ let elf32_linux_x86_file
local_text_strtab_frags @ local_text_strtab_frags @
rodata_strtab_frags @ rodata_strtab_frags @
data_strtab_frags @ data_strtab_frags @
bss_strtab_frags @
(Array.to_list dynamic_needed_strtab_frags))) (Array.to_list dynamic_needed_strtab_frags)))
in in
let interp_section = 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 in
let text_section = let text_section =
@@ -1307,7 +1343,7 @@ let elf32_linux_x86_file
in in
let bss_section = let bss_section =
DEF (bss_section_fixup, DEF (bss_section_fixup,
SEQ [| |]) SEQ (Array.of_list bss_body_frags))
in in
let dynsym_section = let dynsym_section =
DEF (dynsym_section_fixup, DEF (dynsym_section_fixup,
@@ -1486,6 +1522,7 @@ let emit_file
let text_frags = Hashtbl.create 4 in let text_frags = Hashtbl.create 4 in
let rodata_frags = Hashtbl.create 4 in let rodata_frags = Hashtbl.create 4 in
let data_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 let required_fixups = Hashtbl.create 4 in
(* (*
@@ -1584,7 +1621,9 @@ let emit_file
let needed_libs = let needed_libs =
[| [|
"libc.so.6"; if sess.Session.sess_targ = FreeBSD_x86_elf
then "libc.so.7"
else "libc.so.6";
"librustrt.so" "librustrt.so"
|] |]
in in
@@ -1604,6 +1643,27 @@ let emit_file
htab_put text_frags None code; htab_put text_frags None code;
htab_put rodata_frags None data; 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 Hashtbl.iter
begin begin
fun _ tab -> fun _ tab ->
@@ -1616,6 +1676,7 @@ let emit_file
end end
sem.Semant.ctxt_native_required sem.Semant.ctxt_native_required
in in
let all_frags = let all_frags =
elf32_linux_x86_file elf32_linux_x86_file
~sess ~sess
@@ -1623,6 +1684,7 @@ let emit_file
~entry_name: "_start" ~entry_name: "_start"
~text_frags ~text_frags
~data_frags ~data_frags
~bss_frags
~dwarf ~dwarf
~sem ~sem
~rodata_frags ~rodata_frags

View File

@@ -1851,6 +1851,8 @@ let (abi:Abi.abi) =
Abi.abi_word_bits = word_bits; Abi.abi_word_bits = word_bits;
Abi.abi_word_ty = word_ty; Abi.abi_word_ty = word_ty;
Abi.abi_tag = Abi.abi_x86_rustboot_cdecl;
Abi.abi_has_pcrel_data = false; Abi.abi_has_pcrel_data = false;
Abi.abi_has_pcrel_code = true; Abi.abi_has_pcrel_code = true;

View File

@@ -249,6 +249,7 @@ let get_ar
Win32_x86_pe -> Pe.sniff Win32_x86_pe -> Pe.sniff
| MacOS_x86_macho -> Macho.sniff | MacOS_x86_macho -> Macho.sniff
| Linux_x86_elf -> Elf.sniff | Linux_x86_elf -> Elf.sniff
| FreeBSD_x86_elf -> Elf.sniff
in in
sniff sess filename sniff sess filename
end end
@@ -270,6 +271,7 @@ let get_sects
Win32_x86_pe -> Pe.get_sections Win32_x86_pe -> Pe.get_sections
| MacOS_x86_macho -> Macho.get_sections | MacOS_x86_macho -> Macho.get_sections
| Linux_x86_elf -> Elf.get_sections | Linux_x86_elf -> Elf.get_sections
| FreeBSD_x86_elf -> Elf.get_sections
in in
Some (ar, (get_sections sess ar)) Some (ar, (get_sections sess ar))
end end
@@ -350,6 +352,7 @@ let get_mod
Win32_x86_pe -> ".dll" Win32_x86_pe -> ".dll"
| MacOS_x86_macho -> ".dylib" | MacOS_x86_macho -> ".dylib"
| Linux_x86_elf -> ".so" | Linux_x86_elf -> ".so"
| FreeBSD_x86_elf -> ".so"
in in
let rec meta_matches i f_meta = let rec meta_matches i f_meta =
if i >= (Array.length meta) if i >= (Array.length meta)
@@ -447,6 +450,7 @@ let infer_lib_name
Win32_x86_pe -> ident ^ ".dll" Win32_x86_pe -> ident ^ ".dll"
| MacOS_x86_macho -> "lib" ^ ident ^ ".dylib" | MacOS_x86_macho -> "lib" ^ ident ^ ".dylib"
| Linux_x86_elf -> "lib" ^ ident ^ ".so" | Linux_x86_elf -> "lib" ^ ident ^ ".so"
| FreeBSD_x86_elf -> "lib" ^ ident ^ ".so"
;; ;;

View File

@@ -8,12 +8,21 @@ let _ =
let (targ:Common.target) = let (targ:Common.target) =
match Sys.os_type with match Sys.os_type with
"Unix" when Unix.system "test `uname -s` = 'Darwin'" = Unix.WEXITED 0 ->
MacOS_x86_macho | "Win32"
| "Unix" -> Linux_x86_elf
| "Win32" -> Win32_x86_pe
| "Cygwin" -> Win32_x86_pe | "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;; let (abi:Abi.abi) = X86.abi;;
@@ -96,6 +105,7 @@ let default_output_filename (sess:Session.sess) : filename option =
else else
base ^ (match sess.Session.sess_targ with base ^ (match sess.Session.sess_targ with
Linux_x86_elf -> "" Linux_x86_elf -> ""
| FreeBSD_x86_elf -> ""
| MacOS_x86_macho -> "" | MacOS_x86_macho -> ""
| Win32_x86_pe -> ".exe") | Win32_x86_pe -> ".exe")
in in
@@ -144,16 +154,21 @@ let flag f opt desc =
let argspecs = 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 <- fun s -> (sess.Session.sess_targ <-
(match s with (match s with
"win32-x86-pe" -> Win32_x86_pe "win32-x86-pe" -> Win32_x86_pe
| "macos-x86-macho" -> MacOS_x86_macho | "macos-x86-macho" -> MacOS_x86_macho
| "freebsd-x86-elf" -> FreeBSD_x86_elf
| _ -> Linux_x86_elf))), | _ -> Linux_x86_elf))),
(" target (default: " ^ (match sess.Session.sess_targ with (" target (default: " ^ (match sess.Session.sess_targ with
Win32_x86_pe -> "win32-x86-pe" Win32_x86_pe -> "win32-x86-pe"
| Linux_x86_elf -> "linux-x86-elf" | Linux_x86_elf -> "linux-x86-elf"
| MacOS_x86_macho -> "macos-x86-macho" | MacOS_x86_macho -> "macos-x86-macho"
| FreeBSD_x86_elf -> "freebsd-x86-elf"
) ^ ")")); ) ^ ")"));
("-o", Arg.String (fun s -> sess.Session.sess_out <- Some s), ("-o", Arg.String (fun s -> sess.Session.sess_out <- Some s),
"file to output (default: " "file to output (default: "
@@ -320,6 +335,7 @@ let parse_input_crate
let depfile = let depfile =
match sess.Session.sess_targ with match sess.Session.sess_targ with
Linux_x86_elf Linux_x86_elf
| FreeBSD_x86_elf
| MacOS_x86_macho -> outfile ^ ".d" | MacOS_x86_macho -> outfile ^ ".d"
| Win32_x86_pe -> (Filename.chop_extension outfile) ^ ".d" | Win32_x86_pe -> (Filename.chop_extension outfile) ^ ".d"
in in
@@ -473,6 +489,7 @@ let main_pipeline _ =
Win32_x86_pe -> Pe.emit_file Win32_x86_pe -> Pe.emit_file
| MacOS_x86_macho -> Macho.emit_file | MacOS_x86_macho -> Macho.emit_file
| Linux_x86_elf -> Elf.emit_file | Linux_x86_elf -> Elf.emit_file
| FreeBSD_x86_elf -> Elf.emit_file
in in
Session.time_inner "emit" sess Session.time_inner "emit" sess
(fun _ -> emitter sess crate code data sem_cx dwarf); (fun _ -> emitter sess crate code data sem_cx dwarf);

View File

@@ -628,6 +628,7 @@ let parse_crate_file
let (os, arch, libc) = let (os, arch, libc) =
match sess.Session.sess_targ with match sess.Session.sess_targ with
Linux_x86_elf -> ("linux", "x86", "libc.so.6") Linux_x86_elf -> ("linux", "x86", "libc.so.6")
| FreeBSD_x86_elf -> ("freebsd", "x86", "libc.so.7")
| Win32_x86_pe -> ("win32", "x86", "msvcrt.dll") | Win32_x86_pe -> ("win32", "x86", "msvcrt.dll")
| MacOS_x86_macho -> ("macos", "x86", "libc.dylib") | MacOS_x86_macho -> ("macos", "x86", "libc.dylib")
in in

View File

@@ -2727,6 +2727,7 @@ let trans_visitor
[| [|
Il.Cell new_task; Il.Cell new_task;
exit_task_glue_fptr; exit_task_glue_fptr;
(imm (Int64.of_int abi.Abi.abi_tag));
fptr_operand; fptr_operand;
callsz callsz
|]; |];
@@ -2739,6 +2740,7 @@ let trans_visitor
[| [|
Il.Cell new_task; Il.Cell new_task;
exit_task_glue_fptr; exit_task_glue_fptr;
(imm (Int64.of_int abi.Abi.abi_tag));
fptr_operand; fptr_operand;
callsz callsz
|]; |];
@@ -6183,6 +6185,8 @@ let trans_visitor
tab_sz cx.ctxt_required_rust_sym_num; tab_sz cx.ctxt_required_rust_sym_num;
tab_sz cx.ctxt_required_c_sym_num; tab_sz cx.ctxt_required_c_sym_num;
tab_sz cx.ctxt_required_lib_num; tab_sz cx.ctxt_required_lib_num;
Asm.WORD (word_ty_mach, Asm.IMM (Int64.of_int abi.Abi.abi_tag));
|])) |]))
in in

View File

@@ -24,7 +24,6 @@ type typestate_tables =
ts_prestates: (node_id,Bits.t) Hashtbl.t; ts_prestates: (node_id,Bits.t) Hashtbl.t;
ts_poststates: (node_id,Bits.t) Hashtbl.t; ts_poststates: (node_id,Bits.t) Hashtbl.t;
ts_graph: node_graph; ts_graph: node_graph;
ts_siblings: sibling_map;
ts_stmts: Ast.stmt Stack.t; ts_stmts: Ast.stmt Stack.t;
ts_maxid: int ref; ts_maxid: int ref;
} }
@@ -38,7 +37,6 @@ let new_tables _ =
ts_poststates = Hashtbl.create 0; ts_poststates = Hashtbl.create 0;
ts_prestates = Hashtbl.create 0; ts_prestates = Hashtbl.create 0;
ts_graph = Hashtbl.create 0; ts_graph = Hashtbl.create 0;
ts_siblings = Hashtbl.create 0;
ts_stmts = Stack.create (); ts_stmts = Stack.create ();
ts_maxid = ref 0 } 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))) 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 = 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 let existing = Hashtbl.find graph n in
Hashtbl.replace graph n (lset_union existing dsts) 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) (graph:node_graph)
(n:node_id) (predecessors:node_id list)
(dsts:node_id list) (s:Ast.stmt)
: unit = : node_id list =
let existing = Hashtbl.find graph n in
Hashtbl.replace graph n (lset_diff existing dsts) 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 graph_building_visitor
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
(cx:ctxt) (cx:ctxt)
(tables_stack:typestate_tables Stack.t) (tables_stack:typestate_tables Stack.t)
(inner:Walk.visitor) (inner:Walk.visitor)
: Walk.visitor = : Walk.visitor =
let tables _ = Stack.top tables_stack in let tables _ = Stack.top tables_stack in
let graph _ = (tables()).ts_graph in
let visit_stmt_pre s = let blk b =
let ts = tables () in add_flow_edges (graph()) b.id [];
let stmts = ts.ts_stmts in ignore (build_flow_graph_for_stmts (graph()) [b.id] b.node)
Stack.push s stmts;
inner.Walk.visit_stmt_pre s
in in
let visit_stmt_post s = let visit_mod_item_pre n p i =
let ts = tables () in begin
let stmts = ts.ts_stmts in match i.node.Ast.decl_item with
inner.Walk.visit_stmt_post s; Ast.MOD_ITEM_fn fn -> blk fn.Ast.fn_body
ignore (Stack.pop stmts) | _ -> ()
end;
inner.Walk.visit_mod_item_pre n p i
in in
let show_node = let visit_obj_fn_pre obj ident fn =
fun n id -> show_node cx (tables()).ts_graph n id 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 in
let visit_block_pre b = let visit_block_pre b =
begin if Hashtbl.mem cx.ctxt_block_is_loop_body b.id
let ts = tables () in then blk b;
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;
inner.Walk.visit_block_pre b inner.Walk.visit_block_pre b
in in
{ inner with { inner with
Walk.visit_stmt_pre = visit_stmt_pre; Walk.visit_mod_item_pre = visit_mod_item_pre;
Walk.visit_stmt_post = visit_stmt_post; 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 } 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 let find_roots
@@ -1631,13 +1498,7 @@ let process_crate
(condition_assigning_visitor cx tables_stack scopes (condition_assigning_visitor cx tables_stack scopes
Walk.empty_visitor))); Walk.empty_visitor)));
(table_managed (table_managed
(graph_sequence_building_visitor cx tables_stack (graph_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
Walk.empty_visitor)); Walk.empty_visitor));
|] |]
in in

View File

@@ -56,6 +56,7 @@ type target =
Linux_x86_elf Linux_x86_elf
| Win32_x86_pe | Win32_x86_pe
| MacOS_x86_macho | MacOS_x86_macho
| FreeBSD_x86_elf
;; ;;
type ty_mach = type ty_mach =

View File

@@ -44,7 +44,8 @@ const int obj_field_vtbl = 0;
const int obj_field_box = 1; const int obj_field_box = 1;
const int obj_body_elt_tydesc = 0; 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_code = 0;
const int fn_field_box = 1; 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 n_upcall_glues = 7;
const int abi_x86_rustboot_cdecl = 1;
const int abi_x86_rustc_fastcall = 2;
fn memcpy_glue_name() -> str { fn memcpy_glue_name() -> str {
ret "rust_memcpy_glue"; ret "rust_memcpy_glue";
} }
@@ -67,6 +71,10 @@ fn bzero_glue_name() -> str {
ret "rust_bzero_glue"; ret "rust_bzero_glue";
} }
fn vec_append_glue_name() -> str {
ret "rust_vec_append_glue";
}
fn upcall_glue_name(int n) -> str { fn upcall_glue_name(int n) -> str {
ret "rust_upcall_" + util.common.istr(n); ret "rust_upcall_" + util.common.istr(n);
} }

View File

@@ -41,20 +41,117 @@ fn store_esp_to_runtime_sp() -> vec[str] {
ret vec("movl %esp, " + wstr(abi.task_field_runtime_sp) + "(%ecx)"); 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] { fn rust_activate_glue() -> vec[str] {
ret vec("movl 4(%esp), %ecx # ecx = rust_task") ret vec("movl 4(%esp), %ecx # ecx = rust_task")
+ save_callee_saves() + save_callee_saves()
+ store_esp_to_runtime_sp() + store_esp_to_runtime_sp()
+ load_esp_from_rust_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)") + 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() + restore_callee_saves()
+ vec("ret"); + 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] { fn rust_yield_glue() -> vec[str] {
ret vec("movl 0(%esp), %ecx # ecx = rust_task") ret vec("movl 0(%esp), %ecx # ecx = rust_task")
+ load_esp_from_rust_sp() + load_esp_from_rust_sp()

View File

@@ -2,6 +2,7 @@
import front.parser; import front.parser;
import front.token; import front.token;
import front.eval;
import middle.trans; import middle.trans;
import middle.resolve; import middle.resolve;
import middle.typeck; import middle.typeck;
@@ -13,6 +14,30 @@ import std.option.none;
import std._str; import std._str;
import std._vec; 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, impure fn parse_input(session.session sess,
parser.parser p, parser.parser p,
str input) -> @front.ast.crate { str input) -> @front.ast.crate {
@@ -25,20 +50,30 @@ impure fn parse_input(session.session sess,
fail; 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) { 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); auto crate = parse_input(sess, p, input);
crate = resolve.resolve_crate(sess, crate); crate = resolve.resolve_crate(sess, crate);
crate = typeck.check_crate(sess, crate); crate = typeck.check_crate(sess, crate);
trans.trans_crate(sess, crate, output, shared); 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() { fn warn_wrong_compiler() {
log "This is the rust 'self-hosted' compiler."; log "This is the rust 'self-hosted' compiler.";
log "The one written in rust."; log "The one written in rust.";
log "It is currently incomplete."; 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) { 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 " -o <filename> write output to <filename>";
log " -nowarn suppress wrong-compiler warning"; log " -nowarn suppress wrong-compiler warning";
log " -shared compile a shared-library crate"; log " -shared compile a shared-library crate";
log " -pp pretty-print the input instead of compiling";
log " -h display this message"; log " -h display this message";
log ""; log "";
log ""; log "";
@@ -74,6 +110,7 @@ impure fn main(vec[str] args) {
let option.t[str] output_file = none[str]; let option.t[str] output_file = none[str];
let bool do_warn = true; let bool do_warn = true;
let bool shared = false; let bool shared = false;
let bool pretty = false;
auto i = 1u; auto i = 1u;
auto len = _vec.len[str](args); auto len = _vec.len[str](args);
@@ -86,9 +123,9 @@ impure fn main(vec[str] args) {
do_warn = false; do_warn = false;
} else if (_str.eq(arg, "-shared")) { } else if (_str.eq(arg, "-shared")) {
shared = true; shared = true;
} else { } else if (_str.eq(arg, "-pp")) {
// FIXME: rust could use an elif construct. pretty = true;
if (_str.eq(arg, "-o")) { } else if (_str.eq(arg, "-o")) {
if (i+1u < len) { if (i+1u < len) {
output_file = some(args.(i+1u)); output_file = some(args.(i+1u));
i += 1u; i += 1u;
@@ -96,15 +133,12 @@ impure fn main(vec[str] args) {
usage(sess, args.(0)); usage(sess, args.(0));
sess.err("-o requires an argument"); sess.err("-o requires an argument");
} }
} else { } else if (_str.eq(arg, "-h")) {
if (_str.eq(arg, "-h")) {
usage(sess, args.(0)); usage(sess, args.(0));
} else { } else {
usage(sess, args.(0)); usage(sess, args.(0));
sess.err("unrecognized option: " + arg); sess.err("unrecognized option: " + arg);
} }
}
}
} else { } else {
alt (input_file) { alt (input_file) {
case (some[str](_)) { case (some[str](_)) {
@@ -115,8 +149,6 @@ impure fn main(vec[str] args) {
input_file = some[str](arg); input_file = some[str](arg);
} }
} }
// FIXME: dummy node to work around typestate mis-wiring bug.
i = i;
} }
i += 1u; i += 1u;
} }
@@ -131,23 +163,29 @@ impure fn main(vec[str] args) {
sess.err("no input filename"); sess.err("no input filename");
} }
case (some[str](?ifile)) { case (some[str](?ifile)) {
auto env = default_environment(sess, args.(0), ifile);
if (pretty) {
pretty_print_input(sess, env, ifile);
}
else {
alt (output_file) { alt (output_file) {
case (none[str]) { case (none[str]) {
let vec[str] parts = _str.split(ifile, '.' as u8); let vec[str] parts = _str.split(ifile, '.' as u8);
parts = _vec.pop[str](parts); parts = _vec.pop[str](parts);
parts += ".bc"; parts += ".bc";
auto ofile = _str.concat(parts); auto ofile = _str.concat(parts);
compile_input(sess, ifile, ofile, shared); compile_input(sess, env, ifile, ofile, shared);
} }
case (some[str](?ofile)) { case (some[str](?ofile)) {
compile_input(sess, ifile, ofile, shared); compile_input(sess, env, ifile, ofile, shared);
}
} }
} }
} }
} }
} }
// Local Variables: // Local Variables:
// mode: rust // mode: rust
// fill-column: 78; // fill-column: 78;

View File

@@ -5,6 +5,7 @@ import std._vec;
import util.common.span; import util.common.span;
import util.common.spanned; import util.common.spanned;
import util.common.ty_mach; import util.common.ty_mach;
import util.common.filename;
type ident = str; type ident = str;
@@ -36,11 +37,29 @@ tag def {
def_ty_arg(def_id); def_ty_arg(def_id);
def_binding(def_id); def_binding(def_id);
def_use(def_id); def_use(def_id);
def_native_ty(def_id);
def_native_fn(def_id);
} }
type crate = spanned[crate_]; type crate = spanned[crate_];
type crate_ = rec(_mod module); 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 = spanned[meta_item_];
type meta_item_ = rec(ident name, str value); type meta_item_ = rec(ident name, str value);
@@ -55,6 +74,7 @@ type pat = spanned[pat_];
tag pat_ { tag pat_ {
pat_wild(ann); pat_wild(ann);
pat_bind(ident, def_id, ann); pat_bind(ident, def_id, ann);
pat_lit(@lit, ann);
pat_tag(path, vec[@pat], option.t[variant_def], ann); pat_tag(path, vec[@pat], option.t[variant_def], ann);
} }
@@ -63,6 +83,11 @@ tag mutability {
imm; imm;
} }
tag opacity {
op_abstract;
op_transparent;
}
tag layer { tag layer {
layer_value; layer_value;
layer_state; layer_state;
@@ -75,6 +100,11 @@ tag effect {
eff_unsafe; eff_unsafe;
} }
tag proto {
proto_iter;
proto_fn;
}
tag binop { tag binop {
add; add;
sub; sub;
@@ -97,12 +127,49 @@ tag binop {
gt; 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 { tag unop {
box; box;
deref; deref;
bitnot; bitnot;
not; not;
neg; 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 { tag mode {
@@ -113,11 +180,9 @@ tag mode {
type stmt = spanned[stmt_]; type stmt = spanned[stmt_];
tag stmt_ { tag stmt_ {
stmt_decl(@decl); stmt_decl(@decl);
stmt_ret(option.t[@expr]);
stmt_log(@expr);
stmt_check_expr(@expr);
stmt_fail;
stmt_expr(@expr); stmt_expr(@expr);
// These only exist in crate-level blocks.
stmt_crate_directive(@crate_directive);
} }
type local = rec(option.t[@ty] ty, type local = rec(option.t[@ty] ty,
@@ -142,7 +207,7 @@ type expr = spanned[expr_];
tag expr_ { tag expr_ {
expr_vec(vec[@expr], ann); expr_vec(vec[@expr], ann);
expr_tup(vec[elt], 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_call(@expr, vec[@expr], ann);
expr_bind(@expr, vec[option.t[@expr]], ann); expr_bind(@expr, vec[option.t[@expr]], ann);
expr_binary(binop, @expr, @expr, ann); expr_binary(binop, @expr, @expr, ann);
@@ -152,6 +217,7 @@ tag expr_ {
expr_if(@expr, block, option.t[@expr], ann); expr_if(@expr, block, option.t[@expr], ann);
expr_while(@expr, block, ann); expr_while(@expr, block, ann);
expr_for(@decl, @expr, block, ann); expr_for(@decl, @expr, block, ann);
expr_for_each(@decl, @expr, block, ann);
expr_do_while(block, @expr, ann); expr_do_while(block, @expr, ann);
expr_alt(@expr, vec[arm], ann); expr_alt(@expr, vec[arm], ann);
expr_block(block, ann); expr_block(block, ann);
@@ -160,6 +226,13 @@ tag expr_ {
expr_field(@expr, ident, ann); expr_field(@expr, ident, ann);
expr_index(@expr, @expr, ann); expr_index(@expr, @expr, ann);
expr_path(path, option.t[def], 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_]; type lit = spanned[lit_];
@@ -179,7 +252,8 @@ tag lit_ {
type ty_field = rec(ident ident, @ty ty); type ty_field = rec(ident ident, @ty ty);
type ty_arg = rec(mode mode, @ty ty); type ty_arg = rec(mode mode, @ty ty);
// TODO: effect // 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_]; type ty = spanned[ty_];
tag ty_ { tag ty_ {
ty_nil; ty_nil;
@@ -193,17 +267,28 @@ tag ty_ {
ty_vec(@ty); ty_vec(@ty);
ty_tup(vec[@ty]); ty_tup(vec[@ty]);
ty_rec(vec[ty_field]); 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_obj(vec[ty_method]);
ty_path(path, option.t[def]); ty_path(path, option.t[def]);
ty_mutable(@ty); 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 arg = rec(mode mode, @ty ty, ident ident, def_id id);
type _fn = rec(effect effect, type fn_decl = rec(effect effect,
bool is_iter,
vec[arg] inputs, vec[arg] inputs,
@ty output, @ty output);
type _fn = rec(fn_decl decl,
proto proto,
block body); 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_field = rec(@ty ty, ident ident, def_id id, ann ann);
type _obj = rec(vec[obj_field] fields, type _obj = rec(vec[obj_field] fields,
vec[@method] methods); vec[@method] methods,
option.t[block] dtor);
tag mod_index_entry { tag mod_index_entry {
mie_view_item(@view_item); mie_view_item(@view_item);
@@ -221,11 +306,28 @@ tag mod_index_entry {
mie_tag_variant(@item /* tag item */, uint /* variant index */); 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_index = hashmap[ident,mod_index_entry];
type _mod = rec(vec[@view_item] view_items, type _mod = rec(vec[@view_item] view_items,
vec[@item] items, vec[@item] items,
mod_index index); 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_arg = rec(@ty ty, def_id id);
type variant = rec(str name, vec[variant_arg] args, def_id id, ann ann); 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_ { tag view_item_ {
view_item_use(ident, vec[@meta_item], def_id); view_item_use(ident, vec[@meta_item], def_id);
view_item_import(ident, vec[ident], def_id, option.t[def]); view_item_import(ident, vec[ident], def_id, option.t[def]);
view_item_export(ident);
} }
type item = spanned[item_]; type item = spanned[item_];
@@ -240,11 +343,18 @@ tag item_ {
item_const(ident, @ty, @expr, def_id, ann); item_const(ident, @ty, @expr, def_id, ann);
item_fn(ident, _fn, vec[ty_param], def_id, ann); item_fn(ident, _fn, vec[ty_param], def_id, ann);
item_mod(ident, _mod, def_id); 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_ty(ident, @ty, vec[ty_param], def_id, ann);
item_tag(ident, vec[variant], vec[ty_param], def_id); item_tag(ident, vec[variant], vec[ty_param], def_id);
item_obj(ident, _obj, vec[ty_param], def_id, ann); 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) { fn index_view_item(mod_index index, @view_item it) {
alt (it.node) { alt (it.node) {
case(ast.view_item_use(?id, _, _)) { 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,_,_,_)) { case(ast.view_item_import(?def_ident,_,_,_)) {
index.insert(def_ident, ast.mie_view_item(it)); 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, _, _)) { case (ast.item_mod(?id, _, _)) {
index.insert(id, ast.mie_item(it)); 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, _, _, _, _)) { case (ast.item_ty(?id, _, _, _, _)) {
index.insert(id, ast.mie_item(it)); 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: // Local Variables:
// mode: rust // mode: rust

436
src/comp/front/eval.rs Normal file
View 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
View 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:
//

View File

@@ -1,4 +1,4 @@
import std._io.stdio_reader; import std.io.stdio_reader;
import std._str; import std._str;
import std.map; import std.map;
import std.map.hashmap; 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 keywords = new_str_hash[token.token]();
auto reserved = new_str_hash[()]();
keywords.insert("mod", token.MOD); keywords.insert("mod", token.MOD);
keywords.insert("use", token.USE); 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("f32", token.MACH(common.ty_f32));
keywords.insert("f64", token.MACH(common.ty_f64)); 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, ret reader(rdr, filename, rdr.getc() as char, rdr.getc() as char,
1u, 0u, 1u, 0u, keywords, reserved); 1u, 0u, 1u, 0u, keywords, reserved);
} }
@@ -425,6 +434,12 @@ impure fn next_token(reader rdr) -> token.token {
ret kwds.get(accum_str); 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); ret token.IDENT(accum_str);
} }
@@ -650,12 +665,9 @@ impure fn next_token(reader rdr) -> token.token {
case ('%') { case ('%') {
ret binop(rdr, token.PERCENT); ret binop(rdr, token.PERCENT);
} }
} }
log "lexer stopping at "; fail;
log c;
ret token.EOF;
} }

File diff suppressed because it is too large Load Diff

87
src/comp/front/pretty.rs Normal file
View 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:
//

View File

@@ -76,6 +76,25 @@ const uint LLVMIntSLT = 40u;
const uint LLVMIntSLE = 41u; 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 { native mod llvm = llvm_lib {
type ModuleRef; type ModuleRef;
@@ -657,7 +676,7 @@ native mod llvm = llvm_lib {
fn LLVMBuildICmp(BuilderRef B, uint Op, fn LLVMBuildICmp(BuilderRef B, uint Op,
ValueRef LHS, ValueRef RHS, ValueRef LHS, ValueRef RHS,
sbuf Name) -> ValueRef; sbuf Name) -> ValueRef;
fn LLVMBuildFCmp(BuilderRef B, RealPredicate Op, fn LLVMBuildFCmp(BuilderRef B, uint Op,
ValueRef LHS, ValueRef RHS, ValueRef LHS, ValueRef RHS,
sbuf Name) -> ValueRef; sbuf Name) -> ValueRef;
@@ -1034,7 +1053,7 @@ obj builder(BuilderRef B) {
ret llvm.LLVMBuildICmp(B, Op, LHS, RHS, _str.buf("")); 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("")); 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)); ret rec(llth=th, dtor=type_handle_dtor(th));
} }
fn type_to_str(TypeRef ty) -> str {
let vec[TypeRef] v = vec(); state obj type_names(std.map.hashmap[TypeRef, str] type_names,
ret type_to_str_inner(v, ty); 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); auto outer = outer0 + vec(ty);
let int kind = llvm.LLVMGetTypeKind(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 str s = "";
let bool first = true; let bool first = true;
for (TypeRef t in tys) { for (TypeRef t in tys) {
@@ -1171,7 +1242,7 @@ fn type_to_str_inner(vec[TypeRef] outer0, TypeRef ty) -> str {
} else { } else {
s += ", "; s += ", ";
} }
s += type_to_str_inner(outer, t); s += type_to_str_inner(names, outer, t);
} }
ret s; ret s;
} }
@@ -1200,9 +1271,9 @@ fn type_to_str_inner(vec[TypeRef] outer0, TypeRef ty) -> str {
let vec[TypeRef] args = let vec[TypeRef] args =
_vec.init_elt[TypeRef](0 as TypeRef, n_args); _vec.init_elt[TypeRef](0 as TypeRef, n_args);
llvm.LLVMGetParamTypes(ty, _vec.buf[TypeRef](args)); llvm.LLVMGetParamTypes(ty, _vec.buf[TypeRef](args));
s += tys_str(outer, args); s += tys_str(names, outer, args);
s += ") -> "; s += ") -> ";
s += type_to_str_inner(outer, out_ty); s += type_to_str_inner(names, outer, out_ty);
ret s; ret s;
} }
@@ -1212,7 +1283,7 @@ fn type_to_str_inner(vec[TypeRef] outer0, TypeRef ty) -> str {
let vec[TypeRef] elts = let vec[TypeRef] elts =
_vec.init_elt[TypeRef](0 as TypeRef, n_elts); _vec.init_elt[TypeRef](0 as TypeRef, n_elts);
llvm.LLVMGetStructElementTypes(ty, _vec.buf[TypeRef](elts)); llvm.LLVMGetStructElementTypes(ty, _vec.buf[TypeRef](elts));
s += tys_str(outer, elts); s += tys_str(names, outer, elts);
s += "}"; s += "}";
ret 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 "*\\" + 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"; } case (12) { ret "Opaque"; }

View File

@@ -10,6 +10,7 @@ import util.common.ty_mach;
import util.common.append; import util.common.append;
import front.ast; import front.ast;
import front.ast.fn_decl;
import front.ast.ident; import front.ast.ident;
import front.ast.path; import front.ast.path;
import front.ast.mutability; import front.ast.mutability;
@@ -20,6 +21,7 @@ import front.ast.block;
import front.ast.item; import front.ast.item;
import front.ast.view_item; import front.ast.view_item;
import front.ast.meta_item; import front.ast.meta_item;
import front.ast.native_item;
import front.ast.arg; import front.ast.arg;
import front.ast.pat; import front.ast.pat;
import front.ast.decl; import front.ast.decl;
@@ -28,6 +30,7 @@ import front.ast.def;
import front.ast.def_id; import front.ast.def_id;
import front.ast.ann; import front.ast.ann;
import std._uint;
import std._vec; import std._vec;
type ast_fold[ENV] = type ast_fold[ENV] =
@@ -56,6 +59,7 @@ type ast_fold[ENV] =
vec[ast.ty_method] meths) -> @ty) fold_ty_obj, vec[ast.ty_method] meths) -> @ty) fold_ty_obj,
(fn(&ENV e, &span sp, (fn(&ENV e, &span sp,
ast.proto proto,
vec[rec(ast.mode mode, @ty ty)] inputs, vec[rec(ast.mode mode, @ty ty)] inputs,
@ty output) -> @ty) fold_ty_fn, @ty output) -> @ty) fold_ty_fn,
@@ -72,7 +76,8 @@ type ast_fold[ENV] =
vec[ast.elt] es, ann a) -> @expr) fold_expr_tup, vec[ast.elt] es, ann a) -> @expr) fold_expr_tup,
(fn(&ENV e, &span sp, (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, (fn(&ENV e, &span sp,
@expr f, vec[@expr] args, @expr f, vec[@expr] args,
@@ -107,6 +112,10 @@ type ast_fold[ENV] =
@decl decl, @expr seq, &block body, @decl decl, @expr seq, &block body,
ann a) -> @expr) fold_expr_for, 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, (fn(&ENV e, &span sp,
@expr cond, &block body, @expr cond, &block body,
ann a) -> @expr) fold_expr_while, ann a) -> @expr) fold_expr_while,
@@ -144,6 +153,29 @@ type ast_fold[ENV] =
&option.t[def] d, &option.t[def] d,
ann a) -> @expr) fold_expr_path, 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. // Decl folds.
(fn(&ENV e, &span sp, (fn(&ENV e, &span sp,
@ast.local local) -> @decl) fold_decl_local, @ast.local local) -> @decl) fold_decl_local,
@@ -156,6 +188,9 @@ type ast_fold[ENV] =
(fn(&ENV e, &span sp, (fn(&ENV e, &span sp,
ann a) -> @pat) fold_pat_wild, 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, (fn(&ENV e, &span sp,
ident i, def_id did, ann a) -> @pat) fold_pat_bind, ident i, def_id did, ann a) -> @pat) fold_pat_bind,
@@ -169,15 +204,6 @@ type ast_fold[ENV] =
(fn(&ENV e, &span sp, (fn(&ENV e, &span sp,
@decl decl) -> @stmt) fold_stmt_decl, @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, (fn(&ENV e, &span sp,
@expr e) -> @stmt) fold_stmt_expr, @expr e) -> @stmt) fold_stmt_expr,
@@ -191,13 +217,24 @@ type ast_fold[ENV] =
vec[ast.ty_param] ty_params, vec[ast.ty_param] ty_params,
def_id id, ann a) -> @item) fold_item_fn, 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, (fn(&ENV e, &span sp, ident ident,
&ast._mod m, def_id id) -> @item) fold_item_mod, &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, (fn(&ENV e, &span sp, ident ident,
@ty t, vec[ast.ty_param] ty_params, @ty t, vec[ast.ty_param] ty_params,
def_id id, ann a) -> @item) fold_item_ty, 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, (fn(&ENV e, &span sp, ident ident,
vec[ast.variant] variants, vec[ast.variant] variants,
vec[ast.ty_param] ty_params, vec[ast.ty_param] ty_params,
@@ -220,23 +257,30 @@ type ast_fold[ENV] =
(fn(&ENV e, &span sp, (fn(&ENV e, &span sp,
&ast.block_) -> block) fold_block, &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, (fn(&ENV e, ast.effect effect,
bool is_iter,
vec[arg] inputs, 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._mod m) -> ast._mod) fold_mod,
(fn(&ENV e, &ast.native_mod m) -> ast.native_mod) fold_native_mod,
(fn(&ENV e, &span sp, (fn(&ENV e, &span sp,
&ast._mod m) -> @ast.crate) fold_crate, &ast._mod m) -> @ast.crate) fold_crate,
(fn(&ENV e, (fn(&ENV e,
vec[ast.obj_field] fields, 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. // Env updates.
(fn(&ENV e, @ast.crate c) -> ENV) update_env_for_crate, (fn(&ENV e, @ast.crate c) -> ENV) update_env_for_crate,
(fn(&ENV e, @item i) -> ENV) update_env_for_item, (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, @view_item i) -> ENV) update_env_for_view_item,
(fn(&ENV e, &block b) -> ENV) update_env_for_block, (fn(&ENV e, &block b) -> ENV) update_env_for_block,
(fn(&ENV e, @stmt s) -> ENV) update_env_for_stmt, (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)) { case (ast.ty_obj(?meths)) {
let vec[ast.ty_method] meths_ = vec(); let vec[ast.ty_method] meths_ = vec();
for (ast.ty_method m in meths) { 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) { alt (tfn.node) {
case (ast.ty_fn(?ins, ?out)) { case (ast.ty_fn(?p, ?ins, ?out)) {
append[ast.ty_method] 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_); ret fld.fold_ty_mutable(env_, t.span, ty_);
} }
case (ast.ty_fn(?inputs, ?output)) { case (ast.ty_fn(?proto, ?inputs, ?output)) {
ret fold_ty_fn(env_, fld, t.span, 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, fn fold_ty_fn[ENV](&ENV env, ast_fold[ENV] fld, &span sp,
ast.proto proto,
vec[rec(ast.mode mode, @ty ty)] inputs, vec[rec(ast.mode mode, @ty ty)] inputs,
@ty output) -> @ty { @ty output) -> @ty {
auto output_ = fold_ty(env, fld, output); 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); auto input_ = rec(ty=ty_ with input);
inputs_ += vec(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 { 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) { alt (p.node) {
case (ast.pat_wild(?t)) { ret fld.fold_pat_wild(env_, p.span, t); } 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)) { case (ast.pat_bind(?id, ?did, ?t)) {
ret fld.fold_pat_bind(env_, p.span, 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); 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 vec[ast.field] fields = vec();
let option.t[@expr] b = none[@expr];
for (ast.field f in fs) { for (ast.field f in fs) {
fields += fold_rec_field(env, fld, f); 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)) { 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); 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)) { case (ast.expr_while(?cnd, ?body, ?t)) {
auto ccnd = fold_expr(env_, fld, cnd); auto ccnd = fold_expr(env_, fld, cnd);
auto bbody = fold_block(env_, fld, body); 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); auto p_ = fold_path(env_, fld, p);
ret fld.fold_expr_path(env_, e.span, p_, r, t); 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); 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)) { case (ast.stmt_expr(?e)) {
auto ee = fold_expr(env_, fld, e); auto ee = fold_expr(env_, fld, e);
ret fld.fold_stmt_expr(env_, s.span, ee); 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 { 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); ret rec(ty=ty with a);
} }
fn fold_fn_decl[ENV](&ENV env, ast_fold[ENV] fld,
fn fold_fn[ENV](&ENV env, ast_fold[ENV] fld, &ast._fn f) -> ast._fn { &ast.fn_decl decl) -> ast.fn_decl {
let vec[ast.arg] inputs = vec(); 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); 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); 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) { for (ast.obj_field f in ob.fields) {
fields += fold_obj_field(env, fld, f); 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(); let vec[ast.ty_param] tp = vec();
for (@ast.method m in ob.methods) { for (@ast.method m in ob.methods) {
// Fake-up an ast.item for this method. // 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); let ENV _env = fld.update_env_for_item(env, i);
append[@ast.method](meths, fold_method(_env, fld, m)); 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) 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); 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)) { case (ast.item_ty(?ident, ?ty, ?params, ?id, ?ann)) {
let @ast.ty ty_ = fold_ty[ENV](env_, fld, ty); let @ast.ty ty_ = fold_ty[ENV](env_, fld, ty);
ret fld.fold_item_ty(env_, i.span, ident, ty_, params, id, ann); 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; fail;
} }
fn fold_mod[ENV](&ENV e, ast_fold[ENV] fld, &ast._mod m) -> ast._mod { fn fold_mod[ENV](&ENV e, ast_fold[ENV] fld, &ast._mod m) -> ast._mod {
let vec[@view_item] view_items = vec(); 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)); 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 { 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); 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, fn identity_fold_ty_fn[ENV](&ENV env, &span sp,
ast.proto proto,
vec[rec(ast.mode mode, @ty ty)] inputs, vec[rec(ast.mode mode, @ty ty)] inputs,
@ty output) -> @ty { @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, 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, fn identity_fold_expr_rec[ENV](&ENV env, &span sp,
vec[ast.field] fields, ann a) -> @expr { vec[ast.field] fields,
ret @respan(sp, ast.expr_rec(fields, a)); 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, 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)); 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, fn identity_fold_expr_while[ENV](&ENV env, &span sp,
@expr cond, &block body, ann a) -> @expr { @expr cond, &block body, ann a) -> @expr {
ret @respan(sp, ast.expr_while(cond, body, a)); 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)); 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. // 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)); 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) fn identity_fold_pat_bind[ENV](&ENV e, &span sp, ident i, def_id did, ann a)
-> @pat { -> @pat {
ret @respan(sp, ast.pat_bind(i, did, a)); 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)); 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 { fn identity_fold_stmt_expr[ENV](&ENV e, &span sp, @expr x) -> @stmt {
ret @respan(sp, ast.stmt_expr(x)); 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)); 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, fn identity_fold_item_mod[ENV](&ENV e, &span sp, ident i,
&ast._mod m, def_id id) -> @item { &ast._mod m, def_id id) -> @item {
ret @respan(sp, ast.item_mod(i, m, id)); 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, fn identity_fold_item_ty[ENV](&ENV e, &span sp, ident i,
@ty t, vec[ast.ty_param] ty_params, @ty t, vec[ast.ty_param] ty_params,
def_id id, ann a) -> @item { def_id id, ann a) -> @item {
ret @respan(sp, ast.item_ty(i, t, ty_params, id, a)); 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, fn identity_fold_item_tag[ENV](&ENV e, &span sp, ident i,
vec[ast.variant] variants, vec[ast.variant] variants,
vec[ast.ty_param] ty_params, 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); ret respan(sp, blk);
} }
fn identity_fold_fn[ENV](&ENV e, fn identity_fold_fn_decl[ENV](&ENV e,
ast.effect effect, ast.effect effect,
bool is_iter,
vec[arg] inputs, 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 { &block body) -> ast._fn {
ret rec(effect=effect, is_iter=is_iter, inputs=inputs, ret rec(decl=decl, proto=proto, body=body);
output=output, body=body);
} }
fn identity_fold_mod[ENV](&ENV e, &ast._mod m) -> ast._mod { fn identity_fold_mod[ENV](&ENV e, &ast._mod m) -> ast._mod {
ret m; 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 { fn identity_fold_crate[ENV](&ENV e, &span sp, &ast._mod m) -> @ast.crate {
ret @respan(sp, rec(module=m)); ret @respan(sp, rec(module=m));
} }
fn identity_fold_obj[ENV](&ENV e, fn identity_fold_obj[ENV](&ENV e,
vec[ast.obj_field] fields, vec[ast.obj_field] fields,
vec[@ast.method] methods) -> ast._obj { vec[@ast.method] methods,
ret rec(fields=fields, methods=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; 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 { fn identity_update_env_for_view_item[ENV](&ENV e, @view_item i) -> ENV {
ret e; 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_tup = bind identity_fold_ty_tup[ENV](_,_,_),
fold_ty_rec = bind identity_fold_ty_rec[ENV](_,_,_), fold_ty_rec = bind identity_fold_ty_rec[ENV](_,_,_),
fold_ty_obj = bind identity_fold_ty_obj[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_path = bind identity_fold_ty_path[ENV](_,_,_,_),
fold_ty_mutable = bind identity_fold_ty_mutable[ENV](_,_,_), fold_ty_mutable = bind identity_fold_ty_mutable[ENV](_,_,_),
fold_expr_vec = bind identity_fold_expr_vec[ENV](_,_,_,_), fold_expr_vec = bind identity_fold_expr_vec[ENV](_,_,_,_),
fold_expr_tup = bind identity_fold_expr_tup[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_call = bind identity_fold_expr_call[ENV](_,_,_,_,_),
fold_expr_bind = bind identity_fold_expr_bind[ENV](_,_,_,_,_), fold_expr_bind = bind identity_fold_expr_bind[ENV](_,_,_,_,_),
fold_expr_binary = bind identity_fold_expr_binary[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_cast = bind identity_fold_expr_cast[ENV](_,_,_,_,_),
fold_expr_if = bind identity_fold_expr_if[ENV](_,_,_,_,_,_), fold_expr_if = bind identity_fold_expr_if[ENV](_,_,_,_,_,_),
fold_expr_for = bind identity_fold_expr_for[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_while = bind identity_fold_expr_while[ENV](_,_,_,_,_),
fold_expr_do_while fold_expr_do_while
= bind identity_fold_expr_do_while[ENV](_,_,_,_,_), = 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_field = bind identity_fold_expr_field[ENV](_,_,_,_,_),
fold_expr_index = bind identity_fold_expr_index[ENV](_,_,_,_,_), fold_expr_index = bind identity_fold_expr_index[ENV](_,_,_,_,_),
fold_expr_path = bind identity_fold_expr_path[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_local = bind identity_fold_decl_local[ENV](_,_,_),
fold_decl_item = bind identity_fold_decl_item[ENV](_,_,_), fold_decl_item = bind identity_fold_decl_item[ENV](_,_,_),
fold_pat_wild = bind identity_fold_pat_wild[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_bind = bind identity_fold_pat_bind[ENV](_,_,_,_,_),
fold_pat_tag = bind identity_fold_pat_tag[ENV](_,_,_,_,_,_), fold_pat_tag = bind identity_fold_pat_tag[ENV](_,_,_,_,_,_),
fold_stmt_decl = bind identity_fold_stmt_decl[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_stmt_expr = bind identity_fold_stmt_expr[ENV](_,_,_),
fold_item_const= bind identity_fold_item_const[ENV](_,_,_,_,_,_,_), fold_item_const= bind identity_fold_item_const[ENV](_,_,_,_,_,_,_),
fold_item_fn = bind identity_fold_item_fn[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_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_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_tag = bind identity_fold_item_tag[ENV](_,_,_,_,_,_),
fold_item_obj = bind identity_fold_item_obj[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](_,_,_,_,_,_), bind identity_fold_view_item_import[ENV](_,_,_,_,_,_),
fold_block = bind identity_fold_block[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_mod = bind identity_fold_mod[ENV](_,_),
fold_native_mod = bind identity_fold_native_mod[ENV](_,_),
fold_crate = bind identity_fold_crate[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_crate = bind identity_update_env_for_crate[ENV](_,_),
update_env_for_item = bind identity_update_env_for_item[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 = update_env_for_view_item =
bind identity_update_env_for_view_item[ENV](_,_), bind identity_update_env_for_view_item[ENV](_,_),
update_env_for_block = bind identity_update_env_for_block[ENV](_,_), update_env_for_block = bind identity_update_env_for_block[ENV](_,_),

View File

@@ -18,6 +18,7 @@ import std._vec;
tag scope { tag scope {
scope_crate(@ast.crate); scope_crate(@ast.crate);
scope_item(@ast.item); scope_item(@ast.item);
scope_native_item(@ast.native_item);
scope_loop(@ast.decl); // there's only 1 decl per loop. scope_loop(@ast.decl); // there's only 1 decl per loop.
scope_block(ast.block); scope_block(ast.block);
scope_arm(ast.arm); scope_arm(ast.arm);
@@ -34,6 +35,7 @@ tag def_wrap {
def_wrap_use(@ast.view_item); def_wrap_use(@ast.view_item);
def_wrap_import(@ast.view_item); def_wrap_import(@ast.view_item);
def_wrap_mod(@ast.item); def_wrap_mod(@ast.item);
def_wrap_native_mod(@ast.item);
def_wrap_other(def); def_wrap_other(def);
def_wrap_expr_field(uint, def); def_wrap_expr_field(uint, def);
def_wrap_resolving; 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. // should return what a.b.c.d points to in the end.
fn found_something(&env e, import_map index, fn found_something(&env e, import_map index,
&span sp, vec[ident] idents, def_wrap d) -> def_wrap { &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) { alt (d) {
case (def_wrap_import(?imp)) { case (def_wrap_import(?imp)) {
alt (imp.node) { alt (imp.node) {
@@ -122,23 +147,10 @@ fn find_final_def(&env e, import_map index,
} }
alt (d) { alt (d) {
case (def_wrap_mod(?i)) { case (def_wrap_mod(?i)) {
auto rest_idents = _vec.slice[ident](idents, 1u, len); ret found_mod(e, index, sp, idents, i);
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);
}
} }
case (def_wrap_native_mod(?i)) {
ret found_mod(e, index, sp, idents, i);
} }
case (def_wrap_use(?c)) { case (def_wrap_use(?c)) {
e.sess.span_err(sp, "Crate access is not implemented"); 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)) { case (ast.item_mod(_, _, ?id)) {
ret def_wrap_mod(i); ret def_wrap_mod(i);
} }
case (ast.item_native_mod(_, _, ?id)) {
ret def_wrap_native_mod(i);
}
case (ast.item_ty(_, _, _, ?id, _)) { case (ast.item_ty(_, _, _, ?id, _)) {
ret def_wrap_other(ast.def_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 { fn found_decl_stmt(@ast.stmt s) -> def_wrap {
alt (s.node) { alt (s.node) {
case (ast.stmt_decl(?d)) { 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]; 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)) { fn check_native_mod(ast.ident i, ast.native_mod m) -> option.t[def_wrap] {
alt (it.node) {
case (ast.item_fn(_, ?f, ?ty_params, _, _)) { alt (m.index.find(i)) {
for (ast.arg a in f.inputs) { 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)) { if (_str.eq(a.ident, i)) {
auto t = ast.def_arg(a.id); auto t = ast.def_arg(a.id);
ret some(def_wrap_other(t)); 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 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, _, _)) { case (ast.item_obj(_, ?ob, ?ty_params, _, _)) {
for (ast.obj_field f in ob.fields) { 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, _)) { case (ast.item_mod(_, ?m, _)) {
ret check_mod(i, m); ret check_mod(i, m);
} }
case (ast.item_native_mod(_, ?m, _)) {
ret check_native_mod(i, m);
}
case (ast.item_ty(_, _, ?ty_params, _, _)) { case (ast.item_ty(_, _, ?ty_params, _, _)) {
for (ast.ty_param tp in ty_params) { for (ast.ty_param tp in ty_params) {
if (_str.eq(tp.ident, i)) { 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)) { case (scope_loop(?d)) {
alt (d.node) { alt (d.node) {
case (ast.decl_local(?local)) { 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; path_len = n_idents - remaining + 1u;
} }
case (def_wrap_other(_)) { case (def_wrap_other(_)) {
check (n_idents == 1u); path_len = n_idents;
path_len = 1u;
} }
case (def_wrap_mod(?m)) { case (def_wrap_mod(?m)) {
e.sess.span_err(sp, 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); 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 { fn update_env_for_block(&env e, &ast.block b) -> env {
ret rec(scopes = cons[scope](scope_block(b), @e.scopes) with e); 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, _, _, _)) { case (ast.expr_for(?d, _, _, _)) {
ret rec(scopes = cons[scope](scope_loop(d), @e.scopes) with e); 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 (_) { } case (_) { }
} }
ret e; ret e;
@@ -517,6 +593,8 @@ fn resolve_imports(session.session sess, @ast.crate crate) -> @ast.crate {
= bind fold_view_item_import(_,_,import_index,_,_,_,_), = bind fold_view_item_import(_,_,import_index,_,_,_,_),
update_env_for_crate = bind update_env_for_crate(_,_), update_env_for_crate = bind update_env_for_crate(_,_),
update_env_for_item = bind update_env_for_item(_,_), 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_block = bind update_env_for_block(_,_),
update_env_for_arm = bind update_env_for_arm(_,_), update_env_for_arm = bind update_env_for_arm(_,_),
update_env_for_expr = bind update_env_for_expr(_,_) 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(_,_,_,_), fold_ty_path = bind fold_ty_path(_,_,_,_),
update_env_for_crate = bind update_env_for_crate(_,_), update_env_for_crate = bind update_env_for_crate(_,_),
update_env_for_item = bind update_env_for_item(_,_), 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_block = bind update_env_for_block(_,_),
update_env_for_arm = bind update_env_for_arm(_,_), update_env_for_arm = bind update_env_for_arm(_,_),
update_env_for_expr = bind update_env_for_expr(_,_) update_env_for_expr = bind update_env_for_expr(_,_)

File diff suppressed because it is too large Load Diff

View File

@@ -19,7 +19,10 @@ import util.common.span;
type arg = rec(ast.mode mode, @t ty); type arg = rec(ast.mode mode, @t ty);
type field = rec(ast.ident ident, @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 // NB: If you change this, you'll probably want to change the corresponding
// AST structure in front/ast.rs as well. // AST structure in front/ast.rs as well.
@@ -32,16 +35,19 @@ tag sty {
ty_machine(util.common.ty_mach); ty_machine(util.common.ty_mach);
ty_char; ty_char;
ty_str; ty_str;
ty_tag(ast.def_id); ty_tag(ast.def_id, vec[@t]);
ty_box(@t); ty_box(@t);
ty_vec(@t); ty_vec(@t);
ty_tup(vec[@t]); ty_tup(vec[@t]);
ty_rec(vec[field]); 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_obj(vec[method]);
ty_var(int); // ephemeral type var ty_var(int); // ephemeral type var
ty_local(ast.def_id); // type of a local 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 // 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_str) { s = "str"; }
case (ast.ty_box(?t)) { s = "@" + ast_ty_to_str(t); } 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_vec(?t)) { s = "vec[" + ast_ty_to_str(t) + "]"; }
case (ast.ty_type) { s = "type"; }
case (ast.ty_tup(?elts)) { case (ast.ty_tup(?elts)) {
auto f = ast_ty_to_str; auto f = ast_ty_to_str;
@@ -118,9 +125,13 @@ fn ast_ty_to_str(&@ast.ty ty) -> str {
s += ")"; s += ")";
} }
case (ast.ty_fn(?inputs, ?output)) { case (ast.ty_fn(?proto, ?inputs, ?output)) {
auto f = ast_fn_input_to_str; auto f = ast_fn_input_to_str;
if (proto == ast.proto_fn) {
s = "fn("; s = "fn(";
} else {
s = "iter(";
}
auto is = _vec.map[rec(ast.mode mode, @ast.ty ty),str](f, inputs); auto is = _vec.map[rec(ast.mode mode, @ast.ty ty),str](f, inputs);
s += _str.connect(is, ", "); s += _str.connect(is, ", ");
s += ")"; s += ")";
@@ -138,6 +149,7 @@ fn ast_ty_to_str(&@ast.ty ty) -> str {
s = "mutable " + ast_ty_to_str(t); s = "mutable " + ast_ty_to_str(t);
} }
case (_) { case (_) {
fail; // FIXME: typestate bug fail; // FIXME: typestate bug
} }
@@ -157,6 +169,8 @@ fn path_to_str(&ast.path pth) -> str {
ret result; 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 ty_to_str(&@t typ) -> str {
fn fn_input_to_str(&rec(ast.mode mode, @t ty) input) -> 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); 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 { vec[arg] inputs, @t output) -> str {
auto f = fn_input_to_str; auto f = fn_input_to_str;
auto s = "fn"; auto s = "fn";
if (proto == ast.proto_iter) {
s = "iter";
}
alt (ident) { alt (ident) {
case (some[ast.ident](?i)) { case (some[ast.ident](?i)) {
s += " "; s += " ";
@@ -193,7 +211,8 @@ fn ty_to_str(&@t typ) -> str {
} }
fn method_to_str(&method m) -> 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 { fn field_to_str(&field f) -> str {
@@ -206,6 +225,7 @@ fn ty_to_str(&@t typ) -> str {
} }
alt (typ.struct) { alt (typ.struct) {
case (ty_native) { s = "native"; }
case (ty_nil) { s = "()"; } case (ty_nil) { s = "()"; }
case (ty_bool) { s = "bool"; } case (ty_bool) { s = "bool"; }
case (ty_int) { s = "int"; } case (ty_int) { s = "int"; }
@@ -215,6 +235,7 @@ fn ty_to_str(&@t typ) -> str {
case (ty_str) { s = "str"; } case (ty_str) { s = "str"; }
case (ty_box(?t)) { s = "@" + ty_to_str(t); } case (ty_box(?t)) { s = "@" + ty_to_str(t); }
case (ty_vec(?t)) { s = "vec[" + ty_to_str(t) + "]"; } case (ty_vec(?t)) { s = "vec[" + ty_to_str(t) + "]"; }
case (ty_type) { s = "type"; }
case (ty_tup(?elems)) { case (ty_tup(?elems)) {
auto f = ty_to_str; auto f = ty_to_str;
@@ -228,13 +249,23 @@ fn ty_to_str(&@t typ) -> str {
s = "rec(" + _str.connect(strs, ",") + ")"; 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! // 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)) { case (ty_fn(?proto, ?inputs, ?output)) {
s = fn_to_str(none[ast.ident], 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)) { 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_machine(_)) { ret fld.fold_simple_ty(ty); }
case (ty_char) { 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_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)) { case (ty_box(?subty)) {
ret rewrap(ty, ty_box(fold_ty(fld, subty))); ret rewrap(ty, ty_box(fold_ty(fld, subty)));
} }
case (ty_vec(?subty)) { case (ty_vec(?subty)) {
ret rewrap(ty, ty_vec(fold_ty(fld, 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)) { case (ty_tup(?subtys)) {
let vec[@t] new_subtys = vec(); let vec[@t] new_subtys = vec();
for (@t subty in subtys) { 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)); 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(); let vec[arg] new_args = vec();
for (arg a in args) { for (arg a in args) {
auto new_ty = fold_ty(fld, a.ty); auto new_ty = fold_ty(fld, a.ty);
new_args += vec(rec(mode=a.mode, ty=new_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)) { case (ty_obj(?methods)) {
let vec[method] new_methods = vec(); 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) { for (arg a in m.inputs) {
new_args += vec(rec(mode=a.mode, ty=fold_ty(fld, a.ty))); 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))); output=fold_ty(fld, m.output)));
} }
ret rewrap(ty, ty_obj(new_methods)); 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); } case (ty_param(_)) { ret fld.fold_simple_ty(ty); }
} }
ret ty; fail;
} }
// Type utilities // Type utilities
@@ -349,23 +397,43 @@ fn type_is_nil(@t ty) -> bool {
fail; fail;
} }
fn type_is_structural(@t ty) -> bool { fn type_is_structural(@t ty) -> bool {
alt (ty.struct) { alt (ty.struct) {
case (ty_tup(_)) { ret true; } case (ty_tup(_)) { ret true; }
case (ty_rec(_)) { ret true; } case (ty_rec(_)) { ret true; }
case (ty_tag(_)) { ret true; } case (ty_tag(_,_)) { ret true; }
case (ty_fn(_,_)) { ret true; } case (ty_fn(_,_,_)) { ret true; }
case (ty_obj(_)) { ret true; } case (ty_obj(_)) { ret true; }
case (_) { ret false; } case (_) { ret false; }
} }
fail; 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 { fn type_is_tup_like(@t ty) -> bool {
alt (ty.struct) { alt (ty.struct) {
case (ty_box(_)) { ret true; }
case (ty_tup(_)) { ret true; } case (ty_tup(_)) { ret true; }
case (ty_rec(_)) { ret true; } case (ty_rec(_)) { ret true; }
case (ty_tag(_)) { ret true; } case (ty_tag(_,_)) { ret true; }
case (_) { ret false; } case (_) { ret false; }
} }
fail; fail;
@@ -402,6 +470,17 @@ fn type_is_scalar(@t ty) -> bool {
case (ty_uint) { ret true; } case (ty_uint) { ret true; }
case (ty_machine(_)) { ret true; } case (ty_machine(_)) { ret true; }
case (ty_char) { 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; } case (_) { ret false; }
} }
fail; fail;
@@ -423,6 +502,13 @@ fn type_has_dynamic_size(@t ty) -> bool {
i += 1u; 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 (ty_param(_)) { ret true; }
case (_) { /* fall through */ } case (_) { /* fall through */ }
} }
@@ -548,19 +634,38 @@ fn count_ty_params(@t ty) -> uint {
fn ty_fn_args(@t fty) -> vec[arg] { fn ty_fn_args(@t fty) -> vec[arg] {
alt (fty.struct) { 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 { fn ty_fn_ret(@t fty) -> @t {
alt (fty.struct) { 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 { fn is_fn_ty(@t fty) -> bool {
alt (fty.struct) { 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; } case (_) { ret false; }
} }
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 // Given an item, returns the associated type as well as a list of the IDs of
// its type parameters. // 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; let vec[ast.ty_param] ty_params;
auto result_ty; auto result_ty;
alt (it.node) { 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); result_ty = ann_to_type(ann);
} }
case (ast.item_tag(_, _, ?tps, ?did)) { case (ast.item_tag(_, _, ?tps, ?did)) {
// Create a new generic polytype.
ty_params = tps; 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)) { case (ast.item_obj(_, _, ?tps, _, ?ann)) {
ty_params = tps; ty_params = tps;
@@ -628,6 +755,7 @@ fn block_ty(&ast.block b) -> @t {
fn pat_ty(@ast.pat pat) -> @t { fn pat_ty(@ast.pat pat) -> @t {
alt (pat.node) { alt (pat.node) {
case (ast.pat_wild(?ann)) { ret ann_to_type(ann); } 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_bind(_, _, ?ann)) { ret ann_to_type(ann); }
case (ast.pat_tag(_, _, _, ?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) { alt (expr.node) {
case (ast.expr_vec(_, ?ann)) { ret ann_to_type(ann); } case (ast.expr_vec(_, ?ann)) { ret ann_to_type(ann); }
case (ast.expr_tup(_, ?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_bind(_, _, ?ann)) { ret ann_to_type(ann); }
case (ast.expr_call(_, _, ?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); } 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_cast(_, _, ?ann)) { ret ann_to_type(ann); }
case (ast.expr_if(_, _, _, ?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(_, _, _, ?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_while(_, _, ?ann)) { ret ann_to_type(ann); }
case (ast.expr_do_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); } 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_field(_, _, ?ann)) { ret ann_to_type(ann); }
case (ast.expr_index(_, _, ?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_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; 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) fn unify(@ty.t expected, @ty.t actual, &unify_handler handler)
-> unify_result { -> unify_result {
@@ -746,17 +887,23 @@ fn unify(@ty.t expected, @ty.t actual, &unify_handler handler)
ret ures_err(terr_mismatch, expected, actual); 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 expected,
@ty.t actual, @ty.t actual,
&unify_handler handler, &unify_handler handler,
vec[arg] expected_inputs, @t expected_output, vec[arg] expected_inputs, @t expected_output,
vec[arg] actual_inputs, @t actual_output) vec[arg] actual_inputs, @t actual_output)
-> unify_result { -> fn_common_res {
auto expected_len = _vec.len[arg](expected_inputs); auto expected_len = _vec.len[arg](expected_inputs);
auto actual_len = _vec.len[arg](actual_inputs); auto actual_len = _vec.len[arg](actual_inputs);
if (expected_len != actual_len) { 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. // 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 (_) { 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. // Check the output.
auto result_out;
auto result = unify_step(bindings, auto result = unify_step(bindings,
expected_output, expected_output,
actual_output, actual_output,
handler); handler);
alt (result) { alt (result) {
case (ures_ok(?rty)) { case (ures_ok(?rty)) {
result_out = rty; ret fn_common_res_ok(result_ins, rty);
} }
case (_) { case (_) {
ret result; ret fn_common_res_err(result);
}
} }
} }
auto t = plain_ty(ty.ty_fn(result_ins, result_out)); fn unify_fn(@hashmap[int,@ty.t] bindings,
ret ures_ok(t); 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 expected,
@ty.t actual, @ty.t actual,
&unify_handler handler, &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); 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) { while (i < expected_len) {
auto e_meth = expected_meths.(i); auto e_meth = expected_meths.(i);
auto a_meth = actual_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), ret ures_err(terr_obj_meths(e_meth.ident, a_meth.ident),
expected, actual); 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, e_meth.inputs, e_meth.output,
a_meth.inputs, a_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; ret r;
} }
append_if_ok(e_meth, r, result_meths); }
i += 1u; i += 1u;
} }
auto t = plain_ty(ty_obj(result_meths)); auto t = plain_ty(ty_obj(result_meths));
ret ures_ok(t); ret ures_ok(t);
} }
fn unify_step(&hashmap[int,@ty.t] bindings, @ty.t expected, @ty.t actual, fn resolve(@hashmap[int,@t] bindings, @t typ) -> @t {
&unify_handler handler) -> unify_result { 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 // TODO: rewrite this using tuple pattern matching when available, to
// avoid all this rightward drift and spikiness. // 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) { alt (actual.struct) {
// If the RHS is a variable type, then just do the appropriate // If the RHS is a variable type, then just do the appropriate
// binding. // binding.
case (ty.ty_var(?actual_id)) { 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); bindings.insert(actual_id, expected);
ret ures_ok(expected); ret ures_ok(expected);
} }
}
}
case (ty.ty_local(?actual_id)) { case (ty.ty_local(?actual_id)) {
auto actual_ty = handler.resolve_local(actual_id); auto actual_ty = handler.resolve_local(actual_id);
auto result = unify_step(bindings, 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_machine(_)) { ret struct_cmp(expected, actual); }
case (ty.ty_char) { 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_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) { alt (actual.struct) {
case (ty.ty_tag(?actual_id)) { case (ty.ty_tag(?actual_id, ?actual_tps)) {
if (expected_id._0 == actual_id._0 && if (expected_id._0 != actual_id._0 ||
expected_id._1 == actual_id._1) { expected_id._1 != actual_id._1) {
ret ures_ok(expected); 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 */ } case (_) { /* fall through */ }
} }
@@ -970,8 +1201,6 @@ fn unify(@ty.t expected, @ty.t actual, &unify_handler handler)
} }
} }
// TODO: ty_var
case (_) { case (_) {
ret ures_err(terr_mismatch, expected, actual); 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 (_) { case (_) {
ret ures_err(terr_mismatch, expected, actual); 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))); ret ures_ok(plain_ty(ty.ty_tup(result_elems)));
} }
// TODO: ty_var
case (_) { case (_) {
ret ures_err(terr_mismatch, expected, actual); 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))); 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 (_) { case (_) {
ret ures_err(terr_mismatch, expected, actual); 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) { alt (actual.struct) {
case (ty.ty_fn(?actual_inputs, ?actual_output)) { case (ty.ty_native_fn(?a_abi, ?actual_inputs,
ret unify_fn(bindings, expected, actual, handler, ?actual_output)) {
ret unify_native_fn(bindings, e_abi, a_abi,
expected, actual, handler,
expected_inputs, expected_output, expected_inputs, expected_output,
actual_inputs, actual_output); actual_inputs, actual_output);
} }
case (_) { case (_) {
ret ures_err(terr_mismatch, expected, actual); 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)) { case (ty.ty_var(?expected_id)) {
alt (bindings.find(expected_id)) { // Add a binding.
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]) {
bindings.insert(expected_id, actual); bindings.insert(expected_id, actual);
ret ures_ok(actual); ret ures_ok(actual);
} }
}
}
case (ty.ty_local(?expected_id)) { case (ty.ty_local(?expected_id)) {
auto expected_ty = handler.resolve_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; 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 hash_int(&int x) -> uint { ret x as uint; }
fn eq_int(&int a, &int b) -> bool { ret a == b; } fn eq_int(&int a, &int b) -> bool { ret a == b; }
auto hasher = hash_int; auto hasher = hash_int;
auto eqer = eq_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 { 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) { obj resolve_ty_params_handler(@hashmap[ast.def_id,@t] bindings) {
fn resolve_local(ast.def_id id) -> @t { log "resolve local"; fail; } 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; } 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 bindings = @new_def_hash[@t]();
auto handler = resolve_ty_params_handler(bindings); 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; 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: // Local Variables:
// mode: rust // mode: rust
// fill-column: 78; // fill-column: 78;

File diff suppressed because it is too large Load Diff

207
src/comp/pretty/pp.rs Normal file
View 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
View 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, "\"");
}

View File

@@ -5,9 +5,12 @@ use std;
mod front { mod front {
mod ast; mod ast;
mod extfmt;
mod lexer; mod lexer;
mod parser; mod parser;
mod pretty;
mod token; mod token;
mod eval;
} }
mod middle { mod middle {
@@ -28,6 +31,11 @@ mod driver {
mod session; mod session;
} }
mod pretty {
mod pp;
mod pprust;
}
mod util { mod util {
mod common; mod common;
} }
@@ -38,7 +46,6 @@ auth middle.trans.copy_args_to_allocas = impure;
auth middle.trans.trans_block = impure; auth middle.trans.trans_block = impure;
auth lib.llvm = unsafe; auth lib.llvm = unsafe;
mod lib { mod lib {
alt (target_os) { alt (target_os) {
case ("win32") { case ("win32") {

View File

@@ -2,8 +2,10 @@ import std._uint;
import std._int; import std._int;
import front.ast; import front.ast;
type filename = str;
type pos = rec(uint line, uint col); 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); type spanned[T] = rec(T node, span span);
tag ty_mach { tag ty_mach {

View File

@@ -96,25 +96,10 @@ fn buf(str s) -> sbuf {
} }
fn bytes(str s) -> vec[u8] { fn bytes(str s) -> vec[u8] {
/* FIXME (issue #58): fn ith(str s, uint i) -> u8 {
* Should be... ret s.(i);
*
* 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;
} }
ret v; ret _vec.init_fn[u8](bind ith(s, _), byte_len(s));
} }
fn from_bytes(vec[u8] v) : is_utf8(v) -> str { fn from_bytes(vec[u8] v) : is_utf8(v) -> str {

View File

@@ -85,24 +85,13 @@ fn new_buf_reader(str path) -> buf_reader {
ret fd_buf_reader(fd, new_buf()); ret fd_buf_reader(fd, new_buf());
} }
/** tag fileflag {
* FIXME (issue #150): This should be append;
* create;
* type fileflag = tag(append(), create(), truncate()); 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; }
fn new_buf_writer(str path, vec[fileflag] flags) -> buf_writer { fn writefd(int fd, vec[u8] v) {
state obj fd_buf_writer(int fd) {
fn write(vec[u8] v) {
auto len = _vec.len[u8](v); auto len = _vec.len[u8](v);
auto count = 0u; auto count = 0u;
auto vbuf; auto vbuf;
@@ -116,6 +105,14 @@ fn new_buf_writer(str path, vec[fileflag] flags) -> buf_writer {
} }
count += nout as uint; 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 { drop {
@@ -129,13 +126,9 @@ fn new_buf_writer(str path, vec[fileflag] flags) -> buf_writer {
for (fileflag f in flags) { for (fileflag f in flags) {
alt (f) { alt (f) {
// FIXME (issue #150): cf comment above defn of fileflag type case (append) { fflags |= os.libc_constants.O_APPEND(); }
//case (append()) { fflags |= os.libc_constants.O_APPEND(); } case (create) { fflags |= os.libc_constants.O_CREAT(); }
//case (create()) { fflags |= os.libc_constants.O_CREAT(); } case (truncate) { fflags |= os.libc_constants.O_TRUNC(); }
//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(); }
} }
} }

284
src/lib/sha1.rs Normal file
View 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:

View File

@@ -14,7 +14,7 @@ mod _str;
// General IO and system-services modules. // General IO and system-services modules.
mod _io; mod io;
mod sys; mod sys;
mod _task; mod _task;
@@ -25,7 +25,7 @@ mod util;
// Authorize various rule-bendings. // Authorize various rule-bendings.
auth _io = unsafe; auth io = unsafe;
auth _str = unsafe; auth _str = unsafe;
auth _vec = unsafe; auth _vec = unsafe;
auth _task = unsafe; auth _task = unsafe;
@@ -57,6 +57,7 @@ mod dbg;
mod bitv; mod bitv;
mod sort; mod sort;
mod path; mod path;
mod sha1;
// Local Variables: // Local Variables:
// mode: rust; // mode: rust;

View File

@@ -1,7 +1,10 @@
#include "rust_internal.h" #include "rust_internal.h"
#include "memory_region.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) : memory_region::memory_region(rust_srv *srv, bool synchronized) :
_srv(srv), _parent(NULL), _live_allocations(0), _srv(srv), _parent(NULL), _live_allocations(0),

View File

@@ -87,7 +87,8 @@ rust_start(uintptr_t main_fn, rust_crate const *crate, int argc,
rust_dom *dom = handle->referent(); rust_dom *dom = handle->referent();
command_line_args *args = new (dom) command_line_args(dom, argc, argv); 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++) { for (int i = 0; i < args->argc; i++) {
dom->log(rust_log::DOM, dom->log(rust_log::DOM,
"startup: arg[%d] = '%s'", i, args->argv[i]); "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}; uintptr_t main_args[4] = {0, 0, 0, (uintptr_t)args->args};
dom->root_task->start(crate->get_exit_task_glue(), 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(); int ret = dom->start_main_loop();
delete args; delete args;
kernel->destroy_domain(dom); kernel->destroy_domain(dom);

View File

@@ -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, dom->log(rust_log::CACHE, "resolved symbol '%s' to 0x%" PRIxPTR,
name, val); name, val);
} else { } 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); name);
} }
} }
@@ -79,7 +80,7 @@ rust_crate_cache::rust_sym::rust_sym(rust_dom *dom,
typedef rust_crate_reader::die die; typedef rust_crate_reader::die die;
rust_crate const *crate = (rust_crate*)crate_sym->get_val(); rust_crate const *crate = (rust_crate*)crate_sym->get_val();
if (!crate) { if (!crate) {
dom->log(rust_log::CACHE, dom->log(rust_log::CACHE | rust_log::ERR,
"failed to resolve symbol, null crate symbol"); "failed to resolve symbol, null crate symbol");
return; return;
} }

View File

@@ -88,6 +88,10 @@ static size_t const TIME_SLICE_IN_MS = 10;
static intptr_t const CONST_REFCOUNT = 0x7badface; 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. // This accounts for logging buffers.
static size_t const BUF_BYTES = 2048; static size_t const BUF_BYTES = 2048;
@@ -241,6 +245,8 @@ public:
size_t n_c_syms; size_t n_c_syms;
size_t n_libs; size_t n_libs;
uintptr_t abi_tag;
// Crates are immutable, constructed by the compiler. // Crates are immutable, constructed by the compiler.
uintptr_t get_image_base() const; uintptr_t get_image_base() const;

View File

@@ -123,6 +123,7 @@ rust_task::~rust_task()
void void
rust_task::start(uintptr_t exit_task_glue, rust_task::start(uintptr_t exit_task_glue,
uintptr_t spawnee_abi,
uintptr_t spawnee_fn, uintptr_t spawnee_fn,
uintptr_t args, uintptr_t args,
size_t callsz) 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: // The exit_task_glue frame we synthesize above the frame we activate:
*spp-- = (uintptr_t) 0; // closure-or-obj *spp-- = (uintptr_t) 0; // closure-or-obj
*spp-- = (uintptr_t) this; // task *spp-- = (uintptr_t) this; // task
*spp-- = (uintptr_t) 0; // output *spp-- = (uintptr_t) 0x0; // output
*spp-- = (uintptr_t) 0; // retpc *spp-- = (uintptr_t) 0x0; // retpc
uintptr_t exit_task_frame_base; uintptr_t exit_task_frame_base;
if (spawnee_abi == ABI_X86_RUSTBOOT_CDECL) {
for (size_t j = 0; j < n_callee_saves; ++j) { for (size_t j = 0; j < n_callee_saves; ++j) {
// We want 'frame_base' to point to the old fp in this (exit-task) // 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 // frame, because we're going to inject this frame-pointer into
// callee-save frame pointer value in the *next* (spawnee) frame. A // the callee-save frame pointer value in the *next* (spawnee)
// cheap trick, but this means the spawnee frame will restore the // frame. A cheap trick, but this means the spawnee frame will
// proper frame pointer of the glue frame as it runs its epilogue. // restore the proper frame pointer of the glue frame as it runs
// its epilogue.
if (j == callee_save_fp) if (j == callee_save_fp)
exit_task_frame_base = (uintptr_t)spp; 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) dom->root_crate; // crate ptr
*spp-- = (uintptr_t) 0; // frame_glue_fns *spp-- = (uintptr_t) 0; // frame_glue_fns
}
// Copy args from spawner to spawnee. // Copy args from spawner to spawnee.
if (args) { if (args) {
@@ -174,12 +178,16 @@ rust_task::start(uintptr_t exit_task_glue,
src += 1; // spawn-call output slot src += 1; // spawn-call output slot
src += 1; // spawn-call task slot src += 1; // spawn-call task slot
src += 1; // spawn-call closure-or-obj 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); spp = (uintptr_t*) (((uintptr_t)spp) - callsz);
memcpy(spp, src, 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--; spp--;
} else { } else {
// We're at root, starting up. // 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 // The *implicit* incoming args to the spawnee frame we're
// activating: // 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) this; // task
*spp-- = (uintptr_t) 0; // output addr *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 *spp-- = (uintptr_t) exit_task_glue; // retpc
// The context the activate_glue needs to switch stack. // The context the activate_glue needs to switch stack.

View File

@@ -56,6 +56,7 @@ rust_task : public maybe_proxy<rust_task>,
~rust_task(); ~rust_task();
void start(uintptr_t exit_task_glue, void start(uintptr_t exit_task_glue,
uintptr_t spawnee_abi,
uintptr_t spawnee_fn, uintptr_t spawnee_fn,
uintptr_t args, uintptr_t args,
size_t callsz); size_t callsz);

View File

@@ -253,6 +253,10 @@ upcall_fail(rust_task *task,
task->log(rust_log::UPCALL | rust_log::ERR, task->log(rust_log::UPCALL | rust_log::ERR,
"upcall fail '%s', %s:%" PRIdPTR, expr, file, line); "upcall fail '%s', %s:%" PRIdPTR, expr, file, line);
task->fail(4); 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, upcall_start_task(rust_task *spawner,
rust_task *task, rust_task *task,
uintptr_t exit_task_glue, uintptr_t exit_task_glue,
uintptr_t spawnee_abi,
uintptr_t spawnee_fn, uintptr_t spawnee_fn,
size_t callsz) { size_t callsz) {
LOG_UPCALL_ENTRY(spawner); LOG_UPCALL_ENTRY(spawner);
@@ -566,7 +571,8 @@ upcall_start_task(rust_task *spawner,
", spawnee 0x%" PRIxPTR ", spawnee 0x%" PRIxPTR
", callsz %" PRIdPTR ")", task->name, task, exit_task_glue, ", callsz %" PRIdPTR ")", task->name, task, exit_task_glue,
spawnee_fn, callsz); 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; return task;
} }
@@ -619,6 +625,7 @@ extern "C" CDECL maybe_proxy<rust_task> *
upcall_start_thread(rust_task *task, upcall_start_thread(rust_task *task,
rust_proxy<rust_task> *child_task_proxy, rust_proxy<rust_task> *child_task_proxy,
uintptr_t exit_task_glue, uintptr_t exit_task_glue,
uintptr_t spawnee_abi,
uintptr_t spawnee_fn, uintptr_t spawnee_fn,
size_t callsz) { size_t callsz) {
LOG_UPCALL_ENTRY(task); 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(); rust_handle<rust_task> *child_task_handle = child_task_proxy->handle();
task->log(rust_log::UPCALL | rust_log::MEM | rust_log::TASK, task->log(rust_log::UPCALL | rust_log::MEM | rust_log::TASK,
"exit_task_glue: " PTR ", spawnee_fn " PTR "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(); 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__) #if defined(__WIN32__)
HANDLE thread; HANDLE thread;
thread = CreateThread(NULL, 0, rust_thread_start, child_task->dom, 0, thread = CreateThread(NULL, 0, rust_thread_start, child_task->dom, 0,

View File

@@ -54,6 +54,7 @@ rust_task_test::worker::run() {
kernel->create_domain(crate, "test"); kernel->create_domain(crate, "test");
rust_dom *domain = handle->referent(); rust_dom *domain = handle->referent();
domain->root_task->start(crate->get_exit_task_glue(), domain->root_task->start(crate->get_exit_task_glue(),
ABI_X86_RUSTBOOT_CDECL,
(uintptr_t)&task_entry, (uintptr_t)NULL, 0); (uintptr_t)&task_entry, (uintptr_t)NULL, 0);
domain->start_main_loop(); domain->start_main_loop();
kernel->destroy_domain(domain); kernel->destroy_domain(domain);

View File

@@ -0,0 +1,5 @@
// error-pattern:reserved keyword
fn main() {
let int dec = 0;
}

View File

@@ -0,0 +1,5 @@
// error-pattern:reserved keyword
fn main() {
let int f128 = 0;
}

View File

@@ -0,0 +1,5 @@
// error-pattern:reserved keyword
fn main() {
let int f16 = 0;
}

View File

@@ -0,0 +1,5 @@
// error-pattern:reserved keyword
fn main() {
let int f80 = 0;
}

View File

@@ -0,0 +1,5 @@
// error-pattern:reserved keyword
fn main() {
let int m128 = 0;
}

View File

@@ -0,0 +1,5 @@
// error-pattern:reserved keyword
fn main() {
let int m32 = 0;
}

View File

@@ -0,0 +1,5 @@
// error-pattern:reserved keyword
fn main() {
let int m64 = 0;
}

View 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();
}

View File

@@ -0,0 +1,13 @@
// error-pattern: mismatched types
fn f() -> int {
be g();
}
fn g() -> uint {
ret 0u;
}
fn main() {
auto y = f();
}

View 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);
}

View 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
}

View 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);
}

View File

@@ -0,0 +1,9 @@
fn f[T](@T x) -> @T {
ret x;
}
fn main() {
auto x = f(@3);
log *x;
}

View File

@@ -1,8 +1,9 @@
tag list[T] { tag list[T] {
cons(@T, @list[T]); cons(@T, @list[T]);
nil(); nil;
} }
fn main() { 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])));
} }

View File

@@ -1,4 +1,4 @@
type foo[T] = tup(T); type foo[T] = tup(T);
type bar[T] = foo[T]; type bar[T] = foo[T];
fn takebar[T](bar[T] b) {} fn takebar[T](&bar[T] b) {}
fn main() {} fn main() {}

View File

@@ -1,7 +1,7 @@
// -*- rust -*- // -*- rust -*-
use std; use std;
import std._io; import std.io;
import std._str; import std._str;
fn test_simple(str tmpfilebase) { fn test_simple(str tmpfilebase) {
@@ -11,11 +11,11 @@ fn test_simple(str tmpfilebase) {
log frood; 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)); 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()); let str frood2 = _str.from_bytes(inp.read());
log frood2; log frood2;
check (_str.eq(frood, frood2)); check (_str.eq(frood, frood2));

View 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:

View 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) {
}

View File

@@ -0,0 +1,8 @@
mod foo {
fn bar(uint offset) {
}
}
fn main(vec[str] args) {
foo.bar(0u);
}

View File

@@ -1,5 +1,16 @@
use std; use std;
fn main() { import std._str;
auto s = #fmt("hello %d friends and %s things", 10, "formatted");
log s; 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");
} }

View 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 {
}
}