<commit_before>use definitions::PREAMBLE;
use definitions::Value;
use definitions::config::VMConfig;
use definitions::instruction::Instruction;
use definitions::interrupt::{ExternalInterrupt, InternalInterrupt};
use definitions::program::Program;
use definitions::target::Target;
use definitions::typedef::*;
use error::*;
use std::cmp::Ordering;
use std::collections::{BTreeMap, LinkedList};
use std::sync::mpsc::{Receiver, SyncSender, TryRecvError, TrySendError};
use std::thread::{self, JoinHandle};

pub fn start(program: Program, sender: SyncSender<Frame>, receiver: Receiver<ExternalInterrupt>)
    -> JoinHandle<()> {
    thread::spawn(
        move || {
            if let Err(ref e) = VM::default().exec(program, sender, receiver) {
                println!("error: {}", e);

                for e in e.iter().skip(1) {
                    println!("caused by: {}", e);
                }

                // The backtrace is not always generated. Try to run this example
                // with `RUST_BACKTRACE=1`.
                if let Some(backtrace) = e.backtrace() {
                    println!("backtrace: {:?}", backtrace);
                }
            }
        },
    )
}

/// The whole state of the VM
#[derive(Default, Debug)]
struct VM {
    /// The instructions that are currently executed
    image_data: Vec<Instruction>,
    /// The current program counter
    pc: Address,
    stack: LinkedList<Value>,
    val_index: BTreeMap<Address, Value>,
    interrupt_register: BTreeMap<usize, Address>,
    framebuffer: Frame,
    framebuffer_invalid: bool,
    /// A register for holding infomation about a recent comparison
    cmp_register: Option<Ordering>,
    /// A stack to hold the return addresses of function calls
    call_stack: LinkedList<Address>,
    /// A boolean used for locking the program counter
    pc_locked: bool,
    /// The configuration of the VM
    config: VMConfig,
    halted: bool,
}

impl VM {
    // # Maintainance functions

    /// Executes the given program
    pub fn exec(
        &mut self, program: Program, sender: SyncSender<Frame>,
        receiver: Receiver<ExternalInterrupt>
    ) -> VMResult<()> {
        self.reset();
        self.load_program(program)?;
        self.build_framebuffer();

        while (self.pc < self.image_data.len()) && !self.halted {
            self.external_interrupt(&receiver)?;

            let current_instruction = self.image_data[self.pc].clone();

            match current_instruction {
                Instruction::Halt => break,
                Instruction::Int(interrupt) => self.int(&interrupt),

                Instruction::Add(dest, src) => self.add(&dest, &src)?,
                Instruction::Sub(dest, src) => self.sub(&dest, &src)?,
                Instruction::Div(dest, src) => self.div(&dest, &src)?,
                Instruction::Mul(dest, src) => self.mul(&dest, &src)?,
                Instruction::Rem(dest, src) => self.rem(&dest, &src)?,

                Instruction::Cmp(target_a, target_b) => self.cmp(&target_a, &target_b)?,
                Instruction::Jmp(addr) => self.jmp(&addr),
                Instruction::JmpLt(addr) => self.jmp_lt(&addr),
                Instruction::JmpGt(addr) => self.jmp_gt(&addr),
                Instruction::JmpEq(addr) => self.jmp_eq(&addr),
                Instruction::JmpLtEq(addr) => self.jmp_lt_eq(&addr),
                Instruction::JmpGtEq(addr) => self.jmp_gt_eq(&addr),

                Instruction::Push(dest, value) => self.push(&dest, value)?,
                Instruction::Mov(dest, src) => self.mov(&dest, &src)?,
                Instruction::Swp(target_a, target_b) => self.swp(&target_a, &target_b)?,

                Instruction::Call(addr) => self.call(&addr),
                Instruction::Ret => self.ret()?,
            }

            self.flush_framebuffer(&sender)?;

            self.advance_pc();

            thread::yield_now();
        }

        Ok(())
    }

    /// Loads the instructions of the given program to the VM's state
    fn load_program(&mut self, program: Program) -> VMResult<()> {
        if program.preamble != String::from(PREAMBLE) {
            bail!("invalid preamble");
        } else if program.version != String::from(env!("CARGO_PKG_VERSION")) {
            bail!("invalid version");
        } else {
            self.image_data = program.instructions;
            self.config = program.config;
            Ok(())
        }
    }

    /// Aborts the execution of the current image
    fn abort(&mut self) {
        self.halted = true;
    }

    /// Handles an internal interrupt
    fn int(&mut self, interrupt: &InternalInterrupt) {
        match interrupt {
            &InternalInterrupt::FlushFramebuffer => self.invalidate(),
        }
    }

    /// Handles incoming interrupts or moves along
    fn external_interrupt(&mut self, receiver: &Receiver<ExternalInterrupt>) -> VMResult<()> {
        match receiver.try_recv() {
            Ok(interrupt) => {
                if interrupt.signal_id == 0 {
                    self.abort();
                    return Ok(());
                }

                let call_addr = if let Some(call_addr) = self.interrupt_register
                       .get(&interrupt.signal_id) {
                    call_addr.clone()
                } else {
                    bail!(
                        "no registered interrupt found at signal_id {}",
                        &interrupt.signal_id
                    );
                };

                for value in interrupt.args {
                    self.push(&Target::Stack, value)?;
                }

                self.call(&call_addr);

                Ok(())
            }
            Err(TryRecvError::Disconnected) => bail!("interrupt receiver disconnected"),
            _ => Ok(()),
        }
    }

    /// Flushes the internal framebuffer using the given sender
    fn flush_framebuffer(&mut self, sender: &SyncSender<Frame>) -> VMResult<()> {
        if self.framebuffer_invalid {
            if let Err(TrySendError::Disconnected(..)) = sender.try_send(self.framebuffer.clone()) {
                bail!("output channel disconnected");
            }

            self.framebuffer_invalid = false;
        }

        Ok(())
    }

    /// Allocates all the needed space in the framebuffer
    fn build_framebuffer(&mut self) {
        let ref resolution = self.config.display.resolution;
        let allocation_space = resolution.width * resolution.height;
        self.framebuffer = vec![(0, 0, 0); allocation_space];
    }

    /// Resets the VM to a clean state
    fn reset(&mut self) {
        *self = VM::default();
    }

    /// Locks the program counter in place
    fn lock_pc(&mut self) {
        self.pc_locked = true;
    }

    /// Advances the program counter
    fn advance_pc(&mut self) {
        if self.pc_locked {
            self.pc_locked = false;
        } else {
            self.pc += 1;
        }
    }

    /// Invalidates the frambuffer causing it to be resent to the display
    /// receiver
    fn invalidate(&mut self) {
        self.framebuffer_invalid = true;
    }

    /// Return the value at the specified target. The value of the target will
    /// be consumed
    fn pop(&mut self, target: &Target) -> VMResult<Value> {
        match target {
            &Target::ValueIndex(index) => {
                if let Some(value) = self.val_index.remove(&index) {
                    Ok(value)
                } else {
                    bail!("no value found at index {}", index);
                }
            }
            &Target::Stack => {
                if let Some(value) = self.stack.pop_front() {
                    Ok(value)
                } else {
                    bail!("unable to pop value off an empty stack");
                }
            }
            &Target::Framebuffer(index) => {
                if let Some(&(r, g, b)) = self.framebuffer.get(index) {
                    Ok(Value::Color(r, g, b))
                } else {
                    bail!("no value found in framebuffer at index {}", index);
                }
            }
        }
    }

    // # Instruction functions

    /// Adds the value of the src target to the value of the dest target
    fn add(&mut self, dest: &Target, src: &Target) -> VMResult<()> {
        let dest_value = self.pop(dest)?;
        let src_value = self.pop(src)?;

        self.push(dest, dest_value + src_value)?;

        Ok(())
    }

    /// Subtracts the value of the src target from the value of the dest target
    fn sub(&mut self, dest: &Target, src: &Target) -> VMResult<()> {
        let dest_value = self.pop(dest)?;
        let src_value = self.pop(src)?;

        self.push(dest, dest_value - src_value)?;

        Ok(())
    }

    /// Divides the value of the dest target through the value of the src target
    fn div(&mut self, dest: &Target, src: &Target) -> VMResult<()> {
        let dest_value = self.pop(dest)?;
        let src_value = self.pop(src)?;

        self.push(dest, dest_value / src_value)?;

        Ok(())
    }

    /// Multiplies the value of the dest target with the value of the src target
    fn mul(&mut self, dest: &Target, src: &Target) -> VMResult<()> {
        let dest_value = self.pop(dest)?;
        let src_value = self.pop(src)?;

        self.push(dest, dest_value * src_value)?;

        Ok(())
    }

    /// Applies the modulo operator on the value of the dest target using the
    /// value of the src target
    fn rem(&mut self, dest: &Target, src: &Target) -> VMResult<()> {
        let dest_value = self.pop(dest)?;
        let src_value = self.pop(src)?;

        self.push(dest, dest_value * src_value)?;

        Ok(())
    }

    /// Compares the top values of the two targets and saves the result to
    /// `self.cmp_register`
    fn cmp(&mut self, target_a: &Target, target_b: &Target) -> VMResult<()> {
        let target_a_value = self.pop(target_a)?;
        let target_b_value = self.pop(target_b)?;

        if target_a_value < target_b_value {
            self.cmp_register = Some(Ordering::Less);
        } else if target_a_value > target_b_value {
            self.cmp_register = Some(Ordering::Greater);
        } else if target_a_value == target_b_value {
            self.cmp_register = Some(Ordering::Equal);
        }

        Ok(())
    }

    /// Jumps unconditionally to the specified address
    fn jmp(&mut self, addr: &Address) {
        self.pc = *addr;
        self.lock_pc();
    }

    /// Jumps if the last compare got the result `Some(Ordering::Less)`
    fn jmp_lt(&mut self, addr: &Address) {
        if self.cmp_register == Some(Ordering::Less) {
            self.jmp(addr);
        }
    }

    /// Jumps if the last compare got the result `Some(Ordering::Greater)`
    fn jmp_gt(&mut self, addr: &Address) {
        if self.cmp_register == Some(Ordering::Greater) {
            self.jmp(addr);
        }
    }

    /// Jumps if the last compare got the result `Some(Ordering::Equal)`
    fn jmp_eq(&mut self, addr: &Address) {
        if self.cmp_register == Some(Ordering::Equal) {
            self.jmp(addr);
        }
    }

    /// Jumps if the last compare got the result `Some(Ordering::Less)` or
    /// `Some(Ordering::Equal)`
    fn jmp_lt_eq(&mut self, addr: &Address) {
        if (self.cmp_register == Some(Ordering::Less)) ||
           (self.cmp_register == Some(Ordering::Equal)) {
            self.jmp(addr);
        }
    }

    /// Jumps if the last compare got the result `Some(Ordering::Greater)` or
    /// `Some(Ordering::Equal)`
    fn jmp_gt_eq(&mut self, addr: &Address) {
        if (self.cmp_register == Some(Ordering::Greater)) ||
           (self.cmp_register == Some(Ordering::Equal)) {
            self.jmp(addr);
        }
    }

    /// Pushes the given value to the given target
    fn push(&mut self, dest: &Target, value: Value) -> VMResult<()> {
        match dest {
            &Target::ValueIndex(index) => {
                self.val_index.entry(index).or_insert(value);
                Ok(())
            }
            &Target::Stack => {
                self.stack.push_front(value);
                Ok(())
            }
            &Target::Framebuffer(index) => {
                if let Value::Color(r, g, b) = value {
                    self.framebuffer[index] = (r, g, b);
                    Ok(())
                } else {
                    bail!("unable push a non-color value to the framebuffer");
                }
            }
        }
    }

    /// Moves the top value of the src target to the dest target
    fn mov(&mut self, dest: &Target, src: &Target) -> VMResult<()> {
        let src_value = self.pop(src)?;
        self.push(dest, src_value)?;

        Ok(())
    }

