#lang scheme/base (require scheme/list) (require scheme/match) (require scheme/pretty) (require (file "primitives.scm")) (provide trace subst subst* find curry-keywords variable-value? literal-value? simple-value? value-form? statement-form? primitive-form? pure-form? bind-form? traverse-form map-form search-form form-sets? form-uses? form-captures? form-captures-input? form-captures-output? subst-var subst-var* flatten-binds free-variables free-input-variables free-output-variables free-variable? free-input-variable? free-output-variable? value-used?) (define (trace fn . args) (let ([x (apply fn args)]) (pretty-print (list fn x)) x)) (define (subst old new lst) (foldr (lambda (x rst) (cons (if (eq? x old) new x) rst)) '() lst)) (define (subst* old->new lst) (foldr (lambda (x rst) (let ([item (assoc x old->new)]) (cons (if item (second item) x) rst))) '() lst)) (define (find x lst) (let/cc return (for ([i (in-naturals 0)] [y (in-list lst)]) (when (eq? y x) (return i))) #f)) ;; Combines two sorted keyword-value list pairs into a single ;; sorted list-pair, taking the values from the second list ;; where the same keyword exists in both lists. (define (merge-keywords keywords-1 kw-values-1 keywords-2 kw-values-2) (let iter ([kw '()] [kv '()] [kw-1 keywords-1] [kv-1 kw-values-1] [kw-2 keywords-2] [kv-2 kw-values-2]) (cond [(null? kw-2) (values (append (reverse kw) kw-1) (append (reverse kv) kv-1))] [(null? kw-1) (values (append (reverse kw) kw-2) (append (reverse kv) kv-2))] [(eq? (car kw-1) (car kw-2)) (iter (cons (car kw-2) kw) (cons (car kv-2) kv) (cdr kw-1) (cdr kv-1) (cdr kw-2) (cdr kv-2))] [(keywordstring var) "->g")] [unique-var (gensym prefix)]) (subst-var var unique-var bind))) (foldr make-binding-unique bind (filter needs-rename? (second bind)))) (map-form form #:bind (lambda (recurse op bound-vars . original-subforms) (define rename-vars (remove-duplicates (append (free-variables `(,op ,bound-vars ,@original-subforms)) bound-vars))) (define (form->list subform) (if (bind-form? subform) (let ([unique-form (make-bindings-unique (recurse subform) rename-vars)]) (set! bound-vars (append (second unique-form) bound-vars)) (cddr unique-form)) (list subform))) (let ([subforms (append-map form->list original-subforms)]) `(%bind ,bound-vars ,@subforms))) #:lambda (lambda (recurse . form) form))) (define (free-variables form [input? #t] [output? #t]) (define (append-map/unique fn . lsts) (remove-duplicates (apply append-map fn lsts))) (traverse-form form #:bind (lambda (recurse op vars . subforms) (remove* vars (append-map/unique recurse subforms))) #:set (lambda (recurse op var value) (let ([value-free (recurse value)]) (if (and output? (not (memq var value-free))) (cons var value-free) value-free))) #:primitive (lambda (recurse op . simple-values) (append-map/unique recurse simple-values)) #:simple (lambda (recurse kind form) '()) #:variable (lambda (recurse kind var) (if (and input? (not (special-variable? var))) (list var) '())))) (define (free-input-variables form) (free-variables form #t #f)) (define (free-output-variables form) (free-variables form #f #t)) (define (free-variable? variable form [input? #t] [output? #t]) (search-form form #:bind (lambda (recurse op vars . subforms) (and (not (memq variable vars)) (ormap recurse subforms))) #:set (lambda (recurse op var value) (or (and output? (eq? var variable)) (recurse value))) #:variable (lambda (recurse kind var) (and input? (eq? var variable))))) (define (free-input-variable? var form) (free-variable? var form #t #f)) (define (free-output-variable? var form) (free-variable? var form #f #t)) ; vim:set sw=2 expandtab: