<commit_before>// Copyright 2016 PingCAP, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// See the License for the specific language governing permissions and
// limitations under the License.

#![feature(plugin)]
#![plugin(clippy)]

extern crate tikv;
extern crate getopts;
#[macro_use]
extern crate log;
extern crate rocksdb;
extern crate mio;

use std::env;
use std::fs;
use std::path::Path;
use std::sync::{Arc, RwLock};

use getopts::{Options, Matches};
use log::LogLevelFilter;
use rocksdb::DB;
use mio::tcp::TcpListener;

use tikv::storage::{Storage, Dsn};
use tikv::util::{self, logger};
use tikv::server::{DEFAULT_LISTENING_ADDR, SendCh, Server, Node, Config, bind, create_event_loop,
                   create_raft_storage};
use tikv::server::{ServerTransport, ServerRaftStoreRouter, MockRaftStoreRouter};
use tikv::pd::new_rpc_client;

const MEM_DSN: &'static str = "mem";
const ROCKSDB_DSN: &'static str = "rocksdb";
const RAFTKV_DSN: &'static str = "raftkv";

fn print_usage(program: &str, opts: Options) {
    let brief = format!("Usage: {} [options]", program);
    print!("{}", opts.usage(&brief));
}

fn initial_log(matches: &Matches) {
    let log_filter = match matches.opt_str("L") {
        Some(level) => logger::get_level_by_string(&level),
        None => LogLevelFilter::Info,
    };
    util::init_log(log_filter).unwrap();
}

fn build_raftkv(matches: &Matches,
                ch: SendCh,
                addr: String)
                -> (Storage, Arc<RwLock<ServerRaftStoreRouter>>) {
    let pd_addr = matches.opt_str("pd").expect("raftkv needs pd client");
    let pd_client = Arc::new(RwLock::new(new_rpc_client(&pd_addr).unwrap()));
    let id = matches.opt_str("I").expect("raftkv requires cluster id");
    let cluster_id = u64::from_str_radix(&id, 10).expect("invalid cluster id");

    let trans = Arc::new(RwLock::new(ServerTransport::new(cluster_id, ch, pd_client.clone())));

    let path = get_store_path(matches);
    let engine = Arc::new(DB::open_default(&path).unwrap());
    let mut cfg = Config::new();
    cfg.cluster_id = cluster_id;

    cfg.addr = addr.clone();

    // Set advertise address for outer node and client use.
    // If no advertise listening address set, use the associated listening address.
    cfg.advertise_addr = matches.opt_str("advertise-addr")
                                .unwrap_or_else(|| addr);

    let mut node = Node::new(&cfg, pd_client, trans.clone());
    node.start(engine).unwrap();
    let raft_router = node.raft_store_router();

    (create_raft_storage(node).unwrap(), raft_router)
}

fn get_store_path(matches: &Matches) -> String {
    let path = matches.opt_str("s").expect("need store path, but none is specified!");

    let p = Path::new(&path);
    if p.exists() && p.is_file() {
        panic!("{} is not a directory!", path);
    }
    if !p.exists() {
        fs::create_dir_all(p).unwrap();
    }
    let absolute_path = p.canonicalize().unwrap();
    format!("{}", absolute_path.display())
}

fn run_local_server(listener: TcpListener, store: Storage) {
    let mut event_loop = create_event_loop().unwrap();
    let router = Arc::new(RwLock::new(MockRaftStoreRouter));
    let mut svr = Server::new(&mut event_loop, listener, store, router).unwrap();
    svr.run(&mut event_loop).unwrap();
}

fn run_raft_server(listener: TcpListener, matches: &Matches) {
    let mut event_loop = create_event_loop().unwrap();
    let ch = SendCh::new(event_loop.channel());

    let (store, raft_router) = build_raftkv(&matches,
                                            ch,
                                            format!("{}", listener.local_addr().unwrap()));
    let mut svr = Server::new(&mut event_loop, listener, store, raft_router).unwrap();
    svr.run(&mut event_loop).unwrap();
}

fn main() {
    let args: Vec<String> = env::args().collect();
    let program = args[0].clone();
    let mut opts = Options::new();
    opts.optopt("A",
                "addr",
                "set listening address",
                "default is 127.0.0.1:20160");
    opts.optopt("",
                "advertise-addr",
                "set advertise listening address for client communication",
                "127.0.0.1:20160, if not set, use addr instead.");
    opts.optopt("L",
                "log",
                "set log level",
                "log level: trace, debug, info, warn, error, off");
    opts.optflag("h", "help", "print this help menu");
    // TODO: support loading config file
    // opts.optopt("C", "config", "set configuration file", "file path");
    opts.optopt("s",
                "store",
                "set the path to rocksdb directory",
                "/tmp/tikv/store");
    opts.optopt("S",
                "dsn",
                "set which dsn to use, default is mem",
                "dsn: mem, rocksdb, raftkv");
    opts.optopt("I", "cluster-id", "set cluster id", "must greater than 0.");
    opts.optopt("", "pd", "set pd address", "host:port");
    let matches = opts.parse(&args[1..]).expect("opts parse failed");
    if matches.opt_present("h") {
        print_usage(&program, opts);
        return;
    }
    initial_log(&matches);

    let addr = matches.opt_str("A").unwrap_or_else(|| DEFAULT_LISTENING_ADDR.to_owned());
    let listener = bind(&addr).unwrap();

    info!("Start listening on {}...", addr);

    let dsn_name = matches.opt_str("S").unwrap_or_else(|| MEM_DSN.to_owned());

    match dsn_name.as_ref() {
        MEM_DSN => {
            let store = Storage::new(Dsn::Memory).unwrap();
            run_local_server(listener, store);
        }
        ROCKSDB_DSN => {
            let path = get_store_path(&matches);
            let store = Storage::new(Dsn::RocksDBPath(&path)).unwrap();
            run_local_server(listener, store);
        }
        RAFTKV_DSN => {
            run_raft_server(listener, &matches);
        }
        n => panic!("unrecognized dns name: {}", n),
    };
}
<commit_msg>tikv-server: Log listening address before panic.<commit_after>// Copyright 2016 PingCAP, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// See the License for the specific language governing permissions and
// limitations under the License.

#![feature(plugin)]
#![plugin(clippy)]

extern crate tikv;
extern crate getopts;
#[macro_use]
extern crate log;
extern crate rocksdb;
extern crate mio;

use std::env;
use std::fs;
use std::path::Path;
use std::sync::{Arc, RwLock};

use getopts::{Options, Matches};
use log::LogLevelFilter;
use rocksdb::DB;
use mio::tcp::TcpListener;

use tikv::storage::{Storage, Dsn};
use tikv::util::{self, logger};
use tikv::server::{DEFAULT_LISTENING_ADDR, SendCh, Server, Node, Config, bind, create_event_loop,
                   create_raft_storage};
use tikv::server::{ServerTransport, ServerRaftStoreRouter, MockRaftStoreRouter};
use tikv::pd::new_rpc_client;

const MEM_DSN: &'static str = "mem";
const ROCKSDB_DSN: &'static str = "rocksdb";
const RAFTKV_DSN: &'static str = "raftkv";

fn print_usage(program: &str, opts: Options) {
    let brief = format!("Usage: {} [options]", program);
    print!("{}", opts.usage(&brief));
}

fn initial_log(matches: &Matches) {
    let log_filter = match matches.opt_str("L") {
        Some(level) => logger::get_level_by_string(&level),
        None => LogLevelFilter::Info,
    };
    util::init_log(log_filter).unwrap();
}

fn build_raftkv(matches: &Matches,
                ch: SendCh,
                addr: String)
                -> (Storage, Arc<RwLock<ServerRaftStoreRouter>>) {
    let pd_addr = matches.opt_str("pd").expect("raftkv needs pd client");
    let pd_client = Arc::new(RwLock::new(new_rpc_client(&pd_addr).unwrap()));
    let id = matches.opt_str("I").expect("raftkv requires cluster id");
    let cluster_id = u64::from_str_radix(&id, 10).expect("invalid cluster id");

    let trans = Arc::new(RwLock::new(ServerTransport::new(cluster_id, ch, pd_client.clone())));

    let path = get_store_path(matches);
    let engine = Arc::new(DB::open_default(&path).unwrap());
    let mut cfg = Config::new();
    cfg.cluster_id = cluster_id;

    cfg.addr = addr.clone();

    // Set advertise address for outer node and client use.
    // If no advertise listening address set, use the associated listening address.
    cfg.advertise_addr = matches.opt_str("advertise-addr")
                                .unwrap_or_else(|| addr);

    let mut node = Node::new(&cfg, pd_client, trans.clone());
    node.start(engine).unwrap();
    let raft_router = node.raft_store_router();

    (create_raft_storage(node).unwrap(), raft_router)
}

fn get_store_path(matches: &Matches) -> String {
    let path = matches.opt_str("s").expect("need store path, but none is specified!");

    let p = Path::new(&path);
    if p.exists() && p.is_file() {
        panic!("{} is not a directory!", path);
    }
    if !p.exists() {
        fs::create_dir_all(p).unwrap();
    }
    let absolute_path = p.canonicalize().unwrap();
    format!("{}", absolute_path.display())
}

fn run_local_server(listener: TcpListener, store: Storage) {
    let mut event_loop = create_event_loop().unwrap();
    let router = Arc::new(RwLock::new(MockRaftStoreRouter));
    let mut svr = Server::new(&mut event_loop, listener, store, router).unwrap();
    svr.run(&mut event_loop).unwrap();
}

fn run_raft_server(listener: TcpListener, matches: &Matches) {
    let mut event_loop = create_event_loop().unwrap();
    let ch = SendCh::new(event_loop.channel());

    let (store, raft_router) = build_raftkv(&matches,
                                            ch,
                                            format!("{}", listener.local_addr().unwrap()));
    let mut svr = Server::new(&mut event_loop, listener, store, raft_router).unwrap();
    svr.run(&mut event_loop).unwrap();
}

fn main() {
    let args: Vec<String> = env::args().collect();
    let program = args[0].clone();
    let mut opts = Options::new();
    opts.optopt("A",
                "addr",
                "set listening address",
                "default is 127.0.0.1:20160");
    opts.optopt("",
                "advertise-addr",
                "set advertise listening address for client communication",
                "127.0.0.1:20160, if not set, use addr instead.");
    opts.optopt("L",
                "log",
                "set log level",
                "log level: trace, debug, info, warn, error, off");
    opts.optflag("h", "help", "print this help menu");
    // TODO: support loading config file
    // opts.optopt("C", "config", "set configuration file", "file path");
    opts.optopt("s",
                "store",
                "set the path to rocksdb directory",
                "/tmp/tikv/store");
    opts.optopt("S",
                "dsn",
                "set which dsn to use, default is mem",
                "dsn: mem, rocksdb, raftkv");
    opts.optopt("I", "cluster-id", "set cluster id", "must greater than 0.");
    opts.optopt("", "pd", "set pd address", "host:port");
    let matches = opts.parse(&args[1..]).expect("opts parse failed");
    if matches.opt_present("h") {
        print_usage(&program, opts);
        return;
    }
    initial_log(&matches);

    let addr = matches.opt_str("A").unwrap_or_else(|| DEFAULT_LISTENING_ADDR.to_owned());
    info!("Start listening on {}...", addr);
    let listener = bind(&addr).unwrap();

    let dsn_name = matches.opt_str("S").unwrap_or_else(|| MEM_DSN.to_owned());

    match dsn_name.as_ref() {
        MEM_DSN => {
            let store = Storage::new(Dsn::Memory).unwrap();
            run_local_server(listener, store);
        }
        ROCKSDB_DSN => {
            let path = get_store_path(&matches);
            let store = Storage::new(Dsn::RocksDBPath(&path)).unwrap();
            run_local_server(listener, store);
        }
        RAFTKV_DSN => {
            run_raft_server(listener, &matches);
        }
        n => panic!("unrecognized dns name: {}", n),
    };
}
<|endoftext|>


<commit_before>use rustc_hash::FxHashMap;
use smol_str::SmolStr;

use crate::{mbe, tt};

pub fn exapnd(rules: &mbe::MacroRules, input: &tt::Subtree) -> Option<tt::Subtree> {
    rules.rules.iter().find_map(|it| expand_rule(it, input))
}

fn expand_rule(rule: &mbe::Rule, input: &tt::Subtree) -> Option<tt::Subtree> {
    let bindings = match_lhs(&rule.lhs, input)?;
    expand_rhs(&rule.rhs, &bindings)
}

#[derive(Debug, Default)]
struct Bindings {
    inner: FxHashMap<SmolStr, tt::TokenTree>,
}

fn match_lhs(pattern: &mbe::Subtree, input: &tt::Subtree) -> Option<Bindings> {
    Some(Bindings::default())
}

fn expand_rhs(template: &mbe::Subtree, bindings: &Bindings) -> Option<tt::Subtree> {
    None
}
<commit_msg>binders boilerplate<commit_after>use rustc_hash::FxHashMap;
use smol_str::SmolStr;

use crate::{mbe, tt};

pub fn exapnd(rules: &mbe::MacroRules, input: &tt::Subtree) -> Option<tt::Subtree> {
    rules.rules.iter().find_map(|it| expand_rule(it, input))
}

fn expand_rule(rule: &mbe::Rule, input: &tt::Subtree) -> Option<tt::Subtree> {
    let bindings = match_lhs(&rule.lhs, input)?;
    expand_rhs(&rule.rhs, &bindings)
}

#[derive(Debug, Default)]
struct Bindings {
    inner: FxHashMap<SmolStr, Binding>,
}

#[derive(Debug)]
enum Binding {
    Simple(tt::TokenTree),
    Nested(Vec<Binding>),
}

/*

macro_rules! impl_froms {
    ($e:ident: $($v:ident),*) => {
        $(
            impl From<$v> for $e {
                fn from(it: $v) -> $e {
                    $e::$v(it)
                }
            }
        )*
    }
}

impl_froms! (Foo: Bar, Baz)

*/

fn match_lhs(pattern: &mbe::Subtree, input: &tt::Subtree) -> Option<Bindings> {
    let mut res = Bindings::default();
    for pat in pattern.token_trees.iter() {
        match pat {
            mbe::TokenTree::Leaf(leaf) => match leaf {
                mbe::Leaf::Var(mbe::Var { text, kind }) => {
                    let kind = kind.clone()?;
                    match kind.as_str() {
                        "ident" => (),
                        _ => return None,
                    }
                }
                _ => return None,
            },
            _ => {}
        }
    }
    Some(res)
}

fn expand_rhs(template: &mbe::Subtree, bindings: &Bindings) -> Option<tt::Subtree> {
    None
}
<|endoftext|>


<commit_before>use std::mem;
use std::ptr;
use std::sync::Arc;
use std::sync::Mutex;
use std::sync::MutexGuard;

use device::Device;

use OomError;
use SynchronizedVulkanObject;
use VulkanObject;
use VulkanPointers;
use check_errors;
use vk;

/// Pool from which descriptor sets are allocated from.
///
/// A pool has a maximum number of descriptor sets and a maximum number of descriptors (one value
/// per descriptor type) it can allocate.
pub struct DescriptorPool {
    pool: Mutex<vk::DescriptorPool>,
    device: Arc<Device>,
}

impl DescriptorPool {
    /// Initializes a new pool.
    // FIXME: capacity of the pool
    pub fn new(device: &Arc<Device>) -> Result<Arc<DescriptorPool>, OomError> {
        let vk = device.pointers();

        // FIXME: arbitrary
        let pool_sizes = vec![
            vk::DescriptorPoolSize {
                ty: vk::DESCRIPTOR_TYPE_UNIFORM_BUFFER,
                descriptorCount: 10,
            },
            vk::DescriptorPoolSize {
                ty: vk::DESCRIPTOR_TYPE_INPUT_ATTACHMENT,
                descriptorCount: 10,
            }
        ];

        let pool = unsafe {
            let infos = vk::DescriptorPoolCreateInfo {
                sType: vk::STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO,
                pNext: ptr::null(),
                flags: vk::DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT,   // TODO:
                maxSets: 100,       // TODO: let user choose
                poolSizeCount: pool_sizes.len() as u32,
                pPoolSizes: pool_sizes.as_ptr(),
            };

            let mut output = mem::uninitialized();
            try!(check_errors(vk.CreateDescriptorPool(device.internal_object(), &infos,
                                                      ptr::null(), &mut output)));
            output
        };

        Ok(Arc::new(DescriptorPool {
            pool: Mutex::new(pool),
            device: device.clone(),
        }))
    }

    /// Returns the device this pool was created from.
    #[inline]
    pub fn device(&self) -> &Arc<Device> {
        &self.device
    }
}

unsafe impl SynchronizedVulkanObject for DescriptorPool {
    type Object = vk::DescriptorPool;

    #[inline]
    fn internal_object_guard(&self) -> MutexGuard<vk::DescriptorPool> {
        self.pool.lock().unwrap()
    }
}

impl Drop for DescriptorPool {
    #[inline]
    fn drop(&mut self) {
        unsafe {
            let vk = self.device.pointers();
            let pool = self.pool.lock().unwrap();
            vk.DestroyDescriptorPool(self.device.internal_object(), *pool, ptr::null());
        }
    }
}

#[cfg(test)]
mod tests {
    use descriptor_set::DescriptorPool;

    #[test]
    fn create() {
        let (device, _) = gfx_dev_and_queue!();
        let _ = DescriptorPool::new(&device).unwrap();
    }

    #[test]
    fn device() {
        let (device, _) = gfx_dev_and_queue!();
        let pool = DescriptorPool::new(&device).unwrap();
        assert_eq!(&**pool.device() as *const _, &*device as *const _);
    }
}
<commit_msg>Small hack to the descriptor pool to allocate enough resources<commit_after>use std::mem;
use std::ptr;
use std::sync::Arc;
use std::sync::Mutex;
use std::sync::MutexGuard;

use device::Device;

use OomError;
use SynchronizedVulkanObject;
use VulkanObject;
use VulkanPointers;
use check_errors;
use vk;

/// Pool from which descriptor sets are allocated from.
///
/// A pool has a maximum number of descriptor sets and a maximum number of descriptors (one value
/// per descriptor type) it can allocate.
pub struct DescriptorPool {
    pool: Mutex<vk::DescriptorPool>,
    device: Arc<Device>,
}

impl DescriptorPool {
    /// Initializes a new pool.
    // FIXME: capacity of the pool
    pub fn new(device: &Arc<Device>) -> Result<Arc<DescriptorPool>, OomError> {
        let vk = device.pointers();

        // FIXME: arbitrary
        let pool_sizes = vec![
            vk::DescriptorPoolSize {
                ty: vk::DESCRIPTOR_TYPE_UNIFORM_BUFFER,
                descriptorCount: 10,
            },
            vk::DescriptorPoolSize {
                ty: vk::DESCRIPTOR_TYPE_INPUT_ATTACHMENT,
                descriptorCount: 10,
            },
            vk::DescriptorPoolSize {
                ty: vk::DESCRIPTOR_TYPE_SAMPLED_IMAGE,
                descriptorCount: 10,
            },
            vk::DescriptorPoolSize {
                ty: vk::DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,
                descriptorCount: 10,
            },
        ];

        let pool = unsafe {
            let infos = vk::DescriptorPoolCreateInfo {
                sType: vk::STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO,
                pNext: ptr::null(),
                flags: vk::DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT,   // TODO:
                maxSets: 100,       // TODO: let user choose
                poolSizeCount: pool_sizes.len() as u32,
                pPoolSizes: pool_sizes.as_ptr(),
            };

            let mut output = mem::uninitialized();
            try!(check_errors(vk.CreateDescriptorPool(device.internal_object(), &infos,
                                                      ptr::null(), &mut output)));
            output
        };

        Ok(Arc::new(DescriptorPool {
            pool: Mutex::new(pool),
            device: device.clone(),
        }))
    }

    /// Returns the device this pool was created from.
    #[inline]
    pub fn device(&self) -> &Arc<Device> {
        &self.device
    }
}

unsafe impl SynchronizedVulkanObject for DescriptorPool {
    type Object = vk::DescriptorPool;

    #[inline]
    fn internal_object_guard(&self) -> MutexGuard<vk::DescriptorPool> {
        self.pool.lock().unwrap()
    }
}

impl Drop for DescriptorPool {
    #[inline]
    fn drop(&mut self) {
        unsafe {
            let vk = self.device.pointers();
            let pool = self.pool.lock().unwrap();
            vk.DestroyDescriptorPool(self.device.internal_object(), *pool, ptr::null());
        }
    }
}

#[cfg(test)]
mod tests {
    use descriptor_set::DescriptorPool;

    #[test]
    fn create() {
        let (device, _) = gfx_dev_and_queue!();
        let _ = DescriptorPool::new(&device).unwrap();
    }

    #[test]
    fn device() {
        let (device, _) = gfx_dev_and_queue!();
        let pool = DescriptorPool::new(&device).unwrap();
        assert_eq!(&**pool.device() as *const _, &*device as *const _);
    }
}
<|endoftext|>


<commit_before>//! Implementation of `make clean` in rustbuild.
//!
//! Responsible for cleaning out a build directory of all old and stale
//! artifacts to prepare for a fresh build. Currently doesn't remove the
//! `build/cache` directory (download cache) or the `build/$target/llvm`
//! directory unless the `--all` flag is present.

use std::fs;
use std::io::{self, ErrorKind};
use std::path::Path;

use build_helper::t;

use crate::Build;

pub fn clean(build: &Build, all: bool) {
    rm_rf("tmp".as_ref());

    if all {
        rm_rf(&build.out);
    } else {
        rm_rf(&build.out.join("tmp"));
        rm_rf(&build.out.join("dist"));
        rm_rf(&build.out.join("bootstrap"));

        for host in &build.hosts {
            let entries = match build.out.join(host.triple).read_dir() {
                Ok(iter) => iter,
                Err(_) => continue,
            };

            for entry in entries {
                let entry = t!(entry);
                if entry.file_name().to_str() == Some("llvm") {
                    continue;
                }
                let path = t!(entry.path().canonicalize());
                rm_rf(&path);
            }
        }
    }
}

fn rm_rf(path: &Path) {
    match path.symlink_metadata() {
        Err(e) => {
            if e.kind() == ErrorKind::NotFound {
                return;
            }
            panic!("failed to get metadata for file {}: {}", path.display(), e);
        }
        Ok(metadata) => {
            if metadata.file_type().is_file() || metadata.file_type().is_symlink() {
                do_op(path, "remove file", |p| fs::remove_file(p));
                return;
            }

            for file in t!(fs::read_dir(path)) {
                rm_rf(&t!(file).path());
            }
            do_op(path, "remove dir", |p| fs::remove_dir(p));
        }
    };
}

fn do_op<F>(path: &Path, desc: &str, mut f: F)
where
    F: FnMut(&Path) -> io::Result<()>,
{
    match f(path) {
        Ok(()) => {}
        // On windows we can't remove a readonly file, and git will often clone files as readonly.
        // As a result, we have some special logic to remove readonly files on windows.
        // This is also the reason that we can't use things like fs::remove_dir_all().
        Err(ref e) if cfg!(windows) && e.kind() == ErrorKind::PermissionDenied => {
            let mut p = t!(path.symlink_metadata()).permissions();
            p.set_readonly(false);
            t!(fs::set_permissions(path, p));
            f(path).unwrap_or_else(|e| {
                panic!("failed to {} {}: {}", desc, path.display(), e);
            })
        }
        Err(e) => {
            panic!("failed to {} {}: {}", desc, path.display(), e);
        }
    }
}
<commit_msg>Do not delete bootstrap.exe on Windows during clean<commit_after>//! Implementation of `make clean` in rustbuild.
//!
//! Responsible for cleaning out a build directory of all old and stale
//! artifacts to prepare for a fresh build. Currently doesn't remove the
//! `build/cache` directory (download cache) or the `build/$target/llvm`
//! directory unless the `--all` flag is present.

use std::fs;
use std::io::{self, ErrorKind};
use std::path::Path;

use build_helper::t;

use crate::Build;

pub fn clean(build: &Build, all: bool) {
    rm_rf("tmp".as_ref());

    if all {
        rm_rf(&build.out);
    } else {
        rm_rf(&build.out.join("tmp"));
        rm_rf(&build.out.join("dist"));
        // Only delete the bootstrap executable on non-Windows systems
        // Windows does not allow deleting a currently running executable
        #[cfg(not(windows))]
        rm_rf(&build.out.join("bootstrap"));

        for host in &build.hosts {
            let entries = match build.out.join(host.triple).read_dir() {
                Ok(iter) => iter,
                Err(_) => continue,
            };

            for entry in entries {
                let entry = t!(entry);
                if entry.file_name().to_str() == Some("llvm") {
                    continue;
                }
                let path = t!(entry.path().canonicalize());
                rm_rf(&path);
            }
        }
    }
}

fn rm_rf(path: &Path) {
    match path.symlink_metadata() {
        Err(e) => {
            if e.kind() == ErrorKind::NotFound {
                return;
            }
            panic!("failed to get metadata for file {}: {}", path.display(), e);
        }
        Ok(metadata) => {
            if metadata.file_type().is_file() || metadata.file_type().is_symlink() {
                do_op(path, "remove file", |p| fs::remove_file(p));
                return;
            }

            for file in t!(fs::read_dir(path)) {
                rm_rf(&t!(file).path());
            }
            do_op(path, "remove dir", |p| fs::remove_dir(p));
        }
    };
}

fn do_op<F>(path: &Path, desc: &str, mut f: F)
where
    F: FnMut(&Path) -> io::Result<()>,
{
    match f(path) {
        Ok(()) => {}
        // On windows we can't remove a readonly file, and git will often clone files as readonly.
        // As a result, we have some special logic to remove readonly files on windows.
        // This is also the reason that we can't use things like fs::remove_dir_all().
        Err(ref e) if cfg!(windows) && e.kind() == ErrorKind::PermissionDenied => {
            let mut p = t!(path.symlink_metadata()).permissions();
            p.set_readonly(false);
            t!(fs::set_permissions(path, p));
            f(path).unwrap_or_else(|e| {
                panic!("failed to {} {}: {}", desc, path.display(), e);
            })
        }
        Err(e) => {
            panic!("failed to {} {}: {}", desc, path.display(), e);
        }
    }
}
<|endoftext|>


