Skip to content

Commit 99e1539

Browse files
Clean up grammar slightly
1 parent 9977c4d commit 99e1539

File tree

3 files changed

+56
-44
lines changed

3 files changed

+56
-44
lines changed

src/data/redcode.pest

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,13 @@ WHITESPACE = _{ " " | "\t" }
22

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

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

7-
Line = { Instruction? ~ NEWLINE }
7+
Line = { LabelDeclaration* ~ Instruction? }
88

9-
Instruction = _{ LabelList ~ Operation ~ Field ~ ("," ~ Field)? }
9+
Instruction = _{ Operation ~ Field ~ ("," ~ Field)? }
1010

11-
LabelList = _{ (!Operation ~ Label ~ NEWLINE*)* }
11+
LabelDeclaration = _{ !Operation ~ Label ~ (":")? }
1212

1313
Label = @{ Alpha ~ Alphanumeral* }
1414

@@ -26,7 +26,7 @@ Modifier = { ^"AB" | ^"BA" | ^"A" | ^"B" | ^"F" | ^"X" | ^"I" }
2626

2727
AddressMode = { "#" | "$" | "*" | "@" | "{" | "<" | "}" | ">" }
2828

29-
Expr = { Number }
29+
Expr = { Number | Label }
3030

3131
Number = @{ ASCII_DIGIT+ }
3232

src/parser.rs

Lines changed: 46 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,12 @@ use std::{error, fmt, str::FromStr};
22

33
use itertools::Itertools;
44
use pest::{
5-
error::Error as PestError,
5+
error::{Error as PestError, ErrorVariant, LineColLocation},
66
iterators::{Pair, Pairs},
77
Parser,
88
};
99

10-
use crate::load_file::{AddressMode, Core, Field, Instruction, Modifier, Opcode};
10+
use crate::load_file::{AddressMode, Core, Field, Instruction, Modifier, Opcode, Value};
1111

1212
#[derive(Debug)]
1313
pub struct Error {
@@ -30,13 +30,25 @@ impl Error {
3030
}
3131
}
3232

33-
impl<Rule> From<PestError<Rule>> for Error {
33+
impl From<PestError<Rule>> for Error {
3434
fn from(pest_error: PestError<Rule>) -> Error {
3535
Error {
3636
details: format!(
37-
"Error parsing rule '{}' at location '{:?}",
38-
stringify!(Rule),
39-
pest_error.line_col
37+
"Parse error: {} {}",
38+
match pest_error.variant {
39+
ErrorVariant::ParsingError {
40+
positives,
41+
negatives,
42+
} => format!("expected one of {:?}, none of {:?}", positives, negatives),
43+
ErrorVariant::CustomError { message } => message,
44+
},
45+
match pest_error.line_col {
46+
LineColLocation::Pos((line, col)) => format!("at line {} column {}", line, col),
47+
LineColLocation::Span((start_line, start_col), (end_line, end_col)) => format!(
48+
"from line {} column {} to line {} column {}",
49+
start_line, start_col, end_line, end_col
50+
),
51+
}
4052
),
4153
}
4254
}
@@ -59,7 +71,7 @@ pub fn parse(file_contents: &str) -> Result<Core, Error> {
5971

6072
let mut core = Core::default();
6173

62-
let parse_result = RedcodeParser::parse(Rule::AssemblyFile, file_contents)?
74+
let parse_result = RedcodeParser::parse(Rule::RedcodeFile, file_contents)?
6375
.next()
6476
.ok_or_else(Error::no_input)?;
6577

@@ -152,8 +164,12 @@ fn parse_field(field_pair: Pair<Rule>) -> Field {
152164
}
153165
}
154166

155-
fn parse_value(value_pair: Pair<Rule>) -> i32 {
156-
i32::from_str_radix(value_pair.as_str(), 10).unwrap()
167+
fn parse_value(value_pair: Pair<Rule>) -> Value {
168+
if value_pair.as_rule() == Rule::Number {
169+
Value::Literal(i32::from_str_radix(value_pair.as_str(), 10).unwrap())
170+
} else {
171+
Value::Label(value_pair.as_str().to_owned())
172+
}
157173
}
158174

159175
#[cfg(test)]
@@ -270,37 +286,31 @@ mod tests {
270286

271287
#[test]
272288
fn parse_label() {
273-
parses_to! {
274-
parser: RedcodeParser,
275-
input: "some_label\nsome_label2 dat 0, 0",
276-
rule: Rule::Instruction,
277-
tokens: [
278-
Label(0, 10),
279-
Label(11, 22),
280-
Operation(23, 26, [
281-
Opcode(23, 26)
282-
]),
283-
Field(27, 28, [
284-
Expr(27, 28, [
285-
Number(27, 28)
286-
])
287-
]),
288-
Field(30, 31, [
289-
Expr(30, 31, [
290-
Number(30, 31)
291-
])
292-
]),
293-
]
289+
for &(label_input, start, end) in [
290+
("some_label", 0, 10),
291+
("some_label2", 0, 11),
292+
("a: ", 0, 1),
293+
(" a ", 1, 2),
294+
("a :", 0, 1),
295+
]
296+
.iter()
297+
{
298+
parses_to! {
299+
parser: RedcodeParser,
300+
input: label_input,
301+
rule: Rule::LabelDeclaration,
302+
tokens: [Label(start, end)]
303+
}
294304
}
295305
}
296306

297307
#[test]
298308
fn parse_simple_file() {
299309
let simple_input = "
300-
begin
301-
mov 1, 3 ; make sure comments parse out
310+
preload
311+
begin: mov 1, 3 ; make sure comments parse out
302312
mov 100, #12
303-
loop
313+
loop:
304314
main dat 0, 0
305315
jmp 123, 45
306316
";
@@ -317,15 +327,15 @@ mod tests {
317327
);
318328
expected_core.set(
319329
2,
320-
Instruction::new(Opcode::Dat, Field::direct(0), Field::direct(0)),
330+
Instruction::new(Opcode::Dat, Field::immediate(0), Field::immediate(0)),
321331
);
322332
expected_core.set(
323333
3,
324334
Instruction::new(Opcode::Jmp, Field::direct(123), Field::direct(45)),
325335
);
326336

327-
expected_core.add_labels(0, vec!["begin"]).unwrap();
328-
expected_core.add_labels(2, vec!["main", "loop"]).unwrap();
337+
expected_core.add_labels(0, &["preload", "begin"]).unwrap();
338+
expected_core.add_labels(2, &["loop", "main"]).unwrap();
329339

330340
assert_eq!(parse(simple_input).unwrap(), expected_core);
331341
}

tests/dump.rs

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,13 @@
11
extern crate corewa_rs;
22

33
fn run_test(input: &str, expected_output: &str) {
4-
eprintln!("Parsing warrior:\n{}", input);
4+
eprintln!("Parsing warrior:");
5+
eprintln!("{}", input);
56

6-
let core = corewa_rs::parse(input).expect("Failed to parse test_file.red");
7+
let core = corewa_rs::parse(input).expect("Failed to parse input");
78

8-
eprintln!("Loaded core:\n{:?}", core);
9+
eprintln!("Loaded core:");
10+
eprintln!("{:?}", core);
911

1012
assert_eq!(core.dump(), expected_output);
1113
}

0 commit comments

Comments
 (0)