Merge branch 'master' into recursive-elseif

Conflicts:

	src/Makefile
	src/comp/front/ast.rs
	src/comp/front/parser.rs
	src/comp/middle/fold.rs
	src/comp/middle/trans.rs
This commit is contained in:
Brian Anderson 2011-03-07 21:21:01 -05:00
commit 9fc4db6b89
66 changed files with 8303 additions and 2468 deletions

View file

@ -15,6 +15,7 @@ Jason Orendorff <jorendorff@mozilla.com>
Jeff Balogh <jbalogh@mozilla.com>
Jeff 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>

View file

@ -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, _))) @{

View file

@ -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

View file

@ -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)

View file

@ -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 *)

View file

@ -44,7 +44,7 @@ type ei_data =
;;
let elf_identification ei_class ei_data =
let elf_identification sess ei_class ei_data =
SEQ
[|
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
;;

View file

@ -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;

View file

@ -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"
;;

View file

@ -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);

View file

@ -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

View file

@ -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

View file

@ -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

View file

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

View file

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

View file

@ -41,20 +41,117 @@ fn store_esp_to_runtime_sp() -> vec[str] {
ret vec("movl %esp, " + wstr(abi.task_field_runtime_sp) + "(%ecx)");
}
/*
* 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()

View file

@ -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;

View file

@ -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
View file

@ -0,0 +1,436 @@
import std._vec;
import std._str;
import std.option;
import std.option.some;
import std.option.none;
import std.map.hashmap;
import driver.session;
import ast.ident;
import front.parser.parser;
import front.parser.spanned;
import front.parser.new_parser;
import front.parser.parse_mod_items;
import util.common;
import util.common.filename;
import util.common.append;
import util.common.span;
import util.common.new_str_hash;
// Simple dynamic-typed value type for eval_expr.
tag val {
val_bool(bool);
val_int(int);
val_str(str);
}
type env = vec[tup(ident, val)];
fn mk_env() -> env {
let env e = vec();
ret e;
}
fn val_is_bool(val v) -> bool {
alt (v) {
case (val_bool(_)) { ret true; }
case (_) { }
}
ret false;
}
fn val_is_int(val v) -> bool {
alt (v) {
case (val_bool(_)) { ret true; }
case (_) { }
}
ret false;
}
fn val_is_str(val v) -> bool {
alt (v) {
case (val_str(_)) { ret true; }
case (_) { }
}
ret false;
}
fn val_as_bool(val v) -> bool {
alt (v) {
case (val_bool(?b)) { ret b; }
case (_) { }
}
fail;
}
fn val_as_int(val v) -> int {
alt (v) {
case (val_int(?i)) { ret i; }
case (_) { }
}
fail;
}
fn val_as_str(val v) -> str {
alt (v) {
case (val_str(?s)) { ret s; }
case (_) { }
}
fail;
}
fn lookup(session.session sess, env e, span sp, ident i) -> val {
for (tup(ident, val) pair in e) {
if (_str.eq(i, pair._0)) {
ret pair._1;
}
}
sess.span_err(sp, "unknown variable: " + i);
fail;
}
fn eval_lit(session.session sess, env e, span sp, @ast.lit lit) -> val {
alt (lit.node) {
case (ast.lit_bool(?b)) { ret val_bool(b); }
case (ast.lit_int(?i)) { ret val_int(i); }
case (ast.lit_str(?s)) { ret val_str(s); }
case (_) {
sess.span_err(sp, "evaluating unsupported literal");
}
}
fail;
}
fn eval_expr(session.session sess, env e, @ast.expr x) -> val {
alt (x.node) {
case (ast.expr_path(?pth, _, _)) {
if (_vec.len[ident](pth.node.idents) == 1u &&
_vec.len[@ast.ty](pth.node.types) == 0u) {
ret lookup(sess, e, x.span, pth.node.idents.(0));
}
sess.span_err(x.span, "evaluating structured path-name");
}
case (ast.expr_lit(?lit, _)) {
ret eval_lit(sess, e, x.span, lit);
}
case (ast.expr_unary(?op, ?a, _)) {
auto av = eval_expr(sess, e, a);
alt (op) {
case (ast.not) {
if (val_is_bool(av)) {
ret val_bool(!val_as_bool(av));
}
sess.span_err(x.span, "bad types in '!' expression");
}
case (_) {
sess.span_err(x.span, "evaluating unsupported unop");
}
}
}
case (ast.expr_binary(?op, ?a, ?b, _)) {
auto av = eval_expr(sess, e, a);
auto bv = eval_expr(sess, e, b);
alt (op) {
case (ast.add) {
if (val_is_int(av) && val_is_int(bv)) {
ret val_int(val_as_int(av) + val_as_int(bv));
}
if (val_is_str(av) && val_is_str(bv)) {
ret val_str(val_as_str(av) + val_as_str(bv));
}
sess.span_err(x.span, "bad types in '+' expression");
}
case (ast.sub) {
if (val_is_int(av) && val_is_int(bv)) {
ret val_int(val_as_int(av) - val_as_int(bv));
}
sess.span_err(x.span, "bad types in '-' expression");
}
case (ast.mul) {
if (val_is_int(av) && val_is_int(bv)) {
ret val_int(val_as_int(av) * val_as_int(bv));
}
sess.span_err(x.span, "bad types in '*' expression");
}
case (ast.div) {
if (val_is_int(av) && val_is_int(bv)) {
ret val_int(val_as_int(av) / val_as_int(bv));
}
sess.span_err(x.span, "bad types in '/' expression");
}
case (ast.rem) {
if (val_is_int(av) && val_is_int(bv)) {
ret val_int(val_as_int(av) % val_as_int(bv));
}
sess.span_err(x.span, "bad types in '%' expression");
}
case (ast.and) {
if (val_is_bool(av) && val_is_bool(bv)) {
ret val_bool(val_as_bool(av) && val_as_bool(bv));
}
sess.span_err(x.span, "bad types in '&&' expression");
}
case (ast.or) {
if (val_is_bool(av) && val_is_bool(bv)) {
ret val_bool(val_as_bool(av) || val_as_bool(bv));
}
sess.span_err(x.span, "bad types in '||' expression");
}
case (ast.eq) {
ret val_bool(val_eq(sess, x.span, av, bv));
}
case (ast.ne) {
ret val_bool(! val_eq(sess, x.span, av, bv));
}
case (_) {
sess.span_err(x.span, "evaluating unsupported binop");
}
}
}
case (_) {
sess.span_err(x.span, "evaluating unsupported expression");
}
}
fail;
}
fn val_eq(session.session sess, span sp, val av, val bv) -> bool {
if (val_is_bool(av) && val_is_bool(bv)) {
ret val_as_bool(av) == val_as_bool(bv);
}
if (val_is_int(av) && val_is_int(bv)) {
ret val_as_int(av) == val_as_int(bv);
}
if (val_is_str(av) && val_is_str(bv)) {
ret _str.eq(val_as_str(av),
val_as_str(bv));
}
sess.span_err(sp, "bad types in comparison");
fail;
}
impure fn eval_crate_directives(parser p,
env e,
vec[@ast.crate_directive] cdirs,
str prefix,
&mutable vec[@ast.view_item] view_items,
&mutable vec[@ast.item] items,
hashmap[ast.ident,
ast.mod_index_entry] index) {
for (@ast.crate_directive sub_cdir in cdirs) {
eval_crate_directive(p, e, sub_cdir, prefix,
view_items, items, index);
}
}
impure fn eval_crate_directives_to_mod(parser p,
env e,
vec[@ast.crate_directive] cdirs,
str prefix) -> ast._mod {
let vec[@ast.view_item] view_items = vec();
let vec[@ast.item] items = vec();
auto index = new_str_hash[ast.mod_index_entry]();
eval_crate_directives(p, e, cdirs, prefix,
view_items, items, index);
ret rec(view_items=view_items, items=items, index=index);
}
impure fn eval_crate_directive_block(parser p,
env e,
&ast.block blk,
str prefix,
&mutable vec[@ast.view_item] view_items,
&mutable vec[@ast.item] items,
hashmap[ast.ident,
ast.mod_index_entry] index) {
for (@ast.stmt s in blk.node.stmts) {
alt (s.node) {
case (ast.stmt_crate_directive(?cdir)) {
eval_crate_directive(p, e, cdir, prefix,
view_items, items, index);
}
case (_) {
auto sess = p.get_session();
sess.span_err(s.span,
"unsupported stmt in crate-directive block");
}
}
}
}
impure fn eval_crate_directive_expr(parser p,
env e,
@ast.expr x,
str prefix,
&mutable vec[@ast.view_item] view_items,
&mutable vec[@ast.item] items,
hashmap[ast.ident,
ast.mod_index_entry] index) {
auto sess = p.get_session();
alt (x.node) {
case (ast.expr_if(?cond, ?thn, ?elopt, _)) {
auto cv = eval_expr(sess, e, cond);
if (!val_is_bool(cv)) {
sess.span_err(x.span, "bad cond type in 'if'");
}
if (val_as_bool(cv)) {
ret eval_crate_directive_block(p, e, thn, prefix,
view_items, items,
index);
}
alt (elopt) {
case (some[@ast.expr](?els)) {
ret eval_crate_directive_expr(p, e, els, prefix,
view_items, items,
index);
}
case (_) {
// Absent-else is ok.
}
}
}
case (ast.expr_alt(?v, ?arms, _)) {
auto vv = eval_expr(sess, e, v);
for (ast.arm arm in arms) {
alt (arm.pat.node) {
case (ast.pat_lit(?lit, _)) {
auto pv = eval_lit(sess, e,
arm.pat.span, lit);
if (val_eq(sess, arm.pat.span, vv, pv)) {
ret eval_crate_directive_block
(p, e, arm.block, prefix,
view_items, items, index);
}
}
case (ast.pat_wild(_)) {
ret eval_crate_directive_block
(p, e, arm.block, prefix,
view_items, items, index);
}
case (_) {
sess.span_err(arm.pat.span,
"bad pattern type in 'alt'");
}
}
}
sess.span_err(x.span, "no cases matched in 'alt'");
}
case (ast.expr_block(?block, _)) {
ret eval_crate_directive_block(p, e, block, prefix,
view_items, items,
index);
}
case (_) {
sess.span_err(x.span, "unsupported expr type");
}
}
}
impure fn eval_crate_directive(parser p,
env e,
@ast.crate_directive cdir,
str prefix,
&mutable vec[@ast.view_item] view_items,
&mutable vec[@ast.item] items,
hashmap[ast.ident,
ast.mod_index_entry] index) {
alt (cdir.node) {
case (ast.cdir_let(?id, ?x, ?cdirs)) {
auto v = eval_expr(p.get_session(), e, x);
auto e0 = vec(tup(id, v)) + e;
eval_crate_directives(p, e0, cdirs, prefix,
view_items, items, index);
}
case (ast.cdir_expr(?x)) {
eval_crate_directive_expr(p, e, x, prefix,
view_items, items, index);
}
case (ast.cdir_src_mod(?id, ?file_opt)) {
auto file_path = id + ".rs";
alt (file_opt) {
case (some[filename](?f)) {
file_path = f;
}
case (none[filename]) {}
}
auto full_path = prefix + std.os.path_sep() + file_path;
auto p0 = new_parser(p.get_session(), e, 0, full_path);
auto m0 = parse_mod_items(p0, token.EOF);
auto im = ast.item_mod(id, m0, p.next_def_id());
auto i = @spanned(cdir.span, cdir.span, im);
ast.index_item(index, i);
append[@ast.item](items, i);
}
case (ast.cdir_dir_mod(?id, ?dir_opt, ?cdirs)) {
auto path = id;
alt (dir_opt) {
case (some[filename](?d)) {
path = d;
}
case (none[filename]) {}
}
auto full_path = prefix + std.os.path_sep() + path;
auto m0 = eval_crate_directives_to_mod(p, e, cdirs, full_path);
auto im = ast.item_mod(id, m0, p.next_def_id());
auto i = @spanned(cdir.span, cdir.span, im);
ast.index_item(index, i);
append[@ast.item](items, i);
}
case (ast.cdir_view_item(?vi)) {
append[@ast.view_item](view_items, vi);
ast.index_view_item(index, vi);
}
case (ast.cdir_meta(?mi)) {}
case (ast.cdir_syntax(?pth)) {}
case (ast.cdir_auth(?pth, ?eff)) {}
}
}
//
// Local Variables:
// mode: rust
// fill-column: 78;
// indent-tabs-mode: nil
// c-basic-offset: 4
// buffer-file-coding-system: utf-8-unix
// compile-command: "make -k -C ../.. 2>&1 | sed -e 's/\\/x\\//x:\\//g'";
// End:
//

553
src/comp/front/extfmt.rs Normal file
View file

@ -0,0 +1,553 @@
/* The 'fmt' extension is modeled on the posix printf system.
*
* A posix conversion ostensibly looks like this:
*
* %[parameter][flags][width][.precision][length]type
*
* Given the different numeric type bestiary we have, we omit the 'length'
* parameter and support slightly different conversions for 'type':
*
* %[parameter][flags][width][.precision]type
*
* we also only support translating-to-rust a tiny subset of the possible
* combinations at the moment.
*/
import util.common;
import std._str;
import std._vec;
import std.option;
import std.option.none;
import std.option.some;
export expand_syntax_ext;
tag signedness {
signed;
unsigned;
}
tag caseness {
case_upper;
case_lower;
}
tag ty {
ty_bool;
ty_str;
ty_char;
ty_int(signedness);
ty_bits;
ty_hex(caseness);
// FIXME: More types
}
tag flag {
flag_left_justify;
flag_left_zero_pad;
flag_left_space_pad;
flag_plus_if_positive;
flag_alternate;
}
tag count {
count_is(int);
count_is_param(int);
count_is_next_param;
count_implied;
}
// A formatted conversion from an expression to a string
type conv = rec(option.t[int] param,
vec[flag] flags,
count width,
count precision,
ty ty);
// A fragment of the output sequence
tag piece {
piece_string(str);
piece_conv(conv);
}
// TODO: Need to thread parser through here to handle errors correctly
fn expand_syntax_ext(vec[@ast.expr] args,
option.t[@ast.expr] body) -> @ast.expr {
if (_vec.len[@ast.expr](args) == 0u) {
log "malformed #fmt call";
fail;
}
auto fmt = expr_to_str(args.(0));
// log "Format string:";
// log fmt;
auto pieces = parse_fmt_string(fmt);
auto args_len = _vec.len[@ast.expr](args);
auto fmt_args = _vec.slice[@ast.expr](args, 1u, args_len - 1u);
ret pieces_to_expr(pieces, args);
}
fn expr_to_str(@ast.expr expr) -> str {
alt (expr.node) {
case (ast.expr_lit(?l, _)) {
alt (l.node) {
case (ast.lit_str(?s)) {
ret s;
}
}
}
}
log "malformed #fmt call";
fail;
}
fn parse_fmt_string(str s) -> vec[piece] {
let vec[piece] pieces = vec();
auto lim = _str.byte_len(s);
auto buf = "";
fn flush_buf(str buf, &vec[piece] pieces) -> str {
if (_str.byte_len(buf) > 0u) {
auto piece = piece_string(buf);
pieces += piece;
}
ret "";
}
auto i = 0u;
while (i < lim) {
auto curr = _str.substr(s, i, 1u);
if (_str.eq(curr, "%")) {
i += 1u;
if (i >= lim) {
log "unterminated conversion at end of string";
fail;
}
auto curr2 = _str.substr(s, i, 1u);
if (_str.eq(curr2, "%")) {
i += 1u;
} else {
buf = flush_buf(buf, pieces);
auto res = parse_conversion(s, i, lim);
pieces += res._0;
i = res._1;
}
} else {
buf += curr;
i += 1u;
}
}
buf = flush_buf(buf, pieces);
ret pieces;
}
fn peek_num(str s, uint i, uint lim) -> option.t[tup(uint, uint)] {
if (i >= lim) {
ret none[tup(uint, uint)];
}
auto c = s.(i);
if (!('0' as u8 <= c && c <= '9' as u8)) {
ret option.none[tup(uint, uint)];
}
auto n = (c - ('0' as u8)) as uint;
alt (peek_num(s, i + 1u, lim)) {
case (none[tup(uint, uint)]) {
ret some[tup(uint, uint)](tup(n, i + 1u));
}
case (some[tup(uint, uint)](?next)) {
auto m = next._0;
auto j = next._1;
ret some[tup(uint, uint)](tup(n * 10u + m, j));
}
}
}
fn parse_conversion(str s, uint i, uint lim) -> tup(piece, uint) {
auto parm = parse_parameter(s, i, lim);
auto flags = parse_flags(s, parm._1, lim);
auto width = parse_count(s, flags._1, lim);
auto prec = parse_precision(s, width._1, lim);
auto ty = parse_type(s, prec._1, lim);
ret tup(piece_conv(rec(param = parm._0,
flags = flags._0,
width = width._0,
precision = prec._0,
ty = ty._0)),
ty._1);
}
fn parse_parameter(str s, uint i, uint lim) -> tup(option.t[int], uint) {
if (i >= lim) {
ret tup(none[int], i);
}
auto num = peek_num(s, i, lim);
alt (num) {
case (none[tup(uint, uint)]) {
ret tup(none[int], i);
}
case (some[tup(uint, uint)](?t)) {
auto n = t._0;
auto j = t._1;
if (j < lim && s.(j) == '$' as u8) {
ret tup(some[int](n as int), j + 1u);
}
else {
ret tup(none[int], i);
}
}
}
}
fn parse_flags(str s, uint i, uint lim) -> tup(vec[flag], uint) {
let vec[flag] noflags = vec();
if (i >= lim) {
ret tup(noflags, i);
}
fn more_(flag f, str s, uint i, uint lim) -> tup(vec[flag], uint) {
auto next = parse_flags(s, i + 1u, lim);
auto rest = next._0;
auto j = next._1;
let vec[flag] curr = vec(f);
ret tup(curr + rest, j);
}
auto more = bind more_(_, s, i, lim);
auto f = s.(i);
if (f == ('-' as u8)) {
ret more(flag_left_justify);
} else if (f == ('0' as u8)) {
ret more(flag_left_zero_pad);
} else if (f == (' ' as u8)) {
ret more(flag_left_space_pad);
} else if (f == ('+' as u8)) {
ret more(flag_plus_if_positive);
} else if (f == ('#' as u8)) {
ret more(flag_alternate);
} else {
ret tup(noflags, i);
}
}
fn parse_count(str s, uint i, uint lim) -> tup(count, uint) {
if (i >= lim) {
ret tup(count_implied, i);
}
if (s.(i) == ('*' as u8)) {
auto param = parse_parameter(s, i + 1u, lim);
auto j = param._1;
alt (param._0) {
case (none[int]) {
ret tup(count_is_next_param, j);
}
case (some[int](?n)) {
ret tup(count_is_param(n), j);
}
}
} else {
auto num = peek_num(s, i, lim);
alt (num) {
case (none[tup(uint, uint)]) {
ret tup(count_implied, i);
}
case (some[tup(uint, uint)](?num)) {
ret tup(count_is(num._0 as int), num._1);
}
}
}
}
fn parse_precision(str s, uint i, uint lim) -> tup(count, uint) {
if (i >= lim) {
ret tup(count_implied, i);
}
if (s.(i) == '.' as u8) {
ret parse_count(s, i + 1u, lim);
} else {
ret tup(count_implied, i);
}
}
fn parse_type(str s, uint i, uint lim) -> tup(ty, uint) {
if (i >= lim) {
log "missing type in conversion";
fail;
}
auto t;
auto tstr = _str.substr(s, i, 1u);
if (_str.eq(tstr, "b")) {
t = ty_bool;
} else if (_str.eq(tstr, "s")) {
t = ty_str;
} else if (_str.eq(tstr, "c")) {
t = ty_char;
} else if (_str.eq(tstr, "d")
|| _str.eq(tstr, "i")) {
// TODO: Do we really want two signed types here?
// How important is it to be printf compatible?
t = ty_int(signed);
} else if (_str.eq(tstr, "u")) {
t = ty_int(unsigned);
} else if (_str.eq(tstr, "x")) {
t = ty_hex(case_lower);
} else if (_str.eq(tstr, "X")) {
t = ty_hex(case_upper);
} else if (_str.eq(tstr, "t")) {
t = ty_bits;
} else {
log "unknown type in conversion";
fail;
}
ret tup(t, i + 1u);
}
fn pieces_to_expr(vec[piece] pieces, vec[@ast.expr] args) -> @ast.expr {
fn make_new_lit(common.span sp, ast.lit_ lit) -> @ast.expr {
auto sp_lit = @parser.spanned[ast.lit_](sp, sp, lit);
auto expr = ast.expr_lit(sp_lit, ast.ann_none);
ret @parser.spanned[ast.expr_](sp, sp, expr);
}
fn make_new_str(common.span sp, str s) -> @ast.expr {
auto lit = ast.lit_str(s);
ret make_new_lit(sp, lit);
}
fn make_new_uint(common.span sp, uint u) -> @ast.expr {
auto lit = ast.lit_uint(u);
ret make_new_lit(sp, lit);
}
fn make_add_expr(common.span sp,
@ast.expr lhs, @ast.expr rhs) -> @ast.expr {
auto binexpr = ast.expr_binary(ast.add, lhs, rhs, ast.ann_none);
ret @parser.spanned[ast.expr_](sp, sp, binexpr);
}
fn make_call(common.span sp, vec[ast.ident] fn_path,
vec[@ast.expr] args) -> @ast.expr {
let vec[ast.ident] path_idents = fn_path;
let vec[@ast.ty] path_types = vec();
auto path = rec(idents = path_idents, types = path_types);
auto sp_path = parser.spanned[ast.path_](sp, sp, path);
auto pathexpr = ast.expr_path(sp_path, none[ast.def], ast.ann_none);
auto sp_pathexpr = @parser.spanned[ast.expr_](sp, sp, pathexpr);
auto callexpr = ast.expr_call(sp_pathexpr, args, ast.ann_none);
auto sp_callexpr = @parser.spanned[ast.expr_](sp, sp, callexpr);
ret sp_callexpr;
}
fn make_new_conv(conv cnv, @ast.expr arg) -> @ast.expr {
auto unsupported = "conversion not supported in #fmt string";
alt (cnv.param) {
case (option.none[int]) {
}
case (_) {
log unsupported;
fail;
}
}
if (_vec.len[flag](cnv.flags) != 0u) {
log unsupported;
fail;
}
alt (cnv.width) {
case (count_implied) {
}
case (_) {
log unsupported;
fail;
}
}
alt (cnv.precision) {
case (count_implied) {
}
case (_) {
log unsupported;
fail;
}
}
alt (cnv.ty) {
case (ty_str) {
ret arg;
}
case (ty_int(?sign)) {
alt (sign) {
case (signed) {
let vec[str] path = vec("std", "_int", "to_str");
auto radix_expr = make_new_uint(arg.span, 10u);
let vec[@ast.expr] args = vec(arg, radix_expr);
ret make_call(arg.span, path, args);
}
case (unsigned) {
let vec[str] path = vec("std", "_uint", "to_str");
auto radix_expr = make_new_uint(arg.span, 10u);
let vec[@ast.expr] args = vec(arg, radix_expr);
ret make_call(arg.span, path, args);
}
}
}
case (_) {
log unsupported;
fail;
}
}
}
fn log_conv(conv c) {
alt (c.param) {
case (some[int](?p)) {
log "param: " + std._int.to_str(p, 10u);
}
case (_) {
log "param: none";
}
}
for (flag f in c.flags) {
alt (f) {
case (flag_left_justify) {
log "flag: left justify";
}
case (flag_left_zero_pad) {
log "flag: left zero pad";
}
case (flag_left_space_pad) {
log "flag: left space pad";
}
case (flag_plus_if_positive) {
log "flag: plus if positive";
}
case (flag_alternate) {
log "flag: alternate";
}
}
}
alt (c.width) {
case (count_is(?i)) {
log "width: count is " + std._int.to_str(i, 10u);
}
case (count_is_param(?i)) {
log "width: count is param " + std._int.to_str(i, 10u);
}
case (count_is_next_param) {
log "width: count is next param";
}
case (count_implied) {
log "width: count is implied";
}
}
alt (c.precision) {
case (count_is(?i)) {
log "prec: count is " + std._int.to_str(i, 10u);
}
case (count_is_param(?i)) {
log "prec: count is param " + std._int.to_str(i, 10u);
}
case (count_is_next_param) {
log "prec: count is next param";
}
case (count_implied) {
log "prec: count is implied";
}
}
alt (c.ty) {
case (ty_bool) {
log "type: bool";
}
case (ty_str) {
log "type: str";
}
case (ty_char) {
log "type: char";
}
case (ty_int(?s)) {
alt (s) {
case (signed) {
log "type: signed";
}
case (unsigned) {
log "type: unsigned";
}
}
}
case (ty_bits) {
log "type: bits";
}
case (ty_hex(?cs)) {
alt (cs) {
case (case_upper) {
log "type: uhex";
}
case (case_lower) {
log "type: lhex";
}
}
}
}
}
auto sp = args.(0).span;
auto n = 0u;
auto tmp_expr = make_new_str(sp, "");
for (piece p in pieces) {
alt (p) {
case (piece_string(?s)) {
auto s_expr = make_new_str(sp, s);
tmp_expr = make_add_expr(sp, tmp_expr, s_expr);
}
case (piece_conv(?conv)) {
if (n >= _vec.len[@ast.expr](args)) {
log "too many conversions in #fmt string";
fail;
}
// TODO: Remove debug logging
// log "Building conversion:";
// log_conv(conv);
n += 1u;
auto arg_expr = args.(n);
auto c_expr = make_new_conv(conv, arg_expr);
tmp_expr = make_add_expr(sp, tmp_expr, c_expr);
}
}
}
// TODO: Remove this debug logging
// log "dumping expanded ast:";
// log pretty.print_expr(tmp_expr);
ret tmp_expr;
}
//
// Local Variables:
// mode: rust
// fill-column: 78;
// indent-tabs-mode: nil
// c-basic-offset: 4
// buffer-file-coding-system: utf-8-unix
// compile-command: "make -k -C ../.. 2>&1 | sed -e 's/\\/x\\//x:\\//g'";
// End:
//

