Support both old and new sompyler AST slot names in parser

Pre-c3b51bc sompyler emits offset.stem_note/motif.stem_note/clause.note
while new sompyler emits line.stem_note/seq.note. Parser now accepts both
parentSlot values for stem_note, motif, and clause children so the app
works against both old and updated sompyler installations.

Also falls back to reading chain.clause directly from stem_note's children
when no stem_note.chain node is present (old format had no chain wrapper).
This commit is contained in:
c0dev0id
2026-06-27 20:08:31 +02:00
parent 859e62e143
commit b56d84befb
2 changed files with 38 additions and 8 deletions

View File

@@ -520,6 +520,36 @@ let nsThrew = false;
try { parseAstLog(NS_FIXTURE); } catch (e) { nsThrew = true; }
ok('missing slot throws', nsThrew);
section('Old-format AST (pre-c3b51bc sompyler) backward compat');
const OLD_OFFSET_FIXTURE = `00 bar '001P1L1M1'
01 bar.voice 'pi'
02 voice.offset tick=0
03 offset.stem_note pitch='C4'
04 chain.clause 0 repeat=1
05 clause.note letter='o' shift=0 length=1 netlength=1
05 clause.pause length=1
`;
const oldOffset = buildModel(parseAstLog(OLD_OFFSET_FIXTURE)).bars[0].voices['pi'].offsets[0];
ok('old-fmt: offset has stem note', oldOffset.stemNotes.length === 1);
ok('old-fmt: stem note pitch', oldOffset.stemNotes[0].pitch === 'C4');
ok('old-fmt: clause found via direct child', oldOffset.stemNotes[0].clauses.length === 1);
ok('old-fmt: clause.note found', oldOffset.stemNotes[0].clauses[0].notes.length === 1);
ok('old-fmt: clause.pause found', oldOffset.stemNotes[0].clauses[0].pauses.length === 1);
const OLD_MOTIF_FIXTURE = `00 bar '001P1L1M1'
01 bar.voice 'pi'
02 voice.motif label='oct'
03 motif.stem_note pitch=0
04 chain.clause 0 repeat=1
05 clause.note letter='o' shift=0 length=1 netlength=1
05 clause.note letter='o' shift=12 netlength=1 length=1
`;
const oldMotif = buildModel(parseAstLog(OLD_MOTIF_FIXTURE)).bars[0].voices['pi'].motifs[0];
ok('old-fmt: motif stem note found', oldMotif.stemNotes.length === 1);
ok('old-fmt: motif pitch=0 isStatic=false', oldMotif.isStatic === false);
ok('old-fmt: motif clause found', oldMotif.stemNotes[0].clauses.length === 1);
ok('old-fmt: motif clause notes', oldMotif.stemNotes[0].clauses[0].notes.length === 2);
section('line.motif invocation at offset');
const LM_FIXTURE = `00 bar '001P1L1M1'
01 bar.voice 'pi'