<commit_before>
pub fn get_content() -> ~str {
		let c = ~"Foo!";
		return c.clone();
}<commit_msg>Fixup.<commit_after>
pub fn get_content() -> ~str {
		return ~"Foo!";
}<|endoftext|>


<commit_before>use byteorder::{LittleEndian, WriteBytesExt};
use libc::*;
use std::ptr;
use std::mem;
use asm::Reg::*;

#[derive(PartialEq,Eq,Debug,Copy,Clone)]
#[repr(C)]
pub enum Reg {
    Rax, Rcx, Rdx, Rbx, Rsp, Rbp, Rsi, Rdi,
    R8, R9, R10, R11, R12, R13, R14, R15,
}

impl Reg {
    // most significant bit
    fn msb(&self) -> u8 {
        (self.idx() & 8) >> 3
    }

    // least 3 significant bit
    fn lsb3(&self) -> u8 {
        self.idx() & 7
    }

    // index of enum
    fn idx(&self) -> u8 {
        let val : u32 = unsafe { mem::transmute(*self) };

        val as u8
    }
}

#[test]
fn test_msb() {
    assert_eq!(0, Rax.msb());
    assert_eq!(0, Rcx.msb());
    assert_eq!(0, Rdx.msb());
    assert_eq!(0, Rbx.msb());
    assert_eq!(0, Rsp.msb());
    assert_eq!(0, Rbp.msb());
    assert_eq!(0, Rsi.msb());
    assert_eq!(0, Rdi.msb());

    assert_eq!(1, R8.msb());
    assert_eq!(1, R9.msb());
    assert_eq!(1, R10.msb());
    assert_eq!(1, R11.msb());
    assert_eq!(1, R12.msb());
    assert_eq!(1, R13.msb());
    assert_eq!(1, R14.msb());
    assert_eq!(1, R15.msb());
}

#[test]
fn test_idx() {
    assert_eq!(0, Rax.idx());
    assert_eq!(1, Rcx.idx());
    assert_eq!(2, Rdx.idx());
    assert_eq!(3, Rbx.idx());
    assert_eq!(4, Rsp.idx());
    assert_eq!(5, Rbp.idx());
    assert_eq!(6, Rsi.idx());
    assert_eq!(7, Rdi.idx());

    assert_eq!(8, R8.idx());
    assert_eq!(9, R9.idx());
    assert_eq!(10, R10.idx());
    assert_eq!(11, R11.idx());
    assert_eq!(12, R12.idx());
    assert_eq!(13, R13.idx());
    assert_eq!(14, R14.idx());
    assert_eq!(15, R15.idx());
}

#[test]
fn test_lsb3() {
    assert_eq!(0, Rax.lsb3());
    assert_eq!(1, Rcx.lsb3());
    assert_eq!(2, Rdx.lsb3());
    assert_eq!(3, Rbx.lsb3());
    assert_eq!(4, Rsp.lsb3());
    assert_eq!(5, Rbp.lsb3());
    assert_eq!(6, Rsi.lsb3());
    assert_eq!(7, Rdi.lsb3());

    assert_eq!(0, R8.lsb3());
    assert_eq!(1, R9.lsb3());
    assert_eq!(2, R10.lsb3());
    assert_eq!(3, R11.lsb3());
    assert_eq!(4, R12.lsb3());
    assert_eq!(5, R13.lsb3());
    assert_eq!(6, R14.lsb3());
    assert_eq!(7, R15.lsb3());
}

#[derive(Debug)]
pub struct Addr {
    base: Reg,
    index: Option<Reg>,
    scale: u8,
    disp: i32,

    direct: bool,
}

impl Addr {
    pub fn direct(base: Reg) -> Addr {
        Addr { base: base, index: None, scale: 0, disp: 0, direct: true }
    }

    pub fn indirect(base: Reg) -> Addr {
        Addr { base: base, index: None, scale: 0, disp: 0, direct: false }
    }

    pub fn with_disp(base: Reg, disp: i32) -> Addr {
        Addr { base: base, index: None, scale: 0, disp: disp, direct: false }
    }

    pub fn with_sib(base: Reg, idx: Reg, scale: u8, disp: i32) -> Addr {
        assert!(idx != Rsp);
        assert!(scale <= 3);

        Addr { base: base, index: Some(idx), scale: scale, disp: disp, direct: false }
    }

    fn msb(&self) -> u8 {
        self.base.msb()
    }

    fn base_special(&self) -> bool {
        self.base == Rsp || self.base == Rbp || self.base == R12 || self.base == R13
    }

    fn emit(&self, asm: &mut Assembler, modrm_reg: u8) {
        if self.direct {
            asm.modrm(0b11, modrm_reg, self.base.lsb3());

        } else if self.index.is_none() {
            if !self.base_special() {
                self.emit_without_sib(asm, modrm_reg);
            } else if self.base == Rsp || self.base == R13 {
                self.emit_Rsp(asm, modrm_reg);

            } else {
                self.emit_Rbp(asm, modrm_reg);
            }

        } else {
            self.emit_sib(asm, modrm_reg);
        }
    }

    fn emit_Rsp(&self, asm: &mut Assembler, modrm_reg: u8) {
        let fits_into_byte = fits8(self.disp as i64);
        let mode =
            if fits_into_byte { 0b01 }
            else { 0b10 };

        asm.modrm(mode, modrm_reg, 0b100);
        asm.sib(0, 0b100, self.base.lsb3());

        if fits_into_byte {
            asm.emitb(self.disp as u8);
        } else {
            asm.emitd(self.disp as u32);
        }
    }

    fn emit_Rbp(&self, asm: &mut Assembler, modrm_reg: u8) {
        let fits_into_byte = fits8(self.disp as i64);
        let mode =
            if fits_into_byte { 0b01 }
            else { 0b10 };

        asm.modrm(mode, modrm_reg, 0b101);

        if fits_into_byte {
            asm.emitb(self.disp as u8);
        } else {
            asm.emitd(self.disp as u32);
        }
    }

    fn emit_sib(&self, asm: &mut Assembler, modrm_reg: u8) {
        let fits_into_byte = fits8(self.disp as i64);

        let mode =
            if self.disp == 0 { 0b00 }
            else if fits_into_byte { 0b01 }
            else { 0b10 };

        asm.modrm(mode, modrm_reg, 0b100);
        asm.sib(self.scale, self.index.unwrap().lsb3(), self.base.lsb3());

        if self.disp != 0 {
            if fits_into_byte {
                asm.emitb(self.disp as u8);
            } else {
                asm.emitd(self.disp as u32);
            }
        }
    }

    fn emit_without_sib(&self, asm: &mut Assembler, modrm_reg: u8) {
        let fits_into_byte = fits8(self.disp as i64);

        let mode =
            if self.disp == 0 { 0b00 }
            else if fits_into_byte { 0b01 }
            else { 0b10 };

        asm.modrm(mode, modrm_reg, self.base.lsb3());

        if self.disp != 0 {
            if fits_into_byte {
                asm.emitb(self.disp as u8);
            } else {
                asm.emitd(self.disp as u32);
            }
        }
    }
}

fn fits8(v: i64) -> bool {
    v == (v as i8) as i64
}

fn fits16(v: i64) -> bool {
    v == (v as i16) as i64
}

fn fits32(v: i64) -> bool {
    v == (v as i32) as i64
}

#[test]
fn test_fits8() {
    assert!(fits8(0));
    assert!(fits8(127));
    assert!(fits8(-128));
    assert!(!fits8(128));
    assert!(!fits8(-129));
}

#[test]
fn test_fits16() {
    assert!(fits16(8));
    assert!(fits16(32767));
    assert!(fits16(-32768));
    assert!(!fits16(32768));
    assert!(!fits16(-32769));
}

// Machine instruction without any operands, just emits the given
// opcode
macro_rules! i0p {
   ($i:ident, $w:expr) => {pub fn $i(&mut self) { self.opcode($w); }}
}

// Machine Instruction with 1 register operand, register
// index is added to opcode
macro_rules! q1p_r_rpo {
    ($i:ident, $w:expr) => {pub fn $i(&mut self, dest: Reg) {
        if dest.msb() != 0 {
            self.rex_prefix(0, 0, 0, 1);
        }

        self.opcode($w + dest.lsb3());
    }}
}

macro_rules! q2p_atr {
    ($i:ident, $w: expr) => {pub fn $i(&mut self, src: Addr, dest: Reg) {
        self.rex_prefix(1, dest.msb(), 0, src.msb());
        self.opcode($w);
        src.emit(self, dest.lsb3());
    }}
}

// machine instruction with 2 operands. register to address
macro_rules! q2p_rta {
    ($i:ident, $w: expr) => {pub fn $i(&mut self, src: Reg, dest: Addr) {
        self.rex_prefix(1, src.msb(), 0, dest.msb());
        self.opcode($w);

        dest.emit(self, src.lsb3());
    }}
}

// machine instruction with 2 operands. u64 to register. register index is
// added to opcode
macro_rules! q2p_i64tr {
    ($i:ident, $w: expr) => {pub fn $i(&mut self, src: u64, dest: Reg) {
        self.rex_prefix(1, 0, 0, dest.msb());
        self.opcode($w + dest.lsb3());
        self.emitq(src);
    }}
}

// machine instruction with 2 operands. 32 bit immediate and destination operand
macro_rules! q2p_i32ta {
    ($i:ident, $w: expr, $modrm_reg: expr) => {pub fn $i(&mut self, src: u32, dest: Addr) {
        self.rex_prefix(1, 0, 0, dest.msb());
        self.opcode($w);
        dest.emit(self, $modrm_reg);
        self.emitd(src);
    }}
}

// machine instruction with 2 operands. 8 bit immediate and destination operand
macro_rules! q2p_i8ta {
    ($i:ident, $w: expr, $modrm_reg: expr) => {pub fn $i(&mut self, src: u8, dest: Addr) {
        self.rex_prefix(1, 0, 0, dest.msb());
        self.opcode($w);
        dest.emit(self, $modrm_reg);
        self.emitb(src);
    }}
}

#[derive(Copy,Clone)]
struct Label(usize);

pub struct Assembler {
    code: Vec<u8>,
    labels: Vec<Option<usize>>,
    link_jmps: Vec<(usize, usize)>,
}

impl Assembler {
    pub fn new() -> Assembler {
        Assembler { code: Vec::new(), labels: Vec::new(), link_jmps: Vec::new() }
    }

    i0p!(nop, 0x90);
    i0p!(ret, 0xC3);

    q1p_r_rpo!(pushq, 0x50);
    q1p_r_rpo!(popq, 0x58);

    q2p_rta!(addq_rta, 0x01);
    q2p_atr!(addq_atr, 0x03);
    q2p_i32ta!(addq_i32ta, 0x81, 0);
    q2p_i8ta!(addq_i8ta, 0x83, 0);

    q2p_rta!(subq_rta, 0x29);
    q2p_atr!(subq_atr, 0x2B);
    q2p_i32ta!(subq_i32ta, 0x81, 5);
    q2p_i8ta!(subq_i8ta, 0x83, 5);

    q2p_rta!(movq_rta, 0x89);
    q2p_atr!(movq_atr, 0x8B);
    q2p_i64tr!(movq_i64tr, 0xB8);
    q2p_i32ta!(movq_i32ta, 0xC7, 0);

    fn label(&mut self) -> Label {
        let id = self.labels.len();
        self.labels.push(None);

        Label(id)
    }

    fn jmp(&mut self, lbl: Label) {
        let Label(id) = lbl;
        let dest = self.labels[id];
        let src = self.code.len();

        if dest.is_some() {
            let dest = dest.unwrap() as i32;
            let src = src as i32;

            let offset = (dest-src-5) as u32;

            self.jmp_offset(offset);
        } else {
            self.reserve(5);
            self.link_jmps.push((id, src));
        }
    }

    fn jmp_offset(&mut self, offset: u32) {
        self.opcode(0xE9);
        self.emitd(offset);
    }

    fn bind(&mut self, lbl: Label) {
        let Label(id) = lbl;

        assert!(self.labels[id].is_none(), "label already bound");
        self.labels[id] = Some(self.code.len());
    }

    fn opcode(&mut self, c: u8) { self.code.push(c); }
    fn emitb(&mut self, c: u8) { self.code.push(c); }
    fn emitw(&mut self, w: u16) { self.code.write_u16::<LittleEndian>(w).unwrap(); }
    fn emitd(&mut self, d: u32) { self.code.write_u32::<LittleEndian>(d).unwrap(); }
    fn emitq(&mut self, q: u64) { self.code.write_u64::<LittleEndian>(q).unwrap(); }

    fn modrm(&mut self, mode: u8, reg: u8, rm: u8) {
        self.emitb(mode << 6 | reg << 3 | rm );
    }

    fn sib(&mut self, scale: u8, index: u8, base: u8) {
        self.emitb(scale << 6 | index << 3 | base);
    }

