@@ -15,15 +15,21 @@ pub enum ProgramError {
1515 IOError ,
1616
1717 /// Error when performing illegal operation
18- IllegalOperation
18+ IllegalOperation { instruction : Token , pointer : usize } ,
1919}
2020
2121impl fmt:: Display for ProgramError {
2222 fn fmt ( & self , f : & mut fmt:: Formatter < ' _ > ) -> fmt:: Result {
2323 match self {
2424 ProgramError :: OutOfBounds => write ! ( f, "Attempted to move pointer past end of buffer" ) ,
2525 ProgramError :: IOError => write ! ( f, "Error when attempting to perform IO operation" ) ,
26- ProgramError :: IllegalOperation => write ! ( f, "Operation is illegal" )
26+ ProgramError :: IllegalOperation {
27+ instruction,
28+ pointer,
29+ } => write ! (
30+ f,
31+ "Operation is illegal: {instruction} at pointer address {pointer}"
32+ ) ,
2733 }
2834 }
2935}
@@ -34,18 +40,18 @@ const BUFFER_SIZE: usize = 30000;
3440/// Buffer used internally by the interpreter.
3541///
3642/// This struct exists for the sole purpose of exploiting **interior mutability**, allowing [Interpreter] objects to expose an immutable API.
37- struct ArrayBuffer {
43+ struct Tape {
3844 /// The data held in the buffer.
3945 data : [ u8 ; BUFFER_SIZE ] ,
4046
4147 /// A pointer to the *current location* in the buffer.
4248 pointer : usize ,
4349}
4450
45- impl ArrayBuffer {
51+ impl Tape {
4652 /// Creates a new empty [ArrayBuffer] with all elements set to 0 which points to the byte at position 0.
4753 fn new ( ) -> Self {
48- ArrayBuffer {
54+ Tape {
4955 data : [ 0 ; BUFFER_SIZE ] ,
5056 pointer : 0 ,
5157 }
@@ -68,12 +74,14 @@ impl ArrayBuffer {
6874
6975 /// Increments by 1 the value currently pointed at in the buffer
7076 fn inc ( & mut self ) {
71- self . data [ self . pointer ] += 1 ;
77+ self . data [ self . pointer ] = self . data [ self . pointer ] . wrapping_add ( 1 ) ;
78+ // self.data[self.pointer] += 1;
7279 }
7380
7481 /// Decrements by 1 the value currently pointed at in the buffer
7582 fn dec ( & mut self ) {
76- self . data [ self . pointer ] -= 1 ;
83+ self . data [ self . pointer ] = self . data [ self . pointer ] . wrapping_sub ( 1 ) ;
84+ // self.data[self.pointer] -= 1;
7785 }
7886
7987 /// Moves the pointer one position to the left.
@@ -92,7 +100,7 @@ pub struct Interpreter {
92100 /// The data used by the interpreter.
93101 ///
94102 /// This is stored behind a [RefCell] so we can expose an immutable API.
95- data : RefCell < ArrayBuffer > ,
103+ tape : RefCell < Tape > ,
96104
97105 /// Object that abstracts I/O operations away from interpreter objects.
98106 io : IO ,
@@ -102,7 +110,7 @@ impl Interpreter {
102110 /// Creates a new [Interpreter] object with a empty [buffer](ArrayBuffer).
103111 pub fn new ( ) -> Self {
104112 Interpreter {
105- data : RefCell :: new ( ArrayBuffer :: new ( ) ) ,
113+ tape : RefCell :: new ( Tape :: new ( ) ) ,
106114 io : IO :: new ( ) ,
107115 }
108116 }
@@ -111,39 +119,35 @@ impl Interpreter {
111119 fn process_token ( & self , token : Token ) -> Result < ( ) , ProgramError > {
112120 match token {
113121 Token :: Inc => {
114- self . data . borrow_mut ( ) . inc ( ) ;
122+ self . tape . borrow_mut ( ) . inc ( ) ;
115123 }
116124 Token :: Dec => {
117- if self . data . borrow ( ) . get ( ) == 0 {
118- return Err ( ProgramError :: IllegalOperation ) ;
119- }
120-
121- self . data . borrow_mut ( ) . dec ( ) ;
125+ self . tape . borrow_mut ( ) . dec ( ) ;
122126 }
123127 Token :: MoveLeft => {
124- if self . data . borrow ( ) . pointer ( ) == 0 {
128+ if self . tape . borrow ( ) . pointer ( ) == 0 {
125129 return Err ( ProgramError :: OutOfBounds ) ;
126130 }
127131
128- self . data . borrow_mut ( ) . pointer_left ( ) ;
132+ self . tape . borrow_mut ( ) . pointer_left ( ) ;
129133 }
130134 Token :: MoveRight => {
131- if self . data . borrow ( ) . pointer ( ) == BUFFER_SIZE - 1 {
135+ if self . tape . borrow ( ) . pointer ( ) == BUFFER_SIZE - 1 {
132136 return Err ( ProgramError :: OutOfBounds ) ;
133137 }
134138
135- self . data . borrow_mut ( ) . pointer_right ( ) ;
139+ self . tape . borrow_mut ( ) . pointer_right ( ) ;
136140 }
137141 Token :: Print => {
138- let current_byte = self . data . borrow ( ) . get ( ) ;
142+ let current_byte = self . tape . borrow ( ) . get ( ) ;
139143
140144 let character = current_byte as char ;
141145
142146 self . io . print ( character) ;
143147 }
144148 Token :: Read => match self . io . read ( ) {
145149 None => return Err ( ProgramError :: IOError ) ,
146- Some ( character) => self . data . borrow_mut ( ) . set ( character as u8 ) ,
150+ Some ( character) => self . tape . borrow_mut ( ) . set ( character as u8 ) ,
147151 } ,
148152 Token :: Loop ( loop_tokens) => self . run_loop ( loop_tokens) ?,
149153 } ;
@@ -163,7 +167,8 @@ impl Interpreter {
163167 /// Specialized function used to run loops.
164168 fn run_loop ( & self , loop_tokens : Vec < Token > ) -> Result < ( ) , ProgramError > {
165169 loop {
166- if self . data . borrow ( ) . get ( ) == 0 {
170+ // if 0 at the beginning of loop, skip it
171+ if self . tape . borrow ( ) . get ( ) == 0 {
167172 break ;
168173 }
169174
0 commit comments