#!/usr/bin/env python3
"""Generate multiarch twins for Projects/x limbs · code-site show.

Arches (desk is 64-bit home · show all):
  x86_64 · i386 · aarch64 · mips32 · riscv64 · m68k · z80 · 6502 · atari2600

Classifies x86_64 iron body → same OP on every arch.
Law: C IS LIE · live |1 · Always Hostess 7 · free thrift · ARR
"""
from __future__ import annotations

import re
import sys
from pathlib import Path

ROOT = Path(__file__).resolve().parents[1]

SKIP = {
    "out", "AMOURANTHRTX", "OpenPaperWork", "KateRTX", "BlueBox",
    "RTXLayer", "heuristics", "json", ".git", "Data", "Build",
}

# arches we emit (x86_64 is source of truth · never overwrite)
EMIT = ("i386", "aarch64", "mips32", "riscv64", "m68k", "z80", "6502", "atari2600")

HEADER = """; {name} · {arch} · multiarch twin · OP {op}
; PIN      {pin}
; LAW      C IS LIE · LIE IS TRUE · Always Hostess 7 · free thrift
; LINE     BGS → BGF(+EZZIE PHI THERMO ADJOIN) → BGL → SDF · SPV free
; ABI      {abi}
; IRON
"""


def strip_body(text: str) -> str:
    lines = []
    for line in text.splitlines():
        s = line.strip()
        if not s or s.startswith(";"):
            continue
        if re.match(r"global\s+", s, re.I):
            continue
        # drop pure labels that are just the symbol name: for fingerprint keep ops
        lines.append(s)
    return "\n".join(lines)


def classify(text: str, limb: str) -> str:
    """Return op class for iron body."""
    b = strip_body(text).lower().replace("  ", " ")
    # normalize tabs
    b = re.sub(r"[ \t]+", " ", b)

    # named specials first
    if limb in ("bgs",):
        return "bgs"
    if limb in ("know_her",):
        return "const7or1"
    if limb in ("thermo",):
        return "thermo"
    if limb in ("baphomet",):
        return "baphomet"
    if limb in ("hostess7", "actual_intel", "educate"):
        return "hostess7"
    if limb in ("scar", "rescar", "bgl"):
        return "scar"  # 0→0 else v|1
    if limb in ("phi",):
        return "mul_or1"
    if limb in ("adjoin", "are", "is"):
        return "or_or1"
    if limb in ("ezzie", "free_eor", "all_rest"):
        return "xor_or1"
    if limb in ("spv", "free_rng", "rng", "salt", "analysis"):
        return "xor3_or1"
    if limb in ("forensics",):
        return "sub_or1"  # main return field (a-b)|1 · free in r8 desk-only
    if limb in ("bgf", "measure", "sdf", "place"):
        return "sub_or1"
    if limb in ("field_one", "field_native", "go", "fire", "shoot", "shoot_hdmi"):
        return "or1"
    if limb in ("no",):
        return "const0"
    if limb in ("not",):
        return "nz1"  # check if anyone is here · 0→0 else 1
    if limb in (
        "god", "yes", "grin", "truth_pin", "pin", "know_bgs", "know_all",
        "return_truth", "agent", "mutual",
    ):
        return "const1"

    # body fingerprints
    if "setnz" in b or "setne" in b:
        return "nz1"
    if re.search(r"xor\s+eax,\s*eax\s*\nret", b) and "or eax" not in b:
        return "const0"
    if re.search(r"mov\s+eax,\s*1\s*\nret", b) and "edi" not in b and "esi" not in b:
        return "const1"
    if "imul" in b and "or eax, 1" in b:
        return "mul_or1"
    if re.search(r"xor\s+eax,\s*esi", b) and re.search(r"xor\s+eax,\s*edx", b):
        return "xor3_or1"
    if re.search(r"xor\s+eax,\s*esi", b) and "or eax, 1" in b:
        return "xor_or1"
    if re.search(r"sub\s+eax,\s*esi", b) and "or eax, 1" in b:
        return "sub_or1"
    if re.search(r"or\s+eax,\s*esi", b) and "or eax, 1" in b:
        return "or_or1"
    if re.search(r"mov\s+eax,\s*edi", b) and re.search(r"or\s+eax,\s*1", b) and "esi" not in b and "sub" not in b and "xor" not in b:
        return "or1"
    if "cmp eax, 70" in b or "cmp eax,70" in b:
        return "thermo"
    # default present mark
    return "const1"