    fn rex_prefix(&mut self, w: u8, r: u8, x: u8, b: u8) {
        let v = 0x40 | w << 3 | r << 2 | x << 1 | b;

        self.code.push(v);
    }

    fn reserve(&mut self, size: usize) {
        for i in 0..size {
            self.nop();
        }
    }

    fn code(mut self) -> Vec<u8> {
        self.link();

        self.code
    }

    fn link(&mut self) {
        for &(lbl, pos) in &self.link_jmps {
            let dest = self.labels[lbl].unwrap();
            let offset = dest - pos - 5;

            self.code[pos] = 0xE9;
            (&mut self.code[pos+1..]).write_u32::<LittleEndian>(offset as u32).unwrap();
        }
    }
}

#[test]
fn test_backward_jump() {
    let mut asm = Assembler::new();
    let lbl = asm.label();
    asm.bind(lbl);
    asm.nop();
    asm.nop();
    asm.jmp(lbl);

    assert_eq!(vec![0x90, 0x90, 0xE9, 0xF9, 0xFF, 0xFF, 0xFF], asm.code);
}

#[test]
fn test_forward_jump() {
    let mut asm = Assembler::new();
    let lbl = asm.label();
    asm.jmp(lbl);
    asm.nop();
    asm.nop();
    asm.bind(lbl);

    assert_eq!(vec![0x90; 7], asm.code);
    assert_eq!(vec![0xE9, 2, 0, 0, 0, 0x90, 0x90], asm.code());
}

#[test]
#[should_panic]
fn test_label_not_bound() {
    let mut asm = Assembler::new();
    let lbl = asm.label();
    asm.jmp(lbl);

    asm.code();
}

#[test]
#[should_panic]
fn test_label_bound_twice() {
    let mut asm = Assembler::new();
    let lbl = asm.label();
    asm.bind(lbl);
    asm.bind(lbl);
}

#[test]
fn test_nop() {
    let mut asm = Assembler::new();
    asm.nop();

    assert_eq!(vec![0x90], asm.code);
}

#[test]
fn test_ret() {
    let mut asm = Assembler::new();
    asm.ret();

    assert_eq!(vec![0xc3], asm.code);
}

#[test]
#[should_panic]
fn test_sib_with_Rsp() {
    Addr::with_sib(Rsp, Rsp, 1, 1);
}

#[test]
#[should_panic]
fn test_sib_with_illegal_scale() {
    Addr::with_sib(Rsp, Rbp, 4, 1);
}

#[test]
fn test_sib_without_Rsp() {
    Addr::with_sib(Rsp, Rcx, 1, 1);
    Addr::with_sib(Rsp, R9, 1, 1);
    Addr::with_sib(Rsp, Rbp, 1, 1);
}

#[test]
fn test_push() {
    let mut asm = Assembler::new();
    asm.pushq(Rax);
    asm.pushq(R8);
    asm.pushq(Rcx);

    assert_eq!(vec![0x50, 0x41, 0x50, 0x51], asm.code);
}

#[test]
fn test_pop() {
    let mut asm = Assembler::new();
    asm.popq(Rax);
    asm.popq(R8);
    asm.popq(Rcx);

    assert_eq!(vec![0x58, 0x41, 0x58, 0x59], asm.code);
}

#[test]
fn test_mov() {
    let mut asm = Assembler::new();
    asm.movq_rta(R15, Addr::direct(Rax));
    asm.movq_rta(Rsi, Addr::direct(R8));

    assert_eq!(vec![0x4c, 0x89, 0xf8, 0x49, 0x89, 0xf0], asm.code);
}

#[test]
fn test_mov_addr_to_reg() {
    let mut asm = Assembler::new();
    asm.movq_atr(Addr::indirect(Rax), R9);

    assert_eq!(vec![0x4C, 0x8B, 0x08], asm.code);
}

#[test]
fn test_mov_i64_to_reg() {
    let mut asm = Assembler::new();
    asm.movq_i64tr(1, Rax);
    asm.movq_i64tr(2, R8);

    assert_eq!(vec![0x48, 0xb8, 1, 0, 0, 0, 0, 0, 0, 0,
        0x49, 0xb8, 2, 0, 0, 0, 0, 0, 0, 0], asm.code);
}

#[test]
fn test_mov_i32_to_mem() {
    let mut asm = Assembler::new();
    asm.movq_i32ta(2, Addr::with_disp(Rbp, 1));
    asm.movq_i32ta(3, Addr::with_disp(R8, -1));

    assert_eq!(vec![0x48, 0xC7, 0x45, 0x01, 2, 0, 0, 0,
        0x49, 0xC7, 0x40, 0xFF, 3, 0, 0, 0], asm.code);
}

#[test]
fn test_mov_i32_to_reg() {
    let mut asm = Assembler::new();
    asm.movq_i32ta(1, Addr::direct(Rax));
    asm.movq_i32ta(2, Addr::direct(R9));

    assert_eq!(vec![0x48, 0xC7, 0xC0, 1, 0, 0, 0,
        0x49, 0xC7, 0xC1, 2, 0, 0, 0], asm.code);
}

#[test]
fn test_add_reg_to_reg() {
    let mut asm = Assembler::new();
    asm.addq_rta(R10, Addr::direct(Rcx));
    asm.addq_rta(Rbx, Addr::direct(R10));

    assert_eq!(vec![0x4c, 0x01, 0xd1,
        0x49, 0x01, 0xda], asm.code);
}

#[test]
fn test_add_reg_to_addr() {
    let mut asm = Assembler::new();
    asm.addq_rta(R9, Addr::with_disp(Rbp, 1));
    asm.addq_rta(Rcx, Addr::with_disp(Rax, -1));
    asm.addq_rta(R9, Addr::indirect(Rax));

    assert_eq!(vec![0x4C, 0x01, 0x4D, 0x01,
        0x48, 0x01, 0x48, 0xFF,
        0x4C, 0x01, 0x08], asm.code);
}

#[test]
fn test_add_addr_to_reg() {
    let mut asm = Assembler::new();
    asm.addq_atr(Addr::with_disp(Rbp, 1), R9);
    asm.addq_atr(Addr::with_disp(Rax, -1), Rcx);
    asm.addq_atr(Addr::with_sib(Rsp, Rbp, 1, 3), R9);
    asm.addq_atr(Addr::with_sib(Rsp, Rbp, 2, 0), R9);

    assert_eq!(vec![0x4C, 0x03, 0x4D, 0x01,
        0x48, 0x03, 0x48, 0xFF,
        0x4C, 0x03, 0x4C, 0x6C, 0x03,
        0x4C, 0x03, 0x0C, 0xAC], asm.code);
}

#[test]
fn test_add_i32_to_reg() {
    let mut asm = Assembler::new();
    asm.addq_i32ta(1, Addr::direct(Rcx));
    asm.addq_i32ta(0x100, Addr::direct(R9));

    assert_eq!(vec![0x48, 0x81, 0xC1, 1, 0, 0, 0,
        0x49, 0x81, 0xC1, 0, 1, 0, 0], asm.code);
}

#[test]
fn test_add_i8_to_reg() {
    let mut asm = Assembler::new();
    asm.addq_i8ta(1, Addr::direct(R8));
    asm.addq_i8ta(1, Addr::direct(Rsi));

    assert_eq!(vec![0x49, 0x83, 0xC0, 0x01,
        0x48, 0x83, 0xC6, 0x01], asm.code);
}

#[test]
fn test_add_i32_to_addr() {
    let mut asm = Assembler::new();
    asm.addq_i32ta(1, Addr::with_disp(Rcx,1));
    asm.addq_i32ta(0x100, Addr::with_disp(R10,-1));

    assert_eq!(vec![0x48, 0x81, 0x41, 0x01, 1, 0, 0, 0,
        0x49, 0x81, 0x42, 0xFF, 0, 1, 0, 0], asm.code);
}

#[test]
fn test_add_i8_to_addr() {
    let mut asm = Assembler::new();
    asm.addq_i8ta(1, Addr::with_disp(Rcx, 1));
    asm.addq_i8ta(2, Addr::with_disp(R11, -1));

    assert_eq!(vec![0x48, 0x83, 0x41, 0x01, 0x01,
        0x49, 0x83, 0x43, 0xFF, 0x02], asm.code);
}

#[test]
fn test_sub_i32_from_addr() {
    let mut asm = Assembler::new();
    asm.subq_i32ta(1, Addr::with_disp(Rcx,1));
    asm.subq_i32ta(0x100, Addr::with_disp(R10,-1));

    assert_eq!(vec![0x48, 0x81, 0x69, 0x01, 1, 0, 0, 0,
        0x49, 0x81, 0x6A, 0xFF, 0, 1, 0, 0], asm.code);
}

#[test]
fn test_sub_i8_from_addr() {
    let mut asm = Assembler::new();
    asm.subq_i8ta(1, Addr::with_disp(Rcx, 1));
    asm.subq_i8ta(2, Addr::with_disp(R11, -1));

    assert_eq!(vec![0x48, 0x83, 0x69, 0x01, 0x01,
        0x49, 0x83, 0x6B, 0xFF, 0x02], asm.code);
}

#[test]
fn test_sub_reg_from_reg() {
    let mut asm = Assembler::new();
    asm.subq_rta(R10, Addr::direct(Rcx));
    asm.subq_rta(Rbx, Addr::direct(R10));

    assert_eq!(vec![0x4C, 0x29, 0xD1,
        0x49, 0x29, 0xDA], asm.code);
}

#[test]
fn test_sub_reg_from_addr() {
    let mut asm = Assembler::new();
    asm.subq_rta(R9, Addr::with_disp(Rbp, 1));
    asm.subq_rta(Rcx, Addr::with_disp(Rax, -1));

    assert_eq!(vec![0x4C, 0x29, 0x4D, 0x01,
        0x48, 0x29, 0x48, 0xFF], asm.code);
}

#[test]
fn test_sub_addr_from_reg() {
    let mut asm = Assembler::new();
    asm.subq_atr(Addr::with_disp(Rbp, 1), R9);
    asm.subq_atr(Addr::with_disp(Rax, -1), Rcx);

    assert_eq!(vec![0x4C, 0x2B, 0x4D, 0x01,
        0x48, 0x2B, 0x48, 0xFF], asm.code);
}

#[test]
fn test_sub_i32_from_reg() {
    let mut asm = Assembler::new();
    asm.subq_i32ta(1, Addr::direct(Rcx));
    asm.subq_i32ta(0x100, Addr::direct(R9));

    assert_eq!(vec![0x48, 0x81, 0xE9, 1, 0, 0, 0,
        0x49, 0x81, 0xE9, 0, 1, 0, 0], asm.code);
}

#[test]
fn test_sub_i8_from_reg() {
    let mut asm = Assembler::new();
    asm.subq_i8ta(1, Addr::direct(R8));
    asm.subq_i8ta(1, Addr::direct(Rsi));

    assert_eq!(vec![0x49, 0x83, 0xE8, 0x01,
        0x48, 0x83, 0xEE, 0x01], asm.code);
}

pub struct JitFunction {
    pub size: size_t,
    pub ptr: extern fn (u64) -> u64
}

impl JitFunction {
    pub fn new(code: &[u8]) -> JitFunction {
        let size = code.len() as u64;

        unsafe {
            let fct = mmap(0 as *mut c_void, size, PROT_READ | PROT_WRITE,
                MAP_PRIVATE | MAP_ANON, -1, 0);

            if fct == MAP_FAILED {
                panic!("mmap failed");
            }

            ptr::copy_nonoverlapping(code.as_ptr() as *const c_void, fct, code.len());

            if mprotect(fct, size, PROT_READ | PROT_EXEC) == -1 {
                panic!("mprotect failed");
            }

            JitFunction {
                size: size,
                ptr: mem::transmute(fct)
            }
        }
    }
}

impl Drop for JitFunction {
    fn drop(&mut self) {
        unsafe {
            munmap(mem::transmute(self.ptr), self.size);
        }
    }
}

#[test]
fn test_create_function() {
    let mut asm = Assembler::new();
    asm.movq_rta(Rdi, Addr::direct(Rax));
    asm.addq_i8ta(4, Addr::direct(Rax));
    asm.ret();

    let fct = JitFunction::new(&asm.code);

    assert_eq!(5, (fct.ptr)(1));
}
<commit_msg>asm: removed it for now<commit_after><|endoftext|>


<commit_before>use std::fmt::{Display, Error, Formatter};

#[derive(Clone, Debug, PartialEq, Eq)]
pub enum BinOp {
    Ge,
    Gt,
    Eql,       // ==
    EqlStrict, // ===
    Neq,       // !=
    NeqStrict, // !==
    Le,
    Lt,

    And,
    Or,

    BitOr,
    BitXor,
    BitAnd,

    ShiftLeft,
    ShiftRight,
    ShiftRightUnsigned,

    Minus,
    Plus,
    Slash,
    Star,
    Exponent,
    Mod,
}

#[derive(Clone, PartialEq, Eq, PartialOrd, Ord)]
pub enum Precedence {
    Const = 110,
    Sign = 100,
    Inc = 90,
    Mult = 70,
    Add = 60,
    Shift = 52,
    Cmp = 51,
    Equality = 50,
    BitAnd = 43,
    BitXor = 42,
    BitOr = 41,
    And = 40,
    Or = 30,
}

