app.engine.dsl_interpreter module

Walker-based interpreter for the strategy DSL.

This is the sandbox. It walks the JSON AST node-by-node, dispatching on node["type"] through a fixed handler table - no getattr, no eval, no exec. Anything not in the handler table is rejected as DslValidationError (the validator should have caught it; the runtime check is defence in depth).

Hard guarantees:

  • No code path exposes Python attribute lookup to AST-supplied strings.

  • Field access is a frozen-dict lookup; the resolved values were precomputed by ExecutionContext.build_for_ast.

  • Node count and recursion depth are bounded - the validator already rejects programs that would exceed them; the runtime guards exist so that future dynamic expansion (e.g. macros) still can’t blow out.

  • await asyncio.sleep(0) every yield_every visits gives the event loop a chance to actually cancel the coroutine when asyncio.wait_for fires. Without it a CPU-bound walk would run to completion and only then see the timeout - which is what RestrictedPython-style sandboxes generally get wrong.

Execution semantics mirror app/engine/default.py:

  • Rules are evaluated in order.

  • The first assign_points reached in a matched rule sets the result and halts the program (early-return). set_callback_data statements before the assignment accumulate into a dict; statements after the assignment never run.

  • If no rule matches, the program’s default section runs (if any); otherwise the result is (0, None, {}).

class app.engine.dsl_interpreter.DslExecutionResult[source]

Bases: TypedDict