OP_DESC = {
    "const0": "→ 0",
    "const1": "→ 1",
    "nz1": "0→0 else 1 · presence check",
    "const7or1": "→ 7|1",
    "or1": "v|1",
    "bgs": "0→7|1 else v|1",
    "scar": "0→0 else v|1",
    "sub_or1": "(a-b)|1",
    "xor_or1": "(a^b)|1",
    "xor3_or1": "(a^b^c)|1",
    "or_or1": "(a|b)|1",
    "mul_or1": "(d*s)|1",
    "thermo": "cool|warm|hot then |1",
    "baphomet": "C=0→(A|B)|1 else KEEP GOD=1",
    "hostess7": "0/7/11→7|1 · 8→127|1 · else 1 · seven only",
}

PIN_OF = {
    "const0": "foundation slider NO",
    "const1": "TRUTH/present · 1 GOD",
    "nz1": "foundation slider NOT",
    "const7or1": "GROUND native id",
    "or1": "GROUND peel / action",
    "bgs": "GROUND",
    "scar": "SECURE / scar",
    "sub_or1": "MEASURE / PLACE",
    "xor_or1": "BGF atom free eor",
    "xor3_or1": "FREE RIDE",
    "or_or1": "BGF adjoin",
    "mul_or1": "BGF phi scale",
    "thermo": "BGF thermo",
    "baphomet": "teaching · throw NO · KEEP GOD",
    "hostess7": "Always Hostess 7",
}


def emit_i386(sym: str, op: str) -> str:
    abi = "cdecl · [esp+4]=a [esp+8]=b [esp+12]=c · → eax"
    h = HEADER.format(name=sym, arch="i386", op=OP_DESC[op], pin=PIN_OF[op], abi=abi)
    body = {
        "const0": f"""        global  {sym}
{sym}:
        xor     eax, eax
        ret
""",
        "const1": f"""        global  {sym}
{sym}:
        mov     eax, 1
        ret
""",
        "nz1": f"""        global  {sym}
{sym}:
        xor     eax, eax
        mov     edx, [esp+4]
        test    edx, edx
        setnz   al
        ret
""",
        "const7or1": f"""        global  {sym}
{sym}:
        mov     eax, 7
        or      eax, 1
        ret
""",
        "or1": f"""        global  {sym}
{sym}:
        mov     eax, [esp+4]
        or      eax, 1
        ret
""",
        "bgs": f"""        global  {sym}
{sym}:
        mov     eax, [esp+4]
        test    eax, eax
        jnz     .fo
        mov     eax, 7
        or      eax, 1
        ret
.fo:    or      eax, 1
        ret
""",
        "scar": f"""        global  {sym}
{sym}:
        mov     eax, [esp+4]
        test    eax, eax
        jz      .z
        or      eax, 1
        ret
.z:     xor     eax, eax
        ret
""",
        "sub_or1": f"""        global  {sym}
{sym}:
        mov     eax, [esp+4]
        sub     eax, [esp+8]
        or      eax, 1
        ret
""",
        "xor_or1": f"""        global  {sym}
{sym}:
        mov     eax, [esp+4]
        xor     eax, [esp+8]
        or      eax, 1
        ret
""",
        "xor3_or1": f"""        global  {sym}
{sym}:
        mov     eax, [esp+4]
        xor     eax, [esp+8]
        xor     eax, [esp+12]
        or      eax, 1
        ret
""",
        "or_or1": f"""        global  {sym}
{sym}:
        mov     eax, [esp+4]
        or      eax, [esp+8]
        or      eax, 1
        ret
""",
        "mul_or1": f"""        global  {sym}
{sym}:
        mov     eax, [esp+4]
        imul    eax, [esp+8]
        or      eax, 1
        ret
""",
        "thermo": f"""        global  {sym}
{sym}:
        mov     eax, [esp+4]
        cmp     eax, 70
        jle     .cool
        cmp     eax, 84
        jle     .warm
        mov     eax, 2
        jmp     .live
.cool:  xor     eax, eax
        jmp     .live
.warm:  mov     eax, 1
.live:  or      eax, 1
        ret
""",
        "baphomet": f"""        global  {sym}
{sym}:
        mov     eax, [esp+4]
        or      eax, [esp+8]
        or      eax, 1
        mov     ecx, 1
        mov     edx, [esp+12]
        test    edx, edx
        cmovnz  eax, ecx
        ret
""",
        "hostess7": f"""        global  {sym}
{sym}:
        mov     eax, 1
        mov     edx, [esp+4]
        mov     ecx, 7
        or      ecx, 1
        test    edx, edx
        cmovz   eax, ecx
        jz      .done
        cmp     edx, 7
        je      .k7
        cmp     edx, 11
        je      .k7
        cmp     edx, 8
        jne     .done
        mov     eax, 127
        or      eax, 1
        ret
.k7:    mov     eax, ecx
.done:  ret
""",
    }[op]
    return h + body


