<commit_before>use parser::{Expression, Identifier};
use memory::{MemoryBlock};

use operations::item_type::{ItemType, FuncArgType};
use operations::scope::{ScopeStack, TypeId};
use operations::expression;

pub fn define_stdin(scope: &mut ScopeStack, u8_type: TypeId) -> TypeId {
    // Taking advantage of the scope system to simulate modules
    // This will be replaced with something better in:
    // https://github.com/brain-lang/brain/issues/37
    scope.push_scope();

    let type_name = Identifier::from("std::io::Stdin");
    let stdin_type = scope.declare_type(
        type_name.clone(),
        ItemType::Struct {},
    );
    scope.declare(Identifier::from("stdin"), stdin_type);

    let unit_type = scope.primitives().unit();

    scope.declare_builtin_function(
        type_name.clone().concat(Identifier::from("read_exact")),
        ItemType::Function {
            args: vec![
                FuncArgType::Arg(stdin_type),
                // Need an arg here for the thing being read into
                FuncArgType::Array {item: u8_type, size: None},
            ],
            return_type: unit_type,
        },
        |scope, args, _| {
            unimplemented!();
        }
    );

    stdin_type
}

pub fn define_stdout(scope: &mut ScopeStack) -> TypeId {
    // Taking advantage of the scope system to simulate modules
    // This will be replaced with something better in:
    // https://github.com/brain-lang/brain/issues/37
    scope.push_scope();

    let type_name = Identifier::from("std::io::Stdout");
    let stdout_type = scope.declare_type(
        type_name.clone(),
        ItemType::Struct {},
    );
    scope.declare(Identifier::from("stdout"), stdout_type);

    let unit_type = scope.primitives().unit();

    let print_method_name = type_name.clone().concat(Identifier::from("print"));
    scope.declare_builtin_function(
        print_method_name.clone(),
        ItemType::Function {
            args: vec![
                FuncArgType::Arg(stdout_type),
                FuncArgType::Variadic(None),
            ],
            return_type: unit_type,
        },
        |scope, args, _| {
            unimplemented!();
        }
    );

    scope.declare_builtin_function(
        type_name.clone().concat(Identifier::from("println")),
        ItemType::Function {
            args: vec![
                FuncArgType::Arg(stdout_type),
                FuncArgType::Variadic(None),
            ],
            return_type: unit_type,
        },
        move |scope, args, _| {
            let mut ops = expression::call(
                scope,
                print_method_name.clone(),
                args,
                unit_type,
                MemoryBlock::default()
            )?;

            // Write a newline using a temporary cell
            //TODO: ops.extend(...);
            unimplemented!();

            Ok(ops)
        }
    );

    stdout_type
}
<commit_msg>Implementing stdio.print* functions<commit_after>use parser::Identifier;
use memory::{MemoryBlock};

use operations::{Operation, expression};
use operations::item_type::{ItemType, FuncArgType};
use operations::scope::{ScopeStack, TypeId};

pub fn define_stdin(scope: &mut ScopeStack, u8_type: TypeId) -> TypeId {
    // Taking advantage of the scope system to simulate modules
    // This will be replaced with something better in:
    // https://github.com/brain-lang/brain/issues/37
    scope.push_scope();

    let type_name = Identifier::from("std::io::Stdin");
    let stdin_type = scope.declare_type(
        type_name.clone(),
        ItemType::Struct {},
    );
    scope.declare(Identifier::from("stdin"), stdin_type);

    let unit_type = scope.primitives().unit();

    scope.declare_builtin_function(
        type_name.clone().concat(Identifier::from("read_exact")),
        ItemType::Function {
            args: vec![
                FuncArgType::Arg(stdin_type),
                // Need an arg here for the thing being read into
                FuncArgType::Array {item: u8_type, size: None},
            ],
            return_type: unit_type,
        },
        |scope, args, _| {
            unimplemented!();
        }
    );

    stdin_type
}

pub fn define_stdout(scope: &mut ScopeStack) -> TypeId {
    // Taking advantage of the scope system to simulate modules
    // This will be replaced with something better in:
    // https://github.com/brain-lang/brain/issues/37
    scope.push_scope();

    let type_name = Identifier::from("std::io::Stdout");
    let stdout_type = scope.declare_type(
        type_name.clone(),
        ItemType::Struct {},
    );
    scope.declare(Identifier::from("stdout"), stdout_type);

    let unit_type = scope.primitives().unit();

    let print_method_name = type_name.clone().concat(Identifier::from("print"));
    scope.declare_builtin_function(
        print_method_name.clone(),
        ItemType::Function {
            args: vec![
                FuncArgType::Arg(stdout_type),
                FuncArgType::Variadic(None),
            ],
            return_type: unit_type,
        },
        |scope, args, _| {
            let unit_type = scope.primitives().unit();
            args.into_iter().skip(1).map(|arg| expression::call(
                scope,
                Identifier::from("std::fmt::Display::print"),
                vec![arg],
                unit_type,
                MemoryBlock::default()
            )).collect::<Result<Vec<_>, _>>().map(|op_vecs| {
                op_vecs.into_iter().flat_map(|ops| ops).collect()
            })
        }
    );

    scope.declare_builtin_function(
        type_name.clone().concat(Identifier::from("println")),
        ItemType::Function {
            args: vec![
                FuncArgType::Arg(stdout_type),
                FuncArgType::Variadic(None),
            ],
            return_type: unit_type,
        },
        move |scope, args, _| {
            let mut ops = expression::call(
                scope,
                print_method_name.clone(),
                args,
                unit_type,
                MemoryBlock::default()
            )?;

            // Write a newline using a temporary cell
            let u8_type = scope.primitives().u8();
            let mem = scope.allocate(u8_type);
            ops.push(Operation::TempAllocate {
                temp: mem,
                body: vec![
                    Operation::Increment {
                        target: mem.position(),
                        amount: b'\n',
                    },
                ],
            });

            Ok(ops)
        }
    );

    stdout_type
}
<|endoftext|>


<commit_before>#![feature(core_intrinsics, patchpoint_call_intrinsic, stackmap_call_intrinsic)]
#![feature(question_mark)]
// #![feature(type_ascription)]
// #![feature(rustc_attrs)]
#![feature(libc)]
#![feature(const_fn)]
#![feature(rustc_private)]
#![feature(linkage)]
#![allow(unused_features)]

extern crate libc;
#[macro_use] extern crate log;

extern crate util;

pub use util::*;
use util::unwind_hack::{unw_regnum_t};
use util::llvm_stackmaps::LocationVariant;

use std::intrinsics;

const DEMO_ID: i64 = 0;
const SUBCALL1_ID: i64 = 1;
const SUBCALL2_ID: i64 = 2;

#[no_mangle]
pub extern "C" fn subcall_1(data: *mut u8) {
    println!("Enter `subcall_1`");
    unsafe {
        intrinsics::stackmap_call(SUBCALL1_ID, 0, subcall_2, data);
        // intrinsics::patchpoint_call(SUBCALL1_ID, 13, subcall_2, data);
    }
    println!("Finis `subcall_1`");
}

#[linkage="external"]
extern "C" fn subcall_2(data: *mut u8) {
    println!("Enter `subcall_2`");
    let mut i = 0;
    let mut saw_one = false;
    print!("[");
    let mut datum = unsafe { *data.offset(i) as char };
    while datum != '\0' {
        if saw_one {
            print!(", ");
        }
        print!("{}", datum);
        saw_one = true;
        i += 1;
        datum = unsafe { *data.offset(i) as char };
    }
    println!("]");
    unsafe {
        intrinsics::stackmap_call(SUBCALL2_ID, 0, subcall_3, data);
        // intrinsics::patchpoint_call(SUBCALL2_ID, 13, subcall_3, data);

    }
    println!("Finis `subcall_2`");
}

use self::backtrace_hack::ReturnAddress;
use self::backtrace_hack::dlinfo_fbase;

#[derive(Debug)]
enum FrameInfo<'a> {
    Addr(ReturnAddress),
    StackMap(StackMapFrameInfo<'a>),
}

#[derive(Debug)]
struct StackMapFrameInfo<'a> {
    addr: ReturnAddress,
    patchpoint_id: u64,
    instruction_offset: u32,
    locations: &'a [Location],
    live_outs: &'a [LiveOut],
}

trait StackMapExt {
    fn frame_info(&self, addr: ReturnAddress) -> FrameInfo;
}

impl StackMapExt for StackMap {
    fn frame_info(&self, addr: ReturnAddress) -> FrameInfo {
        let mut frame_info = None;

        debug!("");
        debug!("addr: {:?}", addr);

	if let Some(_base) = dlinfo_fbase(addr.0) {
            // Okay, we have a base address for the shared object of addr

            // We still need to find the function itself as well as
            // the call-site within it; here's a naive way to do it.
            //
            // FIXME: build structure ahead of time that allows
            // something faster than this linear scan.
            for r in self.records() {
                let fn_address = address_id(r.patchpoint_id()).unwrap();
                let instr_offset = r.instruction_offset() as usize;
                let call_address = fn_address + instr_offset;

                debug!("frame_info addr {:?} \
                                     record {:?} \
                                     fn_address: 0x{:x} \
                                     instr_offset: {:?} \
                                     call_address: 0x{:x} \
                                     delta: {}",
                         addr, r, fn_address, instr_offset, call_address,
                         call_address as isize - (addr.0 as isize));

                if call_address == addr.0 as usize {
                    assert!(frame_info.is_none());
                    frame_info = Some(StackMapFrameInfo {
                        addr: addr,
                        patchpoint_id: r.patchpoint_id(),
                        instruction_offset: r.instruction_offset(),
                        locations: r.locations(),
                        live_outs: r.live_outs(),
                    })
                }
            }
        } else {
            println!("frame_info no fbase for {:?}", addr);
        }

        if let Some(frame_info) = frame_info {
            FrameInfo::StackMap(frame_info)
        } else {
            FrameInfo::Addr(addr)
        }
    }
}

#[no_mangle]
pub extern "C" fn subcall_3(_data: *mut u8) {
    println!("Start `subcall_3`");

    let map = unsafe { STACK_MAP.get() };
    println!("map:                              {:?}", map);
    unsafe {
        for i in 0..ADDRESS_IDS.len() {
            println!("ADDRESS_IDS[i] 0x{:x}", ADDRESS_IDS[i]);
        }
    }

    let unw = unwind_hack::UnwindContext::new();
    let mut cursor = Some(unw.cursor());

    while let Some(c) = cursor {
        let ip = c.get_reg(unwind_hack::UNW_REG_IP).unwrap();
        let sp = c.get_reg(unwind_hack::UNW_REG_SP).unwrap();
        debug!("ip: 0x{:x} sp: 0x{:x}", ip, sp);
        let opt_fbase = backtrace_hack::dlinfo_fbase(ip as *const libc::c_void);
        debug!("dlinfo_fbase: {:?}", opt_fbase);
        if let Some(fbase) = opt_fbase {
            debug!("dlrel ip: 0x{:x}", ip - (fbase as u64));
        }

        let (offset, name) = {
            let mut buf = Vec::with_capacity(256);
            match c.get_proc_name(&mut buf) {
                Err(e) => {
                    println!("failed to .get_proc_name from subcall_3: {:?}", e);
                    cursor = c.step().unwrap();
                    println!("");
                    continue;
                }
                Ok(offset) => (offset, String::from_utf8(buf).unwrap()),
            }
        };
        debug!("ip: 0x{:08x} name: {} offset: {}", ip, name, offset);
        debug!("start of fn:  0x{:08x}", ip - offset);
        if let Some(fbase) = opt_fbase {
            debug!("rel start of fn:  0x{:08x}", ip - offset - (fbase as u64));
        }
        for (i, rec) in map.records().iter().enumerate() {
            if address_id(rec.patchpoint_id()) == Some((ip - offset) as usize) &&
                rec.instruction_offset() as u64 == offset
            {
                println!("found match at ({}) for `{}`: {:?}", i, name, rec);
                for (j, loc) in rec.locations().iter().enumerate() {
                    let loc_interpreted: i64 = match *loc.variant() {
                        LocationVariant::Register { dwarf_regnum } => {
                            c.get_reg(dwarf_regnum as unw_regnum_t).unwrap() as i64
                        }
                        LocationVariant::Direct { dwarf_regnum, offset } => {
                            c.get_reg(dwarf_regnum as unw_regnum_t).unwrap() as i64 + offset as i64
                        }
                        LocationVariant::Indirect { dwarf_regnum, offset } => {
                            unsafe {
                                *((c.get_reg(dwarf_regnum as unw_regnum_t).unwrap() as i64 +
                                   offset as i64)
                                  as usize as *const usize) as i64
                            }
                        }
                        LocationVariant::Constant { value } => {
                            value as i64
                        }
                        LocationVariant::ConstIndex { offset } => {
                            unimplemented!()
                        }
                    };
                    println!("rec[{}].loc[{}] {:?} => 0x{:x}",
                             i, j, loc, loc_interpreted);
                }
            }
        }

        cursor = c.step().unwrap();
        println!("");
    }
    println!("Finis `subcall_3`");
}

