<commit_before>use class::ClassId;
use ctxt::Context;
use mem;

#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub enum BuiltinType {
    // type with only one value: ()
    Unit,

    // value types
    Int, Bool,

    // type Nil, only used in typeck until final type is known
    Nil,

    // pointer to object, only used internally
    Ptr,

    // String type
    Str,

    // Array types
    IntArray,

    // some class
    Class(ClassId),
}

impl BuiltinType {
    pub fn is_unit(&self) -> bool {
        match *self {
            BuiltinType::Unit => true,
            _ => false,
        }
    }

    pub fn is_nil(&self) -> bool {
        match *self {
            BuiltinType::Nil => true,
            _ => false
        }
    }

    pub fn is_cls(&self) -> bool {
        match *self {
            BuiltinType::Class(_) => true,
            _ => false,
        }
    }

    pub fn is_str(&self) -> bool {
        match *self {
            BuiltinType::Str => true,
            _ => false
        }
    }

    pub fn cls_id(&self) -> ClassId {
        match *self {
            BuiltinType::Class(cls_id) => cls_id,
            _ => panic!()
        }
    }

    pub fn name(&self, ctxt: &Context) -> String {
        match *self {
            BuiltinType::Unit => "()".into(),
            BuiltinType::Int => "int".into(),
            BuiltinType::Bool => "bool".into(),
            BuiltinType::Nil => "nil".into(),
            BuiltinType::Ptr => panic!("type Ptr only for internal use."),
            BuiltinType::Str => "Str".into(),
            BuiltinType::IntArray => "IntArray".into(),
            BuiltinType::Class(cid) => {
                let cls = ctxt.cls_by_id(cid);

                ctxt.interner.str(cls.name).to_string()
            }
        }
    }

    pub fn allows(&self, other: BuiltinType) -> bool {
        match *self {
            BuiltinType::Unit
                | BuiltinType::Bool
                | BuiltinType::Int
                | BuiltinType::Nil => *self == other,
            BuiltinType::Ptr => panic!("ptr does not allow any other types"),
            BuiltinType::Str
                | BuiltinType::IntArray
                | BuiltinType::Class(_) => *self == other || other.is_nil()
        }
    }

    pub fn if_nil(&self, other: BuiltinType) -> BuiltinType {
        if self.is_nil() {
            other
        } else {
            *self
        }
    }

    pub fn size(&self) -> i32 {
        match *self {
            BuiltinType::Unit => 0,
            BuiltinType::Bool => 1,
            BuiltinType::Int => 4,
            BuiltinType::Nil => panic!("type Nil does not have size."),
            BuiltinType::Str
                | BuiltinType::IntArray
                | BuiltinType::Class(_)
                | BuiltinType::Ptr => mem::ptr_width(),
        }
    }
}

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

    #[test]
    fn type_size() {
        assert_eq!(0, BuiltinType::Unit.size());
        assert_eq!(1, BuiltinType::Bool.size());
        assert_eq!(4, BuiltinType::Int.size());
        assert_eq!(mem::ptr_width(), BuiltinType::Str.size());
    }
}
<commit_msg>added MachineMode<commit_after>use class::ClassId;
use ctxt::Context;
use mem;

#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub enum BuiltinType {
    // type with only one value: ()
    Unit,

    // value types
    Int, Bool,

    // type Nil, only used in typeck until final type is known
    Nil,

    // pointer to object, only used internally
    Ptr,

    // String type
    Str,

    // Array types
    IntArray,

    // some class
    Class(ClassId),
}

impl BuiltinType {
    pub fn is_unit(&self) -> bool {
        match *self {
            BuiltinType::Unit => true,
            _ => false,
        }
    }

    pub fn is_nil(&self) -> bool {
        match *self {
            BuiltinType::Nil => true,
            _ => false
        }
    }

    pub fn is_cls(&self) -> bool {
        match *self {
            BuiltinType::Class(_) => true,
            _ => false,
        }
    }

    pub fn is_str(&self) -> bool {
        match *self {
            BuiltinType::Str => true,
            _ => false
        }
    }

    pub fn cls_id(&self) -> ClassId {
        match *self {
            BuiltinType::Class(cls_id) => cls_id,
            _ => panic!()
        }
    }

    pub fn name(&self, ctxt: &Context) -> String {
        match *self {
            BuiltinType::Unit => "()".into(),
            BuiltinType::Int => "int".into(),
            BuiltinType::Bool => "bool".into(),
            BuiltinType::Nil => "nil".into(),
            BuiltinType::Ptr => panic!("type Ptr only for internal use."),
            BuiltinType::Str => "Str".into(),
            BuiltinType::IntArray => "IntArray".into(),
            BuiltinType::Class(cid) => {
                let cls = ctxt.cls_by_id(cid);

                ctxt.interner.str(cls.name).to_string()
            }
        }
    }

    pub fn allows(&self, other: BuiltinType) -> bool {
        match *self {
            BuiltinType::Unit
                | BuiltinType::Bool
                | BuiltinType::Int
                | BuiltinType::Nil => *self == other,
            BuiltinType::Ptr => panic!("ptr does not allow any other types"),
            BuiltinType::Str
                | BuiltinType::IntArray
                | BuiltinType::Class(_) => *self == other || other.is_nil()
        }
    }

    pub fn if_nil(&self, other: BuiltinType) -> BuiltinType {
        if self.is_nil() {
            other
        } else {
            *self
        }
    }

    pub fn size(&self) -> i32 {
        match *self {
            BuiltinType::Unit => 0,
            BuiltinType::Bool => 1,
            BuiltinType::Int => 4,
            BuiltinType::Nil => panic!("no size for nil."),
            BuiltinType::Str
                | BuiltinType::IntArray
                | BuiltinType::Class(_)
                | BuiltinType::Ptr => mem::ptr_width(),
        }
    }

    pub fn mode(&self) -> MachineMode {
        match *self {
            BuiltinType::Unit => panic!("no machine mode for ()."),
            BuiltinType::Bool => MachineMode::Int8,
            BuiltinType::Int => MachineMode::Int32,
            BuiltinType::Nil => panic!("no machine mode for nil."),
            BuiltinType::Str
                | BuiltinType::IntArray
                | BuiltinType::Class(_)
                | BuiltinType::Ptr => MachineMode::Ptr,
        }
    }
}

#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub enum MachineMode {
    Int8, Int32, Ptr
}

impl MachineMode {
    pub fn size(self) -> i32 {
        match self {
            MachineMode::Int8 => 1,
            MachineMode::Int32 => 4,
            MachineMode::Ptr => mem::ptr_width()
        }
    }
}

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

    #[test]
    fn mode_size() {
        assert_eq!(1, MachineMode::Int8.size());
        assert_eq!(4, MachineMode::Int32.size());
        assert_eq!(mem::ptr_width(), MachineMode::Ptr.size());
    }

    #[test]
    fn mode_for_types() {
        assert_eq!(MachineMode::Int8, BuiltinType::Bool.mode());
        assert_eq!(MachineMode::Int32, BuiltinType::Int.mode());
        assert_eq!(MachineMode::Ptr, BuiltinType::Ptr.mode());
        assert_eq!(MachineMode::Ptr, BuiltinType::IntArray.mode());
        assert_eq!(MachineMode::Ptr, BuiltinType::Str.mode());
    }

    #[test]
    #[should_panic]
    fn mode_for_nil() {
        assert_eq!(MachineMode::Ptr, BuiltinType::Nil.mode());
    }

    #[test]
    #[should_panic]
    fn mode_for_unit() {
        assert_eq!(MachineMode::Ptr, BuiltinType::Unit.mode());
    }
}
<|endoftext|>


<commit_before>use find_folder;
use conrod::{
    Button, Canvas, Colorable, Frameable, Positionable, Labelable, Sizeable, Theme,
    Ui, UiCell, Text, Widget, color
};
use piston_window::{G2d, Glyphs, Graphics, PistonWindow};

use game::{Rustris, GameState};
use stats::GameStats;
use settings::*;

