1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
//! Simple brainfuck interpreter in Rust.
//!
//! The brainfuck language was created with the purpose of being a
//! very minimal language which is very easy to write an interpreter
//! for. This is one such interpreter. For more information on the
//! brainfuck language start with the documentation of each
//! [instruction in the language][instruction], or
//! [some material online][brainfuck]. Brainfuck itself is syntactically
//! challenging for humans, but is really not all that complicated. `+.`
//! for example increments the value in the first cell and outputs that
//! value. The instructions that trip people up the most are the control
//! flow contructs `[` and `]`. `+++>,<[>+.<-]` for example prints the 3
//! values after the input value. For more about control flow in brainfuck
//! read the section on [control flow][control-flow].
//!
//! # Examples
//!
//! ```
//! use brainfuck;
//!
//! // Evaluate a simple brainfuck program from a string.
//! brainfuck::eval_string("+>.");
//! // Evaluate a brainfuck program from a file.
//! brainfuck::eval_file("fixtures/helloworld.rs");
//! ```
//!
//! # Semantics and Portability
//!
//! The brainfuck language has a few areas that are undefined behavior. These
//! undefined behaviors are given explicit semantics in this implmentation.
//! Most brainfuck programs should work as expected in this implmentation.
//! For more information on portabiliy of brainfuck programs read
//! [The Unofficial Constraints on Portable Brainfuck Implementations][portabiliy].
//! The deatils below should cover all of the undefined behavior in brainfuck
//! with respect to this implmentation.
//!
//! - The tape contains `TAPE_LENGTH` (currently 30,000) cells.
//! - The tape's pointer may **not** be moved below or above the begining
//! or the end of the tape. The interpreter will return an `Err` if the
//! program does so.
//! - The values of the tape are unsigned bytes (`u8` in rust).
//! - Values may not be incremented or decremented above 255, or below 0.
//! The interpreter will return an `Err` if the program does so.
//! - Attpempts to read input when there is no more input to be read will
//! be effective noops (potentially with a warning).
//! - Programs cannot contain unmatching brackets, and functions like
//! `Program::parse` ensure this before running the program.
//!
//! [instruction]: enum.Instruction.html
//! [brainfuck]: http://www.muppetlabs.com/~breadbox/bf/
//! [control-flow]: enum.Instruction.html#control-flow
//! [instruction-docs]: enum.Instruction.html
//! [portabiliy]: http://www.muppetlabs.com/%7Ebreadbox/bf/standards.html
#![feature(augmented_assignments)]
#![deny(warnings)]

use std::io;
use std::path::Path;
use tape::VecTape;
use program::Program;

/// The number of instructions allowed to execute before the interpreter
/// errors with `Error::CycleLimit`.
pub const CYCLE_LIMIT: u64 = 10000000;

// Re-exports.
pub use error::Error;
pub use interpreter::Interpreter;
pub use instruction::Instruction;

/// Run the given program with STDIN and STDOUT as the IO buffers.
fn eval(program: Program) -> Result<(), Error> {
    let mut stdin = io::stdin();
    let mut stdout = io::stdout();
    Interpreter::<VecTape>::new(program, &mut stdin, &mut stdout).run()
}

/// Parse a program from the given string and `eval` it.
pub fn eval_string(source: &str) -> Result<(), Error> {
    eval(try!(Program::parse(source)))
}

/// Parse a program from the given file path and `eval` it.
pub fn eval_file<P: AsRef<Path>>(path: P) -> Result<(), Error> {
    let program = try!(Program::from_file(path));
    eval(program)
}

/// Brainfuck errors are the best kind of errors.
mod error;

/// Brainfuck interpreters are my favorite kind of interpreter.
mod interpreter;

/// Brainfuck instructions are the best kind of instructions.
mod instruction;

/// Brainfuck programs are the best kind of programs too!
pub mod program;

/// Brainfuck programs have the best underlying data structure.
pub mod tape;