impl BinOp {
    pub fn precedence(&self) -> Precedence {
        match *self {
            BinOp::And => Precedence::And,
            BinOp::Ge | BinOp::Gt | BinOp::Le | BinOp::Lt => Precedence::Cmp,
            BinOp::Eql | BinOp::Neq | BinOp::EqlStrict | BinOp::NeqStrict => Precedence::Equality,
            BinOp::Or => Precedence::Or,
            BinOp::BitOr => Precedence::BitOr,
            BinOp::BitXor => Precedence::BitXor,
            BinOp::BitAnd => Precedence::BitAnd,
            BinOp::Minus | BinOp::Plus => Precedence::Add,
            BinOp::Slash | BinOp::Star | BinOp::Exponent | BinOp::Mod => Precedence::Mult,
            BinOp::ShiftLeft | BinOp::ShiftRight | BinOp::ShiftRightUnsigned => Precedence::Shift,
        }
    }

    pub fn is_commutative(&self) -> bool {
        match *self {
            BinOp::Minus | BinOp::Slash => false,
            _ => true
        }
    }
}

impl Display for BinOp {
    fn fmt(&self, fmt: &mut Formatter) -> Result<(), Error> {
        match *self {
            BinOp::And => write!(fmt, "&&"),
            BinOp::Ge => write!(fmt, ">="),
            BinOp::Gt => write!(fmt, ">"),
            BinOp::Eql => write!(fmt, "=="),
            BinOp::EqlStrict => write!(fmt, "==="),
            BinOp::Le => write!(fmt, "<="),
            BinOp::Lt => write!(fmt, "<"),
            BinOp::Minus => write!(fmt, "-"),
            BinOp::Neq => write!(fmt, "!="),
            BinOp::NeqStrict => write!(fmt, "!=="),
            BinOp::Or => write!(fmt, "||"),
            BinOp::Plus => write!(fmt, "+"),
            BinOp::Slash => write!(fmt, "/"),
            BinOp::Star => write!(fmt, "*"),
            BinOp::Exponent => write!(fmt, "**"),
            BinOp::Mod => write!(fmt, "%"),
            BinOp::BitXor => write!(fmt, "^"),
            BinOp::BitOr => write!(fmt, "|"),
            BinOp::BitAnd => write!(fmt, "&"),
            BinOp::ShiftLeft => write!(fmt, "<<"),
            BinOp::ShiftRight => write!(fmt, ">>"),
            BinOp::ShiftRightUnsigned => write!(fmt, ">>>"),
        }
    }
}

#[derive(Clone, Debug)]
pub enum Exp {
    Array(Vec<Box<Exp>>),
    BinExp(Box<Exp>, BinOp, Box<Exp>),
    Bool(bool),
    Call(Box<Exp>, Vec<Box<Exp>>),
    Defun(Option<String>, Vec<String>, Vec<Stmt>),
    Float(f64),
    InstanceVar(Box<Exp>, String),
    KeyAccessor(Box<Exp>, Box<Exp>),
    Neg(Box<Exp>),
    Null,
    NewObject(Box<Exp>, Vec<Box<Exp>>),
    Object(Vec<(String, Box<Exp>)>),
    Pos(Box<Exp>),
    PostDec(Box<Exp>),
    PostInc(Box<Exp>),
    PreDec(Box<Exp>),
    PreInc(Box<Exp>),
    TypeOf(Box<Exp>),
    Str(String),
    Undefined,
    Var(String),
}

impl Exp {
    pub fn precedence(&self) -> Precedence {
        match *self {
            Exp::BinExp(_, ref o, _) => o.precedence(),
            Exp::Neg(_) | Exp::Pos(_) => Precedence::Sign,
            Exp::PostDec(_) | Exp::PostInc(_) | Exp::PreDec(_) | Exp::PreInc(_) => Precedence::Inc,
            _ => Precedence::Const
        }
    }
}

macro_rules! group {
    ($e:expr, $p:expr) => {
        if $e.precedence() < $p {
            format!("({})", $e)
        } else {
            format!("{}", $e)
        }
    }
}

impl Exp {
    fn fmt_helper(&self, mut fmt: &mut Formatter, indent_level: i32) -> Result<(), Error> {
        macro_rules! stmt_block {
            ($stmt:expr) => {
                for s in $stmt {
                    try!(s.fmt_helper(&mut fmt, indent_level + 2))
                }
            }
        }

        match *self {
            Exp::Array(ref vec) => {
                try!(write!(fmt, "["));

                for (i, elem) in vec.iter().enumerate() {
                    if i != 0 {
                        try!(write!(fmt, ", "));
                    }

                    try!(write!(fmt, "{}", elem));
                }

                write!(fmt, "]")
            }
            Exp::BinExp(ref e1, ref o, ref e2) => {
                let prec = self.precedence();

                // Put grouping parentheses if the left subexpression has a lower-precedence
                // operator, e.g. (1 + 2) * 3
                let left = if prec > e1.precedence() {
                    format!("({})", e1)
                } else {
                    format!("{}", e1)
                };

                let right_prec = e2.precedence();

                // Put grouping parentheses around the right subexpression if it has a
                // lower-precedence operator,  __OR__ if `o` is not commutative and the precedence
                // is the same, e.g. (1 + 2) * 3 __OR__ 1 - (2 + 3)
                let right = if prec > right_prec || (!o.is_commutative() && prec == right_prec) {
                    format!("({})", e2)
                } else {
                    format!("{}", e2)
                };

                write!(fmt, "{} {} {}", left, o, right)
            }
            Exp::Bool(b) => write!(fmt, "{}", b),
            Exp::Call(ref func, ref args) => {
                try!(write!(fmt, "{}(", func));

                for (i, arg) in args.iter().enumerate() {
                    if i != 0 {
                        try!(write!(fmt, ", "));
                    }

                    try!(write!(fmt, "{}", arg));
                }

                write!(fmt, ")")
            }
            Exp::Defun(ref opt, ref params, ref body) => {
                try!(write!(fmt, "function"));

                if let &Some(ref func) = opt {
                    try!(write!(fmt, " {}", func));
                }

                try!(write!(fmt, "("));

                for (i, param) in params.iter().enumerate() {
                    if i != 0 {
                        try!(write!(fmt, ", "));
                    }

                    try!(write!(fmt, "{}", param));
                }

                try!(write!(fmt, ") {{\n"));
                stmt_block!(body);

                let indent : String = (0..indent_level).map(|_| " ").collect();

                write!(fmt, "{}}}", indent)
            }
            Exp::Float(f) => write!(fmt, "{}", f),
            Exp::InstanceVar(ref obj, ref name) => write!(fmt, "{}.{}", obj, name),
            Exp::KeyAccessor(ref obj, ref key) => write!(fmt, "{}[{}]", obj, key),
            Exp::Neg(ref e) => write!(fmt, "-{}", group!(e, Precedence::Sign)),
            Exp::NewObject(ref name, ref args) => {
                try!(write!(fmt, "new {}(", name));

                for (i, arg) in args.iter().enumerate() {
                    if i != 0 {
                        try!(write!(fmt, ", "));
                    }

                    try!(write!(fmt, "{}", arg))
                }

                write!(fmt, ")")
            }
            Exp::Null => write!(fmt, "null"),
            Exp::Object(ref properties) => {
                if properties.is_empty() {
                    return write!(fmt, "{{}}");
                }

                try!(writeln!(fmt, "{{"));

                let indent : String = (0..indent_level + 2).map(|_| " ").collect();

                for (i, &(ref name, ref prop)) in properties.iter().enumerate() {
                    if i != 0 {
                        try!(writeln!(fmt, ","));
                    }

                    try!(write!(fmt, "{}{}: ", indent, name));
                    try!(prop.fmt_helper(&mut fmt, indent_level + 2));
                }

                write!(fmt, "\n}}")
            }
            Exp::Pos(ref e) => write!(fmt, "+{}", group!(e, Precedence::Sign)),
            Exp::PostDec(ref e) => write!(fmt, "{}--", group!(e, Precedence::Inc)),
            Exp::PostInc(ref e) => write!(fmt, "{}++", group!(e, Precedence::Inc)),
            Exp::PreDec(ref e) => write!(fmt, "--{}", group!(e, Precedence::Inc)),
            Exp::PreInc(ref e) => write!(fmt, "++{}", group!(e, Precedence::Inc)),
            Exp::TypeOf(ref e) => write!(fmt, "typeof {}", e),
            Exp::Str(ref s) => write!(fmt, "\"{}\"", s),
            Exp::Undefined => write!(fmt, "undefined"),
            Exp::Var(ref v) => write!(fmt, "{}", v),
        }
    }
}

impl Display for Exp {
    fn fmt(&self, mut fmt: &mut Formatter) -> Result<(), Error> {
        self.fmt_helper(&mut fmt, 0)
    }
}

#[derive(Clone, Debug)]
pub enum Stmt {
    Assign(Exp, Exp),
    BareExp(Exp),
    Decl(String, Exp),
    Empty,
    If(Exp, Vec<Stmt>, Vec<Stmt>),
    Ret(Exp),
    Seq(Box<Stmt>, Box<Stmt>),
    // try block, catch variable, catch block, finally block
    Try(Vec<Stmt>, String, Vec<Stmt>, Vec<Stmt>),
    Throw(Box<Exp>),
    While(Exp, Vec<Stmt>),
}

impl Stmt {
    pub fn fmt_helper(&self, mut fmt: &mut Formatter, indent_level: i32) -> Result<(), Error> {
        macro_rules! stmt_block {
            ($stmt:expr) => {
                for s in $stmt {
                    try!(s.fmt_helper(&mut fmt, indent_level + 2))
                }
            }
        }

        macro_rules! indented_stmt {
            ($s:expr) => {
                try!($s.fmt_helper(&mut fmt, indent_level + 2))
            }
        }

        macro_rules! exp_semi {
            ($exp:expr) => {{
                try!($exp.fmt_helper(&mut fmt, indent_level));
                writeln!(fmt, ";")
            }}
        }

        let indent : String = (0..indent_level).map(|_| " ").collect();

        match *self {
            Stmt::Assign(ref v, ref exp) => {
                try!(write!(fmt, "{}{} = ", indent, v));
                exp_semi!(exp)
            }
            Stmt::BareExp(ref exp) => {
                try!(write!(fmt, "{}", indent));
                exp_semi!(exp)
            }
            Stmt::Decl(ref v, ref exp) => {
                try!(write!(fmt, "{}var {} = ", indent, v));
                exp_semi!(exp)
            }
            Stmt::Empty => Ok(()),
            Stmt::If(ref e, ref s, ref els) => {
                try!(write!(fmt, "{}if (", indent));
                try!(e.fmt_helper(&mut fmt, indent_level + 2));
                try!(writeln!(fmt, ") {{\n"));
                stmt_block!(s);

                if els.len() > 0 {
                    stmt_block!(s);
                }

                //if let &Some(ref stmt) = els {
                //    try!(write!(fmt, "{}else {{\n", indent));
                //    indented_stmt!(stmt);
                //    try!(write!(fmt, "{}}}\n", indent));
                //}

                Ok(())
            }
            Stmt::Ret(ref e) => {
                try!(write!(fmt, "{}return ", indent));
                exp_semi!(e)
            }
            Stmt::Seq(ref s1, ref s2) => {
                try!(s1.fmt_helper(&mut fmt, indent_level));
                s2.fmt_helper(&mut fmt, indent_level)
            }
            Stmt::Throw(ref e) => {
                write!(fmt, "{}throw {}", indent, e)
            }
            Stmt::Try(ref stmt, ref catch_var, ref catch_block, ref finally_block) => {
                try!(write!(fmt, "{}try {{\n", indent));
                stmt_block!(stmt);
                try!(write!(fmt, "{}}}\n", indent));

                if catch_block.len() > 0 {
                    try!(write!(fmt, "{}catch ({}) {{\n", catch_var, indent));
                    stmt_block!(catch_block);
                    try!(write!(fmt, "{}}}\n", indent));
                }

                if finally_block.len() > 0 {
                    try!(write!(fmt, "{}finally {{\n", indent));
                    stmt_block!(finally_block);
                    try!(write!(fmt, "{}}}\n", indent));
                }

                Ok(())
            }
            Stmt::While(ref exp, ref stmt) => {
                try!(write!(fmt, "{}while ({}) {{\n", indent, exp));
                stmt_block!(stmt);
                write!(fmt, "{}}}\n", indent)
            }
        }
    }
}

impl Display for Stmt {
    fn fmt(&self, mut fmt: &mut Formatter) -> Result<(), Error> {
        self.fmt_helper(&mut fmt, 0)
    }
}
<commit_msg>Add LogNot<commit_after>use std::fmt::{Display, Error, Formatter};

#[derive(Clone, Debug, PartialEq, Eq)]
pub enum BinOp {
    Ge,
    Gt,
    Eql,       // ==
    EqlStrict, // ===
    Neq,       // !=
    NeqStrict, // !==
    Le,
    Lt,

    And,
    Or,

    BitOr,
    BitXor,
    BitAnd,

