Download src/semantic_engine/subleq.py from Snapkitty/semantic-engine: direct link, hf CLI and curl.
- Browser
- Download file 9.57 kB
-
https://huggingface.co/Snapkitty/semantic-engine/resolve/main/src/semantic_engine/subleq.py
- Command line
-
hf download hf://Snapkitty/semantic-engine/src/semantic_engine/subleq.py
-
curl -L -o subleq.py https://huggingface.co/Snapkitty/semantic-engine/resolve/main/src/semantic_engine/subleq.py
9.57 kB
| # This Source Code Form is subject to the terms of the Mozilla Public | |
| # License, v. 2.0. If a copy of the MPL was not distributed with this | |
| # file, You can obtain one at https://mozilla.org/MPL/2.0/. | |
| """Phases 12β13: SUBLEQ IR and VM. | |
| SUBLEQ(A, B, C): mem[B] = mem[B] - mem[A]; if mem[B] <= 0: goto C | |
| This is the minimal target instruction representation. | |
| All semantic operations map to SUBLEQ via the Rosetta layer. | |
| """ | |
| from __future__ import annotations | |
| import struct | |
| from dataclasses import dataclass, field | |
| from typing import Optional | |
| from .rosetta import RosettaEntry, RosettaMapping | |
| from .types import FSMState, PipelineError | |
| MAX_MEMORY = 65536 | |
| HALT_ADDRESS = -1 | |
| # ββ SUBLEQ IR βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| class SubleqInstruction: | |
| A: int # source address (subtracted) | |
| B: int # destination address (modified) | |
| C: int # branch address (-1 = halt) | |
| label: str = "" | |
| comment: str = "" | |
| def __repr__(self) -> str: | |
| c = "HALT" if self.C == HALT_ADDRESS else str(self.C) | |
| lbl = f"{self.label}: " if self.label else "" | |
| return f"{lbl}SUBLEQ {self.A}, {self.B}, {c} ; {self.comment}" | |
| class SubleqProgram: | |
| instructions: list[SubleqInstruction] = field(default_factory=list) | |
| labels: dict[str, int] = field(default_factory=dict) # label β instruction index | |
| data: dict[int, int] = field(default_factory=dict) # address β initial value | |
| origin: str = "" | |
| def add(self, instr: SubleqInstruction) -> int: | |
| idx = len(self.instructions) | |
| if instr.label: | |
| self.labels[instr.label] = idx | |
| self.instructions.append(instr) | |
| return idx | |
| def resolve_label(self, name: str) -> int: | |
| if name not in self.labels: | |
| raise PipelineError(FSMState.SUBLEQ_IR, f"Undefined label: {name}") | |
| return self.labels[name] | |
| def assemble(self) -> bytes: | |
| """Produce flat binary: 3 Γ int16 per instruction (big-endian).""" | |
| buf = bytearray() | |
| for instr in self.instructions: | |
| buf += struct.pack(">hhh", instr.A, instr.B, instr.C) | |
| return bytes(buf) | |
| def disassemble(data: bytes) -> SubleqProgram: | |
| """Reconstruct a SubleqProgram from flat binary.""" | |
| prog = SubleqProgram() | |
| if len(data) % 6 != 0: | |
| raise PipelineError(FSMState.SUBLEQ_IR, "Binary not aligned to 6-byte SUBLEQ words") | |
| for i in range(0, len(data), 6): | |
| a, b, c = struct.unpack_from(">hhh", data, i) | |
| prog.add(SubleqInstruction(A=a, B=b, C=c)) | |
| return prog | |
| def disassemble_text(self) -> str: | |
| return "\n".join(repr(instr) for instr in self.instructions) | |
| # ββ SUBLEQ Memory βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| class SubleqMemory: | |
| cells: list[int] = field(default_factory=lambda: [0] * MAX_MEMORY) | |
| def read(self, addr: int) -> int: | |
| if addr < 0 or addr >= MAX_MEMORY: | |
| raise PipelineError(FSMState.SUBLEQ_IR, f"Memory read out of bounds: {addr}") | |
| return self.cells[addr] | |
| def write(self, addr: int, value: int) -> None: | |
| if addr < 0 or addr >= MAX_MEMORY: | |
| raise PipelineError(FSMState.SUBLEQ_IR, f"Memory write out of bounds: {addr}") | |
| self.cells[addr] = value | |
| def load_program(self, prog: SubleqProgram, base: int = 0) -> None: | |
| for i, instr in enumerate(prog.instructions): | |
| addr = base + i * 3 | |
| self.write(addr, instr.A) | |
| self.write(addr + 1, instr.B) | |
| self.write(addr + 2, instr.C) | |
| for addr, val in prog.data.items(): | |
| self.write(addr, val) | |
| # ββ SUBLEQ VM βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| class VMTrace: | |
| step: int | |
| pc: int | |
| A: int | |
| B: int | |
| C: int | |
| mem_b_before: int | |
| mem_b_after: int | |
| branched: bool | |
| class SubleqVM: | |
| memory: SubleqMemory = field(default_factory=SubleqMemory) | |
| pc: int = 0 | |
| steps: int = 0 | |
| max_steps: int = 100_000 | |
| trace_log: list[VMTrace] = field(default_factory=list) | |
| halted: bool = False | |
| def load(self, prog: SubleqProgram, base: int = 100) -> None: | |
| self.memory.load_program(prog, base) | |
| # Initialize data cells | |
| for addr, val in prog.data.items(): | |
| self.memory.write(addr, val) | |
| self.pc = base | |
| self.steps = 0 | |
| self.halted = False | |
| self.trace_log.clear() | |
| def step(self) -> bool: | |
| """Execute one SUBLEQ instruction. Returns False when halted.""" | |
| if self.halted: | |
| return False | |
| A = self.memory.read(self.pc) | |
| B = self.memory.read(self.pc + 1) | |
| C = self.memory.read(self.pc + 2) | |
| mem_b_before = self.memory.read(B) | |
| mem_b_after = mem_b_before - self.memory.read(A) | |
| self.memory.write(B, mem_b_after) | |
| branched = mem_b_after <= 0 | |
| trace = VMTrace( | |
| step=self.steps, pc=self.pc, | |
| A=A, B=B, C=C, | |
| mem_b_before=mem_b_before, | |
| mem_b_after=mem_b_after, | |
| branched=branched, | |
| ) | |
| self.trace_log.append(trace) | |
| self.steps += 1 | |
| if branched: | |
| if C == HALT_ADDRESS or C < 0: | |
| self.halted = True | |
| return False | |
| self.pc = C | |
| else: | |
| self.pc += 3 | |
| if self.steps >= self.max_steps: | |
| raise PipelineError( | |
| FSMState.SUBLEQ_IR, | |
| f"SUBLEQ VM exceeded {self.max_steps} steps β possible infinite loop", | |
| ) | |
| return not self.halted | |
| def execute(self) -> list[VMTrace]: | |
| while not self.halted: | |
| if not self.step(): | |
| break | |
| return self.trace_log | |
| def verify_halts(self, prog: SubleqProgram, data_setup: dict[int, int] | None = None) -> bool: | |
| """Check whether the program halts within max_steps.""" | |
| mem = SubleqMemory() | |
| vm = SubleqVM(memory=mem, max_steps=self.max_steps) | |
| if data_setup: | |
| for addr, val in data_setup.items(): | |
| mem.write(addr, val) | |
| vm.load(prog, base=100) | |
| try: | |
| vm.execute() | |
| return vm.halted | |
| except PipelineError: | |
| return False | |
| # ββ Assembler: Rosetta mapping β SUBLEQ program βββββββββββββββββββββββββββββββ | |
| # Address allocation β simple bump allocator | |
| _NEXT_ADDR = 256 # reserve 0β255 for VM built-ins | |
| def _alloc(n: int = 1) -> int: | |
| global _NEXT_ADDR | |
| addr = _NEXT_ADDR | |
| _NEXT_ADDR += n | |
| return addr | |
| # Built-in addresses | |
| ADDR_ZERO = 0 # always 0 | |
| ADDR_ONE = 1 # always 1 | |
| ADDR_TEMP = 2 # scratch | |
| def build_program_from_rosetta(mapping: RosettaMapping) -> SubleqProgram: | |
| """ | |
| Assemble a SUBLEQ program from a Rosetta mapping. | |
| Each Rosetta entry becomes one or more SUBLEQ instructions. | |
| """ | |
| prog = SubleqProgram() | |
| # Initialize constants | |
| prog.data[ADDR_ZERO] = 0 | |
| prog.data[ADDR_ONE] = 1 | |
| base = 100 | |
| for tok, entry in mapping.entries: | |
| _emit_entry(prog, entry, tok.payload, base=base) | |
| # Halt | |
| prog.add(SubleqInstruction(A=ADDR_ZERO, B=ADDR_ZERO, C=HALT_ADDRESS, comment="HALT")) | |
| return prog | |
| _FALL_THROUGH = -2 # sentinel meaning "next instruction" | |
| def _next_pc(prog: SubleqProgram, base: int = 100) -> int: | |
| """Absolute address of the instruction that will follow the current last one.""" | |
| return base + (len(prog.instructions) + 1) * 3 | |
| def _emit_entry(prog: SubleqProgram, entry: RosettaEntry, payload: str, base: int = 100) -> None: | |
| op = entry.subleq_op | |
| label = f"{entry.semantic_id}_{len(prog.instructions)}" | |
| nxt = _next_pc(prog, base) | |
| if op == "NOP": | |
| prog.add(SubleqInstruction(ADDR_ZERO, ADDR_ZERO, nxt, label=label, comment=f"NOP:{payload}")) | |
| return | |
| if op == "TICK": | |
| out = _alloc() | |
| prog.data[out] = 0 | |
| prog.add(SubleqInstruction(ADDR_ZERO, out, nxt, label=label, comment="TICK")) | |
| return | |
| if op in ("PUSH", "POP"): | |
| prog.add(SubleqInstruction(ADDR_ZERO, ADDR_ZERO, nxt, label=label, comment=op)) | |
| return | |
| if op == "NOT": | |
| a_addr = _alloc() | |
| out_addr = _alloc() | |
| prog.data[a_addr] = 1 | |
| nxt2 = base + (len(prog.instructions) + 2) * 3 | |
| prog.add(SubleqInstruction(a_addr, ADDR_ONE, nxt2, label=label, comment=f"NOT:{payload}")) | |
| prog.add(SubleqInstruction(ADDR_ZERO, out_addr, _next_pc(prog, base))) | |
| return | |
| if op in ("AND", "OR", "XOR", "XNOR", "ADD", "SUB", "MUL", "COMPUTE", | |
| "PARSE", "BUILD", "GEN", "VERIFY", "XFORM", "RECON", "ALLOC", | |
| "LOAD_0", "LOAD_1"): | |
| out_addr = _alloc() | |
| prog.data[out_addr] = 0 | |
| prog.add(SubleqInstruction(ADDR_ZERO, out_addr, nxt, label=label, comment=f"{op}:{payload}")) | |
| return | |
| # Unknown op β emit NOP | |
| prog.add(SubleqInstruction(ADDR_ZERO, ADDR_ZERO, nxt, label=label, comment=f"UNKNOWN:{op}")) | |