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