    /// Swaps the top values of the targets
    fn swp(&mut self, target_a: &Target, target_b: &Target) -> VMResult<()> {
        let a_value = self.pop(target_a)?;
        let b_value = self.pop(target_b)?;

        self.push(target_a, b_value)?;
        self.push(target_b, a_value)?;

        Ok(())
    }

    /// Calls the function at the specified address saving the return address
    /// to the call stack
    fn call(&mut self, addr: &Address) {
        self.call_stack.push_front(self.pc + 1);
        self.jmp(addr);
    }

    /// Returns from an ongoing function call
    fn ret(&mut self) -> VMResult<()> {
        if let Some(retur_addr) = self.call_stack.pop_front() {
            self.jmp(&retur_addr);
        } else {
            bail!("unable to return from an empty call stack");
        }

        Ok(())
    }
}
<commit_msg>Refactored instruction handling<commit_after>use definitions::PREAMBLE;
use definitions::Value;
use definitions::config::VMConfig;
use definitions::instruction::Instruction;
use definitions::interrupt::{ExternalInterrupt, InternalInterrupt};
use definitions::program::Program;
use definitions::target::Target;
use definitions::typedef::*;
use error::*;
use std::cmp::Ordering;
use std::collections::{BTreeMap, LinkedList};
use std::sync::mpsc::{Receiver, SyncSender, TryRecvError, TrySendError};
use std::thread::{self, JoinHandle};

pub fn start(program: Program, sender: SyncSender<Frame>, receiver: Receiver<ExternalInterrupt>)
    -> JoinHandle<()> {
    thread::spawn(
        move || {
            if let Err(ref e) = VM::default().exec(program, sender, receiver) {
                println!("error: {}", e);

                for e in e.iter().skip(1) {
                    println!("caused by: {}", e);
                }

                // The backtrace is not always generated. Try to run this example
                // with `RUST_BACKTRACE=1`.
                if let Some(backtrace) = e.backtrace() {
                    println!("backtrace: {:?}", backtrace);
                }
            }
        },
    )
}

/// The whole state of the VM
#[derive(Default, Debug)]
struct VM {
    /// The instructions that are currently executed
    image_data: Vec<Instruction>,
    /// The current program counter
    pc: Address,
    stack: LinkedList<Value>,
    val_index: BTreeMap<Address, Value>,
    interrupt_register: BTreeMap<usize, Address>,
    framebuffer: Frame,
    framebuffer_invalid: bool,
    /// A register for holding infomation about a recent comparison
    cmp_register: Option<Ordering>,
    /// A stack to hold the return addresses of function calls
    call_stack: LinkedList<Address>,
    /// A boolean used for locking the program counter
    pc_locked: bool,
    /// The configuration of the VM
    config: VMConfig,
    halted: bool,
}

impl VM {
    // # Maintainance functions

    /// Executes the given program
    pub fn exec(
        &mut self, program: Program, sender: SyncSender<Frame>,
        receiver: Receiver<ExternalInterrupt>
    ) -> VMResult<()> {
        self.reset();
        self.load_program(program)?;
        self.build_framebuffer();

        while (self.pc < self.image_data.len()) && !self.halted {
            self.external_interrupt(&receiver)?;

            let current_instruction = self.image_data[self.pc].clone();
            self.handle_instruction(current_instruction)?;

            self.flush_framebuffer(&sender)?;

            self.advance_pc();

            thread::yield_now();
        }

        Ok(())
    }

    /// Loads the instructions of the given program to the VM's state
    fn load_program(&mut self, program: Program) -> VMResult<()> {
        if program.preamble != String::from(PREAMBLE) {
            bail!("invalid preamble");
        } else if program.version != String::from(env!("CARGO_PKG_VERSION")) {
            bail!("invalid version");
        } else {
            self.image_data = program.instructions;
            self.config = program.config;
            Ok(())
        }
    }

    /// Aborts the execution of the current image
    fn abort(&mut self) {
        self.halted = true;
    }

    /// Handles an internal interrupt
    fn int(&mut self, interrupt: &InternalInterrupt) {
        match interrupt {
            &InternalInterrupt::FlushFramebuffer => self.invalidate(),
        }
    }

    /// Handles a single instruction
    fn handle_instruction(&mut self, instruction: Instruction) -> VMResult<()> {
        match instruction {
            Instruction::Halt => self.abort(),
            Instruction::Int(interrupt) => self.int(&interrupt),

            Instruction::Add(dest, src) => self.add(&dest, &src)?,
            Instruction::Sub(dest, src) => self.sub(&dest, &src)?,
            Instruction::Div(dest, src) => self.div(&dest, &src)?,
            Instruction::Mul(dest, src) => self.mul(&dest, &src)?,
            Instruction::Rem(dest, src) => self.rem(&dest, &src)?,

            Instruction::Cmp(target_a, target_b) => self.cmp(&target_a, &target_b)?,
            Instruction::Jmp(addr) => self.jmp(&addr),
            Instruction::JmpLt(addr) => self.jmp_lt(&addr),
            Instruction::JmpGt(addr) => self.jmp_gt(&addr),
            Instruction::JmpEq(addr) => self.jmp_eq(&addr),
            Instruction::JmpLtEq(addr) => self.jmp_lt_eq(&addr),
            Instruction::JmpGtEq(addr) => self.jmp_gt_eq(&addr),

            Instruction::Push(dest, value) => self.push(&dest, value)?,
            Instruction::Mov(dest, src) => self.mov(&dest, &src)?,
            Instruction::Swp(target_a, target_b) => self.swp(&target_a, &target_b)?,

            Instruction::Call(addr) => self.call(&addr),
            Instruction::Ret => self.ret()?,
        }

        Ok(())
    }

    /// Handles incoming interrupts or moves along
    fn external_interrupt(&mut self, receiver: &Receiver<ExternalInterrupt>) -> VMResult<()> {
        match receiver.try_recv() {
            Ok(interrupt) => {
                if interrupt.signal_id == 0 {
                    self.abort();
                    return Ok(());
                }

                let call_addr = if let Some(call_addr) = self.interrupt_register
                       .get(&interrupt.signal_id) {
                    call_addr.clone()
                } else {
                    bail!(
                        "no registered interrupt found at signal_id {}",
                        &interrupt.signal_id
                    );
                };

                for value in interrupt.args {
                    self.push(&Target::Stack, value)?;
                }

                self.call(&call_addr);

                Ok(())
            }
            Err(TryRecvError::Disconnected) => bail!("interrupt receiver disconnected"),
            _ => Ok(()),
        }
    }

    /// Flushes the internal framebuffer using the given sender
    fn flush_framebuffer(&mut self, sender: &SyncSender<Frame>) -> VMResult<()> {
        if self.framebuffer_invalid {
            if let Err(TrySendError::Disconnected(..)) = sender.try_send(self.framebuffer.clone()) {
                bail!("output channel disconnected");
            }

            self.framebuffer_invalid = false;
        }

        Ok(())
    }

    /// Allocates all the needed space in the framebuffer
    fn build_framebuffer(&mut self) {
        let ref resolution = self.config.display.resolution;
        let allocation_space = resolution.width * resolution.height;
        self.framebuffer = vec![(0, 0, 0); allocation_space];
    }

    /// Resets the VM to a clean state
    fn reset(&mut self) {
        *self = VM::default();
    }

    /// Locks the program counter in place
    fn lock_pc(&mut self) {
        self.pc_locked = true;
    }

    /// Advances the program counter
    fn advance_pc(&mut self) {
        if self.pc_locked {
            self.pc_locked = false;
        } else {
            self.pc += 1;
        }
    }

    /// Invalidates the frambuffer causing it to be resent to the display
    /// receiver
    fn invalidate(&mut self) {
        self.framebuffer_invalid = true;
    }

    /// Return the value at the specified target. The value of the target will
    /// be consumed
    fn pop(&mut self, target: &Target) -> VMResult<Value> {
        match target {
            &Target::ValueIndex(index) => {
                if let Some(value) = self.val_index.remove(&index) {
                    Ok(value)
                } else {
                    bail!("no value found at index {}", index);
                }
            }
            &Target::Stack => {
                if let Some(value) = self.stack.pop_front() {
                    Ok(value)
                } else {
                    bail!("unable to pop value off an empty stack");
                }
            }
            &Target::Framebuffer(index) => {
                if let Some(&(r, g, b)) = self.framebuffer.get(index) {
                    Ok(Value::Color(r, g, b))
                } else {
                    bail!("no value found in framebuffer at index {}", index);
                }
            }
        }
    }

    // # Instruction functions

    /// Adds the value of the src target to the value of the dest target
    fn add(&mut self, dest: &Target, src: &Target) -> VMResult<()> {
        let dest_value = self.pop(dest)?;
        let src_value = self.pop(src)?;

        self.push(dest, dest_value + src_value)?;

        Ok(())
    }

    /// Subtracts the value of the src target from the value of the dest target
    fn sub(&mut self, dest: &Target, src: &Target) -> VMResult<()> {
        let dest_value = self.pop(dest)?;
        let src_value = self.pop(src)?;

        self.push(dest, dest_value - src_value)?;

        Ok(())
    }

    /// Divides the value of the dest target through the value of the src target
    fn div(&mut self, dest: &Target, src: &Target) -> VMResult<()> {
        let dest_value = self.pop(dest)?;
        let src_value = self.pop(src)?;

        self.push(dest, dest_value / src_value)?;

        Ok(())
    }

    /// Multiplies the value of the dest target with the value of the src target
    fn mul(&mut self, dest: &Target, src: &Target) -> VMResult<()> {
        let dest_value = self.pop(dest)?;
        let src_value = self.pop(src)?;

        self.push(dest, dest_value * src_value)?;

        Ok(())
    }

    /// Applies the modulo operator on the value of the dest target using the
    /// value of the src target
    fn rem(&mut self, dest: &Target, src: &Target) -> VMResult<()> {
        let dest_value = self.pop(dest)?;
        let src_value = self.pop(src)?;

        self.push(dest, dest_value * src_value)?;

        Ok(())
    }

    /// Compares the top values of the two targets and saves the result to
    /// `self.cmp_register`
    fn cmp(&mut self, target_a: &Target, target_b: &Target) -> VMResult<()> {
        let target_a_value = self.pop(target_a)?;
        let target_b_value = self.pop(target_b)?;

        if target_a_value < target_b_value {
            self.cmp_register = Some(Ordering::Less);
        } else if target_a_value > target_b_value {
            self.cmp_register = Some(Ordering::Greater);
        } else if target_a_value == target_b_value {
            self.cmp_register = Some(Ordering::Equal);
        }

        Ok(())
    }

    /// Jumps unconditionally to the specified address
    fn jmp(&mut self, addr: &Address) {
        self.pc = *addr;
        self.lock_pc();
    }

    /// Jumps if the last compare got the result `Some(Ordering::Less)`
    fn jmp_lt(&mut self, addr: &Address) {
        if self.cmp_register == Some(Ordering::Less) {
            self.jmp(addr);
        }
    }

    /// Jumps if the last compare got the result `Some(Ordering::Greater)`
    fn jmp_gt(&mut self, addr: &Address) {
        if self.cmp_register == Some(Ordering::Greater) {
            self.jmp(addr);
        }
    }

    /// Jumps if the last compare got the result `Some(Ordering::Equal)`
    fn jmp_eq(&mut self, addr: &Address) {
        if self.cmp_register == Some(Ordering::Equal) {
            self.jmp(addr);
        }
    }

    /// Jumps if the last compare got the result `Some(Ordering::Less)` or
    /// `Some(Ordering::Equal)`
    fn jmp_lt_eq(&mut self, addr: &Address) {
        if (self.cmp_register == Some(Ordering::Less)) ||
           (self.cmp_register == Some(Ordering::Equal)) {
            self.jmp(addr);
        }
    }

    /// Jumps if the last compare got the result `Some(Ordering::Greater)` or
    /// `Some(Ordering::Equal)`
    fn jmp_gt_eq(&mut self, addr: &Address) {
        if (self.cmp_register == Some(Ordering::Greater)) ||
           (self.cmp_register == Some(Ordering::Equal)) {
            self.jmp(addr);
        }
    }