pub type Backend = (<G2d<'static> as Graphics>::Texture, Glyphs);
pub type UI = Ui<Backend>;
pub type UICell<'a> = UiCell<'a, Backend>;

pub fn create_ui(window: &PistonWindow) -> UI {
    let assets = find_folder::Search::KidsThenParents(3, 5)
        .for_folder("assets").unwrap();
    let font_path = assets.join("fonts/NotoSans/NotoSans-Regular.ttf");
    let theme = Theme::default();
    let glyph_cache = Glyphs::new(&font_path, window.factory.borrow().clone());
    UI::new(glyph_cache.unwrap(), theme)
}

pub fn set_ui(ref mut ui: UICell, game: &mut Rustris) {
    Canvas::new().flow_right(&[
        (LEFT_COLUMN, Canvas::new().color(color::DARK_CHARCOAL).pad(20.0)),
        (MIDDLE_COLUMN, Canvas::new().color(color::TRANSPARENT).length(300.0)),
        (RIGHT_COLUMN, Canvas::new().color(color::DARK_CHARCOAL).pad(20.0)),
    ]).set(MASTER, ui);
    set_scoreboard(ui, game.get_game_stats());

    if game.is_paused() {
        set_pause_menu(ui, game);
    }

}

fn set_pause_menu(ui: &mut UICell, game: &mut Rustris) {
    Canvas::new()
      .w_h(WINDOW_WIDTH as f64, WINDOW_HEIGHT as f64)
      .floating(true)
      .middle_of(MASTER)
      .set(PAUSE_OVERLAY, ui);

    Canvas::new().flow_down(&[
        (RESUME_CANVAS, Canvas::new()),
        (QUIT_CANVAS, Canvas::new())
    ]).label("Paused")
      .label_color(color::WHITE)
      .w_h(200.0, 200.0)
      .frame(1.0)
      .frame_color(color::WHITE)
      .pad(1.0)
      .middle_of(PAUSE_OVERLAY)
      .set(PAUSE_MENU, ui);

    Button::new()
        .label("Resume")
        .label_color(color::WHITE)
        .color(color::CHARCOAL)
        .middle_of(RESUME_CANVAS)
        .w_h(150.0, 30.0)
        .react(|| {
            game.set_game_state(GameState::Playing);
        })
        .set(RESUME_BUTTON, ui);

    Button::new()
        .label("Quit")
        .label_color(color::WHITE)
        .color(color::CHARCOAL)
        .middle_of(QUIT_CANVAS)
        .w_h(150.0, 30.0)
        .react(|| {})
        .set(QUIT_BUTTON, ui);
}

fn set_scoreboard(ui: &mut UICell, stats: &GameStats) {
    Canvas::new().flow_down(&[
        (SCORE_CANVAS, Canvas::new().label("Score").label_color(color::WHITE)),
        (LEVEL_CANVAS, Canvas::new().label("Level").label_color(color::WHITE)),
        (LINES_CANVAS, Canvas::new().label("Lines").label_color(color::WHITE))
    ]).w_h(150.0, 250.0)
      .frame(1.0)
      .frame_color(color::WHITE)
      .pad(1.0)
      .mid_bottom_of(LEFT_COLUMN)
      .set(SCOREBOARD, ui);

    Text::new(&stats.get_score().to_string())
        .color(color::WHITE)
        .middle_of(SCORE_CANVAS)
        .set(SCORE, ui);
    Text::new(&stats.get_level().to_string())
        .color(color::WHITE)
        .middle_of(LEVEL_CANVAS)
        .set(LEVEL, ui);
    Text::new(&stats.get_lines().to_string())
        .color(color::WHITE)
        .middle_of(LINES_CANVAS)
        .set(LINES, ui);
}

widget_ids! {
    // Canvas IDs
    MASTER,
    LEFT_COLUMN,
    MIDDLE_COLUMN,
    RIGHT_COLUMN,

    // Scoreboard IDs
    SCOREBOARD,
    SCORE_CANVAS,
    LEVEL_CANVAS,
    LINES_CANVAS,
    SCORE,
    LEVEL,
    LINES,

    //Pause Menu
    PAUSE_OVERLAY,
    PAUSE_MENU,
    RESUME_CANVAS,
    RESUME_BUTTON,
    QUIT_CANVAS,
    QUIT_BUTTON
}
<commit_msg>attempt to add the translucency<commit_after>use find_folder;
use conrod::{
    Button, Canvas, Colorable, Frameable, Positionable, Labelable, Sizeable, Theme,
    Ui, UiCell, Text, Widget, color
};
use piston_window::{G2d, Glyphs, Graphics, PistonWindow};

use game::{Rustris, GameState};
use stats::GameStats;
use settings::*;

pub type Backend = (<G2d<'static> as Graphics>::Texture, Glyphs);
pub type UI = Ui<Backend>;
pub type UICell<'a> = UiCell<'a, Backend>;

pub fn create_ui(window: &PistonWindow) -> UI {
    let assets = find_folder::Search::KidsThenParents(3, 5)
        .for_folder("assets").unwrap();
    let font_path = assets.join("fonts/NotoSans/NotoSans-Regular.ttf");
    let theme = Theme::default();
    let glyph_cache = Glyphs::new(&font_path, window.factory.borrow().clone());
    UI::new(glyph_cache.unwrap(), theme)
}

pub fn set_ui(ref mut ui: UICell, game: &mut Rustris) {
    Canvas::new().flow_right(&[
        (LEFT_COLUMN, Canvas::new().color(color::DARK_CHARCOAL).pad(20.0)),
        (MIDDLE_COLUMN, Canvas::new().color(color::TRANSPARENT).length(300.0)),
        (RIGHT_COLUMN, Canvas::new().color(color::DARK_CHARCOAL).pad(20.0)),
    ]).set(MASTER, ui);
    set_scoreboard(ui, game.get_game_stats());

    if game.is_paused() {
        set_pause_menu(ui, game);
    }

}

fn set_pause_menu(ui: &mut UICell, game: &mut Rustris) {
    Canvas::new()
      .w_h(WINDOW_WIDTH as f64, WINDOW_HEIGHT as f64)
      .floating(true)
      .middle_of(MASTER)
      .rgba(0.0, 0.0, 0.0, 0.3)
      .set(PAUSE_OVERLAY, ui);

    Canvas::new().flow_down(&[
        (RESUME_CANVAS, Canvas::new()),
        (QUIT_CANVAS, Canvas::new())
    ]).label("Paused")
      .label_color(color::WHITE)
      .w_h(200.0, 200.0)
      .frame(1.0)
      .frame_color(color::WHITE)
      .pad(1.0)
      .middle_of(PAUSE_OVERLAY)
      .set(PAUSE_MENU, ui);

    Button::new()
        .label("Resume")
        .label_color(color::WHITE)
        .color(color::CHARCOAL)
        .middle_of(RESUME_CANVAS)
        .w_h(150.0, 30.0)
        .react(|| {
            game.set_game_state(GameState::Playing);
        })
        .set(RESUME_BUTTON, ui);

    Button::new()
        .label("Quit")
        .label_color(color::WHITE)
        .color(color::CHARCOAL)
        .middle_of(QUIT_CANVAS)
        .w_h(150.0, 30.0)
        .react(|| {})
        .set(QUIT_BUTTON, ui);
}

fn set_scoreboard(ui: &mut UICell, stats: &GameStats) {
    Canvas::new().flow_down(&[
        (SCORE_CANVAS, Canvas::new().label("Score").label_color(color::WHITE)),
        (LEVEL_CANVAS, Canvas::new().label("Level").label_color(color::WHITE)),
        (LINES_CANVAS, Canvas::new().label("Lines").label_color(color::WHITE))
    ]).w_h(150.0, 250.0)
      .frame(1.0)
      .frame_color(color::WHITE)
      .pad(1.0)
      .mid_bottom_of(LEFT_COLUMN)
      .set(SCOREBOARD, ui);

    Text::new(&stats.get_score().to_string())
        .color(color::WHITE)
        .middle_of(SCORE_CANVAS)
        .set(SCORE, ui);
    Text::new(&stats.get_level().to_string())
        .color(color::WHITE)
        .middle_of(LEVEL_CANVAS)
        .set(LEVEL, ui);
    Text::new(&stats.get_lines().to_string())
        .color(color::WHITE)
        .middle_of(LINES_CANVAS)
        .set(LINES, ui);
}

widget_ids! {
    // Canvas IDs
    MASTER,
    LEFT_COLUMN,
    MIDDLE_COLUMN,
    RIGHT_COLUMN,

    // Scoreboard IDs
    SCOREBOARD,
    SCORE_CANVAS,
    LEVEL_CANVAS,
    LINES_CANVAS,
    SCORE,
    LEVEL,
    LINES,

    //Pause Menu
    PAUSE_OVERLAY,
    PAUSE_MENU,
    RESUME_CANVAS,
    RESUME_BUTTON,
    QUIT_CANVAS,
    QUIT_BUTTON
}
<|endoftext|>


<commit_before>//! Executes compiled JMESPath bytecode instructions.

extern crate rustc_serialize;

use self::rustc_serialize::json::Json;

use ast::{Ast, Comparator, KeyValuePair};

#[derive(Clone, PartialEq, Debug)]
pub enum Opcode {
    // Pops N operands from stack and calls a built-in function by name.
    Call(u8, String),
    // Pops two elements from the stack and pushes true/false.
    Cmp(Comparator),
    // Duplicates the top of the stack
    Dup,
    // Pops TOS and iterates over each element if it is an array. If it
    // is not an array, then jumps to the given address.
    Each(usize),
    // Pops TOS and pushes the <operand> key value of TOS onto the stack.
    // If TOS is not an "object", null is pushed onto the stack.
    Field(String),
    // Pops TOS and pushes the <operand> index value of TOS onto the stack.
    // If TOS is not an "array", null is pushed onto the stack.
    Index(usize),
    // Pops TOS and pushes the <operand> index from the end of the length of
    // of TOS onto the stack. If TOS is not an "array", null is pushed onto
    /// the stack.
    NegativeIndex(usize),
    // Pops two elements, T1 and T2 where T1 is a value and T2 is an
    // "array". Pushes T1 onto T2 and pushes T2 back onto the stack.
    InjectIdx(usize),
    // Pops two elements, T1 and T2 where T1 is a value and T2 is an
    // "object". Adds T1 at the given operand key onto T2 and pushes T2
    // back onto the stack.
    InjectKey(String),
    // Unconditional jump to an address.
    Jump(usize),
    // Pops the TOS and jumps if 0 or false
    Jumpz(usize),
    // Pops the call stack
    Ret(usize),
    // Pops the TOS
    Pop,
    // Pushes a value onto the stack
    Push(Json),
    // Pops TOS and pushes true/false if the value is truthy.
    Truthy,
    // Pops TOS and pushes the type of the popped value.
    Type
}

pub type Program = Vec<Opcode>;

/// JMESPath VM
pub struct Vm<'a> {
    /// The compiled program.
    opcodes: &'a Program,
    /// The opcode index.
    index: usize,
    /// The VM stack consisting of JSON typed values.
    stack: Vec<Json>
}

impl<'a> Vm<'a> {
    /// Creates a new VM using the given program and data.
    pub fn new(opcodes: &'a Vec<Opcode>, data: Json) -> Vm<'a> {
        Vm {
            opcodes: opcodes,
            stack: vec![data],
            index: 0
        }
    }

    pub fn run(&mut self) -> Result<Json, String> {
        macro_rules! tos {
            () => {{
                self.stack.pop().unwrap_or(Json::Null)
            }};
        }
        while self.index < self.opcodes.len() {
            match &self.opcodes[self.index] {
                &Opcode::Push(ref j) => {
                    self.stack.push(j.clone());
                },
                &Opcode::Pop => {
                    self.stack.pop();
                },
                &Opcode::Dup => {
                    if self.stack.is_empty() {
                        self.stack.push(Json::Null);
                    } else {
                        let tos = self.stack.pop().unwrap();
                        self.stack.push(tos.clone());
                        self.stack.push(tos);
                    }
                },
                &Opcode::Field(ref f) => {
                    match tos!().find(f) {
                        Some(j) => self.stack.push(j.clone()),
                        _ => self.stack.push(Json::Null)
                    };
                },
                &Opcode::Index(i) => {
                    let tos = tos!();
                    self.stack.push(tos.as_array()
                        .and_then(|a| a.len().checked_sub(i + 1))
                        .and_then(|_| Some(tos[i].clone()))
                        .unwrap_or(Json::Null));
                },
                &Opcode::NegativeIndex(i) => {
                    let tos = tos!();
                    self.stack.push(tos.as_array()
                        .and_then(|a| a.len().checked_sub(i + 1))
                        .and_then(|i| Some(tos[i].clone()))
                        .unwrap_or(Json::Null));
                },
                &Opcode::Truthy => {
                    let tos = tos!();
                    self.stack.push(Json::Boolean(match tos {
                        Json::Boolean(b) if b == false => false,
                        Json::String(ref s) if s.len() == 0 => false,
                        Json::Array(ref a) if a.is_empty() => false,
                        Json::Object(ref o) if o.is_empty() => false,
                        Json::Null => false,
                        _ => true
                    }));
                },
                &Opcode::Type => {
                    let tos = tos!();
                    self.stack.push(match tos {
                        Json::Boolean(_) => Json::String("boolean".to_string()),
                        Json::String(_) => Json::String("string".to_string()),
                        Json::I64(_) | Json::U64(_) | Json::F64(_) => Json::String("number".to_string()),
                        Json::Array(_) => Json::String("array".to_string()),
                        Json::Object(_) => Json::String("object".to_string()),
                        Json::Null => Json::String("null".to_string()),
                    });
                }
                _ => panic!("Not implemented yet!")
            }
            self.index += 1;
        }

        Ok(self.stack.pop().unwrap_or(Json::Null))
    }
}

#[cfg(test)]
mod test {
    extern crate rustc_serialize;
    use super::{Opcode, Vm};
    use self::rustc_serialize::json::Json;

    #[test] fn truthy_test() {
        let opcodes = vec![Opcode::Truthy];
        let tests = vec![("\"foo\"", true), ("\"\"", false),
                         ("[1]", true), ("[]", false),
                         ("{\"foo\": 1}", true), ("{}", false),
                         ("true", true), ("false", false),
                         ("null", false), ("1", true)];
        for (js, result) in tests {
            let mut vm = Vm::new(&opcodes, Json::from_str(js).unwrap());
            assert_eq!(Json::Boolean(result), vm.run().unwrap());
        }
    }

    #[test] fn pushes_and_pops() {
        let opcodes = vec![Opcode::Pop, Opcode::Push(Json::String("foo".to_string()))];
        let mut vm = Vm::new(&opcodes, Json::Null);
        assert_eq!(Json::String("foo".to_string()), vm.run().unwrap());
    }

    #[test] fn dups_tos() {
        let opcodes = vec![Opcode::Dup, Opcode::Pop];
        let mut vm = Vm::new(&opcodes, Json::I64(1));
        assert_eq!(Json::I64(1), vm.run().unwrap());
    }

    #[test] fn dups_null() {
        let opcodes = vec![Opcode::Pop, Opcode::Dup];
        let mut vm = Vm::new(&opcodes, Json::I64(1));
        assert_eq!(Json::Null, vm.run().unwrap());
    }

    #[test] fn extracts_fields() {
        let opcodes = vec![Opcode::Field("a".to_string())];
        let mut vm = Vm::new(&opcodes, Json::from_str("{\"a\": 1}").unwrap());
        assert_eq!(Json::U64(1), vm.run().unwrap());
    }

    #[test] fn pushes_null_when_extracting_missing_field() {
        let opcodes = vec![Opcode::Field("a".to_string())];
        let mut vm = Vm::new(&opcodes, Json::from_str("{\"b\": 1}").unwrap());
        assert_eq!(Json::Null, vm.run().unwrap());
    }

    #[test] fn pushes_null_when_extracting_field_from_non_object() {
        let opcodes = vec![Opcode::Field("a".to_string())];
        let mut vm = Vm::new(&opcodes, Json::I64(1));
        assert_eq!(Json::Null, vm.run().unwrap());
    }

    #[test] fn extracts_indices() {
        let js = Json::from_str("[0, 1]").unwrap();
        let tests = vec![(Opcode::Index(0), Json::U64(0)),
                         (Opcode::Index(1), Json::U64(1)),
                         (Opcode::Index(2), Json::Null),
                         (Opcode::Index(3), Json::Null)];
        for (op, result) in tests {
            let opcodes = vec![op];
            let mut vm = Vm::new(&opcodes, js.clone());
            assert_eq!(result, vm.run().unwrap());
        }
    }

    #[test] fn extracts_negative_indices() {
        let js = Json::from_str("[0, 1]").unwrap();
        let tests = vec![(Opcode::NegativeIndex(0), Json::U64(1)),
                         (Opcode::NegativeIndex(1), Json::U64(0)),
                         (Opcode::NegativeIndex(2), Json::Null),
                         (Opcode::NegativeIndex(3), Json::Null)];
        for (op, result) in tests {
            let opcodes = vec![op];
            let mut vm = Vm::new(&opcodes, js.clone());
            assert_eq!(result, vm.run().unwrap());
        }
    }

    #[test] fn pushes_type_on_stack() {
        let js = Json::from_str("[0, 1]").unwrap();
        let opcodes = vec![Opcode::Type];
        let tests = vec![(Json::String("a".to_string()), Json::String("string".to_string())),
                         (Json::Array(vec![]), Json::String("array".to_string())),
                         (Json::from_str("{}").unwrap(), Json::String("object".to_string())),
                         (Json::I64(1), Json::String("number".to_string())),
                         (Json::Null, Json::String("null".to_string())),
                         (Json::Boolean(true), Json::String("boolean".to_string()))];
        for (js, result) in tests {
            let mut vm = Vm::new(&opcodes, js);
            assert_eq!(result, vm.run().unwrap());
        }
    }
}
<commit_msg>Adding Jump and Jumpz opcodes<commit_after>//! Executes compiled JMESPath bytecode instructions.

