<commit_before>use libc::{c_char, c_uint};
use ffi::prelude::{LLVMBuilderRef, LLVMValueRef};
use ffi::{core, LLVMBuilder, LLVMRealPredicate, LLVMIntPredicate};
use cbox::{CSemiBox, DisposeRef};
use std::mem;
use std::ffi::CString;
use block::BasicBlock;
use context::Context;
use ty::Type;
use value::{Function, Value, Predicate};
use phi::PhiNode;

static NULL_NAME:[c_char; 1] = [0];

/// This provides a uniform API for creating instructions and inserting them into a basic block.
pub struct Builder;
native_ref!(&Builder = LLVMBuilderRef);
macro_rules! bin_op(
    ($name:ident, $func:ident) => (
        pub fn $name(&self, left: &Value, right: &Value) -> &Value {
            unsafe { core::$func(self.into(), left.into(), right.into(), NULL_NAME.as_ptr()) }.into()
        }
    );
    ($name:ident, $ifunc:ident, $ffunc:ident) => (
        pub fn $name(&self, left: &Value, right: &Value) -> &Value {
            let ty = left.get_type();
            unsafe {
                (if ty.is_integer() {
                    core::$ifunc
                } else {
                    core::$ffunc
                })(self.into(), left.into(), right.into(), NULL_NAME.as_ptr()).into()
            }
        }
    );
);
macro_rules! un_op(
    ($name:ident, $func:ident) => (
        pub fn $name(&self, value: &Value) -> &Value {
            unsafe { core::$func(self.into(), value.into(), NULL_NAME.as_ptr() as *const c_char) }.into()
        }
    );
);
impl Builder {
    /// Create a new builder in the context given.
    pub fn new(context: &Context) -> CSemiBox<Builder> {
        CSemiBox::new(unsafe { core::LLVMCreateBuilderInContext(context.into()) }.into())
    }
    /// Position the builder at the end of `block`.
    pub fn position_at_end(&self, block: &BasicBlock) {
        unsafe { core::LLVMPositionBuilderAtEnd(self.into(), block.into()) }
    }
    /// Position the builder at `instr` within `block`.
    pub fn position_at_instr(&self, block: &BasicBlock, instr: &Value) {
        unsafe { core::LLVMPositionBuilder(self.into(), block.into(), instr.into()) }
    }
    /// Get the block that the builder is currently positioned in.
    pub fn get_position(&self) -> &BasicBlock {
        unsafe { core::LLVMGetInsertBlock(self.into()) }.into()
    }
    /// Build an instruction that returns from the function with void.
    pub fn build_ret_void(&self) -> &Value {
        unsafe { core::LLVMBuildRetVoid(self.into()) }.into()
    }
    /// Build an instruction that returns from the function with `value`.
    pub fn build_ret(&self, value: &Value) -> &Value {
        unsafe { core::LLVMBuildRet(self.into(), value.into()) }.into()
    }
    /// Build an instruction that allocates an array with the element type `elem` and the size `size`.
    ///
    /// The size of this array will be the size of `elem` times `size`.
    pub fn build_array_alloca(&self, elem: &Type, size: &Value) -> &Value {
        unsafe { core::LLVMBuildArrayAlloca(self.into(), elem.into(), size.into(), NULL_NAME.as_ptr() as *const c_char) }.into()
    }
    /// Build an instruction that allocates a pointer to fit the size of `ty` then returns this pointer.
    ///
    /// Make sure to call `build_free` with the pointer value when you're done with it, or you're
    /// gonna have a bad time.
    pub fn build_alloca(&self, ty: &Type) -> &Value {
        unsafe { core::LLVMBuildAlloca(self.into(), ty.into(), NULL_NAME.as_ptr() as *const c_char) }.into()
    }
    /// Build an instruction that frees the `val`, which _MUST_ be a pointer that was returned
    /// from `build_alloca`.
    pub fn build_free(&self, val: &Value) -> &Value {
        unsafe { core::LLVMBuildFree(self.into(), val.into()) }.into()
    }
    /// Build an instruction that store the value `val` in the pointer `ptr`.
    pub fn build_store(&self, val: &Value, ptr: &Value) -> &Value {
        unsafe { core::LLVMBuildStore(self.into(), val.into(), ptr.into()) }.into()
    }
    /// Build an instruction that branches to the block `dest`.
    pub fn build_br(&self, dest: &BasicBlock) -> &Value {
        unsafe { core::LLVMBuildBr(self.into(), dest.into()).into() }
    }
    /// Build an instruction that branches to `if_block` if `cond` evaluates to true, and `else_block` otherwise.
    pub fn build_cond_br(&self, cond: &Value, if_block: &BasicBlock, else_block: Option<&BasicBlock>) -> &Value {
        unsafe { core::LLVMBuildCondBr(self.into(), cond.into(), if_block.into(), mem::transmute(else_block)).into() }
    }
    /// Build an instruction that calls the function `func` with the arguments `args`.
    ///
    /// This will return the return value of the function.
    pub fn build_call(&self, func: &Function, args: &[&Value]) -> &Value {
        unsafe {
            let call = core::LLVMBuildCall(self.into(), func.into(), args.as_ptr() as *mut LLVMValueRef, args.len() as c_uint, NULL_NAME.as_ptr());
            core::LLVMSetTailCall(call, 0);
            call.into()
        }
    }
    /// Build an instruction that calls the function `func` with the arguments `args`.
    ///
    /// This will return the return value of the function.
    pub fn build_tail_call(&self, func: &Function, args: &[&Value]) -> &Value {
        unsafe {
            let call = core::LLVMBuildCall(self.into(), func.into(), args.as_ptr() as *mut LLVMValueRef, args.len() as c_uint, NULL_NAME.as_ptr());
            core::LLVMSetTailCall(call, 1);
            call.into()
        }
    }
    /// Build an instruction that yields to `true_val` if `cond` is equal to `1`, and `false_val` otherwise.
    pub fn build_select(&self, cond: &Value, true_val: &Value, false_val: &Value) -> &Value {
        unsafe { core::LLVMBuildSelect(self.into(), cond.into(), true_val.into(), false_val.into(), NULL_NAME.as_ptr()).into() }
    }
    /// Build an instruction that casts a value into a certain type.
    pub fn build_bit_cast(&self, value: &Value, dest: &Type) -> &Value {
        unsafe { core::LLVMBuildBitCast(self.into(), value.into(), dest.into(), NULL_NAME.as_ptr()).into() }
    }
    /// Build an instruction that inserts a value into an aggregate type.
    pub fn build_insert_value(&self, agg: &Value, elem: &Value, index: usize) -> &Value {
        unsafe { core::LLVMBuildInsertValue(self.into(), agg.into(), elem.into(), index as c_uint, NULL_NAME.as_ptr()).into() }
    }
    /// Build an instruction that computes the address of a subelement of an aggregate data structure.
    ///
    /// Basically type-safe pointer arithmetic.
    pub fn build_gep(&self, pointer: &Value, indices: &[&Value]) -> &Value {
        unsafe { core::LLVMBuildInBoundsGEP(self.into(), pointer.into(), indices.as_ptr() as *mut LLVMValueRef, indices.len() as c_uint, NULL_NAME.as_ptr()).into() }
    }
    /// Build an instruction that runs whichever block matches the value, or `default` if none of them matched it.
    pub fn build_switch(&self, value: &Value, default: &BasicBlock, cases: &[(&Value, &BasicBlock)]) -> &Value {
        unsafe {
            let switch = core::LLVMBuildSwitch(self.into(), value.into(), default.into(), cases.len() as c_uint);
            for case in cases {
                core::LLVMAddCase(switch, case.0.into(), case.1.into());
            }
            switch.into()
        }
    }
    un_op!{build_load, LLVMBuildLoad}
    un_op!{build_neg, LLVMBuildNeg}
    un_op!{build_not, LLVMBuildNot}
    bin_op!{build_add, LLVMBuildAdd, LLVMBuildFAdd}
    bin_op!{build_sub, LLVMBuildSub, LLVMBuildFSub}
    bin_op!{build_mul, LLVMBuildMul, LLVMBuildFMul}
    bin_op!{build_div, LLVMBuildSDiv, LLVMBuildFDiv}
    bin_op!{build_shl, LLVMBuildShl}
    bin_op!{build_ashr, LLVMBuildAShr}
    bin_op!{build_and, LLVMBuildAnd}
    bin_op!{build_or, LLVMBuildOr}
    /// Build an instruction to compare two values with the predicate
    pub fn build_cmp(&self, a: &Value, b: &Value, pred: Predicate) -> &Value {
        let (at, bt) = (a.get_type(), b.get_type());
        assert_eq!(at, bt);
        if at.is_integer() {
            let pred = match pred {
                Predicate::Equal => LLVMIntPredicate::LLVMIntEQ,
                Predicate::NotEqual => LLVMIntPredicate::LLVMIntNE,
                Predicate::GreaterThan => LLVMIntPredicate::LLVMIntSGT,
                Predicate::GreaterThanOrEqual => LLVMIntPredicate::LLVMIntSGE,
                Predicate::LessThan => LLVMIntPredicate::LLVMIntSLT,
                Predicate::LessThanOrEqual => LLVMIntPredicate::LLVMIntSLE
            };
            unsafe { core::LLVMBuildICmp(self.into(), pred, a.into(), b.into(), NULL_NAME.as_ptr()) }.into()
        } else if at.is_float() {
            let pred = match pred {
                Predicate::Equal => LLVMRealPredicate::LLVMRealOEQ,
                Predicate::NotEqual => LLVMRealPredicate::LLVMRealONE,
                Predicate::GreaterThan => LLVMRealPredicate::LLVMRealOGT,
                Predicate::GreaterThanOrEqual => LLVMRealPredicate::LLVMRealOGE,
                Predicate::LessThan => LLVMRealPredicate::LLVMRealOLT,
                Predicate::LessThanOrEqual => LLVMRealPredicate::LLVMRealOLE
            };
            unsafe { core::LLVMBuildFCmp(self.into(), pred, a.into(), b.into(), NULL_NAME.as_ptr()) }.into()
        } else {
            panic!("expected numbers, got {:?}", at)
        }
    }

    /// Build an instruction to select a value depending on the predecessor of the current block.
    pub fn build_phi(&self, ty: &Type, name: &str) -> &PhiNode {
        unsafe { core::LLVMBuildPhi(self.into(), ty.into(), CString::new(name).unwrap().as_ptr()) }.into()
    }
}

impl DisposeRef for Builder {
    type RefTo = LLVMBuilder;
    #[inline(always)]
    unsafe fn dispose(ptr: LLVMBuilderRef) {
        core::LLVMDisposeBuilder(ptr)
    }
}
<commit_msg>Add support for the XOR instruction<commit_after>use libc::{c_char, c_uint};
use ffi::prelude::{LLVMBuilderRef, LLVMValueRef};
use ffi::{core, LLVMBuilder, LLVMRealPredicate, LLVMIntPredicate};
use cbox::{CSemiBox, DisposeRef};
use std::mem;
use std::ffi::CString;
use block::BasicBlock;
use context::Context;
use ty::Type;
use value::{Function, Value, Predicate};
use phi::PhiNode;