#[cfg(use_backtrace_hack)]
fn subcall_3(data: *mut u8) {
    println!("Start `subcall_3`");
    let map = unsafe { STACK_MAP.get() };
    println!("map:                   {:?}", map);
    let addresses = backtrace_hack::backtrace_return_addresses();
    println!("backtrace:             {:?}", addresses);
    let dlinfos = backtrace_hack::backtrace_dlinfos(&addresses);
    println!("backtrace dlinfos:     {:?}", dlinfos);
    let frame_infos: Vec<_> = addresses.iter()
        .map(|a| map.frame_info(*a))
        .collect();
    println!("backtrace frame_infos: {:?}", frame_infos);
    println!("Finis `subcall_3`");
}

fn main() {
    let local: u32 = 0;
    unsafe { MAIN_LOCAL = &local as *const _ as usize; }
    demo().unwrap();
}

#[derive(Debug)]
pub enum DemoError {
    ParseError(elf::ParseError),
    MissingSection(String),
}

impl std::convert::From<elf::ParseError> for DemoError {
    fn from(x: elf::ParseError) -> Self { DemoError::ParseError(x) }
}

use self::llvm_stackmaps::{LiveOut, Location, StackMap};
use std::cell::UnsafeCell;

struct SharedStackMap {
    map: UnsafeCell<Option<StackMap>>
}

impl SharedStackMap {
    /// Initializes the map. Unsafe because it does not attempt to
    /// enforce thread safety in any way: its your own job to make
    /// sure you do this once and only once.
    unsafe fn initialize(&self, map: StackMap) { *self.map.get() = Some(map); }
    const fn new() -> Self { SharedStackMap { map: UnsafeCell::new(None) } }
    unsafe fn get(&self) -> &'static StackMap {
        (*self.map.get()).as_ref().expect("Cannot get an uninitialized stack map")
    }
}

/// I am going to manually ensure that all clients of SharedStackMap access
/// it in solely a read-only fashion.
unsafe impl Sync for SharedStackMap { }

static STACK_MAP: SharedStackMap = SharedStackMap::new();
static mut ADDRESS_IDS: [usize; 3] = [0; 3];
fn address_id(patchpoint_id: u64) -> Option<usize> {
    unsafe {
        if patchpoint_id > ::std::usize::MAX as u64 { return None; }
        let idx = patchpoint_id as usize;
        if idx >= ADDRESS_IDS.len() { return None; }
        Some(ADDRESS_IDS[idx])
    }
}

fn initialize_shared_state() -> Result<(), DemoError> {
    use std::path::Path;
    use self::byteorder::LittleEndian;

    // FIXME: LLVM's stackmap/patchpoint intrinsic API does
    // not embed the identity of the function context where the
    // stackmap/patchpoint.
    //
    // It instead requires each stackmap/patchpoint invocation to
    // include a (globally unique) 64-bit ID, known at compile time.
    //
    // The problem for me is that it means that I have the
    // responsibility of building a mapping from functions to their
    // unique ID's, just so I can map from the return address to the
    // appropriate stackmap record. :(
    //
    // (I do not quite understand why they made this so hard;
    // presumably it is because the stackmap/patchpoint interface was
    // designed for use in JITs, not in AOT compilers.)
    //
    // In any case, for now I can just hardcode a table with the
    // necessary mapping from patchpoint IDs to function addresses.
    // (And hopefully I can hack the Rust backend to generate a table
    // like this automatically, though ensuring the IDs are unique
    // will be a bit harder than what I do here. I guess for that
    // I might as well re-use the SVH approach... we'll cross that
    // bridge when we get to it.)
    unsafe {
        ADDRESS_IDS[DEMO_ID as usize] = demo as usize;
        ADDRESS_IDS[SUBCALL1_ID as usize] = subcall_1 as usize;
        ADDRESS_IDS[SUBCALL2_ID as usize] = subcall_2 as usize;
    }

    // FIXME: this is not a reliable way to extract the executable file path.
    // (look into alternatives)
    let binary = std::env::args().next().unwrap();

    println!("Hello World from {}", binary);

    let path = Path::new(&binary);
    let file = elf::File::open_path(&path)?;

    let stackmap_section = {
        let name = ".llvm_stackmaps".to_string();
        file.get_section(name.clone())
            .ok_or_else(|| DemoError::MissingSection(name))?
    };

    println!("stackmap_section: {:?}", stackmap_section);

    let stack_map = StackMap::read_from::<LittleEndian>(&mut &stackmap_section.data[..]);
    println!("stack_map: {:?}", stack_map);
    let map = stack_map.expect("Cannot do demo without valid stack map");
    unsafe { STACK_MAP.initialize(map); }
    Ok(())
}

#[no_mangle]
// #[rustc_mir(borrowck_graphviz_postflow="/tmp/foo.dot")]
pub fn demo() -> Result<(), DemoError> {
    try!(initialize_shared_state());

    let mut data = vec![b'h', b'e', b'l', b'l', b'o', 0];
    println!("data addr: {:?}", &data as *const _);

    unsafe {
        intrinsics::stackmap_call(DEMO_ID, 0, subcall_1, data.as_mut_ptr());
        // intrinsics::patchpoint_call(DEMO_ID, 13, subcall_1, data.as_mut_ptr());
    }

    println!("Goodbye World");

    Ok(())
}
<commit_msg>experiments after shifting to patchpoint-scanning-take3 branch.<commit_after>#![feature(core_intrinsics, patchpoint_call_intrinsic, stackmap_call_intrinsic)]
#![feature(question_mark)]
// #![feature(type_ascription)]
// #![feature(rustc_attrs)]
#![feature(libc)]
#![feature(const_fn)]
#![feature(rustc_private)]
#![feature(linkage)]
#![feature(drop_types_in_const)]
#![feature(unboxed_closures)]
#![allow(unused_features)]

extern crate libc;
#[macro_use] extern crate log;

extern crate util;

pub use util::*;
use util::unwind_hack::{unw_regnum_t};
use util::llvm_stackmaps::LocationVariant;

use elf::Section;

use std::intrinsics;

const DEMO_ID: i64 = 0;
const SUBCALL1_ID: i64 = 1;
const SUBCALL2_ID: i64 = 2;

#[no_mangle]
pub fn subcall_1(data: *mut u8) {
    println!("Enter `subcall_1`");
    unsafe {
        intrinsics::stackmap_call(SUBCALL1_ID, 0, subcall_2, data);
        // intrinsics::patchpoint_call(SUBCALL1_ID, 13, subcall_2, data);
    }
    println!("Finis `subcall_1`");
}

#[linkage="external"]
fn subcall_2(data: *mut u8) {
    println!("Enter `subcall_2`");
    let mut i = 0;
    let mut saw_one = false;
    print!("[");
    let mut datum = unsafe { *data.offset(i) as char };
    while datum != '\0' {
        if saw_one {
            print!(", ");
        }
        print!("{}", datum);
        saw_one = true;
        i += 1;
        datum = unsafe { *data.offset(i) as char };
    }
    println!("]");
    unsafe {
        intrinsics::stackmap_call(SUBCALL2_ID, 0, subcall_3, data);
        // intrinsics::patchpoint_call(SUBCALL2_ID, 13, subcall_3, data);

    }
    println!("Finis `subcall_2`");
}

use self::backtrace_hack::ReturnAddress;
use self::backtrace_hack::dlinfo_fbase;

#[derive(Debug)]
enum FrameInfo<'a> {
    Addr(ReturnAddress),
    StackMap(StackMapFrameInfo<'a>),
}

#[derive(Debug)]
struct StackMapFrameInfo<'a> {
    addr: ReturnAddress,
    patchpoint_id: u64,
    instruction_offset: u32,
    locations: &'a [Location],
    live_outs: &'a [LiveOut],
}

trait StackMapExt {
    fn frame_info(&self, addr: ReturnAddress) -> FrameInfo;
}

impl StackMapExt for StackMap {
    fn frame_info(&self, addr: ReturnAddress) -> FrameInfo {
        let mut frame_info = None;

        debug!("");
        debug!("addr: {:?}", addr);

	if let Some(_base) = dlinfo_fbase(addr.0) {
            // Okay, we have a base address for the shared object of addr

            // We still need to find the function itself as well as
            // the call-site within it; here's a naive way to do it.
            //
            // FIXME: build structure ahead of time that allows
            // something faster than this linear scan.
            for r in self.records() {
                let fn_address = address_id(r.patchpoint_id()).unwrap();
                let instr_offset = r.instruction_offset() as usize;
                let call_address = fn_address + instr_offset;

                debug!("frame_info addr {:?} \
                                     record {:?} \
                                     fn_address: 0x{:x} \
                                     instr_offset: {:?} \
                                     call_address: 0x{:x} \
                                     delta: {}",
                         addr, r, fn_address, instr_offset, call_address,
                         call_address as isize - (addr.0 as isize));

                if call_address == addr.0 as usize {
                    assert!(frame_info.is_none());
                    frame_info = Some(StackMapFrameInfo {
                        addr: addr,
                        patchpoint_id: r.patchpoint_id(),
                        instruction_offset: r.instruction_offset(),
                        locations: r.locations(),
                        live_outs: r.live_outs(),
                    })
                }
            }
        } else {
            println!("frame_info no fbase for {:?}", addr);
        }

        if let Some(frame_info) = frame_info {
            FrameInfo::StackMap(frame_info)
        } else {
            FrameInfo::Addr(addr)
        }
    }
}