    /// Pushes the given value to the given target
    fn push(&mut self, dest: &Target, value: Value) -> VMResult<()> {
        match dest {
            &Target::ValueIndex(index) => {
                self.val_index.entry(index).or_insert(value);
                Ok(())
            }
            &Target::Stack => {
                self.stack.push_front(value);
                Ok(())
            }
            &Target::Framebuffer(index) => {
                if let Value::Color(r, g, b) = value {
                    self.framebuffer[index] = (r, g, b);
                    Ok(())
                } else {
                    bail!("unable push a non-color value to the framebuffer");
                }
            }
        }
    }

    /// Moves the top value of the src target to the dest target
    fn mov(&mut self, dest: &Target, src: &Target) -> VMResult<()> {
        let src_value = self.pop(src)?;
        self.push(dest, src_value)?;

        Ok(())
    }

    /// Swaps the top values of the targets
    fn swp(&mut self, target_a: &Target, target_b: &Target) -> VMResult<()> {
        let a_value = self.pop(target_a)?;
        let b_value = self.pop(target_b)?;

        self.push(target_a, b_value)?;
        self.push(target_b, a_value)?;

        Ok(())
    }

    /// Calls the function at the specified address saving the return address
    /// to the call stack
    fn call(&mut self, addr: &Address) {
        self.call_stack.push_front(self.pc + 1);
        self.jmp(addr);
    }

    /// Returns from an ongoing function call
    fn ret(&mut self) -> VMResult<()> {
        if let Some(retur_addr) = self.call_stack.pop_front() {
            self.jmp(&retur_addr);
        } else {
            bail!("unable to return from an empty call stack");
        }

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


<commit_before>// Copyright 2015 Nathan Sizemore <nathanrsizemore@gmail.com>
//
// 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 frame module provides a structred way to send and receive
//! message through streams.
//!
//! ## Data Framing
//!
//! ```ignore
//! 0                   1                   2                   3
//! 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0
//! +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
//! | Frame Start   |  Payload Len                  |  Payload  |
//! +-----------------------------------------------------------+
//! |           Payload Data Continued          |   Frame End   |
//! +-----------------------------------------------------------+
//!
//! Start Frame:    8 bits, must be 0x01
//! Payload Len:    16 bits
//! Payload Data:   (Payload Len) bytes
//! End Frame:      8 bits, must be 0x17
//! ```

use std::mem;

pub const START_BYTE:    u8 = 0x01;
pub const END_BYTE:      u8 = 0x17;

pub fn new(buf: &[u8]) -> Vec<u8> {
    let mut ret_buf = Vec::<u8>::with_capacity(buf.len() + 4);
    let buf_len = buf.len() as u16;

    trace!("new buf.len: {}", buf.len());
    trace!("payload_len: {}", buf_len);

    ret_buf.push(START_BYTE);
    ret_buf.push((buf_len >> 8) as u8);
    ret_buf.push(buf_len as u8);
    ret_buf.extend_from_slice(buf);
    ret_buf.push(END_BYTE);

    ret_buf
}

pub fn from_raw_parts(buf: &mut Vec<u8>) -> Option<Vec<u8>> {
    if buf.len() < 5 {
        trace!("buf.len not large enough to process");
        return None;
    }

    if buf[0] != START_BYTE {
        trace!("buf[0] was not START_BYTE");
        let mut new_buf = Vec::<u8>::with_capacity(1024);
        mem::swap(&mut new_buf, buf);
        return None;
    }

    let mask = 0xFFFFu16;
    let mut payload_len = ((buf[1] as u16) << 8) & mask;
    payload_len |= buf[2] as u16;

    trace!("buf.len: {}", buf.len());
    trace!("Payload Len: {}", payload_len);

    let payload_len = payload_len as usize;
    if (buf.len() - 4) < payload_len {
        trace!("Not enough in buf for expected payload\nExpected: {}\nActual: {}",
               payload_len,
               (buf.len() - 4));
        return None;
    }

    if buf[payload_len + 3] != END_BYTE {
        trace!("END_BYTE was not at expected location. Swapping for a fresh buffer");
        let mut new_buf = Vec::<u8>::with_capacity(1024);
        mem::swap(&mut new_buf, buf);
        return None;
    }

    let mut ret_buf = Vec::<u8>::with_capacity(payload_len);
    ret_buf.extend_from_slice(&buf[3..payload_len]);

    let buf_len = buf.len();
    let mut remaining_buf = Vec::<u8>::with_capacity(buf.len() - (payload_len + 4));
    remaining_buf.extend_from_slice(&buf[payload_len..buf_len]);
    mem::swap(buf, &mut remaining_buf);

    trace!("Complete frame read");

    Some(ret_buf)
}
<commit_msg>Off by 3 fix<commit_after>// Copyright 2015 Nathan Sizemore <nathanrsizemore@gmail.com>
//
// 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 frame module provides a structred way to send and receive
//! message through streams.
//!
//! ## Data Framing
//!
//! ```ignore
//! 0                   1                   2                   3
//! 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0
//! +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
//! | Frame Start   |  Payload Len                  |  Payload  |
//! +-----------------------------------------------------------+
//! |           Payload Data Continued          |   Frame End   |
//! +-----------------------------------------------------------+
//!
//! Start Frame:    8 bits, must be 0x01
//! Payload Len:    16 bits
//! Payload Data:   (Payload Len) bytes
//! End Frame:      8 bits, must be 0x17
//! ```

use std::mem;

pub const START_BYTE:    u8 = 0x01;
pub const END_BYTE:      u8 = 0x17;

pub fn new(buf: &[u8]) -> Vec<u8> {
    let mut ret_buf = Vec::<u8>::with_capacity(buf.len() + 4);
    let buf_len = buf.len() as u16;

    trace!("new buf.len: {}", buf.len());
    trace!("payload_len: {}", buf_len);

    ret_buf.push(START_BYTE);
    ret_buf.push((buf_len >> 8) as u8);
    ret_buf.push(buf_len as u8);
    ret_buf.extend_from_slice(buf);
    ret_buf.push(END_BYTE);

    ret_buf
}

pub fn from_raw_parts(buf: &mut Vec<u8>) -> Option<Vec<u8>> {
    if buf.len() < 5 {
        trace!("buf.len not large enough to process");
        return None;
    }

    if buf[0] != START_BYTE {
        trace!("buf[0] was not START_BYTE");
        let mut new_buf = Vec::<u8>::with_capacity(1024);
        mem::swap(&mut new_buf, buf);
        return None;
    }

    let mask = 0xFFFFu16;
    let mut payload_len = ((buf[1] as u16) << 8) & mask;
    payload_len |= buf[2] as u16;

    trace!("buf.len: {}", buf.len());
    trace!("Payload Len: {}", payload_len);

    let payload_len = payload_len as usize;
    if (buf.len() - 4) < payload_len {
        trace!("Not enough in buf for expected payload\nExpected: {}\nActual: {}",
               payload_len,
               (buf.len() - 4));
        return None;
    }

    if buf[payload_len + 3] != END_BYTE {
        trace!("END_BYTE was not at expected location. Swapping for a fresh buffer");
        let mut new_buf = Vec::<u8>::with_capacity(1024);
        mem::swap(&mut new_buf, buf);
        return None;
    }

    let mut ret_buf = Vec::<u8>::with_capacity(payload_len);
    ret_buf.extend_from_slice(&buf[3..payload_len]);

    let buf_len = buf.len();
    let mut remaining_buf = Vec::<u8>::with_capacity(buf.len() - (payload_len + 4));
    remaining_buf.extend_from_slice(&buf[(payload_len + 3)..buf_len]);
    mem::swap(buf, &mut remaining_buf);

    trace!("Complete frame read");

    Some(ret_buf)
}
<|endoftext|>


<commit_before>// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use std::ffi::{CStr, CString};
use std::fmt;
use super::address::SBAddress;
use super::block::SBBlock;
use super::compileunit::SBCompileUnit;
use super::expressionoptions::SBExpressionOptions;
use super::function::SBFunction;
use super::lineentry::SBLineEntry;
use super::module::SBModule;
use super::stream::SBStream;
use super::symbol::SBSymbol;
use super::symbolcontext::SBSymbolContext;
use super::thread::SBThread;
use super::value::SBValue;
use super::valuelist::SBValueList;
use super::variablesoptions::SBVariablesOptions;
use super::lldb_addr_t;
use sys;

/// One of the stack frames associated with a thread.
pub struct SBFrame {
    /// The underlying raw `SBFrameRef`.
    pub raw: sys::SBFrameRef,
}

impl SBFrame {
    /// Construct a new `SBFrame`.
    pub fn wrap(raw: sys::SBFrameRef) -> SBFrame {
        SBFrame { raw: raw }
    }

    /// Construct a new `Some(SBFrame)` or `None`.
    pub fn maybe_wrap(raw: sys::SBFrameRef) -> Option<SBFrame> {
        if unsafe { sys::SBFrameIsValid(raw) != 0 } {
            Some(SBFrame { raw: raw })
        } else {
            None
        }
    }

    /// Check whether or not this is a valid `SBFrame` value.
    pub fn is_valid(&self) -> bool {
        unsafe { sys::SBFrameIsValid(self.raw) != 0 }
    }

    /// The zero-based stack frame index for this frame.
    pub fn frame_id(&self) -> u32 {
        unsafe { sys::SBFrameGetFrameID(self.raw) }
    }

    /// Get the Canonical Frame Address for this stack frame.
    ///
    /// This is the DWARF standard's definition of a CFA, a
    /// stack address that remains constant throughout the
    /// lifetime of the function.
    pub fn cfa(&self) -> Option<lldb_addr_t> {
        let cfa = unsafe { sys::SBFrameGetCFA(self.raw) };
        if cfa != u64::max_value() {
            Some(cfa)
        } else {
            None
        }
    }

    #[allow(missing_docs)]
    pub fn pc(&self) -> lldb_addr_t {
        unsafe { sys::SBFrameGetPC(self.raw) }
    }

    #[allow(missing_docs)]
    pub fn set_pc(&self, new_pc: lldb_addr_t) -> bool {
        unsafe { sys::SBFrameSetPC(self.raw, new_pc) != 0 }
    }

    #[allow(missing_docs)]
    pub fn sp(&self) -> lldb_addr_t {
        unsafe { sys::SBFrameGetSP(self.raw) }
    }

    #[allow(missing_docs)]
    pub fn fp(&self) -> lldb_addr_t {
        unsafe { sys::SBFrameGetFP(self.raw) }
    }

    /// The program counter (PC) as a section offset address (`SBAddress`).
    pub fn pc_address(&self) -> SBAddress {
        SBAddress::wrap(unsafe { sys::SBFrameGetPCAddress(self.raw) })
    }

    /// The symbol context for this frame's current pc value.
    ///
    /// The frame maintains this symbol context and adds information to
    /// it as needed. This helps avoid repeated lookups of the same
    /// information.
    ///
    /// * `resolve_scope`: Flags that specify what type of symbol context
    ///   is needed by the caller. These flags have constants starting
    ///   with `SYMBOL_CONTEXT_ITEM_`.
    pub fn symbol_context(&self, resolve_scope: u32) -> SBSymbolContext {
        SBSymbolContext::wrap(unsafe { sys::SBFrameGetSymbolContext(self.raw, resolve_scope) })
    }

    /// The `SBModule` for this stack frame.
    pub fn module(&self) -> SBModule {
        SBModule::wrap(unsafe { sys::SBFrameGetModule(self.raw) })
    }

    /// The `SBCompileUnit` for this stack frame.
    pub fn compile_unit(&self) -> SBCompileUnit {
        SBCompileUnit::wrap(unsafe { sys::SBFrameGetCompileUnit(self.raw) })
    }

    /// The `SBFunction` for this stack frame.
    pub fn function(&self) -> SBFunction {
        SBFunction::wrap(unsafe { sys::SBFrameGetFunction(self.raw) })
    }

    /// The `SBSymbol` for this stack frame.
    pub fn symbol(&self) -> SBSymbol {
        SBSymbol::wrap(unsafe { sys::SBFrameGetSymbol(self.raw) })
    }

    /// Get the deepest block that contains the frame PC.
    pub fn block(&self) -> SBBlock {
        SBBlock::wrap(unsafe { sys::SBFrameGetBlock(self.raw) })
    }

    /// Get the appropriate function name for this frame. Inlined functions in
    /// LLDB are represented by blocks that have inlined function information, so
    /// just looking at the `SBFunction` or `SBSymbol` for a frame isn't enough.
    /// This function will return the appropriate function, symbol or inlined
    /// function name for the frame.
    ///
    /// This function returns:
    ///
    /// * the name of the inlined function (if there is one)
    /// * the name of the concrete function (if there is one)
    /// * the name of the symbol (if there is one)
    /// * NULL
    ///
    /// See also `is_inlined`.
    pub fn function_name(&self) -> Option<&str> {
        unsafe {
            match CStr::from_ptr(sys::SBFrameGetFunctionName(self.raw)).to_str() {
                Ok(s) => Some(s),
                _ => None,
            }
        }
    }

    #[allow(missing_docs)]
    pub fn display_function_name(&self) -> Option<&str> {
        unsafe {
            match CStr::from_ptr(sys::SBFrameGetDisplayFunctionName(self.raw)).to_str() {
                Ok(s) => Some(s),
                _ => None,
            }
        }
    }

    /// Return `true` if this frame represents an inlined function.
    pub fn is_inlined(&self) -> bool {
        unsafe { sys::SBFrameIsInlined(self.raw) != 0 }
    }

    /// Evaluate an expression within the context of this frame.
    pub fn evaluate_expression(&self, expression: &str, options: &SBExpressionOptions) -> SBValue {
        let expression = CString::new(expression).unwrap();
        SBValue::wrap(unsafe {
                          sys::SBFrameEvaluateExpression(self.raw, expression.as_ptr(), options.raw)
                      })
    }

    /// Gets the lexical block that defines the stack frame. Another way to think
    /// of this is it will return the block that contains all of the variables
    /// for a stack frame. Inlined functions are represented as `SBBlock` objects
    /// that have inlined function information: the name of the inlined function,
    /// where it was called from. The block that is returned will be the first
    /// block at or above the block for the PC (`SBFrame::block()`) that defines
    /// the scope of the frame. When a function contains no inlined functions,
    /// this will be the top most lexical block that defines the function.
    /// When a function has inlined functions and the PC is currently
    /// in one of those inlined functions, this method will return the inlined
    /// block that defines this frame. If the PC isn't currently in an inlined
    /// function, the lexical block that defines the function is returned.
    pub fn frame_block(&self) -> SBBlock {
        SBBlock::wrap(unsafe { sys::SBFrameGetFrameBlock(self.raw) })
    }

    /// The line table entry (`SBLineEntry`) for this stack frame.
    pub fn line_entry(&self) -> Option<SBLineEntry> {
        SBLineEntry::maybe_wrap(unsafe { sys::SBFrameGetLineEntry(self.raw) })
    }

    /// The thread that is executing this stack frame.
    pub fn thread(&self) -> SBThread {
        SBThread::wrap(unsafe { sys::SBFrameGetThread(self.raw) })
    }

    #[allow(missing_docs)]
    pub fn disassemble(&self) -> &str {
        unsafe {
            match CStr::from_ptr(sys::SBFrameDisassemble(self.raw)).to_str() {
                Ok(s) => s,
                _ => panic!("Invalid string?"),
            }
        }
    }

    #[allow(missing_docs)]
    pub fn clear(&self) {
        unsafe { sys::SBFrameClear(self.raw) }
    }

    #[allow(missing_docs)]
    pub fn variables(&self, options: &SBVariablesOptions) -> SBValueList {
        SBValueList::wrap(unsafe { sys::SBFrameGetVariables(self.raw, options.raw) })
    }

    #[allow(missing_docs)]
    pub fn all_variables(&self) -> SBValueList {
        let options = SBVariablesOptions::new();
        options.set_include_arguments(true);
        options.set_include_locals(true);
        options.set_include_statics(true);
        options.set_in_scope_only(true);
        self.variables(&options)
    }

    #[allow(missing_docs)]
    pub fn arguments(&self) -> SBValueList {
        let options = SBVariablesOptions::new();
        options.set_include_arguments(true);
        options.set_include_locals(false);
        options.set_include_statics(false);
        options.set_in_scope_only(false);
        self.variables(&options)
    }

    #[allow(missing_docs)]
    pub fn locals(&self) -> SBValueList {
        let options = SBVariablesOptions::new();
        options.set_include_arguments(false);
        options.set_include_locals(true);
        options.set_include_statics(false);
        options.set_in_scope_only(false);
        self.variables(&options)
    }

    #[allow(missing_docs)]
    pub fn statics(&self) -> SBValueList {
        let options = SBVariablesOptions::new();
        options.set_include_arguments(false);
        options.set_include_locals(false);
        options.set_include_statics(true);
        options.set_in_scope_only(false);
        self.variables(&options)
    }

    #[allow(missing_docs)]
    pub fn registers(&self) -> SBValueList {
        SBValueList::wrap(unsafe { sys::SBFrameGetRegisters(self.raw) })
    }

    #[allow(missing_docs)]
    pub fn find_register(&self, name: &str) -> Option<SBValue> {
        let name = CString::new(name).unwrap();
        SBValue::maybe_wrap(unsafe { sys::SBFrameFindRegister(self.raw, name.as_ptr()) })
    }

    #[allow(missing_docs)]
    pub fn parent_frame(&self) -> Option<SBFrame> {
        let thread = self.thread();
        let parent_idx = self.frame_id() + 1;
        if parent_idx < unsafe { sys::SBThreadGetNumFrames(thread.raw) } {
            SBFrame::maybe_wrap(unsafe { sys::SBThreadGetFrameAtIndex(thread.raw, parent_idx) })
        } else {
            None
        }
    }
}

impl fmt::Debug for SBFrame {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        let stream = SBStream::new();
        unsafe { sys::SBFrameGetDescription(self.raw, stream.raw) };
        write!(fmt, "SBFrame {{ {} }}", stream.data())
    }
}

impl Drop for SBFrame {
    fn drop(&mut self) {
        unsafe { sys::DisposeSBFrame(self.raw) };
    }
}

#[cfg(feature = "graphql")]
graphql_object!(SBFrame: super::debugger::SBDebugger | &self | {
    field is_valid() -> bool {
        self.is_valid()
    }

    // TODO(bm): This should be u32
    field frame_id() -> i64 {
        self.frame_id() as i64
    }

    // TODO(bm) This should be u64
    field cfa() -> Option<i64> {
        self.cfa().map(|i| i as i64)
    }

    // TODO(bm) This should be u64
    field pc() -> i64 {
        self.pc() as i64
    }

    // TODO(bm) This should be u64
    field sp() -> i64 {
        self.sp() as i64
    }

    // TODO(bm) This should be u64
    field fp() -> i64 {
        self.fp() as i64
    }

    field pc_address() -> SBAddress {
        self.pc_address()
    }

    field module() -> SBModule {
        self.module()
    }

    field compile_unit() -> SBCompileUnit {
        self.compile_unit()
    }

    field function() -> SBFunction {
        self.function()
    }

    field symbol() -> SBSymbol {
        self.symbol()
    }

    field block() -> SBBlock {
        self.block()
    }

    field function_name() -> Option<&str> {
        self.function_name()
    }

    field display_function_name() -> Option<&str> {
        self.display_function_name()
    }

    field is_inlined() -> bool {
        self.is_inlined()
    }

    field frame_block() -> SBBlock {
        self.frame_block()
    }

    field line_entry() -> Option<SBLineEntry> {
        self.line_entry()
    }

    field thread() -> SBThread {
        self.thread()
    }
});
<commit_msg>Improve SBFrame docs.<commit_after>// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use std::ffi::{CStr, CString};
use std::fmt;
use super::address::SBAddress;
use super::block::SBBlock;
use super::compileunit::SBCompileUnit;
use super::expressionoptions::SBExpressionOptions;
use super::function::SBFunction;
use super::lineentry::SBLineEntry;
use super::module::SBModule;
use super::stream::SBStream;
use super::symbol::SBSymbol;
use super::symbolcontext::SBSymbolContext;
use super::thread::SBThread;
use super::value::SBValue;
use super::valuelist::SBValueList;
use super::variablesoptions::SBVariablesOptions;
use super::lldb_addr_t;
use sys;

/// One of the stack frames associated with a thread.
pub struct SBFrame {
    /// The underlying raw `SBFrameRef`.
    pub raw: sys::SBFrameRef,
}

impl SBFrame {
    /// Construct a new `SBFrame`.
    pub fn wrap(raw: sys::SBFrameRef) -> SBFrame {
        SBFrame { raw: raw }
    }

