scsh-0.5/env/pacman.scm

334 lines
9.1 KiB
Scheme

; Copyright (c) 1993, 1994 Richard Kelsey and Jonathan Rees. See file COPYING.
; PACkage-manipulation comMANds
(add-sentinel! package-system-sentinel)
(define (set-environment-for-commands! p)
(set-interaction-environment! p)
;; (set-command-level-env! (command-level) p)
)
(define user-environment
(user-context-accessor 'user-environment interaction-environment))
(define set-user-environment!
(user-context-modifier 'user-environment))
(define-command-syntax 'in "<struct> [<command>]"
"go to package, or execute single command in package"
'(name &opt command))
(define (in name . maybe-command)
(if (and (not (null? maybe-command))
(command-just-evaluates-symbol? (car maybe-command)))
(set-focus-object! (environment-ref (really-get-package name)
(cadr (car maybe-command))))
(in-package (get-package name) maybe-command)))
(define (command-just-evaluates-symbol? command)
(and (pair? command)
(not (car command))
(symbol? (cadr command))))
(define-command-syntax 'new-package "" "make and enter a new package"
'())
(define (new-package)
(let ((p (make-simple-package (list (get-structure 'scheme))
#t ;unstable?
(get-reflective-tower (user-environment))
#f)))
(set-package-integrate?! p
(package-integrate? (environment-for-commands)))
(set-environment-for-commands! p)))
(define (get-reflective-tower env) ;Returns promise of (eval . env)
(reflective-tower (if (package? env)
(package->environment env)
env))) ;Mumble
; load-package
(define-command-syntax 'load-package "<struct>" "load package's source code"
'(name))
(define (load-package name)
(ensure-loaded (get-structure name)))
(define-command-syntax 'reload-package "<struct>" "load package's source code again"
'(name))
(define (reload-package name)
(let ((s (get-structure name)))
(set-package-loaded?! (structure-package s) #f)
(ensure-loaded s)))
(define-command-syntax 'structure "<name> <interface>"
"create new structure over the current package"
'(name expression))
(define (structure name interface-expression)
(let* ((c (config-package))
(p (environment-for-commands))
(s (make-structure p
(lambda ()
(evaluate interface-expression c))
name)))
;; (check-structure s)
(environment-define! c name s)))
(define-command-syntax 'open "<struct> ..." "open a structure"
'(&rest name))
(define (open . names)
(for-each (lambda (name)
(let* ((c (config-package))
(thunk (lambda () (environment-ref c name)))
(probe (thunk)))
(if (structure? probe)
(if (ensure-loaded-query probe)
(package-open! (environment-for-commands) thunk)
(error "structure not loaded" name))
(error "not a structure" name))))
names))
(define (ensure-loaded-query struct)
(let ((p (structure-package struct)))
(cond ((or (package-loaded? p)
(and (null? (package-clauses p))
(every (lambda (struct)
(package-loaded? (structure-package struct)))
(package-opens p))))
#t)
((or (batch-mode?)
(y-or-n? (string-append "Load structure "
(symbol->string
(structure-name struct)))
#f))
(ensure-loaded struct)
#t)
(else #f))))
(define-command-syntax 'for-syntax "[<command>]"
"go to current package's package for syntax"
'(&opt command))
(define (for-syntax . maybe-command)
(in-package (cdr (force (get-reflective-tower (environment-for-commands))))
maybe-command))
; ,user goes to the user initial environment.
(define-command-syntax 'user "[<command>]" "go to user package"
'(&opt command))
(define (user . maybe-command)
(in-package (user-environment) maybe-command))
(define-command-syntax 'user-package-is "[<struct>]"
"designate user package (for ,user command)"
'(&opt name))
(define (user-package-is . name-option)
(set-user-environment! (if (null? name-option)
(environment-for-commands)
(get-package (car name-option)))))
(define set-user-environment!
(user-context-modifier 'user-environment))
; Configuration package (should there be ,load-config as well?)
(define-command-syntax 'config "[<command>]" "go to configuration package"
'(&opt command))
(define (config . maybe-command)
(in-package (config-package) maybe-command))
(define-command-syntax 'config-package-is "<struct>"
"designate configuration package"
'(name))
(define (config-package-is name)
(set-config-package! (get-package name)))
; ,exec goes to the exec initial environment.
(define-command-syntax 'exec "[<command>]" "go to command execution package"
'(&opt command))
(define (exec . maybe-command)
(in-package (user-command-environment) maybe-command))
; ,undefine foo removes definition of foo from current package.
(define-command-syntax 'undefine "<name>" "remove definition"
'(name))
(define (undefine name)
(package-undefine! (interaction-environment) name))
; --------------------
; Auxiliaries for package commands
(define (in-package p maybe-command)
(if (null? maybe-command)
(set-environment-for-commands! p)
(with-interaction-environment p
(lambda ()
(let ((command (car maybe-command)))
(if (procedure? command)
(command)
(execute-command (car maybe-command))))))))
(define config-package
(user-context-accessor 'config-package user-environment))
(define set-config-package!
(user-context-modifier 'config-package))
(define (get-package name)
(let ((p (really-get-package name)))
(if (package-unstable? p)
p
(error "read-only structure" p))))
(define (really-get-package name)
(let ((s (get-structure name)))
(ensure-loaded-query s)
(structure-package s)))
(define (get-structure name)
(let ((thing (environment-ref (config-package) name)))
(cond ((structure? thing) thing)
(else (error "not a structure" name thing)))))
; Main entry point, with package setup.
(define (new-command-processor info commands built-in . meta-structs)
;; Argument to ,build command
(lambda (arg)
(call-with-values (lambda ()
(new-user-context commands built-in meta-structs))
(lambda (context env)
(with-interaction-environment env
(lambda ()
(start-command-processor arg
context
;; env
(lambda ()
(greet-user info)))))))))
(define (new-user-context commands built-in meta-structs)
(let* ((tower (make-reflective-tower
eval
(list (*structure-ref built-in 'scheme))
'user))
(user (make-user-package built-in tower))
(config-package (make-config-package 'config
tower
built-in
meta-structs))
(exec-package (make-exec-package commands tower built-in)))
(values (make-user-context
(lambda ()
(set-user-environment! user)
(set-config-package! config-package)
(set-user-command-environment! exec-package)))
user)))
; User package
(define (make-user-package built-in tower)
(let* ((scheme-structure (*structure-ref built-in 'scheme))
(user
(make-simple-package (list scheme-structure)
#t ;unstable?
tower
'user)))
(set-package-integrate?! user #f)
(environment-define! user 'access-scheme-48 access-scheme-48)
user))
(define (access-scheme-48 name) ;For PSD and SLIB, ugh.
(case name
((error) error)
((ascii->char) ascii->char)
((force-output) force-output)
((error-output-port) error-output-port)
(else (call-error "unrecognized name" access-scheme-48 name))))
; Configuration package
(define (make-config-package name tower built-in meta-structs)
(let* ((module-system (*structure-ref built-in 'module-system))
(config
(make-simple-package (cons module-system
(append meta-structs
(list built-in)))
#t ;unstable?
tower
name)))
(set-reflective-tower-maker!
config
(lambda (clauses id)
(if (null? clauses)
tower ;?
(delay (let ((p (eval `(a-package ((for-syntax ,id)) ,@clauses)
config)))
(ensure-loaded (make-structure p
(lambda () (make-simple-interface #f '()))
'for-syntax))
(cons eval p))))))
config))
; Exec package
(define (make-exec-package commands tower built-in)
(make-simple-package (list commands (*structure-ref built-in 'scheme))
#t ;unstable?
tower
'exec))
; for prompt string
(define-method &environment-id-string ((env :package))
(if (eq? env (user-environment))
""
(if (symbol? (package-name env))
(symbol->string (package-name env))
(number->string (package-uid env)))))
(define user-environment
(user-context-accessor 'user-environment interaction-environment))
; Extract a package-specific evaluator from a package. Eventually, it
; would be nice if load, eval-from-file, eval-scanned-forms, and
; perhaps other things were also generic over different kinds of
; environments.
(define funny-name/evaluator (string->symbol ".evaluator."))
(define (set-package-evaluator! p evaluator)
(package-define-funny! p funny-name/evaluator evaluator))
(define (package-evaluator p)
(or (get-funny (package->environment p) funny-name/evaluator) eval))
(define-method &evaluate (form (env :package))
((package-evaluator env) form env))