#[no_mangle]
pub fn subcall_3(_data: *mut u8) {
    println!("Start `subcall_3`");

    let map = unsafe { STACK_MAP.get() };
    println!("map:                              {:?}", map);
    unsafe {
        for i in 0..ADDRESS_IDS.len() {
            println!("ADDRESS_IDS[i] 0x{:x}", ADDRESS_IDS[i]);
        }
    }

    let unw = unwind_hack::UnwindContext::new();
    let mut cursor = Some(unw.cursor());

    while let Some(c) = cursor {
        let ip = c.get_reg(unwind_hack::UNW_REG_IP).unwrap();
        let sp = c.get_reg(unwind_hack::UNW_REG_SP).unwrap();
        debug!("ip: 0x{:x} sp: 0x{:x}", ip, sp);
        let opt_fbase = backtrace_hack::dlinfo_fbase(ip as *const libc::c_void);
        debug!("dlinfo_fbase: {:?}", opt_fbase);
        if let Some(fbase) = opt_fbase {
            debug!("dlrel ip: 0x{:x}", ip - (fbase as u64));
        }

        let (offset, name) = {
            let mut buf = Vec::with_capacity(256);
            match c.get_proc_name(&mut buf) {
                Err(e) => {
                    println!("failed to .get_proc_name from subcall_3: {:?}", e);
                    cursor = c.step().unwrap();
                    println!("");
                    continue;
                }
                Ok(offset) => (offset, String::from_utf8(buf).unwrap()),
            }
        };
        debug!("ip: 0x{:08x} name: {} offset: {}", ip, name, offset);
        debug!("start of fn:  0x{:08x}", ip - offset);
        if let Some(fbase) = opt_fbase {
            debug!("rel start of fn:  0x{:08x}", ip - offset - (fbase as u64));
        }
        for (i, rec) in map.records().iter().enumerate() {
            if address_id(rec.patchpoint_id()) == Some((ip - offset) as usize) &&
                rec.instruction_offset() as u64 == offset
            {
                println!("found match at ({}) for `{}`: {:?}", i, name, rec);
                for (j, loc) in rec.locations().iter().enumerate() {
                    let loc_interpreted: i64 = match *loc.variant() {
                        LocationVariant::Register { dwarf_regnum } => {
                            c.get_reg(dwarf_regnum as unw_regnum_t).unwrap() as i64
                        }
                        LocationVariant::Direct { dwarf_regnum, offset } => {
                            c.get_reg(dwarf_regnum as unw_regnum_t).unwrap() as i64 + offset as i64
                        }
                        LocationVariant::Indirect { dwarf_regnum, offset } => {
                            unsafe {
                                *((c.get_reg(dwarf_regnum as unw_regnum_t).unwrap() as i64 +
                                   offset as i64)
                                  as usize as *const usize) as i64
                            }
                        }
                        LocationVariant::Constant { value } => {
                            value as i64
                        }
                        LocationVariant::ConstIndex { offset } => {
                            unimplemented!()
                        }
                    };
                    println!("rec[{}].loc[{}] {:?} => 0x{:x}",
                             i, j, loc, loc_interpreted);
                }
            }
        }

        cursor = c.step().unwrap();
        println!("");
    }
    println!("Finis `subcall_3`");
}

#[cfg(use_backtrace_hack)]
fn subcall_3(data: *mut u8) {
    println!("Start `subcall_3`");
    let map = unsafe { STACK_MAP.get() };
    println!("map:                   {:?}", map);
    let addresses = backtrace_hack::backtrace_return_addresses();
    println!("backtrace:             {:?}", addresses);
    let dlinfos = backtrace_hack::backtrace_dlinfos(&addresses);
    println!("backtrace dlinfos:     {:?}", dlinfos);
    let frame_infos: Vec<_> = addresses.iter()
        .map(|a| map.frame_info(*a))
        .collect();
    println!("backtrace frame_infos: {:?}", frame_infos);
    println!("Finis `subcall_3`");
}

fn main() {
    let local: u32 = 0;
    unsafe { MAIN_LOCAL = &local as *const _ as usize; }
    demo().unwrap();
}

#[derive(Debug)]
pub enum DemoError {
    ParseError(elf::ParseError),
    MissingSection(String),
}

impl std::convert::From<elf::ParseError> for DemoError {
    fn from(x: elf::ParseError) -> Self { DemoError::ParseError(x) }
}

use self::llvm_stackmaps::{LiveOut, Location, StackMap};
use std::cell::UnsafeCell;

struct SharedStackMap {
    map: UnsafeCell<Option<StackMap>>
}

impl SharedStackMap {
    /// Initializes the map. Unsafe because it does not attempt to
    /// enforce thread safety in any way: its your own job to make
    /// sure you do this once and only once.
    unsafe fn initialize(&self, map: StackMap) { *self.map.get() = Some(map); }
    const fn new() -> Self { SharedStackMap { map: UnsafeCell::new(None) } }
    unsafe fn get(&self) -> &'static StackMap {
        (*self.map.get()).as_ref().expect("Cannot get an uninitialized stack map")
    }
}

/// I am going to manually ensure that all clients of SharedStackMap access
/// it in solely a read-only fashion.
unsafe impl Sync for SharedStackMap { }

static STACK_MAP: SharedStackMap = SharedStackMap::new();
static mut ADDRESS_IDS: [usize; 3] = [0; 3];
fn address_id(patchpoint_id: u64) -> Option<usize> {
    unsafe {
        if patchpoint_id > ::std::usize::MAX as u64 { return None; }
        let idx = patchpoint_id as usize;
        if idx >= ADDRESS_IDS.len() { return None; }
        Some(ADDRESS_IDS[idx])
    }
}

#[derive(Debug)]
pub struct FnPtrData(i64, *const libc::c_void);

impl FnPtrData {
    const fn new<T, F>(id: i64, f: *const F) -> Self where F: Fn<T> {
        FnPtrData(id, f as *const libc::c_void)
    }
}

unsafe impl Sync for FnPtrData { }

#[link_section = ".fn_id_data"]
pub static DEMO_ID_DATA: FnPtrData = FnPtrData::new(DEMO_ID, &demo);

#[link_section = ".fn_id_data"]
pub static SUBCALL1_ID_DATA: FnPtrData = FnPtrData::new(SUBCALL1_ID, &subcall_1);

#[link_section = ".fn_id_data"]
pub static SUBCALL2_ID_DATA: FnPtrData = FnPtrData::new(SUBCALL2_ID, &subcall_2);

fn my_binary() -> Result<elf::File, elf::ParseError> {
    use std::path::Path;
    // FIXME: this is not a reliable way to extract the executable file path.
    // (look into alternatives)
    let binary = std::env::args().next().unwrap();

    println!("Hello World from {}", binary);

    let path = Path::new(&binary);
    elf::File::open_path(&path)
}

fn my_section<'a>(file: &'a elf::File, section_name: &str) -> Result<&'a Section, DemoError> {
    let name = section_name.to_string();
    file.get_section(name.clone())
        .ok_or_else(|| DemoError::MissingSection(name))
}

fn fn_ids(file: &elf::File) -> Result<&[FnPtrData], DemoError> {
    Ok(unsafe { ::std::mem::transmute(&my_section(file, ".fn_id_data")?.data[..]) })
}

fn initialize_shared_state() -> Result<(), DemoError> {
    use self::byteorder::LittleEndian;

    // FIXME: LLVM's stackmap/patchpoint intrinsic API does
    // not embed the identity of the function context where the
    // stackmap/patchpoint.
    //
    // It instead requires each stackmap/patchpoint invocation to
    // include a (globally unique) 64-bit ID, known at compile time.
    //
    // The problem for me is that it means that I have the
    // responsibility of building a mapping from functions to their
    // unique ID's, just so I can map from the return address to the
    // appropriate stackmap record. :(
    //
    // (I do not quite understand why they made this so hard;
    // presumably it is because the stackmap/patchpoint interface was
    // designed for use in JITs, not in AOT compilers.)
    //
    // In any case, for now I can just hardcode a table with the
    // necessary mapping from patchpoint IDs to function addresses.
    // (And hopefully I can hack the Rust backend to generate a table
    // like this automatically, though ensuring the IDs are unique
    // will be a bit harder than what I do here. I guess for that
    // I might as well re-use the SVH approach... we'll cross that
    // bridge when we get to it.)
    unsafe {
        ADDRESS_IDS[DEMO_ID as usize] = demo as usize;
        ADDRESS_IDS[SUBCALL1_ID as usize] = subcall_1 as usize;
        ADDRESS_IDS[SUBCALL2_ID as usize] = subcall_2 as usize;
    }

    let file = my_binary()?;
    let fn_id_data = fn_ids(&file)?;
    println!("fn_id_data section: {:?}", fn_id_data);
    unsafe {
        println!("ADDRESS_IDS: 0x{:x} 0x{:x} 0x{:x}", ADDRESS_IDS[0], ADDRESS_IDS[1], ADDRESS_IDS[2]);
    }

    let stackmap_section = my_section(&file, ".llvm_stackmaps")?;
    println!("stackmap_section: {:?}", stackmap_section);

    let stack_map = StackMap::read_from::<LittleEndian>(&mut &stackmap_section.data[..]);
    println!("stack_map: {:?}", stack_map);
    let map = stack_map.expect("Cannot do demo without valid stack map");
    unsafe { STACK_MAP.initialize(map); }
    Ok(())
}

#[no_mangle]
// #[rustc_mir(borrowck_graphviz_postflow="/tmp/foo.dot")]
pub fn demo() -> Result<(), DemoError> {
    try!(initialize_shared_state());

    let mut data = vec![b'h', b'e', b'l', b'l', b'o', 0];
    println!("data addr: {:?}", &data as *const _);

    unsafe {
        intrinsics::stackmap_call(DEMO_ID, 0, subcall_1, data.as_mut_ptr());
        // intrinsics::patchpoint_call(DEMO_ID, 13, subcall_1, data.as_mut_ptr());
    }

    println!("Goodbye World");

    Ok(())
}
<|endoftext|>


<commit_before>extern crate walkdir;
extern crate chrono;

use std::path;
use self::walkdir::{WalkDir, DirEntry, Error as WalkDirError};
use std::fs::File;
use std::io::BufReader;
use std::io::BufRead;
use self::chrono::{DateTime, UTC};
use std::error::Error;
use std::str::FromStr;
use std::net::SocketAddrV4;

pub struct ELBLogEntry {
    timestamp: DateTime<UTC>,
    elb_name: String,
    client_address: SocketAddrV4,
    backend_address: SocketAddrV4,
    request_processing_time: f32,
    backend_processing_time: f32,
    response_processing_time: f32,
    elb_status_code: u16,
    backend_status_code: u16,
    received_bytes: u64,
    sent_bytes: u64,
    request_method: String,
    request_url: String,
    request_http_version: String
}

pub fn file_list(dir: &path::Path, filenames: &mut Vec<DirEntry>) -> Result<usize, WalkDirError> {
    for entry in WalkDir::new(dir).min_depth(1) {
        match entry {
            Err(err) => return Err(err),
            Ok(entry) => filenames.push(entry),
        }
    }
    Ok(filenames.len())
}

pub fn process_files(runtime_context: &::RuntimeContext, filenames: Vec<walkdir::DirEntry>) -> usize {
    let debug = runtime_context.debug;
    let mut record_count = 0;
    for filename in filenames {
        debug!(debug, "Processing file {}.", filename.path().display());
        match File::open(filename.path()) {
            Ok(file) => {
                let buffered_file = BufReader::new(&file);
                let recs: Vec<_> = buffered_file.lines()
                    .map(|x| {
                        parse_line(&(x.unwrap()))
                    })
                    .collect();
                record_count += recs.len();
                debug!(debug, "Found {} records in file {}.", recs.len(), filename.path().display());
            },
            Err(e) => {
                println!("ERROR: {}", e);
            }
        }
    }

    record_count
}

#[derive(Debug)]
pub struct ParsingError{
    property: &'static str,
    inner_description: Box<Error>,
}

#[derive(Debug)]
pub struct ParsingErrors {
    record: String,
    errors: Vec<ParsingError>,
}

const TIMESTAMP: &'static str = "timestamp";
const CLIENT_ADDRESS: &'static str = "client address";
const BACKEND_ADDRESS: &'static str = "backend address";
const REQUEST_PROCESSING_TIME: &'static str = "request processing time";
const BACKEND_PROCESSING_TIME: &'static str = "backend processing time";
const RESPONSE_PROCESSING_TIME: &'static str = "response processing time";
const ELB_STATUS_CODE: &'static str = "ELB status code";
const BE_STATUS_CODE: &'static str = "backend status code";
const RECEIVED_BYTES: &'static str = "received bytes";
const SENT_BYTES: &'static str = "sent bytes";

