@@ -4,11 +4,12 @@ use itertools::Itertools;
4
4
use pest:: {
5
5
error:: { Error as PestError , ErrorVariant , LineColLocation } ,
6
6
iterators:: { Pair , Pairs } ,
7
- Parser ,
8
7
} ;
9
8
10
9
use crate :: load_file:: { AddressMode , Core , Field , Instruction , Modifier , Opcode , Value } ;
11
10
11
+ mod grammar;
12
+
12
13
#[ derive( Debug ) ]
13
14
pub struct Error {
14
15
details : String ,
@@ -30,8 +31,8 @@ impl Error {
30
31
}
31
32
}
32
33
33
- impl From < PestError < Rule > > for Error {
34
- fn from ( pest_error : PestError < Rule > ) -> Error {
34
+ impl From < PestError < grammar :: Rule > > for Error {
35
+ fn from ( pest_error : PestError < grammar :: Rule > ) -> Error {
35
36
Error {
36
37
details : format ! (
37
38
"Parse error: {} {}" ,
@@ -60,18 +61,14 @@ impl From<String> for Error {
60
61
}
61
62
}
62
63
63
- #[ derive( Parser ) ]
64
- #[ grammar = "data/redcode.pest" ]
65
- struct RedcodeParser ;
66
-
67
64
pub fn parse ( file_contents : & str ) -> Result < Core , Error > {
68
65
if file_contents. is_empty ( ) {
69
66
return Err ( Error :: no_input ( ) ) ;
70
67
}
71
68
72
69
let mut core = Core :: default ( ) ;
73
70
74
- let parse_result = RedcodeParser :: parse ( Rule :: RedcodeFile , file_contents) ?
71
+ let parse_result = grammar :: parse ( grammar :: Rule :: File , file_contents) ?
75
72
. next ( )
76
73
. ok_or_else ( Error :: no_input) ?;
77
74
@@ -82,7 +79,7 @@ pub fn parse(file_contents: &str) -> Result<Core, Error> {
82
79
. filter ( |line_pair| line_pair. peek ( ) . is_some ( ) )
83
80
{
84
81
let label_pairs = line_pair
85
- . take_while_ref ( |pair| pair. as_rule ( ) == Rule :: Label )
82
+ . take_while_ref ( |pair| pair. as_rule ( ) == grammar :: Rule :: Label )
86
83
. map ( |pair| pair. as_str ( ) . to_owned ( ) ) ;
87
84
88
85
for label in label_pairs {
@@ -100,7 +97,7 @@ pub fn parse(file_contents: &str) -> Result<Core, Error> {
100
97
Ok ( core. resolve ( ) ?)
101
98
}
102
99
103
- fn parse_instruction ( mut instruction_pairs : Pairs < Rule > ) -> Instruction {
100
+ fn parse_instruction ( mut instruction_pairs : Pairs < grammar :: Rule > ) -> Instruction {
104
101
let mut operation_pairs = instruction_pairs
105
102
. next ( )
106
103
. expect ( "Operation must be first pair after Label in Instruction" )
@@ -114,7 +111,7 @@ fn parse_instruction(mut instruction_pairs: Pairs<Rule>) -> Instruction {
114
111
115
112
let maybe_modifier = operation_pairs
116
113
. peek ( )
117
- . filter ( |pair| pair. as_rule ( ) == Rule :: Modifier )
114
+ . filter ( |pair| pair. as_rule ( ) == grammar :: Rule :: Modifier )
118
115
. map ( |pair| parse_modifier ( & pair) ) ;
119
116
120
117
let field_a = parse_field (
@@ -125,7 +122,7 @@ fn parse_instruction(mut instruction_pairs: Pairs<Rule>) -> Instruction {
125
122
126
123
let field_b = instruction_pairs
127
124
. next ( )
128
- . filter ( |pair| pair. as_rule ( ) == Rule :: Field )
125
+ . filter ( |pair| pair. as_rule ( ) == grammar :: Rule :: Field )
129
126
. map_or_else ( Field :: default, parse_field) ;
130
127
131
128
let modifier = maybe_modifier. unwrap_or_else ( || {
@@ -140,27 +137,27 @@ fn parse_instruction(mut instruction_pairs: Pairs<Rule>) -> Instruction {
140
137
}
141
138
}
142
139
143
- fn parse_modifier ( modifier_pair : & Pair < Rule > ) -> Modifier {
140
+ fn parse_modifier ( modifier_pair : & Pair < grammar :: Rule > ) -> Modifier {
144
141
Modifier :: from_str ( modifier_pair. as_str ( ) . to_uppercase ( ) . as_ref ( ) ) . unwrap ( )
145
142
}
146
143
147
- fn parse_opcode ( opcode_pair : & Pair < Rule > ) -> Opcode {
144
+ fn parse_opcode ( opcode_pair : & Pair < grammar :: Rule > ) -> Opcode {
148
145
Opcode :: from_str ( opcode_pair. as_str ( ) . to_uppercase ( ) . as_ref ( ) ) . unwrap ( )
149
146
}
150
147
151
- fn parse_field ( field_pair : Pair < Rule > ) -> Field {
148
+ fn parse_field ( field_pair : Pair < grammar :: Rule > ) -> Field {
152
149
let field_pairs = field_pair. into_inner ( ) ;
153
150
154
151
let address_mode = field_pairs
155
152
. peek ( )
156
- . filter ( |pair| pair. as_rule ( ) == Rule :: AddressMode )
153
+ . filter ( |pair| pair. as_rule ( ) == grammar :: Rule :: AddressMode )
157
154
. map_or ( AddressMode :: default ( ) , |pair| {
158
155
AddressMode :: from_str ( pair. as_str ( ) ) . expect ( "Invalid AddressMode" )
159
156
} ) ;
160
157
161
158
let value = parse_value (
162
159
field_pairs
163
- . skip_while ( |pair| pair. as_rule ( ) != Rule :: Expr )
160
+ . skip_while ( |pair| pair. as_rule ( ) != grammar :: Rule :: Expr )
164
161
. next ( )
165
162
. expect ( "No Expr in Field" ) ,
166
163
) ;
@@ -171,27 +168,24 @@ fn parse_field(field_pair: Pair<Rule>) -> Field {
171
168
}
172
169
}
173
170
174
- fn parse_value ( value_pair : Pair < Rule > ) -> Value {
171
+ fn parse_value ( value_pair : Pair < grammar :: Rule > ) -> Value {
175
172
let expr_inner = value_pair
176
173
. into_inner ( )
177
174
. next ( )
178
175
. expect ( "Expr must have inner value" ) ;
179
176
180
177
match expr_inner. as_rule ( ) {
181
- Rule :: Number => Value :: Literal (
178
+ grammar :: Rule :: Number => Value :: Literal (
182
179
i32:: from_str_radix ( expr_inner. as_str ( ) , 10 )
183
180
. expect ( "Number type must be decimal integer" ) ,
184
181
) ,
185
- Rule :: Label => Value :: Label ( expr_inner. as_str ( ) . to_owned ( ) ) ,
182
+ grammar :: Rule :: Label => Value :: Label ( expr_inner. as_str ( ) . to_owned ( ) ) ,
186
183
_ => unreachable ! ( ) ,
187
184
}
188
185
}
189
186
190
187
#[ cfg( test) ]
191
- #[ allow( clippy:: cognitive_complexity) ]
192
188
mod tests {
193
- use pest:: { consumes_to, parses_to} ;
194
-
195
189
use super :: * ;
196
190
197
191
#[ test]
@@ -202,155 +196,6 @@ mod tests {
202
196
assert_eq ! ( result. unwrap_err( ) . details, "No input found" ) ;
203
197
}
204
198
205
- #[ test]
206
- fn parse_field ( ) {
207
- parses_to ! {
208
- parser: RedcodeParser ,
209
- input: "123" ,
210
- rule: Rule :: Field ,
211
- tokens: [
212
- Field ( 0 , 3 , [
213
- Expr ( 0 , 3 , [
214
- Number ( 0 , 3 )
215
- ] ) ,
216
- ] )
217
- ]
218
- } ;
219
- }
220
-
221
- #[ test]
222
- fn parse_field_with_mode ( ) {
223
- for test_input in [
224
- "#123" , "$123" , "*123" , "@123" , "{123" , "<123" , "}123" , ">123" ,
225
- ]
226
- . iter ( )
227
- {
228
- parses_to ! {
229
- parser: RedcodeParser ,
230
- input: test_input,
231
- rule: Rule :: Field ,
232
- tokens: [
233
- Field ( 0 , 4 , [
234
- AddressMode ( 0 , 1 ) ,
235
- Expr ( 1 , 4 , [
236
- Number ( 1 , 4 )
237
- ] ) ,
238
- ] )
239
- ]
240
- } ;
241
- }
242
- }
243
-
244
- #[ test]
245
- fn parse_expr ( ) {
246
- // TODO: expand grammar for math operations, parens, etc.
247
- // Then test it here. Possibly worth breaking into its own module
248
- parses_to ! {
249
- parser: RedcodeParser ,
250
- input: "123" ,
251
- rule: Rule :: Expr ,
252
- tokens: [
253
- Expr ( 0 , 3 , [
254
- Number ( 0 , 3 )
255
- ] ) ,
256
- ]
257
- } ;
258
- }
259
-
260
- #[ test]
261
- fn parse_label_expr ( ) {
262
- for test_input in [ "foo" , "fo2" , "f_2" ] . iter ( ) {
263
- parses_to ! {
264
- parser: RedcodeParser ,
265
- input: test_input,
266
- rule: Rule :: Expr ,
267
- tokens: [
268
- Expr ( 0 , 3 , [
269
- Label ( 0 , 3 )
270
- ] ) ,
271
- ]
272
- } ;
273
- }
274
- }
275
-
276
- #[ test]
277
- fn parse_opcode_modifier ( ) {
278
- for test_input in [
279
- "mov.a" , "mov.b" , "mov.ab" , "mov.ba" , "mov.f" , "mov.x" , "mov.i" ,
280
- ]
281
- . iter ( )
282
- {
283
- parses_to ! {
284
- parser: RedcodeParser ,
285
- input: test_input,
286
- rule: Rule :: Operation ,
287
- tokens: [
288
- Operation ( 0 , test_input. len( ) , [
289
- Opcode ( 0 , 3 ) ,
290
- Modifier ( 4 , test_input. len( ) ) ,
291
- ] ) ,
292
- ]
293
- }
294
- }
295
- }
296
-
297
- #[ test]
298
- fn parse_instruction ( ) {
299
- parses_to ! {
300
- parser: RedcodeParser ,
301
- input: "mov #1, 3" ,
302
- rule: Rule :: Instruction ,
303
- tokens: [
304
- Operation ( 0 , 3 , [
305
- Opcode ( 0 , 3 )
306
- ] ) ,
307
- Field ( 4 , 6 , [
308
- AddressMode ( 4 , 5 ) ,
309
- Expr ( 5 , 6 , [
310
- Number ( 5 , 6 )
311
- ] )
312
- ] ) ,
313
- Field ( 8 , 9 , [
314
- Expr ( 8 , 9 , [
315
- Number ( 8 , 9 )
316
- ] )
317
- ] ) ,
318
- ]
319
- } ;
320
- }
321
-
322
- #[ test]
323
- fn parse_comment ( ) {
324
- parses_to ! {
325
- parser: RedcodeParser ,
326
- input: "; foo bar\n " ,
327
- rule: Rule :: COMMENT ,
328
- tokens: [
329
- COMMENT ( 0 , 9 )
330
- ]
331
- }
332
- }
333
-
334
- #[ test]
335
- fn parse_label ( ) {
336
- for & ( label_input, start, end) in [
337
- ( "some_label" , 0 , 10 ) ,
338
- ( "some_label2" , 0 , 11 ) ,
339
- ( "a: " , 0 , 1 ) ,
340
- ( " a " , 1 , 2 ) ,
341
- ( "a :" , 0 , 1 ) ,
342
- ]
343
- . iter ( )
344
- {
345
- parses_to ! {
346
- parser: RedcodeParser ,
347
- input: label_input,
348
- rule: Rule :: LabelDeclaration ,
349
- tokens: [ Label ( start, end) ]
350
- }
351
- }
352
- }
353
-
354
199
#[ test]
355
200
fn duplicate_labels ( ) {
356
201
let simple_input = "
@@ -405,6 +250,4 @@ mod tests {
405
250
406
251
assert_eq ! ( parsed, expected_core) ;
407
252
}
408
-
409
- // TODO: parse error for unresolvable label
410
253
}
0 commit comments