Toy VM (11)

gauche vm の命令列をベクトルで取ってくる方法が分かった。もともと vm-code->list という手続きがあり、再帰的に実行するようにしただけ。
(というか別の方法が既に用意されているかもしれないけど)

(use gauche.sequence)
(define compile (with-module gauche.internal compile))
(define vm-code->list (with-module gauche.internal vm-code->list))

(define compiled-code?
  (lambda (obj)
    (is-a? obj <compiled-code>)))

(define (vm-code-list->vector lst)
  (list->vector (map (lambda (x)
                       (cond
                        ((identifier? x)
                         (identifier->symbol x))
                        ((pair? x)
                         (cons (make-keyword (car x)) (cdr x)))
                        ((compiled-code? x)
                         (vm-code-list->vector (vm-code->list x)))
                        (else
                         x)))
                     lst)))

(define (compile->vector exp)
  (vm-code-list->vector (vm-code->list (compile exp ()))))

こんな感じで使う。disasm で得られる内容と大差は無いけど、

gosh> (disasm (lambda () (let ((fn (lambda (x) (+ x 2)))) fn)))
main_code (name=#f, code=0x1004f9510, size=6, const=1, stack=4):
args: #f
     0 CLOSURE #<lambda 0>      ; (lambda (x) (+ x 2))
     2 PUSH 
     3 LOCAL-ENV(1)             ; (let ((fn (lambda (x) (+ x 2)))) fn)
     4 LREF(0,0)                ; fn
     5 RET 
internal_closure_0 (name=fn, code=0x1005cd280, size=9, const=1 stack=5):
args: #f
     0 LREF(0,0)                ; x
     1 PUSH 
     2 CONST 2
     4 PUSH 
     5 GREF #<identifier user#+>; +
     7 TAIL-CALL(2)             ; (+ x 2)
     8 RET 
#<undef>
gosh> (compile->vector '(lambda () (let ((fn (lambda (x) (+ x 2)))) fn)))
#((:CLOSURE) #((:CLOSURE) #((:LREF 0 0) (:PUSH) (:CONST) 2 (:PUSH) (:GREF) + (:TAIL-CALL 2) (:RET)) (:PUSH) (:LOCAL-ENV 1) (:LREF 0 0) (:RET)) (:RET))

再帰的に処理しているので止まらない可能性があるかはちょっと自信なし。