67 lines
1.6 KiB
Python
67 lines
1.6 KiB
Python
|
|
import json
|
||
|
|
from dataclasses import dataclass
|
||
|
|
from typing import List, Dict, Any
|
||
|
|
from pathlib import Path
|
||
|
|
|
||
|
|
|
||
|
|
@dataclass
|
||
|
|
class XICInstruction:
|
||
|
|
op: str
|
||
|
|
args: List[Any]
|
||
|
|
|
||
|
|
|
||
|
|
@dataclass
|
||
|
|
class XICProgram:
|
||
|
|
magic: str
|
||
|
|
version: int
|
||
|
|
model: str
|
||
|
|
entrypoint: str
|
||
|
|
symbols: Dict[str, int]
|
||
|
|
instructions: List[XICInstruction]
|
||
|
|
|
||
|
|
|
||
|
|
class XICLoadError(Exception):
|
||
|
|
pass
|
||
|
|
|
||
|
|
|
||
|
|
def load_xic(path: str) -> XICProgram:
|
||
|
|
"""Load and validate an XIC program from JSON."""
|
||
|
|
try:
|
||
|
|
p = Path(path)
|
||
|
|
if not p.exists():
|
||
|
|
raise XICLoadError(f"File not found: {path}")
|
||
|
|
|
||
|
|
with open(p) as f:
|
||
|
|
data = json.load(f)
|
||
|
|
|
||
|
|
# Validate magic and version
|
||
|
|
magic = data.get("magic")
|
||
|
|
if magic != "GXIC1":
|
||
|
|
raise XICLoadError(f"Invalid magic: {magic} (expected GXIC1)")
|
||
|
|
|
||
|
|
version = data.get("version")
|
||
|
|
if version != 1:
|
||
|
|
raise XICLoadError(f"Unsupported version: {version}")
|
||
|
|
|
||
|
|
# Parse instructions
|
||
|
|
instructions = []
|
||
|
|
for instr in data.get("instructions", []):
|
||
|
|
instructions.append(XICInstruction(
|
||
|
|
op=instr["op"],
|
||
|
|
args=instr.get("args", [])
|
||
|
|
))
|
||
|
|
|
||
|
|
return XICProgram(
|
||
|
|
magic=magic,
|
||
|
|
version=version,
|
||
|
|
model=data.get("model", ""),
|
||
|
|
entrypoint=data.get("entrypoint", "main"),
|
||
|
|
symbols=data.get("symbols", {}),
|
||
|
|
instructions=instructions
|
||
|
|
)
|
||
|
|
|
||
|
|
except json.JSONDecodeError as e:
|
||
|
|
raise XICLoadError(f"Invalid JSON: {e}")
|
||
|
|
except Exception as e:
|
||
|
|
raise XICLoadError(f"Load failed: {e}")
|