From 6c039c778747fa6e799f85e6c30445286746f948 Mon Sep 17 00:00:00 2001 From: Wim Pomp Date: Wed, 14 Dec 2022 18:36:42 +0100 Subject: [PATCH] - Option for different integer types for stack and funge-space, funge-space position still isize. - Bugfix in skipping a step. --- Cargo.toml | 3 +- examples/test.bf | 2 +- src/debug.rs | 33 ++-- src/lib.rs | 459 ++++++++++++++++++++++++++--------------------- src/main.rs | 36 +++- 5 files changed, 299 insertions(+), 234 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index dcabde3..3ac595b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "rusty_funge" -version = "2022.12.2" +version = "2022.12.3" edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html @@ -10,3 +10,4 @@ clap = { version = "4.0.29", features = ["derive"] } chrono = "0.4.23" cursive = { version = "0.20.0", features = ["termion-backend"] } rand = "0.8.5" +num = "0.4.0" \ No newline at end of file diff --git a/examples/test.bf b/examples/test.bf index f132b05..90e6e44 100755 --- a/examples/test.bf +++ b/examples/test.bf @@ -1,2 +1,2 @@ #!/usr/bin/env rusty_funge -00gg00@ \ No newline at end of file +zz; ;zz#r#;1jr1j;zz@ \ No newline at end of file diff --git a/src/debug.rs b/src/debug.rs index 4b9499b..b99909a 100644 --- a/src/debug.rs +++ b/src/debug.rs @@ -1,23 +1,20 @@ use std::cmp::{min, max}; -use std::error::Error; +use std::{error::Error, time::Duration}; use std::fmt::{Display, Formatter}; use std::sync::{Arc, Mutex}; use std::thread::{sleep, spawn}; -use std::time::Duration; -use cursive::{Cursive, CursiveExt, Vec2}; -use cursive::view::View; -use cursive::Printer; +use cursive::{Cursive, CursiveExt, Printer, Vec2}; +use cursive::{theme::ColorStyle, view::View}; use cursive::event::{Event, EventResult}; -use cursive::theme::ColorStyle; -use crate::Funge; +use rusty_funge::{Int, Funge}; -struct FungeMutex { - funge: Option +struct FungeMutex { + funge: Option> } -impl FungeMutex { - fn new(funge: Funge) -> Self { +impl FungeMutex { + fn new(funge: Funge) -> Self { Self { funge: Some(funge) } } @@ -31,24 +28,24 @@ impl FungeMutex { Ok(terminated) } - fn funge_ref(&self) -> Option<&Funge> { + fn funge_ref(&self) -> Option<&Funge> { self.funge.as_ref() } } -impl Display for FungeMutex { +impl Display for FungeMutex { fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { write!(f, "{}", self.funge.as_ref().expect("No funge found")) } } -pub(crate) struct FungeView { - funge: Arc> +pub(crate) struct FungeView { + funge: Arc>> } -impl FungeView { - pub (crate) fn new(funge: Funge) -> Result> { +impl FungeView { + pub (crate) fn new(funge: Funge) -> Result> { Ok(FungeView { funge: Arc::new(Mutex::new(FungeMutex::new(funge.with_output()?))) } ) } @@ -86,7 +83,7 @@ impl FungeView { } } -impl View for FungeView { +impl View for FungeView { fn draw(&self, printer: &Printer) { let (text, ips_pos, terminated) = { let lock = self.funge.lock(); diff --git a/src/lib.rs b/src/lib.rs index f7c43f4..d182c40 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,15 +1,19 @@ use std::collections::HashMap; use std::{env, fs, fmt, fmt::{Debug, Display, Formatter}}; -use std::io::stdin; -use std::ops::{Deref, DerefMut, Index, IndexMut}; -use std::{error::Error, hash::Hash, path::Path}; +use std::ops::{Add, Deref, DerefMut, Index, IndexMut, Sub}; +use std::{error::Error, hash::Hash, path::Path, str::FromStr, io::stdin}; use chrono::{offset::Local, {Datelike, Timelike}}; use rand::Rng; +use num::{Integer, NumCast}; const VERSION: &str = env!("CARGO_PKG_VERSION"); +pub trait Int: Integer + NumCast + FromStr + Hash + Clone + Copy + Sync + Send + Display + 'static {} +impl Int for I {} + + fn join(v: &Vec, s: &str) -> String { let mut string = String::new(); if v.len() > 1 { @@ -24,19 +28,34 @@ fn join(v: &Vec, s: &str) -> String { string } -fn ord(c: char) -> Result> { - Ok(u32::try_from(c)?.try_into()?) +fn cast_int(j: J) -> Result> { + Ok(I::from(j).ok_or("Could not convert from primitive")?) } -fn chr(i: isize) -> Result> { - Ok(u32::try_from(i)?.try_into()?) +fn cast_vec_int(j: Vec) -> Result, Box> { + let mut i = Vec::::new(); + for n in j { + i.push(cast_int(n)?); + } + Ok(i) } -fn add(a: &Vec, b: &Vec) -> Vec { +fn ord(c: char) -> Result> +{ + Ok(cast_int::<_, u32>(c.try_into()?)?) +} + +fn chr(i: I) -> Result> { + Ok(cast_int::(i)?.try_into()?) +} + +fn add(a: &Vec, b: &Vec) -> Vec where + Vec: FromIterator<::Output> { a.iter().zip(b.iter()).map(|(&a, &b)| a + b).collect() } -fn sub(a: &Vec, b: &Vec) -> Vec { +fn sub(a: &Vec, b: &Vec) -> Vec where + Vec: FromIterator<::Output> { a.iter().zip(b.iter()).map(|(&a, &b)| a - b).collect() } @@ -88,38 +107,38 @@ impl Output { #[derive(Clone)] -struct Stack { - stack: Vec +struct Stack { + stack: Vec } -impl Stack { +impl Stack { fn new() -> Self { Self { stack: Vec::new() } } - fn pop(&mut self) -> isize { + fn pop(&mut self) -> I { match self.stack.pop() { Some(value) => { value } - None => { 0 } + None => { I::zero() } } } - fn push(&mut self, cell: isize) { + fn push(&mut self, cell: I) { self.stack.push(cell) } fn len(&self) -> usize { self.stack.len() } } -impl Display for Stack { +impl Display for Stack { fn fmt(&self, f: &mut Formatter) -> fmt::Result { write!(f, "[{}]", join(&self.stack, ", ")) } } -impl Index for Stack { - type Output = isize; +impl Index for Stack { + type Output = I; fn index(&self, index: usize) -> &Self::Output { &self.stack[index] @@ -127,11 +146,11 @@ impl Index for Stack { } #[derive(Clone)] -struct StackStack { - stackstack: Vec +struct StackStack { + stackstack: Vec> } -impl StackStack { +impl StackStack { fn new() -> Self { Self { stackstack: vec![Stack::new()] } } @@ -142,26 +161,26 @@ impl StackStack { } } - fn pop(&mut self) -> isize { + fn pop(&mut self) -> I { self.check_stack(); let x = self.len_stack(); self.stackstack[x - 1].pop() } - fn push(&mut self, cell: isize) { + fn push(&mut self, cell: I) { self.check_stack(); let x = self.len_stack(); self.stackstack[x - 1].push(cell); } - fn pop_stack(&mut self) -> Stack { + fn pop_stack(&mut self) -> Stack { match self.stackstack.pop() { Some(stack) => { stack } None => { Stack::new() } } } - fn push_stack(&mut self, stack: Stack) { + fn push_stack(&mut self, stack: Stack) { self.stackstack.push(stack) } @@ -188,21 +207,21 @@ impl StackStack { } } -impl Index for StackStack { - type Output = Stack; +impl Index for StackStack { + type Output = Stack; fn index(&self, index: usize) -> &Self::Output { &self.stackstack[index] } } -impl IndexMut for StackStack { +impl IndexMut for StackStack { fn index_mut(&mut self, index: usize) -> &mut Self::Output { &mut self.stackstack[index] } } -impl Display for StackStack { +impl Display for StackStack { fn fmt(&self, f: &mut Formatter) -> fmt::Result { write!(f, "{}", join(&self.stackstack, "\n")) } @@ -210,19 +229,19 @@ impl Display for StackStack { #[derive(Clone)] -struct IP { +struct IP { id: usize, position: Vec, delta: Vec, offset: Vec, string: bool, - stack: StackStack, - fingerprint_ops: HashMap, + stack: StackStack, + fingerprint_ops: HashMap, } -impl IP { - fn new(funge: &Funge) -> Result> { +impl IP { + fn new(funge: &Funge) -> Result> { let mut new = IP { id: funge.ips.len(), position: vec![0, 0], @@ -232,13 +251,13 @@ impl IP { stack: StackStack::new(), fingerprint_ops: HashMap::new() }; - if (new.op(funge) == ord(' ')?) | (new.op(funge) == ord(';')?) { - new.advance(funge); + if let Ok(32 | 59) = cast_int(new.op(funge)) { + new.advance(funge)?; }; Ok(new) } - fn copy(&self, funge: &Funge) -> Self { + fn copy(&self, funge: &Funge) -> Self { Self { id: funge.ips.len(), position: self.position.to_owned(), @@ -250,7 +269,7 @@ impl IP { } } - fn op(&self, funge: &Funge) -> isize { + fn op(&self, funge: &Funge) -> I { funge.code[&self.position] } @@ -266,10 +285,12 @@ impl IP { self.delta = vec![self.delta[1], -self.delta[0]]; } - fn advance(&mut self, funge: &Funge) { - if self.string { - if funge.code[&self.position] == 32 { - while funge.code[&self.position] == 32 { + fn advance(&mut self, funge: &Funge) -> Result<(), Box> { + let space: I = cast_int(32)?; + let semicolon: I = cast_int(59)?; + Ok(if self.string { + if self.op(funge) == space { + while self.op(funge) == space { self.movep(funge) } } else { @@ -277,36 +298,44 @@ impl IP { } } else { loop { - if self.op(funge) != 59 { + if self.op(funge) != semicolon { self.movep(funge) } - if self.op(funge) == 59 { + if self.op(funge) == semicolon { self.movep(funge); - while self.op(funge) == 59 { + while self.op(funge) != semicolon { self.movep(funge) } self.movep(funge) } - while self.op(funge) == 32 { + while self.op(funge) == space { self.movep(funge) } - if self.op(funge) != 59 { + if self.op(funge) != semicolon { break; } } - } + }) } - fn movep(&mut self, funge: &Funge) { + fn movep(&mut self, funge: &Funge) { self.position = self.next_pos(funge); } - fn check_pos(&self, pos: &Vec, funge: &Funge) -> bool { + fn skip(mut self, funge: Funge) -> Result<(Funge, Option>), Box> { + self.movep(&funge); + if let Ok(32 | 59) = cast_int(self.op(&funge)) { + self.advance(&funge)?; + }; + return Ok((funge, Some(vec![self]))) + } + + fn check_pos(&self, pos: &Vec, funge: &Funge) -> bool { (funge.extent[0] <= pos[0]) & (pos[0] < funge.extent[1]) & (funge.extent[2] <= pos[1]) & (pos[1] < funge.extent[3]) } - fn next_pos(&self, funge: &Funge) -> Vec { + fn next_pos(&self, funge: &Funge) -> Vec { let mut pos= add(&self.position, &self.delta); if !self.check_pos(&pos, funge) { loop { @@ -324,7 +353,7 @@ impl IP { let mut string = String::new(); loop { let f = self.stack.pop(); - if f == 0 { + if f == I::zero() { return Ok(string) } else { string.push_str(&chr(f)?.to_string()) @@ -332,105 +361,117 @@ impl IP { } } - fn get_info(&self, funge: &Funge, n: isize) -> Result, Box> { + fn get_info(&self, funge: &Funge, n: I) -> Result, Box> { let time = Local::now(); - Ok(match n { - 1 => { vec![15] } - 2 => { vec![isize::BITS as isize] } - 3 => { - let mut f = 0; - for (i, c) in "wprustyfunge".chars().enumerate() { - f += (256 as isize).pow(i as u32) * ord(c)?; - } - vec![f] - } - 4 => vec![VERSION.replace(".", "").parse()?], - 5 => vec![1], - 6 => vec![ord(std::path::MAIN_SEPARATOR)?], - 7 => vec![2], - 8 => vec![*&self.id as isize], - 9 => vec![0], - 10 => self.position.to_owned(), - 11 => self.delta.to_owned(), - 12 => self.offset.to_owned(), - 13 => funge.extent.chunks(2).map(|i| i[0]).collect(), - 14 => funge.extent.chunks(2).map(|i| i[1]).collect(), - 15 => vec![((time.year() as isize) - 1900) * 256 * 256 + (time.month() as isize) * 256 + (time.day() as isize)], - 16 => vec![(time.hour() as isize) * 256 * 256 + (time.minute() as isize) * 256 + (time.second() as isize)], - 17 => vec![self.stack.len_stack() as isize], - 18 => { - let mut l = Vec::new(); - for stack in &self.stack.stackstack { - l.push(stack.len() as isize); - } - l.reverse(); - l - } - 19 => { - let mut r = Vec::new(); - let args: Vec = env::args().collect(); - if args.len() > 1 { - for i in 1..args.len() { - let j: Vec = args[i].chars().map(|i| ord(i).expect("")).collect(); - r.extend(j); - r.push(0); + match n.to_usize() { + Some(n @ 1..=20) => { + Ok(match n { + 1 => vec![cast_int(15)?], + 2 => vec![cast_int(8 * std::mem::size_of::())?], + 3 => { + let mut f = 0; + for (i, c) in "wprustyfunge".chars().enumerate() { + f += (256 as isize).pow(i as u32) * ord::(c)?; + } + vec![cast_int(f)?] } - } - r.push(0); - let file = &args[0]; - let path = Path::new(&file); - let j: Vec = path.file_name().ok_or("No file name.")? - .to_str().ok_or("Cannot convert String.")? - .chars().map(|i| ord(i).expect("")).collect(); - r.extend(j); - r.push(0); - r.push(0); - r.reverse(); - r + 4 => vec![cast_int(VERSION.replace(".", "").parse::()?)?], + 5 => vec![I::one()], + 6 => vec![ord(std::path::MAIN_SEPARATOR)?], + 7 => vec![cast_int(2)?], + 8 => vec![cast_int(*&self.id)?], + 9 => vec![I::zero()], + 10 => cast_vec_int(self.position.to_owned())?, + 11 => cast_vec_int(self.delta.to_owned())?, + 12 => cast_vec_int(self.offset.to_owned())?, + 13 => cast_vec_int(funge.extent.chunks(2).map(|i| i[0]).collect())?, + 14 => cast_vec_int(funge.extent.chunks(2).map(|i| i[1]).collect())?, + 15 => vec![cast_int((time.year() - 1900) * 256 * 256 + (time.month() as i32) * 256 + (time.day() as i32))?], + 16 => vec![cast_int(time.hour() * 256 * 256 + time.minute() * 256 + time.second())?], + 17 => vec![cast_int(self.stack.len_stack())?], + 18 => { + let mut l = Vec::new(); + for stack in &self.stack.stackstack { + l.push(cast_int(stack.len())?); + } + l.reverse(); + l + } + 19 => { + let mut r = Vec::new(); + let args: Vec = env::args().collect(); + if args.len() > 1 { + for i in 1..args.len() { + let j: Vec = args[i].chars().map(|i| ord(i).expect("")).collect(); + r.extend(j); + r.push(I::zero()); + } + } + r.push(I::zero()); + let file = &args[0]; + let path = Path::new(&file); + let j: Vec = path.file_name().ok_or("No file name.")? + .to_str().ok_or("Cannot convert String.")? + .chars().map(|i| ord(i).expect("")).collect(); + r.extend(j); + r.push(I::zero()); + r.push(I::zero()); + r.reverse(); + r + } + 20 => { + let mut r = Vec::new(); + let vars = env::vars(); + for (key, value) in vars { + let j: Vec = key.chars().map(|i| ord(i).expect("")).collect(); + r.extend(j); + r.push(ord('=')?); + let j: Vec = value.chars().map(|i| ord(i).expect("")).collect(); + r.extend(j); + r.push(I::zero()); + } + r.push(I::zero()); + r.reverse(); + r + } + i => { + let j = i as usize - 20; + let l = self.stack.len(); + if l >= j { + vec![self.stack.stackstack[0][l - j]] + } else { + vec![I::zero()] + } + } + }) } - 20 => { - let mut r = Vec::new(); - let vars = env::vars(); - for (key, value) in vars { - let j: Vec = key.chars().map(|i| ord(i).expect("")).collect(); - r.extend(j); - r.push(ord('=')?); - let j: Vec = value.chars().map(|i| ord(i).expect("")).collect(); - r.extend(j); - r.push(0); - } - r.push(0); - r.reverse(); - r + _ => { + // TODO: return Error + println!("{}", "Stack size overflow"); + Ok(Vec::new()) } - i => { - let j = i as usize - 20; - let l = self.stack.len(); - if l >= j { - vec![self.stack.stackstack[0][l - j]] - } else { - vec![0] - } - } - }) + } } - fn not_implemented(&mut self, funge: &Funge) { + fn not_implemented(&mut self, funge: &Funge) { + // TODO: reverse or quit option println!("operator {} at {} not implemented", self.op(funge), join(&self.position, ", ")); self.reverse() } - fn step(mut self, mut funge: Funge, k: bool) -> Result<(Funge, Option>), Box> { + fn step(mut self, mut funge: Funge, k: bool) -> Result<(Funge, Option>), Box> { let mut new_ips = Vec::new(); + let op = self.op(&funge); + let op8 = op.to_u8(); if self.string { - match self.op(&funge) { - 34 => { self.string = false } // ' - s => { self.stack.push(s) } + match op8 { + Some(34) => { self.string = false } // " + _ => { self.stack.push(op) } } - } else if self.fingerprint_ops.contains_key(&self.op(&funge)) { + } else if self.fingerprint_ops.contains_key(&op) { // self.fingerprint_ops[self.op(funge)]? - } else if (0 <= self.op(&funge)) & (self.op(&funge) < 255) { - match self.op(&funge) { + } else if let Some(0..=255) = op8 { + match op8.expect("Could not convert.") { 43 => { // + let b = self.stack.pop(); let a = self.stack.pop(); @@ -449,8 +490,8 @@ impl IP { 47 => { // / let b = self.stack.pop(); let a = self.stack.pop(); - if b == 0 { - self.stack.push(0); + if b == I::zero() { + self.stack.push(I::zero()); } else { self.stack.push(a / b); } @@ -462,16 +503,20 @@ impl IP { } 33 => { // ! let a = self.stack.pop(); - if a == 0 { - self.stack.push(1); + if a == I::zero() { + self.stack.push(I::one()); } else { - self.stack.push(0); + self.stack.push(I::zero()); } } 96 => { // ` let b = self.stack.pop(); let a = self.stack.pop(); - self.stack.push((a > b) as isize); + if a > b { + self.stack.push(I::one()); + } else { + self.stack.push(I::zero()); + } } 62 => self.delta = vec![1, 0], // > 60 => self.delta = vec![-1, 0], // < @@ -487,14 +532,14 @@ impl IP { }; } 95 => { // _ - if self.stack.pop() == 0 { + if self.stack.pop() == I::zero() { self.delta = vec![1, 0] } else { self.delta = vec![-1, 0] } } 124 => { // | - if self.stack.pop() == 0 { + if self.stack.pop() == I::zero() { self.delta = vec![0, 1]; } else { self.delta = vec![0, -1]; @@ -515,24 +560,30 @@ impl IP { 36 => { self.stack.pop(); } // $ 46 => funge.output.print(format!("{} ", self.stack.pop())), // . 44 => funge.output.print(format!("{}", chr(self.stack.pop())?)), // , - 35 => self.movep(&funge), // # + 35 => { // # + self.movep(&funge); + return self.skip(funge) + } 112 => { // p - let y = self.stack.pop(); - let x = self.stack.pop(); + let y: isize = cast_int(self.stack.pop())?; + let x: isize = cast_int(self.stack.pop())?; let v = self.stack.pop(); funge.insert(v, x + self.offset[0], y + self.offset[1]); } 103 => { // g - let y = self.stack.pop(); - let x = self.stack.pop(); - self.stack.push(funge.code[&vec![x + self.offset[0], y + self.offset[1]]]); + let y: isize = cast_int(self.stack.pop())?; + let x: isize = cast_int(self.stack.pop())?; + self.stack.push(*&funge.code[&vec![x + self.offset[0], y + self.offset[1]]]); } 38 => { // & let s = funge.inputs.get()?; let i: Vec = s.chars() .skip_while(|i| !i.is_digit(10)) .take_while(|i| i.is_digit(10)).collect(); - self.stack.push(join(&i, "").parse()?); + match join(&i, "").parse() { + Ok(n) => self.stack.push(n), + _ => println!("Cannot convert input to number.") // TODO: Error + } } 126 => { // ~ let s = funge.inputs.get()?; @@ -540,8 +591,8 @@ impl IP { } 64 => { return Ok((funge, Some(Vec::new()))); } // @ 32 => { // space - self.advance(&funge); - return self.step(funge, false); + self.advance(&funge)?; + return Ok(self.step(funge,false)?); } // 98 from here 91 => self.turn_left(), // [ @@ -549,21 +600,22 @@ impl IP { 39 => { // ' self.movep(&funge); self.stack.push(self.op(&funge)); + return self.skip(funge) } 123 => { // { let n = self.stack.pop(); - let cells = if n > 0 { + let cells = if n > I::zero() { let mut cells = Vec::new(); - for _ in 0..n { + for _ in 0..cast_int(n)? { cells.push(self.stack.pop()); } cells.reverse(); cells } else { - vec![0; -n as usize] + vec![I::zero(); -cast_int::(n)? as usize] }; for coordinate in &self.offset { - self.stack.push(*coordinate); + self.stack.push(cast_int(*coordinate)?); } self.stack.push_stack(Stack::new()); for cell in cells { @@ -573,19 +625,19 @@ impl IP { } 125 => { // } let n = self.stack.pop(); - let cells = if n > 0 { + let cells = if n > I::zero() { let mut cells = Vec::new(); - for _ in 0..n { + for _ in 0..cast_int(n)? { cells.push(self.stack.pop()); } cells.reverse(); cells } else { - vec![0; -n as usize] + vec![I::zero(); -cast_int::(n)? as usize] }; self.stack.pop_stack(); - let y = self.stack.pop(); - let x = self.stack.pop(); + let y = cast_int(self.stack.pop())?; + let x = cast_int(self.stack.pop())?; self.offset = vec![x, y]; for cell in cells { self.stack.push(cell); @@ -608,10 +660,10 @@ impl IP { 105 => { // i let file = self.read_string()?; let flags = self.stack.pop(); - let y0 = self.stack.pop(); - let x0 = self.stack.pop(); + let y0 = cast_int(self.stack.pop())?; + let x0 = cast_int(self.stack.pop())?; let text = fs::read_to_string(file)?; - let (width, height) = if flags % 2 != 0 { + let (width, height) = if flags.is_odd() { let code: Vec = text.chars().collect(); funge.insert_code(vec![join(&code, "")], x0, y0)?; (text.len(), 1) @@ -627,19 +679,20 @@ impl IP { funge.insert_code(code, x0, y0)?; (width, height) }; - self.stack.push(x0); - self.stack.push(y0); - self.stack.push(width as isize); - self.stack.push(height as isize); + self.stack.push(cast_int(x0)?); + self.stack.push(cast_int(y0)?); + self.stack.push(cast_int(width)?); + self.stack.push(cast_int(height)?); } 106 => { // j - for _ in 0..self.stack.pop() { + for _ in 0..cast_int(self.stack.pop())? { self.movep(&funge); } + return self.skip(funge) } 107 => { // k - self.advance(&funge); - let n = self.stack.pop(); + self.advance(&funge)?; + let n = cast_int(self.stack.pop())?; let mut ips = vec![self]; for _ in 0..n { let mut new_ips = Vec::new(); @@ -660,12 +713,12 @@ impl IP { 111 => { // o let file = self.read_string()?; let flags = self.stack.pop(); - let x0 = self.stack.pop(); - let y0 = self.stack.pop(); - let width = self.stack.pop(); - let height = self.stack.pop(); + let x0 = cast_int(self.stack.pop())?; + let y0 = cast_int(self.stack.pop())?; + let width: isize = cast_int(self.stack.pop())?; + let height: isize = cast_int(self.stack.pop())?; let mut text = Vec::new(); - if flags % 2 != 0 { + if flags.is_odd() { for x in x0..x0 + width { let mut line = String::new(); for y in y0..y0 + height { @@ -701,7 +754,7 @@ impl IP { if self.stack.is_empty() { self.reverse(); } else { - let n = self.stack.pop(); + let n = cast_int(self.stack.pop())?; let l = self.stack.len_stack(); if n > 0 { for _ in 0..n { @@ -726,15 +779,15 @@ impl IP { } } 120 => { // x - let dy = self.stack.pop(); - let dx = self.stack.pop(); + let dy = cast_int(self.stack.pop())?; + let dx = cast_int(self.stack.pop())?; self.delta = vec![dx, dy]; } 121 => { // y let n = self.stack.pop(); - if n <= 0 { + if n <= I::zero() { for j in 1..21 { - for i in self.get_info(&funge,j) { + for i in self.get_info(&funge,cast_int(j)?) { for cell in i { self.stack.push(cell); } @@ -749,21 +802,15 @@ impl IP { } } 122 => { } // z - d => { - if (48 <= d) & (d <= 57) { // 0123456789 - self.stack.push(d - 48); - } else if (97 <= d) & (d <= 102) { - self.stack.push(d - 87); - } else { - self.not_implemented(&funge); - } - } + 48..=57 => self.stack.push(self.op(&funge) - cast_int(48)?), // 0123456789 + 97..=102 => self.stack.push(self.op(&funge) - cast_int(87)?), // abcdef + _ => self.not_implemented(&funge) } } else { self.not_implemented(&funge); } if !k { - self.advance(&funge); + self.advance(&funge)?; } let mut ips = vec![self]; ips.extend(new_ips); @@ -808,21 +855,21 @@ impl Index<&K> for DefaultHashMap { #[derive(Clone)] -pub struct Funge { +pub struct Funge { extent: Vec, - code: DefaultHashMap, isize>, + code: DefaultHashMap, I>, steps: isize, - ips: Vec, + ips: Vec>, inputs: Input, output: Output, pub terminated: bool } -impl Funge { +impl Funge { pub fn new(code: T) -> Result> { let mut new = Self { - extent: vec![0, 0, 0, 0], - code: DefaultHashMap::new(32), + extent: vec![0; 4], + code: DefaultHashMap::new(cast_int(32)?), steps: 0, ips: Vec::new(), inputs: Input { source: InputEnum::StdIn }, @@ -853,7 +900,7 @@ impl Funge { Ok(self) } - fn insert(&mut self, i: isize, x: isize, y: isize) { + fn insert(&mut self, i: I, x: isize, y: isize) { self.code.insert(vec![x, y], i); } @@ -920,7 +967,7 @@ impl Funge { pos } - fn to_string(&self, show_ips: bool) -> String { + fn get_string(&self, show_ips: bool) -> String { let mut lines = Vec::new(); for (key, value) in (&*self.code).into_iter() { let x= key[0] as usize; @@ -931,7 +978,7 @@ impl Funge { while lines[y].len() <= x { lines[y].push(String::from(" ")); } - if ((&32 <= value) & (value <= &126)) | ((&161 <= value) & (value <= &255)) { + if let Some(32..=126) | Some(161..=255) = value.to_u8() { lines[y][x] = chr(*value).unwrap().to_string(); } else { lines[y][x] = chr(164).unwrap().to_string(); @@ -965,14 +1012,14 @@ impl Funge { } } -impl Display for Funge { +impl Display for Funge { fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { - write!(f, "{}", self.to_string(false)) + write!(f, "{}", self.get_string(false)) } } -impl Debug for Funge { +impl Debug for Funge { fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { - write!(f, "{}", self.to_string(true)) + write!(f, "{}", self.get_string(true)) } } \ No newline at end of file diff --git a/src/main.rs b/src/main.rs index 830a5a2..b2d139b 100644 --- a/src/main.rs +++ b/src/main.rs @@ -14,21 +14,41 @@ struct Args { #[arg(help = "debug, step on key press or steps / second", short, long, value_name = "interval", num_args = 0..=1)] debug: Option>, + #[arg(help = "number of bits in cell and funge values", short, long)] + bits: Option, #[arg(id = "arguments to the funge (& or ~)")] arguments: Vec, } +macro_rules! run { + ($a:expr, $i:ty) => { + let mut funge = Funge::<$i>::from_file(&$a.input)?; + if $a.arguments.len() > 0 { + funge = funge.with_inputs($a.arguments)?; + } + match $a.debug { + Some(interval) => FungeView::new(funge)?.debug(interval).unwrap(), + None => { funge.run()?; } + } + } +} + + fn main() -> Result<(), Box> { let args = Args::parse(); - let mut funge = Funge::from_file(&args.input)?; - if args.arguments.len() > 0 { - funge = funge.with_inputs(args.arguments)?; - } - - match args.debug { - Some(interval) => FungeView::new(funge)?.debug(interval).unwrap(), - None => { funge.run()?; } + if let None = args.bits { + run!(args, isize); + } else if let Some(8) = args.bits { + run!(args, i8); + } else if let Some(16) = args.bits { + run!(args, i16); + } else if let Some(32) = args.bits { + run!(args, i32); + } else if let Some(64) = args.bits { + run!(args, i64); + } else if let Some(128) = args.bits { + run!(args, i128); } Ok(()) } \ No newline at end of file