static NULL_NAME:[c_char; 1] = [0];

/// This provides a uniform API for creating instructions and inserting them into a basic block.
pub struct Builder;
native_ref!(&Builder = LLVMBuilderRef);
macro_rules! bin_op(
    ($name:ident, $func:ident) => (
        pub fn $name(&self, left: &Value, right: &Value) -> &Value {
            unsafe { core::$func(self.into(), left.into(), right.into(), NULL_NAME.as_ptr()) }.into()
        }
    );
    ($name:ident, $ifunc:ident, $ffunc:ident) => (
        pub fn $name(&self, left: &Value, right: &Value) -> &Value {
            let ty = left.get_type();
            unsafe {
                (if ty.is_integer() {
                    core::$ifunc
                } else {
                    core::$ffunc
                })(self.into(), left.into(), right.into(), NULL_NAME.as_ptr()).into()
            }
        }
    );
);
macro_rules! un_op(
    ($name:ident, $func:ident) => (
        pub fn $name(&self, value: &Value) -> &Value {
            unsafe { core::$func(self.into(), value.into(), NULL_NAME.as_ptr() as *const c_char) }.into()
        }
    );
);
impl Builder {
    /// Create a new builder in the context given.
    pub fn new(context: &Context) -> CSemiBox<Builder> {
        CSemiBox::new(unsafe { core::LLVMCreateBuilderInContext(context.into()) }.into())
    }
    /// Position the builder at the end of `block`.
    pub fn position_at_end(&self, block: &BasicBlock) {
        unsafe { core::LLVMPositionBuilderAtEnd(self.into(), block.into()) }
    }
    /// Position the builder at `instr` within `block`.
    pub fn position_at_instr(&self, block: &BasicBlock, instr: &Value) {
        unsafe { core::LLVMPositionBuilder(self.into(), block.into(), instr.into()) }
    }
    /// Get the block that the builder is currently positioned in.
    pub fn get_position(&self) -> &BasicBlock {
        unsafe { core::LLVMGetInsertBlock(self.into()) }.into()
    }
    /// Build an instruction that returns from the function with void.
    pub fn build_ret_void(&self) -> &Value {
        unsafe { core::LLVMBuildRetVoid(self.into()) }.into()
    }
    /// Build an instruction that returns from the function with `value`.
    pub fn build_ret(&self, value: &Value) -> &Value {
        unsafe { core::LLVMBuildRet(self.into(), value.into()) }.into()
    }
    /// Build an instruction that allocates an array with the element type `elem` and the size `size`.
    ///
    /// The size of this array will be the size of `elem` times `size`.
    pub fn build_array_alloca(&self, elem: &Type, size: &Value) -> &Value {
        unsafe { core::LLVMBuildArrayAlloca(self.into(), elem.into(), size.into(), NULL_NAME.as_ptr() as *const c_char) }.into()
    }
    /// Build an instruction that allocates a pointer to fit the size of `ty` then returns this pointer.
    ///
    /// Make sure to call `build_free` with the pointer value when you're done with it, or you're
    /// gonna have a bad time.
    pub fn build_alloca(&self, ty: &Type) -> &Value {
        unsafe { core::LLVMBuildAlloca(self.into(), ty.into(), NULL_NAME.as_ptr() as *const c_char) }.into()
    }
    /// Build an instruction that frees the `val`, which _MUST_ be a pointer that was returned
    /// from `build_alloca`.
    pub fn build_free(&self, val: &Value) -> &Value {
        unsafe { core::LLVMBuildFree(self.into(), val.into()) }.into()
    }
    /// Build an instruction that store the value `val` in the pointer `ptr`.
    pub fn build_store(&self, val: &Value, ptr: &Value) -> &Value {
        unsafe { core::LLVMBuildStore(self.into(), val.into(), ptr.into()) }.into()
    }
    /// Build an instruction that branches to the block `dest`.
    pub fn build_br(&self, dest: &BasicBlock) -> &Value {
        unsafe { core::LLVMBuildBr(self.into(), dest.into()).into() }
    }
    /// Build an instruction that branches to `if_block` if `cond` evaluates to true, and `else_block` otherwise.
    pub fn build_cond_br(&self, cond: &Value, if_block: &BasicBlock, else_block: Option<&BasicBlock>) -> &Value {
        unsafe { core::LLVMBuildCondBr(self.into(), cond.into(), if_block.into(), mem::transmute(else_block)).into() }
    }
    /// Build an instruction that calls the function `func` with the arguments `args`.
    ///
    /// This will return the return value of the function.
    pub fn build_call(&self, func: &Function, args: &[&Value]) -> &Value {
        unsafe {
            let call = core::LLVMBuildCall(self.into(), func.into(), args.as_ptr() as *mut LLVMValueRef, args.len() as c_uint, NULL_NAME.as_ptr());
            core::LLVMSetTailCall(call, 0);
            call.into()
        }
    }
    /// Build an instruction that calls the function `func` with the arguments `args`.
    ///
    /// This will return the return value of the function.
    pub fn build_tail_call(&self, func: &Function, args: &[&Value]) -> &Value {
        unsafe {
            let call = core::LLVMBuildCall(self.into(), func.into(), args.as_ptr() as *mut LLVMValueRef, args.len() as c_uint, NULL_NAME.as_ptr());
            core::LLVMSetTailCall(call, 1);
            call.into()
        }
    }
    /// Build an instruction that yields to `true_val` if `cond` is equal to `1`, and `false_val` otherwise.
    pub fn build_select(&self, cond: &Value, true_val: &Value, false_val: &Value) -> &Value {
        unsafe { core::LLVMBuildSelect(self.into(), cond.into(), true_val.into(), false_val.into(), NULL_NAME.as_ptr()).into() }
    }
    /// Build an instruction that casts a value into a certain type.
    pub fn build_bit_cast(&self, value: &Value, dest: &Type) -> &Value {
        unsafe { core::LLVMBuildBitCast(self.into(), value.into(), dest.into(), NULL_NAME.as_ptr()).into() }
    }
    /// Build an instruction that inserts a value into an aggregate type.
    pub fn build_insert_value(&self, agg: &Value, elem: &Value, index: usize) -> &Value {
        unsafe { core::LLVMBuildInsertValue(self.into(), agg.into(), elem.into(), index as c_uint, NULL_NAME.as_ptr()).into() }
    }
    /// Build an instruction that computes the address of a subelement of an aggregate data structure.
    ///
    /// Basically type-safe pointer arithmetic.
    pub fn build_gep(&self, pointer: &Value, indices: &[&Value]) -> &Value {
        unsafe { core::LLVMBuildInBoundsGEP(self.into(), pointer.into(), indices.as_ptr() as *mut LLVMValueRef, indices.len() as c_uint, NULL_NAME.as_ptr()).into() }
    }
    /// Build an instruction that runs whichever block matches the value, or `default` if none of them matched it.
    pub fn build_switch(&self, value: &Value, default: &BasicBlock, cases: &[(&Value, &BasicBlock)]) -> &Value {
        unsafe {
            let switch = core::LLVMBuildSwitch(self.into(), value.into(), default.into(), cases.len() as c_uint);
            for case in cases {
                core::LLVMAddCase(switch, case.0.into(), case.1.into());
            }
            switch.into()
        }
    }
    un_op!{build_load, LLVMBuildLoad}
    un_op!{build_neg, LLVMBuildNeg}
    un_op!{build_not, LLVMBuildNot}
    bin_op!{build_add, LLVMBuildAdd, LLVMBuildFAdd}
    bin_op!{build_sub, LLVMBuildSub, LLVMBuildFSub}
    bin_op!{build_mul, LLVMBuildMul, LLVMBuildFMul}
    bin_op!{build_div, LLVMBuildSDiv, LLVMBuildFDiv}
    bin_op!{build_shl, LLVMBuildShl}
    bin_op!{build_ashr, LLVMBuildAShr}
    bin_op!{build_and, LLVMBuildAnd}
    bin_op!{build_or, LLVMBuildOr}
    bin_op!{build_xor, LLVMBuildXor}
    /// Build an instruction to compare two values with the predicate
    pub fn build_cmp(&self, a: &Value, b: &Value, pred: Predicate) -> &Value {
        let (at, bt) = (a.get_type(), b.get_type());
        assert_eq!(at, bt);
        if at.is_integer() {
            let pred = match pred {
                Predicate::Equal => LLVMIntPredicate::LLVMIntEQ,
                Predicate::NotEqual => LLVMIntPredicate::LLVMIntNE,
                Predicate::GreaterThan => LLVMIntPredicate::LLVMIntSGT,
                Predicate::GreaterThanOrEqual => LLVMIntPredicate::LLVMIntSGE,
                Predicate::LessThan => LLVMIntPredicate::LLVMIntSLT,
                Predicate::LessThanOrEqual => LLVMIntPredicate::LLVMIntSLE
            };
            unsafe { core::LLVMBuildICmp(self.into(), pred, a.into(), b.into(), NULL_NAME.as_ptr()) }.into()
        } else if at.is_float() {
            let pred = match pred {
                Predicate::Equal => LLVMRealPredicate::LLVMRealOEQ,
                Predicate::NotEqual => LLVMRealPredicate::LLVMRealONE,
                Predicate::GreaterThan => LLVMRealPredicate::LLVMRealOGT,
                Predicate::GreaterThanOrEqual => LLVMRealPredicate::LLVMRealOGE,
                Predicate::LessThan => LLVMRealPredicate::LLVMRealOLT,
                Predicate::LessThanOrEqual => LLVMRealPredicate::LLVMRealOLE
            };
            unsafe { core::LLVMBuildFCmp(self.into(), pred, a.into(), b.into(), NULL_NAME.as_ptr()) }.into()
        } else {
            panic!("expected numbers, got {:?}", at)
        }
    }

    /// Build an instruction to select a value depending on the predecessor of the current block.
    pub fn build_phi(&self, ty: &Type, name: &str) -> &PhiNode {
        unsafe { core::LLVMBuildPhi(self.into(), ty.into(), CString::new(name).unwrap().as_ptr()) }.into()
    }
}

impl DisposeRef for Builder {
    type RefTo = LLVMBuilder;
    #[inline(always)]
    unsafe fn dispose(ptr: LLVMBuilderRef) {
        core::LLVMDisposeBuilder(ptr)
    }
}
<|endoftext|>


<commit_before>//! Function names.
//!
//! The name of a function doesn't have any meaning to Cretonne which compiles functions
//! independently.

use std::fmt::{self, Write};
use std::ascii::AsciiExt;

/// The name of a function can be any sequence of bytes.
///
/// Function names are mostly a testing and debugging tool.
/// In particular, `.cton` files use function names to identify functions.
#[derive(Debug, Clone, PartialEq, Eq, Default)]
pub struct FunctionName(NameRepr);