View file

@ -1,4 +1,4 @@
import std._io.stdio_reader;
import std.io.stdio_reader;
import std._str;
import std.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
View file

@ -0,0 +1,87 @@
import std._int;
import std._str;
import std._uint;
import std._vec;
export print_expr;
// FIXME this is superseded by ../pretty/pprust.rs. can it be dropped?
fn unknown() -> str {
ret "<unknown ast node>";
}
fn print_expr(@ast.expr expr) -> str {
alt (expr.node) {
case (ast.expr_lit(?lit, _)) {
ret print_lit(lit);
}
case (ast.expr_binary(?op, ?lhs, ?rhs, _)) {
ret print_expr_binary(op, lhs, rhs);
}
case (ast.expr_call(?path, ?args, _)) {
ret print_expr_call(path, args);
}
case (ast.expr_path(?path, _, _)) {
ret print_path(path);
}
case (_) {
ret unknown();
}
}
}
fn print_lit(@ast.lit lit) -> str {
alt (lit.node) {
case (ast.lit_str(?s)) {
ret "\"" + s + "\"";
}
case (ast.lit_int(?i)) {
ret _int.to_str(i, 10u);
}
case (ast.lit_uint(?u)) {
ret _uint.to_str(u, 10u);
}
case (_) {
ret unknown();
}
}
}
fn print_expr_binary(ast.binop op, @ast.expr lhs, @ast.expr rhs) -> str {
alt (op) {
case (ast.add) {
auto l = print_expr(lhs);
auto r = print_expr(rhs);
ret l + " + " + r;
}
}
}
fn print_expr_call(@ast.expr path_expr, vec[@ast.expr] args) -> str {
auto s = print_expr(path_expr);
s += "(";
fn print_expr_ref(&@ast.expr e) -> str { ret print_expr(e); }
auto mapfn = print_expr_ref;
auto argstrs = _vec.map[@ast.expr, str](mapfn, args);
s += _str.connect(argstrs, ", ");
s += ")";
ret s;
}
fn print_path(ast.path path) -> str {
ret _str.connect(path.node.idents, ".");
}
//
// Local Variables:
// mode: rust
// fill-column: 78;
// indent-tabs-mode: nil
// c-basic-offset: 4
// buffer-file-coding-system: utf-8-unix
// compile-command: "make -k -C ../.. 2>&1 | sed -e 's/\\/x\\//x:\\//g'";
// End:
//