extern crate rustc_serialize;

use self::rustc_serialize::json::Json;

use ast::{Ast, Comparator, KeyValuePair};

#[derive(Clone, PartialEq, Debug)]
pub enum Opcode {
    // Pops N operands from stack and calls a built-in function by name.
    Call(u8, String),
    // Pops two elements from the stack and pushes true/false.
    Cmp(Comparator),
    // Duplicates the top of the stack
    Dup,
    // Pops TOS and iterates over each element if it is an array. If it
    // is not an array, then jumps to the given address.
    Each(usize),
    // Pops TOS and pushes the <operand> key value of TOS onto the stack.
    // If TOS is not an "object", null is pushed onto the stack.
    Field(String),
    // Pops TOS and pushes the <operand> index value of TOS onto the stack.
    // If TOS is not an "array", null is pushed onto the stack.
    Index(usize),
    // Pops TOS and pushes the <operand> index from the end of the length of
    // of TOS onto the stack. If TOS is not an "array", null is pushed onto
    /// the stack.
    NegativeIndex(usize),
    // Pops two elements, T1 and T2 where T1 is a value and T2 is an
    // "array". Pushes T1 onto T2 and pushes T2 back onto the stack.
    InjectIdx(usize),
    // Pops two elements, T1 and T2 where T1 is a value and T2 is an
    // "object". Adds T1 at the given operand key onto T2 and pushes T2
    // back onto the stack.
    InjectKey(String),
    // Unconditional jump to an address.
    Jump(usize),
    // Pops the TOS and jumps if 0 or false
    Jumpz(usize),
    // Pops the call stack
    Ret(usize),
    // Pops the TOS
    Pop,
    // Pushes a value onto the stack
    Push(Json),
    // Pops TOS and pushes true/false if the value is truthy.
    Truthy,
    // Pops TOS and pushes the type of the popped value.
    Type
}

pub type Program = Vec<Opcode>;

/// JMESPath VM
pub struct Vm<'a> {
    /// The compiled program.
    opcodes: &'a Program,
    /// The opcode index.
    index: usize,
    /// The VM stack consisting of JSON typed values.
    stack: Vec<Json>
}

impl<'a> Vm<'a> {
    /// Creates a new VM using the given program and data.
    pub fn new(opcodes: &'a Vec<Opcode>, data: Json) -> Vm<'a> {
        Vm {
            opcodes: opcodes,
            stack: vec![data],
            index: 0
        }
    }

    pub fn run(&mut self) -> Result<Json, String> {
        macro_rules! tos {
            () => {{
                self.stack.pop().unwrap_or(Json::Null)
            }};
        }
        while self.index < self.opcodes.len() {
            match &self.opcodes[self.index] {
                &Opcode::Push(ref j) => {
                    self.stack.push(j.clone());
                },
                &Opcode::Pop => {
                    self.stack.pop();
                },
                &Opcode::Dup => {
                    if self.stack.is_empty() {
                        self.stack.push(Json::Null);
                    } else {
                        let tos = self.stack.pop().unwrap();
                        self.stack.push(tos.clone());
                        self.stack.push(tos);
                    }
                },
                &Opcode::Field(ref f) => {
                    match tos!().find(f) {
                        Some(j) => self.stack.push(j.clone()),
                        _ => self.stack.push(Json::Null)
                    };
                },
                &Opcode::Index(i) => {
                    let tos = tos!();
                    self.stack.push(tos.as_array()
                        .and_then(|a| a.len().checked_sub(i + 1))
                        .and_then(|_| Some(tos[i].clone()))
                        .unwrap_or(Json::Null));
                },
                &Opcode::NegativeIndex(i) => {
                    let tos = tos!();
                    self.stack.push(tos.as_array()
                        .and_then(|a| a.len().checked_sub(i + 1))
                        .and_then(|i| Some(tos[i].clone()))
                        .unwrap_or(Json::Null));
                },
                &Opcode::Truthy => {
                    let tos = tos!();
                    self.stack.push(Json::Boolean(match tos {
                        Json::Boolean(b) if b == false => false,
                        Json::String(ref s) if s.len() == 0 => false,
                        Json::Array(ref a) if a.is_empty() => false,
                        Json::Object(ref o) if o.is_empty() => false,
                        Json::Null => false,
                        _ => true
                    }));
                },
                &Opcode::Type => {
                    let tos = tos!();
                    self.stack.push(match tos {
                        Json::Boolean(_) => Json::String("boolean".to_string()),
                        Json::String(_) => Json::String("string".to_string()),
                        Json::I64(_) | Json::U64(_) | Json::F64(_) => {
                            Json::String("number".to_string())
                        },
                        Json::Array(_) => Json::String("array".to_string()),
                        Json::Object(_) => Json::String("object".to_string()),
                        Json::Null => Json::String("null".to_string()),
                    });
                },
                &Opcode::Jump(address) => {
                    if self.opcodes.get(address).is_none() {
                        return Err(format!("Invalid jump address {}", address));

                    }
                    self.index = address;
                    continue;
                },
                &Opcode::Jumpz(address) => {
                    if self.opcodes.get(address).is_none() {
                        return Err(format!("Invalid jump address {}", address));
                    }
                    let tos = tos!();
                    self.index = match tos {
                        Json::Boolean(b) if b == false => address,
                        Json::I64(d) if d == 0 => address,
                        Json::F64(f) if f == 0f64 => address,
                        Json::U64(u) if u == 0 => address,
                        _ => self.index + 1
                    };
                    continue;
                },
                _ => panic!("Not implemented yet!")
            }
            self.index += 1;
        }

        Ok(self.stack.pop().unwrap_or(Json::Null))
    }
}

#[cfg(test)]
mod test {
    extern crate rustc_serialize;
    use super::{Opcode, Vm};
    use self::rustc_serialize::json::Json;

    #[test] fn truthy_test() {
        let opcodes = vec![Opcode::Truthy];
        let tests = vec![("\"foo\"", true), ("\"\"", false),
                         ("[1]", true), ("[]", false),
                         ("{\"foo\": 1}", true), ("{}", false),
                         ("true", true), ("false", false),
                         ("null", false), ("1", true)];
        for (js, result) in tests {
            let mut vm = Vm::new(&opcodes, Json::from_str(js).unwrap());
            assert_eq!(Json::Boolean(result), vm.run().unwrap());
        }
    }

    #[test] fn pushes_and_pops() {
        let opcodes = vec![Opcode::Pop, Opcode::Push(Json::String("foo".to_string()))];
        let mut vm = Vm::new(&opcodes, Json::Null);
        assert_eq!(Json::String("foo".to_string()), vm.run().unwrap());
    }

    #[test] fn dups_tos() {
        let opcodes = vec![Opcode::Dup, Opcode::Pop];
        let mut vm = Vm::new(&opcodes, Json::I64(1));
        assert_eq!(Json::I64(1), vm.run().unwrap());
    }

    #[test] fn dups_null() {
        let opcodes = vec![Opcode::Pop, Opcode::Dup];
        let mut vm = Vm::new(&opcodes, Json::I64(1));
        assert_eq!(Json::Null, vm.run().unwrap());
    }

    #[test] fn extracts_fields() {
        let opcodes = vec![Opcode::Field("a".to_string())];
        let mut vm = Vm::new(&opcodes, Json::from_str("{\"a\": 1}").unwrap());
        assert_eq!(Json::U64(1), vm.run().unwrap());
    }

    #[test] fn pushes_null_when_extracting_missing_field() {
        let opcodes = vec![Opcode::Field("a".to_string())];
        let mut vm = Vm::new(&opcodes, Json::from_str("{\"b\": 1}").unwrap());
        assert_eq!(Json::Null, vm.run().unwrap());
    }

    #[test] fn pushes_null_when_extracting_field_from_non_object() {
        let opcodes = vec![Opcode::Field("a".to_string())];
        let mut vm = Vm::new(&opcodes, Json::I64(1));
        assert_eq!(Json::Null, vm.run().unwrap());
    }

    #[test] fn extracts_indices() {
        let js = Json::from_str("[0, 1]").unwrap();
        let tests = vec![(Opcode::Index(0), Json::U64(0)),
                         (Opcode::Index(1), Json::U64(1)),
                         (Opcode::Index(2), Json::Null),
                         (Opcode::Index(3), Json::Null)];
        for (op, result) in tests {
            let opcodes = vec![op];
            let mut vm = Vm::new(&opcodes, js.clone());
            assert_eq!(result, vm.run().unwrap());
        }
    }

    #[test] fn extracts_negative_indices() {
        let js = Json::from_str("[0, 1]").unwrap();
        let tests = vec![(Opcode::NegativeIndex(0), Json::U64(1)),
                         (Opcode::NegativeIndex(1), Json::U64(0)),
                         (Opcode::NegativeIndex(2), Json::Null),
                         (Opcode::NegativeIndex(3), Json::Null)];
        for (op, result) in tests {
            let opcodes = vec![op];
            let mut vm = Vm::new(&opcodes, js.clone());
            assert_eq!(result, vm.run().unwrap());
        }
    }

    #[test] fn pushes_type_on_stack() {
        let js = Json::from_str("[0, 1]").unwrap();
        let opcodes = vec![Opcode::Type];
        let tests = vec![(Json::String("a".to_string()), Json::String("string".to_string())),
                         (Json::Array(vec![]), Json::String("array".to_string())),
                         (Json::from_str("{}").unwrap(), Json::String("object".to_string())),
                         (Json::I64(1), Json::String("number".to_string())),
                         (Json::Null, Json::String("null".to_string())),
                         (Json::Boolean(true), Json::String("boolean".to_string()))];
        for (js, result) in tests {
            let mut vm = Vm::new(&opcodes, js);
            assert_eq!(result, vm.run().unwrap());
        }
    }

    #[test] fn can_jump() {
        let opcodes = vec![Opcode::Jump(2),
                           Opcode::Jump(3),
                           Opcode::Jump(1),
                           Opcode::Push(Json::Boolean(true))];
        let mut vm = Vm::new(&opcodes, Json::Null);
        assert_eq!(Json::Boolean(true), vm.run().unwrap());
    }

    #[test] fn checks_if_jump_is_valid() {
        let opcodes = vec![Opcode::Jump(2)];
        let mut vm = Vm::new(&opcodes, Json::Null);
        assert_eq!(Err("Invalid jump address 2".to_string()), vm.run());
    }

    #[test] fn checks_if_jumpz_is_valid() {
        let opcodes = vec![Opcode::Jumpz(2)];
        let mut vm = Vm::new(&opcodes, Json::Null);
        assert_eq!(Err("Invalid jump address 2".to_string()), vm.run());
    }

    #[test] fn can_jump_conditionally() {
        let opcodes = vec![Opcode::Jumpz(2),
                           Opcode::Index(0),
                           Opcode::Push(Json::Boolean(true))];
        let mut vm = Vm::new(&opcodes, Json::Boolean(false));
        assert_eq!(Json::Boolean(true), vm.run().unwrap());
    }

    #[test] fn can_not_jump_conditionally() {
        let opcodes = vec![Opcode::Jumpz(2),
                           Opcode::Jump(100),
                           Opcode::Push(Json::Boolean(true))];
        let mut vm = Vm::new(&opcodes, Json::Boolean(true));
        assert_eq!(Err("Invalid jump address 100".to_string()), vm.run());
    }
}
<|endoftext|>


