<commit_before>//! The `libopenreil` crate aims to provide an okay wrapper around openreil-sys.

extern crate openreil_sys;
extern crate libc;

use openreil_sys::root::{reil_addr_t, reil_inst_t, reil_t, reil_arch_t, reil_inst_print,
                            reil_inst_handler_t, reil_init, reil_close, reil_translate,
                            reil_translate_insn};
pub use openreil_sys::root::{reil_op_t, reil_type_t, reil_size_t, reil_arg_t, reil_raw_t};

use std::mem;
use std::ops::Drop;
use std::marker;

/// Specifies the architecture of the binary code.
///
/// As of now, supported architectures are `x86` and `ARM`.
#[derive(Clone, Copy, Debug)]
pub enum ReilArch {
    X86,
    ARM,
}

/// Callback handler type to further process the resulting REIL instructions.
/// Is a type alias for a C function.
///
/// Please take care to assert that neither argument is NULL.
pub type ReilInstHandler<T> = extern "C" fn(*mut ReilRawInst, *mut T) -> i32;

/// A raw REIL instruction, that is a simple autogenerated wrapper for the original C type.
pub type ReilRawInst = reil_inst_t;

/// A disassembler object.
///
/// The `Reil` type provides a simple interface to disassemble and translate single or multiple instructions
/// to the OpenREIL intermediate language.
///
/// A `handler` callback function can be provided during construction to further process the resulting REIL instructions.
pub struct Reil<'a, T: 'a> {
    reil_handle: reil_t,
    _marker: marker::PhantomData<&'a mut T>,
}

impl<'a, T: 'a> Reil<'a, T> {
    /// Construct a new disassembler object
    /// The handler function can be used to process the resulting REIL instructions
    /// The `context` gets handed to the callback function
    pub fn new(
        arch: ReilArch,
        handler: Option<ReilInstHandler<T>>,
        context: &'a mut T,
    ) -> Option<Self> {
        let arch = match arch {
            ReilArch::X86 => reil_arch_t::ARCH_X86,
            ReilArch::ARM => reil_arch_t::ARCH_ARM,
        };
        let handler: reil_inst_handler_t = unsafe { mem::transmute(handler) };

        let c_ptr = context as *mut _;

        let reil = unsafe { reil_init(arch, handler, c_ptr as *mut libc::c_void) };

        if reil.is_null() {
            return None;
        }

        let new_reil = Reil {
            reil_handle: reil,
            _marker: marker::PhantomData,
        };

        Some(new_reil)
    }

    /// Translate the binary data given in `data` to REIL instructions,
    /// `start_address` designates the starting address the decoded instructions get assigned.
    pub fn translate(&mut self, data: &mut [u8], start_address: u32) {
        unsafe {
            reil_translate(
                self.reil_handle,
                start_address as reil_addr_t,
                data.as_mut_ptr(),
                data.len() as libc::c_int,
            );
        }
    }

    /// Translate a single instruction from the binary data given in `data` and start addressing at the given address.
    pub fn translate_instruction(&mut self, data: &mut [u8], start_address: u32) {
        unsafe {
            reil_translate_insn(
                self.reil_handle,
                start_address as reil_addr_t,
                data.as_mut_ptr(),
                data.len() as libc::c_int,
            );
        }
    }
}

impl<'a, T: 'a> Drop for Reil<'a, T> {
    fn drop(&mut self) {
        unsafe {
            reil_close(self.reil_handle);
        }
    }
}

pub trait ReilInst {
    fn address(&self) -> u64;
    fn reil_offset(&self) -> u8;
    fn raw_address(&self) -> u64;
    fn print(&self);
    fn first_operand(&self) -> Option<reil_arg_t>;
    fn second_operand(&self) -> Option<reil_arg_t>;
    fn third_operand(&self) -> Option<reil_arg_t>;
    fn opcode(&self) -> reil_op_t;
}

impl ReilInst for reil_inst_t {
    fn address(&self) -> u64 {
        let raw_addr = self.raw_address() << 8;
        let reil_offset = self.reil_offset() as u64;
        raw_addr | reil_offset
    }

    fn reil_offset(&self) -> u8 {
        self.inum as u8
    }

    fn raw_address(&self) -> u64 {
        self.raw_info.addr as u64
    }

    fn print(&self) {
        let mut_ptr: *mut reil_inst_t = unsafe { mem::transmute(self) };
        unsafe { reil_inst_print(mut_ptr); }
    }

    fn first_operand(&self) -> Option<reil_arg_t> {
        match self.a.type_ {
            reil_type_t::A_NONE => None,
            _ => Some(self.a)
        }
    }

    fn second_operand(&self) -> Option<reil_arg_t> {
        match self.b.type_ {
            reil_type_t::A_NONE => None,
            _ => Some(self.b)
        }
    }

    fn third_operand(&self) -> Option<reil_arg_t> {
        match self.c.type_ {
            reil_type_t::A_NONE => None,
            _ => Some(self.c)
        }
    }

    fn opcode(&self) -> reil_op_t {
        self.op
    }
}

pub trait ReilArg {
    fn arg_type(&self) -> reil_type_t;
    fn size(&self) -> reil_size_t;
    fn val(&self) -> Option<u64>;
    fn name(&self) -> Option<String>;
}

impl ReilArg for reil_arg_t {
    fn arg_type(&self) -> reil_type_t {
        self.type_
    }

    fn size(&self) -> reil_size_t {
        self.size
    }

    fn val(&self) -> Option<u64> {
        match self.arg_type() {
            reil_type_t::A_CONST | reil_type_t::A_LOC => Some(self.val as u64),
            _ => None,
        }
    }

    fn name(&self) -> Option<String> {
        if self.arg_type() == reil_type_t::A_NONE {
            return None;
        }
        let chars = self.name.iter()
            .take_while(|&b| b as u8 != 0)
            .map(|&b| b as u8)
            .collect();

        String::from_utf8(chars).ok()
    }
}
<commit_msg>Bugfix<commit_after>//! The `libopenreil` crate aims to provide an okay wrapper around openreil-sys.

extern crate openreil_sys;
extern crate libc;

use openreil_sys::root::{reil_addr_t, reil_inst_t, reil_t, reil_arch_t, reil_inst_print,
                            reil_inst_handler_t, reil_init, reil_close, reil_translate,
                            reil_translate_insn};
pub use openreil_sys::root::{reil_op_t, reil_type_t, reil_size_t, reil_arg_t, reil_raw_t};

use std::mem;
use std::ops::Drop;
use std::marker;

/// Specifies the architecture of the binary code.
///
/// As of now, supported architectures are `x86` and `ARM`.
#[derive(Clone, Copy, Debug)]
pub enum ReilArch {
    X86,
    ARM,
}

/// Callback handler type to further process the resulting REIL instructions.
/// Is a type alias for a C function.
///
/// Please take care to assert that neither argument is NULL.
pub type ReilInstHandler<T> = extern "C" fn(*mut ReilRawInst, *mut T) -> i32;

/// A raw REIL instruction, that is a simple autogenerated wrapper for the original C type.
pub type ReilRawInst = reil_inst_t;

/// A disassembler object.
///
/// The `Reil` type provides a simple interface to disassemble and translate single or multiple instructions
/// to the OpenREIL intermediate language.
///
/// A `handler` callback function can be provided during construction to further process the resulting REIL instructions.
pub struct Reil<'a, T: 'a> {
    reil_handle: reil_t,
    _marker: marker::PhantomData<&'a mut T>,
}

impl<'a, T: 'a> Reil<'a, T> {
    /// Construct a new disassembler object
    /// The handler function can be used to process the resulting REIL instructions
    /// The `context` gets handed to the callback function
    pub fn new(
        arch: ReilArch,
        handler: Option<ReilInstHandler<T>>,
        context: &'a mut T,
    ) -> Option<Self> {
        let arch = match arch {
            ReilArch::X86 => reil_arch_t::ARCH_X86,
            ReilArch::ARM => reil_arch_t::ARCH_ARM,
        };
        let handler: reil_inst_handler_t = unsafe { mem::transmute(handler) };

        let c_ptr = context as *mut _;

        let reil = unsafe { reil_init(arch, handler, c_ptr as *mut libc::c_void) };

        if reil.is_null() {
            return None;
        }

        let new_reil = Reil {
            reil_handle: reil,
            _marker: marker::PhantomData,
        };

        Some(new_reil)
    }

    /// Translate the binary data given in `data` to REIL instructions,
    /// `start_address` designates the starting address the decoded instructions get assigned.
    pub fn translate(&mut self, data: &mut [u8], start_address: u32) {
        unsafe {
            reil_translate(
                self.reil_handle,
                start_address as reil_addr_t,
                data.as_mut_ptr(),
                data.len() as libc::c_int,
            );
        }
    }

    /// Translate a single instruction from the binary data given in `data` and start addressing at the given address.
    pub fn translate_instruction(&mut self, data: &mut [u8], start_address: u32) {
        unsafe {
            reil_translate_insn(
                self.reil_handle,
                start_address as reil_addr_t,
                data.as_mut_ptr(),
                data.len() as libc::c_int,
            );
        }
    }
}

impl<'a, T: 'a> Drop for Reil<'a, T> {
    fn drop(&mut self) {
        unsafe {
            reil_close(self.reil_handle);
        }
    }
}

pub trait ReilInst {
    fn address(&self) -> u64;
    fn reil_offset(&self) -> u8;
    fn raw_address(&self) -> u64;
    fn print(&self);
    fn first_operand(&self) -> Option<reil_arg_t>;
    fn second_operand(&self) -> Option<reil_arg_t>;
    fn third_operand(&self) -> Option<reil_arg_t>;
    fn opcode(&self) -> reil_op_t;
}

impl ReilInst for reil_inst_t {
    fn address(&self) -> u64 {
        let raw_addr = self.raw_address() << 8;
        let reil_offset = self.reil_offset() as u64;
        raw_addr | reil_offset
    }

    fn reil_offset(&self) -> u8 {
        self.inum as u8
    }

    fn raw_address(&self) -> u64 {
        self.raw_info.addr as u64
    }

    fn print(&self) {
        let mut_ptr: *mut reil_inst_t = unsafe { mem::transmute(self) };
        unsafe { reil_inst_print(mut_ptr); }
    }

    fn first_operand(&self) -> Option<reil_arg_t> {
        match self.a.type_ {
            reil_type_t::A_NONE => None,
            _ => Some(self.a)
        }
    }

    fn second_operand(&self) -> Option<reil_arg_t> {
        match self.b.type_ {
            reil_type_t::A_NONE => None,
            _ => Some(self.b)
        }
    }

    fn third_operand(&self) -> Option<reil_arg_t> {
        match self.c.type_ {
            reil_type_t::A_NONE => None,
            _ => Some(self.c)
        }
    }

    fn opcode(&self) -> reil_op_t {
        self.op
    }
}

pub trait ReilArg {
    fn arg_type(&self) -> reil_type_t;
    fn size(&self) -> reil_size_t;
    fn val(&self) -> Option<u64>;
    fn name(&self) -> Option<String>;
}