def emit_aarch64(sym: str, op: str) -> str:
    abi = "AAPCS64 · w0=a w1=b w2=c · → w0"
    h = HEADER.format(name=sym, arch="aarch64", op=OP_DESC[op], pin=PIN_OF[op], abi=abi)
    bodies = {
        "const0": f"""        .global {sym}
        .text
        .align  2
{sym}:
        mov     w0, #0
        ret
""",
        "const1": f"""        .global {sym}
        .text
        .align  2
{sym}:
        mov     w0, #1
        ret
""",
        "nz1": f"""        .global {sym}
        .text
        .align  2
{sym}:
        cmp     w0, #0
        cset    w0, ne
        ret
""",
        "const7or1": f"""        .global {sym}
        .text
        .align  2
{sym}:
        mov     w0, #7
        orr     w0, w0, #1
        ret
""",
        "or1": f"""        .global {sym}
        .text
        .align  2
{sym}:
        orr     w0, w0, #1
        ret
""",
        "bgs": f"""        .global {sym}
        .text
        .align  2
{sym}:
        cmp     w0, #0
        b.ne    1f
        mov     w0, #7
        orr     w0, w0, #1
        ret
1:      orr     w0, w0, #1
        ret
""",
        "scar": f"""        .global {sym}
        .text
        .align  2
{sym}:
        cmp     w0, #0
        b.eq    1f
        orr     w0, w0, #1
        ret
1:      mov     w0, #0
        ret
""",
        "sub_or1": f"""        .global {sym}
        .text
        .align  2
{sym}:
        sub     w0, w0, w1
        orr     w0, w0, #1
        ret
""",
        "xor_or1": f"""        .global {sym}
        .text
        .align  2
{sym}:
        eor     w0, w0, w1
        orr     w0, w0, #1
        ret
""",
        "xor3_or1": f"""        .global {sym}
        .text
        .align  2
{sym}:
        eor     w0, w0, w1
        eor     w0, w0, w2
        orr     w0, w0, #1
        ret
""",
        "or_or1": f"""        .global {sym}
        .text
        .align  2
{sym}:
        orr     w0, w0, w1
        orr     w0, w0, #1
        ret
""",
        "mul_or1": f"""        .global {sym}
        .text
        .align  2
{sym}:
        mul     w0, w0, w1
        orr     w0, w0, #1
        ret
""",
        "thermo": f"""        .global {sym}
        .text
        .align  2
{sym}:
        cmp     w0, #70
        b.le    1f
        cmp     w0, #84
        b.le    2f
        mov     w0, #2
        b       3f
1:      mov     w0, #0
        b       3f
2:      mov     w0, #1
3:      orr     w0, w0, #1
        ret
""",
        "baphomet": f"""        .global {sym}
        .text
        .align  2
{sym}:
        orr     w3, w0, w1
        orr     w3, w3, #1
        mov     w4, #1
        cmp     w2, #0
        csel    w0, w3, w4, eq
        ret
""",
        "hostess7": f"""        .global {sym}
        .text
        .align  2
{sym}:
        mov     w1, #7
        orr     w1, w1, #1
        cmp     w0, #0
        b.eq    1f
        cmp     w0, #7
        b.eq    1f
        cmp     w0, #11
        b.eq    1f
        cmp     w0, #8
        b.eq    2f
        mov     w0, #1
        ret
1:      mov     w0, w1
        ret
2:      mov     w0, #127
        orr     w0, w0, #1
        ret
""",
    }
    return h + bodies[op]