<commit_before>use std::io;
use std::io::{Write, Read};
use command::Command;

type Cell = u8;

pub struct VM<'a> {
    pub cells: [Cell; 30_000],
    pub data_pointer: usize,
    out: &'a mut Write,
}

impl<'a> VM<'a> {
    pub fn new(out: &mut Write) -> VM {
        VM {
            cells: [0; 30_000],
            data_pointer: 0,
            out,
        }
    }

    pub fn output(&mut self) {
        self.out
            .write_fmt(format_args!("{}", self.cells[self.data_pointer] as char))
            .expect("Could not output current byte");
    }

    pub fn input(&mut self) {
        match io::stdin().bytes().next() {
            Some(res) => {
                match res {
                    Ok(value) => self.cells[self.data_pointer] = value,
                    Err(error) => panic!(error),
                }
            }
            None => {}
        }
        println!("");
    }

    pub fn increment(&mut self) {
        self.cells[self.data_pointer] = self.cells[self.data_pointer].checked_add(1).unwrap_or(0);
    }

    pub fn decrement(&mut self) {
        self.cells[self.data_pointer] = self.cells[self.data_pointer].checked_sub(1).unwrap_or(
            Cell::max_value(),
        );
    }

    pub fn right_shift(&mut self) {
        self.data_pointer += 1;
    }

    pub fn left_shift(&mut self) {
        self.data_pointer -= 1;
    }

    pub fn apply(&mut self, command: Command) {
        match command {
            Command::Output => self.output(),
            Command::Input => self.input(),
            Command::Increment => self.increment(),
            Command::Decrement => self.decrement(),
            Command::RightShift => self.right_shift(),
            Command::LeftShift => self.left_shift(),
            _ => {}
        }
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    #[test]
    fn test_new() {
        let mut stdout = io::stdout();
        let vm = VM::new(&mut stdout);
        assert!(vm.cells[0] == 0);
        assert!(vm.cells[30_000 - 1] == 0);
        assert!(vm.cells[0] == 0);
    }

    #[test]
    fn test_increment() {
        let mut stdout = io::stdout();
        let mut vm = VM::new(&mut stdout);
        vm.increment();
        assert!(vm.cells[0] == 1);
    }

    #[test]
    fn test_decrement() {
        const STARTING_VALUE: u8 = 2;

        let mut stdout = io::stdout();
        let mut vm = VM::new(&mut stdout);
        vm.cells[0] = STARTING_VALUE;
        vm.decrement();
        assert!(vm.cells[0] == STARTING_VALUE - 1);
    }

    #[test]
    fn test_right_shift() {
        let mut stdout = io::stdout();
        let mut vm = VM::new(&mut stdout);
        vm.right_shift();
        assert!(vm.data_pointer == 1);
    }

    #[test]
    fn test_left_shift() {
        const STARTING_POSITION: usize = 2;

        let mut stdout = io::stdout();
        let mut vm = VM::new(&mut stdout);
        vm.data_pointer = STARTING_POSITION;
        vm.left_shift();
        assert!(vm.data_pointer == 1);
    }
}
<commit_msg>Make Cell type public<commit_after>use std::io;
use std::io::{Write, Read};
use command::Command;

pub type Cell = u8;

pub struct VM<'a> {
    pub cells: [Cell; 30_000],
    pub data_pointer: usize,
    out: &'a mut Write,
}

impl<'a> VM<'a> {
    pub fn new(out: &mut Write) -> VM {
        VM {
            cells: [0; 30_000],
            data_pointer: 0,
            out,
        }
    }

    pub fn output(&mut self) {
        self.out
            .write_fmt(format_args!("{}", self.cells[self.data_pointer] as char))
            .expect("Could not output current byte");
    }

    pub fn input(&mut self) {
        match io::stdin().bytes().next() {
            Some(res) => {
                match res {
                    Ok(value) => self.cells[self.data_pointer] = value,
                    Err(error) => panic!(error),
                }
            }
            None => {}
        }
        println!("");
    }

    pub fn increment(&mut self) {
        self.cells[self.data_pointer] = self.cells[self.data_pointer].checked_add(1).unwrap_or(0);
    }

    pub fn decrement(&mut self) {
        self.cells[self.data_pointer] = self.cells[self.data_pointer].checked_sub(1).unwrap_or(
            Cell::max_value(),
        );
    }

    pub fn right_shift(&mut self) {
        self.data_pointer += 1;
    }

    pub fn left_shift(&mut self) {
        self.data_pointer -= 1;
    }

    pub fn apply(&mut self, command: Command) {
        match command {
            Command::Output => self.output(),
            Command::Input => self.input(),
            Command::Increment => self.increment(),
            Command::Decrement => self.decrement(),
            Command::RightShift => self.right_shift(),
            Command::LeftShift => self.left_shift(),
            _ => {}
        }
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    #[test]
    fn test_new() {
        let mut stdout = io::stdout();
        let vm = VM::new(&mut stdout);
        assert!(vm.cells[0] == 0);
        assert!(vm.cells[30_000 - 1] == 0);
        assert!(vm.cells[0] == 0);
    }

    #[test]
    fn test_increment() {
        let mut stdout = io::stdout();
        let mut vm = VM::new(&mut stdout);
        vm.increment();
        assert!(vm.cells[0] == 1);
    }

    #[test]
    fn test_decrement() {
        const STARTING_VALUE: u8 = 2;

        let mut stdout = io::stdout();
        let mut vm = VM::new(&mut stdout);
        vm.cells[0] = STARTING_VALUE;
        vm.decrement();
        assert!(vm.cells[0] == STARTING_VALUE - 1);
    }

    #[test]
    fn test_right_shift() {
        let mut stdout = io::stdout();
        let mut vm = VM::new(&mut stdout);
        vm.right_shift();
        assert!(vm.data_pointer == 1);
    }

    #[test]
    fn test_left_shift() {
        const STARTING_POSITION: usize = 2;

        let mut stdout = io::stdout();
        let mut vm = VM::new(&mut stdout);
        vm.data_pointer = STARTING_POSITION;
        vm.left_shift();
        assert!(vm.data_pointer == 1);
    }
}
<|endoftext|>


<commit_before>use std::io::{BufWriter, Reader};
use std::num::Float;
use error::Ch8Error;
use ops::{Op, Instruction};
use std::slice::Chunks;

use std::rand::Rng;
use std::rand;

const RAM_SIZE: usize = 4096;
const PROGRAM_START: usize = 0x200;
const CLOCK_SPEED_HZ: u32 = 512 * 1024; // 512KHz
const STEP_TIME: f32 = 1.0f32 / CLOCK_SPEED_HZ as f32;

const FONT_ADDR: usize = 0;
const FONT_HEIGHT: usize = 5;
const FONT_BYTES: usize = FONT_HEIGHT * 16;
const FONT: [u8; FONT_BYTES] = [
	0xF0, 0x90, 0x90, 0x90, 0xF0, // 0
	0x20, 0x60, 0x20, 0x20, 0x70, // 1
	0xF0, 0x10, 0xF0, 0x80, 0xF0, // 2
	0xF0, 0x10, 0xF0, 0x10, 0xF0, // 3
	0x90, 0x90, 0xF0, 0x10, 0x10, // 4
	0xF0, 0x80, 0xF0, 0x10, 0xF0, // 5
	0xF0, 0x80, 0xF0, 0x90, 0xF0, // 6
	0xF0, 0x10, 0x20, 0x40, 0x40, // 7
	0xF0, 0x90, 0xF0, 0x90, 0xF0, // 8
	0xF0, 0x90, 0xF0, 0x10, 0xF0, // 9
	0xF0, 0x90, 0xF0, 0x90, 0x90, // A
	0xE0, 0x90, 0xE0, 0x90, 0xE0, // B
	0xF0, 0x80, 0x80, 0x80, 0xF0, // C
	0xE0, 0x90, 0x90, 0x90, 0xE0, // D
	0xF0, 0x80, 0xF0, 0x80, 0xF0, // E
	0xF0, 0x80, 0xF0, 0x80, 0x80, // F
];

pub struct Vm {
    reg: [u8; 16],
    i: usize,
    pc: usize,
    sp: usize,
    stack: [usize; 256],
    ram: [u8; RAM_SIZE],

    timer: u8,
    t_tick: f32,

    sound_timer: u8,
    st_tick: f32,

    screen: [u8; 64 * 32],
    keys: [u8; 16],
}

impl Vm {
    pub fn new() -> Vm {
        let mut vm = Vm {
            reg: [0; 16],
            i: 0,
            pc: PROGRAM_START,
            sp: 0,
            stack: [0; 256],
            ram: [0; RAM_SIZE],

            timer: 0,
            t_tick: 0.0,

            sound_timer: 0,
            st_tick: 0.0,

            screen: [0; 64 * 32],
            keys: [0; 16],
        };
        {
            let mut ram = BufWriter::new(&mut vm.ram[FONT_ADDR..(FONT_ADDR + FONT_BYTES)]);
            ram.write(FONT.as_slice());
        }
        vm
    }

    pub fn load_rom(&mut self, reader: &mut Reader) -> Result<usize, Ch8Error> {
        let rom = try!(reader.read_to_end());
        if rom.len() > (RAM_SIZE - PROGRAM_START) {
           return Err(Ch8Error::Io("Rom was larger than available RAM", None))
        }
        let mut ram = BufWriter::new(&mut self.ram[PROGRAM_START..RAM_SIZE]);
        try!(ram.write(rom.as_slice()));
        return Ok(rom.len());
    }

