Files
2125_GCE/glyphos/control/predicate.py
T

79 lines
2.5 KiB
Python
Raw Normal View History

"""
Safe predicate evaluator for XIC v2 control flow.
Supports simple expressions referencing fused symbol fields and helper functions.
Allowed: comparisons, boolean ops, dominant_contains('glyph://id').
"""
import ast
from typing import Any, Dict
ALLOWED_NODE_TYPES = (
ast.Expression, ast.BoolOp, ast.BinOp, ast.UnaryOp, ast.Compare,
ast.Name, ast.Load, ast.Constant, ast.Call, ast.Attribute,
ast.And, ast.Or, ast.Not,
ast.Gt, ast.Lt, ast.GtE, ast.LtE, ast.Eq, ast.NotEq, ast.In, ast.NotIn
)
def _validate_node(node: ast.AST):
"""Recursively validate AST node is safe for eval."""
if not isinstance(node, ALLOWED_NODE_TYPES):
raise ValueError(f"Unsafe predicate node: {type(node).__name__}")
for child in ast.iter_child_nodes(node):
_validate_node(child)
class DotDict:
"""Helper class that allows dict access via dot notation."""
def __init__(self, data: Dict[str, Any]):
self.__dict__.update(data)
def _build_context(fused: Dict[str, Any], dominant: list):
"""Build safe evaluation context with helpers and fused symbol fields."""
def dominant_contains(glyph_id: str) -> bool:
"""Check if a glyph is in the dominant list."""
return any(g == glyph_id for g, _ in dominant)
safe = {
"dominant_contains": dominant_contains,
"fused": DotDict(fused or {}),
}
return safe
def eval_predicate(
expr: str,
fused: Dict[str, Any] | None = None,
dominant: list | None = None
) -> bool:
"""
Evaluate predicate expression safely.
Example predicates:
"fused.global_resonance_score > 0.7"
"dominant_contains('glyph://entropy') and fused.global_resonance_score > 0.5"
Args:
expr: Predicate expression string
fused: Fused symbol dict with fields like global_resonance_score, glyph_ids
dominant: List of (glyph_id, weight) tuples for dominant glyphs
Returns:
Boolean result of predicate evaluation
"""
if dominant is None:
dominant = []
# Parse and validate AST
try:
expr_ast = ast.parse(expr, mode="eval")
except SyntaxError as e:
raise ValueError(f"Invalid predicate syntax: {e}")
_validate_node(expr_ast)
# Compile and evaluate
compiled = compile(expr_ast, "<predicate>", "eval")
safe_ctx = _build_context(fused or {}, dominant)
try:
return bool(eval(compiled, {}, safe_ctx))
except Exception as e:
raise ValueError(f"Predicate evaluation error: {e}")