You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
This repo is archived. You can view files and clone it, but cannot push or open issues/pull-requests.

326 lines
8.2 KiB
Scheme

;;; 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)])))))