    pub fn dump_ram(&self, writer: &mut Writer) {
        writer.write(&self.ram).unwrap();
    }

    pub fn set_key(&mut self, idx: u8) {
        self.keys[idx as usize] = 1;
    }

    pub fn unset_key(&mut self, idx: u8) {
        self.keys[idx as usize] = 0;
    }

    fn exec(&mut self, op: &Op) -> bool {
        use ops::Instruction::*;
        let ins = Instruction::from_op(op);
//        if self.timer == 0 {
//            println!("Executing instruction: 0x{:X} {:?}", self.pc, ins);
//            println!("v: {:?}", self.reg);
//            println!("timers: t: {} s: {}", self.timer, self.sound_timer);
//            self.print_screen();
//        }
        match ins {
            // Sys(addr) intentionally left unimplemented.
            Clear => {
                for b in self.screen.iter_mut() {
                    *b = 0;
                }
            },
            Return => {
                self.pc = self.stack[self.sp];
                self.sp-=1;
            },
            Jump(addr) => {
                let idle = self.pc-2 == addr as usize;
                self.pc = addr as usize;
                if idle { return true; }
            }
            Call(addr) => {
                self.sp+=1;
                self.stack[self.sp] = self.pc;
                self.pc = addr as usize;
            },
            SkipEqualK(vx, k) => {
                if self.reg[vx as usize] == k {
                    self.pc += 2;
                }
            },
            SkipNotEqualK(vx, k) => {
                if self.reg[vx as usize] != k {
                    self.pc += 2;
                }
            },
            SkipEqual(vx, vy) => {
                let x = self.reg[vx as usize];
                let y = self.reg[vy as usize];
                if x == y {
                    self.pc += 2;
                }
            },
            SetK(vx, byte) => {
                self.reg[vx as usize] = byte;
            },
            AddK(vx, byte) => {
                self.reg[vx as usize] += byte;
            },
            Set(vx, vy) => self.reg[vx as usize] = self.reg[vy as usize],
            Or(vx, vy)  => self.reg[vx as usize] |= self.reg[vy as usize],
            And(vx, vy) => self.reg[vx as usize] &= self.reg[vy as usize],
            XOr(vx, vy) => self.reg[vx as usize] ^= self.reg[vy as usize],
            Add(vx, vy) => {
                let x = self.reg[vx as usize] as u16;
                let y = self.reg[vy as usize] as u16;
                let res = x + y;

                // VF is carryover
                self.reg[15] = (res > 255) as u8;

                self.reg[vx as usize] = res as u8;
            },
            Sub(vx, vy) => {
                let x = self.reg[vx as usize];
                let y = self.reg[vy as usize];

                // VF is Not Borrow i.e. x > y
                self.reg[15] = (x > y) as u8;

                self.reg[vx as usize] = x - y;
            },
            ShiftRight(vx, vy) => {
                let y = self.reg[vy as usize];

                // VF is lsb before shift
                self.reg[15] = 0x1 & y;

                self.reg[vx as usize] = y >> 1;
            },
            SubInv(vx, vy) => {
                let x = self.reg[vx as usize];
                let y = self.reg[vy as usize];

                // VF is Not Borrow i.e. y > x
                self.reg[15] = (y > x) as u8;

                self.reg[vx as usize] = y - x;
            },
            ShiftLeft(vx, vy) => {
                let y = self.reg[vy as usize];

                // VF is msb before shift
                self.reg[15] =  0x80 & y;

                self.reg[vx as usize] = y << 1;
            }
            SkipNotEqual(vx, vy) => {
                let x = self.reg[vx as usize];
                let y = self.reg[vy as usize];
                if x != y {
                    self.pc += 2;
                }
            },
            LoadI(addr) => {
                self.i = addr as usize;
            },
            LongJump(addr) => {
                self.pc = (self.reg[0] as u16 + addr) as usize;
            },
            Rand(vx, byte) => {
                self.reg[vx as usize] = rand::thread_rng().gen::<u8>() & byte;
            }
            Draw(vx, vy, n) => {
                let x = self.reg[vx as usize] as usize;
                let y = self.reg[vy as usize] as usize;
                let i = self.i as usize;
                let n = n as usize;

                let sprite = &self.ram[i..i+n];

                self.reg[15] = 0;
                for (sy, byte) in sprite.iter().enumerate() {
                    let dy = (y + sy) % 32;
                    for sx in 0us..8 {
                        let px = (*byte >> (7 - sx)) & 0b00000001;
                        let dx = (x + sx) % 64;
                        let idx = dy * 64 + dx;
                        self.screen[idx] ^= px;

                        // Vf is if there was a collision
                        self.reg[15] |= (self.screen[idx] == 0 && px == 1) as u8;
                    }
                }
            },
            SkipPressed(vx) => {
                let idx = self.reg[vx as usize];
                if self.keys[idx as usize] == 1 {
                    self.pc += 2;
                }
            }
            SkipNotPressed(vx) => {
                let idx = self.reg[vx as usize];
                if self.keys[idx  as usize] != 1 {
                    self.pc += 2;
                }
            }
            GetTimer(vx) => {
                self.reg[vx as usize] = self.timer;
            },
            //TODO WaitKey(vx) => {}
            SetTimer(vx) => {
                self.timer = self.reg[vx as usize];
                self.t_tick = 1.0 / 60.0;
            },
            SetSoundTimer(vx) => {
                self.sound_timer = self.reg[vx as usize];
                self.st_tick = 1.0 / 60.0;
            },
            AddToI(vx) => {
                self.i += self.reg[vx as usize] as usize;
            },
            LoadHexGlyph(vx) => {
                let x = self.reg[vx as usize];
                self.i = FONT_ADDR + x as usize * FONT_HEIGHT;
            }
            StoreBCD(vx) => {
                let mut x = self.reg[vx as usize];

                let mut place = 100;
                for i in 0us..2 {
                    self.i += i;
                    let bcd = x / place;
                    self.ram[self.i] = bcd;
                    x -= bcd;
                    place /= 10;
                }
            }
            StoreRegisters(vx) => {
                let vx = vx as usize;
                let i = self.i as usize;

                let mut dst = &mut self.ram[i..i+vx+1];
                for (x,b) in dst.iter_mut().enumerate() {
                  //println!("store reg {} to {}", x, i);
                    *b = self.reg[x];
                }
            },
            LoadRegisters(vx) => {
                let vx = vx as usize;
                let i = self.i as usize;

                let src = &self.ram[i..i+vx+1];
                for (x,b) in src.iter().enumerate() {
                  //println!("read reg {} from {}", x, i);
                    self.reg[x] = *b;
                }
            },
            other => {
                println!("Instruction not implemented {:?} skipping...", other)
            }
        }
        return false;
    }

    fn time_step(&mut self) {
        if self.timer > 0 {
            self.t_tick -= STEP_TIME;
            if self.t_tick <= 0.0 {
                self.timer -= 1;
                self.t_tick = 1.0 / 60.0;
            }
        }

        if self.sound_timer > 0 {
            self.st_tick -= STEP_TIME;
            if self.st_tick <= 0.0 {
                self.sound_timer -= 1;
                self.st_tick = 1.0 / 60.0;
            }
        }
    }

    // dt: Time in seconds since last step
    pub fn step(&mut self, dt:f32) -> bool {
        let steps = (CLOCK_SPEED_HZ as f32 * dt).round() as u32;
        let mut idle = false;

        for _ in 0u32..steps {
            let raw = {
                let codes = &self.ram[self.pc..self.pc+2];
                ((codes[0] as u16) << 8) | codes[1] as u16
            };
            let op = Op::new(raw);
            self.pc += 2;
            idle = self.exec(&op);
            self.time_step();
            if idle { break; }
        }
        return idle;
    }

    pub fn screen_rows<'a>(&'a self) -> Chunks<'a, u8> {
        self.screen.chunks(64)
    }

    pub fn print_screen(&self) {
        for row in self.screen.chunks(64) {
            println!("");
            for byte in row.iter() {
                match *byte {
                    0x0 => print!("░"),
                    _ => print!("▓")
                }
            }
        }
    }

    pub fn print_disassembly(&self) {
        for i in self.ram.chunks(2) {
            match i {
                [0, 0] => continue,
                [h, l] => {
                    let op = Op::new(((h as u16) << 8) | l as u16);
                    println!("raw: 0x{:X}", op.raw());
                    println!("instruction: {:?}", Instruction::from_op(&op));
                    println!("addr: 0x{:X}", op.addr());
                    println!("x: 0x{:X}", op.x());
                    println!("y: 0x{:X}", op.y());
                    println!("n_high: 0x{:X}", op.n_high());
                    println!("n_low: 0x{:X}", op.n_low());
                    println!("k: 0x{:X}\n", op.k());
                },
                _ => continue
            }
        }
    }
}
<commit_msg>Revert time step code<commit_after>use std::io::{BufWriter, Reader};
use std::num::Float;
use error::Ch8Error;
use ops::{Op, Instruction};
use std::slice::Chunks;

use std::rand::Rng;
use std::rand;

const RAM_SIZE: usize = 4096;
const PROGRAM_START: usize = 0x200;

const FONT_ADDR: usize = 0;
const FONT_HEIGHT: usize = 5;
const FONT_BYTES: usize = FONT_HEIGHT * 16;
const FONT: [u8; FONT_BYTES] = [
	0xF0, 0x90, 0x90, 0x90, 0xF0, // 0
	0x20, 0x60, 0x20, 0x20, 0x70, // 1
	0xF0, 0x10, 0xF0, 0x80, 0xF0, // 2
	0xF0, 0x10, 0xF0, 0x10, 0xF0, // 3
	0x90, 0x90, 0xF0, 0x10, 0x10, // 4
	0xF0, 0x80, 0xF0, 0x10, 0xF0, // 5
	0xF0, 0x80, 0xF0, 0x90, 0xF0, // 6
	0xF0, 0x10, 0x20, 0x40, 0x40, // 7
	0xF0, 0x90, 0xF0, 0x90, 0xF0, // 8
	0xF0, 0x90, 0xF0, 0x10, 0xF0, // 9
	0xF0, 0x90, 0xF0, 0x90, 0x90, // A
	0xE0, 0x90, 0xE0, 0x90, 0xE0, // B
	0xF0, 0x80, 0x80, 0x80, 0xF0, // C
	0xE0, 0x90, 0x90, 0x90, 0xE0, // D
	0xF0, 0x80, 0xF0, 0x80, 0xF0, // E
	0xF0, 0x80, 0xF0, 0x80, 0x80, // F
];

pub struct Vm {
    reg: [u8; 16],
    i: usize,
    pc: usize,
    sp: usize,
    stack: [usize; 256],
    ram: [u8; RAM_SIZE],

    timer: u8,
    t_tick: f32,

    sound_timer: u8,
    st_tick: f32,

    screen: [u8; 64 * 32],
    keys: [u8; 16],
}

impl Vm {
    pub fn new() -> Vm {
        let mut vm = Vm {
            reg: [0; 16],
            i: 0,
            pc: PROGRAM_START,
            sp: 0,
            stack: [0; 256],
            ram: [0; RAM_SIZE],

            timer: 0,
            t_tick: 0.0,

            sound_timer: 0,
            st_tick: 0.0,

            screen: [0; 64 * 32],
            keys: [0; 16],
        };
        {
            let mut ram = BufWriter::new(&mut vm.ram[FONT_ADDR..(FONT_ADDR + FONT_BYTES)]);
            ram.write(FONT.as_slice());
        }
        vm
    }

    pub fn load_rom(&mut self, reader: &mut Reader) -> Result<usize, Ch8Error> {
        let rom = try!(reader.read_to_end());
        if rom.len() > (RAM_SIZE - PROGRAM_START) {
           return Err(Ch8Error::Io("Rom was larger than available RAM", None))
        }
        let mut ram = BufWriter::new(&mut self.ram[PROGRAM_START..RAM_SIZE]);
        try!(ram.write(rom.as_slice()));
        return Ok(rom.len());
    }

