- Use anyhow to handle errors.

- Debug speed control, pause/run, step back, run until.
- IO is a struct instead of traits.
- Handprint now is wprusty.
- Return code upon q instruction.
- Option to quit when not implemented.
This commit is contained in:
Wim Pomp
2022-12-23 21:38:40 +01:00
parent 6c039c7787
commit d6df8786f8
4 changed files with 419 additions and 191 deletions

View File

@@ -1,6 +1,6 @@
[package] [package]
name = "rusty_funge" name = "rusty_funge"
version = "2022.12.3" version = "2022.12.4"
edition = "2021" edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
@@ -11,3 +11,4 @@ chrono = "0.4.23"
cursive = { version = "0.20.0", features = ["termion-backend"] } cursive = { version = "0.20.0", features = ["termion-backend"] }
rand = "0.8.5" rand = "0.8.5"
num = "0.4.0" num = "0.4.0"
anyhow = "1.0.66"

View File

@@ -1,133 +1,314 @@
use std::cmp::{min, max};
use std::{error::Error, time::Duration};
use std::fmt::{Display, Formatter}; use std::fmt::{Display, Formatter};
use std::sync::{Arc, Mutex}; use std::sync::{Arc, Mutex};
use std::thread::{sleep, spawn}; use std::thread::{spawn, sleep};
use std::time::{Duration, Instant};
use cursive::{Cursive, CursiveExt, Printer, Vec2}; use cursive::{Cursive, CursiveExt, Printer, Vec2};
use cursive::{theme::ColorStyle, view::View}; use cursive::view::View;
use cursive::event::{Event, EventResult}; use cursive::theme::{BorderStyle, ColorStyle, Palette, Theme};
use rusty_funge::{Int, Funge}; use cursive::event::{Event, EventResult, Key};
use rusty_funge::{Int, Funge, join, ord, IO};
use anyhow::Result;
struct FungeMutex<I: Int> { // TODO: Use anyhow::Result
funge: Option<Funge<I>> #[derive(Clone)]
enum FungeError<I: Int> {
Funge(Funge<I>),
Error(String)
} }
impl<I: Int> FungeMutex<I> {
struct FungeDebug<I: Int> {
funge: Option<FungeError<I>>,
history: Vec<Funge<I>>,
interval: f64,
running: bool,
stop_op: Option<I>
}
impl<I: Int> FungeDebug<I> {
fn new(funge: Funge<I>) -> Self { fn new(funge: Funge<I>) -> Self {
Self { funge: Some(funge) } Self {
funge: Some(FungeError::Funge(funge)),
history: Vec::new(),
interval: 0.05,
running: false,
stop_op: None
}
} }
fn step(&mut self) -> Result<bool, Box<dyn Error>> { fn step_back(&mut self) {
let mut funge = self.funge.to_owned().ok_or("No funge found")?; match self.history.pop() {
if !funge.terminated { Some(funge) => {
funge = funge.step()?; self.running = false;
self.funge = Some(FungeError::Funge(funge));
}
None => {}
} }
let terminated = funge.terminated;
self.funge = Some(funge);
Ok(terminated)
} }
fn funge_ref(&self) -> Option<&Funge<I>> { fn is_terminated(&self) -> bool {
self.funge.as_ref() match &self.funge {
Some(FungeError::Funge(f)) if !f.terminated => false,
_ => true
}
}
fn step(&mut self) {
match self.funge.to_owned() {
Some(FungeError::Funge(funge)) if !funge.terminated => {
self.history.push(funge.clone());
if self.history.len() > 16384 {
self.history.remove(0);
}
match funge.step() {
Ok(f) => self.funge = Some(FungeError::Funge(f)),
Err(e) => {
self.funge = Some(FungeError::Error(e.to_string()))
}
}
}
Some(f) => self.funge = Some(f),
None => {}
}
} }
} }
impl<I: Int> Display for FungeMutex<I> { impl<I: Int> Display for FungeDebug<I> {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
write!(f, "{}", self.funge.as_ref().expect("No funge found")) match self.funge.as_ref().expect("No funge found") {
FungeError::Funge(funge) => write!(f, "{}", funge),
FungeError::Error(e) => write!(f, "{}", e)
}
} }
} }
pub(crate) struct FungeView<I: Int> { pub(crate) struct FungeView<I: Int> {
funge: Arc<Mutex<FungeMutex<I>>> funge: Arc<Mutex<FungeDebug<I>>>
} }
impl<I: Int> FungeView<I> { impl<I: Int> FungeView<I> {
pub (crate) fn new(funge: Funge<I>) -> Result<Self, Box<dyn Error>> { pub (crate) fn new(funge: Funge<I>, input: Vec<String>) -> Result<Self> {
Ok(FungeView { funge: Arc::new(Mutex::new(FungeMutex::new(funge.with_output()?))) } ) Ok(FungeView { funge: Arc::new(Mutex::new(FungeDebug::new(
funge.with_input(IO::new()
.with_store(input)
.with_input(|store| {
Ok(match store.pop() {
None => String::from("5"), // TODO: cursive input
Some(s) => s
})
})).with_output(IO::new()
.with_output(|store, s| {
Ok(store.push(s))
})))))
})
} }
fn step(&mut self) -> Result<bool, Box<dyn Error>> { fn step_back(&mut self) {
self.funge.lock().unwrap().step() match self.funge.lock() {
Ok(mut f) => f.step_back(),
Err(_) => {}
}
} }
fn get_mutex(&self) -> Self { fn step(&mut self) {
match self.funge.lock() {
Ok(mut f) => f.step(),
Err(_) => {}
}
}
pub fn step_n(&mut self, n: usize) {
match self.funge.lock() {
Ok(mut funge) => {
for _ in 0..n {
funge.step();
if funge.is_terminated() { break }
}
}
Err(_) => {}
}
}
fn new_mutex(&self) -> Self {
Self { funge: Arc::clone(&self.funge) } Self { funge: Arc::clone(&self.funge) }
} }
pub(crate) fn debug(self, interval: Option<f64>) -> Result<(), Box<dyn Error>> { fn is_running(&self) -> bool {
match self.funge.lock() {
Ok(mut funge) => {
if funge.is_terminated() | !funge.running { return false }
if let Some(op) = funge.stop_op {
match funge.funge.as_ref() {
Some(FungeError::Funge(f)) => {
for pos in f.ips_pos() {
if f.code[&pos] == op {
funge.stop_op = None;
funge.running = false;
return false
}
}
}
Some(FungeError::Error(_)) => {
funge.running = false;
return false
}
None => return false
}
}
true
}
Err(_) => false
}
}
fn toggle_run(&self) {
let running = { self.funge.lock().unwrap().running };
match running {
true => self.pause(),
false => self.run()
}
}
fn pause(&self) {
self.funge.lock().unwrap().running = false;
}
fn run(&self) {
let mut funge_mutex = self.new_mutex();
{ funge_mutex.funge.lock().unwrap().running = true; }
spawn(move || {
loop {
let instant = Instant::now();
funge_mutex.step();
let duration = Duration::from_micros(match funge_mutex.funge.lock() {
Ok(f) => (f.interval * 1e6) as u64,
Err(_) => 100000
});
if !funge_mutex.is_running() {
funge_mutex.funge.lock().unwrap().running = false;
break
}
let sleep_time = duration - instant.elapsed();
if sleep_time.as_secs_f64() > 0f64 { sleep(duration) }
}
});
}
pub(crate) fn debug(self, interval: Option<f64>) {
let mut app = Cursive::new(); let mut app = Cursive::new();
match interval { match interval {
None => {} None => {}
Some(interval) => { Some(interval) => {
let duration = Duration::from_micros((interval * 1e6) as u64); { self.funge.lock().unwrap().interval = interval; }
let mut funge_mutex = self.get_mutex(); self.toggle_run();
app.set_fps(max((1f64 / interval) as u32, 50));
spawn(move || {
loop {
sleep(duration);
match funge_mutex.step() {
Ok(terminated) => if terminated { break },
Err(_) => break
}
}
});
} }
} }
app.add_layer(self); app.add_layer(self);
app.add_global_callback('q', |app| app.quit()); app.add_global_callback(Key::Esc, |app| app.quit());
app.set_autorefresh(true);
app.set_theme(Theme { shadow: false, borders: BorderStyle::None, palette: Palette::default() });
app.run(); app.run();
Ok(())
} }
} }
impl<I: Int> View for FungeView<I> { impl<I: Int> View for FungeView<I> {
fn draw(&self, printer: &Printer) { fn draw(&self, printer: &Printer) {
let (text, ips_pos, terminated) = { match self.funge.lock().as_ref() {
let lock = self.funge.lock(); Ok(funge_mutex) => {
let funge = lock.as_ref().unwrap().funge_ref().unwrap(); let hist_len = funge_mutex.history.len();
(format!("{}", funge), funge.ips_pos(), funge.terminated) let running = funge_mutex.running;
}; match funge_mutex.funge.as_ref() {
Some(FungeError::Funge(funge)) => {
let text = format!("{}", funge);
let lines: Vec<&str> = text.lines().collect(); let lines: Vec<&str> = text.lines().collect();
for (i, line) in lines.iter().enumerate() { for (i, line) in lines.iter().enumerate() {
printer.print((0, i), line); printer.print((0, i), line);
} }
for pos in ips_pos.iter() { for pos in funge.ips_pos().iter() {
if (pos[0] >= 0) & (pos[1] >= 0) { if (pos[0] >= 0) & (pos[1] >= 0) {
let x = pos[0] as usize; let x = pos[0] as usize;
let y = pos[1] as usize + 1; let y = pos[1] as usize + 1;
printer.with_color(ColorStyle::highlight(), |printer| printer.print((x, y), &*lines[y].chars().nth(x).unwrap().to_string())); printer.with_color(ColorStyle::highlight(),
|printer| {
match lines[y].chars().nth(x) {
None => {}
Some(l) => printer.print((x, y), &*l.to_string())
}
});
} }
} }
let mut bottom = String::from("Press 'q' to quit"); let n = lines.len() + 1;
if terminated {
bottom.push_str("."); let mut text = vec!["esc: quit"];
if hist_len > 0 {
text.push("backspace: back");
}
if running {
text.push("space: pause")
} else { } else {
bottom.push_str(", any other key to continue."); text.push("space: run")
}
if !funge.terminated {
text.push("enter: step")
}
let interval = format!("interval: {} up/down arrow", funge_mutex.interval);
text.push(&*interval);
printer.print((0, n + 1), &*join(&text, ", "));
}
Some(FungeError::Error(e)) => {
printer.print((0, 0), "Error occured:");
printer.print((0, 1), &*format!("{}", e));
printer.print((0, 3), "esc: quit, backspace: back");
}
None => {}
}
}
Err(_) => {}
} }
printer.print((0, lines.len() + 1), &*bottom);
} }
fn required_size(&mut self, constraint: Vec2) -> Vec2 { fn required_size(&mut self, constraint: Vec2) -> Vec2 {
let text = format!("{}", self.funge.lock().as_ref().unwrap()); constraint
let x = match text.lines().map(|line| line.len()).collect::<Vec<usize>>().iter().max() {
None => 0,
Some(x) => *x
};
Vec2::new(min(max(80, x), constraint.x), min(max(25, text.lines().count() + 2), constraint.y))
} }
fn on_event(&mut self, event: Event) -> EventResult { fn on_event(&mut self, event: Event) -> EventResult {
match event { match event {
Event::Char('q') => EventResult::Ignored, Event::Key(Key::Esc) => EventResult::Ignored,
Event::Char(_) => { Event::Key(Key::Backspace) => {
self.step().ok(); self.step_back();
EventResult::Consumed(None) EventResult::Consumed(None)
} }
Event::Key(_) => { Event::Char(' ') => {
self.step().ok(); self.toggle_run();
EventResult::Consumed(None)
}
Event::Key(Key::Enter) => {
self.step();
EventResult::Consumed(None)
}
Event::Key(Key::Up) => {
let lock = self.funge.lock();
let mut funge = lock.unwrap();
let interval = funge.interval / 2.0;
if interval < 0.01 {
funge.interval = 0.01;
} else {
funge.interval = interval;
}
EventResult::Consumed(None)
}
Event::Key(Key::Down) => {
self.funge.lock().unwrap().interval *= 2.0;
EventResult::Consumed(None)
}
Event::Char(c) => {
match ord(c) {
Ok(i) => self.funge.lock().unwrap().stop_op = Some(i),
Err(_) => {}
}
self.run();
EventResult::Consumed(None) EventResult::Consumed(None)
} }
_ => EventResult::Ignored _ => EventResult::Ignored

View File

@@ -1,10 +1,11 @@
use std::collections::HashMap; use std::collections::HashMap;
use std::{env, fs, fmt, fmt::{Debug, Display, Formatter}}; use std::{env, fs, fmt, fmt::{Debug, Display, Formatter}};
use std::ops::{Add, Deref, DerefMut, Index, IndexMut, Sub}; use std::ops::{Add, Deref, DerefMut, Index, IndexMut, Sub};
use std::{error::Error, hash::Hash, path::Path, str::FromStr, io::stdin}; use std::{hash::Hash, path::Path, str::FromStr, io::stdin};
use chrono::{offset::Local, {Datelike, Timelike}}; use chrono::{offset::Local, {Datelike, Timelike}};
use rand::Rng; use rand::Rng;
use num::{Integer, NumCast}; use num::{Integer, NumCast};
use anyhow::{Error, Result};
const VERSION: &str = env!("CARGO_PKG_VERSION"); const VERSION: &str = env!("CARGO_PKG_VERSION");
@@ -14,7 +15,7 @@ pub trait Int: Integer + NumCast + FromStr + Hash + Clone + Copy + Sync + Send +
impl<I: Integer + NumCast + FromStr + Hash + Clone + Copy + Sync + Send + Display + 'static> Int for I {} impl<I: Integer + NumCast + FromStr + Hash + Clone + Copy + Sync + Send + Display + 'static> Int for I {}
fn join<T: ToString>(v: &Vec<T>, s: &str) -> String { pub fn join<T: ToString>(v: &Vec<T>, s: &str) -> String {
let mut string = String::new(); let mut string = String::new();
if v.len() > 1 { if v.len() > 1 {
for i in 0..v.len() - 1 { for i in 0..v.len() - 1 {
@@ -28,11 +29,11 @@ fn join<T: ToString>(v: &Vec<T>, s: &str) -> String {
string string
} }
fn cast_int<I: NumCast, J: NumCast>(j: J) -> Result<I, Box<dyn Error>> { fn cast_int<I: NumCast, J: NumCast>(j: J) -> Result<I> {
Ok(I::from(j).ok_or("Could not convert from primitive")?) Ok(I::from(j).ok_or(Error::msg("Could not convert from primitive"))?)
} }
fn cast_vec_int<I: NumCast, J: NumCast>(j: Vec<J>) -> Result<Vec<I>, Box<dyn Error>> { fn cast_vec_int<I: NumCast, J: NumCast>(j: Vec<J>) -> Result<Vec<I>> {
let mut i = Vec::<I>::new(); let mut i = Vec::<I>::new();
for n in j { for n in j {
i.push(cast_int(n)?); i.push(cast_int(n)?);
@@ -40,12 +41,11 @@ fn cast_vec_int<I: NumCast, J: NumCast>(j: Vec<J>) -> Result<Vec<I>, Box<dyn Err
Ok(i) Ok(i)
} }
fn ord<I: NumCast>(c: char) -> Result<I, Box<dyn Error>> pub fn ord<I: NumCast>(c: char) -> Result<I> {
{
Ok(cast_int::<_, u32>(c.try_into()?)?) Ok(cast_int::<_, u32>(c.try_into()?)?)
} }
fn chr<I: NumCast>(i: I) -> Result<char, Box<dyn Error>> { fn chr<I: NumCast>(i: I) -> Result<char> {
Ok(cast_int::<u32, _>(i)?.try_into()?) Ok(cast_int::<u32, _>(i)?.try_into()?)
} }
@@ -61,50 +61,63 @@ fn sub<I: Sub + Copy>(a: &Vec<I>, b: &Vec<I>) -> Vec<I> where
#[derive(Clone)] #[derive(Clone)]
enum InputEnum { pub struct IO {
StdIn, store: Vec<String>,
Vector(Vec<String>) input: fn(&mut Vec<String>) -> Result<String>,
output: fn(&mut Vec<String>, String) -> Result<()>
} }
#[derive(Clone)] impl IO {
struct Input { pub fn new() -> Self {
source: InputEnum Self {
} store: Vec::new(),
input: |store| {
impl Input { Ok(match store.pop() {
fn get(&mut self) -> Result<String, Box<dyn Error>> { None => {
Ok(match self.source {
InputEnum::StdIn => {
let mut s = String::new(); let mut s = String::new();
stdin().read_line(&mut s)?; stdin().read_line(&mut s)?;
s s
} }
InputEnum::Vector(ref mut v) => v.pop().ok_or("No more input!")? Some(s) => s
}) })
},
output: |_, s| {
print!("{}", s);
Ok(())
}
}
}
pub fn with_store(mut self, mut store: Vec<String>) -> Self {
store.reverse();
self.store = store;
self
}
pub fn with_input(mut self, fun: fn(&mut Vec<String>) -> Result<String>) -> Self {
self.input = fun;
self
}
pub fn with_output(mut self, fun: fn(&mut Vec<String>, String) -> Result<()>) -> Self {
self.output = fun;
self
}
fn pop(&mut self) -> Result<String> {
(self.input)(&mut self.store)
}
fn push(&mut self, s: String) -> Result<()> {
(self.output)(&mut self.store, s)
}
pub fn get(&self) -> String {
join(&self.store, "")
} }
} }
#[derive(Clone)]
enum OutputEnum {
StdOut,
Vector(Vec<String>)
}
#[derive(Clone)]
struct Output {
sink: OutputEnum
}
impl Output {
fn print(&mut self, string: String) {
match self.sink {
OutputEnum::StdOut => print!("{}", string),
OutputEnum::Vector(ref mut v) => v.push(string)
}
}
}
#[derive(Clone)] #[derive(Clone)]
struct Stack<I: Int> { struct Stack<I: Int> {
@@ -229,11 +242,11 @@ impl<I: Int> Display for StackStack<I> {
#[derive(Clone)] #[derive(Clone)]
struct IP<I: Int> { pub struct IP<I: Int> { // TODO, getter fns in funge instead of pubs
id: usize, id: usize,
position: Vec<isize>, position: Vec<isize>,
delta: Vec<isize>, delta: Vec<isize>,
offset: Vec<isize>, pub offset: Vec<isize>,
string: bool, string: bool,
stack: StackStack<I>, stack: StackStack<I>,
fingerprint_ops: HashMap<I, ()>, fingerprint_ops: HashMap<I, ()>,
@@ -241,7 +254,7 @@ struct IP<I: Int> {
impl<I: Int> IP<I> { impl<I: Int> IP<I> {
fn new(funge: &Funge<I>) -> Result<Self, Box<dyn Error>> { fn new(funge: &Funge<I>) -> Result<Self> {
let mut new = IP { let mut new = IP {
id: funge.ips.len(), id: funge.ips.len(),
position: vec![0, 0], position: vec![0, 0],
@@ -285,7 +298,7 @@ impl<I: Int> IP<I> {
self.delta = vec![self.delta[1], -self.delta[0]]; self.delta = vec![self.delta[1], -self.delta[0]];
} }
fn advance(&mut self, funge: &Funge<I>) -> Result<(), Box<dyn Error>> { fn advance(&mut self, funge: &Funge<I>) -> Result<()> {
let space: I = cast_int(32)?; let space: I = cast_int(32)?;
let semicolon: I = cast_int(59)?; let semicolon: I = cast_int(59)?;
Ok(if self.string { Ok(if self.string {
@@ -322,7 +335,7 @@ impl<I: Int> IP<I> {
self.position = self.next_pos(funge); self.position = self.next_pos(funge);
} }
fn skip(mut self, funge: Funge<I>) -> Result<(Funge<I>, Option<Vec<Self>>), Box<dyn Error>> { fn skip(mut self, funge: Funge<I>) -> Result<(Funge<I>, Option<Vec<Self>>)> {
self.movep(&funge); self.movep(&funge);
if let Ok(32 | 59) = cast_int(self.op(&funge)) { if let Ok(32 | 59) = cast_int(self.op(&funge)) {
self.advance(&funge)?; self.advance(&funge)?;
@@ -349,7 +362,7 @@ impl<I: Int> IP<I> {
pos pos
} }
fn read_string(&mut self) -> Result<String, Box<dyn Error>> { fn read_string(&mut self) -> Result<String> {
let mut string = String::new(); let mut string = String::new();
loop { loop {
let f = self.stack.pop(); let f = self.stack.pop();
@@ -361,7 +374,7 @@ impl<I: Int> IP<I> {
} }
} }
fn get_info(&self, funge: &Funge<I>, n: I) -> Result<Vec<I>, Box<dyn Error>> { fn get_info(&self, funge: &Funge<I>, n: I) -> Result<Vec<I>> {
let time = Local::now(); let time = Local::now();
match n.to_usize() { match n.to_usize() {
Some(n @ 1..=20) => { Some(n @ 1..=20) => {
@@ -370,7 +383,7 @@ impl<I: Int> IP<I> {
2 => vec![cast_int(8 * std::mem::size_of::<I>())?], 2 => vec![cast_int(8 * std::mem::size_of::<I>())?],
3 => { 3 => {
let mut f = 0; let mut f = 0;
for (i, c) in "wprustyfunge".chars().enumerate() { for (i, c) in "wprusty".chars().enumerate() {
f += (256 as isize).pow(i as u32) * ord::<isize>(c)?; f += (256 as isize).pow(i as u32) * ord::<isize>(c)?;
} }
vec![cast_int(f)?] vec![cast_int(f)?]
@@ -410,8 +423,8 @@ impl<I: Int> IP<I> {
r.push(I::zero()); r.push(I::zero());
let file = &args[0]; let file = &args[0];
let path = Path::new(&file); let path = Path::new(&file);
let j: Vec<I> = path.file_name().ok_or("No file name.")? let j: Vec<I> = path.file_name().ok_or(Error::msg("No file name."))?
.to_str().ok_or("Cannot convert String.")? .to_str().ok_or(Error::msg("Cannot convert String."))?
.chars().map(|i| ord(i).expect("")).collect(); .chars().map(|i| ord(i).expect("")).collect();
r.extend(j); r.extend(j);
r.push(I::zero()); r.push(I::zero());
@@ -445,21 +458,21 @@ impl<I: Int> IP<I> {
} }
}) })
} }
_ => { _ => Err(Error::msg("Stack size overflow"))
// TODO: return Error
println!("{}", "Stack size overflow");
Ok(Vec::new())
}
} }
} }
fn not_implemented(&mut self, funge: &Funge<I>) { fn not_implemented(mut self, funge: &Funge<I>) -> Option<Self> {
// TODO: reverse or quit option match funge.on_error {
println!("operator {} at {} not implemented", self.op(funge), join(&self.position, ", ")); OnError::Reverse => {
self.reverse() self.reverse();
Some(self)
}
OnError::Quit => None
}
} }
fn step(mut self, mut funge: Funge<I>, k: bool) -> Result<(Funge<I>, Option<Vec<Self>>), Box<dyn Error>> { fn step(mut self, mut funge: Funge<I>, k: bool) -> Result<(Funge<I>, Option<Vec<Self>>)> {
let mut new_ips = Vec::new(); let mut new_ips = Vec::new();
let op = self.op(&funge); let op = self.op(&funge);
let op8 = op.to_u8(); let op8 = op.to_u8();
@@ -558,8 +571,8 @@ impl<I: Int> IP<I> {
self.stack.push(b); self.stack.push(b);
} }
36 => { self.stack.pop(); } // $ 36 => { self.stack.pop(); } // $
46 => funge.output.print(format!("{} ", self.stack.pop())), // . 46 => funge.output.push(format!("{} ", self.stack.pop()))?,
44 => funge.output.print(format!("{}", chr(self.stack.pop())?)), // , 44 => funge.output.push(format!("{}", chr(self.stack.pop())?))?, // ,
35 => { // # 35 => { // #
self.movep(&funge); self.movep(&funge);
return self.skip(funge) return self.skip(funge)
@@ -576,18 +589,18 @@ impl<I: Int> IP<I> {
self.stack.push(*&funge.code[&vec![x + self.offset[0], y + self.offset[1]]]); self.stack.push(*&funge.code[&vec![x + self.offset[0], y + self.offset[1]]]);
} }
38 => { // & 38 => { // &
let s = funge.inputs.get()?; let s = funge.input.pop()?;
let i: Vec<char> = s.chars() let i: Vec<char> = s.chars()
.skip_while(|i| !i.is_digit(10)) .skip_while(|i| !i.is_digit(10))
.take_while(|i| i.is_digit(10)).collect(); .take_while(|i| i.is_digit(10)).collect();
match join(&i, "").parse() { match join(&i, "").parse() {
Ok(n) => self.stack.push(n), Ok(n) => self.stack.push(n),
_ => println!("Cannot convert input to number.") // TODO: Error _ => Err(Error::msg("Cannot convert input to number."))?
} }
} }
126 => { // ~ 126 => { // ~
let s = funge.inputs.get()?; let s = funge.input.pop()?;
self.stack.push(ord(s.chars().nth(0).ok_or("No valid input.")?)?); self.stack.push(ord(s.chars().nth(0).ok_or(Error::msg("No valid input."))?)?);
} }
64 => { return Ok((funge, Some(Vec::new()))); } // @ 64 => { return Ok((funge, Some(Vec::new()))); } // @
32 => { // space 32 => { // space
@@ -649,7 +662,7 @@ impl<I: Int> IP<I> {
} }
40 => { // ( no fingerprints are implemented 40 => { // ( no fingerprints are implemented
// self.read_fingerprint(); // self.read_fingerprint();
// self.fingerprint_ops[] = self.reverse; // self.fingerprint_ops[] = self.Reverse;
self.reverse(); self.reverse();
} }
41 => { // ) 41 => { // )
@@ -670,7 +683,7 @@ impl<I: Int> IP<I> {
} else { } else {
let text: Vec<&str> = text.lines().collect(); let text: Vec<&str> = text.lines().collect();
let height = text.len(); let height = text.len();
let width = text.iter().map(|i| i.len()).min().ok_or("Cannot calculate width.")?; let width = text.iter().map(|i| i.len()).min().ok_or(Error::msg("Cannot calculate width."))?;
let mut code: Vec<String> = Vec::new(); let mut code: Vec<String> = Vec::new();
for line in text { for line in text {
let a = format!("{}{}", line, join(&vec![" "; width - line.len()], "")); let a = format!("{}{}", line, join(&vec![" "; width - line.len()], ""));
@@ -739,7 +752,10 @@ impl<I: Int> IP<I> {
let text = join(&text, "\n"); let text = join(&text, "\n");
fs::write(file, text)?; fs::write(file, text)?;
} }
113 => { return Ok((funge, None)) } // q 113 => {
funge.return_code = cast_int(self.stack.pop())?;
return Ok((funge, None))
} // q
114 => self.reverse(), // r 114 => self.reverse(), // r
115 => { // s 115 => { // s
self.movep(&funge); self.movep(&funge);
@@ -804,10 +820,16 @@ impl<I: Int> IP<I> {
122 => { } // z 122 => { } // z
48..=57 => self.stack.push(self.op(&funge) - cast_int(48)?), // 0123456789 48..=57 => self.stack.push(self.op(&funge) - cast_int(48)?), // 0123456789
97..=102 => self.stack.push(self.op(&funge) - cast_int(87)?), // abcdef 97..=102 => self.stack.push(self.op(&funge) - cast_int(87)?), // abcdef
_ => self.not_implemented(&funge) _ => self = match self.not_implemented(&funge) {
Some(ip) => ip,
None => return Ok((funge, None))
}
} }
} else { } else {
self.not_implemented(&funge); self = match self.not_implemented(&funge) {
Some(ip) => ip,
None => return Ok((funge, None))
}
} }
if !k { if !k {
self.advance(&funge)?; self.advance(&funge)?;
@@ -820,7 +842,7 @@ impl<I: Int> IP<I> {
#[derive(Clone)] #[derive(Clone)]
struct DefaultHashMap<K: Eq + Hash, V: Clone> { pub struct DefaultHashMap<K: Eq + Hash, V: Clone> {
hashmap: HashMap<K, V>, hashmap: HashMap<K, V>,
default: V default: V
} }
@@ -854,30 +876,42 @@ impl<K: Eq + Hash, V: Clone> Index<&K> for DefaultHashMap<K, V> {
} }
#[derive(Clone)]
enum OnError {
Reverse,
#[allow(dead_code)]
Quit,
}
#[derive(Clone)] #[derive(Clone)]
pub struct Funge<I: Int> { pub struct Funge<I: Int> {
extent: Vec<isize>, pub extent: Vec<isize>,
code: DefaultHashMap<Vec<isize>, I>, pub code: DefaultHashMap<Vec<isize>, I>,
steps: isize, pub steps: isize,
ips: Vec<IP<I>>, pub ips: Vec<IP<I>>,
inputs: Input, pub input: IO,
output: Output, pub output: IO,
pub terminated: bool pub terminated: bool,
pub return_code: i32,
on_error: OnError
} }
impl<I: Int> Funge<I> { impl<I: Int> Funge<I> {
pub fn new<T: ToString>(code: T) -> Result<Self, Box<dyn Error>> { pub fn new<T: ToString>(code: T) -> Result<Self> {
let mut new = Self { let mut new = Self {
extent: vec![0; 4], extent: vec![0; 4],
code: DefaultHashMap::new(cast_int(32)?), code: DefaultHashMap::new(cast_int(32)?),
steps: 0, steps: 0,
ips: Vec::new(), ips: Vec::new(),
inputs: Input { source: InputEnum::StdIn }, input: IO::new(),
output: Output { sink: OutputEnum::StdOut }, output: IO::new(),
terminated: false terminated: false,
return_code: 0,
on_error: OnError::Reverse
}; };
let mut code: Vec<String> = code.to_string().lines().map(|i| String::from(i)).collect(); let mut code: Vec<String> = code.to_string().lines().map(|i| String::from(i)).collect();
let exe = env::current_exe()?.file_name().ok_or("No exe name")?.to_str().unwrap().to_string(); let exe = env::current_exe()?.file_name().ok_or(Error::msg("No exe name"))?.to_str().unwrap().to_string();
if code[0].starts_with(&*format!(r"#!/usr/bin/env {}", exe)) | code[0].starts_with(&*format!(r"#!/usr/bin/env -S {}", exe)) { if code[0].starts_with(&*format!(r"#!/usr/bin/env {}", exe)) | code[0].starts_with(&*format!(r"#!/usr/bin/env -S {}", exe)) {
code.remove(0); code.remove(0);
} }
@@ -886,25 +920,30 @@ impl<I: Int> Funge<I> {
Ok(new) Ok(new)
} }
pub fn from_file(file: &String) -> Result<Self, Box<dyn Error>> { pub fn from_file(file: &String) -> Result<Self> {
Ok(Self::new(fs::read_to_string(file)?)?) Ok(Self::new(fs::read_to_string(file)?)?)
} }
pub fn with_inputs(mut self, inputs: Vec<String>) -> Result<Self, Box<dyn Error>> { pub fn with_arguments(mut self, args: Vec<String>) -> Self {
self.inputs = Input { source: InputEnum::Vector(inputs) }; self.input = IO::new().with_store(args);
Ok(self) self
} }
pub fn with_output(mut self) -> Result<Self, Box<dyn Error>> { pub fn with_input(mut self, input: IO) -> Self {
self.output = Output { sink: OutputEnum::Vector(Vec::new()) }; self.input = input;
Ok(self) self
}
pub fn with_output(mut self, output: IO) -> Self {
self.output = output;
self
} }
fn insert(&mut self, i: I, x: isize, y: isize) { fn insert(&mut self, i: I, x: isize, y: isize) {
self.code.insert(vec![x, y], i); self.code.insert(vec![x, y], i);
} }
fn insert_code(&mut self, code: Vec<String>, x0: isize, y0: isize) -> Result<(), Box<dyn Error>> { fn insert_code(&mut self, code: Vec<String>, x0: isize, y0: isize) -> Result<()> {
for (y, line) in code.iter().enumerate() { for (y, line) in code.iter().enumerate() {
for (x, char) in line.chars().enumerate() { for (x, char) in line.chars().enumerate() {
let x1: isize = x.try_into()?; let x1: isize = x.try_into()?;
@@ -926,14 +965,14 @@ impl<I: Int> Funge<I> {
Ok(()) Ok(())
} }
pub fn run(mut self) -> Result<Self, Box<dyn Error>>{ pub fn run(mut self) -> Result<Self>{
while !self.terminated { while !self.terminated {
self = self.step()?; self = self.step()?;
} }
Ok(self) Ok(self)
} }
pub fn step(mut self) -> Result<Self, Box<dyn Error>> { pub fn step(mut self) -> Result<Self> {
if !self.terminated { if !self.terminated {
self.ips.reverse(); self.ips.reverse();
let mut new_ips = Vec::new(); let mut new_ips = Vec::new();
@@ -998,13 +1037,12 @@ impl<I: Int> Funge<I> {
string.push_str("\n\nstacks:\n"); string.push_str("\n\nstacks:\n");
string.push_str(&join(&(&self.ips).iter().map(|ip| ip.stack.to_string()).collect(), "\n")); string.push_str(&join(&(&self.ips).iter().map(|ip| ip.stack.to_string()).collect(), "\n"));
match &self.output.sink { string.push_str("\n\nIP offset:\n");
OutputEnum::StdOut => { }, string.push_str(&*join(&self.ips.iter().map(|ip| join(&ip.offset, ", ")).collect(), "; "));
OutputEnum::Vector(v) => {
string.push_str("\n\nOutput:\n");
string.push_str(&join(&v, "")); string.push_str("\n\nOutput\n");
} string.push_str(&self.output.get());
};
string.push_str("\n\nsteps:\n"); string.push_str("\n\nsteps:\n");
string.push_str(&self.steps.to_string()); string.push_str(&self.steps.to_string());

View File

@@ -1,9 +1,9 @@
mod debug; mod debug;
use std::error::Error;
use clap::Parser; use clap::Parser;
use rusty_funge::Funge; use rusty_funge::Funge;
use debug::FungeView; use debug::FungeView;
use anyhow::Result;
#[derive(Parser)] #[derive(Parser)]
@@ -16,6 +16,8 @@ struct Args {
debug: Option<Option<f64>>, debug: Option<Option<f64>>,
#[arg(help = "number of bits in cell and funge values", short, long)] #[arg(help = "number of bits in cell and funge values", short, long)]
bits: Option<u8>, bits: Option<u8>,
#[arg(help = "skip steps", short, long)]
steps: Option<usize>,
#[arg(id = "arguments to the funge (& or ~)")] #[arg(id = "arguments to the funge (& or ~)")]
arguments: Vec<String>, arguments: Vec<String>,
} }
@@ -24,18 +26,24 @@ struct Args {
macro_rules! run { macro_rules! run {
($a:expr, $i:ty) => { ($a:expr, $i:ty) => {
let mut funge = Funge::<$i>::from_file(&$a.input)?; let mut funge = Funge::<$i>::from_file(&$a.input)?;
if $a.arguments.len() > 0 {
funge = funge.with_inputs($a.arguments)?;
}
match $a.debug { match $a.debug {
Some(interval) => FungeView::new(funge)?.debug(interval).unwrap(), Some(interval) => {
None => { funge.run()?; } let mut funge = FungeView::new(funge, $a.arguments)?;
if let Some(s) = $a.steps {
funge.step_n(s);
}
funge.debug(interval);
}
None => {
funge = funge.with_arguments($a.arguments).run()?;
std::process::exit(funge.return_code);
}
} }
} }
} }
fn main() -> Result<(), Box<dyn Error>> { fn main() -> Result<()> {
let args = Args::parse(); let args = Args::parse();
if let None = args.bits { if let None = args.bits {
run!(args, isize); run!(args, isize);