<commit_before>use index::btree::internal::InNode;
use index::btree::{NodeCellRef, NodeWriteGuard, write_node, BPlusTree, NodeData};
use index::{EntryKey, Slice};
use std::fmt::Debug;

pub fn is_node_serial<KS, PS>(node: &NodeWriteGuard<KS, PS>) -> bool
where
    KS: Slice<EntryKey> + Debug + 'static,
    PS: Slice<NodeCellRef> + 'static,
{
    // check keys
    for i in 0..node.len() {
        if node.keys()[i] <= smallvec!() {
            error!("EMPTY KEY DETECTED !!!");
            return false;
        }
    }
    for i in 1..node.len() {
        if node.keys()[i - 1] >= node.keys()[i] {
            error!("serial check failed for key ordering");
            return false;
        }
    }
    true
}

pub fn is_node_list_serial<KS, PS>(nodes: &Vec<NodeWriteGuard<KS, PS>>) -> bool
where
    KS: Slice<EntryKey> + Debug + 'static,
    PS: Slice<NodeCellRef> + 'static,
{
    if nodes.len() == 0 {
        return true;
    }
    for (i, n) in nodes.iter().enumerate() {
        if !is_node_serial(n) {
            error!("node at {} not serial", i);
            return false;
        }
    }

    // check right ref
    for i in 0..nodes.len() - 1 {
        let first_right_bound = nodes[i].right_bound();
        let second_first_node = nodes[i + 1].first_key();
        let second_right_bound = nodes[i + 1].right_bound();
        if first_right_bound >= second_right_bound {
            error!("right bound at {} larger than right right bound", i);
            return false;
        }
        if first_right_bound > second_first_node {
            error!("right bound at {} larger than right first node", i);
            return false;
        }
    }
    return true;
}

pub fn is_node_level_serial<KS, PS>(mut node: NodeWriteGuard<KS, PS>, lsm_level: usize, tree_level: usize) -> bool
    where
        KS: Slice<EntryKey> + Debug + 'static,
        PS: Slice<NodeCellRef> + 'static,
{
    let min_key = smallvec!();
    loop {
        let right_ref = node.right_ref().unwrap();
        let right_bound = if !node.is_empty_node() {
            let right_bound = node.right_bound();
            if !is_node_serial(&node) {
                error!("Node not serial - {} - {}", lsm_level, tree_level);
                return false;
            }
            if node.first_key() > right_bound {
                error!("Node have right key smaller than the first - {} - {}", lsm_level, tree_level);
                return false;
            }
            if node.last_key() > right_bound {
                error!("Node have right key smaller than the last - {} - {}", lsm_level, tree_level);
                return false;
            }
            right_bound
        } else {
            &min_key
        };
        let next = write_node(right_ref);
        if next.is_none() {
            debug!("Node level check reached non node - {} - {}", lsm_level, tree_level);
            return true;
        }
        if !next.is_empty_node() {
            assert!(right_bound > &min_key);
            if next.first_key() < right_bound {
                error!("next first key smaller than right bound - {} - {}, type {}. Left keys {:?}, right keys {:?}, right bound {:?}, next right bound {:?}",
                       lsm_level, tree_level, node.type_name(), node.keys(), next.keys(), node.right_bound(), next.right_bound());
                return false;
            }
            if next.right_bound() < right_bound {
                error!("next right bound key smaller than right bound - {} - {}", lsm_level, tree_level);
                return false
            }
        }
        node = next;
    }
}

pub fn is_tree_in_order<KS, PS>(tree: &BPlusTree<KS, PS>, level: usize) -> bool
    where
        KS: Slice<EntryKey> + Debug + 'static,
        PS: Slice<NodeCellRef> + 'static,
{
    debug!("Checking tree {} in order...", level);
    return ensure_level_in_order::<KS, PS>(&tree.get_root(), level, 0);
}

fn ensure_level_in_order<KS, PS>(node: &NodeCellRef, lsm_level: usize, tree_level: usize) -> bool
    where
        KS: Slice<EntryKey> + Debug + 'static,
        PS: Slice<NodeCellRef> + 'static,
{
    let first_node = write_node::<KS, PS>(&node);
    let sub_ref = match &*first_node {
        &NodeData::Internal(ref n) => Some(n.ptrs.as_slice_immute()[0].clone()),
        _ => None
    };
    if !is_node_level_serial(first_node, lsm_level, tree_level) {
        return false;
    }
    if let Some(sub_level) = sub_ref {
        return ensure_level_in_order::<KS, PS>(&sub_level, lsm_level, tree_level + 1);
    }
    return true;
}<commit_msg>assert right bound<commit_after>use index::btree::internal::InNode;
use index::btree::{NodeCellRef, NodeWriteGuard, write_node, BPlusTree, NodeData};
use index::{EntryKey, Slice};
use std::fmt::Debug;

pub fn is_node_serial<KS, PS>(node: &NodeWriteGuard<KS, PS>) -> bool
where
    KS: Slice<EntryKey> + Debug + 'static,
    PS: Slice<NodeCellRef> + 'static,
{
    // check keys
    for i in 0..node.len() {
        if node.keys()[i] <= smallvec!() {
            error!("EMPTY KEY DETECTED !!!");
            return false;
        }
    }
    for i in 1..node.len() {
        if node.keys()[i - 1] >= node.keys()[i] {
            error!("serial check failed for key ordering");
            return false;
        }
    }
    true
}

pub fn is_node_list_serial<KS, PS>(nodes: &Vec<NodeWriteGuard<KS, PS>>) -> bool
where
    KS: Slice<EntryKey> + Debug + 'static,
    PS: Slice<NodeCellRef> + 'static,
{
    if nodes.len() == 0 {
        return true;
    }
    for (i, n) in nodes.iter().enumerate() {
        if !is_node_serial(n) {
            error!("node at {} not serial", i);
            return false;
        }
    }

    // check right ref
    for i in 0..nodes.len() - 1 {
        let first_right_bound = nodes[i].right_bound();
        let second_first_node = nodes[i + 1].first_key();
        let second_right_bound = nodes[i + 1].right_bound();
        if first_right_bound >= second_right_bound {
            error!("right bound at {} larger than right right bound", i);
            return false;
        }
        if first_right_bound > second_first_node {
            error!("right bound at {} larger than right first node", i);
            return false;
        }
    }
    return true;
}

pub fn is_node_level_serial<KS, PS>(mut node: NodeWriteGuard<KS, PS>, lsm_level: usize, tree_level: usize) -> bool
    where
        KS: Slice<EntryKey> + Debug + 'static,
        PS: Slice<NodeCellRef> + 'static,
{
    let min_key = smallvec!();
    loop {
        let right_ref = node.right_ref().unwrap();
        let right_bound = if !node.is_empty_node() {
            let right_bound = node.right_bound();
            assert!(right_bound > &min_key);
            if !is_node_serial(&node) {
                error!("Node not serial - {} - {}", lsm_level, tree_level);
                return false;
            }
            if node.first_key() > right_bound {
                error!("Node have right key smaller than the first - {} - {}", lsm_level, tree_level);
                return false;
            }
            if node.last_key() > right_bound {
                error!("Node have right key smaller than the last - {} - {}", lsm_level, tree_level);
                return false;
            }
            right_bound
        } else {
            &min_key
        };
        let next = write_node(right_ref);
        if next.is_none() {
            debug!("Node level check reached non node - {} - {}", lsm_level, tree_level);
            return true;
        }
        if !next.is_empty_node() {
            assert!(right_bound > &min_key);
            if next.first_key() < right_bound {
                error!("next first key smaller than right bound - {} - {}, type {}. Left keys {:?}, right keys {:?}, right bound {:?}, next right bound {:?}",
                       lsm_level, tree_level, node.type_name(), node.keys(), next.keys(), node.right_bound(), next.right_bound());
                return false;
            }
            if next.right_bound() < right_bound {
                error!("next right bound key smaller than right bound - {} - {}", lsm_level, tree_level);
                return false
            }
        }
        node = next;
    }
}

pub fn is_tree_in_order<KS, PS>(tree: &BPlusTree<KS, PS>, level: usize) -> bool
    where
        KS: Slice<EntryKey> + Debug + 'static,
        PS: Slice<NodeCellRef> + 'static,
{
    debug!("Checking tree {} in order...", level);
    return ensure_level_in_order::<KS, PS>(&tree.get_root(), level, 0);
}

fn ensure_level_in_order<KS, PS>(node: &NodeCellRef, lsm_level: usize, tree_level: usize) -> bool
    where
        KS: Slice<EntryKey> + Debug + 'static,
        PS: Slice<NodeCellRef> + 'static,
{
    let first_node = write_node::<KS, PS>(&node);
    let sub_ref = match &*first_node {
        &NodeData::Internal(ref n) => Some(n.ptrs.as_slice_immute()[0].clone()),
        _ => None
    };
    if !is_node_level_serial(first_node, lsm_level, tree_level) {
        return false;
    }
    if let Some(sub_level) = sub_ref {
        return ensure_level_in_order::<KS, PS>(&sub_level, lsm_level, tree_level + 1);
    }
    return true;
}<|endoftext|>


<commit_before>#![feature(rustc_private)]

extern crate getopts;
extern crate miri;
extern crate rustc;
extern crate rustc_driver;
extern crate env_logger;
extern crate log_settings;
extern crate syntax;
#[macro_use] extern crate log;

use miri::{
    EvalContext,
    CachedMir,
    step,
    EvalError,
    Frame,
};
use rustc::session::Session;
use rustc_driver::{driver, CompilerCalls, Compilation};
use rustc::ty::{TyCtxt, subst};
use rustc::hir::def_id::DefId;

struct MiriCompilerCalls;

impl<'a> CompilerCalls<'a> for MiriCompilerCalls {
    fn build_controller(
        &mut self,
        _: &Session,
        _: &getopts::Matches
    ) -> driver::CompileController<'a> {
        let mut control = driver::CompileController::basic();

        control.after_analysis.stop = Compilation::Stop;
        control.after_analysis.callback = Box::new(|state| {
            state.session.abort_if_errors();

            let tcx = state.tcx.unwrap();
            let mir_map = state.mir_map.unwrap();

            let (node_id, span) = state.session.entry_fn.borrow().expect("no main or start function found");
            debug!("found `main` function at: {:?}", span);

            let mir = mir_map.map.get(&node_id).expect("no mir for main function");
            let def_id = tcx.map.local_def_id(node_id);
            let mut ecx = EvalContext::new(tcx, mir_map);
            let substs = tcx.mk_substs(subst::Substs::empty());
            let return_ptr = ecx.alloc_ret_ptr(mir.return_ty, substs).expect("main function should not be diverging");

            ecx.push_stack_frame(def_id, mir.span, CachedMir::Ref(mir), substs, Some(return_ptr));

            if mir.arg_decls.len() == 2 {
                // start function
                let ptr_size = ecx.memory().pointer_size;
                let nargs = ecx.memory_mut().allocate(ptr_size);
                ecx.memory_mut().write_usize(nargs, 0).unwrap();
                let args = ecx.memory_mut().allocate(ptr_size);
                ecx.memory_mut().write_usize(args, 0).unwrap();
                ecx.frame_mut().locals[0] = nargs;
                ecx.frame_mut().locals[1] = args;
            }

            loop {
                match step(&mut ecx) {
                    Ok(true) => {}
                    Ok(false) => break,
                    // FIXME: diverging functions can end up here in some future miri
                    Err(e) => {
                        report(tcx, &ecx, e);
                        break;
                    }
                }
            }
            state.session.abort_if_errors();
        });

        control
    }
}

fn report(tcx: TyCtxt, ecx: &EvalContext, e: EvalError) {
    let frame = ecx.stack().last().expect("stackframe was empty");
    let block = &frame.mir.basic_blocks()[frame.block];
    let span = if frame.stmt < block.statements.len() {
        block.statements[frame.stmt].source_info.span
    } else {
        block.terminator().source_info.span
    };
    let mut err = tcx.sess.struct_span_err(span, &e.to_string());
    for &Frame { def_id, substs, span, .. } in ecx.stack().iter().rev() {
        // FIXME(solson): Find a way to do this without this Display impl hack.
        use rustc::util::ppaux;
        use std::fmt;
        struct Instance<'tcx>(DefId, &'tcx subst::Substs<'tcx>);
        impl<'tcx> fmt::Display for Instance<'tcx> {
            fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
                ppaux::parameterized(f, self.1, self.0, ppaux::Ns::Value, &[],
                    |tcx| Some(tcx.lookup_item_type(self.0).generics))
            }
        }
        err.span_note(span, &format!("inside call to {}", Instance(def_id, substs)));
    }
    err.emit();
}