    pub fn dump_ram(&self, writer: &mut Writer) {
        writer.write(&self.ram).unwrap();
    }

    pub fn set_key(&mut self, idx: u8) {
        self.keys[idx as usize] = 1;
    }

    pub fn unset_key(&mut self, idx: u8) {
        self.keys[idx as usize] = 0;
    }

    fn exec(&mut self, op: &Op) -> bool {
        use ops::Instruction::*;
        let ins = Instruction::from_op(op);
//        if self.timer == 0 {
//            println!("Executing instruction: 0x{:X} {:?}", self.pc, ins);
//            println!("v: {:?}", self.reg);
//            println!("timers: t: {} s: {}", self.timer, self.sound_timer);
//            self.print_screen();
//        }
        match ins {
            // Sys(addr) intentionally left unimplemented.
            Clear => {
                for b in self.screen.iter_mut() {
                    *b = 0;
                }
            },
            Return => {
                self.pc = self.stack[self.sp];
                self.sp-=1;
            },
            Jump(addr) => {
                let idle = self.pc-2 == addr as usize;
                self.pc = addr as usize;
                if idle { return true; }
            }
            Call(addr) => {
                self.sp+=1;
                self.stack[self.sp] = self.pc;
                self.pc = addr as usize;
            },
            SkipEqualK(vx, k) => {
                if self.reg[vx as usize] == k {
                    self.pc += 2;
                }
            },
            SkipNotEqualK(vx, k) => {
                if self.reg[vx as usize] != k {
                    self.pc += 2;
                }
            },
            SkipEqual(vx, vy) => {
                let x = self.reg[vx as usize];
                let y = self.reg[vy as usize];
                if x == y {
                    self.pc += 2;
                }
            },
            SetK(vx, byte) => {
                self.reg[vx as usize] = byte;
            },
            AddK(vx, byte) => {
                self.reg[vx as usize] += byte;
            },
            Set(vx, vy) => self.reg[vx as usize] = self.reg[vy as usize],
            Or(vx, vy)  => self.reg[vx as usize] |= self.reg[vy as usize],
            And(vx, vy) => self.reg[vx as usize] &= self.reg[vy as usize],
            XOr(vx, vy) => self.reg[vx as usize] ^= self.reg[vy as usize],
            Add(vx, vy) => {
                let x = self.reg[vx as usize] as u16;
                let y = self.reg[vy as usize] as u16;
                let res = x + y;

                // VF is carryover
                self.reg[15] = (res > 255) as u8;

                self.reg[vx as usize] = res as u8;
            },
            Sub(vx, vy) => {
                let x = self.reg[vx as usize];
                let y = self.reg[vy as usize];

                // VF is Not Borrow i.e. x > y
                self.reg[15] = (x > y) as u8;

                self.reg[vx as usize] = x - y;
            },
            ShiftRight(vx, vy) => {
                let y = self.reg[vy as usize];

                // VF is lsb before shift
                self.reg[15] = 0x1 & y;

                self.reg[vx as usize] = y >> 1;
            },
            SubInv(vx, vy) => {
                let x = self.reg[vx as usize];
                let y = self.reg[vy as usize];

                // VF is Not Borrow i.e. y > x
                self.reg[15] = (y > x) as u8;

                self.reg[vx as usize] = y - x;
            },
            ShiftLeft(vx, vy) => {
                let y = self.reg[vy as usize];

                // VF is msb before shift
                self.reg[15] =  0x80 & y;

                self.reg[vx as usize] = y << 1;
            }
            SkipNotEqual(vx, vy) => {
                let x = self.reg[vx as usize];
                let y = self.reg[vy as usize];
                if x != y {
                    self.pc += 2;
                }
            },
            LoadI(addr) => {
                self.i = addr as usize;
            },
            LongJump(addr) => {
                self.pc = (self.reg[0] as u16 + addr) as usize;
            },
            Rand(vx, byte) => {
                self.reg[vx as usize] = rand::thread_rng().gen::<u8>() & byte;
            }
            Draw(vx, vy, n) => {
                let x = self.reg[vx as usize] as usize;
                let y = self.reg[vy as usize] as usize;
                let i = self.i as usize;
                let n = n as usize;

                let sprite = &self.ram[i..i+n];

                self.reg[15] = 0;
                for (sy, byte) in sprite.iter().enumerate() {
                    let dy = (y + sy) % 32;
                    for sx in 0us..8 {
                        let px = (*byte >> (7 - sx)) & 0b00000001;
                        let dx = (x + sx) % 64;
                        let idx = dy * 64 + dx;
                        self.screen[idx] ^= px;

                        // Vf is if there was a collision
                        self.reg[15] |= (self.screen[idx] == 0 && px == 1) as u8;
                    }
                }
            },
            SkipPressed(vx) => {
                let idx = self.reg[vx as usize];
                if self.keys[idx as usize] == 1 {
                    self.pc += 2;
                }
            }
            SkipNotPressed(vx) => {
                let idx = self.reg[vx as usize];
                if self.keys[idx  as usize] != 1 {
                    self.pc += 2;
                }
            }
            GetTimer(vx) => {
                self.reg[vx as usize] = self.timer;
            },
            //TODO WaitKey(vx) => {}
            SetTimer(vx) => {
                self.timer = self.reg[vx as usize];
                self.t_tick = 1.0 / 60.0;
            },
            SetSoundTimer(vx) => {
                self.sound_timer = self.reg[vx as usize];
                self.st_tick = 1.0 / 60.0;
            },
            AddToI(vx) => {
                self.i += self.reg[vx as usize] as usize;
            },
            LoadHexGlyph(vx) => {
                let x = self.reg[vx as usize];
                self.i = FONT_ADDR + x as usize * FONT_HEIGHT;
            }
            StoreBCD(vx) => {
                let mut x = self.reg[vx as usize];

                let mut place = 100;
                for i in 0us..2 {
                    self.i += i;
                    let bcd = x / place;
                    self.ram[self.i] = bcd;
                    x -= bcd;
                    place /= 10;
                }
            }
            StoreRegisters(vx) => {
                let vx = vx as usize;
                let i = self.i as usize;

                let mut dst = &mut self.ram[i..i+vx+1];
                for (x,b) in dst.iter_mut().enumerate() {
                  //println!("store reg {} to {}", x, i);
                    *b = self.reg[x];
                }
            },
            LoadRegisters(vx) => {
                let vx = vx as usize;
                let i = self.i as usize;

                let src = &self.ram[i..i+vx+1];
                for (x,b) in src.iter().enumerate() {
                  //println!("read reg {} from {}", x, i);
                    self.reg[x] = *b;
                }
            },
            other => {
                println!("Instruction not implemented {:?} skipping...", other)
            }
        }
        return false;
    }

    fn time_step(&mut self, dt:f32) {
        if self.timer > 0 {
            self.t_tick -= dt;
            if self.t_tick <= 0.0 {
                self.timer -= 1;
                self.t_tick = 1.0 / 60.0;
            }
        }

        if self.sound_timer > 0 {
            self.st_tick -= dt;
            if self.st_tick <= 0.0 {
                self.sound_timer -= 1;
                self.st_tick = 1.0 / 60.0;
            }
        }
    }

    // dt: Time in seconds since last step
    pub fn step(&mut self, dt:f32) -> bool {
        let mut idle = false;

        let raw = {
            let codes = &self.ram[self.pc..self.pc+2];
            ((codes[0] as u16) << 8) | codes[1] as u16
        };
        let op = Op::new(raw);
        self.pc += 2;
        idle = self.exec(&op);
        self.time_step(dt);
        return idle;
    }

    pub fn screen_rows<'a>(&'a self) -> Chunks<'a, u8> {
        self.screen.chunks(64)
    }

    pub fn print_screen(&self) {
        for row in self.screen.chunks(64) {
            println!("");
            for byte in row.iter() {
                match *byte {
                    0x0 => print!("░"),
                    _ => print!("▓")
                }
            }
        }
    }

    pub fn print_disassembly(&self) {
        for i in self.ram.chunks(2) {
            match i {
                [0, 0] => continue,
                [h, l] => {
                    let op = Op::new(((h as u16) << 8) | l as u16);
                    println!("raw: 0x{:X}", op.raw());
                    println!("instruction: {:?}", Instruction::from_op(&op));
                    println!("addr: 0x{:X}", op.addr());
                    println!("x: 0x{:X}", op.x());
                    println!("y: 0x{:X}", op.y());
                    println!("n_high: 0x{:X}", op.n_high());
                    println!("n_low: 0x{:X}", op.n_low());
                    println!("k: 0x{:X}\n", op.k());
                },
                _ => continue
            }
        }
    }
}
<|endoftext|>


<commit_before>use std::ffi::{CStr,CString};
use std::ptr;
use std::mem;
use std::str;

use libc;
use z3_sys;

pub struct Z3 {
    ctx: z3_sys::Z3_context
}
#[derive(Clone)]
pub struct Z3Ast<'a> {
    ast: z3_sys::Z3_ast,
    z3: &'a Z3
}
pub struct Z3Model<'a> {
    model: *mut z3_sys::Z3_model,
    res: i32,
    z3: &'a Z3
}

macro_rules! impl_mk_1 {
    ($name:ident, $fun:ident) => (
        pub fn $name<'a>(&'a self, a: &Z3Ast) -> Z3Ast<'a> {
            unsafe {
                let ast = z3_sys::$fun(self.ctx, a.ast);
                Z3Ast {
                    ast: ast,
                    z3: &self
                }
            }
        }
    )
}
macro_rules! impl_mk_2 {
    ($name:ident, $fun:ident) => (
        pub fn $name<'a>(&'a self, t1: &Z3Ast, t2: &Z3Ast) -> Z3Ast<'a> {
            unsafe {
                let ast = z3_sys::$fun(self.ctx, t1.ast, t2.ast);
                Z3Ast {
                    ast: ast,
                    z3: &self
                }
            }
        }
    )
}
macro_rules! impl_mk_i_1 {
    ($name:ident, $fun:ident) => (
        pub fn $name<'a>(&'a self, i: u32, t1: &Z3Ast) -> Z3Ast<'a> {
            unsafe {
                let ast = z3_sys::$fun(self.ctx, i, t1.ast);
                Z3Ast {
                    ast: ast,
                    z3: &self
                }
            }
        }
    )
}

impl Z3 {
    pub fn new() -> Z3 {
        unsafe {
            let cfg = z3_sys::Z3_mk_config();
            let ctx = z3_sys::Z3_mk_context(cfg);
            Z3 {
                ctx: ctx
            }
        }
    }
    #[inline]
    pub unsafe fn ctx(&self) -> z3_sys::Z3_context {
        self.ctx
    }
    pub unsafe fn get_model_str(&self, m: z3_sys::Z3_model) -> &str {
        let cstr = z3_sys::Z3_model_to_string(self.ctx, m);
        let slice = CStr::from_ptr(cstr);
        let buf: &[u8] = slice.to_bytes();
        let str_slice: &str = str::from_utf8(buf).unwrap();
        str_slice
    }

