1
1
#![ feature( try_trait) ]
2
+ #![ allow( dead_code) ]
2
3
use std:: { collections:: HashMap , option:: NoneError } ;
3
4
use Command :: * ;
4
5
use Operator :: * ;
@@ -39,6 +40,7 @@ impl From<NoneError> for Error {
39
40
40
41
#[ derive( Default , Debug ) ]
41
42
pub struct Forth {
43
+ text : String ,
42
44
stack : Vec < i32 > ,
43
45
words : HashMap < String , String > ,
44
46
}
@@ -51,38 +53,38 @@ impl Forth {
51
53
self . stack . clone ( )
52
54
}
53
55
54
- fn filter_words ( input : & str ) -> String {
55
- input . chars ( ) . fold ( String :: new ( ) , |acc, chr| {
56
+ fn filter_words ( & mut self ) {
57
+ let filtered = self . text . chars ( ) . fold ( String :: new ( ) , |acc, chr| {
56
58
if chr. is_whitespace ( ) || chr. is_control ( ) {
57
59
acc + & ' ' . to_string ( )
58
60
} else {
59
61
acc + & chr. to_string ( )
60
62
}
61
- } )
63
+ } ) ;
64
+ self . text = filtered;
62
65
}
63
66
64
- pub fn eval < ' a > ( & ' a mut self , input : & ' a str ) -> ForthResult {
65
- let mut input = Self :: filter_words ( input) ;
66
- while !input. is_empty ( ) {
67
- input = self . eval_digits ( & input) ;
68
- input = self . eval_operators ( & input) ?. to_string ( ) ;
69
- input = self . eval_word_declarations ( input) ?;
70
- input = self . eval_word ( & input) ?;
71
- input = self . eval_commands ( input) ?;
67
+ pub fn eval ( & mut self , input : & str ) -> ForthResult {
68
+ self . text = input. to_string ( ) ;
69
+ self . filter_words ( ) ;
70
+ while !self . text . is_empty ( ) {
71
+ self . eval_digits ( ) ;
72
+ self . eval_operators ( ) ?;
73
+ // input = self.eval_word_declarations(input)?;
74
+ // input = self.eval_word(&input)?;
75
+ self . eval_commands ( ) ?;
72
76
}
73
77
Ok ( ( ) )
74
78
}
75
79
76
- fn eval_digits ( & mut self , mut input : & str ) -> String {
77
- while let ( Some ( head) , tail) = Self :: parse_digit ( & input) {
78
- self . stack . push ( head) ;
79
- input = tail;
80
+ fn eval_digits ( & mut self ) {
81
+ while let Some ( digit) = self . parse_digit ( ) {
82
+ self . stack . push ( digit) ;
80
83
}
81
- input. to_string ( )
82
84
}
83
85
84
- fn eval_operators < ' a > ( & ' a mut self , mut input : & ' a str ) -> Result < & ' a str , Error > {
85
- while let ( Some ( operator) , tail ) = Self :: parse_operator ( & input ) {
86
+ fn eval_operators < ' b > ( & ' b mut self ) -> Result < ( ) , Error > {
87
+ while let Some ( operator) = self . parse_operator ( ) {
86
88
let value2 = self . stack . pop ( ) ?;
87
89
let value1 = self . stack . pop ( ) ?;
88
90
match operator {
@@ -96,9 +98,8 @@ impl Forth {
96
98
}
97
99
Multiply => self . stack . push ( value1 * value2) ,
98
100
}
99
- input = tail;
100
101
}
101
- Ok ( input )
102
+ Ok ( ( ) )
102
103
}
103
104
104
105
fn eval_word_declarations ( & mut self , mut input : String ) -> Result < String , Error > {
@@ -116,8 +117,8 @@ impl Forth {
116
117
Ok ( input. to_string ( ) )
117
118
}
118
119
119
- fn eval_commands ( & mut self , mut input : String ) -> Result < String , Error > {
120
- while let ( Some ( command) , tail ) = Self :: parse_command ( & input ) ? {
120
+ fn eval_commands ( & mut self ) -> Result < ( ) , Error > {
121
+ while let Some ( command) = self . parse_command ( ) ? {
121
122
match command {
122
123
Swap => {
123
124
let value2 = self . stack . pop ( ) ?;
@@ -143,62 +144,94 @@ impl Forth {
143
144
self . words . insert ( key, value) ;
144
145
}
145
146
}
146
- input = tail. to_string ( ) ;
147
147
}
148
- Ok ( input )
148
+ Ok ( ( ) )
149
149
}
150
150
151
- fn parse_digit ( input : & str ) -> ( Option < Value > , & str ) {
152
- match input . chars ( ) . position ( |chr| chr. is_whitespace ( ) ) {
151
+ fn parse_digit ( & mut self ) -> Option < Value > {
152
+ match self . text . chars ( ) . position ( |chr| chr. is_whitespace ( ) ) {
153
153
Some ( position) => {
154
- let head = & input [ ..position] ;
155
- let tail = & input [ position..] ;
154
+ let head = & self . text . clone ( ) [ ..position] ;
155
+ let tail = & self . text . clone ( ) [ position..] ;
156
156
if let Ok ( value) = head. parse :: < Value > ( ) {
157
- ( Some ( value) , tail. trim_left ( ) )
157
+ self . text = tail. trim_left ( ) . to_string ( ) ;
158
+ Some ( value)
158
159
} else {
159
- ( None , input. trim ( ) )
160
+ self . text = self . text . trim ( ) . to_string ( ) ;
161
+ None
160
162
}
161
163
}
162
- _ => match input. parse :: < Value > ( ) {
163
- Ok ( value) => ( Some ( value) , "" ) ,
164
- _ => ( None , input) ,
164
+ _ => match self . text . parse :: < Value > ( ) {
165
+ Ok ( value) => {
166
+ self . text = "" . to_string ( ) ;
167
+ Some ( value)
168
+ }
169
+ _ => None ,
165
170
} ,
166
171
}
167
172
}
168
173
169
- fn parse_operator ( input : & str ) -> ( Option < Operator > , & str ) {
170
- if input. is_empty ( ) {
171
- return ( None , "" ) ;
174
+ fn parse_operator ( & mut self ) -> Option < Operator > {
175
+ if self . text . is_empty ( ) {
176
+ self . text = "" . to_string ( ) ;
177
+ return None ;
172
178
}
173
- let head = & input[ ..1 ] ;
174
- let tail = & input[ 1 ..] . trim_left ( ) ;
179
+ let text = self . text . clone ( ) ;
180
+ let head = & text[ ..1 ] ;
181
+ let tail = & text[ 1 ..] . trim_left ( ) ;
175
182
match head {
176
- "+" => ( Some ( Plus ) , tail) ,
177
- "-" => ( Some ( Minus ) , tail) ,
178
- "/" => ( Some ( Divide ) , tail) ,
179
- "*" => ( Some ( Multiply ) , tail) ,
180
- _ => ( None , input) ,
183
+ "+" => {
184
+ self . text = tail. to_string ( ) ;
185
+ Some ( Plus )
186
+ }
187
+ "-" => {
188
+ self . text = tail. to_string ( ) ;
189
+ Some ( Minus )
190
+ }
191
+ "/" => {
192
+ self . text = tail. to_string ( ) ;
193
+ Some ( Divide )
194
+ }
195
+ "*" => {
196
+ self . text = tail. to_string ( ) ;
197
+ Some ( Multiply )
198
+ }
199
+ _ => None ,
181
200
}
182
201
}
183
202
184
- fn parse_command ( input : & str ) -> Result < ( Option < Command > , String ) , Error > {
185
- if input. is_empty ( ) {
186
- return Ok ( ( None , "" . to_string ( ) ) ) ;
203
+ fn parse_command ( & mut self ) -> Result < Option < Command > , Error > {
204
+ if self . text . is_empty ( ) {
205
+ self . text = "" . to_string ( ) ;
206
+ return Ok ( None ) ;
187
207
}
188
- let ( head, tail) = match input. chars ( ) . position ( |chr| chr. is_whitespace ( ) ) {
208
+ let text = self . text . clone ( ) ;
209
+ let ( head, tail) = match self . text . chars ( ) . position ( |chr| chr. is_whitespace ( ) ) {
189
210
Some ( position) => {
190
- let head = input [ ..position] . to_lowercase ( ) ;
191
- let tail = input [ position..] . trim_left ( ) ;
211
+ let head = text [ ..position] . to_lowercase ( ) ;
212
+ let tail = text [ position..] . trim_left ( ) . to_string ( ) ;
192
213
( head, tail)
193
214
}
194
- None => ( input . to_string ( ) . to_lowercase ( ) , "" ) ,
215
+ None => ( self . text . to_string ( ) . to_lowercase ( ) , "" . to_string ( ) ) ,
195
216
} ;
196
217
match head. as_str ( ) {
197
- "drop" => Ok ( ( Some ( Dropp ) , tail. to_string ( ) ) ) ,
198
- "dup" => Ok ( ( Some ( Dup ) , tail. to_string ( ) ) ) ,
199
- "swap" => Ok ( ( Some ( Swap ) , tail. to_string ( ) ) ) ,
200
- "over" => Ok ( ( Some ( Over ) , tail. to_string ( ) ) ) ,
201
- digits if digits. parse :: < u32 > ( ) . is_ok ( ) => Ok ( ( None , "" . to_string ( ) ) ) ,
218
+ "drop" => {
219
+ self . text = tail;
220
+ Ok ( Some ( Dropp ) )
221
+ }
222
+ "dup" => {
223
+ self . text = tail;
224
+ Ok ( Some ( Dup ) )
225
+ }
226
+ "swap" => {
227
+ self . text = tail;
228
+ Ok ( Some ( Swap ) )
229
+ }
230
+ "over" => {
231
+ self . text = tail;
232
+ Ok ( Some ( Over ) )
233
+ }
234
+ digits if digits. parse :: < u32 > ( ) . is_ok ( ) => Ok ( None ) ,
202
235
_ => Err ( Error :: UnknownWord ) ,
203
236
}
204
237
}
@@ -241,7 +274,7 @@ impl Forth {
241
274
) )
242
275
}
243
276
244
- fn parse_word < ' a > ( & self , input : & ' a str ) -> ( Option < String > , & ' a str ) {
277
+ fn parse_word < ' b > ( & self , input : & ' b str ) -> ( Option < String > , & ' b str ) {
245
278
let ( head, tail) = match input. chars ( ) . position ( |chr| chr. is_whitespace ( ) ) {
246
279
Some ( position) => {
247
280
let head = & input[ ..position] ;
0 commit comments