View file

@ -76,6 +76,25 @@ const uint LLVMIntSLT = 40u;
const uint LLVMIntSLE = 41u;
// 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"; }

View file

@ -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](_,_),

View file

@ -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
View file

@ -0,0 +1,207 @@
import std.io;
import std._vec;
import std._str;
tag boxtype {box_h; box_v; box_hv; box_align;}
tag contexttype {cx_h; cx_v;}
tag token {
brk(uint);
word(str);
cword(str); // closing token
open(boxtype, uint);
close;
}
type context = rec(contexttype tp, uint indent);
type ps = @rec(mutable vec[context] context,
uint width,
mutable vec[token] buffered,
mutable uint scandepth,
mutable uint bufferedcol,
mutable uint col,
mutable bool start_of_line);
fn mkstate(uint width) -> ps {
let vec[context] stack = vec(rec(tp=cx_v, indent=0u));
let vec[token] buff = vec();
ret @rec(mutable context=stack,
width=width,
mutable buffered=buff,
mutable scandepth=0u,
mutable bufferedcol=0u,
mutable col=0u,
mutable start_of_line=true);
}
impure fn push_context(ps p, contexttype tp, uint indent) {
before_print(p, false);
p.context = _vec.push[context](p.context, rec(tp=tp, indent=base_indent(p)
+ indent));
}
impure fn pop_context(ps p) {
p.context = _vec.pop[context](p.context);
}
impure fn add_token(ps p, token tok) {
if (p.scandepth == 0u) {do_token(p, tok);}
else {buffer_token(p, tok);}
}
impure fn buffer_token(ps p, token tok) {
p.buffered += vec(tok);
p.bufferedcol += token_size(tok);
alt (p.buffered.(0)) {
case (brk(_)) {
alt (tok) {
case (brk(_)) {
if (p.scandepth == 1u) {finish_break_scan(p);}
}
case (open(box_h,_)) {p.scandepth += 1u;}
case (open(_,_)) {finish_break_scan(p);}
case (close) {
p.scandepth -= 1u;
if (p.scandepth == 0u) {finish_break_scan(p);}
}
case (_) {}
}
}
case (open(_,_)) {
if (p.bufferedcol > p.width) {finish_block_scan(p, cx_v);}
else {
alt (tok) {
case (open(_,_)) {p.scandepth += 1u;}
case (close) {
p.scandepth -= 1u;
if (p.scandepth == 0u) {finish_block_scan(p, cx_h);}
}
case (_) {}
}
}
}
}
}
impure fn finish_block_scan(ps p, contexttype tp) {
auto indent;
alt (p.buffered.(0)){
case (open(box_hv,?ind)) {
indent = ind;
}
case (open(box_align, _)) {
indent = p.col - base_indent(p);
}
}
p.scandepth = 0u;
push_context(p, tp, indent);
for (token t in _vec.shift[token](p.buffered)) {add_token(p, t);}
}
impure fn finish_break_scan(ps p) {
if (p.bufferedcol > p.width) {
write_str("\n");
p.col = 0u;
}
else {
auto width;
alt (p.buffered.(0)) {case(brk(?w)) {width = w;}}
auto i = 0u;
while (i < width) {write_str(" "); i+=1u;}
p.col += width;
}
p.scandepth = 0u;
for (token t in _vec.shift[token](p.buffered)) {add_token(p, t);}
}
impure fn start_scan(ps p, token tok) {
p.buffered = vec(tok);
p.scandepth = 1u;
p.bufferedcol = p.col;
}
fn cur_context(ps p) -> context {
ret p.context.(_vec.len[context](p.context)-1u);
}
fn base_indent(ps p) -> uint {
auto i = _vec.len[context](p.context);
while (i > 0u) {
i -= 1u;
auto cx = p.context.(i);
if (cx.tp == cx_v) {ret cx.indent;}
}
}
impure fn do_token(ps p, token tok) {
alt (tok) {
case (brk(?sz)) {
alt (cur_context(p).tp) {
case (cx_h) {
before_print(p, false);
start_scan(p, tok);
}
case (cx_v) {
write_str("\n");
p.col = 0u;
p.start_of_line = true;
}
}
}
case (word(?w)) {
before_print(p, false);
write_str(w);
p.col += _str.byte_len(w); // TODO char_len
}
case (cword(?w)) {
before_print(p, true);
write_str(w);
p.col += _str.byte_len(w); // TODO char_len
}
case (open(?tp, ?indent)) {
alt (tp) {
case (box_hv) {start_scan(p, tok);}
case (box_align) {start_scan(p, tok);}
case (box_h) {push_context(p, cx_h, indent);}
case (box_v) {push_context(p, cx_v, indent);}
}
}
case (close) {pop_context(p);}
}
}
impure fn before_print(ps p, bool closing) {
if (p.start_of_line) {
p.start_of_line = false;
auto ind;
if (closing) {ind = base_indent(p);}
else {ind = cur_context(p).indent;}
p.col = ind;
while (ind > 0u) {write_str(" "); ind -= 1u;}
}
}
fn write_str(str s) {
io.writefd(1, _str.bytes(s));
}
fn token_size(token tok) -> uint {
alt (tok) {
case (brk(?sz)) {ret sz;}
case (word(?w)) {ret _str.byte_len(w);}
case (cword(?w)) {ret _str.byte_len(w);}
case (open(_, _)) {ret 0u;} // TODO exception for V blocks?
case (close) {ret 0u;}
}
}
impure fn box(ps p, uint indent) {add_token(p, open(box_hv, indent));}
impure fn abox(ps p) {add_token(p, open(box_align, 0u));}
impure fn vbox(ps p, uint indent) {add_token(p, open(box_v, indent));}
impure fn hbox(ps p, uint indent) {add_token(p, open(box_h, indent));}
impure fn end(ps p) {add_token(p, close);}
impure fn wrd(ps p, str wrd) {add_token(p, word(wrd));}
impure fn cwrd(ps p, str wrd) {add_token(p, cword(wrd));}
impure fn space(ps p) {add_token(p, brk(1u));}
impure fn spaces(ps p, uint n) {add_token(p, brk(n));}
impure fn line(ps p) {add_token(p, brk(0u));}

