;;; command-interface/command-utils.scm
;;; These are utilities used by the command interface.
;;; These send output to the user
;;; This is used in emacs mode
(define (say/em . args)
(say1 args))
;;; This is for both ordinary text to emacs and output to the command interface
(define (say . args)
(say1 args))
(define (say1 args)
(apply (function format) (cons (current-output-port) args)))
;;; This is for non-emacs output
(define (say/ne . args)
(when (not *emacs-mode*)
(say1 args)))
;;; These random utilities should be elsewhere
;;; This determines whether the current module is loaded & available.
;;; If the module is Main, an empty Main module is created.
(define (cm-available?)
(cond ((table-entry *modules* *current-mod*)
'#t)
((eq? *current-mod* '|Main|)
(make-empty-main)
'#t)
(else
'#f)))
;;; This creates a empty module named Main to use as a scratch pad.
(define (make-empty-main)
(compile/load "$PRELUDE/Prelude")
(setf *unit* '|Main|)
(setf *current-mod* '|Main|)
(let ((mods (parse-from-string
"module Main where {import Prelude}"
(function parse-module-list)
"foo")))
;;; This should generate no code at all so the returned code is ignored.
(modules->lisp-code mods)
(setf (table-entry *modules* *current-mod*) (car mods))
(clear-extended-modules)))
(define (eval-fragment eval?)
(cond ((not (cm-available?))
(say "~&Module ~A is not loaded.~%" *current-mod*)
'error)
((memq *fragment-status* '(Compiled Saved))
(when eval?
(eval-module *extension-module*))
'ok)
((eq? *fragment-status* 'Error)
(say/ne "~&Errors exist in current fragment.~%")
'error)
((string=? *current-string* "")
(say/ne "~&Current extension is empty.~%")
'error)
(else
(let ((res (compile-fragment
*current-mod* *current-string*
*extension-file-name*)))
(cond ((eq? res 'error)
(setf *fragment-status* 'Error)
(notify-error))
(else
(setf *extension-module* res)
(setf *fragment-status* 'Compiled)
(when eval?
(eval-module *extension-module*))))))))
(define (set-current-file file)
(cond ((null? file)
'())
((null? (cdr file))
(setf *remembered-file* (car file)))
(else
(say "~&Invalid file spec ~s.~%" file)
(funcall *abort-command*))))
(define (select-current-mod mods)
(when (pair? mods)
(when (not (memq *current-mod* mods))
(setf *current-mod* (car mods))
(say/ne "~&Now in module ~A.~%" *current-mod*))))
;;; Emacs mode stuff
;;; *** bogus alert!!! This coercion may fail to produce a
;;; *** real character in some Lisps.
(define *emacs-notify-char* (integer->char 1))
(define (notify-ready)
(when *emacs-mode*
(say/em "~Ar" *emacs-notify-char*)
(force-output (current-output-port))))
(define (notify-input-request)
(when *emacs-mode*
(say/em "~Ai" *emacs-notify-char*)
(force-output (current-output-port))))
(define (notify-error)
(when *emacs-mode*
(say/em "~Ae" *emacs-notify-char*)
(force-output (current-output-port))))
(define (notify-printers printers)
(notify-settings "p" printers))
(define (notify-optimizers optimizers)
(notify-settings "o" optimizers))
(define (notify-settings flag values)
(when *emacs-mode*
(say/em "~A~A(" *emacs-notify-char* flag)
(dolist (p values)
(say/em " ~A" (string-downcase (symbol->string p))))
(say/em ")~%")
(force-output (current-output-port))))
(define (notify-status-line str)
(when *emacs-mode*
(say/em "~As~A~%" *emacs-notify-char* str)
(force-output (current-output-port))))
;;; These are used to drive the real compiler.
(define *compile/compile-cflags*
(make cflags
(load-code? '#t)
(compile-code? '#t)
(write-code? '#t)
(write-interface? '#t)))
(define (compile/compile file)
(haskell-compile file *compile/compile-cflags*))
(define *compile/load-cflags*
(make cflags
(load-code? '#t)
(compile-code? '#f)
(write-code? '#f)
(write-interface? '#f)))
(define (compile/load file)
(haskell-compile file *compile/load-cflags*))
;;; Printer setting support
(define (set-printers args mode)
(set-switches *printers* (strings->syms args)
mode *all-printers* "printers"))
(define (set-optimizers args mode)
(set-switches *optimizers* (strings->syms args)
mode *all-optimizers* "optimizers"))
(define (set-switches current new mode all name)
(dolist (s new)
(when (and (not (eq? s 'all)) (not (memq s all)))
(signal-invalid-value s name all)))
(let ((res (cond ((eq? mode '+)
(set-union current new))
((eq? mode '-)
(set-difference current new))
((eq? mode '=)
(if (equal? new '(all))
all
new)))))
res))
(define (signal-invalid-value s name all)
(recoverable-error 'invalid-value
"~A is not one of the valid ~A. Possible values are: ~%~A"
s name all))
(define (print-file file)
(call-with-input-file file (function write-all-chars)))
(define (write-all-chars port)
(let ((line (read-line port)))
(if (eof-object? line)
'ok
(begin
(write-line line)
(write-all-chars port)))))
(define (strings->syms l)
(map (lambda (x)
(string->symbol (string-upcase x)))
l))
|