fn init_logger() {
    const NSPACES: usize = 40;
    let format = |record: &log::LogRecord| {
        // prepend spaces to indent the final string
        let indentation = log_settings::settings().indentation;
        format!("{lvl}:{module}{depth:2}{indent:<indentation$} {text}",
            lvl = record.level(),
            module = record.location().module_path(),
            depth = indentation / NSPACES,
            indentation = indentation % NSPACES,
            indent = "",
            text = record.args())
    };

    let mut builder = env_logger::LogBuilder::new();
    builder.format(format).filter(None, log::LogLevelFilter::Info);

    if std::env::var("MIRI_LOG").is_ok() {
        builder.parse(&std::env::var("MIRI_LOG").unwrap());
    }

    builder.init().unwrap();
}

fn find_sysroot() -> String {
    // Taken from https://github.com/Manishearth/rust-clippy/pull/911.
    let home = option_env!("RUSTUP_HOME").or(option_env!("MULTIRUST_HOME"));
    let toolchain = option_env!("RUSTUP_TOOLCHAIN").or(option_env!("MULTIRUST_TOOLCHAIN"));
    match (home, toolchain) {
        (Some(home), Some(toolchain)) => format!("{}/toolchains/{}", home, toolchain),
        _ => option_env!("RUST_SYSROOT")
            .expect("need to specify RUST_SYSROOT env var or use rustup or multirust")
            .to_owned(),
    }
}

fn main() {
    init_logger();
    let mut args: Vec<String> = std::env::args().collect();

    let sysroot_flag = String::from("--sysroot");
    if !args.contains(&sysroot_flag) {
        args.push(sysroot_flag);
        args.push(find_sysroot());
    }

    rustc_driver::run_compiler(&args, &mut MiriCompilerCalls);
}
<commit_msg>Only indent trace logs.<commit_after>#![feature(rustc_private)]

extern crate getopts;
extern crate miri;
extern crate rustc;
extern crate rustc_driver;
extern crate env_logger;
extern crate log_settings;
extern crate syntax;
#[macro_use] extern crate log;

use miri::{
    EvalContext,
    CachedMir,
    step,
    EvalError,
    Frame,
};
use rustc::session::Session;
use rustc_driver::{driver, CompilerCalls, Compilation};
use rustc::ty::{TyCtxt, subst};
use rustc::hir::def_id::DefId;

struct MiriCompilerCalls;

impl<'a> CompilerCalls<'a> for MiriCompilerCalls {
    fn build_controller(
        &mut self,
        _: &Session,
        _: &getopts::Matches
    ) -> driver::CompileController<'a> {
        let mut control = driver::CompileController::basic();

        control.after_analysis.stop = Compilation::Stop;
        control.after_analysis.callback = Box::new(|state| {
            state.session.abort_if_errors();

            let tcx = state.tcx.unwrap();
            let mir_map = state.mir_map.unwrap();

            let (node_id, span) = state.session.entry_fn.borrow().expect("no main or start function found");
            debug!("found `main` function at: {:?}", span);

            let mir = mir_map.map.get(&node_id).expect("no mir for main function");
            let def_id = tcx.map.local_def_id(node_id);
            let mut ecx = EvalContext::new(tcx, mir_map);
            let substs = tcx.mk_substs(subst::Substs::empty());
            let return_ptr = ecx.alloc_ret_ptr(mir.return_ty, substs).expect("main function should not be diverging");

            ecx.push_stack_frame(def_id, mir.span, CachedMir::Ref(mir), substs, Some(return_ptr));

            if mir.arg_decls.len() == 2 {
                // start function
                let ptr_size = ecx.memory().pointer_size;
                let nargs = ecx.memory_mut().allocate(ptr_size);
                ecx.memory_mut().write_usize(nargs, 0).unwrap();
                let args = ecx.memory_mut().allocate(ptr_size);
                ecx.memory_mut().write_usize(args, 0).unwrap();
                ecx.frame_mut().locals[0] = nargs;
                ecx.frame_mut().locals[1] = args;
            }

            loop {
                match step(&mut ecx) {
                    Ok(true) => {}
                    Ok(false) => break,
                    // FIXME: diverging functions can end up here in some future miri
                    Err(e) => {
                        report(tcx, &ecx, e);
                        break;
                    }
                }
            }
            state.session.abort_if_errors();
        });

        control
    }
}

fn report(tcx: TyCtxt, ecx: &EvalContext, e: EvalError) {
    let frame = ecx.stack().last().expect("stackframe was empty");
    let block = &frame.mir.basic_blocks()[frame.block];
    let span = if frame.stmt < block.statements.len() {
        block.statements[frame.stmt].source_info.span
    } else {
        block.terminator().source_info.span
    };
    let mut err = tcx.sess.struct_span_err(span, &e.to_string());
    for &Frame { def_id, substs, span, .. } in ecx.stack().iter().rev() {
        // FIXME(solson): Find a way to do this without this Display impl hack.
        use rustc::util::ppaux;
        use std::fmt;
        struct Instance<'tcx>(DefId, &'tcx subst::Substs<'tcx>);
        impl<'tcx> fmt::Display for Instance<'tcx> {
            fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
                ppaux::parameterized(f, self.1, self.0, ppaux::Ns::Value, &[],
                    |tcx| Some(tcx.lookup_item_type(self.0).generics))
            }
        }
        err.span_note(span, &format!("inside call to {}", Instance(def_id, substs)));
    }
    err.emit();
}

fn init_logger() {
    const NSPACES: usize = 40;
    let format = |record: &log::LogRecord| {
        if record.level() == log::LogLevel::Trace {
            // prepend spaces to indent the final string
            let indentation = log_settings::settings().indentation;
            format!("{lvl}:{module}{depth:2}{indent:<indentation$} {text}",
                lvl = record.level(),
                module = record.location().module_path(),
                depth = indentation / NSPACES,
                indentation = indentation % NSPACES,
                indent = "",
                text = record.args())
        } else {
            format!("{lvl}:{module}: {text}",
                lvl = record.level(),
                module = record.location().module_path(),
                text = record.args())
        }
    };

    let mut builder = env_logger::LogBuilder::new();
    builder.format(format).filter(None, log::LogLevelFilter::Info);

    if std::env::var("MIRI_LOG").is_ok() {
        builder.parse(&std::env::var("MIRI_LOG").unwrap());
    }

    builder.init().unwrap();
}

fn find_sysroot() -> String {
    // Taken from https://github.com/Manishearth/rust-clippy/pull/911.
    let home = option_env!("RUSTUP_HOME").or(option_env!("MULTIRUST_HOME"));
    let toolchain = option_env!("RUSTUP_TOOLCHAIN").or(option_env!("MULTIRUST_TOOLCHAIN"));
    match (home, toolchain) {
        (Some(home), Some(toolchain)) => format!("{}/toolchains/{}", home, toolchain),
        _ => option_env!("RUST_SYSROOT")
            .expect("need to specify RUST_SYSROOT env var or use rustup or multirust")
            .to_owned(),
    }
}

fn main() {
    init_logger();
    let mut args: Vec<String> = std::env::args().collect();

    let sysroot_flag = String::from("--sysroot");
    if !args.contains(&sysroot_flag) {
        args.push(sysroot_flag);
        args.push(find_sysroot());
    }

    rustc_driver::run_compiler(&args, &mut MiriCompilerCalls);
}
<|endoftext|>


<commit_before>#![deny(warnings)]

extern crate arg_parser;
extern crate extra;
extern crate time;
extern crate redox_users;

use std::{env, fmt, fs};
use std::io::{stdout, stderr, Write};
use std::os::unix::fs::MetadataExt;
use std::process::exit;

use arg_parser::ArgParser;
use extra::option::OptionalExt;
use redox_users::{AllUsers, AllGroups};

use time::Timespec;

const MAN_PAGE: &'static str = /* @MANSTART{stat} */ r#"
NAME
    stat - display file status

SYNOPSIS
    stat [ -h | --help ] FILE...

DESCRIPTION
    Displays file status.

OPTIONS
    --help, -h
        print this message
"#; /* @MANEND */

const TIME_FMT: &'static str = "%Y-%m-%d %H:%M:%S.%f %z";

struct Perms(u32);

impl fmt::Display for Perms {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "(0{:o}/", self.0 & 0o777)?;
        let perm = |i, c| {
            if self.0 & ((1 << i) as u32) != 0 {
                c
            } else {
                "-"
            }
        };
        write!(f, "{}{}{}", perm(8, "r"), perm(7, "w"), perm(6, "x"))?;
        write!(f, "{}{}{}", perm(5, "r"), perm(4, "w"), perm(3, "x"))?;
        write!(f, "{}{}{}", perm(2, "r"), perm(1, "w"), perm(0, "x"))?;
        write!(f, ")")?;
        Ok(())
    }
}

fn main() {
    let stdout = stdout();
    let mut stdout = stdout.lock();
    let mut stderr = stderr();
    let mut parser = ArgParser::new(1)
        .add_flag(&["h", "help"]);
    parser.parse(env::args());

    if parser.found("help") {
        stdout.write_all(MAN_PAGE.as_bytes()).try(&mut stderr);
        stdout.flush().try(&mut stderr);
        return;
    }
    let (all_users, all_groups) = match (AllUsers::new(false), AllGroups::new()) {
        (Ok(all_users), Ok(all_groups)) => (all_users, all_groups),
        (Err(_), Ok(_)) => {
            eprintln!("Unable to access password file");
            exit(1);
        },
        (Ok(_), Err(_)) => {
            eprintln!("Unable to access group file");
            exit(1);
        }
        _ => {
            eprintln!("Unable to access password and group file");
            exit(1);
        }
    };

    for path in &parser.args[0..] {
        let meta = fs::symlink_metadata(path).unwrap();
        let file_type = if meta.file_type().is_symlink() {
            "symbolic link"
        } else if meta.is_file() {
            "regular file"
        } else if meta.is_dir() {
            "directory"
        } else {
            ""
        };
        if meta.file_type().is_symlink() {
            println!("File: {} -> {}", path, fs::read_link(path).unwrap().display());
        } else {
            println!("File: {}", path);
        }
        let username = all_users.get_by_id(meta.uid() as usize)
            .map(|x| x.user.to_string())
            .unwrap_or("UNKNOWN".to_string());
        let groupname = all_groups.get_by_id(meta.gid() as usize)
            .map(|x| x.group.to_string())
            .unwrap_or("UNKNOWN".to_string());
        println!("Size: {}  Blocks: {}  IO Block: {} {}", meta.size(), meta.blocks(), meta.blksize(), file_type);
        println!("Device: {}  Inode: {}  Links: {}", meta.dev(), meta.ino(), meta.nlink());
        println!("Access: {}  Uid: ({}/{})  Gid: ({}/{})", Perms(meta.mode()),
                 meta.uid(), username, meta.gid(), groupname);
        println!("Access: {}", time::at(Timespec::new(meta.atime(), meta.atime_nsec() as i32)).strftime(TIME_FMT).unwrap());
        println!("Modify: {}", time::at(Timespec::new(meta.mtime(), meta.mtime_nsec() as i32)).strftime(TIME_FMT).unwrap());
        println!("Change: {}", time::at(Timespec::new(meta.ctime(), meta.ctime_nsec() as i32)).strftime(TIME_FMT).unwrap());
    }
}
<commit_msg>Enable coreutils build with redox users v3<commit_after>#![deny(warnings)]

extern crate arg_parser;
extern crate extra;
extern crate time;
extern crate redox_users;

use std::{env, fmt, fs};
use std::io::{stdout, stderr, Write};
use std::os::unix::fs::MetadataExt;
use std::process::exit;

use arg_parser::ArgParser;
use extra::option::OptionalExt;
use redox_users::{All, AllUsers, AllGroups, Config};

use time::Timespec;

