diff options
Diffstat (limited to 'audio/src/parse/parser.rs')
| -rw-r--r-- | audio/src/parse/parser.rs | 232 |
1 files changed, 167 insertions, 65 deletions
diff --git a/audio/src/parse/parser.rs b/audio/src/parse/parser.rs index b46e707..989a6f1 100644 --- a/audio/src/parse/parser.rs +++ b/audio/src/parse/parser.rs @@ -1,104 +1,206 @@ -use std::iter::Peekable; - -use crate::program::{ChanSpec, Instruction}; +use std::{iter::Peekable, str::FromStr, vec::IntoIter}; use super::{ Result, - lex::{Lexer, Token}, + lexer::{Token, TokenKind}, + util::{SpanParserError, TokenError}, }; +use crate::program::{ChanSpec, Instruction}; +use TokenKind as K; pub struct Parser<'s> { - lexer: Peekable<Lexer<'s>>, + tokens: Peekable<IntoIter<Token<'s>>>, + spec: Option<ChanSpec>, + eof: Token<'s>, } impl<'s> Parser<'s> { - pub fn new(src: &'s str) -> Self { + pub fn new(tokens: Vec<Token<'s>>) -> Self { + let eof = Token { + span: tokens[tokens.len() - 1].span, + content: "", + kind: K::Eof, + }; Self { - lexer: Lexer::new(src).peekable(), + tokens: tokens.into_iter().peekable(), + spec: None, + eof, } } - fn next(&mut self) -> Result<Token> { - self.lexer - .next() - .unwrap_or_else(|| Err("should not happen".to_owned())) + fn next(&mut self) -> Token<'s> { + self.tokens.next().unwrap_or(self.eof) } - fn peek(&mut self) -> Result<Token> { - self.lexer - .peek() - .map_or_else(|| Err("should not happen".to_owned()), Result::clone) + fn peek(&mut self) -> Token<'s> { + self.tokens.peek().cloned().unwrap_or(self.eof) } - 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 expect(&mut self, kind: TokenKind) -> Result<Token<'s>> { + let token = self.next(); + if token.kind == kind { + Ok(token) + } else { + token.token_err(format!("expected {kind}, got {}", token.kind)) } } - 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) + fn parse_int<T>(&mut self) -> Result<T> + where + T: FromStr, + <T as FromStr>::Err: std::error::Error, + { + let token = self.expect(K::Integer)?; + token.content.parse().span_err(token.span) + } + + fn parse_note(&mut self) -> Result<u8> { + if self.peek().kind == K::Integer { + return self.parse_int(); + } + + let ident = self.expect(K::Identifier)?; + let str = ident.content; + let str_len = str.len(); + let last = str.chars().last().unwrap_or_default(); + + let note_str = &str[..1]; + let note = match note_str { + "a" => 80, + "b" => 82, + "c" => 83, + "d" => 85, + "e" => 87, + "f" => 88, + "g" => 90, + _ => return ident.token_err("invalid note"), + }; + + let octave_str = if last.is_ascii_digit() { + &str[1..str_len] + } else { + &str[1..str_len - 1] + }; + let octave = if !octave_str.is_empty() { + octave_str.parse().span_err(ident.span)? + } else { + 4 + }; + + let off = match last { + 'b' | 'f' => -1, + '#' | 's' => 1, + _ => 0, + }; + + let pitch_u32 = (note + octave * 12) + off; + let pitch = u8::try_from(pitch_u32).span_err(ident.span)?; + + Ok(pitch) + } + + fn parse_bool(&mut self) -> Result<bool> { + let n = self.parse_int::<u8>()?; + Ok(n > 0) + } + + fn parse_chan_ins(&mut self) -> Result<Instruction> { + let token = self.next(); + let Some(spec) = self.spec else { + return token.token_err("missing channel specifier"); + }; + let ins = match token.kind { + K::Volume => { + let volume = self.parse_int()?; + Instruction::SetVolume(spec, volume) + } + K::Pitch => { + let pitch = self.parse_note()?; + Instruction::SetPitch(spec, pitch) + } + K::DutyCycle if spec == ChanSpec::PulseA => { + let cycle = self.parse_int()?; + Instruction::SetPulseDutyA(cycle) } - T::SetPulseDuty(duty_cycle) if spec == ChanSpec::PulseA => { - Instruction::SetPulseDutyA(duty_cycle) + K::DutyCycle if spec == ChanSpec::PulseB => { + let cycle = self.parse_int()?; + Instruction::SetPulseDutyB(cycle) } - T::SetPulseDuty(duty_cycle) if spec == ChanSpec::PulseB => { - Instruction::SetPulseDutyB(duty_cycle) + K::DutyCycle => { + return token.token_err("cannot set duty cycle for this channel"); } - _ => unexpected(t)?, + K::Mode if spec == ChanSpec::Noise => { + let mode = self.parse_bool()?; + Instruction::SetNoiseMode(mode) + } + K::Mode => return token.token_err("cannot set mode for this channel"), + _ => return token.token_err("invalid channel argument"), }; 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; + fn parse_pause_len(&mut self) -> Result<Instruction> { + self.next(); + let num = self.parse_int()?; + Ok(Instruction::PauseLen(num)) + } + + fn parse_pause(&mut self) -> Result<Instruction> { + self.next(); + let next = self.peek(); + let ins = if next.kind == K::Integer { + let num = self.parse_int()?; + Instruction::Pause(num) + } else { + Instruction::Pause(1) + }; + Ok(ins) + } + + fn parse_ins(&mut self) -> Result<Instruction> { + let token = self.peek(); + let spec = self.spec.take(); + match token.kind { + K::PulseA => { + self.spec = Some(ChanSpec::PulseA); + self.next(); + self.parse_chan_ins() + } + K::PulseB => { + self.spec = Some(ChanSpec::PulseB); + self.next(); + self.parse_chan_ins() + } + K::Triangle => { + self.spec = Some(ChanSpec::Triangle); + self.next(); + self.parse_chan_ins() + } + K::Noise => { + self.spec = Some(ChanSpec::Noise); + self.next(); + self.parse_chan_ins() + } + K::PauseLen => self.parse_pause_len(), + K::Dash => self.parse_pause(), + _ => { + self.spec = spec; + self.parse_chan_ins() } } - 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()?; + let token = self.peek(); + match token.kind { + K::Eof => break, + K::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)); - } - Token::PauseLen(pause_len) => { - self.next()?; - prog.push(Instruction::PauseLen(pause_len)); - } - _ => self.parse_line(&mut prog)?, + _ => prog.push(self.parse_ins()?), } } Ok(prog) } } - -fn unexpected<T>(t: Token) -> Result<T> { - let msg = format!("unexpected token: {t:?}"); - Err(msg) -} |