pub fn parse_line(line: &String) -> Result<Box<ELBLogEntry>, Box<ParsingErrors>> {
    let split_line: Vec<_> = line.split(" ").collect();
    let mut errors: Vec<ParsingError> = Vec::new();

    let ts = parse_property::<DateTime<UTC>>(split_line[0], TIMESTAMP, &mut errors);
    let clnt_addr = parse_property::<SocketAddrV4>(split_line[2], CLIENT_ADDRESS, &mut errors);
    let be_addr = parse_property::<SocketAddrV4>(split_line[3], BACKEND_ADDRESS, &mut errors);
    let req_proc_time = parse_property::<f32>(split_line[4], REQUEST_PROCESSING_TIME, &mut errors);
    let be_proc_time = parse_property::<f32>(split_line[5], BACKEND_PROCESSING_TIME, &mut errors);
    let res_proc_time = parse_property::<f32>(split_line[6], RESPONSE_PROCESSING_TIME, &mut errors);
    let elb_sc = parse_property::<u16>(split_line[7], ELB_STATUS_CODE, &mut errors);
    let be_sc = parse_property::<u16>(split_line[8], BE_STATUS_CODE, &mut errors);
    let bytes_received = parse_property::<u64>(split_line[9], RECEIVED_BYTES, &mut errors);
    let bytes_sent = parse_property::<u64>(split_line[10], SENT_BYTES, &mut errors);

    if errors.is_empty() {
        Ok(Box::new(
            ELBLogEntry {
                timestamp: ts.unwrap(),
                elb_name: split_line[1].to_string(),
                client_address: clnt_addr.unwrap(),
                backend_address: be_addr.unwrap(),
                request_processing_time: req_proc_time.unwrap(),
                backend_processing_time: be_proc_time.unwrap(),
                response_processing_time: res_proc_time.unwrap(),
                elb_status_code: elb_sc.unwrap(),
                backend_status_code: be_sc.unwrap(),
                received_bytes: bytes_received.unwrap(),
                sent_bytes: bytes_sent.unwrap(),
                request_method: split_line[11].trim_matches('"').to_string(),
                request_url: split_line[12].to_string(),
                request_http_version: split_line[13].trim_matches('"').to_string()
            }
        ))
    } else {
        Err(Box::new(
            ParsingErrors {
                record: line.clone(),
                errors: errors
            }
        ))
    }
}

fn parse_property<T>(raw_prop: &str, prop_name: &'static str, errors: &mut Vec<ParsingError>) -> Option<T>
    where T: FromStr,
    T::Err: Error + 'static,
{
    match raw_prop.parse::<T>() {
        Ok(parsed) => Some(parsed),

        Err(e) => {
            errors.push(
                ParsingError {
                    property: prop_name,
                    inner_description: Box::new(e),
                }
            );
            None
        }
    }
}

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

    const TEST_LINE: &'static str = "2015-08-15T23:43:05.302180Z elb-name 172.16.1.6:54814 \
    172.16.1.5:9000 0.000039 0.145507 0.00003 200 200 0 7582 \
    \"GET http://some.domain.com:80/path0/path1?param0=p0&param1=p1 HTTP/1.1\" \
    ";

    #[test]
	fn parse_line_returns_a_log_entry_with_the_request_http_version() {
        let elb_log_entry = parse_line(&TEST_LINE.to_string()).unwrap();

		assert_eq!(elb_log_entry.request_http_version, "HTTP/1.1")
	}

    #[test]
	fn parse_line_returns_a_log_entry_with_the_request_url() {
        let elb_log_entry = parse_line(&TEST_LINE.to_string()).unwrap();

		assert_eq!(elb_log_entry.request_url, "http://some.domain.com:80/path0/path1?param0=p0&param1=p1")
	}

    #[test]
	fn parse_line_returns_a_log_entry_with_the_request_method() {
        let elb_log_entry = parse_line(&TEST_LINE.to_string()).unwrap();

		assert_eq!(elb_log_entry.request_method, "GET")
	}

    #[test]
	fn parse_line_returns_a_log_entry_with_the_sent_bytes() {
        let elb_log_entry = parse_line(&TEST_LINE.to_string()).unwrap();

		assert_eq!(elb_log_entry.sent_bytes, 7582)
	}

    #[test]
	fn parse_line_returns_a_log_entry_with_the_received_bytes() {
        let elb_log_entry = parse_line(&TEST_LINE.to_string()).unwrap();

		assert_eq!(elb_log_entry.received_bytes, 0)
	}

    #[test]
	fn parse_line_returns_a_log_entry_with_the_backend_status_code() {
        let elb_log_entry = parse_line(&TEST_LINE.to_string()).unwrap();

		assert_eq!(elb_log_entry.backend_status_code, 200)
	}

    #[test]
	fn parse_line_returns_a_log_entry_with_the_elb_status_code() {
        let elb_log_entry = parse_line(&TEST_LINE.to_string()).unwrap();

		assert_eq!(elb_log_entry.elb_status_code, 200)
	}

    #[test]
	fn parse_line_returns_a_log_entry_with_the_response_processing_time() {
        let elb_log_entry = parse_line(&TEST_LINE.to_string()).unwrap();

		assert_eq!(elb_log_entry.response_processing_time, 0.00003)
	}

    #[test]
	fn parse_line_returns_a_log_entry_with_the_backend_processing_time() {
        let elb_log_entry = parse_line(&TEST_LINE.to_string()).unwrap();

		assert_eq!(elb_log_entry.backend_processing_time, 0.145507)
	}

    #[test]
	fn parse_line_returns_a_log_entry_with_the_request_processing_time() {
        let elb_log_entry = parse_line(&TEST_LINE.to_string()).unwrap();

		assert_eq!(elb_log_entry.request_processing_time, 0.000039)
	}

    #[test]
	fn parse_line_returns_a_log_entry_with_the_backend_address() {
        let elb_log_entry = parse_line(&TEST_LINE.to_string()).unwrap();

		assert_eq!(elb_log_entry.backend_address, "172.16.1.5:9000".parse().unwrap())
	}

    #[test]
	fn parse_line_returns_a_log_entry_with_the_client_address() {
        let elb_log_entry = parse_line(&TEST_LINE.to_string()).unwrap();

		assert_eq!(elb_log_entry.client_address, "172.16.1.6:54814".parse().unwrap())
	}

    #[test]
	fn parse_line_returns_a_log_entry_with_the_timestamp() {
        let elb_log_entry = parse_line(&TEST_LINE.to_string()).unwrap();

		assert_eq!(format!("{:?}", elb_log_entry.timestamp), "2015-08-15T23:43:05.302180Z")
	}

    #[test]
	fn parse_line_returns_a_log_entry_with_the_elb_name() {
        let elb_log_entry = parse_line(&TEST_LINE.to_string()).unwrap();

		assert_eq!(elb_log_entry.elb_name, "elb-name")
	}
}
<commit_msg>Added todos.<commit_after>extern crate walkdir;
extern crate chrono;

use std::path;
use self::walkdir::{WalkDir, DirEntry, Error as WalkDirError};
use std::fs::File;
use std::io::BufReader;
use std::io::BufRead;
use self::chrono::{DateTime, UTC};
use std::error::Error;
use std::str::FromStr;
use std::net::SocketAddrV4;

pub struct ELBLogEntry {
    timestamp: DateTime<UTC>,
    elb_name: String,
    client_address: SocketAddrV4,
    backend_address: SocketAddrV4,
    request_processing_time: f32,
    backend_processing_time: f32,
    response_processing_time: f32,
    elb_status_code: u16,
    backend_status_code: u16,
    received_bytes: u64,
    sent_bytes: u64,
    request_method: String,
    request_url: String,
    request_http_version: String
}

pub fn file_list(dir: &path::Path, filenames: &mut Vec<DirEntry>) -> Result<usize, WalkDirError> {
    for entry in WalkDir::new(dir).min_depth(1) {
        match entry {
            Err(err) => return Err(err),
            Ok(entry) => filenames.push(entry),
        }
    }
    Ok(filenames.len())
}

//TODO Reconsider logging based on the standard interfaces included with Rust.
//TODO We really want to accept a function to handle the parsed lines.
pub fn process_files(runtime_context: &::RuntimeContext, filenames: Vec<walkdir::DirEntry>) -> usize {
    let debug = runtime_context.debug;
    let mut record_count = 0;
    for filename in filenames {
        debug!(debug, "Processing file {}.", filename.path().display());
        match File::open(filename.path()) {
            Ok(file) => {
                let buffered_file = BufReader::new(&file);
                let recs: Vec<_> = buffered_file.lines()
                    .map(|x| {
                        parse_line(&(x.unwrap()))
                    })
                    .collect();
                record_count += recs.len();
                debug!(debug, "Found {} records in file {}.", recs.len(), filename.path().display());
            },
            Err(e) => {
                println!("ERROR: {}", e);
            }
        }
    }

    record_count
}

//TODO Take a look at the error handling once again.  This doesn't feel write given code you've read.
#[derive(Debug)]
pub struct ParsingError{
    property: &'static str,
    inner_description: Box<Error>,
}

#[derive(Debug)]
pub struct ParsingErrors {
    record: String,
    errors: Vec<ParsingError>,
}

const TIMESTAMP: &'static str = "timestamp";
const CLIENT_ADDRESS: &'static str = "client address";
const BACKEND_ADDRESS: &'static str = "backend address";
const REQUEST_PROCESSING_TIME: &'static str = "request processing time";
const BACKEND_PROCESSING_TIME: &'static str = "backend processing time";
const RESPONSE_PROCESSING_TIME: &'static str = "response processing time";
const ELB_STATUS_CODE: &'static str = "ELB status code";
const BE_STATUS_CODE: &'static str = "backend status code";
const RECEIVED_BYTES: &'static str = "received bytes";
const SENT_BYTES: &'static str = "sent bytes";

pub fn parse_line(line: &String) -> Result<Box<ELBLogEntry>, Box<ParsingErrors>> {
    let split_line: Vec<_> = line.split(" ").collect();
    let mut errors: Vec<ParsingError> = Vec::new();

    //TODO consider an enum representing the idices
    let ts = parse_property::<DateTime<UTC>>(split_line[0], TIMESTAMP, &mut errors);
    let clnt_addr = parse_property::<SocketAddrV4>(split_line[2], CLIENT_ADDRESS, &mut errors);
    let be_addr = parse_property::<SocketAddrV4>(split_line[3], BACKEND_ADDRESS, &mut errors);
    let req_proc_time = parse_property::<f32>(split_line[4], REQUEST_PROCESSING_TIME, &mut errors);
    let be_proc_time = parse_property::<f32>(split_line[5], BACKEND_PROCESSING_TIME, &mut errors);
    let res_proc_time = parse_property::<f32>(split_line[6], RESPONSE_PROCESSING_TIME, &mut errors);
    let elb_sc = parse_property::<u16>(split_line[7], ELB_STATUS_CODE, &mut errors);
    let be_sc = parse_property::<u16>(split_line[8], BE_STATUS_CODE, &mut errors);
    let bytes_received = parse_property::<u64>(split_line[9], RECEIVED_BYTES, &mut errors);
    let bytes_sent = parse_property::<u64>(split_line[10], SENT_BYTES, &mut errors);

    if errors.is_empty() {
        Ok(Box::new(
            ELBLogEntry {
                timestamp: ts.unwrap(),
                elb_name: split_line[1].to_string(),
                client_address: clnt_addr.unwrap(),
                backend_address: be_addr.unwrap(),
                request_processing_time: req_proc_time.unwrap(),
                backend_processing_time: be_proc_time.unwrap(),
                response_processing_time: res_proc_time.unwrap(),
                elb_status_code: elb_sc.unwrap(),
                backend_status_code: be_sc.unwrap(),
                received_bytes: bytes_received.unwrap(),
                sent_bytes: bytes_sent.unwrap(),
                request_method: split_line[11].trim_matches('"').to_string(),
                request_url: split_line[12].to_string(),
                request_http_version: split_line[13].trim_matches('"').to_string()
            }
        ))
    } else {
        Err(Box::new(
            ParsingErrors {
                record: line.clone(),
                errors: errors
            }
        ))
    }
}