    ShiftLeft,
    ShiftRight,
    ShiftRightUnsigned,

    Minus,
    Plus,
    Slash,
    Star,
    Exponent,
    Mod,
}

#[derive(Clone, PartialEq, Eq, PartialOrd, Ord)]
pub enum Precedence {
    Const = 110,
    Sign = 100,
    Inc = 90,
    Mult = 70,
    Add = 60,
    Shift = 52,
    Cmp = 51,
    Equality = 50,
    BitAnd = 43,
    BitXor = 42,
    BitOr = 41,
    And = 40,
    Or = 30,
}

impl BinOp {
    pub fn precedence(&self) -> Precedence {
        match *self {
            BinOp::And => Precedence::And,
            BinOp::Ge | BinOp::Gt | BinOp::Le | BinOp::Lt => Precedence::Cmp,
            BinOp::Eql | BinOp::Neq | BinOp::EqlStrict | BinOp::NeqStrict => Precedence::Equality,
            BinOp::Or => Precedence::Or,
            BinOp::BitOr => Precedence::BitOr,
            BinOp::BitXor => Precedence::BitXor,
            BinOp::BitAnd => Precedence::BitAnd,
            BinOp::Minus | BinOp::Plus => Precedence::Add,
            BinOp::Slash | BinOp::Star | BinOp::Exponent | BinOp::Mod => Precedence::Mult,
            BinOp::ShiftLeft | BinOp::ShiftRight | BinOp::ShiftRightUnsigned => Precedence::Shift,
        }
    }

    pub fn is_commutative(&self) -> bool {
        match *self {
            BinOp::Minus | BinOp::Slash => false,
            _ => true
        }
    }
}

impl Display for BinOp {
    fn fmt(&self, fmt: &mut Formatter) -> Result<(), Error> {
        match *self {
            BinOp::And => write!(fmt, "&&"),
            BinOp::Ge => write!(fmt, ">="),
            BinOp::Gt => write!(fmt, ">"),
            BinOp::Eql => write!(fmt, "=="),
            BinOp::EqlStrict => write!(fmt, "==="),
            BinOp::Le => write!(fmt, "<="),
            BinOp::Lt => write!(fmt, "<"),
            BinOp::Minus => write!(fmt, "-"),
            BinOp::Neq => write!(fmt, "!="),
            BinOp::NeqStrict => write!(fmt, "!=="),
            BinOp::Or => write!(fmt, "||"),
            BinOp::Plus => write!(fmt, "+"),
            BinOp::Slash => write!(fmt, "/"),
            BinOp::Star => write!(fmt, "*"),
            BinOp::Exponent => write!(fmt, "**"),
            BinOp::Mod => write!(fmt, "%"),
            BinOp::BitXor => write!(fmt, "^"),
            BinOp::BitOr => write!(fmt, "|"),
            BinOp::BitAnd => write!(fmt, "&"),
            BinOp::ShiftLeft => write!(fmt, "<<"),
            BinOp::ShiftRight => write!(fmt, ">>"),
            BinOp::ShiftRightUnsigned => write!(fmt, ">>>"),
        }
    }
}

#[derive(Clone, Debug)]
pub enum Exp {
    Array(Vec<Box<Exp>>),
    BinExp(Box<Exp>, BinOp, Box<Exp>),
    Bool(bool),
    Call(Box<Exp>, Vec<Box<Exp>>),
    Defun(Option<String>, Vec<String>, Vec<Stmt>),
    Float(f64),
    InstanceVar(Box<Exp>, String),
    KeyAccessor(Box<Exp>, Box<Exp>),
    LogNot(Box<Exp>),
    Neg(Box<Exp>),
    Null,
    NewObject(Box<Exp>, Vec<Box<Exp>>),
    Object(Vec<(String, Box<Exp>)>),
    Pos(Box<Exp>),
    PostDec(Box<Exp>),
    PostInc(Box<Exp>),
    PreDec(Box<Exp>),
    PreInc(Box<Exp>),
    TypeOf(Box<Exp>),
    Str(String),
    Undefined,
    Var(String),
}

impl Exp {
    pub fn precedence(&self) -> Precedence {
        match *self {
            Exp::BinExp(_, ref o, _) => o.precedence(),
            Exp::LogNot(_) | Exp::Neg(_) | Exp::Pos(_) => Precedence::Sign,
            Exp::PostDec(_) | Exp::PostInc(_) | Exp::PreDec(_) | Exp::PreInc(_) => Precedence::Inc,
            _ => Precedence::Const
        }
    }
}

macro_rules! group {
    ($e:expr, $p:expr) => {
        if $e.precedence() < $p {
            format!("({})", $e)
        } else {
            format!("{}", $e)
        }
    }
}

impl Exp {
    fn fmt_helper(&self, mut fmt: &mut Formatter, indent_level: i32) -> Result<(), Error> {
        macro_rules! stmt_block {
            ($stmt:expr) => {
                for s in $stmt {
                    try!(s.fmt_helper(&mut fmt, indent_level + 2))
                }
            }
        }

        match *self {
            Exp::Array(ref vec) => {
                try!(write!(fmt, "["));

                for (i, elem) in vec.iter().enumerate() {
                    if i != 0 {
                        try!(write!(fmt, ", "));
                    }

                    try!(write!(fmt, "{}", elem));
                }

                write!(fmt, "]")
            }
            Exp::BinExp(ref e1, ref o, ref e2) => {
                let prec = self.precedence();

                // Put grouping parentheses if the left subexpression has a lower-precedence
                // operator, e.g. (1 + 2) * 3
                let left = if prec > e1.precedence() {
                    format!("({})", e1)
                } else {
                    format!("{}", e1)
                };

                let right_prec = e2.precedence();

                // Put grouping parentheses around the right subexpression if it has a
                // lower-precedence operator,  __OR__ if `o` is not commutative and the precedence
                // is the same, e.g. (1 + 2) * 3 __OR__ 1 - (2 + 3)
                let right = if prec > right_prec || (!o.is_commutative() && prec == right_prec) {
                    format!("({})", e2)
                } else {
                    format!("{}", e2)
                };

                write!(fmt, "{} {} {}", left, o, right)
            }
            Exp::Bool(b) => write!(fmt, "{}", b),
            Exp::Call(ref func, ref args) => {
                try!(write!(fmt, "{}(", func));

                for (i, arg) in args.iter().enumerate() {
                    if i != 0 {
                        try!(write!(fmt, ", "));
                    }

                    try!(write!(fmt, "{}", arg));
                }

                write!(fmt, ")")
            }
            Exp::Defun(ref opt, ref params, ref body) => {
                try!(write!(fmt, "function"));

                if let &Some(ref func) = opt {
                    try!(write!(fmt, " {}", func));
                }

                try!(write!(fmt, "("));

                for (i, param) in params.iter().enumerate() {
                    if i != 0 {
                        try!(write!(fmt, ", "));
                    }

                    try!(write!(fmt, "{}", param));
                }

                try!(write!(fmt, ") {{\n"));
                stmt_block!(body);

                let indent : String = (0..indent_level).map(|_| " ").collect();

                write!(fmt, "{}}}", indent)
            }
            Exp::Float(f) => write!(fmt, "{}", f),
            Exp::InstanceVar(ref obj, ref name) => write!(fmt, "{}.{}", obj, name),
            Exp::KeyAccessor(ref obj, ref key) => write!(fmt, "{}[{}]", obj, key),
            Exp::LogNot(ref e) => write!(fmt, "!{}", group!(e, Precedence::Sign)),
            Exp::Neg(ref e) => write!(fmt, "-{}", group!(e, Precedence::Sign)),
            Exp::NewObject(ref name, ref args) => {
                try!(write!(fmt, "new {}(", name));

                for (i, arg) in args.iter().enumerate() {
                    if i != 0 {
                        try!(write!(fmt, ", "));
                    }

                    try!(write!(fmt, "{}", arg))
                }

                write!(fmt, ")")
            }
            Exp::Null => write!(fmt, "null"),
            Exp::Object(ref properties) => {
                if properties.is_empty() {
                    return write!(fmt, "{{}}");
                }

                try!(writeln!(fmt, "{{"));

                let indent : String = (0..indent_level + 2).map(|_| " ").collect();

                for (i, &(ref name, ref prop)) in properties.iter().enumerate() {
                    if i != 0 {
                        try!(writeln!(fmt, ","));
                    }

                    try!(write!(fmt, "{}{}: ", indent, name));
                    try!(prop.fmt_helper(&mut fmt, indent_level + 2));
                }

                write!(fmt, "\n}}")
            }
            Exp::Pos(ref e) => write!(fmt, "+{}", group!(e, Precedence::Sign)),
            Exp::PostDec(ref e) => write!(fmt, "{}--", group!(e, Precedence::Inc)),
            Exp::PostInc(ref e) => write!(fmt, "{}++", group!(e, Precedence::Inc)),
            Exp::PreDec(ref e) => write!(fmt, "--{}", group!(e, Precedence::Inc)),
            Exp::PreInc(ref e) => write!(fmt, "++{}", group!(e, Precedence::Inc)),
            Exp::TypeOf(ref e) => write!(fmt, "typeof {}", e),
            Exp::Str(ref s) => write!(fmt, "\"{}\"", s),
            Exp::Undefined => write!(fmt, "undefined"),
            Exp::Var(ref v) => write!(fmt, "{}", v),
        }
    }
}

impl Display for Exp {
    fn fmt(&self, mut fmt: &mut Formatter) -> Result<(), Error> {
        self.fmt_helper(&mut fmt, 0)
    }
}

#[derive(Clone, Debug)]
pub enum Stmt {
    Assign(Exp, Exp),
    BareExp(Exp),
    Decl(String, Exp),
    Empty,
    If(Exp, Vec<Stmt>, Vec<Stmt>),
    Ret(Exp),
    Seq(Box<Stmt>, Box<Stmt>),
    // try block, catch variable, catch block, finally block
    Try(Vec<Stmt>, String, Vec<Stmt>, Vec<Stmt>),
    Throw(Box<Exp>),
    While(Exp, Vec<Stmt>),
}

impl Stmt {
    pub fn fmt_helper(&self, mut fmt: &mut Formatter, indent_level: i32) -> Result<(), Error> {
        macro_rules! stmt_block {
            ($stmt:expr) => {
                for s in $stmt {
                    try!(s.fmt_helper(&mut fmt, indent_level + 2))
                }
            }
        }

        macro_rules! indented_stmt {
            ($s:expr) => {
                try!($s.fmt_helper(&mut fmt, indent_level + 2))
            }
        }

        macro_rules! exp_semi {
            ($exp:expr) => {{
                try!($exp.fmt_helper(&mut fmt, indent_level));
                writeln!(fmt, ";")
            }}
        }

        let indent : String = (0..indent_level).map(|_| " ").collect();

        match *self {
            Stmt::Assign(ref v, ref exp) => {
                try!(write!(fmt, "{}{} = ", indent, v));
                exp_semi!(exp)
            }
            Stmt::BareExp(ref exp) => {
                try!(write!(fmt, "{}", indent));
                exp_semi!(exp)
            }
            Stmt::Decl(ref v, ref exp) => {
                try!(write!(fmt, "{}var {} = ", indent, v));
                exp_semi!(exp)
            }
            Stmt::Empty => Ok(()),
            Stmt::If(ref e, ref s, ref els) => {
                try!(write!(fmt, "{}if (", indent));
                try!(e.fmt_helper(&mut fmt, indent_level + 2));
                try!(writeln!(fmt, ") {{\n"));
                stmt_block!(s);

                if els.len() > 0 {
                    stmt_block!(s);
                }

                //if let &Some(ref stmt) = els {
                //    try!(write!(fmt, "{}else {{\n", indent));
                //    indented_stmt!(stmt);
                //    try!(write!(fmt, "{}}}\n", indent));
                //}

                Ok(())
            }
            Stmt::Ret(ref e) => {
                try!(write!(fmt, "{}return ", indent));
                exp_semi!(e)
            }
            Stmt::Seq(ref s1, ref s2) => {
                try!(s1.fmt_helper(&mut fmt, indent_level));
                s2.fmt_helper(&mut fmt, indent_level)
            }
            Stmt::Throw(ref e) => {
                write!(fmt, "{}throw {}", indent, e)
            }
            Stmt::Try(ref stmt, ref catch_var, ref catch_block, ref finally_block) => {
                try!(write!(fmt, "{}try {{\n", indent));
                stmt_block!(stmt);
                try!(write!(fmt, "{}}}\n", indent));

                if catch_block.len() > 0 {
                    try!(write!(fmt, "{}catch ({}) {{\n", catch_var, indent));
                    stmt_block!(catch_block);
                    try!(write!(fmt, "{}}}\n", indent));
                }

                if finally_block.len() > 0 {
                    try!(write!(fmt, "{}finally {{\n", indent));
                    stmt_block!(finally_block);
                    try!(write!(fmt, "{}}}\n", indent));
                }

                Ok(())
            }
            Stmt::While(ref exp, ref stmt) => {
                try!(write!(fmt, "{}while ({}) {{\n", indent, exp));
                stmt_block!(stmt);
                write!(fmt, "{}}}\n", indent)
            }
        }
    }
}