708
src/comp/pretty/pprust.rs Normal file
View file

@ -0,0 +1,708 @@
import std._vec;
import std._str;
import std.option;
import front.ast;
import pp.box; import pp.abox; import pp.vbox;
import pp.end; import pp.wrd; import pp.space; import pp.line;
import pp.ps;
import foo = std.io;
const uint indent_unit = 2u;
const int as_prec = 5;
impure fn print_ast(ast._mod _mod) {
auto s = pp.mkstate(80u);
for (@ast.view_item vitem in _mod.view_items) {print_view_item(s, vitem);}
line(s);
for (@ast.item item in _mod.items) {print_item(s, item);}
}
impure fn hbox(ps s) {
pp.hbox(s, indent_unit);
}
impure fn wrd1(ps s, str word) {
wrd(s, word);
space(s);
}
impure fn popen(ps s) {
wrd(s, "(");
abox(s);
}
impure fn pclose(ps s) {
end(s);
wrd(s, ")");
}
impure fn bopen(ps s) {
wrd1(s, "{");
vbox(s, indent_unit);
line(s);
}
impure fn bclose(ps s) {
end(s);
pp.cwrd(s, "}");
}
impure fn commasep[IN](ps s, vec[IN] elts, impure fn (ps, IN) op) {
auto first = true;
for (IN elt in elts) {
if (first) {first = false;}
else {wrd1(s, ",");}
op(s, elt);
}
}
impure fn print_type(ps s, @ast.ty ty) {
hbox(s);
alt (ty.node) {
case (ast.ty_nil) {wrd(s, "()");}
case (ast.ty_bool) {wrd(s, "bool");}
case (ast.ty_int) {wrd(s, "int");}
case (ast.ty_uint) {wrd(s, "uint");}
case (ast.ty_machine(?tm)) {wrd(s, util.common.ty_mach_to_str(tm));}
case (ast.ty_char) {wrd(s, "char");}
case (ast.ty_str) {wrd(s, "str");}
case (ast.ty_box(?t)) {wrd(s, "@"); print_type(s, t);}
case (ast.ty_vec(?t)) {wrd(s, "vec["); print_type(s, t); wrd(s, "]");}
case (ast.ty_type) {wrd(s, "type");}
case (ast.ty_tup(?elts)) {
wrd(s, "tup");
popen(s);
auto f = print_type;
commasep[@ast.ty](s, elts, f);
pclose(s);
}
case (ast.ty_rec(?fields)) {
wrd(s, "rec");
popen(s);
impure fn print_field(ps s, ast.ty_field f) {
hbox(s);
print_type(s, f.ty);
space(s);
wrd(s, f.ident);
end(s);
}
auto f = print_field;
commasep[ast.ty_field](s, fields, f);
pclose(s);
}
case (ast.ty_fn(?proto,?inputs,?output)) {
if (proto == ast.proto_fn) {wrd(s, "fn");}
else {wrd(s, "iter");}
popen(s);
impure fn print_arg(ps s, ast.ty_arg input) {
if (middle.ty.mode_is_alias(input.mode)) {wrd(s, "&");}
print_type(s, input.ty);
}
auto f = print_arg;
commasep[ast.ty_arg](s, inputs, f);
pclose(s);
if (output.node != ast.ty_nil) {
space(s);
hbox(s);
wrd1(s, "->");
print_type(s, output);
end(s);
}
}
case (ast.ty_path(?path,_)) {
print_path(s, path);
}
case (ast.ty_mutable(?t)) {
wrd1(s, "mutable");
print_type(s, t);
}
}
end(s);
}
impure fn print_item(ps s, @ast.item item) {
hbox(s);
alt (item.node) {
case (ast.item_const(?id, ?ty, ?expr, _, _)) {
wrd1(s, "const");
print_type(s, ty);
space(s);
wrd1(s, id);
wrd1(s, "=");
print_expr(s, expr);
wrd(s, ";");
}
case (ast.item_fn(?name,?_fn,?typarams,_,_)) {
print_fn(s, _fn.decl, name, typarams);
space(s);
print_block(s, _fn.body);
}
case (ast.item_mod(?id,?_mod,_)) {
wrd1(s, "mod");
wrd1(s, id);
bopen(s);
for (@ast.item itm in _mod.items) {print_item(s, itm);}
bclose(s);
}
case (ast.item_native_mod(?id,?nmod,_)) {
wrd1(s, "native");
alt (nmod.abi) {
case (ast.native_abi_rust) {wrd1(s, "\"rust\"");}
case (ast.native_abi_cdecl) {wrd1(s, "\"cdecl\"");}
}
wrd1(s, "mod");
wrd1(s, id);
bopen(s);
for (@ast.native_item item in nmod.items) {
hbox(s);
alt (item.node) {
case (ast.native_item_ty(?id,_)) {
wrd1(s, "type");
wrd(s, id);
}
case (ast.native_item_fn(?id,?decl,?typarams,_,_)) {
print_fn(s, decl, id, typarams);
}
}
wrd(s, ";");
end(s);
}
bclose(s);
}
case (ast.item_ty(?id,?ty,?params,_,_)) {
wrd1(s, "type");
wrd(s, id);
print_type_params(s, params);
space(s);
wrd1(s, "=");
print_type(s, ty);
wrd(s, ";");
}
case (ast.item_tag(?id,?variants,?params,_)) {
wrd1(s, "tag");
wrd(s, id);
print_type_params(s, params);
space(s);
bopen(s);
for (ast.variant v in variants) {
wrd(s, v.name);
if (_vec.len[ast.variant_arg](v.args) > 0u) {
popen(s);
impure fn print_variant_arg(ps s, ast.variant_arg arg) {
print_type(s, arg.ty);
}
auto f = print_variant_arg;
commasep[ast.variant_arg](s, v.args, f);
pclose(s);
}
wrd(s, ";");
line(s);
}
bclose(s);
}
case (ast.item_obj(?id,?_obj,?params,_,_)) {
wrd1(s, "obj");
wrd(s, id);
print_type_params(s, params);
popen(s);
impure fn print_field(ps s, ast.obj_field field) {
hbox(s);
print_type(s, field.ty);
space(s);
wrd(s, field.ident);
end(s);
}
auto f = print_field;
commasep[ast.obj_field](s, _obj.fields, f);
pclose(s);
space(s);
bopen(s);
for (@ast.method meth in _obj.methods) {
hbox(s);
let vec[ast.ty_param] typarams = vec();
print_fn(s, meth.node.meth.decl, meth.node.ident, typarams);
space(s);
print_block(s, meth.node.meth.body);
end(s);
line(s);
}
alt (_obj.dtor) {
case (option.some[ast.block](?dtor)) {
hbox(s);
wrd1(s, "close");
print_block(s, dtor);
end(s);
line(s);
}
case (_) {}
}
bclose(s);
}
}
end(s);
line(s);
line(s);
}
impure fn print_block(ps s, ast.block blk) {
bopen(s);
for (@ast.stmt st in blk.node.stmts) {
alt (st.node) {
case (ast.stmt_decl(?decl)) {print_decl(s, decl);}
case (ast.stmt_expr(?expr)) {print_expr(s, expr);}
}
if (front.parser.stmt_ends_with_semi(st)) {wrd(s, ";");}
line(s);
}
alt (blk.node.expr) {
case (option.some[@ast.expr](?expr)) {
print_expr(s, expr);
line(s);
}
case (_) {}
}
bclose(s);
}
impure fn print_literal(ps s, @ast.lit lit) {
alt (lit.node) {
case (ast.lit_str(?st)) {print_string(s, st);}
case (ast.lit_char(?ch)) {
wrd(s, "'" + escape_str(_str.from_bytes(vec(ch as u8)), '\'') + "'");
}
case (ast.lit_int(?val)) {
wrd(s, util.common.istr(val));
}
case (ast.lit_uint(?val)) { // TODO clipping? uistr?
wrd(s, util.common.istr(val as int) + "u");
}
case (ast.lit_mach_int(?mach,?val)) {
wrd(s, util.common.istr(val as int));
wrd(s, util.common.ty_mach_to_str(mach));
}
case (ast.lit_nil) {wrd(s, "()");}
case (ast.lit_bool(?val)) {
if (val) {wrd(s, "true");} else {wrd(s, "false");}
}
}
}
impure fn print_expr(ps s, @ast.expr expr) {
auto pe = print_expr;
hbox(s);
alt (expr.node) {
case (ast.expr_vec(?exprs,_)) {
wrd(s, "vec");
popen(s);
commasep[@ast.expr](s, exprs, pe);
pclose(s);
}
case (ast.expr_tup(?exprs,_)) {
impure fn printElt(ps s, ast.elt elt) {
hbox(s);
if (elt.mut == ast.mut) {wrd1(s, "mutable");}
print_expr(s, elt.expr);
end(s);
}
wrd(s, "tup");
popen(s);
auto f = printElt;
commasep[ast.elt](s, exprs, f);
pclose(s);
}
case (ast.expr_rec(?fields,_,_)) {
impure fn print_field(ps s, ast.field field) {
hbox(s);
if (field.mut == ast.mut) {wrd1(s, "mutable");}
wrd(s, field.ident);
wrd(s, "=");
print_expr(s, field.expr);
end(s);
}
wrd(s, "rec");
popen(s);
auto f = print_field;
commasep[ast.field](s, fields, f);
pclose(s);
}
case (ast.expr_call(?func,?args,_)) {
print_expr(s, func);
popen(s);
commasep[@ast.expr](s, args, pe);
pclose(s);
}
case (ast.expr_bind(?func,?args,_)) {
impure fn print_opt(ps s, option.t[@ast.expr] expr) {
alt (expr) {
case (option.some[@ast.expr](?expr)) {
print_expr(s, expr);
}
case (_) {wrd(s, "_");}
}
}
wrd1(s, "bind");
print_expr(s, func);
popen(s);
auto f = print_opt;
commasep[option.t[@ast.expr]](s, args, f);
pclose(s);
}
case (ast.expr_binary(?op,?lhs,?rhs,_)) {
auto prec = operator_prec(op);
print_maybe_parens(s, lhs, prec);
space(s);
wrd1(s, ast.binop_to_str(op));
print_maybe_parens(s, rhs, prec + 1);
}
case (ast.expr_unary(?op,?expr,_)) {
wrd(s, ast.unop_to_str(op));
if (op == ast._mutable) {space(s);}
print_expr(s, expr);
}
case (ast.expr_lit(?lit,_)) {
print_literal(s, lit);
}
case (ast.expr_cast(?expr,?ty,_)) {
print_maybe_parens(s, expr, as_prec);
space(s);
wrd1(s, "as");
print_type(s, ty);
}
case (ast.expr_if(?test,?block,?elseopt,_)) {
wrd1(s, "if");
popen(s);
print_expr(s, test);
pclose(s);
space(s);
print_block(s, block);
alt (elseopt) {
case (option.some[@ast.expr](?_else)) {
space(s);
wrd1(s, "else");
print_expr(s, _else);
}
}
}
case (ast.expr_while(?test,?block,_)) {
wrd1(s, "while");
popen(s);
print_expr(s, test);
pclose(s);
space(s);
print_block(s, block);
}
case (ast.expr_for(?decl,?expr,?block,_)) {
wrd1(s, "for");
popen(s);
print_decl(s, decl);
space(s);
wrd1(s, "in");
print_expr(s, expr);
pclose(s);
space(s);
print_block(s, block);
}
case (ast.expr_for_each(?decl,?expr,?block,_)) {
wrd1(s, "for each");
popen(s);
print_decl(s, decl);
space(s);
wrd1(s, "in");
print_expr(s, expr);
space(s);
print_block(s, block);
}
case (ast.expr_do_while(?block,?expr,_)) {
wrd1(s, "do");
space(s);
print_block(s, block);
space(s);
wrd1(s, "while");
popen(s);
print_expr(s, expr);
pclose(s);
}
case (ast.expr_alt(?expr,?arms,_)) {
wrd1(s, "alt");
popen(s);
print_expr(s, expr);
pclose(s);
space(s);
bopen(s);
for (ast.arm arm in arms) {
hbox(s);
wrd1(s, "case");
popen(s);
print_pat(s, arm.pat);
pclose(s);
space(s);
print_block(s, arm.block);
end(s);
line(s);
}
bclose(s);
}
case (ast.expr_block(?block,_)) {
print_block(s, block);
}
case (ast.expr_assign(?lhs,?rhs,_)) {
print_expr(s, lhs);
space(s);
wrd1(s, "=");
print_expr(s, rhs);
}
case (ast.expr_assign_op(?op,?lhs,?rhs,_)) {
print_expr(s, lhs);
space(s);
wrd(s, ast.binop_to_str(op));
wrd1(s, "=");
print_expr(s, rhs);
}
case (ast.expr_field(?expr,?id,_)) {
print_expr(s, expr);
wrd(s, ".");
wrd(s, id);
}
case (ast.expr_index(?expr,?index,_)) {
print_expr(s, expr);
wrd(s, ".");
popen(s);
print_expr(s, index);
pclose(s);
}
case (ast.expr_path(?path,_,_)) {
print_path(s, path);
}
case (ast.expr_fail) {
wrd(s, "fail");
}
case (ast.expr_ret(?result)) {
wrd(s, "ret");
alt (result) {
case (option.some[@ast.expr](?expr)) {
space(s);
print_expr(s, expr);
}
case (_) {}
}
}
case (ast.expr_put(?result)) {
wrd(s, "put");
alt (result) {
case (option.some[@ast.expr](?expr)) {
space(s);
print_expr(s, expr);
}
case (_) {}
}
}
case (ast.expr_be(?result)) {
wrd1(s, "be");
print_expr(s, result);
}
case (ast.expr_log(?expr)) {
wrd1(s, "log");
print_expr(s, expr);
}
case (ast.expr_check_expr(?expr)) {
wrd1(s, "check");
print_expr(s, expr);
}
case (_) {wrd(s, "X");}
// TODO expr_ext(path, vec[@expr], option.t[@expr], @expr, ann);
}
end(s);
}
impure fn print_decl(ps s, @ast.decl decl) {
hbox(s);
alt (decl.node) {
case (ast.decl_local(?loc)) {
alt (loc.ty) {
case (option.some[@ast.ty](?ty)) {
wrd1(s, "let");
print_type(s, ty);
space(s);
}
case (_) {
wrd1(s, "auto");
}
}
wrd(s, loc.ident);
alt (loc.init) {
case (option.some[@ast.expr](?init)) {
space(s);
wrd1(s, "=");
print_expr(s, init);
}
case (_) {}
}
}
case (ast.decl_item(?item)) {
print_item(s, item);
}
}
end(s);
}
impure fn print_path(ps s, ast.path path) {
auto first = true;
for (str id in path.node.idents) {
if (first) {first = false;}
else {wrd(s, ".");}
wrd(s, id);
}
if (_vec.len[@ast.ty](path.node.types) > 0u) {
wrd(s, "[");
auto f = print_type;
commasep[@ast.ty](s, path.node.types, f);
wrd(s, "]");
}
}
impure fn print_pat(ps s, @ast.pat pat) {
alt (pat.node) {
case (ast.pat_wild(_)) {wrd(s, "_");}
case (ast.pat_bind(?id,_,_)) {wrd(s, "?" + id);}
case (ast.pat_lit(?lit,_)) {print_literal(s, lit);}
case (ast.pat_tag(?path,?args,_,_)) {
print_path(s, path);
if (_vec.len[@ast.pat](args) > 0u) {
popen(s);
auto f = print_pat;
commasep[@ast.pat](s, args, f);
pclose(s);
}
}
}
}
impure fn print_fn(ps s, ast.fn_decl decl, str name,
vec[ast.ty_param] typarams) {
alt (decl.effect) {
case (ast.eff_impure) {wrd1(s, "impure");}
case (ast.eff_unsafe) {wrd1(s, "unsafe");}
case (_) {}
}
wrd1(s, "fn");
wrd(s, name);
print_type_params(s, typarams);
popen(s);
impure fn print_arg(ps s, ast.arg x) {
hbox(s);
print_type(s, x.ty);
space(s);
wrd(s, x.ident);
end(s);
}
auto f = print_arg;
commasep[ast.arg](s, decl.inputs, f);
pclose(s);
if (decl.output.node != ast.ty_nil) {
space(s);
hbox(s);
wrd1(s, "->");
print_type(s, decl.output);
end(s);
}
}
impure fn print_type_params(ps s, vec[ast.ty_param] params) {
if (_vec.len[ast.ty_param](params) > 0u) {
wrd(s, "[");
impure fn printParam(ps s, ast.ty_param param) {wrd(s, param.ident);}
auto f = printParam;
commasep[ast.ty_param](s, params, f);
wrd(s, "]");
}
}
impure fn print_view_item(ps s, @ast.view_item item) {
hbox(s);
alt (item.node) {
case (ast.view_item_use(?id,?mta,_)) {
wrd1(s, "use");
wrd(s, id);
if (_vec.len[@ast.meta_item](mta) > 0u) {
popen(s);
impure fn print_meta(ps s, @ast.meta_item item) {
hbox(s);
wrd1(s, item.node.name);
wrd1(s, "=");
print_string(s, item.node.value);
end(s);
}
auto f = print_meta;
commasep[@ast.meta_item](s, mta, f);
pclose(s);
}
}
case (ast.view_item_import(?id,?ids,_,_)) {
wrd1(s, "import");
if (!_str.eq(id, ids.(_vec.len[str](ids)-1u))) {
wrd1(s, id);
wrd1(s, "=");
}
auto first = true;
for (str elt in ids) {
if (first) {first = false;}
else {wrd(s, ".");}
wrd(s, elt);
}
}
case (ast.view_item_export(?id)) {
wrd1(s, "export");
wrd(s, id);
}
}
end(s);
wrd(s, ";");
line(s);
}
// FIXME: The fact that this builds up the table anew for every call is
// not good. Eventually, table should be a const.
fn operator_prec(ast.binop op) -> int {
for (front.parser.op_spec spec in front.parser.prec_table()) {
if (spec.op == op) {ret spec.prec;}
}
fail;
}
impure fn print_maybe_parens(ps s, @ast.expr expr, int outer_prec) {
auto add_them;
alt (expr.node) {
case (ast.expr_binary(?op,_,_,_)) {
add_them = operator_prec(op) < outer_prec;
}
case (ast.expr_cast(_,_,_)) {
add_them = as_prec < outer_prec;
}
case (_) {
add_them = false;
}
}
if (add_them) {popen(s);}
print_expr(s, expr);
if (add_them) {pclose(s);}
}
// TODO non-ascii
fn escape_str(str st, char to_escape) -> str {
let str out = "";
auto len = _str.byte_len(st);
auto i = 0u;
while (i < len) {
alt (st.(i) as char) {
case ('\n') {out += "\\n";}
case ('\t') {out += "\\t";}
case ('\r') {out += "\\r";}
case ('\\') {out += "\\\\";}
case (?cur) {
if (cur == to_escape) {out += "\\";}
out += cur as u8;
}
}
i += 1u;
}
ret out;
}
impure fn print_string(ps s, str st) {
wrd(s, "\""); wrd(s, escape_str(st, '"')); wrd(s, "\"");
}

