;;; Copyright (c) 2000-2015 Dipanwita Sarkar, Andrew W. Keep, R. Kent Dybvig, Oscar Waddell ;;; See the accompanying file Copyright for details (library (tests helpers) (export compose disjoin any every choose reverse-filter fold reduce constant? keyword? list-of-user-primitives list-of-system-primitives user-primitive? system-primitive? primitive? predicate-primitive? value-primitive? effect-primitive? effect-free-primitive? gen-label reset-seed gen-symbol set? iota with-values empty-set singleton-set add-element member? empty? union intersection difference variable? datum? list-index primapp sys-primapp app const-datum const var quoted-const time printf system interpret pretty-print format set-cons define-who) (import (rnrs) (tests implementation-helpers) (nanopass helpers)) (define-syntax primapp (syntax-rules () [(_ expr expr* ...) (expr expr* ...)])) (define-syntax sys-primapp (syntax-rules () [(_ expr expr* ...) (expr expr* ...)])) (define-syntax app (syntax-rules () [(_ expr expr* ...) (expr expr* ...)])) (define-syntax const-datum (syntax-rules () [(_ expr) (quote expr)])) (define-syntax const (syntax-rules () [(_ expr) expr])) (define-syntax var (syntax-rules () [(_ expr) expr])) (define-syntax quoted-const (syntax-rules () [(_ expr) (quote expr)])) (define compose (case-lambda [() (lambda (x) x)] [(f) f] [(f . g*) (lambda (x) (f ((apply compose g*) x)))])) (define disjoin (case-lambda [() (lambda (x) #f)] [(p?) p?] [(p? . q?*) (lambda (x) (or (p? x) ((apply disjoin q?*) x)))])) (define any (lambda (pred? ls) (let loop ([ls ls]) (cond [(null? ls) #f] [(pred? (car ls)) #t] [else (loop (cdr ls))])))) (define every (lambda (pred? ls) (let loop ([ls ls]) (cond [(null? ls) #t] [(pred? (car ls)) (loop (cdr ls))] [else #f])))) (define choose (lambda (pred? ls) (fold (lambda (elt tail) (if (pred? elt) (cons elt tail) tail)) '() ls))) (define reverse-filter (lambda (pred? ls) (fold (lambda (elt tail) (if (pred? elt) tail (cons elt tail))) '() ls))) ;; fold op base (cons a (cons b (cons c '()))) = ;; (op a (op b (op c base))) (define fold (lambda (op base ls) (let recur ([ls ls]) (if (null? ls) base (op (car ls) (recur (cdr ls))))))) ;; reduce op base (cons a (cons b (cons c '()))) ;; (op c (op b (op a base))) (define reduce (lambda (op base ls) (let loop ([ls ls] [ans base]) (if (null? ls) ans (loop (cdr ls) (op (car ls) ans)))))) ;;; General Scheme helpers for the compiler (define constant? (disjoin null? number? char? boolean? string?)) (define keyword? (lambda (x) (and (memq x '(quote set! if begin let letrec lambda)) #t))) (define datum? (lambda (x) (or (constant? x) (null? x) (if (pair? x) (and (datum? (car x)) (datum? (cdr x))) (and (vector? x) (for-all datum? (vector->list x))))))) (define variable? symbol?) (define list-of-user-primitives '(; not is a special case (not 1 not) ; predicates (< 2 test) (<= 2 test) (= 2 test) (boolean? 1 test) (char? 1 test) (eq? 2 test) (integer? 1 test) (null? 1 test) (pair? 1 test) (procedure? 1 test) (vector? 1 test) (zero? 1 test) ; value-producing (* 2 value) (+ 2 value) (- 2 value) (add1 1 value) (car 1 value) (cdr 1 value) (char->integer 1 value) (cons 2 value) (make-vector 1 value) (quotient 2 value) (remainder 2 value) (sub1 1 value) (vector -1 value) (vector-length 1 value) (vector-ref 2 value) (void 0 value) ; side-effecting (set-car! 2 effect) (set-cdr! 2 effect) (vector-set! 3 effect))) (define list-of-system-primitives ; these are introduced later by the compiler '(; value-producing (closure-ref 2 value) (make-closure 2 value) (procedure-code 1 value) ; side-effecting (closure-set! 3 effect) (fref 1 value) (fset! 2 effect) (fincr! 1 effect) (fdecr! 1 effect) (href 2 value) (hset! 3 effect) (logand 2 value) (sll 2 value) (sra 2 value))) (define user-primitive? (lambda (x) (and (assq x list-of-user-primitives) #t))) (define system-primitive? (lambda (x) (and (assq x list-of-system-primitives) #t))) (define primitive? (lambda (x) (or (user-primitive? x) (system-primitive? x)))) (define predicate-primitive? (lambda (x) (cond [(or (assq x list-of-user-primitives) (assq x list-of-system-primitives)) => (lambda (a) (eq? (caddr a) 'test))] [else #f]))) (define value-primitive? (lambda (x) (cond [(or (assq x list-of-user-primitives) (assq x list-of-system-primitives)) => (lambda (a) (eq? (caddr a) 'value))] [else #f]))) (define effect-primitive? (lambda (x) (cond [(or (assq x list-of-user-primitives) (assq x list-of-system-primitives)) => (lambda (a) (eq? (caddr a) 'effect))] [else #f]))) (define effect-free-primitive? (lambda (x) (not (effect-primitive? x)))) (define gen-label ; at some point, gen-label should be redefined to emit ; assembler-friendly labels (lambda (sym) (string->symbol (format "~a%" sym)))) (define gen-symbol-seed 0) (define reset-seed (lambda () (set! gen-symbol-seed 0))) (define gen-symbol (lambda (sym) (set! gen-symbol-seed (+ gen-symbol-seed 1)) (string->symbol (format "~a_~s" sym gen-symbol-seed)))) (define set? (lambda (ls) (or (null? ls) (and (not (memq (car ls) (cdr ls))) (set? (cdr ls)))))) ;;; ==================== ;;; Extra syntax and helpers for multiple values ;;; Set abstraction (define empty-set (lambda () '())) (define singleton-set (lambda (elt) (list elt))) (define add-element (lambda (elt set) (if (member? elt set) set (cons elt set)))) (define member? memq) (define empty? null?) (define set-cons (lambda (a set) (if (memq a set) set (cons a set)))) (define union (case-lambda [() (empty-set)] [(set1 set2) (cond [(empty? set1) set2] [(empty? set2) set1] [(eq? set1 set2) set1] [else (reduce (lambda (elt set) (if (member? elt set2) set (cons elt set))) set2 set1)])] [(set1 . sets) (if (null? sets) set1 (union set1 (reduce union (empty-set) sets)))])) (define intersection (lambda (set1 . sets) (cond [(null? sets) set1] [(any empty? sets) (empty-set)] [else (choose (lambda (elt) (every (lambda (set) (member? elt set)) sets)) set1)]))) (define list-index (lambda (a ls) (cond [(null? ls) -1] [(eq? (car ls) a) 0] [else (maybe-add1 (list-index a (cdr ls)))]))) (define maybe-add1 (lambda (n) (if (= n -1) -1 (+ n 1)))) (define difference (lambda (set1 . sets) (let ((sets (reverse-filter empty? sets))) (cond [(null? sets) set1] [else (reverse-filter (lambda (elt) (any (lambda (set) (member? elt set)) sets)) set1)])))))