diff --git a/spec/bytecode.sx b/spec/bytecode.sx index 6db1f28..c1665be 100644 --- a/spec/bytecode.sx +++ b/spec/bytecode.sx @@ -19,83 +19,83 @@ ;; -------------------------------------------------------------------------- ;; Stack / Constants -(define OP_CONST 0x01) ;; u16 pool_idx — push constant -(define OP_NIL 0x02) ;; push nil -(define OP_TRUE 0x03) ;; push true -(define OP_FALSE 0x04) ;; push false -(define OP_POP 0x05) ;; discard TOS -(define OP_DUP 0x06) ;; duplicate TOS +(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 0x10) ;; u8 slot -(define OP_LOCAL_SET 0x11) ;; u8 slot -(define OP_UPVALUE_GET 0x12) ;; u8 idx -(define OP_UPVALUE_SET 0x13) ;; u8 idx -(define OP_GLOBAL_GET 0x14) ;; u16 name_idx -(define OP_GLOBAL_SET 0x15) ;; u16 name_idx +(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 0x20) ;; i16 offset -(define OP_JUMP_IF_FALSE 0x21) ;; i16 offset -(define OP_JUMP_IF_TRUE 0x22) ;; i16 offset +(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 0x30) ;; u8 argc -(define OP_TAIL_CALL 0x31) ;; u8 argc — reuse frame (TCO) -(define OP_RETURN 0x32) ;; return TOS -(define OP_CLOSURE 0x33) ;; u16 code_idx — create closure -(define OP_CALL_PRIM 0x34) ;; u16 name_idx, u8 argc — direct primitive -(define OP_APPLY 0x35) ;; (apply f args-list) +(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 0x40) ;; u16 count — build list from stack -(define OP_DICT 0x41) ;; u16 count — build dict from stack pairs -(define OP_APPEND_BANG 0x42) ;; (append! TOS-1 TOS) +(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 0x50) ;; init iterator on TOS list -(define OP_ITER_NEXT 0x51) ;; i16 end_offset — push next or jump -(define OP_MAP_OPEN 0x52) ;; push empty accumulator -(define OP_MAP_APPEND 0x53) ;; append TOS to accumulator -(define OP_MAP_CLOSE 0x54) ;; pop accumulator as list -(define OP_FILTER_TEST 0x55) ;; i16 skip — if falsy jump (skip append) +(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 0x58) ;; (map fn coll) -(define OP_HO_FILTER 0x59) ;; (filter fn coll) -(define OP_HO_REDUCE 0x5A) ;; (reduce fn init coll) -(define OP_HO_FOR_EACH 0x5B) ;; (for-each fn coll) -(define OP_HO_SOME 0x5C) ;; (some fn coll) -(define OP_HO_EVERY 0x5D) ;; (every? fn coll) +(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 0x60) ;; TOS = name -(define OP_SCOPE_POP 0x61) -(define OP_PROVIDE_PUSH 0x62) ;; TOS-1 = name, TOS = value -(define OP_PROVIDE_POP 0x63) -(define OP_CONTEXT 0x64) ;; TOS = name → push value -(define OP_EMIT 0x65) ;; TOS-1 = name, TOS = value -(define OP_EMITTED 0x66) ;; TOS = name → push collected +(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 0x70) ;; i16 body_len — push delimiter -(define OP_SHIFT 0x71) ;; u8 k_slot, i16 body_len — capture k +(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 0x80) ;; u16 name_idx — bind TOS to name -(define OP_DEFCOMP 0x81) ;; u16 template_idx -(define OP_DEFISLAND 0x82) ;; u16 template_idx -(define OP_DEFMACRO 0x83) ;; u16 template_idx -(define OP_EXPAND_MACRO 0x84) ;; u8 argc — runtime macro expansion +(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 0x90) ;; u8 count — concat N values as strings -(define OP_STR_JOIN 0x91) ;; (join sep list) -(define OP_SERIALIZE 0x92) ;; serialize TOS to SX string +(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 -;; Aser specialization (optional, 0xE0-0xEF reserved) -(define OP_ASER_TAG 0xE0) ;; u16 tag_name_idx — serialize HTML tag -(define OP_ASER_FRAG 0xE1) ;; u8 child_count — serialize fragment +;; 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 ;; -------------------------------------------------------------------------- @@ -115,32 +115,31 @@ (define BYTECODE_VERSION 1) ;; Constant pool tags -(define CONST_NUMBER 0x01) -(define CONST_STRING 0x02) -(define CONST_BOOL 0x03) -(define CONST_NIL 0x04) -(define CONST_SYMBOL 0x05) -(define CONST_KEYWORD 0x06) -(define CONST_LIST 0x07) -(define CONST_DICT 0x08) -(define CONST_CODE 0x09) +(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-names - {:0x01 "CONST" :0x02 "NIL" :0x03 "TRUE" :0x04 "FALSE" - :0x05 "POP" :0x06 "DUP" - :0x10 "LOCAL_GET" :0x11 "LOCAL_SET" - :0x12 "UPVALUE_GET" :0x13 "UPVALUE_SET" - :0x14 "GLOBAL_GET" :0x15 "GLOBAL_SET" - :0x20 "JUMP" :0x21 "JUMP_IF_FALSE" :0x22 "JUMP_IF_TRUE" - :0x30 "CALL" :0x31 "TAIL_CALL" :0x32 "RETURN" - :0x33 "CLOSURE" :0x34 "CALL_PRIM" :0x35 "APPLY" - :0x40 "LIST" :0x41 "DICT" :0x42 "APPEND!" - :0x50 "ITER_INIT" :0x51 "ITER_NEXT" - :0x52 "MAP_OPEN" :0x53 "MAP_APPEND" :0x54 "MAP_CLOSE" - :0x80 "DEFINE" :0x90 "STR_CONCAT" :0x92 "SERIALIZE" - :0xE0 "ASER_TAG" :0xE1 "ASER_FRAG"}) +(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)))) diff --git a/spec/compiler.sx b/spec/compiler.sx index 9771a9e..8947eda 100644 --- a/spec/compiler.sx +++ b/spec/compiler.sx @@ -116,7 +116,7 @@ (define emit-const (fn (em value) (let ((idx (pool-add (get em "pool") value))) - (emit-op em 0x01) ;; OP_CONST + (emit-op em 1) ;; OP_CONST (emit-u16 em idx)))) (define current-offset @@ -143,7 +143,7 @@ (cond ;; Nil (nil? expr) - (emit-op em 0x02) ;; OP_NIL + (emit-op em 2) ;; OP_NIL ;; Number (= (type-of expr) "number") @@ -155,7 +155,7 @@ ;; Boolean (= (type-of expr) "boolean") - (emit-op em (if expr 0x03 0x04)) ;; OP_TRUE / OP_FALSE + (emit-op em (if expr 3 4)) ;; OP_TRUE / OP_FALSE ;; Keyword (= (type-of expr) "keyword") @@ -168,7 +168,7 @@ ;; List — dispatch on head (= (type-of expr) "list") (if (empty? expr) - (do (emit-op em 0x40) (emit-u16 em 0)) ;; OP_LIST 0 + (do (emit-op em 64) (emit-u16 em 0)) ;; OP_LIST 0 (compile-list em expr scope tail?)) ;; Dict literal @@ -185,15 +185,15 @@ (let ((resolved (scope-resolve scope name))) (cond (= (get resolved "type") "local") - (do (emit-op em 0x10) ;; OP_LOCAL_GET + (do (emit-op em 16) ;; OP_LOCAL_GET (emit-byte em (get resolved "index"))) (= (get resolved "type") "upvalue") - (do (emit-op em 0x12) ;; OP_UPVALUE_GET + (do (emit-op em 18) ;; OP_UPVALUE_GET (emit-byte em (get resolved "index"))) :else ;; Global or primitive (let ((idx (pool-add (get em "pool") name))) - (emit-op em 0x14) ;; OP_GLOBAL_GET + (emit-op em 20) ;; OP_GLOBAL_GET (emit-u16 em idx)))))) @@ -205,7 +205,7 @@ (emit-const em k) (compile-expr em (get expr k) scope false)) ks) - (emit-op em 0x41) ;; OP_DICT + (emit-op em 65) ;; OP_DICT (emit-u16 em count)))) @@ -254,23 +254,23 @@ ;; Compile test (compile-expr em test scope false) ;; Jump if false to else - (emit-op em 0x21) ;; OP_JUMP_IF_FALSE + (emit-op em 33) ;; OP_JUMP_IF_FALSE (let ((else-jump (current-offset em))) (emit-i16 em 0) ;; placeholder ;; Compile then (in tail position if if is) (compile-expr em then-expr scope tail?) ;; Jump over else - (emit-op em 0x20) ;; OP_JUMP + (emit-op em 32) ;; OP_JUMP (let ((end-jump (current-offset em))) (emit-i16 em 0) ;; placeholder ;; Patch else jump - (patch-i16 em else-jump (- (current-offset em) else-jump -2)) + (patch-i16 em else-jump (- (current-offset em) (+ else-jump 2))) ;; Compile else (if (nil? else-expr) - (emit-op em 0x02) ;; OP_NIL + (emit-op em 2) ;; OP_NIL (compile-expr em else-expr scope tail?)) ;; Patch end jump - (patch-i16 em end-jump (- (current-offset em) end-jump -2))))))) + (patch-i16 em end-jump (- (current-offset em) (+ end-jump 2)))))))) (define compile-when @@ -278,61 +278,61 @@ (let ((test (first args)) (body (rest args))) (compile-expr em test scope false) - (emit-op em 0x21) ;; OP_JUMP_IF_FALSE + (emit-op em 33) ;; OP_JUMP_IF_FALSE (let ((skip-jump (current-offset em))) (emit-i16 em 0) (compile-begin em body scope tail?) - (emit-op em 0x20) ;; OP_JUMP + (emit-op em 32) ;; OP_JUMP (let ((end-jump (current-offset em))) (emit-i16 em 0) - (patch-i16 em skip-jump (- (current-offset em) skip-jump -2)) - (emit-op em 0x02) ;; OP_NIL - (patch-i16 em end-jump (- (current-offset em) end-jump -2))))))) + (patch-i16 em skip-jump (- (current-offset em) (+ skip-jump 2))) + (emit-op em 2) ;; OP_NIL + (patch-i16 em end-jump (- (current-offset em) (+ end-jump 2)))))))) (define compile-and (fn (em args scope tail?) (if (empty? args) - (emit-op em 0x03) ;; OP_TRUE + (emit-op em 3) ;; OP_TRUE (if (= (len args) 1) (compile-expr em (first args) scope tail?) (do (compile-expr em (first args) scope false) - (emit-op em 0x06) ;; OP_DUP - (emit-op em 0x21) ;; OP_JUMP_IF_FALSE + (emit-op em 6) ;; OP_DUP + (emit-op em 33) ;; OP_JUMP_IF_FALSE (let ((skip (current-offset em))) (emit-i16 em 0) - (emit-op em 0x05) ;; OP_POP (discard duplicated truthy) + (emit-op em 5) ;; OP_POP (discard duplicated truthy) (compile-and em (rest args) scope tail?) - (patch-i16 em skip (- (current-offset em) skip -2)))))))) + (patch-i16 em skip (- (current-offset em) (+ skip 2))))))))) (define compile-or (fn (em args scope tail?) (if (empty? args) - (emit-op em 0x04) ;; OP_FALSE + (emit-op em 4) ;; OP_FALSE (if (= (len args) 1) (compile-expr em (first args) scope tail?) (do (compile-expr em (first args) scope false) - (emit-op em 0x06) ;; OP_DUP - (emit-op em 0x22) ;; OP_JUMP_IF_TRUE + (emit-op em 6) ;; OP_DUP + (emit-op em 34) ;; OP_JUMP_IF_TRUE (let ((skip (current-offset em))) (emit-i16 em 0) - (emit-op em 0x05) ;; OP_POP + (emit-op em 5) ;; OP_POP (compile-or em (rest args) scope tail?) - (patch-i16 em skip (- (current-offset em) skip -2)))))))) + (patch-i16 em skip (- (current-offset em) (+ skip 2))))))))) (define compile-begin (fn (em exprs scope tail?) (if (empty? exprs) - (emit-op em 0x02) ;; OP_NIL + (emit-op em 2) ;; OP_NIL (if (= (len exprs) 1) (compile-expr em (first exprs) scope tail?) (do (compile-expr em (first exprs) scope false) - (emit-op em 0x05) ;; OP_POP + (emit-op em 5) ;; OP_POP (compile-begin em (rest exprs) scope tail?)))))) @@ -349,7 +349,7 @@ (value (nth binding 1)) (slot (scope-define-local let-scope name))) (compile-expr em value let-scope false) - (emit-op em 0x11) ;; OP_LOCAL_SET + (emit-op em 17) ;; OP_LOCAL_SET (emit-byte em slot))) bindings) ;; Compile body in let scope @@ -371,14 +371,14 @@ params) ;; Compile body (compile-begin fn-em body fn-scope true) ;; tail position - (emit-op fn-em 0x32) ;; OP_RETURN + (emit-op fn-em 50) ;; OP_RETURN ;; Add code object to parent constant pool (let ((code {:arity (len (get fn-scope "locals")) :bytecode (get fn-em "bytecode") :pool (get fn-em "pool") :upvalues (get fn-scope "upvalues")}) (code-idx (pool-add (get em "pool") code))) - (emit-op em 0x33) ;; OP_CLOSURE + (emit-op em 51) ;; OP_CLOSURE (emit-u16 em code-idx))))) @@ -391,7 +391,7 @@ (value (nth args 1)) (name-idx (pool-add (get em "pool") name))) (compile-expr em value scope false) - (emit-op em 0x80) ;; OP_DEFINE + (emit-op em 128) ;; OP_DEFINE (emit-u16 em name-idx)))) @@ -405,21 +405,21 @@ (compile-expr em value scope false) (cond (= (get resolved "type") "local") - (do (emit-op em 0x11) ;; OP_LOCAL_SET + (do (emit-op em 17) ;; OP_LOCAL_SET (emit-byte em (get resolved "index"))) (= (get resolved "type") "upvalue") - (do (emit-op em 0x13) ;; OP_UPVALUE_SET + (do (emit-op em 19) ;; OP_UPVALUE_SET (emit-byte em (get resolved "index"))) :else (let ((idx (pool-add (get em "pool") name))) - (emit-op em 0x15) ;; OP_GLOBAL_SET + (emit-op em 21) ;; OP_GLOBAL_SET (emit-u16 em idx)))))) (define compile-quote (fn (em args) (if (empty? args) - (emit-op em 0x02) ;; OP_NIL + (emit-op em 2) ;; OP_NIL (emit-const em (first args))))) @@ -440,7 +440,7 @@ (let ((name (symbol-name head)) (name-idx (pool-add (get em "pool") name))) (for-each (fn (a) (compile-expr em a scope false)) args) - (emit-op em 0x34) ;; OP_CALL_PRIM + (emit-op em 52) ;; OP_CALL_PRIM (emit-u16 em name-idx) (emit-byte em (len args))) ;; General call @@ -448,9 +448,9 @@ (compile-expr em head scope false) (for-each (fn (a) (compile-expr em a scope false)) args) (if tail? - (do (emit-op em 0x31) ;; OP_TAIL_CALL + (do (emit-op em 49) ;; OP_TAIL_CALL (emit-byte em (len args))) - (do (emit-op em 0x30) ;; OP_CALL + (do (emit-op em 48) ;; OP_CALL (emit-byte em (len args))))))))) @@ -464,7 +464,7 @@ (let ((em (make-emitter)) (scope (make-scope nil))) (compile-expr em expr scope false) - (emit-op em 0x32) ;; OP_RETURN + (emit-op em 50) ;; OP_RETURN {:bytecode (get em "bytecode") :pool (get em "pool")}))) @@ -475,10 +475,10 @@ (scope (make-scope nil))) (for-each (fn (expr) (compile-expr em expr scope false) - (emit-op em 0x05)) ;; OP_POP between top-level exprs + (emit-op em 5)) ;; OP_POP between top-level exprs (init exprs)) ;; Last expression's value is the module result (compile-expr em (last exprs) scope false) - (emit-op em 0x32) ;; OP_RETURN + (emit-op em 50) ;; OP_RETURN {:bytecode (get em "bytecode") :pool (get em "pool")})))