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
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
|
use std::iter::Peekable;
use crate::audio::program::{ChanSpec, Instruction};
use super::{
Result,
lex::{Lexer, Token},
};
pub struct Parser<'s> {
lexer: Peekable<Lexer<'s>>,
}
impl<'s> Parser<'s> {
pub fn new(src: &'s str) -> Self {
Self {
lexer: Lexer::new(src).peekable(),
}
}
fn next(&mut self) -> Result<Token> {
self.lexer
.next()
.unwrap_or_else(|| Err("should not happen".to_owned()))
}
fn peek(&mut self) -> Result<Token> {
self.lexer
.peek()
.map_or_else(|| Err("should not happen".to_owned()), Result::clone)
}
fn parse_chan_spec(&mut self) -> Result<ChanSpec> {
match self.next()? {
Token::ChanSpec(spec) => Ok(spec),
t => Err(format!("expected channel specifier, got {t:?}")),
}
}
fn parse_ins(&mut self, spec: ChanSpec) -> Result<Instruction> {
use Token as T;
let t = self.next()?;
let ins = match t {
T::SetPitch(pitch) => Instruction::SetPitch(spec, pitch),
T::SetVolume(volume) => Instruction::SetVolume(spec, volume),
T::SetNoiseMode(mode) if spec == ChanSpec::Noise => {
Instruction::SetNoiseMode(mode)
}
T::SetPulseDuty(duty_cycle) if spec == ChanSpec::PulseA => {
Instruction::SetPulseDutyA(duty_cycle)
}
T::SetPulseDuty(duty_cycle) if spec == ChanSpec::PulseB => {
Instruction::SetPulseDutyB(duty_cycle)
}
_ => unexpected(t)?,
};
Ok(ins)
}
fn parse_line(&mut self, prog: &mut Vec<Instruction>) -> Result<()> {
let spec = self.parse_chan_spec()?;
loop {
prog.push(self.parse_ins(spec)?);
let peek = self.peek()?;
if peek.is_eol() || matches!(peek, Token::Pause(_)) {
break;
}
}
Ok(())
}
pub fn parse(&mut self) -> Result<Vec<Instruction>> {
let mut prog = vec![];
loop {
let t = self.peek()?;
match t {
Token::Eof => break,
Token::LineSeparator => {
self.next()?;
}
Token::Pause(count) => {
self.next()?;
for _ in 0..count {
prog.push(Instruction::Pause);
}
}
Token::Jump(pc) => {
self.next()?;
prog.push(Instruction::Jump(pc));
}
_ => self.parse_line(&mut prog)?,
}
}
Ok(prog)
}
}
fn unexpected<T>(t: Token) -> Result<T> {
let msg = format!("unexpected token: {t:?}");
Err(msg)
}
|