impl ReilArg for reil_arg_t {
    fn arg_type(&self) -> reil_type_t {
        self.type_
    }

    fn size(&self) -> reil_size_t {
        self.size
    }

    fn val(&self) -> Option<u64> {
        match self.arg_type() {
            reil_type_t::A_CONST | reil_type_t::A_LOC => Some(self.val as u64),
            _ => None,
        }
    }

    fn name(&self) -> Option<String> {
        if self.arg_type() == reil_type_t::A_NONE {
            return None;
        }
        let chars = self.name.iter()
            .take_while(|&b| *b as u8 != 0)
            .map(|&b| b as u8)
            .collect();

        String::from_utf8(chars).ok()
    }
}
<|endoftext|>


<commit_before>//! Solvent is a dependency resolver library written in rust.
//!
//! Solvent helps you to resolve dependency orderings by building up a dependency
//! graph and then resolving the dependences of some target node in an order such
//! that each output depends only upon the previous outputs.
//!
//! It is currently quite simple, but is still useful.
//!
//! #Example
//!
//! ```rust
//! extern crate solvent;
//!
//! use solvent::DepGraph;
//!
//! fn main() {
//!     // Create a new empty DepGraph.  Must be `mut` or else it cannot
//!     // be used by the rest of the library.
//!     let mut depgraph: DepGraph = DepGraph::new();
//!
//!     // You can register a dependency like this.  Solvent will
//!     // automatically create nodes for any term it has not seen before.
//!     // This means 'b' depends on 'd'
//!     depgraph.register_dependency("b","d");
//!
//!     // You can also register multiple dependencies at once
//!     depgraph.register_dependencies("a",&["b","c","d"]);
//!     depgraph.register_dependencies("c",&["e"]);
//!
//!     // Iterate through each dependency of "a".  The dependencies will be
//!     // returned in an order such that each output only depends on the
//!     // previous outputs (or nothing).  The target itself will be output
//!     // last.
//!     for node in depgraph.dependencies_of("a") {
//!         match node {
//!             Ok(n) => print!("{} ", n),
//!             Err(e) => panic!("Solvent error detected: {:?}", e),
//!         }
//!     }
//! }
//! ```
//!
//! The above will output:  `d b e c a` or `e c d b a` or some other valid
//! dependency order.
//!
//! The algorithm is not deterministic, and may give a different answer each
//! time it is run.  Beware.
//!
//! The iterator dependencies_of() returns an Option<Result<String,SolventError>>.
//! The for loop handles the Option part for you, but you may want to check the
//! result for SolventErrors.  Once an error is returned, all subsequent calls to
//! the iterator next() will yield None.
//!
//! You can also mark some elements as already satisfied, and the iterator
//! will take that into account:
//!
//! ```ignore
//! depgraph.mark_as_satisfied(["e","c"]);
//! ```
//!
//! Dependency cycles are detected and will return SolventError::CycleDetected.

#![crate_name = "solvent"]
#![crate_type = "lib"]

#[macro_use] extern crate log;

use std::collections::{HashMap,HashSet};
use std::collections::hash_map::Entry;
use std::iter::{Iterator};
use std::borrow::ToOwned;

/// This is the dependency graph.
#[derive(Clone)]
pub struct DepGraph {
    /// List of dependencies.  Key is the element, values are the
    /// other elements that the key element depends upon.
    pub dependencies: HashMap<String,HashSet<String>>,

    /// Nodes already satisfied.  dependencies_of() will prune
    /// dependency searches at these nodes, and not output nodes
    /// registered here.
    pub satisfied: HashSet<String>,
}

#[derive(Copy,Show,PartialEq)]
pub enum SolventError {
    CycleDetected,
    // TODO once we implement conflicts: Conflict(String)
}

/// This iterates through the dependencies of the DepGraph's target
pub struct DepGraphIterator<'a> {
    depgraph: &'a DepGraph,

    // Target we are trying to satisfy
    target: String,

    // Elements already satisfied during this iterator's walk
    satisfied: HashSet<String>,

    // Current path, for cycle detection
    curpath: HashSet<String>,

    // Halted.  Used so that it can return None after an Err is returned.
    halted: bool,
}

impl DepGraph {

    /// Create an empty DepGraph.
    pub fn new() -> DepGraph
    {
        DepGraph {
            dependencies: HashMap::new(),
            satisfied: HashSet::new(),
        }
    }

    /// Add a dependency to a DepGraph.  The node does not need
    /// to pre-exist, nor do the dependency nodes.  But if the
    /// node does pre-exist, the depends_on will be added to its
    /// existing dependency list.
    pub fn register_dependency<'a>( &mut self,
                                node: &'a str,
                                depends_on: &'a str )
    {
        match self.dependencies.entry( String::from_str(node) ) {
            Entry::Vacant(entry) => {
                let mut deps = HashSet::with_capacity(1);
                deps.insert( String::from_str(depends_on) );
                entry.insert( deps );
            },
            Entry::Occupied(mut entry) => {
                (*entry.get_mut()).insert(String::from_str(depends_on));
            },
        }
    }

    /// Add multiple dependencies of one node to a DepGraph.  The
    /// node does not need to pre-exist, nor do the dependency elements.
    /// But if the node does pre-exist, the depends_on will be added
    /// to its existing dependency list.
    pub fn register_dependencies<'a>( &mut self,
                                  node: &'a str,
                                  depends_on: &'a[&'a str] )
    {
        match self.dependencies.entry( String::from_str(node) ) {
            Entry::Vacant(entry) => {
                let mut deps = HashSet::with_capacity( depends_on.len() );
                for s in depends_on.iter() {
                    deps.insert( String::from_str(*s) );
                }
                entry.insert( deps );
            },
            Entry::Occupied(mut entry) => {
                for s in depends_on.iter() {
                    (*entry.get_mut()).insert( String::from_str(*s) );
                }
            },
        }
    }

    /// This marks a node as satisfied.  Iterators will not output
    /// such nodes.
    pub fn mark_as_satisfied<'a>( &mut self,
                                   nodes: &'a[&'a str] )
    {
        for node in nodes.iter() {
            self.satisfied.insert(String::from_str(*node));
        }
    }

    /// Get an iterator to iterate through the dependencies of
    /// the target node.
    pub fn dependencies_of<'a>(&'a self, target: &str) -> DepGraphIterator<'a>
    {
        // TODO: iterator's satisfied could start empty, and all checks
        //       could separately check depgraph's and iterator's.  That
        //       would avoid the copy.
        DepGraphIterator {
            depgraph: self,
            target: target.to_owned(),
            satisfied: self.satisfied.clone(),
            curpath: HashSet::new(),
            halted: false,
        }
    }
}

impl<'a> DepGraphIterator<'a> {

    fn get_next_dependency(&mut self, node: &String) -> Result<String,SolventError>
    {
        if self.curpath.contains(node) {
            return Err(SolventError::CycleDetected);
        }
        self.curpath.insert(node.clone());

        let deplist = match self.depgraph.dependencies.get(node) {
            None => return Ok(node.clone()),
            Some(deplist) => deplist.clone() // ouch
        };

        for n in deplist.iter() {
            // Prune satisfied nodes
            if self.satisfied.contains(n) {
                continue;
            }

            return self.get_next_dependency(n);
        }
        // nodes dependencies are satisfied
        Ok(node.clone())
    }
}

impl<'a> Iterator for DepGraphIterator<'a> {
    type Item = Result<String,SolventError>;

    /// Get next dependency.  Returns None when finished.  If
    /// Some(Err(SolventError)) occurs, all subsequent calls will
    /// return None.
    fn next(&mut self) -> Option< Result<String,SolventError> >
    {
        if self.halted {
            return None;
        }

        let node = self.target.clone();
        if self.satisfied.contains(&node) {
            return None;
        }

        self.curpath.clear();
        let next = match self.get_next_dependency(&node) {
            Ok(d) => d,
            Err(e) => {
                self.halted = true;
                return Some(Err(e));
            }
        };
        self.satisfied.insert(next.clone());
        Some(Ok(next))
    }
}

#[test]
fn solvent_test_branching() {
    let mut depgraph: DepGraph = DepGraph::new();

    depgraph.register_dependencies("a",&["b","c","d"]);
    depgraph.register_dependency("b","d");
    depgraph.register_dependencies("c",&["e","m","g"]);
    depgraph.register_dependency("e","f");
    depgraph.register_dependency("g","h");
    depgraph.register_dependency("h","i");
    depgraph.register_dependencies("i",&["j","k"]);
    depgraph.register_dependencies("k",&["l","m"]);
    depgraph.register_dependency("m","n");

    let mut results: Vec<String> = Vec::new();

    for node in depgraph.dependencies_of("a") {
        // detect infinite looping bugs
        assert!(results.len() < 30);

        let n = match node {
            Err(e) => panic!("Solvent error detected: {:?}", e),
            Ok(n) => n,
        };

        // Check that all of that nodes dependencies have already been output
        let deps: Option<&HashSet<String>> = depgraph.dependencies.get(&n);
        if deps.is_some() {
            for dep in deps.unwrap().iter() {
                assert!( results.contains(dep) );
            }
        }

        results.push(n.clone());
    }

    // Be sure we actually output enough stuff
    assert!(results.len() == 14);

    // Be sure each output is unique
    for result in results.iter() {
        let mut count: usize = 0;
        for result2 in results.iter() {
            if result == result2 { count = count + 1; }
        }
        assert!(count == 1);
    }
}

#[test]
fn solvent_test_updating_dependencies() {
    let mut depgraph: DepGraph = DepGraph::new();

    depgraph.register_dependencies("a",&["b","c"]);
    depgraph.register_dependency("a","d");
    assert!(depgraph.dependencies.get("a").unwrap().contains("b"));
    assert!(depgraph.dependencies.get("a").unwrap().contains("c"));
    assert!(depgraph.dependencies.get("a").unwrap().contains("d"));
}

#[test]
fn solvent_test_circular() {

    let mut depgraph: DepGraph = DepGraph::new();
    depgraph.register_dependency("a","b");
    depgraph.register_dependency("b","c");
    depgraph.register_dependency("c","a");

    for node in depgraph.dependencies_of("a") {
        assert!(node.is_err());
        assert!(node.unwrap_err() == SolventError::CycleDetected);
    }
}

