~jpl8/piet_interpreter

a4114f0db4f03397e67b912fbce047bdd4c85161 — jpl 2 years ago 44cce5b
add push, pop, and add
A images/test_add.png => images/test_add.png +0 -0
A images/test_push.png => images/test_push.png +0 -0
M src/TODO.md => src/TODO.md +2 -0
@@ 1,5 1,7 @@
# Upscale Pixels into codels

# Change movement through white blocks to match spec

# Create rules
Create the rules modules, which represents the rules of the language.
This entails implementing the operations on the stack when moving

M src/color.rs => src/color.rs +112 -1
@@ 29,9 29,120 @@ impl Color {
        if color == [0xFF, 0xFF, 0xFF] { return Some(Color::White);        }
        if color == [0x00, 0x00, 0x00] { return Some(Color::Black);        }
    
        return None
        None
    
    
    }

    fn is_light(&self) -> bool {
        match self {
            Color::LightRed  | Color::LightYellow | Color::LightGreen   |
            Color::LightCyan | Color::LightBlue   | Color::LightMagenta => true,
            _ => false,

        }

    }

    fn is_normal(&self) -> bool {
        match self {
            Color::Red  | Color::Yellow | Color::Green   |
            Color::Cyan | Color::Blue   | Color::Magenta => true,
            _ => false,

        }
    }

    fn is_dark(&self) -> bool {
        match self {
            Color::DarkRed  | Color::DarkYellow | Color::DarkGreen   |
            Color::DarkCyan | Color::DarkBlue   | Color::DarkMagenta => true,
            _ => false,

        }


    }

    fn get_light(&self) -> Option<isize> {
        if self.is_light()          { Some(0) }
        else if self.is_normal()    { Some(1) }
        else if self.is_dark()      { Some(2) }
        else { None }
    }

    pub fn light_diff(&self, next: &Self) -> Option<u32> {
        if let (Some(n_light), Some(s_light)) = (next.get_light(), self.get_light()) {
            let mut diff = n_light - s_light;
            if diff < 0 { diff += 3 };
            Some(diff as u32)
        }
        else { None }
    }

    fn is_red(&self) -> bool { 
        match self {
            Color::LightRed | Color::Red | Color::DarkRed => true,
            _ => false,
        }
    }

    fn is_yellow(&self) -> bool { 
        match self {
            Color::LightYellow | Color::Yellow | Color::DarkYellow => true,
            _ => false,
        }
    }

    fn is_green(&self) -> bool { 
        match self {
            Color::LightGreen | Color::Green | Color::DarkGreen => true,
            _ => false,
        }
    }

    fn is_cyan(&self) -> bool { 
        match self {
            Color::LightCyan | Color::Cyan | Color::DarkCyan => true,
            _ => false,
        }
    }


    fn is_blue(&self) -> bool { 
        match self {
            Color::LightBlue | Color::Blue | Color::DarkBlue => true,
            _ => false,
        }
    }

    fn is_magenta(&self) -> bool { 
        match self {
            Color::LightMagenta | Color::Magenta | Color::DarkMagenta => true,
            _ => false,
        }
    }



    fn get_hue(&self) -> Option<isize> {
        if self.is_red()          { Some(0) }
        else if self.is_yellow()  { Some(1) }
        else if self.is_green()   { Some(2) }
        else if self.is_cyan()    { Some(3) }
        else if self.is_blue()    { Some(4) }
        else if self.is_magenta() { Some(5) }
        else { None }
    }

    pub fn hue_diff(&self, next: &Self) -> Option<u32> {
        if let (Some(next_hue), Some(self_hue)) = (next.get_hue(), self.get_hue()) {
            let mut diff = next_hue - self_hue;
            if diff < 0 { diff += 6 };
            Some(diff as u32) 
        }
        else { None }
    }


}

M src/interpreter/interpreter_tests.rs => src/interpreter/interpreter_tests.rs +25 -0
@@ 237,3 237,28 @@ fn exec_finishes() {

    assert_eq!(interpreter.head().pos(), (2,1));
}

#[test]
fn push_works() {

    let mut interpreter = Interpreter::new("images/test_push.png").expect("Image not found");
    interpreter.exec().expect("Execution failed!");
    let popped = interpreter.stack.pop().unwrap();
    assert_eq!(popped, 6);
}

#[test]
#[ignore]
fn pop_works() {}

#[test]
fn add_works() {
    let mut interpreter = Interpreter::new("images/test_add.png").unwrap();
    //println!("{:#?}", interpreter.img());
    interpreter.exec().expect("Execution failed!");
    let popped = interpreter.stack.pop().unwrap();
    assert_eq!(popped, 5);

}



M src/interpreter/mod.rs => src/interpreter/mod.rs +53 -3
@@ 1,9 1,10 @@
use std::io;
use std::io::{self, Error, ErrorKind};
use std::path::Path;

