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
#![feature(try_from)]#[macro_use]extern crate derive_more;
use std::io::{BufRead,self};use std::fmt::{Display, self};use std::convert::TryInto;use std::iter::Iterator;use std::num::ParseIntError;#[cfg(test)]mod test;
#[doc="Represents a single character in one of the programs on the tape.\n"]
#[doc="Because unicode doesn't define valid characters for every single 32-bit bitmask, this value allows switching between interpreting the character as a number or as a unicode codepoint."]
#[derive(Clone,Copy,Debug,PartialOrd,Ord,PartialEq,Eq,From)]pub enum C{C(char),N(u32)}
impl C{#[doc="Converts self into a C::C when self is C::N, identity otherwise\n\n#Panics\nWhen `C::N` is an invalid unicode codepoint."]
 pub fn norm(&self)->C{match self{C::C(c)=>C::C(*c),C::N(_n)=>C::C((*self).into())}}}
impl From<C> for char{fn from(c:C)->char{match c{C::C(c)=>c,C::N(n)=>n.try_into().expect(&format!("{} not valid unicode codepoint",n))}}}
impl From<C> for u32{fn from(c:C)->u32{match c{C::N(n)=>n,C::C(c)=>c.into()}}} impl Display for C{fn fmt(&self,f:&mut fmt::Formatter)->Result<(),fmt::Error>{char::from(*self).fmt(f)}}
#[derive(Clone,Debug,PartialOrd,Ord,PartialEq,Eq,From,Into)]pub struct CSt(Vec<C>);impl CSt{pub fn n(&self)->Result<u32,ParseIntError>{self.to_string().parse()}}
impl Display for CSt{fn fmt(&self,f:&mut fmt::Formatter)->Result<(),fmt::Error>{let g:String=self.clone().0.into_iter().map(|v|char::from(v)).collect(); g.fmt(f)}}
#[derive(Clone,Debug,PartialOrd,Ord,PartialEq,Eq)]pub enum S{Main,Read{buf:CSt},Write{buf:CSt},Stack{buf:CSt},Print{escap:bool,buf:CSt},Stopped}impl Default for S{fn default()->S{S::Main}}
#[derive(Clone,Debug,PartialOrd,Ord,PartialEq,Eq,Default)]pub struct I{pub program:usize,pub head_pos:usize,pub tape:Vec<Vec<C>>,pub state:S,pub stack:Vec<C>,pub max_stack:usize,pub max_programs:usize}
#[derive(Clone,Copy,Debug,PartialOrd,Ord,PartialEq,Eq)]pub enum R{Running,Stopped}impl Default for R{fn default()->R{R::Stopped}}
impl I{pub fn new()->I{let mut i=I::default();i.max_stack=8;i.max_programs=8;i}
 pub fn rd<R:io::Read>(&mut self,r:R){let b=io::BufReader::new(r);for(i,l)in(1..).zip(b.lines()){if i>self.max_programs{panic!("max programs")}
   self.tape.push(l.unwrap().chars().map(|c|C::C(c)).collect::<Vec<_>>().into())};self.tape.resize(self.max_programs,vec![]);
  let targ=self.tape.iter().map(|v|v.len()).fold(0,|a,v|if v>a{v}else{a});self.tape.iter_mut().map(|v|v.resize(targ,C::C(' '))).collect()}
 pub fn sp(&mut self)->C{self.stack.pop().expect("empty stack")}
 pub fn step(&mut self)->R{let c=self.tape[self.program][self.head_pos];let mut ns=self.state.clone();match self.state{
  S::Stopped=>return R::Stopped,S::Main=>{match c.into(){'"'=>ns=S::Print{escap:false,buf:vec![].into()},'>'=>ns=S::Stack{buf:vec![].into()},
   '|'=>ns=S::Read{buf:vec![].into()},']'=>ns=S::Write{buf:vec![].into()},'!'=>{let a=self.stack.pop().expect("empty stack");if u32::from(a)==0{self.stack.push(1.into())}else{self.stack.push(0.into())}}
   '#'=>if self.tape.len()-1!=self.program{self.program+=1}else{ns=S::Stopped},'^'=>if self.program!=0{self.program-=1}else{ns=S::Stopped}
   ','=>{let _=self.stack.pop();()},'~'=>{let v=self.sp();self.stack.push(v);self.stack.push(v)},'d'=>{let a=self.sp();print!("{}",u32::from(a))},'D'=>{let a=self.sp();eprint!("{}",u32::from(a))}
   '+'=>{let a=self.sp();let b=self.sp();self.stack.push(C::from(u32::from(a)+u32::from(b)))},'-'=>{let a=self.sp();let b=self.sp();self.stack.push(C::from(u32::from(a)-u32::from(b)))}
   '*'=>{let a=self.sp();let b=self.sp();self.stack.push(C::from(u32::from(a)* u32::from(b)))},'%'=>{let a=self.sp();let b=self.sp();self.stack.push(C::from(u32::from(a)/u32::from(b)))}
   '/'=>{let a=self.sp();if a!=C::N(0){if self.program!=0{self.program-=1}else{ns=S::Stopped}}},
   '\\'=>{let a=self.sp();if a!=C::N(0){if self.tape.len()-1!=self.program{self.program+=1}else{ns=S::Stopped}}},
   '='=>{let a=self.sp();let b=self.sp();if u32::from(a)==u32::from(b){self.stack.push(1.into())}else{self.stack.push(0.into())}},' '|'\0'|'\t'=>{},c=>panic!("unknown instruction {}",c)}}
  S::Print{escap,ref buf}=>{let mut b:Vec<C>=buf.clone().into();let mut es_new=false;let mut repla=true;if!escap{match c.into(){'\\'=>es_new=true,
    '"'=>{ns=S::Main;repla=false;print!("{}",CSt::from(b.clone()))},'`'=>{ns=S::Main;repla=false;eprint!("{}",CSt::from(b.clone()))},_=>b.push(c)}}
   else{b.push(C::from(match c.into(){'n'=>'\n','`'=>'`','"'=>'"','\\'=>'\\',c=>panic!("unknown escape character \\{}",c)}))}
   if repla{ns=S::Print{escap:es_new,buf:b.into()}}},
  S::Stack{ref buf}=>{let mut b:Vec<C>=buf.clone().into();match c.into(){'0'...'9'=>{b.push(c);ns=S::Stack{buf:b.into()}}
    '.'=>{ns=S::Main;self.stack.push(CSt::from(b).n().unwrap().into());if self.stack.len()>self.max_stack{panic!("max stack entries exceeded")}}
    c=>panic!("unknown character in stack push: {}",c)}},
  S::Read{ref buf}=>{let mut b:Vec<C>=buf.clone().into();match c.into(){'0'...'9'=>{b.push(c);ns=S::Read{buf:b.into()}}
    '.'=>{ns=S::Main;self.stack.push(self.tape[(CSt::from(b).n().unwrap()+1)as usize][self.head_pos])},
    c=>panic!("unknown character in tape read: {}",c)}},
  S::Write{ref buf}=>{let mut b:Vec<C>=buf.clone().into();match c.into(){'0'...'9'=>{b.push(c);ns=S::Write{buf:b.into()}}
    '.'=>{ns=S::Main;self.tape[(CSt::from(b).n().unwrap()+1)as usize][self.head_pos]=self.stack.pop().expect("empty stack")},
  c=>panic!("unknown character in tape read: {}",c)}}}
 self.state=ns;if self.head_pos!=self.tape[self.program].len()-1{self.head_pos+=1}else{self.head_pos=0}R::Running}}