#[test]
fn solvent_test_satisfied_stoppage() {

    let mut depgraph: DepGraph = DepGraph::new();
    depgraph.register_dependencies("superconn", &[]);
    depgraph.register_dependencies("owneruser", &["superconn"]);
    depgraph.register_dependencies("appuser", &["superconn"]);
    depgraph.register_dependencies("database", &["owneruser"]);
    depgraph.register_dependencies("ownerconn", &["database","owneruser"]);
    depgraph.register_dependencies("adminconn", &["database"]);
    depgraph.register_dependencies("extensions", &["database","adminconn"]);
    depgraph.register_dependencies("schema_table", &["database","ownerconn"]);
    depgraph.register_dependencies("schemas", &["ownerconn","extensions","schema_table","appuser"]);
    depgraph.register_dependencies("appconn", &["database","appuser","schemas"]);

    depgraph.mark_as_satisfied(&["owneruser","appuser"]);

    let mut results: Vec<String> = Vec::new();

    for node in depgraph.dependencies_of("appconn") {
        assert!(results.len() < 30);
        match node {
            Ok(n) => results.push(n),
            Err(e) => panic!("Solvent error detected: {:?}",e),
        };
    }

    // Be sure we did not depend on these
    assert!( !results.contains(&String::from_str("appuser")) );
    assert!( !results.contains(&String::from_str("owneruser")) );
    assert!( !results.contains(&String::from_str("superconn")) );

    // Be sure we actually output enough stuff
    assert!(results.len() == 7);

    // Be sure each output is unique
    for result in results.iter() {
        let mut count: usize = 0;
        for result2 in results.iter() {
            if result == result2 { count = count + 1; }
        }
        assert!(count == 1);
    }
}

<commit_msg>silence warnings<commit_after>//! Solvent is a dependency resolver library written in rust.
//!
//! Solvent helps you to resolve dependency orderings by building up a dependency
//! graph and then resolving the dependences of some target node in an order such
//! that each output depends only upon the previous outputs.
//!
//! It is currently quite simple, but is still useful.
//!
//! #Example
//!
//! ```rust
//! extern crate solvent;
//!
//! use solvent::DepGraph;
//!
//! fn main() {
//!     // Create a new empty DepGraph.  Must be `mut` or else it cannot
//!     // be used by the rest of the library.
//!     let mut depgraph: DepGraph = DepGraph::new();
//!
//!     // You can register a dependency like this.  Solvent will
//!     // automatically create nodes for any term it has not seen before.
//!     // This means 'b' depends on 'd'
//!     depgraph.register_dependency("b","d");
//!
//!     // You can also register multiple dependencies at once
//!     depgraph.register_dependencies("a",&["b","c","d"]);
//!     depgraph.register_dependencies("c",&["e"]);
//!
//!     // Iterate through each dependency of "a".  The dependencies will be
//!     // returned in an order such that each output only depends on the
//!     // previous outputs (or nothing).  The target itself will be output
//!     // last.
//!     for node in depgraph.dependencies_of("a") {
//!         match node {
//!             Ok(n) => print!("{} ", n),
//!             Err(e) => panic!("Solvent error detected: {:?}", e),
//!         }
//!     }
//! }
//! ```
//!
//! The above will output:  `d b e c a` or `e c d b a` or some other valid
//! dependency order.
//!
//! The algorithm is not deterministic, and may give a different answer each
//! time it is run.  Beware.
//!
//! The iterator dependencies_of() returns an Option<Result<String,SolventError>>.
//! The for loop handles the Option part for you, but you may want to check the
//! result for SolventErrors.  Once an error is returned, all subsequent calls to
//! the iterator next() will yield None.
//!
//! You can also mark some elements as already satisfied, and the iterator
//! will take that into account:
//!
//! ```ignore
//! depgraph.mark_as_satisfied(["e","c"]);
//! ```
//!
//! Dependency cycles are detected and will return SolventError::CycleDetected.

#![crate_name = "solvent"]
#![crate_type = "lib"]

// Silence warnings about unstable library features
#![feature(core)]
#![feature(collections)]
#![feature(std_misc)]

#[macro_use] extern crate log;

use std::collections::{HashMap,HashSet};
use std::collections::hash_map::Entry;
use std::iter::{Iterator};
use std::borrow::ToOwned;

/// This is the dependency graph.
#[derive(Clone)]
pub struct DepGraph {
    /// List of dependencies.  Key is the element, values are the
    /// other elements that the key element depends upon.
    pub dependencies: HashMap<String,HashSet<String>>,

    /// Nodes already satisfied.  dependencies_of() will prune
    /// dependency searches at these nodes, and not output nodes
    /// registered here.
    pub satisfied: HashSet<String>,
}

#[derive(Copy,Debug,PartialEq)]
pub enum SolventError {
    CycleDetected,
    // TODO once we implement conflicts: Conflict(String)
}

/// This iterates through the dependencies of the DepGraph's target
pub struct DepGraphIterator<'a> {
    depgraph: &'a DepGraph,

    // Target we are trying to satisfy
    target: String,

    // Elements already satisfied during this iterator's walk
    satisfied: HashSet<String>,

    // Current path, for cycle detection
    curpath: HashSet<String>,

    // Halted.  Used so that it can return None after an Err is returned.
    halted: bool,
}

impl DepGraph {

    /// Create an empty DepGraph.
    pub fn new() -> DepGraph
    {
        DepGraph {
            dependencies: HashMap::new(),
            satisfied: HashSet::new(),
        }
    }

    /// Add a dependency to a DepGraph.  The node does not need
    /// to pre-exist, nor do the dependency nodes.  But if the
    /// node does pre-exist, the depends_on will be added to its
    /// existing dependency list.
    pub fn register_dependency<'a>( &mut self,
                                node: &'a str,
                                depends_on: &'a str )
    {
        match self.dependencies.entry( String::from_str(node) ) {
            Entry::Vacant(entry) => {
                let mut deps = HashSet::with_capacity(1);
                deps.insert( String::from_str(depends_on) );
                entry.insert( deps );
            },
            Entry::Occupied(mut entry) => {
                (*entry.get_mut()).insert(String::from_str(depends_on));
            },
        }
    }

    /// Add multiple dependencies of one node to a DepGraph.  The
    /// node does not need to pre-exist, nor do the dependency elements.
    /// But if the node does pre-exist, the depends_on will be added
    /// to its existing dependency list.
    pub fn register_dependencies<'a>( &mut self,
                                  node: &'a str,
                                  depends_on: &'a[&'a str] )
    {
        match self.dependencies.entry( String::from_str(node) ) {
            Entry::Vacant(entry) => {
                let mut deps = HashSet::with_capacity( depends_on.len() );
                for s in depends_on.iter() {
                    deps.insert( String::from_str(*s) );
                }
                entry.insert( deps );
            },
            Entry::Occupied(mut entry) => {
                for s in depends_on.iter() {
                    (*entry.get_mut()).insert( String::from_str(*s) );
                }
            },
        }
    }

    /// This marks a node as satisfied.  Iterators will not output
    /// such nodes.
    pub fn mark_as_satisfied<'a>( &mut self,
                                   nodes: &'a[&'a str] )
    {
        for node in nodes.iter() {
            self.satisfied.insert(String::from_str(*node));
        }
    }

    /// Get an iterator to iterate through the dependencies of
    /// the target node.
    pub fn dependencies_of<'a>(&'a self, target: &str) -> DepGraphIterator<'a>
    {
        // TODO: iterator's satisfied could start empty, and all checks
        //       could separately check depgraph's and iterator's.  That
        //       would avoid the copy.
        DepGraphIterator {
            depgraph: self,
            target: target.to_owned(),
            satisfied: self.satisfied.clone(),
            curpath: HashSet::new(),
            halted: false,
        }
    }
}

impl<'a> DepGraphIterator<'a> {

    fn get_next_dependency(&mut self, node: &String) -> Result<String,SolventError>
    {
        if self.curpath.contains(node) {
            return Err(SolventError::CycleDetected);
        }
        self.curpath.insert(node.clone());

        let deplist = match self.depgraph.dependencies.get(node) {
            None => return Ok(node.clone()),
            Some(deplist) => deplist.clone() // ouch
        };

        for n in deplist.iter() {
            // Prune satisfied nodes
            if self.satisfied.contains(n) {
                continue;
            }

            return self.get_next_dependency(n);
        }
        // nodes dependencies are satisfied
        Ok(node.clone())
    }
}

impl<'a> Iterator for DepGraphIterator<'a> {
    type Item = Result<String,SolventError>;

    /// Get next dependency.  Returns None when finished.  If
    /// Some(Err(SolventError)) occurs, all subsequent calls will
    /// return None.
    fn next(&mut self) -> Option< Result<String,SolventError> >
    {
        if self.halted {
            return None;
        }

        let node = self.target.clone();
        if self.satisfied.contains(&node) {
            return None;
        }

        self.curpath.clear();
        let next = match self.get_next_dependency(&node) {
            Ok(d) => d,
            Err(e) => {
                self.halted = true;
                return Some(Err(e));
            }
        };
        self.satisfied.insert(next.clone());
        Some(Ok(next))
    }
}

#[test]
fn solvent_test_branching() {
    let mut depgraph: DepGraph = DepGraph::new();

    depgraph.register_dependencies("a",&["b","c","d"]);
    depgraph.register_dependency("b","d");
    depgraph.register_dependencies("c",&["e","m","g"]);
    depgraph.register_dependency("e","f");
    depgraph.register_dependency("g","h");
    depgraph.register_dependency("h","i");
    depgraph.register_dependencies("i",&["j","k"]);
    depgraph.register_dependencies("k",&["l","m"]);
    depgraph.register_dependency("m","n");

    let mut results: Vec<String> = Vec::new();

    for node in depgraph.dependencies_of("a") {
        // detect infinite looping bugs
        assert!(results.len() < 30);

        let n = match node {
            Err(e) => panic!("Solvent error detected: {:?}", e),
            Ok(n) => n,
        };

        // Check that all of that nodes dependencies have already been output
        let deps: Option<&HashSet<String>> = depgraph.dependencies.get(&n);
        if deps.is_some() {
            for dep in deps.unwrap().iter() {
                assert!( results.contains(dep) );
            }
        }

        results.push(n.clone());
    }

    // Be sure we actually output enough stuff
    assert!(results.len() == 14);

    // Be sure each output is unique
    for result in results.iter() {
        let mut count: usize = 0;
        for result2 in results.iter() {
            if result == result2 { count = count + 1; }
        }
        assert!(count == 1);
    }
}

#[test]
fn solvent_test_updating_dependencies() {
    let mut depgraph: DepGraph = DepGraph::new();

    depgraph.register_dependencies("a",&["b","c"]);
    depgraph.register_dependency("a","d");
    assert!(depgraph.dependencies.get("a").unwrap().contains("b"));
    assert!(depgraph.dependencies.get("a").unwrap().contains("c"));
    assert!(depgraph.dependencies.get("a").unwrap().contains("d"));
}

#[test]
fn solvent_test_circular() {

    let mut depgraph: DepGraph = DepGraph::new();
    depgraph.register_dependency("a","b");
    depgraph.register_dependency("b","c");
    depgraph.register_dependency("c","a");

    for node in depgraph.dependencies_of("a") {
        assert!(node.is_err());
        assert!(node.unwrap_err() == SolventError::CycleDetected);
    }
}