View file

@ -5,9 +5,12 @@ use std;
mod front {
mod 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") {

View file

@ -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 {

View file

@ -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 {

View file

@ -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
View file

@ -0,0 +1,284 @@
/*
* A SHA-1 implementation derived from Paul E. Jones's reference
* implementation, which is written for clarity, not speed. At some
* point this will want to be rewritten.
*/
import std._vec;
import std._str;
export sha1;
export mk_sha1;
state type sha1 = state obj {
// Provide message input as bytes
fn input(&vec[u8]);
// Provide message input as string
fn input_str(&str);
// Read the digest as a vector of 20 bytes. After
// calling this no further input may provided
// until reset is called
fn result() -> vec[u8];
// Reset the sha1 state for reuse. This is called
// automatically during construction
fn reset();
};
// Some unexported constants
const uint digest_buf_len = 5;
const uint msg_block_len = 64;
// Builds a sha1 object
fn mk_sha1() -> sha1 {
state type sha1state = rec(vec[mutable u32] h,
mutable u32 len_low,
mutable u32 len_high,
vec[mutable u8] msg_block,
mutable uint msg_block_idx,
mutable bool computed);
impure fn add_input(&sha1state st, &vec[u8] msg) {
// FIXME: Should be typestate precondition
check (!st.computed);
for (u8 element in msg) {
st.msg_block.(st.msg_block_idx) = element;
st.msg_block_idx += 1u;
st.len_low += 8u32;
if (st.len_low == 0u32) {
st.len_high += 1u32;
if (st.len_high == 0u32) {
// FIXME: Need better failure mode
fail;
}
}
if (st.msg_block_idx == msg_block_len) {
process_msg_block(st);
}
}
}
impure fn process_msg_block(&sha1state st) {
// FIXME: Make precondition
check (_vec.len[mutable u32](st.h) == digest_buf_len);
// Constants
auto k = vec(0x5A827999u32,
0x6ED9EBA1u32,
0x8F1BBCDCu32,
0xCA62C1D6u32);
let int t; // Loop counter
let vec[mutable u32] w = _vec.init_elt[mutable u32](0u32, 80u);
// Initialize the first 16 words of the vector w
t = 0;
while (t < 16) {
w.(t) = (st.msg_block.(t * 4) as u32) << 24u32;
w.(t) = w.(t) | ((st.msg_block.(t * 4 + 1) as u32) << 16u32);
w.(t) = w.(t) | ((st.msg_block.(t * 4 + 2) as u32) << 8u32);
w.(t) = w.(t) | (st.msg_block.(t * 4 + 3) as u32);
t += 1;
}
// Initialize the rest of vector w
while (t < 80) {
auto val = w.(t-3) ^ w.(t-8) ^ w.(t-14) ^ w.(t-16);
w.(t) = circular_shift(1u32, val);
t += 1;
}
auto a = st.h.(0);
auto b = st.h.(1);
auto c = st.h.(2);
auto d = st.h.(3);
auto e = st.h.(4);
let u32 temp;
t = 0;
while (t < 20) {
temp = circular_shift(5u32, a)
+ ((b & c) | ((~b) & d)) + e + w.(t) + k.(0);
e = d;
d = c;
c = circular_shift(30u32, b);
b = a;
a = temp;
t += 1;
}
while (t < 40) {
temp = circular_shift(5u32, a)
+ (b ^ c ^ d) + e + w.(t) + k.(1);
e = d;
d = c;
c = circular_shift(30u32, b);
b = a;
a = temp;
t += 1;
}
while (t < 60) {
temp = circular_shift(5u32, a)
+ ((b & c) | (b & d) | (c & d)) + e + w.(t) + k.(2);
e = d;
d = c;
c = circular_shift(30u32, b);
b = a;
a = temp;
t += 1;
}
while (t < 80) {
temp = circular_shift(5u32, a)
+ (b ^ c ^ d) + e + w.(t) + k.(3);
e = d;
d = c;
c = circular_shift(30u32, b);
b = a;
a = temp;
t += 1;
}
st.h.(0) = st.h.(0) + a;
st.h.(1) = st.h.(1) + b;
st.h.(2) = st.h.(2) + c;
st.h.(3) = st.h.(3) + d;
st.h.(4) = st.h.(4) + e;
st.msg_block_idx = 0u;
}
fn circular_shift(u32 bits, u32 word) -> u32 {
// FIXME: This is a workaround for a rustboot
// "unrecognized quads" codegen bug
auto bits_hack = bits;
ret (word << bits_hack) | (word >> (32u32 - bits));
}
impure fn mk_result(&sha1state st) -> vec[u8] {
if (!st.computed) {
pad_msg(st);
st.computed = true;
}
let vec[u8] res = vec();
for (u32 hpart in st.h) {
res += (hpart >> 24u32) & 0xFFu32 as u8;
res += (hpart >> 16u32) & 0xFFu32 as u8;
res += (hpart >> 8u32) & 0xFFu32 as u8;
res += hpart & 0xFFu32 as u8;
}
ret res;
}
/*
* According to the standard, the message must be padded to an even
* 512 bits. The first padding bit must be a '1'. The last 64 bits
* represent the length of the original message. All bits in between
* should be 0. This function will pad the message according to those
* rules by filling the msg_block vector accordingly. It will also
* call process_msg_block() appropriately. When it returns, it
* can be assumed that the message digest has been computed.
*/
impure fn pad_msg(&sha1state st) {
// FIXME: Should be a precondition
check (_vec.len[mutable u8](st.msg_block) == msg_block_len);
/*
* Check to see if the current message block is too small to hold
* the initial padding bits and length. If so, we will pad the
* block, process it, and then continue padding into a second block.
*/
if (st.msg_block_idx > 55u) {
st.msg_block.(st.msg_block_idx) = 0x80u8;
st.msg_block_idx += 1u;
while (st.msg_block_idx < msg_block_len) {
st.msg_block.(st.msg_block_idx) = 0u8;
st.msg_block_idx += 1u;
}
process_msg_block(st);
} else {
st.msg_block.(st.msg_block_idx) = 0x80u8;
st.msg_block_idx += 1u;
}
while (st.msg_block_idx < 56u) {
st.msg_block.(st.msg_block_idx) = 0u8;
st.msg_block_idx += 1u;
}
// Store the message length as the last 8 octets
st.msg_block.(56) = (st.len_high >> 24u32) & 0xFFu32 as u8;
st.msg_block.(57) = (st.len_high >> 16u32) & 0xFFu32 as u8;
st.msg_block.(58) = (st.len_high >> 8u32) & 0xFFu32 as u8;
st.msg_block.(59) = st.len_high & 0xFFu32 as u8;
st.msg_block.(60) = (st.len_low >> 24u32) & 0xFFu32 as u8;
st.msg_block.(61) = (st.len_low >> 16u32) & 0xFFu32 as u8;
st.msg_block.(62) = (st.len_low >> 8u32) & 0xFFu32 as u8;
st.msg_block.(63) = st.len_low & 0xFFu32 as u8;
process_msg_block(st);
}
state obj sha1(sha1state st) {
fn reset() {
// FIXME: Should be typestate precondition
check (_vec.len[mutable u32](st.h) == digest_buf_len);
st.len_low = 0u32;
st.len_high = 0u32;
st.msg_block_idx = 0u;
st.h.(0) = 0x67452301u32;
st.h.(1) = 0xEFCDAB89u32;
st.h.(2) = 0x98BADCFEu32;
st.h.(3) = 0x10325476u32;
st.h.(4) = 0xC3D2E1F0u32;
st.computed = false;
}
fn input(&vec[u8] msg) {
add_input(st, msg);
}
fn input_str(&str msg) {
add_input(st, _str.bytes(msg));
}
fn result() -> vec[u8] {
ret mk_result(st);
}
}
auto st = rec(h = _vec.init_elt[mutable u32](0u32, digest_buf_len),
mutable len_low = 0u32,
mutable len_high = 0u32,
msg_block = _vec.init_elt[mutable u8](0u8, msg_block_len),
mutable msg_block_idx = 0u,
mutable computed = false);
auto sh = sha1(st);
sh.reset();
ret sh;
}
// Local Variables:
// mode: rust;
// fill-column: 78;
// indent-tabs-mode: nil
// c-basic-offset: 4
// buffer-file-coding-system: utf-8-unix
// compile-command: "make -k -C .. 2>&1 | sed -e 's/\\/x\\//x:\\//g'";
// End:

View file

@ -14,7 +14,7 @@ mod _str;
// General IO and system-services modules.
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;

View file

@ -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),

View file

@ -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);

View file

@ -49,7 +49,8 @@ rust_crate_cache::c_sym::c_sym(rust_dom *dom, lib *library, char const *name)
dom->log(rust_log::CACHE, "resolved symbol '%s' to 0x%" PRIxPTR,
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;
}

View file

@ -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;

View file

@ -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.

View file

@ -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);

