commit
d062de8aa4
|
@ -1469,34 +1469,6 @@ cannot be stored in data structures or returned from
|
|||
functions. Despite these limitations, stack closures are used
|
||||
pervasively in Rust code.
|
||||
|
||||
## Managed closures
|
||||
|
||||
When you need to store a closure in a data structure, a stack closure
|
||||
will not do, since the compiler will refuse to let you store it. For
|
||||
this purpose, Rust provides a type of closure that has an arbitrary
|
||||
lifetime, written `@fn` (boxed closure, analogous to the `@` pointer
|
||||
type described earlier). This type of closure *is* first-class.
|
||||
|
||||
A managed closure does not directly access its environment, but merely
|
||||
copies out the values that it closes over into a private data
|
||||
structure. This means that it can not assign to these variables, and
|
||||
cannot observe updates to them.
|
||||
|
||||
This code creates a closure that adds a given string to its argument,
|
||||
returns it from a function, and then calls it:
|
||||
|
||||
~~~~
|
||||
fn mk_appender(suffix: ~str) -> @fn(~str) -> ~str {
|
||||
// The compiler knows that we intend this closure to be of type @fn
|
||||
return |s| s + suffix;
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let shout = mk_appender(~"!");
|
||||
println(shout(~"hey ho, let's go"));
|
||||
}
|
||||
~~~~
|
||||
|
||||
## Owned closures
|
||||
|
||||
Owned closures, written `~fn` in analogy to the `~` pointer type,
|
||||
|
|
|
@ -36,37 +36,39 @@
|
|||
* still held if needed.
|
||||
*/
|
||||
|
||||
|
||||
use std::option;
|
||||
use std::ptr;
|
||||
use std::routine::Runnable;
|
||||
use std::util;
|
||||
|
||||
/**
|
||||
* The type representing a foreign chunk of memory
|
||||
*
|
||||
*/
|
||||
pub struct CVec<T> {
|
||||
priv base: *mut T,
|
||||
priv len: uint,
|
||||
priv rsrc: @DtorRes
|
||||
priv rsrc: @DtorRes,
|
||||
}
|
||||
|
||||
struct DtorRes {
|
||||
dtor: Option<@fn()>,
|
||||
dtor: Option<~Runnable>,
|
||||
}
|
||||
|
||||
#[unsafe_destructor]
|
||||
impl Drop for DtorRes {
|
||||
fn drop(&mut self) {
|
||||
match self.dtor {
|
||||
option::None => (),
|
||||
option::Some(f) => f()
|
||||
let dtor = util::replace(&mut self.dtor, None);
|
||||
match dtor {
|
||||
None => (),
|
||||
Some(f) => f.run()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn DtorRes(dtor: Option<@fn()>) -> DtorRes {
|
||||
impl DtorRes {
|
||||
fn new(dtor: Option<~Runnable>) -> DtorRes {
|
||||
DtorRes {
|
||||
dtor: dtor
|
||||
dtor: dtor,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -83,10 +85,10 @@ fn DtorRes(dtor: Option<@fn()>) -> DtorRes {
|
|||
* * len - The number of elements in the buffer
|
||||
*/
|
||||
pub unsafe fn CVec<T>(base: *mut T, len: uint) -> CVec<T> {
|
||||
return CVec{
|
||||
return CVec {
|
||||
base: base,
|
||||
len: len,
|
||||
rsrc: @DtorRes(option::None)
|
||||
rsrc: @DtorRes::new(None)
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -101,12 +103,12 @@ pub unsafe fn CVec<T>(base: *mut T, len: uint) -> CVec<T> {
|
|||
* * dtor - A function to run when the value is destructed, useful
|
||||
* for freeing the buffer, etc.
|
||||
*/
|
||||
pub unsafe fn c_vec_with_dtor<T>(base: *mut T, len: uint, dtor: @fn())
|
||||
pub unsafe fn c_vec_with_dtor<T>(base: *mut T, len: uint, dtor: ~Runnable)
|
||||
-> CVec<T> {
|
||||
return CVec{
|
||||
base: base,
|
||||
len: len,
|
||||
rsrc: @DtorRes(option::Some(dtor))
|
||||
rsrc: @DtorRes::new(Some(dtor))
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -153,6 +155,20 @@ mod tests {
|
|||
|
||||
use std::libc::*;
|
||||
use std::libc;
|
||||
use std::routine::Runnable;
|
||||
|
||||
struct LibcFree {
|
||||
mem: *c_void,
|
||||
}
|
||||
|
||||
impl Runnable for LibcFree {
|
||||
#[fixed_stack_segment]
|
||||
fn run(~self) {
|
||||
unsafe {
|
||||
libc::free(self.mem)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn malloc(n: size_t) -> CVec<u8> {
|
||||
#[fixed_stack_segment];
|
||||
|
@ -163,12 +179,11 @@ mod tests {
|
|||
|
||||
assert!(mem as int != 0);
|
||||
|
||||
return c_vec_with_dtor(mem as *mut u8, n as uint, || f(mem));
|
||||
}
|
||||
|
||||
fn f(mem: *c_void) {
|
||||
#[fixed_stack_segment]; #[inline(never)];
|
||||
unsafe { libc::free(mem) }
|
||||
return c_vec_with_dtor(mem as *mut u8,
|
||||
n as uint,
|
||||
~LibcFree {
|
||||
mem: mem,
|
||||
} as ~Runnable);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -30,7 +30,7 @@ pub mod rustrt {
|
|||
|
||||
macro_rules! locked {
|
||||
($expr:expr) => {
|
||||
unsafe {
|
||||
{
|
||||
// FIXME #9105: can't use a static mutex in pure Rust yet.
|
||||
rustrt::rust_take_linenoise_lock();
|
||||
let x = $expr;
|
||||
|
@ -43,35 +43,46 @@ macro_rules! locked {
|
|||
/// Add a line to history
|
||||
pub fn add_history(line: &str) -> bool {
|
||||
do line.with_c_str |buf| {
|
||||
unsafe {
|
||||
(locked!(rustrt::linenoiseHistoryAdd(buf))) == 1 as c_int
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Set the maximum amount of lines stored
|
||||
pub fn set_history_max_len(len: int) -> bool {
|
||||
(locked!(rustrt::linenoiseHistorySetMaxLen(len as c_int))) == 1 as c_int
|
||||
unsafe {
|
||||
(locked!(rustrt::linenoiseHistorySetMaxLen(len as c_int))) == 1
|
||||
as c_int
|
||||
}
|
||||
}
|
||||
|
||||
/// Save line history to a file
|
||||
pub fn save_history(file: &str) -> bool {
|
||||
do file.with_c_str |buf| {
|
||||
// 0 on success, -1 on failure
|
||||
unsafe {
|
||||
(locked!(rustrt::linenoiseHistorySave(buf))) == 0 as c_int
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Load line history from a file
|
||||
pub fn load_history(file: &str) -> bool {
|
||||
do file.with_c_str |buf| {
|
||||
// 0 on success, -1 on failure
|
||||
unsafe {
|
||||
(locked!(rustrt::linenoiseHistoryLoad(buf))) == 0 as c_int
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Print out a prompt and then wait for input and return it
|
||||
pub fn read(prompt: &str) -> Option<~str> {
|
||||
do prompt.with_c_str |buf| {
|
||||
let line = locked!(rustrt::linenoise(buf));
|
||||
let line = unsafe {
|
||||
locked!(rustrt::linenoise(buf))
|
||||
};
|
||||
|
||||
if line.is_null() { None }
|
||||
else {
|
||||
|
@ -88,9 +99,13 @@ pub fn read(prompt: &str) -> Option<~str> {
|
|||
}
|
||||
}
|
||||
|
||||
pub type CompletionCb = @fn(~str, @fn(~str));
|
||||
/// The callback used to perform completions.
|
||||
pub trait CompletionCb {
|
||||
/// Performs a completion.
|
||||
fn complete(&self, line: ~str, suggestion: &fn(~str));
|
||||
}
|
||||
|
||||
local_data_key!(complete_key: CompletionCb)
|
||||
local_data_key!(complete_key: @CompletionCb)
|
||||
|
||||
/// Bind to the main completion callback in the current task.
|
||||
///
|
||||
|
@ -98,25 +113,22 @@ local_data_key!(complete_key: CompletionCb)
|
|||
/// other than the closure that it receives as its second
|
||||
/// argument. Calling such a function will deadlock on the mutex used
|
||||
/// to ensure that the calls are thread-safe.
|
||||
pub fn complete(cb: CompletionCb) {
|
||||
pub unsafe fn complete(cb: @CompletionCb) {
|
||||
local_data::set(complete_key, cb);
|
||||
|
||||
extern fn callback(c_line: *c_char, completions: *()) {
|
||||
extern fn callback(line: *c_char, completions: *()) {
|
||||
do local_data::get(complete_key) |opt_cb| {
|
||||
// only fetch completions if a completion handler has been
|
||||
// registered in the current task.
|
||||
match opt_cb {
|
||||
None => {},
|
||||
None => {}
|
||||
Some(cb) => {
|
||||
let line = unsafe { str::raw::from_c_str(c_line) };
|
||||
do (*cb)(line) |suggestion| {
|
||||
do suggestion.with_c_str |buf| {
|
||||
// This isn't locked, because `callback` gets
|
||||
// called inside `rustrt::linenoise`, which
|
||||
// *is* already inside the mutex, so
|
||||
// re-locking would be a deadlock.
|
||||
unsafe {
|
||||
rustrt::linenoiseAddCompletion(completions, buf);
|
||||
do cb.complete(str::raw::from_c_str(line))
|
||||
|suggestion| {
|
||||
do suggestion.with_c_str |buf| {
|
||||
rustrt::linenoiseAddCompletion(completions,
|
||||
buf);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -807,11 +807,6 @@ pub fn filter_tests(
|
|||
}
|
||||
}
|
||||
|
||||
struct TestFuture {
|
||||
test: TestDesc,
|
||||
wait: @fn() -> TestResult,
|
||||
}
|
||||
|
||||
pub fn run_test(force_ignore: bool,
|
||||
test: TestDescAndFn,
|
||||
monitor_ch: SharedChan<MonitorMsg>) {
|
||||
|
|
|
@ -113,8 +113,8 @@ pub fn build_configuration(sess: Session) ->
|
|||
}
|
||||
|
||||
// Convert strings provided as --cfg [cfgspec] into a crate_cfg
|
||||
fn parse_cfgspecs(cfgspecs: ~[~str],
|
||||
demitter: diagnostic::Emitter) -> ast::CrateConfig {
|
||||
fn parse_cfgspecs(cfgspecs: ~[~str], demitter: @diagnostic::Emitter)
|
||||
-> ast::CrateConfig {
|
||||
do cfgspecs.move_iter().map |s| {
|
||||
let sess = parse::new_parse_sess(Some(demitter));
|
||||
parse::parse_meta_from_source_str(@"cfgspec", s.to_managed(), ~[], sess)
|
||||
|
@ -439,16 +439,53 @@ pub fn compile_input(sess: Session, cfg: ast::CrateConfig, input: &input,
|
|||
phase_6_link_output(sess, &trans, outputs);
|
||||
}
|
||||
|
||||
pub fn pretty_print_input(sess: Session, cfg: ast::CrateConfig, input: &input,
|
||||
ppm: PpMode) {
|
||||
struct IdentifiedAnnotation {
|
||||
contents: (),
|
||||
}
|
||||
|
||||
fn ann_paren_for_expr(node: pprust::ann_node) {
|
||||
impl pprust::pp_ann for IdentifiedAnnotation {
|
||||
fn pre(&self, node: pprust::ann_node) {
|
||||
match node {
|
||||
pprust::node_expr(s, _) => pprust::popen(s),
|
||||
_ => ()
|
||||
}
|
||||
}
|
||||
fn ann_typed_post(tcx: ty::ctxt, node: pprust::ann_node) {
|
||||
fn post(&self, node: pprust::ann_node) {
|
||||
match node {
|
||||
pprust::node_item(s, item) => {
|
||||
pp::space(s.s);
|
||||
pprust::synth_comment(s, item.id.to_str());
|
||||
}
|
||||
pprust::node_block(s, ref blk) => {
|
||||
pp::space(s.s);
|
||||
pprust::synth_comment(s, ~"block " + blk.id.to_str());
|
||||
}
|
||||
pprust::node_expr(s, expr) => {
|
||||
pp::space(s.s);
|
||||
pprust::synth_comment(s, expr.id.to_str());
|
||||
pprust::pclose(s);
|
||||
}
|
||||
pprust::node_pat(s, pat) => {
|
||||
pp::space(s.s);
|
||||
pprust::synth_comment(s, ~"pat " + pat.id.to_str());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct TypedAnnotation {
|
||||
analysis: CrateAnalysis,
|
||||
}
|
||||
|
||||
impl pprust::pp_ann for TypedAnnotation {
|
||||
fn pre(&self, node: pprust::ann_node) {
|
||||
match node {
|
||||
pprust::node_expr(s, _) => pprust::popen(s),
|
||||
_ => ()
|
||||
}
|
||||
}
|
||||
fn post(&self, node: pprust::ann_node) {
|
||||
let tcx = self.analysis.ty_cx;
|
||||
match node {
|
||||
pprust::node_expr(s, expr) => {
|
||||
pp::space(s.s);
|
||||
|
@ -460,26 +497,22 @@ pub fn pretty_print_input(sess: Session, cfg: ast::CrateConfig, input: &input,
|
|||
_ => ()
|
||||
}
|
||||
}
|
||||
fn ann_identified_post(node: pprust::ann_node) {
|
||||
}
|
||||
|
||||
pub fn pretty_print_input(sess: Session,
|
||||
cfg: ast::CrateConfig,
|
||||
input: &input,
|
||||
ppm: PpMode) {
|
||||
fn ann_typed_post(tcx: ty::ctxt, node: pprust::ann_node) {
|
||||
match node {
|
||||
pprust::node_item(s, item) => {
|
||||
pp::space(s.s);
|
||||
pprust::synth_comment(s, item.id.to_str());
|
||||
}
|
||||
pprust::node_block(s, ref blk) => {
|
||||
pp::space(s.s);
|
||||
pprust::synth_comment(
|
||||
s, ~"block " + blk.id.to_str());
|
||||
}
|
||||
pprust::node_expr(s, expr) => {
|
||||
pp::space(s.s);
|
||||
pprust::synth_comment(s, expr.id.to_str());
|
||||
pp::word(s.s, "as");
|
||||
pp::space(s.s);
|
||||
pp::word(s.s, ppaux::ty_to_str(tcx, ty::expr_ty(tcx, expr)));
|
||||
pprust::pclose(s);
|
||||
}
|
||||
pprust::node_pat(s, pat) => {
|
||||
pp::space(s.s);
|
||||
pprust::synth_comment(s, ~"pat " + pat.id.to_str());
|
||||
}
|
||||
_ => ()
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -494,28 +527,30 @@ pub fn pretty_print_input(sess: Session, cfg: ast::CrateConfig, input: &input,
|
|||
|
||||
let annotation = match ppm {
|
||||
PpmIdentified | PpmExpandedIdentified => {
|
||||
pprust::pp_ann {
|
||||
pre: ann_paren_for_expr,
|
||||
post: ann_identified_post
|
||||
}
|
||||
@IdentifiedAnnotation {
|
||||
contents: (),
|
||||
} as @pprust::pp_ann
|
||||
}
|
||||
PpmTyped => {
|
||||
let analysis = phase_3_run_analysis_passes(sess, crate);
|
||||
pprust::pp_ann {
|
||||
pre: ann_paren_for_expr,
|
||||
post: |a| ann_typed_post(analysis.ty_cx, a)
|
||||
@TypedAnnotation {
|
||||
analysis: analysis
|
||||
} as @pprust::pp_ann
|
||||
}
|
||||
}
|
||||
_ => pprust::no_ann()
|
||||
_ => @pprust::no_ann::new() as @pprust::pp_ann,
|
||||
};
|
||||
|
||||
let src = sess.codemap.get_filemap(source_name(input)).src;
|
||||
do io::with_str_reader(src) |rdr| {
|
||||
pprust::print_crate(sess.codemap, token::get_ident_interner(),
|
||||
sess.span_diagnostic, crate,
|
||||
pprust::print_crate(sess.codemap,
|
||||
token::get_ident_interner(),
|
||||
sess.span_diagnostic,
|
||||
crate,
|
||||
source_name(input),
|
||||
rdr, io::stdout(),
|
||||
annotation, is_expanded);
|
||||
rdr,
|
||||
io::stdout(),
|
||||
annotation,
|
||||
is_expanded);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -554,7 +589,7 @@ static architecture_abis : &'static [(&'static str, abi::Architecture)] = &'stat
|
|||
("mips", abi::Mips)];
|
||||
|
||||
pub fn build_target_config(sopts: @session::options,
|
||||
demitter: diagnostic::Emitter)
|
||||
demitter: @diagnostic::Emitter)
|
||||
-> @session::config {
|
||||
let os = match get_os(sopts.target_triple) {
|
||||
Some(os) => os,
|
||||
|
@ -603,7 +638,7 @@ pub fn host_triple() -> ~str {
|
|||
|
||||
pub fn build_session_options(binary: @str,
|
||||
matches: &getopts::Matches,
|
||||
demitter: diagnostic::Emitter)
|
||||
demitter: @diagnostic::Emitter)
|
||||
-> @session::options {
|
||||
let crate_type = if matches.opt_present("lib") {
|
||||
session::lib_crate
|
||||
|
@ -777,8 +812,8 @@ pub fn build_session_options(binary: @str,
|
|||
return sopts;
|
||||
}
|
||||
|
||||
pub fn build_session(sopts: @session::options,
|
||||
demitter: diagnostic::Emitter) -> Session {
|
||||
pub fn build_session(sopts: @session::options, demitter: @diagnostic::Emitter)
|
||||
-> Session {
|
||||
let codemap = @codemap::CodeMap::new();
|
||||
let diagnostic_handler =
|
||||
diagnostic::mk_handler(Some(demitter));
|
||||
|
@ -789,7 +824,7 @@ pub fn build_session(sopts: @session::options,
|
|||
|
||||
pub fn build_session_(sopts: @session::options,
|
||||
cm: @codemap::CodeMap,
|
||||
demitter: diagnostic::Emitter,
|
||||
demitter: @diagnostic::Emitter,
|
||||
span_diagnostic_handler: @mut diagnostic::span_handler)
|
||||
-> Session {
|
||||
let target_cfg = build_target_config(sopts, demitter);
|
||||
|
@ -1000,8 +1035,8 @@ pub fn build_output_filenames(input: &input,
|
|||
}
|
||||
}
|
||||
|
||||
pub fn early_error(emitter: diagnostic::Emitter, msg: ~str) -> ! {
|
||||
emitter(None, msg, diagnostic::fatal);
|
||||
pub fn early_error(emitter: @diagnostic::Emitter, msg: ~str) -> ! {
|
||||
emitter.emit(None, msg, diagnostic::fatal);
|
||||
fail!();
|
||||
}
|
||||
|
||||
|
@ -1030,8 +1065,12 @@ mod test {
|
|||
Err(f) => fail!("test_switch_implies_cfg_test: %s", f.to_err_msg())
|
||||
};
|
||||
let sessopts = build_session_options(
|
||||
@"rustc", matches, diagnostic::emit);
|
||||
let sess = build_session(sessopts, diagnostic::emit);
|
||||
@"rustc",
|
||||
matches,
|
||||
@diagnostic::DefaultEmitter as @diagnostic::Emitter);
|
||||
let sess = build_session(sessopts,
|
||||
@diagnostic::DefaultEmitter as
|
||||
@diagnostic::Emitter);
|
||||
let cfg = build_configuration(sess);
|
||||
assert!((attr::contains_name(cfg, "test")));
|
||||
}
|
||||
|
@ -1048,8 +1087,12 @@ mod test {
|
|||
}
|
||||
};
|
||||
let sessopts = build_session_options(
|
||||
@"rustc", matches, diagnostic::emit);
|
||||
let sess = build_session(sessopts, diagnostic::emit);
|
||||
@"rustc",
|
||||
matches,
|
||||
@diagnostic::DefaultEmitter as @diagnostic::Emitter);
|
||||
let sess = build_session(sessopts,
|
||||
@diagnostic::DefaultEmitter as
|
||||
@diagnostic::Emitter);
|
||||
let cfg = build_configuration(sess);
|
||||
let mut test_items = cfg.iter().filter(|m| "test" == m.name());
|
||||
assert!(test_items.next().is_some());
|
||||
|
|
|
@ -11,9 +11,22 @@
|
|||
use driver::session::Session;
|
||||
|
||||
use syntax::ast;
|
||||
use syntax::ast_util;
|
||||
use syntax::fold::ast_fold;
|
||||
|
||||
struct NodeIdAssigner {
|
||||
sess: Session,
|
||||
}
|
||||
|
||||
impl ast_fold for NodeIdAssigner {
|
||||
fn new_id(&self, old_id: ast::NodeId) -> ast::NodeId {
|
||||
assert_eq!(old_id, ast::DUMMY_NODE_ID);
|
||||
self.sess.next_node_id()
|
||||
}
|
||||
}
|
||||
|
||||
pub fn assign_node_ids(sess: Session, crate: @ast::Crate) -> @ast::Crate {
|
||||
let fold = ast_util::node_id_assigner(|| sess.next_node_id());
|
||||
let fold = NodeIdAssigner {
|
||||
sess: sess,
|
||||
};
|
||||
@fold.fold_crate(crate)
|
||||
}
|
||||
|
|
|
@ -9,13 +9,11 @@
|
|||
// except according to those terms.
|
||||
|
||||
|
||||
use std::option;
|
||||
use syntax::fold::ast_fold;
|
||||
use syntax::{ast, fold, attr};
|
||||
|
||||
type in_cfg_pred = @fn(attrs: &[ast::Attribute]) -> bool;
|
||||
|
||||
struct Context {
|
||||
in_cfg: in_cfg_pred
|
||||
struct Context<'self> {
|
||||
in_cfg: &'self fn(attrs: &[ast::Attribute]) -> bool,
|
||||
}
|
||||
|
||||
// Support conditional compilation by transforming the AST, stripping out
|
||||
|
@ -26,43 +24,55 @@ pub fn strip_unconfigured_items(crate: @ast::Crate) -> @ast::Crate {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn strip_items(crate: &ast::Crate, in_cfg: in_cfg_pred)
|
||||
-> @ast::Crate {
|
||||
|
||||
let ctxt = @Context { in_cfg: in_cfg };
|
||||
|
||||
let precursor = @fold::AstFoldFns {
|
||||
fold_mod: |a,b| fold_mod(ctxt, a, b),
|
||||
fold_block: |a,b| fold_block(ctxt, a, b),
|
||||
fold_foreign_mod: |a,b| fold_foreign_mod(ctxt, a, b),
|
||||
fold_item_underscore: |a,b| fold_item_underscore(ctxt, a, b),
|
||||
.. *fold::default_ast_fold()
|
||||
};
|
||||
|
||||
let fold = fold::make_fold(precursor);
|
||||
@fold.fold_crate(crate)
|
||||
}
|
||||
|
||||
fn filter_item(cx: @Context, item: @ast::item) ->
|
||||
Option<@ast::item> {
|
||||
if item_in_cfg(cx, item) { option::Some(item) } else { option::None }
|
||||
}
|
||||
|
||||
fn filter_view_item<'r>(cx: @Context, view_item: &'r ast::view_item)-> Option<&'r ast::view_item> {
|
||||
if view_item_in_cfg(cx, view_item) {
|
||||
option::Some(view_item)
|
||||
} else {
|
||||
option::None
|
||||
impl<'self> fold::ast_fold for Context<'self> {
|
||||
fn fold_mod(&self, module: &ast::_mod) -> ast::_mod {
|
||||
fold_mod(self, module)
|
||||
}
|
||||
fn fold_block(&self, block: &ast::Block) -> ast::Block {
|
||||
fold_block(self, block)
|
||||
}
|
||||
fn fold_foreign_mod(&self, foreign_module: &ast::foreign_mod)
|
||||
-> ast::foreign_mod {
|
||||
fold_foreign_mod(self, foreign_module)
|
||||
}
|
||||
fn fold_item_underscore(&self, item: &ast::item_) -> ast::item_ {
|
||||
fold_item_underscore(self, item)
|
||||
}
|
||||
}
|
||||
|
||||
fn fold_mod(cx: @Context, m: &ast::_mod, fld: @fold::ast_fold) -> ast::_mod {
|
||||
pub fn strip_items(crate: &ast::Crate,
|
||||
in_cfg: &fn(attrs: &[ast::Attribute]) -> bool)
|
||||
-> @ast::Crate {
|
||||
let ctxt = Context {
|
||||
in_cfg: in_cfg,
|
||||
};
|
||||
@ctxt.fold_crate(crate)
|
||||
}
|
||||
|
||||
fn filter_item(cx: &Context, item: @ast::item) -> Option<@ast::item> {
|
||||
if item_in_cfg(cx, item) {
|
||||
Some(item)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
fn filter_view_item<'r>(cx: &Context, view_item: &'r ast::view_item)
|
||||
-> Option<&'r ast::view_item> {
|
||||
if view_item_in_cfg(cx, view_item) {
|
||||
Some(view_item)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
fn fold_mod(cx: &Context, m: &ast::_mod) -> ast::_mod {
|
||||
let filtered_items = do m.items.iter().filter_map |a| {
|
||||
filter_item(cx, *a).and_then(|x| fld.fold_item(x))
|
||||
filter_item(cx, *a).and_then(|x| cx.fold_item(x))
|
||||
}.collect();
|
||||
let filtered_view_items = do m.view_items.iter().filter_map |a| {
|
||||
do filter_view_item(cx, a).map_move |x| {
|
||||
fld.fold_view_item(x)
|
||||
cx.fold_view_item(x)
|
||||
}
|
||||
}.collect();
|
||||
ast::_mod {
|
||||
|
@ -71,22 +81,23 @@ fn fold_mod(cx: @Context, m: &ast::_mod, fld: @fold::ast_fold) -> ast::_mod {
|
|||
}
|
||||
}
|
||||
|
||||
fn filter_foreign_item(cx: @Context, item: @ast::foreign_item) ->
|
||||
Option<@ast::foreign_item> {
|
||||
fn filter_foreign_item(cx: &Context, item: @ast::foreign_item)
|
||||
-> Option<@ast::foreign_item> {
|
||||
if foreign_item_in_cfg(cx, item) {
|
||||
option::Some(item)
|
||||
} else { option::None }
|
||||
Some(item)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
fn fold_foreign_mod(
|
||||
cx: @Context,
|
||||
nm: &ast::foreign_mod,
|
||||
fld: @fold::ast_fold
|
||||
) -> ast::foreign_mod {
|
||||
let filtered_items = nm.items.iter().filter_map(|a| filter_foreign_item(cx, *a)).collect();
|
||||
fn fold_foreign_mod(cx: &Context, nm: &ast::foreign_mod) -> ast::foreign_mod {
|
||||
let filtered_items = nm.items
|
||||
.iter()
|
||||
.filter_map(|a| filter_foreign_item(cx, *a))
|
||||
.collect();
|
||||
let filtered_view_items = do nm.view_items.iter().filter_map |a| {
|
||||
do filter_view_item(cx, a).map_move |x| {
|
||||
fld.fold_view_item(x)
|
||||
cx.fold_view_item(x)
|
||||
}
|
||||
}.collect();
|
||||
ast::foreign_mod {
|
||||
|
@ -97,8 +108,7 @@ fn fold_foreign_mod(
|
|||
}
|
||||
}
|
||||
|
||||
fn fold_item_underscore(cx: @Context, item: &ast::item_,
|
||||
fld: @fold::ast_fold) -> ast::item_ {
|
||||
fn fold_item_underscore(cx: &Context, item: &ast::item_) -> ast::item_ {
|
||||
let item = match *item {
|
||||
ast::item_impl(ref a, ref b, ref c, ref methods) => {
|
||||
let methods = methods.iter().filter(|m| method_in_cfg(cx, **m))
|
||||
|
@ -106,71 +116,70 @@ fn fold_item_underscore(cx: @Context, item: &ast::item_,
|
|||
ast::item_impl((*a).clone(), (*b).clone(), (*c).clone(), methods)
|
||||
}
|
||||
ast::item_trait(ref a, ref b, ref methods) => {
|
||||
let methods = methods.iter().filter(|m| trait_method_in_cfg(cx, *m) )
|
||||
.map(|x| (*x).clone()).collect();
|
||||
let methods = methods.iter()
|
||||
.filter(|m| trait_method_in_cfg(cx, *m) )
|
||||
.map(|x| (*x).clone())
|
||||
.collect();
|
||||
ast::item_trait((*a).clone(), (*b).clone(), methods)
|
||||
}
|
||||
ref item => (*item).clone(),
|
||||
};
|
||||
|
||||
fold::noop_fold_item_underscore(&item, fld)
|
||||
fold::noop_fold_item_underscore(&item, cx)
|
||||
}
|
||||
|
||||
fn filter_stmt(cx: @Context, stmt: @ast::Stmt) ->
|
||||
Option<@ast::Stmt> {
|
||||
fn filter_stmt(cx: &Context, stmt: @ast::Stmt) -> Option<@ast::Stmt> {
|
||||
match stmt.node {
|
||||
ast::StmtDecl(decl, _) => {
|
||||
match decl.node {
|
||||
ast::DeclItem(item) => {
|
||||
if item_in_cfg(cx, item) {
|
||||
option::Some(stmt)
|
||||
} else { option::None }
|
||||
}
|
||||
_ => option::Some(stmt)
|
||||
Some(stmt)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
_ => option::Some(stmt)
|
||||
_ => Some(stmt)
|
||||
}
|
||||
}
|
||||
_ => Some(stmt),
|
||||
}
|
||||
}
|
||||
|
||||
fn fold_block(
|
||||
cx: @Context,
|
||||
b: &ast::Block,
|
||||
fld: @fold::ast_fold
|
||||
) -> ast::Block {
|
||||
fn fold_block(cx: &Context, b: &ast::Block) -> ast::Block {
|
||||
let resulting_stmts = do b.stmts.iter().filter_map |a| {
|
||||
filter_stmt(cx, *a).and_then(|stmt| fld.fold_stmt(stmt))
|
||||
filter_stmt(cx, *a).and_then(|stmt| cx.fold_stmt(stmt))
|
||||
}.collect();
|
||||
let filtered_view_items = do b.view_items.iter().filter_map |a| {
|
||||
filter_view_item(cx, a).map(|x| fld.fold_view_item(*x))
|
||||
filter_view_item(cx, a).map(|x| cx.fold_view_item(*x))
|
||||
}.collect();
|
||||
ast::Block {
|
||||
view_items: filtered_view_items,
|
||||
stmts: resulting_stmts,
|
||||
expr: b.expr.map(|x| fld.fold_expr(*x)),
|
||||
expr: b.expr.map(|x| cx.fold_expr(*x)),
|
||||
id: b.id,
|
||||
rules: b.rules,
|
||||
span: b.span,
|
||||
}
|
||||
}
|
||||
|
||||
fn item_in_cfg(cx: @Context, item: @ast::item) -> bool {
|
||||
fn item_in_cfg(cx: &Context, item: @ast::item) -> bool {
|
||||
return (cx.in_cfg)(item.attrs);
|
||||
}
|
||||
|
||||
fn foreign_item_in_cfg(cx: @Context, item: @ast::foreign_item) -> bool {
|
||||
fn foreign_item_in_cfg(cx: &Context, item: @ast::foreign_item) -> bool {
|
||||
return (cx.in_cfg)(item.attrs);
|
||||
}
|
||||
|
||||
fn view_item_in_cfg(cx: @Context, item: &ast::view_item) -> bool {
|
||||
fn view_item_in_cfg(cx: &Context, item: &ast::view_item) -> bool {
|
||||
return (cx.in_cfg)(item.attrs);
|
||||
}
|
||||
|
||||
fn method_in_cfg(cx: @Context, meth: @ast::method) -> bool {
|
||||
fn method_in_cfg(cx: &Context, meth: @ast::method) -> bool {
|
||||
return (cx.in_cfg)(meth.attrs);
|
||||
}
|
||||
|
||||
fn trait_method_in_cfg(cx: @Context, meth: &ast::trait_method) -> bool {
|
||||
fn trait_method_in_cfg(cx: &Context, meth: &ast::trait_method) -> bool {
|
||||
match *meth {
|
||||
ast::required(ref meth) => (cx.in_cfg)(meth.attrs),
|
||||
ast::provided(@ref meth) => (cx.in_cfg)(meth.attrs)
|
||||
|
@ -182,3 +191,4 @@ fn trait_method_in_cfg(cx: @Context, meth: &ast::trait_method) -> bool {
|
|||
fn in_cfg(cfg: &[@ast::MetaItem], attrs: &[ast::Attribute]) -> bool {
|
||||
attr::test_cfg(cfg, attrs.iter().map(|x| *x))
|
||||
}
|
||||
|
||||
|
|
|
@ -16,6 +16,7 @@ use syntax::ast;
|
|||
use syntax::attr;
|
||||
use syntax::codemap::dummy_sp;
|
||||
use syntax::codemap;
|
||||
use syntax::fold::ast_fold;
|
||||
use syntax::fold;
|
||||
use syntax::opt_vec;
|
||||
|
||||
|
@ -38,20 +39,27 @@ fn no_prelude(attrs: &[ast::Attribute]) -> bool {
|
|||
attr::contains_name(attrs, "no_implicit_prelude")
|
||||
}
|
||||
|
||||
fn inject_libstd_ref(sess: Session, crate: &ast::Crate) -> @ast::Crate {
|
||||
fn spanned<T>(x: T) -> codemap::Spanned<T> {
|
||||
codemap::Spanned { node: x, span: dummy_sp() }
|
||||
fn spanned<T>(x: T) -> codemap::Spanned<T> {
|
||||
codemap::Spanned {
|
||||
node: x,
|
||||
span: dummy_sp(),
|
||||
}
|
||||
}
|
||||
|
||||
let precursor = @fold::AstFoldFns {
|
||||
fold_crate: |crate, fld| {
|
||||
let n1 = ast::DUMMY_NODE_ID;
|
||||
struct StandardLibraryInjector {
|
||||
sess: Session,
|
||||
}
|
||||
|
||||
impl fold::ast_fold for StandardLibraryInjector {
|
||||
fn fold_crate(&self, crate: &ast::Crate) -> ast::Crate {
|
||||
let version = STD_VERSION.to_managed();
|
||||
let vi1 = ast::view_item {
|
||||
node: ast::view_item_extern_mod(
|
||||
sess.ident_of("std"), None, ~[], n1),
|
||||
node: ast::view_item_extern_mod(self.sess.ident_of("std"),
|
||||
None,
|
||||
~[],
|
||||
ast::DUMMY_NODE_ID),
|
||||
attrs: ~[
|
||||
attr::mk_attr(
|
||||
attr::mk_name_value_item_str(@"vers", STD_VERSION.to_managed()))
|
||||
attr::mk_attr(attr::mk_name_value_item_str(@"vers", version))
|
||||
],
|
||||
vis: ast::private,
|
||||
span: dummy_sp()
|
||||
|
@ -66,7 +74,7 @@ fn inject_libstd_ref(sess: Session, crate: &ast::Crate) -> @ast::Crate {
|
|||
if !no_prelude(crate.attrs) {
|
||||
// only add `use std::prelude::*;` if there wasn't a
|
||||
// `#[no_implicit_prelude];` at the crate level.
|
||||
new_module = fld.fold_mod(&new_module);
|
||||
new_module = self.fold_mod(&new_module);
|
||||
}
|
||||
|
||||
// FIXME #2543: Bad copy.
|
||||
|
@ -74,42 +82,45 @@ fn inject_libstd_ref(sess: Session, crate: &ast::Crate) -> @ast::Crate {
|
|||
module: new_module,
|
||||
..(*crate).clone()
|
||||
}
|
||||
},
|
||||
fold_item: |item, fld| {
|
||||
}
|
||||
|
||||
fn fold_item(&self, item: @ast::item) -> Option<@ast::item> {
|
||||
if !no_prelude(item.attrs) {
|
||||
// only recur if there wasn't `#[no_implicit_prelude];`
|
||||
// on this item, i.e. this means that the prelude is not
|
||||
// implicitly imported though the whole subtree
|
||||
fold::noop_fold_item(item, fld)
|
||||
fold::noop_fold_item(item, self)
|
||||
} else {
|
||||
Some(item)
|
||||
}
|
||||
},
|
||||
fold_mod: |module, fld| {
|
||||
let n2 = ast::DUMMY_NODE_ID;
|
||||
}
|
||||
|
||||
fn fold_mod(&self, module: &ast::_mod) -> ast::_mod {
|
||||
let prelude_path = ast::Path {
|
||||
span: dummy_sp(),
|
||||
global: false,
|
||||
segments: ~[
|
||||
ast::PathSegment {
|
||||
identifier: sess.ident_of("std"),
|
||||
identifier: self.sess.ident_of("std"),
|
||||
lifetime: None,
|
||||
types: opt_vec::Empty,
|
||||
},
|
||||
ast::PathSegment {
|
||||
identifier: sess.ident_of("prelude"),
|
||||
identifier: self.sess.ident_of("prelude"),
|
||||
lifetime: None,
|
||||
types: opt_vec::Empty,
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
let vp = @spanned(ast::view_path_glob(prelude_path, n2));
|
||||
let vi2 = ast::view_item { node: ast::view_item_use(~[vp]),
|
||||
let vp = @spanned(ast::view_path_glob(prelude_path,
|
||||
ast::DUMMY_NODE_ID));
|
||||
let vi2 = ast::view_item {
|
||||
node: ast::view_item_use(~[vp]),
|
||||
attrs: ~[],
|
||||
vis: ast::private,
|
||||
span: dummy_sp() };
|
||||
span: dummy_sp(),
|
||||
};
|
||||
|
||||
let vis = vec::append(~[vi2], module.view_items);
|
||||
|
||||
|
@ -118,11 +129,13 @@ fn inject_libstd_ref(sess: Session, crate: &ast::Crate) -> @ast::Crate {
|
|||
view_items: vis,
|
||||
..(*module).clone()
|
||||
};
|
||||
fold::noop_fold_mod(&new_module, fld)
|
||||
},
|
||||
..*fold::default_ast_fold()
|
||||
};
|
||||
fold::noop_fold_mod(&new_module, self)
|
||||
}
|
||||
}
|
||||
|
||||
let fold = fold::make_fold(precursor);
|
||||
fn inject_libstd_ref(sess: Session, crate: &ast::Crate) -> @ast::Crate {
|
||||
let fold = StandardLibraryInjector {
|
||||
sess: sess,
|
||||
};
|
||||
@fold.fold_crate(crate)
|
||||
}
|
||||
|
|
|
@ -21,13 +21,12 @@ use syntax::attr;
|
|||
use syntax::codemap::{dummy_sp, Span, ExpnInfo, NameAndSpan};
|
||||
use syntax::codemap;
|
||||
use syntax::ext::base::ExtCtxt;
|
||||
use syntax::fold::ast_fold;
|
||||
use syntax::fold;
|
||||
use syntax::opt_vec;
|
||||
use syntax::print::pprust;
|
||||
use syntax::{ast, ast_util};
|
||||
|
||||
type node_id_gen = @fn() -> ast::NodeId;
|
||||
|
||||
struct Test {
|
||||
span: Span,
|
||||
path: ~[ast::Ident],
|
||||
|
@ -61,50 +60,58 @@ pub fn modify_for_testing(sess: session::Session,
|
|||
}
|
||||
}
|
||||
|
||||
fn generate_test_harness(sess: session::Session,
|
||||
crate: @ast::Crate)
|
||||
-> @ast::Crate {
|
||||
let cx: @mut TestCtxt = @mut TestCtxt {
|
||||
sess: sess,
|
||||
crate: crate,
|
||||
ext_cx: ExtCtxt::new(sess.parse_sess, sess.opts.cfg.clone()),
|
||||
path: ~[],
|
||||
testfns: ~[]
|
||||
struct TestHarnessGenerator {
|
||||
cx: @mut TestCtxt,
|
||||
}
|
||||
|
||||
impl fold::ast_fold for TestHarnessGenerator {
|
||||
fn fold_crate(&self, c: &ast::Crate) -> ast::Crate {
|
||||
let folded = fold::noop_fold_crate(c, self);
|
||||
|
||||
// Add a special __test module to the crate that will contain code
|
||||
// generated for the test harness
|
||||
ast::Crate {
|
||||
module: add_test_module(self.cx, &folded.module),
|
||||
.. folded
|
||||
}
|
||||
}
|
||||
|
||||
fn fold_item(&self, i: @ast::item) -> Option<@ast::item> {
|
||||
self.cx.path.push(i.ident);
|
||||
debug!("current path: %s",
|
||||
ast_util::path_name_i(self.cx.path.clone()));
|
||||
|
||||
if is_test_fn(self.cx, i) || is_bench_fn(i) {
|
||||
match i.node {
|
||||
ast::item_fn(_, purity, _, _, _)
|
||||
if purity == ast::unsafe_fn => {
|
||||
let sess = self.cx.sess;
|
||||
sess.span_fatal(i.span,
|
||||
"unsafe functions cannot be used for \
|
||||
tests");
|
||||
}
|
||||
_ => {
|
||||
debug!("this is a test function");
|
||||
let test = Test {
|
||||
span: i.span,
|
||||
path: self.cx.path.clone(),
|
||||
bench: is_bench_fn(i),
|
||||
ignore: is_ignored(self.cx, i),
|
||||
should_fail: should_fail(i)
|
||||
};
|
||||
|
||||
let ext_cx = cx.ext_cx;
|
||||
ext_cx.bt_push(ExpnInfo {
|
||||
call_site: dummy_sp(),
|
||||
callee: NameAndSpan {
|
||||
name: @"test",
|
||||
span: None
|
||||
self.cx.testfns.push(test);
|
||||
// debug!("have %u test/bench functions",
|
||||
// cx.testfns.len());
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
let precursor = @fold::AstFoldFns {
|
||||
fold_crate: |a,b| fold_crate(cx, a, b),
|
||||
fold_item: |a,b| fold_item(cx, a, b),
|
||||
fold_mod: |a,b| fold_mod(cx, a, b),.. *fold::default_ast_fold()};
|
||||
|
||||
let fold = fold::make_fold(precursor);
|
||||
let res = @fold.fold_crate(&*crate);
|
||||
ext_cx.bt_pop();
|
||||
let res = fold::noop_fold_item(i, self);
|
||||
self.cx.path.pop();
|
||||
return res;
|
||||
}
|
||||
|
||||
fn strip_test_functions(crate: &ast::Crate) -> @ast::Crate {
|
||||
// When not compiling with --test we should not compile the
|
||||
// #[test] functions
|
||||
do config::strip_items(crate) |attrs| {
|
||||
!attr::contains_name(attrs, "test") &&
|
||||
!attr::contains_name(attrs, "bench")
|
||||
}
|
||||
}
|
||||
|
||||
fn fold_mod(cx: @mut TestCtxt,
|
||||
m: &ast::_mod,
|
||||
fld: @fold::ast_fold)
|
||||
-> ast::_mod {
|
||||
fn fold_mod(&self, m: &ast::_mod) -> ast::_mod {
|
||||
// Remove any #[main] from the AST so it doesn't clash with
|
||||
// the one we're going to add. Only if compiling an executable.
|
||||
|
||||
|
@ -127,59 +134,49 @@ fn fold_mod(cx: @mut TestCtxt,
|
|||
|
||||
let mod_nomain = ast::_mod {
|
||||
view_items: m.view_items.clone(),
|
||||
items: m.items.iter().map(|i| nomain(cx, *i)).collect(),
|
||||
items: m.items.iter().map(|i| nomain(self.cx, *i)).collect(),
|
||||
};
|
||||
|
||||
fold::noop_fold_mod(&mod_nomain, fld)
|
||||
}
|
||||
|
||||
fn fold_crate(cx: @mut TestCtxt, c: &ast::Crate, fld: @fold::ast_fold)
|
||||
-> ast::Crate {
|
||||
let folded = fold::noop_fold_crate(c, fld);
|
||||
|
||||
// Add a special __test module to the crate that will contain code
|
||||
// generated for the test harness
|
||||
ast::Crate {
|
||||
module: add_test_module(cx, &folded.module),
|
||||
.. folded
|
||||
fold::noop_fold_mod(&mod_nomain, self)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
fn fold_item(cx: @mut TestCtxt, i: @ast::item, fld: @fold::ast_fold)
|
||||
-> Option<@ast::item> {
|
||||
cx.path.push(i.ident);
|
||||
debug!("current path: %s",
|
||||
ast_util::path_name_i(cx.path.clone()));
|
||||
|
||||
if is_test_fn(cx, i) || is_bench_fn(i) {
|
||||
match i.node {
|
||||
ast::item_fn(_, purity, _, _, _) if purity == ast::unsafe_fn => {
|
||||
let sess = cx.sess;
|
||||
sess.span_fatal(
|
||||
i.span,
|
||||
"unsafe functions cannot be used for tests");
|
||||
}
|
||||
_ => {
|
||||
debug!("this is a test function");
|
||||
let test = Test {
|
||||
span: i.span,
|
||||
path: cx.path.clone(),
|
||||
bench: is_bench_fn(i),
|
||||
ignore: is_ignored(cx, i),
|
||||
should_fail: should_fail(i)
|
||||
fn generate_test_harness(sess: session::Session, crate: @ast::Crate)
|
||||
-> @ast::Crate {
|
||||
let cx: @mut TestCtxt = @mut TestCtxt {
|
||||
sess: sess,
|
||||
crate: crate,
|
||||
ext_cx: ExtCtxt::new(sess.parse_sess, sess.opts.cfg.clone()),
|
||||
path: ~[],
|
||||
testfns: ~[]
|
||||
};
|
||||
cx.testfns.push(test);
|
||||
// debug!("have %u test/bench functions", cx.testfns.len());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let res = fold::noop_fold_item(i, fld);
|
||||
cx.path.pop();
|
||||
let ext_cx = cx.ext_cx;
|
||||
ext_cx.bt_push(ExpnInfo {
|
||||
call_site: dummy_sp(),
|
||||
callee: NameAndSpan {
|
||||
name: @"test",
|
||||
span: None
|
||||
}
|
||||
});
|
||||
|
||||
let fold = TestHarnessGenerator {
|
||||
cx: cx
|
||||
};
|
||||
let res = @fold.fold_crate(&*crate);
|
||||
ext_cx.bt_pop();
|
||||
return res;
|
||||
}
|
||||
|
||||
fn strip_test_functions(crate: &ast::Crate) -> @ast::Crate {
|
||||
// When not compiling with --test we should not compile the
|
||||
// #[test] functions
|
||||
do config::strip_items(crate) |attrs| {
|
||||
!attr::contains_name(attrs, "test") &&
|
||||
!attr::contains_name(attrs, "bench")
|
||||
}
|
||||
}
|
||||
|
||||
fn is_test_fn(cx: @mut TestCtxt, i: @ast::item) -> bool {
|
||||
let has_test_attr = attr::contains_name(i.attrs, "test");
|
||||
|
||||
|
|
|
@ -95,8 +95,7 @@ pub fn parse_ident(st: &mut PState, last: char) -> ast::Ident {
|
|||
return parse_ident_(st, |a| is_last(last, a) );
|
||||
}
|
||||
|
||||
fn parse_ident_(st: &mut PState, is_last: @fn(char) -> bool) ->
|
||||
ast::Ident {
|
||||
fn parse_ident_(st: &mut PState, is_last: &fn(char) -> bool) -> ast::Ident {
|
||||
let rslt = scan(st, is_last, str::from_utf8);
|
||||
return st.tcx.sess.ident_of(rslt);
|
||||
}
|
||||
|
|
|
@ -26,7 +26,7 @@ use syntax::print::pprust::*;
|
|||
pub struct ctxt {
|
||||
diag: @mut span_handler,
|
||||
// Def -> str Callback:
|
||||
ds: @fn(DefId) -> ~str,
|
||||
ds: extern "Rust" fn(DefId) -> ~str,
|
||||
// The type context.
|
||||
tcx: ty::ctxt,
|
||||
abbrevs: abbrev_ctxt
|
||||
|
|
|
@ -24,6 +24,7 @@ use middle;
|
|||
use util::ppaux::ty_to_str;
|
||||
|
||||
use std::at_vec;
|
||||
use std::libc;
|
||||
use extra::ebml::reader;
|
||||
use extra::ebml;
|
||||
use extra::serialize;
|
||||
|
@ -287,25 +288,23 @@ fn encode_ast(ebml_w: &mut writer::Encoder, item: ast::inlined_item) {
|
|||
ebml_w.end_tag();
|
||||
}
|
||||
|
||||
// Produces a simplified copy of the AST which does not include things
|
||||
// that we do not need to or do not want to export. For example, we
|
||||
// do not include any nested items: if these nested items are to be
|
||||
// inlined, their AST will be exported separately (this only makes
|
||||
// sense because, in Rust, nested items are independent except for
|
||||
// their visibility).
|
||||
//
|
||||
// As it happens, trans relies on the fact that we do not export
|
||||
// nested items, as otherwise it would get confused when translating
|
||||
// inlined items.
|
||||
fn simplify_ast(ii: &ast::inlined_item) -> ast::inlined_item {
|
||||
fn drop_nested_items(blk: &ast::Block, fld: @fold::ast_fold) -> ast::Block {
|
||||
struct NestedItemsDropper {
|
||||
contents: (),
|
||||
}
|
||||
|
||||
impl fold::ast_fold for NestedItemsDropper {
|
||||
fn fold_block(&self, blk: &ast::Block) -> ast::Block {
|
||||
let stmts_sans_items = do blk.stmts.iter().filter_map |stmt| {
|
||||
match stmt.node {
|
||||
ast::StmtExpr(_, _) | ast::StmtSemi(_, _) |
|
||||
ast::StmtDecl(@codemap::Spanned { node: ast::DeclLocal(_), span: _}, _)
|
||||
=> Some(*stmt),
|
||||
ast::StmtDecl(@codemap::Spanned { node: ast::DeclItem(_), span: _}, _)
|
||||
=> None,
|
||||
ast::StmtDecl(@codemap::Spanned {
|
||||
node: ast::DeclLocal(_),
|
||||
span: _
|
||||
}, _) => Some(*stmt),
|
||||
ast::StmtDecl(@codemap::Spanned {
|
||||
node: ast::DeclItem(_),
|
||||
span: _
|
||||
}, _) => None,
|
||||
ast::StmtMac(*) => fail!("unexpanded macro in astencode")
|
||||
}
|
||||
}.collect();
|
||||
|
@ -318,13 +317,24 @@ fn simplify_ast(ii: &ast::inlined_item) -> ast::inlined_item {
|
|||
rules: blk.rules,
|
||||
span: blk.span,
|
||||
};
|
||||
fold::noop_fold_block(&blk_sans_items, fld)
|
||||
fold::noop_fold_block(&blk_sans_items, self)
|
||||
}
|
||||
}
|
||||
|
||||
let fld = fold::make_fold(@fold::AstFoldFns {
|
||||
fold_block: drop_nested_items,
|
||||
.. *fold::default_ast_fold()
|
||||
});
|
||||
// Produces a simplified copy of the AST which does not include things
|
||||
// that we do not need to or do not want to export. For example, we
|
||||
// do not include any nested items: if these nested items are to be
|
||||
// inlined, their AST will be exported separately (this only makes
|
||||
// sense because, in Rust, nested items are independent except for
|
||||
// their visibility).
|
||||
//
|
||||
// As it happens, trans relies on the fact that we do not export
|
||||
// nested items, as otherwise it would get confused when translating
|
||||
// inlined items.
|
||||
fn simplify_ast(ii: &ast::inlined_item) -> ast::inlined_item {
|
||||
let fld = NestedItemsDropper {
|
||||
contents: (),
|
||||
};
|
||||
|
||||
match *ii {
|
||||
//hack: we're not dropping items
|
||||
|
@ -341,14 +351,24 @@ fn decode_ast(par_doc: ebml::Doc) -> ast::inlined_item {
|
|||
Decodable::decode(&mut d)
|
||||
}
|
||||
|
||||
struct AstRenumberer {
|
||||
xcx: @ExtendedDecodeContext,
|
||||
}
|
||||
|
||||
impl fold::ast_fold for AstRenumberer {
|
||||
fn new_id(&self, id: ast::NodeId) -> ast::NodeId {
|
||||
self.xcx.tr_id(id)
|
||||
}
|
||||
fn new_span(&self, span: Span) -> Span {
|
||||
self.xcx.tr_span(span)
|
||||
}
|
||||
}
|
||||
|
||||
fn renumber_ast(xcx: @ExtendedDecodeContext, ii: ast::inlined_item)
|
||||
-> ast::inlined_item {
|
||||
let fld = fold::make_fold(@fold::AstFoldFns{
|
||||
new_id: |a| xcx.tr_id(a),
|
||||
new_span: |a| xcx.tr_span(a),
|
||||
.. *fold::default_ast_fold()
|
||||
});
|
||||
|
||||
let fld = AstRenumberer {
|
||||
xcx: xcx,
|
||||
};
|
||||
match ii {
|
||||
ast::ii_item(i) => ast::ii_item(fld.fold_item(i).unwrap()),
|
||||
ast::ii_method(d, is_provided, m) =>
|
||||
|
@ -830,6 +850,26 @@ impl write_tag_and_id for writer::Encoder {
|
|||
}
|
||||
}
|
||||
|
||||
struct SideTableEncodingIdVisitor {
|
||||
ecx_ptr: *libc::c_void,
|
||||
new_ebml_w: writer::Encoder,
|
||||
maps: Maps,
|
||||
}
|
||||
|
||||
impl ast_util::IdVisitingOperation for SideTableEncodingIdVisitor {
|
||||
fn visit_id(&self, id: ast::NodeId) {
|
||||
// Note: this will cause a copy of ebml_w, which is bad as
|
||||
// it is mutable. But I believe it's harmless since we generate
|
||||
// balanced EBML.
|
||||
let mut new_ebml_w = self.new_ebml_w.clone();
|
||||
// See above
|
||||
let ecx: &e::EncodeContext = unsafe {
|
||||
cast::transmute(self.ecx_ptr)
|
||||
};
|
||||
encode_side_tables_for_id(ecx, self.maps, &mut new_ebml_w, id)
|
||||
}
|
||||
}
|
||||
|
||||
fn encode_side_tables_for_ii(ecx: &e::EncodeContext,
|
||||
maps: Maps,
|
||||
ebml_w: &mut writer::Encoder,
|
||||
|
@ -837,22 +877,16 @@ fn encode_side_tables_for_ii(ecx: &e::EncodeContext,
|
|||
ebml_w.start_tag(c::tag_table as uint);
|
||||
let new_ebml_w = (*ebml_w).clone();
|
||||
|
||||
// Because the ast visitor uses @fn, I can't pass in
|
||||
// ecx directly, but /I/ know that it'll be fine since
|
||||
// the lifetime is tied to the CrateContext that
|
||||
// lives this entire section.
|
||||
let ecx_ptr : *() = unsafe { cast::transmute(ecx) };
|
||||
ast_util::visit_ids_for_inlined_item(
|
||||
ii,
|
||||
|id: ast::NodeId| {
|
||||
// Note: this will cause a copy of ebml_w, which is bad as
|
||||
// it is mutable. But I believe it's harmless since we generate
|
||||
// balanced EBML.
|
||||
let mut new_ebml_w = new_ebml_w.clone();
|
||||
// See above
|
||||
let ecx : &e::EncodeContext = unsafe { cast::transmute(ecx_ptr) };
|
||||
encode_side_tables_for_id(ecx, maps, &mut new_ebml_w, id)
|
||||
});
|
||||
// Because the ast visitor uses @IdVisitingOperation, I can't pass in
|
||||
// ecx directly, but /I/ know that it'll be fine since the lifetime is
|
||||
// tied to the CrateContext that lives throughout this entire section.
|
||||
ast_util::visit_ids_for_inlined_item(ii, @SideTableEncodingIdVisitor {
|
||||
ecx_ptr: unsafe {
|
||||
cast::transmute(ecx)
|
||||
},
|
||||
new_ebml_w: new_ebml_w,
|
||||
maps: maps,
|
||||
} as @ast_util::IdVisitingOperation);
|
||||
ebml_w.end_tag();
|
||||
}
|
||||
|
||||
|
|
|
@ -87,6 +87,42 @@ struct LoopScope<'self> {
|
|||
break_bits: ~[uint]
|
||||
}
|
||||
|
||||
impl<O:DataFlowOperator> pprust::pp_ann for DataFlowContext<O> {
|
||||
fn pre(&self, node: pprust::ann_node) {
|
||||
let (ps, id) = match node {
|
||||
pprust::node_expr(ps, expr) => (ps, expr.id),
|
||||
pprust::node_block(ps, blk) => (ps, blk.id),
|
||||
pprust::node_item(ps, _) => (ps, 0),
|
||||
pprust::node_pat(ps, pat) => (ps, pat.id)
|
||||
};
|
||||
|
||||
if self.nodeid_to_bitset.contains_key(&id) {
|
||||
let (start, end) = self.compute_id_range_frozen(id);
|
||||
let on_entry = self.on_entry.slice(start, end);
|
||||
let entry_str = bits_to_str(on_entry);
|
||||
|
||||
let gens = self.gens.slice(start, end);
|
||||
let gens_str = if gens.iter().any(|&u| u != 0) {
|
||||
fmt!(" gen: %s", bits_to_str(gens))
|
||||
} else {
|
||||
~""
|
||||
};
|
||||
|
||||
let kills = self.kills.slice(start, end);
|
||||
let kills_str = if kills.iter().any(|&u| u != 0) {
|
||||
fmt!(" kill: %s", bits_to_str(kills))
|
||||
} else {
|
||||
~""
|
||||
};
|
||||
|
||||
let comment_str = fmt!("id %d: %s%s%s",
|
||||
id, entry_str, gens_str, kills_str);
|
||||
pprust::synth_comment(ps, comment_str);
|
||||
pp::space(ps.s);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<O:DataFlowOperator> DataFlowContext<O> {
|
||||
pub fn new(tcx: ty::ctxt,
|
||||
method_map: typeck::method_map,
|
||||
|
@ -319,46 +355,9 @@ impl<O:DataFlowOperator+Clone+'static> DataFlowContext<O> {
|
|||
}
|
||||
|
||||
fn pretty_print_to(@self, wr: @io::Writer, blk: &ast::Block) {
|
||||
let pre: @fn(pprust::ann_node) = |node| {
|
||||
let (ps, id) = match node {
|
||||
pprust::node_expr(ps, expr) => (ps, expr.id),
|
||||
pprust::node_block(ps, blk) => (ps, blk.id),
|
||||
pprust::node_item(ps, _) => (ps, 0),
|
||||
pprust::node_pat(ps, pat) => (ps, pat.id)
|
||||
};
|
||||
|
||||
if self.nodeid_to_bitset.contains_key(&id) {
|
||||
let (start, end) = self.compute_id_range_frozen(id);
|
||||
let on_entry = self.on_entry.slice(start, end);
|
||||
let entry_str = bits_to_str(on_entry);
|
||||
|
||||
let gens = self.gens.slice(start, end);
|
||||
let gens_str = if gens.iter().any(|&u| u != 0) {
|
||||
fmt!(" gen: %s", bits_to_str(gens))
|
||||
} else {
|
||||
~""
|
||||
};
|
||||
|
||||
let kills = self.kills.slice(start, end);
|
||||
let kills_str = if kills.iter().any(|&u| u != 0) {
|
||||
fmt!(" kill: %s", bits_to_str(kills))
|
||||
} else {
|
||||
~""
|
||||
};
|
||||
|
||||
let comment_str = fmt!("id %d: %s%s%s",
|
||||
id, entry_str, gens_str, kills_str);
|
||||
pprust::synth_comment(ps, comment_str);
|
||||
pp::space(ps.s);
|
||||
}
|
||||
};
|
||||
|
||||
let post: @fn(pprust::ann_node) = |_| {
|
||||
};
|
||||
|
||||
let ps = pprust::rust_printer_annotated(
|
||||
wr, self.tcx.sess.intr(),
|
||||
pprust::pp_ann {pre:pre, post:post});
|
||||
let ps = pprust::rust_printer_annotated(wr,
|
||||
self.tcx.sess.intr(),
|
||||
self as @pprust::pp_ann);
|
||||
pprust::cbox(ps, pprust::indent_unit);
|
||||
pprust::ibox(ps, 0u);
|
||||
pprust::print_block(ps, blk);
|
||||
|
|
|
@ -218,14 +218,25 @@ fn with_appropriate_checker(cx: Context, id: NodeId,
|
|||
|
||||
let fty = ty::node_id_to_type(cx.tcx, id);
|
||||
match ty::get(fty).sty {
|
||||
ty::ty_closure(ty::ClosureTy {sigil: OwnedSigil, bounds: bounds, _}) => {
|
||||
ty::ty_closure(ty::ClosureTy {
|
||||
sigil: OwnedSigil,
|
||||
bounds: bounds,
|
||||
_
|
||||
}) => {
|
||||
b(|cx, fv| check_for_uniq(cx, fv, bounds))
|
||||
}
|
||||
ty::ty_closure(ty::ClosureTy {sigil: ManagedSigil, bounds: bounds, _}) => {
|
||||
b(|cx, fv| check_for_box(cx, fv, bounds))
|
||||
ty::ty_closure(ty::ClosureTy {
|
||||
sigil: ManagedSigil,
|
||||
_
|
||||
}) => {
|
||||
// can't happen
|
||||
}
|
||||
ty::ty_closure(ty::ClosureTy {sigil: BorrowedSigil, bounds: bounds,
|
||||
region: region, _}) => {
|
||||
ty::ty_closure(ty::ClosureTy {
|
||||
sigil: BorrowedSigil,
|
||||
bounds: bounds,
|
||||
region: region,
|
||||
_
|
||||
}) => {
|
||||
b(|cx, fv| check_for_block(cx, fv, bounds, region))
|
||||
}
|
||||
ty::ty_bare_fn(_) => {
|
||||
|
|
|
@ -1228,17 +1228,27 @@ fn lint_unused_mut() -> @mut OuterLint {
|
|||
@mut UnusedMutLintVisitor{ stopping_on_items: false } as @mut OuterLint
|
||||
}
|
||||
|
||||
fn lint_session(cx: @mut Context) -> @mut visit::Visitor<()> {
|
||||
ast_util::id_visitor(|id| {
|
||||
match cx.tcx.sess.lints.pop(&id) {
|
||||
None => {},
|
||||
struct LintReportingIdVisitor {
|
||||
cx: @mut Context,
|
||||
}
|
||||
|
||||
impl ast_util::IdVisitingOperation for LintReportingIdVisitor {
|
||||
fn visit_id(&self, id: ast::NodeId) {
|
||||
match self.cx.tcx.sess.lints.pop(&id) {
|
||||
None => {}
|
||||
Some(l) => {
|
||||
for (lint, span, msg) in l.move_iter() {
|
||||
cx.span_lint(lint, span, msg)
|
||||
self.cx.span_lint(lint, span, msg)
|
||||
}
|
||||
}
|
||||
}
|
||||
}, false)
|
||||
}
|
||||
}
|
||||
|
||||
fn lint_session(cx: @mut Context) -> @mut visit::Visitor<()> {
|
||||
ast_util::id_visitor(@LintReportingIdVisitor {
|
||||
cx: cx,
|
||||
} as @ast_util::IdVisitingOperation, false)
|
||||
}
|
||||
|
||||
struct UnnecessaryAllocationLintVisitor { stopping_on_items: bool }
|
||||
|
|
|
@ -187,8 +187,7 @@ pub fn opt_deref_kind(t: ty::t) -> Option<deref_kind> {
|
|||
Some(deref_ptr(gc_ptr(m)))
|
||||
}
|
||||
|
||||
ty::ty_estr(ty::vstore_box) |
|
||||
ty::ty_closure(ty::ClosureTy {sigil: ast::ManagedSigil, _}) => {
|
||||
ty::ty_estr(ty::vstore_box) => {
|
||||
Some(deref_ptr(gc_ptr(ast::MutImmutable)))
|
||||
}
|
||||
|
||||
|
@ -515,7 +514,8 @@ impl mem_categorization_ctxt {
|
|||
(ast::BorrowedSigil, ast::Once) => true,
|
||||
// Heap closures always capture by copy/move, and can
|
||||
// move out iff they are once.
|
||||
(ast::OwnedSigil, _) | (ast::ManagedSigil, _) => false,
|
||||
(ast::OwnedSigil, _) |
|
||||
(ast::ManagedSigil, _) => false,
|
||||
|
||||
};
|
||||
if var_is_refd {
|
||||
|
|
|
@ -116,8 +116,7 @@ fn stack_check_fn<'a>(v: StackCheckVisitor,
|
|||
visit::fk_anon(*) | visit::fk_fn_block => {
|
||||
match ty::get(ty::node_id_to_type(in_cx.tcx, id)).sty {
|
||||
ty::ty_bare_fn(*) |
|
||||
ty::ty_closure(ty::ClosureTy {sigil: ast::OwnedSigil, _}) |
|
||||
ty::ty_closure(ty::ClosureTy {sigil: ast::ManagedSigil, _}) => {
|
||||
ty::ty_closure(ty::ClosureTy {sigil: ast::OwnedSigil, _}) => {
|
||||
false
|
||||
}
|
||||
_ => {
|
||||
|
|
|
@ -533,7 +533,7 @@ fn enter_default<'r>(bcx: @mut Block,
|
|||
m: &[Match<'r>],
|
||||
col: uint,
|
||||
val: ValueRef,
|
||||
chk: Option<mk_fail>)
|
||||
chk: FailureHandler)
|
||||
-> ~[Match<'r>] {
|
||||
debug!("enter_default(bcx=%s, m=%s, col=%u, val=%s)",
|
||||
bcx.to_str(),
|
||||
|
@ -567,7 +567,7 @@ fn enter_default<'r>(bcx: @mut Block,
|
|||
// we don't need any default cases. If the check *isn't* nonexhaustive
|
||||
// (because chk is Some), then we need the defaults anyways.
|
||||
let is_exhaustive = match matches.last_opt() {
|
||||
Some(m) if m.data.arm.guard.is_some() && chk.is_none() => true,
|
||||
Some(m) if m.data.arm.guard.is_some() && chk.is_infallible() => true,
|
||||
_ => false
|
||||
};
|
||||
|
||||
|
@ -1185,7 +1185,62 @@ fn any_tuple_struct_pat(bcx: @mut Block, m: &[Match], col: uint) -> bool {
|
|||
}
|
||||
}
|
||||
|
||||
type mk_fail = @fn() -> BasicBlockRef;
|
||||
trait CustomFailureHandler {
|
||||
fn handle_fail(&self) -> BasicBlockRef;
|
||||
}
|
||||
|
||||
struct DynamicFailureHandler {
|
||||
bcx: @mut Block,
|
||||
sp: Span,
|
||||
msg: @str,
|
||||
finished: @mut Option<BasicBlockRef>,
|
||||
}
|
||||
|
||||
impl CustomFailureHandler for DynamicFailureHandler {
|
||||
fn handle_fail(&self) -> BasicBlockRef {
|
||||
match *self.finished {
|
||||
Some(bb) => return bb,
|
||||
_ => (),
|
||||
}
|
||||
|
||||
let fail_cx = sub_block(self.bcx, "case_fallthrough");
|
||||
controlflow::trans_fail(fail_cx, Some(self.sp), self.msg);
|
||||
*self.finished = Some(fail_cx.llbb);
|
||||
fail_cx.llbb
|
||||
}
|
||||
}
|
||||
|
||||
/// What to do when the pattern match fails.
|
||||
enum FailureHandler {
|
||||
Infallible,
|
||||
JumpToBasicBlock(BasicBlockRef),
|
||||
CustomFailureHandlerClass(@CustomFailureHandler),
|
||||
}
|
||||
|
||||
impl FailureHandler {
|
||||
fn is_infallible(&self) -> bool {
|
||||
match *self {
|
||||
Infallible => true,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
fn is_fallible(&self) -> bool {
|
||||
!self.is_infallible()
|
||||
}
|
||||
|
||||
fn handle_fail(&self) -> BasicBlockRef {
|
||||
match *self {
|
||||
Infallible => {
|
||||
fail!("attempted to fail in infallible failure handler!")
|
||||
}
|
||||
JumpToBasicBlock(basic_block) => basic_block,
|
||||
CustomFailureHandlerClass(custom_failure_handler) => {
|
||||
custom_failure_handler.handle_fail()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn pick_col(m: &[Match]) -> uint {
|
||||
fn score(p: &ast::Pat) -> uint {
|
||||
|
@ -1347,7 +1402,7 @@ fn compile_guard(bcx: @mut Block,
|
|||
data: &ArmData,
|
||||
m: &[Match],
|
||||
vals: &[ValueRef],
|
||||
chk: Option<mk_fail>)
|
||||
chk: FailureHandler)
|
||||
-> @mut Block {
|
||||
debug!("compile_guard(bcx=%s, guard_expr=%s, m=%s, vals=%s)",
|
||||
bcx.to_str(),
|
||||
|
@ -1402,7 +1457,7 @@ fn compile_guard(bcx: @mut Block,
|
|||
fn compile_submatch(bcx: @mut Block,
|
||||
m: &[Match],
|
||||
vals: &[ValueRef],
|
||||
chk: Option<mk_fail>) {
|
||||
chk: FailureHandler) {
|
||||
debug!("compile_submatch(bcx=%s, m=%s, vals=%s)",
|
||||
bcx.to_str(),
|
||||
m.repr(bcx.tcx()),
|
||||
|
@ -1412,11 +1467,11 @@ fn compile_submatch(bcx: @mut Block,
|
|||
/*
|
||||
For an empty match, a fall-through case must exist
|
||||
*/
|
||||
assert!((m.len() > 0u || chk.is_some()));
|
||||
assert!((m.len() > 0u || chk.is_fallible()));
|
||||
let _icx = push_ctxt("match::compile_submatch");
|
||||
let mut bcx = bcx;
|
||||
if m.len() == 0u {
|
||||
Br(bcx, chk.unwrap()());
|
||||
Br(bcx, chk.handle_fail());
|
||||
return;
|
||||
}
|
||||
if m[0].pats.len() == 0u {
|
||||
|
@ -1454,7 +1509,7 @@ fn compile_submatch(bcx: @mut Block,
|
|||
fn compile_submatch_continue(mut bcx: @mut Block,
|
||||
m: &[Match],
|
||||
vals: &[ValueRef],
|
||||
chk: Option<mk_fail>,
|
||||
chk: FailureHandler,
|
||||
col: uint,
|
||||
val: ValueRef) {
|
||||
let tcx = bcx.tcx();
|
||||
|
@ -1617,7 +1672,7 @@ fn compile_submatch_continue(mut bcx: @mut Block,
|
|||
};
|
||||
|
||||
let defaults = enter_default(else_cx, dm, m, col, val, chk);
|
||||
let exhaustive = chk.is_none() && defaults.len() == 0u;
|
||||
let exhaustive = chk.is_infallible() && defaults.len() == 0u;
|
||||
let len = opts.len();
|
||||
|
||||
// Compile subtrees for each option
|
||||
|
@ -1721,7 +1776,7 @@ fn compile_submatch_continue(mut bcx: @mut Block,
|
|||
|
||||
// If none of these subcases match, move on to the
|
||||
// next condition.
|
||||
branch_chk = Some::<mk_fail>(|| bcx.llbb);
|
||||
branch_chk = JumpToBasicBlock(bcx.llbb);
|
||||
CondBr(after_cx, matches, opt_cx.llbb, bcx.llbb);
|
||||
}
|
||||
_ => ()
|
||||
|
@ -1860,11 +1915,15 @@ fn trans_match_inner(scope_cx: @mut Block,
|
|||
if ty::type_is_empty(tcx, t) {
|
||||
// Special case for empty types
|
||||
let fail_cx = @mut None;
|
||||
let f: mk_fail = || mk_fail(scope_cx, discr_expr.span,
|
||||
@"scrutinizing value that can't exist", fail_cx);
|
||||
Some(f)
|
||||
let fail_handler = @DynamicFailureHandler {
|
||||
bcx: scope_cx,
|
||||
sp: discr_expr.span,
|
||||
msg: @"scrutinizing value that can't exist",
|
||||
finished: fail_cx,
|
||||
} as @CustomFailureHandler;
|
||||
CustomFailureHandlerClass(fail_handler)
|
||||
} else {
|
||||
None
|
||||
Infallible
|
||||
}
|
||||
};
|
||||
let lldiscr = discr_datum.to_zeroable_ref_llval(bcx);
|
||||
|
@ -1892,15 +1951,6 @@ fn trans_match_inner(scope_cx: @mut Block,
|
|||
|
||||
bcx = controlflow::join_blocks(scope_cx, arm_cxs);
|
||||
return bcx;
|
||||
|
||||
fn mk_fail(bcx: @mut Block, sp: Span, msg: @str,
|
||||
finished: @mut Option<BasicBlockRef>) -> BasicBlockRef {
|
||||
match *finished { Some(bb) => return bb, _ => () }
|
||||
let fail_cx = sub_block(bcx, "case_fallthrough");
|
||||
controlflow::trans_fail(fail_cx, Some(sp), msg);
|
||||
*finished = Some(fail_cx.llbb);
|
||||
return fail_cx.llbb;
|
||||
}
|
||||
}
|
||||
|
||||
enum IrrefutablePatternBindingMode {
|
||||
|
|
|
@ -1320,7 +1320,7 @@ pub fn trans_block_cleanups_(bcx: @mut Block,
|
|||
// Some types don't need to be cleaned up during
|
||||
// landing pads because they can be freed en mass later
|
||||
if cleanup_type == normal_exit_and_unwind || !is_lpad {
|
||||
bcx = cfn(bcx);
|
||||
bcx = cfn.clean(bcx);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -172,7 +172,7 @@ pub fn allocate_cbox(bcx: @mut Block, sigil: ast::Sigil, cdata_ty: ty::t)
|
|||
// Allocate and initialize the box:
|
||||
match sigil {
|
||||
ast::ManagedSigil => {
|
||||
malloc_raw(bcx, cdata_ty, heap_managed)
|
||||
tcx.sess.bug("trying to trans allocation of @fn")
|
||||
}
|
||||
ast::OwnedSigil => {
|
||||
malloc_raw(bcx, cdata_ty, heap_for_unique_closure(bcx, cdata_ty))
|
||||
|
@ -197,7 +197,8 @@ pub struct ClosureResult {
|
|||
// Otherwise, it is stack allocated and copies pointers to the upvars.
|
||||
pub fn store_environment(bcx: @mut Block,
|
||||
bound_values: ~[EnvValue],
|
||||
sigil: ast::Sigil) -> ClosureResult {
|
||||
sigil: ast::Sigil)
|
||||
-> ClosureResult {
|
||||
let _icx = push_ctxt("closure::store_environment");
|
||||
let ccx = bcx.ccx();
|
||||
let tcx = ccx.tcx;
|
||||
|
@ -444,27 +445,6 @@ pub fn make_closure_glue(
|
|||
}
|
||||
}
|
||||
|
||||
pub fn make_opaque_cbox_take_glue(
|
||||
bcx: @mut Block,
|
||||
sigil: ast::Sigil,
|
||||
cboxptr: ValueRef) // ptr to ptr to the opaque closure
|
||||
-> @mut Block {
|
||||
// Easy cases:
|
||||
let _icx = push_ctxt("closure::make_opaque_cbox_take_glue");
|
||||
match sigil {
|
||||
ast::BorrowedSigil => {
|
||||
return bcx;
|
||||
}
|
||||
ast::ManagedSigil => {
|
||||
glue::incr_refcnt_of_boxed(bcx, Load(bcx, cboxptr));
|
||||
return bcx;
|
||||
}
|
||||
ast::OwnedSigil => {
|
||||
fail!("unique closures are not copyable")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn make_opaque_cbox_drop_glue(
|
||||
bcx: @mut Block,
|
||||
sigil: ast::Sigil,
|
||||
|
@ -474,9 +454,7 @@ pub fn make_opaque_cbox_drop_glue(
|
|||
match sigil {
|
||||
ast::BorrowedSigil => bcx,
|
||||
ast::ManagedSigil => {
|
||||
glue::decr_refcnt_maybe_free(
|
||||
bcx, Load(bcx, cboxptr), Some(cboxptr),
|
||||
ty::mk_opaque_closure_ptr(bcx.tcx(), sigil))
|
||||
bcx.tcx().sess.bug("trying to trans drop glue of @fn")
|
||||
}
|
||||
ast::OwnedSigil => {
|
||||
glue::free_ty(
|
||||
|
@ -516,12 +494,8 @@ pub fn make_opaque_cbox_free_glue(
|
|||
abi::tydesc_field_drop_glue, None);
|
||||
|
||||
// Free the ty descr (if necc) and the box itself
|
||||
match sigil {
|
||||
ast::ManagedSigil => glue::trans_free(bcx, cbox),
|
||||
ast::OwnedSigil => glue::trans_exchange_free(bcx, cbox),
|
||||
ast::BorrowedSigil => {
|
||||
bcx.sess().bug("impossible")
|
||||
}
|
||||
}
|
||||
glue::trans_exchange_free(bcx, cbox);
|
||||
|
||||
bcx
|
||||
}
|
||||
}
|
||||
|
|
|
@ -294,9 +294,85 @@ pub enum cleantype {
|
|||
normal_exit_and_unwind
|
||||
}
|
||||
|
||||
// Cleanup functions
|
||||
|
||||
/// A cleanup function: a built-in destructor.
|
||||
pub trait CleanupFunction {
|
||||
fn clean(&self, block: @mut Block) -> @mut Block;
|
||||
}
|
||||
|
||||
/// A cleanup function that calls the "drop glue" (destructor function) on
|
||||
/// a typed value.
|
||||
pub struct TypeDroppingCleanupFunction {
|
||||
val: ValueRef,
|
||||
t: ty::t,
|
||||
}
|
||||
|
||||
impl CleanupFunction for TypeDroppingCleanupFunction {
|
||||
fn clean(&self, block: @mut Block) -> @mut Block {
|
||||
glue::drop_ty(block, self.val, self.t)
|
||||
}
|
||||
}
|
||||
|
||||
/// A cleanup function that calls the "drop glue" (destructor function) on
|
||||
/// an immediate typed value.
|
||||
pub struct ImmediateTypeDroppingCleanupFunction {
|
||||
val: ValueRef,
|
||||
t: ty::t,
|
||||
}
|
||||
|
||||
impl CleanupFunction for ImmediateTypeDroppingCleanupFunction {
|
||||
fn clean(&self, block: @mut Block) -> @mut Block {
|
||||
glue::drop_ty_immediate(block, self.val, self.t)
|
||||
}
|
||||
}
|
||||
|
||||
/// A cleanup function that releases a write guard, returning a value to
|
||||
/// mutable status.
|
||||
pub struct WriteGuardReleasingCleanupFunction {
|
||||
root_key: root_map_key,
|
||||
frozen_val_ref: ValueRef,
|
||||
bits_val_ref: ValueRef,
|
||||
filename_val: ValueRef,
|
||||
line_val: ValueRef,
|
||||
}
|
||||
|
||||
impl CleanupFunction for WriteGuardReleasingCleanupFunction {
|
||||
fn clean(&self, bcx: @mut Block) -> @mut Block {
|
||||
write_guard::return_to_mut(bcx,
|
||||
self.root_key,
|
||||
self.frozen_val_ref,
|
||||
self.bits_val_ref,
|
||||
self.filename_val,
|
||||
self.line_val)
|
||||
}
|
||||
}
|
||||
|
||||
/// A cleanup function that frees some memory in the garbage-collected heap.
|
||||
pub struct GCHeapFreeingCleanupFunction {
|
||||
ptr: ValueRef,
|
||||
}
|
||||
|
||||
impl CleanupFunction for GCHeapFreeingCleanupFunction {
|
||||
fn clean(&self, bcx: @mut Block) -> @mut Block {
|
||||
glue::trans_free(bcx, self.ptr)
|
||||
}
|
||||
}
|
||||
|
||||
/// A cleanup function that frees some memory in the exchange heap.
|
||||
pub struct ExchangeHeapFreeingCleanupFunction {
|
||||
ptr: ValueRef,
|
||||
}
|
||||
|
||||
impl CleanupFunction for ExchangeHeapFreeingCleanupFunction {
|
||||
fn clean(&self, bcx: @mut Block) -> @mut Block {
|
||||
glue::trans_exchange_free(bcx, self.ptr)
|
||||
}
|
||||
}
|
||||
|
||||
pub enum cleanup {
|
||||
clean(@fn(@mut Block) -> @mut Block, cleantype),
|
||||
clean_temp(ValueRef, @fn(@mut Block) -> @mut Block, cleantype),
|
||||
clean(@CleanupFunction, cleantype),
|
||||
clean_temp(ValueRef, @CleanupFunction, cleantype),
|
||||
}
|
||||
|
||||
// Can't use deriving(Clone) because of the managed closure.
|
||||
|
@ -337,13 +413,19 @@ pub fn cleanup_type(cx: ty::ctxt, ty: ty::t) -> cleantype {
|
|||
}
|
||||
|
||||
pub fn add_clean(bcx: @mut Block, val: ValueRef, t: ty::t) {
|
||||
if !ty::type_needs_drop(bcx.tcx(), t) { return; }
|
||||
if !ty::type_needs_drop(bcx.tcx(), t) {
|
||||
return
|
||||
}
|
||||
|
||||
debug!("add_clean(%s, %s, %s)", bcx.to_str(), bcx.val_to_str(val), t.repr(bcx.tcx()));
|
||||
|
||||
let cleanup_type = cleanup_type(bcx.tcx(), t);
|
||||
do in_scope_cx(bcx, None) |scope_info| {
|
||||
scope_info.cleanups.push(clean(|a| glue::drop_ty(a, val, t), cleanup_type));
|
||||
scope_info.cleanups.push(clean(@TypeDroppingCleanupFunction {
|
||||
val: val,
|
||||
t: t,
|
||||
} as @CleanupFunction,
|
||||
cleanup_type));
|
||||
grow_scope_clean(scope_info);
|
||||
}
|
||||
}
|
||||
|
@ -355,8 +437,11 @@ pub fn add_clean_temp_immediate(cx: @mut Block, val: ValueRef, ty: ty::t) {
|
|||
ty.repr(cx.tcx()));
|
||||
let cleanup_type = cleanup_type(cx.tcx(), ty);
|
||||
do in_scope_cx(cx, None) |scope_info| {
|
||||
scope_info.cleanups.push(
|
||||
clean_temp(val, |a| glue::drop_ty_immediate(a, val, ty),
|
||||
scope_info.cleanups.push(clean_temp(val,
|
||||
@ImmediateTypeDroppingCleanupFunction {
|
||||
val: val,
|
||||
t: ty,
|
||||
} as @CleanupFunction,
|
||||
cleanup_type));
|
||||
grow_scope_clean(scope_info);
|
||||
}
|
||||
|
@ -381,7 +466,12 @@ pub fn add_clean_temp_mem_in_scope_(bcx: @mut Block, scope_id: Option<ast::NodeI
|
|||
t.repr(bcx.tcx()));
|
||||
let cleanup_type = cleanup_type(bcx.tcx(), t);
|
||||
do in_scope_cx(bcx, scope_id) |scope_info| {
|
||||
scope_info.cleanups.push(clean_temp(val, |a| glue::drop_ty(a, val, t), cleanup_type));
|
||||
scope_info.cleanups.push(clean_temp(val,
|
||||
@TypeDroppingCleanupFunction {
|
||||
val: val,
|
||||
t: t,
|
||||
} as @CleanupFunction,
|
||||
cleanup_type));
|
||||
grow_scope_clean(scope_info);
|
||||
}
|
||||
}
|
||||
|
@ -405,11 +495,15 @@ pub fn add_clean_return_to_mut(bcx: @mut Block,
|
|||
bcx.val_to_str(frozen_val_ref),
|
||||
bcx.val_to_str(bits_val_ref));
|
||||
do in_scope_cx(bcx, Some(scope_id)) |scope_info| {
|
||||
scope_info.cleanups.push(
|
||||
clean_temp(
|
||||
scope_info.cleanups.push(clean_temp(
|
||||
frozen_val_ref,
|
||||
|bcx| write_guard::return_to_mut(bcx, root_key, frozen_val_ref, bits_val_ref,
|
||||
filename_val, line_val),
|
||||
@WriteGuardReleasingCleanupFunction {
|
||||
root_key: root_key,
|
||||
frozen_val_ref: frozen_val_ref,
|
||||
bits_val_ref: bits_val_ref,
|
||||
filename_val: filename_val,
|
||||
line_val: line_val,
|
||||
} as @CleanupFunction,
|
||||
normal_exit_only));
|
||||
grow_scope_clean(scope_info);
|
||||
}
|
||||
|
@ -417,16 +511,19 @@ pub fn add_clean_return_to_mut(bcx: @mut Block,
|
|||
pub fn add_clean_free(cx: @mut Block, ptr: ValueRef, heap: heap) {
|
||||
let free_fn = match heap {
|
||||
heap_managed | heap_managed_unique => {
|
||||
let f: @fn(@mut Block) -> @mut Block = |a| glue::trans_free(a, ptr);
|
||||
f
|
||||
@GCHeapFreeingCleanupFunction {
|
||||
ptr: ptr,
|
||||
} as @CleanupFunction
|
||||
}
|
||||
heap_exchange | heap_exchange_closure => {
|
||||
let f: @fn(@mut Block) -> @mut Block = |a| glue::trans_exchange_free(a, ptr);
|
||||
f
|
||||
@ExchangeHeapFreeingCleanupFunction {
|
||||
ptr: ptr,
|
||||
} as @CleanupFunction
|
||||
}
|
||||
};
|
||||
do in_scope_cx(cx, None) |scope_info| {
|
||||
scope_info.cleanups.push(clean_temp(ptr, free_fn,
|
||||
scope_info.cleanups.push(clean_temp(ptr,
|
||||
free_fn,
|
||||
normal_exit_and_unwind));
|
||||
grow_scope_clean(scope_info);
|
||||
}
|
||||
|
|
|
@ -1086,6 +1086,36 @@ fn pointer_type_metadata(cx: &mut CrateContext,
|
|||
return ptr_metadata;
|
||||
}
|
||||
|
||||
trait MemberDescriptionFactory {
|
||||
fn create_member_descriptions(&self, cx: &mut CrateContext)
|
||||
-> ~[MemberDescription];
|
||||
}
|
||||
|
||||
struct StructMemberDescriptionFactory {
|
||||
fields: ~[ty::field],
|
||||
span: Span,
|
||||
}
|
||||
|
||||
impl MemberDescriptionFactory for StructMemberDescriptionFactory {
|
||||
fn create_member_descriptions(&self, cx: &mut CrateContext)
|
||||
-> ~[MemberDescription] {
|
||||
do self.fields.map |field| {
|
||||
let name = if field.ident.name == special_idents::unnamed_field.name {
|
||||
@""
|
||||
} else {
|
||||
token::ident_to_str(&field.ident)
|
||||
};
|
||||
|
||||
MemberDescription {
|
||||
name: name,
|
||||
llvm_type: type_of::type_of(cx, field.mt.ty),
|
||||
type_metadata: type_metadata(cx, field.mt.ty, self.span),
|
||||
offset: ComputedMemberOffset,
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn prepare_struct_metadata(cx: &mut CrateContext,
|
||||
struct_type: ty::t,
|
||||
def_id: ast::DefId,
|
||||
|
@ -1114,22 +1144,10 @@ fn prepare_struct_metadata(cx: &mut CrateContext,
|
|||
metadata_stub: struct_metadata_stub,
|
||||
llvm_type: struct_llvm_type,
|
||||
file_metadata: file_metadata,
|
||||
member_description_factory: |cx| {
|
||||
do fields.map |field| {
|
||||
let name = if field.ident.name == special_idents::unnamed_field.name {
|
||||
@""
|
||||
} else {
|
||||
token::ident_to_str(&field.ident)
|
||||
};
|
||||
|
||||
MemberDescription {
|
||||
name: name,
|
||||
llvm_type: type_of::type_of(cx, field.mt.ty),
|
||||
type_metadata: type_metadata(cx, field.mt.ty, span),
|
||||
offset: ComputedMemberOffset,
|
||||
}
|
||||
}
|
||||
}
|
||||
member_description_factory: @StructMemberDescriptionFactory {
|
||||
fields: fields,
|
||||
span: span,
|
||||
} as @MemberDescriptionFactory,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1139,7 +1157,7 @@ enum RecursiveTypeDescription {
|
|||
metadata_stub: DICompositeType,
|
||||
llvm_type: Type,
|
||||
file_metadata: DIFile,
|
||||
member_description_factory: @fn(cx: &mut CrateContext) -> ~[MemberDescription],
|
||||
member_description_factory: @MemberDescriptionFactory,
|
||||
},
|
||||
FinalMetadata(DICompositeType)
|
||||
}
|
||||
|
@ -1167,7 +1185,8 @@ impl RecursiveTypeDescription {
|
|||
debug_context(cx).created_types.insert(cache_id, metadata_stub);
|
||||
|
||||
// ... then create the member descriptions ...
|
||||
let member_descriptions = member_description_factory(cx);
|
||||
let member_descriptions = member_description_factory.
|
||||
create_member_descriptions(cx);
|
||||
|
||||
// ... and attach them to the stub to complete it.
|
||||
set_members_of_composite_type(cx,
|
||||
|
@ -1182,6 +1201,25 @@ impl RecursiveTypeDescription {
|
|||
}
|
||||
}
|
||||
|
||||
struct TupleMemberDescriptionFactory {
|
||||
component_types: ~[ty::t],
|
||||
span: Span,
|
||||
}
|
||||
|
||||
impl MemberDescriptionFactory for TupleMemberDescriptionFactory {
|
||||
fn create_member_descriptions(&self, cx: &mut CrateContext)
|
||||
-> ~[MemberDescription] {
|
||||
do self.component_types.map |&component_type| {
|
||||
MemberDescription {
|
||||
name: @"",
|
||||
llvm_type: type_of::type_of(cx, component_type),
|
||||
type_metadata: type_metadata(cx, component_type, self.span),
|
||||
offset: ComputedMemberOffset,
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn prepare_tuple_metadata(cx: &mut CrateContext,
|
||||
tuple_type: ty::t,
|
||||
component_types: &[ty::t],
|
||||
|
@ -1192,8 +1230,6 @@ fn prepare_tuple_metadata(cx: &mut CrateContext,
|
|||
|
||||
let loc = span_start(cx, span);
|
||||
let file_metadata = file_metadata(cx, loc.file.name);
|
||||
// Needs to be copied for closure below :(
|
||||
let component_types = component_types.to_owned();
|
||||
|
||||
UnfinishedMetadata {
|
||||
cache_id: cache_id_for_type(tuple_type),
|
||||
|
@ -1205,17 +1241,147 @@ fn prepare_tuple_metadata(cx: &mut CrateContext,
|
|||
span),
|
||||
llvm_type: tuple_llvm_type,
|
||||
file_metadata: file_metadata,
|
||||
member_description_factory: |cx| {
|
||||
do component_types.map |&component_type| {
|
||||
member_description_factory: @TupleMemberDescriptionFactory {
|
||||
component_types: component_types.to_owned(),
|
||||
span: span,
|
||||
} as @MemberDescriptionFactory
|
||||
}
|
||||
}
|
||||
|
||||
struct GeneralMemberDescriptionFactory {
|
||||
type_rep: @adt::Repr,
|
||||
variants: @~[@ty::VariantInfo],
|
||||
discriminant_type_metadata: ValueRef,
|
||||
containing_scope: DIScope,
|
||||
file_metadata: DIFile,
|
||||
span: Span,
|
||||
}
|
||||
|
||||
impl MemberDescriptionFactory for GeneralMemberDescriptionFactory {
|
||||
fn create_member_descriptions(&self, cx: &mut CrateContext)
|
||||
-> ~[MemberDescription] {
|
||||
// Capture type_rep, so we don't have to copy the struct_defs array
|
||||
let struct_defs = match *self.type_rep {
|
||||
adt::General(ref struct_defs) => struct_defs,
|
||||
_ => cx.sess.bug("unreachable")
|
||||
};
|
||||
|
||||
do struct_defs
|
||||
.iter()
|
||||
.enumerate()
|
||||
.map |(i, struct_def)| {
|
||||
let (variant_type_metadata, variant_llvm_type, member_desc_factory) =
|
||||
describe_variant(cx,
|
||||
struct_def,
|
||||
self.variants[i],
|
||||
Some(self.discriminant_type_metadata),
|
||||
self.containing_scope,
|
||||
self.file_metadata,
|
||||
self.span);
|
||||
|
||||
let member_descriptions =
|
||||
member_desc_factory.create_member_descriptions(cx);
|
||||
|
||||
set_members_of_composite_type(cx,
|
||||
variant_type_metadata,
|
||||
variant_llvm_type,
|
||||
member_descriptions,
|
||||
self.file_metadata,
|
||||
codemap::dummy_sp());
|
||||
MemberDescription {
|
||||
name: @"",
|
||||
llvm_type: type_of::type_of(cx, component_type),
|
||||
type_metadata: type_metadata(cx, component_type, span),
|
||||
llvm_type: variant_llvm_type,
|
||||
type_metadata: variant_type_metadata,
|
||||
offset: FixedMemberOffset { bytes: 0 },
|
||||
}
|
||||
}.collect()
|
||||
}
|
||||
}
|
||||
|
||||
struct EnumVariantMemberDescriptionFactory {
|
||||
args: ~[(@str, ty::t)],
|
||||
discriminant_type_metadata: Option<DIType>,
|
||||
span: Span,
|
||||
}
|
||||
|
||||
impl MemberDescriptionFactory for EnumVariantMemberDescriptionFactory {
|
||||
fn create_member_descriptions(&self, cx: &mut CrateContext)
|
||||
-> ~[MemberDescription] {
|
||||
do self.args.iter().enumerate().map |(i, &(name, ty))| {
|
||||
MemberDescription {
|
||||
name: name,
|
||||
llvm_type: type_of::type_of(cx, ty),
|
||||
type_metadata: match self.discriminant_type_metadata {
|
||||
Some(metadata) if i == 0 => metadata,
|
||||
_ => type_metadata(cx, ty, self.span)
|
||||
},
|
||||
offset: ComputedMemberOffset,
|
||||
}
|
||||
}.collect()
|
||||
}
|
||||
}
|
||||
|
||||
fn describe_variant(cx: &mut CrateContext,
|
||||
struct_def: &adt::Struct,
|
||||
variant_info: &ty::VariantInfo,
|
||||
discriminant_type_metadata: Option<DIType>,
|
||||
containing_scope: DIScope,
|
||||
file_metadata: DIFile,
|
||||
span: Span)
|
||||
-> (DICompositeType, Type, @MemberDescriptionFactory) {
|
||||
let variant_name = token::ident_to_str(&variant_info.name);
|
||||
let variant_llvm_type = Type::struct_(struct_def.fields.map(|&t| type_of::type_of(cx, t)),
|
||||
struct_def.packed);
|
||||
// Could some consistency checks here: size, align, field count, discr type
|
||||
|
||||
// Find the source code location of the variant's definition
|
||||
let variant_definition_span = if variant_info.id.crate == ast::LOCAL_CRATE {
|
||||
match cx.tcx.items.find(&variant_info.id.node) {
|
||||
Some(&ast_map::node_variant(ref variant, _, _)) => variant.span,
|
||||
ref node => {
|
||||
cx.sess.span_warn(span,
|
||||
fmt!("debuginfo::enum_metadata()::adt_struct_metadata() - Unexpected node \
|
||||
type: %?. This is a bug.", node));
|
||||
codemap::dummy_sp()
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// For definitions from other crates we have no location information available.
|
||||
codemap::dummy_sp()
|
||||
};
|
||||
|
||||
let metadata_stub = create_struct_stub(cx,
|
||||
variant_llvm_type,
|
||||
variant_name,
|
||||
containing_scope,
|
||||
file_metadata,
|
||||
variant_definition_span);
|
||||
|
||||
// Get the argument names from the enum variant info
|
||||
let mut arg_names = match variant_info.arg_names {
|
||||
Some(ref names) => do names.map |ident| { token::ident_to_str(ident) },
|
||||
None => do variant_info.args.map |_| { @"" }
|
||||
};
|
||||
|
||||
// If this is not a univariant enum, there is also the (unnamed) discriminant field
|
||||
if discriminant_type_metadata.is_some() {
|
||||
arg_names.insert(0, @"");
|
||||
}
|
||||
|
||||
// Build an array of (field name, field type) pairs to be captured in the factory closure.
|
||||
let args: ~[(@str, ty::t)] = arg_names.iter()
|
||||
.zip(struct_def.fields.iter())
|
||||
.map(|(&s, &t)| (s, t))
|
||||
.collect();
|
||||
|
||||
let member_description_factory =
|
||||
@EnumVariantMemberDescriptionFactory {
|
||||
args: args,
|
||||
discriminant_type_metadata: discriminant_type_metadata,
|
||||
span: span,
|
||||
} as @MemberDescriptionFactory;
|
||||
|
||||
(metadata_stub, variant_llvm_type, member_description_factory)
|
||||
}
|
||||
|
||||
fn prepare_enum_metadata(cx: &mut CrateContext,
|
||||
|
@ -1336,42 +1502,14 @@ fn prepare_enum_metadata(cx: &mut CrateContext,
|
|||
metadata_stub: enum_metadata,
|
||||
llvm_type: enum_llvm_type,
|
||||
file_metadata: file_metadata,
|
||||
member_description_factory: |cx| {
|
||||
// Capture type_rep, so we don't have to copy the struct_defs array
|
||||
let struct_defs = match *type_rep {
|
||||
adt::General(ref struct_defs) => struct_defs,
|
||||
_ => cx.sess.bug("unreachable")
|
||||
};
|
||||
|
||||
do struct_defs
|
||||
.iter()
|
||||
.enumerate()
|
||||
.map |(i, struct_def)| {
|
||||
let (variant_type_metadata, variant_llvm_type, member_desc_factory) =
|
||||
describe_variant(cx,
|
||||
struct_def,
|
||||
variants[i],
|
||||
Some(discriminant_type_metadata),
|
||||
containing_scope,
|
||||
file_metadata,
|
||||
span);
|
||||
|
||||
let member_descriptions = member_desc_factory(cx);
|
||||
|
||||
set_members_of_composite_type(cx,
|
||||
variant_type_metadata,
|
||||
variant_llvm_type,
|
||||
member_descriptions,
|
||||
file_metadata,
|
||||
codemap::dummy_sp());
|
||||
MemberDescription {
|
||||
name: @"",
|
||||
llvm_type: variant_llvm_type,
|
||||
type_metadata: variant_type_metadata,
|
||||
offset: FixedMemberOffset { bytes: 0 },
|
||||
}
|
||||
}.collect()
|
||||
}
|
||||
member_description_factory: @GeneralMemberDescriptionFactory {
|
||||
type_rep: type_rep,
|
||||
variants: variants,
|
||||
discriminant_type_metadata: discriminant_type_metadata,
|
||||
containing_scope: containing_scope,
|
||||
file_metadata: file_metadata,
|
||||
span: span,
|
||||
} as @MemberDescriptionFactory,
|
||||
}
|
||||
}
|
||||
adt::NullablePointer { nonnull: ref struct_def, nndiscr, _ } => {
|
||||
|
@ -1393,76 +1531,6 @@ fn prepare_enum_metadata(cx: &mut CrateContext,
|
|||
}
|
||||
}
|
||||
};
|
||||
|
||||
fn describe_variant(cx: &mut CrateContext,
|
||||
struct_def: &adt::Struct,
|
||||
variant_info: &ty::VariantInfo,
|
||||
discriminant_type_metadata: Option<DIType>,
|
||||
containing_scope: DIScope,
|
||||
file_metadata: DIFile,
|
||||
span: Span)
|
||||
-> (DICompositeType, Type, @fn(&mut CrateContext) -> ~[MemberDescription]) {
|
||||
let variant_name = token::ident_to_str(&variant_info.name);
|
||||
let variant_llvm_type = Type::struct_(struct_def.fields.map(|&t| type_of::type_of(cx, t)),
|
||||
struct_def.packed);
|
||||
// Could some consistency checks here: size, align, field count, discr type
|
||||
|
||||
// Find the source code location of the variant's definition
|
||||
let variant_definition_span = if variant_info.id.crate == ast::LOCAL_CRATE {
|
||||
match cx.tcx.items.find(&variant_info.id.node) {
|
||||
Some(&ast_map::node_variant(ref variant, _, _)) => variant.span,
|
||||
ref node => {
|
||||
cx.sess.span_warn(span,
|
||||
fmt!("debuginfo::enum_metadata()::adt_struct_metadata() - Unexpected node \
|
||||
type: %?. This is a bug.", node));
|
||||
codemap::dummy_sp()
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// For definitions from other crates we have no location information available.
|
||||
codemap::dummy_sp()
|
||||
};
|
||||
|
||||
let metadata_stub = create_struct_stub(cx,
|
||||
variant_llvm_type,
|
||||
variant_name,
|
||||
containing_scope,
|
||||
file_metadata,
|
||||
variant_definition_span);
|
||||
|
||||
// Get the argument names from the enum variant info
|
||||
let mut arg_names = match variant_info.arg_names {
|
||||
Some(ref names) => do names.map |ident| { token::ident_to_str(ident) },
|
||||
None => do variant_info.args.map |_| { @"" }
|
||||
};
|
||||
|
||||
// If this is not a univariant enum, there is also the (unnamed) discriminant field
|
||||
if discriminant_type_metadata.is_some() {
|
||||
arg_names.insert(0, @"");
|
||||
}
|
||||
|
||||
// Build an array of (field name, field type) pairs to be captured in the factory closure.
|
||||
let args: ~[(@str, ty::t)] = arg_names.iter()
|
||||
.zip(struct_def.fields.iter())
|
||||
.map(|(&s, &t)| (s, t))
|
||||
.collect();
|
||||
|
||||
let member_description_factory: @fn(cx: &mut CrateContext) -> ~[MemberDescription] = |cx| {
|
||||
do args.iter().enumerate().map |(i, &(name, ty))| {
|
||||
MemberDescription {
|
||||
name: name,
|
||||
llvm_type: type_of::type_of(cx, ty),
|
||||
type_metadata: match discriminant_type_metadata {
|
||||
Some(metadata) if i == 0 => metadata,
|
||||
_ => type_metadata(cx, ty, span)
|
||||
},
|
||||
offset: ComputedMemberOffset,
|
||||
}
|
||||
}.collect()
|
||||
};
|
||||
|
||||
(metadata_stub, variant_llvm_type, member_description_factory)
|
||||
}
|
||||
}
|
||||
|
||||
enum MemberOffset {
|
||||
|
|
|
@ -581,11 +581,7 @@ pub fn make_take_glue(bcx: @mut Block, v: ValueRef, t: ty::t) -> @mut Block {
|
|||
| ty::ty_estr(ty::vstore_slice(_)) => {
|
||||
bcx
|
||||
}
|
||||
ty::ty_closure(ty::ClosureTy { sigil: ast::BorrowedSigil, _ }) |
|
||||
ty::ty_closure(ty::ClosureTy { sigil: ast::ManagedSigil, _ }) => {
|
||||
closure::make_closure_glue(bcx, v, t, take_ty)
|
||||
}
|
||||
ty::ty_closure(ty::ClosureTy { sigil: ast::OwnedSigil, _ }) => bcx,
|
||||
ty::ty_closure(_) => bcx,
|
||||
ty::ty_trait(_, _, ty::BoxTraitStore, _, _) => {
|
||||
let llbox = Load(bcx, GEPi(bcx, v, [0u, abi::trt_field_box]));
|
||||
incr_refcnt_of_boxed(bcx, llbox);
|
||||
|
@ -606,9 +602,7 @@ pub fn make_take_glue(bcx: @mut Block, v: ValueRef, t: ty::t) -> @mut Block {
|
|||
None);
|
||||
bcx
|
||||
}
|
||||
ty::ty_opaque_closure_ptr(ck) => {
|
||||
closure::make_opaque_cbox_take_glue(bcx, ck, v)
|
||||
}
|
||||
ty::ty_opaque_closure_ptr(_) => bcx,
|
||||
ty::ty_struct(did, _) => {
|
||||
let tcx = bcx.tcx();
|
||||
let bcx = iter_structural_ty(bcx, v, t, take_ty);
|
||||
|
|
|
@ -2308,12 +2308,7 @@ pub fn type_contents(cx: ctxt, ty: t) -> TypeContents {
|
|||
ast::Many => TC_NONE
|
||||
};
|
||||
// Prevent noncopyable types captured in the environment from being copied.
|
||||
let ct = if cty.sigil == ast::ManagedSigil {
|
||||
TC_NONE
|
||||
} else {
|
||||
TC_NONCOPY_TRAIT
|
||||
};
|
||||
st + rt + ot + ct
|
||||
st + rt + ot + TC_NONCOPY_TRAIT
|
||||
}
|
||||
|
||||
fn trait_contents(store: TraitStore, mutbl: ast::Mutability,
|
||||
|
|
|
@ -400,6 +400,11 @@ pub fn ast_ty_to_ty<AC:AstConv, RS:RegionScope + Clone + 'static>(
|
|||
bf.abis, &bf.lifetimes, &bf.decl))
|
||||
}
|
||||
ast::ty_closure(ref f) => {
|
||||
if f.sigil == ast::ManagedSigil {
|
||||
tcx.sess.span_err(ast_ty.span,
|
||||
"managed closures are not supported");
|
||||
}
|
||||
|
||||
let bounds = conv_builtin_bounds(this.tcx(), &f.bounds, match f.sigil {
|
||||
// Use corresponding trait store to figure out default bounds
|
||||
// if none were specified.
|
||||
|
|
|
@ -33,6 +33,7 @@ use driver::driver::{compile_input};
|
|||
use driver::session;
|
||||
use middle::lint;
|
||||
|
||||
use std::comm;
|
||||
use std::io;
|
||||
use std::num;
|
||||
use std::os;
|
||||
|
@ -43,6 +44,7 @@ use std::vec;
|
|||
use extra::getopts::groups;
|
||||
use extra::getopts;
|
||||
use syntax::codemap;
|
||||
use syntax::diagnostic::Emitter;
|
||||
use syntax::diagnostic;
|
||||
|
||||
pub mod middle {
|
||||
|
@ -191,7 +193,7 @@ pub fn describe_debug_flags() {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn run_compiler(args: &[~str], demitter: diagnostic::Emitter) {
|
||||
pub fn run_compiler(args: &[~str], demitter: @diagnostic::Emitter) {
|
||||
// Don't display log spew by default. Can override with RUST_LOG.
|
||||
::std::logging::console_off();
|
||||
|
||||
|
@ -291,6 +293,23 @@ pub enum monitor_msg {
|
|||
done,
|
||||
}
|
||||
|
||||
struct RustcEmitter {
|
||||
ch_capture: comm::SharedChan<monitor_msg>
|
||||
}
|
||||
|
||||
impl diagnostic::Emitter for RustcEmitter {
|
||||
fn emit(&self,
|
||||
cmsp: Option<(@codemap::CodeMap, codemap::Span)>,
|
||||
msg: &str,
|
||||
lvl: diagnostic::level) {
|
||||
if lvl == diagnostic::fatal {
|
||||
self.ch_capture.send(fatal)
|
||||
}
|
||||
|
||||
diagnostic::DefaultEmitter.emit(cmsp, msg, lvl)
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
This is a sanity check that any failure of the compiler is performed
|
||||
through the diagnostic module and reported properly - we shouldn't be calling
|
||||
|
@ -303,7 +322,7 @@ diagnostic emitter which records when we hit a fatal error. If the task
|
|||
fails without recording a fatal error then we've encountered a compiler
|
||||
bug and need to present an error.
|
||||
*/
|
||||
pub fn monitor(f: ~fn(diagnostic::Emitter)) {
|
||||
pub fn monitor(f: ~fn(@diagnostic::Emitter)) {
|
||||
use std::comm::*;
|
||||
|
||||
// XXX: This is a hack for newsched since it doesn't support split stacks.
|
||||
|
@ -324,18 +343,11 @@ pub fn monitor(f: ~fn(diagnostic::Emitter)) {
|
|||
|
||||
match do task_builder.try {
|
||||
let ch = ch_capture.clone();
|
||||
let ch_capture = ch.clone();
|
||||
// The 'diagnostics emitter'. Every error, warning, etc. should
|
||||
// go through this function.
|
||||
let demitter: @fn(Option<(@codemap::CodeMap, codemap::Span)>,
|
||||
&str,
|
||||
diagnostic::level) =
|
||||
|cmsp, msg, lvl| {
|
||||
if lvl == diagnostic::fatal {
|
||||
ch_capture.send(fatal);
|
||||
}
|
||||
diagnostic::emit(cmsp, msg, lvl);
|
||||
};
|
||||
let demitter = @RustcEmitter {
|
||||
ch_capture: ch.clone(),
|
||||
} as @diagnostic::Emitter;
|
||||
|
||||
struct finally {
|
||||
ch: SharedChan<monitor_msg>,
|
||||
|
@ -357,7 +369,7 @@ pub fn monitor(f: ~fn(diagnostic::Emitter)) {
|
|||
result::Err(_) => {
|
||||
// Task failed without emitting a fatal diagnostic
|
||||
if p.recv() == done {
|
||||
diagnostic::emit(
|
||||
diagnostic::DefaultEmitter.emit(
|
||||
None,
|
||||
diagnostic::ice_msg("unexpected failure"),
|
||||
diagnostic::error);
|
||||
|
@ -370,7 +382,9 @@ pub fn monitor(f: ~fn(diagnostic::Emitter)) {
|
|||
to github.com/mozilla/rust/issues"
|
||||
];
|
||||
for note in xs.iter() {
|
||||
diagnostic::emit(None, *note, diagnostic::note)
|
||||
diagnostic::DefaultEmitter.emit(None,
|
||||
*note,
|
||||
diagnostic::note)
|
||||
}
|
||||
}
|
||||
// Fail so the process returns a failure code
|
||||
|
|
|
@ -60,12 +60,12 @@ pub fn field_exprs(fields: ~[ast::Field]) -> ~[@ast::Expr] {
|
|||
fields.map(|f| f.expr)
|
||||
}
|
||||
|
||||
struct LoopQueryVisitor {
|
||||
p: @fn(&ast::Expr_) -> bool
|
||||
struct LoopQueryVisitor<'self> {
|
||||
p: &'self fn(&ast::Expr_) -> bool
|
||||
}
|
||||
|
||||
impl Visitor<@mut bool> for LoopQueryVisitor {
|
||||
fn visit_expr(&mut self, e:@ast::Expr, flag:@mut bool) {
|
||||
impl<'self> Visitor<@mut bool> for LoopQueryVisitor<'self> {
|
||||
fn visit_expr(&mut self, e: @ast::Expr, flag: @mut bool) {
|
||||
*flag |= (self.p)(&e.node);
|
||||
match e.node {
|
||||
// Skip inner loops, since a break in the inner loop isn't a
|
||||
|
@ -78,19 +78,21 @@ impl Visitor<@mut bool> for LoopQueryVisitor {
|
|||
|
||||
// Takes a predicate p, returns true iff p is true for any subexpressions
|
||||
// of b -- skipping any inner loops (loop, while, loop_body)
|
||||
pub fn loop_query(b: &ast::Block, p: @fn(&ast::Expr_) -> bool) -> bool {
|
||||
pub fn loop_query(b: &ast::Block, p: &fn(&ast::Expr_) -> bool) -> bool {
|
||||
let rs = @mut false;
|
||||
let mut v = LoopQueryVisitor { p: p };
|
||||
let mut v = LoopQueryVisitor {
|
||||
p: p,
|
||||
};
|
||||
visit::walk_block(&mut v, b, rs);
|
||||
return *rs;
|
||||
}
|
||||
|
||||
struct BlockQueryVisitor {
|
||||
p: @fn(@ast::Expr) -> bool
|
||||
struct BlockQueryVisitor<'self> {
|
||||
p: &'self fn(@ast::Expr) -> bool
|
||||
}
|
||||
|
||||
impl Visitor<@mut bool> for BlockQueryVisitor {
|
||||
fn visit_expr(&mut self, e:@ast::Expr, flag:@mut bool) {
|
||||
impl<'self> Visitor<@mut bool> for BlockQueryVisitor<'self> {
|
||||
fn visit_expr(&mut self, e: @ast::Expr, flag: @mut bool) {
|
||||
*flag |= (self.p)(e);
|
||||
visit::walk_expr(self, e, flag)
|
||||
}
|
||||
|
@ -98,9 +100,11 @@ impl Visitor<@mut bool> for BlockQueryVisitor {
|
|||
|
||||
// Takes a predicate p, returns true iff p is true for any subexpressions
|
||||
// of b -- skipping any inner loops (loop, while, loop_body)
|
||||
pub fn block_query(b: &ast::Block, p: @fn(@ast::Expr) -> bool) -> bool {
|
||||
pub fn block_query(b: &ast::Block, p: &fn(@ast::Expr) -> bool) -> bool {
|
||||
let rs = @mut false;
|
||||
let mut v = BlockQueryVisitor { p: p };
|
||||
let mut v = BlockQueryVisitor {
|
||||
p: p,
|
||||
};
|
||||
visit::walk_block(&mut v, b, rs);
|
||||
return *rs;
|
||||
}
|
||||
|
|
|
@ -11,9 +11,10 @@
|
|||
use rustc;
|
||||
use rustc::{driver, middle};
|
||||
|
||||
use syntax;
|
||||
use syntax::parse;
|
||||
use syntax::ast;
|
||||
use syntax::diagnostic;
|
||||
use syntax::parse;
|
||||
use syntax;
|
||||
|
||||
use std::os;
|
||||
use std::local_data;
|
||||
|
@ -48,8 +49,10 @@ fn get_ast_and_resolve(cpath: &Path, libs: ~[Path]) -> DocContext {
|
|||
let span_diagnostic_handler =
|
||||
syntax::diagnostic::mk_span_handler(diagnostic_handler, parsesess.cm);
|
||||
|
||||
let sess = driver::driver::build_session_(sessopts, parsesess.cm,
|
||||
syntax::diagnostic::emit,
|
||||
let sess = driver::driver::build_session_(sessopts,
|
||||
parsesess.cm,
|
||||
@diagnostic::DefaultEmitter as
|
||||
@diagnostic::Emitter,
|
||||
span_diagnostic_handler);
|
||||
|
||||
let mut cfg = build_configuration(sess);
|
||||
|
|
|
@ -72,12 +72,14 @@ extern mod syntax;
|
|||
|
||||
use std::{libc, io, os, task};
|
||||
use std::cell::Cell;
|
||||
use extra::rl::CompletionCb;
|
||||
use extra::rl;
|
||||
|
||||
use rustc::driver::{driver, session};
|
||||
use rustc::back::link::jit;
|
||||
use syntax::{ast, diagnostic};
|
||||
use syntax::{ast, codemap, diagnostic};
|
||||
use syntax::ast_util::*;
|
||||
use syntax::diagnostic::Emitter;
|
||||
use syntax::parse::token;
|
||||
use syntax::print::pprust;
|
||||
|
||||
|
@ -107,6 +109,28 @@ enum CmdAction {
|
|||
action_run_line(~str),
|
||||
}
|
||||
|
||||
struct EncodableWarningEmitter;
|
||||
|
||||
impl diagnostic::Emitter for EncodableWarningEmitter {
|
||||
fn emit(&self,
|
||||
cm: Option<(@codemap::CodeMap, codemap::Span)>,
|
||||
msg: &str,
|
||||
lvl: diagnostic::level) {
|
||||
diagnostic::DefaultEmitter.emit(cm, msg, lvl);
|
||||
if msg.contains("failed to find an implementation of trait") &&
|
||||
msg.contains("extra::serialize::Encodable") {
|
||||
diagnostic::DefaultEmitter.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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Run an input string in a Repl, returning the new Repl.
|
||||
fn run(mut program: ~Program, binary: ~str, lib_search_paths: ~[~str],
|
||||
input: ~str) -> (~Program, Option<~jit::Engine>)
|
||||
|
@ -124,18 +148,9 @@ fn run(mut program: ~Program, binary: ~str, lib_search_paths: ~[~str],
|
|||
// 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 sess = driver::build_session(options,
|
||||
@EncodableWarningEmitter as
|
||||
@diagnostic::Emitter);
|
||||
let intr = token::get_ident_interner();
|
||||
|
||||
//
|
||||
|
@ -243,7 +258,9 @@ fn run(mut program: ~Program, binary: ~str, lib_search_paths: ~[~str],
|
|||
let input = driver::str_input(code.to_managed());
|
||||
let cfg = driver::build_configuration(sess);
|
||||
let outputs = driver::build_output_filenames(&input, &None, &None, [], sess);
|
||||
let sess = driver::build_session(options, diagnostic::emit);
|
||||
let sess = driver::build_session(options,
|
||||
@diagnostic::DefaultEmitter as
|
||||
@diagnostic::Emitter);
|
||||
|
||||
let crate = driver::phase_1_parse_input(sess, cfg.clone(), &input);
|
||||
let expanded_crate = driver::phase_2_configure_and_expand(sess, cfg, crate);
|
||||
|
@ -305,7 +322,9 @@ fn compile_crate(src_filename: ~str, binary: ~str) -> Option<bool> {
|
|||
.. (*session::basic_options()).clone()
|
||||
};
|
||||
let input = driver::file_input(src_path.clone());
|
||||
let sess = driver::build_session(options, diagnostic::emit);
|
||||
let sess = driver::build_session(options,
|
||||
@diagnostic::DefaultEmitter as
|
||||
@diagnostic::Emitter);
|
||||
*sess.building_library = true;
|
||||
let cfg = driver::build_configuration(sess);
|
||||
let outputs = driver::build_output_filenames(
|
||||
|
@ -502,6 +521,19 @@ pub fn main() {
|
|||
main_args(args);
|
||||
}
|
||||
|
||||
struct Completer;
|
||||
|
||||
impl CompletionCb for Completer {
|
||||
fn complete(&self, line: ~str, suggest: &fn(~str)) {
|
||||
if line.starts_with(":") {
|
||||
suggest(~":clear");
|
||||
suggest(~":exit");
|
||||
suggest(~":help");
|
||||
suggest(~":load");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn main_args(args: &[~str]) {
|
||||
#[fixed_stack_segment]; #[inline(never)];
|
||||
|
||||
|
@ -525,13 +557,8 @@ pub fn main_args(args: &[~str]) {
|
|||
println("unstable. If you encounter problems, please use the");
|
||||
println("compiler instead. Type :help for help.");
|
||||
|
||||
do rl::complete |line, suggest| {
|
||||
if line.starts_with(":") {
|
||||
suggest(~":clear");
|
||||
suggest(~":exit");
|
||||
suggest(~":help");
|
||||
suggest(~":load");
|
||||
}
|
||||
unsafe {
|
||||
rl::complete(@Completer as @CompletionCb)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -15,11 +15,11 @@ use syntax::print::pprust;
|
|||
use syntax::parse::token;
|
||||
use syntax::visit;
|
||||
|
||||
struct EachBindingVisitor {
|
||||
f: @fn(&ast::Path, ast::NodeId)
|
||||
struct EachBindingVisitor<'self> {
|
||||
f: &'self fn(&ast::Path, ast::NodeId)
|
||||
}
|
||||
|
||||
impl visit::Visitor<()> for EachBindingVisitor {
|
||||
impl<'self> visit::Visitor<()> for EachBindingVisitor<'self> {
|
||||
fn visit_pat(&mut self, pat:@ast::Pat, _:()) {
|
||||
match pat.node {
|
||||
ast::PatIdent(_, ref path, _) => {
|
||||
|
@ -32,7 +32,7 @@ impl visit::Visitor<()> for EachBindingVisitor {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn each_binding(l: @ast::Local, f: @fn(&ast::Path, ast::NodeId)) {
|
||||
pub fn each_binding(l: @ast::Local, f: &fn(&ast::Path, ast::NodeId)) {
|
||||
use syntax::visit::Visitor;
|
||||
|
||||
let mut vt = EachBindingVisitor{ f: f };
|
||||
|
|
|
@ -110,7 +110,9 @@ impl<'self> PkgScript<'self> {
|
|||
.. (*session::basic_options()).clone()
|
||||
};
|
||||
let input = driver::file_input(script.clone());
|
||||
let sess = driver::build_session(options, diagnostic::emit);
|
||||
let sess = driver::build_session(options,
|
||||
@diagnostic::DefaultEmitter as
|
||||
@diagnostic::Emitter);
|
||||
let cfg = driver::build_configuration(sess);
|
||||
let crate = driver::phase_1_parse_input(sess, cfg.clone(), &input);
|
||||
let crate = driver::phase_2_configure_and_expand(sess, cfg.clone(), crate);
|
||||
|
|
|
@ -1567,8 +1567,11 @@ fn test_linker_build() {
|
|||
let matches = getopts([], optgroups());
|
||||
let options = build_session_options(@"rustpkg",
|
||||
matches.get_ref(),
|
||||
diagnostic::emit);
|
||||
let sess = build_session(options, diagnostic::emit);
|
||||
@diagnostic::DefaultEmitter as
|
||||
@diagnostic::Emitter);
|
||||
let sess = build_session(options,
|
||||
@diagnostic::DefaultEmitter as
|
||||
@diagnostic::Emitter);
|
||||
command_line_test([test_sysroot().to_str(),
|
||||
~"install",
|
||||
~"--linker",
|
||||
|
|
|
@ -16,8 +16,11 @@ use extra::getopts::groups::getopts;
|
|||
use syntax::ast_util::*;
|
||||
use syntax::codemap::{dummy_sp, Spanned};
|
||||
use syntax::ext::base::ExtCtxt;
|
||||
use syntax::{ast, attr, codemap, diagnostic, fold};
|
||||
use syntax::{ast, attr, codemap, diagnostic, fold, visit};
|
||||
use syntax::attr::AttrMetaMethods;
|
||||
use syntax::fold::ast_fold;
|
||||
use syntax::visit::Visitor;
|
||||
use rustc::back::link::output_type_exe;
|
||||
use rustc::back::link;
|
||||
use rustc::driver::session::{lib_crate, bin_crate};
|
||||
use context::{in_target, StopBefore, Link, Assemble, BuildContext};
|
||||
|
@ -26,6 +29,7 @@ use package_source::PkgSrc;
|
|||
use workspace::pkg_parent_workspaces;
|
||||
use path_util::{installed_library_in_workspace, U_RWX, rust_path, system_library, target_build_dir};
|
||||
use messages::error;
|
||||
use conditions::nonexistent_package::cond;
|
||||
|
||||
pub use target::{OutputType, Main, Lib, Bench, Test, JustOne, lib_name_of, lib_crate_filename};
|
||||
use workcache_support::{digest_file_with_date, digest_only_date};
|
||||
|
@ -70,9 +74,8 @@ struct ReadyCtx {
|
|||
fns: ~[ListenerFn]
|
||||
}
|
||||
|
||||
fn fold_mod(_ctx: @mut ReadyCtx,
|
||||
m: &ast::_mod,
|
||||
fold: @fold::ast_fold) -> ast::_mod {
|
||||
fn fold_mod(_ctx: @mut ReadyCtx, m: &ast::_mod, fold: &CrateSetup)
|
||||
-> ast::_mod {
|
||||
fn strip_main(item: @ast::item) -> @ast::item {
|
||||
@ast::item {
|
||||
attrs: do item.attrs.iter().filter_map |attr| {
|
||||
|
@ -94,9 +97,8 @@ fn fold_mod(_ctx: @mut ReadyCtx,
|
|||
}, fold)
|
||||
}
|
||||
|
||||
fn fold_item(ctx: @mut ReadyCtx,
|
||||
item: @ast::item,
|
||||
fold: @fold::ast_fold) -> Option<@ast::item> {
|
||||
fn fold_item(ctx: @mut ReadyCtx, item: @ast::item, fold: &CrateSetup)
|
||||
-> Option<@ast::item> {
|
||||
ctx.path.push(item.ident);
|
||||
|
||||
let mut cmds = ~[];
|
||||
|
@ -134,6 +136,19 @@ fn fold_item(ctx: @mut ReadyCtx,
|
|||
res
|
||||
}
|
||||
|
||||
struct CrateSetup {
|
||||
ctx: @mut ReadyCtx,
|
||||
}
|
||||
|
||||
impl fold::ast_fold for CrateSetup {
|
||||
fn fold_item(&self, item: @ast::item) -> Option<@ast::item> {
|
||||
fold_item(self.ctx, item, self)
|
||||
}
|
||||
fn fold_mod(&self, module: &ast::_mod) -> ast::_mod {
|
||||
fold_mod(self.ctx, module, self)
|
||||
}
|
||||
}
|
||||
|
||||
/// Generate/filter main function, add the list of commands, etc.
|
||||
pub fn ready_crate(sess: session::Session,
|
||||
crate: @ast::Crate) -> @ast::Crate {
|
||||
|
@ -144,15 +159,9 @@ pub fn ready_crate(sess: session::Session,
|
|||
path: ~[],
|
||||
fns: ~[]
|
||||
};
|
||||
let precursor = @fold::AstFoldFns {
|
||||
// fold_crate: fold::wrap(|a, b| fold_crate(ctx, a, b)),
|
||||
fold_item: |a, b| fold_item(ctx, a, b),
|
||||
fold_mod: |a, b| fold_mod(ctx, a, b),
|
||||
.. *fold::default_ast_fold()
|
||||
let fold = CrateSetup {
|
||||
ctx: ctx,
|
||||
};
|
||||
|
||||
let fold = fold::make_fold(precursor);
|
||||
|
||||
@fold.fold_crate(crate)
|
||||
}
|
||||
|
||||
|
@ -225,7 +234,10 @@ pub fn compile_input(context: &BuildContext,
|
|||
maybe_sysroot: Some(sysroot_to_use),
|
||||
addl_lib_search_paths: @mut (~[]),
|
||||
output_type: output_type,
|
||||
.. (*driver::build_session_options(binary, &matches, diagnostic::emit)).clone()
|
||||
.. (*driver::build_session_options(binary,
|
||||
&matches,
|
||||
@diagnostic::DefaultEmitter as
|
||||
@diagnostic::Emitter)).clone()
|
||||
};
|
||||
|
||||
let addl_lib_search_paths = @mut options.addl_lib_search_paths;
|
||||
|
@ -240,7 +252,9 @@ pub fn compile_input(context: &BuildContext,
|
|||
}
|
||||
}
|
||||
|
||||
let sess = driver::build_session(options, diagnostic::emit);
|
||||
let sess = driver::build_session(options,
|
||||
@diagnostic::DefaultEmitter as
|
||||
@diagnostic::Emitter);
|
||||
|
||||
// Infer dependencies that rustpkg needs to build, by scanning for
|
||||
// `extern mod` directives.
|
||||
|
@ -383,31 +397,28 @@ pub fn compile_crate(ctxt: &BuildContext,
|
|||
compile_input(ctxt, exec, pkg_id, crate, workspace, flags, cfgs, opt, what)
|
||||
}
|
||||
|
||||
|
||||
/// Collect all `extern mod` directives in `c`, then
|
||||
/// try to install their targets, failing if any target
|
||||
/// can't be found.
|
||||
pub fn find_and_install_dependencies(context: &BuildContext,
|
||||
parent: &PkgId,
|
||||
struct ViewItemVisitor<'self> {
|
||||
context: &'self BuildContext,
|
||||
parent: &'self PkgId,
|
||||
sess: session::Session,
|
||||
exec: &mut workcache::Exec,
|
||||
c: &ast::Crate,
|
||||
save: @fn(Path)
|
||||
) {
|
||||
use conditions::nonexistent_package::cond;
|
||||
exec: &'self mut workcache::Exec,
|
||||
c: &'self ast::Crate,
|
||||
save: &'self fn(Path),
|
||||
}
|
||||
|
||||
do c.each_view_item() |vi: &ast::view_item| {
|
||||
impl<'self> Visitor<()> for ViewItemVisitor<'self> {
|
||||
fn visit_view_item(&mut self, vi: &ast::view_item, env: ()) {
|
||||
debug!("A view item!");
|
||||
match vi.node {
|
||||
// ignore metadata, I guess
|
||||
ast::view_item_extern_mod(lib_ident, path_opt, _, _) => {
|
||||
let lib_name = match path_opt {
|
||||
Some(p) => p,
|
||||
None => sess.str_of(lib_ident)
|
||||
None => self.sess.str_of(lib_ident)
|
||||
};
|
||||
debug!("Finding and installing... %s", lib_name);
|
||||
// Check standard Rust library path first
|
||||
match system_library(&context.sysroot(), lib_name) {
|
||||
match system_library(&self.context.sysroot(), lib_name) {
|
||||
Some(ref installed_path) => {
|
||||
debug!("It exists: %s", installed_path.to_str());
|
||||
// Say that [path for c] has a discovered dependency on
|
||||
|
@ -416,7 +427,8 @@ pub fn find_and_install_dependencies(context: &BuildContext,
|
|||
// I'm not sure what the right thing is.
|
||||
// Now we know that this crate has a discovered dependency on
|
||||
// installed_path
|
||||
exec.discover_input("binary", installed_path.to_str(),
|
||||
self.exec.discover_input("binary",
|
||||
installed_path.to_str(),
|
||||
digest_only_date(installed_path));
|
||||
}
|
||||
None => {
|
||||
|
@ -425,34 +437,43 @@ pub fn find_and_install_dependencies(context: &BuildContext,
|
|||
lib_name.to_str());
|
||||
// Try to install it
|
||||
let pkg_id = PkgId::new(lib_name);
|
||||
let workspaces = pkg_parent_workspaces(&context.context, &pkg_id);
|
||||
let workspaces = pkg_parent_workspaces(&self.context.context,
|
||||
&pkg_id);
|
||||
let dep_workspace = if workspaces.is_empty() {
|
||||
error(fmt!("Couldn't find package %s, which is needed by %s, \
|
||||
in any of the workspaces in the RUST_PATH (%?)",
|
||||
lib_name, parent.to_str(), rust_path()));
|
||||
lib_name,
|
||||
self.parent.to_str(),
|
||||
rust_path()));
|
||||
cond.raise((pkg_id.clone(), ~"Dependency not found"))
|
||||
}
|
||||
else {
|
||||
workspaces[0]
|
||||
};
|
||||
let (outputs_disc, inputs_disc) =
|
||||
context.install(PkgSrc::new(dep_workspace.clone(),
|
||||
false, pkg_id), &JustOne(Path(lib_crate_filename)));
|
||||
self.context.install(PkgSrc::new(dep_workspace.clone(),
|
||||
false,
|
||||
pkg_id),
|
||||
&JustOne(Path(
|
||||
lib_crate_filename)));
|
||||
debug!("Installed %s, returned %? dependencies and \
|
||||
%? transitive dependencies",
|
||||
lib_name, outputs_disc.len(), inputs_disc.len());
|
||||
for dep in outputs_disc.iter() {
|
||||
debug!("Discovering a binary input: %s", dep.to_str());
|
||||
exec.discover_input("binary", dep.to_str(),
|
||||
self.exec.discover_input("binary",
|
||||
dep.to_str(),
|
||||
digest_only_date(dep));
|
||||
}
|
||||
for &(ref what, ref dep) in inputs_disc.iter() {
|
||||
if *what == ~"file" {
|
||||
exec.discover_input(*what, *dep,
|
||||
self.exec.discover_input(*what,
|
||||
*dep,
|
||||
digest_file_with_date(&Path(*dep)));
|
||||
}
|
||||
else if *what == ~"binary" {
|
||||
exec.discover_input(*what, *dep,
|
||||
self.exec.discover_input(*what,
|
||||
*dep,
|
||||
digest_only_date(&Path(*dep)));
|
||||
}
|
||||
else {
|
||||
|
@ -468,14 +489,36 @@ pub fn find_and_install_dependencies(context: &BuildContext,
|
|||
let install_dir = installed_library.pop();
|
||||
debug!("Installed %s into %s [%?]", lib_name, install_dir.to_str(),
|
||||
datestamp(&installed_library));
|
||||
save(install_dir);
|
||||
(self.save)(install_dir);
|
||||
}
|
||||
}}
|
||||
// Ignore `use`s
|
||||
_ => ()
|
||||
}
|
||||
true
|
||||
|
||||
visit::walk_view_item(self, vi, env)
|
||||
}
|
||||
}
|
||||
|
||||
/// Collect all `extern mod` directives in `c`, then
|
||||
/// try to install their targets, failing if any target
|
||||
/// can't be found.
|
||||
pub fn find_and_install_dependencies(context: &BuildContext,
|
||||
parent: &PkgId,
|
||||
sess: session::Session,
|
||||
exec: &mut workcache::Exec,
|
||||
c: &ast::Crate,
|
||||
save: &fn(Path)) {
|
||||
debug!("In find_and_install_dependencies...");
|
||||
let mut visitor = ViewItemVisitor {
|
||||
context: context,
|
||||
parent: parent,
|
||||
sess: sess,
|
||||
exec: exec,
|
||||
c: c,
|
||||
save: save,
|
||||
};
|
||||
visit::walk_crate(&mut visitor, c, ())
|
||||
}
|
||||
|
||||
pub fn mk_string_lit(s: @str) -> ast::lit {
|
||||
|
|
|
@ -1846,31 +1846,38 @@ pub mod fsync {
|
|||
pub struct Arg<t> {
|
||||
val: t,
|
||||
opt_level: Option<Level>,
|
||||
fsync_fn: @fn(f: &t, Level) -> int,
|
||||
fsync_fn: extern "Rust" fn(f: &t, Level) -> int,
|
||||
}
|
||||
|
||||
// fsync file after executing blk
|
||||
// FIXME (#2004) find better way to create resources within lifetime of
|
||||
// outer res
|
||||
pub fn FILE_res_sync(file: &FILERes, opt_level: Option<Level>,
|
||||
pub fn FILE_res_sync(file: &FILERes,
|
||||
opt_level: Option<Level>,
|
||||
blk: &fn(v: Res<*libc::FILE>)) {
|
||||
blk(Res::new(Arg {
|
||||
val: file.f, opt_level: opt_level,
|
||||
fsync_fn: |file, l| fsync_fd(fileno(*file), l)
|
||||
val: file.f,
|
||||
opt_level: opt_level,
|
||||
fsync_fn: fsync_FILE,
|
||||
}));
|
||||
|
||||
fn fileno(stream: *libc::FILE) -> libc::c_int {
|
||||
#[fixed_stack_segment]; #[inline(never)];
|
||||
unsafe { libc::fileno(stream) }
|
||||
}
|
||||
|
||||
fn fsync_FILE(stream: &*libc::FILE, level: Level) -> int {
|
||||
fsync_fd(fileno(*stream), level)
|
||||
}
|
||||
}
|
||||
|
||||
// fsync fd after executing blk
|
||||
pub fn fd_res_sync(fd: &FdRes, opt_level: Option<Level>,
|
||||
blk: &fn(v: Res<fd_t>)) {
|
||||
blk(Res::new(Arg {
|
||||
val: fd.fd, opt_level: opt_level,
|
||||
fsync_fn: |fd, l| fsync_fd(*fd, l)
|
||||
val: fd.fd,
|
||||
opt_level: opt_level,
|
||||
fsync_fn: fsync_fd_helper,
|
||||
}));
|
||||
}
|
||||
|
||||
|
@ -1880,6 +1887,10 @@ pub mod fsync {
|
|||
os::fsync_fd(fd, level) as int
|
||||
}
|
||||
|
||||
fn fsync_fd_helper(fd_ptr: &libc::c_int, level: Level) -> int {
|
||||
fsync_fd(*fd_ptr, level)
|
||||
}
|
||||
|
||||
// Type of objects that may want to fsync
|
||||
pub trait FSyncable { fn fsync(&self, l: Level) -> int; }
|
||||
|
||||
|
@ -1887,10 +1898,15 @@ pub mod fsync {
|
|||
pub fn obj_sync(o: @FSyncable, opt_level: Option<Level>,
|
||||
blk: &fn(v: Res<@FSyncable>)) {
|
||||
blk(Res::new(Arg {
|
||||
val: o, opt_level: opt_level,
|
||||
fsync_fn: |o, l| (*o).fsync(l)
|
||||
val: o,
|
||||
opt_level: opt_level,
|
||||
fsync_fn: obj_fsync_fn,
|
||||
}));
|
||||
}
|
||||
|
||||
fn obj_fsync_fn(o: &@FSyncable, level: Level) -> int {
|
||||
(*o).fsync(level)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
|
|
|
@ -485,9 +485,11 @@ impl<V:TyVisitor + MovePtr> TyVisitor for MovePtrAdaptor<V> {
|
|||
}
|
||||
|
||||
fn visit_closure_ptr(&mut self, ck: uint) -> bool {
|
||||
self.align_to::<@fn()>();
|
||||
if ! self.inner.visit_closure_ptr(ck) { return false; }
|
||||
self.bump_past::<@fn()>();
|
||||
self.align_to::<~fn()>();
|
||||
if ! self.inner.visit_closure_ptr(ck) {
|
||||
return false
|
||||
}
|
||||
self.bump_past::<~fn()>();
|
||||
true
|
||||
}
|
||||
}
|
||||
|
|
|
@ -8,21 +8,21 @@
|
|||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
fn add(n: int) -> @fn(int) -> int {
|
||||
let result: @fn(int) -> int = |m| m + n;
|
||||
result
|
||||
/*!
|
||||
* Routines are like closures except that they own their arguments and can
|
||||
* only run once.
|
||||
*/
|
||||
|
||||
/// A routine that takes no arguments and returns nothing.
|
||||
pub trait Runnable {
|
||||
/// The entry point for the routine.
|
||||
fn run(~self);
|
||||
}
|
||||
|
||||
pub fn main()
|
||||
{
|
||||
assert_eq!(add(3)(4), 7);
|
||||
/// A convenience routine that does nothing.
|
||||
pub struct NoOpRunnable;
|
||||
|
||||
let add1 : @fn(int)->int = add(1);
|
||||
assert_eq!(add1(6), 7);
|
||||
|
||||
let add2 : &(@fn(int)->int) = &add(2);
|
||||
assert_eq!((*add2)(5), 7);
|
||||
|
||||
let add3 : &fn(int)->int = add(3);
|
||||
assert_eq!(add3(4), 7);
|
||||
impl Runnable for NoOpRunnable {
|
||||
fn run(~self) {}
|
||||
}
|
||||
|
|
@ -189,7 +189,7 @@ pub mod reflect;
|
|||
pub mod condition;
|
||||
pub mod logging;
|
||||
pub mod util;
|
||||
|
||||
pub mod routine;
|
||||
|
||||
/* Unsupported interfaces */
|
||||
|
||||
|
|
|
@ -158,11 +158,14 @@ pub mod ct {
|
|||
|
||||
// A fragment of the output sequence
|
||||
#[deriving(Eq)]
|
||||
pub enum Piece { PieceString(~str), PieceConv(Conv), }
|
||||
pub enum Piece {
|
||||
PieceString(~str),
|
||||
PieceConv(Conv),
|
||||
}
|
||||
|
||||
pub type ErrorFn = @fn(&str) -> !;
|
||||
pub type ErrorFn<'self> = &'self fn(&str) -> !;
|
||||
|
||||
pub fn parse_fmt_string(s: &str, err: ErrorFn) -> ~[Piece] {
|
||||
pub fn parse_fmt_string<'a>(s: &str, err: ErrorFn<'a>) -> ~[Piece] {
|
||||
fn push_slice(ps: &mut ~[Piece], s: &str, from: uint, to: uint) {
|
||||
if to > from {
|
||||
ps.push(PieceString(s.slice(from, to).to_owned()));
|
||||
|
@ -185,7 +188,10 @@ pub mod ct {
|
|||
i += 1;
|
||||
} else {
|
||||
push_slice(&mut pieces, s, h, i - 1);
|
||||
let Parsed {val, next} = parse_conversion(s, i, lim, err);
|
||||
let Parsed {
|
||||
val,
|
||||
next
|
||||
} = parse_conversion(s, i, lim, |s| err(s));
|
||||
pieces.push(val);
|
||||
i = next;
|
||||
}
|
||||
|
@ -224,8 +230,8 @@ pub mod ct {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn parse_conversion(s: &str, i: uint, lim: uint, err: ErrorFn) ->
|
||||
Parsed<Piece> {
|
||||
pub fn parse_conversion<'a>(s: &str, i: uint, lim: uint, err: ErrorFn<'a>)
|
||||
-> Parsed<Piece> {
|
||||
let param = parse_parameter(s, i, lim);
|
||||
// avoid copying ~[Flag] by destructuring
|
||||
let Parsed {val: flags_val, next: flags_next} = parse_flags(s,
|
||||
|
@ -308,8 +314,8 @@ pub mod ct {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn parse_type(s: &str, i: uint, lim: uint, err: ErrorFn) ->
|
||||
Parsed<Ty> {
|
||||
pub fn parse_type<'a>(s: &str, i: uint, lim: uint, err: ErrorFn<'a>)
|
||||
-> Parsed<Ty> {
|
||||
if i >= lim { err("missing type in conversion"); }
|
||||
|
||||
// FIXME (#2249): Do we really want two signed types here?
|
||||
|
|
|
@ -55,7 +55,6 @@ impl<'self,T> Finally<T> for &'self fn() -> T {
|
|||
}
|
||||
|
||||
finally_fn!(~fn() -> T)
|
||||
finally_fn!(@fn() -> T)
|
||||
finally_fn!(extern "Rust" fn() -> T)
|
||||
|
||||
struct Finallyalizer<'self> {
|
||||
|
@ -119,14 +118,3 @@ fn test_owned() {
|
|||
spawn_with_finalizer(owned);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_managed() {
|
||||
let i = @mut 10;
|
||||
let managed: @fn() -> int = || {
|
||||
let r = *i;
|
||||
*i += 10;
|
||||
r
|
||||
};
|
||||
assert_eq!(do managed.finally {}, 10);
|
||||
assert_eq!(*i, 20);
|
||||
}
|
||||
|
|
|
@ -12,7 +12,6 @@ use ast::*;
|
|||
use ast;
|
||||
use ast_util;
|
||||
use codemap::{Span, dummy_sp};
|
||||
use fold;
|
||||
use opt_vec;
|
||||
use parse::token;
|
||||
use visit::Visitor;
|
||||
|
@ -371,21 +370,6 @@ pub fn empty_generics() -> Generics {
|
|||
ty_params: opt_vec::Empty}
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// Assigning node ids
|
||||
|
||||
fn node_id_assigner(next_id: @fn() -> ast::NodeId) -> @fold::ast_fold {
|
||||
let precursor = @fold::AstFoldFns {
|
||||
new_id: |old_id| {
|
||||
assert_eq!(old_id, ast::DUMMY_NODE_ID);
|
||||
next_id()
|
||||
},
|
||||
..*fold::default_ast_fold()
|
||||
};
|
||||
|
||||
fold::make_fold(precursor)
|
||||
}
|
||||
|
||||
// ______________________________________________________________________
|
||||
// Enumerating the IDs which appear in an AST
|
||||
|
||||
|
@ -413,18 +397,22 @@ impl id_range {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn id_visitor(vfn: @fn(NodeId), pass_through_items: bool)
|
||||
pub fn id_visitor(operation: @IdVisitingOperation, pass_through_items: bool)
|
||||
-> @mut Visitor<()> {
|
||||
let visitor = @mut IdVisitor {
|
||||
visit_callback: vfn,
|
||||
operation: operation,
|
||||
pass_through_items: pass_through_items,
|
||||
visited_outermost: false,
|
||||
};
|
||||
visitor as @mut Visitor<()>
|
||||
}
|
||||
|
||||
pub trait IdVisitingOperation {
|
||||
fn visit_id(&self, node_id: NodeId);
|
||||
}
|
||||
|
||||
pub struct IdVisitor {
|
||||
visit_callback: @fn(NodeId),
|
||||
operation: @IdVisitingOperation,
|
||||
pass_through_items: bool,
|
||||
visited_outermost: bool,
|
||||
}
|
||||
|
@ -432,10 +420,10 @@ pub struct IdVisitor {
|
|||
impl IdVisitor {
|
||||
fn visit_generics_helper(&self, generics: &Generics) {
|
||||
for type_parameter in generics.ty_params.iter() {
|
||||
(self.visit_callback)(type_parameter.id)
|
||||
self.operation.visit_id(type_parameter.id)
|
||||
}
|
||||
for lifetime in generics.lifetimes.iter() {
|
||||
(self.visit_callback)(lifetime.id)
|
||||
self.operation.visit_id(lifetime.id)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -446,26 +434,26 @@ impl Visitor<()> for IdVisitor {
|
|||
_: Span,
|
||||
node_id: NodeId,
|
||||
env: ()) {
|
||||
(self.visit_callback)(node_id);
|
||||
self.operation.visit_id(node_id);
|
||||
visit::walk_mod(self, module, env)
|
||||
}
|
||||
|
||||
fn visit_view_item(&mut self, view_item: &view_item, env: ()) {
|
||||
match view_item.node {
|
||||
view_item_extern_mod(_, _, _, node_id) => {
|
||||
(self.visit_callback)(node_id)
|
||||
self.operation.visit_id(node_id)
|
||||
}
|
||||
view_item_use(ref view_paths) => {
|
||||
for view_path in view_paths.iter() {
|
||||
match view_path.node {
|
||||
view_path_simple(_, _, node_id) |
|
||||
view_path_glob(_, node_id) => {
|
||||
(self.visit_callback)(node_id)
|
||||
self.operation.visit_id(node_id)
|
||||
}
|
||||
view_path_list(_, ref paths, node_id) => {
|
||||
(self.visit_callback)(node_id);
|
||||
self.operation.visit_id(node_id);
|
||||
for path in paths.iter() {
|
||||
(self.visit_callback)(path.node.id)
|
||||
self.operation.visit_id(path.node.id)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -476,7 +464,7 @@ impl Visitor<()> for IdVisitor {
|
|||
}
|
||||
|
||||
fn visit_foreign_item(&mut self, foreign_item: @foreign_item, env: ()) {
|
||||
(self.visit_callback)(foreign_item.id);
|
||||
self.operation.visit_id(foreign_item.id);
|
||||
visit::walk_foreign_item(self, foreign_item, env)
|
||||
}
|
||||
|
||||
|
@ -489,11 +477,11 @@ impl Visitor<()> for IdVisitor {
|
|||
}
|
||||
}
|
||||
|
||||
(self.visit_callback)(item.id);
|
||||
self.operation.visit_id(item.id);
|
||||
match item.node {
|
||||
item_enum(ref enum_definition, _) => {
|
||||
for variant in enum_definition.variants.iter() {
|
||||
(self.visit_callback)(variant.node.id)
|
||||
self.operation.visit_id(variant.node.id)
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
|
@ -505,22 +493,22 @@ impl Visitor<()> for IdVisitor {
|
|||
}
|
||||
|
||||
fn visit_local(&mut self, local: @Local, env: ()) {
|
||||
(self.visit_callback)(local.id);
|
||||
self.operation.visit_id(local.id);
|
||||
visit::walk_local(self, local, env)
|
||||
}
|
||||
|
||||
fn visit_block(&mut self, block: &Block, env: ()) {
|
||||
(self.visit_callback)(block.id);
|
||||
self.operation.visit_id(block.id);
|
||||
visit::walk_block(self, block, env)
|
||||
}
|
||||
|
||||
fn visit_stmt(&mut self, statement: @Stmt, env: ()) {
|
||||
(self.visit_callback)(ast_util::stmt_id(statement));
|
||||
self.operation.visit_id(ast_util::stmt_id(statement));
|
||||
visit::walk_stmt(self, statement, env)
|
||||
}
|
||||
|
||||
fn visit_pat(&mut self, pattern: @Pat, env: ()) {
|
||||
(self.visit_callback)(pattern.id);
|
||||
self.operation.visit_id(pattern.id);
|
||||
visit::walk_pat(self, pattern, env)
|
||||
}
|
||||
|
||||
|
@ -529,17 +517,17 @@ impl Visitor<()> for IdVisitor {
|
|||
{
|
||||
let optional_callee_id = expression.get_callee_id();
|
||||
for callee_id in optional_callee_id.iter() {
|
||||
(self.visit_callback)(*callee_id)
|
||||
self.operation.visit_id(*callee_id)
|
||||
}
|
||||
}
|
||||
(self.visit_callback)(expression.id);
|
||||
self.operation.visit_id(expression.id);
|
||||
visit::walk_expr(self, expression, env)
|
||||
}
|
||||
|
||||
fn visit_ty(&mut self, typ: &Ty, env: ()) {
|
||||
(self.visit_callback)(typ.id);
|
||||
self.operation.visit_id(typ.id);
|
||||
match typ.node {
|
||||
ty_path(_, _, id) => (self.visit_callback)(id),
|
||||
ty_path(_, _, id) => self.operation.visit_id(id),
|
||||
_ => {}
|
||||
}
|
||||
visit::walk_ty(self, typ, env)
|
||||
|
@ -565,21 +553,21 @@ impl Visitor<()> for IdVisitor {
|
|||
}
|
||||
}
|
||||
|
||||
(self.visit_callback)(node_id);
|
||||
self.operation.visit_id(node_id);
|
||||
|
||||
match *function_kind {
|
||||
visit::fk_item_fn(_, generics, _, _) => {
|
||||
self.visit_generics_helper(generics)
|
||||
}
|
||||
visit::fk_method(_, generics, method) => {
|
||||
(self.visit_callback)(method.self_id);
|
||||
self.operation.visit_id(method.self_id);
|
||||
self.visit_generics_helper(generics)
|
||||
}
|
||||
visit::fk_anon(_) | visit::fk_fn_block => {}
|
||||
}
|
||||
|
||||
for argument in function_declaration.inputs.iter() {
|
||||
(self.visit_callback)(argument.id)
|
||||
self.operation.visit_id(argument.id)
|
||||
}
|
||||
|
||||
visit::walk_fn(self,
|
||||
|
@ -599,25 +587,36 @@ impl Visitor<()> for IdVisitor {
|
|||
}
|
||||
|
||||
fn visit_struct_field(&mut self, struct_field: @struct_field, env: ()) {
|
||||
(self.visit_callback)(struct_field.node.id);
|
||||
self.operation.visit_id(struct_field.node.id);
|
||||
visit::walk_struct_field(self, struct_field, env)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn visit_ids_for_inlined_item(item: &inlined_item, vfn: @fn(NodeId)) {
|
||||
pub fn visit_ids_for_inlined_item(item: &inlined_item,
|
||||
operation: @IdVisitingOperation) {
|
||||
let mut id_visitor = IdVisitor {
|
||||
visit_callback: vfn,
|
||||
operation: operation,
|
||||
pass_through_items: true,
|
||||
visited_outermost: false,
|
||||
};
|
||||
item.accept((), &mut id_visitor);
|
||||
}
|
||||
|
||||
pub fn compute_id_range(visit_ids_fn: &fn(@fn(NodeId))) -> id_range {
|
||||
let result = @mut id_range::max();
|
||||
do visit_ids_fn |id| {
|
||||
result.add(id);
|
||||
struct IdRangeComputingVisitor {
|
||||
result: @mut id_range,
|
||||
}
|
||||
|
||||
impl IdVisitingOperation for IdRangeComputingVisitor {
|
||||
fn visit_id(&self, id: NodeId) {
|
||||
self.result.add(id)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn compute_id_range(visit_ids_fn: &fn(@IdVisitingOperation)) -> id_range {
|
||||
let result = @mut id_range::max();
|
||||
visit_ids_fn(@IdRangeComputingVisitor {
|
||||
result: result,
|
||||
} as @IdVisitingOperation);
|
||||
*result
|
||||
}
|
||||
|
||||
|
|
|
@ -15,9 +15,12 @@ use std::io;
|
|||
use std::local_data;
|
||||
use extra::term;
|
||||
|
||||
pub type Emitter = @fn(cmsp: Option<(@codemap::CodeMap, Span)>,
|
||||
pub trait Emitter {
|
||||
fn emit(&self,
|
||||
cmsp: Option<(@codemap::CodeMap, Span)>,
|
||||
msg: &str,
|
||||
lvl: level);
|
||||
}
|
||||
|
||||
// a handler deals with errors; certain errors
|
||||
// (fatal, bug, unimpl) may cause immediate exit,
|
||||
|
@ -55,7 +58,7 @@ pub trait span_handler {
|
|||
|
||||
struct HandlerT {
|
||||
err_count: uint,
|
||||
emit: Emitter,
|
||||
emit: @Emitter,
|
||||
}
|
||||
|
||||
struct CodemapT {
|
||||
|
@ -91,11 +94,11 @@ impl span_handler for CodemapT {
|
|||
|
||||
impl handler for HandlerT {
|
||||
fn fatal(@mut self, msg: &str) -> ! {
|
||||
(self.emit)(None, msg, fatal);
|
||||
self.emit.emit(None, msg, fatal);
|
||||
fail!();
|
||||
}
|
||||
fn err(@mut self, msg: &str) {
|
||||
(self.emit)(None, msg, error);
|
||||
self.emit.emit(None, msg, error);
|
||||
self.bump_err_count();
|
||||
}
|
||||
fn bump_err_count(@mut self) {
|
||||
|
@ -120,10 +123,10 @@ impl handler for HandlerT {
|
|||
self.fatal(s);
|
||||
}
|
||||
fn warn(@mut self, msg: &str) {
|
||||
(self.emit)(None, msg, warning);
|
||||
self.emit.emit(None, msg, warning);
|
||||
}
|
||||
fn note(@mut self, msg: &str) {
|
||||
(self.emit)(None, msg, note);
|
||||
self.emit.emit(None, msg, note);
|
||||
}
|
||||
fn bug(@mut self, msg: &str) -> ! {
|
||||
self.fatal(ice_msg(msg));
|
||||
|
@ -135,7 +138,7 @@ impl handler for HandlerT {
|
|||
cmsp: Option<(@codemap::CodeMap, Span)>,
|
||||
msg: &str,
|
||||
lvl: level) {
|
||||
(self.emit)(cmsp, msg, lvl);
|
||||
self.emit.emit(cmsp, msg, lvl);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -145,19 +148,22 @@ pub fn ice_msg(msg: &str) -> ~str {
|
|||
|
||||
pub fn mk_span_handler(handler: @mut handler, cm: @codemap::CodeMap)
|
||||
-> @mut span_handler {
|
||||
@mut CodemapT { handler: handler, cm: cm } as @mut span_handler
|
||||
@mut CodemapT {
|
||||
handler: handler,
|
||||
cm: cm,
|
||||
} as @mut span_handler
|
||||
}
|
||||
|
||||
pub fn mk_handler(emitter: Option<Emitter>) -> @mut handler {
|
||||
let emit: Emitter = match emitter {
|
||||
pub fn mk_handler(emitter: Option<@Emitter>) -> @mut handler {
|
||||
let emit: @Emitter = match emitter {
|
||||
Some(e) => e,
|
||||
None => {
|
||||
let emit: Emitter = |cmsp, msg, t| emit(cmsp, msg, t);
|
||||
emit
|
||||
}
|
||||
None => @DefaultEmitter as @Emitter
|
||||
};
|
||||
|
||||
@mut HandlerT { err_count: 0, emit: emit } as @mut handler
|
||||
@mut HandlerT {
|
||||
err_count: 0,
|
||||
emit: emit,
|
||||
} as @mut handler
|
||||
}
|
||||
|
||||
#[deriving(Eq)]
|
||||
|
@ -230,14 +236,13 @@ fn print_diagnostic(topic: &str, lvl: level, msg: &str) {
|
|||
print_maybe_styled(fmt!("%s\n", msg), term::attr::Bold);
|
||||
}
|
||||
|
||||
pub fn collect(messages: @mut ~[~str])
|
||||
-> @fn(Option<(@codemap::CodeMap, Span)>, &str, level) {
|
||||
let f: @fn(Option<(@codemap::CodeMap, Span)>, &str, level) =
|
||||
|_o, msg: &str, _l| { messages.push(msg.to_str()); };
|
||||
f
|
||||
}
|
||||
pub struct DefaultEmitter;
|
||||
|
||||
pub fn emit(cmsp: Option<(@codemap::CodeMap, Span)>, msg: &str, lvl: level) {
|
||||
impl Emitter for DefaultEmitter {
|
||||
fn emit(&self,
|
||||
cmsp: Option<(@codemap::CodeMap, Span)>,
|
||||
msg: &str,
|
||||
lvl: level) {
|
||||
match cmsp {
|
||||
Some((cm, sp)) => {
|
||||
let sp = cm.adjust_span(sp);
|
||||
|
@ -247,14 +252,14 @@ pub fn emit(cmsp: Option<(@codemap::CodeMap, Span)>, msg: &str, lvl: level) {
|
|||
highlight_lines(cm, sp, lvl, lines);
|
||||
print_macro_backtrace(cm, sp);
|
||||
}
|
||||
None => {
|
||||
print_diagnostic("", lvl, msg);
|
||||
None => print_diagnostic("", lvl, msg),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn highlight_lines(cm: @codemap::CodeMap,
|
||||
sp: Span, lvl: level,
|
||||
sp: Span,
|
||||
lvl: level,
|
||||
lines: @codemap::FileLines) {
|
||||
let fm = lines.file;
|
||||
|
||||
|
|
|
@ -33,62 +33,120 @@ pub struct MacroDef {
|
|||
ext: SyntaxExtension
|
||||
}
|
||||
|
||||
// No context arg for an Item Decorator macro, simply because
|
||||
// adding it would require adding a ctxt field to all items.
|
||||
// we could do this if it turns out to be useful.
|
||||
|
||||
pub type ItemDecoratorFun = @fn(@ExtCtxt,
|
||||
pub type ItemDecorator = extern "Rust" fn(@ExtCtxt,
|
||||
Span,
|
||||
@ast::MetaItem,
|
||||
~[@ast::item])
|
||||
-> ~[@ast::item];
|
||||
|
||||
pub type SyntaxExpanderTTFun = @fn(@ExtCtxt,
|
||||
Span,
|
||||
&[ast::token_tree],
|
||||
ast::SyntaxContext)
|
||||
pub struct SyntaxExpanderTT {
|
||||
expander: SyntaxExpanderTTExpander,
|
||||
span: Option<Span>
|
||||
}
|
||||
|
||||
pub trait SyntaxExpanderTTTrait {
|
||||
fn expand(&self,
|
||||
ecx: @ExtCtxt,
|
||||
span: Span,
|
||||
token_tree: &[ast::token_tree],
|
||||
context: ast::SyntaxContext)
|
||||
-> MacResult;
|
||||
}
|
||||
|
||||
pub type SyntaxExpanderTTFunNoCtxt =
|
||||
extern "Rust" fn(ecx: @ExtCtxt,
|
||||
span: codemap::Span,
|
||||
token_tree: &[ast::token_tree])
|
||||
-> MacResult;
|
||||
|
||||
pub type SyntaxExpanderTTItemFun = @fn(@ExtCtxt,
|
||||
enum SyntaxExpanderTTExpander {
|
||||
SyntaxExpanderTTExpanderWithoutContext(SyntaxExpanderTTFunNoCtxt),
|
||||
}
|
||||
|
||||
impl SyntaxExpanderTTTrait for SyntaxExpanderTT {
|
||||
fn expand(&self,
|
||||
ecx: @ExtCtxt,
|
||||
span: Span,
|
||||
token_tree: &[ast::token_tree],
|
||||
_: ast::SyntaxContext)
|
||||
-> MacResult {
|
||||
match self.expander {
|
||||
SyntaxExpanderTTExpanderWithoutContext(f) => {
|
||||
f(ecx, span, token_tree)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
enum SyntaxExpanderTTItemExpander {
|
||||
SyntaxExpanderTTItemExpanderWithContext(SyntaxExpanderTTItemFun),
|
||||
SyntaxExpanderTTItemExpanderWithoutContext(SyntaxExpanderTTItemFunNoCtxt),
|
||||
}
|
||||
|
||||
pub struct SyntaxExpanderTTItem {
|
||||
expander: SyntaxExpanderTTItemExpander,
|
||||
span: Option<Span>
|
||||
}
|
||||
|
||||
pub trait SyntaxExpanderTTItemTrait {
|
||||
fn expand(&self,
|
||||
cx: @ExtCtxt,
|
||||
sp: Span,
|
||||
ident: ast::Ident,
|
||||
token_tree: ~[ast::token_tree],
|
||||
context: ast::SyntaxContext)
|
||||
-> MacResult;
|
||||
}
|
||||
|
||||
impl SyntaxExpanderTTItemTrait for SyntaxExpanderTTItem {
|
||||
fn expand(&self,
|
||||
cx: @ExtCtxt,
|
||||
sp: Span,
|
||||
ident: ast::Ident,
|
||||
token_tree: ~[ast::token_tree],
|
||||
context: ast::SyntaxContext)
|
||||
-> MacResult {
|
||||
match self.expander {
|
||||
SyntaxExpanderTTItemExpanderWithContext(fun) => {
|
||||
fun(cx, sp, ident, token_tree, context)
|
||||
}
|
||||
SyntaxExpanderTTItemExpanderWithoutContext(fun) => {
|
||||
fun(cx, sp, ident, token_tree)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub type SyntaxExpanderTTItemFun = extern "Rust" fn(@ExtCtxt,
|
||||
Span,
|
||||
ast::Ident,
|
||||
~[ast::token_tree],
|
||||
ast::SyntaxContext)
|
||||
-> MacResult;
|
||||
|
||||
// oog... in order to make the presentation of builtin_normal_tt_no_ctxt
|
||||
// and builtin_ident_tt_no_ctxt palatable, we need one-off types for
|
||||
// functions that don't consume a ctxt:
|
||||
|
||||
pub type SyntaxExpanderTTFunNoCtxt = @fn(@ExtCtxt,
|
||||
Span,
|
||||
&[ast::token_tree])
|
||||
pub type SyntaxExpanderTTItemFunNoCtxt =
|
||||
extern "Rust" fn(@ExtCtxt, Span, ast::Ident, ~[ast::token_tree])
|
||||
-> MacResult;
|
||||
|
||||
pub type SyntaxExpanderTTItemFunNoCtxt = @fn(@ExtCtxt,
|
||||
Span,
|
||||
ast::Ident,
|
||||
~[ast::token_tree])
|
||||
-> MacResult;
|
||||
|
||||
|
||||
pub trait AnyMacro {
|
||||
fn make_expr(&self) -> @ast::Expr;
|
||||
fn make_item(&self) -> Option<@ast::item>;
|
||||
fn make_stmt(&self) -> @ast::Stmt;
|
||||
}
|
||||
|
||||
pub enum MacResult {
|
||||
MRExpr(@ast::Expr),
|
||||
MRItem(@ast::item),
|
||||
MRAny(@fn() -> @ast::Expr,
|
||||
@fn() -> Option<@ast::item>,
|
||||
@fn() -> @ast::Stmt),
|
||||
MRDef(MacroDef)
|
||||
MRAny(@AnyMacro),
|
||||
MRDef(MacroDef),
|
||||
}
|
||||
|
||||
pub enum SyntaxExtension {
|
||||
|
||||
// #[auto_encode] and such
|
||||
ItemDecorator(ItemDecoratorFun),
|
||||
ItemDecorator(ItemDecorator),
|
||||
|
||||
// Token-tree expanders
|
||||
NormalTT(SyntaxExpanderTTFun, Option<Span>),
|
||||
NormalTT(@SyntaxExpanderTTTrait, Option<Span>),
|
||||
|
||||
// An IdentTT is a macro that has an
|
||||
// identifier in between the name of the
|
||||
|
@ -98,7 +156,7 @@ pub enum SyntaxExtension {
|
|||
|
||||
// perhaps macro_rules! will lose its odd special identifier argument,
|
||||
// and this can go away also
|
||||
IdentTT(SyntaxExpanderTTItemFun, Option<Span>),
|
||||
IdentTT(@SyntaxExpanderTTItemTrait, Option<Span>),
|
||||
}
|
||||
|
||||
|
||||
|
@ -133,16 +191,22 @@ type RenameList = ~[(ast::Ident,Name)];
|
|||
// AST nodes into full ASTs
|
||||
pub fn syntax_expander_table() -> SyntaxEnv {
|
||||
// utility function to simplify creating NormalTT syntax extensions
|
||||
// that ignore their contexts
|
||||
fn builtin_normal_tt_no_ctxt(f: SyntaxExpanderTTFunNoCtxt) -> @Transformer {
|
||||
let wrapped_expander : SyntaxExpanderTTFun = |a,b,c,_d|{f(a,b,c)};
|
||||
@SE(NormalTT(wrapped_expander, None))
|
||||
fn builtin_normal_tt_no_ctxt(f: SyntaxExpanderTTFunNoCtxt)
|
||||
-> @Transformer {
|
||||
@SE(NormalTT(@SyntaxExpanderTT{
|
||||
expander: SyntaxExpanderTTExpanderWithoutContext(f),
|
||||
span: None,
|
||||
} as @SyntaxExpanderTTTrait,
|
||||
None))
|
||||
}
|
||||
// utility function to simplify creating IdentTT syntax extensions
|
||||
// that ignore their contexts
|
||||
fn builtin_item_tt_no_ctxt(f: SyntaxExpanderTTItemFunNoCtxt) -> @Transformer {
|
||||
let wrapped_expander : SyntaxExpanderTTItemFun = |a,b,c,d,_e|{f(a,b,c,d)};
|
||||
@SE(IdentTT(wrapped_expander, None))
|
||||
@SE(IdentTT(@SyntaxExpanderTTItem {
|
||||
expander: SyntaxExpanderTTItemExpanderWithoutContext(f),
|
||||
span: None,
|
||||
} as @SyntaxExpanderTTItemTrait,
|
||||
None))
|
||||
}
|
||||
let mut syntax_expanders = HashMap::new();
|
||||
// NB identifier starts with space, and can't conflict with legal idents
|
||||
|
@ -152,11 +216,18 @@ pub fn syntax_expander_table() -> SyntaxEnv {
|
|||
pending_renames : @mut ~[]
|
||||
}));
|
||||
syntax_expanders.insert(intern(&"macro_rules"),
|
||||
@SE(IdentTT(ext::tt::macro_rules::add_new_extension, None)));
|
||||
@SE(IdentTT(@SyntaxExpanderTTItem {
|
||||
expander: SyntaxExpanderTTItemExpanderWithContext(
|
||||
ext::tt::macro_rules::add_new_extension),
|
||||
span: None,
|
||||
} as @SyntaxExpanderTTItemTrait,
|
||||
None)));
|
||||
syntax_expanders.insert(intern(&"fmt"),
|
||||
builtin_normal_tt_no_ctxt(ext::fmt::expand_syntax_ext));
|
||||
builtin_normal_tt_no_ctxt(
|
||||
ext::fmt::expand_syntax_ext));
|
||||
syntax_expanders.insert(intern(&"format_args"),
|
||||
builtin_normal_tt_no_ctxt(ext::format::expand_args));
|
||||
builtin_normal_tt_no_ctxt(
|
||||
ext::format::expand_args));
|
||||
syntax_expanders.insert(
|
||||
intern(&"auto_encode"),
|
||||
@SE(ItemDecorator(ext::auto_encode::expand_auto_encode)));
|
||||
|
@ -164,11 +235,14 @@ pub fn syntax_expander_table() -> SyntaxEnv {
|
|||
intern(&"auto_decode"),
|
||||
@SE(ItemDecorator(ext::auto_encode::expand_auto_decode)));
|
||||
syntax_expanders.insert(intern(&"env"),
|
||||
builtin_normal_tt_no_ctxt(ext::env::expand_env));
|
||||
builtin_normal_tt_no_ctxt(
|
||||
ext::env::expand_env));
|
||||
syntax_expanders.insert(intern(&"option_env"),
|
||||
builtin_normal_tt_no_ctxt(ext::env::expand_option_env));
|
||||
builtin_normal_tt_no_ctxt(
|
||||
ext::env::expand_option_env));
|
||||
syntax_expanders.insert(intern("bytes"),
|
||||
builtin_normal_tt_no_ctxt(ext::bytes::expand_syntax_ext));
|
||||
builtin_normal_tt_no_ctxt(
|
||||
ext::bytes::expand_syntax_ext));
|
||||
syntax_expanders.insert(intern("concat_idents"),
|
||||
builtin_normal_tt_no_ctxt(
|
||||
ext::concat_idents::expand_syntax_ext));
|
||||
|
@ -184,15 +258,20 @@ pub fn syntax_expander_table() -> SyntaxEnv {
|
|||
builtin_normal_tt_no_ctxt(
|
||||
ext::quote::expand_quote_tokens));
|
||||
syntax_expanders.insert(intern(&"quote_expr"),
|
||||
builtin_normal_tt_no_ctxt(ext::quote::expand_quote_expr));
|
||||
builtin_normal_tt_no_ctxt(
|
||||
ext::quote::expand_quote_expr));
|
||||
syntax_expanders.insert(intern(&"quote_ty"),
|
||||
builtin_normal_tt_no_ctxt(ext::quote::expand_quote_ty));
|
||||
builtin_normal_tt_no_ctxt(
|
||||
ext::quote::expand_quote_ty));
|
||||
syntax_expanders.insert(intern(&"quote_item"),
|
||||
builtin_normal_tt_no_ctxt(ext::quote::expand_quote_item));
|
||||
builtin_normal_tt_no_ctxt(
|
||||
ext::quote::expand_quote_item));
|
||||
syntax_expanders.insert(intern(&"quote_pat"),
|
||||
builtin_normal_tt_no_ctxt(ext::quote::expand_quote_pat));
|
||||
builtin_normal_tt_no_ctxt(
|
||||
ext::quote::expand_quote_pat));
|
||||
syntax_expanders.insert(intern(&"quote_stmt"),
|
||||
builtin_normal_tt_no_ctxt(ext::quote::expand_quote_stmt));
|
||||
builtin_normal_tt_no_ctxt(
|
||||
ext::quote::expand_quote_stmt));
|
||||
|
||||
syntax_expanders.insert(intern(&"line"),
|
||||
builtin_normal_tt_no_ctxt(
|
||||
|
@ -219,12 +298,14 @@ pub fn syntax_expander_table() -> SyntaxEnv {
|
|||
builtin_normal_tt_no_ctxt(
|
||||
ext::source_util::expand_mod));
|
||||
syntax_expanders.insert(intern(&"asm"),
|
||||
builtin_normal_tt_no_ctxt(ext::asm::expand_asm));
|
||||
builtin_normal_tt_no_ctxt(
|
||||
ext::asm::expand_asm));
|
||||
syntax_expanders.insert(intern(&"cfg"),
|
||||
builtin_normal_tt_no_ctxt(ext::cfg::expand_cfg));
|
||||
syntax_expanders.insert(
|
||||
intern(&"trace_macros"),
|
||||
builtin_normal_tt_no_ctxt(ext::trace_macros::expand_trace_macros));
|
||||
builtin_normal_tt_no_ctxt(
|
||||
ext::cfg::expand_cfg));
|
||||
syntax_expanders.insert(intern(&"trace_macros"),
|
||||
builtin_normal_tt_no_ctxt(
|
||||
ext::trace_macros::expand_trace_macros));
|
||||
MapChain::new(~syntax_expanders)
|
||||
}
|
||||
|
||||
|
|
|
@ -15,6 +15,7 @@ use ast_util;
|
|||
use codemap::{Span, respan, dummy_sp};
|
||||
use ext::base::ExtCtxt;
|
||||
use ext::quote::rt::*;
|
||||
use fold;
|
||||
use opt_vec;
|
||||
use opt_vec::OptVec;
|
||||
|
||||
|
@ -862,3 +863,32 @@ impl AstBuilder for @ExtCtxt {
|
|||
ast::view_path_glob(self.path(sp, path), ast::DUMMY_NODE_ID))])
|
||||
}
|
||||
}
|
||||
|
||||
struct Duplicator {
|
||||
cx: @ExtCtxt,
|
||||
}
|
||||
|
||||
impl fold::ast_fold for Duplicator {
|
||||
fn new_id(&self, _: NodeId) -> NodeId {
|
||||
ast::DUMMY_NODE_ID
|
||||
}
|
||||
}
|
||||
|
||||
pub trait Duplicate {
|
||||
//
|
||||
// Duplication functions
|
||||
//
|
||||
// These functions just duplicate AST nodes.
|
||||
//
|
||||
|
||||
fn duplicate(&self, cx: @ExtCtxt) -> Self;
|
||||
}
|
||||
|
||||
impl Duplicate for @ast::Expr {
|
||||
fn duplicate(&self, cx: @ExtCtxt) -> @ast::Expr {
|
||||
let folder = @Duplicator {
|
||||
cx: cx,
|
||||
} as @fold::ast_fold;
|
||||
folder.fold_expr(*self)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -10,7 +10,7 @@
|
|||
|
||||
use ast::{Block, Crate, DeclLocal, Expr_, ExprMac, SyntaxContext};
|
||||
use ast::{Local, Ident, mac_invoc_tt};
|
||||
use ast::{item_mac, Mrk, Stmt_, StmtDecl, StmtMac, StmtExpr, StmtSemi};
|
||||
use ast::{item_mac, Mrk, Stmt, StmtDecl, StmtMac, StmtExpr, StmtSemi};
|
||||
use ast::{token_tree};
|
||||
use ast;
|
||||
use ast_util::{mtwt_outer_mark, new_rename, new_mark};
|
||||
|
@ -21,6 +21,7 @@ use codemap;
|
|||
use codemap::{Span, Spanned, ExpnInfo, NameAndSpan};
|
||||
use ext::base::*;
|
||||
use fold::*;
|
||||
use opt_vec;
|
||||
use parse;
|
||||
use parse::{parse_item_from_source_str};
|
||||
use parse::token;
|
||||
|
@ -32,12 +33,10 @@ use std::vec;
|
|||
|
||||
pub fn expand_expr(extsbox: @mut SyntaxEnv,
|
||||
cx: @ExtCtxt,
|
||||
e: &Expr_,
|
||||
span: Span,
|
||||
fld: @ast_fold,
|
||||
orig: @fn(&Expr_, Span, @ast_fold) -> (Expr_, Span))
|
||||
-> (Expr_, Span) {
|
||||
match *e {
|
||||
e: @ast::Expr,
|
||||
fld: &MacroExpander)
|
||||
-> @ast::Expr {
|
||||
match e.node {
|
||||
// expr_mac should really be expr_ext or something; it's the
|
||||
// entry-point for all syntax extensions.
|
||||
ExprMac(ref mac) => {
|
||||
|
@ -66,7 +65,7 @@ pub fn expand_expr(extsbox: @mut SyntaxEnv,
|
|||
}
|
||||
Some(@SE(NormalTT(expandfun, exp_span))) => {
|
||||
cx.bt_push(ExpnInfo {
|
||||
call_site: span,
|
||||
call_site: e.span,
|
||||
callee: NameAndSpan {
|
||||
name: extnamestr,
|
||||
span: exp_span,
|
||||
|
@ -84,10 +83,12 @@ pub fn expand_expr(extsbox: @mut SyntaxEnv,
|
|||
let mac_span = original_span(cx);
|
||||
|
||||
let expanded =
|
||||
match expandfun(cx, mac_span.call_site,
|
||||
marked_before, marked_ctxt) {
|
||||
match expandfun.expand(cx,
|
||||
mac_span.call_site,
|
||||
marked_before,
|
||||
marked_ctxt) {
|
||||
MRExpr(e) => e,
|
||||
MRAny(expr_maker,_,_) => expr_maker(),
|
||||
MRAny(any_macro) => any_macro.make_expr(),
|
||||
_ => {
|
||||
cx.span_fatal(
|
||||
pth.span,
|
||||
|
@ -101,12 +102,19 @@ pub fn expand_expr(extsbox: @mut SyntaxEnv,
|
|||
// mark after:
|
||||
let marked_after = mark_expr(expanded,fm);
|
||||
|
||||
//keep going, outside-in
|
||||
// Keep going, outside-in.
|
||||
//
|
||||
// XXX(pcwalton): Is it necessary to clone the
|
||||
// node here?
|
||||
let fully_expanded =
|
||||
fld.fold_expr(marked_after).node.clone();
|
||||
cx.bt_pop();
|
||||
|
||||
(fully_expanded, span)
|
||||
@ast::Expr {
|
||||
id: ast::DUMMY_NODE_ID,
|
||||
node: fully_expanded,
|
||||
span: e.span,
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
cx.span_fatal(
|
||||
|
@ -125,8 +133,48 @@ pub fn expand_expr(extsbox: @mut SyntaxEnv,
|
|||
ast::ExprForLoop(src_pat, src_expr, ref src_loop_block, opt_ident) => {
|
||||
// Expand any interior macros etc.
|
||||
// NB: we don't fold pats yet. Curious.
|
||||
let src_expr = fld.fold_expr(src_expr);
|
||||
let src_loop_block = fld.fold_block(src_loop_block);
|
||||
let src_expr = fld.fold_expr(src_expr).clone();
|
||||
let src_loop_block = fld.fold_block(src_loop_block).clone();
|
||||
|
||||
let span = e.span;
|
||||
|
||||
pub fn mk_expr(_: @ExtCtxt, span: Span, node: Expr_)
|
||||
-> @ast::Expr {
|
||||
@ast::Expr {
|
||||
id: ast::DUMMY_NODE_ID,
|
||||
node: node,
|
||||
span: span,
|
||||
}
|
||||
}
|
||||
|
||||
fn mk_block(_: @ExtCtxt,
|
||||
stmts: &[@ast::Stmt],
|
||||
expr: Option<@ast::Expr>,
|
||||
span: Span)
|
||||
-> ast::Block {
|
||||
ast::Block {
|
||||
view_items: ~[],
|
||||
stmts: stmts.to_owned(),
|
||||
expr: expr,
|
||||
id: ast::DUMMY_NODE_ID,
|
||||
rules: ast::DefaultBlock,
|
||||
span: span,
|
||||
}
|
||||
}
|
||||
|
||||
fn mk_simple_path(ident: ast::Ident, span: Span) -> ast::Path {
|
||||
ast::Path {
|
||||
span: span,
|
||||
global: false,
|
||||
segments: ~[
|
||||
ast::PathSegment {
|
||||
identifier: ident,
|
||||
lifetime: None,
|
||||
types: opt_vec::Empty,
|
||||
}
|
||||
],
|
||||
}
|
||||
}
|
||||
|
||||
// to:
|
||||
//
|
||||
|
@ -182,10 +230,14 @@ pub fn expand_expr(extsbox: @mut SyntaxEnv,
|
|||
~[iter_decl_stmt],
|
||||
Some(loop_expr));
|
||||
|
||||
(ast::ExprBlock(block), span)
|
||||
@ast::Expr {
|
||||
id: ast::DUMMY_NODE_ID,
|
||||
node: ast::ExprBlock(block),
|
||||
span: span,
|
||||
}
|
||||
}
|
||||
|
||||
_ => orig(e, span, fld)
|
||||
_ => noop_fold_expr(e, fld)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -201,12 +253,10 @@ pub fn expand_expr(extsbox: @mut SyntaxEnv,
|
|||
pub fn expand_mod_items(extsbox: @mut SyntaxEnv,
|
||||
cx: @ExtCtxt,
|
||||
module_: &ast::_mod,
|
||||
fld: @ast_fold,
|
||||
orig: @fn(&ast::_mod, @ast_fold) -> ast::_mod)
|
||||
fld: &MacroExpander)
|
||||
-> ast::_mod {
|
||||
|
||||
// Fold the contents first:
|
||||
let module_ = orig(module_, fld);
|
||||
let module_ = noop_fold_mod(module_, fld);
|
||||
|
||||
// For each item, look through the attributes. If any of them are
|
||||
// decorated with "item decorators", then use that function to transform
|
||||
|
@ -233,7 +283,10 @@ pub fn expand_mod_items(extsbox: @mut SyntaxEnv,
|
|||
}
|
||||
};
|
||||
|
||||
ast::_mod { items: new_items, ..module_ }
|
||||
ast::_mod {
|
||||
items: new_items,
|
||||
..module_
|
||||
}
|
||||
}
|
||||
|
||||
// eval $e with a new exts frame:
|
||||
|
@ -256,19 +309,20 @@ static special_block_name : &'static str = " block";
|
|||
pub fn expand_item(extsbox: @mut SyntaxEnv,
|
||||
cx: @ExtCtxt,
|
||||
it: @ast::item,
|
||||
fld: @ast_fold,
|
||||
orig: @fn(@ast::item, @ast_fold) -> Option<@ast::item>)
|
||||
fld: &MacroExpander)
|
||||
-> Option<@ast::item> {
|
||||
match it.node {
|
||||
ast::item_mac(*) => expand_item_mac(extsbox, cx, it, fld),
|
||||
ast::item_mod(_) | ast::item_foreign_mod(_) => {
|
||||
cx.mod_push(it.ident);
|
||||
let macro_escape = contains_macro_escape(it.attrs);
|
||||
let result = with_exts_frame!(extsbox,macro_escape,orig(it,fld));
|
||||
let result = with_exts_frame!(extsbox,
|
||||
macro_escape,
|
||||
noop_fold_item(it, fld));
|
||||
cx.mod_pop();
|
||||
result
|
||||
},
|
||||
_ => orig(it,fld)
|
||||
_ => noop_fold_item(it, fld)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -280,11 +334,15 @@ pub fn contains_macro_escape(attrs: &[ast::Attribute]) -> bool {
|
|||
// Support for item-position macro invocations, exactly the same
|
||||
// logic as for expression-position macro invocations.
|
||||
pub fn expand_item_mac(extsbox: @mut SyntaxEnv,
|
||||
cx: @ExtCtxt, it: @ast::item,
|
||||
fld: @ast_fold)
|
||||
cx: @ExtCtxt,
|
||||
it: @ast::item,
|
||||
fld: &MacroExpander)
|
||||
-> Option<@ast::item> {
|
||||
let (pth, tts, ctxt) = match it.node {
|
||||
item_mac(codemap::Spanned { node: mac_invoc_tt(ref pth, ref tts, ctxt), _}) => {
|
||||
item_mac(codemap::Spanned {
|
||||
node: mac_invoc_tt(ref pth, ref tts, ctxt),
|
||||
_
|
||||
}) => {
|
||||
(pth, (*tts).clone(), ctxt)
|
||||
}
|
||||
_ => cx.span_bug(it.span, "invalid item macro invocation")
|
||||
|
@ -314,7 +372,7 @@ pub fn expand_item_mac(extsbox: @mut SyntaxEnv,
|
|||
// mark before expansion:
|
||||
let marked_before = mark_tts(tts,fm);
|
||||
let marked_ctxt = new_mark(fm,ctxt);
|
||||
expander(cx, it.span, marked_before, marked_ctxt)
|
||||
expander.expand(cx, it.span, marked_before, marked_ctxt)
|
||||
}
|
||||
Some(@SE(IdentTT(expander, span))) => {
|
||||
if it.ident.name == parse::token::special_idents::invalid.name {
|
||||
|
@ -332,7 +390,7 @@ pub fn expand_item_mac(extsbox: @mut SyntaxEnv,
|
|||
// mark before expansion:
|
||||
let marked_tts = mark_tts(tts,fm);
|
||||
let marked_ctxt = new_mark(fm,ctxt);
|
||||
expander(cx, it.span, it.ident, marked_tts, marked_ctxt)
|
||||
expander.expand(cx, it.span, it.ident, marked_tts, marked_ctxt)
|
||||
}
|
||||
_ => cx.span_fatal(
|
||||
it.span, fmt!("%s! is not legal in item position", extnamestr))
|
||||
|
@ -346,8 +404,8 @@ pub fn expand_item_mac(extsbox: @mut SyntaxEnv,
|
|||
MRExpr(_) => {
|
||||
cx.span_fatal(pth.span, fmt!("expr macro in item position: %s", extnamestr))
|
||||
}
|
||||
MRAny(_, item_maker, _) => {
|
||||
item_maker()
|
||||
MRAny(any_macro) => {
|
||||
any_macro.make_item()
|
||||
.and_then(|i| mark_item(i,fm))
|
||||
.and_then(|i| fld.fold_item(i))
|
||||
}
|
||||
|
@ -382,15 +440,12 @@ fn insert_macro(exts: SyntaxEnv, name: ast::Name, transformer: @Transformer) {
|
|||
// expand a stmt
|
||||
pub fn expand_stmt(extsbox: @mut SyntaxEnv,
|
||||
cx: @ExtCtxt,
|
||||
s: &Stmt_,
|
||||
sp: Span,
|
||||
fld: @ast_fold,
|
||||
orig: @fn(&Stmt_, Span, @ast_fold)
|
||||
-> (Option<Stmt_>, Span))
|
||||
-> (Option<Stmt_>, Span) {
|
||||
s: &Stmt,
|
||||
fld: &MacroExpander)
|
||||
-> Option<@Stmt> {
|
||||
// why the copying here and not in expand_expr?
|
||||
// looks like classic changed-in-only-one-place
|
||||
let (pth, tts, semi, ctxt) = match *s {
|
||||
let (pth, tts, semi, ctxt) = match s.node {
|
||||
StmtMac(ref mac, semi) => {
|
||||
match mac.node {
|
||||
mac_invoc_tt(ref pth, ref tts, ctxt) => {
|
||||
|
@ -398,24 +453,26 @@ pub fn expand_stmt(extsbox: @mut SyntaxEnv,
|
|||
}
|
||||
}
|
||||
}
|
||||
_ => return expand_non_macro_stmt(*extsbox,s,sp,fld,orig)
|
||||
_ => return expand_non_macro_stmt(*extsbox, s, fld)
|
||||
};
|
||||
if (pth.segments.len() > 1u) {
|
||||
cx.span_fatal(
|
||||
pth.span,
|
||||
fmt!("expected macro name without module \
|
||||
separators"));
|
||||
cx.span_fatal(pth.span,
|
||||
"expected macro name without module separators");
|
||||
}
|
||||
let extname = &pth.segments[0].identifier;
|
||||
let extnamestr = ident_to_str(extname);
|
||||
let (fully_expanded, sp) = match (*extsbox).find(&extname.name) {
|
||||
None =>
|
||||
cx.span_fatal(pth.span, fmt!("macro undefined: '%s'", extnamestr)),
|
||||
let fully_expanded: @ast::Stmt = match (*extsbox).find(&extname.name) {
|
||||
None => {
|
||||
cx.span_fatal(pth.span, fmt!("macro undefined: '%s'", extnamestr))
|
||||
}
|
||||
|
||||
Some(@SE(NormalTT(expandfun, exp_span))) => {
|
||||
cx.bt_push(ExpnInfo {
|
||||
call_site: sp,
|
||||
callee: NameAndSpan { name: extnamestr, span: exp_span }
|
||||
call_site: s.span,
|
||||
callee: NameAndSpan {
|
||||
name: extnamestr,
|
||||
span: exp_span,
|
||||
}
|
||||
});
|
||||
let fm = fresh_mark();
|
||||
// mark before expansion:
|
||||
|
@ -426,24 +483,32 @@ pub fn expand_stmt(extsbox: @mut SyntaxEnv,
|
|||
// not the current mac.span.
|
||||
let mac_span = original_span(cx);
|
||||
|
||||
let expanded = match expandfun(cx, mac_span.call_site,
|
||||
marked_tts, marked_ctxt) {
|
||||
MRExpr(e) =>
|
||||
@codemap::Spanned { node: StmtExpr(e, ast::DUMMY_NODE_ID),
|
||||
span: e.span},
|
||||
MRAny(_,_,stmt_mkr) => stmt_mkr(),
|
||||
let expanded = match expandfun.expand(cx,
|
||||
mac_span.call_site,
|
||||
marked_tts,
|
||||
marked_ctxt) {
|
||||
MRExpr(e) => {
|
||||
@codemap::Spanned {
|
||||
node: StmtExpr(e, ast::DUMMY_NODE_ID),
|
||||
span: e.span,
|
||||
}
|
||||
}
|
||||
MRAny(any_macro) => any_macro.make_stmt(),
|
||||
_ => cx.span_fatal(
|
||||
pth.span,
|
||||
fmt!("non-stmt macro in stmt pos: %s", extnamestr))
|
||||
};
|
||||
let marked_after = mark_stmt(expanded,fm);
|
||||
|
||||
//keep going, outside-in
|
||||
// Keep going, outside-in.
|
||||
let fully_expanded = match fld.fold_stmt(marked_after) {
|
||||
Some(stmt) => {
|
||||
let fully_expanded = &stmt.node;
|
||||
cx.bt_pop();
|
||||
(*fully_expanded).clone()
|
||||
@Spanned {
|
||||
span: stmt.span,
|
||||
node: (*fully_expanded).clone(),
|
||||
}
|
||||
}
|
||||
None => {
|
||||
cx.span_fatal(pth.span,
|
||||
|
@ -451,7 +516,7 @@ pub fn expand_stmt(extsbox: @mut SyntaxEnv,
|
|||
}
|
||||
};
|
||||
|
||||
(fully_expanded, sp)
|
||||
fully_expanded
|
||||
}
|
||||
|
||||
_ => {
|
||||
|
@ -460,24 +525,28 @@ pub fn expand_stmt(extsbox: @mut SyntaxEnv,
|
|||
}
|
||||
};
|
||||
|
||||
(match fully_expanded {
|
||||
StmtExpr(e, stmt_id) if semi => Some(StmtSemi(e, stmt_id)),
|
||||
_ => { Some(fully_expanded) } /* might already have a semi */
|
||||
}, sp)
|
||||
|
||||
match fully_expanded.node {
|
||||
StmtExpr(e, stmt_id) if semi => {
|
||||
Some(@Spanned {
|
||||
span: fully_expanded.span,
|
||||
node: StmtSemi(e, stmt_id),
|
||||
})
|
||||
}
|
||||
_ => Some(fully_expanded), /* might already have a semi */
|
||||
}
|
||||
}
|
||||
|
||||
// expand a non-macro stmt. this is essentially the fallthrough for
|
||||
// expand_stmt, above.
|
||||
fn expand_non_macro_stmt (exts: SyntaxEnv,
|
||||
s: &Stmt_,
|
||||
sp: Span,
|
||||
fld: @ast_fold,
|
||||
orig: @fn(&Stmt_, Span, @ast_fold) -> (Option<Stmt_>, Span))
|
||||
-> (Option<Stmt_>,Span) {
|
||||
fn expand_non_macro_stmt(exts: SyntaxEnv, s: &Stmt, fld: &MacroExpander)
|
||||
-> Option<@Stmt> {
|
||||
// is it a let?
|
||||
match *s {
|
||||
StmtDecl(@Spanned{node: DeclLocal(ref local), span: stmt_span}, node_id) => {
|
||||
match s.node {
|
||||
StmtDecl(@Spanned {
|
||||
node: DeclLocal(ref local),
|
||||
span: stmt_span
|
||||
},
|
||||
node_id) => {
|
||||
let block_info = get_block_info(exts);
|
||||
let pending_renames = block_info.pending_renames;
|
||||
|
||||
|
@ -515,19 +584,24 @@ fn expand_non_macro_stmt (exts: SyntaxEnv,
|
|||
// also, don't forget to expand the init:
|
||||
let new_init_opt = init.map(|e| fld.fold_expr(*e));
|
||||
let rewritten_local =
|
||||
@Local{is_mutbl:is_mutbl,
|
||||
ty:ty,
|
||||
pat:rewritten_pat,
|
||||
init:new_init_opt,
|
||||
id:id,
|
||||
span:span};
|
||||
(Some(StmtDecl(@Spanned{node:DeclLocal(rewritten_local),
|
||||
span: stmt_span},node_id)),
|
||||
sp)
|
||||
@Local {
|
||||
is_mutbl: is_mutbl,
|
||||
ty: ty,
|
||||
pat: rewritten_pat,
|
||||
init: new_init_opt,
|
||||
id: id,
|
||||
span: span,
|
||||
};
|
||||
Some(@Spanned {
|
||||
node: StmtDecl(@Spanned {
|
||||
node: DeclLocal(rewritten_local),
|
||||
span: stmt_span
|
||||
},
|
||||
_ => {
|
||||
orig(s, sp, fld)
|
||||
}
|
||||
node_id),
|
||||
span: span
|
||||
})
|
||||
},
|
||||
_ => noop_fold_stmt(s, fld),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -628,10 +702,9 @@ pub fn new_path_finder(paths: @mut ~[ast::Path]) -> @mut Visitor<()> {
|
|||
|
||||
// expand a block. pushes a new exts_frame, then calls expand_block_elts
|
||||
pub fn expand_block(extsbox: @mut SyntaxEnv,
|
||||
_cx: @ExtCtxt,
|
||||
_: @ExtCtxt,
|
||||
blk: &Block,
|
||||
fld: @ast_fold,
|
||||
_orig: @fn(&Block, @ast_fold) -> Block)
|
||||
fld: &MacroExpander)
|
||||
-> Block {
|
||||
// see note below about treatment of exts table
|
||||
with_exts_frame!(extsbox,false,
|
||||
|
@ -639,7 +712,8 @@ pub fn expand_block(extsbox: @mut SyntaxEnv,
|
|||
}
|
||||
|
||||
// expand the elements of a block.
|
||||
pub fn expand_block_elts(exts: SyntaxEnv, b: &Block, fld: @ast_fold) -> Block {
|
||||
pub fn expand_block_elts(exts: SyntaxEnv, b: &Block, fld: &MacroExpander)
|
||||
-> Block {
|
||||
let block_info = get_block_info(exts);
|
||||
let pending_renames = block_info.pending_renames;
|
||||
let rename_fld = renames_to_fold(pending_renames);
|
||||
|
@ -680,9 +754,47 @@ fn get_block_info(exts : SyntaxEnv) -> BlockInfo {
|
|||
}
|
||||
}
|
||||
|
||||
struct IdentRenamer {
|
||||
renames: @mut ~[(ast::Ident,ast::Name)],
|
||||
}
|
||||
|
||||
impl ast_fold for IdentRenamer {
|
||||
fn fold_ident(&self, id: ast::Ident) -> ast::Ident {
|
||||
let new_ctxt = self.renames.iter().fold(id.ctxt, |ctxt, &(from, to)| {
|
||||
new_rename(from, to, ctxt)
|
||||
});
|
||||
ast::Ident {
|
||||
name: id.name,
|
||||
ctxt: new_ctxt,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// given a mutable list of renames, return a tree-folder that applies those
|
||||
// renames.
|
||||
pub fn renames_to_fold(renames: @mut ~[(ast::Ident,ast::Name)]) -> @ast_fold {
|
||||
@IdentRenamer {
|
||||
renames: renames,
|
||||
} as @ast_fold
|
||||
}
|
||||
|
||||
// perform a bunch of renames
|
||||
fn apply_pending_renames(folder : @ast_fold, stmt : ast::Stmt) -> @ast::Stmt {
|
||||
match folder.fold_stmt(&stmt) {
|
||||
Some(s) => s,
|
||||
None => fail!(fmt!("renaming of stmt produced None"))
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
pub fn new_span(cx: @ExtCtxt, sp: Span) -> Span {
|
||||
/* this discards information in the case of macro-defining macros */
|
||||
return Span {lo: sp.lo, hi: sp.hi, expn_info: cx.backtrace()};
|
||||
Span {
|
||||
lo: sp.lo,
|
||||
hi: sp.hi,
|
||||
expn_info: cx.backtrace(),
|
||||
}
|
||||
}
|
||||
|
||||
// FIXME (#2247): this is a moderately bad kludge to inject some macros into
|
||||
|
@ -1025,10 +1137,28 @@ pub fn std_macros() -> @str {
|
|||
}";
|
||||
}
|
||||
|
||||
struct Injector {
|
||||
sm: @ast::item,
|
||||
}
|
||||
|
||||
impl ast_fold for Injector {
|
||||
fn fold_mod(&self, module: &ast::_mod) -> ast::_mod {
|
||||
// Just inject the standard macros at the start of the first module
|
||||
// in the crate: that is, at the start of the crate file itself.
|
||||
let items = vec::append(~[ self.sm ], module.items);
|
||||
ast::_mod {
|
||||
items: items,
|
||||
..(*module).clone() // FIXME #2543: Bad copy.
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// add a bunch of macros as though they were placed at the head of the
|
||||
// program (ick). This should run before cfg stripping.
|
||||
pub fn inject_std_macros(parse_sess: @mut parse::ParseSess,
|
||||
cfg: ast::CrateConfig, c: &Crate) -> @Crate {
|
||||
cfg: ast::CrateConfig,
|
||||
c: @Crate)
|
||||
-> @Crate {
|
||||
let sm = match parse_item_from_source_str(@"<std-macros>",
|
||||
std_macros(),
|
||||
cfg.clone(),
|
||||
|
@ -1038,48 +1168,80 @@ pub fn inject_std_macros(parse_sess: @mut parse::ParseSess,
|
|||
None => fail!("expected core macros to parse correctly")
|
||||
};
|
||||
|
||||
let injecter = @AstFoldFns {
|
||||
fold_mod: |modd, _| {
|
||||
// just inject the std macros at the start of the first
|
||||
// module in the crate (i.e the crate file itself.)
|
||||
let items = vec::append(~[sm], modd.items);
|
||||
ast::_mod {
|
||||
items: items,
|
||||
// FIXME #2543: Bad copy.
|
||||
.. (*modd).clone()
|
||||
let injector = @Injector {
|
||||
sm: sm,
|
||||
} as @ast_fold;
|
||||
@injector.fold_crate(c)
|
||||
}
|
||||
|
||||
struct NoOpFolder {
|
||||
contents: (),
|
||||
}
|
||||
|
||||
impl ast_fold for NoOpFolder {}
|
||||
|
||||
struct MacroExpander {
|
||||
extsbox: @mut SyntaxEnv,
|
||||
cx: @ExtCtxt,
|
||||
}
|
||||
|
||||
impl ast_fold for MacroExpander {
|
||||
fn fold_expr(&self, expr: @ast::Expr) -> @ast::Expr {
|
||||
expand_expr(self.extsbox,
|
||||
self.cx,
|
||||
expr,
|
||||
self)
|
||||
}
|
||||
|
||||
fn fold_mod(&self, module: &ast::_mod) -> ast::_mod {
|
||||
expand_mod_items(self.extsbox,
|
||||
self.cx,
|
||||
module,
|
||||
self)
|
||||
}
|
||||
|
||||
fn fold_item(&self, item: @ast::item) -> Option<@ast::item> {
|
||||
expand_item(self.extsbox,
|
||||
self.cx,
|
||||
item,
|
||||
self)
|
||||
}
|
||||
|
||||
fn fold_stmt(&self, stmt: &ast::Stmt) -> Option<@ast::Stmt> {
|
||||
expand_stmt(self.extsbox,
|
||||
self.cx,
|
||||
stmt,
|
||||
self)
|
||||
}
|
||||
|
||||
fn fold_block(&self, block: &ast::Block) -> ast::Block {
|
||||
expand_block(self.extsbox,
|
||||
self.cx,
|
||||
block,
|
||||
self)
|
||||
}
|
||||
|
||||
fn new_span(&self, span: Span) -> Span {
|
||||
new_span(self.cx, span)
|
||||
}
|
||||
},
|
||||
.. *default_ast_fold()
|
||||
};
|
||||
@make_fold(injecter).fold_crate(c)
|
||||
}
|
||||
|
||||
pub fn expand_crate(parse_sess: @mut parse::ParseSess,
|
||||
cfg: ast::CrateConfig, c: &Crate) -> @Crate {
|
||||
cfg: ast::CrateConfig,
|
||||
c: &Crate) -> @Crate {
|
||||
// adding *another* layer of indirection here so that the block
|
||||
// visitor can swap out one exts table for another for the duration
|
||||
// of the block. The cleaner alternative would be to thread the
|
||||
// exts table through the fold, but that would require updating
|
||||
// every method/element of AstFoldFns in fold.rs.
|
||||
let extsbox = @mut syntax_expander_table();
|
||||
let afp = default_ast_fold();
|
||||
let extsbox = syntax_expander_table();
|
||||
let cx = ExtCtxt::new(parse_sess, cfg.clone());
|
||||
let f_pre = @AstFoldFns {
|
||||
fold_expr: |expr,span,recur|
|
||||
expand_expr(extsbox, cx, expr, span, recur, afp.fold_expr),
|
||||
fold_mod: |modd,recur|
|
||||
expand_mod_items(extsbox, cx, modd, recur, afp.fold_mod),
|
||||
fold_item: |item,recur|
|
||||
expand_item(extsbox, cx, item, recur, afp.fold_item),
|
||||
fold_stmt: |stmt,span,recur|
|
||||
expand_stmt(extsbox, cx, stmt, span, recur, afp.fold_stmt),
|
||||
fold_block: |blk,recur|
|
||||
expand_block(extsbox, cx, blk, recur, afp.fold_block),
|
||||
new_span: |a| new_span(cx, a),
|
||||
.. *afp};
|
||||
let f = make_fold(f_pre);
|
||||
let expander = @MacroExpander {
|
||||
extsbox: @mut extsbox,
|
||||
cx: cx,
|
||||
} as @ast_fold;
|
||||
|
||||
let ret = @f.fold_crate(c);
|
||||
let ret = @expander.fold_crate(c);
|
||||
parse_sess.span_diagnostic.handler().abort_if_errors();
|
||||
return ret;
|
||||
}
|
||||
|
@ -1145,53 +1307,56 @@ impl CtxtFn for Repainter {
|
|||
}
|
||||
}
|
||||
|
||||
// given a function from ctxts to ctxts, produce
|
||||
// an ast_fold that applies that function to all ctxts:
|
||||
pub fn fun_to_ctxt_folder<T : 'static + CtxtFn>(cf: @T) -> @AstFoldFns {
|
||||
let afp = default_ast_fold();
|
||||
let fi : @fn(ast::Ident, @ast_fold) -> ast::Ident =
|
||||
|ast::Ident{name, ctxt}, _| {
|
||||
ast::Ident{name:name,ctxt:cf.f(ctxt)}
|
||||
};
|
||||
let fm : @fn(&ast::mac_, Span, @ast_fold) -> (ast::mac_,Span) =
|
||||
|m, sp, fld| {
|
||||
match *m {
|
||||
mac_invoc_tt(ref path, ref tts, ctxt) =>
|
||||
(mac_invoc_tt(fld.fold_path(path),
|
||||
fold_tts(*tts,fld),
|
||||
cf.f(ctxt)),
|
||||
sp)
|
||||
}
|
||||
pub struct ContextWrapper {
|
||||
context_function: @CtxtFn,
|
||||
}
|
||||
|
||||
impl ast_fold for ContextWrapper {
|
||||
fn fold_ident(&self, id: ast::Ident) -> ast::Ident {
|
||||
let ast::Ident {
|
||||
name,
|
||||
ctxt
|
||||
} = id;
|
||||
ast::Ident {
|
||||
name: name,
|
||||
ctxt: self.context_function.f(ctxt),
|
||||
}
|
||||
}
|
||||
fn fold_mac(&self, m: &ast::mac) -> ast::mac {
|
||||
let macro = match m.node {
|
||||
mac_invoc_tt(ref path, ref tts, ctxt) => {
|
||||
mac_invoc_tt(self.fold_path(path),
|
||||
fold_tts(*tts, self),
|
||||
self.context_function.f(ctxt))
|
||||
}
|
||||
};
|
||||
@AstFoldFns{
|
||||
fold_ident : fi,
|
||||
fold_mac : fm,
|
||||
.. *afp
|
||||
Spanned {
|
||||
node: macro,
|
||||
span: m.span,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
// given a mutable list of renames, return a tree-folder that applies those
|
||||
// renames.
|
||||
// FIXME #4536: currently pub to allow testing
|
||||
pub fn renames_to_fold(renames : @mut ~[(ast::Ident,ast::Name)]) -> @AstFoldFns {
|
||||
fun_to_ctxt_folder(@MultiRenamer{renames : renames})
|
||||
// given a function from ctxts to ctxts, produce
|
||||
// an ast_fold that applies that function to all ctxts:
|
||||
pub fn fun_to_ctxt_folder<T : 'static + CtxtFn>(cf: @T) -> @ContextWrapper {
|
||||
@ContextWrapper {
|
||||
context_function: cf as @CtxtFn,
|
||||
}
|
||||
}
|
||||
|
||||
// just a convenience:
|
||||
pub fn new_mark_folder(m : Mrk) -> @AstFoldFns {
|
||||
pub fn new_mark_folder(m: Mrk) -> @ContextWrapper {
|
||||
fun_to_ctxt_folder(@Marker{mark:m})
|
||||
}
|
||||
|
||||
pub fn new_rename_folder(from : ast::Ident, to : ast::Name) -> @AstFoldFns {
|
||||
pub fn new_rename_folder(from: ast::Ident, to: ast::Name) -> @ContextWrapper {
|
||||
fun_to_ctxt_folder(@Renamer{from:from,to:to})
|
||||
}
|
||||
|
||||
// apply a given mark to the given token trees. Used prior to expansion of a macro.
|
||||
fn mark_tts(tts : &[token_tree], m : Mrk) -> ~[token_tree] {
|
||||
fold_tts(tts,new_mark_folder(m) as @ast_fold)
|
||||
fold_tts(tts,new_mark_folder(m))
|
||||
}
|
||||
|
||||
// apply a given mark to the given expr. Used following the expansion of a macro.
|
||||
|
@ -1359,7 +1524,7 @@ mod test {
|
|||
let ident_str = @"x";
|
||||
let tts = string_to_tts(ident_str);
|
||||
let fm = fresh_mark();
|
||||
let marked_once = fold::fold_tts(tts,new_mark_folder(fm) as @fold::ast_fold);
|
||||
let marked_once = fold::fold_tts(tts,new_mark_folder(fm));
|
||||
assert_eq!(marked_once.len(),1);
|
||||
let marked_once_ctxt =
|
||||
match marked_once[0] {
|
||||
|
|
|
@ -38,7 +38,7 @@ pub fn expand_syntax_ext(cx: @ExtCtxt, sp: Span, tts: &[ast::token_tree])
|
|||
fn parse_fmt_err_(cx: @ExtCtxt, sp: Span, msg: &str) -> ! {
|
||||
cx.span_fatal(sp, msg);
|
||||
}
|
||||
let parse_fmt_err: @fn(&str) -> ! = |s| parse_fmt_err_(cx, fmtspan, s);
|
||||
let parse_fmt_err: &fn(&str) -> ! = |s| parse_fmt_err_(cx, fmtspan, s);
|
||||
let pieces = parse_fmt_string(fmt, parse_fmt_err);
|
||||
MRExpr(pieces_to_expr(cx, sp, pieces, args))
|
||||
}
|
||||
|
|
|
@ -12,9 +12,9 @@ use ast::{Ident, matcher_, matcher, match_tok, match_nonterminal, match_seq};
|
|||
use ast::{tt_delim};
|
||||
use ast;
|
||||
use codemap::{Span, Spanned, dummy_sp};
|
||||
use ext::base::{ExtCtxt, MacResult, MRAny, MRDef, MacroDef, NormalTT};
|
||||
use ext::base::{AnyMacro, ExtCtxt, MacResult, MRAny, MRDef, MacroDef};
|
||||
use ext::base::{NormalTT, SyntaxExpanderTTTrait};
|
||||
use ext::base;
|
||||
use ext::expand;
|
||||
use ext::tt::macro_parser::{error};
|
||||
use ext::tt::macro_parser::{named_match, matched_seq, matched_nonterminal};
|
||||
use ext::tt::macro_parser::{parse, parse_or_else, success, failure};
|
||||
|
@ -24,69 +24,47 @@ use parse::token::{get_ident_interner, special_idents, gensym_ident, ident_to_st
|
|||
use parse::token::{FAT_ARROW, SEMI, nt_matchers, nt_tt};
|
||||
use print;
|
||||
|
||||
// this procedure performs the expansion of the
|
||||
// macro_rules! macro. It parses the RHS and adds
|
||||
// an extension to the current context.
|
||||
pub fn add_new_extension(cx: @ExtCtxt,
|
||||
struct ParserAnyMacro {
|
||||
parser: @Parser,
|
||||
}
|
||||
|
||||
impl AnyMacro for ParserAnyMacro {
|
||||
fn make_expr(&self) -> @ast::Expr {
|
||||
self.parser.parse_expr()
|
||||
}
|
||||
fn make_item(&self) -> Option<@ast::item> {
|
||||
self.parser.parse_item(~[]) // no attrs
|
||||
}
|
||||
fn make_stmt(&self) -> @ast::Stmt {
|
||||
self.parser.parse_stmt(~[]) // no attrs
|
||||
}
|
||||
}
|
||||
|
||||
struct MacroRulesSyntaxExpanderTTFun {
|
||||
name: Ident,
|
||||
lhses: @~[@named_match],
|
||||
rhses: @~[@named_match],
|
||||
}
|
||||
|
||||
impl SyntaxExpanderTTTrait for MacroRulesSyntaxExpanderTTFun {
|
||||
fn expand(&self,
|
||||
cx: @ExtCtxt,
|
||||
sp: Span,
|
||||
arg: &[ast::token_tree],
|
||||
_: ast::SyntaxContext)
|
||||
-> MacResult {
|
||||
generic_extension(cx, sp, self.name, arg, *self.lhses, *self.rhses)
|
||||
}
|
||||
}
|
||||
|
||||
// Given `lhses` and `rhses`, this is the new macro we create
|
||||
fn generic_extension(cx: @ExtCtxt,
|
||||
sp: Span,
|
||||
name: Ident,
|
||||
arg: ~[ast::token_tree],
|
||||
stx_ctxt: ast::SyntaxContext)
|
||||
-> base::MacResult {
|
||||
let arg = expand::mtwt_cancel_outer_mark(arg,stx_ctxt);
|
||||
// Wrap a matcher_ in a spanned to produce a matcher.
|
||||
// these spans won't matter, anyways
|
||||
fn ms(m: matcher_) -> matcher {
|
||||
Spanned {
|
||||
node: m.clone(),
|
||||
span: dummy_sp()
|
||||
}
|
||||
}
|
||||
|
||||
let lhs_nm = gensym_ident("lhs");
|
||||
let rhs_nm = gensym_ident("rhs");
|
||||
|
||||
// The pattern that macro_rules matches.
|
||||
// The grammar for macro_rules! is:
|
||||
// $( $lhs:mtcs => $rhs:tt );+
|
||||
// ...quasiquoting this would be nice.
|
||||
let argument_gram = ~[
|
||||
ms(match_seq(~[
|
||||
ms(match_nonterminal(lhs_nm, special_idents::matchers, 0u)),
|
||||
ms(match_tok(FAT_ARROW)),
|
||||
ms(match_nonterminal(rhs_nm, special_idents::tt, 1u)),
|
||||
], Some(SEMI), false, 0u, 2u)),
|
||||
//to phase into semicolon-termination instead of
|
||||
//semicolon-separation
|
||||
ms(match_seq(~[ms(match_tok(SEMI))], None, true, 2u, 2u))];
|
||||
|
||||
|
||||
// Parse the macro_rules! invocation (`none` is for no interpolations):
|
||||
let arg_reader = new_tt_reader(cx.parse_sess().span_diagnostic,
|
||||
None,
|
||||
arg.clone());
|
||||
let argument_map = parse_or_else(cx.parse_sess(),
|
||||
cx.cfg(),
|
||||
arg_reader as @mut reader,
|
||||
argument_gram);
|
||||
|
||||
// Extract the arguments:
|
||||
let lhses = match *argument_map.get(&lhs_nm) {
|
||||
@matched_seq(ref s, _) => /* FIXME (#2543) */ @(*s).clone(),
|
||||
_ => cx.span_bug(sp, "wrong-structured lhs")
|
||||
};
|
||||
|
||||
let rhses = match *argument_map.get(&rhs_nm) {
|
||||
@matched_seq(ref s, _) => /* FIXME (#2543) */ @(*s).clone(),
|
||||
_ => cx.span_bug(sp, "wrong-structured rhs")
|
||||
};
|
||||
|
||||
// Given `lhses` and `rhses`, this is the new macro we create
|
||||
fn generic_extension(cx: @ExtCtxt, sp: Span, name: Ident,
|
||||
arg: &[ast::token_tree],
|
||||
lhses: &[@named_match], rhses: &[@named_match])
|
||||
lhses: &[@named_match],
|
||||
rhses: &[@named_match])
|
||||
-> MacResult {
|
||||
|
||||
if cx.trace_macros() {
|
||||
printfln!("%s! { %s }",
|
||||
cx.str_of(name),
|
||||
|
@ -135,9 +113,137 @@ pub fn add_new_extension(cx: @ExtCtxt,
|
|||
|
||||
// Let the context choose how to interpret the result.
|
||||
// Weird, but useful for X-macros.
|
||||
return MRAny(|| p.parse_expr(),
|
||||
|| p.parse_item(~[/* no attrs*/]),
|
||||
|| p.parse_stmt(~[/* no attrs*/]));
|
||||
return MRAny(@ParserAnyMacro {
|
||||
parser: p,
|
||||
} as @AnyMacro)
|
||||
}
|
||||
failure(sp, ref msg) => if sp.lo >= best_fail_spot.lo {
|
||||
best_fail_spot = sp;
|
||||
best_fail_msg = (*msg).clone();
|
||||
},
|
||||
error(sp, ref msg) => cx.span_fatal(sp, (*msg))
|
||||
}
|
||||
}
|
||||
_ => cx.bug("non-matcher found in parsed lhses")
|
||||
}
|
||||
}
|
||||
cx.span_fatal(best_fail_spot, best_fail_msg);
|
||||
}
|
||||
|
||||
// this procedure performs the expansion of the
|
||||
// macro_rules! macro. It parses the RHS and adds
|
||||
// an extension to the current context.
|
||||
pub fn add_new_extension(cx: @ExtCtxt,
|
||||
sp: Span,
|
||||
name: Ident,
|
||||
arg: ~[ast::token_tree],
|
||||
_: ast::SyntaxContext)
|
||||
-> base::MacResult {
|
||||
// these spans won't matter, anyways
|
||||
fn ms(m: matcher_) -> matcher {
|
||||
Spanned {
|
||||
node: m.clone(),
|
||||
span: dummy_sp()
|
||||
}
|
||||
}
|
||||
|
||||
let lhs_nm = gensym_ident("lhs");
|
||||
let rhs_nm = gensym_ident("rhs");
|
||||
|
||||
// The pattern that macro_rules matches.
|
||||
// The grammar for macro_rules! is:
|
||||
// $( $lhs:mtcs => $rhs:tt );+
|
||||
// ...quasiquoting this would be nice.
|
||||
let argument_gram = ~[
|
||||
ms(match_seq(~[
|
||||
ms(match_nonterminal(lhs_nm, special_idents::matchers, 0u)),
|
||||
ms(match_tok(FAT_ARROW)),
|
||||
ms(match_nonterminal(rhs_nm, special_idents::tt, 1u)),
|
||||
], Some(SEMI), false, 0u, 2u)),
|
||||
//to phase into semicolon-termination instead of
|
||||
//semicolon-separation
|
||||
ms(match_seq(~[ms(match_tok(SEMI))], None, true, 2u, 2u))];
|
||||
|
||||
|
||||
// Parse the macro_rules! invocation (`none` is for no interpolations):
|
||||
let arg_reader = new_tt_reader(cx.parse_sess().span_diagnostic,
|
||||
None,
|
||||
arg.clone());
|
||||
let argument_map = parse_or_else(cx.parse_sess(),
|
||||
cx.cfg(),
|
||||
arg_reader as @mut reader,
|
||||
argument_gram);
|
||||
|
||||
// Extract the arguments:
|
||||
let lhses = match *argument_map.get(&lhs_nm) {
|
||||
@matched_seq(ref s, _) => /* FIXME (#2543) */ @(*s).clone(),
|
||||
_ => cx.span_bug(sp, "wrong-structured lhs")
|
||||
};
|
||||
|
||||
let rhses = match *argument_map.get(&rhs_nm) {
|
||||
@matched_seq(ref s, _) => /* FIXME (#2543) */ @(*s).clone(),
|
||||
_ => cx.span_bug(sp, "wrong-structured rhs")
|
||||
};
|
||||
|
||||
// Given `lhses` and `rhses`, this is the new macro we create
|
||||
fn generic_extension(cx: @ExtCtxt,
|
||||
sp: Span,
|
||||
name: Ident,
|
||||
arg: &[ast::token_tree],
|
||||
lhses: &[@named_match],
|
||||
rhses: &[@named_match])
|
||||
-> MacResult {
|
||||
if cx.trace_macros() {
|
||||
printfln!("%s! { %s }",
|
||||
cx.str_of(name),
|
||||
print::pprust::tt_to_str(
|
||||
&ast::tt_delim(@mut arg.to_owned()),
|
||||
get_ident_interner()));
|
||||
}
|
||||
|
||||
// Which arm's failure should we report? (the one furthest along)
|
||||
let mut best_fail_spot = dummy_sp();
|
||||
let mut best_fail_msg = ~"internal error: ran no matchers";
|
||||
|
||||
let s_d = cx.parse_sess().span_diagnostic;
|
||||
|
||||
for (i, lhs) in lhses.iter().enumerate() { // try each arm's matchers
|
||||
match *lhs {
|
||||
@matched_nonterminal(nt_matchers(ref mtcs)) => {
|
||||
// `none` is because we're not interpolating
|
||||
let arg_rdr = new_tt_reader(
|
||||
s_d,
|
||||
None,
|
||||
arg.to_owned()
|
||||
) as @mut reader;
|
||||
match parse(cx.parse_sess(), cx.cfg(), arg_rdr, *mtcs) {
|
||||
success(named_matches) => {
|
||||
let rhs = match rhses[i] {
|
||||
// okay, what's your transcriber?
|
||||
@matched_nonterminal(nt_tt(@ref tt)) => {
|
||||
match (*tt) {
|
||||
// cut off delimiters; don't parse 'em
|
||||
tt_delim(ref tts) => {
|
||||
(*tts).slice(1u,(*tts).len()-1u).to_owned()
|
||||
}
|
||||
_ => cx.span_fatal(
|
||||
sp, "macro rhs must be delimited")
|
||||
}
|
||||
},
|
||||
_ => cx.span_bug(sp, "bad thing in rhs")
|
||||
};
|
||||
// rhs has holes ( `$id` and `$(...)` that need filled)
|
||||
let trncbr = new_tt_reader(s_d, Some(named_matches),
|
||||
rhs);
|
||||
let p = @Parser(cx.parse_sess(),
|
||||
cx.cfg(),
|
||||
trncbr as @mut reader);
|
||||
|
||||
// Let the context choose how to interpret the result.
|
||||
// Weird, but useful for X-macros.
|
||||
return MRAny(@ParserAnyMacro {
|
||||
parser: p
|
||||
} as @AnyMacro);
|
||||
}
|
||||
failure(sp, ref msg) => if sp.lo >= best_fail_spot.lo {
|
||||
best_fail_spot = sp;
|
||||
|
@ -152,10 +258,13 @@ pub fn add_new_extension(cx: @ExtCtxt,
|
|||
cx.span_fatal(best_fail_spot, best_fail_msg);
|
||||
}
|
||||
|
||||
let exp: @fn(@ExtCtxt, Span, &[ast::token_tree], ctxt: ast::SyntaxContext) -> MacResult =
|
||||
|cx, sp, arg, _ctxt| generic_extension(cx, sp, name, arg, *lhses, *rhses);
|
||||
let exp = @MacroRulesSyntaxExpanderTTFun {
|
||||
name: name,
|
||||
lhses: lhses,
|
||||
rhses: rhses,
|
||||
} as @SyntaxExpanderTTTrait;
|
||||
|
||||
return MRDef(MacroDef{
|
||||
return MRDef(MacroDef {
|
||||
name: ident_to_str(&name),
|
||||
ext: NormalTT(exp, Some(sp))
|
||||
});
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -45,7 +45,7 @@ pub struct ParseSess {
|
|||
included_mod_stack: ~[Path],
|
||||
}
|
||||
|
||||
pub fn new_parse_sess(demitter: Option<Emitter>) -> @mut ParseSess {
|
||||
pub fn new_parse_sess(demitter: Option<@Emitter>) -> @mut ParseSess {
|
||||
let cm = @CodeMap::new();
|
||||
@mut ParseSess {
|
||||
cm: cm,
|
||||
|
|
|
@ -37,16 +37,26 @@ pub enum ann_node<'self> {
|
|||
node_expr(@ps, &'self ast::Expr),
|
||||
node_pat(@ps, &'self ast::Pat),
|
||||
}
|
||||
pub struct pp_ann {
|
||||
pre: @fn(ann_node),
|
||||
post: @fn(ann_node)
|
||||
|
||||
pub trait pp_ann {
|
||||
fn pre(&self, _node: ann_node) {}
|
||||
fn post(&self, _node: ann_node) {}
|
||||
}
|
||||
|
||||
pub fn no_ann() -> pp_ann {
|
||||
fn ignore(_node: ann_node) { }
|
||||
return pp_ann {pre: ignore, post: ignore};
|
||||
pub struct no_ann {
|
||||
contents: (),
|
||||
}
|
||||
|
||||
impl no_ann {
|
||||
pub fn new() -> no_ann {
|
||||
no_ann {
|
||||
contents: (),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl pp_ann for no_ann {}
|
||||
|
||||
pub struct CurrentCommentAndLiteral {
|
||||
cur_cmnt: uint,
|
||||
cur_lit: uint,
|
||||
|
@ -60,7 +70,7 @@ pub struct ps {
|
|||
literals: Option<~[comments::lit]>,
|
||||
cur_cmnt_and_lit: @mut CurrentCommentAndLiteral,
|
||||
boxes: @mut ~[pp::breaks],
|
||||
ann: pp_ann
|
||||
ann: @pp_ann
|
||||
}
|
||||
|
||||
pub fn ibox(s: @ps, u: uint) {
|
||||
|
@ -74,12 +84,13 @@ pub fn end(s: @ps) {
|
|||
}
|
||||
|
||||
pub fn rust_printer(writer: @io::Writer, intr: @ident_interner) -> @ps {
|
||||
return rust_printer_annotated(writer, intr, no_ann());
|
||||
return rust_printer_annotated(writer, intr, @no_ann::new() as @pp_ann);
|
||||
}
|
||||
|
||||
pub fn rust_printer_annotated(writer: @io::Writer,
|
||||
intr: @ident_interner,
|
||||
ann: pp_ann) -> @ps {
|
||||
ann: @pp_ann)
|
||||
-> @ps {
|
||||
return @ps {
|
||||
s: pp::mk_printer(writer, default_columns),
|
||||
cm: None::<@CodeMap>,
|
||||
|
@ -109,7 +120,7 @@ pub fn print_crate(cm: @CodeMap,
|
|||
filename: @str,
|
||||
input: @io::Reader,
|
||||
out: @io::Writer,
|
||||
ann: pp_ann,
|
||||
ann: @pp_ann,
|
||||
is_expanded: bool) {
|
||||
let (cmnts, lits) = comments::gather_comments_and_literals(
|
||||
span_diagnostic,
|
||||
|
@ -484,7 +495,7 @@ pub fn print_item(s: @ps, item: &ast::item) {
|
|||
maybe_print_comment(s, item.span.lo);
|
||||
print_outer_attributes(s, item.attrs);
|
||||
let ann_node = node_item(s, item);
|
||||
(s.ann.pre)(ann_node);
|
||||
s.ann.pre(ann_node);
|
||||
match item.node {
|
||||
ast::item_static(ref ty, m, expr) => {
|
||||
head(s, visibility_qualified(item.vis, "static"));
|
||||
|
@ -635,7 +646,7 @@ pub fn print_item(s: @ps, item: &ast::item) {
|
|||
end(s);
|
||||
}
|
||||
}
|
||||
(s.ann.post)(ann_node);
|
||||
s.ann.post(ann_node);
|
||||
}
|
||||
|
||||
fn print_trait_ref(s: @ps, t: &ast::trait_ref) {
|
||||
|
@ -958,7 +969,7 @@ pub fn print_possibly_embedded_block_(s: @ps,
|
|||
}
|
||||
maybe_print_comment(s, blk.span.lo);
|
||||
let ann_node = node_block(s, blk);
|
||||
(s.ann.pre)(ann_node);
|
||||
s.ann.pre(ann_node);
|
||||
match embedded {
|
||||
block_block_fn => end(s),
|
||||
block_normal => bopen(s)
|
||||
|
@ -979,7 +990,7 @@ pub fn print_possibly_embedded_block_(s: @ps,
|
|||
_ => ()
|
||||
}
|
||||
bclose_maybe_open(s, blk.span, indented, close_box);
|
||||
(s.ann.post)(ann_node);
|
||||
s.ann.post(ann_node);
|
||||
}
|
||||
|
||||
pub fn print_if(s: @ps, test: &ast::Expr, blk: &ast::Block,
|
||||
|
@ -1121,7 +1132,7 @@ pub fn print_expr(s: @ps, expr: &ast::Expr) {
|
|||
maybe_print_comment(s, expr.span.lo);
|
||||
ibox(s, indent_unit);
|
||||
let ann_node = node_expr(s, expr);
|
||||
(s.ann.pre)(ann_node);
|
||||
s.ann.pre(ann_node);
|
||||
match expr.node {
|
||||
ast::ExprVstore(e, v) => {
|
||||
print_expr_vstore(s, v);
|
||||
|
@ -1456,7 +1467,7 @@ pub fn print_expr(s: @ps, expr: &ast::Expr) {
|
|||
pclose(s);
|
||||
}
|
||||
}
|
||||
(s.ann.post)(ann_node);
|
||||
s.ann.post(ann_node);
|
||||
end(s);
|
||||
}
|
||||
|
||||
|
@ -1578,7 +1589,7 @@ pub fn print_bounded_path(s: @ps, path: &ast::Path,
|
|||
pub fn print_pat(s: @ps, pat: &ast::Pat) {
|
||||
maybe_print_comment(s, pat.span.lo);
|
||||
let ann_node = node_pat(s, pat);
|
||||
(s.ann.pre)(ann_node);
|
||||
s.ann.pre(ann_node);
|
||||
/* Pat isn't normalized, but the beauty of it
|
||||
is that it doesn't matter */
|
||||
match pat.node {
|
||||
|
@ -1678,7 +1689,7 @@ pub fn print_pat(s: @ps, pat: &ast::Pat) {
|
|||
word(s.s, "]");
|
||||
}
|
||||
}
|
||||
(s.ann.post)(ann_node);
|
||||
s.ann.post(ann_node);
|
||||
}
|
||||
|
||||
pub fn explicit_self_to_str(explicit_self: &ast::explicit_self_, intr: @ident_interner) -> ~str {
|
||||
|
@ -2254,17 +2265,6 @@ pub fn print_fn_header_info(s: @ps,
|
|||
print_opt_sigil(s, opt_sigil);
|
||||
}
|
||||
|
||||
pub fn opt_sigil_to_str(opt_p: Option<ast::Sigil>) -> &'static str {
|
||||
match opt_p {
|
||||
None => "fn",
|
||||
Some(p) => match p {
|
||||
ast::BorrowedSigil => "fn&",
|
||||
ast::OwnedSigil => "fn~",
|
||||
ast::ManagedSigil => "fn@"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn purity_to_str(p: ast::purity) -> &'static str {
|
||||
match p {
|
||||
ast::impure_fn => "impure",
|
||||
|
|
|
@ -14,7 +14,7 @@ pub struct Entry<A,B> {
|
|||
}
|
||||
|
||||
pub struct alist<A,B> {
|
||||
eq_fn: @fn(A,A) -> bool,
|
||||
eq_fn: extern "Rust" fn(A,A) -> bool,
|
||||
data: @mut ~[Entry<A,B>]
|
||||
}
|
||||
|
||||
|
|
|
@ -1,14 +0,0 @@
|
|||
// Copyright 2012 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.
|
||||
|
||||
pub fn to_closure<A:'static + Clone>(x: A) -> @fn() -> A {
|
||||
let result: @fn() -> A = || x.clone();
|
||||
result
|
||||
}
|
|
@ -46,7 +46,6 @@ type nillist = List<()>;
|
|||
struct State {
|
||||
box: @nillist,
|
||||
unique: ~nillist,
|
||||
fn_box: @fn() -> @nillist,
|
||||
tuple: (@nillist, ~nillist),
|
||||
vec: ~[@nillist],
|
||||
res: r
|
||||
|
@ -79,19 +78,15 @@ fn recurse_or_fail(depth: int, st: Option<State>) {
|
|||
State {
|
||||
box: @Nil,
|
||||
unique: ~Nil,
|
||||
fn_box: || @Nil::<()>,
|
||||
tuple: (@Nil, ~Nil),
|
||||
vec: ~[@Nil],
|
||||
res: r(@Nil)
|
||||
}
|
||||
}
|
||||
Some(st) => {
|
||||
let fn_box = st.fn_box;
|
||||
|
||||
State {
|
||||
box: @Cons((), st.box),
|
||||
unique: ~Cons((), @*st.unique),
|
||||
fn_box: || @Cons((), fn_box()),
|
||||
tuple: (@Cons((), st.tuple.first()),
|
||||
~Cons((), @*st.tuple.second())),
|
||||
vec: st.vec + &[@Cons((), *st.vec.last())],
|
||||
|
|
|
@ -1,27 +0,0 @@
|
|||
// Copyright 2012 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.
|
||||
|
||||
fn foo(x: @int) -> @fn() -> &'static int {
|
||||
let result: @fn() -> &'static int = || &*x; //~ ERROR cannot root
|
||||
result
|
||||
}
|
||||
|
||||
fn bar(x: @int) -> @fn() -> &int {
|
||||
let result: @fn() -> &int = || &*x; //~ ERROR cannot root
|
||||
result
|
||||
}
|
||||
|
||||
fn zed(x: @int) -> @fn() -> int {
|
||||
let result: @fn() -> int = || *&*x;
|
||||
result
|
||||
}
|
||||
|
||||
fn main() {
|
||||
}
|
|
@ -1,13 +1,13 @@
|
|||
pub fn main() {
|
||||
let foo = ~3;
|
||||
let _pfoo = &foo;
|
||||
let _f: @fn() -> int = || *foo + 5;
|
||||
let _f: ~fn() -> int = || *foo + 5;
|
||||
//~^ ERROR cannot move `foo`
|
||||
|
||||
// FIXME(#2202) - Due to the way that borrowck treats closures,
|
||||
// you get two error reports here.
|
||||
let bar = ~3;
|
||||
let _g = || { //~ ERROR capture of moved value
|
||||
let _h: @fn() -> int = || *bar; //~ ERROR capture of moved value
|
||||
let _h: ~fn() -> int = || *bar; //~ ERROR capture of moved value
|
||||
};
|
||||
}
|
||||
|
|
|
@ -9,10 +9,10 @@
|
|||
// except according to those terms.
|
||||
|
||||
struct X {
|
||||
field: @fn:Send(),
|
||||
field: ~fn:Send(),
|
||||
}
|
||||
|
||||
fn foo(blk: @fn:()) -> X {
|
||||
fn foo(blk: ~fn:()) -> X {
|
||||
return X { field: blk }; //~ ERROR expected bounds `Send` but found no bounds
|
||||
}
|
||||
|
||||
|
|
|
@ -1,3 +1,8 @@
|
|||
// xfail-test
|
||||
|
||||
// xfail'd because the lint pass doesn't know to ignore standard library
|
||||
// stuff.
|
||||
|
||||
// -*- rust -*-
|
||||
// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
fn f(f: @fn(int) -> bool) -> bool { f(10i) }
|
||||
fn f(f: &fn(int) -> bool) -> bool { f(10i) }
|
||||
|
||||
fn main() {
|
||||
assert!(do f() |i| { i == 10i } == 10i);
|
||||
|
|
|
@ -1,30 +0,0 @@
|
|||
// Copyright 2012 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.
|
||||
|
||||
fn reproduce<T>(t: T) -> @fn() -> T {
|
||||
let result: @fn() -> T = || t;
|
||||
result
|
||||
}
|
||||
|
||||
fn main() {
|
||||
// type of x is the variable X,
|
||||
// with the lower bound @mut int
|
||||
let x = @mut 3;
|
||||
|
||||
// type of r is @fn() -> X
|
||||
let r = reproduce(x);
|
||||
|
||||
// Requires that X be a subtype of
|
||||
// @mut int.
|
||||
let f: @mut int = r();
|
||||
|
||||
// Bad.
|
||||
let h: @int = r(); //~ ERROR (values differ in mutability)
|
||||
}
|
|
@ -1,32 +0,0 @@
|
|||
// Copyright 2012 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.
|
||||
|
||||
fn mk_identity<T>() -> @fn(T) -> T {
|
||||
let result: @fn(t: T) -> T = |t| t;
|
||||
result
|
||||
}
|
||||
|
||||
fn main() {
|
||||
// type of r is @fn(X) -> X
|
||||
// for some fresh X
|
||||
let r = mk_identity();
|
||||
|
||||
// @mut int <: X
|
||||
r(@mut 3);
|
||||
|
||||
// @int <: X
|
||||
//
|
||||
// Here the type check fails because @const is gone and there is no
|
||||
// supertype.
|
||||
r(@3); //~ ERROR mismatched types
|
||||
|
||||
// Here the type check succeeds.
|
||||
*r(@mut 3) = 4;
|
||||
}
|
|
@ -9,8 +9,8 @@
|
|||
// except according to those terms.
|
||||
|
||||
// xfail-test
|
||||
struct T { f: @fn() };
|
||||
struct S { f: @fn() };
|
||||
struct T { f: extern "Rust" fn() };
|
||||
struct S { f: extern "Rust" fn() };
|
||||
|
||||
fn fooS(t: S) {
|
||||
}
|
||||
|
@ -22,11 +22,11 @@ fn bar() {
|
|||
}
|
||||
|
||||
fn main() {
|
||||
let x: @fn() = bar;
|
||||
let x: extern "Rust" fn() = bar;
|
||||
fooS(S {f: x});
|
||||
fooS(S {f: bar});
|
||||
|
||||
let x: @fn() = bar;
|
||||
let x: extern "Rust" fn() = bar;
|
||||
fooT(T {f: x});
|
||||
fooT(T {f: bar});
|
||||
}
|
||||
|
|
|
@ -1,26 +0,0 @@
|
|||
// Copyright 2012 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.
|
||||
|
||||
// Test that we require managed closures to be rooted when borrowed.
|
||||
|
||||
struct boxedFn<'self> { theFn: &'self fn() -> uint }
|
||||
|
||||
fn createClosure (closedUint: uint) -> boxedFn {
|
||||
let theFn: @fn() -> uint = || closedUint;
|
||||
boxedFn {theFn: theFn} //~ ERROR cannot root
|
||||
}
|
||||
|
||||
fn main () {
|
||||
let aFn: boxedFn = createClosure(10);
|
||||
|
||||
let myInt: uint = (aFn.theFn)();
|
||||
|
||||
assert_eq!(myInt, 10);
|
||||
}
|
|
@ -10,11 +10,11 @@
|
|||
|
||||
// xfail-test
|
||||
fn main() {
|
||||
let one: @fn() -> uint = || {
|
||||
let one: &fn() -> uint = || {
|
||||
enum r { a };
|
||||
a as uint
|
||||
};
|
||||
let two = @fn() -> uint = || {
|
||||
let two = &fn() -> uint = || {
|
||||
enum r { a };
|
||||
a as uint
|
||||
};
|
||||
|
|
|
@ -1,3 +1,7 @@
|
|||
// xfail-test
|
||||
// xfail'd because the lint pass doesn't know to ignore standard library
|
||||
// stuff.
|
||||
|
||||
// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
// xfail-test
|
||||
|
||||
// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
|
|
|
@ -1,28 +0,0 @@
|
|||
// Copyright 2012 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.
|
||||
|
||||
fn copy1<T:Clone>(t: T) -> @fn() -> T {
|
||||
let result: @fn() -> T = || t.clone(); //~ ERROR does not fulfill `'static`
|
||||
result
|
||||
}
|
||||
|
||||
fn copy2<T:Clone + 'static>(t: T) -> @fn() -> T {
|
||||
let result: @fn() -> T = || t.clone();
|
||||
result
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let x = &3;
|
||||
copy2(&x); //~ ERROR does not fulfill `'static`
|
||||
|
||||
copy2(@3);
|
||||
copy2(@&x); //~ ERROR value may contain borrowed pointers
|
||||
//~^ ERROR does not fulfill `'static`
|
||||
}
|
|
@ -1,25 +0,0 @@
|
|||
// Copyright 2012 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.
|
||||
|
||||
// Make sure that nesting a block within a @fn doesn't let us
|
||||
// mutate upvars from a @fn.
|
||||
fn f2(x: &fn()) { x(); }
|
||||
|
||||
fn main() {
|
||||
let i = 0;
|
||||
let ctr: @fn() -> int = || { f2(|| i = i + 1 ); i };
|
||||
//~^ ERROR cannot assign
|
||||
error!(ctr());
|
||||
error!(ctr());
|
||||
error!(ctr());
|
||||
error!(ctr());
|
||||
error!(ctr());
|
||||
error!(i);
|
||||
}
|
|
@ -1,22 +0,0 @@
|
|||
// Copyright 2012 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.
|
||||
|
||||
// Make sure we can't write to upvars from @fns
|
||||
fn main() {
|
||||
let i = 0;
|
||||
let ctr: @fn() -> int = || { i = i + 1; i };
|
||||
//~^ ERROR cannot assign
|
||||
error!(ctr());
|
||||
error!(ctr());
|
||||
error!(ctr());
|
||||
error!(ctr());
|
||||
error!(ctr());
|
||||
error!(i);
|
||||
}
|
|
@ -9,7 +9,7 @@
|
|||
// except according to those terms.
|
||||
|
||||
fn main() {
|
||||
let j: @fn() -> int = || {
|
||||
let j: &fn() -> int = || {
|
||||
let i: int;
|
||||
i //~ ERROR use of possibly uninitialized variable: `i`
|
||||
};
|
||||
|
|
|
@ -9,7 +9,7 @@
|
|||
// except according to those terms.
|
||||
|
||||
fn main() {
|
||||
let f: @fn() -> int = || {
|
||||
let f: &fn() -> int = || {
|
||||
let i: int;
|
||||
i //~ ERROR use of possibly uninitialized variable: `i`
|
||||
};
|
||||
|
|
|
@ -8,8 +8,8 @@
|
|||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
fn of<T>() -> @fn(T) { fail!(); }
|
||||
fn subtype<T>(x: @fn(T)) { fail!(); }
|
||||
fn of<T>() -> &fn(T) { fail!(); }
|
||||
fn subtype<T>(x: &fn(T)) { fail!(); }
|
||||
|
||||
fn test_fn<'x,'y,'z,T>(_x: &'x T, _y: &'y T, _z: &'z T) {
|
||||
// Here, x, y, and z are free. Other letters
|
||||
|
@ -40,18 +40,6 @@ fn test_fn<'x,'y,'z,T>(_x: &'x T, _y: &'y T, _z: &'z T) {
|
|||
|
||||
subtype::<&fn<'x,'y>(&'x T, &'y T)>(
|
||||
of::<&fn<'a,'b>(&'a T, &'b T)>()); //~ ERROR mismatched types
|
||||
|
||||
subtype::<&fn<'x,'a>(&'x T) -> @fn(&'a T)>(
|
||||
of::<&fn<'x,'a>(&'x T) -> @fn(&'a T)>());
|
||||
|
||||
subtype::<&fn<'a>(&'a T) -> @fn(&'a T)>(
|
||||
of::<&fn<'a,'b>(&'a T) -> @fn(&'b T)>()); //~ ERROR mismatched types
|
||||
|
||||
subtype::<&fn<'a>(&'a T) -> @fn(&'a T)>(
|
||||
of::<&fn<'x,'b>(&'x T) -> @fn(&'b T)>()); //~ ERROR mismatched types
|
||||
|
||||
subtype::<&fn<'a,'b>(&'a T) -> @fn(&'b T)>(
|
||||
of::<&fn<'a>(&'a T) -> @fn(&'a T)>());
|
||||
}
|
||||
|
||||
fn main() {}
|
||||
|
|
|
@ -12,7 +12,7 @@
|
|||
// we reported errors in this case:
|
||||
|
||||
fn not_ok<'b>(a: &uint, b: &'b uint) {
|
||||
let mut g: @fn(x: &uint) = |x: &'b uint| {};
|
||||
let mut g: &fn(x: &uint) = |x: &'b uint| {};
|
||||
//~^ ERROR mismatched types
|
||||
g(a);
|
||||
}
|
||||
|
|
|
@ -13,11 +13,11 @@ struct parameterized1<'self> {
|
|||
}
|
||||
|
||||
struct not_parameterized1 {
|
||||
g: @fn()
|
||||
g: &'static fn()
|
||||
}
|
||||
|
||||
struct not_parameterized2 {
|
||||
g: @fn()
|
||||
g: &'static fn()
|
||||
}
|
||||
|
||||
fn take1(p: parameterized1) -> parameterized1 { p }
|
||||
|
|
|
@ -14,7 +14,7 @@
|
|||
// the normal case.
|
||||
|
||||
struct contravariant<'self> {
|
||||
f: @fn() -> &'self int
|
||||
f: &'static fn() -> &'self int
|
||||
}
|
||||
|
||||
fn to_same_lifetime<'r>(bi: contravariant<'r>) {
|
||||
|
|
|
@ -13,7 +13,7 @@
|
|||
// You can upcast to a *larger region* but not a smaller one.
|
||||
|
||||
struct covariant<'self> {
|
||||
f: @fn(x: &'self int) -> int
|
||||
f: &'static fn(x: &'self int) -> int
|
||||
}
|
||||
|
||||
fn to_same_lifetime<'r>(bi: covariant<'r>) {
|
||||
|
|
|
@ -9,7 +9,7 @@
|
|||
// except according to those terms.
|
||||
|
||||
struct invariant<'self> {
|
||||
f: @fn(x: @mut &'self int)
|
||||
f: &'static fn(x: @mut &'self int)
|
||||
}
|
||||
|
||||
fn to_same_lifetime<'r>(bi: invariant<'r>) {
|
||||
|
|
|
@ -9,7 +9,7 @@
|
|||
// except according to those terms.
|
||||
|
||||
struct invariant<'self> {
|
||||
f: @fn() -> @mut &'self int
|
||||
f: &'static fn() -> @mut &'self int
|
||||
}
|
||||
|
||||
fn to_same_lifetime<'r>(bi: invariant<'r>) {
|
||||
|
|
|
@ -14,12 +14,12 @@ struct direct<'self> {
|
|||
|
||||
struct indirect1 {
|
||||
// Here the lifetime parameter of direct is bound by the fn()
|
||||
g: @fn(direct)
|
||||
g: &'static fn(direct)
|
||||
}
|
||||
|
||||
struct indirect2<'self> {
|
||||
// But here it is set to 'self
|
||||
g: @fn(direct<'self>)
|
||||
g: &'static fn(direct<'self>)
|
||||
}
|
||||
|
||||
fn take_direct(p: direct) -> direct { p } //~ ERROR mismatched types
|
||||
|
|
|
@ -1,18 +0,0 @@
|
|||
// Copyright 2012 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.
|
||||
|
||||
fn test(f: @fn(uint) -> uint) -> uint {
|
||||
return f(22u);
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let f: ~fn(x: uint) -> uint = |x| 4u;
|
||||
info!(test(f)); //~ ERROR expected @ closure, found ~ closure
|
||||
}
|
|
@ -1,77 +0,0 @@
|
|||
// Copyright 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.
|
||||
|
||||
// compile-flags:-Z extra-debug-info
|
||||
// debugger:rbreak zzz
|
||||
// debugger:run
|
||||
|
||||
// debugger:finish
|
||||
// debugger:print x
|
||||
// check:$1 = false
|
||||
// debugger:continue
|
||||
|
||||
// debugger:finish
|
||||
// debugger:print x
|
||||
// check:$2 = false
|
||||
// debugger:continue
|
||||
|
||||
// debugger:finish
|
||||
// debugger:print x
|
||||
// check:$3 = 1000
|
||||
// debugger:continue
|
||||
|
||||
// debugger:finish
|
||||
// debugger:print x
|
||||
// check:$4 = 2.5
|
||||
// debugger:continue
|
||||
|
||||
// debugger:finish
|
||||
// debugger:print x
|
||||
// check:$5 = true
|
||||
// debugger:continue
|
||||
|
||||
// debugger:finish
|
||||
// debugger:print x
|
||||
// check:$6 = false
|
||||
// debugger:continue
|
||||
|
||||
fn main() {
|
||||
|
||||
let x = false;
|
||||
|
||||
zzz();
|
||||
sentinel();
|
||||
|
||||
let managed_closure: @fn(int) = |x| {
|
||||
zzz();
|
||||
sentinel();
|
||||
|
||||
let x = 2.5;
|
||||
|
||||
zzz();
|
||||
sentinel();
|
||||
|
||||
let x = true;
|
||||
|
||||
zzz();
|
||||
sentinel();
|
||||
};
|
||||
|
||||
zzz();
|
||||
sentinel();
|
||||
|
||||
managed_closure(1000);
|
||||
|
||||
zzz();
|
||||
sentinel();
|
||||
}
|
||||
|
||||
fn zzz() {()}
|
||||
fn sentinel() {()}
|
|
@ -1,56 +0,0 @@
|
|||
// Copyright 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.
|
||||
|
||||
// compile-flags:-Z extra-debug-info
|
||||
// debugger:rbreak zzz
|
||||
// debugger:run
|
||||
// debugger:finish
|
||||
|
||||
// debugger:print constant
|
||||
// check:$1 = 1
|
||||
// debugger:print a_struct
|
||||
// check:$2 = {a = -2, b = 3.5, c = 4}
|
||||
// debugger:print *owned
|
||||
// check:$3 = 5
|
||||
// debugger:print managed->val
|
||||
// check:$4 = 6
|
||||
|
||||
#[allow(unused_variable)];
|
||||
|
||||
struct Struct {
|
||||
a: int,
|
||||
b: float,
|
||||
c: uint
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let constant = 1;
|
||||
|
||||
let a_struct = Struct {
|
||||
a: -2,
|
||||
b: 3.5,
|
||||
c: 4
|
||||
};
|
||||
|
||||
let owned = ~5;
|
||||
let managed = @6;
|
||||
|
||||
let closure: @fn() = || {
|
||||
zzz();
|
||||
do_something(&constant, &a_struct.a, owned, managed);
|
||||
};
|
||||
|
||||
closure();
|
||||
}
|
||||
|
||||
fn do_something(_: &int, _:&int, _:&int, _:&int) {
|
||||
}
|
||||
|
||||
fn zzz() {()}
|
|
@ -1,12 +0,0 @@
|
|||
// Copyright 2012 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.
|
||||
|
||||
fn blk1(_b: &fn()) -> @fn() { return || { }; }
|
||||
fn test1() { (do blk1 { info!("hi"); })(); }
|
|
@ -10,6 +10,6 @@
|
|||
|
||||
// pp-exact
|
||||
|
||||
fn f(f: @fn(int)) { f(10) }
|
||||
fn f(f: &fn(int)) { f(10) }
|
||||
|
||||
fn main() { do f |i| { assert!(i == 10) } }
|
||||
|
|
|
@ -12,6 +12,5 @@
|
|||
|
||||
fn from_foreign_fn(_x: extern "Rust" fn()) { }
|
||||
fn from_stack_closure(_x: &fn()) { }
|
||||
fn from_box_closure(_x: @fn()) { }
|
||||
fn from_unique_closure(_x: ~fn()) { }
|
||||
fn main() { }
|
||||
|
|
|
@ -1,24 +0,0 @@
|
|||
// Copyright 2012 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.
|
||||
|
||||
// error-pattern:fail
|
||||
|
||||
fn failfn() {
|
||||
fail!();
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let y = ~0;
|
||||
let x: @@fn() = @|| {
|
||||
error!(y.clone());
|
||||
};
|
||||
failfn();
|
||||
error!(x);
|
||||
}
|
|
@ -1,21 +0,0 @@
|
|||
// Copyright 2012 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.
|
||||
|
||||
// error-pattern:fail
|
||||
|
||||
fn f(_a: @int) {
|
||||
fail!();
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let b = @0;
|
||||
let g: @fn() = || f(b);
|
||||
g();
|
||||
}
|
|
@ -14,7 +14,7 @@ fn main() {
|
|||
let cheese = ~"roquefort";
|
||||
let carrots = @~"crunchy";
|
||||
|
||||
let result: @fn(@~str, &fn(~str)) = (|tasties, macerate| {
|
||||
let result: &'static fn(@~str, &fn(~str)) = (|tasties, macerate| {
|
||||
macerate((*tasties).clone());
|
||||
});
|
||||
result(carrots, |food| {
|
||||
|
|
|
@ -12,13 +12,30 @@ struct pair<A,B> {
|
|||
a: A, b: B
|
||||
}
|
||||
|
||||
fn f<A:Clone + 'static>(a: A, b: u16) -> @fn() -> (A, u16) {
|
||||
let result: @fn() -> (A, u16) = || (a.clone(), b);
|
||||
result
|
||||
trait Invokable<A> {
|
||||
fn f(&self) -> (A, u16);
|
||||
}
|
||||
|
||||
struct Invoker<A> {
|
||||
a: A,
|
||||
b: u16,
|
||||
}
|
||||
|
||||
impl<A:Clone> Invokable<A> for Invoker<A> {
|
||||
fn f(&self) -> (A, u16) {
|
||||
(self.a.clone(), self.b)
|
||||
}
|
||||
}
|
||||
|
||||
fn f<A:Clone + 'static>(a: A, b: u16) -> @Invokable<A> {
|
||||
@Invoker {
|
||||
a: a,
|
||||
b: b,
|
||||
} as @Invokable<A>
|
||||
}
|
||||
|
||||
pub fn main() {
|
||||
let (a, b) = f(22_u64, 44u16)();
|
||||
let (a, b) = f(22_u64, 44u16).f();
|
||||
info!("a=%? b=%?", a, b);
|
||||
assert_eq!(a, 22u64);
|
||||
assert_eq!(b, 44u16);
|
||||
|
|
|
@ -23,13 +23,30 @@ fn make_cycle<A:'static>(a: A) {
|
|||
g.rec = Some(g);
|
||||
}
|
||||
|
||||
struct Invoker<A,B> {
|
||||
a: A,
|
||||
b: B,
|
||||
}
|
||||
|
||||
trait Invokable<A,B> {
|
||||
fn f(&self) -> (A, B);
|
||||
}
|
||||
|
||||
impl<A:Clone,B:Clone> Invokable<A,B> for Invoker<A,B> {
|
||||
fn f(&self) -> (A, B) {
|
||||
(self.a.clone(), self.b.clone())
|
||||
}
|
||||
}
|
||||
|
||||
fn f<A:Send + Clone + 'static,
|
||||
B:Send + Clone + 'static>(
|
||||
a: A,
|
||||
b: B)
|
||||
-> @fn() -> (A, B) {
|
||||
let result: @fn() -> (A, B) = || (a.clone(), b.clone());
|
||||
result
|
||||
-> @Invokable<A,B> {
|
||||
@Invoker {
|
||||
a: a,
|
||||
b: b,
|
||||
} as @Invokable<A,B>
|
||||
}
|
||||
|
||||
pub fn main() {
|
||||
|
@ -37,7 +54,7 @@ pub fn main() {
|
|||
let y = 44_u64;
|
||||
let z = f(~x, y);
|
||||
make_cycle(z);
|
||||
let (a, b) = z();
|
||||
let (a, b) = z.f();
|
||||
info!("a=%u b=%u", *a as uint, b as uint);
|
||||
assert_eq!(*a, x);
|
||||
assert_eq!(b, y);
|
||||
|
|
|
@ -14,10 +14,6 @@ fn asSendfn( f : ~fn()->uint ) -> uint {
|
|||
return f();
|
||||
}
|
||||
|
||||
fn asLambda( f : @fn()->uint ) -> uint {
|
||||
return f();
|
||||
}
|
||||
|
||||
fn asBlock( f : &fn()->uint ) -> uint {
|
||||
return f();
|
||||
}
|
||||
|
@ -25,8 +21,6 @@ fn asBlock( f : &fn()->uint ) -> uint {
|
|||
pub fn main() {
|
||||
let x = asSendfn(|| 22u);
|
||||
assert_eq!(x, 22u);
|
||||
let x = asLambda(|| 22u);
|
||||
assert_eq!(x, 22u);
|
||||
let x = asBlock(|| 22u);
|
||||
assert_eq!(x, 22u);
|
||||
}
|
||||
|
|
|
@ -1,24 +0,0 @@
|
|||
// Copyright 2012 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.
|
||||
|
||||
fn to_lambda(f: @fn(uint) -> uint) -> @fn(uint) -> uint {
|
||||
return f;
|
||||
}
|
||||
|
||||
pub fn main() {
|
||||
let x: @fn(uint) -> uint = to_lambda(|x| x * 2u );
|
||||
let y = to_lambda(x);
|
||||
|
||||
let x_r = x(22u);
|
||||
let y_r = y(x_r);
|
||||
|
||||
assert_eq!(x_r, 44u);
|
||||
assert_eq!(y_r, 88u);
|
||||
}
|
|
@ -1,5 +1,5 @@
|
|||
pub fn main() {
|
||||
let bar = ~3;
|
||||
let h: @fn() -> int = || *bar;
|
||||
let h: ~fn() -> int = || *bar;
|
||||
assert_eq!(h(), 3);
|
||||
}
|
||||
|
|
|
@ -11,7 +11,7 @@
|
|||
fn foo() -> int { 22 }
|
||||
|
||||
pub fn main() {
|
||||
let mut x: ~[@fn() -> int] = ~[];
|
||||
let mut x: ~[extern "Rust" fn() -> int] = ~[];
|
||||
x.push(foo);
|
||||
assert_eq!((x[0])(), 22);
|
||||
}
|
||||
|
|
|
@ -11,16 +11,6 @@
|
|||
use std::ptr;
|
||||
|
||||
pub fn main() {
|
||||
let x = ~1;
|
||||
let y = ptr::to_unsafe_ptr(&(*x)) as uint;
|
||||
let lam_move: @fn() -> uint = || ptr::to_unsafe_ptr(&(*x)) as uint;
|
||||
assert_eq!(lam_move(), y);
|
||||
|
||||
let x = ~2;
|
||||
let y = ptr::to_unsafe_ptr(&(*x)) as uint;
|
||||
let lam_move: @fn() -> uint = || ptr::to_unsafe_ptr(&(*x)) as uint;
|
||||
assert_eq!(lam_move(), y);
|
||||
|
||||
let x = ~3;
|
||||
let y = ptr::to_unsafe_ptr(&(*x)) as uint;
|
||||
let snd_move: ~fn() -> uint = || ptr::to_unsafe_ptr(&(*x)) as uint;
|
||||
|
|
|
@ -16,13 +16,30 @@ struct Pair<A,B> {
|
|||
a: A, b: B
|
||||
}
|
||||
|
||||
fn f<A:Clone + 'static>(a: A, b: u16) -> @fn() -> (A, u16) {
|
||||
let result: @fn() -> (A, u16) = || (a.clone(), b);
|
||||
result
|
||||
struct Invoker<A> {
|
||||
a: A,
|
||||
b: u16,
|
||||
}
|
||||
|
||||
trait Invokable<A> {
|
||||
fn f(&self) -> (A, u16);
|
||||
}
|
||||
|
||||
impl<A:Clone> Invokable<A> for Invoker<A> {
|
||||
fn f(&self) -> (A, u16) {
|
||||
(self.a.clone(), self.b)
|
||||
}
|
||||
}
|
||||
|
||||
fn f<A:Clone + 'static>(a: A, b: u16) -> @Invokable<A> {
|
||||
@Invoker {
|
||||
a: a,
|
||||
b: b,
|
||||
} as @Invokable<A>
|
||||
}
|
||||
|
||||
pub fn main() {
|
||||
let (a, b) = f(22_u64, 44u16)();
|
||||
let (a, b) = f(22_u64, 44u16).f();
|
||||
info!("a=%? b=%?", a, b);
|
||||
assert_eq!(a, 22u64);
|
||||
assert_eq!(b, 44u16);
|
||||
|
|
|
@ -8,13 +8,33 @@
|
|||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
struct foo { z: @fn() }
|
||||
struct foo {
|
||||
z: Option<@Invokable>,
|
||||
}
|
||||
|
||||
struct Thing {
|
||||
w: @mut foo,
|
||||
}
|
||||
|
||||
trait Invokable {
|
||||
fn f(&self);
|
||||
}
|
||||
|
||||
impl Invokable for Thing {
|
||||
fn f(&self) {
|
||||
nop_foo(self.w);
|
||||
}
|
||||
}
|
||||
|
||||
fn nop() { }
|
||||
fn nop_foo(_x : @mut foo) { }
|
||||
|
||||
pub fn main() {
|
||||
let w = @mut foo{ z: || nop() };
|
||||
let x: @fn() = || nop_foo(w);
|
||||
w.z = x;
|
||||
let w = @mut foo {
|
||||
z: None,
|
||||
};
|
||||
let x = @Thing {
|
||||
w: w,
|
||||
} as @Invokable;
|
||||
w.z = Some(x);
|
||||
}
|
||||
|
|
|
@ -1,20 +0,0 @@
|
|||
// Copyright 2012 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.
|
||||
|
||||
struct foo { z : @fn() }
|
||||
|
||||
fn nop() { }
|
||||
fn nop_foo(_y: ~[int], _x : @mut foo) { }
|
||||
|
||||
pub fn main() {
|
||||
let w = @mut foo{ z: || nop() };
|
||||
let x : @fn() = || nop_foo(~[], w);
|
||||
w.z = x;
|
||||
}
|
|
@ -1,22 +0,0 @@
|
|||
// Copyright 2012 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.
|
||||
|
||||
struct foo { z: @fn() }
|
||||
|
||||
fn nop() { }
|
||||
fn nop_foo(_y: @int, _x: @mut foo) { }
|
||||
|
||||
fn o() -> @int { @10 }
|
||||
|
||||
pub fn main() {
|
||||
let w = @mut foo { z: || nop() };
|
||||
let x : @fn() = || nop_foo(o(), w);
|
||||
w.z = x;
|
||||
}
|
|
@ -10,9 +10,9 @@
|
|||
|
||||
// Testing that we can drop the || in do exprs
|
||||
|
||||
fn f(_f: @fn() -> bool) -> bool { true }
|
||||
fn f(_f: &fn() -> bool) -> bool { true }
|
||||
|
||||
fn d(_f: @fn()) { }
|
||||
fn d(_f: &fn()) { }
|
||||
|
||||
pub fn main() {
|
||||
do d { }
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
fn f(f: @fn(int)) { f(10) }
|
||||
fn f(f: &fn(int)) { f(10) }
|
||||
|
||||
pub fn main() {
|
||||
do f() |i| { assert!(i == 10) }
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
fn f(f: @fn(int) -> int) -> int { f(10) }
|
||||
fn f(f: &fn(int) -> int) -> int { f(10) }
|
||||
|
||||
pub fn main() {
|
||||
assert_eq!(do f() |i| { i }, 10);
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue