- 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:
@@ -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"
|
||||||
311
src/debug.rs
311
src/debug.rs
@@ -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
|
||||||
|
|||||||
242
src/lib.rs
242
src/lib.rs
@@ -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());
|
||||||
|
|||||||
22
src/main.rs
22
src/main.rs
@@ -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);
|
||||||
|
|||||||
Reference in New Issue
Block a user