This repository has been archived on 2022-08-10. You can view files and clone it, but cannot push or open issues or pull requests.
chez-openbsd/examples/def.ss
2022-07-29 15:12:07 +02:00

126 lines
5.2 KiB
Scheme

;;; def.ss
;;; Copyright (C) 1987 R. Kent Dybvig
;;; Permission is hereby granted, free of charge, to any person obtaining a
;;; copy of this software and associated documentation files (the "Software"),
;;; to deal in the Software without restriction, including without limitation
;;; the rights to use, copy, modify, merge, publish, distribute, sublicense,
;;; and/or sell copies of the Software, and to permit persons to whom the
;;; Software is furnished to do so, subject to the following conditions:
;;;
;;; The above copyright notice and this permission notice shall be included in
;;; all copies or substantial portions of the Software.
;;;
;;; THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
;;; IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
;;; FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
;;; THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
;;; LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
;;; FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
;;; DEALINGS IN THE SOFTWARE.
;;; Prototype code for definition facility that remembers definitions and
;;; allows you to pretty-print or edit them (using the structure editor
;;; defined in the file "edit.ss").
;;; def can be in place of define at top level (i.e., not within a lambda,
;;; let, let*, or letrec body). It saves the source for the definition
;;; as well as performing the defintion. Type (ls-def) for a list of
;;; variables defined this session, and (pp-def variable) to return the
;;; definition of a particular variable.
;;; Possible exercises/enhancements:
;;;
;;; 1) Write a "dskout" function that pretty-prints the definitions of
;;; all or selected variables defined this session to a file.
;;;
;;; 2) In place of "def", write a modified "load" that remembers where
;;; (that is, in which file) it saw the definition for each variable
;;; defined in a particular session. This would be used instead of
;;; the "def" form. "ls-def" would be similar to what it is now.
;;; "pp-def" could be similar to what it is now, or it could involve
;;; rereading the corresponding file. "ed-def" could invoke the
;;; structure editor and (as an option) print the modified definition
;;; back to the corresponding file, or "ed-def" could invoke a host
;;; editor (such as Unix "vi" or VMS "edit") on the corresponding
;;; source file, with an option to reload. If this tool is smart
;;; enough, it could get around the limitation that definitions use
;;; define at top-level, i.e., (let ([x #f]) (set! foo (lambda () x)))
;;; could be recognized as a definition for foo.
(define-syntax def
;; only makes sense for "top level" definitions
(syntax-rules ()
[(_ (var . formals) . body)
(begin (define (var . formals) . body)
(insert-def! 'var '(def (var . formals) . body) var)
'var)]
[(_ var exp)
(begin (define var exp)
(insert-def! 'var '(def var exp) var)
'var)]))
(define-syntax pp-def
(syntax-rules (quote)
; allow var to be unquoted or quoted
[(_ var) (pp-def-help 'var var)]
[(_ 'var) (pp-def-help 'var var)]))
(define-syntax ed-def
(syntax-rules (quote)
; allow var to be unquoted or quoted
[(_ var) (ed-def-help 'var var)]
[(_ 'var) (ed-def-help 'var var)]))
(define insert-def! #f) ; assigned within the let below
(define ls-def #f) ; assigned within the let below
(define pp-def-help #f) ; assigned within the let below
(define ed-def-help #f) ; assigned within the let below
(let ([defs '()])
(define tree-copy
(rec tree-copy
(lambda (x)
(if (pair? x)
(cons (tree-copy (car x)) (tree-copy (cdr x)))
x))))
(set! insert-def!
(lambda (var defn val)
(unless (symbol? var)
(error 'insert-def! "~s is not a symbol" var))
(let ([a (assq var defs)])
(if a
(set-cdr! a (cons defn val))
(set! defs (cons (cons var (cons defn val)) defs))))))
(set! ls-def
(lambda ()
(map car defs)))
(set! pp-def-help
(lambda (var val)
(unless (symbol? var)
(error 'pp-def "~s is not a symbol" var))
(let ([a (assq var defs)])
(unless a
(error 'pp-def
"~s has not been defined during this session"
var))
(unless (eq? (cddr a) val)
(printf "Warning: ~s has been reassigned since definition"
var))
(cadr a))))
(set! ed-def-help
(lambda (var val)
(unless (symbol? var)
(error 'ed-def "~s is not a symbol" var))
(let ([a (assq var defs)])
(unless a
(error 'ed-def
"~s has not been defined during this session"
var))
(unless (eq? (cddr a) val)
(printf "Warning: ~s reassigned since last definition"
var))
; edit is destructive; the copy allows the defined name to
; be changed without affecting the old name's definition
(eval (edit (tree-copy (cadr a))))))))