impl FunctionName {
    /// Creates a new function name from a sequence of bytes.
    ///
    /// # Examples
    ///
    /// ```rust
    /// # use cretonne::ir::FunctionName;
    /// // Create `FunctionName` from a string.
    /// let name = FunctionName::new("hello");
    /// assert_eq!(name.to_string(), "%hello");
    ///
    /// // Create `FunctionName` from a sequence of bytes.
    /// let bytes: &[u8] = &[10, 9, 8];
    /// let name = FunctionName::new(bytes);
    /// assert_eq!(name.to_string(), "#0a0908");
    /// ```
    pub fn new<T>(v: T) -> FunctionName
    where
        T: Into<Vec<u8>>,
    {
        let vec = v.into();
        if vec.len() <= NAME_LENGTH_THRESHOLD {
            let mut bytes = [0u8; NAME_LENGTH_THRESHOLD];
            for (i, &byte) in vec.iter().enumerate() {
                bytes[i] = byte;
            }
            FunctionName(NameRepr::Short {
                length: vec.len() as u8,
                bytes: bytes,
            })
        } else {
            FunctionName(NameRepr::Long(vec))
        }
    }
}

/// Tries to interpret bytes as ASCII alphanumerical characters and `_`.
fn try_as_name(bytes: &[u8]) -> Option<String> {
    let mut name = String::with_capacity(bytes.len());
    for c in bytes.iter().map(|&b| b as char) {
        if c.is_ascii() && c.is_alphanumeric() || c == '_' {
            name.push(c);
        } else {
            return None;
        }
    }
    Some(name)
}

const NAME_LENGTH_THRESHOLD: usize = 22;

#[derive(Debug, Clone, PartialEq, Eq)]
enum NameRepr {
    Short {
        length: u8,
        bytes: [u8; NAME_LENGTH_THRESHOLD],
    },
    Long(Vec<u8>),
}

impl AsRef<[u8]> for NameRepr {
    fn as_ref(&self) -> &[u8] {
        match *self {
            NameRepr::Short { length, ref bytes } => &bytes[0..length as usize],
            NameRepr::Long(ref vec) => vec.as_ref(),
        }
    }
}

impl AsRef<[u8]> for FunctionName {
    fn as_ref(&self) -> &[u8] {
        self.0.as_ref()
    }
}

impl Default for NameRepr {
    fn default() -> Self {
        NameRepr::Short {
            length: 0,
            bytes: [0; NAME_LENGTH_THRESHOLD],
        }
    }
}

impl fmt::Display for FunctionName {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        if let Some(name) = try_as_name(self.0.as_ref()) {
            write!(f, "%{}", name)
        } else {
            f.write_char('#')?;
            for byte in self.0.as_ref() {
                write!(f, "{:02x}", byte)?;
            }
            Ok(())
        }
    }
}

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

    #[test]
    fn displaying() {
        assert_eq!(FunctionName::new("").to_string(), "%");
        assert_eq!(FunctionName::new("x").to_string(), "%x");
        assert_eq!(FunctionName::new("x_1").to_string(), "%x_1");
        assert_eq!(FunctionName::new(" ").to_string(), "#20");
        assert_eq!(
            FunctionName::new("кретон").to_string(),
            "#d0bad180d0b5d182d0bed0bd"
        );
        assert_eq!(
            FunctionName::new("印花棉布").to_string(),
            "#e58db0e88ab1e6a389e5b883"
        );
        assert_eq!(
            FunctionName::new(vec![0, 1, 2, 3, 4, 5]).to_string(),
            "#000102030405"
        );
    }
}
<commit_msg>Clarify FunctionName's role in its comment.<commit_after>//! Function names.
//!
//! The name of a function doesn't have any meaning to Cretonne which compiles functions
//! independently.

use std::fmt::{self, Write};
use std::ascii::AsciiExt;

/// The name of a function can be any sequence of bytes.
///
/// Function names are primarily used as keys by code using Cretonne to map
/// from a cretonne::ir::Function to additional associated data.
///
/// Function names can also serve as a primitive testing and debugging tool.
/// In particular, many `.cton` test files use function names to identify
/// functions.
#[derive(Debug, Clone, PartialEq, Eq, Default)]
pub struct FunctionName(NameRepr);

impl FunctionName {
    /// Creates a new function name from a sequence of bytes.
    ///
    /// # Examples
    ///
    /// ```rust
    /// # use cretonne::ir::FunctionName;
    /// // Create `FunctionName` from a string.
    /// let name = FunctionName::new("hello");
    /// assert_eq!(name.to_string(), "%hello");
    ///
    /// // Create `FunctionName` from a sequence of bytes.
    /// let bytes: &[u8] = &[10, 9, 8];
    /// let name = FunctionName::new(bytes);
    /// assert_eq!(name.to_string(), "#0a0908");
    /// ```
    pub fn new<T>(v: T) -> FunctionName
    where
        T: Into<Vec<u8>>,
    {
        let vec = v.into();
        if vec.len() <= NAME_LENGTH_THRESHOLD {
            let mut bytes = [0u8; NAME_LENGTH_THRESHOLD];
            for (i, &byte) in vec.iter().enumerate() {
                bytes[i] = byte;
            }
            FunctionName(NameRepr::Short {
                length: vec.len() as u8,
                bytes: bytes,
            })
        } else {
            FunctionName(NameRepr::Long(vec))
        }
    }
}

/// Tries to interpret bytes as ASCII alphanumerical characters and `_`.
fn try_as_name(bytes: &[u8]) -> Option<String> {
    let mut name = String::with_capacity(bytes.len());
    for c in bytes.iter().map(|&b| b as char) {
        if c.is_ascii() && c.is_alphanumeric() || c == '_' {
            name.push(c);
        } else {
            return None;
        }
    }
    Some(name)
}

const NAME_LENGTH_THRESHOLD: usize = 22;

#[derive(Debug, Clone, PartialEq, Eq)]
enum NameRepr {
    Short {
        length: u8,
        bytes: [u8; NAME_LENGTH_THRESHOLD],
    },
    Long(Vec<u8>),
}

impl AsRef<[u8]> for NameRepr {
    fn as_ref(&self) -> &[u8] {
        match *self {
            NameRepr::Short { length, ref bytes } => &bytes[0..length as usize],
            NameRepr::Long(ref vec) => vec.as_ref(),
        }
    }
}

impl AsRef<[u8]> for FunctionName {
    fn as_ref(&self) -> &[u8] {
        self.0.as_ref()
    }
}

impl Default for NameRepr {
    fn default() -> Self {
        NameRepr::Short {
            length: 0,
            bytes: [0; NAME_LENGTH_THRESHOLD],
        }
    }
}

impl fmt::Display for FunctionName {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        if let Some(name) = try_as_name(self.0.as_ref()) {
            write!(f, "%{}", name)
        } else {
            f.write_char('#')?;
            for byte in self.0.as_ref() {
                write!(f, "{:02x}", byte)?;
            }
            Ok(())
        }
    }
}

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

    #[test]
    fn displaying() {
        assert_eq!(FunctionName::new("").to_string(), "%");
        assert_eq!(FunctionName::new("x").to_string(), "%x");
        assert_eq!(FunctionName::new("x_1").to_string(), "%x_1");
        assert_eq!(FunctionName::new(" ").to_string(), "#20");
        assert_eq!(
            FunctionName::new("кретон").to_string(),
            "#d0bad180d0b5d182d0bed0bd"
        );
        assert_eq!(
            FunctionName::new("印花棉布").to_string(),
            "#e58db0e88ab1e6a389e5b883"
        );
        assert_eq!(
            FunctionName::new(vec![0, 1, 2, 3, 4, 5]).to_string(),
            "#000102030405"
        );
    }
}
<|endoftext|>


<commit_before>use super::*;
use redox::*;

impl Editor {
    /// Redraw the window
    pub fn redraw(&mut self) {
        // TODO: Only draw when relevant for the window
        let x = self.x();
        let y = self.y();
        // Redraw window
        self.window.set(Color::BLACK);

        self.window.rect(8 * (x - self.scroll_y) as isize,
                         16 * (y - self.scroll_x) as isize,
                         8,
                         16,
                         Color::WHITE);

        let mut string = false;

        for (y, row) in self.text.iter().enumerate() {
            for (x, &c) in row.iter().enumerate() {
                let color = match c {
                    '\'' | '"' => {
                        string = !string;
                        (226, 225, 167) //(167, 222, 156)
                    },
                    _ if string => (226, 225, 167), //(167, 222, 156)
                    '!' | '@' | '#' | '$' | '%' | '^' | '&' | '|' | '*' | '+' | '-' | '/' | ':' | '=' | '<' | '>' => (198, 83, 83), //(228, 190, 175), //(194, 106, 71),
                    '.' | ',' => (241, 213, 226),
                    '(' | ')' | '[' | ']' | '{' | '}' => (164, 212, 125), //(195, 139, 75),
                    '0' | '1' | '2' | '3' | '4' | '5' | '6' | '7' | '8' | '9' => (209, 209, 177),
                    _ => (255, 255, 255),
                };

                if self.x() == x && self.y() == y {
                    self.window.char(8 * (x - self.scroll_y) as isize,
                                     16 * (y - self.scroll_x) as isize,
                                     c,
                                     Color::rgb(color.0 / 3, color.1 / 3, color.2 / 3));
                } else {
                    self.window.char(8 * (x - self.scroll_y) as isize,
                                     16 * (y - self.scroll_x) as isize,
                                     c,
                                     Color::rgb(color.0, color.1, color.2));
                }
            }
        }
        let h = self.window.height();
        let w = self.window.width();
        self.window.rect(0, h as isize - 18, w, 18, Color::rgba(74, 74, 74, 255));

        for (n, c) in (if self.status_bar.mode.len() > w / (8 * 4) {
            self.status_bar.mode.chars().take(w / (8 * 4) - 5).chain(vec!['.', '.', '.']).collect::<Vec<_>>()
        } else {
            self.status_bar.mode.chars().collect()
        }).into_iter().enumerate() {

            self.window.char(n as isize * 8, h as isize - 16 - 1, if c == '\t' { ' ' } else { c }, Color::RED);
        }

        self.window.sync();
    }
}

/// The statubar (showing various info about the current state of the editor)
pub struct StatusBar {
    /// The current mode
    pub mode: String,
    /// The cureent char
    pub file: String,
    /// The current command
    pub cmd: String,
    /// A message (such as an error or other info to the user)
    pub msg: String,
}

impl StatusBar {
    /// Create new status bar
    pub fn new() -> Self {
        StatusBar {
            mode: "Normal".to_string(),
            file: String::new(),
            cmd: String::new(),
            msg: String::new(),
        }
    }
}
<commit_msg>Change statusbar color<commit_after>use super::*;
use redox::*;