const MAN_PAGE: &'static str = /* @MANSTART{stat} */ r#"
NAME
    stat - display file status

SYNOPSIS
    stat [ -h | --help ] FILE...

DESCRIPTION
    Displays file status.

OPTIONS
    --help, -h
        print this message
"#; /* @MANEND */

const TIME_FMT: &'static str = "%Y-%m-%d %H:%M:%S.%f %z";

struct Perms(u32);

impl fmt::Display for Perms {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "(0{:o}/", self.0 & 0o777)?;
        let perm = |i, c| {
            if self.0 & ((1 << i) as u32) != 0 {
                c
            } else {
                "-"
            }
        };
        write!(f, "{}{}{}", perm(8, "r"), perm(7, "w"), perm(6, "x"))?;
        write!(f, "{}{}{}", perm(5, "r"), perm(4, "w"), perm(3, "x"))?;
        write!(f, "{}{}{}", perm(2, "r"), perm(1, "w"), perm(0, "x"))?;
        write!(f, ")")?;
        Ok(())
    }
}

fn main() {
    let stdout = stdout();
    let mut stdout = stdout.lock();
    let mut stderr = stderr();
    let mut parser = ArgParser::new(1)
        .add_flag(&["h", "help"]);
    parser.parse(env::args());

    if parser.found("help") {
        stdout.write_all(MAN_PAGE.as_bytes()).try(&mut stderr);
        stdout.flush().try(&mut stderr);
        return;
    }
    let (all_users, all_groups) = match (AllUsers::new(Config::default()), AllGroups::new(Config::default())) {
        (Ok(all_users), Ok(all_groups)) => (all_users, all_groups),
        (Err(_), Ok(_)) => {
            eprintln!("Unable to access password file");
            exit(1);
        },
        (Ok(_), Err(_)) => {
            eprintln!("Unable to access group file");
            exit(1);
        }
        _ => {
            eprintln!("Unable to access password and group file");
            exit(1);
        }
    };

    for path in &parser.args[0..] {
        let meta = fs::symlink_metadata(path).unwrap();
        let file_type = if meta.file_type().is_symlink() {
            "symbolic link"
        } else if meta.is_file() {
            "regular file"
        } else if meta.is_dir() {
            "directory"
        } else {
            ""
        };
        if meta.file_type().is_symlink() {
            println!("File: {} -> {}", path, fs::read_link(path).unwrap().display());
        } else {
            println!("File: {}", path);
        }
        let username = all_users.get_by_id(meta.uid() as usize)
            .map(|x| x.user.to_string())
            .unwrap_or("UNKNOWN".to_string());
        let groupname = all_groups.get_by_id(meta.gid() as usize)
            .map(|x| x.group.to_string())
            .unwrap_or("UNKNOWN".to_string());
        println!("Size: {}  Blocks: {}  IO Block: {} {}", meta.size(), meta.blocks(), meta.blksize(), file_type);
        println!("Device: {}  Inode: {}  Links: {}", meta.dev(), meta.ino(), meta.nlink());
        println!("Access: {}  Uid: ({}/{})  Gid: ({}/{})", Perms(meta.mode()),
                 meta.uid(), username, meta.gid(), groupname);
        println!("Access: {}", time::at(Timespec::new(meta.atime(), meta.atime_nsec() as i32)).strftime(TIME_FMT).unwrap());
        println!("Modify: {}", time::at(Timespec::new(meta.mtime(), meta.mtime_nsec() as i32)).strftime(TIME_FMT).unwrap());
        println!("Change: {}", time::at(Timespec::new(meta.ctime(), meta.ctime_nsec() as i32)).strftime(TIME_FMT).unwrap());
    }
}
<|endoftext|>


<commit_before>use std::old_io::process::ProcessExit::*;
use std::os::unix::prelude::*;

use std::env;
use std::cmp::*;
use std::num::*;

use types::WashArgs::*;

use util::*;
use constants::*;
use types::*;
use env::*;

macro_rules! builtin {
    ($name:ident, $args:pat, $env:pat, $func:block) => {
        pub fn $name($args:&WashArgs, $env:&mut WashEnv) -> Result<WashArgs, String>
            $func
    }
}

builtin!(source_func, args, env, {
    let name = match args {
        &Empty => return Err("No arguments given".to_string()),
        &Long(_) => return Err("Can only source flat names".to_string()),
        &Flat(ref v) => v.clone()
    };
    env.load_script(Path::new(name), &args.slice(1, -1))
});

builtin!(cd_func, args, _, {
    let newp = {
        if args.len() == 0 {
            expand_path(Path::new("~"))
        } else if &args.get_flat(0)[..min(args.get_flat(0).len(), 2)] == "./" {
            // this specifical case can't be put through expand_path
            Path::new(&args.get_flat(0))
        } else {
            expand_path(Path::new(&args.get_flat(0)))
        }
    };
    match env::set_current_dir(&newp) {
        Err(e) => return Err(e.desc.to_string()),
        Ok(_) => return Ok(Empty)
    }
});

builtin!(outs_func, args, env, {
    let mut argf = args.flatten();
    env.outs(argf.as_slice());
    if argf.pop() != Some(NL) {
        env.outc(NL);
    }
    return Ok(Empty);
});

fn job_args(args:&WashArgs, env:&mut WashEnv) -> Result<(Option<Fd>, Option<Fd>, Option<Fd>,
                                                         String, Vec<String>, Vec<(String, Option<String>)>), String> {
    // turns arguments into file descriptor options, command name and args
    // utility function because job_func and run_func use this same code
    let (mut stdin, mut stdout, mut stderr) = (None, None, None);
    let mut argc = match args {
        &Long(ref v) => v.clone(),
        _ => return Err(format!("Not given Long"))
    };
    let mut envs = vec![];
    let mut name; let mut fname;
    loop {
        // check for stop
        try!(env.func_stop());
        // fail if only file descriptors given
        if argc.is_empty() {
            return Err("No command given".to_string());
        }
        // pop out arguments from the front until no more file descriptors remain
        name = argc.remove(0);
        fname = name.flatten();
        if name.is_empty() {
            // skip empties
            continue;
        } else if FD_REGEX.is_match(fname.as_slice()) {
            let caps = FD_REGEX.captures(fname.as_slice()).unwrap();
            match from_str_radix::<Fd>(caps.at(2).unwrap(), 10) {
                Err(e) => return Err(format!("{} could not be turned into usize: {}", caps.at(2).unwrap(), e)),
                Ok(fd) => match caps.at(1).unwrap() {
                    path if path.is_empty() || path == "in" =>
                        // default to stdin
                        stdin = Some(fd as Fd),
                    path if path == "out" =>
                        stdout = Some(fd as Fd),
                    path if path == "err" =>
                        stderr = Some(fd as Fd),
                    _ => return Err(format!("{} is not a valid standard output", caps.at(1).unwrap()))
                }
            }
        } else if EQ_TEMP_REGEX.is_match(fname.as_slice()) {
            // given environment variables for this job
            let caps = EQ_TEMP_REGEX.captures(fname.as_slice()).unwrap();
            let path = caps.at(1).unwrap();
            if path != "env" {
                return Err(format!("Can only set environment variables on commands"));
            }
            let name = caps.at(2).unwrap();
            if argc.is_empty() {
                return Err(format!("Incomplete temporary variable decleration"));
            }
            let val = match argc.remove(0) {
                Empty => None,
                Flat(s) => Some(s),
                _ => return Err(format!("Environment variables can only be flat"))
            };
            envs.push((name.to_string(), val));
        } else {
            // end of special arguments
            break;
        }
    }
    return Ok((stdin, stdout, stderr, fname, Long(argc).flatten_vec(), envs));
}

builtin!(job_func, args, env, {
    let id;
    if args.is_empty() || args.len() < 1 {
        return Err("No arguments given".to_string());
    } else if args.is_flat() {
        // easy case, no arguments to the function
        id = try!(env.run_job(&args.flatten(), &vec![]));
    } else if !args.get(0).is_flat() {
        return Err("Can only run flat names".to_string());
    } else if !FD_REGEX.is_match(args.get(0).flatten().as_slice()) &&
        !EQ_TEMP_REGEX.is_match(args.get(0).flatten().as_slice()) {
        // easy case, just a command
        let args_slice = args.slice(1, -1);
        id = try!(env.run_job(&args.get(0).flatten(), &args_slice.flatten_vec()));
    } else {
        // hard case, full argument set
        let (stdin, stdout, stderr, name, argc, envs) = try!(job_args(args, env));
        id = try!(env.run_job_fd(stdin, stdout, stderr, &name, &argc, &envs));
    }
    return Ok(Flat(format!("{}", id)));
});

builtin!(job_output_func, args, env, {
    let arg = args.get(0);
    if !arg.is_flat() {
        return Err("Give a job number".to_string());
    }
    let id = match from_str_radix(arg.flatten().as_slice(), 10) {
        Err(e) => return Err(format!("Couldn't turn {} into a job number: {}", arg.flatten(), e)),
        Ok(num) => num
    };
    let out = try!(env.job_output(&id));
    if !out.status.success() {
        let mut s = String::from_utf8_lossy(out.error.as_slice()).into_owned();
        // remove trailing newlines
        match s.pop() {
            Some(v) if v != NL => s.push(v),
            _ => {}
        };
        return Err(s);
    } else {
        let mut s = String::from_utf8_lossy(out.output.as_slice()).into_owned();
                // remove trailing newlines
        match s.pop() {
            Some(v) if v != NL => s.push(v),
            _ => {}
        };
        return Ok(Flat(s));
    }
});

builtin!(directed_job_func, args, env, {
    return job_output_func(&try!(job_func(args, env)), env);
});

builtin!(run_func, args, env, {
    let out;
    if args.is_empty() || args.len() < 1 {
        return Err("No arguments given".to_string());
    } else if args.is_flat() {
        // easy case, no arguments to the function
        out = try!(env.run_command(&args.flatten(), &vec![]));
    } else if !args.get(0).is_flat() {
        return Err("Can only run flat names".to_string());
    } else if !FD_REGEX.is_match(args.get(0).flatten().as_slice()) &&
        !EQ_TEMP_REGEX.is_match(args.get(0).flatten().as_slice()) {
            // easy case, just a command
            let args_slice = args.slice(1, -1);
            out = try!(env.run_command(&args.get(0).flatten(), &args_slice.flatten_vec()));
    } else {
        // hard case, full argument set
        let (stdin, stdout, stderr, name, argc, envs) = try!(job_args(args, env));
        out = try!(env.run_command_fd(stdin, stdout, stderr, &name, &argc, &envs));
    }
    return match out {
        ExitSignal(sig) => {
            return Ok(Long(vec![Flat("signal".to_string()),
                                Flat(format!("{}", sig))]));
        },
        ExitStatus(status) => {
            return Ok(Long(vec![Flat("status".to_string()),
                                Flat(format!("{}", status))]));
        }
    }
});

builtin!(jobs_func, _, env, {
    let jobs = env.get_jobs();
    if jobs.len() == 0 {
        return Err("No jobs".to_string());
    } else {
        return Ok(env.get_jobs());
    }
});

builtin!(fg_func, args, env, {
    let mut id;
    if args.len() < 1 {
        id = try!(env.front_job());
        while !env.has_job(&id) {
            id = try!(env.front_job());
        }
    } else {
        id = match from_str_radix(args.get(0).flatten().as_slice(), 10) {
            Err(e) => return Err(format!("Not given a job number: {}", e)),
            Ok(v) => v
        };
        if !env.has_job(&id) {
            return Err(format!("Job not found"));
        }
    }
    let name = try!(env.get_job(&id)).command.clone();
    env.outf(format_args!("Returning to: {}\n", name));
    try!(env.restart_job(&id));
    let out = try!(env.wait_job(&id));
    try!(env.remove_if_done(&id));
    return describe_process_output(&match out {
        ExitSignal(sig) => Long(vec![Flat("signal".to_string()),
                                     Flat(format!("{}", sig))]),
        ExitStatus(status) => Long(vec![Flat("status".to_string()),
                                        Flat(format!("{}", status))])
    }, env)
});

