Skip to content

Commit 7fc5455

Browse files
Refactor grammar into module and remove all mod.rs
1 parent 3fc7641 commit 7fc5455

File tree

4 files changed

+184
-175
lines changed

4 files changed

+184
-175
lines changed

src/data/redcode.pest

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ WHITESPACE = _{ " " | "\t" }
22

33
COMMENT = @{ ";" ~ (!NEWLINE ~ ANY)* ~ &NEWLINE }
44

5-
RedcodeFile = { SOI ~ (Line ~ NEWLINE)+ ~ Line? ~ EOI }
5+
File = { SOI ~ (Line ~ NEWLINE)+ ~ Line? ~ EOI }
66

77
Line = { LabelDeclaration* ~ Instruction? }
88

File renamed without changes.

src/parser.rs

Lines changed: 17 additions & 174 deletions
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,12 @@ use itertools::Itertools;
44
use pest::{
55
error::{Error as PestError, ErrorVariant, LineColLocation},
66
iterators::{Pair, Pairs},
7-
Parser,
87
};
98

109
use crate::load_file::{AddressMode, Core, Field, Instruction, Modifier, Opcode, Value};
1110

11+
mod grammar;
12+
1213
#[derive(Debug)]
1314
pub struct Error {
1415
details: String,
@@ -30,8 +31,8 @@ impl Error {
3031
}
3132
}
3233

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 {
3536
Error {
3637
details: format!(
3738
"Parse error: {} {}",
@@ -60,18 +61,14 @@ impl From<String> for Error {
6061
}
6162
}
6263

63-
#[derive(Parser)]
64-
#[grammar = "data/redcode.pest"]
65-
struct RedcodeParser;
66-
6764
pub fn parse(file_contents: &str) -> Result<Core, Error> {
6865
if file_contents.is_empty() {
6966
return Err(Error::no_input());
7067
}
7168

7269
let mut core = Core::default();
7370

74-
let parse_result = RedcodeParser::parse(Rule::RedcodeFile, file_contents)?
71+
let parse_result = grammar::parse(grammar::Rule::File, file_contents)?
7572
.next()
7673
.ok_or_else(Error::no_input)?;
7774

@@ -82,7 +79,7 @@ pub fn parse(file_contents: &str) -> Result<Core, Error> {
8279
.filter(|line_pair| line_pair.peek().is_some())
8380
{
8481
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)
8683
.map(|pair| pair.as_str().to_owned());
8784

8885
for label in label_pairs {
@@ -100,7 +97,7 @@ pub fn parse(file_contents: &str) -> Result<Core, Error> {
10097
Ok(core.resolve()?)
10198
}
10299

103-
fn parse_instruction(mut instruction_pairs: Pairs<Rule>) -> Instruction {
100+
fn parse_instruction(mut instruction_pairs: Pairs<grammar::Rule>) -> Instruction {
104101
let mut operation_pairs = instruction_pairs
105102
.next()
106103
.expect("Operation must be first pair after Label in Instruction")
@@ -114,7 +111,7 @@ fn parse_instruction(mut instruction_pairs: Pairs<Rule>) -> Instruction {
114111

115112
let maybe_modifier = operation_pairs
116113
.peek()
117-
.filter(|pair| pair.as_rule() == Rule::Modifier)
114+
.filter(|pair| pair.as_rule() == grammar::Rule::Modifier)
118115
.map(|pair| parse_modifier(&pair));
119116

120117
let field_a = parse_field(
@@ -125,7 +122,7 @@ fn parse_instruction(mut instruction_pairs: Pairs<Rule>) -> Instruction {
125122

126123
let field_b = instruction_pairs
127124
.next()
128-
.filter(|pair| pair.as_rule() == Rule::Field)
125+
.filter(|pair| pair.as_rule() == grammar::Rule::Field)
129126
.map_or_else(Field::default, parse_field);
130127

131128
let modifier = maybe_modifier.unwrap_or_else(|| {
@@ -140,27 +137,27 @@ fn parse_instruction(mut instruction_pairs: Pairs<Rule>) -> Instruction {
140137
}
141138
}
142139

143-
fn parse_modifier(modifier_pair: &Pair<Rule>) -> Modifier {
140+
fn parse_modifier(modifier_pair: &Pair<grammar::Rule>) -> Modifier {
144141
Modifier::from_str(modifier_pair.as_str().to_uppercase().as_ref()).unwrap()
145142
}
146143

147-
fn parse_opcode(opcode_pair: &Pair<Rule>) -> Opcode {
144+
fn parse_opcode(opcode_pair: &Pair<grammar::Rule>) -> Opcode {
148145
Opcode::from_str(opcode_pair.as_str().to_uppercase().as_ref()).unwrap()
149146
}
150147

151-
fn parse_field(field_pair: Pair<Rule>) -> Field {
148+
fn parse_field(field_pair: Pair<grammar::Rule>) -> Field {
152149
let field_pairs = field_pair.into_inner();
153150

154151
let address_mode = field_pairs
155152
.peek()
156-
.filter(|pair| pair.as_rule() == Rule::AddressMode)
153+
.filter(|pair| pair.as_rule() == grammar::Rule::AddressMode)
157154
.map_or(AddressMode::default(), |pair| {
158155
AddressMode::from_str(pair.as_str()).expect("Invalid AddressMode")
159156
});
160157

161158
let value = parse_value(
162159
field_pairs
163-
.skip_while(|pair| pair.as_rule() != Rule::Expr)
160+
.skip_while(|pair| pair.as_rule() != grammar::Rule::Expr)
164161
.next()
165162
.expect("No Expr in Field"),
166163
);
@@ -171,27 +168,24 @@ fn parse_field(field_pair: Pair<Rule>) -> Field {
171168
}
172169
}
173170

174-
fn parse_value(value_pair: Pair<Rule>) -> Value {
171+
fn parse_value(value_pair: Pair<grammar::Rule>) -> Value {
175172
let expr_inner = value_pair
176173
.into_inner()
177174
.next()
178175
.expect("Expr must have inner value");
179176

180177
match expr_inner.as_rule() {
181-
Rule::Number => Value::Literal(
178+
grammar::Rule::Number => Value::Literal(
182179
i32::from_str_radix(expr_inner.as_str(), 10)
183180
.expect("Number type must be decimal integer"),
184181
),
185-
Rule::Label => Value::Label(expr_inner.as_str().to_owned()),
182+
grammar::Rule::Label => Value::Label(expr_inner.as_str().to_owned()),
186183
_ => unreachable!(),
187184
}
188185
}
189186

190187
#[cfg(test)]
191-
#[allow(clippy::cognitive_complexity)]
192188
mod tests {
193-
use pest::{consumes_to, parses_to};
194-
195189
use super::*;
196190

197191
#[test]
@@ -202,155 +196,6 @@ mod tests {
202196
assert_eq!(result.unwrap_err().details, "No input found");
203197
}
204198

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-
354199
#[test]
355200
fn duplicate_labels() {
356201
let simple_input = "
@@ -405,6 +250,4 @@ mod tests {
405250

406251
assert_eq!(parsed, expected_core);
407252
}
408-
409-
// TODO: parse error for unresolvable label
410253
}

0 commit comments

Comments
 (0)