home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
The World of Computer Software
/
World_Of_Computer_Software-02-385-Vol-1of3.iso
/
s
/
s48.zip
/
VM
/
PRIM.SCM
< prev
next >
Wrap
Text File
|
1992-06-17
|
15KB
|
476 lines
; -*- Mode: Scheme; Syntax: Scheme; Package: Scheme; -*-
; Copyright (c) 1992 by Richard Kelsey and Jonathan Rees. See file COPYING.
; This is file prim.scm.
; Requires DEFINE-PRIMITIVE macro.
;;;; VM data manipulation primitives
; Input checking and coercion
(define (input-type pred coercer) ;Alonzo wins
(lambda (f) (f pred coercer)))
(define (input-type-predicate type) (type (lambda (x y) y x)))
(define (input-type-coercion type) (type (lambda (x y) x y)))
(define (no-coercion x) x)
(define any-> (input-type (lambda (x) x #t) no-coercion))
(define fixnum-> (input-type fixnum? extract-fixnum))
(define char-> (input-type vm-char? extract-char))
(define boolean-> (input-type boolean? extract-boolean))
; Output coercion
(define (return val)
(set! *val* val)
(goto interpret))
(define return-any return)
(define (return-boolean x)
(return (enter-boolean x)))
(define (return-fixnum x)
(return (enter-fixnum x)))
(define (return-char x)
(return (enter-char x)))
(define (return-unspecified x)
x ;ignored
(return unspecified))
; Scalar primitives
(define-primitive op/eq? (any-> any->) vm-eq? return-boolean)
; Rudimentary generic arithmetic. Incomplete and confusing.
; How to modularize for VM's like Maclisp that have generic arithmetic
; built-in?
; These predicates are used to characterize the numeric representations that
; are implemented in the VM.
(define primitive-number? fixnum?)
(define primitive-real? fixnum?)
(define primitive-integer? fixnum?)
(define number-> (input-type primitive-number? no-coercion))
(define real-> (input-type primitive-real? no-coercion))
(define integer-> (input-type primitive-integer? no-coercion))
(define-primitive op/number? (any->) vm-number? return-boolean)
(define (define-numeric-predicate op)
(define-primitive op
(any->)
(lambda (n)
(cond ((fixnum? n)
(return (enter-boolean #t)))
((extended-number? n)
(raise-exception1 0 n))
(else
(return (enter-boolean #f)))))))
(define-numeric-predicate op/integer?)
(define-numeric-predicate op/rational?)
(define-numeric-predicate op/real?)
(define-numeric-predicate op/complex?)
; These primitives have a simple answer in the case of fixnums; for all other
; they punt to the run-time system.
(define-primitive op/exact? (number->) (lambda (n) #t) return-boolean)
(define-primitive op/real-part (number->) (lambda (n) (return n)))
(define-primitive op/imag-part (number->) (lambda (n)
(return (enter-fixnum 0))))
(define-primitive op/floor (number->) (lambda (n) (return n)))
(define-primitive op/numerator (number->) (lambda (n) (return n)))
(define-primitive op/denominator (number->) (lambda (n)
(return (enter-fixnum 1))))
(define-primitive op/angle (number->) (lambda (n)
(if (>= n 0)
(return (enter-fixnum 0))
(raise-exception1 0 n))))
; beware of (abs least-fixnum)
(define-primitive op/magnitude (number->)
(lambda (n)
(let ((r (abs n)))
(if (too-big-for-fixnum? r)
(raise-exception1 0 n)
(return (enter-fixnum r))))))
; These primitives all just raise an exception and let the run-time system do
; the work.
(define (define-punt-primitive op)
(define-primitive op (number->) (lambda (n) (raise-exception1 0 n))))
(define-punt-primitive op/exact->inexact)
(define-punt-primitive op/inexact->exact)
(define-punt-primitive op/exp)
(define-punt-primitive op/log)
(define-punt-primitive op/sin)
(define-punt-primitive op/cos)
(define-punt-primitive op/tan)
(define-punt-primitive op/asin)
(define-punt-primitive op/acos)
(define-punt-primitive op/atan)
(define-punt-primitive op/sqrt)
(define-punt-primitive op/make-polar)
(define-punt-primitive op/make-rectangular)
(define (arithmetic-overflow x y)
(raise-exception2 0 x y))
(define (arith op)
(lambda (x y)
(op x y return arithmetic-overflow)))
(define-primitive op/+ (number-> number->) (arith add-carefully))
(define-primitive op/- (number-> number->) (arith subtract-carefully))
(define-primitive op/* (number-> number->) (arith multiply-carefully))
(define-primitive op// (number-> number->) (arith divide-carefully))
(define-primitive op/quotient (integer-> integer->) (arith quotient-carefully))
(define-primitive op/remainder (integer-> integer->) (arith remainder-carefully))
(define-primitive op/= (number-> number->) vm-= return-boolean)
(define-primitive op/< (real-> real->) vm-< return-boolean)
(define-primitive op/char? (any->) vm-char? return-boolean)
(define-primitive op/char=? (char-> char->) vm-char=? return-boolean)
(define-primitive op/char<? (char-> char->) vm-char<? return-boolean)
(define-primitive op/char->ascii (char->) char->ascii return-fixnum)
(define-primitive op/ascii->char
(fixnum->)
(lambda (x)
(if (or (> x 255) (< x 0))
(raise-exception1 0 (enter-fixnum x))
(return (enter-char (ascii->char x))))))
(define-primitive op/eof-object?
(any->)
(lambda (x) (vm-eq? x eof-object))
return-boolean)
(define-primitive op/bitwise-not (fixnum->) bitwise-not return-fixnum)
(define-primitive op/bitwise-and (fixnum-> fixnum->) bitwise-and return-fixnum)
(define-primitive op/bitwise-ior (fixnum-> fixnum->) bitwise-ior return-fixnum)
(define-primitive op/bitwise-xor (fixnum-> fixnum->) bitwise-xor return-fixnum)
(define-primitive op/arithmetic-shift
(fixnum-> fixnum->)
(lambda (value count)
(if (< count 0)
(ashr value (- 0 count))
(let ((result (extract-fixnum (enter-fixnum (ashl value count)))))
(if (and (= value (ashr result count))
(if (>= value 0)
(>= result 0)
(< result 0)))
result
(arithmetic-overflow (enter-fixnum value)
(enter-fixnum count))))))
return-fixnum)
; Synchronize this with struct.scm.
(define-primitive-structure-type #t pair cons
(car set-car!)
(cdr set-cdr!))
(define-primitive-structure-type #t symbol make-symbol
(symbol->string))
(define-primitive-structure-type #f closure make-closure
(closure-template)
(closure-env))
(define-primitive-structure-type #f location make-location
(contents set-contents!)
(location-id))
(define location-> (input-type location? no-coercion))
(define-primitive op/location-defined? (location->)
(lambda (loc)
(return-boolean (or (not (undefined? (contents loc)))
(= (contents loc) unassigned-marker)))))
(define-primitive op/set-location-defined?! (location-> boolean->)
(lambda (loc value)
(cond ((not value)
(set-contents! loc unbound-marker))
((undefined? (contents loc))
(set-contents! loc unassigned-marker)))
(return unspecified)))
; (Note: no port primitives.)
(define (vector-maker size make set)
(lambda (len init)
(let ((finish (lambda (init)
(let ((v (make len (preallocate-space (size len)))))
;; Clear out storage
(do ((i (- len 1) (- i 1)))
((< i 0)
(return v))
(set v i init))))))
(cond ((not (>= len 0))
(raise-exception2 0 (enter-fixnum len) init))
((available? (size len))
(finish init))
(else
(let ((init (collect-saving-temp init)))
(if (available? (size len))
(finish init)
(raise-exception2 0 (enter-fixnum len) init))))))))
(define (vector-referencer length ref coerce)
(lambda (v index)
(cond ((valid-index? index (length v))
(coerce (ref v index)))
(else
(raise-exception2 0 v (enter-fixnum index))))))
(define (vector-setter length set)
(lambda (v index val)
(cond ((valid-index? index (length v))
(set v index val)
(return unspecified))
(else
(raise-exception2 0 v (enter-fixnum index))))))
(define-vector-type vector any #t)
(define-vector-type record any #f)
(define-vector-type extended-number any #f)
(define-vector-type continuation any #f)
(define-vector-type string char #t)
(define-vector-type code-vector fixnum #f)
(define string-> (input-type vm-string? no-coercion))
(define vector-> (input-type vm-vector? no-coercion))
; I/O primitives
(define (vm-input-port? obj)
(and (port? obj)
(= (port-mode obj) (enter-fixnum for-input))))
(define (vm-output-port? obj)
(and (port? obj)
(= (port-mode obj) (enter-fixnum for-output))))
(define port-> (input-type port? no-coercion))
(define input-port-> (input-type vm-input-port? no-coercion))
(define output-port-> (input-type vm-output-port? no-coercion))
(define-primitive op/halt (any->)
(lambda (status)
(halt-machine status)))
(define-primitive op/input-port? (any->) vm-input-port? return-boolean)
(define-primitive op/output-port? (any->) vm-output-port? return-boolean)
(define-consing-primitive op/open-port (string-> fixnum->)
(lambda (ignore) port-size)
(lambda (filename mode key)
(let loop ((index (find-port-index)) (filename filename))
(cond (index
(let* ((port
(cond ((= mode for-output)
(open-output-file (extract-string filename)))
(else ;(= mode for-input)
(open-input-file (extract-string filename))))))
(if port
(let ((vm-port (make-port (enter-fixnum mode)
(enter-fixnum index)
false
filename
key)))
(use-port-index! index vm-port port)
(return vm-port))
(return false))))
(else
(let ((filename (collect-saving-temp filename)))
(let ((index (find-port-index)))
(if index
(loop index filename)
(error "ran out of ports")))))))))
(define-primitive op/close-port (port->) close-port return-unspecified)
(define-primitive op/read-char (input-port->)
(lambda (port)
(if (open? port)
(let ((c (peeked-char port)))
(return (cond ((false? c)
(vm-read-char (extract-port port)
(lambda (c) (enter-char c))
(lambda () eof-object)))
(else
(set-peeked-char! port false)
c))))
(raise-exception1 0 port))))
(define-primitive op/peek-char (input-port->)
(lambda (port)
(if (open? port)
(let ((c (peeked-char port)))
(return (cond ((false? c)
(let ((c (vm-read-char (extract-port port)
(lambda (c) (enter-char c))
(lambda () eof-object))))
(set-peeked-char! port c)
c))
(else c))))
(raise-exception1 0 port))))
(define-primitive op/write-char (char-> output-port->)
(lambda (c port)
(cond ((open? port)
(write-char c (extract-port port))
(return unspecified))
(else
(raise-exception2 0 c port)))))
(define-primitive op/write-string (string-> output-port->)
(lambda (s port)
(cond ((open? port)
(write-vm-string s (extract-port port))
(return unspecified))
(else
(raise-exception2 0 s port)))))
(define-primitive op/force-output (output-port->)
(lambda (port)
(cond ((open? port)
(force-output (extract-port port))
(return unspecified))
(else
(raise-exception1 0 port)))))
; Misc
(define-primitive op/false ()
(lambda ()
(return false)))
(define-primitive op/trap (any->)
(lambda (arg)
(raise-exception1 0 arg)))
(define-primitive op/find-all-symbols (vector->)
(lambda (table)
(if (add-symbols-to-table table)
(return unspecified)
(raise-exception 0))))
; RESUME-PROC is called when the image is resumed.
; CONTINUE-PROC is called to continue the current computation. CONTINUE-PROC
; is not saved in the image.
(define-primitive op/write-image (string-> any-> any->)
(lambda (filename resume-proc continue-proc)
(let ((port (open-output-file (extract-string filename))))
(cond ((not port)
(raise-exception3 0 filename resume-proc continue-proc))
(else
(clear-registers)
(set! *val* resume-proc)
(interpreter-collect)
(write-image port *val*)
(close-output-port port)
(let ((continue-proc (trace-value continue-proc)))
(set! *val* continue-proc)
(set! *nargs* 0)
(goto perform-application)))))))
(define-primitive op/collect ()
(lambda ()
(set! *val* unspecified)
(interpreter-collect)
(return unspecified)))
(define-primitive op/vm (fixnum-> any->)
(lambda (key other)
(if (or (< key 0) (>= key 3))
(raise-exception2 0 (enter-fixnum key) other)
(return (cond ((= key 0)
(enter-fixnum (available)))
((= key 1)
(enter-fixnum (apply-primitive runtime))))))))
(define-primitive op/vm-extension (fixnum-> any->)
(lambda (key value)
(let ((return-value (extended-vm key value)))
(if (undefined? return-value)
(raise-exception2 0 (enter-fixnum key) value)
(return return-value)))))
(define-primitive op/vm-return (fixnum-> any->)
(lambda (key value)
(set! *val* value)
(halt-machine key)))
(define-primitive op/get-dynamic-state ()
(lambda () *dynamic-state*)
return-any)
(define-primitive op/set-dynamic-state! (any->)
(lambda (state)
(set! *dynamic-state* state)
unspecified)
return-any)
; Unnecessary primitives
(define-primitive op/string=? (string-> string->) vm-string=? return-boolean)
; Special primitive called by the reader.
; Primitive for the sake of speed. Probably should be flushed.
(define-consing-primitive op/reverse-list->string (any-> fixnum->)
(lambda (n) (vm-string-size n))
(lambda (l n k)
(if (not (or (vm-pair? l) (vm-eq? l null)))
(raise-exception2 0 l n)
(let ((obj (vm-make-string n k)))
(do ((l l (vm-cdr l))
(i (- n 1) (- i 1)))
((< i 0) (return obj))
(vm-string-set! obj i (extract-char (vm-car l))))))))
(define-primitive op/string-hash (string->) vm-string-hash return-fixnum)
(define-consing-primitive op/intern (string-> vector->)
(lambda (ignore) (+ vm-symbol-size vm-pair-size))
intern
return)
(define-consing-primitive op/lookup (any-> any->)
(lambda (ignore) (+ location-size vm-pair-size))
lookup
return)
;#|
;(define-primitive op/vector (fixnum->)
; (let* ((min-args (next-byte))
; (len (- *nargs* min-args))
; (key (ensure-space (vector-size len)))
; (vec (make-vector len)))
; (do ((i (- len 1) (- i 1)))
; ((= i -1)
; (set! *val* l)
; (set! *nargs* (+ min-args 1))
; (goto interpret))
; (vector-set vec i (pop)))))
;|#
; Eventually add make-table, table-ref, table-set! as primitives?
; No -- write a compiler instead.