builtin!(get_func, args, env, {
    if args.len() < 1 {
        return Err("No variable name given".to_string());
    }
    let name = match args.get(0) {
        ref v if !v.is_flat() => {
            return Err("Variable names can only be flat".to_string());
        },
        ref v if !EQ_VAR_REGEX.is_match(v.flatten().as_slice()) => {
            return Err("Varibale names cannot contain whitespace, quotes, or parentheses".to_string());
        }
        v => v.flatten()
    };
    if EQ_PATH_REGEX.is_match(name.as_slice()) {
        let caps = EQ_PATH_REGEX.captures(name.as_slice()).unwrap();
        let path = caps.at(1).unwrap().to_string();
        let name = caps.at(2).unwrap().to_string();
        if path.is_empty() {
            // use default path
            // this can be used to set a variable
            // with a name containing a colon
            return env.getv(&name);
        } else {
            return env.getvp(&name, &path);
        }
    } else {
        return env.getv(&name);
    }
});

builtin!(setp_func, args, env, {
    if args.len() < 1 {
        env.variables = String::new();
        return Ok(Flat(String::new()));
    } else {
        let path = match args.get(0) {
            ref v if !v.is_flat() => {
                return Err("Variable paths can only be flat".to_string());
            }
            v => v.flatten()
        };
        if path == "env".to_string() {
            return Err("Cannot set variable path to environment variables".to_string());
        } else if path == "pipe".to_string() {
            return Err("Cannot set variable path to job pipes".to_string());
        } else {
            env.variables = path.clone();
            return Ok(Flat(path));
        }
    }
});

builtin!(describe_process_output, args, _, {
    let argv = args.flatten_vec();
    if args.is_empty() {
        return Err("Command Failed".to_string());
    } else if argv.len() < 2 {
        return Err(format!("Command failed: {}", args.flatten()));
    } else if argv == vec!["signal", "19"] || // SIGSTOP
        argv == vec!["signal", "20"] { // SIGTSTP
            return Err(format!("Command stopped"));
    } else if argv != vec!["status", "0"] {
        return Err(format!("Command failed with {} {}", argv[0], argv[1]));
    } else {
        return Ok(Empty);
    }
});

fn builtins_func(_:&WashArgs, _:&mut WashEnv) -> Result<WashArgs, String> {
    return Ok(Long(vec![
        Flat("$".to_string()),
        Flat("builtins".to_string()),
        Flat("cd".to_string()),
        Flat("fg".to_string()),
        Flat("get".to_string()),
        Flat("jobs".to_string()),
        Flat("run".to_string()),
        Flat("setp".to_string()),
        Flat("source".to_string())]));
}

pub fn load_builtins(env:&mut WashEnv) -> Result<WashArgs, String> {
    // functions
    try!(env.insf("source", source_func));
    try!(env.insf("cd", cd_func));
    try!(env.insf("builtins", builtins_func));
    try!(env.insf("outs", outs_func));
    try!(env.insf("$", directed_job_func));
    try!(env.insf("run", run_func));
    try!(env.insf("get", get_func));
    try!(env.insf("setp", setp_func));
    try!(env.insf("jobs", jobs_func));
    try!(env.insf("job", job_func));
    try!(env.insf("fg", fg_func));

    // commands that aren't really meant to be called by users
    try!(env.insf("describe_process_output", describe_process_output));

    return Ok(Empty);
}
<commit_msg>Forgot one<commit_after>use std::old_io::process::ProcessExit::*;
use std::os::unix::prelude::*;

use std::env;
use std::cmp::*;
use std::num::*;

use types::WashArgs::*;

use util::*;
use constants::*;
use types::*;
use env::*;

macro_rules! builtin {
    ($name:ident, $args:pat, $env:pat, $func:block) => {
        pub fn $name($args:&WashArgs, $env:&mut WashEnv) -> Result<WashArgs, String>
            $func
    }
}

builtin!(source_func, args, env, {
    let name = match args {
        &Empty => return Err("No arguments given".to_string()),
        &Long(_) => return Err("Can only source flat names".to_string()),
        &Flat(ref v) => v.clone()
    };
    env.load_script(Path::new(name), &args.slice(1, -1))
});

builtin!(cd_func, args, _, {
    let newp = {
        if args.len() == 0 {
            expand_path(Path::new("~"))
        } else if &args.get_flat(0)[..min(args.get_flat(0).len(), 2)] == "./" {
            // this specifical case can't be put through expand_path
            Path::new(&args.get_flat(0))
        } else {
            expand_path(Path::new(&args.get_flat(0)))
        }
    };
    match env::set_current_dir(&newp) {
        Err(e) => return Err(e.desc.to_string()),
        Ok(_) => return Ok(Empty)
    }
});

builtin!(outs_func, args, env, {
    let mut argf = args.flatten();
    env.outs(argf.as_slice());
    if argf.pop() != Some(NL) {
        env.outc(NL);
    }
    return Ok(Empty);
});

fn job_args(args:&WashArgs, env:&mut WashEnv) -> Result<(Option<Fd>, Option<Fd>, Option<Fd>,
                                                         String, Vec<String>, Vec<(String, Option<String>)>), String> {
    // turns arguments into file descriptor options, command name and args
    // utility function because job_func and run_func use this same code
    let (mut stdin, mut stdout, mut stderr) = (None, None, None);
    let mut argc = match args {
        &Long(ref v) => v.clone(),
        _ => return Err(format!("Not given Long"))
    };
    let mut envs = vec![];
    let mut name; let mut fname;
    loop {
        // check for stop
        try!(env.func_stop());
        // fail if only file descriptors given
        if argc.is_empty() {
            return Err("No command given".to_string());
        }
        // pop out arguments from the front until no more file descriptors remain
        name = argc.remove(0);
        fname = name.flatten();
        if name.is_empty() {
            // skip empties
            continue;
        } else if FD_REGEX.is_match(fname.as_slice()) {
            let caps = FD_REGEX.captures(fname.as_slice()).unwrap();
            match from_str_radix::<Fd>(caps.at(2).unwrap(), 10) {
                Err(e) => return Err(format!("{} could not be turned into usize: {}", caps.at(2).unwrap(), e)),
                Ok(fd) => match caps.at(1).unwrap() {
                    path if path.is_empty() || path == "in" =>
                        // default to stdin
                        stdin = Some(fd as Fd),
                    path if path == "out" =>
                        stdout = Some(fd as Fd),
                    path if path == "err" =>
                        stderr = Some(fd as Fd),
                    _ => return Err(format!("{} is not a valid standard output", caps.at(1).unwrap()))
                }
            }
        } else if EQ_TEMP_REGEX.is_match(fname.as_slice()) {
            // given environment variables for this job
            let caps = EQ_TEMP_REGEX.captures(fname.as_slice()).unwrap();
            let path = caps.at(1).unwrap();
            if path != "env" {
                return Err(format!("Can only set environment variables on commands"));
            }
            let name = caps.at(2).unwrap();
            if argc.is_empty() {
                return Err(format!("Incomplete temporary variable decleration"));
            }
            let val = match argc.remove(0) {
                Empty => None,
                Flat(s) => Some(s),
                _ => return Err(format!("Environment variables can only be flat"))
            };
            envs.push((name.to_string(), val));
        } else {
            // end of special arguments
            break;
        }
    }
    return Ok((stdin, stdout, stderr, fname, Long(argc).flatten_vec(), envs));
}

builtin!(job_func, args, env, {
    let id;
    if args.is_empty() || args.len() < 1 {
        return Err("No arguments given".to_string());
    } else if args.is_flat() {
        // easy case, no arguments to the function
        id = try!(env.run_job(&args.flatten(), &vec![]));
    } else if !args.get(0).is_flat() {
        return Err("Can only run flat names".to_string());
    } else if !FD_REGEX.is_match(args.get(0).flatten().as_slice()) &&
        !EQ_TEMP_REGEX.is_match(args.get(0).flatten().as_slice()) {
        // easy case, just a command
        let args_slice = args.slice(1, -1);
        id = try!(env.run_job(&args.get(0).flatten(), &args_slice.flatten_vec()));
    } else {
        // hard case, full argument set
        let (stdin, stdout, stderr, name, argc, envs) = try!(job_args(args, env));
        id = try!(env.run_job_fd(stdin, stdout, stderr, &name, &argc, &envs));
    }
    return Ok(Flat(format!("{}", id)));
});

builtin!(job_output_func, args, env, {
    let arg = args.get(0);
    if !arg.is_flat() {
        return Err("Give a job number".to_string());
    }
    let id = match from_str_radix(arg.flatten().as_slice(), 10) {
        Err(e) => return Err(format!("Couldn't turn {} into a job number: {}", arg.flatten(), e)),
        Ok(num) => num
    };
    let out = try!(env.job_output(&id));
    if !out.status.success() {
        let mut s = String::from_utf8_lossy(out.error.as_slice()).into_owned();
        // remove trailing newlines
        match s.pop() {
            Some(v) if v != NL => s.push(v),
            _ => {}
        };
        return Err(s);
    } else {
        let mut s = String::from_utf8_lossy(out.output.as_slice()).into_owned();
                // remove trailing newlines
        match s.pop() {
            Some(v) if v != NL => s.push(v),
            _ => {}
        };
        return Ok(Flat(s));
    }
});

builtin!(directed_job_func, args, env, {
    return job_output_func(&try!(job_func(args, env)), env);
});

builtin!(run_func, args, env, {
    let out;
    if args.is_empty() || args.len() < 1 {
        return Err("No arguments given".to_string());
    } else if args.is_flat() {
        // easy case, no arguments to the function
        out = try!(env.run_command(&args.flatten(), &vec![]));
    } else if !args.get(0).is_flat() {
        return Err("Can only run flat names".to_string());
    } else if !FD_REGEX.is_match(args.get(0).flatten().as_slice()) &&
        !EQ_TEMP_REGEX.is_match(args.get(0).flatten().as_slice()) {
            // easy case, just a command
            let args_slice = args.slice(1, -1);
            out = try!(env.run_command(&args.get(0).flatten(), &args_slice.flatten_vec()));
    } else {
        // hard case, full argument set
        let (stdin, stdout, stderr, name, argc, envs) = try!(job_args(args, env));
        out = try!(env.run_command_fd(stdin, stdout, stderr, &name, &argc, &envs));
    }
    return match out {
        ExitSignal(sig) => {
            return Ok(Long(vec![Flat("signal".to_string()),
                                Flat(format!("{}", sig))]));
        },
        ExitStatus(status) => {
            return Ok(Long(vec![Flat("status".to_string()),
                                Flat(format!("{}", status))]));
        }
    }
});

builtin!(jobs_func, _, env, {
    let jobs = env.get_jobs();
    if jobs.len() == 0 {
        return Err("No jobs".to_string());
    } else {
        return Ok(env.get_jobs());
    }
});

builtin!(fg_func, args, env, {
    let mut id;
    if args.len() < 1 {
        id = try!(env.front_job());
        while !env.has_job(&id) {
            id = try!(env.front_job());
        }
    } else {
        id = match from_str_radix(args.get(0).flatten().as_slice(), 10) {
            Err(e) => return Err(format!("Not given a job number: {}", e)),
            Ok(v) => v
        };
        if !env.has_job(&id) {
            return Err(format!("Job not found"));
        }
    }
    let name = try!(env.get_job(&id)).command.clone();
    env.outf(format_args!("Returning to: {}\n", name));
    try!(env.restart_job(&id));
    let out = try!(env.wait_job(&id));
    try!(env.remove_if_done(&id));
    return describe_process_output(&match out {
        ExitSignal(sig) => Long(vec![Flat("signal".to_string()),
                                     Flat(format!("{}", sig))]),
        ExitStatus(status) => Long(vec![Flat("status".to_string()),
                                        Flat(format!("{}", status))])
    }, env)
});

builtin!(get_func, args, env, {
    if args.len() < 1 {
        return Err("No variable name given".to_string());
    }
    let name = match args.get(0) {
        ref v if !v.is_flat() => {
            return Err("Variable names can only be flat".to_string());
        },
        ref v if !EQ_VAR_REGEX.is_match(v.flatten().as_slice()) => {
            return Err("Varibale names cannot contain whitespace, quotes, or parentheses".to_string());
        }
        v => v.flatten()
    };
    if EQ_PATH_REGEX.is_match(name.as_slice()) {
        let caps = EQ_PATH_REGEX.captures(name.as_slice()).unwrap();
        let path = caps.at(1).unwrap().to_string();
        let name = caps.at(2).unwrap().to_string();
        if path.is_empty() {
            // use default path
            // this can be used to set a variable
            // with a name containing a colon
            return env.getv(&name);
        } else {
            return env.getvp(&name, &path);
        }
    } else {
        return env.getv(&name);
    }
});

