use std::{iter::Peekable, str::FromStr, vec::IntoIter}; use super::{ Result, lexer::{Token, TokenKind}, util::{SpanParserError, TokenError}, }; use crate::program::{ChanSpec, Instruction}; use TokenKind as K; pub struct Parser<'s> { tokens: Peekable>>, spec: Option, eof: Token<'s>, } impl<'s> Parser<'s> { pub fn new(tokens: Vec>) -> Self { let eof = Token { span: tokens[tokens.len() - 1].span, content: "", kind: K::Eof, }; Self { tokens: tokens.into_iter().peekable(), spec: None, eof, } } fn next(&mut self) -> Token<'s> { self.tokens.next().unwrap_or(self.eof) } fn peek(&mut self) -> Token<'s> { self.tokens.peek().cloned().unwrap_or(self.eof) } fn expect(&mut self, kind: TokenKind) -> Result> { let token = self.next(); if token.kind == kind { Ok(token) } else { token.token_err(format!("expected {kind}, got {}", token.kind)) } } fn parse_int(&mut self) -> Result where T: FromStr, ::Err: std::error::Error, { let token = self.expect(K::Integer)?; token.content.parse().span_err(token.span) } fn parse_note(&mut self) -> Result { 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 { let n = self.parse_int::()?; Ok(n > 0) } fn parse_chan_ins(&mut self) -> Result { 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) } K::DutyCycle if spec == ChanSpec::PulseB => { let cycle = self.parse_int()?; Instruction::SetPulseDutyB(cycle) } K::DutyCycle => { return token.token_err("cannot set duty cycle for this channel"); } 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_pause_len(&mut self) -> Result { self.next(); let num = self.parse_int()?; Ok(Instruction::PauseLen(num)) } fn parse_pause(&mut self) -> Result { 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 { 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() } } } pub fn parse(&mut self) -> Result> { let mut prog = vec![]; loop { let token = self.peek(); match token.kind { K::Eof => break, K::LineSeparator => { self.next(); } _ => prog.push(self.parse_ins()?), } } Ok(prog) } }