fn parse_property<T>(raw_prop: &str, prop_name: &'static str, errors: &mut Vec<ParsingError>) -> Option<T>
    where T: FromStr,
    T::Err: Error + 'static,
{
    match raw_prop.parse::<T>() {
        Ok(parsed) => Some(parsed),

        Err(e) => {
            errors.push(
                ParsingError {
                    property: prop_name,
                    inner_description: Box::new(e),
                }
            );
            None
        }
    }
}

//TODO test the error case.

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

    const TEST_LINE: &'static str = "2015-08-15T23:43:05.302180Z elb-name 172.16.1.6:54814 \
    172.16.1.5:9000 0.000039 0.145507 0.00003 200 200 0 7582 \
    \"GET http://some.domain.com:80/path0/path1?param0=p0&param1=p1 HTTP/1.1\" \
    ";

    #[test]
	fn parse_line_returns_a_log_entry_with_the_request_http_version() {
        let elb_log_entry = parse_line(&TEST_LINE.to_string()).unwrap();

		assert_eq!(elb_log_entry.request_http_version, "HTTP/1.1")
	}

    #[test]
	fn parse_line_returns_a_log_entry_with_the_request_url() {
        let elb_log_entry = parse_line(&TEST_LINE.to_string()).unwrap();

		assert_eq!(elb_log_entry.request_url, "http://some.domain.com:80/path0/path1?param0=p0&param1=p1")
	}

    #[test]
	fn parse_line_returns_a_log_entry_with_the_request_method() {
        let elb_log_entry = parse_line(&TEST_LINE.to_string()).unwrap();

		assert_eq!(elb_log_entry.request_method, "GET")
	}

    #[test]
	fn parse_line_returns_a_log_entry_with_the_sent_bytes() {
        let elb_log_entry = parse_line(&TEST_LINE.to_string()).unwrap();

		assert_eq!(elb_log_entry.sent_bytes, 7582)
	}

    #[test]
	fn parse_line_returns_a_log_entry_with_the_received_bytes() {
        let elb_log_entry = parse_line(&TEST_LINE.to_string()).unwrap();

		assert_eq!(elb_log_entry.received_bytes, 0)
	}

    #[test]
	fn parse_line_returns_a_log_entry_with_the_backend_status_code() {
        let elb_log_entry = parse_line(&TEST_LINE.to_string()).unwrap();

		assert_eq!(elb_log_entry.backend_status_code, 200)
	}

    #[test]
	fn parse_line_returns_a_log_entry_with_the_elb_status_code() {
        let elb_log_entry = parse_line(&TEST_LINE.to_string()).unwrap();

		assert_eq!(elb_log_entry.elb_status_code, 200)
	}

    #[test]
	fn parse_line_returns_a_log_entry_with_the_response_processing_time() {
        let elb_log_entry = parse_line(&TEST_LINE.to_string()).unwrap();

		assert_eq!(elb_log_entry.response_processing_time, 0.00003)
	}

    #[test]
	fn parse_line_returns_a_log_entry_with_the_backend_processing_time() {
        let elb_log_entry = parse_line(&TEST_LINE.to_string()).unwrap();

		assert_eq!(elb_log_entry.backend_processing_time, 0.145507)
	}

    #[test]
	fn parse_line_returns_a_log_entry_with_the_request_processing_time() {
        let elb_log_entry = parse_line(&TEST_LINE.to_string()).unwrap();

		assert_eq!(elb_log_entry.request_processing_time, 0.000039)
	}

    #[test]
	fn parse_line_returns_a_log_entry_with_the_backend_address() {
        let elb_log_entry = parse_line(&TEST_LINE.to_string()).unwrap();

		assert_eq!(elb_log_entry.backend_address, "172.16.1.5:9000".parse().unwrap())
	}

    #[test]
	fn parse_line_returns_a_log_entry_with_the_client_address() {
        let elb_log_entry = parse_line(&TEST_LINE.to_string()).unwrap();

		assert_eq!(elb_log_entry.client_address, "172.16.1.6:54814".parse().unwrap())
	}

    #[test]
	fn parse_line_returns_a_log_entry_with_the_timestamp() {
        let elb_log_entry = parse_line(&TEST_LINE.to_string()).unwrap();

		assert_eq!(format!("{:?}", elb_log_entry.timestamp), "2015-08-15T23:43:05.302180Z")
	}

    #[test]
	fn parse_line_returns_a_log_entry_with_the_elb_name() {
        let elb_log_entry = parse_line(&TEST_LINE.to_string()).unwrap();

		assert_eq!(elb_log_entry.elb_name, "elb-name")
	}
}
<|endoftext|>


<commit_before>use frame::ChannelAssignment;

// Decode left and side channels to left and right channels.
//
// Two channels, left and side (difference) that transforms the difference
// into the right channel.
pub fn decode_left_side(buffer: &mut [i64]) {
  let block_size = buffer.len() / 2;

  for i in 0..block_size {
    let left = buffer[i];
    let side = buffer[i + block_size];

    // right channel
    buffer[i + block_size] = left - side;
  }
}

// Decode side and right channels to left and right channels.
//
// Two channels, side (difference) and right that transforms the difference
// into the left channel.
pub fn decode_right_side(buffer: &mut [i64]) {
  let block_size = buffer.len() / 2;

  for i in 0..block_size {
    let side  = buffer[i];
    let right = buffer[i + block_size];

    // left channel
    buffer[i] = side + right;
  }
}

// Decode midpoint and side channels to left and right channels.
//
// Two channels, midpoint (average) and side (difference) that transforms
// the average and difference into the left and right channels.
pub fn decode_midpoint_side(buffer: &mut [i64]) {
  let block_size = buffer.len() / 2;

  for i in 0..block_size {
    let mut midpoint = buffer[i];
    let side         = buffer[i + block_size];

    midpoint = (midpoint << 1) | (side & 1);

    // left and right channel
    buffer[i]              = (midpoint + side) >> 1;
    buffer[i + block_size] = (midpoint - side) >> 1;
  }
}

/// Decode the current frame buffer
///
/// * `Independent` - does nothing to buffer because this channel assignment
///   is already correct.
/// * `LeftSide` - decode left and side channels to left and right channels.
/// * `RightSide` - decode side and right channels to left and right
///   channels.
/// * `MidpointSide` - decode midpoint and side channels to left and right
///   channels.
pub fn decode(channel_assignment: ChannelAssignment, buffer: &mut [i64]) {
  match channel_assignment {
    ChannelAssignment::Independent  => return,
    ChannelAssignment::LeftSide     => decode_left_side(buffer),
    ChannelAssignment::RightSide    => decode_right_side(buffer),
    ChannelAssignment::MidpointSide => decode_midpoint_side(buffer),
  }
}

#[cfg(test)]
mod tests {
  use super::*;
  use frame::ChannelAssignment;

  #[test]
  fn test_decode_left_side() {
    let mut channels = [ 2, 5, 83, 113, 127, -63, -45, -15
                       , 7, 38, 142, 238, 0, -152, -52, -18
                       ];
    let result       = [-5, -33, -59, -125, 127, 89, 7, 3];

    decode_left_side(&mut channels);

    assert_eq!(&channels[8..16], &result);
  }

  #[test]
  fn test_decode_right_side() {
    let mut channels = [ 7, 38, 142, 238, 0, -152, -52, -18
                       , -5, -33, -59, -125, 127, 89, 7, 3
                       ];
    let result       = [2, 5, 83, 113, 127, -63, -45, -15];

    decode_right_side(&mut channels);

    assert_eq!(&channels[0..8], &result);
  }

  #[test]
  fn test_decode_midpoint_side() {
    let mut channels = [ -2, -14, 12, -6, 127, 13, -19, -6
                       , 7, 38, 142, 238, 0, -152, -52, -18
                       ];
    let results      = [ 2, 5, 83, 113, 127, -63, -45, -15
                       , -5, -33, -59, -125, 127, 89, 7, 3
                       ];

    decode_midpoint_side(&mut channels);

    assert_eq!(&channels, &results);
  }

  #[test]
  fn test_decode() {
    let mut channels = [ 2, 5, 83, 113, 127, -63, -45, -15
                       , 7, 38, 142, 238, 0, -152, -52, -18
                       ];

    let results = [ [ 2, 5, 83, 113, 127, -63, -45, -15
                    , 7, 38, 142, 238, 0, -152, -52, -18
                    ],
                    [ 2, 5, 83, 113, 127, -63, -45, -15
                    ,-5, -33, -59, -125, 127, 89, 7, 3
                    ]
                  ];

    decode(ChannelAssignment::Independent, &mut channels);
    assert_eq!(&channels, &results[0]);

    channels = [ 2, 5, 83, 113, 127, -63, -45, -15
               , 7, 38, 142, 238, 0, -152, -52, -18
               ];

    decode(ChannelAssignment::LeftSide, &mut channels);
    assert_eq!(&channels, &results[1]);

    channels = [ 7, 38, 142, 238, 0, -152, -52, -18
               , -5, -33, -59, -125, 127, 89, 7, 3
               ];

    decode(ChannelAssignment::RightSide, &mut channels);
    assert_eq!(&channels, &results[1]);

    channels = [ -2, -14, 12, -6, 127, 13, -19, -6
               , 7, 38, 142, 238, 0, -152, -52, -18
               ];

    decode(ChannelAssignment::MidpointSide, &mut channels);
    assert_eq!(&channels, &results[1]);
  }
}
<commit_msg>Change frame decoder to using the Sample trait<commit_after>use frame::ChannelAssignment;
use utility::Sample;

// Decode left and side channels to left and right channels.
//
// Two channels, left and side (difference) that transforms the difference
// into the right channel.
pub fn decode_left_side<S: Sample>(buffer: &mut [S]) {
  let block_size = buffer.len() / 2;

  for i in 0..block_size {
    let left = buffer[i];
    let side = buffer[i + block_size];

    // right channel
    buffer[i + block_size] = left - side;
  }
}

// Decode side and right channels to left and right channels.
//
// Two channels, side (difference) and right that transforms the difference
// into the left channel.
pub fn decode_right_side<S: Sample>(buffer: &mut [S]) {
  let block_size = buffer.len() / 2;

  for i in 0..block_size {
    let side  = buffer[i];
    let right = buffer[i + block_size];

    // left channel
    buffer[i] = side + right;
  }
}

// Decode midpoint and side channels to left and right channels.
//
// Two channels, midpoint (average) and side (difference) that transforms
// the average and difference into the left and right channels.
pub fn decode_midpoint_side<S: Sample>(buffer: &mut [S]) {
  let block_size = buffer.len() / 2;

  for i in 0..block_size {
    let mut midpoint = buffer[i];
    let side         = buffer[i + block_size];

    midpoint = (midpoint << 1) | (side & S::from_i8(1));

    // left and right channel
    buffer[i]              = (midpoint + side) >> 1;
    buffer[i + block_size] = (midpoint - side) >> 1;
  }
}