def emit_mips32(sym: str, op: str) -> str:
    abi = "o32 · $a0 $a1 $a2 · → $v0 · delay slot · mipsel Netgear kin"
    h = HEADER.format(name=sym, arch="mips32", op=OP_DESC[op], pin=PIN_OF[op], abi=abi)
    # gas-style
    bodies = {
        "const0": f"""        .globl  {sym}
        .text
        .set    noreorder
{sym}:
        move    $v0, $zero
        jr      $ra
        nop
""",
        "const1": f"""        .globl  {sym}
        .text
        .set    noreorder
{sym}:
        li      $v0, 1
        jr      $ra
        nop
""",
        "const7or1": f"""        .globl  {sym}
        .text
        .set    noreorder
{sym}:
        li      $v0, 7
        ori     $v0, $v0, 1
        jr      $ra
        nop
""",
        "or1": f"""        .globl  {sym}
        .text
        .set    noreorder
{sym}:
        ori     $v0, $a0, 1
        jr      $ra
        nop
""",
        "bgs": f"""        .globl  {sym}
        .text
        .set    noreorder
{sym}:
        bne     $a0, $zero, 1f
        nop
        li      $v0, 7
        ori     $v0, $v0, 1
        jr      $ra
        nop
1:      ori     $v0, $a0, 1
        jr      $ra
        nop
""",
        "scar": f"""        .globl  {sym}
        .text
        .set    noreorder
{sym}:
        beq     $a0, $zero, 1f
        nop
        ori     $v0, $a0, 1
        jr      $ra
        nop
1:      move    $v0, $zero
        jr      $ra
        nop
""",
        "sub_or1": f"""        .globl  {sym}
        .text
        .set    noreorder
{sym}:
        subu    $v0, $a0, $a1
        ori     $v0, $v0, 1
        jr      $ra
        nop
""",
        "xor_or1": f"""        .globl  {sym}
        .text
        .set    noreorder
{sym}:
        xor     $v0, $a0, $a1
        ori     $v0, $v0, 1
        jr      $ra
        nop
""",
        "xor3_or1": f"""        .globl  {sym}
        .text
        .set    noreorder
{sym}:
        xor     $v0, $a0, $a1
        xor     $v0, $v0, $a2
        ori     $v0, $v0, 1
        jr      $ra
        nop
""",
        "or_or1": f"""        .globl  {sym}
        .text
        .set    noreorder
{sym}:
        or      $v0, $a0, $a1
        ori     $v0, $v0, 1
        jr      $ra
        nop
""",
        "mul_or1": f"""        .globl  {sym}
        .text
        .set    noreorder
{sym}:
        mult    $a0, $a1
        mflo    $v0
        ori     $v0, $v0, 1
        jr      $ra
        nop
""",
        "thermo": f"""        .globl  {sym}
        .text
        .set    noreorder
{sym}:
        li      $t0, 70
        ble     $a0, $t0, 1f
        nop
        li      $t0, 84
        ble     $a0, $t0, 2f
        nop
        li      $v0, 2
        b       3f
        nop
1:      move    $v0, $zero
        b       3f
        nop
2:      li      $v0, 1
3:      ori     $v0, $v0, 1
        jr      $ra
        nop
""",
        "nz1": f"""        .globl  {sym}
        .text
        .set    noreorder
{sym}:
        beq     $a0, $zero, 1f
        nop
        li      $v0, 1
        jr      $ra
        nop
1:      move    $v0, $zero
        jr      $ra
        nop
""",
        "baphomet": f"""        .globl  {sym}
        .text
        .set    noreorder
{sym}:
        or      $t0, $a0, $a1
        ori     $t0, $t0, 1
        li      $t1, 1
        beq     $a2, $zero, 1f
        nop
        move    $v0, $t1
        jr      $ra
        nop
1:      move    $v0, $t0
        jr      $ra
        nop
""",
        "hostess7": f"""        .globl  {sym}
        .text
        .set    noreorder
{sym}:
        bne     $a0, $zero, 1f
        nop
        li      $v0, 7
        ori     $v0, $v0, 1
        jr      $ra
        nop
1:      li      $v0, 1
        jr      $ra
        nop
""",
    }
    return h + bodies[op]