builtin!(setp_func, args, env, {
    if args.len() < 1 {
        env.variables = String::new();
        return Ok(Flat(String::new()));
    } else {
        let path = match args.get(0) {
            ref v if !v.is_flat() => {
                return Err("Variable paths can only be flat".to_string());
            }
            v => v.flatten()
        };
        if path == "env".to_string() {
            return Err("Cannot set variable path to environment variables".to_string());
        } else if path == "pipe".to_string() {
            return Err("Cannot set variable path to job pipes".to_string());
        } else {
            env.variables = path.clone();
            return Ok(Flat(path));
        }
    }
});

builtin!(describe_process_output, args, _, {
    let argv = args.flatten_vec();
    if args.is_empty() {
        return Err("Command Failed".to_string());
    } else if argv.len() < 2 {
        return Err(format!("Command failed: {}", args.flatten()));
    } else if argv == vec!["signal", "19"] || // SIGSTOP
        argv == vec!["signal", "20"] { // SIGTSTP
            return Err(format!("Command stopped"));
    } else if argv != vec!["status", "0"] {
        return Err(format!("Command failed with {} {}", argv[0], argv[1]));
    } else {
        return Ok(Empty);
    }
});

builtin!(builtins_func, _, _, {
    return Ok(Long(vec![
        Flat("$".to_string()),
        Flat("builtins".to_string()),
        Flat("cd".to_string()),
        Flat("fg".to_string()),
        Flat("get".to_string()),
        Flat("jobs".to_string()),
        Flat("run".to_string()),
        Flat("setp".to_string()),
        Flat("source".to_string())]));
});

pub fn load_builtins(env:&mut WashEnv) -> Result<WashArgs, String> {
    // functions
    try!(env.insf("source", source_func));
    try!(env.insf("cd", cd_func));
    try!(env.insf("builtins", builtins_func));
    try!(env.insf("outs", outs_func));
    try!(env.insf("$", directed_job_func));
    try!(env.insf("run", run_func));
    try!(env.insf("get", get_func));
    try!(env.insf("setp", setp_func));
    try!(env.insf("jobs", jobs_func));
    try!(env.insf("job", job_func));
    try!(env.insf("fg", fg_func));

    // commands that aren't really meant to be called by users
    try!(env.insf("describe_process_output", describe_process_output));

    return Ok(Empty);
}
<|endoftext|>


<commit_before>use fixpoint::{Fix, fix, fix_result};

use super::term::Term;

#[derive (Debug, PartialEq, Eq)]
pub enum Ctx<T> {
    Top,
    Abs(String, T, Box<Ctx<T>>),
    AppL(Box<Ctx<T>>, Term<T>),
    AppR(Term<T>, Box<Ctx<T>>),
    Let(Box<Ctx<T>>),
}

#[derive (Debug, PartialEq, Eq)]
pub struct Env<T>(Vec<(String, Option<(T, Box<Term<T>>)>)>);

impl<T> Env<T> {

    pub fn new() -> Env<T> {
        Env(Vec::new())
    }

    pub fn push(&mut self, s: String, o: Option<(T, Box<Term<T>>)>) {
        self.0.push((s, o))
    }

    pub fn pop(&mut self) -> (String, Option<(T, Box<Term<T>>)>) {
        self.0.pop().unwrap()
    }

    pub fn take(&mut self, s: &String) -> Option<(T, Box<Term<T>>)> {
        self.0.iter_mut().rev().find(|&&mut (ref v, _)| s == v).and_then(|&mut (_, ref mut o)| o.take())
    }

}

#[derive (Debug, PartialEq, Eq)]
pub struct Loc<T>(pub Term<T>, pub Ctx<T>, pub Env<T>);

impl<T> Loc<T> {

    pub fn get(self) -> Term<T> {
        self.0
    }

    pub fn set(self, term: Term<T>) -> Loc<T> {
        Loc(term, self.1, self.2)
    }

    pub fn down(self) -> Fix<Loc<T>> {
        match self {
            Loc(Term::Abs(s, y, t1), c, e) => Fix::Pro(Loc(*t1, Ctx::Abs(s, y, Box::new(c)), e)),
            Loc(Term::App(t1, t2), c, e) => Fix::Pro(Loc(*t1, Ctx::AppL(Box::new(c), *t2), e)),
            Loc(Term::Let(s, o, t1), c, mut e) => {
                e.push(s, o);
                Fix::Pro(Loc(*t1, Ctx::Let(Box::new(c)), e))
            },
            _ => Fix::Fix(self)
        }
    }

    pub fn up(self) -> Fix<Loc<T>> {
        match self {
            Loc(t1, Ctx::Abs(s, y, c), e) => Fix::Pro(Loc(Term::abs(s, y, t1), *c, e)),
            Loc(t1, Ctx::AppL(c, t2), e) => Fix::Pro(Loc(Term::app(t1, t2), *c, e)),
            Loc(t2, Ctx::AppR(t1, c), e) => Fix::Pro(Loc(Term::app(t1, t2), *c, e)),
            Loc(t1, Ctx::Let(c), mut e) => {
                let (s, o) = e.pop();
                Fix::Pro(Loc(Term::Let(s, o, Box::new(t1)), *c, e))
            },
            _ => Fix::Fix(self)
        }
    }

    pub fn left(self) -> Fix<Loc<T>> {
        match self {
            Loc(t2, Ctx::AppR(t1, c), e) => Fix::Pro(Loc(t1, Ctx::AppL(c, t2), e)),
            _ => Fix::Fix(self)
        }
    }

    pub fn right(self) -> Fix<Loc<T>> {
        match self {
            Loc(t1, Ctx::AppL(c, t2), e) => Fix::Pro(Loc(t2, Ctx::AppR(t1, c), e)),
            _ => Fix::Fix(self)
        }
    }

    pub fn top(term: Term<T>) -> Loc<T> {
        Loc(term, Ctx::Top, Env::new())
    }

    pub fn fix<F: FnMut(Loc<T>) -> Fix<Loc<T>>>(self, mut f: F) -> Term<T> {
        fix(self, |loc| {
            match f(loc) {
                Fix::Fix(loc) => loc.up(),
                fix => fix
            }
        }).get()
    }

    pub fn fix_result<E, F: FnMut(Loc<T>) -> Result<Fix<Loc<T>>, E>>(self, mut f: F) -> Result<Term<T>, E> {
        fix_result(self, |loc| {
            f(loc).map(|fix| match fix {
                Fix::Fix(loc) => loc.up(),
                _ => fix
            })
        }).map(Loc::get)
    }

}
<commit_msg>move unwrap (invariant) to up function<commit_after>use fixpoint::{Fix, fix, fix_result};

use super::term::Term;

#[derive (Debug, PartialEq, Eq)]
pub enum Ctx<T> {
    Top,
    Abs(String, T, Box<Ctx<T>>),
    AppL(Box<Ctx<T>>, Term<T>),
    AppR(Term<T>, Box<Ctx<T>>),
    Let(Box<Ctx<T>>),
}

#[derive (Debug, PartialEq, Eq)]
pub struct Env<T>(Vec<(String, Option<(T, Box<Term<T>>)>)>);

impl<T> Env<T> {

    pub fn new() -> Env<T> {
        Env(Vec::new())
    }

    pub fn push(&mut self, s: String, o: Option<(T, Box<Term<T>>)>) {
        self.0.push((s, o))
    }

    pub fn pop(&mut self) -> Option<(String, Option<(T, Box<Term<T>>)>)> {
        self.0.pop()
    }

    pub fn take(&mut self, s: &String) -> Option<(T, Box<Term<T>>)> {
        self.0.iter_mut().rev().find(|&&mut (ref v, _)| s == v).and_then(|&mut (_, ref mut o)| o.take())
    }

}

#[derive (Debug, PartialEq, Eq)]
pub struct Loc<T>(pub Term<T>, pub Ctx<T>, pub Env<T>);

impl<T> Loc<T> {

    pub fn get(self) -> Term<T> {
        self.0
    }

    pub fn set(self, term: Term<T>) -> Loc<T> {
        Loc(term, self.1, self.2)
    }

    pub fn down(self) -> Fix<Loc<T>> {
        match self {
            Loc(Term::Abs(s, y, t1), c, e) => Fix::Pro(Loc(*t1, Ctx::Abs(s, y, Box::new(c)), e)),
            Loc(Term::App(t1, t2), c, e) => Fix::Pro(Loc(*t1, Ctx::AppL(Box::new(c), *t2), e)),
            Loc(Term::Let(s, o, t1), c, mut e) => {
                e.push(s, o);
                Fix::Pro(Loc(*t1, Ctx::Let(Box::new(c)), e))
            },
            _ => Fix::Fix(self)
        }
    }

    pub fn up(self) -> Fix<Loc<T>> {
        match self {
            Loc(t1, Ctx::Abs(s, y, c), e) => Fix::Pro(Loc(Term::abs(s, y, t1), *c, e)),
            Loc(t1, Ctx::AppL(c, t2), e) => Fix::Pro(Loc(Term::app(t1, t2), *c, e)),
            Loc(t2, Ctx::AppR(t1, c), e) => Fix::Pro(Loc(Term::app(t1, t2), *c, e)),
            Loc(t1, Ctx::Let(c), mut e) => {
                let (s, o) = e.pop().unwrap();
                Fix::Pro(Loc(Term::Let(s, o, Box::new(t1)), *c, e))
            },
            _ => Fix::Fix(self)
        }
    }

    pub fn left(self) -> Fix<Loc<T>> {
        match self {
            Loc(t2, Ctx::AppR(t1, c), e) => Fix::Pro(Loc(t1, Ctx::AppL(c, t2), e)),
            _ => Fix::Fix(self)
        }
    }

    pub fn right(self) -> Fix<Loc<T>> {
        match self {
            Loc(t1, Ctx::AppL(c, t2), e) => Fix::Pro(Loc(t2, Ctx::AppR(t1, c), e)),
            _ => Fix::Fix(self)
        }
    }

    pub fn top(term: Term<T>) -> Loc<T> {
        Loc(term, Ctx::Top, Env::new())
    }

    pub fn fix<F: FnMut(Loc<T>) -> Fix<Loc<T>>>(self, mut f: F) -> Term<T> {
        fix(self, |loc| {
            match f(loc) {
                Fix::Fix(loc) => loc.up(),
                fix => fix
            }
        }).get()
    }

    pub fn fix_result<E, F: FnMut(Loc<T>) -> Result<Fix<Loc<T>>, E>>(self, mut f: F) -> Result<Term<T>, E> {
        fix_result(self, |loc| {
            f(loc).map(|fix| match fix {
                Fix::Fix(loc) => loc.up(),
                _ => fix
            })
        }).map(Loc::get)
    }

}
<|endoftext|>


<commit_before>use crate::ast::{self, BinOpKind};
use crate::token::{self, BinOpToken, Token};
use rustc_span::symbol::kw;

/// Associative operator with precedence.
///
/// This is the enum which specifies operator precedence and fixity to the parser.
#[derive(PartialEq, Debug)]
pub enum AssocOp {
    /// `+`
    Add,
    /// `-`
    Subtract,
    /// `*`
    Multiply,
    /// `/`
    Divide,
    /// `%`
    Modulus,
    /// `&&`
    LAnd,
    /// `||`
    LOr,
    /// `^`
    BitXor,
    /// `&`
    BitAnd,
    /// `|`
    BitOr,
    /// `<<`
    ShiftLeft,
    /// `>>`
    ShiftRight,
    /// `==`
    Equal,
    /// `<`
    Less,
    /// `<=`
    LessEqual,
    /// `!=`
    NotEqual,
    /// `>`
    Greater,
    /// `>=`
    GreaterEqual,
    /// `=`
    Assign,
    /// `?=` where ? is one of the BinOpToken
    AssignOp(BinOpToken),
    /// `as`
    As,
    /// `..` range
    DotDot,
    /// `..=` range
    DotDotEq,
    /// `:`
    Colon,
}

