ikarus/scheme/ikarus.fixnums.ss

405 lines
12 KiB
Scheme

;;; Ikarus Scheme -- A compiler for R6RS Scheme.
;;; Copyright (C) 2006,2007 Abdulaziz Ghuloum
;;;
;;; This program is free software: you can redistribute it and/or modify
;;; it under the terms of the GNU General Public License version 3 as
;;; published by the Free Software Foundation.
;;;
;;; 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. If not, see <http://www.gnu.org/licenses/>.
(library (ikarus fixnums)
(export fxzero? fxadd1 fxsub1 fxlognot fx+ fx- fx* fxquotient
fx+/carry fx*/carry fx-/carry
fxremainder fxmodulo fxlogor fxlogand fxlogxor fxsll fxsra
fx= fx< fx<= fx> fx>=
fx=? fx<? fx<=? fx>? fx>=?
fxior fxand fxxor fxnot fxif
fxpositive? fxnegative?
fxeven? fxodd?
fixnum->string
fxarithmetic-shift-left fxarithmetic-shift-right fxarithmetic-shift
fxmin fxmax
error@fx+)
(import
(ikarus system $fx)
(ikarus system $chars)
(ikarus system $pairs)
(ikarus system $strings)
(prefix (only (ikarus) fx+) sys:)
(except (ikarus) fxzero? fxadd1 fxsub1 fxlognot fx+ fx- fx*
fxquotient fxremainder fxmodulo fxlogor fxlogand
fxlogxor fxsll fxsra fx= fx< fx<= fx> fx>=
fx=? fx<? fx<=? fx>? fx>=?
fxior fxand fxxor fxnot fxif
fxpositive? fxnegative?
fxeven? fxodd?
fxarithmetic-shift-left fxarithmetic-shift-right fxarithmetic-shift
fx+/carry fx*/carry fx-/carry
fxmin fxmax
fixnum->string))
(define fxzero?
(lambda (x)
(cond
[(eq? x 0) #t]
[(fixnum? x) #f]
[else (error 'fxzero? "not a fixnum" x)])))
(define fxadd1
(lambda (n)
(if (fixnum? n)
($fxadd1 n)
(error 'fxadd1 "not a fixnum" n))))
(define fxsub1
(lambda (n)
(if (fixnum? n)
($fxsub1 n)
(error 'fxsub1 "not a fixnum" n))))
(define fxlognot
(lambda (x)
(unless (fixnum? x)
(error 'fxlognot "not a fixnum" x))
($fxlognot x)))
(define fxnot
(lambda (x)
(unless (fixnum? x)
(error 'fxnot "not a fixnum" x))
($fxlognot x)))
(define error@fx+
(lambda (x y)
(if (fixnum? x)
(if (fixnum? y)
(error 'fx+ "overflow when adding numbers" x y)
(error 'fx+ "not a fixnum" y))
(error 'fx+ "not a fixnum" x))))
(define fx+
(lambda (x y)
(sys:fx+ x y)))
(define fx-
(lambda (x y)
(unless (fixnum? x)
(error 'fx- "not a fixnum" x))
(unless (fixnum? y)
(error 'fx- "not a fixnum" y))
($fx- x y)))
(define fx*
(lambda (x y)
(unless (fixnum? x)
(error 'fx* "not a fixnum" x))
(unless (fixnum? y)
(error 'fx* "not a fixnum" y))
($fx* x y)))
(define false-loop
(lambda (who ls)
(if (pair? ls)
(if (fixnum? ($car ls))
(false-loop who ($cdr ls))
(error who "not a fixnum" ($car ls)))
#f)))
(define-syntax fxcmp
(syntax-rules ()
[(_ who $op)
(case-lambda
[(x y)
(unless (fixnum? x)
(error 'who "not a fixnum" x))
(unless (fixnum? y)
(error 'who "not a fixnum" y))
($op x y)]
[(x y . ls)
(if (fixnum? x)
(if (fixnum? y)
(if ($op x y)
(let f ([x y] [ls ls])
(if (pair? ls)
(let ([y ($car ls)] [ls ($cdr ls)])
(if (fixnum? y)
(if ($op x y)
(f y ls)
(false-loop 'who ls))
(error 'who "not a fixnum" y)))
#t))
(false-loop 'who ls))
(error 'who "not a fixnum" y))
(error 'who "not a fixnum" x))]
[(x)
(if (fixnum? x) #t (error 'who "not a fixnum" x))])]))
(define fx= (fxcmp fx= $fx=))
(define fx< (fxcmp fx< $fx<))
(define fx<= (fxcmp fx<= $fx<=))
(define fx> (fxcmp fx> $fx>))
(define fx>= (fxcmp fx>= $fx>=))
(define fx=? (fxcmp fx=? $fx=))
(define fx<? (fxcmp fx<? $fx<))
(define fx<=? (fxcmp fx<=? $fx<=))
(define fx>? (fxcmp fx>? $fx>))
(define fx>=? (fxcmp fx>=? $fx>=))
(define fxquotient
(lambda (x y)
(unless (fixnum? x)
(error 'fxquotient "not a fixnum" x))
(unless (fixnum? y)
(error 'fxquotient "not a fixnum" y))
(when ($fxzero? y)
(error 'fxquotient "zero dividend" y))
($fxquotient x y)))
(define fxremainder
(lambda (x y)
(unless (fixnum? x)
(error 'fxremainder "not a fixnum" x))
(unless (fixnum? y)
(error 'fxremainder "not a fixnum" y))
(when ($fxzero? y)
(error 'fxremainder "zero dividend" y))
(let ([q ($fxquotient x y)])
($fx- x ($fx* q y)))))
(define fxmodulo
(lambda (x y)
(unless (fixnum? x)
(error 'fxmodulo "not a fixnum" x))
(unless (fixnum? y)
(error 'fxmodulo "not a fixnum" y))
(when ($fxzero? y)
(error 'fxmodulo "zero dividend" y))
($fxmodulo x y)))
(define-syntax fxbitop
(syntax-rules ()
[(_ who $op identity)
(case-lambda
[(x y)
(if (fixnum? x)
(if (fixnum? y)
($op x y)
(error 'who "not a fixnum" y))
(error 'who "not a fixnum" x))]
[(x y . ls)
(if (fixnum? x)
(if (fixnum? y)
(let f ([a ($op x y)] [ls ls])
(cond
[(pair? ls)
(let ([b ($car ls)])
(if (fixnum? b)
(f ($op a b) ($cdr ls))
(error 'who "not a fixnum" b)))]
[else a]))
(error 'who "not a fixnum" y))
(error 'who "not a fixnum" x))]
[(x) (if (fixnum? x) x (error 'who "not a fixnum" x))]
[() identity])]))
(define fxlogor (fxbitop fxlogor $fxlogor 0))
(define fxlogand (fxbitop fxlogand $fxlogand -1))
(define fxlogxor (fxbitop fxlogxor $fxlogxor 0))
(define fxior (fxbitop fxior $fxlogor 0))
(define fxand (fxbitop fxand $fxlogand -1))
(define fxxor (fxbitop fxxor $fxlogxor 0))
(define (fxif x y z)
(if (fixnum? x)
(if (fixnum? y)
(if (fixnum? z)
($fxlogor
($fxlogand x y)
($fxlogand ($fxlognot x) z))
(error 'fxif "not a fixnum" z))
(error 'fxif "not a fixnum" y))
(error 'fxif "not a fixnum" x)))
(define fxsra
(lambda (x y)
(unless (fixnum? x)
(error 'fxsra "not a fixnum" x))
(unless (fixnum? y)
(error 'fxsra "not a fixnum" y))
(unless ($fx>= y 0)
(error 'fxsra "negative shift not allowed" y))
($fxsra x y)))
(define fxarithmetic-shift-right
(lambda (x y)
(unless (fixnum? x)
(error 'fxarithmetic-shift-right "not a fixnum" x))
(unless (fixnum? y)
(error 'fxarithmetic-shift-right "not a fixnum" y))
(unless ($fx>= y 0)
(error 'fxarithmetic-shift-right "negative shift not allowed" y))
($fxsra x y)))
(define fxsll
(lambda (x y)
(unless (fixnum? x)
(error 'fxsll "not a fixnum" x))
(unless (fixnum? y)
(error 'fxsll "not a fixnum" y))
(unless ($fx>= y 0)
(error 'fxsll "negative shift not allowed" y))
($fxsll x y)))
(define fxarithmetic-shift-left
(lambda (x y)
(unless (fixnum? x)
(error 'fxarithmetic-shift-left "not a fixnum" x))
(unless (fixnum? y)
(error 'fxarithmetic-shift-left "not a fixnum" y))
(unless ($fx>= y 0)
(error 'fxarithmetic-shift-left "negative shift not allowed" y))
($fxsll x y)))
(define fxarithmetic-shift
(lambda (x y)
(unless (fixnum? x)
(error 'fxarithmetic-shift "not a fixnum" x))
(unless (fixnum? y)
(error 'fxarithmetic-shift "not a fixnum" y))
(if ($fx>= y 0)
($fxsll x y)
(if ($fx< x -100) ;;; arbitrary number < (fixnum-width)
($fxsra x 32)
($fxsra x ($fx- 0 y))))))
(define (fxpositive? x)
(if (fixnum? x)
($fx> x 0)
(error 'fxpositive? "not a fixnum" x)))
(define (fxnegative? x)
(if (fixnum? x)
($fx< x 0)
(error 'fxnegative? "not a fixnum" x)))
(define (fxeven? x)
(if (fixnum? x)
($fxzero? ($fxlogand x 1))
(error 'fxeven? "not a fixnum" x)))
(define (fxodd? x)
(if (fixnum? x)
(not ($fxzero? ($fxlogand x 1)))
(error 'fxodd? "not a fixnum" x)))
(define fxmin
(case-lambda
[(x y)
(if (fixnum? x)
(if (fixnum? y)
(if ($fx< x y) x y)
(error 'fxmin "not a fixnum" y))
(error 'fxmin "not a fixnum" x))]
[(x y z . ls)
(fxmin (fxmin x y)
(if (fixnum? z)
(let f ([z z] [ls ls])
(if (null? ls)
z
(let ([a ($car ls)])
(if (fixnum? a)
(if ($fx< a z)
(f a ($cdr ls))
(f z ($cdr ls)))
(error 'fxmin "not a fixnum" a)))))
(error 'fxmin "not a fixnum" z)))]
[(x) (if (fixnum? x) x (error 'fxmin "not a fixnum" x))]))
(define fxmax
(case-lambda
[(x y)
(if (fixnum? x)
(if (fixnum? y)
(if ($fx> x y) x y)
(error 'fxmax "not a fixnum" y))
(error 'fxmax "not a fixnum" x))]
[(x y z . ls)
(fxmax (fxmax x y)
(if (fixnum? z)
(let f ([z z] [ls ls])
(if (null? ls)
z
(let ([a ($car ls)])
(if (fixnum? a)
(if ($fx> a z)
(f a ($cdr ls))
(f z ($cdr ls)))
(error 'fxmax "not a fixnum" a)))))
(error 'fxmax "not a fixnum" z)))]
[(x) (if (fixnum? x) x (error 'fxmax "not a fixnum" x))]))
(define (fx*/carry fx1 fx2 fx3)
(let ([s0 ($fx+ ($fx* fx1 fx2) fx3)])
(values
s0
(sra (+ (* fx1 fx2) (- fx3 s0)) (fixnum-width)))))
(define (fx+/carry fx1 fx2 fx3)
(let ([s0 ($fx+ ($fx+ fx1 fx2) fx3)])
(values
s0
(sra (+ (+ fx1 fx2) (- fx3 s0)) (fixnum-width)))))
(define (fx-/carry fx1 fx2 fx3)
(let ([s0 ($fx- ($fx- fx1 fx2) fx3)])
(values
s0
(sra (- (- fx1 fx2) (+ s0 fx3)) (fixnum-width)))))
(module (fixnum->string)
(define f
(lambda (n i j)
(cond
[($fxzero? n)
(values (make-string i) j)]
[else
(let ([q ($fxquotient n 10)])
(call-with-values
(lambda () (f q ($fxadd1 i) j))
(lambda (str j)
(let ([r ($fx- n ($fx* q 10))])
(string-set! str j
($fixnum->char ($fx+ r ($char->fixnum #\0))))
(values str ($fxadd1 j))))))])))
(define fixnum->string
(lambda (x)
(unless (fixnum? x) (error 'fixnum->string "not a fixnum" x))
(cond
[($fxzero? x) "0"]
[($fx> x 0)
(call-with-values
(lambda () (f x 0 0))
(lambda (str j) str))]
;;; FIXME: DON'T HARDCODE CONSTANTS
[($fx= x -536870912) "-536870912"]
[else
(call-with-values
(lambda () (f ($fx- 0 x) 1 1))
(lambda (str j)
($string-set! str 0 #\-)
str))]))))
)