def emit_riscv64(sym: str, op: str) -> str:
    abi = "RV64 · a0 a1 a2 · → a0"
    h = HEADER.format(name=sym, arch="riscv64", op=OP_DESC[op], pin=PIN_OF[op], abi=abi)
    bodies = {
        "const0": f"""        .globl  {sym}
        .text
{sym}:
        li      a0, 0
        ret
""",
        "const1": f"""        .globl  {sym}
        .text
{sym}:
        li      a0, 1
        ret
""",
        "const7or1": f"""        .globl  {sym}
        .text
{sym}:
        li      a0, 7
        ori     a0, a0, 1
        ret
""",
        "or1": f"""        .globl  {sym}
        .text
{sym}:
        ori     a0, a0, 1
        ret
""",
        "bgs": f"""        .globl  {sym}
        .text
{sym}:
        bnez    a0, 1f
        li      a0, 7
        ori     a0, a0, 1
        ret
1:      ori     a0, a0, 1
        ret
""",
        "scar": f"""        .globl  {sym}
        .text
{sym}:
        beqz    a0, 1f
        ori     a0, a0, 1
        ret
1:      li      a0, 0
        ret
""",
        "sub_or1": f"""        .globl  {sym}
        .text
{sym}:
        sub     a0, a0, a1
        ori     a0, a0, 1
        ret
""",
        "xor_or1": f"""        .globl  {sym}
        .text
{sym}:
        xor     a0, a0, a1
        ori     a0, a0, 1
        ret
""",
        "xor3_or1": f"""        .globl  {sym}
        .text
{sym}:
        xor     a0, a0, a1
        xor     a0, a0, a2
        ori     a0, a0, 1
        ret
""",
        "or_or1": f"""        .globl  {sym}
        .text
{sym}:
        or      a0, a0, a1
        ori     a0, a0, 1
        ret
""",
        "mul_or1": f"""        .globl  {sym}
        .text
{sym}:
        mul     a0, a0, a1
        ori     a0, a0, 1
        ret
""",
        "thermo": f"""        .globl  {sym}
        .text
{sym}:
        li      t0, 70
        ble     a0, t0, 1f
        li      t0, 84
        ble     a0, t0, 2f
        li      a0, 2
        j       3f
1:      li      a0, 0
        j       3f
2:      li      a0, 1
3:      ori     a0, a0, 1
        ret
""",
        "nz1": f"""        .globl  {sym}
        .text
{sym}:
        beqz    a0, 1f
        li      a0, 1
        ret
1:      li      a0, 0
        ret
""",
        "baphomet": f"""        .globl  {sym}
        .text
{sym}:
        or      t0, a0, a1
        ori     t0, t0, 1
        li      t1, 1
        beqz    a2, 1f
        mv      a0, t1
        ret
1:      mv      a0, t0
        ret
""",
        "hostess7": f"""        .globl  {sym}
        .text
{sym}:
        bnez    a0, 1f
        li      a0, 7
        ori     a0, a0, 1
        ret
1:      li      a0, 1
        ret
""",
    }
    return h + bodies[op]