    /// Construct a new `Some(SBFrame)` or `None`.
    pub fn maybe_wrap(raw: sys::SBFrameRef) -> Option<SBFrame> {
        if unsafe { sys::SBFrameIsValid(raw) != 0 } {
            Some(SBFrame { raw: raw })
        } else {
            None
        }
    }

    /// Check whether or not this is a valid `SBFrame` value.
    pub fn is_valid(&self) -> bool {
        unsafe { sys::SBFrameIsValid(self.raw) != 0 }
    }

    /// The zero-based stack frame index for this frame.
    ///
    /// This can be used to locate adjacent frames in the
    /// thread's stack frames.
    pub fn frame_id(&self) -> u32 {
        unsafe { sys::SBFrameGetFrameID(self.raw) }
    }

    /// Get the Canonical Frame Address for this stack frame.
    ///
    /// This is the DWARF standard's definition of a CFA, a
    /// stack address that remains constant throughout the
    /// lifetime of the function.
    pub fn cfa(&self) -> Option<lldb_addr_t> {
        let cfa = unsafe { sys::SBFrameGetCFA(self.raw) };
        if cfa != u64::max_value() {
            Some(cfa)
        } else {
            None
        }
    }

    /// The program counter (PC) as an unsigned integer.
    pub fn pc(&self) -> lldb_addr_t {
        unsafe { sys::SBFrameGetPC(self.raw) }
    }

    #[allow(missing_docs)]
    pub fn set_pc(&self, new_pc: lldb_addr_t) -> bool {
        unsafe { sys::SBFrameSetPC(self.raw, new_pc) != 0 }
    }

    /// The stack pointer address as an unsigned integer.
    pub fn sp(&self) -> lldb_addr_t {
        unsafe { sys::SBFrameGetSP(self.raw) }
    }

    /// The frame pointer address as an unsigned integer.
    pub fn fp(&self) -> lldb_addr_t {
        unsafe { sys::SBFrameGetFP(self.raw) }
    }

    /// The program counter (PC) as a section offset address (`SBAddress`).
    pub fn pc_address(&self) -> SBAddress {
        SBAddress::wrap(unsafe { sys::SBFrameGetPCAddress(self.raw) })
    }

    /// The symbol context for this frame's current pc value.
    ///
    /// The frame maintains this symbol context and adds information to
    /// it as needed. This helps avoid repeated lookups of the same
    /// information.
    ///
    /// * `resolve_scope`: Flags that specify what type of symbol context
    ///   is needed by the caller. These flags have constants starting
    ///   with `SYMBOL_CONTEXT_ITEM_`.
    pub fn symbol_context(&self, resolve_scope: u32) -> SBSymbolContext {
        SBSymbolContext::wrap(unsafe { sys::SBFrameGetSymbolContext(self.raw, resolve_scope) })
    }

    /// The `SBModule` for this stack frame.
    pub fn module(&self) -> SBModule {
        SBModule::wrap(unsafe { sys::SBFrameGetModule(self.raw) })
    }