#[test]
fn solvent_test_satisfied_stoppage() {

    let mut depgraph: DepGraph = DepGraph::new();
    depgraph.register_dependencies("superconn", &[]);
    depgraph.register_dependencies("owneruser", &["superconn"]);
    depgraph.register_dependencies("appuser", &["superconn"]);
    depgraph.register_dependencies("database", &["owneruser"]);
    depgraph.register_dependencies("ownerconn", &["database","owneruser"]);
    depgraph.register_dependencies("adminconn", &["database"]);
    depgraph.register_dependencies("extensions", &["database","adminconn"]);
    depgraph.register_dependencies("schema_table", &["database","ownerconn"]);
    depgraph.register_dependencies("schemas", &["ownerconn","extensions","schema_table","appuser"]);
    depgraph.register_dependencies("appconn", &["database","appuser","schemas"]);

    depgraph.mark_as_satisfied(&["owneruser","appuser"]);

    let mut results: Vec<String> = Vec::new();

    for node in depgraph.dependencies_of("appconn") {
        assert!(results.len() < 30);
        match node {
            Ok(n) => results.push(n),
            Err(e) => panic!("Solvent error detected: {:?}",e),
        };
    }

    // Be sure we did not depend on these
    assert!( !results.contains(&String::from_str("appuser")) );
    assert!( !results.contains(&String::from_str("owneruser")) );
    assert!( !results.contains(&String::from_str("superconn")) );

    // Be sure we actually output enough stuff
    assert!(results.len() == 7);

    // Be sure each output is unique
    for result in results.iter() {
        let mut count: usize = 0;
        for result2 in results.iter() {
            if result == result2 { count = count + 1; }
        }
        assert!(count == 1);
    }
}

<|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/. */

#![crate_name = "cssparser"]
#![crate_type = "rlib"]

#![cfg_attr(feature = "bench", feature(test))]
#![deny(missing_docs)]

/*!

Implementation of [CSS Syntax Module Level 3](https://drafts.csswg.org/css-syntax/) for Rust.

# Input

Everything is based on `Parser` objects, which borrow a `&str` input.
If you have bytes (from a file, the network, or something)
and want to support character encodings other than UTF-8,
see the `stylesheet_encoding` function,
which can be used together with rust-encoding or encoding-rs.

# Conventions for parsing functions

* Take (at least) a `input: &mut cssparser::Parser` parameter
* Return `Result<_, ()>`
* When returning `Ok(_)`,
  the function must have consume exactly the amount of input that represents the parsed value.
* When returning `Err(())`, any amount of input may have been consumed.

As a consequence, when calling another parsing function, either:

* Any `Err(())` return value must be propagated.
  This happens by definition for tail calls,
  and can otherwise be done with the `try!` macro.
* Or the call must be wrapped in a `Parser::try` call.
  `try` takes a closure that takes a `Parser` and returns a `Result`,
  calls it once,
  and returns itself that same result.
  If the result is `Err`,
  it restores the position inside the input to the one saved before calling the closure.

Examples:

```{rust,ignore}
// 'none' | <image>
fn parse_background_image(context: &ParserContext, input: &mut Parser)
                                    -> Result<Option<Image>, ()> {
    if input.try(|input| input.expect_ident_matching("none")).is_ok() {
        Ok(None)
    } else {
        Image::parse(context, input).map(Some)  // tail call
    }
}
```

```{rust,ignore}
// [ <length> | <percentage> ] [ <length> | <percentage> ]?
fn parse_border_spacing(_context: &ParserContext, input: &mut Parser)
                          -> Result<(LengthOrPercentage, LengthOrPercentage), ()> {
    let first = try!(LengthOrPercentage::parse);
    let second = input.try(LengthOrPercentage::parse).unwrap_or(first);
    (first, second)
}
```

*/

#![recursion_limit="200"]  // For color::parse_color_keyword

#[macro_use] extern crate cssparser_macros;
#[macro_use] extern crate matches;
extern crate phf;
#[cfg(test)] extern crate encoding_rs;
#[cfg(test)] extern crate tempdir;
#[cfg(test)] extern crate rustc_serialize;
#[cfg(feature = "serde")] extern crate serde;
#[cfg(feature = "heapsize")] #[macro_use] extern crate heapsize;

pub use tokenizer::{Token, NumericValue, PercentageValue, SourceLocation};
pub use rules_and_declarations::{parse_important};
pub use rules_and_declarations::{DeclarationParser, DeclarationListParser, parse_one_declaration};
pub use rules_and_declarations::{RuleListParser, parse_one_rule};
pub use rules_and_declarations::{AtRuleType, QualifiedRuleParser, AtRuleParser};
pub use from_bytes::{stylesheet_encoding, EncodingSupport};
pub use color::{RGBA, Color, parse_color_keyword};
pub use nth::parse_nth;
pub use serializer::{ToCss, CssStringWriter, serialize_identifier, serialize_string, TokenSerializationType};
pub use parser::{Parser, Delimiter, Delimiters, SourcePosition};
pub use unicode_range::UnicodeRange;

/// Expands to an expression equivalent to a `match` with string patterns,
/// but matching is case-insensitive in the ASCII range.
///
/// Requirements:
///
/// * The `cssparser_macros` crate must also be imported at the crate root
/// * The patterns must not contain ASCII upper case letters. (They must be already be lower-cased.)
///
/// # Example
///
/// ```rust
/// #[macro_use] extern crate cssparser;
/// #[macro_use] extern crate cssparser_macros;
///
/// # fn main() {}  // Make doctest not wrap everythig in its own main
/// # fn dummy(function_name: &String) { let _ =
/// match_ignore_ascii_case! { &function_name,
///     "rgb" => parse_rgb(..),
///     "rgba" => parse_rgba(..),
///     "hsl" => parse_hsl(..),
///     "hsla" => parse_hsla(..),
///     _ => Err("unknown function")
/// }
/// # ;}
/// # use std::ops::RangeFull;
/// # fn parse_rgb(_: RangeFull) -> Result<(), &'static str> { Err("") }
/// # fn parse_rgba(_: RangeFull) -> Result<(), &'static str> { Err("") }
/// # fn parse_hsl(_: RangeFull) -> Result<(), &'static str> { Err("") }
/// # fn parse_hsla(_: RangeFull) -> Result<(), &'static str> { Err("") }
/// ```
#[macro_export]
macro_rules! match_ignore_ascii_case {
    // parse the last case plus the fallback
    (@inner $value:expr, ($string:expr => $result:expr, _ => $fallback:expr) -> ($($parsed:tt)*) ) => {
        match_ignore_ascii_case!(@inner $value, () -> ($($parsed)* ($string => $result)) $fallback)
    };

    // parse a case (not the last one)
    (@inner $value:expr, ($string:expr => $result:expr, $($rest:tt)*) -> ($($parsed:tt)*) ) => {
        match_ignore_ascii_case!(@inner $value, ($($rest)*) -> ($($parsed)* ($string => $result)))
    };

    // finished parsing
    (@inner $value:expr, () -> ($(($string:expr => $result:expr))*) $fallback:expr ) => {
        {
            #[derive(cssparser__assert_ascii_lowercase)]
            #[cssparser__assert_ascii_lowercase__data($(string = $string),+)]
            #[allow(dead_code)]
            struct Dummy;

            _cssparser_internal__to_lowercase!($value => lowercase, $($string),+);
            match lowercase {
                $(
                    Some($string) => $result,
                )+
                _ => $fallback
            }
        }
    };

    // entry point, start parsing
    ( $value:expr, $($rest:tt)* ) => {
        match_ignore_ascii_case!(@inner $value, ($($rest)*) -> ())
    };
}

/// Define a placeholder type `$Name`
/// with a method `fn get(input: &str) -> Option<&'static $ValueType>`.
///
/// This method uses finds a match for the input string
/// in a [`phf` map](https://github.com/sfackler/rust-phf).
/// Matching is case-insensitive in the ASCII range.
///
/// Requirements:
///
/// * The `phf` and `cssparser_macros` crates must also be imported at the crate root
/// * The values must be given a strings that contain Rust syntax for a constant expression.
///
/// ## Example:
///
/// ```rust
/// extern crate phf;
/// #[macro_use] extern crate cssparser;
/// #[macro_use] extern crate cssparser_macros;
///
/// # fn main() {}  // Make doctest not wrap everythig in its own main
///
/// fn color_rgb(input: &str) -> Option<(u8, u8, u8)> {
///     ascii_case_insensitive_phf_map! {
///         KEYWORDS: Map<(u8, u8, u8)> = {
///             "red" => "(255, 0, 0)",
///             "green" => "(0, 255, 0)",
///             "blue" => "(0, 0, 255)",
///         }
///     }
///     KEYWORDS::get(input).cloned()
/// }
#[macro_export]
macro_rules! ascii_case_insensitive_phf_map {
    ($Name: ident : Map<$ValueType: ty> = {
        $( $key: expr => $value: expr, )*
    }) => {
        #[derive(cssparser__phf_map)]
        #[cssparser__phf_map__kv_pairs(
            $(
                key = $key,
                value = $value
            ),+
        )]
        struct $Name($ValueType);

        impl $Name {
            #[inline]
            fn get(input: &str) -> Option<&'static $ValueType> {
                _cssparser_internal__to_lowercase!(input => lowercase, $($key),+);
                lowercase.and_then(|string| $Name::map().get(string))
            }
        }
    }
}

/// Implementation detail of match_ignore_ascii_case! and ascii_case_insensitive_phf_map! macros.
///
/// **This macro is not part of the public API. It can change or be removed between any versions.**
///
/// * Check at compile-time that none of the `$string`s contain ASCII uppercase letters
/// * Define a local variable named `$output` to the result of calling `_internal__to_lowercase`
///   with a stack-allocated buffer as long as the longest `$string`.
#[macro_export]
#[doc(hidden)]
macro_rules! _cssparser_internal__to_lowercase {
    ($input: expr => $output: ident, $($string: expr),+) => {
        #[derive(cssparser__max_len)]
        #[cssparser__max_len__data($(string = $string),+)]
        #[allow(dead_code)]
        struct Dummy2;

        // MAX_LENGTH is generated by cssparser__match_ignore_ascii_case__max_len
        let mut buffer: [u8; MAX_LENGTH] =
            // `buffer` is only used in `_internal__to_lowercase`,
            // which initializes with `copy_from_slice` the part of the buffer it uses,
            // before it uses it.
            unsafe {
                ::std::mem::uninitialized()
            };
        let $output = $crate::_internal__to_lowercase(&mut buffer, $input);
    }
}

/// Implementation detail of match_ignore_ascii_case! and ascii_case_insensitive_phf_map! macros.
///
/// **This function is not part of the public API. It can change or be removed between any verisons.**
///
/// Return `input`, lower-cased, unless larger than `buffer`
/// which is used temporary space for lower-casing a copy of `input` if necessary.
#[doc(hidden)]
#[allow(non_snake_case)]
pub fn _internal__to_lowercase<'a>(buffer: &'a mut [u8], input: &'a str) -> Option<&'a str> {
    if let Some(buffer) = buffer.get_mut(..input.len()) {
        if let Some(first_uppercase) = input.bytes().position(|byte| matches!(byte, b'A'...b'Z')) {
            buffer.copy_from_slice(input.as_bytes());
            std::ascii::AsciiExt::make_ascii_lowercase(&mut buffer[first_uppercase..]);
            // `buffer` was initialized to a copy of `input` (which is &str so well-formed UTF-8)
            // then lowercased (which preserves UTF-8 well-formedness)
            unsafe {
                Some(::std::str::from_utf8_unchecked(buffer))
            }
        } else {
            // Input is already lower-case
            Some(input)
        }
    } else {
        // Input is longer than buffer, which has the length of the longest expected string:
        // none of the expected strings would match.
        None
    }
}

