mirror of
https://github.com/imjasonh/nescript
synced 2026-07-09 09:18:01 +00:00
Parser: audio statements (play / start_music / stop_music)
The \`play\`, \`start_music\`, and \`stop_music\` keywords were lexed
but not parsed. Programs using them failed with a generic "unexpected
token" error. Now:
- \`Statement::Play(sfx_name, span)\`
- \`Statement::StartMusic(track_name, span)\`
- \`Statement::StopMusic(span)\`
parse successfully and flow through analyzer / IR lowering / codegen
as no-ops. Semantics match the spec but produce no output — no audio
driver exists yet. Users who need sound can still wire in custom
code via \`asm { ... }\` blocks.
https://claude.ai/code/session_01W6eQFStA66EuMKHUFo2rx3
This commit is contained in:
parent
59970a4a45
commit
e16b765959
6 changed files with 67 additions and 2 deletions
|
|
@ -974,6 +974,11 @@ impl Analyzer {
|
|||
// codegen parses and validates the body; analysis has
|
||||
// nothing to check.
|
||||
}
|
||||
Statement::Play(_, _) | Statement::StartMusic(_, _) | Statement::StopMusic(_) => {
|
||||
// Audio statements are parsed and recognized but
|
||||
// currently generate no code — no audio driver exists.
|
||||
// Users who need audio can use inline `asm` blocks.
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1219,7 +1224,10 @@ fn collect_calls_stmt(stmt: &Statement, calls: &mut Vec<String>) {
|
|||
| Statement::Continue(_)
|
||||
| Statement::LoadBackground(_, _)
|
||||
| Statement::SetPalette(_, _)
|
||||
| Statement::InlineAsm(_, _) => {}
|
||||
| Statement::InlineAsm(_, _)
|
||||
| Statement::Play(_, _)
|
||||
| Statement::StartMusic(_, _)
|
||||
| Statement::StopMusic(_) => {}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -370,6 +370,9 @@ impl CodeGen {
|
|||
self.emit(BRK, AM::Implied);
|
||||
}
|
||||
},
|
||||
Statement::Play(_, _) | Statement::StartMusic(_, _) | Statement::StopMusic(_) => {
|
||||
// Audio statements compile to no-ops for now.
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -344,6 +344,10 @@ impl LoweringContext {
|
|||
Statement::InlineAsm(body, _) => {
|
||||
self.emit(IrOp::InlineAsm(body.clone()));
|
||||
}
|
||||
Statement::Play(_, _) | Statement::StartMusic(_, _) | Statement::StopMusic(_) => {
|
||||
// No audio driver yet — these parse but produce no
|
||||
// IR.
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -286,6 +286,15 @@ pub enum Statement {
|
|||
/// Inline 6502 assembly captured verbatim. The body is parsed by
|
||||
/// the codegen stage using `asm::parse_inline`.
|
||||
InlineAsm(String, Span),
|
||||
/// Audio: `play SfxName` — trigger a one-shot sound effect.
|
||||
/// Currently a no-op at codegen time; no audio driver exists.
|
||||
Play(String, Span),
|
||||
/// Audio: `start_music TrackName` — begin playing background music.
|
||||
/// Currently a no-op at codegen time.
|
||||
StartMusic(String, Span),
|
||||
/// Audio: `stop_music` — stop any currently-playing music.
|
||||
/// Currently a no-op at codegen time.
|
||||
StopMusic(Span),
|
||||
}
|
||||
|
||||
impl Statement {
|
||||
|
|
@ -308,7 +317,10 @@ impl Statement {
|
|||
| Self::Scroll(_, _, s)
|
||||
| Self::DebugLog(_, s)
|
||||
| Self::DebugAssert(_, s)
|
||||
| Self::InlineAsm(_, s) => *s,
|
||||
| Self::InlineAsm(_, s)
|
||||
| Self::Play(_, s)
|
||||
| Self::StartMusic(_, s)
|
||||
| Self::StopMusic(s) => *s,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -899,6 +899,23 @@ impl Parser {
|
|||
Ok(Statement::Scroll(x, y, span))
|
||||
}
|
||||
TokenKind::KwDebug => self.parse_debug_statement(),
|
||||
TokenKind::KwPlay => {
|
||||
let span = self.current_span();
|
||||
self.advance();
|
||||
let (name, _) = self.expect_ident()?;
|
||||
Ok(Statement::Play(name, span))
|
||||
}
|
||||
TokenKind::KwStartMusic => {
|
||||
let span = self.current_span();
|
||||
self.advance();
|
||||
let (name, _) = self.expect_ident()?;
|
||||
Ok(Statement::StartMusic(name, span))
|
||||
}
|
||||
TokenKind::KwStopMusic => {
|
||||
let span = self.current_span();
|
||||
self.advance();
|
||||
Ok(Statement::StopMusic(span))
|
||||
}
|
||||
TokenKind::KwAsm => {
|
||||
let span = self.current_span();
|
||||
self.advance(); // KwAsm
|
||||
|
|
|
|||
|
|
@ -665,6 +665,27 @@ fn parse_mmc3_mapper() {
|
|||
assert_eq!(prog.game.mapper, Mapper::MMC3);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn parse_audio_statements() {
|
||||
let src = r#"
|
||||
game "Audio" { mapper: NROM }
|
||||
on frame {
|
||||
play JumpSfx
|
||||
start_music MainTheme
|
||||
stop_music
|
||||
}
|
||||
start Main
|
||||
"#;
|
||||
let prog = parse_ok(src);
|
||||
let frame = prog.states[0].on_frame.as_ref().unwrap();
|
||||
assert!(matches!(frame.statements[0], Statement::Play(ref n, _) if n == "JumpSfx"));
|
||||
assert!(matches!(
|
||||
frame.statements[1],
|
||||
Statement::StartMusic(ref n, _) if n == "MainTheme"
|
||||
));
|
||||
assert!(matches!(frame.statements[2], Statement::StopMusic(_)));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn parse_struct_decl() {
|
||||
let src = r#"
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue