~jpl8/piet_interpreter

ac8f40844156db2645529a8247fc9b7da1d0e2a9 — jpl 1 year, 7 months ago b9a5e20
Update README
3 files changed, 38 insertions(+), 407 deletions(-)

D README
A README.md
D src/interpreter/.rules.rs.rustfmt
D README => README +0 -4
@@ 1,4 0,0 @@
# A somewhat functional Piet interpreter

## Usage


A README.md => README.md +38 -0
@@ 0,0 1,38 @@
# A somewhat functional Piet interpreter

## Example

## Usage

To interpret a piet program simply pass it as input to the binary
```sh
piet <INPUT_FILE>
```
or use cargo
```sh
cargo run -- <INPUT_FILE>
```
### Debug
To see debug information, pass the debug flag (-d):

```sh
piet -d <INPUT_FILE>
```

### Codel size

If the image is upscaled perfectly, without interpolation, and the smallest group of equal colored pixels is a nxn square then the interpreter will assume that the codel size is n.
It is possible to specify the desired codel size directly as a parameter, but beware, funky behaviour may be encountered if the wrong codel size is passed, potentially never terminating.
However, there are also some piet programs that can be interpreted in different, intended forms depending on the codel size.

To specify the codel size use the -c or --codel-size option:

```sh
piet -c 20 <INPUT_FILE>
```

Further parameters are available and can be consulted by invoking the help flag (-h):
```sh
piet -h
```


D src/interpreter/.rules.rs.rustfmt => src/interpreter/.rules.rs.rustfmt +0 -403
@@ 1,403 0,0 @@
use crate::interpreter::Interpreter;
use crate::piet_img::Codel;
use std::io::{self, Error, ErrorKind, Write};

#[derive(Debug)]
pub enum Op {
    Push,
    Pop,
    Add,
    Sub,
    Mult,
    Div,
    Mod,
    Not,
    Greater,
    Pointer,
    Switch,
    Duplicate,
    Roll,
    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
    }
}

pub fn do_op(interpreter: &mut Interpreter, curr: &Codel, next: &Codel) -> io::Result<()> {
    if let Some(op) = get_op(curr, next) {
        match op {
            Op::Push => {
                let block_size = curr.block_size().expect("Block size set to None!") as isize;
                interpreter.stack_as_mut().push(block_size);

                if interpreter.debug {
                    eprintln!("Executed: Push({})", block_size);
                }

                Ok(())
            }

            Op::Pop => {
                let popped = interpreter.stack_as_mut().pop();
                if interpreter.debug {
                    if let Some(v) = popped {
                        eprintln!("Executed: Pop -> {}", v);
                    } else {
                        eprintln!("Executed: Pop, but stack was empty");
                    }
                }
                Ok(())
            }

            Op::Add => {
                if interpreter.stack.len() >= 2 {
                    let first_pop = interpreter.stack_as_mut().pop().unwrap();
                    let second_pop = interpreter.stack_as_mut().pop().unwrap();
                    interpreter.stack_as_mut().push(second_pop + first_pop);

                    if interpreter.debug {
                        eprintln!(
                            "Executed: Add({}, {}) -> {}",
                            second_pop,
                            first_pop,
                            second_pop + first_pop
                        );
                    }
                } else {
                    eprintln!(
                        "Not enough values on the stack! Were {}, needed 2",
                        interpreter.stack.len()
                    );
                }
                Ok(())
            }

            Op::Sub => {
                if interpreter.stack.len() >= 2 {
                    let first_pop = interpreter.stack_as_mut().pop().unwrap();
                    let second_pop = interpreter.stack_as_mut().pop().unwrap();
                    interpreter.stack_as_mut().push(second_pop - first_pop);

                    if interpreter.debug {
                        eprintln!(
                            "Executed: Sub({}, {}) -> {}",
                            second_pop,
                            first_pop,
                            second_pop - first_pop
                        );
                    }
                } else {
                    eprintln!(
                        "Not enough values on the stack! Were {}, needed 2",
                        interpreter.stack.len()
                    );
                }

                Ok(())
            }

            Op::Mult => {
                if interpreter.stack.len() >= 2 {
                    let first_pop = interpreter.stack_as_mut().pop().unwrap();
                    let second_pop = interpreter.stack_as_mut().pop().unwrap();
                    interpreter.stack_as_mut().push(second_pop * first_pop);

                    if interpreter.debug {
                        eprintln!(
                            "Executed: Mult({}, {}) -> {}",
                            second_pop,
                            first_pop,
                            second_pop * first_pop
                        );
                    }
                } else {
                    eprintln!(
                        "Not enough values on the stack! Were {}, needed 2",
                        interpreter.stack.len()
                    );
                }
                Ok(())
            }

            Op::Div => {
                if interpreter.stack.len() >= 2 {
                    let first_pop = interpreter.stack_as_mut().pop().unwrap();
                    let second_pop = interpreter.stack_as_mut().pop().unwrap();
                    if first_pop == 0 {
                        return Ok(());
                    }
                    interpreter.stack_as_mut().push(second_pop / first_pop);

                    if interpreter.debug {
                        eprintln!(
                            "Executed: Div({}, {}) -> {}",
                            second_pop,
                            first_pop,
                            second_pop / first_pop
                        );
                    }
                } else {
                    eprintln!(
                        "Not enough values on the stack! Were {}, needed 2",
                        interpreter.stack.len()
                    );
                }
                Ok(())
            }

            Op::Mod => {
                if interpreter.stack.len() >= 2 {
                    let first_pop = interpreter.stack_as_mut().pop().unwrap();
                    let second_pop = interpreter.stack_as_mut().pop().unwrap();
                    if first_pop == 0 {
                        eprintln!("Division by zero!");
                        return Ok(());
                    }

                    interpreter.stack_as_mut().push(
                        second_pop % first_pop
                            + if second_pop % first_pop < 0 {
                                first_pop
                            } else {
                                0
                            },
                    );

                    if interpreter.debug {
                        eprintln!(
                            "Executed: Div({}, {}) -> {}",
                            second_pop,
                            first_pop,
                            second_pop / first_pop
                        );
                    }
                } else {
                    eprintln!(
                        "Not enough values on the stack! Were {}, needed 2",
                        interpreter.stack.len()
                    );
                }
                Ok(())
            }

            Op::Not => {
                if interpreter.stack().len() > 0 {
                    let popped = interpreter.stack_as_mut().pop().unwrap();
                    let negated = if popped == 0 { 1 } else { 0 };

                    interpreter.stack_as_mut().push(negated);

                    if interpreter.debug {
                        eprintln!("Executed: Not({}) -> {}", popped, negated);
                    }
                } else {
                    eprintln!(
                        "Not enough values on the stack! Were {}, needed 1",
                        interpreter.stack.len()
                    );
                }
                Ok(())
            }

            Op::Greater => {

                if interpreter.stack.len() >= 2 {
                    let first_pop = interpreter.stack_as_mut().pop().unwrap();
                    let second_pop = interpreter.stack_as_mut().pop().unwrap();
                    if first_pop == 0 {
                        return Ok(());
                    }

                    let push_val = 
                    if second_pop > first_pop {
                        1
                    } else {
                        0
                    };

                    interpreter.stack_as_mut().push(push_val);


                    if interpreter.debug {
                        eprintln!(
                            "Executed: ({}, {}) -> {}",
                            second_pop,
                            first_pop,
                            second_pop / first_pop
                        );
                    }
                } else {
                    eprintln!(
                        "Not enough values on the stack! Were {}, needed 2",
                        interpreter.stack.len()
                    );
                }
                Ok(())
 


                if let (Some(a), Some(b)) = (first_pop, second_pop) {
                    Ok(())
                } else {
                    Err(Error::new(
                        ErrorKind::InvalidInput,
                        "Not enough values on stack!",
                    ))
                }
            }

            Op::Pointer => {
                if let Some(val) = interpreter.stack_as_mut().pop() {
                    if val < 0 {
                        for _ in 0..(-val) {
                            let new_dir = interpreter.head().direction_pointer().anticlockwise();
                            interpreter.head_as_mut().set_direction(new_dir);
                        }
                    } else {
                        for _ in 0..val {
                            let new_dir = interpreter.head().direction_pointer().clockwise();
                            interpreter.head_as_mut().set_direction(new_dir);
                        }
                    }
                }

                Ok(())
            }

            Op::Switch => {
                if let Some(val) = interpreter.stack_as_mut().pop() {
                    for _ in 0..(val.abs()) {
                        let new_dir = interpreter.head().codel_chooser().toggle();
                        interpreter.head_as_mut().set_codel_chooser(new_dir);
                    }
                }
                Ok(())
            }

            Op::Duplicate => {
                if let Some(val) = interpreter.stack_as_mut().pop() {
                    interpreter.stack_as_mut().push(val);
                    interpreter.stack_as_mut().push(val);
                }
                Ok(())
            }

            Op::Roll => {
                if interpreter.stack_as_mut().len() < 3 {
                    return Err(Error::new(
                        ErrorKind::InvalidInput,
                        "Not enough values on stack!",
                    ));
                }

                let first_pop = interpreter.stack_as_mut().pop().unwrap();
                let second_pop = interpreter.stack_as_mut().pop().unwrap();
                if second_pop < 0 {
                    // depth is negative -> ignore
                    return Ok(());
                }

                if first_pop < 0 {
                    for _ in 0..(first_pop.abs()) {
                        let front = interpreter.stack_as_mut().remove(0);
                        interpreter
                            .stack_as_mut()
                            .insert((second_pop) as usize, front);
                    }
                } else {
                    for _ in 0..first_pop {
                        let len = interpreter.stack().len();
                        let depth = if (len as isize) < second_pop {
                            return Ok(());
                        } else {
                            len - second_pop as usize
                        };
                        let third_pop = interpreter.stack_as_mut().pop().unwrap();
                        interpreter.stack_as_mut().insert(depth, third_pop);
                    }
                }
                Ok(())
            }

            Op::InNum => {
                let mut input = String::with_capacity(8);
                // Ignore errors (it's what the author recommended)
                io::stdout().flush().expect("Failed to flush to stdout!");
                if let Err(_) = io::stdin().read_line(&mut input) {
                    return Ok(());
                }
                input = input.trim().to_string();
                if let Ok(val) = input.parse::<isize>() {
                    interpreter.stack_as_mut().push(val);
                }

                Ok(())
            }

            Op::InChar => {
                let mut input = String::with_capacity(8);
                // Ignore errors (it's what the author recommended)
                io::stdout().flush().expect("Failed to flush to stdout!");
                if let Err(_) = io::stdin().read_line(&mut input) {
                    return Ok(());
                }
                input = input.trim().to_string();

                let bytes = Interpreter::get_utf8_char(&input);
                let code_point = Interpreter::utf8_to_unicode(&bytes);

                interpreter.stack_as_mut().push(code_point);

                Ok(())
            }

            Op::OutNum => {
                if let Some(val) = interpreter.stack_as_mut().pop() {
                    print!("{}", val);
                }
                Ok(())
            }

            Op::OutChar => {
                if let Some(val) = interpreter.stack_as_mut().pop() {
                    if let Some(c) = char::from_u32(val as u32) {
                        print!("{}", c);
                    }
                }
                Ok(())
            }
        }
    } else {
        Ok(())
    }
}