#[derive(PartialEq, Debug)]
pub enum Fixity {
    /// The operator is left-associative
    Left,
    /// The operator is right-associative
    Right,
    /// The operator is not associative
    None,
}

impl AssocOp {
    /// Creates a new AssocOP from a token
    pub fn from_token(t: &Token) -> Option<AssocOp> {
        use AssocOp::*;
        match t.kind {
            token::BinOpEq(k) => Some(AssignOp(k)),
            token::Eq => Some(Assign),
            token::BinOp(BinOpToken::Star) => Some(Multiply),
            token::BinOp(BinOpToken::Slash) => Some(Divide),
            token::BinOp(BinOpToken::Percent) => Some(Modulus),
            token::BinOp(BinOpToken::Plus) => Some(Add),
            token::BinOp(BinOpToken::Minus) => Some(Subtract),
            token::BinOp(BinOpToken::Shl) => Some(ShiftLeft),
            token::BinOp(BinOpToken::Shr) => Some(ShiftRight),
            token::BinOp(BinOpToken::And) => Some(BitAnd),
            token::BinOp(BinOpToken::Caret) => Some(BitXor),
            token::BinOp(BinOpToken::Or) => Some(BitOr),
            token::Lt => Some(Less),
            token::Le => Some(LessEqual),
            token::Ge => Some(GreaterEqual),
            token::Gt => Some(Greater),
            token::EqEq => Some(Equal),
            token::Ne => Some(NotEqual),
            token::AndAnd => Some(LAnd),
            token::OrOr => Some(LOr),
            token::DotDot => Some(DotDot),
            token::DotDotEq => Some(DotDotEq),
            // DotDotDot is no longer supported, but we need some way to display the error
            token::DotDotDot => Some(DotDotEq),
            token::Colon => Some(Colon),
            // `<-` should probably be `< -`
            token::LArrow => Some(Less),
            _ if t.is_keyword(kw::As) => Some(As),
            _ => None,
        }
    }

    /// Creates a new AssocOp from ast::BinOpKind.
    pub fn from_ast_binop(op: BinOpKind) -> Self {
        use AssocOp::*;
        match op {
            BinOpKind::Lt => Less,
            BinOpKind::Gt => Greater,
            BinOpKind::Le => LessEqual,
            BinOpKind::Ge => GreaterEqual,
            BinOpKind::Eq => Equal,
            BinOpKind::Ne => NotEqual,
            BinOpKind::Mul => Multiply,
            BinOpKind::Div => Divide,
            BinOpKind::Rem => Modulus,
            BinOpKind::Add => Add,
            BinOpKind::Sub => Subtract,
            BinOpKind::Shl => ShiftLeft,
            BinOpKind::Shr => ShiftRight,
            BinOpKind::BitAnd => BitAnd,
            BinOpKind::BitXor => BitXor,
            BinOpKind::BitOr => BitOr,
            BinOpKind::And => LAnd,
            BinOpKind::Or => LOr,
        }
    }

    /// Gets the precedence of this operator
    pub fn precedence(&self) -> usize {
        use AssocOp::*;
        match *self {
            As | Colon => 14,
            Multiply | Divide | Modulus => 13,
            Add | Subtract => 12,
            ShiftLeft | ShiftRight => 11,
            BitAnd => 10,
            BitXor => 9,
            BitOr => 8,
            Less | Greater | LessEqual | GreaterEqual | Equal | NotEqual => 7,
            LAnd => 6,
            LOr => 5,
            DotDot | DotDotEq => 4,
            Assign | AssignOp(_) => 2,
        }
    }

    /// Gets the fixity of this operator
    pub fn fixity(&self) -> Fixity {
        use AssocOp::*;
        // NOTE: it is a bug to have an operators that has same precedence but different fixities!
        match *self {
            Assign | AssignOp(_) => Fixity::Right,
            As | Multiply | Divide | Modulus | Add | Subtract | ShiftLeft | ShiftRight | BitAnd
            | BitXor | BitOr | Less | Greater | LessEqual | GreaterEqual | Equal | NotEqual
            | LAnd | LOr | Colon => Fixity::Left,
            DotDot | DotDotEq => Fixity::None,
        }
    }

    pub fn is_comparison(&self) -> bool {
        use AssocOp::*;
        match *self {
            Less | Greater | LessEqual | GreaterEqual | Equal | NotEqual => true,
            Assign | AssignOp(_) | As | Multiply | Divide | Modulus | Add | Subtract
            | ShiftLeft | ShiftRight | BitAnd | BitXor | BitOr | LAnd | LOr | DotDot | DotDotEq
            | Colon => false,
        }
    }

    pub fn is_assign_like(&self) -> bool {
        use AssocOp::*;
        match *self {
            Assign | AssignOp(_) => true,
            Less | Greater | LessEqual | GreaterEqual | Equal | NotEqual | As | Multiply
            | Divide | Modulus | Add | Subtract | ShiftLeft | ShiftRight | BitAnd | BitXor
            | BitOr | LAnd | LOr | DotDot | DotDotEq | Colon => false,
        }
    }

    pub fn to_ast_binop(&self) -> Option<BinOpKind> {
        use AssocOp::*;
        match *self {
            Less => Some(BinOpKind::Lt),
            Greater => Some(BinOpKind::Gt),
            LessEqual => Some(BinOpKind::Le),
            GreaterEqual => Some(BinOpKind::Ge),
            Equal => Some(BinOpKind::Eq),
            NotEqual => Some(BinOpKind::Ne),
            Multiply => Some(BinOpKind::Mul),
            Divide => Some(BinOpKind::Div),
            Modulus => Some(BinOpKind::Rem),
            Add => Some(BinOpKind::Add),
            Subtract => Some(BinOpKind::Sub),
            ShiftLeft => Some(BinOpKind::Shl),
            ShiftRight => Some(BinOpKind::Shr),
            BitAnd => Some(BinOpKind::BitAnd),
            BitXor => Some(BinOpKind::BitXor),
            BitOr => Some(BinOpKind::BitOr),
            LAnd => Some(BinOpKind::And),
            LOr => Some(BinOpKind::Or),
            Assign | AssignOp(_) | As | DotDot | DotDotEq | Colon => None,
        }
    }

    /// This operator could be used to follow a block unambiguously.
    ///
    /// This is used for error recovery at the moment, providing a suggestion to wrap blocks with
    /// parentheses while having a high degree of confidence on the correctness of the suggestion.
    pub fn can_continue_expr_unambiguously(&self) -> bool {
        use AssocOp::*;
        match self {
            BitXor | // `{ 42 } ^ 3`
            Assign | // `{ 42 } = { 42 }`
            Divide | // `{ 42 } / 42`
            Modulus | // `{ 42 } % 2`
            ShiftRight | // `{ 42 } >> 2`
            LessEqual | // `{ 42 } <= 3`
            Greater | // `{ 42 } > 3`
            GreaterEqual | // `{ 42 } >= 3`
            AssignOp(_) | // `{ 42 } +=`
            LAnd | // `{ 42 } &&foo`
            As | // `{ 42 } as usize`
            // Equal | // `{ 42 } == { 42 }`    Accepting these here would regress incorrect
            // NotEqual | // `{ 42 } != { 42 }  struct literals parser recovery.
            Colon => true, // `{ 42 }: usize`
            _ => false,
        }
    }
}

pub const PREC_RESET: i8 = -100;
pub const PREC_CLOSURE: i8 = -40;
pub const PREC_JUMP: i8 = -30;
pub const PREC_RANGE: i8 = -10;
// The range 2..=14 is reserved for AssocOp binary operator precedences.
pub const PREC_PREFIX: i8 = 50;
pub const PREC_POSTFIX: i8 = 60;
pub const PREC_PAREN: i8 = 99;
pub const PREC_FORCE_PAREN: i8 = 100;

#[derive(Debug, Clone, Copy)]
pub enum ExprPrecedence {
    Closure,
    Break,
    Continue,
    Ret,
    Yield,

    Range,

    Binary(BinOpKind),

    Cast,
    Type,

    Assign,
    AssignOp,

    Box,
    AddrOf,
    Let,
    Unary,

    Call,
    MethodCall,
    Field,
    Index,
    Try,
    InlineAsm,
    Mac,

    Array,
    Repeat,
    Tup,
    Lit,
    Path,
    Paren,
    If,
    While,
    ForLoop,
    Loop,
    Match,
    Block,
    TryBlock,
    Struct,
    Async,
    Await,
    Err,
}

impl ExprPrecedence {
    pub fn order(self) -> i8 {
        match self {
            ExprPrecedence::Closure => PREC_CLOSURE,

            ExprPrecedence::Break |
            ExprPrecedence::Continue |
            ExprPrecedence::Ret |
            ExprPrecedence::Yield => PREC_JUMP,

            // `Range` claims to have higher precedence than `Assign`, but `x .. x = x` fails to
            // parse, instead of parsing as `(x .. x) = x`.  Giving `Range` a lower precedence
            // ensures that `pprust` will add parentheses in the right places to get the desired
            // parse.
            ExprPrecedence::Range => PREC_RANGE,

            // Binop-like expr kinds, handled by `AssocOp`.
            ExprPrecedence::Binary(op) => AssocOp::from_ast_binop(op).precedence() as i8,
            ExprPrecedence::Cast => AssocOp::As.precedence() as i8,
            ExprPrecedence::Type => AssocOp::Colon.precedence() as i8,

            ExprPrecedence::Assign |
            ExprPrecedence::AssignOp => AssocOp::Assign.precedence() as i8,

            // Unary, prefix
            ExprPrecedence::Box |
            ExprPrecedence::AddrOf |
            // Here `let pats = expr` has `let pats =` as a "unary" prefix of `expr`.
            // However, this is not exactly right. When `let _ = a` is the LHS of a binop we
            // need parens sometimes. E.g. we can print `(let _ = a) && b` as `let _ = a && b`
            // but we need to print `(let _ = a) < b` as-is with parens.
            ExprPrecedence::Let |
            ExprPrecedence::Unary => PREC_PREFIX,

            // Unary, postfix
            ExprPrecedence::Await |
            ExprPrecedence::Call |
            ExprPrecedence::MethodCall |
            ExprPrecedence::Field |
            ExprPrecedence::Index |
            ExprPrecedence::Try |
            ExprPrecedence::InlineAsm |
            ExprPrecedence::Mac => PREC_POSTFIX,

            // Never need parens
            ExprPrecedence::Array |
            ExprPrecedence::Repeat |
            ExprPrecedence::Tup |
            ExprPrecedence::Lit |
            ExprPrecedence::Path |
            ExprPrecedence::Paren |
            ExprPrecedence::If |
            ExprPrecedence::While |
            ExprPrecedence::ForLoop |
            ExprPrecedence::Loop |
            ExprPrecedence::Match |
            ExprPrecedence::Block |
            ExprPrecedence::TryBlock |
            ExprPrecedence::Async |
            ExprPrecedence::Struct |
            ExprPrecedence::Err => PREC_PAREN,
        }
    }
}

/// In `let p = e`, operators with precedence `<=` this one requires parenthesis in `e`.
pub fn prec_let_scrutinee_needs_par() -> usize {
    AssocOp::LAnd.precedence()
}

/// Suppose we have `let _ = e` and the `order` of `e`.
/// Is the `order` such that `e` in `let _ = e` needs parenthesis when it is on the RHS?
///
/// Conversely, suppose that we have `(let _ = a) OP b` and `order` is that of `OP`.
/// Can we print this as `let _ = a OP b`?
pub fn needs_par_as_let_scrutinee(order: i8) -> bool {
    order <= prec_let_scrutinee_needs_par() as i8
}