    pub fn check_and_get_model<'a>(&'a self, f: &Z3Ast) -> Z3Model<'a> {
        unsafe {
            let m: *mut z3_sys::Z3_model =
                libc::malloc(mem::size_of::<usize>() as libc::size_t)
                as *mut z3_sys::Z3_model;

            z3_sys::Z3_push(self.ctx);
            let not_f = z3_sys::Z3_mk_not(self.ctx, f.ast);
            z3_sys::Z3_assert_cnstr(self.ctx, not_f);

            let res = z3_sys::Z3_check_and_get_model(self.ctx, m);

            z3_sys::Z3_pop(self.ctx, 1);

            Z3Model {
                model: m,
                res: res,
                z3: &self
            }
        }
    }

    pub fn prove(&self, f: &Z3Ast, is_valid: bool) {
        unsafe {
            z3_sys::Z3_push(self.ctx);
            let not_f = z3_sys::Z3_mk_not(self.ctx, f.ast);
            z3_sys::Z3_assert_cnstr(self.ctx, not_f);

            let m: *mut z3_sys::Z3_model =
                libc::malloc(mem::size_of::<usize>() as libc::size_t)
                as *mut z3_sys::Z3_model;

            match z3_sys::Z3_check_and_get_model(self.ctx, m) {
                z3_sys::Z3_L_FALSE => {
                    /* proved */
                    println!("valid\n");
                    if !is_valid {
                        //exitf("unexpected result");
                    }
                },
                z3_sys::Z3_L_UNDEF => {
                    /* Z3 failed to prove/disprove f. */
                    println!("unknown\n");
                    if *m != ptr::null_mut() {
                        /* m should be viewed as a potential counterexample. */
                        println!("potential counterexample:\n{}\n",
                                 self.get_model_str(*m));
                    }
                    if is_valid {
                        //exitf("unexpected result");
                    }
                },
                z3_sys::Z3_L_TRUE => {
                    /* disproved */
                    println!("invalid\n");
                    if *m != ptr::null_mut() {
                        /* the model returned by Z3 is a counterexample */
                        println!("counterexample:\n{}\n",
                                 self.get_model_str(*m));
                    }
                    if is_valid {
                        //exitf("unexpected result");
                    }
                },
                _ => panic!("not supported")
            }
            if *m != ptr::null_mut() {
                z3_sys::Z3_del_model(self.ctx, *m);
            }
            z3_sys::Z3_pop(self.ctx(), 1);
        }
    }

    impl_mk_2!(eq, Z3_mk_eq);
    impl_mk_2!(div, Z3_mk_div);
    impl_mk_2!(mod_, Z3_mk_mod);
    impl_mk_2!(rem, Z3_mk_rem);
    impl_mk_2!(power, Z3_mk_power);
    impl_mk_2!(lt, Z3_mk_lt);
    impl_mk_2!(le, Z3_mk_le);
    impl_mk_2!(gt, Z3_mk_gt);
    impl_mk_2!(ge, Z3_mk_ge);
    impl_mk_2!(bvand, Z3_mk_bvand);
    impl_mk_2!(bvor, Z3_mk_bvor);
    impl_mk_2!(bvxor, Z3_mk_bvxor);
    impl_mk_2!(bvnand, Z3_mk_bvnand);
    impl_mk_2!(bvnor, Z3_mk_bvnor);
    impl_mk_2!(bvxnor, Z3_mk_bvxnor);
    impl_mk_2!(bvadd, Z3_mk_bvadd);
    impl_mk_2!(bvsub, Z3_mk_bvsub);
    impl_mk_2!(bvmul, Z3_mk_bvmul);
    impl_mk_2!(bvudiv, Z3_mk_bvudiv);
    impl_mk_2!(bvsdiv, Z3_mk_bvsdiv);
    impl_mk_2!(bvure, Z3_mk_bvurem);
    impl_mk_2!(bvsre, Z3_mk_bvsrem);
    impl_mk_2!(bvsmod, Z3_mk_bvsmod);
    impl_mk_2!(bvult, Z3_mk_bvult);
    impl_mk_2!(bvslt, Z3_mk_bvslt);
    impl_mk_2!(bvule, Z3_mk_bvule);
    impl_mk_2!(bvsle, Z3_mk_bvsle);
    impl_mk_2!(bvuge, Z3_mk_bvuge);
    impl_mk_2!(bvsge, Z3_mk_bvsge);
    impl_mk_2!(bvugt, Z3_mk_bvugt);
    impl_mk_2!(bvsgt, Z3_mk_bvsgt);
    impl_mk_2!(concat, Z3_mk_concat);
    impl_mk_2!(bvshl, Z3_mk_bvshl);
    impl_mk_2!(bvlshr, Z3_mk_bvlshr);
    impl_mk_2!(bvashr, Z3_mk_bvashr);
    impl_mk_2!(ext_rotate_left, Z3_mk_ext_rotate_left);
    impl_mk_2!(ext_rotate_right, Z3_mk_ext_rotate_right);
    impl_mk_2!(bvadd_no_underflow, Z3_mk_bvadd_no_underflow);
    impl_mk_2!(bvsub_no_overflow, Z3_mk_bvsub_no_overflow);
    impl_mk_2!(bvsdiv_no_overflow, Z3_mk_bvsdiv_no_overflow);
    impl_mk_2!(bvmul_no_underflow, Z3_mk_bvmul_no_underflow);

    impl_mk_1!(not, Z3_mk_not);
    impl_mk_1!(int2real, Z3_mk_int2real);
    impl_mk_1!(real2int, Z3_mk_real2int);
    impl_mk_1!(is_int, Z3_mk_is_int);
    impl_mk_1!(bvnot, Z3_mk_bvnot);
    impl_mk_1!(bvredand, Z3_mk_bvredand);
    impl_mk_1!(bvredor, Z3_mk_bvredor);
    impl_mk_1!(bvneg_no_overflow, Z3_mk_bvneg_no_overflow);
    impl_mk_1!(bvneg, Z3_mk_bvneg);

    impl_mk_i_1!(sign_ext, Z3_mk_sign_ext);
    impl_mk_i_1!(zero_ext, Z3_mk_zero_ext);
    impl_mk_i_1!(repeat, Z3_mk_repeat);
    impl_mk_i_1!(rotate_left, Z3_mk_rotate_left);
    impl_mk_i_1!(rotate_right, Z3_mk_rotate_right);

    /// Create a new BitVector const of name `i` and width `w`
    pub fn mk_bv_i<'a>(&'a self, i: i32, w: u32) -> Z3Ast<'a> {
        unsafe {
            let sort= z3_sys::Z3_mk_bv_sort(self.ctx, w);
            let sym = z3_sys::Z3_mk_int_symbol(self.ctx, i);
            Z3Ast {
                ast: z3_sys::Z3_mk_const(self.ctx, sym, sort),
                z3: &self
            }
        }
    }
    /// Create a new BitVector const of name `s` and width `w`
    pub fn mk_bv_str<'a>(&'a self, s: &str, w: u32) -> Z3Ast<'a> {
        unsafe {
            let sort= z3_sys::Z3_mk_bv_sort(self.ctx, w);
            let cs = CString::new(s).unwrap();
            let sym = z3_sys::Z3_mk_string_symbol(self.ctx, cs.as_ptr());
            Z3Ast {
                ast: z3_sys::Z3_mk_const(self.ctx, sym, sort),
                z3: &self
            }
        }
    }

}

impl <'a> Z3Ast<'a> {
    pub fn get_u64(&self) -> Option<u64> {
        unsafe {
            let mut res: u64 = 0;
            if z3_sys::Z3_get_numeral_uint64(self.z3.ctx(), self.ast, &mut res)
                == z3_sys::Z3_L_TRUE
            {
                Some(res)
            } else {
                None
            }
        }
    }
}

impl <'a> Z3Model<'a> {
    pub fn eval(&'a self, ast: &Z3Ast) -> Option<Z3Ast<'a>> {
        if self.is_model() {
            unsafe {
                let mut res_ast: z3_sys::Z3_ast = ptr::null_mut();
                if z3_sys::Z3_model_eval(self.z3.ctx(), *self.model,
                                         ast.ast, z3_sys::Z3_L_TRUE,
                                         &mut res_ast) == z3_sys::Z3_L_TRUE {
                    Some(Z3Ast {
                        ast: res_ast,
                        z3: self.z3
                    })
                } else {
                    None
                }
            }
        } else {
            None
        }
    }
    pub fn is_model(&self) -> bool {
        match self.res {
            z3_sys::Z3_L_UNDEF | z3_sys::Z3_L_TRUE => true,
            z3_sys::Z3_L_FALSE => false,
            _ => panic!("not supported")
        }
    }

    pub fn get_str(&self) -> &str {
        if self.is_model() {
                unsafe {
                    let cstr = z3_sys::Z3_model_to_string(self.z3.ctx(), *self.model);
                    let slice = CStr::from_ptr(cstr);
                    let buf: &[u8] = slice.to_bytes();
                    let str_slice: &str = str::from_utf8(buf).unwrap();
                    str_slice
                }
        } else {
            "no model"
        }
    }
}

impl Drop for Z3 {
    fn drop(&mut self) {
        unsafe {
            z3_sys::Z3_del_context(self.ctx);
        }
    }
}

#[test]
fn it_works() {
    let z3 = Z3::new();
    let a = z3.mk_bv_i(1, 32);
    let b = z3.mk_bv_i(2, 32);
    let c = z3.mk_bv_str("c", 32);

    let d = z3.bvand(&a, &b);
    let e = z3.bvor(&a, &b);

    let gt = z3.bvugt(&d, &e);
    let eq = z3.eq(&d, &e);
    let neq = z3.not(&gt);

    let h = z3.prove(&eq, true);

    let model = z3.check_and_get_model(&eq);
    println!("model: {}", model.get_str());

    let new_a = model.eval(&a).unwrap();
    let val_a = new_a.get_u64().unwrap();
    println!("val_a: 0x{:x}", val_a);
}
<commit_msg>adding is_valid and get_bv_width to model and fixing some names<commit_after>use std::ffi::{CStr,CString};
use std::ptr;
use std::mem;
use std::str;

use libc;
use z3_sys;

pub struct Z3 {
    ctx: z3_sys::Z3_context
}
#[derive(Clone)]
pub struct Z3Ast<'a> {
    ast: z3_sys::Z3_ast,
    z3: &'a Z3
}
pub struct Z3Model<'a> {
    model: *mut z3_sys::Z3_model,
    res: i32,
    z3: &'a Z3
}

macro_rules! impl_mk_1 {
    ($name:ident, $fun:ident) => (
        pub fn $name<'a>(&'a self, a: &Z3Ast) -> Z3Ast<'a> {
            unsafe {
                let ast = z3_sys::$fun(self.ctx, a.ast);
                Z3Ast {
                    ast: ast,
                    z3: &self
                }
            }
        }
    )
}
macro_rules! impl_mk_2 {
    ($name:ident, $fun:ident) => (
        pub fn $name<'a>(&'a self, t1: &Z3Ast, t2: &Z3Ast) -> Z3Ast<'a> {
            unsafe {
                let ast = z3_sys::$fun(self.ctx, t1.ast, t2.ast);
                Z3Ast {
                    ast: ast,
                    z3: &self
                }
            }
        }
    )
}
macro_rules! impl_mk_i_1 {
    ($name:ident, $fun:ident) => (
        pub fn $name<'a>(&'a self, i: u32, t1: &Z3Ast) -> Z3Ast<'a> {
            unsafe {
                let ast = z3_sys::$fun(self.ctx, i, t1.ast);
                Z3Ast {
                    ast: ast,
                    z3: &self
                }
            }
        }
    )
}

impl Z3 {
    pub fn new() -> Z3 {
        unsafe {
            let cfg = z3_sys::Z3_mk_config();
            let ctx = z3_sys::Z3_mk_context(cfg);
            Z3 {
                ctx: ctx
            }
        }
    }
    #[inline]
    pub unsafe fn ctx(&self) -> z3_sys::Z3_context {
        self.ctx
    }
    pub unsafe fn get_model_str(&self, m: z3_sys::Z3_model) -> &str {
        let cstr = z3_sys::Z3_model_to_string(self.ctx, m);
        let slice = CStr::from_ptr(cstr);
        let buf: &[u8] = slice.to_bytes();
        let str_slice: &str = str::from_utf8(buf).unwrap();
        str_slice
    }