    /// The `SBCompileUnit` for this stack frame.
    pub fn compile_unit(&self) -> SBCompileUnit {
        SBCompileUnit::wrap(unsafe { sys::SBFrameGetCompileUnit(self.raw) })
    }

    /// The `SBFunction` for this stack frame.
    pub fn function(&self) -> SBFunction {
        SBFunction::wrap(unsafe { sys::SBFrameGetFunction(self.raw) })
    }

    /// The `SBSymbol` for this stack frame.
    pub fn symbol(&self) -> SBSymbol {
        SBSymbol::wrap(unsafe { sys::SBFrameGetSymbol(self.raw) })
    }

    /// Get the deepest block that contains the frame PC.
    pub fn block(&self) -> SBBlock {
        SBBlock::wrap(unsafe { sys::SBFrameGetBlock(self.raw) })
    }

    /// Get the appropriate function name for this frame. Inlined functions in
    /// LLDB are represented by blocks that have inlined function information, so
    /// just looking at the `SBFunction` or `SBSymbol` for a frame isn't enough.
    /// This function will return the appropriate function, symbol or inlined
    /// function name for the frame.
    ///
    /// This function returns:
    ///
    /// * the name of the inlined function (if there is one)
    /// * the name of the concrete function (if there is one)
    /// * the name of the symbol (if there is one)
    /// * NULL
    ///
    /// See also `is_inlined`.
    pub fn function_name(&self) -> Option<&str> {
        unsafe {
            match CStr::from_ptr(sys::SBFrameGetFunctionName(self.raw)).to_str() {
                Ok(s) => Some(s),
                _ => None,
            }
        }
    }

    #[allow(missing_docs)]
    pub fn display_function_name(&self) -> Option<&str> {
        unsafe {
            match CStr::from_ptr(sys::SBFrameGetDisplayFunctionName(self.raw)).to_str() {
                Ok(s) => Some(s),
                _ => None,
            }
        }
    }

    /// Return `true` if this frame represents an inlined function.
    pub fn is_inlined(&self) -> bool {
        unsafe { sys::SBFrameIsInlined(self.raw) != 0 }
    }

    /// Evaluate an expression within the context of this frame.
    pub fn evaluate_expression(&self, expression: &str, options: &SBExpressionOptions) -> SBValue {
        let expression = CString::new(expression).unwrap();
        SBValue::wrap(unsafe {
                          sys::SBFrameEvaluateExpression(self.raw, expression.as_ptr(), options.raw)
                      })
    }

    /// Gets the lexical block that defines the stack frame. Another way to think
    /// of this is it will return the block that contains all of the variables
    /// for a stack frame. Inlined functions are represented as `SBBlock` objects
    /// that have inlined function information: the name of the inlined function,
    /// where it was called from. The block that is returned will be the first
    /// block at or above the block for the PC (`SBFrame::block()`) that defines
    /// the scope of the frame. When a function contains no inlined functions,
    /// this will be the top most lexical block that defines the function.
    /// When a function has inlined functions and the PC is currently
    /// in one of those inlined functions, this method will return the inlined
    /// block that defines this frame. If the PC isn't currently in an inlined
    /// function, the lexical block that defines the function is returned.
    pub fn frame_block(&self) -> SBBlock {
        SBBlock::wrap(unsafe { sys::SBFrameGetFrameBlock(self.raw) })
    }

    /// The line table entry (`SBLineEntry`) for this stack frame.
    pub fn line_entry(&self) -> Option<SBLineEntry> {
        SBLineEntry::maybe_wrap(unsafe { sys::SBFrameGetLineEntry(self.raw) })
    }

    /// The thread that is executing this stack frame.
    pub fn thread(&self) -> SBThread {
        SBThread::wrap(unsafe { sys::SBFrameGetThread(self.raw) })
    }

    /// The disassembly of this function, presented as a string.
    pub fn disassemble(&self) -> &str {
        unsafe {
            match CStr::from_ptr(sys::SBFrameDisassemble(self.raw)).to_str() {
                Ok(s) => s,
                _ => panic!("Invalid string?"),
            }
        }
    }

    #[allow(missing_docs)]
    pub fn clear(&self) {
        unsafe { sys::SBFrameClear(self.raw) }
    }

    /// The values for variables matching the specified options.
    pub fn variables(&self, options: &SBVariablesOptions) -> SBValueList {
        SBValueList::wrap(unsafe { sys::SBFrameGetVariables(self.raw, options.raw) })
    }

    /// The values for all variables in this stack frame.
    pub fn all_variables(&self) -> SBValueList {
        let options = SBVariablesOptions::new();
        options.set_include_arguments(true);
        options.set_include_locals(true);
        options.set_include_statics(true);
        options.set_in_scope_only(true);
        self.variables(&options)
    }

    /// The values for the argument variables in this stack frame.
    pub fn arguments(&self) -> SBValueList {
        let options = SBVariablesOptions::new();
        options.set_include_arguments(true);
        options.set_include_locals(false);
        options.set_include_statics(false);
        options.set_in_scope_only(false);
        self.variables(&options)
    }

    /// The values for the local variables in this stack frame.
    pub fn locals(&self) -> SBValueList {
        let options = SBVariablesOptions::new();
        options.set_include_arguments(false);
        options.set_include_locals(true);
        options.set_include_statics(false);
        options.set_in_scope_only(false);
        self.variables(&options)
    }

    /// The values for the static variables in this stack frame.
    pub fn statics(&self) -> SBValueList {
        let options = SBVariablesOptions::new();
        options.set_include_arguments(false);
        options.set_include_locals(false);
        options.set_include_statics(true);
        options.set_in_scope_only(false);
        self.variables(&options)
    }

    /// The values for the CPU registers for this stack frame.
    pub fn registers(&self) -> SBValueList {
        SBValueList::wrap(unsafe { sys::SBFrameGetRegisters(self.raw) })
    }

    /// The value for a particular register, if present.
    pub fn find_register(&self, name: &str) -> Option<SBValue> {
        let name = CString::new(name).unwrap();
        SBValue::maybe_wrap(unsafe { sys::SBFrameFindRegister(self.raw, name.as_ptr()) })
    }

    /// The parent frame that invoked this frame, if available.
    pub fn parent_frame(&self) -> Option<SBFrame> {
        let thread = self.thread();
        let parent_idx = self.frame_id() + 1;
        if parent_idx < unsafe { sys::SBThreadGetNumFrames(thread.raw) } {
            SBFrame::maybe_wrap(unsafe { sys::SBThreadGetFrameAtIndex(thread.raw, parent_idx) })
        } else {
            None
        }
    }
}

impl fmt::Debug for SBFrame {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        let stream = SBStream::new();
        unsafe { sys::SBFrameGetDescription(self.raw, stream.raw) };
        write!(fmt, "SBFrame {{ {} }}", stream.data())
    }
}

impl Drop for SBFrame {
    fn drop(&mut self) {
        unsafe { sys::DisposeSBFrame(self.raw) };
    }
}

#[cfg(feature = "graphql")]
graphql_object!(SBFrame: super::debugger::SBDebugger | &self | {
    field is_valid() -> bool {
        self.is_valid()
    }

    // TODO(bm): This should be u32
    field frame_id() -> i64 {
        self.frame_id() as i64
    }

    // TODO(bm) This should be u64
    field cfa() -> Option<i64> {
        self.cfa().map(|i| i as i64)
    }

    // TODO(bm) This should be u64
    field pc() -> i64 {
        self.pc() as i64
    }

    // TODO(bm) This should be u64
    field sp() -> i64 {
        self.sp() as i64
    }

    // TODO(bm) This should be u64
    field fp() -> i64 {
        self.fp() as i64
    }

    field pc_address() -> SBAddress {
        self.pc_address()
    }

    field module() -> SBModule {
        self.module()
    }

    field compile_unit() -> SBCompileUnit {
        self.compile_unit()
    }

    field function() -> SBFunction {
        self.function()
    }

    field symbol() -> SBSymbol {
        self.symbol()
    }

    field block() -> SBBlock {
        self.block()
    }

    field function_name() -> Option<&str> {
        self.function_name()
    }

    field display_function_name() -> Option<&str> {
        self.display_function_name()
    }

    field is_inlined() -> bool {
        self.is_inlined()
    }

    field frame_block() -> SBBlock {
        self.frame_block()
    }

    field line_entry() -> Option<SBLineEntry> {
        self.line_entry()
    }

    field thread() -> SBThread {
        self.thread()
    }
});
<|endoftext|>


<commit_before>use conrod::{Ui, UiId, Button, Label, Positionable, Labelable, Sizeable};
use petgraph::Graph;
use petgraph::graph::NodeIndex;
use opengl_graphics::glyph_cache::GlyphCache;

pub trait EditableNode: Clone {
    fn get_position(&self) -> [f64; 2];
    fn set_position(&mut self, [f64; 2]);
    fn default() -> Self;
}

pub trait EditableEdge: Clone {
    fn default() -> Self;
}

pub struct UiNode<N: EditableNode> {
    source_node: N,
    ui_id: UiId,

    // NOTE - These state variables probably eventually belong in a conrod widget state..
    drag: bool,
    collapse: bool,
    destroy: bool,
}

impl<N: EditableNode> UiNode<N> {
    pub fn draw(&mut self, ui: &mut Ui<GlyphCache>) {

        if self.destroy { return }

        if self.drag {
            self.source_node.set_position(ui.mouse.xy);
        }

        let ui_id_start = self.ui_id;

        let position = self.source_node.get_position();

        Button::new() //this should be a press-action, not a release; fixme with custom widget! also conrod should have a drag controller widget, which is basically what we're building
            .xy(position[0], position[1])
            .dimensions(100.0,20.0)
            .react(|| { self.drag = !self.drag; })
            .set(ui_id_start, ui);

        let mut cl = "<";
        if self.collapse { cl = ">"; }

        Button::new()
            .right(5.0)
            .label(cl)
            .dimensions(20.0,20.0)
            .react(|| { self.collapse = !self.collapse; })
            .set(ui_id_start + 1, ui);

        Button::new()
            .right(5.0)
            .label("x")
            .dimensions(20.0,20.0)
            .react(|| {
                // TODO how to handle nicely...
                //graph.remove_node(self.nidx);
                self.destroy=true;
            })
            .set(ui_id_start + 2, ui);

        if !self.collapse {
            Label::new("STUFF")
                .down_from(ui_id_start + 2, 5.0)
                .set(ui_id_start + 3, ui);
        }
    }
}

pub struct UiEdge<E> {
    source_edge: E,
    ui_id: UiId,
}

pub struct UiGraph<N: EditableNode, E: EditableEdge> {
    graph: Graph<UiNode<N>, UiEdge<E>>,
    ui_id_range: [UiId; 2],
}

impl<N: EditableNode, E: EditableEdge> UiGraph<N, E> {

    /// Initialize a UiGraph from a source graph structure
    pub fn new(source_graph: &Graph<N, E>, start_index: UiId) -> UiGraph<N, E> {

        let mut graph = Graph::new();

        let mut ui_id = start_index;

        // Add nodes from source graph to ui graph

        for node in source_graph.raw_nodes().iter() {
            graph.add_node(UiNode {
                source_node: node.weight.clone(),
                ui_id: ui_id,
                drag: false,
                collapse: false,
                destroy: false,
            });
            ui_id += 4;
        }

        // Node indices should be consistent between source graph and ui graph (as long as we don't remove nodes)
        // Add edges from source graph to ui graph

        for edge in source_graph.raw_edges().iter() {
            graph.add_edge(edge.source(), edge.target(), UiEdge {
                source_edge: edge.weight.clone(),
                ui_id: ui_id,
            });
            ui_id += 1;
        }

        UiGraph {
            graph: graph,
            ui_id_range: [start_index, ui_id]
        }
    }

    /// Add a node to the graph, adjusting the allocated UiId range
    pub fn add_node(&mut self) {
        let ui_id_range = self.ui_id_range;
        self.graph.add_node(UiNode {
            source_node: N::default(),
            ui_id: ui_id_range[1],
            drag: false,
            collapse: false,
            destroy: false,
        });
        self.ui_id_range = [ui_id_range[0], ui_id_range[1] + 4];
    }