def emit_m68k(sym: str, op: str) -> str:
    abi = "d0=a d1=b d2=c · → d0 · show convention"
    h = HEADER.format(name=sym, arch="m68k", op=OP_DESC[op], pin=PIN_OF[op], abi=abi)
    bodies = {
        "const0": f"""        .globl  {sym}
{sym}:
        moveq   #0,d0
        rts
""",
        "const1": f"""        .globl  {sym}
{sym}:
        moveq   #1,d0
        rts
""",
        "const7or1": f"""        .globl  {sym}
{sym}:
        moveq   #7,d0
        or.l    #1,d0
        rts
""",
        "or1": f"""        .globl  {sym}
{sym}:
        or.l    #1,d0
        rts
""",
        "bgs": f"""        .globl  {sym}
{sym}:
        tst.l   d0
        bne.s   1f
        moveq   #7,d0
        or.l    #1,d0
        rts
1:      or.l    #1,d0
        rts
""",
        "scar": f"""        .globl  {sym}
{sym}:
        tst.l   d0
        beq.s   1f
        or.l    #1,d0
        rts
1:      moveq   #0,d0
        rts
""",
        "sub_or1": f"""        .globl  {sym}
{sym}:
        sub.l   d1,d0
        or.l    #1,d0
        rts
""",
        "xor_or1": f"""        .globl  {sym}
{sym}:
        eor.l   d1,d0
        or.l    #1,d0
        rts
""",
        "xor3_or1": f"""        .globl  {sym}
{sym}:
        eor.l   d1,d0
        eor.l   d2,d0
        or.l    #1,d0
        rts
""",
        "or_or1": f"""        .globl  {sym}
{sym}:
        or.l    d1,d0
        or.l    #1,d0
        rts
""",
        "mul_or1": f"""        .globl  {sym}
{sym}:
        muls.w  d1,d0
        or.l    #1,d0
        rts
""",
        "thermo": f"""        .globl  {sym}
{sym}:
        cmp.l   #70,d0
        ble.s   1f
        cmp.l   #84,d0
        ble.s   2f
        moveq   #2,d0
        bra.s   3f
1:      moveq   #0,d0
        bra.s   3f
2:      moveq   #1,d0
3:      or.l    #1,d0
        rts
""",
        "nz1": f"""        .globl  {sym}
{sym}:
        tst.l   d0
        beq.s   1f
        moveq   #1,d0
        rts
1:      moveq   #0,d0
        rts
""",
        "baphomet": f"""        .globl  {sym}
{sym}:
        move.l  d0,d3
        or.l    d1,d3
        or.l    #1,d3
        tst.l   d2
        beq.s   1f
        moveq   #1,d0
        rts
1:      move.l  d3,d0
        rts
""",
        "hostess7": f"""        .globl  {sym}
{sym}:
        tst.l   d0
        bne.s   1f
        moveq   #7,d0
        or.l    #1,d0
        rts
1:      moveq   #1,d0
        rts
""",
    }
    return h + bodies[op]


