diff options
| author | tanaka takashi <isazaka@gmail.com> | 2026-07-12 16:03:29 +0900 |
|---|---|---|
| committer | tanaka takashi <isazaka@gmail.com> | 2026-07-12 16:03:29 +0900 |
| commit | 22f96694a96ed9fba169e77bc27d19d00edca083 (patch) | |
| tree | 8f59c1d3f211c296b005a3f6ede8206bc3675a68 /src/mml_composemusic_mcp/server.py | |
| parent | 3bb311ad8e0f10617805c8737d92d13e6a627818 (diff) | |
MML構文解析処理を追加
Diffstat (limited to 'src/mml_composemusic_mcp/server.py')
| -rw-r--r-- | src/mml_composemusic_mcp/server.py | 30 |
1 files changed, 24 insertions, 6 deletions
diff --git a/src/mml_composemusic_mcp/server.py b/src/mml_composemusic_mcp/server.py index 0a09131..de0ea82 100644 --- a/src/mml_composemusic_mcp/server.py +++ b/src/mml_composemusic_mcp/server.py @@ -6,10 +6,12 @@ from pathlib import Path from fastmcp import FastMCP -from .ir import ErrorCode, ErrorDetail, NoteSequence +from .ir import ErrorCode, ErrorDetail, ErrorPhase, NoteSequence from .lexer import tokenize from .parser_ppmck import parse_ppmck from .parser_pyxel import parse_pyxel +from .semantic_ppmck import analyze_ppmck +from .semantic_pyxel import analyze_pyxel from .synthesizer import build_channel_summary, synthesize, write_wav from .templates import get_template @@ -40,16 +42,25 @@ def _split_errors(errors: list[ErrorDetail]) -> tuple[list[dict], list[dict]]: return errs, warns -def _parse_mml(mml: str, mode: str) -> tuple[dict, list[ErrorDetail]]: +def _parse_mml(mml: str, mode: str) -> tuple[dict | None, list[ErrorDetail]]: + """Run lexer, parser, and semantic analyzer for the given mode.""" tokens = tokenize(mml, mode) + if mode == "ppmck": - note_sequence, errors = parse_ppmck(mml, tokens) + program, errors = parse_ppmck(mml, tokens) + if not _is_error(errors): + note_sequence, semantic_errors = analyze_ppmck(mml, program) + errors.extend(semantic_errors) elif mode == "pyxel": - note_sequence, errors = parse_pyxel(mml, tokens) + program, errors = parse_pyxel(mml, tokens) + if not _is_error(errors): + note_sequence, semantic_errors = analyze_pyxel(mml, program) + errors.extend(semantic_errors) else: errors = [ ErrorDetail( code=ErrorCode.VALIDATION_INVALID_MODE, + phase=ErrorPhase.API, line=0, column=0, message=f"未知のモード '{mode}' です。", @@ -58,6 +69,9 @@ def _parse_mml(mml: str, mode: str) -> tuple[dict, list[ErrorDetail]]: ) ] note_sequence = None + + if _is_error(errors): + note_sequence = None return (note_sequence.to_dict() if note_sequence else None), errors @@ -89,6 +103,7 @@ def compose_mml( "errors": [ { "code": ErrorCode.VALIDATION_MISSING_PARAMETER.value, + "phase": ErrorPhase.API.value, "line": 0, "column": 0, "message": "mml と mode は compose/validate の必須パラメータです。", @@ -136,7 +151,8 @@ def compose_mml( "validation": { "errors": [ { - "code": ErrorCode.SYSTEM_SYNTHESIS_FAILED.value, + "code": ErrorCode.RUNTIME_SYNTHESIS_FAILED.value, + "phase": ErrorPhase.RUNTIME.value, "line": 0, "column": 0, "message": f"音声合成中にエラーが発生しました: {exc}", @@ -177,7 +193,8 @@ def compose_mml( "validation": { "errors": [ { - "code": ErrorCode.SYSTEM_INTERNAL_ERROR.value, + "code": ErrorCode.RUNTIME_INTERNAL_ERROR.value, + "phase": ErrorPhase.RUNTIME.value, "line": 0, "column": 0, "message": f"内部エラーが発生しました: {exc}", @@ -195,6 +212,7 @@ def compose_mml( "errors": [ { "code": ErrorCode.VALIDATION_INVALID_ACTION.value, + "phase": ErrorPhase.API.value, "line": 0, "column": 0, "message": f"未知の action '{action}' です。", |