    pub fn draw(&mut self, ui: &mut Ui<GlyphCache>) {
        let node_count = self.graph.node_count();
        for i in (0..node_count) {
            let index = NodeIndex::new(i);
            self.graph.node_weight_mut(index).map(|node| node.draw(ui));
        }
    }

    /// Export the UiGraph structure to the original source graph format
    pub fn as_source_graph(&self) -> Graph<N, E> {
        // TODO
        Graph::new()
    }
}
<commit_msg>UiGraph removes nodes marked for destruction<commit_after>use conrod::{Ui, UiId, Button, Label, Positionable, Labelable, Sizeable};
use petgraph::Graph;
use petgraph::graph::NodeIndex;
use opengl_graphics::glyph_cache::GlyphCache;

pub trait EditableNode: Clone {
    fn get_position(&self) -> [f64; 2];
    fn set_position(&mut self, [f64; 2]);
    fn default() -> Self;
}

pub trait EditableEdge: Clone {
    fn default() -> Self;
}

pub struct UiNode<N: EditableNode> {
    source_node: N,
    ui_id: UiId,

    // NOTE - These state variables probably eventually belong in a conrod widget state..
    drag: bool,
    collapse: bool,
    destroy: bool,
}

impl<N: EditableNode> UiNode<N> {
    pub fn draw(&mut self, ui: &mut Ui<GlyphCache>) {

        if self.destroy { return }

        if self.drag {
            self.source_node.set_position(ui.mouse.xy);
        }

        let ui_id_start = self.ui_id;

        let position = self.source_node.get_position();

        Button::new() //this should be a press-action, not a release; fixme with custom widget! also conrod should have a drag controller widget, which is basically what we're building
            .xy(position[0], position[1])
            .dimensions(100.0,20.0)
            .react(|| self.drag = !self.drag)
            .set(ui_id_start, ui);

        let mut cl = "<";
        if self.collapse { cl = ">"; }

        Button::new()
            .right(5.0)
            .label(cl)
            .dimensions(20.0,20.0)
            .react(|| self.collapse = !self.collapse)
            .set(ui_id_start + 1, ui);

        Button::new()
            .right(5.0)
            .label("x")
            .dimensions(20.0,20.0)
            .react(|| self.destroy = true)
            .set(ui_id_start + 2, ui);

        if !self.collapse {
            Label::new("STUFF")
                .down_from(ui_id_start + 2, 5.0)
                .set(ui_id_start + 3, ui);
        }
    }
}

pub struct UiEdge<E> {
    source_edge: E,
    ui_id: UiId,
}

pub struct UiGraph<N: EditableNode, E: EditableEdge> {
    graph: Graph<UiNode<N>, UiEdge<E>>,
    ui_id_range: [UiId; 2],
}

impl<N: EditableNode, E: EditableEdge> UiGraph<N, E> {

    /// Initialize a UiGraph from a source graph structure
    pub fn new(source_graph: &Graph<N, E>, start_index: UiId) -> UiGraph<N, E> {

        let mut graph = Graph::new();

        let mut ui_id = start_index;

        // Add nodes from source graph to ui graph

        for node in source_graph.raw_nodes().iter() {
            graph.add_node(UiNode {
                source_node: node.weight.clone(),
                ui_id: ui_id,
                drag: false,
                collapse: false,
                destroy: false,
            });
            ui_id += 4;
        }

        // Node indices should be consistent between source graph and ui graph (as long as we don't remove nodes)
        // Add edges from source graph to ui graph

        for edge in source_graph.raw_edges().iter() {
            graph.add_edge(edge.source(), edge.target(), UiEdge {
                source_edge: edge.weight.clone(),
                ui_id: ui_id,
            });
            ui_id += 1;
        }

        UiGraph {
            graph: graph,
            ui_id_range: [start_index, ui_id]
        }
    }

    /// Add a node to the graph, adjusting the allocated UiId range
    pub fn add_node(&mut self) {
        let ui_id_range = self.ui_id_range;
        self.graph.add_node(UiNode {
            source_node: N::default(),
            ui_id: ui_id_range[1],
            drag: false,
            collapse: false,
            destroy: false,
        });
        self.ui_id_range = [ui_id_range[0], ui_id_range[1] + 4];
    }

    pub fn draw(&mut self, ui: &mut Ui<GlyphCache>) {
        self.cleanup();
        let node_count = self.graph.node_count();
        for i in (0..node_count) {
            let index = NodeIndex::new(i);
            self.graph.node_weight_mut(index).map(|node| node.draw(ui));
        }
    }

    /// Remove all nodes and edges marked for destruction
    pub fn cleanup(&mut self) {
        loop {
            if let Some((i, _)) = self.graph.raw_nodes().iter().enumerate().find(|&(_i, ref node)| node.weight.destroy) {
                let index = NodeIndex::new(i);
                self.graph.remove_node(index);
            }
            break;
        }
    }

    /// Export the UiGraph structure to the original source graph format
    pub fn as_source_graph(&self) -> Graph<N, E> {
        // TODO
        Graph::new()
    }
}
<|endoftext|>


<commit_before>/// Represents the right-most end of a heterogeneous list
///
/// Used to begin one:
///
/// ```
/// # use frust::hlist::*;
///
/// let hlist1 = h_cons(1, HNil);
/// let (h, _) = hlist1.pop();
/// assert_eq!(h, 1);
/// ```
pub struct HNil;

/// Represents a heterogeneous list.
///
/// To construct one, use the h_cons method
///
/// ```
/// # use frust::hlist::*;
///
/// let h_list = h_cons("hello", h_cons(1, HNil));
/// let (h1, tail) = h_list.pop();
/// let (h2, _) = tail.pop();
/// assert_eq!(h1, "hello");
/// assert_eq!(h2, 1);
/// ```
pub struct HCons<H, T: HListPush> {
    head: H,
    tail: T,
}

pub trait HListPush {
    fn push<H>(self, h: H) -> HCons<H, Self> where Self: Sized;
}

impl<H, T: HListPush> HCons<H, T> {
    pub fn pop(self) -> (H, T) {
        (self.head, self.tail)
    }
}

impl HListPush for HNil {
    fn push<NewH>(self, h: NewH) -> HCons<NewH, HNil>
        where Self: Sized
    {
        HCons {
            head: h,
            tail: self,
        }
    }
}

impl<H, T: HListPush> HListPush for HCons<H, T> {
    fn push<NewH>(self, h: NewH) -> HCons<NewH, Self>
        where Self: Sized
    {
        HCons {
            head: h,
            tail: self,
        }
    }
}

pub fn h_cons<H, T: HListPush>(h: H, tail: T) -> HCons<H, T> {
    tail.push(h)
}

#[cfg(test)]
mod tests {

    use super::*;

    #[test]
    fn test_hcons() {
        let hlist1 = h_cons(1, HNil);
        let (h, _) = hlist1.pop();
        assert_eq!(h, 1);

        let hlist2 = h_cons("hello", h_cons(1, HNil));
        let (h2, tail2) = hlist2.pop();
        let (h1, _) = tail2.pop();
        assert_eq!(h2, "hello");
        assert_eq!(h1, 1);
    }
}
<commit_msg>Add docs for pop()<commit_after>/// Represents the right-most end of a heterogeneous list
///
/// Used to begin one:
///
/// ```
/// # use frust::hlist::*;
///
/// let hlist1 = h_cons(1, HNil);
/// let (h, _) = hlist1.pop();
/// assert_eq!(h, 1);
/// ```
pub struct HNil;

/// Represents a heterogeneous list.
///
/// To construct one, use the h_cons method
///
/// ```
/// # use frust::hlist::*;
///
/// let h_list = h_cons("hello", h_cons(1, HNil));
/// let (h1, tail) = h_list.pop();
/// let (h2, _) = tail.pop();
/// assert_eq!(h1, "hello");
/// assert_eq!(h2, 1);
/// ```
pub struct HCons<H, T: HListPush> {
    head: H,
    tail: T,
}

pub trait HListPush {
    fn push<H>(self, h: H) -> HCons<H, Self> where Self: Sized;
}

impl<H, T: HListPush> HCons<H, T> {

    /// Returns the head of the list and the tail of the list as a tuple2.
    /// The original list is consumed
    ///
    /// ```
    /// # use frust::hlist::*;
    ///
    /// let hlist1 = h_cons("hi", HNil);
    /// let (h, _) = hlist1.pop();
    /// assert_eq!(h, "hi");
    /// ```
    pub fn pop(self) -> (H, T) {
        (self.head, self.tail)
    }
}

impl HListPush for HNil {
    fn push<NewH>(self, h: NewH) -> HCons<NewH, HNil>
        where Self: Sized
    {
        HCons {
            head: h,
            tail: self,
        }
    }
}

impl<H, T: HListPush> HListPush for HCons<H, T> {
    fn push<NewH>(self, h: NewH) -> HCons<NewH, Self>
        where Self: Sized
    {
        HCons {
            head: h,
            tail: self,
        }
    }
}

/// Takes an element and an Hlist and returns another one with
/// the element prepended to the original list. The original list
/// is consumed
///
/// ```
/// # use frust::hlist::*;
///
/// let h_list = h_cons("what", h_cons(1.23f32, HNil));
/// let (h1, tail) = h_list.pop();
/// let (h2, _) = tail.pop();
/// assert_eq!(h1, "what");
/// assert_eq!(h2, 1.23f32);
/// ```
pub fn h_cons<H, T: HListPush>(h: H, tail: T) -> HCons<H, T> {
    tail.push(h)
}

#[cfg(test)]
mod tests {

    use super::*;

    #[test]
    fn test_hcons() {
        let hlist1 = h_cons(1, HNil);
        let (h, _) = hlist1.pop();
        assert_eq!(h, 1);

        let hlist2 = h_cons("hello", h_cons(1, HNil));
        let (h2, tail2) = hlist2.pop();
        let (h1, _) = tail2.pop();
        assert_eq!(h2, "hello");
        assert_eq!(h1, 1);
    }
}
<|endoftext|>


<commit_before>// Copyright 2016 Revolution Solid & Contributors.
// author(s): sysnett, carlos-lopez-garces
// rust-monster is licensed under an MIT License.

//! GA Scaling Schemes
//!
//! Scales the raw score of a Population's individuals.

use super::ga_core::GASolution;
use super::ga_population::GAPopulation;

/// Scaling Scheme Trait
///
/// Embeeded in the population, scales the values of raw score in a
/// GASolution to set their fitness score
pub trait GAScaling<T: GASolution>
{
    fn evaluate(&self, pop: &mut GAPopulation<T>);
}

/// No Scaling - Raw and Scaled are the same
pub struct GANoScaling;

impl<T: GASolution> GAScaling<T> for GANoScaling
{
    fn evaluate(&self, pop: &mut GAPopulation<T>)
    {
        // TODO: This is why we need iterators :(
        let pop_vec = pop.population();
        for ind in pop_vec
        {
            let rs = ind.score();
            ind.set_fitness(rs);
        }
    }
}

/// Linear Scaling
/// Uses a simple ```a*score+ b``` scaling.
/// ```a``` and ```b``` are the intersect of the linear function and are calculated
/// based on Goldberg's book implementation
pub struct GALinearScaling
{
    multiplier: f32
}

#[allow(unused_variables)]
const GA_LINEAR_SCALING_MULTIPLIER : f32 = 2.0;
impl GALinearScaling
{
    fn new(mult: f32) -> GALinearScaling
    {
        GALinearScaling{ multiplier: mult }
    }

    fn prescale(&self, max: f32, min: f32, avg: f32) -> (f32, f32)
    {
        let m = self.multiplier;
        let a;
        let b;
        let delta;

        if min > ((m*avg - max) / (m - 1.0))
        {
            delta = max - avg;
            a = (m - 1.0) * avg / delta;
            b = avg * (max - m * avg) / delta;
        }
        else
        {
            delta = avg - min;
            a = avg / delta;
            b = (-1.0*min*avg) / delta;
        }

        (a, b)
    }
}