impl Editor {
    /// Redraw the window
    pub fn redraw(&mut self) {
        // TODO: Only draw when relevant for the window
        let x = self.x();
        let y = self.y();
        // Redraw window
        self.window.set(Color::BLACK);

        self.window.rect(8 * (x - self.scroll_y) as isize,
                         16 * (y - self.scroll_x) as isize,
                         8,
                         16,
                         Color::WHITE);

        let mut string = false;

        for (y, row) in self.text.iter().enumerate() {
            for (x, &c) in row.iter().enumerate() {
                // TODO: Move outta here
                let color = match c {
                    '\'' | '"' => {
                        string = !string;
                        (226, 225, 167) //(167, 222, 156)
                    },
                    _ if string => (226, 225, 167), //(167, 222, 156)
                    '!' | '@' | '#' | '$' | '%' | '^' | '&' | '|' | '*' | '+' | '-' | '/' | ':' | '=' | '<' | '>' => (198, 83, 83), //(228, 190, 175), //(194, 106, 71),
                    '.' | ',' => (241, 213, 226),
                    '(' | ')' | '[' | ']' | '{' | '}' => (164, 212, 125), //(195, 139, 75),
                    '0' | '1' | '2' | '3' | '4' | '5' | '6' | '7' | '8' | '9' => (209, 209, 177),
                    _ => (255, 255, 255),
                };

                if self.x() == x && self.y() == y {
                    self.window.char(8 * (x - self.scroll_y) as isize,
                                     16 * (y - self.scroll_x) as isize,
                                     c,
                                     Color::rgb(color.0 / 3, color.1 / 3, color.2 / 3));
                } else {
                    self.window.char(8 * (x - self.scroll_y) as isize,
                                     16 * (y - self.scroll_x) as isize,
                                     c,
                                     Color::rgb(color.0, color.1, color.2));
                }
            }
        }
        let h = self.window.height();
        let w = self.window.width();
        self.window.rect(0, h as isize - 18, w, 18, Color::rgba(74, 74, 74, 255));

        for (n, c) in (if self.status_bar.mode.len() > w / (8 * 4) {
            self.status_bar.mode.chars().take(w / (8 * 4) - 5).chain(vec!['.', '.', '.']).collect::<Vec<_>>()
        } else {
            self.status_bar.mode.chars().collect()
        }).into_iter().enumerate() {

            self.window.char(n as isize * 8, h as isize - 16 - 1, if c == '\t' { ' ' } else { c }, Color::WHITE);
        }

        self.window.sync();
    }
}

/// The statubar (showing various info about the current state of the editor)
pub struct StatusBar {
    /// The current mode
    pub mode: String,
    /// The cureent char
    pub file: String,
    /// The current command
    pub cmd: String,
    /// A message (such as an error or other info to the user)
    pub msg: String,
}

impl StatusBar {
    /// Create new status bar
    pub fn new() -> Self {
        StatusBar {
            mode: "Normal".to_string(),
            file: String::new(),
            cmd: String::new(),
            msg: String::new(),
        }
    }
}
<|endoftext|>


<commit_before>//! Intel Instruction Set Architectures.

pub mod settings;
mod abi;
mod binemit;
mod enc_tables;
mod registers;

use binemit::{CodeSink, MemoryCodeSink, emit_function};
use super::super::settings as shared_settings;
use isa::enc_tables::{self as shared_enc_tables, lookup_enclist, Encodings};
use isa::Builder as IsaBuilder;
use isa::{TargetIsa, RegInfo, RegClass, EncInfo};
use ir;
use regalloc;

#[allow(dead_code)]
struct Isa {
    shared_flags: shared_settings::Flags,
    isa_flags: settings::Flags,
    cpumode: &'static [shared_enc_tables::Level1Entry<u16>],
}

/// Get an ISA builder for creating Intel targets.
pub fn isa_builder() -> IsaBuilder {
    IsaBuilder {
        setup: settings::builder(),
        constructor: isa_constructor,
    }
}

fn isa_constructor(
    shared_flags: shared_settings::Flags,
    builder: &shared_settings::Builder,
) -> Box<TargetIsa> {
    let level1 = if shared_flags.is_64bit() {
        &enc_tables::LEVEL1_I64[..]
    } else {
        &enc_tables::LEVEL1_I32[..]
    };
    Box::new(Isa {
        isa_flags: settings::Flags::new(&shared_flags, builder),
        shared_flags,
        cpumode: level1,
    })
}

impl TargetIsa for Isa {
    fn name(&self) -> &'static str {
        "intel"
    }

    fn flags(&self) -> &shared_settings::Flags {
        &self.shared_flags
    }

    fn register_info(&self) -> RegInfo {
        registers::INFO.clone()
    }

    fn encoding_info(&self) -> EncInfo {
        enc_tables::INFO.clone()
    }

    fn legal_encodings<'a>(
        &'a self,
        dfg: &'a ir::DataFlowGraph,
        inst: &'a ir::InstructionData,
        ctrl_typevar: ir::Type,
    ) -> Encodings<'a> {
        lookup_enclist(
            ctrl_typevar,
            inst,
            dfg,
            self.cpumode,
            &enc_tables::LEVEL2[..],
            &enc_tables::ENCLISTS[..],
            &enc_tables::LEGALIZE_ACTIONS[..],
            &enc_tables::RECIPE_PREDICATES[..],
            &enc_tables::INST_PREDICATES[..],
            self.isa_flags.predicate_view(),
        )
    }

    fn legalize_signature(&self, sig: &mut ir::Signature, current: bool) {
        abi::legalize_signature(sig, &self.shared_flags, current)
    }

    fn regclass_for_abi_type(&self, ty: ir::Type) -> RegClass {
        abi::regclass_for_abi_type(ty)
    }

    fn allocatable_registers(&self, func: &ir::Function) -> regalloc::AllocatableSet {
        abi::allocatable_registers(func, &self.shared_flags)
    }

    fn emit_inst(
        &self,
        func: &ir::Function,
        inst: ir::Inst,
        divert: &mut regalloc::RegDiversions,
        sink: &mut CodeSink,
    ) {
        binemit::emit_inst(func, inst, divert, sink)
    }

    fn emit_function(&self, func: &ir::Function, sink: &mut MemoryCodeSink) {
        emit_function(func, binemit::emit_inst, sink)
    }

    fn reloc_names(&self) -> &'static [&'static str] {
        &binemit::RELOC_NAMES
    }
}
<commit_msg>Sketch of prologue generation<commit_after>//! Intel Instruction Set Architectures.

pub mod settings;
mod abi;
mod binemit;
mod enc_tables;
mod registers;

use binemit::{CodeSink, MemoryCodeSink, emit_function};
use super::super::settings as shared_settings;
use isa::enc_tables::{self as shared_enc_tables, lookup_enclist, Encodings};
use isa::Builder as IsaBuilder;
use isa::{TargetIsa, RegInfo, RegClass, EncInfo, RegUnit};
use self::registers::RU;
use ir;
use regalloc;
use result;
use ir::InstBuilder;
use legalizer;

#[allow(dead_code)]
struct Isa {
    shared_flags: shared_settings::Flags,
    isa_flags: settings::Flags,
    cpumode: &'static [shared_enc_tables::Level1Entry<u16>],
}

/// Get an ISA builder for creating Intel targets.
pub fn isa_builder() -> IsaBuilder {
    IsaBuilder {
        setup: settings::builder(),
        constructor: isa_constructor,
    }
}

fn isa_constructor(
    shared_flags: shared_settings::Flags,
    builder: &shared_settings::Builder,
) -> Box<TargetIsa> {
    let level1 = if shared_flags.is_64bit() {
        &enc_tables::LEVEL1_I64[..]
    } else {
        &enc_tables::LEVEL1_I32[..]
    };
    Box::new(Isa {
        isa_flags: settings::Flags::new(&shared_flags, builder),
        shared_flags,
        cpumode: level1,
    })
}

impl TargetIsa for Isa {
    fn name(&self) -> &'static str {
        "intel"
    }

    fn flags(&self) -> &shared_settings::Flags {
        &self.shared_flags
    }

    fn register_info(&self) -> RegInfo {
        registers::INFO.clone()
    }

    fn encoding_info(&self) -> EncInfo {
        enc_tables::INFO.clone()
    }

    fn legal_encodings<'a>(
        &'a self,
        dfg: &'a ir::DataFlowGraph,
        inst: &'a ir::InstructionData,
        ctrl_typevar: ir::Type,
    ) -> Encodings<'a> {
        lookup_enclist(
            ctrl_typevar,
            inst,
            dfg,
            self.cpumode,
            &enc_tables::LEVEL2[..],
            &enc_tables::ENCLISTS[..],
            &enc_tables::LEGALIZE_ACTIONS[..],
            &enc_tables::RECIPE_PREDICATES[..],
            &enc_tables::INST_PREDICATES[..],
            self.isa_flags.predicate_view(),
        )
    }

    fn legalize_signature(&self, sig: &mut ir::Signature, current: bool) {
        abi::legalize_signature(sig, &self.shared_flags, current)
    }

    fn regclass_for_abi_type(&self, ty: ir::Type) -> RegClass {
        abi::regclass_for_abi_type(ty)
    }

    fn allocatable_registers(&self, func: &ir::Function) -> regalloc::AllocatableSet {
        abi::allocatable_registers(func, &self.shared_flags)
    }

    fn emit_inst(
        &self,
        func: &ir::Function,
        inst: ir::Inst,
        divert: &mut regalloc::RegDiversions,
        sink: &mut CodeSink,
    ) {
        binemit::emit_inst(func, inst, divert, sink)
    }

    fn emit_function(&self, func: &ir::Function, sink: &mut MemoryCodeSink) {
        emit_function(func, binemit::emit_inst, sink)
    }

    fn reloc_names(&self) -> &'static [&'static str] {
        &binemit::RELOC_NAMES
    }

    fn prologue_epilogue(&self, func: &mut ir::Function) -> result::CtonResult {
        use stack_layout::layout_stack;
        use cursor::{Cursor, EncCursor};

        let word_size = if self.flags().is_64bit() { 8 } else { 4 };
        let stack_size = layout_stack(&mut func.stack_slots, word_size)?;

        // Append frame pointer to function signature
        let rbp_arg = ir::AbiParam::special_reg(
            ir::types::I64,
            ir::ArgumentPurpose::FramePointer,
            RU::rbp as RegUnit,
        );
        func.signature.params.push(rbp_arg);

        // Append param to entry EBB
        let entry_ebb = func.layout.entry_block().expect("missing entry block");
        func.dfg.append_ebb_param(entry_ebb, ir::types::I64);

        // Find our frame pointer parameter Value
        let fp = func.special_param(ir::ArgumentPurpose::FramePointer)
            .expect("missing frame pointer");

        // Assign it a location
        func.locations[fp] = ir::ValueLoc::Reg(RU::rbp as RegUnit);

        // Insert prologue
        let mut pos = EncCursor::new(func, self).at_first_insertion_point(entry_ebb);
        pos.ins().x86_push(fp);
        pos.ins().copy_special(
            RU::rbp as RegUnit,
            RU::rsp as RegUnit,
        );
        pos.ins().adjust_sp_imm(-(stack_size as i32));

        //legalizer::legalize_function(func, &mut func.cfg, self);

        Ok(())
    }
}
<|endoftext|>


<commit_before>use serde_json::Value;
use ::{Error, Result};
use ::odata::Parameters;

/// Item path
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)]
pub enum Path {
	/// The Home folder
	Home,
	/// The Parent favorite item
	Favorites,
	/// The Parent Shared Folders items
	AllShared,
	/// The Parent Connectors item
	Connectors,
	/// The FileBox item
	Box,
	/// The Top item
	Top,
	/// The item identified by ID
	Id(String),
	/// The absolute path
	Absolute(String),
	/// The relative path
	Relative(String, String),
	/// Parent
	Parent(String),
}