mod rules_and_declarations;

#[cfg(feature = "dummy_match_byte")]
macro_rules! match_byte {
    ($value:expr, $($rest:tt)* ) => {
        match $value {
            $(
                $rest
            )+
        }
    };
}

#[cfg(feature = "dummy_match_byte")]
mod tokenizer;

#[cfg(not(feature = "dummy_match_byte"))]
mod tokenizer {
    include!(concat!(env!("OUT_DIR"), "/tokenizer.rs"));
}
mod parser;
mod from_bytes;
mod color;
mod nth;
mod serializer;
mod unicode_range;

#[cfg(test)]
mod tests;
<commit_msg>Support macros being used in a module with #[deny(unsafe_code)]<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/. */

#![crate_name = "cssparser"]
#![crate_type = "rlib"]

#![cfg_attr(feature = "bench", feature(test))]
#![deny(missing_docs)]

/*!

Implementation of [CSS Syntax Module Level 3](https://drafts.csswg.org/css-syntax/) for Rust.

# Input

Everything is based on `Parser` objects, which borrow a `&str` input.
If you have bytes (from a file, the network, or something)
and want to support character encodings other than UTF-8,
see the `stylesheet_encoding` function,
which can be used together with rust-encoding or encoding-rs.

# Conventions for parsing functions

* Take (at least) a `input: &mut cssparser::Parser` parameter
* Return `Result<_, ()>`
* When returning `Ok(_)`,
  the function must have consume exactly the amount of input that represents the parsed value.
* When returning `Err(())`, any amount of input may have been consumed.

As a consequence, when calling another parsing function, either:

* Any `Err(())` return value must be propagated.
  This happens by definition for tail calls,
  and can otherwise be done with the `try!` macro.
* Or the call must be wrapped in a `Parser::try` call.
  `try` takes a closure that takes a `Parser` and returns a `Result`,
  calls it once,
  and returns itself that same result.
  If the result is `Err`,
  it restores the position inside the input to the one saved before calling the closure.

Examples:

```{rust,ignore}
// 'none' | <image>
fn parse_background_image(context: &ParserContext, input: &mut Parser)
                                    -> Result<Option<Image>, ()> {
    if input.try(|input| input.expect_ident_matching("none")).is_ok() {
        Ok(None)
    } else {
        Image::parse(context, input).map(Some)  // tail call
    }
}
```

```{rust,ignore}
// [ <length> | <percentage> ] [ <length> | <percentage> ]?
fn parse_border_spacing(_context: &ParserContext, input: &mut Parser)
                          -> Result<(LengthOrPercentage, LengthOrPercentage), ()> {
    let first = try!(LengthOrPercentage::parse);
    let second = input.try(LengthOrPercentage::parse).unwrap_or(first);
    (first, second)
}
```

*/

#![recursion_limit="200"]  // For color::parse_color_keyword

#[macro_use] extern crate cssparser_macros;
#[macro_use] extern crate matches;
extern crate phf;
#[cfg(test)] extern crate encoding_rs;
#[cfg(test)] extern crate tempdir;
#[cfg(test)] extern crate rustc_serialize;
#[cfg(feature = "serde")] extern crate serde;
#[cfg(feature = "heapsize")] #[macro_use] extern crate heapsize;

pub use tokenizer::{Token, NumericValue, PercentageValue, SourceLocation};
pub use rules_and_declarations::{parse_important};
pub use rules_and_declarations::{DeclarationParser, DeclarationListParser, parse_one_declaration};
pub use rules_and_declarations::{RuleListParser, parse_one_rule};
pub use rules_and_declarations::{AtRuleType, QualifiedRuleParser, AtRuleParser};
pub use from_bytes::{stylesheet_encoding, EncodingSupport};
pub use color::{RGBA, Color, parse_color_keyword};
pub use nth::parse_nth;
pub use serializer::{ToCss, CssStringWriter, serialize_identifier, serialize_string, TokenSerializationType};
pub use parser::{Parser, Delimiter, Delimiters, SourcePosition};
pub use unicode_range::UnicodeRange;

/// Expands to an expression equivalent to a `match` with string patterns,
/// but matching is case-insensitive in the ASCII range.
///
/// Requirements:
///
/// * The `cssparser_macros` crate must also be imported at the crate root
/// * The patterns must not contain ASCII upper case letters. (They must be already be lower-cased.)
///
/// # Example
///
/// ```rust
/// #[macro_use] extern crate cssparser;
/// #[macro_use] extern crate cssparser_macros;
///
/// # fn main() {}  // Make doctest not wrap everythig in its own main
/// # fn dummy(function_name: &String) { let _ =
/// match_ignore_ascii_case! { &function_name,
///     "rgb" => parse_rgb(..),
///     "rgba" => parse_rgba(..),
///     "hsl" => parse_hsl(..),
///     "hsla" => parse_hsla(..),
///     _ => Err("unknown function")
/// }
/// # ;}
/// # use std::ops::RangeFull;
/// # fn parse_rgb(_: RangeFull) -> Result<(), &'static str> { Err("") }
/// # fn parse_rgba(_: RangeFull) -> Result<(), &'static str> { Err("") }
/// # fn parse_hsl(_: RangeFull) -> Result<(), &'static str> { Err("") }
/// # fn parse_hsla(_: RangeFull) -> Result<(), &'static str> { Err("") }
/// ```
#[macro_export]
macro_rules! match_ignore_ascii_case {
    // parse the last case plus the fallback
    (@inner $value:expr, ($string:expr => $result:expr, _ => $fallback:expr) -> ($($parsed:tt)*) ) => {
        match_ignore_ascii_case!(@inner $value, () -> ($($parsed)* ($string => $result)) $fallback)
    };

    // parse a case (not the last one)
    (@inner $value:expr, ($string:expr => $result:expr, $($rest:tt)*) -> ($($parsed:tt)*) ) => {
        match_ignore_ascii_case!(@inner $value, ($($rest)*) -> ($($parsed)* ($string => $result)))
    };

    // finished parsing
    (@inner $value:expr, () -> ($(($string:expr => $result:expr))*) $fallback:expr ) => {
        {
            #[derive(cssparser__assert_ascii_lowercase)]
            #[cssparser__assert_ascii_lowercase__data($(string = $string),+)]
            #[allow(dead_code)]
            struct Dummy;

            _cssparser_internal__to_lowercase!($value => lowercase, $($string),+);
            match lowercase {
                $(
                    Some($string) => $result,
                )+
                _ => $fallback
            }
        }
    };

    // entry point, start parsing
    ( $value:expr, $($rest:tt)* ) => {
        match_ignore_ascii_case!(@inner $value, ($($rest)*) -> ())
    };
}

/// Define a placeholder type `$Name`
/// with a method `fn get(input: &str) -> Option<&'static $ValueType>`.
///
/// This method uses finds a match for the input string
/// in a [`phf` map](https://github.com/sfackler/rust-phf).
/// Matching is case-insensitive in the ASCII range.
///
/// Requirements:
///
/// * The `phf` and `cssparser_macros` crates must also be imported at the crate root
/// * The values must be given a strings that contain Rust syntax for a constant expression.
///
/// ## Example:
///
/// ```rust
/// extern crate phf;
/// #[macro_use] extern crate cssparser;
/// #[macro_use] extern crate cssparser_macros;
///
/// # fn main() {}  // Make doctest not wrap everythig in its own main
///
/// fn color_rgb(input: &str) -> Option<(u8, u8, u8)> {
///     ascii_case_insensitive_phf_map! {
///         KEYWORDS: Map<(u8, u8, u8)> = {
///             "red" => "(255, 0, 0)",
///             "green" => "(0, 255, 0)",
///             "blue" => "(0, 0, 255)",
///         }
///     }
///     KEYWORDS::get(input).cloned()
/// }
#[macro_export]
macro_rules! ascii_case_insensitive_phf_map {
    ($Name: ident : Map<$ValueType: ty> = {
        $( $key: expr => $value: expr, )*
    }) => {
        #[derive(cssparser__phf_map)]
        #[cssparser__phf_map__kv_pairs(
            $(
                key = $key,
                value = $value
            ),+
        )]
        struct $Name($ValueType);

        impl $Name {
            #[inline]
            fn get(input: &str) -> Option<&'static $ValueType> {
                _cssparser_internal__to_lowercase!(input => lowercase, $($key),+);
                lowercase.and_then(|string| $Name::map().get(string))
            }
        }
    }
}

/// Implementation detail of match_ignore_ascii_case! and ascii_case_insensitive_phf_map! macros.
///
/// **This macro is not part of the public API. It can change or be removed between any versions.**
///
/// * Check at compile-time that none of the `$string`s contain ASCII uppercase letters
/// * Define a local variable named `$output` to the result of calling `_internal__to_lowercase`
///   with a stack-allocated buffer as long as the longest `$string`.
#[macro_export]
#[doc(hidden)]
macro_rules! _cssparser_internal__to_lowercase {
    ($input: expr => $output: ident, $($string: expr),+) => {
        #[derive(cssparser__max_len)]
        #[cssparser__max_len__data($(string = $string),+)]
        #[allow(dead_code)]
        struct Dummy2;

        // mem::uninitialized() is ok because `buffer` is only used in `_internal__to_lowercase`,
        // which initializes with `copy_from_slice` the part of the buffer it uses,
        // before it uses it.
        #[allow(unsafe_code)]
        // MAX_LENGTH is generated by cssparser__max_len
        let mut buffer: [u8; MAX_LENGTH] = unsafe {
            ::std::mem::uninitialized()
        };
        let $output = $crate::_internal__to_lowercase(&mut buffer, $input);
    }
}

/// Implementation detail of match_ignore_ascii_case! and ascii_case_insensitive_phf_map! macros.
///
/// **This function is not part of the public API. It can change or be removed between any verisons.**
///
/// Return `input`, lower-cased, unless larger than `buffer`
/// which is used temporary space for lower-casing a copy of `input` if necessary.
#[doc(hidden)]
#[allow(non_snake_case)]
pub fn _internal__to_lowercase<'a>(buffer: &'a mut [u8], input: &'a str) -> Option<&'a str> {
    if let Some(buffer) = buffer.get_mut(..input.len()) {
        if let Some(first_uppercase) = input.bytes().position(|byte| matches!(byte, b'A'...b'Z')) {
            buffer.copy_from_slice(input.as_bytes());
            std::ascii::AsciiExt::make_ascii_lowercase(&mut buffer[first_uppercase..]);
            // `buffer` was initialized to a copy of `input` (which is &str so well-formed UTF-8)
            // then lowercased (which preserves UTF-8 well-formedness)
            unsafe {
                Some(::std::str::from_utf8_unchecked(buffer))
            }
        } else {
            // Input is already lower-case
            Some(input)
        }
    } else {
        // Input is longer than buffer, which has the length of the longest expected string:
        // none of the expected strings would match.
        None
    }
}

mod rules_and_declarations;