impl Display for Stmt {
    fn fmt(&self, mut fmt: &mut Formatter) -> Result<(), Error> {
        self.fmt_helper(&mut fmt, 0)
    }
}
<|endoftext|>


<commit_before>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

//! Style retrieval from DOM elements.

use data::LayoutDataWrapper;
use wrapper::{PseudoElementType, ThreadSafeLayoutNode};

use style::properties::ComputedValues;

use std::cell::Ref;
use std::sync::Arc;

/// Node mixin providing `style` method that returns a `NodeStyle`
pub trait StyledNode {
    fn get_style<'a>(&self, layout_data_ref: &'a LayoutDataWrapper) -> &'a Arc<ComputedValues>;
    /// Returns the style results for the given node. If CSS selector matching has not yet been
    /// performed, fails.
    fn style<'a>(&'a self) -> Ref<'a, Arc<ComputedValues>>;
    /// Does this node have a computed style yet?
    fn has_style(&self) -> bool;
    /// Removes the style from this node.
    fn unstyle(self);
}

impl<'ln> StyledNode for ThreadSafeLayoutNode<'ln> {
    #[inline]
    fn get_style<'a>(&self, layout_data_ref: &'a LayoutDataWrapper) -> &'a Arc<ComputedValues> {
        match self.get_pseudo_element_type() {
            PseudoElementType::Before(_) => layout_data_ref.data.before_style.as_ref().unwrap(),
            PseudoElementType::After(_) => layout_data_ref.data.after_style.as_ref().unwrap(),
            PseudoElementType::Normal => layout_data_ref.shared_data.style.as_ref().unwrap(),
        }
    }

    #[inline]
    fn style<'a>(&'a self) -> Ref<'a, Arc<ComputedValues>> {
        Ref::map(self.borrow_layout_data(), |layout_data_ref| {
            let layout_data = layout_data_ref.as_ref().expect("no layout data");
            self.get_style(layout_data)
        })
    }

    fn has_style(&self) -> bool {
        let layout_data_ref = self.borrow_layout_data();
        layout_data_ref.as_ref().unwrap().shared_data.style.is_some()
    }

    fn unstyle(self) {
        let mut layout_data_ref = self.mutate_layout_data();
        let layout_data = layout_data_ref.as_mut().expect("no layout data");

        let style =
            match self.get_pseudo_element_type() {
                PseudoElementType::Before(_) => &mut layout_data.data.before_style,
                PseudoElementType::After (_) => &mut layout_data.data.after_style,
                PseudoElementType::Normal    => &mut layout_data.shared_data.style,
            };

        *style = None;
    }
}
<commit_msg>Remove unused StyledNode::has_style method.<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

//! Style retrieval from DOM elements.

use data::LayoutDataWrapper;
use wrapper::{PseudoElementType, ThreadSafeLayoutNode};

use style::properties::ComputedValues;

use std::cell::Ref;
use std::sync::Arc;

/// Node mixin providing `style` method that returns a `NodeStyle`
pub trait StyledNode {
    fn get_style<'a>(&self, layout_data_ref: &'a LayoutDataWrapper) -> &'a Arc<ComputedValues>;
    /// Returns the style results for the given node. If CSS selector matching has not yet been
    /// performed, fails.
    fn style<'a>(&'a self) -> Ref<'a, Arc<ComputedValues>>;
    /// Removes the style from this node.
    fn unstyle(self);
}

impl<'ln> StyledNode for ThreadSafeLayoutNode<'ln> {
    #[inline]
    fn get_style<'a>(&self, layout_data_ref: &'a LayoutDataWrapper) -> &'a Arc<ComputedValues> {
        match self.get_pseudo_element_type() {
            PseudoElementType::Before(_) => layout_data_ref.data.before_style.as_ref().unwrap(),
            PseudoElementType::After(_) => layout_data_ref.data.after_style.as_ref().unwrap(),
            PseudoElementType::Normal => layout_data_ref.shared_data.style.as_ref().unwrap(),
        }
    }

    #[inline]
    fn style<'a>(&'a self) -> Ref<'a, Arc<ComputedValues>> {
        Ref::map(self.borrow_layout_data(), |layout_data_ref| {
            let layout_data = layout_data_ref.as_ref().expect("no layout data");
            self.get_style(layout_data)
        })
    }

    fn unstyle(self) {
        let mut layout_data_ref = self.mutate_layout_data();
        let layout_data = layout_data_ref.as_mut().expect("no layout data");

        let style =
            match self.get_pseudo_element_type() {
                PseudoElementType::Before(_) => &mut layout_data.data.before_style,
                PseudoElementType::After (_) => &mut layout_data.data.after_style,
                PseudoElementType::Normal    => &mut layout_data.shared_data.style,
            };

        *style = None;
    }
}
<|endoftext|>


<commit_before>extern crate mli;
extern crate rand;

type R = rand::isaac::Isaac64Rng;

#[derive(Clone)]
enum Ins {
    ADD,
    SUB,
    MUL,
    DIV,
    GRT,
    LES,
    SIN,
    COS,
    SQT,
}

fn processor(ins: &Ins, a: i64, b: i64) -> i64 {
    match *ins {
        Ins::ADD => a + b,
        Ins::SUB => a - b,
        Ins::MUL => a * b,
        Ins::DIV => if b == 0 {
            i64::max_value()
        } else {
            a / b
        },
        Ins::GRT => if a > b {
            1
        } else {
            0
        },
        Ins::LES => if a < b {
            1
        } else {
            0
        },
        Ins::SIN => ((a as f64 / b as f64).sin() * b as f64) as i64,
        Ins::COS => ((a as f64 / b as f64).cos() * b as f64) as i64,
        Ins::SQT => ((a as f64 / b as f64).sqrt() * b as f64) as i64,
    }
}

fn mutator(ins: &mut Ins, rng: &mut R) {

}

#[derive(Clone)]
struct Bot {
    brain: mli::Mep<Ins, rand::isaac::Isaac64Rng, i64,
        fn(&mut Ins, &mut R), fn(&Ins, i64, i64)>,
}
<commit_msg>make mutator correct<commit_after>extern crate mli;
extern crate rand;

type R = rand::isaac::Isaac64Rng;

#[derive(Clone)]
enum Ins {
    ADD,
    SUB,
    MUL,
    DIV,
    GRT,
    LES,
    SIN,
    COS,
    SQT,
}

fn processor(ins: &Ins, a: i64, b: i64) -> i64 {
    match *ins {
        Ins::ADD => a + b,
        Ins::SUB => a - b,
        Ins::MUL => a * b,
        Ins::DIV => if b == 0 {
            i64::max_value()
        } else {
            a / b
        },
        Ins::GRT => if a > b {
            1
        } else {
            0
        },
        Ins::LES => if a < b {
            1
        } else {
            0
        },
        Ins::SIN => ((a as f64 / b as f64).sin() * b as f64) as i64,
        Ins::COS => ((a as f64 / b as f64).cos() * b as f64) as i64,
        Ins::SQT => ((a as f64 / b as f64).sqrt() * b as f64) as i64,
    }
}

fn mutator(ins: &mut Ins, rng: &mut R) {
    use std::mem;
    use rand::Rng;
    *ins = unsafe{mem::transmute(rng.gen_range::<u8>(0, 9))};
}

#[derive(Clone)]
struct Bot {
    brain: mli::Mep<Ins, rand::isaac::Isaac64Rng, i64,
        fn(&mut Ins, &mut R), fn(&Ins, i64, i64)>,
}
<|endoftext|>


<commit_before>use std::iter::Peekable;
use std::str::Chars;

pub struct Reader<'l> {
    line: usize,
    column: usize,
    offset: usize,
    content: &'l str,
    cursor: Peekable<Chars<'l>>,
}

impl<'l> Reader<'l> {
    #[inline]
    pub fn new(content: &'l str) -> Self {
        Reader {
            line: 1,
            column: 1,
            offset: 0,
            content: content,
            cursor: content.chars().peekable(),
        }
    }

    pub fn capture<F>(&mut self, block: F) -> Option<&'l str>
        where F: Fn(&mut Reader<'l>) -> bool
    {
        let start = self.offset;
        if !block(self) {
            return None;
        }
        let content = &self.content[start..self.offset].trim();
        if content.is_empty() { None } else { Some(content) }
    }

    #[inline]
    pub fn consume_all(&mut self) -> bool {
        self.consume_while(|_| true)
    }

    #[inline]
    pub fn consume_any(&mut self, chars: &str) -> bool {
        self.consume_while(|c| chars.contains(c))
    }

    /// https://www.w3.org/TR/REC-xml/#NT-Attribute
    pub fn consume_attribute(&mut self) -> bool {
        self.consume_name() && self.consume_equality() && self.consume_attribute_value()
    }

    /// https://www.w3.org/TR/REC-xml/#NT-AttValue
    pub fn consume_attribute_value(&mut self) -> bool {
        if self.consume_char('\'') {
            self.consume_until_any("<&'");
            self.consume_char('\'')
        } else if self.consume_char('"') {
            self.consume_until_any("<&\"");
            self.consume_char('"')
        } else {
            false
        }
    }

    pub fn consume_char(&mut self, target: char) -> bool {
        match self.peek() {
            Some(c) if c == target => {
                self.next();
                true
            },
            _ => false,
        }
    }

    #[inline]
    pub fn consume_digits(&mut self) -> bool {
        self.consume_while(|c| c >= '0' && c <= '9')
    }

    /// https://www.w3.org/TR/REC-xml/#NT-Eq
    pub fn consume_equality(&mut self) -> bool {
        self.consume_whitespace();
        let consumed = self.consume_char('=');
        self.consume_whitespace();
        consumed
    }

    pub fn consume_if<F>(&mut self, check: F) -> bool where F: Fn(char) -> bool {
        match self.peek() {
            Some(c) => {
                if check(c) {
                    self.next();
                    true
                } else {
                    false
                }
            },
            _ => false,
        }
    }

    /// https://www.w3.org/TR/REC-xml/#NT-Name
    pub fn consume_name(&mut self) -> bool {
        self.consume_name_start_char() && {
            while self.consume_name_char() {}
            true
        }
    }

    /// https://www.w3.org/TR/REC-xml/#NT-NameChar
    pub fn consume_name_char(&mut self) -> bool {
        self.consume_name_start_char() || self.consume_if(|c| {
            match c {
                '-' |
                '.' |
                '0'...'9' |
                '\u{B7}' |
                '\u{0300}'...'\u{036F}' |
                '\u{203F}'...'\u{2040}' => true,
                _ => false,
            }
        })
    }

    /// https://www.w3.org/TR/REC-xml/#NT-NameStartChar
    pub fn consume_name_start_char(&mut self) -> bool {
        self.consume_if(|c| {
            match c {
                ':' |
                'A'...'Z' |
                '_' |
                'a'...'z' |
                '\u{C0}'...'\u{D6}' |
                '\u{D8}'...'\u{F6}' |
                '\u{F8}'...'\u{2FF}' |
                '\u{370}'...'\u{37D}' |
                '\u{37F}'...'\u{1FFF}' |
                '\u{200C}'...'\u{200D}' |
                '\u{2070}'...'\u{218F}' |
                '\u{2C00}'...'\u{2FEF}' |
                '\u{3001}'...'\u{D7FF}' |
                '\u{F900}'...'\u{FDCF}' |
                '\u{FDF0}'...'\u{FFFD}' |
                '\u{10000}'...'\u{EFFFF}' => true,
                _ => false,
            }
        })
    }

    /// https://www.w3.org/TR/SVG/types.html#DataTypeNumber
    pub fn consume_number(&mut self) -> bool {
        self.consume_sign();
        if self.consume_digits() {
            if self.consume_char('.') && !self.consume_digits() {
                return false;
            }
        } else {
            if !self.consume_char('.') || !self.consume_digits() {
                return false;
            }
        }
        if !self.consume_char('e') && !self.consume_char('E') {
            return true;
        }
        self.consume_sign();
        self.consume_digits()
    }

    pub fn consume_sign(&mut self) -> bool {
        self.consume_char('+') || self.consume_char('-')
    }

    #[inline]
    pub fn consume_until_any(&mut self, chars: &str) -> bool {
        self.consume_while(|c| !chars.contains(c))
    }

    #[inline]
    pub fn consume_until_char(&mut self, target: char) -> bool {
        self.consume_while(|c| c != target)
    }

    pub fn consume_while<F>(&mut self, check: F) -> bool where F: Fn(char) -> bool {
        let mut consumed = false;
        while self.consume_if(|c| check(c)) {
            consumed = true;
        }
        consumed
    }

    /// https://www.w3.org/TR/REC-xml/#NT-S
    #[inline]
    pub fn consume_whitespace(&mut self) -> bool {
        self.consume_any("\x20\x09\x0D\x0A")
    }

    #[inline]
    pub fn is_done(&self) -> bool {
        self.offset == self.content.len()
    }

    #[inline]
    pub fn peek(&mut self) -> Option<char> {
        self.cursor.peek().and_then(|&c| Some(c))
    }

    #[inline]
    pub fn position(&self) -> (usize, usize) {
        (self.line, self.column)
    }
}

impl<'l> Iterator for Reader<'l> {
    type Item = char;

