summaryrefslogtreecommitdiff
path: root/tests/test_lexer.py
diff options
context:
space:
mode:
authortanaka takashi <isazaka@gmail.com>2026-07-12 17:58:19 +0900
committertanaka takashi <isazaka@gmail.com>2026-07-12 17:59:16 +0900
commitbf36a773918959eeb6ffe7dae2fb8b0874438eb4 (patch)
treeda7ff0037ea923fea255d2ed69ed2fb51395d9b9 /tests/test_lexer.py
parentf1cd4d7d16f6e75a50bb0c587c0f759f7cf710cd (diff)
feat(ppmck): mckc準拠の構文拡張とIR保持コマンド追加
- @をデューティ比、qをクオンタイズに修正(mckc原本準拠) - ^タイ、Dディチューン、sスイープ、v+/v-相対音量を追加 - @v/@@/@MP/@EP/@EN エンベロープ・LFO系を構文解析してIR保持 - 上記IR保持コマンドは合成未対応を SEMANTIC_UNSUPPORTED_FEATURE で警告 - Design.md / MML_BNF.md を更新 - 全200テスト + ruff チェック通過
Diffstat (limited to 'tests/test_lexer.py')
-rw-r--r--tests/test_lexer.py74
1 files changed, 73 insertions, 1 deletions
diff --git a/tests/test_lexer.py b/tests/test_lexer.py
index 64fa17c..1d7f8e7 100644
--- a/tests/test_lexer.py
+++ b/tests/test_lexer.py
@@ -4,12 +4,13 @@ from mml_composemusic_mcp.lexer import TokenType, tokenize
def test_ppmck_tokens():
- source = "A t150 l8 o4 v15 q2\nc d e f"
+ source = "A t150 l8 o4 v15 @2\nc d e f"
tokens = tokenize(source, "ppmck")
types = [t.type for t in tokens]
assert TokenType.TRACK_HEADER in types
assert TokenType.TEMPO in types
assert TokenType.NOTE in types
+ assert TokenType.DUTY in types
def test_pyxel_tokens():
@@ -35,3 +36,74 @@ def test_ppmck_invalid_token():
def test_pyxel_invalid_token():
tokens = tokenize("0: T120 L4 O4 X C", "pyxel")
assert any(t.type == TokenType.INVALID for t in tokens)
+
+
+def test_ppmck_at_duty():
+ tokens = tokenize("A @2 c", "ppmck")
+ assert any(t.type == TokenType.DUTY for t in tokens)
+
+
+def test_ppmck_quantize():
+ tokens = tokenize("A q4 c", "ppmck")
+ assert any(t.type == TokenType.QUANTIZE for t in tokens)
+
+
+def test_ppmck_tie_cmd():
+ tokens = tokenize("A c4 ^4", "ppmck")
+ assert any(t.type == TokenType.TIE_CMD for t in tokens)
+
+
+def test_ppmck_detune():
+ tokens = tokenize("A D10 c", "ppmck")
+ assert any(t.type == TokenType.DETUNE for t in tokens)
+
+
+def test_ppmck_sweep():
+ tokens = tokenize("A s1,2 c", "ppmck")
+ assert any(t.type == TokenType.SWEEP for t in tokens)
+
+
+def test_ppmck_rel_vol():
+ tokens = tokenize("A v+5 v-3 c", "ppmck")
+ assert any(t.type == TokenType.REL_VOL_UP for t in tokens)
+ assert any(t.type == TokenType.REL_VOL_DOWN for t in tokens)
+
+
+def test_ppmck_vol_env():
+ tokens = tokenize("A @v0 c", "ppmck")
+ assert any(t.type == TokenType.VOL_ENV for t in tokens)
+
+
+def test_ppmck_vol_env_def():
+ tokens = tokenize("@v0 = { 15, 10, | 5 }", "ppmck")
+ assert any(t.type == TokenType.VOL_ENV for t in tokens)
+ assert any(t.type == TokenType.BRACE_OPEN for t in tokens)
+ assert any(t.type == TokenType.BRACE_CLOSE for t in tokens)
+
+
+def test_ppmck_lfo_def():
+ tokens = tokenize("@MP0 = { 0, 10, 5, 0 }", "ppmck")
+ assert any(t.type == TokenType.LFO_DEF for t in tokens)
+
+
+def test_ppmck_lfo_use_off():
+ tokens = tokenize("A MP1 MPOF c", "ppmck")
+ assert any(t.type == TokenType.LFO_USE for t in tokens)
+ assert any(t.type == TokenType.LFO_OFF for t in tokens)
+
+
+def test_ppmck_pitch_env():
+ tokens = tokenize("A EP1 EPOF c", "ppmck")
+ assert any(t.type == TokenType.PITCH_ENV_USE for t in tokens)
+ assert any(t.type == TokenType.PITCH_ENV_OFF for t in tokens)
+
+
+def test_ppmck_note_env():
+ tokens = tokenize("A EN1 ENOF c", "ppmck")
+ assert any(t.type == TokenType.NOTE_ENV_USE for t in tokens)
+ assert any(t.type == TokenType.NOTE_ENV_OFF for t in tokens)
+
+
+def test_ppmck_duty_env_use():
+ tokens = tokenize("A @@0 c", "ppmck")
+ assert any(t.type == TokenType.DUTY_ENV_USE for t in tokens)