#[cfg(feature = "dummy_match_byte")]
macro_rules! match_byte {
    ($value:expr, $($rest:tt)* ) => {
        match $value {
            $(
                $rest
            )+
        }
    };
}

#[cfg(feature = "dummy_match_byte")]
mod tokenizer;

#[cfg(not(feature = "dummy_match_byte"))]
mod tokenizer {
    include!(concat!(env!("OUT_DIR"), "/tokenizer.rs"));
}
mod parser;
mod from_bytes;
mod color;
mod nth;
mod serializer;
mod unicode_range;

#[cfg(test)]
mod tests;
<|endoftext|>


<commit_before>// Copyright (C) 2016 Benjamin Fry <benjaminfry@me.com>

use std::ascii::AsciiExt;

/// returns true if and only if the phrase is a palindrome
///
/// # Arguments
///
/// * `phrase` - the phrase to inspect
///
/// This is just to have fun with iterators...
/// This should be O(n/2), and would be fewer lines without all the comments.
pub fn is_palindrome(phrase: &str) -> bool {
    // get the chars iterator and associated index
    phrase.char_indices().filter(|&(_,c)| c.is_alphabetic())
                // zip with the second half...
                .zip(phrase.char_indices()
                           // which needs to be reversed...
                           .rev()
                           // and filter out bad cars
                           .filter(|&(_,c)| c.is_alphabetic()))
                // accept all input until the indexes have crossed
                .take_while(|&((first_count, _), (last_count, _))| {first_count < last_count})
                // check that all the chars from the begining and end match
                .all(|((_, first_char), (_, last_char))| {
                    first_char.to_ascii_lowercase() == last_char.to_ascii_lowercase()
                })
}

/// this is a classic array implementation (for comparison)
///
/// # Arguments
///
/// * `phrase` - the phrase to inspect
///
/// This is definitely not the most efficient, but is meant show the difference to above. And be
///  close to the semantics used in C/C++, with the exception of the chars().collect() this should
///  be O(n/2).
pub fn is_palindrome_classic(phrase: &str) -> bool {
    if phrase.len() == 0 { return true }

    // need to do this because Rust is rightly trying to force you away from treating strs as
    //  arrays
    let phrase: Vec<char> = phrase.chars().collect();

    // start from the beginning
    let mut first_idx = 0;

    // and the end, btw, don't forget the off-by-one b/c of len() is actually past the last index...
    //  this is a classic error avoided implicitly above.
    let mut last_idx = phrase.len() - 1;
    // loop and guard that we don't go too far
    while first_idx < last_idx {
        // filter out non-alphabetics, the += and -= would be something you could accidentally screw up,
        //   avoided in the iterator based impl
        if !phrase[first_idx].is_alphabetic() { first_idx += 1; continue }
        if !phrase[last_idx].is_alphabetic() { last_idx -= 1; continue }

        // compare the values, did we compare the write indexes? again avoided in the iterator impl
        if phrase[first_idx].to_ascii_lowercase() != phrase[last_idx].to_ascii_lowercase() {
            return false;
        }

        // same += and -= potential bug avoided in the iterator impl
        first_idx += 1;
        last_idx -= 1;
    }

    // is this actually simpler or more readable? I don't think so...

    true
}

#[test]
fn test_is_palindrome() {
    test_is_palindrome_base(is_palindrome);
}

#[test]
fn test_palindrome_classic() {
    test_is_palindrome_base(is_palindrome_classic);
}

#[cfg(test)]
fn test_is_palindrome_base<F>(is_palindrome: F) where F: Fn(&str) -> bool {
    assert!(is_palindrome(""));
    assert!(is_palindrome("a"));
    assert!(is_palindrome(".,,/.,/.,././.,=-=--"));
    assert!(is_palindrome("a,,,,,,,,,,,,,,,a"));
    assert!(is_palindrome("a,,,,,bb,,,,,,,,a"));
    assert!(is_palindrome("race car"));
    assert!(is_palindrome("racecar"));
    assert!(is_palindrome("raccar"));
    assert!(is_palindrome("A man, a plan, a canal, Panama!"));
    assert!(is_palindrome("Amor, Roma"));
    assert!(is_palindrome("stack cats"));
    assert!(is_palindrome("step on no pets"));
    assert!(is_palindrome("taco cat"));
    assert!(is_palindrome("put it up"));
    assert!(is_palindrome("Was it a car or a cat I saw?"));
    assert!(is_palindrome("No ‘x’ in Nixon"));

    // negative for good messure
    assert!(!is_palindrome("Not a palindrome"))
}
<commit_msg>fix a typo<commit_after>// Copyright (C) 2016 Benjamin Fry <benjaminfry@me.com>

use std::ascii::AsciiExt;

/// returns true if and only if the phrase is a palindrome
///
/// # Arguments
///
/// * `phrase` - the phrase to inspect
///
/// This is just to have fun with iterators...
/// This should be O(n/2), and would be fewer lines without all the comments.
pub fn is_palindrome(phrase: &str) -> bool {
    // get the chars iterator and associated index
    phrase.char_indices().filter(|&(_,c)| c.is_alphabetic())
                // zip with the second half...
                .zip(phrase.char_indices()
                           // which needs to be reversed...
                           .rev()
                           // and filter out bad cars
                           .filter(|&(_,c)| c.is_alphabetic()))
                // accept all input until the indexes have crossed
                .take_while(|&((first_count, _), (last_count, _))| {first_count < last_count})
                // check that all the chars from the begining and end match
                .all(|((_, first_char), (_, last_char))| {
                    first_char.to_ascii_lowercase() == last_char.to_ascii_lowercase()
                })
}

/// this is a classic array implementation (for comparison)
///
/// # Arguments
///
/// * `phrase` - the phrase to inspect
///
/// This is definitely not the most efficient, but is meant show the difference to above. And be
///  close to the semantics used in C/C++, with the exception of the chars().collect() this should
///  be O(n/2).
pub fn is_palindrome_classic(phrase: &str) -> bool {
    if phrase.len() == 0 { return true }

    // need to do this because Rust is rightly trying to force you away from treating strs as
    //  arrays
    let phrase: Vec<char> = phrase.chars().collect();

    // start from the beginning
    let mut first_idx = 0;

    // and the end, btw, don't forget the off-by-one b/c of len() is actually past the last index...
    //  this is a classic error avoided implicitly above.
    let mut last_idx = phrase.len() - 1;
    // loop and guard that we don't go too far
    while first_idx < last_idx {
        // filter out non-alphabetics, the += and -= would be something you could accidentally screw up,
        //   avoided in the iterator based impl
        if !phrase[first_idx].is_alphabetic() { first_idx += 1; continue }
        if !phrase[last_idx].is_alphabetic() { last_idx -= 1; continue }

        // compare the values, did we compare the correct indexes? again avoided in the iterator impl
        if phrase[first_idx].to_ascii_lowercase() != phrase[last_idx].to_ascii_lowercase() {
            return false;
        }

        // same += and -= potential bug avoided in the iterator impl
        first_idx += 1;
        last_idx -= 1;
    }

    // is this actually simpler or more readable? I don't think so...

    true
}

#[test]
fn test_is_palindrome() {
    test_is_palindrome_base(is_palindrome);
}

#[test]
fn test_palindrome_classic() {
    test_is_palindrome_base(is_palindrome_classic);
}

#[cfg(test)]
fn test_is_palindrome_base<F>(is_palindrome: F) where F: Fn(&str) -> bool {
    assert!(is_palindrome(""));
    assert!(is_palindrome("a"));
    assert!(is_palindrome(".,,/.,/.,././.,=-=--"));
    assert!(is_palindrome("a,,,,,,,,,,,,,,,a"));
    assert!(is_palindrome("a,,,,,bb,,,,,,,,a"));
    assert!(is_palindrome("race car"));
    assert!(is_palindrome("racecar"));
    assert!(is_palindrome("raccar"));
    assert!(is_palindrome("A man, a plan, a canal, Panama!"));
    assert!(is_palindrome("Amor, Roma"));
    assert!(is_palindrome("stack cats"));
    assert!(is_palindrome("step on no pets"));
    assert!(is_palindrome("taco cat"));
    assert!(is_palindrome("put it up"));
    assert!(is_palindrome("Was it a car or a cat I saw?"));
    assert!(is_palindrome("No ‘x’ in Nixon"));

    // negative for good messure
    assert!(!is_palindrome("Not a palindrome"))
}
<|endoftext|>


<commit_before>// Zinc, the bare metal stack for rust.
// Copyright 2014 Vladimir "farcaller" Pouzanov <farcaller@gmail.com>
//
// 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,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#![feature(asm, lang_items, plugin, range_inclusive)]
#![feature(core_intrinsics, core_slice_ext, core_str_ext)]
#![allow(improper_ctypes)]
#![feature(const_fn)]
#![deny(missing_docs)]
#![no_std]

/*!
Zinc is an embedded stack for rust.

Zinc provides a complete embedded stack for application development in rust. It
is provided in a form of library, compiled for a specific MCU, that can be
linked into user's own applications.

### Supported architectures

ARM is the only architecture, supported at the moment. Zinc can be compiled for
"native" architecture as well, which should be useful only for testing the code,
though.

### Supported ARM MCUs

Two MCUs are supported at the moment, specifically

 * NXP LPC1768
 * ST STM32F407
 * ST STM32L152RCT6
 * Freescale MK20DX32
 * TI TM4C123GXL

The code is generic enough to support other MCUs in the same family (LPC17xx and
STM32F403/407).
*/
#![plugin(ioreg)]
#![feature(no_std)]

#[cfg(target_os = "none")]
extern crate rlibc;

#[macro_use] #[no_link] extern crate ioreg;
#[macro_use] extern crate volatile_cell;

#[cfg(test)] extern crate std;

#[cfg(test)] #[macro_use(expect)] extern crate expectest;

pub mod drivers;
pub mod hal;
pub mod util;
pub mod os;

/// Export a subset of `core` as `std.
///
/// This is exported as a temporary convenience as `rustc` still looks
/// for some items in the `std` namespace.
///
/// TODO(farcaller): clean up when fixed.
#[cfg(target_os = "none")]
pub mod std {
  pub use core::cmp;  // used for #[derive(Eq)] until fixed in rust.
  pub use core::option;
  pub use core::num;
  pub use core::marker;
}
<commit_msg>core_ext_str feature is gone<commit_after>// Zinc, the bare metal stack for rust.
// Copyright 2014 Vladimir "farcaller" Pouzanov <farcaller@gmail.com>
//
// 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,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#![feature(asm, lang_items, plugin, range_inclusive)]
#![feature(core_intrinsics, core_slice_ext)]
#![allow(improper_ctypes)]
#![feature(const_fn)]
#![deny(missing_docs)]
#![no_std]

/*!
Zinc is an embedded stack for rust.

Zinc provides a complete embedded stack for application development in rust. It
is provided in a form of library, compiled for a specific MCU, that can be
linked into user's own applications.

### Supported architectures

ARM is the only architecture, supported at the moment. Zinc can be compiled for
"native" architecture as well, which should be useful only for testing the code,
though.

### Supported ARM MCUs

Two MCUs are supported at the moment, specifically

 * NXP LPC1768
 * ST STM32F407
 * ST STM32L152RCT6
 * Freescale MK20DX32
 * TI TM4C123GXL

The code is generic enough to support other MCUs in the same family (LPC17xx and
STM32F403/407).
*/
#![plugin(ioreg)]
#![feature(no_std)]

#[cfg(target_os = "none")]
extern crate rlibc;

#[macro_use] #[no_link] extern crate ioreg;
#[macro_use] extern crate volatile_cell;

#[cfg(test)] extern crate std;

#[cfg(test)] #[macro_use(expect)] extern crate expectest;

pub mod drivers;
pub mod hal;
pub mod util;
pub mod os;

/// Export a subset of `core` as `std.
///
/// This is exported as a temporary convenience as `rustc` still looks
/// for some items in the `std` namespace.
///
/// TODO(farcaller): clean up when fixed.
#[cfg(target_os = "none")]
pub mod std {
  pub use core::cmp;  // used for #[derive(Eq)] until fixed in rust.
  pub use core::option;
  pub use core::num;
  pub use core::marker;
}
<|endoftext|>


<commit_before>extern crate itertools;

use itertools::Itertools;

use std::collections::HashMap;
use std::fmt;
use std::str::FromStr;

mod prim;

#[derive(Debug, Clone)]
pub enum EvalError {
    StackUnderflow,
    NotFound(String),
    TypeMismatch,
}

impl fmt::Display for EvalError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            EvalError::StackUnderflow => write!(f, "stack underflow"),
            EvalError::NotFound(ref name) => write!(f, "could not find `{}`", name),
            EvalError::TypeMismatch => write!(f, "type mismatch"),
        }
    }
}

pub type EvalResult = Result<Stack, EvalError>;

#[derive(Copy, Clone, Debug, PartialEq)]
pub enum Value {
    Bool(bool),
    Number(i32),
}

impl fmt::Display for Value {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            Value::Bool(x) => write!(f, "{}", x),
            Value::Number(x) => write!(f, "{}", x),
        }
    }
}

pub type PrimFn = fn(Stack, &Words) -> EvalResult;

// The type `fn(T, &U) -> V` does not implement `Debug`, `Clone`, or
// `PartialEq`, so to enable `#[derive(..)]` to work for `Term`, we implement
// these for a wrapper struct.
#[derive(Copy)]
pub struct Prim {
    f: PrimFn,
}

impl fmt::Debug for Prim {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "Prim(..)")
    }
}

impl Clone for Prim {
    fn clone(&self) -> Prim { Prim { f: self.f } }
}

impl PartialEq for Prim {
    fn eq(&self, other: &Prim) -> bool {
        &self.f as *const _ == &other.f as *const _
    }
}

#[derive(Clone, Debug, PartialEq)]
pub enum Term {
    Push(Value),
    Quote(Stack),
    Call(String),
    Prim(Prim),
}

impl Term {
    pub fn prim(f: PrimFn) -> Term {
        Term::Prim(Prim { f: f })
    }
}

impl fmt::Display for Term {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            Term::Push(value) => write!(f, "{}", value),
            Term::Quote(ref stack) if stack.terms.is_empty() => write!(f, "[ ]"),
            Term::Quote(ref stack) => write!(f, "[ {} ]", stack),
            Term::Call(ref name) => write!(f, "{}", name),
            Term::Prim(_) => write!(f, "<prim>"),
        }
    }
}

#[derive(Clone, Debug)]
pub struct Words {
    defs: HashMap<String, Term>,
}

impl Words {
    pub fn empty() -> Words {
        Words {
            defs: HashMap::new(),
        }
    }

    pub fn standard() -> Words {
        let mut words = Words::empty();

        words.define("words", Term::prim(prim::words)); // (A ~> A)

        words.define("dup", Term::prim(prim::dup)); // (A b -> A b b)
        words.define("pop", Term::prim(prim::pop)); // (A b -> A)
        words.define("swap", Term::prim(prim::swap)); // (A b c -> A c b)
        words.define("apply", Term::prim(prim::apply)); // (A (A -> B) -> B)
        words.define("quote", Term::prim(prim::quote)); // (A b -> A (C -> C b))
        words.define("compose", Term::prim(prim::compose)); // (A (B -> C) (C -> D) -> A (B -> D)))

        words.define("if", Term::prim(prim::if_)); // (A bool (A -> B) (A -> B) -> B)

        words.define("true", Term::Push(Value::Bool(true))); // (A -> A bool)
        words.define("false", Term::Push(Value::Bool(false))); // (A -> A bool)

        words.define("eq", Term::prim(prim::eq)); // (A num num -> A bool)
        words.define("and", Term::prim(prim::and)); // (A bool bool -> A bool)
        words.define("or", Term::prim(prim::or)); // (A bool bool -> A bool)
        words.define("not", Term::prim(prim::not)); // (A bool -> A bool)

        words.define("+", Term::prim(prim::add)); // (A num num -> A num)
        words.define("-", Term::prim(prim::sub)); // (A num num -> A num)
        words.define("*", Term::prim(prim::mul)); // (A num num -> A num)
        words.define("/", Term::prim(prim::div)); // (A num num -> A num)
        words.define("%", Term::prim(prim::rem)); // (A num num -> A num)

        words
    }

    pub fn define<S: Into<String>>(&mut self, name: S, x: Term) {
        self.defs.insert(name.into(), x);
    }

    pub fn lookup(&self, name: &str) -> Option<&Term> {
        self.defs.get(name)
    }
}

#[derive(Clone, Debug, PartialEq)]
pub struct Stack {
    terms: Vec<Term>,
}

impl Stack {
    pub fn new(terms: Vec<Term>) -> Stack {
        Stack { terms: terms }
    }

    pub fn empty() -> Stack {
        Stack::new(vec![])
    }

    fn push(mut self, term: Term) -> Stack {
        self.terms.push(term);
        self
    }

    fn pop(mut self) -> Result<(Stack, Term), EvalError> {
        match self.terms.pop() {
            Some(term) => Ok((self, term)),
            None => Err(EvalError::StackUnderflow),
        }
    }

    fn pop_bool(self) -> Result<(Stack, bool), EvalError> {
        let (stack, term) = try!(self.pop());
        match term {
            Term::Push(Value::Bool(x)) => Ok((stack, x)),
            _ => Err(EvalError::TypeMismatch),
        }
    }

    fn pop_number(self) -> Result<(Stack, i32), EvalError> {
        let (stack, term) = try!(self.pop());
        match term {
            Term::Push(Value::Number(x)) => Ok((stack, x)),
            _ => Err(EvalError::TypeMismatch),
        }
    }

    fn pop_quote(self) -> Result<(Stack, Stack), EvalError> {
        let (stack, term) = try!(self.pop());
        match term {
            Term::Quote(quoted) => Ok((stack, quoted)),
            _ => Err(EvalError::TypeMismatch),
        }
    }

    fn peek(&self) -> Result<&Term, EvalError> {
        match self.terms.last() {
            Some(term) => Ok(term),
            None => Err(EvalError::StackUnderflow),
        }
    }

    fn eval_name(self, words: &Words, name: String) -> EvalResult {
        match words.lookup(&name) {
            Some(term) => self.eval_term(words, term.clone()),
            None => Err(EvalError::NotFound(name)),
        }
    }

    fn eval_term(self, words: &Words, term: Term) -> EvalResult {
        match term {
            Term::Push(value) => Ok(self.push(Term::Push(value))),
            Term::Quote(stack) => Ok(self.push(Term::Quote(stack))),
            Term::Call(name) => self.eval_name(words, name),
            Term::Prim(Prim { f }) => f(self, words),
        }
    }

    fn eval_stack(mut self, words: &Words, quote: Stack) -> EvalResult {
        let mut terms = quote.terms.into_iter();
        while let Some(term) = terms.next() {
            self = try!(self.eval_term(words, term));
        }
        Ok(self)
    }
}

pub fn eval(stack: Stack, words: &Words) -> EvalResult {
    Stack::empty().eval_stack(words, stack)
}

impl FromStr for Stack {
    type Err = String;

    fn from_str(src: &str) -> Result<Stack, String> {
        fn parse_tokens<'a, I>(tokens: &mut I, in_quote: bool) -> Result<Stack, String> where
            I: Iterator<Item = &'a str>,
        {
            let mut terms = vec![];

            while let Some(token) = tokens.next() {
                match token {
                    "[" => {
                        terms.push(Term::Quote(
                            try!(parse_tokens(tokens, true))
                        ))
                    },
                    "]" => {
                        if in_quote {
                            return Ok(Stack::new(terms));
                        } else {
                            return Err("found unexpected `]`".to_string());
                        }
                    },
                    token => match token.parse() {
                        Ok(x) => terms.push(Term::Push(Value::Number(x))),
                        Err(_) => terms.push(Term::Call(token.to_string())),
                    },
                }
            }

            if in_quote {
                Err("expected closing `]`".to_string())
            } else {
                Ok(Stack::new(terms))
            }
        }

        parse_tokens(&mut src.split_whitespace(), false)
    }
}

impl fmt::Display for Stack {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{}", self.terms.iter().format(" ", |t, f| f(t)))
    }
}

#[cfg(test)]
mod tests {
    mod prim {
        mod eq {
            use Prim;
            use prim;

            #[test]
            fn test_same() {
                assert_eq!(Prim(prim::eq), Prim(prim::eq));
                assert_eq!(Prim(prim::add), Prim(prim::add));
            }

            #[test]
            fn test_different() {
                assert!(Prim(prim::eq) != Prim(prim::add));
                assert!(Prim(prim::add) != Prim(prim::eq));
            }
        }
    }

    mod stack {
        mod parse {
            use Stack;
            use Term::*;
            use Value::*;

            #[test]
            fn test_number() {
                assert_eq!("123".parse(), Ok(Stack::new(vec![Push(Number(123))])));
                assert_eq!(" 34 ".parse(), Ok(Stack::new(vec![Push(Number(34))])));
            }

            #[test]
            fn test_name() {
                assert_eq!("foo".parse(), Ok(Stack::new(vec![Call("foo".to_string())])));
                assert_eq!(" * ".parse(), Ok(Stack::new(vec![Call("*".to_string())])));
            }

            #[test]
            fn test_quote() {
                assert_eq!("[ foo ]".parse(),
                    Ok(Stack::new(vec![
                        Quote(Stack::new(vec![Call("foo".to_string())]))
                    ])));

                assert_eq!("[ 1 2 * + ]".parse(),
                    Ok(Stack::new(vec![
                        Quote(Stack::new(vec![
                            Push(Number(1)),
                            Push(Number(2)),
                            Call("*".to_string()),
                            Call("+".to_string()),
                        ])),
                    ])));
            }