impl<T: GASolution> GAScaling<T> for GALinearScaling
{
    fn evaluate(&self, pop : &mut GAPopulation<T>)
    {
        let max = pop.best_by_raw_score().score();
        let min = pop.worst_by_raw_score().score();

        // TODO: avg should be part of GAPopulation
        let avg = (max - min) / 2.0;

        let (a, b) = self.prescale(max, min, avg);

        let pop_vec = pop.population();
        for ind in pop_vec
        {
            let rs = ind.score();
            ind.set_fitness(a*rs+b);
        }
    }
}

////////////////////////////////////////
// Tests
#[cfg(test)]
mod test
{
    use super::*;
    use super::super::ga_core::*;
    use super::super::ga_population::*;
    use super::super::ga_test::*;

    #[test]
    fn no_scaling()
    {
        ga_test_setup("ga_scaling::no_scaling");
        let f = GA_TEST_FITNESS_VAL;
        let mut population = GAPopulation::new(vec![GATestSolution::new(f)], GAPopulationSortOrder::HighIsBest);
        population.sort();

        let scaler = GANoScaling{};

        scaler.evaluate(&mut population);

        assert_eq!(population.individual(0, GAPopulationSortBasis::Raw).fitness(),
                   population.individual(0, GAPopulationSortBasis::Raw).score());

        ga_test_teardown();
    }

    #[test]
    fn linear_scaling()
    {
        ga_test_setup("ga_scaling::no_scaling");
        let f = GA_TEST_FITNESS_VAL;
        let mut population = GAPopulation::new(vec![GATestSolution::new(f)], GAPopulationSortOrder::HighIsBest);
        population.sort();

        let scaler = GALinearScaling{ multiplier: super::GA_LINEAR_SCALING_MULTIPLIER };

        scaler.evaluate(&mut population);

        // TODO: Real test
        assert!(population.individual(0, GAPopulationSortBasis::Raw).fitness() !=
                population.individual(0, GAPopulationSortBasis::Raw).score());

        ga_test_teardown();
    }

}
<commit_msg>Remove {} when allocating GANoScaling, b/c unstable.<commit_after>// Copyright 2016 Revolution Solid & Contributors.
// author(s): sysnett, carlos-lopez-garces
// rust-monster is licensed under an MIT License.

//! GA Scaling Schemes
//!
//! Scales the raw score of a Population's individuals.

use super::ga_core::GASolution;
use super::ga_population::GAPopulation;

/// Scaling Scheme Trait
///
/// Embeeded in the population, scales the values of raw score in a
/// GASolution to set their fitness score
pub trait GAScaling<T: GASolution>
{
    fn evaluate(&self, pop: &mut GAPopulation<T>);
}

/// No Scaling - Raw and Scaled are the same
pub struct GANoScaling;

impl<T: GASolution> GAScaling<T> for GANoScaling
{
    fn evaluate(&self, pop: &mut GAPopulation<T>)
    {
        // TODO: This is why we need iterators :(
        let pop_vec = pop.population();
        for ind in pop_vec
        {
            let rs = ind.score();
            ind.set_fitness(rs);
        }
    }
}

/// Linear Scaling
/// Uses a simple ```a*score+ b``` scaling.
/// ```a``` and ```b``` are the intersect of the linear function and are calculated
/// based on Goldberg's book implementation
pub struct GALinearScaling
{
    multiplier: f32
}

#[allow(unused_variables)]
const GA_LINEAR_SCALING_MULTIPLIER : f32 = 2.0;
impl GALinearScaling
{
    fn new(mult: f32) -> GALinearScaling
    {
        GALinearScaling{ multiplier: mult }
    }

    fn prescale(&self, max: f32, min: f32, avg: f32) -> (f32, f32)
    {
        let m = self.multiplier;
        let a;
        let b;
        let delta;

        if min > ((m*avg - max) / (m - 1.0))
        {
            delta = max - avg;
            a = (m - 1.0) * avg / delta;
            b = avg * (max - m * avg) / delta;
        }
        else
        {
            delta = avg - min;
            a = avg / delta;
            b = (-1.0*min*avg) / delta;
        }

        (a, b)
    }
}

impl<T: GASolution> GAScaling<T> for GALinearScaling
{
    fn evaluate(&self, pop : &mut GAPopulation<T>)
    {
        let max = pop.best_by_raw_score().score();
        let min = pop.worst_by_raw_score().score();

        // TODO: avg should be part of GAPopulation
        let avg = (max - min) / 2.0;

        let (a, b) = self.prescale(max, min, avg);

        let pop_vec = pop.population();
        for ind in pop_vec
        {
            let rs = ind.score();
            ind.set_fitness(a*rs+b);
        }
    }
}

////////////////////////////////////////
// Tests
#[cfg(test)]
mod test
{
    use super::*;
    use super::super::ga_core::*;
    use super::super::ga_population::*;
    use super::super::ga_test::*;

    #[test]
    fn no_scaling()
    {
        ga_test_setup("ga_scaling::no_scaling");
        let f = GA_TEST_FITNESS_VAL;
        let mut population = GAPopulation::new(vec![GATestSolution::new(f)], GAPopulationSortOrder::HighIsBest);
        population.sort();

        let scaler = GANoScaling;

        scaler.evaluate(&mut population);

        assert_eq!(population.individual(0, GAPopulationSortBasis::Raw).fitness(),
                   population.individual(0, GAPopulationSortBasis::Raw).score());

        ga_test_teardown();
    }

    #[test]
    fn linear_scaling()
    {
        ga_test_setup("ga_scaling::no_scaling");
        let f = GA_TEST_FITNESS_VAL;
        let mut population = GAPopulation::new(vec![GATestSolution::new(f)], GAPopulationSortOrder::HighIsBest);
        population.sort();

        let scaler = GALinearScaling{ multiplier: super::GA_LINEAR_SCALING_MULTIPLIER };

        scaler.evaluate(&mut population);

        // TODO: Real test
        assert!(population.individual(0, GAPopulationSortBasis::Raw).fitness() !=
                population.individual(0, GAPopulationSortBasis::Raw).score());

        ga_test_teardown();
    }

}
<|endoftext|>


<commit_before>use std::str::CharIndices;
use std::ascii::AsciiExt;
use std::iter::Peekable;

use super::error::Error;

// use ascii end of transmission as EOF
const EOF: char = 0x4 as char;

macro_rules! my_try {
    ($e:expr) => ({
        match $e {
            Ok(x) => x,
            Err(x) => return Some(Err(x)),
        }
    });
}

#[derive(Clone, Copy, Debug)]
pub enum Token<'input> {
    OpenParen,
    ClosingParen,
    Dot,
    Quote,
    WhiteSpace,
    Char(char),
    Integer(i64),
    String(&'input str),
    Symbol(&'input str),
    Recur,
}

// Tokenzer state
#[derive(Debug, Clone, Copy)]
enum State<'input> {
    // start
    NewToken,
    Finished(Spanned<Token<'input>>),
    // start
    EatInteger(usize),
    WhiteSpace(usize),
    Minus(usize),
    Symbol(usize),
    StringStart(usize),
    StringBackslash(usize),
    Pound(usize),
    CharBegin(usize),
    EscapedChar(usize),
    FinishedChar(usize, char),
}
use self::State::*;

#[derive(Debug)]
pub struct Tokenizer<'input> {
    text: &'input str,
    chars: Peekable<CharIndices<'input>>,
    state: State<'input>,
}

pub type Spanned<T> = (usize, T, usize);

impl<'input> Tokenizer<'input> {
    pub fn new(text: &'input str) -> Tokenizer<'input> {
        Tokenizer {
            text: text,
            chars: text.char_indices().peekable(),
            state: NewToken,
        }
    }

    fn next_char(&mut self) -> Option<(usize, char)> {
        self.chars.next()
    }

    fn peek_next(&mut self) -> Option<&(usize, char)> {
        self.chars.peek()
    }
}

impl<'input> Iterator for Tokenizer<'input> {
    type Item = Result<Spanned<Token<'input>>, Error>;