View file

@ -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,

View file

@ -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);

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -0,0 +1,10 @@
// error-pattern: Non-call expression in tail call
fn f() -> int {
auto x = 1;
be x;
}
fn main() {
auto y = f();
}

View file

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

View file

@ -0,0 +1,17 @@
fn altlit(int f) -> int {
alt (f) {
case (10) {
log "case 10";
ret 20;
}
case (11) {
log "case 11";
ret 22;
}
}
}
fn main() {
check (altlit(10) == 20);
check (altlit(11) == 22);
}

View file

@ -0,0 +1,24 @@
// Unsigned integer operations
fn main() {
check (0u8 < 255u8);
check (0u8 <= 255u8);
check (255u8 > 0u8);
check (255u8 >= 0u8);
check (250u8 / 10u8 == 25u8);
check (255u8 % 10u8 == 5u8);
check (0u16 < 60000u16);
check (0u16 <= 60000u16);
check (60000u16 > 0u16);
check (60000u16 >= 0u16);
check (60000u16 / 10u16 == 6000u16);
check (60005u16 % 10u16 == 5u16);
check (0u32 < 4000000000u32);
check (0u32 <= 4000000000u32);
check (4000000000u32 > 0u32);
check (4000000000u32 >= 0u32);
check (4000000000u32 / 10u32 == 400000000u32);
check (4000000005u32 % 10u32 == 5u32);
// 64-bit numbers have some flakiness yet. Not tested
}