            #[test]
            fn test_compose() {
                assert_eq!(" 1 2 [ foo ]  * +".parse(),
                    Ok(Stack::new(vec![
                        Push(Number(1)),
                        Push(Number(2)),
                        Quote(Stack::new(vec![Call("foo".to_string())])),
                        Call("*".to_string()),
                        Call("+".to_string()),
                    ])));
                assert_eq!(" 1 2 [ foo [ -23 bar ] ]  * +".parse(),
                    Ok(Stack::new(vec![
                        Push(Number(1)),
                        Push(Number(2)),
                        Quote(Stack::new(vec![
                            Call("foo".to_string()),
                            Quote(Stack::new(vec![
                                Push(Number(-23)),
                                Call("bar".to_string())
                            ]))
                        ])),
                        Call("*".to_string()),
                        Call("+".to_string()),
                    ])));
            }
        }
    }
}
<commit_msg>Inline eval_name method<commit_after>extern crate itertools;

use itertools::Itertools;

use std::collections::HashMap;
use std::fmt;
use std::str::FromStr;

mod prim;

#[derive(Debug, Clone)]
pub enum EvalError {
    StackUnderflow,
    NotFound(String),
    TypeMismatch,
}

impl fmt::Display for EvalError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            EvalError::StackUnderflow => write!(f, "stack underflow"),
            EvalError::NotFound(ref name) => write!(f, "could not find `{}`", name),
            EvalError::TypeMismatch => write!(f, "type mismatch"),
        }
    }
}

pub type EvalResult = Result<Stack, EvalError>;

#[derive(Copy, Clone, Debug, PartialEq)]
pub enum Value {
    Bool(bool),
    Number(i32),
}

impl fmt::Display for Value {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            Value::Bool(x) => write!(f, "{}", x),
            Value::Number(x) => write!(f, "{}", x),
        }
    }
}

pub type PrimFn = fn(Stack, &Words) -> EvalResult;

// The type `fn(T, &U) -> V` does not implement `Debug`, `Clone`, or
// `PartialEq`, so to enable `#[derive(..)]` to work for `Term`, we implement
// these for a wrapper struct.
#[derive(Copy)]
pub struct Prim {
    f: PrimFn,
}

impl fmt::Debug for Prim {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "Prim(..)")
    }
}

impl Clone for Prim {
    fn clone(&self) -> Prim { Prim { f: self.f } }
}

impl PartialEq for Prim {
    fn eq(&self, other: &Prim) -> bool {
        &self.f as *const _ == &other.f as *const _
    }
}

#[derive(Clone, Debug, PartialEq)]
pub enum Term {
    Push(Value),
    Quote(Stack),
    Call(String),
    Prim(Prim),
}

impl Term {
    pub fn prim(f: PrimFn) -> Term {
        Term::Prim(Prim { f: f })
    }
}

impl fmt::Display for Term {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            Term::Push(value) => write!(f, "{}", value),
            Term::Quote(ref stack) if stack.terms.is_empty() => write!(f, "[ ]"),
            Term::Quote(ref stack) => write!(f, "[ {} ]", stack),
            Term::Call(ref name) => write!(f, "{}", name),
            Term::Prim(_) => write!(f, "<prim>"),
        }
    }
}

#[derive(Clone, Debug)]
pub struct Words {
    defs: HashMap<String, Term>,
}

impl Words {
    pub fn empty() -> Words {
        Words {
            defs: HashMap::new(),
        }
    }

    pub fn standard() -> Words {
        let mut words = Words::empty();

        words.define("words", Term::prim(prim::words)); // (A ~> A)

        words.define("dup", Term::prim(prim::dup)); // (A b -> A b b)
        words.define("pop", Term::prim(prim::pop)); // (A b -> A)
        words.define("swap", Term::prim(prim::swap)); // (A b c -> A c b)
        words.define("apply", Term::prim(prim::apply)); // (A (A -> B) -> B)
        words.define("quote", Term::prim(prim::quote)); // (A b -> A (C -> C b))
        words.define("compose", Term::prim(prim::compose)); // (A (B -> C) (C -> D) -> A (B -> D)))

        words.define("if", Term::prim(prim::if_)); // (A bool (A -> B) (A -> B) -> B)

        words.define("true", Term::Push(Value::Bool(true))); // (A -> A bool)
        words.define("false", Term::Push(Value::Bool(false))); // (A -> A bool)

        words.define("eq", Term::prim(prim::eq)); // (A num num -> A bool)
        words.define("and", Term::prim(prim::and)); // (A bool bool -> A bool)
        words.define("or", Term::prim(prim::or)); // (A bool bool -> A bool)
        words.define("not", Term::prim(prim::not)); // (A bool -> A bool)

        words.define("+", Term::prim(prim::add)); // (A num num -> A num)
        words.define("-", Term::prim(prim::sub)); // (A num num -> A num)
        words.define("*", Term::prim(prim::mul)); // (A num num -> A num)
        words.define("/", Term::prim(prim::div)); // (A num num -> A num)
        words.define("%", Term::prim(prim::rem)); // (A num num -> A num)

        words
    }

    pub fn define<S: Into<String>>(&mut self, name: S, x: Term) {
        self.defs.insert(name.into(), x);
    }

    pub fn lookup(&self, name: &str) -> Option<&Term> {
        self.defs.get(name)
    }
}

#[derive(Clone, Debug, PartialEq)]
pub struct Stack {
    terms: Vec<Term>,
}

impl Stack {
    pub fn new(terms: Vec<Term>) -> Stack {
        Stack { terms: terms }
    }

    pub fn empty() -> Stack {
        Stack::new(vec![])
    }

    fn push(mut self, term: Term) -> Stack {
        self.terms.push(term);
        self
    }

    fn pop(mut self) -> Result<(Stack, Term), EvalError> {
        match self.terms.pop() {
            Some(term) => Ok((self, term)),
            None => Err(EvalError::StackUnderflow),
        }
    }

    fn pop_bool(self) -> Result<(Stack, bool), EvalError> {
        let (stack, term) = try!(self.pop());
        match term {
            Term::Push(Value::Bool(x)) => Ok((stack, x)),
            _ => Err(EvalError::TypeMismatch),
        }
    }

    fn pop_number(self) -> Result<(Stack, i32), EvalError> {
        let (stack, term) = try!(self.pop());
        match term {
            Term::Push(Value::Number(x)) => Ok((stack, x)),
            _ => Err(EvalError::TypeMismatch),
        }
    }

    fn pop_quote(self) -> Result<(Stack, Stack), EvalError> {
        let (stack, term) = try!(self.pop());
        match term {
            Term::Quote(quoted) => Ok((stack, quoted)),
            _ => Err(EvalError::TypeMismatch),
        }
    }

    fn peek(&self) -> Result<&Term, EvalError> {
        match self.terms.last() {
            Some(term) => Ok(term),
            None => Err(EvalError::StackUnderflow),
        }
    }

    fn eval_term(self, words: &Words, term: Term) -> EvalResult {
        match term {
            Term::Push(value) => Ok(self.push(Term::Push(value))),
            Term::Quote(stack) => Ok(self.push(Term::Quote(stack))),
            Term::Call(name) => {
                match words.lookup(&name) {
                    Some(term) => self.eval_term(words, term.clone()),
                    None => Err(EvalError::NotFound(name)),
                }
            },
            Term::Prim(Prim { f }) => f(self, words),
        }
    }

    fn eval_stack(mut self, words: &Words, quote: Stack) -> EvalResult {
        let mut terms = quote.terms.into_iter();
        while let Some(term) = terms.next() {
            self = try!(self.eval_term(words, term));
        }
        Ok(self)
    }
}

pub fn eval(stack: Stack, words: &Words) -> EvalResult {
    Stack::empty().eval_stack(words, stack)
}

impl FromStr for Stack {
    type Err = String;

    fn from_str(src: &str) -> Result<Stack, String> {
        fn parse_tokens<'a, I>(tokens: &mut I, in_quote: bool) -> Result<Stack, String> where
            I: Iterator<Item = &'a str>,
        {
            let mut terms = vec![];

            while let Some(token) = tokens.next() {
                match token {
                    "[" => {
                        terms.push(Term::Quote(
                            try!(parse_tokens(tokens, true))
                        ))
                    },
                    "]" => {
                        if in_quote {
                            return Ok(Stack::new(terms));
                        } else {
                            return Err("found unexpected `]`".to_string());
                        }
                    },
                    token => match token.parse() {
                        Ok(x) => terms.push(Term::Push(Value::Number(x))),
                        Err(_) => terms.push(Term::Call(token.to_string())),
                    },
                }
            }

            if in_quote {
                Err("expected closing `]`".to_string())
            } else {
                Ok(Stack::new(terms))
            }
        }

        parse_tokens(&mut src.split_whitespace(), false)
    }
}

impl fmt::Display for Stack {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{}", self.terms.iter().format(" ", |t, f| f(t)))
    }
}

#[cfg(test)]
mod tests {
    mod prim {
        mod eq {
            use Prim;
            use prim;

            #[test]
            fn test_same() {
                assert_eq!(Prim(prim::eq), Prim(prim::eq));
                assert_eq!(Prim(prim::add), Prim(prim::add));
            }

            #[test]
            fn test_different() {
                assert!(Prim(prim::eq) != Prim(prim::add));
                assert!(Prim(prim::add) != Prim(prim::eq));
            }
        }
    }

    mod stack {
        mod parse {
            use Stack;
            use Term::*;
            use Value::*;

            #[test]
            fn test_number() {
                assert_eq!("123".parse(), Ok(Stack::new(vec![Push(Number(123))])));
                assert_eq!(" 34 ".parse(), Ok(Stack::new(vec![Push(Number(34))])));
            }

            #[test]
            fn test_name() {
                assert_eq!("foo".parse(), Ok(Stack::new(vec![Call("foo".to_string())])));
                assert_eq!(" * ".parse(), Ok(Stack::new(vec![Call("*".to_string())])));
            }

            #[test]
            fn test_quote() {
                assert_eq!("[ foo ]".parse(),
                    Ok(Stack::new(vec![
                        Quote(Stack::new(vec![Call("foo".to_string())]))
                    ])));

                assert_eq!("[ 1 2 * + ]".parse(),
                    Ok(Stack::new(vec![
                        Quote(Stack::new(vec![
                            Push(Number(1)),
                            Push(Number(2)),
                            Call("*".to_string()),
                            Call("+".to_string()),
                        ])),
                    ])));
            }

            #[test]
            fn test_compose() {
                assert_eq!(" 1 2 [ foo ]  * +".parse(),
                    Ok(Stack::new(vec![
                        Push(Number(1)),
                        Push(Number(2)),
                        Quote(Stack::new(vec![Call("foo".to_string())])),
                        Call("*".to_string()),
                        Call("+".to_string()),
                    ])));
                assert_eq!(" 1 2 [ foo [ -23 bar ] ]  * +".parse(),
                    Ok(Stack::new(vec![
                        Push(Number(1)),
                        Push(Number(2)),
                        Quote(Stack::new(vec![
                            Call("foo".to_string()),
                            Quote(Stack::new(vec![
                                Push(Number(-23)),
                                Call("bar".to_string())
                            ]))
                        ])),
                        Call("*".to_string()),
                        Call("+".to_string()),
                    ])));
            }
        }
    }
}
<|endoftext|>