;; ==========================================================================
;; bytecode.sx — SX bytecode format definition
;;
;; Universal bytecode for SX evaluation. Produced by compiler.sx,
;; executed by platform-native VMs (OCaml, JS, WASM).
;;
;; Design principles:
;;   - One byte per opcode (~65 ops, fits in u8)
;;   - Variable-length encoding (1-5 bytes per instruction)
;;   - Lexical scope resolved at compile time (no hash lookups)
;;   - Tail calls detected statically (no thunks/trampoline)
;;   - Control flow via jumps (no continuation frames for if/when/etc.)
;;   - Content-addressable (deterministic binary for CID)
;; ==========================================================================


;; --------------------------------------------------------------------------
;; Opcode constants
;; --------------------------------------------------------------------------

;; Stack / Constants

(define-library (sx bytecode)
  (export
    OP_CONST
    OP_NIL
    OP_TRUE
    OP_FALSE
    OP_POP
    OP_DUP
    OP_LOCAL_GET
    OP_LOCAL_SET
    OP_UPVALUE_GET
    OP_UPVALUE_SET
    OP_GLOBAL_GET
    OP_GLOBAL_SET
    OP_JUMP
    OP_JUMP_IF_FALSE
    OP_JUMP_IF_TRUE
    OP_CALL
    OP_TAIL_CALL
    OP_RETURN
    OP_CLOSURE
    OP_CALL_PRIM
    OP_APPLY
    OP_LIST
    OP_DICT
    OP_APPEND_BANG
    OP_ITER_INIT
    OP_ITER_NEXT
    OP_MAP_OPEN
    OP_MAP_APPEND
    OP_MAP_CLOSE
    OP_FILTER_TEST
    OP_HO_MAP
    OP_HO_FILTER
    OP_HO_REDUCE
    OP_HO_FOR_EACH
    OP_HO_SOME
    OP_HO_EVERY
    OP_SCOPE_PUSH
    OP_SCOPE_POP
    OP_PROVIDE_PUSH
    OP_PROVIDE_POP
    OP_CONTEXT
    OP_EMIT
    OP_EMITTED
    OP_RESET
    OP_SHIFT
    OP_DEFINE
    OP_DEFCOMP
    OP_DEFISLAND
    OP_DEFMACRO
    OP_EXPAND_MACRO
    OP_STR_CONCAT
    OP_STR_JOIN
    OP_SERIALIZE
    OP_ADD
    OP_SUB
    OP_MUL
    OP_DIV
    OP_EQ
    OP_LT
    OP_GT
    OP_NOT
    OP_LEN
    OP_FIRST
    OP_REST
    OP_NTH
    OP_CONS
    OP_NEG
    OP_INC
    OP_DEC
    OP_ASER_TAG
    OP_ASER_FRAG
    BYTECODE_MAGIC
    BYTECODE_VERSION
    CONST_NUMBER
    CONST_STRING
    CONST_BOOL
    CONST_NIL
    CONST_SYMBOL
    CONST_KEYWORD
    CONST_LIST
    CONST_DICT
    CONST_CODE
    opcode-name)
  (begin

(define OP_CONST          1)  ;; u16 pool_idx — push constant
(define OP_NIL            2)  ;; push nil
(define OP_TRUE           3)  ;; push true
(define OP_FALSE          4)  ;; push false
(define OP_POP            5)  ;; discard TOS
(define OP_DUP            6)  ;; duplicate TOS

;; Variable access (resolved at compile time)
(define OP_LOCAL_GET      16)  ;; u8 slot
(define OP_LOCAL_SET      17)  ;; u8 slot
(define OP_UPVALUE_GET    18)  ;; u8 idx
(define OP_UPVALUE_SET    19)  ;; u8 idx
(define OP_GLOBAL_GET     20)  ;; u16 name_idx
(define OP_GLOBAL_SET     21)  ;; u16 name_idx

;; Control flow (replaces if/when/cond/and/or frames)
(define OP_JUMP           32)  ;; i16 offset
(define OP_JUMP_IF_FALSE  33)  ;; i16 offset
(define OP_JUMP_IF_TRUE   34)  ;; i16 offset

;; Function operations
(define OP_CALL           48)  ;; u8 argc
(define OP_TAIL_CALL      49)  ;; u8 argc — reuse frame (TCO)
(define OP_RETURN         50)  ;; return TOS
(define OP_CLOSURE        51)  ;; u16 code_idx — create closure
(define OP_CALL_PRIM      52)  ;; u16 name_idx, u8 argc — direct primitive
(define OP_APPLY          53)  ;; (apply f args-list)

;; Collection construction
(define OP_LIST           64)  ;; u16 count — build list from stack
(define OP_DICT           65)  ;; u16 count — build dict from stack pairs
(define OP_APPEND_BANG    66)  ;; (append! TOS-1 TOS)

;; Higher-order forms (inlined loop)
(define OP_ITER_INIT      80)  ;; init iterator on TOS list
(define OP_ITER_NEXT      81)  ;; i16 end_offset — push next or jump
(define OP_MAP_OPEN       82)  ;; push empty accumulator
(define OP_MAP_APPEND     83)  ;; append TOS to accumulator
(define OP_MAP_CLOSE      84)  ;; pop accumulator as list
(define OP_FILTER_TEST    85)  ;; i16 skip — if falsy jump (skip append)

;; HO fallback (dynamic callback)
(define OP_HO_MAP         88)  ;; (map fn coll)
(define OP_HO_FILTER      89)  ;; (filter fn coll)
(define OP_HO_REDUCE      90)  ;; (reduce fn init coll)
(define OP_HO_FOR_EACH    91)  ;; (for-each fn coll)
(define OP_HO_SOME        92)  ;; (some fn coll)
(define OP_HO_EVERY       93)  ;; (every? fn coll)

;; Scope / dynamic binding
(define OP_SCOPE_PUSH     96)  ;; TOS = name
(define OP_SCOPE_POP      97)
(define OP_PROVIDE_PUSH   98)  ;; TOS-1 = name, TOS = value
(define OP_PROVIDE_POP    99)
(define OP_CONTEXT        100)  ;; TOS = name → push value
(define OP_EMIT           101)  ;; TOS-1 = name, TOS = value
(define OP_EMITTED        102)  ;; TOS = name → push collected

;; Continuations
(define OP_RESET          112)  ;; i16 body_len — push delimiter
(define OP_SHIFT          113)  ;; u8 k_slot, i16 body_len — capture k

;; Define / component
(define OP_DEFINE         128)  ;; u16 name_idx — bind TOS to name
(define OP_DEFCOMP        129)  ;; u16 template_idx
(define OP_DEFISLAND      130)  ;; u16 template_idx
(define OP_DEFMACRO       131)  ;; u16 template_idx
(define OP_EXPAND_MACRO   132)  ;; u8 argc — runtime macro expansion

;; String / serialize (hot path)
(define OP_STR_CONCAT     144)  ;; u8 count — concat N values as strings
(define OP_STR_JOIN       145)  ;; (join sep list)
(define OP_SERIALIZE      146)  ;; serialize TOS to SX string

;; Inline primitives (hot path — no hashtable lookup)
(define OP_ADD            160)  ;; TOS-1 + TOS → push
(define OP_SUB            161)  ;; TOS-1 - TOS → push
(define OP_MUL            162)  ;; TOS-1 * TOS → push
(define OP_DIV            163)  ;; TOS-1 / TOS → push
(define OP_EQ             164)  ;; TOS-1 = TOS → push bool
(define OP_LT             165)  ;; TOS-1 < TOS → push bool
(define OP_GT             166)  ;; TOS-1 > TOS → push bool
(define OP_NOT            167)  ;; !TOS → push bool
(define OP_LEN            168)  ;; len(TOS) → push number
(define OP_FIRST          169)  ;; first(TOS) → push
(define OP_REST           170)  ;; rest(TOS) → push list
(define OP_NTH            171)  ;; nth(TOS-1, TOS) → push
(define OP_CONS           172)  ;; cons(TOS-1, TOS) → push list
(define OP_NEG            173)  ;; negate TOS → push number
(define OP_INC            174)  ;; TOS + 1 → push
(define OP_DEC            175)  ;; TOS - 1 → push

;; Aser specialization (optional, 224-239 reserved)
(define OP_ASER_TAG       224)  ;; u16 tag_name_idx — serialize HTML tag
(define OP_ASER_FRAG      225)  ;; u8 child_count — serialize fragment


;; --------------------------------------------------------------------------
;; Bytecode module structure
;; --------------------------------------------------------------------------

;; A module contains:
;;   magic:      "SXBC" (4 bytes)
;;   version:    u16
;;   pool_count: u32
;;   pool:       constant pool entries (self-describing tagged values)
;;   code_count: u32
;;   codes:      code objects
;;   entry:      u32 (index of entry-point code object)

(define BYTECODE_MAGIC "SXBC")
(define BYTECODE_VERSION 1)

;; Constant pool tags
(define CONST_NUMBER   1)
(define CONST_STRING   2)
(define CONST_BOOL     3)
(define CONST_NIL      4)
(define CONST_SYMBOL   5)
(define CONST_KEYWORD  6)
(define CONST_LIST     7)
(define CONST_DICT     8)
(define CONST_CODE     9)


;; --------------------------------------------------------------------------
;; Disassembler
;; --------------------------------------------------------------------------

(define opcode-name
  (fn (op)
    (cond
      (= op 1) "CONST"    (= op 2) "NIL"
      (= op 3) "TRUE"     (= op 4) "FALSE"
      (= op 5) "POP"      (= op 6) "DUP"
      (= op 16) "LOCAL_GET"  (= op 17) "LOCAL_SET"
      (= op 20) "GLOBAL_GET" (= op 21) "GLOBAL_SET"
      (= op 32) "JUMP"     (= op 33) "JUMP_IF_FALSE"
      (= op 48) "CALL"     (= op 49) "TAIL_CALL"
      (= op 50) "RETURN"   (= op 52) "CALL_PRIM"
      (= op 128) "DEFINE"   (= op 144) "STR_CONCAT"
      :else (str "OP_" op))))


)) ;; end define-library

;; Re-export to global namespace for backward compatibility
(import (sx bytecode))
