created react app but not actually started doing anything nice

This commit is contained in:
nora 2021-06-18 16:11:51 +02:00
parent 812e492640
commit 3ee494fed9
39 changed files with 12654 additions and 925 deletions

8
bfi-rust/.gitignore vendored
View file

@ -1,5 +1,5 @@
/target
.idea
# brainfuck testing code, get your own
*.b
/target
.idea
# brainfuck testing code, get your own
*.b
*.bf

View file

@ -1,13 +1,13 @@
[package]
name = "bfinterpreter"
version = "0.1.1"
authors = ["Nilstrieb <nilstrieb@gmail.com>"]
edition = "2018"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
[profile.dev]
[package]
name = "bfinterpreter"
version = "0.1.1"
authors = ["Nilstrieb <nilstrieb@gmail.com>"]
edition = "2018"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
[profile.dev]
opt-level = 3

View file

@ -1,96 +1,96 @@
use crate::interpreter::optimized::PrintMode;
use std::str::Chars;
pub mod simple;
pub mod parsed;
pub mod optimized;
pub const MEM_SIZE: usize = 0xFFFF;
pub type Memory = [u8; MEM_SIZE];
#[derive(Debug, PartialOrd, PartialEq, Ord, Eq, Clone)]
pub enum Statement {
Inc,
Dec,
R,
L,
Out,
DOut,
In,
Loop(Vec<Statement>),
}
const ALLOWED_CHARS: [char; 8] = ['>', '<', '+', '-', '.', ',', '[', ']'];
pub fn minify(code: &str) -> String {
code.chars().filter(|c| ALLOWED_CHARS.contains(c)).collect()
}
pub fn parse(chars: Chars, print_mode: PrintMode) -> Vec<Statement> {
let mut loop_stack = vec![vec![]];
for c in chars {
match c {
'+' => loop_stack.last_mut().unwrap().push(Statement::Inc),
'-' => loop_stack.last_mut().unwrap().push(Statement::Dec),
'>' => loop_stack.last_mut().unwrap().push(Statement::R),
'<' => loop_stack.last_mut().unwrap().push(Statement::L),
'.' => {
match print_mode {
PrintMode::ToString => loop_stack.last_mut().unwrap().push(Statement::Out),
PrintMode::DirectPrint => loop_stack.last_mut().unwrap().push(Statement::DOut)
}
}
',' => loop_stack.last_mut().unwrap().push(Statement::In),
'[' => loop_stack.push(vec![]),
']' => {
let statement = Statement::Loop(loop_stack.pop().unwrap());
loop_stack.last_mut().unwrap().push(statement);
}
_ => ()
}
}
loop_stack.pop().unwrap()
}
#[cfg(test)]
mod tests {
use crate::interpreter::{parse, minify};
use crate::interpreter::Statement::{Dec, In, Inc, L, Loop, Out, R};
#[test]
fn minify_test() {
let program = "sdahf+saga-46<sgbv>a[r]r.hr,e";
let expected = "+-<>[].,";
assert_eq!(String::from(expected), minify(program));
}
#[test]
fn parse_no_loop() {
let program = "+-<>,.";
let statements = vec![Inc, Dec, L, R, In, Out];
let result = parse(program.chars().collect(), false);
assert_eq!(statements, result);
}
#[test]
fn parse_simple_loop() {
let program = "+[<<]-";
let statements = vec![Inc, Loop(vec![L, L]), Dec];
let result = parse(program.chars().collect(), false);
assert_eq!(statements, result);
}
#[test]
fn parse_complex_loops() {
let program = ">[<[][<[<]>]>[>]]";
let statements = vec![R, Loop(vec![L, Loop(vec![]), Loop(vec![L, Loop(vec![L]), R]), R, Loop(vec![R])])];
let result = parse(program.chars().collect(), false);
assert_eq!(statements, result);
}
use crate::interpreter::optimized::PrintMode;
use std::str::Chars;
pub mod simple;
pub mod parsed;
pub mod optimized;
pub const MEM_SIZE: usize = 0xFFFF;
pub type Memory = [u8; MEM_SIZE];
#[derive(Debug, PartialOrd, PartialEq, Ord, Eq, Clone)]
pub enum Statement {
Inc,
Dec,
R,
L,
Out,
DOut,
In,
Loop(Vec<Statement>),
}
const ALLOWED_CHARS: [char; 8] = ['>', '<', '+', '-', '.', ',', '[', ']'];
pub fn minify(code: &str) -> String {
code.chars().filter(|c| ALLOWED_CHARS.contains(c)).collect()
}
pub fn parse(chars: Chars, print_mode: PrintMode) -> Vec<Statement> {
let mut loop_stack = vec![vec![]];
for c in chars {
match c {
'+' => loop_stack.last_mut().unwrap().push(Statement::Inc),
'-' => loop_stack.last_mut().unwrap().push(Statement::Dec),
'>' => loop_stack.last_mut().unwrap().push(Statement::R),
'<' => loop_stack.last_mut().unwrap().push(Statement::L),
'.' => {
match print_mode {
PrintMode::ToString => loop_stack.last_mut().unwrap().push(Statement::Out),
PrintMode::DirectPrint => loop_stack.last_mut().unwrap().push(Statement::DOut)
}
}
',' => loop_stack.last_mut().unwrap().push(Statement::In),
'[' => loop_stack.push(vec![]),
']' => {
let statement = Statement::Loop(loop_stack.pop().unwrap());
loop_stack.last_mut().unwrap().push(statement);
}
_ => ()
}
}
loop_stack.pop().unwrap()
}
#[cfg(test)]
mod tests {
use crate::interpreter::{parse, minify};
use crate::interpreter::Statement::{Dec, In, Inc, L, Loop, Out, R};
#[test]
fn minify_test() {
let program = "sdahf+saga-46<sgbv>a[r]r.hr,e";
let expected = "+-<>[].,";
assert_eq!(String::from(expected), minify(program));
}
#[test]
fn parse_no_loop() {
let program = "+-<>,.";
let statements = vec![Inc, Dec, L, R, In, Out];
let result = parse(program.chars().collect(), false);
assert_eq!(statements, result);
}
#[test]
fn parse_simple_loop() {
let program = "+[<<]-";
let statements = vec![Inc, Loop(vec![L, L]), Dec];
let result = parse(program.chars().collect(), false);
assert_eq!(statements, result);
}
#[test]
fn parse_complex_loops() {
let program = ">[<[][<[<]>]>[>]]";
let statements = vec![R, Loop(vec![L, Loop(vec![]), Loop(vec![L, Loop(vec![L]), R]), R, Loop(vec![R])])];
let result = parse(program.chars().collect(), false);
assert_eq!(statements, result);
}
}

View file

@ -1,229 +1,229 @@
//! # optimization time
//! some better optimizations like set null, repeating and doing more stuff with simplifying stuff
//!
mod patterns;
use std::io::{Read, stdin, Write};
use crate::interpreter::{minify, parse, Statement, Memory, MEM_SIZE};
use std::error::Error;
use std::fmt::{Display, Formatter};
use std::fmt;
use std::ops::Deref;
#[derive(PartialOrd, PartialEq, Ord, Eq, Clone, Debug)]
enum ExStatement {
Inc,
Dec,
R,
L,
Out,
DOut,
In,
Loop(Vec<ExStatement>),
SetNull,
Repeat(Box<ExStatement>, usize),
_ForLoop(usize, Box<ExStatement>),
}
impl From<Statement> for ExStatement {
fn from(s: Statement) -> Self {
match s {
Statement::L => ExStatement::L,
Statement::R => ExStatement::R,
Statement::Inc => ExStatement::Inc,
Statement::Dec => ExStatement::Dec,
Statement::In => ExStatement::In,
Statement::Out => ExStatement::Out,
Statement::Loop(v) => ExStatement::Loop(
v.into_iter().map(ExStatement::from).collect()
),
Statement::DOut => ExStatement::DOut
}
}
}
#[derive(Debug)]
pub struct BfErr {
msg: &'static str,
}
impl BfErr {
pub fn new(msg: &'static str) -> BfErr {
BfErr { msg }
}
}
impl Display for BfErr {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
write!(f, "Error interpreting brainfuck code: {}", self.msg)
}
}
impl Error for BfErr {}
pub enum PrintMode {
ToString,
DirectPrint,
}
pub fn run(pgm: &str, print_mode: PrintMode) -> Result<String, BfErr> {
let pgm = minify(pgm);
if pgm.is_empty() { return Err(BfErr::new("no program found")); };
let pgm = parse(pgm.chars(), print_mode);
let pgm = optimize(&pgm);
let out = interpret(&pgm);
Ok(out)
}
fn optimize(code: &[Statement]) -> Vec<ExStatement> {
let code = o_set_null(code);
o_repeat(code)
}
fn o_set_null(code: &[Statement]) -> Vec<ExStatement> {
code.iter().map(|s| {
match s {
Statement::Loop(v) => {
if let [Statement::Dec] = v[..] {
ExStatement::SetNull
} else {
ExStatement::Loop(optimize(v))
}
}
Statement::Inc => ExStatement::Inc,
Statement::Dec => ExStatement::Dec,
Statement::R => ExStatement::R,
Statement::L => ExStatement::L,
Statement::Out => ExStatement::Out,
Statement::DOut => ExStatement::DOut,
Statement::In => ExStatement::In,
}
}).collect()
}
fn o_repeat(code: Vec<ExStatement>) -> Vec<ExStatement> {
let mut amount = 0;
let mut result: Vec<ExStatement> = vec![];
for i in 0..code.len() {
if code.get(i) == code.get(i + 1) {
amount += 1;
} else if amount == 0 {
result.push(code[i].clone())
} else {
amount += 1;
result.push(ExStatement::Repeat(Box::new(code[i].clone()), amount as usize));
amount = 0;
}
}
result
}
fn interpret(pgm: &[ExStatement]) -> String {
let mut out = String::new();
let mut pointer: usize = 0;
let mut mem: [u8; MEM_SIZE] = [0; MEM_SIZE];
for s in pgm {
execute(s, &mut mem, &mut pointer, &mut out)
}
out
}
fn execute(statement: &ExStatement, mem: &mut Memory, pointer: &mut usize, out: &mut String) {
match statement {
ExStatement::R => if *pointer == MEM_SIZE - 1 { *pointer = 0 } else { *pointer += 1 },
ExStatement::L => if *pointer == 0 { *pointer = MEM_SIZE - 1 } else { *pointer -= 1 },
ExStatement::Inc => mem[*pointer] = mem[*pointer].wrapping_add(1),
ExStatement::Dec => mem[*pointer] = mem[*pointer].wrapping_sub(1),
ExStatement::SetNull => mem[*pointer] = 0,
ExStatement::Out => out.push(mem[*pointer] as u8 as char),
ExStatement::DOut => {
print!("{}", mem[*pointer] as u8 as char);
std::io::stdout().flush().unwrap();
}
ExStatement::In => {
let mut in_buffer = [0, 1];
stdin().read_exact(&mut in_buffer).unwrap();
mem[*pointer] = in_buffer[0] as u8;
}
ExStatement::Loop(vec) => {
while mem[*pointer] != 0 {
for s in vec {
execute(&s, mem, pointer, out);
}
}
}
ExStatement::Repeat(statement, amount) => {
match statement.deref() {
ExStatement::R => {
*pointer += amount;
if *pointer > MEM_SIZE {
*pointer %= MEM_SIZE
}
}
ExStatement::L => *pointer = (*pointer).wrapping_sub(*amount),
ExStatement::Inc => mem[*pointer] = mem[*pointer].wrapping_add(*amount as u8),
ExStatement::Dec => mem[*pointer] = mem[*pointer].wrapping_sub(*amount as u8),
ExStatement::Loop(v) => {
for _ in 0..*amount {
execute(&ExStatement::Loop(v.clone()), mem, pointer, out)
}
}
s => {
for _ in 0..*amount {
execute(s, mem, pointer, out)
}
}
}
}
ExStatement::_ForLoop(offset, statement) => {
*pointer += offset;
while mem[*pointer - offset] != 0 {
execute(statement, mem, pointer, out);
}
}
};
}
#[cfg(test)]
mod test {
use crate::interpreter::optimized::{run, o_repeat};
use crate::interpreter::optimized::ExStatement::{Inc, Repeat, R, L, Dec};
#[test]
fn run_loop() {
let program = "++++++++++[>++++++++++<-]>.";
let out = run(program, false).unwrap();
assert_eq!(out, String::from("d"));
}
#[test]
fn hello_world() {
let program = "++++++++[>++++[>++>+++>+++>+<<<<-]>+>+>->>+[<]<-]>>.>---.+++++++..+++.>>.<-.<.+++.------.--------.>>+.>++.";
let out = run(program, false).unwrap();
assert_eq!(out, String::from("Hello World!\n"));
}
#[test]
fn o_repeat_simple() {
let code = vec![Inc, Inc, Inc, R];
let expected = vec![Repeat(Box::new(Inc), 3), R];
println!("{}", code.len());
assert_eq!(expected, o_repeat(code));
}
#[test]
fn o_repeat_long() {
let code = vec![Inc, Inc, Inc, R, L, L, L, Dec, L, L, Dec];
let expected = vec![Repeat(Box::new(Inc), 3), R, Repeat(Box::new(L), 3), Dec, Repeat(Box::new(L), 2), Dec];
assert_eq!(expected, o_repeat(code));
}
}
//! # optimization time
//! some better optimizations like set null, repeating and doing more stuff with simplifying stuff
//!
mod patterns;
use std::io::{Read, stdin, Write};
use crate::interpreter::{minify, parse, Statement, Memory, MEM_SIZE};
use std::error::Error;
use std::fmt::{Display, Formatter};
use std::fmt;
use std::ops::Deref;
#[derive(PartialOrd, PartialEq, Ord, Eq, Clone, Debug)]
enum ExStatement {
Inc,
Dec,
R,
L,
Out,
DOut,
In,
Loop(Vec<ExStatement>),
SetNull,
Repeat(Box<ExStatement>, usize),
_ForLoop(usize, Box<ExStatement>),
}
impl From<Statement> for ExStatement {
fn from(s: Statement) -> Self {
match s {
Statement::L => ExStatement::L,
Statement::R => ExStatement::R,
Statement::Inc => ExStatement::Inc,
Statement::Dec => ExStatement::Dec,
Statement::In => ExStatement::In,
Statement::Out => ExStatement::Out,
Statement::Loop(v) => ExStatement::Loop(
v.into_iter().map(ExStatement::from).collect()
),
Statement::DOut => ExStatement::DOut
}
}
}
#[derive(Debug)]
pub struct BfErr {
msg: &'static str,
}
impl BfErr {
pub fn new(msg: &'static str) -> BfErr {
BfErr { msg }
}
}
impl Display for BfErr {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
write!(f, "Error interpreting brainfuck code: {}", self.msg)
}
}
impl Error for BfErr {}
pub enum PrintMode {
ToString,
DirectPrint,
}
pub fn run(pgm: &str, print_mode: PrintMode) -> Result<String, BfErr> {
let pgm = minify(pgm);
if pgm.is_empty() { return Err(BfErr::new("no program found")); };
let pgm = parse(pgm.chars(), print_mode);
let pgm = optimize(&pgm);
let out = interpret(&pgm);
Ok(out)
}
fn optimize(code: &[Statement]) -> Vec<ExStatement> {
let code = o_set_null(code);
o_repeat(code)
}
fn o_set_null(code: &[Statement]) -> Vec<ExStatement> {
code.iter().map(|s| {
match s {
Statement::Loop(v) => {
if let [Statement::Dec] = v[..] {
ExStatement::SetNull
} else {
ExStatement::Loop(optimize(v))
}
}
Statement::Inc => ExStatement::Inc,
Statement::Dec => ExStatement::Dec,
Statement::R => ExStatement::R,
Statement::L => ExStatement::L,
Statement::Out => ExStatement::Out,
Statement::DOut => ExStatement::DOut,
Statement::In => ExStatement::In,
}
}).collect()
}
fn o_repeat(code: Vec<ExStatement>) -> Vec<ExStatement> {
let mut amount = 0;
let mut result: Vec<ExStatement> = vec![];
for i in 0..code.len() {
if code.get(i) == code.get(i + 1) {
amount += 1;
} else if amount == 0 {
result.push(code[i].clone())
} else {
amount += 1;
result.push(ExStatement::Repeat(Box::new(code[i].clone()), amount as usize));
amount = 0;
}
}
result
}
fn interpret(pgm: &[ExStatement]) -> String {
let mut out = String::new();
let mut pointer: usize = 0;
let mut mem: [u8; MEM_SIZE] = [0; MEM_SIZE];
for s in pgm {
execute(s, &mut mem, &mut pointer, &mut out)
}
out
}
fn execute(statement: &ExStatement, mem: &mut Memory, pointer: &mut usize, out: &mut String) {
match statement {
ExStatement::R => if *pointer == MEM_SIZE - 1 { *pointer = 0 } else { *pointer += 1 },
ExStatement::L => if *pointer == 0 { *pointer = MEM_SIZE - 1 } else { *pointer -= 1 },
ExStatement::Inc => mem[*pointer] = mem[*pointer].wrapping_add(1),
ExStatement::Dec => mem[*pointer] = mem[*pointer].wrapping_sub(1),
ExStatement::SetNull => mem[*pointer] = 0,
ExStatement::Out => out.push(mem[*pointer] as u8 as char),
ExStatement::DOut => {
print!("{}", mem[*pointer] as u8 as char);
std::io::stdout().flush().unwrap();
}
ExStatement::In => {
let mut in_buffer = [0, 1];
stdin().read_exact(&mut in_buffer).unwrap();
mem[*pointer] = in_buffer[0] as u8;
}
ExStatement::Loop(vec) => {
while mem[*pointer] != 0 {
for s in vec {
execute(&s, mem, pointer, out);
}
}
}
ExStatement::Repeat(statement, amount) => {
match statement.deref() {
ExStatement::R => {
*pointer += amount;
if *pointer > MEM_SIZE {
*pointer %= MEM_SIZE
}
}
ExStatement::L => *pointer = (*pointer).wrapping_sub(*amount),
ExStatement::Inc => mem[*pointer] = mem[*pointer].wrapping_add(*amount as u8),
ExStatement::Dec => mem[*pointer] = mem[*pointer].wrapping_sub(*amount as u8),
ExStatement::Loop(v) => {
for _ in 0..*amount {
execute(&ExStatement::Loop(v.clone()), mem, pointer, out)
}
}
s => {
for _ in 0..*amount {
execute(s, mem, pointer, out)
}
}
}
}
ExStatement::_ForLoop(offset, statement) => {
*pointer += offset;
while mem[*pointer - offset] != 0 {
execute(statement, mem, pointer, out);
}
}
};
}
#[cfg(test)]
mod test {
use crate::interpreter::optimized::{run, o_repeat};
use crate::interpreter::optimized::ExStatement::{Inc, Repeat, R, L, Dec};
#[test]
fn run_loop() {
let program = "++++++++++[>++++++++++<-]>.";
let out = run(program, false).unwrap();
assert_eq!(out, String::from("d"));
}
#[test]
fn hello_world() {
let program = "++++++++[>++++[>++>+++>+++>+<<<<-]>+>+>->>+[<]<-]>>.>---.+++++++..+++.>>.<-.<.+++.------.--------.>>+.>++.";
let out = run(program, false).unwrap();
assert_eq!(out, String::from("Hello World!\n"));
}
#[test]
fn o_repeat_simple() {
let code = vec![Inc, Inc, Inc, R];
let expected = vec![Repeat(Box::new(Inc), 3), R];
println!("{}", code.len());
assert_eq!(expected, o_repeat(code));
}
#[test]
fn o_repeat_long() {
let code = vec![Inc, Inc, Inc, R, L, L, L, Dec, L, L, Dec];
let expected = vec![Repeat(Box::new(Inc), 3), R, Repeat(Box::new(L), 3), Dec, Repeat(Box::new(L), 2), Dec];
assert_eq!(expected, o_repeat(code));
}
}