View file

@ -0,0 +1,8 @@
fn box[T](&tup(T,T,T) x) -> @tup(T,T,T) {
ret @x;
}
fn main() {
let @tup(int,int,int) x = box[int](tup(1,2,3));
check (x._1 == 2);
}

View file

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

View file

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

View file

@ -6,4 +6,4 @@ tag option[T] {
fn main() {
let option[int] a = some[int](@10);
a = none[int];
}
}

View file

@ -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() {}

View file

@ -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));

View file

@ -0,0 +1,115 @@
// -*- rust -*-
use std;
import std.sha1;
import std._vec;
import std._str;
fn main() {
type test = rec(str input, vec[u8] output);
fn a_million_letter_a() -> str {
auto i = 0;
auto res = "";
while (i < 100000) {
res += "aaaaaaaaaa";
i += 1;
}
ret res;
}
// Test messages from FIPS 180-1
let vec[test] fips_180_1_tests =
vec(
rec(input = "abc",
output = vec(0xA9u8, 0x99u8, 0x3Eu8, 0x36u8, 0x47u8,
0x06u8, 0x81u8, 0x6Au8, 0xBAu8, 0x3Eu8,
0x25u8, 0x71u8, 0x78u8, 0x50u8, 0xC2u8,
0x6Cu8, 0x9Cu8, 0xD0u8, 0xD8u8, 0x9Du8)
),
rec(input = "abcdbcdecdefdefgefghfghighij"
+ "hijkijkljklmklmnlmnomnopnopq",
output = vec(0x84u8, 0x98u8, 0x3Eu8, 0x44u8, 0x1Cu8,
0x3Bu8, 0xD2u8, 0x6Eu8, 0xBAu8, 0xAEu8,
0x4Au8, 0xA1u8, 0xF9u8, 0x51u8, 0x29u8,
0xE5u8, 0xE5u8, 0x46u8, 0x70u8, 0xF1u8)
)
// FIXME: This test is disabled because it takes some
// minutes to run under rustboot+valgrind. It may be
// possible to reenable once things are more optimized.
/*,
rec(input = a_million_letter_a(),
output = vec(0x34u8, 0xAAu8, 0x97u8, 0x3Cu8, 0xD4u8,
0xC4u8, 0xDAu8, 0xA4u8, 0xF6u8, 0x1Eu8,
0xEBu8, 0x2Bu8, 0xDBu8, 0xADu8, 0x27u8,
0x31u8, 0x65u8, 0x34u8, 0x01u8, 0x6Fu8)
)
*/
);
// Examples from wikipedia
let vec[test] wikipedia_tests =
vec(
rec(input = "The quick brown fox jumps over the lazy dog",
output = vec(0x2fu8, 0xd4u8, 0xe1u8, 0xc6u8, 0x7au8,
0x2du8, 0x28u8, 0xfcu8, 0xedu8, 0x84u8,
0x9eu8, 0xe1u8, 0xbbu8, 0x76u8, 0xe7u8,
0x39u8, 0x1bu8, 0x93u8, 0xebu8, 0x12u8)
),
rec(input = "The quick brown fox jumps over the lazy cog",
output = vec(0xdeu8, 0x9fu8, 0x2cu8, 0x7fu8, 0xd2u8,
0x5eu8, 0x1bu8, 0x3au8, 0xfau8, 0xd3u8,
0xe8u8, 0x5au8, 0x0bu8, 0xd1u8, 0x7du8,
0x9bu8, 0x10u8, 0x0du8, 0xb4u8, 0xb3u8)
)
);
auto tests = fips_180_1_tests + wikipedia_tests;
fn check_vec_eq(vec[u8] v0, vec[u8] v1) {
check (_vec.len[u8](v0) == _vec.len[u8](v1));
auto len = _vec.len[u8](v0);
auto i = 0u;
while (i < len) {
auto a = v0.(i);
auto b = v1.(i);
check (a == b);
i += 1u;
}
}
// Test that it works when accepting the message all at once
auto sh = sha1.mk_sha1();
for (test t in tests) {
sh.input_str(t.input);
auto out = sh.result();
check_vec_eq(t.output, out);
sh.reset();
}
// Test that it works when accepting the message in pieces
for (test t in tests) {
auto len = _str.byte_len(t.input);
auto left = len;
while (left > 0u) {
auto take = (left + 1u) / 2u;
sh.input_str(_str.substr(t.input, len - left, take));
left = left - take;
}
auto out = sh.result();
check_vec_eq(t.output, out);
sh.reset();
}
}
// Local Variables:
// mode: rust;
// fill-column: 78;
// indent-tabs-mode: nil
// c-basic-offset: 4
// buffer-file-coding-system: utf-8-unix
// compile-command: "make -k -C .. 2>&1 | sed -e 's/\\/x\\//x:\\//g'";
// End:

View file

@ -0,0 +1,20 @@
native "rust" mod rustrt {
type vbuf;
fn vec_buf[T](vec[T] v, uint offset) -> vbuf;
}
native "rust" mod bar = "foo" {
}
native mod zed {
}
native mod libc = "libc.dylib" {
fn write(int fd, rustrt.vbuf buf, uint count) -> int;
}
native "cdecl" mod baz {
}
fn main(vec[str] args) {
}

View file

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

View file

@ -1,5 +1,16 @@
use std;
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");
}

View file

@ -0,0 +1,26 @@
fn f() {
auto x = 10;
auto y = 11;
if (true) {
alt (x) {
case (_) {
y = x;
}
}
} else {
}
}
fn main() {
auto x = 10;
auto y = 11;
if (true) {
while (false) {
y = x;
}
} else {
}
}