    fn next(&mut self) -> Option<Self::Item> {
        loop {
            let next;
            match self.peek_next() {
                Some(&(pos, c)) => next = (self.state, pos, c),
                // check if we still need something
                None => next = (self.state, self.text.len(), EOF),
            }
/*
                {
                    let last_token = match self.state {
                        EscapedChar(start) => Ok((start, Token::Char('\\'), self.text.len())),

                    };
                    // fuse iterator
                    self.state = NewToken;
                    return Some(last_token);
                },
            }
            */

            self.state = match next {
                // pos + 1 is safe, because all these chars have width 1 byte
                (NewToken, pos, '(') => { self.next_char(); Finished((pos, Token::OpenParen, pos+1)) },
                (NewToken, pos, ')') => { self.next_char(); Finished((pos, Token::ClosingParen, pos+1)) },
                (NewToken, pos, '\'') => { self.next_char(); Finished((pos, Token::Quote, pos+1)) },
                (NewToken, pos, '.') => { self.next_char(); Finished((pos, Token::Dot, pos+1)) },
                (NewToken, pos, '-') => Minus(pos),
                (NewToken, pos, '"') => StringStart(pos),
                (NewToken, pos, '#') => Pound(pos),
                (NewToken, _, EOF) => return None,
                (NewToken, pos, c) if whitespace(c) => WhiteSpace(pos),
                (NewToken, pos, c) if numeric(c) => EatInteger(pos),
                (NewToken, pos, _) => Symbol(pos),

                // minus special case
                (Minus(start), _, c) if numeric(c) => EatInteger(start),
                (Minus(start), end, c) if end_of_item(c) => Finished((start, Token::Symbol(&self.text[start..end]), end)),
                (Minus(start), _, _) => Symbol(start),

                // whitespace
                (WhiteSpace(pos), _, c) if whitespace(c) => WhiteSpace(pos),
                (WhiteSpace(start), end, _) => Finished((start, Token::WhiteSpace, end)),

                // chars
                (Pound(pos), _, '\\') => CharBegin(pos),
                (Pound(start), end, c) if end_of_item(c) => Finished((start, Token::Symbol(&self.text[start..end]), end)),
                (Pound(pos), _, _) => Symbol(pos),

                (CharBegin(pos), _, '\\') => EscapedChar(pos),
                (CharBegin(_), _, EOF) => return Some(Err(Error::UnexpectedEofChar(self.text.len()))),
                (CharBegin(pos), _, c) if printable_char(c) => FinishedChar(pos, c),
                (CharBegin(_), pos, _) => return Some(Err(Error::NonAsciiChar(pos))),

                (EscapedChar(pos), _, c) if unescape_char(c).is_some() => FinishedChar(pos, unescape_char(c).unwrap()),
                (EscapedChar(start), end, EOF) => Finished((start, Token::Char('\\'), end)),
                (EscapedChar(start), end, _) => return Some(Err(Error::InvalidEscape(start+2, next_char(&self.text, end)))), // +2 bc #\ is 2 bytes

                (FinishedChar(start, x), end, c) if end_of_item(c) => Finished((start, Token::Char(x), end)),
                (FinishedChar(_, _), end, _) => return Some(Err(Error::InvalidToken(end, end))),

                // integers
                (EatInteger(start), _, c) if numeric(c) => EatInteger(start),
                (EatInteger(start), pos, c) if end_of_item(c) =>
                    // safe because we checked that text[start..pos] is a valid number
                    Finished((start, Token::Integer(self.text[start..pos].parse().unwrap()), pos)),
                (EatInteger(_), pos, _) => return Some(Err(Error::InvalidToken(pos, pos))),

                // strings
                (StringStart(start), end, '"') => {
                    self.next_char(); // bump
                    let string = &self.text[start+1..end];
                    for (i, c) in string.char_indices() {
                        if !c.is_ascii() {
                            return Some(Err(Error::NonAsciiChar(i+1))) // +1 bc start+1 above
                        }
                    }
                    Finished((start, Token::String(string), end))
                },
                (StringStart(_), _, EOF) => return Some(Err(Error::UnexpectedEofString(self.text.len()))),
                (StringStart(start), _, '\\') => StringBackslash(start),
                (StringStart(start), _, _) => StringStart(start),
                (StringBackslash(start), _, '"') => StringStart(start),
                (StringBackslash(start), _, c) if unescape_char(c).is_some() => StringStart(start),
                (StringBackslash(_), _, EOF) => return Some(Err(Error::UnexpectedEofString(self.text.len()))),
                (StringBackslash(_), pos, _) => return Some(Err(Error::InvalidEscape(pos-1, next_char(&self.text, pos)))), // -1 bc \ is 1 byte

                // symbols
                (Symbol(start), end, c) if end_of_item(c) => {
                    let token = if &self.text[start..end] == "recur" {
                        Token::Recur
                    } else {
                        Token::Symbol(&self.text[start..end])
                    };

                    Finished((start, token, end))
                },
                (Symbol(start), _, _) => Symbol(start),
                (Finished(_), _, _) => unreachable!(),
            };

            match self.state {
                Finished(token) => {
                    self.state = NewToken;
                    return Some(Ok(token))
                },
                _ if next.2 == EOF => self.state = NewToken, // fuse iterator
                _  => { self.next_char(); }, // bump
            }
        }
    }
}

fn whitespace(x: char) -> bool {
    x == ' ' ||
    x == '\n' ||
    x == '\t'
}

fn end_of_item(x: char) -> bool {
    whitespace(x) ||
    x == ')' ||
    x == EOF
}

pub fn escape_char(x: char) -> Option<char> {
    match x {
        '\n' => Some('n'),
        ' ' => Some('s'),
        '\t' => Some('t'),
        '\\' => Some('\\'),
        _ => None,
    }
}

fn unescape_char(x: char) -> Option<char> {
    match x {
        'n' => Some('\n'),
        's' => Some(' '),
        't' => Some('\t'),
        '\\' => Some('\\'),
        _ => None,
    }
}

fn next_char(text: &str, pos: usize) -> usize {
    pos + char::len_utf8(text.as_bytes()[pos] as char)
}

fn numeric(x: char) -> bool {
    '0' <= x && x <= '9'
}

fn printable_char(x: char) -> bool {
    x >= '!' &&
    x <= '~'
}

#[allow(dead_code)]
pub fn unescape_string(input: &str) -> String {
    let mut chars = input.chars();
    let mut s = String::with_capacity(input.chars().count());

    while let Some(c) = chars.next() {
        if c == '\\' {
            if let Some(next) = chars.next() {
                match next {
                    'n' => s.push('\n'),
                    't' => s.push('\t'),
                    '"' => s.push('"'),
                    's' => s.push(' '),
                    '\\' => s.push('\\'),
                    x => {
                        s.push('\\');
                        s.push(x);
                    }
                }
                continue;
            }
        }
        s.push(c);
    }
    s
}
<commit_msg>teach lexer names of special forms<commit_after>use std::str::CharIndices;
use std::ascii::AsciiExt;
use std::iter::Peekable;

use super::error::Error;

// use ascii end of transmission as EOF
const EOF: char = 0x4 as char;

macro_rules! my_try {
    ($e:expr) => ({
        match $e {
            Ok(x) => x,
            Err(x) => return Some(Err(x)),
        }
    });
}

#[derive(Clone, Copy, Debug)]
pub enum Token<'input> {
    OpenParen,
    ClosingParen,
    Dot,
    Quote,
    WhiteSpace,
    Char(char),
    Integer(i64),
    String(&'input str),
    Symbol(&'input str),
    Begin,
    Define,
    If,
    Let,
    Loop,
    Lambda,
    Recur,
}

// Tokenzer state
#[derive(Debug, Clone, Copy)]
enum State<'input> {
    // start
    NewToken,
    Finished(Spanned<Token<'input>>),
    // start
    EatInteger(usize),
    WhiteSpace(usize),
    Minus(usize),
    Symbol(usize),
    StringStart(usize),
    StringBackslash(usize),
    Pound(usize),
    CharBegin(usize),
    EscapedChar(usize),
    FinishedChar(usize, char),
}
use self::State::*;

#[derive(Debug)]
pub struct Tokenizer<'input> {
    text: &'input str,
    chars: Peekable<CharIndices<'input>>,
    state: State<'input>,
}

pub type Spanned<T> = (usize, T, usize);

impl<'input> Tokenizer<'input> {
    pub fn new(text: &'input str) -> Tokenizer<'input> {
        Tokenizer {
            text: text,
            chars: text.char_indices().peekable(),
            state: NewToken,
        }
    }

    fn next_char(&mut self) -> Option<(usize, char)> {
        self.chars.next()
    }

    fn peek_next(&mut self) -> Option<&(usize, char)> {
        self.chars.peek()
    }
}

impl<'input> Iterator for Tokenizer<'input> {
    type Item = Result<Spanned<Token<'input>>, Error>;

    fn next(&mut self) -> Option<Self::Item> {
        loop {
            let next;
            match self.peek_next() {
                Some(&(pos, c)) => next = (self.state, pos, c),
                // check if we still need something
                None => next = (self.state, self.text.len(), EOF),
            }
/*
                {
                    let last_token = match self.state {
                        EscapedChar(start) => Ok((start, Token::Char('\\'), self.text.len())),

                    };
                    // fuse iterator
                    self.state = NewToken;
                    return Some(last_token);
                },
            }
            */

            self.state = match next {
                // pos + 1 is safe, because all these chars have width 1 byte
                (NewToken, pos, '(') => { self.next_char(); Finished((pos, Token::OpenParen, pos+1)) },
                (NewToken, pos, ')') => { self.next_char(); Finished((pos, Token::ClosingParen, pos+1)) },
                (NewToken, pos, '\'') => { self.next_char(); Finished((pos, Token::Quote, pos+1)) },
                (NewToken, pos, '.') => { self.next_char(); Finished((pos, Token::Dot, pos+1)) },
                (NewToken, pos, '-') => Minus(pos),
                (NewToken, pos, '"') => StringStart(pos),
                (NewToken, pos, '#') => Pound(pos),
                (NewToken, _, EOF) => return None,
                (NewToken, pos, c) if whitespace(c) => WhiteSpace(pos),
                (NewToken, pos, c) if numeric(c) => EatInteger(pos),
                (NewToken, pos, _) => Symbol(pos),

                // minus special case
                (Minus(start), _, c) if numeric(c) => EatInteger(start),
                (Minus(start), end, c) if end_of_item(c) => Finished((start, Token::Symbol(&self.text[start..end]), end)),
                (Minus(start), _, _) => Symbol(start),

                // whitespace
                (WhiteSpace(pos), _, c) if whitespace(c) => WhiteSpace(pos),
                (WhiteSpace(start), end, _) => Finished((start, Token::WhiteSpace, end)),

                // chars
                (Pound(pos), _, '\\') => CharBegin(pos),
                (Pound(start), end, c) if end_of_item(c) => Finished((start, Token::Symbol(&self.text[start..end]), end)),
                (Pound(pos), _, _) => Symbol(pos),

                (CharBegin(pos), _, '\\') => EscapedChar(pos),
                (CharBegin(_), _, EOF) => return Some(Err(Error::UnexpectedEofChar(self.text.len()))),
                (CharBegin(pos), _, c) if printable_char(c) => FinishedChar(pos, c),
                (CharBegin(_), pos, _) => return Some(Err(Error::NonAsciiChar(pos))),

                (EscapedChar(pos), _, c) if unescape_char(c).is_some() => FinishedChar(pos, unescape_char(c).unwrap()),
                (EscapedChar(start), end, EOF) => Finished((start, Token::Char('\\'), end)),
                (EscapedChar(start), end, _) => return Some(Err(Error::InvalidEscape(start+2, next_char(&self.text, end)))), // +2 bc #\ is 2 bytes

                (FinishedChar(start, x), end, c) if end_of_item(c) => Finished((start, Token::Char(x), end)),
                (FinishedChar(_, _), end, _) => return Some(Err(Error::InvalidToken(end, end))),

                // integers
                (EatInteger(start), _, c) if numeric(c) => EatInteger(start),
                (EatInteger(start), pos, c) if end_of_item(c) =>
                    // safe because we checked that text[start..pos] is a valid number
                    Finished((start, Token::Integer(self.text[start..pos].parse().unwrap()), pos)),
                (EatInteger(_), pos, _) => return Some(Err(Error::InvalidToken(pos, pos))),

                // strings
                (StringStart(start), end, '"') => {
                    self.next_char(); // bump
                    let string = &self.text[start+1..end];
                    for (i, c) in string.char_indices() {
                        if !c.is_ascii() {
                            return Some(Err(Error::NonAsciiChar(i+1))) // +1 bc start+1 above
                        }
                    }
                    Finished((start, Token::String(string), end))
                },
                (StringStart(_), _, EOF) => return Some(Err(Error::UnexpectedEofString(self.text.len()))),
                (StringStart(start), _, '\\') => StringBackslash(start),
                (StringStart(start), _, _) => StringStart(start),
                (StringBackslash(start), _, '"') => StringStart(start),
                (StringBackslash(start), _, c) if unescape_char(c).is_some() => StringStart(start),
                (StringBackslash(_), _, EOF) => return Some(Err(Error::UnexpectedEofString(self.text.len()))),
                (StringBackslash(_), pos, _) => return Some(Err(Error::InvalidEscape(pos-1, next_char(&self.text, pos)))), // -1 bc \ is 1 byte

                // symbols
                (Symbol(start), end, c) if end_of_item(c) => {
                    let token = match &self.text[start..end] {
                        "begin" => Token::Begin,
                        "define" => Token::Define,
                        "if" => Token::If,
                        "let" => Token::Let,
                        "loop" => Token::Loop,
                        "lambda" => Token::Lambda,
                        "recur" => Token::Recur,
                        x => Token::Symbol(x),
                    };

                    Finished((start, token, end))
                },
                (Symbol(start), _, _) => Symbol(start),
                (Finished(_), _, _) => unreachable!(),
            };

            match self.state {
                Finished(token) => {
                    self.state = NewToken;
                    return Some(Ok(token))
                },
                _ if next.2 == EOF => self.state = NewToken, // fuse iterator
                _  => { self.next_char(); }, // bump
            }
        }
    }
}

fn whitespace(x: char) -> bool {
    x == ' ' ||
    x == '\n' ||
    x == '\t'
}

fn end_of_item(x: char) -> bool {
    whitespace(x) ||
    x == ')' ||
    x == EOF
}

pub fn escape_char(x: char) -> Option<char> {
    match x {
        '\n' => Some('n'),
        ' ' => Some('s'),
        '\t' => Some('t'),
        '\\' => Some('\\'),
        _ => None,
    }
}

fn unescape_char(x: char) -> Option<char> {
    match x {
        'n' => Some('\n'),
        's' => Some(' '),
        't' => Some('\t'),
        '\\' => Some('\\'),
        _ => None,
    }
}

fn next_char(text: &str, pos: usize) -> usize {
    pos + char::len_utf8(text.as_bytes()[pos] as char)
}

fn numeric(x: char) -> bool {
    '0' <= x && x <= '9'
}

fn printable_char(x: char) -> bool {
    x >= '!' &&
    x <= '~'
}

#[allow(dead_code)]
pub fn unescape_string(input: &str) -> String {
    let mut chars = input.chars();
    let mut s = String::with_capacity(input.chars().count());

    while let Some(c) = chars.next() {
        if c == '\\' {
            if let Some(next) = chars.next() {
                match next {
                    'n' => s.push('\n'),
                    't' => s.push('\t'),
                    '"' => s.push('"'),
                    's' => s.push(' '),
                    '\\' => s.push('\\'),
                    x => {
                        s.push('\\');
                        s.push(x);
                    }
                }
                continue;
            }
        }
        s.push(c);
    }
    s
}
<|endoftext|>