feat(protocol): grammatica S-expression (15 verbi) + parser

Aggiunge il modulo `multi_swarm.protocol` con la grammatica del DSL di
strategia (15 verbi: 4 azioni, 3 logici, 3 comparatori, 4 dati, `when`
e `strategy`) e un parser che produce un AST tipizzato (Strategy/Rule/
Node). Lessing delegato a sexpdata, validazione del set di verbi e
forma `(when <cond> <action>)` gestita dal parser. Sollevata ParseError
su top-level malformato, strategia vuota, verbi sconosciuti o azioni
non terminali.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-05-09 19:30:54 +02:00
parent 7290900dc7
commit 19035812c3
4 changed files with 169 additions and 0 deletions
+47
View File
@@ -0,0 +1,47 @@
import pytest
from multi_swarm.protocol.grammar import VERBS
from multi_swarm.protocol.parser import ParseError, parse_strategy
def test_grammar_has_15_verbs():
assert len(VERBS) == 15
def test_parse_simple_strategy():
src = "(strategy (when (gt (indicator rsi 14) 70.0) (entry-short)))"
ast = parse_strategy(src)
assert ast.kind == "strategy"
assert len(ast.rules) == 1
rule = ast.rules[0]
assert rule.kind == "when"
assert rule.condition.kind == "gt"
assert rule.action.kind == "entry-short"
def test_parse_multiple_rules():
src = """
(strategy
(when (gt (indicator rsi 14) 70.0) (entry-short))
(when (lt (indicator rsi 14) 30.0) (entry-long)))
"""
ast = parse_strategy(src)
assert len(ast.rules) == 2
def test_parse_unknown_verb_raises():
src = "(strategy (when (frobnicate 1 2) (entry-long)))"
with pytest.raises(ParseError):
parse_strategy(src)
def test_parse_malformed_raises():
src = "(strategy (when"
with pytest.raises(ParseError):
parse_strategy(src)
def test_parse_empty_strategy_raises():
src = "(strategy)"
with pytest.raises(ParseError):
parse_strategy(src)