    pub fn check_and_get_model<'a>(&'a self, f: &Z3Ast) -> Z3Model<'a> {
        unsafe {
            let m: *mut z3_sys::Z3_model =
                libc::malloc(mem::size_of::<usize>() as libc::size_t)
                as *mut z3_sys::Z3_model;

            z3_sys::Z3_push(self.ctx);
            let not_f = z3_sys::Z3_mk_not(self.ctx, f.ast);
            z3_sys::Z3_assert_cnstr(self.ctx, not_f);

            let res = z3_sys::Z3_check_and_get_model(self.ctx, m);

            z3_sys::Z3_pop(self.ctx, 1);

            Z3Model {
                model: m,
                res: res,
                z3: &self
            }
        }
    }

    //#[deprecated]
    pub fn prove(&self, f: &Z3Ast, is_valid: bool) {
        unsafe {
            z3_sys::Z3_push(self.ctx);
            let not_f = z3_sys::Z3_mk_not(self.ctx, f.ast);
            z3_sys::Z3_assert_cnstr(self.ctx, not_f);

            let m: *mut z3_sys::Z3_model =
                libc::malloc(mem::size_of::<usize>() as libc::size_t)
                as *mut z3_sys::Z3_model;

            match z3_sys::Z3_check_and_get_model(self.ctx, m) {
                z3_sys::Z3_L_FALSE => {
                    /* proved */
                    println!("valid\n");
                    if !is_valid {
                        //exitf("unexpected result");
                    }
                },
                z3_sys::Z3_L_UNDEF => {
                    /* Z3 failed to prove/disprove f. */
                    println!("unknown\n");
                    if *m != ptr::null_mut() {
                        /* m should be viewed as a potential counterexample. */
                        println!("potential counterexample:\n{}\n",
                                 self.get_model_str(*m));
                    }
                    if is_valid {
                        //exitf("unexpected result");
                    }
                },
                z3_sys::Z3_L_TRUE => {
                    /* disproved */
                    println!("invalid\n");
                    if *m != ptr::null_mut() {
                        /* the model returned by Z3 is a counterexample */
                        println!("counterexample:\n{}\n",
                                 self.get_model_str(*m));
                    }
                    if is_valid {
                        //exitf("unexpected result");
                    }
                },
                _ => panic!("not supported")
            }
            if *m != ptr::null_mut() {
                z3_sys::Z3_del_model(self.ctx, *m);
            }
            z3_sys::Z3_pop(self.ctx(), 1);
        }
    }

    impl_mk_2!(eq, Z3_mk_eq);
    impl_mk_2!(div, Z3_mk_div);
    impl_mk_2!(mod_, Z3_mk_mod);
    impl_mk_2!(rem, Z3_mk_rem);
    impl_mk_2!(power, Z3_mk_power);
    impl_mk_2!(lt, Z3_mk_lt);
    impl_mk_2!(le, Z3_mk_le);
    impl_mk_2!(gt, Z3_mk_gt);
    impl_mk_2!(ge, Z3_mk_ge);
    impl_mk_2!(bvand, Z3_mk_bvand);
    impl_mk_2!(bvor, Z3_mk_bvor);
    impl_mk_2!(bvxor, Z3_mk_bvxor);
    impl_mk_2!(bvnand, Z3_mk_bvnand);
    impl_mk_2!(bvnor, Z3_mk_bvnor);
    impl_mk_2!(bvxnor, Z3_mk_bvxnor);
    impl_mk_2!(bvadd, Z3_mk_bvadd);
    impl_mk_2!(bvsub, Z3_mk_bvsub);
    impl_mk_2!(bvmul, Z3_mk_bvmul);
    impl_mk_2!(bvudiv, Z3_mk_bvudiv);
    impl_mk_2!(bvsdiv, Z3_mk_bvsdiv);
    impl_mk_2!(bvurem, Z3_mk_bvurem);
    impl_mk_2!(bvsrem, Z3_mk_bvsrem);
    impl_mk_2!(bvsmod, Z3_mk_bvsmod);
    impl_mk_2!(bvult, Z3_mk_bvult);
    impl_mk_2!(bvslt, Z3_mk_bvslt);
    impl_mk_2!(bvule, Z3_mk_bvule);
    impl_mk_2!(bvsle, Z3_mk_bvsle);
    impl_mk_2!(bvuge, Z3_mk_bvuge);
    impl_mk_2!(bvsge, Z3_mk_bvsge);
    impl_mk_2!(bvugt, Z3_mk_bvugt);
    impl_mk_2!(bvsgt, Z3_mk_bvsgt);
    impl_mk_2!(concat, Z3_mk_concat);
    impl_mk_2!(bvshl, Z3_mk_bvshl);
    impl_mk_2!(bvlshr, Z3_mk_bvlshr);
    impl_mk_2!(bvashr, Z3_mk_bvashr);
    impl_mk_2!(ext_rotate_left, Z3_mk_ext_rotate_left);
    impl_mk_2!(ext_rotate_right, Z3_mk_ext_rotate_right);
    impl_mk_2!(bvadd_no_underflow, Z3_mk_bvadd_no_underflow);
    impl_mk_2!(bvsub_no_overflow, Z3_mk_bvsub_no_overflow);
    impl_mk_2!(bvsdiv_no_overflow, Z3_mk_bvsdiv_no_overflow);
    impl_mk_2!(bvmul_no_underflow, Z3_mk_bvmul_no_underflow);

    impl_mk_1!(not, Z3_mk_not);
    impl_mk_1!(int2real, Z3_mk_int2real);
    impl_mk_1!(real2int, Z3_mk_real2int);
    impl_mk_1!(is_int, Z3_mk_is_int);
    impl_mk_1!(bvnot, Z3_mk_bvnot);
    impl_mk_1!(bvredand, Z3_mk_bvredand);
    impl_mk_1!(bvredor, Z3_mk_bvredor);
    impl_mk_1!(bvneg_no_overflow, Z3_mk_bvneg_no_overflow);
    impl_mk_1!(bvneg, Z3_mk_bvneg);

    impl_mk_i_1!(sign_ext, Z3_mk_sign_ext);
    impl_mk_i_1!(zero_ext, Z3_mk_zero_ext);
    impl_mk_i_1!(repeat, Z3_mk_repeat);
    impl_mk_i_1!(rotate_left, Z3_mk_rotate_left);
    impl_mk_i_1!(rotate_right, Z3_mk_rotate_right);

    /// Create a new BitVector const of name `i` and width `w`
    pub fn mk_bv_i<'a>(&'a self, i: i32, w: u32) -> Z3Ast<'a> {
        unsafe {
            let sort= z3_sys::Z3_mk_bv_sort(self.ctx, w);
            let sym = z3_sys::Z3_mk_int_symbol(self.ctx, i);
            Z3Ast {
                ast: z3_sys::Z3_mk_const(self.ctx, sym, sort),
                z3: &self
            }
        }
    }
    /// Create a new BitVector const of name `s` and width `w`
    pub fn mk_bv_str<'a>(&'a self, s: &str, w: u32) -> Z3Ast<'a> {
        unsafe {
            let sort= z3_sys::Z3_mk_bv_sort(self.ctx, w);
            let cs = CString::new(s).unwrap();
            let sym = z3_sys::Z3_mk_string_symbol(self.ctx, cs.as_ptr());
            Z3Ast {
                ast: z3_sys::Z3_mk_const(self.ctx, sym, sort),
                z3: &self
            }
        }
    }

}

impl <'a> Z3Ast<'a> {
    /// Get u64 representation of this Ast value if possible
    pub fn get_u64(&self) -> Option<u64> {
        unsafe {
            let mut res: u64 = 0;
            if z3_sys::Z3_get_numeral_uint64(self.z3.ctx(), self.ast, &mut res)
                == z3_sys::Z3_L_TRUE
            {
                Some(res)
            } else {
                None
            }
        }
    }
    /// Get BitVector width
    pub fn get_bv_width(&self) -> u32 {
        unsafe {
            let sort = z3_sys::Z3_get_sort(self.z3.ctx(), self.ast);
            z3_sys::Z3_get_bv_sort_size(self.z3.ctx(), sort)
        }
    }
    /// Zero extend BitVector
    pub fn zero_ext(&self, i: u32) -> Z3Ast<'a> {
        self.z3.zero_ext(i, &self)
    }
    /// Sign extend BitVector
    pub fn sign_ext(&self, i: u32) -> Z3Ast<'a> {
        self.z3.sign_ext(i, &self)
    }
}

impl <'a> Z3Model<'a> {
    pub fn eval(&'a self, ast: &Z3Ast) -> Option<Z3Ast<'a>> {
        if self.is_model() {
            unsafe {
                let mut res_ast: z3_sys::Z3_ast = ptr::null_mut();
                if z3_sys::Z3_model_eval(self.z3.ctx(), *self.model,
                                         ast.ast, z3_sys::Z3_L_TRUE,
                                         &mut res_ast) == z3_sys::Z3_L_TRUE {
                    Some(Z3Ast {
                        ast: res_ast,
                        z3: self.z3
                    })
                } else {
                    None
                }
            }
        } else {
            None
        }
    }

    pub fn is_valid(&self) -> bool { self.res == z3_sys::Z3_L_FALSE }
    pub fn is_model(&self) -> bool {
        match self.res {
            z3_sys::Z3_L_UNDEF | z3_sys::Z3_L_TRUE => true,
            z3_sys::Z3_L_FALSE => false,
            _ => panic!("not supported")
        }
    }

    pub fn get_str(&self) -> &str {
        if self.is_model() {
            unsafe {
                let cstr = z3_sys::Z3_model_to_string(self.z3.ctx(), *self.model);
                let slice = CStr::from_ptr(cstr);
                let buf: &[u8] = slice.to_bytes();
                let str_slice: &str = str::from_utf8(buf).unwrap();
                str_slice
            }
        } else {
            "no model"
        }
    }
}

impl Drop for Z3 {
    fn drop(&mut self) {
        unsafe {
            z3_sys::Z3_del_context(self.ctx);
        }
    }
}

#[test]
fn test_get_bv_width() {
    let z3 = Z3::new();
    let a = z3.mk_bv_i(1, 32);
    let b = z3.mk_bv_str("b", 64);
    let c = z3.mk_bv_str("big", 256);
    let d = z3.mk_bv_i(2, 1);

    assert_eq!(a.get_bv_width(), 32);
    assert_eq!(b.get_bv_width(), 64);
    assert_eq!(c.get_bv_width(), 256);
    assert_eq!(d.get_bv_width(), 1);
}

#[test]
fn test_zero_ext() {
    let z3 = Z3::new();
    let a = z3.mk_bv_str("a", 32);
    let b = a.zero_ext(32);
    assert_eq!(b.get_bv_width(), 64);
}

#[test]
fn it_works() {
    let z3 = Z3::new();
    let a = z3.mk_bv_i(1, 32);
    let b = z3.mk_bv_i(2, 32);
    let c = z3.mk_bv_str("c", 32);

    assert_eq!(c.get_bv_width(), 32);

    let d = z3.bvand(&a, &b);
    let e = z3.bvor(&a, &b);

    let gt = z3.bvugt(&d, &e);
    let eq = z3.eq(&d, &e);
    let neq = z3.not(&gt);

    let h = z3.prove(&eq, true);

    let model = z3.check_and_get_model(&eq);
    println!("model: {}", model.get_str());

    let new_a = model.eval(&a).unwrap();
    let val_a = new_a.get_u64().unwrap();
    println!("val_a: 0x{:x}", val_a);
}
<|endoftext|>