librustc: Fix merge fallout and test cases.
This commit is contained in:
parent
e015bee286
commit
bb830558d1
26 changed files with 743 additions and 46 deletions
|
@ -49,9 +49,9 @@ fn to_hex(rr: &[u8]) -> ~str {
|
||||||
for rr.iter().advance() |b| {
|
for rr.iter().advance() |b| {
|
||||||
let hex = uint::to_str_radix(*b as uint, 16u);
|
let hex = uint::to_str_radix(*b as uint, 16u);
|
||||||
if hex.len() == 1 {
|
if hex.len() == 1 {
|
||||||
s += "0";
|
s.push_char('0');
|
||||||
}
|
}
|
||||||
s += hex;
|
s.push_str(hex);
|
||||||
}
|
}
|
||||||
return s;
|
return s;
|
||||||
}
|
}
|
||||||
|
|
|
@ -470,13 +470,14 @@ priv fn format(val: Param, op: FormatOp, flags: Flags) -> Result<~[u8],~str> {
|
||||||
FormatHex|FormatHEX => 16,
|
FormatHex|FormatHEX => 16,
|
||||||
FormatString => util::unreachable()
|
FormatString => util::unreachable()
|
||||||
};
|
};
|
||||||
let mut (s,_) = match op {
|
let (s,_) = match op {
|
||||||
FormatDigit => {
|
FormatDigit => {
|
||||||
let sign = if flags.sign { SignAll } else { SignNeg };
|
let sign = if flags.sign { SignAll } else { SignNeg };
|
||||||
to_str_bytes_common(&d, radix, false, sign, DigAll)
|
to_str_bytes_common(&d, radix, false, sign, DigAll)
|
||||||
}
|
}
|
||||||
_ => to_str_bytes_common(&(d as uint), radix, false, SignNone, DigAll)
|
_ => to_str_bytes_common(&(d as uint), radix, false, SignNone, DigAll)
|
||||||
};
|
};
|
||||||
|
let mut s = s;
|
||||||
if flags.precision > s.len() {
|
if flags.precision > s.len() {
|
||||||
let mut s_ = vec::with_capacity(flags.precision);
|
let mut s_ = vec::with_capacity(flags.precision);
|
||||||
let n = flags.precision - s.len();
|
let n = flags.precision - s.len();
|
||||||
|
|
|
@ -403,8 +403,12 @@ mod test {
|
||||||
|
|
||||||
fn make_crate(with_bin: bool, with_lib: bool) -> @ast::crate {
|
fn make_crate(with_bin: bool, with_lib: bool) -> @ast::crate {
|
||||||
let mut attrs = ~[];
|
let mut attrs = ~[];
|
||||||
if with_bin { attrs += [make_crate_type_attr(@"bin")]; }
|
if with_bin {
|
||||||
if with_lib { attrs += [make_crate_type_attr(@"lib")]; }
|
attrs.push(make_crate_type_attr(@"bin"));
|
||||||
|
}
|
||||||
|
if with_lib {
|
||||||
|
attrs.push(make_crate_type_attr(@"lib"));
|
||||||
|
}
|
||||||
@codemap::respan(codemap::dummy_sp(), ast::crate_ {
|
@codemap::respan(codemap::dummy_sp(), ast::crate_ {
|
||||||
module: ast::_mod { view_items: ~[], items: ~[] },
|
module: ast::_mod { view_items: ~[], items: ~[] },
|
||||||
attrs: attrs,
|
attrs: attrs,
|
||||||
|
|
|
@ -484,7 +484,7 @@ fn each_auxiliary_node_id(item: @item, callback: &fn(node_id) -> bool)
|
||||||
let mut continue = true;
|
let mut continue = true;
|
||||||
match item.node {
|
match item.node {
|
||||||
item_enum(ref enum_def, _) => {
|
item_enum(ref enum_def, _) => {
|
||||||
for enum_def.variants.each |variant| {
|
for enum_def.variants.iter().advance |variant| {
|
||||||
continue = callback(variant.node.id);
|
continue = callback(variant.node.id);
|
||||||
if !continue {
|
if !continue {
|
||||||
break
|
break
|
||||||
|
@ -516,7 +516,7 @@ fn encode_reexports(ecx: &EncodeContext,
|
||||||
match ecx.reexports2.find(&id) {
|
match ecx.reexports2.find(&id) {
|
||||||
Some(ref exports) => {
|
Some(ref exports) => {
|
||||||
debug!("(encoding info for module) found reexports for %d", id);
|
debug!("(encoding info for module) found reexports for %d", id);
|
||||||
for exports.each |exp| {
|
for exports.iter().advance |exp| {
|
||||||
debug!("(encoding info for module) reexport '%s' for %d",
|
debug!("(encoding info for module) reexport '%s' for %d",
|
||||||
exp.name, id);
|
exp.name, id);
|
||||||
ebml_w.start_tag(tag_items_data_item_reexport);
|
ebml_w.start_tag(tag_items_data_item_reexport);
|
||||||
|
@ -900,7 +900,7 @@ fn encode_info_for_item(ecx: &EncodeContext,
|
||||||
encode_path(ecx, ebml_w, path, ast_map::path_name(item.ident));
|
encode_path(ecx, ebml_w, path, ast_map::path_name(item.ident));
|
||||||
|
|
||||||
// Encode all the items in this module.
|
// Encode all the items in this module.
|
||||||
for fm.items.each |foreign_item| {
|
for fm.items.iter().advance |foreign_item| {
|
||||||
ebml_w.start_tag(tag_mod_child);
|
ebml_w.start_tag(tag_mod_child);
|
||||||
ebml_w.wr_str(def_to_str(local_def(foreign_item.id)));
|
ebml_w.wr_str(def_to_str(local_def(foreign_item.id)));
|
||||||
ebml_w.end_tag();
|
ebml_w.end_tag();
|
||||||
|
@ -1506,7 +1506,7 @@ fn encode_misc_info(ecx: &EncodeContext,
|
||||||
ebml_w: &mut writer::Encoder) {
|
ebml_w: &mut writer::Encoder) {
|
||||||
ebml_w.start_tag(tag_misc_info);
|
ebml_w.start_tag(tag_misc_info);
|
||||||
ebml_w.start_tag(tag_misc_info_crate_items);
|
ebml_w.start_tag(tag_misc_info_crate_items);
|
||||||
for crate.node.module.items.each |&item| {
|
for crate.node.module.items.iter().advance |&item| {
|
||||||
ebml_w.start_tag(tag_mod_child);
|
ebml_w.start_tag(tag_mod_child);
|
||||||
ebml_w.wr_str(def_to_str(local_def(item.id)));
|
ebml_w.wr_str(def_to_str(local_def(item.id)));
|
||||||
ebml_w.end_tag();
|
ebml_w.end_tag();
|
||||||
|
|
|
@ -140,7 +140,7 @@ impl ReachableContext {
|
||||||
}
|
}
|
||||||
item_enum(ref enum_def, _) => {
|
item_enum(ref enum_def, _) => {
|
||||||
if privacy_context == PublicContext {
|
if privacy_context == PublicContext {
|
||||||
for enum_def.variants.each |variant| {
|
for enum_def.variants.iter().advance |variant| {
|
||||||
reachable_symbols.insert(variant.node.id);
|
reachable_symbols.insert(variant.node.id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -159,7 +159,7 @@ impl ReachableContext {
|
||||||
};
|
};
|
||||||
|
|
||||||
// Mark all public methods as reachable.
|
// Mark all public methods as reachable.
|
||||||
for methods.each |&method| {
|
for methods.iter().advance |&method| {
|
||||||
if should_be_considered_public(method) {
|
if should_be_considered_public(method) {
|
||||||
reachable_symbols.insert(method.id);
|
reachable_symbols.insert(method.id);
|
||||||
}
|
}
|
||||||
|
@ -168,7 +168,7 @@ impl ReachableContext {
|
||||||
if generics_require_inlining(generics) {
|
if generics_require_inlining(generics) {
|
||||||
// If the impl itself has generics, add all public
|
// If the impl itself has generics, add all public
|
||||||
// symbols to the worklist.
|
// symbols to the worklist.
|
||||||
for methods.each |&method| {
|
for methods.iter().advance |&method| {
|
||||||
if should_be_considered_public(method) {
|
if should_be_considered_public(method) {
|
||||||
worklist.push(method.id)
|
worklist.push(method.id)
|
||||||
}
|
}
|
||||||
|
@ -176,7 +176,7 @@ impl ReachableContext {
|
||||||
} else {
|
} else {
|
||||||
// Otherwise, add only public methods that have
|
// Otherwise, add only public methods that have
|
||||||
// generics to the worklist.
|
// generics to the worklist.
|
||||||
for methods.each |method| {
|
for methods.iter().advance |method| {
|
||||||
let generics = &method.generics;
|
let generics = &method.generics;
|
||||||
let attrs = &method.attrs;
|
let attrs = &method.attrs;
|
||||||
if generics_require_inlining(generics) ||
|
if generics_require_inlining(generics) ||
|
||||||
|
@ -190,7 +190,7 @@ impl ReachableContext {
|
||||||
item_trait(_, _, ref trait_methods) => {
|
item_trait(_, _, ref trait_methods) => {
|
||||||
// Mark all provided methods as reachable.
|
// Mark all provided methods as reachable.
|
||||||
if privacy_context == PublicContext {
|
if privacy_context == PublicContext {
|
||||||
for trait_methods.each |trait_method| {
|
for trait_methods.iter().advance |trait_method| {
|
||||||
match *trait_method {
|
match *trait_method {
|
||||||
provided(method) => {
|
provided(method) => {
|
||||||
reachable_symbols.insert(method.id);
|
reachable_symbols.insert(method.id);
|
||||||
|
|
|
@ -1240,7 +1240,7 @@ impl Resolver {
|
||||||
// Create the module and add all methods.
|
// Create the module and add all methods.
|
||||||
match *ty {
|
match *ty {
|
||||||
Ty {
|
Ty {
|
||||||
node: ty_path(path, _),
|
node: ty_path(path, _, _),
|
||||||
_
|
_
|
||||||
} if path.idents.len() == 1 => {
|
} if path.idents.len() == 1 => {
|
||||||
let name = path_to_ident(path);
|
let name = path_to_ident(path);
|
||||||
|
|
|
@ -616,7 +616,7 @@ pub fn GEPi(cx: block, base: ValueRef, ixs: &[uint]) -> ValueRef {
|
||||||
// we care about.
|
// we care about.
|
||||||
if ixs.len() < 16 {
|
if ixs.len() < 16 {
|
||||||
let mut small_vec = [ C_i32(0), ..16 ];
|
let mut small_vec = [ C_i32(0), ..16 ];
|
||||||
for ixs.eachi |i, &ix| {
|
for ixs.iter().enumerate().advance |(i, &ix)| {
|
||||||
small_vec[i] = C_i32(ix as i32)
|
small_vec[i] = C_i32(ix as i32)
|
||||||
}
|
}
|
||||||
InBoundsGEP(cx, base, small_vec.slice(0, ixs.len()))
|
InBoundsGEP(cx, base, small_vec.slice(0, ixs.len()))
|
||||||
|
|
|
@ -39,7 +39,11 @@ enum RegClass {
|
||||||
Memory
|
Memory
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Type {
|
trait TypeMethods {
|
||||||
|
fn is_reg_ty(&self) -> bool;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TypeMethods for Type {
|
||||||
fn is_reg_ty(&self) -> bool {
|
fn is_reg_ty(&self) -> bool {
|
||||||
match self.kind() {
|
match self.kind() {
|
||||||
Integer | Pointer | Float | Double => true,
|
Integer | Pointer | Float | Double => true,
|
||||||
|
|
|
@ -1908,7 +1908,7 @@ impl TypeContents {
|
||||||
// this assertion.
|
// this assertion.
|
||||||
assert!(self.intersects(TC_OWNED_POINTER));
|
assert!(self.intersects(TC_OWNED_POINTER));
|
||||||
}
|
}
|
||||||
let tc = TC_MANAGED + TC_DTOR + TypeContents::owned(cx);
|
let tc = TC_MANAGED + TC_DTOR + TypeContents::sendable(cx);
|
||||||
self.intersects(tc)
|
self.intersects(tc)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1088,16 +1088,19 @@ impl<'self> LookupContext<'self> {
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
|
|
||||||
return match candidate.method_ty.explicit_self {
|
let result = match candidate.method_ty.explicit_self {
|
||||||
sty_static => {
|
sty_static => {
|
||||||
|
debug!("(is relevant?) explicit self is static");
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
|
|
||||||
sty_value => {
|
sty_value => {
|
||||||
|
debug!("(is relevant?) explicit self is by-value");
|
||||||
self.fcx.can_mk_subty(rcvr_ty, candidate.rcvr_ty).is_ok()
|
self.fcx.can_mk_subty(rcvr_ty, candidate.rcvr_ty).is_ok()
|
||||||
}
|
}
|
||||||
|
|
||||||
sty_region(_, m) => {
|
sty_region(_, m) => {
|
||||||
|
debug!("(is relevant?) explicit self is a region");
|
||||||
match ty::get(rcvr_ty).sty {
|
match ty::get(rcvr_ty).sty {
|
||||||
ty::ty_rptr(_, mt) => {
|
ty::ty_rptr(_, mt) => {
|
||||||
mutability_matches(mt.mutbl, m) &&
|
mutability_matches(mt.mutbl, m) &&
|
||||||
|
@ -1109,6 +1112,7 @@ impl<'self> LookupContext<'self> {
|
||||||
}
|
}
|
||||||
|
|
||||||
sty_box(m) => {
|
sty_box(m) => {
|
||||||
|
debug!("(is relevant?) explicit self is a box");
|
||||||
match ty::get(rcvr_ty).sty {
|
match ty::get(rcvr_ty).sty {
|
||||||
ty::ty_box(mt) => {
|
ty::ty_box(mt) => {
|
||||||
mutability_matches(mt.mutbl, m) &&
|
mutability_matches(mt.mutbl, m) &&
|
||||||
|
@ -1120,6 +1124,7 @@ impl<'self> LookupContext<'self> {
|
||||||
}
|
}
|
||||||
|
|
||||||
sty_uniq(m) => {
|
sty_uniq(m) => {
|
||||||
|
debug!("(is relevant?) explicit self is a unique pointer");
|
||||||
match ty::get(rcvr_ty).sty {
|
match ty::get(rcvr_ty).sty {
|
||||||
ty::ty_uniq(mt) => {
|
ty::ty_uniq(mt) => {
|
||||||
mutability_matches(mt.mutbl, m) &&
|
mutability_matches(mt.mutbl, m) &&
|
||||||
|
@ -1131,6 +1136,10 @@ impl<'self> LookupContext<'self> {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
debug!("(is relevant?) %s", if result { "yes" } else { "no" });
|
||||||
|
|
||||||
|
return result;
|
||||||
|
|
||||||
fn mutability_matches(self_mutbl: ast::mutability,
|
fn mutability_matches(self_mutbl: ast::mutability,
|
||||||
candidate_mutbl: ast::mutability) -> bool {
|
candidate_mutbl: ast::mutability) -> bool {
|
||||||
//! True if `self_mutbl <: candidate_mutbl`
|
//! True if `self_mutbl <: candidate_mutbl`
|
||||||
|
|
|
@ -895,8 +895,22 @@ impl CoherenceChecker {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Record all the trait methods.
|
// Record all the trait methods.
|
||||||
let implementation = @implementation;
|
let mut implementation = @implementation;
|
||||||
for associated_traits.iter().advance |trait_ref| {
|
for associated_traits.iter().advance |trait_ref| {
|
||||||
|
self.instantiate_default_methods(implementation.did,
|
||||||
|
*trait_ref);
|
||||||
|
|
||||||
|
// XXX(sully): We could probably avoid this copy if there are no
|
||||||
|
// default methods.
|
||||||
|
let mut methods = copy implementation.methods;
|
||||||
|
self.add_provided_methods_to_impl(&mut methods,
|
||||||
|
&trait_ref.def_id,
|
||||||
|
&implementation.did);
|
||||||
|
implementation = @Impl {
|
||||||
|
methods: methods,
|
||||||
|
..*implementation
|
||||||
|
};
|
||||||
|
|
||||||
self.add_trait_method(trait_ref.def_id, implementation);
|
self.add_trait_method(trait_ref.def_id, implementation);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -929,9 +943,6 @@ impl CoherenceChecker {
|
||||||
do iter_crate_data(crate_store) |crate_number, _crate_metadata| {
|
do iter_crate_data(crate_store) |crate_number, _crate_metadata| {
|
||||||
for each_path(crate_store, crate_number) |_, def_like, _| {
|
for each_path(crate_store, crate_number) |_, def_like, _| {
|
||||||
match def_like {
|
match def_like {
|
||||||
dl_def(def_trait(def_id)) => {
|
|
||||||
self.add_default_methods_for_external_trait(def_id);
|
|
||||||
}
|
|
||||||
dl_impl(def_id) => {
|
dl_impl(def_id) => {
|
||||||
self.add_external_impl(&mut impls_seen,
|
self.add_external_impl(&mut impls_seen,
|
||||||
crate_store,
|
crate_store,
|
||||||
|
|
|
@ -488,7 +488,9 @@ pub fn parameterized(cx: ctxt,
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
strs += vec::map(tps, |t| ty_to_str(cx, *t));
|
for tps.iter().advance |t| {
|
||||||
|
strs.push(ty_to_str(cx, *t))
|
||||||
|
}
|
||||||
|
|
||||||
if strs.len() > 0u {
|
if strs.len() > 0u {
|
||||||
fmt!("%s<%s>", base, strs.connect(","))
|
fmt!("%s<%s>", base, strs.connect(","))
|
||||||
|
|
666
src/librusti/rusti.rc
Normal file
666
src/librusti/rusti.rc
Normal file
|
@ -0,0 +1,666 @@
|
||||||
|
// Copyright 2012-2013 The Rust Project Developers. See the COPYRIGHT
|
||||||
|
// file at the top-level directory of this distribution and at
|
||||||
|
// http://rust-lang.org/COPYRIGHT.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||||
|
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||||
|
// option. This file may not be copied, modified, or distributed
|
||||||
|
// except according to those terms.
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* rusti - A REPL using the JIT backend
|
||||||
|
*
|
||||||
|
* Rusti works by serializing state between lines of input. This means that each
|
||||||
|
* line can be run in a separate task, and the only limiting factor is that all
|
||||||
|
* local bound variables are encodable.
|
||||||
|
*
|
||||||
|
* This is accomplished by feeding in generated input to rustc for execution in
|
||||||
|
* the JIT compiler. Currently input actually gets fed in three times to get
|
||||||
|
* information about the program.
|
||||||
|
*
|
||||||
|
* - Pass #1
|
||||||
|
* In this pass, the input is simply thrown at the parser and the input comes
|
||||||
|
* back. This validates the structure of the program, and at this stage the
|
||||||
|
* global items (fns, structs, impls, traits, etc.) are filtered from the
|
||||||
|
* input into the "global namespace". These declarations shadow all previous
|
||||||
|
* declarations of an item by the same name.
|
||||||
|
*
|
||||||
|
* - Pass #2
|
||||||
|
* After items have been stripped, the remaining input is passed to rustc
|
||||||
|
* along with all local variables declared (initialized to nothing). This pass
|
||||||
|
* runs up to typechecking. From this, we can learn about the types of each
|
||||||
|
* bound variable, what variables are bound, and also ensure that all the
|
||||||
|
* types are encodable (the input can actually be run).
|
||||||
|
*
|
||||||
|
* - Pass #3
|
||||||
|
* Finally, a program is generated to deserialize the local variable state,
|
||||||
|
* run the code input, and then reserialize all bindings back into a local
|
||||||
|
* hash map. Once this code runs, the input has fully been run and the REPL
|
||||||
|
* waits for new input.
|
||||||
|
*
|
||||||
|
* Encoding/decoding is done with EBML, and there is simply a map of ~str ->
|
||||||
|
* ~[u8] maintaining the values of each local binding (by name).
|
||||||
|
*/
|
||||||
|
|
||||||
|
#[link(name = "rusti",
|
||||||
|
vers = "0.7-pre",
|
||||||
|
uuid = "7fb5bf52-7d45-4fee-8325-5ad3311149fc",
|
||||||
|
url = "https://github.com/mozilla/rust/tree/master/src/rusti")];
|
||||||
|
|
||||||
|
#[license = "MIT/ASL2"];
|
||||||
|
#[crate_type = "lib"];
|
||||||
|
|
||||||
|
extern mod extra;
|
||||||
|
extern mod rustc;
|
||||||
|
extern mod syntax;
|
||||||
|
|
||||||
|
use std::{libc, io, os, task, vec};
|
||||||
|
use std::cell::Cell;
|
||||||
|
use extra::rl;
|
||||||
|
|
||||||
|
use rustc::driver::{driver, session};
|
||||||
|
use syntax::{ast, diagnostic};
|
||||||
|
use syntax::ast_util::*;
|
||||||
|
use syntax::parse::token;
|
||||||
|
use syntax::print::pprust;
|
||||||
|
|
||||||
|
use program::Program;
|
||||||
|
use utils::*;
|
||||||
|
|
||||||
|
mod program;
|
||||||
|
pub mod utils;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A structure shared across REPL instances for storing history
|
||||||
|
* such as statements and view items. I wish the AST was sendable.
|
||||||
|
*/
|
||||||
|
pub struct Repl {
|
||||||
|
prompt: ~str,
|
||||||
|
binary: ~str,
|
||||||
|
running: bool,
|
||||||
|
lib_search_paths: ~[~str],
|
||||||
|
|
||||||
|
program: Program,
|
||||||
|
}
|
||||||
|
|
||||||
|
// Action to do after reading a :command
|
||||||
|
enum CmdAction {
|
||||||
|
action_none,
|
||||||
|
action_run_line(~str),
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Run an input string in a Repl, returning the new Repl.
|
||||||
|
fn run(mut repl: Repl, input: ~str) -> Repl {
|
||||||
|
// Build some necessary rustc boilerplate for compiling things
|
||||||
|
let binary = repl.binary.to_managed();
|
||||||
|
let options = @session::options {
|
||||||
|
crate_type: session::unknown_crate,
|
||||||
|
binary: binary,
|
||||||
|
addl_lib_search_paths: @mut repl.lib_search_paths.map(|p| Path(*p)),
|
||||||
|
jit: true,
|
||||||
|
.. copy *session::basic_options()
|
||||||
|
};
|
||||||
|
// Because we assume that everything is encodable (and assert so), add some
|
||||||
|
// extra helpful information if the error crops up. Otherwise people are
|
||||||
|
// bound to be very confused when they find out code is running that they
|
||||||
|
// never typed in...
|
||||||
|
let sess = driver::build_session(options, |cm, msg, lvl| {
|
||||||
|
diagnostic::emit(cm, msg, lvl);
|
||||||
|
if msg.contains("failed to find an implementation of trait") &&
|
||||||
|
msg.contains("extra::serialize::Encodable") {
|
||||||
|
diagnostic::emit(cm,
|
||||||
|
"Currrently rusti serializes bound locals between \
|
||||||
|
different lines of input. This means that all \
|
||||||
|
values of local variables need to be encodable, \
|
||||||
|
and this type isn't encodable",
|
||||||
|
diagnostic::note);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
let intr = token::get_ident_interner();
|
||||||
|
|
||||||
|
//
|
||||||
|
// Stage 1: parse the input and filter it into the program (as necessary)
|
||||||
|
//
|
||||||
|
debug!("parsing: %s", input);
|
||||||
|
let crate = parse_input(sess, binary, input);
|
||||||
|
let mut to_run = ~[]; // statements to run (emitted back into code)
|
||||||
|
let new_locals = @mut ~[]; // new locals being defined
|
||||||
|
let mut result = None; // resultant expression (to print via pp)
|
||||||
|
do find_main(crate, sess) |blk| {
|
||||||
|
// Fish out all the view items, be sure to record 'extern mod' items
|
||||||
|
// differently beause they must appear before all 'use' statements
|
||||||
|
for blk.node.view_items.iter().advance |vi| {
|
||||||
|
let s = do with_pp(intr) |pp, _| {
|
||||||
|
pprust::print_view_item(pp, *vi);
|
||||||
|
};
|
||||||
|
match vi.node {
|
||||||
|
ast::view_item_extern_mod(*) => {
|
||||||
|
repl.program.record_extern(s);
|
||||||
|
}
|
||||||
|
ast::view_item_use(*) => { repl.program.record_view_item(s); }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Iterate through all of the block's statements, inserting them into
|
||||||
|
// the correct portions of the program
|
||||||
|
for blk.node.stmts.iter().advance |stmt| {
|
||||||
|
let s = do with_pp(intr) |pp, _| { pprust::print_stmt(pp, *stmt); };
|
||||||
|
match stmt.node {
|
||||||
|
ast::stmt_decl(d, _) => {
|
||||||
|
match d.node {
|
||||||
|
ast::decl_item(it) => {
|
||||||
|
let name = sess.str_of(it.ident);
|
||||||
|
match it.node {
|
||||||
|
// Structs are treated specially because to make
|
||||||
|
// them at all usable they need to be decorated
|
||||||
|
// with #[deriving(Encoable, Decodable)]
|
||||||
|
ast::item_struct(*) => {
|
||||||
|
repl.program.record_struct(name, s);
|
||||||
|
}
|
||||||
|
// Item declarations are hoisted out of main()
|
||||||
|
_ => { repl.program.record_item(name, s); }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Local declarations must be specially dealt with,
|
||||||
|
// record all local declarations for use later on
|
||||||
|
ast::decl_local(l) => {
|
||||||
|
let mutbl = l.node.is_mutbl;
|
||||||
|
do each_binding(l) |path, _| {
|
||||||
|
let s = do with_pp(intr) |pp, _| {
|
||||||
|
pprust::print_path(pp, path, false);
|
||||||
|
};
|
||||||
|
new_locals.push((s, mutbl));
|
||||||
|
}
|
||||||
|
to_run.push(s);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// run statements with expressions (they have effects)
|
||||||
|
ast::stmt_mac(*) | ast::stmt_semi(*) | ast::stmt_expr(*) => {
|
||||||
|
to_run.push(s);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
result = do blk.node.expr.map_consume |e| {
|
||||||
|
do with_pp(intr) |pp, _| { pprust::print_expr(pp, e); }
|
||||||
|
};
|
||||||
|
}
|
||||||
|
// return fast for empty inputs
|
||||||
|
if to_run.len() == 0 && result.is_none() {
|
||||||
|
return repl;
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// Stage 2: run everything up to typeck to learn the types of the new
|
||||||
|
// variables introduced into the program
|
||||||
|
//
|
||||||
|
info!("Learning about the new types in the program");
|
||||||
|
repl.program.set_cache(); // before register_new_vars (which changes them)
|
||||||
|
let input = to_run.connect("\n");
|
||||||
|
let test = repl.program.test_code(input, &result, *new_locals);
|
||||||
|
debug!("testing with ^^^^^^ %?", (||{ println(test) })());
|
||||||
|
let dinput = driver::str_input(test.to_managed());
|
||||||
|
let cfg = driver::build_configuration(sess, binary, &dinput);
|
||||||
|
let outputs = driver::build_output_filenames(&dinput, &None, &None, [], sess);
|
||||||
|
let (crate, tcx) = driver::compile_upto(sess, copy cfg, &dinput,
|
||||||
|
driver::cu_typeck, Some(outputs));
|
||||||
|
// Once we're typechecked, record the types of all local variables defined
|
||||||
|
// in this input
|
||||||
|
do find_main(crate.expect("crate after cu_typeck"), sess) |blk| {
|
||||||
|
repl.program.register_new_vars(blk, tcx.expect("tcx after cu_typeck"));
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// Stage 3: Actually run the code in the JIT
|
||||||
|
//
|
||||||
|
info!("actually running code");
|
||||||
|
let code = repl.program.code(input, &result);
|
||||||
|
debug!("actually running ^^^^^^ %?", (||{ println(code) })());
|
||||||
|
let input = driver::str_input(code.to_managed());
|
||||||
|
let cfg = driver::build_configuration(sess, binary, &input);
|
||||||
|
let outputs = driver::build_output_filenames(&input, &None, &None, [], sess);
|
||||||
|
let sess = driver::build_session(options, diagnostic::emit);
|
||||||
|
driver::compile_upto(sess, cfg, &input, driver::cu_everything,
|
||||||
|
Some(outputs));
|
||||||
|
|
||||||
|
//
|
||||||
|
// Stage 4: Inform the program that computation is done so it can update all
|
||||||
|
// local variable bindings.
|
||||||
|
//
|
||||||
|
info!("cleaning up after code");
|
||||||
|
repl.program.consume_cache();
|
||||||
|
|
||||||
|
return repl;
|
||||||
|
|
||||||
|
fn parse_input(sess: session::Session, binary: @str,
|
||||||
|
input: &str) -> @ast::crate {
|
||||||
|
let code = fmt!("fn main() {\n %s \n}", input);
|
||||||
|
let input = driver::str_input(code.to_managed());
|
||||||
|
let cfg = driver::build_configuration(sess, binary, &input);
|
||||||
|
let outputs = driver::build_output_filenames(&input, &None, &None, [], sess);
|
||||||
|
let (crate, _) = driver::compile_upto(sess, cfg, &input,
|
||||||
|
driver::cu_parse, Some(outputs));
|
||||||
|
crate.expect("parsing should return a crate")
|
||||||
|
}
|
||||||
|
|
||||||
|
fn find_main(crate: @ast::crate, sess: session::Session,
|
||||||
|
f: &fn(&ast::blk)) {
|
||||||
|
for crate.node.module.items.iter().advance |item| {
|
||||||
|
match item.node {
|
||||||
|
ast::item_fn(_, _, _, _, ref blk) => {
|
||||||
|
if item.ident == sess.ident_of("main") {
|
||||||
|
return f(blk);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fail!("main function was expected somewhere...");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Compiles a crate given by the filename as a library if the compiled
|
||||||
|
// version doesn't exist or is older than the source file. Binary is
|
||||||
|
// the name of the compiling executable. Returns Some(true) if it
|
||||||
|
// successfully compiled, Some(false) if the crate wasn't compiled
|
||||||
|
// because it already exists and is newer than the source file, or
|
||||||
|
// None if there were compile errors.
|
||||||
|
fn compile_crate(src_filename: ~str, binary: ~str) -> Option<bool> {
|
||||||
|
match do task::try {
|
||||||
|
let src_path = Path(src_filename);
|
||||||
|
let binary = binary.to_managed();
|
||||||
|
let options = @session::options {
|
||||||
|
binary: binary,
|
||||||
|
addl_lib_search_paths: @mut ~[os::getcwd()],
|
||||||
|
.. copy *session::basic_options()
|
||||||
|
};
|
||||||
|
let input = driver::file_input(copy src_path);
|
||||||
|
let sess = driver::build_session(options, diagnostic::emit);
|
||||||
|
*sess.building_library = true;
|
||||||
|
let cfg = driver::build_configuration(sess, binary, &input);
|
||||||
|
let outputs = driver::build_output_filenames(
|
||||||
|
&input, &None, &None, [], sess);
|
||||||
|
// If the library already exists and is newer than the source
|
||||||
|
// file, skip compilation and return None.
|
||||||
|
let mut should_compile = true;
|
||||||
|
let dir = os::list_dir_path(&Path(outputs.out_filename.dirname()));
|
||||||
|
let maybe_lib_path = do dir.iter().find_ |file| {
|
||||||
|
// The actual file's name has a hash value and version
|
||||||
|
// number in it which is unknown at this time, so looking
|
||||||
|
// for a file that matches out_filename won't work,
|
||||||
|
// instead we guess which file is the library by matching
|
||||||
|
// the prefix and suffix of out_filename to files in the
|
||||||
|
// directory.
|
||||||
|
let file_str = file.filename().get();
|
||||||
|
file_str.starts_with(outputs.out_filename.filestem().get())
|
||||||
|
&& file_str.ends_with(outputs.out_filename.filetype().get())
|
||||||
|
};
|
||||||
|
match maybe_lib_path {
|
||||||
|
Some(lib_path) => {
|
||||||
|
let (src_mtime, _) = src_path.get_mtime().get();
|
||||||
|
let (lib_mtime, _) = lib_path.get_mtime().get();
|
||||||
|
if lib_mtime >= src_mtime {
|
||||||
|
should_compile = false;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
None => { },
|
||||||
|
}
|
||||||
|
if (should_compile) {
|
||||||
|
println(fmt!("compiling %s...", src_filename));
|
||||||
|
driver::compile_upto(sess, cfg, &input, driver::cu_everything,
|
||||||
|
Some(outputs));
|
||||||
|
true
|
||||||
|
} else { false }
|
||||||
|
} {
|
||||||
|
Ok(true) => Some(true),
|
||||||
|
Ok(false) => Some(false),
|
||||||
|
Err(_) => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Tries to get a line from rl after outputting a prompt. Returns
|
||||||
|
/// None if no input was read (e.g. EOF was reached).
|
||||||
|
fn get_line(use_rl: bool, prompt: &str) -> Option<~str> {
|
||||||
|
if use_rl {
|
||||||
|
let result = unsafe { rl::read(prompt) };
|
||||||
|
|
||||||
|
match result {
|
||||||
|
None => None,
|
||||||
|
Some(line) => {
|
||||||
|
unsafe { rl::add_history(line) };
|
||||||
|
Some(line)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if io::stdin().eof() {
|
||||||
|
None
|
||||||
|
} else {
|
||||||
|
Some(io::stdin().read_line())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Run a command, e.g. :clear, :exit, etc.
|
||||||
|
fn run_cmd(repl: &mut Repl, _in: @io::Reader, _out: @io::Writer,
|
||||||
|
cmd: ~str, args: ~[~str], use_rl: bool) -> CmdAction {
|
||||||
|
let mut action = action_none;
|
||||||
|
match cmd {
|
||||||
|
~"exit" => repl.running = false,
|
||||||
|
~"clear" => {
|
||||||
|
repl.program.clear();
|
||||||
|
|
||||||
|
// XXX: Win32 version of linenoise can't do this
|
||||||
|
//rl::clear();
|
||||||
|
}
|
||||||
|
~"help" => {
|
||||||
|
println(
|
||||||
|
":{\\n ..lines.. \\n:}\\n - execute multiline command\n\
|
||||||
|
:load <crate> ... - loads given crates as dynamic libraries\n\
|
||||||
|
:clear - clear the bindings\n\
|
||||||
|
:exit - exit from the repl\n\
|
||||||
|
:help - show this message");
|
||||||
|
}
|
||||||
|
~"load" => {
|
||||||
|
let mut loaded_crates: ~[~str] = ~[];
|
||||||
|
for args.iter().advance |arg| {
|
||||||
|
let (crate, filename) =
|
||||||
|
if arg.ends_with(".rs") || arg.ends_with(".rc") {
|
||||||
|
(arg.slice_to(arg.len() - 3).to_owned(), copy *arg)
|
||||||
|
} else {
|
||||||
|
(copy *arg, *arg + ".rs")
|
||||||
|
};
|
||||||
|
match compile_crate(filename, copy repl.binary) {
|
||||||
|
Some(_) => loaded_crates.push(crate),
|
||||||
|
None => { }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for loaded_crates.iter().advance |crate| {
|
||||||
|
let crate_path = Path(*crate);
|
||||||
|
let crate_dir = crate_path.dirname();
|
||||||
|
repl.program.record_extern(fmt!("extern mod %s;", *crate));
|
||||||
|
if !repl.lib_search_paths.iter().any_(|x| x == &crate_dir) {
|
||||||
|
repl.lib_search_paths.push(crate_dir);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if loaded_crates.is_empty() {
|
||||||
|
println("no crates loaded");
|
||||||
|
} else {
|
||||||
|
println(fmt!("crates loaded: %s",
|
||||||
|
loaded_crates.connect(", ")));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
~"{" => {
|
||||||
|
let mut multiline_cmd = ~"";
|
||||||
|
let mut end_multiline = false;
|
||||||
|
while (!end_multiline) {
|
||||||
|
match get_line(use_rl, "rusti| ") {
|
||||||
|
None => fail!("unterminated multiline command :{ .. :}"),
|
||||||
|
Some(line) => {
|
||||||
|
if line.trim() == ":}" {
|
||||||
|
end_multiline = true;
|
||||||
|
} else {
|
||||||
|
multiline_cmd.push_str(line);
|
||||||
|
multiline_cmd.push_char('\n');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
action = action_run_line(multiline_cmd);
|
||||||
|
}
|
||||||
|
_ => println(~"unknown cmd: " + cmd)
|
||||||
|
}
|
||||||
|
return action;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Executes a line of input, which may either be rust code or a
|
||||||
|
/// :command. Returns a new Repl if it has changed.
|
||||||
|
pub fn run_line(repl: &mut Repl, in: @io::Reader, out: @io::Writer, line: ~str,
|
||||||
|
use_rl: bool)
|
||||||
|
-> Option<Repl> {
|
||||||
|
if line.starts_with(":") {
|
||||||
|
// drop the : and the \n (one byte each)
|
||||||
|
let full = line.slice(1, line.len());
|
||||||
|
let split: ~[~str] = full.word_iter().transform(|s| s.to_owned()).collect();
|
||||||
|
let len = split.len();
|
||||||
|
|
||||||
|
if len > 0 {
|
||||||
|
let cmd = copy split[0];
|
||||||
|
|
||||||
|
if !cmd.is_empty() {
|
||||||
|
let args = if len > 1 {
|
||||||
|
vec::slice(split, 1, len).to_owned()
|
||||||
|
} else { ~[] };
|
||||||
|
|
||||||
|
match run_cmd(repl, in, out, cmd, args, use_rl) {
|
||||||
|
action_none => { }
|
||||||
|
action_run_line(multiline_cmd) => {
|
||||||
|
if !multiline_cmd.is_empty() {
|
||||||
|
return run_line(repl, in, out, multiline_cmd, use_rl);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let line = Cell::new(line);
|
||||||
|
let r = Cell::new(copy *repl);
|
||||||
|
let result = do task::try {
|
||||||
|
run(r.take(), line.take())
|
||||||
|
};
|
||||||
|
|
||||||
|
if result.is_ok() {
|
||||||
|
return Some(result.get());
|
||||||
|
}
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn main() {
|
||||||
|
let args = os::args();
|
||||||
|
let in = io::stdin();
|
||||||
|
let out = io::stdout();
|
||||||
|
let mut repl = Repl {
|
||||||
|
prompt: ~"rusti> ",
|
||||||
|
binary: copy args[0],
|
||||||
|
running: true,
|
||||||
|
lib_search_paths: ~[],
|
||||||
|
|
||||||
|
program: Program::new(),
|
||||||
|
};
|
||||||
|
|
||||||
|
let istty = unsafe { libc::isatty(libc::STDIN_FILENO as i32) } != 0;
|
||||||
|
|
||||||
|
// only print this stuff if the user is actually typing into rusti
|
||||||
|
if istty {
|
||||||
|
println("WARNING: The Rust REPL is experimental and may be");
|
||||||
|
println("unstable. If you encounter problems, please use the");
|
||||||
|
println("compiler instead. Type :help for help.");
|
||||||
|
|
||||||
|
unsafe {
|
||||||
|
do rl::complete |line, suggest| {
|
||||||
|
if line.starts_with(":") {
|
||||||
|
suggest(~":clear");
|
||||||
|
suggest(~":exit");
|
||||||
|
suggest(~":help");
|
||||||
|
suggest(~":load");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
while repl.running {
|
||||||
|
match get_line(istty, repl.prompt) {
|
||||||
|
None => break,
|
||||||
|
Some(line) => {
|
||||||
|
if line.is_empty() {
|
||||||
|
if istty {
|
||||||
|
println("()");
|
||||||
|
}
|
||||||
|
loop;
|
||||||
|
}
|
||||||
|
match run_line(&mut repl, in, out, line, istty) {
|
||||||
|
Some(new_repl) => repl = new_repl,
|
||||||
|
None => { }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use std::io;
|
||||||
|
use std::iterator::IteratorUtil;
|
||||||
|
use program::Program;
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
fn repl() -> Repl {
|
||||||
|
Repl {
|
||||||
|
prompt: ~"rusti> ",
|
||||||
|
binary: ~"rusti",
|
||||||
|
running: true,
|
||||||
|
lib_search_paths: ~[],
|
||||||
|
program: Program::new(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn run_program(prog: &str) {
|
||||||
|
let mut r = repl();
|
||||||
|
for prog.split_iter('\n').advance |cmd| {
|
||||||
|
let result = run_line(&mut r, io::stdin(), io::stdout(),
|
||||||
|
cmd.to_owned(), false);
|
||||||
|
r = result.expect(fmt!("the command '%s' failed", cmd));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
// FIXME: #7220 rusti on 32bit mac doesn't work.
|
||||||
|
#[cfg(not(target_word_size="32",
|
||||||
|
target_os="macos"))]
|
||||||
|
fn run_all() {
|
||||||
|
// FIXME(#7071):
|
||||||
|
// By default, unit tests are run in parallel. Rusti, on the other hand,
|
||||||
|
// does not enjoy doing this. I suspect that it is because the LLVM
|
||||||
|
// bindings are not thread-safe (when running parallel tests, some tests
|
||||||
|
// were triggering assertions in LLVM (or segfaults). Hence, this
|
||||||
|
// function exists to run everything serially (sadface).
|
||||||
|
//
|
||||||
|
// To get some interesting output, run with RUST_LOG=rusti::tests
|
||||||
|
|
||||||
|
debug!("hopefully this runs");
|
||||||
|
run_program("");
|
||||||
|
|
||||||
|
debug!("regression test for #5937");
|
||||||
|
run_program("use std::hashmap;");
|
||||||
|
|
||||||
|
debug!("regression test for #5784");
|
||||||
|
run_program("let a = 3;");
|
||||||
|
|
||||||
|
// XXX: can't spawn new tasks because the JIT code is cleaned up
|
||||||
|
// after the main function is done.
|
||||||
|
// debug!("regression test for #5803");
|
||||||
|
// run_program("
|
||||||
|
// spawn( || println(\"Please don't segfault\") );
|
||||||
|
// do spawn { println(\"Please?\"); }
|
||||||
|
// ");
|
||||||
|
|
||||||
|
debug!("inferred integers are usable");
|
||||||
|
run_program("let a = 2;\n()\n");
|
||||||
|
run_program("
|
||||||
|
let a = 3;
|
||||||
|
let b = 4u;
|
||||||
|
assert!((a as uint) + b == 7)
|
||||||
|
");
|
||||||
|
|
||||||
|
debug!("local variables can be shadowed");
|
||||||
|
run_program("
|
||||||
|
let a = 3;
|
||||||
|
let a = 5;
|
||||||
|
assert!(a == 5)
|
||||||
|
");
|
||||||
|
|
||||||
|
debug!("strings are usable");
|
||||||
|
run_program("
|
||||||
|
let a = ~\"\";
|
||||||
|
let b = \"\";
|
||||||
|
let c = @\"\";
|
||||||
|
let d = a + b + c;
|
||||||
|
assert!(d.len() == 0);
|
||||||
|
");
|
||||||
|
|
||||||
|
debug!("vectors are usable");
|
||||||
|
run_program("
|
||||||
|
let a = ~[1, 2, 3];
|
||||||
|
let b = &[1, 2, 3];
|
||||||
|
let c = @[1, 2, 3];
|
||||||
|
let d = a + b + c;
|
||||||
|
assert!(d.len() == 9);
|
||||||
|
let e: &[int] = [];
|
||||||
|
");
|
||||||
|
|
||||||
|
debug!("structs are usable");
|
||||||
|
run_program("
|
||||||
|
struct A{ a: int }
|
||||||
|
let b = A{ a: 3 };
|
||||||
|
assert!(b.a == 3)
|
||||||
|
");
|
||||||
|
|
||||||
|
debug!("mutable variables");
|
||||||
|
run_program("
|
||||||
|
let mut a = 3;
|
||||||
|
a = 5;
|
||||||
|
let mut b = std::hashmap::HashSet::new::<int>();
|
||||||
|
b.insert(a);
|
||||||
|
assert!(b.contains(&5))
|
||||||
|
assert!(b.len() == 1)
|
||||||
|
");
|
||||||
|
|
||||||
|
debug!("functions are cached");
|
||||||
|
run_program("
|
||||||
|
fn fib(x: int) -> int { if x < 2 {x} else { fib(x - 1) + fib(x - 2) } }
|
||||||
|
let a = fib(3);
|
||||||
|
let a = a + fib(4);
|
||||||
|
assert!(a == 5)
|
||||||
|
");
|
||||||
|
|
||||||
|
debug!("modules are cached");
|
||||||
|
run_program("
|
||||||
|
mod b { pub fn foo() -> uint { 3 } }
|
||||||
|
assert!(b::foo() == 3)
|
||||||
|
");
|
||||||
|
|
||||||
|
debug!("multiple function definitions are allowed");
|
||||||
|
run_program("
|
||||||
|
fn f() {}
|
||||||
|
fn f() {}
|
||||||
|
f()
|
||||||
|
");
|
||||||
|
|
||||||
|
debug!("multiple item definitions are allowed");
|
||||||
|
run_program("
|
||||||
|
fn f() {}
|
||||||
|
mod f {}
|
||||||
|
struct f;
|
||||||
|
enum f {}
|
||||||
|
fn f() {}
|
||||||
|
f()
|
||||||
|
");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
// FIXME: #7220 rusti on 32bit mac doesn't work.
|
||||||
|
#[cfg(not(target_word_size="32",
|
||||||
|
target_os="macos"))]
|
||||||
|
fn exit_quits() {
|
||||||
|
let mut r = repl();
|
||||||
|
assert!(r.running);
|
||||||
|
let result = run_line(&mut r, io::stdin(), io::stdout(),
|
||||||
|
~":exit", false);
|
||||||
|
assert!(result.is_none());
|
||||||
|
assert!(!r.running);
|
||||||
|
}
|
||||||
|
}
|
|
@ -248,7 +248,7 @@ fn command_line_test_output(args: &[~str]) -> ~[~str] {
|
||||||
let p_output = command_line_test(args, &os::getcwd());
|
let p_output = command_line_test(args, &os::getcwd());
|
||||||
let test_output = str::from_bytes(p_output.output);
|
let test_output = str::from_bytes(p_output.output);
|
||||||
for test_output.split_iter('\n').advance |s| {
|
for test_output.split_iter('\n').advance |s| {
|
||||||
result += [s.to_owned()];
|
result.push(s.to_owned());
|
||||||
}
|
}
|
||||||
result
|
result
|
||||||
}
|
}
|
||||||
|
|
|
@ -55,7 +55,7 @@ impl<A:ToStr+Hash+Eq, B:ToStr+Hash+Eq> ToStr for HashMap<A, B> {
|
||||||
fn to_str(&self) -> ~str {
|
fn to_str(&self) -> ~str {
|
||||||
let mut acc = ~"{";
|
let mut acc = ~"{";
|
||||||
let mut first = true;
|
let mut first = true;
|
||||||
for self.iter().advance |key, value| {
|
for self.iter().advance |(key, value)| {
|
||||||
if first {
|
if first {
|
||||||
first = false;
|
first = false;
|
||||||
}
|
}
|
||||||
|
|
|
@ -563,7 +563,7 @@ pub mod keywords {
|
||||||
// Strict keywords
|
// Strict keywords
|
||||||
As,
|
As,
|
||||||
Break,
|
Break,
|
||||||
Freeze,
|
Const,
|
||||||
Copy,
|
Copy,
|
||||||
Do,
|
Do,
|
||||||
Else,
|
Else,
|
||||||
|
|
|
@ -8,7 +8,7 @@ fn take_copyable(_: &fn:Copy()) {
|
||||||
fn take_copyable_owned(_: &fn:Copy+Send()) {
|
fn take_copyable_owned(_: &fn:Copy+Send()) {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn take_const_owned(_: &fn:Const+Owned()) {
|
fn take_const_owned(_: &fn:Freeze+Send()) {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn give_any(f: &fn:()) {
|
fn give_any(f: &fn:()) {
|
||||||
|
@ -33,7 +33,7 @@ fn give_copyable_owned(f: &fn:Copy+Send()) {
|
||||||
take_any(f);
|
take_any(f);
|
||||||
take_copyable(f);
|
take_copyable(f);
|
||||||
take_copyable_owned(f);
|
take_copyable_owned(f);
|
||||||
take_const_owned(f); //~ ERROR expected bounds `Owned+Const` but found bounds `Copy+Owned`
|
take_const_owned(f); //~ ERROR expected bounds `Send+Freeze` but found bounds `Copy+Send`
|
||||||
}
|
}
|
||||||
|
|
||||||
fn main() {}
|
fn main() {}
|
||||||
|
|
|
@ -11,7 +11,7 @@
|
||||||
struct Foo;
|
struct Foo;
|
||||||
impl Foo {
|
impl Foo {
|
||||||
fn orange(&self){}
|
fn orange(&self){}
|
||||||
fn orange(&self){} //~ ERROR error: duplicate definition of method `orange`
|
fn orange(&self){} //~ ERROR error: duplicate definition of value `orange`
|
||||||
}
|
}
|
||||||
|
|
||||||
fn main() {}
|
fn main() {}
|
||||||
|
|
|
@ -11,14 +11,14 @@
|
||||||
trait Foo {
|
trait Foo {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn a(_x: ~Foo:Owned) {
|
fn a(_x: ~Foo:Send) {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn b(_x: ~Foo:Owned+Copy) {
|
fn b(_x: ~Foo:Send+Copy) {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn c(x: ~Foo:Const+Owned) {
|
fn c(x: ~Foo:Freeze+Send) {
|
||||||
b(x); //~ ERROR expected bounds `Copy+Owned`
|
b(x); //~ ERROR expected bounds `Copy+Send`
|
||||||
}
|
}
|
||||||
|
|
||||||
fn d(x: ~Foo:) {
|
fn d(x: ~Foo:) {
|
||||||
|
|
|
@ -13,7 +13,7 @@ trait Foo {
|
||||||
|
|
||||||
// This should emit the less confusing error, not the more confusing one.
|
// This should emit the less confusing error, not the more confusing one.
|
||||||
|
|
||||||
fn foo(_x: Foo:Owned) { //~ERROR reference to trait `Foo` where a type is expected
|
fn foo(_x: Foo:Send) { //~ERROR reference to trait `Foo` where a type is expected
|
||||||
}
|
}
|
||||||
|
|
||||||
fn main() { }
|
fn main() { }
|
||||||
|
|
|
@ -10,6 +10,6 @@
|
||||||
|
|
||||||
struct Foo;
|
struct Foo;
|
||||||
|
|
||||||
fn foo(_x: ~Foo:Owned) { } //~ ERROR kind bounds can only be used on trait types
|
fn foo(_x: ~Foo:Send) { } //~ ERROR kind bounds can only be used on trait types
|
||||||
|
|
||||||
fn main() { }
|
fn main() { }
|
||||||
|
|
|
@ -10,7 +10,7 @@
|
||||||
|
|
||||||
trait Foo {
|
trait Foo {
|
||||||
fn orange(&self);
|
fn orange(&self);
|
||||||
fn orange(&self); //~ ERROR error: duplicate definition of method `orange`
|
fn orange(&self); //~ ERROR error: duplicate definition of value `orange`
|
||||||
}
|
}
|
||||||
|
|
||||||
fn main() {}
|
fn main() {}
|
||||||
|
|
|
@ -8,7 +8,7 @@
|
||||||
// option. This file may not be copied, modified, or distributed
|
// option. This file may not be copied, modified, or distributed
|
||||||
// except according to those terms.
|
// except according to those terms.
|
||||||
|
|
||||||
// error-pattern: implement a trait or new type instead
|
// error-pattern: found value name used as a type
|
||||||
impl<T> Option<T> {
|
impl<T> Option<T> {
|
||||||
pub fn foo(&self) { }
|
pub fn foo(&self) { }
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,7 +10,7 @@
|
||||||
|
|
||||||
use std::comm;
|
use std::comm;
|
||||||
|
|
||||||
fn foo(blk: ~fn:Owned()) {
|
fn foo(blk: ~fn:Send()) {
|
||||||
blk();
|
blk();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -14,14 +14,14 @@ trait Foo {
|
||||||
fn a(_x: ~Foo:) {
|
fn a(_x: ~Foo:) {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn b(_x: ~Foo:Owned) {
|
fn b(_x: ~Foo:Send) {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn c(x: ~Foo:Const+Owned) {
|
fn c(x: ~Foo:Freeze+Send) {
|
||||||
a(x);
|
a(x);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn d(x: ~Foo:Owned+Copy) {
|
fn d(x: ~Foo:Send+Copy) {
|
||||||
b(x);
|
b(x);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -44,12 +44,12 @@ fn main () {
|
||||||
let a = thing { x: 0 };
|
let a = thing { x: 0 };
|
||||||
let b = thing { x: 1 };
|
let b = thing { x: 1 };
|
||||||
|
|
||||||
assert_eq!(0i.g(), 10);
|
//assert_eq!(0i.g(), 10);
|
||||||
assert_eq!(a.g(), 10);
|
assert_eq!(a.g(), 10);
|
||||||
assert_eq!(a.h(), 10);
|
assert_eq!(a.h(), 10);
|
||||||
|
|
||||||
|
|
||||||
assert_eq!(0i.thing(3.14, 1), (3.14, 1));
|
//assert_eq!(0i.thing(3.14, 1), (3.14, 1));
|
||||||
|
|
||||||
assert_eq!(g(0i, 3.14, 1), (3.14, 1));
|
assert_eq!(g(0i, 3.14, 1), (3.14, 1));
|
||||||
assert_eq!(g(false, 3.14, 1), (3.14, 1));
|
assert_eq!(g(false, 3.14, 1), (3.14, 1));
|
||||||
|
@ -59,8 +59,8 @@ fn main () {
|
||||||
|
|
||||||
|
|
||||||
// Trying out a real one
|
// Trying out a real one
|
||||||
assert!(12.test_neq(&10));
|
//assert!(12.test_neq(&10));
|
||||||
assert!(!10.test_neq(&10));
|
//assert!(!10.test_neq(&10));
|
||||||
assert!(a.test_neq(&b));
|
assert!(a.test_neq(&b));
|
||||||
assert!(!a.test_neq(&a));
|
assert!(!a.test_neq(&a));
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue