; Copyright (c) 1993-1999 by Richard Kelsey and Jonathan Rees. See file COPYING.


; Fixnum-only primitive operations

; These predicates are used to characterize the numeric representations that
; are implemented in the VM.

(define (unary-lose x)
  (raise-exception wrong-type-argument 0 x))

(define (binary-lose x y)
  (raise-exception wrong-type-argument 0 x y))

(define-primitive number? (any->)
  (lambda (x)
    (or (fixnum? x)
	(bignum? x)
	(ratnum? x)
	(double? x)
	(extended-number? x)))
  return-boolean)
  
(define (vm-number-predicate rationals? doubles?)
  (lambda (n)
    (cond ((or (fixnum? n)
	       (bignum? n)
	       (and rationals? (ratnum? n))
	       (and doubles? (double? n)))
	   (goto return-boolean #t))
	  ((extended-number? n)
	   (unary-lose n))
	  (else
	   (goto return-boolean #f)))))

(define-primitive integer?  (any->) (vm-number-predicate #f #f))
(define-primitive rational? (any->) (vm-number-predicate #t #t))
(define-primitive real?     (any->) (vm-number-predicate #t #t))
(define-primitive complex?  (any->) (vm-number-predicate #t #t))

;----------------
; A macro for defining primitives that only operate on fixnums.

(define-syntax define-fixnum-only
  (syntax-rules ()
    ((define-fixnum-only (opcode arg) value)
     (define-primitive opcode (any->)
       (lambda (arg)
	 (if (fixnum? arg)
	     (goto return value)
	     (unary-lose arg)))))
    ((define-fixnum-only (opcode arg0 arg1) value)
     (define-primitive opcode (any-> any->)
       (lambda (arg0 arg1)
	 (if (and (fixnum? arg0)
		  (fixnum? arg1))
	     (goto return value)
	     (binary-lose arg0 arg1)))))))

; These primitives have a simple answer in the case of fixnums; for all others
; they punt to the run-time system.

(define-fixnum-only (exact?      n) true)
(define-fixnum-only (real-part   n) n)
(define-fixnum-only (imag-part   n) (enter-fixnum 0))
(define-fixnum-only (floor       n) n)
(define-fixnum-only (numerator   n) n)
(define-fixnum-only (denominator n) (enter-fixnum 1))

(define-primitive angle (any->)
  (lambda (n)
    (if (and (fixnum? n)
	     (>= n 0))
	(goto return (enter-fixnum 0))
	(unary-lose n))))

(define-primitive magnitude (any->)
  (lambda (n)
    (if (fixnum? n)
	(abs-carefully n
		       (lambda (r)
			 (goto return r))
		       unary-lose)
	(unary-lose n))))

; These all just raise an exception and let the run-time system do the work.

(define-syntax define-punter
  (syntax-rules ()
    ((define-punter opcode)
     (define-primitive opcode (any->) unary-lose))))

(define-punter exact->inexact)
(define-punter inexact->exact)
(define-punter exp)
(define-punter log)
(define-punter sin)
(define-punter cos)
(define-punter tan)
(define-punter asin)
(define-punter acos)
(define-punter sqrt)

(define-syntax define-punter2
  (syntax-rules ()
    ((define-punter2 opcode)
     (define-primitive opcode (any-> any->) binary-lose))))

(define-punter2 atan)
(define-punter2 make-polar)
(define-punter2 make-rectangular)

(define-syntax define-binop
  (syntax-rules ()
    ((define-binop opcode careful-op)
     (define-primitive opcode (any-> any->)
       (lambda (x y)
	 (if (and (fixnum? x)
		  (fixnum? y))
	     (goto careful-op x y return binary-lose)
	     (binary-lose x y)))))))

(define-binop + add-carefully)
(define-binop - subtract-carefully)
(define-binop * multiply-carefully)
(define-binop / divide-carefully)
(define-binop quotient         quotient-carefully)
(define-binop remainder        remainder-carefully)
(define-binop arithmetic-shift shift-carefully)

(define-fixnum-only (=  x y) (enter-boolean (fixnum=  x y)))
(define-fixnum-only (<  x y) (enter-boolean (fixnum<  x y)))
(define-fixnum-only (>  x y) (enter-boolean (fixnum>  x y)))
(define-fixnum-only (<= x y) (enter-boolean (fixnum<= x y)))
(define-fixnum-only (>= x y) (enter-boolean (fixnum>= x y)))

(define-fixnum-only (bitwise-not x)   (fixnum-bitwise-not x))
(define-fixnum-only (bitwise-and x y) (fixnum-bitwise-and x y))
(define-fixnum-only (bitwise-ior x y) (fixnum-bitwise-ior x y))
(define-fixnum-only (bitwise-xor x y) (fixnum-bitwise-xor x y))