mirror of
https://git.savannah.gnu.org/git/guile.git
synced 2025-04-30 03:40:34 +02:00
156 lines
4.4 KiB
Scheme
156 lines
4.4 KiB
Scheme
;;; Guile VM code converters
|
||
|
||
;; Copyright (C) 2001 Free Software Foundation, Inc.
|
||
|
||
;; This program is free software; you can redistribute it and/or modify
|
||
;; it under the terms of the GNU General Public License as published by
|
||
;; the Free Software Foundation; either version 2, or (at your option)
|
||
;; any later version.
|
||
;;
|
||
;; This program is distributed in the hope that it will be useful,
|
||
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||
;; GNU General Public License for more details.
|
||
;;
|
||
;; You should have received a copy of the GNU General Public License
|
||
;; along with this program; see the file COPYING. If not, write to
|
||
;; the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
|
||
;; Boston, MA 02111-1307, USA.
|
||
|
||
;;; Code:
|
||
|
||
(define-module (system vm conv)
|
||
:use-module (system vm core)
|
||
:use-module (ice-9 match)
|
||
:use-module (ice-9 regex)
|
||
:export (code-pack code-unpack object->code code->object code->bytes
|
||
make-byte-decoder))
|
||
|
||
;;;
|
||
;;; Code compress/decompression
|
||
;;;
|
||
|
||
(define (code-pack code)
|
||
(match code
|
||
((inst (? integer? n))
|
||
(cond ((< n 10)
|
||
(let ((abbrev (string->symbol (format #f "~A:~A" inst n))))
|
||
(if (instruction? abbrev) (list abbrev) code)))
|
||
(else code)))
|
||
(else code)))
|
||
|
||
(define (code-unpack code)
|
||
(let ((inst (symbol->string (car code))))
|
||
(cond
|
||
((string-match "^([^:]*):([0-9]+)$" inst) =>
|
||
(lambda (data)
|
||
(cons* (string->symbol (match:substring data 1))
|
||
(string->number (match:substring data 2))
|
||
(cdr code))))
|
||
(else code))))
|
||
|
||
|
||
;;;
|
||
;;; Encoder/decoder
|
||
;;;
|
||
|
||
(define (object->code x)
|
||
(cond ((eq? x #t) `(make-true))
|
||
((eq? x #f) `(make-false))
|
||
((null? x) `(make-eol))
|
||
((and (integer? x) (exact? x))
|
||
(cond ((and (<= -128 x) (< x 128))
|
||
`(make-int8 ,(modulo x 256)))
|
||
((and (<= -32768 x) (< x 32768))
|
||
(let ((n (if (< x 0) (+ x 65536) x)))
|
||
`(make-int16 ,(quotient n 256) ,(modulo n 256))))
|
||
(else #f)))
|
||
((char? x) `(make-char8 ,(char->integer x)))
|
||
(else #f)))
|
||
|
||
(define (code->object code)
|
||
(match code
|
||
(('make-true) #t)
|
||
(('make-false) #f) ;; FIXME: Same as the `else' case!
|
||
(('make-eol) '())
|
||
(('make-int8 n)
|
||
(if (< n 128) n (- n 256)))
|
||
(('make-int16 n1 n2)
|
||
(let ((n (+ (* n1 256) n2)))
|
||
(if (< n 32768) n (- n 65536))))
|
||
(('make-char8 n)
|
||
(integer->char n))
|
||
(('load-string s) s)
|
||
(('load-symbol s) (string->symbol s))
|
||
(('load-keyword s) (make-keyword-from-dash-symbol (string->symbol s)))
|
||
(('link s) (cons (string->symbol s) '???))
|
||
(else #f)))
|
||
|
||
(define (code->bytes code)
|
||
(let* ((code (code-pack code))
|
||
(inst (car code))
|
||
(rest (cdr code))
|
||
(head (make-string 1 (integer->char (instruction->opcode inst))))
|
||
(len (instruction-length inst)))
|
||
(cond ((< len 0)
|
||
;; Variable-length code
|
||
(let ((str (car rest)))
|
||
(string-append head (encode-length (string-length str)) str)))
|
||
((= len (length rest))
|
||
;; Fixed-length code
|
||
(string-append head (list->string (map integer->char rest))))
|
||
(else
|
||
(error "Invalid code:" code)))))
|
||
|
||
(define (make-byte-decoder bytes)
|
||
(let ((addr 0) (size (string-length bytes)))
|
||
(define (pop)
|
||
(let ((byte (char->integer (string-ref bytes addr))))
|
||
(set! addr (1+ addr))
|
||
byte))
|
||
(lambda ()
|
||
(if (< addr size)
|
||
(let* ((start addr)
|
||
(inst (opcode->instruction (pop)))
|
||
(n (instruction-length inst))
|
||
(code (if (< n 0)
|
||
;; variable length
|
||
(let* ((end (+ (decode-length pop) addr))
|
||
(str (substring bytes addr end)))
|
||
(set! addr end)
|
||
(list inst str))
|
||
;; fixed length
|
||
(do ((n n (1- n))
|
||
(l '() (cons (pop) l)))
|
||
((= n 0) (cons* inst (reverse! l)))))))
|
||
(values start code))
|
||
#f))))
|
||
|
||
|
||
;;;
|
||
;;; Variable-length interface
|
||
;;;
|
||
|
||
;; NOTE: decoded in vm_fetch_length in vm.c.
|
||
|
||
(define (encode-length len)
|
||
(define C integer->char)
|
||
(cond ((< len 254) (string (C len)))
|
||
((< len (* 256 256))
|
||
(string (C 254) (C (quotient len 256)) (C (modulo len 256))))
|
||
((< len most-positive-fixnum)
|
||
(string (C 255)
|
||
(C (quotient len (* 256 256 256)))
|
||
(C (modulo (quotient len (* 256 256)) 256))
|
||
(C (modulo (quotient len 256) 256))
|
||
(C (modulo len 256))))
|
||
(else (error "Too long code length:" len))))
|
||
|
||
(define (decode-length pop)
|
||
(let ((len (pop)))
|
||
(cond ((< len 254) len)
|
||
((= len 254) (+ (* (pop) 256) (pop)))
|
||
(else (+ (* (pop) 256 256 256)
|
||
(* (pop) 256 256)
|
||
(* (pop) 256)
|
||
(pop))))))
|