Last active
May 31, 2018 02:23
-
-
Save f0rki/8fb98f404b6a28807eb9edd024eccc5a to your computer and use it in GitHub Desktop.
Interpreter for the TapeBagel esoteric language
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
* ---------------------------------------------------------------------------- | |
* "THE BEER-WARE LICENSE" (Revision 42): | |
* <[email protected]> wrote this file. As long as you retain this notice you | |
* can do whatever you want with this stuff. If we meet some day, and you think | |
* this stuff is worth it, you can buy me a beer in return. | |
* ---------------------------------------------------------------------------- | |
*/ | |
/// Interpreter for the TapeBagel esoteric language | |
/// see https://esolangs.org/wiki/TapeBagel for a partial spec | |
use std::env; | |
use std::fs::File; | |
use std::io; | |
use std::io::{Read, BufRead}; | |
struct TapeBagel { | |
integers: [i64; 3], | |
index: usize, | |
output: String, | |
} | |
impl TapeBagel { | |
fn new() -> TapeBagel { | |
TapeBagel { | |
integers: [0, 0, 0], | |
index: 0, | |
output: String::new(), | |
} | |
} | |
fn set_all_ints_to(&mut self, val: i64) { | |
for i in 0..self.integers.len() { | |
self.integers[i] = val; | |
} | |
} | |
fn pause(&self) { | |
println!("Pause\nindex = {}", self.index); | |
// let mut n = 0; | |
for (n, i) in self.integers.iter().enumerate() { | |
println!("i{} = {}", n, i); | |
// n += 1; | |
} | |
println!("Continue?"); | |
let stdin = std::io::stdin(); | |
stdin.lock().lines().next().unwrap().unwrap(); | |
} | |
fn clear_screen(&mut self) { | |
println!("{}", self.output); | |
self.output.clear(); | |
} | |
fn handle_int_op(&mut self, cmd: &str) { | |
let mut i1 = 0; | |
let mut i = 0; | |
let mut operator = ' '; | |
for c in cmd.chars() { | |
if c == '*' { | |
i += 1 | |
} else { | |
operator = c; | |
i1 = i - 1; | |
i = 0; | |
} | |
} | |
let i2 = i - 1; | |
// println!("operation: {} with {}, {}", operator, i1, i2); | |
match operator { | |
'&' => self.integers[self.index] = self.integers[i1] * self.integers[i2], | |
'+' => self.integers[self.index] = self.integers[i1] + self.integers[i2], | |
'$' => self.integers[self.index] = self.integers[i1] / self.integers[i2], | |
'-' => self.integers[self.index] = self.integers[i1] - self.integers[i2], | |
_ => panic!("Unkown operator '{}'", operator), | |
} | |
// println!("result = {}", self.integers[self.index]); | |
} | |
fn int_to_char(&self, i: i64) -> char { | |
if i == 0 { | |
return ' '; | |
} | |
let j: u32; | |
j = (i as u32) + 64; | |
std::char::from_u32(j).unwrap() | |
} | |
fn handle_print(&mut self, cmd: &str) { | |
let mut i = 0; | |
for c in cmd.chars() { | |
if c == '*' { | |
i += 1; | |
} | |
} | |
if i == 0 { | |
panic!("need some integer specifier"); | |
} | |
i -= 1; | |
if cmd.starts_with("@@") { | |
// println!("print_int({}) = {}", i, self.integers[i]); | |
let istr = self.integers[i].to_string(); | |
self.output.push_str(&istr); | |
} else if cmd.starts_with("@") { | |
let outchar = self.int_to_char(self.integers[i]); | |
// println!("print_char({}) = {} = {}", i, self.integers[i], outchar); | |
self.output.push(outchar); | |
} | |
} | |
fn execute(&mut self, program: &str) -> String { | |
self.output.clear(); | |
let mut institer = program.split_whitespace(); | |
loop { | |
match institer.next() { | |
Some(c) => { | |
match c { | |
"%#" => self.index += 1, | |
"%%" => self.index = 0, | |
"#%" => self.set_all_ints_to(1), | |
"##" => self.set_all_ints_to(0), | |
"&&" => self.pause(), | |
"&@" => self.clear_screen(), | |
"%++" => self.integers[self.index] += 1, | |
_ => { | |
if c.starts_with("@") { | |
self.handle_print(c); | |
} else if c.starts_with("*") { | |
self.handle_int_op(c); | |
} else { | |
println!("Invalid command '{}'", c); | |
break; | |
} | |
} | |
} | |
} | |
None => { | |
println!("Execution stop"); | |
break; | |
} | |
} | |
} | |
self.output.clone() | |
} | |
} | |
fn from_file(filepath: &str) -> io::Result<String> { | |
let mut contents = Vec::new(); | |
let mut file = try!(File::open(filepath)); | |
try!(file.read_to_end(&mut contents)); | |
Ok(String::from_utf8(contents).unwrap()) | |
} | |
fn main() { | |
println!("TapeBagel.rs"); | |
let args: Vec<String> = env::args().collect(); | |
if args.len() == 2 { | |
println!("Executing file '{}':", args[1]); | |
let fcontents = from_file(&args[1]).unwrap(); | |
println!("{}", fcontents); | |
let mut machine = TapeBagel::new(); | |
let out = machine.execute(&fcontents); | |
println!("output:\n{}", out); | |
} else { | |
println!("usage: {} <path to input file>", args[0]); | |
} | |
} | |
#[test] | |
fn test_hello_world() { | |
let program_text = "%% %++ %++ %++ %++ %++ %++ %++ %++ @* ## %++ %++ %++ %++ %++ @* ## %++ \ | |
%++ %++ %++ %++ %++ %++ %++ %++ %++ %++ %++ @* @* ## %++ %++ %++ %++ %++ \ | |
%++ %++ %++ %++ %++ %++ %++ %++ %++ %++ @* ## @* %++ %++ %++ %++ %++ %++ \ | |
%++ %++ %++ %++ %++ %++ %++ %++ %++ %++ %++ %++ %++ %++ %++ %++ %++ @* ## \ | |
%++ %++ %++ %++ %++ %++ %++ %++ %++ %++ %++ %++ %++ %++ %++ @* ## %++ %++ \ | |
%++ %++ %++ %++ %++ %++ %++ %++ %++ %++ %++ %++ %++ %++ %++ %++ @* ## \ | |
%++ %++ %++ %++ %++ %++ %++ %++ %++ %++ %++ %++ @* ## %++ %++ %++ %++ @* \ | |
## "; | |
let mut machine = TapeBagel::new(); | |
let out = machine.execute(program_text); | |
assert_eq!(out, "HELLO WORLD"); | |
} | |
#[test] | |
fn test_iwctf() { | |
let program_text = "## %% %++ %++ %++ %# *&* @** %# **&* ***-* ***-* %++ %++ @*** *-* @*** \ | |
@** *+** @*** ***+* @*** **+** ***+* %++ @*** #% %% %++ %++ %++ %++ @* %# \ | |
%++ %++ %++ %% *&** @* @*** *-** @* %# %++ @** *-** *-** **-*** **-*** \ | |
**-*** @** @*** #% %% %++ %++ %++ %++ %# *+** %++ @** @* %# *+** @*** ## \ | |
%% @***"; | |
let mut machine = TapeBagel::new(); | |
let out = machine.execute(program_text); | |
assert_eq!(out, "IW ILOVETAPEBAGEL "); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
I wonder who this elusive S. R. Farmer is who is mentioned on the TapeBagel wiki page... https://esolangs.org/wiki/TapeBagel