    fn next(&mut self) -> Option<char> {
        match self.cursor.next() {
            Some(c) => {
                if c == '\n' {
                    self.line += 1;
                    self.column = 1;
                } else {
                    self.column += 1;
                }
                self.offset += 1;
                Some(c)
            }
            _ => None,
        }
    }
}

#[cfg(test)]
mod tests {
    use super::Reader;

    #[test]
    fn capture() {
        let mut reader = Reader::new("abcdefg");
        reader.consume_any("ab");
        let content = reader.capture(|reader| reader.consume_any("cde"));

        assert_eq!(content.unwrap(), "cde");
    }

    #[test]
    fn consume_attribute() {
        macro_rules! test(
            ($content:expr) => ({
                let mut reader = Reader::new($content);
                assert!(reader.consume_attribute());
            });
        );

        test!("foo='bar'");
        test!("foo = \t 'bar'");
        test!("foo= \"bar\"");

        macro_rules! test(
            ($content:expr) => ({
                let mut reader = Reader::new($content);
                assert!(!reader.consume_attribute());
            });
        );

        test!("foo");
        test!("foo bar");
        test!("foo=bar");
        test!("foo='bar");
        test!("foo=\"bar");
    }

    #[test]
    fn consume_name() {
        macro_rules! test(
            ($content:expr, $value:expr) => ({
                let mut reader = Reader::new($content);
                let value = reader.capture(|reader| reader.consume_name());
                assert_eq!(value.unwrap(), $value);
            });
        );

        test!("foo", "foo");
        test!("foo bar", "foo");
        test!("foo42 bar", "foo42");
        test!("foo-bar baz", "foo-bar");
        test!("foo/", "foo");

        macro_rules! test(
            ($content:expr) => ({
                let mut reader = Reader::new($content);
                assert!(!reader.consume_name());
            });
        );

        test!(" foo");
        test!("!foo");
        test!("<foo");
        test!("?foo");
    }

    #[test]
    fn consume_number() {
        macro_rules! test(
            ($content:expr, $value:expr) => ({
                let mut reader = Reader::new($content);
                let value = reader.capture(|reader| reader.consume_number());
                assert_eq!(value.unwrap(), $value);
            });
        );

        test!("1 ", "1");
        test!("1a", "1");

        test!("1", "1");
        test!("-1", "-1");
        test!("+1", "+1");

        test!(".1", ".1");
        test!("-.1", "-.1");
        test!("+.1", "+.1");

        test!("1.2", "1.2");
        test!("-1.2", "-1.2");
        test!("+1.2", "+1.2");

        test!("1E2", "1E2");
        test!("-1e2", "-1e2");
        test!("+1e2", "+1e2");

        test!("1.2e3", "1.2e3");
        test!("-1.2E3", "-1.2E3");
        test!("+1.2e3", "+1.2e3");

        test!("1.2e-3", "1.2e-3");
        test!("-1.2e-3", "-1.2e-3");
        test!("+1.2E-3", "+1.2E-3");

        test!("1.2E+3", "1.2E+3");
        test!("-1.2e+3", "-1.2e+3");
        test!("+1.2e+3", "+1.2e+3");

        macro_rules! test(
            ($content:expr) => ({
                let mut reader = Reader::new($content);
                assert!(reader.capture(|reader| reader.consume_number()).is_none());
            });
        );

        test!("1.e2");
        test!("-1.e2");
        test!("+1.e2");
    }

    #[test]
    fn consume_whitespace() {
        let mut reader = Reader::new(" \t  \n\n  \tm ");
        reader.consume_whitespace();

        assert_eq!(reader.line, 3);
        assert_eq!(reader.column, 4);
        assert_eq!(reader.offset, 9);
    }
}
<commit_msg>Adjust the comments in Reader<commit_after>use std::iter::Peekable;
use std::str::Chars;

pub struct Reader<'l> {
    line: usize,
    column: usize,
    offset: usize,
    content: &'l str,
    cursor: Peekable<Chars<'l>>,
}

impl<'l> Reader<'l> {
    #[inline]
    pub fn new(content: &'l str) -> Self {
        Reader {
            line: 1,
            column: 1,
            offset: 0,
            content: content,
            cursor: content.chars().peekable(),
        }
    }

    pub fn capture<F>(&mut self, block: F) -> Option<&'l str>
        where F: Fn(&mut Reader<'l>) -> bool
    {
        let start = self.offset;
        if !block(self) {
            return None;
        }
        let content = &self.content[start..self.offset].trim();
        if content.is_empty() { None } else { Some(content) }
    }

    #[inline]
    pub fn consume_all(&mut self) -> bool {
        self.consume_while(|_| true)
    }

    #[inline]
    pub fn consume_any(&mut self, chars: &str) -> bool {
        self.consume_while(|c| chars.contains(c))
    }

    // https://www.w3.org/TR/REC-xml/#NT-Attribute
    pub fn consume_attribute(&mut self) -> bool {
        self.consume_name() && self.consume_equality() && self.consume_attribute_value()
    }

    // https://www.w3.org/TR/REC-xml/#NT-AttValue
    pub fn consume_attribute_value(&mut self) -> bool {
        if self.consume_char('\'') {
            self.consume_until_any("<&'");
            self.consume_char('\'')
        } else if self.consume_char('"') {
            self.consume_until_any("<&\"");
            self.consume_char('"')
        } else {
            false
        }
    }

    pub fn consume_char(&mut self, target: char) -> bool {
        match self.peek() {
            Some(c) if c == target => {
                self.next();
                true
            },
            _ => false,
        }
    }

    #[inline]
    pub fn consume_digits(&mut self) -> bool {
        self.consume_while(|c| c >= '0' && c <= '9')
    }

    // https://www.w3.org/TR/REC-xml/#NT-Eq
    pub fn consume_equality(&mut self) -> bool {
        self.consume_whitespace();
        let consumed = self.consume_char('=');
        self.consume_whitespace();
        consumed
    }

    pub fn consume_if<F>(&mut self, check: F) -> bool where F: Fn(char) -> bool {
        match self.peek() {
            Some(c) => {
                if check(c) {
                    self.next();
                    true
                } else {
                    false
                }
            },
            _ => false,
        }
    }

    // https://www.w3.org/TR/REC-xml/#NT-Name
    pub fn consume_name(&mut self) -> bool {
        self.consume_name_start_char() && {
            while self.consume_name_char() {}
            true
        }
    }

    // https://www.w3.org/TR/REC-xml/#NT-NameChar
    pub fn consume_name_char(&mut self) -> bool {
        self.consume_name_start_char() || self.consume_if(|c| {
            match c {
                '-' |
                '.' |
                '0'...'9' |
                '\u{B7}' |
                '\u{0300}'...'\u{036F}' |
                '\u{203F}'...'\u{2040}' => true,
                _ => false,
            }
        })
    }

    // https://www.w3.org/TR/REC-xml/#NT-NameStartChar
    pub fn consume_name_start_char(&mut self) -> bool {
        self.consume_if(|c| {
            match c {
                ':' |
                'A'...'Z' |
                '_' |
                'a'...'z' |
                '\u{C0}'...'\u{D6}' |
                '\u{D8}'...'\u{F6}' |
                '\u{F8}'...'\u{2FF}' |
                '\u{370}'...'\u{37D}' |
                '\u{37F}'...'\u{1FFF}' |
                '\u{200C}'...'\u{200D}' |
                '\u{2070}'...'\u{218F}' |
                '\u{2C00}'...'\u{2FEF}' |
                '\u{3001}'...'\u{D7FF}' |
                '\u{F900}'...'\u{FDCF}' |
                '\u{FDF0}'...'\u{FFFD}' |
                '\u{10000}'...'\u{EFFFF}' => true,
                _ => false,
            }
        })
    }

    // https://www.w3.org/TR/SVG/types.html#DataTypeNumber
    pub fn consume_number(&mut self) -> bool {
        self.consume_sign();
        if self.consume_digits() {
            if self.consume_char('.') && !self.consume_digits() {
                return false;
            }
        } else {
            if !self.consume_char('.') || !self.consume_digits() {
                return false;
            }
        }
        if !self.consume_char('e') && !self.consume_char('E') {
            return true;
        }
        self.consume_sign();
        self.consume_digits()
    }

    pub fn consume_sign(&mut self) -> bool {
        self.consume_char('+') || self.consume_char('-')
    }

    #[inline]
    pub fn consume_until_any(&mut self, chars: &str) -> bool {
        self.consume_while(|c| !chars.contains(c))
    }

    #[inline]
    pub fn consume_until_char(&mut self, target: char) -> bool {
        self.consume_while(|c| c != target)
    }

    pub fn consume_while<F>(&mut self, check: F) -> bool where F: Fn(char) -> bool {
        let mut consumed = false;
        while self.consume_if(|c| check(c)) {
            consumed = true;
        }
        consumed
    }

    // https://www.w3.org/TR/REC-xml/#NT-S
    #[inline]
    pub fn consume_whitespace(&mut self) -> bool {
        self.consume_any("\x20\x09\x0D\x0A")
    }

    #[inline]
    pub fn is_done(&self) -> bool {
        self.offset == self.content.len()
    }

    #[inline]
    pub fn peek(&mut self) -> Option<char> {
        self.cursor.peek().and_then(|&c| Some(c))
    }

    #[inline]
    pub fn position(&self) -> (usize, usize) {
        (self.line, self.column)
    }
}

impl<'l> Iterator for Reader<'l> {
    type Item = char;

    fn next(&mut self) -> Option<char> {
        match self.cursor.next() {
            Some(c) => {
                if c == '\n' {
                    self.line += 1;
                    self.column = 1;
                } else {
                    self.column += 1;
                }
                self.offset += 1;
                Some(c)
            }
            _ => None,
        }
    }
}

#[cfg(test)]
mod tests {
    use super::Reader;

    #[test]
    fn capture() {
        let mut reader = Reader::new("abcdefg");
        reader.consume_any("ab");
        let content = reader.capture(|reader| reader.consume_any("cde"));

        assert_eq!(content.unwrap(), "cde");
    }

    #[test]
    fn consume_attribute() {
        macro_rules! test(
            ($content:expr) => ({
                let mut reader = Reader::new($content);
                assert!(reader.consume_attribute());
            });
        );

        test!("foo='bar'");
        test!("foo = \t 'bar'");
        test!("foo= \"bar\"");

        macro_rules! test(
            ($content:expr) => ({
                let mut reader = Reader::new($content);
                assert!(!reader.consume_attribute());
            });
        );

        test!("foo");
        test!("foo bar");
        test!("foo=bar");
        test!("foo='bar");
        test!("foo=\"bar");
    }

    #[test]
    fn consume_name() {
        macro_rules! test(
            ($content:expr, $value:expr) => ({
                let mut reader = Reader::new($content);
                let value = reader.capture(|reader| reader.consume_name());
                assert_eq!(value.unwrap(), $value);
            });
        );

        test!("foo", "foo");
        test!("foo bar", "foo");
        test!("foo42 bar", "foo42");
        test!("foo-bar baz", "foo-bar");
        test!("foo/", "foo");

        macro_rules! test(
            ($content:expr) => ({
                let mut reader = Reader::new($content);
                assert!(!reader.consume_name());
            });
        );

        test!(" foo");
        test!("!foo");
        test!("<foo");
        test!("?foo");
    }

    #[test]
    fn consume_number() {
        macro_rules! test(
            ($content:expr, $value:expr) => ({
                let mut reader = Reader::new($content);
                let value = reader.capture(|reader| reader.consume_number());
                assert_eq!(value.unwrap(), $value);
            });
        );

        test!("1 ", "1");
        test!("1a", "1");

        test!("1", "1");
        test!("-1", "-1");
        test!("+1", "+1");

        test!(".1", ".1");
        test!("-.1", "-.1");
        test!("+.1", "+.1");

        test!("1.2", "1.2");
        test!("-1.2", "-1.2");
        test!("+1.2", "+1.2");

        test!("1E2", "1E2");
        test!("-1e2", "-1e2");
        test!("+1e2", "+1e2");

        test!("1.2e3", "1.2e3");
        test!("-1.2E3", "-1.2E3");
        test!("+1.2e3", "+1.2e3");

        test!("1.2e-3", "1.2e-3");
        test!("-1.2e-3", "-1.2e-3");
        test!("+1.2E-3", "+1.2E-3");

        test!("1.2E+3", "1.2E+3");
        test!("-1.2e+3", "-1.2e+3");
        test!("+1.2e+3", "+1.2e+3");

        macro_rules! test(
            ($content:expr) => ({
                let mut reader = Reader::new($content);
                assert!(reader.capture(|reader| reader.consume_number()).is_none());
            });
        );

        test!("1.e2");
        test!("-1.e2");
        test!("+1.e2");
    }

    #[test]
    fn consume_whitespace() {
        let mut reader = Reader::new(" \t  \n\n  \tm ");
        reader.consume_whitespace();

        assert_eq!(reader.line, 3);
        assert_eq!(reader.column, 4);
        assert_eq!(reader.offset, 9);
    }
}
<|endoftext|>