; Copyright (c) 1994 by Richard Kelsey.  See file COPYING.


(define prescheme-primop-table (make-symbol-table))

(walk-vector (lambda (primop)
	       (if (primop? primop)
		   (table-set! prescheme-primop-table
			       (primop-id primop)
			       primop)))
	     all-primops)

(define (get-prescheme-primop id)
  (cond ((table-ref prescheme-primop-table id)
	 => identity)
	((name->enumerand id primop)
	 => get-primop)
	(else
	 (bug "Scheme primop ~A not found" id))))

(define (add-scheme-primop! id primop)
  (table-set! prescheme-primop-table id primop))

(define-syntax define-scheme-primop
  (syntax-rules ()
    ((define-scheme-primop id type)
     (define-scheme-primop id #f type))
    ((define-scheme-primop id side-effects type)
     (define-scheme-primop id side-effects type default-simplifier))
    ((define-scheme-primop id side-effects type simplifier)
     (define-polymorphic-scheme-primop
       id side-effects (lambda (call) type) simplifier))))

(define-syntax define-polymorphic-scheme-primop
  (syntax-rules ()
    ((define-polymorphic-scheme-primop id type)
     (define-polymorphic-scheme-primop id #f type))
    ((define-polymorphic-scheme-primop id side-effects type)
     (define-polymorphic-scheme-primop id side-effects type default-simplifier))
    ((define-scheme-primop id side-effects type simplifier)
     (add-scheme-primop! 'id
			 (make-primop 'id #t 'side-effects simplifier
				      (lambda (call) 1)
				      type)))))

(define-syntax define-nonsimple-scheme-primop
  (syntax-rules ()
    ((define-nonsimple-scheme-primop id)
     (define-nonsimple-scheme-primop id #f))
    ((define-nonsimple-scheme-primop id side-effects)
     (define-nonsimple-scheme-primop id side-effects default-simplifier))
    ((define-nonsimple-scheme-primop id side-effects simplifier)
     (add-scheme-primop! 'id
			 (make-primop 'id #f 'side-effects simplifier
				      (lambda (call) 1)
				      'nontrivial-primop)))))

(define-syntax define-scheme-cond-primop
  (syntax-rules ()
    ((define-scheme-cond-primop id simplifier expand simplify?)
     (add-scheme-primop! 'id
			 (make-conditional-primop 'id
						  #f
						  simplifier
						  (lambda (call) 1)
						  expand
						  simplify?)))))

;(define-prescheme! 'error  ; all four args must be present if used as value
;  (lambda (exp env)
;    (let ((string (expand (cadr exp) env #f))
;          (args (map (lambda (arg)
;                       (expand arg env #f))
;                     (cddr exp))))
;      (make-block-exp
;       (list
;        (make-call-exp (get-prescheme-primop 'error)
;                       0
;                       type/unknown
;                       `(,string
;                         ,(make-quote-exp (length args) type/int32)
;                         . ,(case (length args)
;                              ((0)
;                               (list (make-quote-exp 0 type/int32)
;                                     (make-quote-exp 0 type/int32)
;                                     (make-quote-exp 0 type/int32)))
;                              ((1)
;                               (list (car args)
;                                     (make-quote-exp 0 type/int32)
;                                     (make-quote-exp 0 type/int32)))
;                              ((2)
;                               (list (car args)
;                                     (cadr args)
;                                     (make-quote-exp 0 type/int32)))
;                              ((3)
;                               args)
;                              (else
;                               (error "too many arguments to ERROR in ~S" exp))))
;                       exp)
;        (make-quote-exp the-undefined-value type/unknown))))))

; For the moment VALUES is more or less a macro.

;(define-prescheme! 'values   ; dies if used as a value
;  (lambda (exp env)
;    (make-call-exp (get-prescheme-primop 'pack)
;                   0
;                   type/unknown
;                   (map (lambda (arg)
;                          (expand arg env #f))
;                        (cdr exp))
;                   exp)))

; Each arg spec is either #F = non-continuation argument or a list of
; variable (name . type)s for the continuation.

;(define (define-continuation-expander id primop-id arg-specs)
;  (define-primitive-expander id (length arg-specs)
;    (lambda (source args cenv)
;      (receive (conts other)
;          (expand-arguments args arg-specs cenv)
;        (make-call-exp (get-prescheme-primop primop-id)
;                       (length conts)
;                       type/unknown
;                       (append conts other)
;                       source)))))

;(define (expand-arguments args specs cenv)
;  (let loop ((args args) (specs specs) (conts '()) (other '()))
;    (if (null? args)
;        (values (reverse conts) (reverse other))
;        (let ((arg (expand (car args) cenv #f)))
;          (if (not (car specs))
;              (loop (cdr args) (cdr specs) conts (cons arg other))
;              (loop (cdr args) (cdr specs)
;                    (cons (expand-continuation-arg arg (car specs))
;                          conts)
;                    other))))))                                            
;
;(define (expand-continuation-arg arg var-specs)
;  (let* ((vars (map (lambda (p)
;                      (make-variable (car p) (cdr p)))
;                    var-specs)))
;    (make-continuation-exp
;     vars
;     (make-call-exp (get-primop (enum primop unknown-call))
;                    0
;                    type/unknown
;                    `(,arg
;                      ,(make-quote-exp (length vars) #f)
;                      . ,vars)
;                    #f)))) ; no source

; Randomness needed by both arith.scm and c-arith.scm.

; What we will get in C.
(define prescheme-integer-size 32)

(define int-mask (- (arithmetic-shift 1 prescheme-integer-size) 1))

(define (lshr i n)
  (arithmetic-shift (bitwise-and i int-mask) (- 0 n)))