1995-10-13 23:34:21 -04:00
|
|
|
|
; Copyright (c) 1993, 1994 Richard Kelsey and Jonathan Rees. See file COPYING.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
; This is file command.scm.
|
|
|
|
|
|
|
|
|
|
; Command processor.
|
|
|
|
|
|
|
|
|
|
; The command processor's state is of three kinds:
|
|
|
|
|
; 1. User context - preserved across dump commands.
|
|
|
|
|
; This includes the designated user and configuration environments.
|
|
|
|
|
; 2. Session state - one per "login"; not preserved across dump commands.
|
|
|
|
|
; This includes ## and the command loop's interactive ports.
|
|
|
|
|
; 3. Command levels - one for each different command level.
|
|
|
|
|
; This includes any condition being handled, and continuations.
|
|
|
|
|
|
|
|
|
|
(define command-prefix #\,)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
; User context.
|
|
|
|
|
|
|
|
|
|
(define (make-user-context thunk)
|
|
|
|
|
(let ((t (make-table)))
|
|
|
|
|
(let-fluid $user-context t
|
|
|
|
|
(lambda ()
|
|
|
|
|
(for-each (lambda (name+thunk)
|
|
|
|
|
(table-set! t (car name+thunk) ((cdr name+thunk))))
|
|
|
|
|
*user-context-initializers*)
|
|
|
|
|
(thunk)
|
|
|
|
|
t))))
|
|
|
|
|
|
|
|
|
|
(define *user-context-initializers* '())
|
|
|
|
|
|
|
|
|
|
(define $user-context (make-fluid #f))
|
|
|
|
|
; (set-fluid! $user-context (make-user-context unspecific)) ;Bad for GC
|
|
|
|
|
(define (user-context) (fluid $user-context))
|
|
|
|
|
|
|
|
|
|
(define (user-context-accessor name initializer)
|
|
|
|
|
(set! *user-context-initializers*
|
|
|
|
|
(append *user-context-initializers*
|
|
|
|
|
(list (cons name initializer))))
|
|
|
|
|
(let ((probe (fluid $user-context)))
|
|
|
|
|
(if probe (table-set! probe name (initializer))))
|
|
|
|
|
(lambda ()
|
|
|
|
|
(table-ref (user-context) name)))
|
|
|
|
|
|
|
|
|
|
(define (user-context-modifier name)
|
|
|
|
|
(lambda (new)
|
|
|
|
|
(table-set! (user-context) name new)))
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
; Session state.
|
|
|
|
|
|
|
|
|
|
(define session-type
|
|
|
|
|
(make-record-type 'session '(input output values batch-mode? bow?)))
|
|
|
|
|
(define make-session
|
|
|
|
|
(record-constructor session-type
|
|
|
|
|
'(input output values batch-mode? bow?)))
|
|
|
|
|
(define $session
|
|
|
|
|
(make-fluid (make-session (current-input-port)
|
|
|
|
|
(current-output-port)
|
|
|
|
|
'() #f #f)))
|
|
|
|
|
(define (session-accessor name)
|
|
|
|
|
(let ((a (record-accessor session-type name)))
|
|
|
|
|
(lambda () (a (fluid $session)))))
|
|
|
|
|
(define (session-modifier name)
|
|
|
|
|
(let ((m (record-modifier session-type name)))
|
|
|
|
|
(lambda (new) (m (fluid $session) new))))
|
|
|
|
|
(define command-input (session-accessor 'input))
|
|
|
|
|
(define command-output (session-accessor 'output))
|
|
|
|
|
(define focus-values (session-accessor 'values))
|
|
|
|
|
(define set-focus-values! (session-modifier 'values))
|
|
|
|
|
(define batch-mode? (session-accessor 'batch-mode?))
|
|
|
|
|
(define set-batch-mode?! (session-modifier 'batch-mode?))
|
|
|
|
|
(define break-on-warnings? (session-accessor 'bow?))
|
|
|
|
|
(define set-break-on-warnings?! (session-modifier 'bow?))
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
; Command levels.
|
|
|
|
|
|
|
|
|
|
(define $command-levels (make-fluid '()))
|
|
|
|
|
(define (command-level) (car (fluid $command-levels)))
|
|
|
|
|
|
|
|
|
|
(define :command-level
|
|
|
|
|
(make-record-type 'command-level
|
|
|
|
|
'(throw vm-cont condition interrupts
|
|
|
|
|
;; env
|
|
|
|
|
)))
|
|
|
|
|
(define make-command-level
|
|
|
|
|
(record-constructor :command-level
|
|
|
|
|
'(throw vm-cont condition interrupts
|
|
|
|
|
;; env
|
|
|
|
|
)))
|
|
|
|
|
(define command-level? (record-predicate :command-level))
|
|
|
|
|
(define command-level-throw
|
|
|
|
|
(record-accessor :command-level 'throw))
|
|
|
|
|
(define command-level-vm-cont
|
|
|
|
|
(record-accessor :command-level 'vm-cont))
|
|
|
|
|
(define command-level-condition
|
|
|
|
|
(record-accessor :command-level 'condition))
|
|
|
|
|
(define command-level-interrupts
|
|
|
|
|
(record-accessor :command-level 'interrupts))
|
|
|
|
|
;(define command-level-env
|
|
|
|
|
; (record-accessor :command-level 'env))
|
|
|
|
|
;(define set-command-level-env!
|
|
|
|
|
; (record-modifier :command-level 'env))
|
|
|
|
|
|
|
|
|
|
(define environment-for-commands interaction-environment)
|
|
|
|
|
|
|
|
|
|
; --------------------
|
|
|
|
|
; Main entry point.
|
|
|
|
|
|
|
|
|
|
(define (with-user-context context thunk)
|
|
|
|
|
(let-fluid $user-context context thunk)) ; Log in.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
(define (with-new-session context iport oport resume-args batch? thunk)
|
|
|
|
|
(let-fluids $user-context context
|
|
|
|
|
$command-levels '()
|
|
|
|
|
$session (make-session iport oport resume-args batch? #f)
|
|
|
|
|
thunk))
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
;; The double-paren around the w-n-s is because it returns a continuation
|
|
|
|
|
;; which is the thing to do after the command-processor exits.
|
|
|
|
|
|
|
|
|
|
(define (start-command-processor resume-args context
|
|
|
|
|
;; initial-env
|
|
|
|
|
start-thunk)
|
|
|
|
|
(interrupt-before-heap-overflow!)
|
|
|
|
|
((with-new-session context
|
|
|
|
|
(current-input-port) (current-output-port)
|
|
|
|
|
resume-args (and (pair? resume-args)
|
|
|
|
|
(equal? (car resume-args) "batch"))
|
|
|
|
|
(lambda ()
|
|
|
|
|
(command-loop start-thunk #f
|
|
|
|
|
;; initial-env
|
|
|
|
|
)))))
|
|
|
|
|
|
|
|
|
|
; Entry for initialization & testing.
|
|
|
|
|
|
|
|
|
|
(define (command-processor command-env args)
|
|
|
|
|
(start-command-processor args
|
|
|
|
|
(make-user-context
|
|
|
|
|
(lambda ()
|
|
|
|
|
(set-user-command-environment! command-env)))
|
|
|
|
|
;; (interaction-environment)
|
|
|
|
|
unspecific))
|
|
|
|
|
|
|
|
|
|
; Command loop
|
|
|
|
|
; Uses:
|
|
|
|
|
; 1. startup, 2. condition handler, 3. abort-to-level, 4. breakpoint
|
|
|
|
|
|
|
|
|
|
(define (command-loop start-thunk condition
|
|
|
|
|
;; env
|
|
|
|
|
)
|
|
|
|
|
(call-with-command-level condition ;; env
|
|
|
|
|
(lambda (level)
|
|
|
|
|
(start-command-level start-thunk level))))
|
|
|
|
|
|
|
|
|
|
(define (call-with-command-level condition
|
|
|
|
|
;; env
|
|
|
|
|
proc)
|
|
|
|
|
(primitive-catch
|
|
|
|
|
(lambda (vm-cont)
|
|
|
|
|
((call-with-current-continuation
|
|
|
|
|
(lambda (throw)
|
|
|
|
|
(proc (make-command-level throw vm-cont condition
|
|
|
|
|
(enabled-interrupts)
|
|
|
|
|
;; env
|
|
|
|
|
))))))))
|
|
|
|
|
|
|
|
|
|
(define (start-command-level start-thunk level)
|
|
|
|
|
(with-handler command-loop-condition-handler
|
|
|
|
|
(lambda ()
|
|
|
|
|
(let-fluids $command-levels (cons level (fluid $command-levels))
|
|
|
|
|
$note-undefined #f ;useful
|
|
|
|
|
(lambda ()
|
|
|
|
|
;;(with-interaction-environment (command-level-env level)
|
|
|
|
|
;;(lambda ()
|
|
|
|
|
(start-thunk)
|
|
|
|
|
(let ((condition (command-level-condition level)))
|
|
|
|
|
(if condition
|
|
|
|
|
(display-condition condition (command-output)))
|
|
|
|
|
(if (not (= (enabled-interrupts) all-interrupts))
|
|
|
|
|
(begin (if (not (and (interrupt? condition)
|
|
|
|
|
(= (caddr condition) all-interrupts)))
|
|
|
|
|
(write-line "(Enabling interrupts)"
|
|
|
|
|
(command-output)))
|
|
|
|
|
(set-enabled-interrupts! all-interrupts))))
|
|
|
|
|
(let loop ()
|
|
|
|
|
(let ((command (read-command-carefully (command-prompt)
|
|
|
|
|
(form-preferred?)
|
|
|
|
|
(command-input))))
|
|
|
|
|
(showing-focus-object
|
|
|
|
|
(lambda ()
|
|
|
|
|
(execute-command command)))
|
|
|
|
|
(loop))))))));;))
|
|
|
|
|
|
|
|
|
|
(define form-preferred?
|
|
|
|
|
(user-context-accessor 'form-preferred? (lambda () #t)))
|
|
|
|
|
|
|
|
|
|
; Command level control
|
|
|
|
|
|
|
|
|
|
(define (pop-command-level)
|
|
|
|
|
(let ((levels (fluid $command-levels)))
|
|
|
|
|
(if (null? (cdr levels))
|
|
|
|
|
(if (or (batch-mode?)
|
|
|
|
|
(y-or-n? "Exit the Scheme Shell" #t))
|
|
|
|
|
(exit-command-processor (lambda () 0))
|
|
|
|
|
(abort-to-command-level (car levels)))
|
|
|
|
|
(abort-to-command-level (cadr levels)))))
|
|
|
|
|
|
|
|
|
|
(define (abort-to-command-level level)
|
|
|
|
|
(throw-to-command-level
|
|
|
|
|
level
|
|
|
|
|
(lambda ()
|
|
|
|
|
(start-command-level
|
|
|
|
|
(lambda ()
|
|
|
|
|
(cond ((command-level-condition level)
|
|
|
|
|
(display "Back to" (command-output)))
|
|
|
|
|
((null? (fluid $command-levels))
|
|
|
|
|
(newline (command-output))
|
|
|
|
|
(write-line "Top level" (command-output)))))
|
|
|
|
|
;; Condition will be displayed.
|
|
|
|
|
level))))
|
|
|
|
|
|
|
|
|
|
(define (throw-to-command-level level thunk)
|
|
|
|
|
((command-level-throw level) thunk))
|
|
|
|
|
|
|
|
|
|
(define (exit-command-processor thunk)
|
|
|
|
|
(throw-to-command-level (top-command-level)
|
|
|
|
|
(lambda () thunk)))
|
|
|
|
|
|
|
|
|
|
; Condition handler
|
|
|
|
|
|
|
|
|
|
(define (command-loop-condition-handler c next-handler)
|
|
|
|
|
(cond ((or (warning? c) (note? c))
|
|
|
|
|
(if (break-on-warnings?)
|
|
|
|
|
(deal-with-condition c)
|
|
|
|
|
(begin (display-condition c (command-output))
|
|
|
|
|
(unspecific)))) ;proceed
|
|
|
|
|
((or (error? c) (interrupt? c))
|
|
|
|
|
(if (batch-mode?)
|
|
|
|
|
(begin (display-condition c (command-output))
|
|
|
|
|
(let ((status (if (error? c) 1 2)))
|
|
|
|
|
(exit-command-processor (lambda () status))))
|
|
|
|
|
(deal-with-condition c)))
|
|
|
|
|
(else
|
|
|
|
|
(next-handler))))
|
|
|
|
|
|
|
|
|
|
(define push-command-levels?
|
|
|
|
|
(user-context-accessor 'push-command-levels (lambda () #t)))
|
|
|
|
|
;(define set-push-command-levels?!
|
|
|
|
|
; (user-context-modifier 'push-command-levels))
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
(define (deal-with-condition c)
|
|
|
|
|
(if (push-command-levels?)
|
|
|
|
|
(command-loop list c
|
|
|
|
|
;; (interaction-environment)
|
|
|
|
|
)
|
|
|
|
|
(call-with-command-level c ;; (interaction-environment)
|
|
|
|
|
(lambda (level)
|
|
|
|
|
(set-focus-object! level)
|
|
|
|
|
(display-condition c (command-output))
|
|
|
|
|
(abort-to-command-level (car (fluid $command-levels)))))))
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
(define-condition-type 'note '())
|
|
|
|
|
(define note? (condition-predicate 'note))
|
|
|
|
|
|
|
|
|
|
(define (command-prompt)
|
|
|
|
|
(let ((level (- (length (fluid $command-levels)) 1))
|
|
|
|
|
(id (environment-id-string (environment-for-commands))))
|
|
|
|
|
(string-append (if (= level 0)
|
|
|
|
|
""
|
|
|
|
|
(number->string level))
|
|
|
|
|
(if (or (= level 0) (= (string-length id) 0))
|
|
|
|
|
""
|
|
|
|
|
" ")
|
|
|
|
|
id
|
|
|
|
|
"> ")))
|
|
|
|
|
|
|
|
|
|
(define-generic environment-id-string &environment-id-string (env))
|
|
|
|
|
|
|
|
|
|
(define-method &environment-id-string (env) "")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
; Evaluate a form
|
|
|
|
|
|
|
|
|
|
(define (evaluate-and-select form env)
|
|
|
|
|
(call-with-values (lambda ()
|
|
|
|
|
(evaluate form env))
|
|
|
|
|
(lambda results
|
|
|
|
|
(if (or (null? results)
|
|
|
|
|
(not (null? (cdr results)))
|
|
|
|
|
(not (eq? (car results) (unspecific))))
|
|
|
|
|
(set-focus-values! results))
|
|
|
|
|
(apply values results))))
|
|
|
|
|
|
|
|
|
|
(define-generic evaluate &evaluate (form env))
|
|
|
|
|
|
|
|
|
|
(define-method &evaluate (form env) (eval form env))
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
; Display the focus object if it changes (sort of like emacs's redisplay)
|
|
|
|
|
|
|
|
|
|
(define (showing-focus-object thunk)
|
|
|
|
|
(let ((focus-before (focus-values)))
|
|
|
|
|
(thunk)
|
|
|
|
|
(let ((focus-after (focus-values)))
|
|
|
|
|
(if (not (eq? focus-after focus-before))
|
|
|
|
|
(show-command-results focus-after)))))
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
(define (focus-object)
|
|
|
|
|
(let ((v (focus-values)))
|
|
|
|
|
(if (and (pair? v) (null? (cdr v))) (car v) v)))
|
|
|
|
|
|
|
|
|
|
(define (set-focus-object! obj)
|
|
|
|
|
(set-focus-values! (list obj)))
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
(define (show-command-results results)
|
|
|
|
|
(cond ((null? results))
|
|
|
|
|
((not (null? (cdr results)))
|
|
|
|
|
(let ((out (command-output)))
|
|
|
|
|
(display "; " out)
|
|
|
|
|
(write (length results) out)
|
|
|
|
|
(display " values" out)
|
|
|
|
|
(newline out))
|
|
|
|
|
(for-each show-command-result results))
|
|
|
|
|
(else ;(not (eq? (car results) (unspecific)))
|
|
|
|
|
(show-command-result (car results)))))
|
|
|
|
|
|
|
|
|
|
(define (show-command-result result)
|
|
|
|
|
(write-carefully (value->expression result)
|
|
|
|
|
(command-output))
|
|
|
|
|
(newline (command-output)))
|
|
|
|
|
|
|
|
|
|
(define $write-depth (make-fluid -1))
|
|
|
|
|
(define $write-length (make-fluid -1))
|
|
|
|
|
|
|
|
|
|
(define (write-carefully x port)
|
|
|
|
|
(if (error? (ignore-errors (lambda ()
|
|
|
|
|
(limited-write x port
|
|
|
|
|
(fluid $write-depth)
|
|
|
|
|
(fluid $write-length))
|
|
|
|
|
#f)))
|
|
|
|
|
(display "<Error while printing.>" port)))
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
; Sentinels - run after every command.
|
|
|
|
|
|
|
|
|
|
(define *sentinels* '())
|
|
|
|
|
(define (run-sentinels)
|
|
|
|
|
(for-each (lambda (sentinel) (sentinel)) *sentinels*))
|
|
|
|
|
(define (add-sentinel! sentinel)
|
|
|
|
|
(if (not (memq sentinel *sentinels*))
|
|
|
|
|
(set! *sentinels* (cons sentinel *sentinels*))))
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
; Commands.
|
|
|
|
|
|
|
|
|
|
(define command-environment
|
|
|
|
|
(user-context-accessor 'command-environment interaction-environment))
|
|
|
|
|
|
|
|
|
|
;(define *command-structure* (unspecific))
|
|
|
|
|
;
|
|
|
|
|
;(define (command-structure)
|
|
|
|
|
; *command-structure*)
|
|
|
|
|
;
|
|
|
|
|
;(define (set-command-structure! structure) ; called on initial startup
|
|
|
|
|
; (set! *command-structure* structure))
|
|
|
|
|
|
|
|
|
|
(define command-syntax-table (make-table))
|
|
|
|
|
(define *command-help* '())
|
|
|
|
|
|
|
|
|
|
(define (get-command-syntax name)
|
|
|
|
|
(or (table-ref (user-command-syntax-table) name)
|
|
|
|
|
(table-ref command-syntax-table name)))
|
|
|
|
|
|
|
|
|
|
(define (define-command-syntax name help1 help2 arg-descriptions)
|
|
|
|
|
(table-set! command-syntax-table name arg-descriptions)
|
|
|
|
|
(if help1
|
|
|
|
|
(set! *command-help* (add-help *command-help* name help1 help2))))
|
|
|
|
|
|
|
|
|
|
(define (add-help help name help1 help2)
|
|
|
|
|
(insert (list name
|
|
|
|
|
(string-append (symbol->string name) " " help1)
|
|
|
|
|
help2)
|
|
|
|
|
help
|
|
|
|
|
(lambda (z1 z2)
|
|
|
|
|
(string<=? (cadr z1) (cadr z2)))))
|
|
|
|
|
|
|
|
|
|
(define user-command-syntax-table
|
|
|
|
|
(user-context-accessor 'user-command-syntax-table (lambda () (make-table))))
|
|
|
|
|
|
|
|
|
|
(define user-command-environment
|
|
|
|
|
(user-context-accessor 'user-command-environment (lambda () #f)))
|
|
|
|
|
|
|
|
|
|
(define set-user-command-environment!
|
|
|
|
|
(user-context-modifier 'user-command-environment))
|
|
|
|
|
|
|
|
|
|
(define user-command-help
|
|
|
|
|
(user-context-accessor 'user-command-help (lambda () *command-help*)))
|
|
|
|
|
|
|
|
|
|
(define set-user-command-help!
|
|
|
|
|
(user-context-modifier 'user-command-help))
|
|
|
|
|
|
|
|
|
|
(define (define-user-command-syntax name help1 help2 arg-descriptions)
|
|
|
|
|
(table-set! (user-command-syntax-table) name arg-descriptions)
|
|
|
|
|
(if help1
|
|
|
|
|
(set-user-command-help!
|
|
|
|
|
(add-help (user-command-help) name help1 help2))))
|
|
|
|
|
|
|
|
|
|
(define (execute-command command)
|
|
|
|
|
(cond ((eof-object? command)
|
|
|
|
|
(newline (command-output))
|
|
|
|
|
(pop-command-level))
|
|
|
|
|
((not command)) ; error while reading
|
|
|
|
|
(else
|
|
|
|
|
(let* ((name (car command))
|
|
|
|
|
(proc (evaluate name (user-command-environment))))
|
|
|
|
|
(dynamic-wind (lambda () #f)
|
|
|
|
|
(lambda ()
|
|
|
|
|
(apply proc (cdr command)))
|
|
|
|
|
run-sentinels)))))
|
|
|
|
|
|
|
|
|
|
; help
|
|
|
|
|
|
|
|
|
|
(define (help . maybe-id)
|
|
|
|
|
(if (null? maybe-id)
|
|
|
|
|
(list-commands)
|
|
|
|
|
(print-command-help (car maybe-id))))
|
|
|
|
|
|
|
|
|
|
(define (print-command-help id)
|
|
|
|
|
(let ((o-port (command-output)))
|
|
|
|
|
(display #\space o-port)
|
|
|
|
|
(cond ((assq id (user-command-help))
|
|
|
|
|
=> (lambda (data)
|
|
|
|
|
(if (form-preferred?) (display command-prefix o-port))
|
|
|
|
|
(display (cadr data) o-port)
|
|
|
|
|
(display " " o-port)
|
|
|
|
|
(display (caddr data) o-port)))
|
|
|
|
|
(else
|
|
|
|
|
(display #\" o-port)
|
|
|
|
|
(display id o-port)
|
|
|
|
|
(display #\" o-port)
|
|
|
|
|
(display #\space o-port)
|
|
|
|
|
(display "is not a command.")))
|
|
|
|
|
(newline o-port)))
|
|
|
|
|
|
|
|
|
|
(define (list-commands)
|
|
|
|
|
(let ((o-port (command-output))
|
|
|
|
|
(widest 28)
|
|
|
|
|
(f? (form-preferred?)))
|
|
|
|
|
(for-each (lambda (s)
|
|
|
|
|
(write-line s o-port))
|
|
|
|
|
'(
|
|
|
|
|
"This is an alpha-test version of Scheme 48. You are interacting with"
|
|
|
|
|
"the command processor. A command is either a Scheme form to evaluate"
|
|
|
|
|
"or one of the following:"
|
|
|
|
|
""))
|
|
|
|
|
|
|
|
|
|
(list-command-help (user-command-help) f? o-port)
|
|
|
|
|
(for-each (lambda (s)
|
|
|
|
|
(write-line s o-port))
|
|
|
|
|
'(
|
|
|
|
|
""
|
|
|
|
|
"Square brackets [...] indicate optional arguments."
|
|
|
|
|
""
|
|
|
|
|
"The expression ## evaluates to the last value displayed by the command"
|
|
|
|
|
"processor."
|
|
|
|
|
))))
|
|
|
|
|
|
|
|
|
|
(define (list-command-help data prefix? o-port)
|
|
|
|
|
(let* ((strings (map (if prefix?
|
|
|
|
|
(lambda (d)
|
|
|
|
|
(string-append (command-prefix-string
|
|
|
|
|
command-prefix)
|
|
|
|
|
(cadr d)))
|
|
|
|
|
cadr)
|
|
|
|
|
data))
|
|
|
|
|
(count (length strings))
|
|
|
|
|
(back-half (list-tail strings (quotient (+ 1 count) 2))))
|
|
|
|
|
(let loop ((s1 strings) (s2 back-half))
|
|
|
|
|
(cond ((not (eq? s1 back-half))
|
|
|
|
|
(display #\space o-port)
|
|
|
|
|
(display (car s1) o-port)
|
|
|
|
|
(write-spaces (max 1 (- 32 (string-length (car s1)))) o-port)
|
|
|
|
|
(if (not (null? s2))
|
|
|
|
|
(display (car s2) o-port))
|
|
|
|
|
(newline o-port)
|
|
|
|
|
(loop (cdr s1) (if (null? s2) s2 (cdr s2))))))))
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
; Utilities
|
|
|
|
|
|
|
|
|
|
(define (top-command-level)
|
|
|
|
|
(last (fluid $command-levels)))
|
|
|
|
|
|
|
|
|
|
(define (error-form proc args)
|
|
|
|
|
(cons proc (map value->expression args)))
|
|
|
|
|
|
|
|
|
|
(define (value->expression obj) ;mumble
|
|
|
|
|
(if (or (number? obj) (char? obj) (string? obj) (boolean? obj))
|
|
|
|
|
obj
|
|
|
|
|
`',obj))
|
|
|
|
|
|
|
|
|
|
(define (write-spaces count o-port)
|
|
|
|
|
(do ((count count (- count 1)))
|
|
|
|
|
((<= count 0))
|
|
|
|
|
(display #\space o-port)))
|
|
|
|
|
|
|
|
|
|
(define (command-prefix-string prefix)
|
|
|
|
|
(cond ((string? prefix) prefix)
|
|
|
|
|
((char? prefix) (string prefix))
|
|
|
|
|
((symbol? prefix) (symbol->string prefix))))
|
|
|
|
|
|
|
|
|
|
(define (write-line string port)
|
|
|
|
|
(display string port)
|
|
|
|
|
(newline port))
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
(define (y-or-n? question eof-value)
|
|
|
|
|
(let ((i-port (command-input))
|
|
|
|
|
(o-port (command-output)))
|
|
|
|
|
(let loop ((count *y-or-n-eof-count*))
|
|
|
|
|
(display question o-port)
|
|
|
|
|
(display " (y/n)? " o-port)
|
|
|
|
|
(let ((line (read-line i-port)))
|
|
|
|
|
(cond ((eof-object? line)
|
|
|
|
|
(newline o-port)
|
|
|
|
|
(if (= count 0)
|
|
|
|
|
eof-value
|
|
|
|
|
(begin (display "I'll only ask another " o-port)
|
|
|
|
|
(write count o-port)
|
|
|
|
|
(display " times." o-port)
|
|
|
|
|
(newline o-port)
|
|
|
|
|
(loop (- count 1)))))
|
|
|
|
|
((< (string-length line) 1) (loop count))
|
|
|
|
|
((char=? (string-ref line 0) #\y) #t)
|
|
|
|
|
((char=? (string-ref line 0) #\n) #f)
|
|
|
|
|
(else (loop count)))))))
|
|
|
|
|
|
|
|
|
|
(define *y-or-n-eof-count* 100)
|
|
|
|
|
|
|
|
|
|
(define (read-line port)
|
|
|
|
|
(let loop ((l '()))
|
|
|
|
|
(let ((c (read-char port)))
|
|
|
|
|
(if (eof-object? c)
|
|
|
|
|
c
|
|
|
|
|
(if (char=? c #\newline)
|
|
|
|
|
(list->string (reverse l))
|
|
|
|
|
(loop (cons c l)))))))
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
(define (greet-user info)
|
|
|
|
|
(let ((port (command-output)))
|
|
|
|
|
(display "Welcome to Scheme 48 " port)
|
|
|
|
|
(display version-info port)
|
|
|
|
|
(if info
|
|
|
|
|
(begin (write-char #\space port)
|
|
|
|
|
(display info port)))
|
|
|
|
|
(display "." port)
|
|
|
|
|
(newline port)
|
|
|
|
|
(write-line "Copyright (c) 1993, 1994 by Richard Kelsey and Jonathan Rees."
|
|
|
|
|
port)
|
1999-08-10 14:18:00 -04:00
|
|
|
|
(write-line "Please report bugs to scheme-48-bugs@zurich.ai.mit.edu."
|
1995-10-13 23:34:21 -04:00
|
|
|
|
port)
|
|
|
|
|
(if (not (batch-mode?))
|
|
|
|
|
(write-line "Type ,? (comma question-mark) for help." port))))
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
(define (command-continuation) ;utility for debugger
|
|
|
|
|
(let ((obj (focus-object)))
|
|
|
|
|
(command-level-vm-cont
|
|
|
|
|
(if (command-level? obj)
|
|
|
|
|
obj
|
|
|
|
|
(command-level)))))
|