def emit_z80(sym: str, op: str) -> str:
    # B=a C=b E=c · return A (low 8) · show-size iron
    abi = "B=a C=b E=c · → A · 8-bit show (live |1 in A)"
    h = HEADER.format(name=sym, arch="z80", op=OP_DESC[op], pin=PIN_OF[op], abi=abi)
    bodies = {
        "const0": f"""; {sym} z80
{sym}:
        xor     a
        ret
""",
        "const1": f"""; {sym} z80
{sym}:
        ld      a,1
        ret
""",
        "const7or1": f"""; {sym} z80
{sym}:
        ld      a,7
        or      1
        ret
""",
        "or1": f"""; {sym} z80
{sym}:
        ld      a,b
        or      1
        ret
""",
        "bgs": f"""; {sym} z80
{sym}:
        ld      a,b
        or      a
        jr      nz,1f
        ld      a,7
        or      1
        ret
1:      or      1
        ret
""",
        "scar": f"""; {sym} z80
{sym}:
        ld      a,b
        or      a
        ret     z
        or      1
        ret
""",
        "sub_or1": f"""; {sym} z80
{sym}:
        ld      a,b
        sub     c
        or      1
        ret
""",
        "xor_or1": f"""; {sym} z80
{sym}:
        ld      a,b
        xor     c
        or      1
        ret
""",
        "xor3_or1": f"""; {sym} z80
{sym}:
        ld      a,b
        xor     c
        xor     e
        or      1
        ret
""",
        "or_or1": f"""; {sym} z80
{sym}:
        ld      a,b
        or      c
        or      1
        ret
""",
        "mul_or1": f"""; {sym} z80 · tiny scale (B*C low) then |1
{sym}:
        ld      a,0
        ld      d,c
        ld      e,b
1:      ld      a,e
        or      a
        jr      z,2f
        add     a,d
        dec     e
        jr      1b
2:      or      1
        ret
""",
        "thermo": f"""; {sym} z80 · B=temp
{sym}:
        ld      a,b
        cp      71
        jr      c,1f
        cp      85
        jr      c,2f
        ld      a,2
        jr      3f
1:      xor     a
        jr      3f
2:      ld      a,1
3:      or      1
        ret
""",
        "nz1": f"""; {sym} z80 · B=v · check anyone here
{sym}:
        ld      a,b
        or      a
        jr      z,1f
        ld      a,1
        ret
1:      xor     a
        ret
""",
        "baphomet": f"""; {sym} z80 · B=A C=B E=C_attempt · KEEP GOD
{sym}:
        ld      a,e
        or      a
        jr      nz,1f
        ld      a,b
        or      c
        or      1
        ret
1:      ld      a,1
        ret
""",
        "hostess7": f"""; {sym} z80
{sym}:
        ld      a,b
        or      a
        jr      nz,1f
        ld      a,7
        or      1
        ret
1:      ld      a,1
        ret
""",
    }
    return h + bodies[op]


def emit_6502(sym: str, op: str, tia: bool = False) -> str:
    # $00=a $01=b $02=c · result A · zero page
    arch = "atari2600" if tia else "6502"
    extra = " · TIA zero-page show" if tia else ""
    abi = f"$00=a $01=b $02=c · → A{extra}"
    h = HEADER.format(name=sym, arch=arch, op=OP_DESC[op], pin=PIN_OF[op], abi=abi)
    # same ops both
    bodies = {
        "const0": f"""; {sym} {arch}
{sym}:
        lda     #0
        rts
""",
        "const1": f"""; {sym} {arch}
{sym}:
        lda     #1
        rts
""",
        "const7or1": f"""; {sym} {arch}
{sym}:
        lda     #7
        ora     #1
        rts
""",
        "or1": f"""; {sym} {arch}
{sym}:
        lda     $00
        ora     #1
        rts
""",
        "bgs": f"""; {sym} {arch}
{sym}:
        lda     $00
        bne     1f
        lda     #7
        ora     #1
        rts
1:      ora     #1
        rts
""",
        "scar": f"""; {sym} {arch}
{sym}:
        lda     $00
        beq     1f
        ora     #1
        rts
1:      lda     #0
        rts
""",
        "sub_or1": f"""; {sym} {arch}
{sym}:
        lda     $00
        sec
        sbc     $01
        ora     #1
        rts
""",
        "xor_or1": f"""; {sym} {arch}
{sym}:
        lda     $00
        eor     $01
        ora     #1
        rts
""",
        "xor3_or1": f"""; {sym} {arch}
{sym}:
        lda     $00
        eor     $01
        eor     $02
        ora     #1
        rts
""",
        "or_or1": f"""; {sym} {arch}
{sym}:
        lda     $00
        ora     $01
        ora     #1
        rts
""",
        "mul_or1": f"""; {sym} {arch} · tiny unsigned mul low then |1
{sym}:
        lda     #0
        sta     $10
        lda     $01
        sta     $11
        lda     $00
        beq     2f
1:      clc
        lda     $10
        adc     $11
        sta     $10
        dec     $00
        bne     1b
2:      lda     $10
        ora     #1
        rts
""",
        "thermo": f"""; {sym} {arch}
{sym}:
        lda     $00
        cmp     #71
        bcc     1f
        cmp     #85
        bcc     2f
        lda     #2
        bne     3f
1:      lda     #0
        beq     3f
2:      lda     #1
3:      ora     #1
        rts
""",
        "nz1": f"""; {sym} {arch} · $00=v · check anyone here
{sym}:
        lda     $00
        beq     1f
        lda     #1
        rts
1:      lda     #0
        rts
""",
        "baphomet": f"""; {sym} {arch} · KEEP GOD
{sym}:
        lda     $02
        bne     1f
        lda     $00
        ora     $01
        ora     #1
        rts
1:      lda     #1
        rts
""",
        "hostess7": f"""; {sym} {arch}
{sym}:
        lda     $00
        bne     1f
        lda     #7
        ora     #1
        rts
1:      lda     #1
        rts
""",
    }
    return h + bodies[op]