use crate::color::Color;
use crate::piet_img::PietImage;
use crate::piet_img::{PietImage, Codel};
use crate::translator;
use crate::rules::{self, Op};


pub struct Interpreter {


@@ 30,12 31,21 @@ impl Interpreter {
        }
    }

    pub fn head(&self) -> Head { self.head }
    pub fn head(&self) -> &Head { &self.head }
    pub fn img(&self) -> &PietImage { &self.img }
    pub fn stack(&self) -> &Vec<isize> { &self.stack }
    pub fn mut_stack(&mut self) -> &Vec<isize> { &mut self.stack }

    pub fn exec(&mut self) -> io::Result<()> {

       loop {
            let curr = self.head.pos();
            if let Some(next) = self.move_next() {

                let curr_codel = self.img().get(curr.0, curr.1);
                let next_codel = self.img().get(next.0, next.1);
                self.do_op(&curr_codel, &next_codel)?;

            }

            else { return Ok(()) }


@@ 43,6 53,46 @@ impl Interpreter {
       }

    }
    fn do_op(&mut self, curr: &Codel, next: &Codel) -> io::Result<()> {

        // error = Err(Error::new(ErrorKind::InvalidInput, "ERROR"));
   
       
        if let Some(op) = rules::get_op(curr, next) {

            match op {

                Op::Push => {
                    let block_size = curr.block_size().expect("Block size set to None!") as isize;
                    self.stack.push(block_size);
                    Ok(())
                }

                Op::Pop => {
                    self.stack.pop();
                    Ok(())
                }

                Op::Add => {
                    let first_pop  = self.stack.pop();
                    let second_pop = self.stack.pop();
                    if let (Some(a), Some(b)) = (first_pop, second_pop) {
                        self.stack.push(a + b);
                        Ok(())
                    }
                    else { Err(Error::new(ErrorKind::InvalidInput, "Not enough values on stack to add!")) }
                }

                _ => {Ok(())}


            }

        }
        else { Ok(()) }


    }

    fn move_next(&mut self) -> Option<(u32, u32)> {
        let curr_codel = self.head.pos;

M src/lib.rs => src/lib.rs +1 -0
@@ 2,4 2,5 @@ pub mod color;
pub mod piet_img;
pub mod interpreter;
pub mod translator;
pub mod rules;


M src/piet_img.rs => src/piet_img.rs +6 -2
@@ 41,10 41,14 @@ pub struct PietImage {
impl PietImage {

    pub fn new(dimensions: (u32, u32), codels: Vec<Vec<Codel>>) -> Self {
        Self {
        let mut piet = Self {
            dimensions,
            codels,
        }
        };

        piet.update_block_sizes();

        piet
    }

    pub fn new_test() -> Self {

M src/rules.rs => src/rules.rs +37 -3
@@ 1,4 1,7 @@
enum Ops {
use crate::piet_img::Codel;
use crate::color::Color;

pub enum Op {
    Push,
    Pop,
    Add,


@@ 12,6 15,37 @@ enum Ops {
    Switch,
    Duplicate,
    Roll,
    In,
    Out,
    InNum,
    InChar,
    OutNum,
    OutChar,
}

pub fn get_op(curr: &Codel, next: &Codel) -> Option<Op> {

    if let (Some(hue_diff), Some(light_diff)) = (curr.color().hue_diff(&next.color()), curr.color().light_diff(&next.color())) {
        match (hue_diff, light_diff) {
            (0, 1) => Some(Op::Push),
            (0, 2) => Some(Op::Pop),
            (1, 0) => Some(Op::Add),
            (1, 1) => Some(Op::Sub),
            (1, 2) => Some(Op::Mult),
            (2, 0) => Some(Op::Div),
            (2, 1) => Some(Op::Mod),
            (2, 2) => Some(Op::Not),
            (3, 0) => Some(Op::Greater),
            (3, 1) => Some(Op::Pointer),
            (3, 2) => Some(Op::Switch),
            (4, 0) => Some(Op::Duplicate),
            (4, 1) => Some(Op::Roll),
            (4, 2) => Some(Op::InNum),
            (5, 0) => Some(Op::InChar),
            (5, 1) => Some(Op::OutNum),
            (5, 2) => Some(Op::OutChar),
            _ => None

        }
    }
    else { None }

}

M src/translator.rs => src/translator.rs +1 -1
@@ 10,7 10,7 @@ pub fn png_to_piet_img<P>(path: P) -> io::Result<PietImage>
where P: AsRef<Path> 
{

    let error = Err(Error::new(ErrorKind::InvalidInput, "Failed to convert to PietImage"));
    let error = Err(Error::new(ErrorKind::InvalidInput, "Failed to convert to PietImage! Some color is not accepted"));

    let img = ImageReader::open(path).expect("Failed to open given path!")
                                .decode().expect("Failed to decode!");