/// Expressions that syntactically contain an "exterior" struct literal i.e., not surrounded by any
/// parens or other delimiters, e.g., `X { y: 1 }`, `X { y: 1 }.method()`, `foo == X { y: 1 }` and
/// `X { y: 1 } == foo` all do, but `(X { y: 1 }) == foo` does not.
pub fn contains_exterior_struct_lit(value: &ast::Expr) -> bool {
    match value.kind {
        ast::ExprKind::Struct(..) => true,

        ast::ExprKind::Assign(ref lhs, ref rhs, _)
        | ast::ExprKind::AssignOp(_, ref lhs, ref rhs)
        | ast::ExprKind::Binary(_, ref lhs, ref rhs) => {
            // X { y: 1 } + X { y: 2 }
            contains_exterior_struct_lit(&lhs) || contains_exterior_struct_lit(&rhs)
        }
        ast::ExprKind::Await(ref x)
        | ast::ExprKind::Unary(_, ref x)
        | ast::ExprKind::Cast(ref x, _)
        | ast::ExprKind::Type(ref x, _)
        | ast::ExprKind::Field(ref x, _)
        | ast::ExprKind::Index(ref x, _) => {
            // &X { y: 1 }, X { y: 1 }.y
            contains_exterior_struct_lit(&x)
        }

        ast::ExprKind::MethodCall(.., ref exprs, _) => {
            // X { y: 1 }.bar(...)
            contains_exterior_struct_lit(&exprs[0])
        }

        _ => false,
    }
}
<commit_msg>Make AssocOp Copy<commit_after>use crate::ast::{self, BinOpKind};
use crate::token::{self, BinOpToken, Token};
use rustc_span::symbol::kw;

/// Associative operator with precedence.
///
/// This is the enum which specifies operator precedence and fixity to the parser.
#[derive(Copy, Clone, PartialEq, Debug)]
pub enum AssocOp {
    /// `+`
    Add,
    /// `-`
    Subtract,
    /// `*`
    Multiply,
    /// `/`
    Divide,
    /// `%`
    Modulus,
    /// `&&`
    LAnd,
    /// `||`
    LOr,
    /// `^`
    BitXor,
    /// `&`
    BitAnd,
    /// `|`
    BitOr,
    /// `<<`
    ShiftLeft,
    /// `>>`
    ShiftRight,
    /// `==`
    Equal,
    /// `<`
    Less,
    /// `<=`
    LessEqual,
    /// `!=`
    NotEqual,
    /// `>`
    Greater,
    /// `>=`
    GreaterEqual,
    /// `=`
    Assign,
    /// `?=` where ? is one of the BinOpToken
    AssignOp(BinOpToken),
    /// `as`
    As,
    /// `..` range
    DotDot,
    /// `..=` range
    DotDotEq,
    /// `:`
    Colon,
}

#[derive(PartialEq, Debug)]
pub enum Fixity {
    /// The operator is left-associative
    Left,
    /// The operator is right-associative
    Right,
    /// The operator is not associative
    None,
}

impl AssocOp {
    /// Creates a new AssocOP from a token
    pub fn from_token(t: &Token) -> Option<AssocOp> {
        use AssocOp::*;
        match t.kind {
            token::BinOpEq(k) => Some(AssignOp(k)),
            token::Eq => Some(Assign),
            token::BinOp(BinOpToken::Star) => Some(Multiply),
            token::BinOp(BinOpToken::Slash) => Some(Divide),
            token::BinOp(BinOpToken::Percent) => Some(Modulus),
            token::BinOp(BinOpToken::Plus) => Some(Add),
            token::BinOp(BinOpToken::Minus) => Some(Subtract),
            token::BinOp(BinOpToken::Shl) => Some(ShiftLeft),
            token::BinOp(BinOpToken::Shr) => Some(ShiftRight),
            token::BinOp(BinOpToken::And) => Some(BitAnd),
            token::BinOp(BinOpToken::Caret) => Some(BitXor),
            token::BinOp(BinOpToken::Or) => Some(BitOr),
            token::Lt => Some(Less),
            token::Le => Some(LessEqual),
            token::Ge => Some(GreaterEqual),
            token::Gt => Some(Greater),
            token::EqEq => Some(Equal),
            token::Ne => Some(NotEqual),
            token::AndAnd => Some(LAnd),
            token::OrOr => Some(LOr),
            token::DotDot => Some(DotDot),
            token::DotDotEq => Some(DotDotEq),
            // DotDotDot is no longer supported, but we need some way to display the error
            token::DotDotDot => Some(DotDotEq),
            token::Colon => Some(Colon),
            // `<-` should probably be `< -`
            token::LArrow => Some(Less),
            _ if t.is_keyword(kw::As) => Some(As),
            _ => None,
        }
    }

    /// Creates a new AssocOp from ast::BinOpKind.
    pub fn from_ast_binop(op: BinOpKind) -> Self {
        use AssocOp::*;
        match op {
            BinOpKind::Lt => Less,
            BinOpKind::Gt => Greater,
            BinOpKind::Le => LessEqual,
            BinOpKind::Ge => GreaterEqual,
            BinOpKind::Eq => Equal,
            BinOpKind::Ne => NotEqual,
            BinOpKind::Mul => Multiply,
            BinOpKind::Div => Divide,
            BinOpKind::Rem => Modulus,
            BinOpKind::Add => Add,
            BinOpKind::Sub => Subtract,
            BinOpKind::Shl => ShiftLeft,
            BinOpKind::Shr => ShiftRight,
            BinOpKind::BitAnd => BitAnd,
            BinOpKind::BitXor => BitXor,
            BinOpKind::BitOr => BitOr,
            BinOpKind::And => LAnd,
            BinOpKind::Or => LOr,
        }
    }

    /// Gets the precedence of this operator
    pub fn precedence(&self) -> usize {
        use AssocOp::*;
        match *self {
            As | Colon => 14,
            Multiply | Divide | Modulus => 13,
            Add | Subtract => 12,
            ShiftLeft | ShiftRight => 11,
            BitAnd => 10,
            BitXor => 9,
            BitOr => 8,
            Less | Greater | LessEqual | GreaterEqual | Equal | NotEqual => 7,
            LAnd => 6,
            LOr => 5,
            DotDot | DotDotEq => 4,
            Assign | AssignOp(_) => 2,
        }
    }

    /// Gets the fixity of this operator
    pub fn fixity(&self) -> Fixity {
        use AssocOp::*;
        // NOTE: it is a bug to have an operators that has same precedence but different fixities!
        match *self {
            Assign | AssignOp(_) => Fixity::Right,
            As | Multiply | Divide | Modulus | Add | Subtract | ShiftLeft | ShiftRight | BitAnd
            | BitXor | BitOr | Less | Greater | LessEqual | GreaterEqual | Equal | NotEqual
            | LAnd | LOr | Colon => Fixity::Left,
            DotDot | DotDotEq => Fixity::None,
        }
    }

    pub fn is_comparison(&self) -> bool {
        use AssocOp::*;
        match *self {
            Less | Greater | LessEqual | GreaterEqual | Equal | NotEqual => true,
            Assign | AssignOp(_) | As | Multiply | Divide | Modulus | Add | Subtract
            | ShiftLeft | ShiftRight | BitAnd | BitXor | BitOr | LAnd | LOr | DotDot | DotDotEq
            | Colon => false,
        }
    }

    pub fn is_assign_like(&self) -> bool {
        use AssocOp::*;
        match *self {
            Assign | AssignOp(_) => true,
            Less | Greater | LessEqual | GreaterEqual | Equal | NotEqual | As | Multiply
            | Divide | Modulus | Add | Subtract | ShiftLeft | ShiftRight | BitAnd | BitXor
            | BitOr | LAnd | LOr | DotDot | DotDotEq | Colon => false,
        }
    }

    pub fn to_ast_binop(&self) -> Option<BinOpKind> {
        use AssocOp::*;
        match *self {
            Less => Some(BinOpKind::Lt),
            Greater => Some(BinOpKind::Gt),
            LessEqual => Some(BinOpKind::Le),
            GreaterEqual => Some(BinOpKind::Ge),
            Equal => Some(BinOpKind::Eq),
            NotEqual => Some(BinOpKind::Ne),
            Multiply => Some(BinOpKind::Mul),
            Divide => Some(BinOpKind::Div),
            Modulus => Some(BinOpKind::Rem),
            Add => Some(BinOpKind::Add),
            Subtract => Some(BinOpKind::Sub),
            ShiftLeft => Some(BinOpKind::Shl),
            ShiftRight => Some(BinOpKind::Shr),
            BitAnd => Some(BinOpKind::BitAnd),
            BitXor => Some(BinOpKind::BitXor),
            BitOr => Some(BinOpKind::BitOr),
            LAnd => Some(BinOpKind::And),
            LOr => Some(BinOpKind::Or),
            Assign | AssignOp(_) | As | DotDot | DotDotEq | Colon => None,
        }
    }

    /// This operator could be used to follow a block unambiguously.
    ///
    /// This is used for error recovery at the moment, providing a suggestion to wrap blocks with
    /// parentheses while having a high degree of confidence on the correctness of the suggestion.
    pub fn can_continue_expr_unambiguously(&self) -> bool {
        use AssocOp::*;
        match self {
            BitXor | // `{ 42 } ^ 3`
            Assign | // `{ 42 } = { 42 }`
            Divide | // `{ 42 } / 42`
            Modulus | // `{ 42 } % 2`
            ShiftRight | // `{ 42 } >> 2`
            LessEqual | // `{ 42 } <= 3`
            Greater | // `{ 42 } > 3`
            GreaterEqual | // `{ 42 } >= 3`
            AssignOp(_) | // `{ 42 } +=`
            LAnd | // `{ 42 } &&foo`
            As | // `{ 42 } as usize`
            // Equal | // `{ 42 } == { 42 }`    Accepting these here would regress incorrect
            // NotEqual | // `{ 42 } != { 42 }  struct literals parser recovery.
            Colon => true, // `{ 42 }: usize`
            _ => false,
        }
    }
}

pub const PREC_RESET: i8 = -100;
pub const PREC_CLOSURE: i8 = -40;
pub const PREC_JUMP: i8 = -30;
pub const PREC_RANGE: i8 = -10;
// The range 2..=14 is reserved for AssocOp binary operator precedences.
pub const PREC_PREFIX: i8 = 50;
pub const PREC_POSTFIX: i8 = 60;
pub const PREC_PAREN: i8 = 99;
pub const PREC_FORCE_PAREN: i8 = 100;

#[derive(Debug, Clone, Copy)]
pub enum ExprPrecedence {
    Closure,
    Break,
    Continue,
    Ret,
    Yield,

    Range,

    Binary(BinOpKind),

    Cast,
    Type,

    Assign,
    AssignOp,

    Box,
    AddrOf,
    Let,
    Unary,

    Call,
    MethodCall,
    Field,
    Index,
    Try,
    InlineAsm,
    Mac,

    Array,
    Repeat,
    Tup,
    Lit,
    Path,
    Paren,
    If,
    While,
    ForLoop,
    Loop,
    Match,
    Block,
    TryBlock,
    Struct,
    Async,
    Await,
    Err,
}

impl ExprPrecedence {
    pub fn order(self) -> i8 {
        match self {
            ExprPrecedence::Closure => PREC_CLOSURE,

            ExprPrecedence::Break |
            ExprPrecedence::Continue |
            ExprPrecedence::Ret |
            ExprPrecedence::Yield => PREC_JUMP,

            // `Range` claims to have higher precedence than `Assign`, but `x .. x = x` fails to
            // parse, instead of parsing as `(x .. x) = x`.  Giving `Range` a lower precedence
            // ensures that `pprust` will add parentheses in the right places to get the desired
            // parse.
            ExprPrecedence::Range => PREC_RANGE,

            // Binop-like expr kinds, handled by `AssocOp`.
            ExprPrecedence::Binary(op) => AssocOp::from_ast_binop(op).precedence() as i8,
            ExprPrecedence::Cast => AssocOp::As.precedence() as i8,
            ExprPrecedence::Type => AssocOp::Colon.precedence() as i8,

            ExprPrecedence::Assign |
            ExprPrecedence::AssignOp => AssocOp::Assign.precedence() as i8,

            // Unary, prefix
            ExprPrecedence::Box |
            ExprPrecedence::AddrOf |
            // Here `let pats = expr` has `let pats =` as a "unary" prefix of `expr`.
            // However, this is not exactly right. When `let _ = a` is the LHS of a binop we
            // need parens sometimes. E.g. we can print `(let _ = a) && b` as `let _ = a && b`
            // but we need to print `(let _ = a) < b` as-is with parens.
            ExprPrecedence::Let |
            ExprPrecedence::Unary => PREC_PREFIX,

            // Unary, postfix
            ExprPrecedence::Await |
            ExprPrecedence::Call |
            ExprPrecedence::MethodCall |
            ExprPrecedence::Field |
            ExprPrecedence::Index |
            ExprPrecedence::Try |
            ExprPrecedence::InlineAsm |
            ExprPrecedence::Mac => PREC_POSTFIX,

            // Never need parens
            ExprPrecedence::Array |
            ExprPrecedence::Repeat |
            ExprPrecedence::Tup |
            ExprPrecedence::Lit |
            ExprPrecedence::Path |
            ExprPrecedence::Paren |
            ExprPrecedence::If |
            ExprPrecedence::While |
            ExprPrecedence::ForLoop |
            ExprPrecedence::Loop |
            ExprPrecedence::Match |
            ExprPrecedence::Block |
            ExprPrecedence::TryBlock |
            ExprPrecedence::Async |
            ExprPrecedence::Struct |
            ExprPrecedence::Err => PREC_PAREN,
        }
    }
}