/// Decode the current frame buffer
///
/// * `Independent` - does nothing to buffer because this channel assignment
///   is already correct.
/// * `LeftSide` - decode left and side channels to left and right channels.
/// * `RightSide` - decode side and right channels to left and right
///   channels.
/// * `MidpointSide` - decode midpoint and side channels to left and right
///   channels.
pub fn decode<S>(channel_assignment: ChannelAssignment, buffer: &mut [S])
 where S: Sample {
  match channel_assignment {
    ChannelAssignment::Independent  => return,
    ChannelAssignment::LeftSide     => decode_left_side(buffer),
    ChannelAssignment::RightSide    => decode_right_side(buffer),
    ChannelAssignment::MidpointSide => decode_midpoint_side(buffer),
  }
}

#[cfg(test)]
mod tests {
  use super::*;
  use frame::ChannelAssignment;

  #[test]
  fn test_decode_left_side() {
    let mut channels = [ 2, 5, 83, 113, 127, -63, -45, -15
                       , 7, 38, 142, 238, 0, -152, -52, -18
                       ];
    let result       = [-5, -33, -59, -125, 127, 89, 7, 3];

    decode_left_side(&mut channels);

    assert_eq!(&channels[8..16], &result);
  }

  #[test]
  fn test_decode_right_side() {
    let mut channels = [ 7, 38, 142, 238, 0, -152, -52, -18
                       , -5, -33, -59, -125, 127, 89, 7, 3
                       ];
    let result       = [2, 5, 83, 113, 127, -63, -45, -15];

    decode_right_side(&mut channels);

    assert_eq!(&channels[0..8], &result);
  }

  #[test]
  fn test_decode_midpoint_side() {
    let mut channels = [ -2, -14, 12, -6, 127, 13, -19, -6
                       , 7, 38, 142, 238, 0, -152, -52, -18
                       ];
    let results      = [ 2, 5, 83, 113, 127, -63, -45, -15
                       , -5, -33, -59, -125, 127, 89, 7, 3
                       ];

    decode_midpoint_side(&mut channels);

    assert_eq!(&channels, &results);
  }

  #[test]
  fn test_decode() {
    let mut channels = [ 2, 5, 83, 113, 127, -63, -45, -15
                       , 7, 38, 142, 238, 0, -152, -52, -18
                       ];

    let results = [ [ 2, 5, 83, 113, 127, -63, -45, -15
                    , 7, 38, 142, 238, 0, -152, -52, -18
                    ],
                    [ 2, 5, 83, 113, 127, -63, -45, -15
                    ,-5, -33, -59, -125, 127, 89, 7, 3
                    ]
                  ];

    decode(ChannelAssignment::Independent, &mut channels);
    assert_eq!(&channels, &results[0]);

    channels = [ 2, 5, 83, 113, 127, -63, -45, -15
               , 7, 38, 142, 238, 0, -152, -52, -18
               ];

    decode(ChannelAssignment::LeftSide, &mut channels);
    assert_eq!(&channels, &results[1]);

    channels = [ 7, 38, 142, 238, 0, -152, -52, -18
               , -5, -33, -59, -125, 127, 89, 7, 3
               ];

    decode(ChannelAssignment::RightSide, &mut channels);
    assert_eq!(&channels, &results[1]);

    channels = [ -2, -14, 12, -6, 127, 13, -19, -6
               , 7, 38, 142, 238, 0, -152, -52, -18
               ];

    decode(ChannelAssignment::MidpointSide, &mut channels);
    assert_eq!(&channels, &results[1]);
  }
}
<|endoftext|>


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

pub struct GapBuffer {
    pub buffer: Vec<char>,
    pub gap_start: usize,
    pub gap_end: usize,
}

impl GapBuffer {
    fn place_gap(&mut self, index: usize) {
        if index == self.gap_start {
            return;
        }
        if index < self.gap_start {
            let count = self.gap_end - self.gap_start;
            let amt = self.gap_start - index;

            let temp_buffer = self.buffer.clone();
            for i in index..self.gap_start {
                self.buffer[i + count] = temp_buffer[i];
            }
            self.gap_start -= amt;
            self.gap_end -= amt;

            for i in self.gap_start..self.gap_end {
                self.buffer[i] = '\0';
            }
        } else {
            let count = self.gap_end - self.gap_start;
            let amt = index - self.gap_start;

            let temp_buffer = self.buffer.clone();
            for i in self.gap_end..self.buffer.len() {
                self.buffer[i - count] = temp_buffer[i];
            }
            self.gap_start += amt;
            self.gap_end += amt;

            for i in self.gap_start..self.gap_end {
                self.buffer[i] = '\0';
            }
        }
    }
    fn check_capacity(&mut self, index: usize) {
        if self.gap_end == self.gap_start {
            self.extend_buffer(index);
        }
    }
    fn extend_buffer(&mut self, index: usize) {
        let len = self.buffer.clone().len();
        self.buffer.resize(len * 2, '\0');
        self.gap_start += len - index;
        self.gap_end = self.buffer.len();
        self.place_gap(index);
    }
    pub fn insert(&mut self, index: usize, ch: char) {
        self.place_gap(index);
        self.check_capacity(index);
        self.buffer[index] = ch;
        self.gap_start += 1;
    }
    pub fn delete(&mut self, index: usize) {
        self.place_gap(index);
        self.buffer[self.gap_end] = '\0';
        self.gap_end += 1;
    }
    pub fn new(size: usize) -> GapBuffer {
        GapBuffer {
            buffer: vec!['\0'; size],
            gap_start: 0,
            gap_end: size,
        }
    }
    pub fn len(&self) -> usize {
        let mut len: usize = 0;
        for i in self.buffer.clone() {
            if i != '\0' {
                len += 1
            }
        }
        len
    }
    pub fn get_line_size(&self, line_num: usize) -> usize {
        let mut line_start = 0;
        let mut line_end = 0;
        let mut eol_count = 0;

        if line_num == 1 {
            for i in 0..self.buffer.len() {
                if self.buffer[i] == '\n' {
                    break;
                }
                // don't count empty char
                if self.buffer[i] == '\0' {
                    continue;
                }
                eol_count += 1;
            }
            for i in eol_count..self.buffer.len() {
                if self.buffer[i] == '\n' {
                    // newline counts, too
                    eol_count = i + 1;
                    break;
                }
                // if gap moved
                if self.buffer[i] == '\0' {
                    // eol needs to be accounted for
                    eol_count += 1;
                    break;
                }
            }
            return self.buffer[line_start..eol_count].len();
        } else {
            // move to newline
            for i in 0..self.buffer.len() {
                if self.buffer[i] == '\n' {
                    eol_count += 1;
                }
                if eol_count == line_num - 1 {
                    eol_count = i;
                    break;
                }
            }
            line_start = eol_count + 1;
            line_end = eol_count + 1;
            for i in line_start..self.buffer.len() {
                if self.buffer[i] == '\n' {
                    line_end += 1;
                    break;
                }
                if self.buffer[i] == '\0' {
                    break;
                }
                line_end += 1;
            }
            return self.buffer[line_start..line_end].len();
        }
    }
}

impl Display for GapBuffer {
    fn fmt(&self, f: &mut Formatter) -> Result {
        let mut string = String::new();
        for i in self.buffer.clone() {
            string.push(i);
        }
        write!(f, "{}", string)
    }
}

#[cfg(test)]
mod tests {
    #[test]
    fn test_gap_check() {
        use gapbuffer::GapBuffer;
        let mut buffer = GapBuffer::new(5);
        buffer.insert(0, 'a');
        buffer.insert(1, 'c');

        assert_eq!('a', buffer.buffer[0]);
        assert_eq!('c', buffer.buffer[1]);
        buffer.insert(0, 'd');
        assert_eq!('d', buffer.buffer[0]);
        assert_eq!('a', buffer.buffer[3]);
        assert_eq!('c', buffer.buffer[4]);
    }
}
<commit_msg>now it's working :D<commit_after>use std::fmt::Display;
use std::fmt::{Formatter, Result};

pub struct GapBuffer {
    pub buffer: Vec<char>,
    pub gap_start: usize,
    pub gap_end: usize,
}

impl GapBuffer {
    fn place_gap(&mut self, index: usize) {
        if index == self.gap_start {
            return;
        }
        if index < self.gap_start {
            let count = self.gap_end - self.gap_start;
            let amt = self.gap_start - index;

            let temp_buffer = self.buffer.clone();
            for i in index..self.gap_start {
                self.buffer[i + count] = temp_buffer[i];
            }
            self.gap_start -= amt;
            self.gap_end -= amt;

            for i in self.gap_start..self.gap_end {
                self.buffer[i] = '\0';
            }
        } else {
            let count = self.gap_end - self.gap_start;
            let amt = index - self.gap_start;

            let temp_buffer = self.buffer.clone();
            for i in self.gap_end..self.buffer.len() {
                self.buffer[i - count] = temp_buffer[i];
            }
            self.gap_start += amt;
            self.gap_end += amt;

            for i in self.gap_start..self.gap_end {
                self.buffer[i] = '\0';
            }
        }
    }
    fn check_capacity(&mut self, index: usize) {
        if self.gap_end == self.gap_start {
            self.extend_buffer(index);
        }
    }
    fn extend_buffer(&mut self, index: usize) {
        let len = self.buffer.clone().len();
        self.buffer.resize(len * 2, '\0');
        self.gap_start += len - index;
        self.gap_end = self.buffer.len();
        self.place_gap(index);
    }
    pub fn insert(&mut self, index: usize, ch: char) {
        self.place_gap(index);
        self.check_capacity(index);
        self.buffer[index] = ch;
        self.gap_start += 1;
    }
    pub fn delete(&mut self, index: usize) {
        self.place_gap(index);
        self.buffer[self.gap_end] = '\0';
        self.gap_end += 1;
    }
    pub fn new(size: usize) -> GapBuffer {
        GapBuffer {
            buffer: vec!['\0'; size],
            gap_start: 0,
            gap_end: size,
        }
    }
    pub fn len(&self) -> usize {
        let mut len: usize = 0;
        for i in self.buffer.clone() {
            if i != '\0' {
                len += 1
            }
        }
        len
    }
    pub fn get_line_size(&self, line_num: usize) -> usize {
        let mut line_start = 0;
        let mut line_end = 0;
        let mut eol_count = 0;

        if line_num == 1 {
            for i in 0..self.buffer.len() {
                if self.buffer[i] == '\n' {
                    break;
                }
                // don't count empty char
                if self.buffer[i] == '\0' {
                    continue;
                }
                eol_count += 1;
            }
            for i in eol_count..self.buffer.len() {
                if self.buffer[i] == '\n' {
                    // newline counts, too
                    eol_count = i + 1;
                    break;
                }
                // if gap moved
                if self.buffer[i] == '\0' {
                    // eol needs to be accounted for
                    eol_count += 1;
                    break;
                }
            }
            return self.buffer[line_start..eol_count].len();
        } else {
            // move to newline
            for i in 0..self.buffer.len() {
                if self.buffer[i] == '\n' {
                    eol_count += 1;
                }
                if eol_count == line_num - 1 {
                    eol_count = i;
                    break;
                }
            }
            line_start = eol_count + 1;
            line_end = eol_count + 1;
            for i in line_start..self.buffer.len() {
                if self.buffer[i] == '\n' {
                    line_end += 1;
                    break;
                }
                // if gap moved
                if self.buffer[i] == '\0' {
                    continue;
                }
                line_end += 1;
            }
            return self.buffer[line_start..line_end].len();
        }
    }
}

impl Display for GapBuffer {
    fn fmt(&self, f: &mut Formatter) -> Result {
        let mut string = String::new();
        for i in self.buffer.clone() {
            string.push(i);
        }
        write!(f, "{}", string)
    }
}

#[cfg(test)]
mod tests {
    #[test]
    fn test_gap_check() {
        use gapbuffer::GapBuffer;
        let mut buffer = GapBuffer::new(5);
        buffer.insert(0, 'a');
        buffer.insert(1, 'c');

        assert_eq!('a', buffer.buffer[0]);
        assert_eq!('c', buffer.buffer[1]);
        buffer.insert(0, 'd');
        assert_eq!('d', buffer.buffer[0]);
        assert_eq!('a', buffer.buffer[3]);
        assert_eq!('c', buffer.buffer[4]);
    }
}
<|endoftext|>