impl Path {
	/// Test if path points to the home folder
	pub fn is_home(&self) -> bool {
		match self {
			&Path::Home => true,
			_ => false
		}
	}

	/// Test if path points to the favorites folder
	pub fn is_favorites(&self) -> bool {
		match self {
			&Path::Favorites => true,
			_ => false
		}
	}

	/// Test if path points to the all shared folder
	pub fn is_allshared(&self) -> bool {
		match self {
			&Path::AllShared => true,
			_ => false
		}
	}

	/// Test if path points to the connectors folder
	pub fn is_connectors(&self) -> bool {
		match self {
			&Path::Connectors => true,
			_ => false
		}
	}

	/// Test if path points to the filebox folder
	pub fn is_box(&self) -> bool {
		match self {
			&Path::Box => true,
			_ => false
		}
	}

	/// Test if path points to the top folder
	pub fn is_top(&self) -> bool {
		match self {
			&Path::Top => true,
			_ => false
		}
	}

	/// Test if path holds the ID
	pub fn is_id(&self) -> bool {
		match self {
			&Path::Id(_) => true,
			_ => false
		}
	}

	/// Test if path is absolute
	pub fn is_absolute(&self) -> bool {
		match self {
			&Path::Absolute(_) => true,
			_ => false
		}
	}

	/// Test if path is relative
	pub fn is_relative(&self) -> bool {
		match self {
			&Path::Relative(_, _) => true,
			_ => false
		}
	}

	/// Test if path points to the parent item
	pub fn is_parent(&self) -> bool {
		match self {
			&Path::Parent(_) => true,
			_ => false
		}
	}

	/// Used internally to build OAuth URIs.
	pub fn entity_and_parameters(&self, segment: Option<&str>, parameters: Option<Parameters>) -> String {
		let segment = segment.map_or("", |s| s);
		let parameters = parameters.map_or(String::from(""), |p| p.to_string());

		match self {
			&Path::Home => format!("Items(home){}?{}", segment, parameters),
			&Path::Favorites => format!("Items(favorites){}?{}", segment, parameters),
			&Path::AllShared => format!("Items(allshared){}?{}", segment, parameters),
			&Path::Connectors => format!("Items(connectors){}?{}", segment, parameters),
			&Path::Box => format!("Items(box){}?{}", segment, parameters),
			&Path::Top => format!("Items(top){}?{}", segment, parameters),
			&Path::Id(ref id) => format!("Items({}){}?{}", id, segment, parameters),
			&Path::Absolute(ref path) => format!("Items/ByPath?path={}&{}", path, parameters),
			&Path::Relative(ref id, ref path) => format!("Items({})/ByPath?path={}&{}", id, path, parameters),
			&Path::Parent(ref id) => format!("Items({})/Parent&{}", id, parameters),
		}
	}

	// Parse the path from the result JSON
	pub fn from_json(value: Value) -> Result<Path> {
		value.find("Id")
			.ok_or(Error::new("Cannot find Item ID"))
			.map(|id| Path::Id(id.as_string().unwrap().to_owned()))
	}
}

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

	#[test]
	fn path_home() {
		let path = Path::Home;
		assert!(path.is_home());
	}

	#[test]
	fn path_favorites() {
		let path = Path::Favorites;
		assert!(path.is_favorites());
	}

	#[test]
	fn path_allshared() {
		let path = Path::AllShared;
		assert!(path.is_allshared());
	}

	#[test]
	fn path_connectors() {
		let path = Path::Connectors;
		assert!(path.is_connectors());
	}

	#[test]
	fn path_box() {
		let path = Path::Box;
		assert!(path.is_box());
	}

	#[test]
	fn path_top() {
		let path = Path::Top;
		assert!(path.is_top());
	}

	#[test]
	fn path_id() {
		let path = Path::Id("id".to_owned());
		assert!(path.is_id());
	}

	#[test]
	fn path_absolute() {
		let path = Path::Absolute("path".to_owned());
		assert!(path.is_absolute());
	}

	#[test]
	fn path_relative() {
		let path = Path::Relative("this".to_owned(), "that".to_owned());
		assert!(path.is_relative());
	}

	#[test]
	fn path_parent() {
		let path = Path::Parent("up".to_owned());
		assert!(path.is_parent());
	}
}
<commit_msg>Add Path JSON parsing tests<commit_after>use serde_json::Value;
use ::{Error, Result};
use ::odata::Parameters;

/// Item path
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)]
pub enum Path {
	/// The Home folder
	Home,
	/// The Parent favorite item
	Favorites,
	/// The Parent Shared Folders items
	AllShared,
	/// The Parent Connectors item
	Connectors,
	/// The FileBox item
	Box,
	/// The Top item
	Top,
	/// The item identified by ID
	Id(String),
	/// The absolute path
	Absolute(String),
	/// The relative path
	Relative(String, String),
	/// Parent
	Parent(String),
}

impl Path {
	/// Test if path points to the home folder
	pub fn is_home(&self) -> bool {
		match self {
			&Path::Home => true,
			_ => false
		}
	}

	/// Test if path points to the favorites folder
	pub fn is_favorites(&self) -> bool {
		match self {
			&Path::Favorites => true,
			_ => false
		}
	}

	/// Test if path points to the all shared folder
	pub fn is_allshared(&self) -> bool {
		match self {
			&Path::AllShared => true,
			_ => false
		}
	}

	/// Test if path points to the connectors folder
	pub fn is_connectors(&self) -> bool {
		match self {
			&Path::Connectors => true,
			_ => false
		}
	}

	/// Test if path points to the filebox folder
	pub fn is_box(&self) -> bool {
		match self {
			&Path::Box => true,
			_ => false
		}
	}

	/// Test if path points to the top folder
	pub fn is_top(&self) -> bool {
		match self {
			&Path::Top => true,
			_ => false
		}
	}

	/// Test if path holds the ID
	pub fn is_id(&self) -> bool {
		match self {
			&Path::Id(_) => true,
			_ => false
		}
	}

	/// Test if path is absolute
	pub fn is_absolute(&self) -> bool {
		match self {
			&Path::Absolute(_) => true,
			_ => false
		}
	}

	/// Test if path is relative
	pub fn is_relative(&self) -> bool {
		match self {
			&Path::Relative(_, _) => true,
			_ => false
		}
	}

	/// Test if path points to the parent item
	pub fn is_parent(&self) -> bool {
		match self {
			&Path::Parent(_) => true,
			_ => false
		}
	}

	/// Used internally to build OAuth URIs.
	pub fn entity_and_parameters(&self, segment: Option<&str>, parameters: Option<Parameters>) -> String {
		let segment = segment.map_or("", |s| s);
		let parameters = parameters.map_or(String::from(""), |p| p.to_string());

		match self {
			&Path::Home => format!("Items(home){}?{}", segment, parameters),
			&Path::Favorites => format!("Items(favorites){}?{}", segment, parameters),
			&Path::AllShared => format!("Items(allshared){}?{}", segment, parameters),
			&Path::Connectors => format!("Items(connectors){}?{}", segment, parameters),
			&Path::Box => format!("Items(box){}?{}", segment, parameters),
			&Path::Top => format!("Items(top){}?{}", segment, parameters),
			&Path::Id(ref id) => format!("Items({}){}?{}", id, segment, parameters),
			&Path::Absolute(ref path) => format!("Items/ByPath?path={}&{}", path, parameters),
			&Path::Relative(ref id, ref path) => format!("Items({})/ByPath?path={}&{}", id, path, parameters),
			&Path::Parent(ref id) => format!("Items({})/Parent&{}", id, parameters),
		}
	}

	// Parse the path from the result JSON
	pub fn from_json(value: Value) -> Result<Path> {
		value.find("Id")
			.ok_or(Error::new("Cannot find Item ID"))
			.map(|id| Path::Id(id.as_string().unwrap().to_owned()))
	}
}

#[cfg(test)]
mod tests {
	use super::Path;
	use serde_json::{self, Value};

	#[test]
	fn path_home() {
		let path = Path::Home;
		assert!(path.is_home());
	}

	#[test]
	fn path_favorites() {
		let path = Path::Favorites;
		assert!(path.is_favorites());
	}

	#[test]
	fn path_allshared() {
		let path = Path::AllShared;
		assert!(path.is_allshared());
	}

	#[test]
	fn path_connectors() {
		let path = Path::Connectors;
		assert!(path.is_connectors());
	}

	#[test]
	fn path_box() {
		let path = Path::Box;
		assert!(path.is_box());
	}

	#[test]
	fn path_top() {
		let path = Path::Top;
		assert!(path.is_top());
	}

	#[test]
	fn path_id() {
		let path = Path::Id("id".to_owned());
		assert!(path.is_id());
	}

	#[test]
	fn path_absolute() {
		let path = Path::Absolute("path".to_owned());
		assert!(path.is_absolute());
	}

	#[test]
	fn path_relative() {
		let path = Path::Relative("this".to_owned(), "that".to_owned());
		assert!(path.is_relative());
	}

	#[test]
	fn path_parent() {
		let path = Path::Parent("up".to_owned());
		assert!(path.is_parent());
	}

	#[test]
	fn parse_valid_path() {
		let data: Value = serde_json::from_str("{\"Id\":\"fi111111-2222-3333-4444-555555555555\"}").unwrap();
		let path = Path::from_json(data).unwrap();
		assert!(path.is_id());
	}

	#[test]
	#[should_panic]
	fn parse_invalid_path() {
		let data: Value = serde_json::from_str("{\"code\":\"error\"}").unwrap();
		let _ = Path::from_json(data).unwrap();
	}

	#[test]
	fn parse_path_id() {
		let data: Value = serde_json::from_str("{\"Id\":\"fi111111-2222-3333-4444-555555555555\"}").unwrap();
		match Path::from_json(data).unwrap() {
			Path::Id(id) => assert_eq!(id, "fi111111-2222-3333-4444-555555555555"),
			_ => panic!("Parsed Path must be Id")
		};
	}
}
<|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/. */

//! The `servo` test application.
//!
//! Creates a `Servo` instance with a simple implementation of
//! the compositor's `WindowMethods` to create a working web browser.
//!
//! This browser's implementation of `WindowMethods` is built on top
//! of [glutin], the cross-platform OpenGL utility and windowing
//! library.
//!
//! For the engine itself look next door in `components/servo/lib.rs`.
//!
//! [glutin]: https://github.com/tomaka/glutin

#![feature(start, core_intrinsics)]

#[cfg(target_os = "android")]
extern crate android_injected_glue;
extern crate backtrace;
// The window backed by glutin
extern crate glutin_app as app;
#[macro_use]
extern crate log;
// The Servo engine
extern crate servo;
#[cfg(not(target_os = "android"))]
#[macro_use]
extern crate sig;

use backtrace::Backtrace;
use servo::Servo;
use servo::compositing::windowing::WindowEvent;
#[cfg(target_os = "android")]
use servo::config;
use servo::config::opts::{self, ArgumentParsingResult, parse_url_or_filename};
use servo::config::servo_version;
use servo::ipc_channel::ipc;
use servo::servo_config::prefs::PREFS;
use servo::servo_url::ServoUrl;
use std::env;
use std::panic;
use std::process;
use std::rc::Rc;
use std::thread;

