-
Notifications
You must be signed in to change notification settings - Fork 2
/
Copy pathparser.rs
76 lines (67 loc) · 2.13 KB
/
parser.rs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
use nom::{
branch::alt,
bytes::complete::tag,
character::complete::{char, digit1, line_ending, one_of, space1},
combinator::{map, map_res, opt, recognize},
multi::many1,
sequence::tuple,
IResult,
};
use crate::program::{Register, Operand, Instruction};
fn register(input: &str) -> IResult<&str, Register> {
let (remainder, matched_char) = one_of("wxyz")(input)?;
let register_id = match matched_char {
'w' => 0,
'x' => 1,
'y' => 2,
'z' => 3,
_ => unreachable!("{}", matched_char),
};
Ok((remainder, Register(register_id)))
}
fn text_signed_int(input: &str) -> IResult<&str, i64> {
map_res(recognize(tuple((opt(char('-')), digit1))), |value: &str| {
value.parse()
})(input)
}
fn operand(input: &str) -> IResult<&str, Operand> {
if let Ok((remainder, register)) = register(input) {
Ok((remainder, Operand::Register(register)))
} else {
map(text_signed_int, Operand::Literal)(input)
}
}
fn input_instruction(input: &str) -> IResult<&str, Instruction> {
map(
tuple((tag("inp"), space1, register, opt(line_ending))),
|(_, _, reg, _)| Instruction::Input(reg),
)(input)
}
fn binary_instruction(input: &str) -> IResult<&str, Instruction> {
map(
tuple((
alt((tag("add"), tag("mul"), tag("div"), tag("mod"), tag("eql"))),
space1,
register,
space1,
operand,
opt(line_ending),
)),
|(instr, _, reg, _, val, _)| match instr {
"add" => Instruction::Add(reg, val),
"mul" => Instruction::Mul(reg, val),
"div" => Instruction::Div(reg, val),
"mod" => Instruction::Mod(reg, val),
"eql" => Instruction::Equal(reg, val),
_ => unreachable!("{}", instr),
},
)(input)
}
fn instruction(input: &str) -> IResult<&str, Instruction> {
alt((input_instruction, binary_instruction))(input)
}
pub fn parse_program(input: &str) -> Vec<Instruction> {
let (remainder, program) = many1(instruction)(input).unwrap();
assert!(remainder.is_empty());
program
}