<commit_before>use std::usize;
use lalrpop_util::ParseError;
use ::value::Value;
use super::parse;
use super::lexer::Token;
use super::error::Error;
use ::string_interner::StringInterner;

const EOF: usize = usize::MAX;

fn whatever(x: &ParseError<usize, Token, Error>) -> usize {
    match x {
        &ParseError::InvalidToken{location: pos} => pos,
        &ParseError::UnrecognizedToken{expected: _, token: Some((pos, _, _))} => pos,
        &ParseError::User{error: Error::InvalidToken(_, end)} => end,
        &ParseError::User{error: Error::UnexpectedEofString(_)} => EOF,
        &ParseError::User{error: Error::UnexpectedEofChar(_)} => EOF,
        &ParseError::User{error: Error::NonAsciiChar(x)} => x,
        x => panic!("got: {:?}", x),
    }
}

macro_rules! expect_error {
    // whatever
    ($parser:ident, $input:expr, $position:expr) => (
        expect_error!($parser, $input, whatever, true, $position);
    );

    // whatever wherever
    ($parser:ident, $input:expr) => (
        expect_error!($parser, $input, whatever, false, 0);
    );

    //internal
    ($parser:ident, $input:expr, $token_fn:ident, $use_pos:expr, $position:expr) => (
        let input = &*$input;
        let interner = &mut StringInterner::new();
        let result = $parser(input, interner);

        match result {
            Err(ref err) => {
                if $use_pos && $token_fn(err) != $position {
                    panic!("for input: {:?}, got Err({:?}) at pos {}, expected pos: {}", input, err, $token_fn(err), $position);
                }
            },
            Ok(v) => panic!("expected error for string: '{}', got: {}", input, v[0].to_string(interner)),
        }
    );
}

macro_rules! expect_ok {
    // with rest
    ($parser:ident, $interner:expr, $input:expr, $expected:expr) => (
        let input = &*$input;
        let expected = $expected.to_string($interner);
        let result = $parser(input, $interner);
        match result {
            Ok(v) => {
                assert!(v.len() == 1);
                let v = &v[0];
                let res = v.to_string($interner);
                if res != expected {
                    panic!("parser ok, but input: {:?} got: Ok({:?}), expected: {}", input, res, expected);
                }
            },
            Err(e) => {
                panic!("input: {:?} got: Err({:?}), expected: {}", input, e, &expected);
            }
        }
    );
}

#[test]
fn bool() {
    let interner = &mut StringInterner::new();
    expect_ok!(parse, interner, "true", Value::new_bool(true));
    expect_ok!(parse, interner, "false", Value::new_bool(false));
    expect_ok!(parse, interner, "trude", Value::new_symbol(interner.intern("trude")));
    expect_ok!(parse, interner, "fale", Value::new_symbol(interner.intern("fale")));
}