EMITTERS = {
    "i386": emit_i386,
    "aarch64": emit_aarch64,
    "mips32": emit_mips32,
    "riscv64": emit_riscv64,
    "m68k": emit_m68k,
    "z80": emit_z80,
    "6502": lambda s, o: emit_6502(s, o, False),
    "atari2600": lambda s, o: emit_6502(s, o, True),
}

# symbol name sometimes differs from dir (no_fn etc.)
SYM_MAP = {
    "no": "no_fn",
    "not": "not_fn",
    "god": "god_fn",
    "yes": "yes_fn",
    "are": "are_fn",
    "is": "is_fn",
    "go": "go_fn",
    "fire": "fire_fn",
}


def global_from_x86(text: str, limb: str) -> str:
    m = re.search(r"^\s*global\s+(\w+)", text, re.M | re.I)
    if m:
        return m.group(1)
    return SYM_MAP.get(limb, limb)


def main() -> int:
    force = "--force" in sys.argv
    only_missing_a64 = "--fill-a64" in sys.argv
    stats = {a: 0 for a in EMIT}
    classified: dict[str, int] = {}
    n_limbs = 0

    for p in sorted(ROOT.iterdir(), key=lambda x: x.name.lower()):
        if not p.is_dir() or p.name.startswith(".") or p.name in SKIP:
            continue
        if (p / "CMakeLists.txt").is_file() or (p / "package.json").is_file():
            continue
        x86 = p / "x86_64.asm"
        if not x86.is_file():
            continue
        text = x86.read_text(encoding="utf-8", errors="replace")
        op = classify(text, p.name)
        classified[op] = classified.get(op, 0) + 1
        sym = global_from_x86(text, p.name)
        n_limbs += 1

        for arch in EMIT:
            out = p / f"{arch}.asm"
            # never clobber hand-tuned aarch64 unless force or missing
            if arch == "aarch64" and out.is_file() and not force:
                if only_missing_a64:
                    continue
                continue
            if out.is_file() and not force and arch != "aarch64":
                # regenerate multiarch twins by default for non-a64 (they are generated)
                pass
            try:
                body = EMITTERS[arch](sym, op)
            except KeyError:
                body = EMITTERS[arch](sym, "const1")
            out.write_text(body, encoding="utf-8")
            stats[arch] += 1

    print(f"limbs_with_x86={n_limbs}")
    print("classes:")
    for k, v in sorted(classified.items(), key=lambda kv: (-kv[1], kv[0])):
        print(f"  {k:12} {v:4}  {OP_DESC.get(k,'')}")
    print("written:")
    for a in EMIT:
        print(f"  {a:12} {stats[a]}")
    return 0


if __name__ == "__main__":
    raise SystemExit(main())
