File size: 3,913 Bytes
ed6bec6 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 |
from typing import List, Dict, Any
from .glyph_dictionary_loader import get_dictionary
from .glyph_validator import validate_sequence, validate_roles
class GlyphSyntaxError(Exception): #strict syntax order of glyphs
pass
ROLE_ORDER = [
"actor",
"action",
"object",
"modifier",
"context"
]
CONTEXT_ORDER = [
"place",
"time",
"emotion",
"sensory",
"social"
]
def _get_role(entry: Dict[str, Any]) -> str:
"""Return the highest-priority role for a glyph."""
roles = entry.get("roles", [])
for r in ROLE_ORDER:
if r in roles:
return r
return "context"
def _get_context_type(entry: Dict[str, Any]) -> str:
"""Return the context subtype."""
category = entry.get("category", "")
if category.startswith("context_place"):
return "place"
if category.startswith("context_time"):
return "time"
if category.startswith("context_emotion") or category.startswith("emotion_context"):
return "emotion"
if category.startswith("context_sensory") or category.startswith("sensory_context"):
return "sensory"
if category.startswith("context_social") or category.startswith("social_context"):
return "social"
return "unknown"
def parse_syntax(glyphs: List[str]) -> Dict[str, Any]:
"""
Strict syntax parser enforcing:
- required roles
- strict ordering
- single actor/action/object
- context last
- deterministic structure
"""
validate_sequence(glyphs)
validate_roles(glyphs)
dictionary = get_dictionary()
syntax_tree = {
"actor": None,
"action": None,
"object": None,
"modifiers": [],
"context": {
"place": [],
"time": [],
"emotion": [],
"sensory": [],
"social": []
},
"raw": glyphs
}
last_role_index = -1
last_context_index = -1
for g in glyphs:
entries = dictionary.get_entry_by_glyph(g)
entry = entries[0] # canonical
role = _get_role(entry)
# Enforce ordering
role_index = ROLE_ORDER.index(role)
if role_index < last_role_index:
raise GlyphSyntaxError(
f"Invalid ordering: {g} ({role}) appears after a later role."
)
last_role_index = role_index
# Assign roles
if role == "actor":
if syntax_tree["actor"] is not None:
raise GlyphSyntaxError("Multiple actors not allowed.")
syntax_tree["actor"] = entry
elif role == "action":
if syntax_tree["action"] is not None:
raise GlyphSyntaxError("Multiple actions not allowed.")
syntax_tree["action"] = entry
elif role == "object":
if syntax_tree["object"] is not None:
raise GlyphSyntaxError("Multiple objects not allowed.")
syntax_tree["object"] = entry
elif role == "modifier":
syntax_tree["modifiers"].append(entry)
elif role == "context":
ctx_type = _get_context_type(entry)
if ctx_type == "unknown":
raise GlyphSyntaxError(f"Unknown context type for glyph {g}")
# Enforce context ordering
ctx_index = CONTEXT_ORDER.index(ctx_type)
if ctx_index < last_context_index:
raise GlyphSyntaxError(
f"Context out of order: {ctx_type} appears after later context."
)
last_context_index = ctx_index
syntax_tree["context"][ctx_type].append(entry)
return syntax_tree
def get_syntax_tree(glyphs: List[str]) -> Dict[str, Any]:
return parse_syntax(glyphs)
def is_valid_order(glyphs: List[str]) -> bool:
try:
parse_syntax(glyphs)
return True
except Exception:
return False
|