#[test]
fn char() {
    let interner = &mut StringInterner::new();
    use std::char;
    use std::iter;
    let mut input: String = "#\\".into();
    let printlable_asci = ('!' as u32)..('~' as u32) + 1;
    for x in printlable_asci {
        let c = char::from_u32(x).expect(&format!("tried to create invalid char with: 0x{:X}", x));
        input.push(c);
        { expect_ok!(parse, interner, input, Value::new_char(c)); }
        input.pop();
    }

    let invalid_asci = (0..('!' as u32)).chain(iter::once(127));
    for x in invalid_asci {
        let c = char::from_u32(x).expect(&format!("tried to create invalid char with: 0x{:X}", x));
        input.push(c);
        if c != '\n' && c != '\t' && c != ' ' { expect_error!(parse, input); }
        input.pop();
    }

    // special forms
    expect_ok!(parse, interner, r"#\\s", Value::new_char(' '));
    expect_ok!(parse, interner, r"#\\t", Value::new_char('\t'));
    expect_ok!(parse, interner, r"#\\n", Value::new_char('\n'));
    expect_ok!(parse, interner, r"#\\", Value::new_char('\\'));

    expect_error!(parse, r"#\", EOF);
    expect_error!(parse, "#\\\0", 2);
}

#[test]
fn integer() {
    let interner = &mut StringInterner::new();
    expect_ok!(parse, interner, "007", Value::new_integer(7));
    expect_ok!(parse, interner, "-007", Value::new_integer(-7));
    expect_ok!(parse, interner, "123456789", Value::new_integer(123456789));
    expect_ok!(parse, interner, "-123456789", Value::new_integer(-123456789));

    expect_error!(parse, "123b456789", 3);
    expect_error!(parse, "123456789c", 9);
    expect_error!(parse, "00-7", 2);
    expect_ok!(parse, interner, "a123456789", Value::new_symbol(interner.intern("a123456789")));
    expect_ok!(parse, interner, "--7", Value::new_symbol(interner.intern("--7")));
}

#[test]
fn symbol() {
    let interner = &mut StringInterner::new();
    expect_ok!(parse, interner, "+", Value::new_symbol(interner.intern("+")));
    expect_ok!(parse, interner, "-", Value::new_symbol(interner.intern("-")));
    expect_ok!(parse, interner, "#", Value::new_symbol(interner.intern("#")));
    expect_ok!(parse, interner, "a1a", Value::new_symbol(interner.intern("a1a")));
    expect_ok!(parse, interner, "num->str", Value::new_symbol(interner.intern("num->str")));
    expect_ok!(parse, interner, "//", Value::new_symbol(interner.intern("//")));

    // error is at 1 bc lexer tries to lex integer
    expect_error!(parse, "1a", 1);
}

#[test]
fn string() {
    fn q(s: &str) -> String {
        format!("\"{}\"", s)
    }

    macro_rules! expect_str_ok {
        ($s:expr, $e:expr) => ({
            let s = q($s);
            let interner = &mut StringInterner::new();
            expect_ok!(parse, interner, s, Value::new_string($e));
        });

        ($s:expr) => (expect_str_ok!($s, $s));
    }

    expect_str_ok!("");
    expect_str_ok!("abc");
    expect_str_ok!("Hello, World!!");
    expect_str_ok!("\n");
    expect_str_ok!(r"\n", "\n");
    expect_str_ok!("\t");
    expect_str_ok!(r"\t", "\t");
    expect_str_ok!(r"\\\\", "\\\\");
    expect_str_ok!(r#"Hi there: \" \\ \n \t"#, "Hi there: \" \\ \n \t");

    expect_error!(parse, "\"", EOF);
    expect_error!(parse, "\"❤\"", 1); // non ascii
}

#[test]
fn list() {
    let interner = &mut StringInterner::new();
    expect_ok!(parse, interner, "()", Value::empty_list());
    expect_ok!(parse, interner, r#"(1 "2" 3 4)"#, Value::new_list(&vec![Value::new_integer(1), Value::new_string("2"), Value::new_integer(3), Value::new_integer(4)]));
    expect_ok!(parse, interner, "(() ())", Value::new_list(&vec![Value::empty_list(), Value::empty_list()]));

    expect_error!(parse, "(( ())");
}

#[test]
fn quote() {
    fn quoted(v: Value, interner: &mut StringInterner) -> Value {
        let quote_id = interner.intern("quote");
        Value::new_list(&[Value::new_symbol(quote_id), v])
    }
    let interner = &mut StringInterner::new();
    expect_ok!(parse, interner, "'()", quoted(Value::empty_list(), interner));
    expect_ok!(parse, interner, "'1", quoted(Value::new_integer(1), interner));
    expect_ok!(parse, interner, "'true", quoted(Value::new_bool(true), interner));
    expect_ok!(parse, interner, r#"'"2""#, quoted(Value::new_string("2"), interner));
    expect_ok!(parse, interner, "'#\\a", quoted(Value::new_char('a'), interner));
    expect_ok!(parse, interner, "'sym", quoted(Value::new_symbol(interner.intern("sym")), interner));
    expect_ok!(parse, interner, "'(1 2)", quoted(Value::new_list(&[Value::new_integer(1), Value::new_integer(2)]), interner));
}

#[test]
fn recur() {
    let interner = &mut StringInterner::new();

    expect_ok!(parse, interner, "recur", Value::new_symbol(interner.intern("recur")));
    expect_ok!(parse, interner, "'(recur)", Value::new_list(&[Value::new_symbol(interner.intern("quote")), Value::new_list(&[Value::new_symbol(interner.intern("recur"))])]));
    expect_ok!(parse, interner, "'recur", Value::new_list(&[Value::new_symbol(interner.intern("quote")), Value::new_symbol(interner.intern("recur"))]));
}

#[test]
fn tail_calls() {
    let interner = &mut StringInterner::new();

    // top level
    expect_error!(parse, "(recur)");

    // begin
    expect_error!(parse, "(begin (recur))");
    expect_error!(parse, "(begin bla (recur))");

    // define covered later

    // if
    expect_error!(parse, "(if true (recur) bla)");
    expect_error!(parse, "(if true bla (recur))");
    expect_error!(parse, "(if true (recur) (recur))");

    // let
    expect_error!(parse, "(let () (recur))");
    expect_error!(parse, "(let () bla (recur))");

    // loop
    expect_ok!(parse, interner, "(loop () (recur))", Value::new_list(&[Value::new_symbol(interner.intern("loop")), Value::empty_list(), Value::new_list(&[Value::new_symbol(interner.intern("recur"))])]));
    expect_ok!(parse, interner, "(loop () bla (recur))", Value::new_list(&[Value::new_symbol(interner.intern("loop")), Value::empty_list(), Value::new_symbol(interner.intern("bla")), Value::new_list(&[Value::new_symbol(interner.intern("recur"))])]));
    expect_error!(parse, "(loop () (recur) bla)");

    // lambda
    expect_ok!(parse, interner, "(lambda () (recur))", Value::new_list(&[Value::new_symbol(interner.intern("lambda")), Value::empty_list(), Value::new_list(&[Value::new_symbol(interner.intern("recur"))])]));
    expect_ok!(parse, interner, "(lambda () bla (recur))", Value::new_list(&[Value::new_symbol(interner.intern("lambda")), Value::empty_list(), Value::new_symbol(interner.intern("bla")), Value::new_list(&[Value::new_symbol(interner.intern("recur"))])]));
    expect_error!(parse, "(lambda () (recur) bla)");

    // invalid tail calls
    let begin = "(begin (recur) bla)";
    let define = "(define a (recur))";
    let let_ = "(let () (recur) bla)";

    let no_tail_calls = &[begin, define, let_];

    for x in no_tail_calls {
        // insert x so that a tail call would be correct
        let code = format!("(loop () {})", x);
        expect_error!(parse, code);
    }
}

// TODO add tests for special forms

#[test]
fn everything_together() {
    let interner = &mut StringInterner::new();
    let string = r#"("hi" my "NaMe" #\i #\s recur -42 # #\\n)"#;
    let parsed = parse(string, interner).unwrap();
    assert!(parsed.len() == 1);
    assert_eq!(parsed[0].to_string(interner), r#"("hi" my "NaMe" #\i #\s recur -42 # #\\n)"#);
}
<commit_msg>add failing tests for quote<commit_after>use std::usize;
use lalrpop_util::ParseError;
use ::value::Value;
use super::parse;
use super::lexer::Token;
use super::error::Error;
use ::string_interner::StringInterner;

const EOF: usize = usize::MAX;

fn whatever(x: &ParseError<usize, Token, Error>) -> usize {
    match x {
        &ParseError::InvalidToken{location: pos} => pos,
        &ParseError::UnrecognizedToken{expected: _, token: Some((pos, _, _))} => pos,
        &ParseError::User{error: Error::InvalidToken(_, end)} => end,
        &ParseError::User{error: Error::UnexpectedEofString(_)} => EOF,
        &ParseError::User{error: Error::UnexpectedEofChar(_)} => EOF,
        &ParseError::User{error: Error::NonAsciiChar(x)} => x,
        x => panic!("got: {:?}", x),
    }
}

macro_rules! expect_error {
    // whatever
    ($parser:ident, $input:expr, $position:expr) => (
        expect_error!($parser, $input, whatever, true, $position);
    );

    // whatever wherever
    ($parser:ident, $input:expr) => (
        expect_error!($parser, $input, whatever, false, 0);
    );

    //internal
    ($parser:ident, $input:expr, $token_fn:ident, $use_pos:expr, $position:expr) => (
        let input = &*$input;
        let interner = &mut StringInterner::new();
        let result = $parser(input, interner);

        match result {
            Err(ref err) => {
                if $use_pos && $token_fn(err) != $position {
                    panic!("for input: {:?}, got Err({:?}) at pos {}, expected pos: {}", input, err, $token_fn(err), $position);
                }
            },
            Ok(v) => panic!("expected error for string: '{}', got: {}", input, v[0].to_string(interner)),
        }
    );
}

macro_rules! expect_ok {
    // with rest
    ($parser:ident, $interner:expr, $input:expr, $expected:expr) => (
        let input = &*$input;
        let expected = $expected.to_string($interner);
        let result = $parser(input, $interner);
        match result {
            Ok(v) => {
                assert!(v.len() == 1);
                let v = &v[0];
                let res = v.to_string($interner);
                if res != expected {
                    panic!("parser ok, but input: {:?} got: Ok({:?}), expected: {}", input, res, expected);
                }
            },
            Err(e) => {
                panic!("input: {:?} got: Err({:?}), expected: {}", input, e, &expected);
            }
        }
    );
}

#[test]
fn bool() {
    let interner = &mut StringInterner::new();
    expect_ok!(parse, interner, "true", Value::new_bool(true));
    expect_ok!(parse, interner, "false", Value::new_bool(false));
    expect_ok!(parse, interner, "trude", Value::new_symbol(interner.intern("trude")));
    expect_ok!(parse, interner, "fale", Value::new_symbol(interner.intern("fale")));
}

#[test]
fn char() {
    let interner = &mut StringInterner::new();
    use std::char;
    use std::iter;
    let mut input: String = "#\\".into();
    let printlable_asci = ('!' as u32)..('~' as u32) + 1;
    for x in printlable_asci {
        let c = char::from_u32(x).expect(&format!("tried to create invalid char with: 0x{:X}", x));
        input.push(c);
        { expect_ok!(parse, interner, input, Value::new_char(c)); }
        input.pop();
    }

    let invalid_asci = (0..('!' as u32)).chain(iter::once(127));
    for x in invalid_asci {
        let c = char::from_u32(x).expect(&format!("tried to create invalid char with: 0x{:X}", x));
        input.push(c);
        if c != '\n' && c != '\t' && c != ' ' { expect_error!(parse, input); }
        input.pop();
    }

    // special forms
    expect_ok!(parse, interner, r"#\\s", Value::new_char(' '));
    expect_ok!(parse, interner, r"#\\t", Value::new_char('\t'));
    expect_ok!(parse, interner, r"#\\n", Value::new_char('\n'));
    expect_ok!(parse, interner, r"#\\", Value::new_char('\\'));

    expect_error!(parse, r"#\", EOF);
    expect_error!(parse, "#\\\0", 2);
}

#[test]
fn integer() {
    let interner = &mut StringInterner::new();
    expect_ok!(parse, interner, "007", Value::new_integer(7));
    expect_ok!(parse, interner, "-007", Value::new_integer(-7));
    expect_ok!(parse, interner, "123456789", Value::new_integer(123456789));
    expect_ok!(parse, interner, "-123456789", Value::new_integer(-123456789));

    expect_error!(parse, "123b456789", 3);
    expect_error!(parse, "123456789c", 9);
    expect_error!(parse, "00-7", 2);
    expect_ok!(parse, interner, "a123456789", Value::new_symbol(interner.intern("a123456789")));
    expect_ok!(parse, interner, "--7", Value::new_symbol(interner.intern("--7")));
}

#[test]
fn symbol() {
    let interner = &mut StringInterner::new();
    expect_ok!(parse, interner, "+", Value::new_symbol(interner.intern("+")));
    expect_ok!(parse, interner, "-", Value::new_symbol(interner.intern("-")));
    expect_ok!(parse, interner, "#", Value::new_symbol(interner.intern("#")));
    expect_ok!(parse, interner, "a1a", Value::new_symbol(interner.intern("a1a")));
    expect_ok!(parse, interner, "num->str", Value::new_symbol(interner.intern("num->str")));
    expect_ok!(parse, interner, "//", Value::new_symbol(interner.intern("//")));

    // error is at 1 bc lexer tries to lex integer
    expect_error!(parse, "1a", 1);
}

#[test]
fn string() {
    fn q(s: &str) -> String {
        format!("\"{}\"", s)
    }

    macro_rules! expect_str_ok {
        ($s:expr, $e:expr) => ({
            let s = q($s);
            let interner = &mut StringInterner::new();
            expect_ok!(parse, interner, s, Value::new_string($e));
        });

        ($s:expr) => (expect_str_ok!($s, $s));
    }

    expect_str_ok!("");
    expect_str_ok!("abc");
    expect_str_ok!("Hello, World!!");
    expect_str_ok!("\n");
    expect_str_ok!(r"\n", "\n");
    expect_str_ok!("\t");
    expect_str_ok!(r"\t", "\t");
    expect_str_ok!(r"\\\\", "\\\\");
    expect_str_ok!(r#"Hi there: \" \\ \n \t"#, "Hi there: \" \\ \n \t");

    expect_error!(parse, "\"", EOF);
    expect_error!(parse, "\"❤\"", 1); // non ascii
}

#[test]
fn list() {
    let interner = &mut StringInterner::new();
    expect_ok!(parse, interner, "()", Value::empty_list());
    expect_ok!(parse, interner, r#"(1 "2" 3 4)"#, Value::new_list(&vec![Value::new_integer(1), Value::new_string("2"), Value::new_integer(3), Value::new_integer(4)]));
    expect_ok!(parse, interner, "(() ())", Value::new_list(&vec![Value::empty_list(), Value::empty_list()]));

    expect_error!(parse, "(( ())");
}

#[test]
fn quote() {
    fn quoted(v: Value, interner: &mut StringInterner) -> Value {
        let quote_id = interner.intern("quote");
        Value::new_list(&[Value::new_symbol(quote_id), v])
    }
    let interner = &mut StringInterner::new();
    expect_ok!(parse, interner, "'()", quoted(Value::empty_list(), interner));
    expect_ok!(parse, interner, "'1", quoted(Value::new_integer(1), interner));
    expect_ok!(parse, interner, "'true", quoted(Value::new_bool(true), interner));
    expect_ok!(parse, interner, r#"'"2""#, quoted(Value::new_string("2"), interner));
    expect_ok!(parse, interner, "'#\\a", quoted(Value::new_char('a'), interner));
    expect_ok!(parse, interner, "'sym", quoted(Value::new_symbol(interner.intern("sym")), interner));
    expect_ok!(parse, interner, "'(1 2)", quoted(Value::new_list(&[Value::new_integer(1), Value::new_integer(2)]), interner));

    // quoted lists should parse even if they contain invalid special forms
    let special_forms = &["define", "quote", "if", "lambda", "let", "loop", "recur", "begin"];
    for &special in special_forms {
        let special_symbol = Value::new_symbol(interner.intern(special));
        expect_ok!(parse, interner, format!("'({})", special), quoted(Value::new_list(&[special_symbol.clone()]), interner));
        expect_ok!(parse, interner, format!("(quote ({}))", special), quoted(Value::new_list(&[special_symbol.clone()]), interner));
        expect_ok!(parse, interner, format!("'(({}))", special), quoted(Value::new_list(&[Value::new_list(&[special_symbol.clone()])]), interner));
        expect_ok!(parse, interner, format!("(quote (({})))", special), quoted(Value::new_list(&[Value::new_list(&[special_symbol.clone()])]), interner));
        expect_ok!(parse, interner, format!("'(1 ({}))", special), quoted(Value::new_list(&[Value::new_integer(1), Value::new_list(&[special_symbol.clone()])]), interner));
        expect_ok!(parse, interner, format!("(quote (1 ({})))", special), quoted(Value::new_list(&[Value::new_integer(1), Value::new_list(&[special_symbol.clone()])]), interner));
    }
}

#[test]
fn recur() {
    let interner = &mut StringInterner::new();

    expect_ok!(parse, interner, "recur", Value::new_symbol(interner.intern("recur")));
    expect_ok!(parse, interner, "'(recur)", Value::new_list(&[Value::new_symbol(interner.intern("quote")), Value::new_list(&[Value::new_symbol(interner.intern("recur"))])]));
    expect_ok!(parse, interner, "'recur", Value::new_list(&[Value::new_symbol(interner.intern("quote")), Value::new_symbol(interner.intern("recur"))]));
}

#[test]
fn tail_calls() {
    let interner = &mut StringInterner::new();

    // top level
    expect_error!(parse, "(recur)");

    // begin
    expect_error!(parse, "(begin (recur))");
    expect_error!(parse, "(begin bla (recur))");

    // define covered later

    // if
    expect_error!(parse, "(if true (recur) bla)");
    expect_error!(parse, "(if true bla (recur))");
    expect_error!(parse, "(if true (recur) (recur))");

    // let
    expect_error!(parse, "(let () (recur))");
    expect_error!(parse, "(let () bla (recur))");

    // loop
    expect_ok!(parse, interner, "(loop () (recur))", Value::new_list(&[Value::new_symbol(interner.intern("loop")), Value::empty_list(), Value::new_list(&[Value::new_symbol(interner.intern("recur"))])]));
    expect_ok!(parse, interner, "(loop () bla (recur))", Value::new_list(&[Value::new_symbol(interner.intern("loop")), Value::empty_list(), Value::new_symbol(interner.intern("bla")), Value::new_list(&[Value::new_symbol(interner.intern("recur"))])]));
    expect_error!(parse, "(loop () (recur) bla)");

    // lambda
    expect_ok!(parse, interner, "(lambda () (recur))", Value::new_list(&[Value::new_symbol(interner.intern("lambda")), Value::empty_list(), Value::new_list(&[Value::new_symbol(interner.intern("recur"))])]));
    expect_ok!(parse, interner, "(lambda () bla (recur))", Value::new_list(&[Value::new_symbol(interner.intern("lambda")), Value::empty_list(), Value::new_symbol(interner.intern("bla")), Value::new_list(&[Value::new_symbol(interner.intern("recur"))])]));
    expect_error!(parse, "(lambda () (recur) bla)");

    // invalid tail calls
    let begin = "(begin (recur) bla)";
    let define = "(define a (recur))";
    let let_ = "(let () (recur) bla)";

    let no_tail_calls = &[begin, define, let_];

    for x in no_tail_calls {
        // insert x so that a tail call would be correct
        let code = format!("(loop () {})", x);
        expect_error!(parse, code);
    }
}

// TODO add tests for special forms

#[test]
fn everything_together() {
    let interner = &mut StringInterner::new();
    let string = r#"("hi" my "NaMe" #\i #\s recur -42 # #\\n)"#;
    let parsed = parse(string, interner).unwrap();
    assert!(parsed.len() == 1);
    assert_eq!(parsed[0].to_string(interner), r#"("hi" my "NaMe" #\i #\s recur -42 # #\\n)"#);
}
<|endoftext|>