pub mod platform {
    #[cfg(target_os = "macos")]
    pub use platform::macos::deinit;

    #[cfg(target_os = "macos")]
    pub mod macos;

    #[cfg(not(target_os = "macos"))]
    pub fn deinit() {}
}

#[cfg(not(target_os = "android"))]
fn install_crash_handler() {
    use backtrace::Backtrace;
    use sig::ffi::Sig;
    use std::intrinsics::abort;
    use std::thread;

    fn handler(_sig: i32) {
        let name = thread::current()
            .name()
            .map(|n| format!(" for thread \"{}\"", n))
            .unwrap_or("".to_owned());
        println!("Stack trace{}\n{:?}", name, Backtrace::new());
        unsafe {
            // N.B. Using process::abort() here causes the crash handler to be
            //      triggered recursively.
            abort();
        }
    }

    signal!(Sig::SEGV, handler); // handle segfaults
    signal!(Sig::ILL, handler); // handle stack overflow and unsupported CPUs
    signal!(Sig::IOT, handler); // handle double panics
    signal!(Sig::BUS, handler); // handle invalid memory access
}

#[cfg(target_os = "android")]
fn install_crash_handler() {}

fn main() {
    install_crash_handler();

    // Parse the command line options and store them globally
    let opts_result = opts::from_cmdline_args(&*args());

    let content_process_token = if let ArgumentParsingResult::ContentProcess(token) = opts_result {
        Some(token)
    } else {
        if opts::get().is_running_problem_test && ::std::env::var("RUST_LOG").is_err() {
            ::std::env::set_var("RUST_LOG", "compositing::constellation");
        }

        None
    };

    // TODO: once log-panics is released, can this be replaced by
    // log_panics::init()?
    panic::set_hook(Box::new(|info| {
        warn!("Panic hook called.");
        let msg = match info.payload().downcast_ref::<&'static str>() {
            Some(s) => *s,
            None => {
                match info.payload().downcast_ref::<String>() {
                    Some(s) => &**s,
                    None => "Box<Any>",
                }
            },
        };
        let current_thread = thread::current();
        let name = current_thread.name().unwrap_or("<unnamed>");
        if let Some(location) = info.location() {
            println!("{} (thread {}, at {}:{})",
                     msg,
                     name,
                     location.file(),
                     location.line());
        } else {
            println!("{} (thread {})", msg, name);
        }
        if env::var("RUST_BACKTRACE").is_ok() {
            println!("{:?}", Backtrace::new());
        }

        error!("{}", msg);
    }));

    setup_logging();

    if let Some(token) = content_process_token {
        return servo::run_content_process(token);
    }

    if opts::get().is_printing_version {
        println!("{}", servo_version());
        process::exit(0);
    }

    let window = app::create_window(None);

    // If the url is not provided, we fallback to the homepage in PREFS,
    // or a blank page in case the homepage is not set either.
    let cwd = env::current_dir().unwrap();
    let cmdline_url = opts::get().url.clone();
    let pref_url = PREFS.get("shell.homepage").as_string()
        .and_then(|str| parse_url_or_filename(&cwd, str).ok());
    let blank_url = ServoUrl::parse("about:blank").ok();

    let target_url = cmdline_url.or(pref_url).or(blank_url).unwrap();

    // Our wrapper around `ServoWrapper` that also implements some
    // callbacks required by the glutin window implementation.
    let mut servo_wrapper = ServoWrapper {
        servo: Servo::new(window.clone())
    };

    let (sender, receiver) = ipc::channel().unwrap();
    servo_wrapper.servo.handle_events(vec![WindowEvent::NewBrowser(target_url, sender)]);
    let browser_id = receiver.recv().unwrap();
    window.set_browser_id(browser_id);
    servo_wrapper.servo.handle_events(vec![WindowEvent::SelectBrowser(browser_id)]);

    servo_wrapper.servo.setup_logging();

    register_glutin_resize_handler(&window, &mut servo_wrapper);

    // Feed events from the window to the browser until the browser
    // says to stop.
    loop {
        let should_continue = servo_wrapper.servo.handle_events(window.wait_events());
        if !should_continue {
            break;
        }
    }

    unregister_glutin_resize_handler(&window);

    servo_wrapper.servo.deinit();

    platform::deinit()
}

fn register_glutin_resize_handler(window: &Rc<app::window::Window>, browser: &mut ServoWrapper) {
    unsafe {
        window.set_nested_event_loop_listener(browser);
    }
}

fn unregister_glutin_resize_handler(window: &Rc<app::window::Window>) {
    unsafe {
        window.remove_nested_event_loop_listener();
    }
}

struct ServoWrapper {
    servo: Servo<app::window::Window>,
}

impl app::NestedEventLoopListener for ServoWrapper {
    fn handle_event_from_nested_event_loop(&mut self, event: WindowEvent) -> bool {
        let is_resize = match event {
            WindowEvent::Resize(..) => true,
            _ => false,
        };
        if !self.servo.handle_events(vec![event]) {
            return false;
        }
        if is_resize {
            self.servo.repaint_synchronously()
        }
        true
    }
}

#[cfg(target_os = "android")]
fn setup_logging() {
    // Piping logs from stdout/stderr to logcat happens in android_injected_glue.
    ::std::env::set_var("RUST_LOG", "error");

    unsafe { android_injected_glue::ffi::app_dummy() };
}

#[cfg(not(target_os = "android"))]
fn setup_logging() {}

#[cfg(target_os = "android")]
/// Attempt to read parameters from a file since they are not passed to us in Android environments.
/// The first line should be the "servo" argument and the last should be the URL to load.
/// Blank lines and those beginning with a '#' are ignored.
/// Each line should be a separate parameter as would be parsed by the shell.
/// For example, "servo -p 10 http://en.wikipedia.org/wiki/Rust" would take 4 lines.
fn args() -> Vec<String> {
    use std::error::Error;
    use std::fs::File;
    use std::io::{BufRead, BufReader};

    let mut params_file = config::basedir::default_config_dir().unwrap();
    params_file.push("android_params");
    match File::open(params_file.to_str().unwrap()) {
        Ok(f) => {
            let mut vec = Vec::new();
            let file = BufReader::new(&f);
            for line in file.lines() {
                let l = line.unwrap().trim().to_owned();
                // ignore blank lines and those that start with a '#'
                match l.is_empty() || l.as_bytes()[0] == b'#' {
                    true => (),
                    false => vec.push(l),
                }
            }
            vec
        },
        Err(e) => {
            debug!("Failed to open params file '{}': {}",
                   params_file.to_str().unwrap(),
                   Error::description(&e));
            vec!["servo".to_owned(), "http://en.wikipedia.org/wiki/Rust".to_owned()]
        },
    }
}

#[cfg(not(target_os = "android"))]
fn args() -> Vec<String> {
    use std::env;
    env::args().collect()
}

#[cfg(target_os = "android")]
#[no_mangle]
#[inline(never)]
#[allow(non_snake_case)]
pub extern "C" fn android_main(app: *mut ()) {
    android_injected_glue::android_main2(app as *mut _, move |_, _| main());
}
<commit_msg>Remove unused 'start' feature flag<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/. */

//! The `servo` test application.
//!
//! Creates a `Servo` instance with a simple implementation of
//! the compositor's `WindowMethods` to create a working web browser.
//!
//! This browser's implementation of `WindowMethods` is built on top
//! of [glutin], the cross-platform OpenGL utility and windowing
//! library.
//!
//! For the engine itself look next door in `components/servo/lib.rs`.
//!
//! [glutin]: https://github.com/tomaka/glutin

#![feature(core_intrinsics)]

#[cfg(target_os = "android")]
extern crate android_injected_glue;
extern crate backtrace;
// The window backed by glutin
extern crate glutin_app as app;
#[macro_use]
extern crate log;
// The Servo engine
extern crate servo;
#[cfg(not(target_os = "android"))]
#[macro_use]
extern crate sig;

use backtrace::Backtrace;
use servo::Servo;
use servo::compositing::windowing::WindowEvent;
#[cfg(target_os = "android")]
use servo::config;
use servo::config::opts::{self, ArgumentParsingResult, parse_url_or_filename};
use servo::config::servo_version;
use servo::ipc_channel::ipc;
use servo::servo_config::prefs::PREFS;
use servo::servo_url::ServoUrl;
use std::env;
use std::panic;
use std::process;
use std::rc::Rc;
use std::thread;

pub mod platform {
    #[cfg(target_os = "macos")]
    pub use platform::macos::deinit;

    #[cfg(target_os = "macos")]
    pub mod macos;

    #[cfg(not(target_os = "macos"))]
    pub fn deinit() {}
}

#[cfg(not(target_os = "android"))]
fn install_crash_handler() {
    use backtrace::Backtrace;
    use sig::ffi::Sig;
    use std::intrinsics::abort;
    use std::thread;

    fn handler(_sig: i32) {
        let name = thread::current()
            .name()
            .map(|n| format!(" for thread \"{}\"", n))
            .unwrap_or("".to_owned());
        println!("Stack trace{}\n{:?}", name, Backtrace::new());
        unsafe {
            // N.B. Using process::abort() here causes the crash handler to be
            //      triggered recursively.
            abort();
        }
    }

    signal!(Sig::SEGV, handler); // handle segfaults
    signal!(Sig::ILL, handler); // handle stack overflow and unsupported CPUs
    signal!(Sig::IOT, handler); // handle double panics
    signal!(Sig::BUS, handler); // handle invalid memory access
}

#[cfg(target_os = "android")]
fn install_crash_handler() {}