/// In `let p = e`, operators with precedence `<=` this one requires parenthesis in `e`.
pub fn prec_let_scrutinee_needs_par() -> usize {
    AssocOp::LAnd.precedence()
}

/// Suppose we have `let _ = e` and the `order` of `e`.
/// Is the `order` such that `e` in `let _ = e` needs parenthesis when it is on the RHS?
///
/// Conversely, suppose that we have `(let _ = a) OP b` and `order` is that of `OP`.
/// Can we print this as `let _ = a OP b`?
pub fn needs_par_as_let_scrutinee(order: i8) -> bool {
    order <= prec_let_scrutinee_needs_par() as i8
}

/// Expressions that syntactically contain an "exterior" struct literal i.e., not surrounded by any
/// parens or other delimiters, e.g., `X { y: 1 }`, `X { y: 1 }.method()`, `foo == X { y: 1 }` and
/// `X { y: 1 } == foo` all do, but `(X { y: 1 }) == foo` does not.
pub fn contains_exterior_struct_lit(value: &ast::Expr) -> bool {
    match value.kind {
        ast::ExprKind::Struct(..) => true,

        ast::ExprKind::Assign(ref lhs, ref rhs, _)
        | ast::ExprKind::AssignOp(_, ref lhs, ref rhs)
        | ast::ExprKind::Binary(_, ref lhs, ref rhs) => {
            // X { y: 1 } + X { y: 2 }
            contains_exterior_struct_lit(&lhs) || contains_exterior_struct_lit(&rhs)
        }
        ast::ExprKind::Await(ref x)
        | ast::ExprKind::Unary(_, ref x)
        | ast::ExprKind::Cast(ref x, _)
        | ast::ExprKind::Type(ref x, _)
        | ast::ExprKind::Field(ref x, _)
        | ast::ExprKind::Index(ref x, _) => {
            // &X { y: 1 }, X { y: 1 }.y
            contains_exterior_struct_lit(&x)
        }

        ast::ExprKind::MethodCall(.., ref exprs, _) => {
            // X { y: 1 }.bar(...)
            contains_exterior_struct_lit(&exprs[0])
        }

        _ => false,
    }
}
<|endoftext|>


<commit_before>//! # mm_cli
//!
//! The `mm_cli` feature provides the ability to compile a very minimal cli for querying against
//! the PBS Media Manager API. It is built directly on top of the [Client](struct.Client.html)
//! and allows for querying against either the production API or the staging API.
//!
//! ### Configuration
//!
//! Configuration for the cli is contained within a `config.toml` file. It uses a `live` key to
//! designate your credentials for the production API and a `staging` key for the staging API.
//!
//! The confiuration file can be created manually or the cli can generate it with some assistance.
//! If you run the cli without a configuration file then it will attempt to generate one and prompt
//! for the necessary credentials. Settings can be rewritten by running the cli with the `init`
//! flag.

#![deny(missing_docs)]
extern crate app_dirs;
extern crate clap;
extern crate mm_client;
extern crate serde;
#[macro_use]
extern crate serde_derive;
extern crate serde_json;

mod error;
mod config;

use app_dirs::{AppDataType, AppInfo, get_app_dir};
use clap::{App, Arg};
use mm_client::Client;
use mm_client::Endpoints;
use mm_client::MMCResult;

use std::str::FromStr;

use error::CLIError;
use config::Config;

fn main() {

    let matches = App::new("MediaManager CLI")
        .author(env!("CARGO_PKG_AUTHORS"))
        .version(env!("CARGO_PKG_VERSION"))
        .arg(Arg::with_name("init")
            .long("init")
            .takes_value(false)
            .help("Creates/replaces a config.toml file"))
        .arg(Arg::with_name("type")
            .takes_value(true)
            .required(false)
            .help("Object type to query for"))
        .arg(Arg::with_name("id")
            .takes_value(true)
            .required(false)
            .help("Object id to query for"))
        .arg(Arg::with_name("staging")
            .short("s")
            .long("staging")
            .takes_value(false)
            .help("Runs query against the staging environment"))
        .get_matches();

    let info = AppInfo {
        name: env!("CARGO_PKG_NAME"),
        author: "tpt",
    };

    let config_path = get_app_dir(AppDataType::UserConfig, &info, "/")
        .and_then(|mut path| {
            path.push("config.toml");
            Ok(path)
        })
        .expect("Failed to run. Unable to determine default config location.");

    let path = config_path.to_str().expect("Failed to parse config location.");

    if matches.is_present("init") {
        Config::create(path);
    };

    match (matches.value_of("type"), matches.value_of("id")) {
        (Some(endpoint), Some(id)) => {

            Config::parse_config(path).and_then(|config| {
                let result = Endpoints::from_str(endpoint)
                    .or(Err(CLIError::Endpoint))
                    .and_then(|ep| rq_endpoint(&config, matches.is_present("staging"), ep, id));

                // Handle the result from the client, outputting it to the user
                match result {
                    Ok(ref value) => println!("{}", value),
                    Err(ref error) => println!("An error occured: {}", error),
                };

                result
            });
        }
        _ => (),
    }
}

fn rq_endpoint(config: &Config,
               is_staging: bool,
               endpoint: Endpoints,
               id: &str)
               -> Result<String, CLIError> {
    let conf = if is_staging {
        &config.staging
    } else {
        &config.live
    };

    // Attempt to get a response from the requested endpoint if it is
    // one of the available endpoints
    match *conf {
        Some(ref key_sec) => {

            let client = if is_staging {
                Client::staging(key_sec.key.as_str(), key_sec.secret.as_str())
            } else {
                Client::new(key_sec.key.as_str(), key_sec.secret.as_str())
            };

            client.map_err(CLIError::Network)
                .and_then(|cl| handle_client_response(cl.get(endpoint, id)))
        }
        None => Err(CLIError::EndpointConfigMissing),
    }
}

/// Handles responses from the Core Data Client and transforms them into
/// a Result that is ready for output to a user
fn handle_client_response(result: MMCResult<String>) -> Result<String, CLIError> {
    match result {
        Ok(json_string) => to_pretty_print(json_string),
        Err(err) => Err(CLIError::Network(err)),
    }
}

// Accepts a String of json, and returns the Result of attempting to transform
// it into a pretty printable String
fn to_pretty_print(json_string: String) -> Result<String, CLIError> {

    // Attempt to deserialize the json string
    let parsed: Result<serde_json::Value, serde_json::Error> =
        serde_json::from_str(json_string.as_str());

    // Return either successfully decoded json or a Format error
    match parsed {
        Ok(json) => serde_json::ser::to_string_pretty(&json).map_err(CLIError::Format),
        Err(err) => Err(CLIError::Format(err)),
    }
}
<commit_msg>Fix cli name<commit_after>//! # mm_cli
//!
//! The `mm_cli` feature provides the ability to compile a very minimal cli for querying against
//! the PBS Media Manager API. It is built directly on top of the [Client](struct.Client.html)
//! and allows for querying against either the production API or the staging API.
//!
//! ### Configuration
//!
//! Configuration for the cli is contained within a `config.toml` file. It uses a `live` key to
//! designate your credentials for the production API and a `staging` key for the staging API.
//!
//! The confiuration file can be created manually or the cli can generate it with some assistance.
//! If you run the cli without a configuration file then it will attempt to generate one and prompt
//! for the necessary credentials. Settings can be rewritten by running the cli with the `init`
//! flag.

#![deny(missing_docs)]
extern crate app_dirs;
extern crate clap;
extern crate mm_client;
extern crate serde;
#[macro_use]
extern crate serde_derive;
extern crate serde_json;

mod error;
mod config;

use app_dirs::{AppDataType, AppInfo, get_app_dir};
use clap::{App, Arg};
use mm_client::Client;
use mm_client::Endpoints;
use mm_client::MMCResult;

use std::str::FromStr;

use error::CLIError;
use config::Config;

fn main() {

    let matches = App::new(env!("CARGO_PKG_NAME"))
        .author(env!("CARGO_PKG_AUTHORS"))
        .version(env!("CARGO_PKG_VERSION"))
        .arg(Arg::with_name("init")
            .long("init")
            .takes_value(false)
            .help("Creates/replaces a config.toml file"))
        .arg(Arg::with_name("type")
            .takes_value(true)
            .required(false)
            .help("Object type to query for"))
        .arg(Arg::with_name("id")
            .takes_value(true)
            .required(false)
            .help("Object id to query for"))
        .arg(Arg::with_name("staging")
            .short("s")
            .long("staging")
            .takes_value(false)
            .help("Runs query against the staging environment"))
        .get_matches();

    let info = AppInfo {
        name: env!("CARGO_PKG_NAME"),
        author: "tpt",
    };

    let config_path = get_app_dir(AppDataType::UserConfig, &info, "/")
        .and_then(|mut path| {
            path.push("config.toml");
            Ok(path)
        })
        .expect("Failed to run. Unable to determine default config location.");

    let path = config_path.to_str().expect("Failed to parse config location.");

    if matches.is_present("init") {
        Config::create(path);
    };

    match (matches.value_of("type"), matches.value_of("id")) {
        (Some(endpoint), Some(id)) => {

            Config::parse_config(path).and_then(|config| {
                let result = Endpoints::from_str(endpoint)
                    .or(Err(CLIError::Endpoint))
                    .and_then(|ep| rq_endpoint(&config, matches.is_present("staging"), ep, id));

                // Handle the result from the client, outputting it to the user
                match result {
                    Ok(ref value) => println!("{}", value),
                    Err(ref error) => println!("An error occured: {}", error),
                };

                result
            });
        }
        _ => (),
    }
}

fn rq_endpoint(config: &Config,
               is_staging: bool,
               endpoint: Endpoints,
               id: &str)
               -> Result<String, CLIError> {
    let conf = if is_staging {
        &config.staging
    } else {
        &config.live
    };

    // Attempt to get a response from the requested endpoint if it is
    // one of the available endpoints
    match *conf {
        Some(ref key_sec) => {

            let client = if is_staging {
                Client::staging(key_sec.key.as_str(), key_sec.secret.as_str())
            } else {
                Client::new(key_sec.key.as_str(), key_sec.secret.as_str())
            };

            client.map_err(CLIError::Network)
                .and_then(|cl| handle_client_response(cl.get(endpoint, id)))
        }
        None => Err(CLIError::EndpointConfigMissing),
    }
}

/// Handles responses from the Core Data Client and transforms them into
/// a Result that is ready for output to a user
fn handle_client_response(result: MMCResult<String>) -> Result<String, CLIError> {
    match result {
        Ok(json_string) => to_pretty_print(json_string),
        Err(err) => Err(CLIError::Network(err)),
    }
}

// Accepts a String of json, and returns the Result of attempting to transform
// it into a pretty printable String
fn to_pretty_print(json_string: String) -> Result<String, CLIError> {

    // Attempt to deserialize the json string
    let parsed: Result<serde_json::Value, serde_json::Error> =
        serde_json::from_str(json_string.as_str());

    // Return either successfully decoded json or a Format error
    match parsed {
        Ok(json) => serde_json::ser::to_string_pretty(&json).map_err(CLIError::Format),
        Err(err) => Err(CLIError::Format(err)),
    }
}
<|endoftext|>