View file

@ -1,43 +1,43 @@
//!
//! # Patterns find and replace
//! Pattern-match ExStatements and replace them with optimizations like add, multiply etc
use crate::interpreter::optimized::ExStatement;
///
/// Replace this: `[>>x<<-]` or `[->>x<<]` with `WhileAdd(2, x)`
fn _for_loop(to_test: ExStatement) -> ExStatement {
match to_test {
ExStatement::Loop(v) => {
match v[..] {
[ExStatement::R, ExStatement::Inc, ExStatement::L, ExStatement::Dec] => {
ExStatement::_ForLoop(1, Box::from(ExStatement::Inc))
}
_ => ExStatement::Loop(v)
}
},
s => s
}
}
#[cfg(test)]
mod test {
use crate::interpreter::optimized::ExStatement::{Out, Loop, Inc, R, L, Dec, _ForLoop};
use crate::interpreter::optimized::patterns::_for_loop;
#[test]
fn for_loop_false() {
let statement = Loop(vec![Out, Inc]);
assert_eq!(statement.clone(), _for_loop(statement));
}
#[test]
fn for_loop_simplest() {
let statement = Loop(vec![R, Inc, L, Dec]);
assert_eq!(_ForLoop(1, Box::from(Inc)), _for_loop(statement));
}
//!
//! # Patterns find and replace
//! Pattern-match ExStatements and replace them with optimizations like add, multiply etc
use crate::interpreter::optimized::ExStatement;
///
/// Replace this: `[>>x<<-]` or `[->>x<<]` with `WhileAdd(2, x)`
fn _for_loop(to_test: ExStatement) -> ExStatement {
match to_test {
ExStatement::Loop(v) => {
match v[..] {
[ExStatement::R, ExStatement::Inc, ExStatement::L, ExStatement::Dec] => {
ExStatement::_ForLoop(1, Box::from(ExStatement::Inc))
}
_ => ExStatement::Loop(v)
}
},
s => s
}
}
#[cfg(test)]
mod test {
use crate::interpreter::optimized::ExStatement::{Out, Loop, Inc, R, L, Dec, _ForLoop};
use crate::interpreter::optimized::patterns::_for_loop;
#[test]
fn for_loop_false() {
let statement = Loop(vec![Out, Inc]);
assert_eq!(statement.clone(), _for_loop(statement));
}
#[test]
fn for_loop_simplest() {
let statement = Loop(vec![R, Inc, L, Dec]);
assert_eq!(_ForLoop(1, Box::from(Inc)), _for_loop(statement));
}
}

View file

@ -1,122 +1,122 @@
//!
//! # optimization time
//!
//! first parse the bf so that it can be executed faster
//! most importantly: loop jumps should be immediate
#![allow(dead_code)]
use std::io::{Read, stdin, Write};
use crate::interpreter::{MEM_SIZE, Memory, minify, parse, Statement};
use crate::interpreter::optimized::PrintMode;
use crate::repl::BrainfuckState;
pub fn run(pgm: &str) -> String {
let pgm = minify(pgm);
let pgm = parse(pgm.chars(), PrintMode::ToString);
interpret(&pgm)
}
fn interpret(pgm: &[Statement]) -> String {
let mut out = String::new();
let mut pointer: usize = 0;
let mut mem: [u8; MEM_SIZE] = [0; MEM_SIZE];
for s in pgm {
execute(s, &mut mem, &mut pointer, &mut out)
}
out
}
pub fn interpret_with_state(pgm: &[Statement], state: &mut BrainfuckState) {
for s in pgm {
execute(s, &mut state.memory, &mut state.pointer, &mut String::new())
}
}
fn execute(statement: &Statement, mem: &mut Memory, pointer: &mut usize, out: &mut String) {
match statement {
Statement::R => if *pointer == MEM_SIZE - 1 { *pointer = 0 } else { *pointer += 1 },
Statement::L => if *pointer == 0 { *pointer = MEM_SIZE - 1 } else { *pointer -= 1 },
Statement::Inc => mem[*pointer] = mem[*pointer].wrapping_add(1),
Statement::Dec => mem[*pointer] = mem[*pointer].wrapping_sub(1),
Statement::Out => out.push(mem[*pointer] as u8 as char),
Statement::In => {
let mut in_buffer = [0, 1];
stdin().read_exact(&mut in_buffer).unwrap();
mem[*pointer] = in_buffer[0] as u8;
}
Statement::Loop(vec) => {
while mem[*pointer] != 0 {
for s in vec {
execute(&s, mem, pointer, out);
}
}
}
Statement::DOut => {
print!("{}", mem[*pointer] as u8 as char);
std::io::stdout().flush().unwrap();
}
}
}
#[cfg(test)]
mod test {
use crate::interpreter::parsed::{execute, run, Statement};
#[test]
fn execute_simple() {
let mut pointer: usize = 0;
let mut mem: [u8; 65535] = [0; 65535];
let mut out = String::new();
execute(&Statement::R, &mut mem, &mut pointer, &mut out);
assert_eq!(pointer, 1);
execute(&Statement::L, &mut mem, &mut pointer, &mut out);
assert_eq!(pointer, 0);
execute(&Statement::Inc, &mut mem, &mut pointer, &mut out);
assert_eq!(mem[pointer], 1);
execute(&Statement::Dec, &mut mem, &mut pointer, &mut out);
assert_eq!(mem[pointer], 0);
}
#[test]
fn execute_false_loop() {
let statement = Statement::Loop(vec![Statement::Inc, Statement::Inc, Statement::R]);
let mut pointer: usize = 0;
let mut mem: [u8; 65535] = [0; 65535];
execute(&statement, &mut mem, &mut pointer, &mut String::new());
assert_eq!(mem[0], 0);
assert_eq!(mem[1], 0);
}
#[test]
fn execute_loop() {
let statement = Statement::Loop(vec![Statement::Inc, Statement::Inc, Statement::R]);
let mut pointer: usize = 0;
let mut mem: [u8; 65535] = [0; 65535];
mem[0] = 1;
execute(&statement, &mut mem, &mut pointer, &mut String::new());
assert_eq!(mem[0], 3);
assert_eq!(mem[1], 0);
}
#[test]
fn run_loop() {
let program = "++++++++++[>++++++++++<-]>.";
let out = run(program);
assert_eq!(out, String::from("d"));
}
#[test]
fn hello_world() {
let program = "++++++++[>++++[>++>+++>+++>+<<<<-]>+>+>->>+[<]<-]>>.>---.+++++++..+++.>>.<-.<.+++.------.--------.>>+.>++.";
let out = run(program);
assert_eq!(out, String::from("Hello World!\n"));
}
//!
//! # optimization time
//!
//! first parse the bf so that it can be executed faster
//! most importantly: loop jumps should be immediate
#![allow(dead_code)]
use std::io::{Read, stdin, Write};
use crate::interpreter::{MEM_SIZE, Memory, minify, parse, Statement};
use crate::interpreter::optimized::PrintMode;
use crate::repl::BrainfuckState;
pub fn run(pgm: &str) -> String {
let pgm = minify(pgm);
let pgm = parse(pgm.chars(), PrintMode::ToString);
interpret(&pgm)
}
fn interpret(pgm: &[Statement]) -> String {
let mut out = String::new();
let mut pointer: usize = 0;
let mut mem: [u8; MEM_SIZE] = [0; MEM_SIZE];
for s in pgm {
execute(s, &mut mem, &mut pointer, &mut out)
}
out
}
pub fn interpret_with_state(pgm: &[Statement], state: &mut BrainfuckState) {
for s in pgm {
execute(s, &mut state.memory, &mut state.pointer, &mut String::new())
}
}
fn execute(statement: &Statement, mem: &mut Memory, pointer: &mut usize, out: &mut String) {
match statement {
Statement::R => if *pointer == MEM_SIZE - 1 { *pointer = 0 } else { *pointer += 1 },
Statement::L => if *pointer == 0 { *pointer = MEM_SIZE - 1 } else { *pointer -= 1 },
Statement::Inc => mem[*pointer] = mem[*pointer].wrapping_add(1),
Statement::Dec => mem[*pointer] = mem[*pointer].wrapping_sub(1),
Statement::Out => out.push(mem[*pointer] as u8 as char),
Statement::In => {
let mut in_buffer = [0, 1];
stdin().read_exact(&mut in_buffer).unwrap();
mem[*pointer] = in_buffer[0] as u8;
}
Statement::Loop(vec) => {
while mem[*pointer] != 0 {
for s in vec {
execute(&s, mem, pointer, out);
}
}
}
Statement::DOut => {
print!("{}", mem[*pointer] as u8 as char);
std::io::stdout().flush().unwrap();
}
}
}
#[cfg(test)]
mod test {
use crate::interpreter::parsed::{execute, run, Statement};
#[test]
fn execute_simple() {
let mut pointer: usize = 0;
let mut mem: [u8; 65535] = [0; 65535];
let mut out = String::new();
execute(&Statement::R, &mut mem, &mut pointer, &mut out);
assert_eq!(pointer, 1);
execute(&Statement::L, &mut mem, &mut pointer, &mut out);
assert_eq!(pointer, 0);
execute(&Statement::Inc, &mut mem, &mut pointer, &mut out);
assert_eq!(mem[pointer], 1);
execute(&Statement::Dec, &mut mem, &mut pointer, &mut out);
assert_eq!(mem[pointer], 0);
}
#[test]
fn execute_false_loop() {
let statement = Statement::Loop(vec![Statement::Inc, Statement::Inc, Statement::R]);
let mut pointer: usize = 0;
let mut mem: [u8; 65535] = [0; 65535];
execute(&statement, &mut mem, &mut pointer, &mut String::new());
assert_eq!(mem[0], 0);
assert_eq!(mem[1], 0);
}
#[test]
fn execute_loop() {
let statement = Statement::Loop(vec![Statement::Inc, Statement::Inc, Statement::R]);
let mut pointer: usize = 0;
let mut mem: [u8; 65535] = [0; 65535];
mem[0] = 1;
execute(&statement, &mut mem, &mut pointer, &mut String::new());
assert_eq!(mem[0], 3);
assert_eq!(mem[1], 0);
}
#[test]
fn run_loop() {
let program = "++++++++++[>++++++++++<-]>.";
let out = run(program);
assert_eq!(out, String::from("d"));
}
#[test]
fn hello_world() {
let program = "++++++++[>++++[>++>+++>+++>+<<<<-]>+>+>->>+[<]<-]>>.>---.+++++++..+++.>>.<-.<.+++.------.--------.>>+.>++.";
let out = run(program);
assert_eq!(out, String::from("Hello World!\n"));
}
}

View file

@ -1,71 +1,71 @@
//!
//! The very basic interpreter without any optimizations
#![allow(dead_code)]
use crate::interpreter::{MEM_SIZE, minify};
use std::io::{stdin, Read};
pub fn run(program: &str) -> String{
let program = minify(program);
let out = interpret(program.chars().collect());
out
}
fn interpret(pgm: Vec<char>) -> String {
let mut out = String::new();
let mut pointer: usize = 0;
let mut mem: [u8; MEM_SIZE] = [0; MEM_SIZE];
let mut in_buffer = [0; 1];
let mut pc = 0;
let len = pgm.len();
while pc < len {
match pgm[pc] {
'>' => if pointer == MEM_SIZE - 1 { pointer = 0 } else { pointer += 1 },
'<' => if pointer == 0 { pointer = MEM_SIZE - 1 } else { pointer -= 1 },
'+' => mem[pointer] = mem[pointer].wrapping_add(1),
'-' => mem[pointer] = mem[pointer].wrapping_sub(1),
'.' => out.push(mem[pointer] as u8 as char),
',' => {
stdin().read_exact(&mut in_buffer).unwrap();
mem[pointer] = in_buffer[0] as u8;
}
'[' => {
//jump to corresponding ]
if mem[pointer] == 0 {
let mut level = 0;
while pgm[pc] != ']' || level > -1 {
pc += 1;
match pgm[pc] {
'[' => {
level += 1
}
']' => {
level -= 1
}
_ => (),
}
}
}
}
']' => {
if mem[pointer] != 0 {
//jump to corresponding [
let mut level = 0;
while pgm[pc] != '[' || level > -1 {
pc -= 1;
match pgm[pc] {
'[' => level -= 1,
']' => level += 1,
_ => (),
}
}
}
}
_ => (),
}
pc += 1;
}
out
//!
//! The very basic interpreter without any optimizations
#![allow(dead_code)]
use crate::interpreter::{MEM_SIZE, minify};
use std::io::{stdin, Read};
pub fn run(program: &str) -> String{
let program = minify(program);
let out = interpret(program.chars().collect());
out
}
fn interpret(pgm: Vec<char>) -> String {
let mut out = String::new();
let mut pointer: usize = 0;
let mut mem: [u8; MEM_SIZE] = [0; MEM_SIZE];
let mut in_buffer = [0; 1];
let mut pc = 0;
let len = pgm.len();
while pc < len {
match pgm[pc] {
'>' => if pointer == MEM_SIZE - 1 { pointer = 0 } else { pointer += 1 },
'<' => if pointer == 0 { pointer = MEM_SIZE - 1 } else { pointer -= 1 },
'+' => mem[pointer] = mem[pointer].wrapping_add(1),
'-' => mem[pointer] = mem[pointer].wrapping_sub(1),
'.' => out.push(mem[pointer] as u8 as char),
',' => {
stdin().read_exact(&mut in_buffer).unwrap();
mem[pointer] = in_buffer[0] as u8;
}
'[' => {
//jump to corresponding ]
if mem[pointer] == 0 {
let mut level = 0;
while pgm[pc] != ']' || level > -1 {
pc += 1;
match pgm[pc] {
'[' => {
level += 1
}
']' => {
level -= 1
}
_ => (),
}
}
}
}
']' => {
if mem[pointer] != 0 {
//jump to corresponding [
let mut level = 0;
while pgm[pc] != '[' || level > -1 {
pc -= 1;
match pgm[pc] {
'[' => level -= 1,
']' => level += 1,
_ => (),
}
}
}
}
_ => (),
}
pc += 1;
}
out
}

View file

@ -1,37 +1,37 @@
mod interpreter;
mod repl;
use std::{env, fs};
use std::time::SystemTime;
use crate::repl::start_repl;
use crate::interpreter::optimized::{PrintMode};
use std::error::Error;
fn main() {
let path = env::args().nth(1);
match path {
Some(p) => {
if let Err(why) = run_program(p) {
eprintln!("An error occurred in the program: {}", why)
}
},
None => start_repl()
};
}
fn run_program(path: String) -> Result<(), Box<dyn Error>> {
let program = match fs::read_to_string(path) {
Ok(p) => p,
Err(e) => {
println!("Error reading file: {}", e);
return Err(Box::from(e));
}
};
let start_time = SystemTime::now();
let out = interpreter::optimized::run(&*program, PrintMode::DirectPrint)?;
let duration = start_time.elapsed()?;
println!("{}\nFinished execution. Took {}ms", out, duration.as_millis());
Ok(())
mod interpreter;
mod repl;
use std::{env, fs};
use std::time::SystemTime;
use crate::repl::start_repl;
use crate::interpreter::optimized::{PrintMode};
use std::error::Error;
fn main() {
let path = env::args().nth(1);
match path {
Some(p) => {
if let Err(why) = run_program(p) {
eprintln!("An error occurred in the program: {}", why)
}
},
None => start_repl()
};
}
fn run_program(path: String) -> Result<(), Box<dyn Error>> {
let program = match fs::read_to_string(path) {
Ok(p) => p,
Err(e) => {
println!("Error reading file: {}", e);
return Err(Box::from(e));
}
};
let start_time = SystemTime::now();
let out = interpreter::optimized::run(&*program, PrintMode::DirectPrint)?;
let duration = start_time.elapsed()?;
println!("{}\nFinished execution. Took {}ms", out, duration.as_millis());
Ok(())
}

View file

@ -1,111 +1,111 @@
use std::fmt::{Display, Formatter};
use std::fmt;
use std::io::{stdin, stdout, Write};
use crate::interpreter::{minify, parse, parsed, Memory, MEM_SIZE};
use crate::interpreter::optimized::PrintMode;
pub struct BrainfuckState {
pub memory: Memory,
pub pointer: usize,
}
impl Display for BrainfuckState {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
write!(f, "{}", display_state(self))
}
}
fn display_state(state: &BrainfuckState) -> String {
let start = if state.pointer < 5 {
0
} else if state.pointer > MEM_SIZE - 10 {
MEM_SIZE - 10
} else {
state.pointer - 5
};
format!("{}-\n|{}|\n{}-\n{}|\n{}|\n{}|\n{}-\n {}^^^^",
"----------".repeat(10),
{
let mut out = String::new();
let end = start + 10;
for i in start..end {
out.push_str(&*format!(" {: >5} ", i));
}
out
},
"----------".repeat(10),
"| ".repeat(10),
{
let mut out = String::new();
let end = start + 10;
for i in start..end {
out.push_str(&*format!("| {: >3} ", state.memory[i]));
}
out
},
"| ".repeat(10),
"----------".repeat(10),
" ".repeat(state.pointer - start))
}
pub fn start_repl() {
println!("Brainfuck REPL");
let mut state = BrainfuckState {
memory: [0; MEM_SIZE],
pointer: 0,
};
println!("Enter Brainfuck programs and they will be executed immediatly.");
println!("State is kept.");
println!("{}", state);
loop {
print!(">> ");
stdout().flush().unwrap();
match read_line() {
Ok(s) => {
match &*s {
":q" => break,
":?" | "help" | "?" => print_help(),
":r" => {
reset(&mut state);
println!("{}", state);
},
_ => {
print!("Output: ");
println!();
parse_input(s, &mut state);
println!("{}", state);
}
}
}
Err(why) => println!("Error reading input: {}\nPlease try again.", why)
}
}
}
fn reset(state: &mut BrainfuckState) {
state.pointer = 0;
state.memory = [0; MEM_SIZE];
}
fn print_help() {
println!("Brainfuck REPL help
:q => quit
:? => help
:r => reset state");
}
fn parse_input(pgm: String, state: &mut BrainfuckState) {
let pgm = minify(&*pgm);
let pgm = parse(pgm.chars(), PrintMode::DirectPrint);
parsed::interpret_with_state(&*pgm, state);
}
pub fn read_line() -> Result<String, std::io::Error> {
let mut buf = String::new();
stdin().read_line(&mut buf)?;
buf.pop();
Ok(buf)
use std::fmt::{Display, Formatter};
use std::fmt;
use std::io::{stdin, stdout, Write};
use crate::interpreter::{minify, parse, parsed, Memory, MEM_SIZE};
use crate::interpreter::optimized::PrintMode;
pub struct BrainfuckState {
pub memory: Memory,
pub pointer: usize,
}
impl Display for BrainfuckState {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
write!(f, "{}", display_state(self))
}
}
fn display_state(state: &BrainfuckState) -> String {
let start = if state.pointer < 5 {
0
} else if state.pointer > MEM_SIZE - 10 {
MEM_SIZE - 10
} else {
state.pointer - 5
};
format!("{}-\n|{}|\n{}-\n{}|\n{}|\n{}|\n{}-\n {}^^^^",
"----------".repeat(10),
{
let mut out = String::new();
let end = start + 10;
for i in start..end {
out.push_str(&*format!(" {: >5} ", i));
}
out
},
"----------".repeat(10),
"| ".repeat(10),
{
let mut out = String::new();
let end = start + 10;
for i in start..end {
out.push_str(&*format!("| {: >3} ", state.memory[i]));
}
out
},
"| ".repeat(10),
"----------".repeat(10),
" ".repeat(state.pointer - start))
}
pub fn start_repl() {
println!("Brainfuck REPL");
let mut state = BrainfuckState {
memory: [0; MEM_SIZE],
pointer: 0,
};
println!("Enter Brainfuck programs and they will be executed immediatly.");
println!("State is kept.");
println!("{}", state);
loop {
print!(">> ");
stdout().flush().unwrap();
match read_line() {
Ok(s) => {
match &*s {
":q" => break,
":?" | "help" | "?" => print_help(),
":r" => {
reset(&mut state);
println!("{}", state);
},
_ => {
print!("Output: ");
println!();
parse_input(s, &mut state);
println!("{}", state);
}
}
}
Err(why) => println!("Error reading input: {}\nPlease try again.", why)
}
}
}
fn reset(state: &mut BrainfuckState) {
state.pointer = 0;
state.memory = [0; MEM_SIZE];
}
fn print_help() {
println!("Brainfuck REPL help
:q => quit
:? => help
:r => reset state");
}
fn parse_input(pgm: String, state: &mut BrainfuckState) {
let pgm = minify(&*pgm);
let pgm = parse(pgm.chars(), PrintMode::DirectPrint);
parsed::interpret_with_state(&*pgm, state);
}
pub fn read_line() -> Result<String, std::io::Error> {
let mut buf = String::new();
stdin().read_line(&mut buf)?;
buf.pop();
Ok(buf)
}