fn main() {
    install_crash_handler();

    // Parse the command line options and store them globally
    let opts_result = opts::from_cmdline_args(&*args());

    let content_process_token = if let ArgumentParsingResult::ContentProcess(token) = opts_result {
        Some(token)
    } else {
        if opts::get().is_running_problem_test && ::std::env::var("RUST_LOG").is_err() {
            ::std::env::set_var("RUST_LOG", "compositing::constellation");
        }

        None
    };

    // TODO: once log-panics is released, can this be replaced by
    // log_panics::init()?
    panic::set_hook(Box::new(|info| {
        warn!("Panic hook called.");
        let msg = match info.payload().downcast_ref::<&'static str>() {
            Some(s) => *s,
            None => {
                match info.payload().downcast_ref::<String>() {
                    Some(s) => &**s,
                    None => "Box<Any>",
                }
            },
        };
        let current_thread = thread::current();
        let name = current_thread.name().unwrap_or("<unnamed>");
        if let Some(location) = info.location() {
            println!("{} (thread {}, at {}:{})",
                     msg,
                     name,
                     location.file(),
                     location.line());
        } else {
            println!("{} (thread {})", msg, name);
        }
        if env::var("RUST_BACKTRACE").is_ok() {
            println!("{:?}", Backtrace::new());
        }

        error!("{}", msg);
    }));

    setup_logging();

    if let Some(token) = content_process_token {
        return servo::run_content_process(token);
    }

    if opts::get().is_printing_version {
        println!("{}", servo_version());
        process::exit(0);
    }

    let window = app::create_window(None);

    // If the url is not provided, we fallback to the homepage in PREFS,
    // or a blank page in case the homepage is not set either.
    let cwd = env::current_dir().unwrap();
    let cmdline_url = opts::get().url.clone();
    let pref_url = PREFS.get("shell.homepage").as_string()
        .and_then(|str| parse_url_or_filename(&cwd, str).ok());
    let blank_url = ServoUrl::parse("about:blank").ok();

    let target_url = cmdline_url.or(pref_url).or(blank_url).unwrap();

    // Our wrapper around `ServoWrapper` that also implements some
    // callbacks required by the glutin window implementation.
    let mut servo_wrapper = ServoWrapper {
        servo: Servo::new(window.clone())
    };

    let (sender, receiver) = ipc::channel().unwrap();
    servo_wrapper.servo.handle_events(vec![WindowEvent::NewBrowser(target_url, sender)]);
    let browser_id = receiver.recv().unwrap();
    window.set_browser_id(browser_id);
    servo_wrapper.servo.handle_events(vec![WindowEvent::SelectBrowser(browser_id)]);

    servo_wrapper.servo.setup_logging();

    register_glutin_resize_handler(&window, &mut servo_wrapper);

    // Feed events from the window to the browser until the browser
    // says to stop.
    loop {
        let should_continue = servo_wrapper.servo.handle_events(window.wait_events());
        if !should_continue {
            break;
        }
    }

    unregister_glutin_resize_handler(&window);

    servo_wrapper.servo.deinit();

    platform::deinit()
}

fn register_glutin_resize_handler(window: &Rc<app::window::Window>, browser: &mut ServoWrapper) {
    unsafe {
        window.set_nested_event_loop_listener(browser);
    }
}

fn unregister_glutin_resize_handler(window: &Rc<app::window::Window>) {
    unsafe {
        window.remove_nested_event_loop_listener();
    }
}

struct ServoWrapper {
    servo: Servo<app::window::Window>,
}

impl app::NestedEventLoopListener for ServoWrapper {
    fn handle_event_from_nested_event_loop(&mut self, event: WindowEvent) -> bool {
        let is_resize = match event {
            WindowEvent::Resize(..) => true,
            _ => false,
        };
        if !self.servo.handle_events(vec![event]) {
            return false;
        }
        if is_resize {
            self.servo.repaint_synchronously()
        }
        true
    }
}

#[cfg(target_os = "android")]
fn setup_logging() {
    // Piping logs from stdout/stderr to logcat happens in android_injected_glue.
    ::std::env::set_var("RUST_LOG", "error");

    unsafe { android_injected_glue::ffi::app_dummy() };
}

#[cfg(not(target_os = "android"))]
fn setup_logging() {}

#[cfg(target_os = "android")]
/// Attempt to read parameters from a file since they are not passed to us in Android environments.
/// The first line should be the "servo" argument and the last should be the URL to load.
/// Blank lines and those beginning with a '#' are ignored.
/// Each line should be a separate parameter as would be parsed by the shell.
/// For example, "servo -p 10 http://en.wikipedia.org/wiki/Rust" would take 4 lines.
fn args() -> Vec<String> {
    use std::error::Error;
    use std::fs::File;
    use std::io::{BufRead, BufReader};

    let mut params_file = config::basedir::default_config_dir().unwrap();
    params_file.push("android_params");
    match File::open(params_file.to_str().unwrap()) {
        Ok(f) => {
            let mut vec = Vec::new();
            let file = BufReader::new(&f);
            for line in file.lines() {
                let l = line.unwrap().trim().to_owned();
                // ignore blank lines and those that start with a '#'
                match l.is_empty() || l.as_bytes()[0] == b'#' {
                    true => (),
                    false => vec.push(l),
                }
            }
            vec
        },
        Err(e) => {
            debug!("Failed to open params file '{}': {}",
                   params_file.to_str().unwrap(),
                   Error::description(&e));
            vec!["servo".to_owned(), "http://en.wikipedia.org/wiki/Rust".to_owned()]
        },
    }
}

#[cfg(not(target_os = "android"))]
fn args() -> Vec<String> {
    use std::env;
    env::args().collect()
}

#[cfg(target_os = "android")]
#[no_mangle]
#[inline(never)]
#[allow(non_snake_case)]
pub extern "C" fn android_main(app: *mut ()) {
    android_injected_glue::android_main2(app as *mut _, move |_, _| main());
}
<|endoftext|>


<commit_before>// parser/mod.rs

use std::collections::HashMap;
use std::iter::Peekable;
use std::str::Chars;
use utils::{Result, err_position, Position};
use super::compiler::abstract_tree::{AbstractTree, TokenType};

struct Parser<'a> {
    table: HashMap<char, fn(&mut Parser) -> Result<Option<AbstractTree>>>,
    stream: Peekable<Chars<'a>>,
    position: Position,
}

impl<'a> Parser<'a> {
    fn new(string: &'a str) -> Parser<'a> {
        Parser {
            table: HashMap::new(),
            stream: string.chars().peekable(),
            position: Position(0, 0),
        }
    }

    fn advance_char(&mut self) -> Option<char> {
        let current_char = self.stream.next();
        match current_char {
            Some(c) => {
                if c == '\n' {
                    // column set to 0
                    // line incremented
                    self.position.0 += 1;
                    self.position.1 = 0;
                } else {
                    // column incremented
                    self.position.1 += 1;
                }
            }
            None => {}
        }
        current_char
    }

    fn at_eof(&mut self) -> bool {
        self.current_char().is_none()
    }

    fn read_as(mut self,
               key: char,
               f: fn(&mut Parser) -> Result<Option<AbstractTree>>)
               -> Parser<'a> {
        self.table.insert(key, f);
        self
    }

    fn parse_expression(&mut self) -> Result<Option<AbstractTree>> {
        let current_reader = self.current_reader().unwrap_or(Parser::default_parse);
        current_reader(self)
    }

    fn current_reader(&mut self) -> Option<fn(&mut Parser) -> Result<Option<AbstractTree>>> {
        if self.current_char().is_none() {
            return None;
        }
        self.table.get(self.stream.peek().unwrap()).map(|f| *f)
    }

    fn current_char(&mut self) -> Option<&char> {
        self.stream.peek()
    }

    fn default_parse<'b>(parser: &mut Parser) -> Result<Option<AbstractTree>> {
        let mut chars = String::new();
        let starting_position = parser.position.clone();

        loop {
            // refactor this to a while - let
            // if parser.at_eof() { break; } // I don't think this is necessary
            let current_reader = parser.current_reader();
            match current_reader {
                Some(_) => {
                    break;
                }
                None => {
                    match parser.advance_char() {
                        Some(c) => chars.push(c),
                        None => {
                            break;
                        }
                    }
                }
            }
        }
        if chars.len() == 0 {
            return Ok(None);
        }
        Ok(Some(AbstractTree::Token(TokenType::Symbol, chars, starting_position)))
    }

    fn parse_complete(&mut self) -> Result<Option<AbstractTree>> {
        let starting_position = self.position.clone();
        let mut accumulator = vec![];
        loop {
            let expression = top_level_expression(self);
            match expression {
                Ok(Some(AbstractTree::Token(TokenType::Flag, s, p))) => {
                    // this way I can ensure ( } doesnt happen
                    return err_position(starting_position,
                                        format!("encountered incorrect flag {},\
                                                at position {:?}, while reading an \
                                                the top level",
                                                s,
                                                p));
                }
                Ok(Some(a)) => accumulator.push(a),
                Ok(None) => {
                    if self.at_eof() {
                        break;
                    }
                }
                error @ Err(_) => return error,
            }
        }
        Ok(Some(AbstractTree::Node(accumulator, starting_position)))
    }
}

fn no_op(parser: &mut Parser) -> Result<Option<AbstractTree>> {
    parser.advance_char();
    Ok(None)
}

// consolidate these into one function.
fn close_paren(parser: &mut Parser) -> Result<Option<AbstractTree>> {
    parser.advance_char();
    Ok(Some(AbstractTree::Token(TokenType::Flag, ")".to_string(), Position(0, 0))))
}

fn close_curly(parser: &mut Parser) -> Result<Option<AbstractTree>> {
    parser.advance_char();
    Ok(Some(AbstractTree::Token(TokenType::Flag, "}".to_string(), Position(0, 0))))
}

fn newline(parser: &mut Parser) -> Result<Option<AbstractTree>> {
    parser.advance_char();
    Ok(Some(AbstractTree::Token(TokenType::Flag, "\n".to_string(), Position(0, 0))))
}

macro_rules! define_expression_parser {
    (
        $a: ident
        name: $name: expr,
        close: $close: expr,
        advance: $should_advance: expr,
        top_level: $top_level: expr
    ) => {

        fn $a(parser: &mut Parser) -> Result<Option<AbstractTree>> {
            let starting_position = parser.position.clone();
            if $should_advance {
                parser.advance_char();
            }
            let mut accumulator = vec![];
            loop {
                let expression = parser.parse_expression();
                match expression {
                    Ok(Some(AbstractTree::Token(TokenType::Flag, s, p))) => {
                        if s == $close.to_string() {
                            break;
                        } else {
                            // this way I can ensure ( } doesnt happen
                            return err_position(starting_position,
                                                format!("encountered incorrect flag {},\
                                                        at position {:?}, while reading an \
                                                        {}", s, p, $name))
                        }
                    }
                    Ok(Some(a)) => accumulator.push(a),
                    Ok(None) => {
                        if parser.at_eof() {
                            if $top_level { break; }

                            return err_position(starting_position,
                                                format!("hit end of file \
                                                        while reading an {}", $name))
                        }
                    }
                    error @ Err(_) => return error,
                }
            }

            if accumulator.is_empty() { // This might be a bug // && parser.at_eof() {
                return Ok(None)
            }

            Ok(Some(AbstractTree::Node(accumulator, starting_position)))
        }

    }
}

define_expression_parser! { open_paren
    name: "open paren",
    close: ")",
    advance: true,
    top_level: false
}

define_expression_parser! { top_level_expression
    name: "top level expression",
    close: "\n",
    advance: false,
    top_level: true
}

pub fn parse(string: &str) -> Result<Option<AbstractTree>> {
    Parser::new(string)
        .read_as('\n', newline)
        .read_as(' ', no_op)
        .read_as(')', close_paren)
        .read_as('(', open_paren)
        .read_as('}', close_curly)
        // .read_as('{', open_curly)
        .parse_complete()
}

#[cfg(test)]
mod tests {
    use parser::parse;
    use compiler::abstract_tree::AbstractTree::*;
    use compiler::abstract_tree::TokenType::*;
    use utils::{Position, Error};

    #[test]
    fn test_parse_symbol() {
        assert_eq!(parse("symbol").unwrap().unwrap(),
                   Node(vec![Node(vec![Token(Symbol, "symbol".to_string(), Position(0, 0))],
                                  Position(0, 0))],
                        Position(0, 0)))
    }

