(module runtime mzscheme (provide (struct a60:array (vec dimens)) (struct a60:switch (choices)) undefined check-boolean goto get-value set-target! make-array array-ref array-set! make-switch switch-ref coerce) (define-struct a60:array (vec dimens)) (define-struct a60:switch (choices)) (define undefined (letrec ([x x]) x)) (define (check-boolean b) b) (define (goto f) (f)) (define (get-value v) (v)) (define (set-target! t name v) (unless (procedure-arity-includes? t 1) (error 'assignment "formal-argument variable ~a is assigned, but actual argument was not assignable" name)) (t v)) (define (bad what v) (error '|bad value| "expected a ~a, got ~e" what v)) (define (coerce type v) (cond [(eq? type 'integer) (if (number? v) (inexact->exact (floor v)) (bad 'number v))] [(eq? type 'real) (if (number? v) (exact->inexact v) (bad 'number v))] [(eq? type 'boolean) (if (boolean? v) v (bad 'boolean v))] [else v])) (define (make-array . dimens) (make-a60:array ((let loop ([dimens dimens]) (if (null? dimens) (lambda () undefined) (let ([start (car dimens)] [end (cadr dimens)]) (let ([build (loop (cddr dimens))]) (lambda () (let ([len (add1 (- end start))]) (let ([v (make-vector len)]) (let loop ([len len]) (unless (zero? len) (vector-set! v (sub1 len) (build)) (loop (sub1 len)))) v)))))))) dimens)) (define (check-array a is who) (unless (a60:array? a) (error who "not an array: ~e" a)) (unless (= (length is) (/ (length (a60:array-dimens a)) 2)) (error who "array dimension ~a doesn't match the number of provided indices ~a" (length is) (/ (length (a60:array-dimens a)) 2)))) (define (check-index who dimens indices) (unless (and (number? (car indices)) (exact? (car indices)) (integer? (car indices))) (error who "index is not an integer: ~e" (car indices))) (unless (<= (car dimens) (car indices) (cadr dimens)) (error who "index ~a out of range ~a:~a" (car indices) (car dimens) (cadr dimens)))) (define (array-ref a . indices) (check-array a indices 'array-reference) (let loop ([v (a60:array-vec a)][indices indices][dimens (a60:array-dimens a)]) (check-index 'array-reference dimens indices) (let ([i (vector-ref v (- (car indices) (car dimens)))]) (if (null? (cdr indices)) i (loop i (cdr indices) (cddr dimens)))))) (define (array-set! a val . indices) (check-array a indices 'array-assignment) (let loop ([v (a60:array-vec a)][indices indices][dimens (a60:array-dimens a)]) (check-index 'array-assignment dimens indices) (if (null? (cdr indices)) (vector-set! v (- (car indices) (car dimens)) val) (loop (vector-ref v (- (car indices) (car dimens))) (cdr indices) (cddr dimens))))) (define (make-switch . choices) (make-a60:switch (list->vector choices))) (define (switch-ref sw index) (unless (and (number? index) (integer? index) (exact? index) (<= 1 index (vector-length (a60:switch-choices sw)))) (error "bad switch index: " index)) ((vector-ref (a60:switch-choices sw) (sub1 index)))))