    #[test]
    fn test_parse_parentheses() {
        assert_eq!(parse("(hi there)").unwrap().unwrap(),
                   Node(vec![Node(vec![Node(vec![Token(Symbol,
                                                       "hi".to_string(),
                                                       Position(0, 1)),
                                                 Token(Symbol,
                                                       "there".to_string(),
                                                       Position(0, 4))],
                                            Position(0, 0))],
                                  Position(0, 0))],
                        Position(0, 0)));

        // Try with two levels
        assert_eq!(parse("(hi (one) there)").unwrap().unwrap(),
                   Node(vec![Node(vec![Node(vec![Token(Symbol,
                                                       "hi".to_string(),
                                                       Position(0, 1)),
                                                 Node(vec![Token(Symbol,
                                                                 "one".to_string(),
                                                                 Position(0, 5))],
                                                      Position(0, 4)),
                                                 Token(Symbol,
                                                       "there".to_string(),
                                                       Position(0, 10))],
                                            Position(0, 0))],
                                  Position(0, 0))],
                        Position(0, 0)));
    }

    #[test]
    fn test_fail_parse_parentheses() {
        match parse("(hi there") {
            Ok(_) => panic!("I'm assertng this should not parse correctly"),
            Err(Error { description, position: _ }) => {
                assert_eq!("hit end of file while reading an open paren".to_string(),
                           description);
            }
        }
    }

    #[test]
    fn test_two_lines_of_code() {
        assert_eq!(parse("hi there\n(one two)").unwrap().unwrap(),
                   Node(vec![
                Node(vec![
                    Token(Symbol, "hi".to_string(), Position(0, 0)),
                    Token(Symbol, "there".to_string(), Position(0, 3))
                ], Position(0,0)),
                Node(vec![
                    Node(vec![
                        Token(Symbol, "one".to_string(), Position(1, 1)),
                        Token(Symbol, "two".to_string(), Position(1, 5))
                    ], Position(1,0)),
                ], Position(1,0)),
            ],
                        Position(0, 0)));
    }

}
<commit_msg>parsing newlines correctly in parentheses<commit_after>// parser/mod.rs

use std::collections::HashMap;
use std::iter::Peekable;
use std::str::Chars;
use utils::{Result, err_position, Position};
use super::compiler::abstract_tree::{AbstractTree, TokenType};

struct Parser<'a> {
    table: HashMap<char, fn(&mut Parser) -> Result<Option<AbstractTree>>>,
    stream: Peekable<Chars<'a>>,
    position: Position,
}

impl<'a> Parser<'a> {
    fn new(string: &'a str) -> Parser<'a> {
        Parser {
            table: HashMap::new(),
            stream: string.chars().peekable(),
            position: Position(0, 0),
        }
    }

    fn advance_char(&mut self) -> Option<char> {
        let current_char = self.stream.next();
        match current_char {
            Some(c) => {
                if c == '\n' {
                    // column set to 0
                    // line incremented
                    self.position.0 += 1;
                    self.position.1 = 0;
                } else {
                    // column incremented
                    self.position.1 += 1;
                }
            }
            None => {}
        }
        current_char
    }

    fn at_eof(&mut self) -> bool {
        self.current_char().is_none()
    }

    fn read_as(mut self,
               key: char,
               f: fn(&mut Parser) -> Result<Option<AbstractTree>>)
               -> Parser<'a> {
        self.table.insert(key, f);
        self
    }

    fn parse_expression(&mut self) -> Result<Option<AbstractTree>> {
        let current_reader = self.current_reader().unwrap_or(Parser::default_parse);
        current_reader(self)
    }

    fn current_reader(&mut self) -> Option<fn(&mut Parser) -> Result<Option<AbstractTree>>> {
        if self.current_char().is_none() {
            return None;
        }
        self.table.get(self.stream.peek().unwrap()).map(|f| *f)
    }

    fn current_char(&mut self) -> Option<&char> {
        self.stream.peek()
    }

    fn default_parse<'b>(parser: &mut Parser) -> Result<Option<AbstractTree>> {
        let mut chars = String::new();
        let starting_position = parser.position.clone();

        loop {
            // refactor this to a while - let
            // if parser.at_eof() { break; } // I don't think this is necessary
            let current_reader = parser.current_reader();
            match current_reader {
                Some(_) => {
                    break;
                }
                None => {
                    match parser.advance_char() {
                        Some(c) => chars.push(c),
                        None => {
                            break;
                        }
                    }
                }
            }
        }
        if chars.len() == 0 {
            return Ok(None);
        }
        Ok(Some(AbstractTree::Token(TokenType::Symbol, chars, starting_position)))
    }

    fn parse_complete(&mut self) -> Result<Option<AbstractTree>> {
        let starting_position = self.position.clone();
        let mut accumulator = vec![];
        loop {
            let expression = top_level_expression(self);
            match expression {
                Ok(Some(AbstractTree::Token(TokenType::Flag, s, p))) => {
                    // this way I can ensure ( } doesnt happen
                    return err_position(starting_position,
                                        format!("encountered incorrect flag {},\
                                                at position {:?}, while reading an \
                                                the top level",
                                                s,
                                                p));
                }
                Ok(Some(a)) => accumulator.push(a),
                Ok(None) => {
                    if self.at_eof() {
                        break;
                    }
                }
                error @ Err(_) => return error,
            }
        }
        Ok(Some(AbstractTree::Node(accumulator, starting_position)))
    }

    // Newline-specific logic - top level only
    //
    fn remove_newlines(&mut self) {
        self.table.insert('\n', no_op);
    }

    fn add_newlines(&mut self) {
        self.table.insert('\n', newline);
    }
}

fn no_op(parser: &mut Parser) -> Result<Option<AbstractTree>> {
    parser.advance_char();
    Ok(None)
}

// consolidate these into one function.
fn close_paren(parser: &mut Parser) -> Result<Option<AbstractTree>> {
    parser.advance_char();
    Ok(Some(AbstractTree::Token(TokenType::Flag, ")".to_string(), parser.position.clone())))
}

fn close_curly(parser: &mut Parser) -> Result<Option<AbstractTree>> {
    parser.advance_char();
    Ok(Some(AbstractTree::Token(TokenType::Flag, "}".to_string(), parser.position.clone())))
}

fn newline(parser: &mut Parser) -> Result<Option<AbstractTree>> {
    parser.advance_char();
    Ok(Some(AbstractTree::Token(TokenType::Flag, "\n".to_string(), parser.position.clone())))
}

macro_rules! define_expression_parser {
    (
        $a: ident
        name: $name: expr,
        close: $close: expr,
        advance: $should_advance: expr,
        top_level: $top_level: expr,
        ignore_newlines: $should_ignore_newlines: expr,
    ) => {

        fn $a(parser: &mut Parser) -> Result<Option<AbstractTree>> {
            let starting_position = parser.position.clone();
            if $should_advance {
                parser.advance_char();
            }
            let mut accumulator = vec![];
            loop {

                if !$should_ignore_newlines { parser.remove_newlines() }

                let expression = parser.parse_expression();

                if !$should_ignore_newlines { parser.add_newlines() }

                match expression {
                    Ok(Some(AbstractTree::Token(TokenType::Flag, s, p))) => {
                        if s == $close.to_string() {
                            break;
                        } else {
                            // this way I can ensure ( } doesnt happen
                            return err_position(starting_position,
                                                format!("encountered incorrect flag {},\
                                                        at position {:?}, while reading an \
                                                        {}", s, p, $name))
                        }
                    }
                    Ok(Some(a)) => accumulator.push(a),
                    Ok(None) => {
                        if parser.at_eof() {
                            if $top_level { break; }

                            return err_position(starting_position,
                                                format!("hit end of file \
                                                        while reading an {}", $name))
                        }
                    }
                    error @ Err(_) => return error,
                }
            }

            if accumulator.is_empty() { // This might be a bug // && parser.at_eof() {
                return Ok(None)
            }

            Ok(Some(AbstractTree::Node(accumulator, starting_position)))
        }

    }
}

define_expression_parser! { open_paren
    name: "open paren",
    close: ")",
    advance: true,
    top_level: false,
    ignore_newlines: false,
}

define_expression_parser! { top_level_expression
    name: "top level expression",
    close: "\n",
    advance: false,
    top_level: true,
    ignore_newlines: true,
}

pub fn parse(string: &str) -> Result<Option<AbstractTree>> {
    Parser::new(string)
        .read_as('\n', newline)
        .read_as(' ', no_op)
        .read_as(')', close_paren)
        .read_as('(', open_paren)
        .read_as('}', close_curly)
        // .read_as('{', open_curly)
        .parse_complete()
}

#[cfg(test)]
mod tests {
    use parser::parse;
    use compiler::abstract_tree::AbstractTree::*;
    use compiler::abstract_tree::TokenType::*;
    use utils::{Position, Error};

    macro_rules! assert_parses {
        ( $str: expr, $( $node: expr ),* ) => {
            assert_eq!(parse($str).unwrap().unwrap(),
                       Node(vec![
                            $( $node ),*
                       ], Position(0,0)))
        }
    }

    #[test]
    fn test_parse_symbol() {
        assert_parses!("symbol",
                       Node(vec![Token(Symbol, "symbol".to_string(), Position(0, 0))],
                            Position(0, 0)));
    }

    #[test]
    fn test_parse_parentheses() {
        assert_parses!("(hi there)",
                       Node(vec![Node(vec![Token(Symbol, "hi".to_string(), Position(0, 1)),
                                           Token(Symbol, "there".to_string(), Position(0, 4))],
                                      Position(0, 0))],
                            Position(0, 0)));

        // Try with two levels
        assert_parses!("(hi (one) there)",
                       Node(vec![Node(vec![Token(Symbol, "hi".to_string(), Position(0, 1)),
                                           Node(vec![Token(Symbol,
                                                           "one".to_string(),
                                                           Position(0, 5))],
                                                Position(0, 4)),
                                           Token(Symbol, "there".to_string(), Position(0, 10))],
                                      Position(0, 0))],
                            Position(0, 0)));
    }

    #[test]
    fn test_fail_parse_parentheses() {
        match parse("(hi there") {
            Ok(_) => panic!("I'm assertng this should not parse correctly"),
            Err(Error { description, position: _ }) => {
                assert_eq!("hit end of file while reading an open paren".to_string(),
                           description);
            }
        }
    }

    #[test]
    fn test_two_lines_of_code() {
        assert_parses!("hi there\n(one two)",
                       Node(vec![Token(Symbol, "hi".to_string(), Position(0, 0)),
                                 Token(Symbol, "there".to_string(), Position(0, 3))],
                            Position(0, 0)),
                       Node(vec![
                    Node(vec![
                        Token(Symbol, "one".to_string(), Position(1, 1)),
                        Token(Symbol, "two".to_string(), Position(1, 5))
                    ], Position(1,0)),
                ],
                            Position(1, 0)))
    }

    #[test]
    fn test_parse_parentheses_with_newline() {
        assert_parses!("(hi \n\n\nthere)",
                       Node(vec![Node(vec![Token(Symbol, "hi".to_string(), Position(0, 1)),
                                           Token(Symbol, "there".to_string(), Position(3, 0))],
                                      Position(0, 0))],
                            Position(0, 0)));
    }

}
<|endoftext|>