;;; cl-definitions.lisp -- mumble compatibility package for Common Lisp ;;; ;;; author : Sandra Loosemore ;;; date : 11 Oct 1991 ;;; ;;; You must load cl-setup and cl-support before trying to compile this ;;; file. (in-package "MUMBLE-IMPLEMENTATION") ;;;===================================================================== ;;; Syntax ;;;===================================================================== (define-mumble-import quote) (define-mumble-import function) ;;; Lambda lists have to have dot syntax converted to &rest. (define-mumble-macro mumble::lambda (lambda-list &rest body) `(function (lambda ,(mung-lambda-list lambda-list) ,@body))) (defun mung-lambda-list (lambda-list) (cond ((consp lambda-list) (let ((last (last lambda-list))) (if (null (cdr last)) lambda-list `(,@(ldiff lambda-list last) ,(car last) &rest ,(cdr last))))) ((null lambda-list) '()) (t `(&rest ,lambda-list)))) ;;; We only funcall and apply things that are real functions. ;;; Gag. Lucid needs to see the procedure declaration to avoid putting ;;; a coerce-to-procedure check in, but there's a compiler bug that causes ;;; it to barf if the function is a lambda form. #+lucid (define-mumble-macro mumble::funcall (fn . args) (if (and (consp fn) (eq (car fn) 'mumble::lambda)) `(funcall ,fn ,@args) `(funcall (the system::procedure ,fn) ,@args))) #+(or cmu allegro akcl lispworks mcl) (define-mumble-macro mumble::funcall (fn . args) `(funcall (the function ,fn) ,@args)) #+wcl (define-mumble-macro mumble::funcall (fn . args) `(funcall (the lisp:procedure ,fn) ,@args)) #-(or lucid cmu allegro akcl mcl lispworks wcl) (missing-mumble-definition mumble::funcall) ;;; Could make this declare its fn argument too (define-mumble-import apply) (define-mumble-synonym mumble::map mapcar) (define-mumble-synonym mumble::for-each mapc) (define-mumble-import some) (define-mumble-import every) (define-mumble-import notany) (define-mumble-import notevery) (define-mumble-synonym mumble::procedure? functionp) (define-mumble-import if) (define-mumble-import when) (define-mumble-import unless) ;;; COND and CASE differ from Common Lisp because of using "else" instead ;;; of "t" as the fall-through case. (define-mumble-import mumble::else) (define-mumble-macro mumble::cond (&rest cases) (let ((last (car (last cases)))) (if (eq (car last) 'mumble::else) `(cond ,@(butlast cases) (t ,@(cdr last))) `(cond ,@cases)))) (define-mumble-macro mumble::case (data &rest cases) (let ((last (car (last cases)))) (if (eq (car last) 'mumble::else) `(case ,data ,@(butlast cases) (t ,@(cdr last))) `(case ,data ,@cases)))) (define-mumble-import and) (define-mumble-import or) (define-mumble-import not) (define-mumble-macro mumble::set! (variable value) `(setq ,variable ,value)) (define-mumble-import setf) ;;; AKCL's SETF brokenly tries to macroexpand the place ;;; form before looking for a define-setf-expander Redefine the ;;; internal function to do the right thing. #+akcl (defun system::setf-expand-1 (place newvalue env) (multiple-value-bind (vars vals stores store-form access-form) (get-setf-method place env) (declare (ignore access-form)) `(let* ,(mapcar #'list (append vars stores) (append vals (list newvalue))) ,store-form))) ;;; Allegro has renamed this stuff as per ANSI CL. #+(or cmu allegro) (eval-when (eval compile load) (setf (macro-function 'define-setf-method) (macro-function 'define-setf-expander)) (setf (symbol-function 'get-setf-method) (symbol-function 'get-setf-expansion)) ) (define-mumble-import let) (define-mumble-import let*) (define-mumble-macro mumble::letrec (bindings &rest body) `(let ,(mapcar #'car bindings) ,@(mapcar #'(lambda (b) (cons 'setq b)) bindings) (locally ,@body))) (define-mumble-import flet) (define-mumble-import labels) (define-mumble-macro mumble::dynamic-let (bindings &rest body) `(let ,bindings (declare (special ,@(mapcar #'car bindings))) ,@body)) (define-mumble-macro mumble::dynamic (name) `(locally (declare (special ,name)) ,name)) (define-setf-expander mumble::dynamic (name) (let ((store (gensym))) (values nil nil (list store) `(locally (declare (special ,name)) (setf ,name ,store)) `(locally (declare (special ,name)) ,name)))) (define-mumble-macro mumble::begin (&rest body) `(progn ,@body)) (define-mumble-import block) (define-mumble-import return-from) (define-mumble-import do) (define-mumble-import dolist) (define-mumble-import dotimes) (define-mumble-import values) (define-mumble-import multiple-value-bind) (define-mumble-macro mumble::let/cc (variable &rest body) (let ((tagvar (gensym))) `(let* ((,tagvar (gensym)) (,variable (let/cc-aux ,tagvar))) (catch ,tagvar (locally ,@body))))) (defun let/cc-aux (tag) #'(lambda (&rest values) (throw tag (values-list values)))) (define-mumble-import unwind-protect) (define-mumble-import declare) (define-mumble-import ignore) ;;; IGNORABLE is part of ANSI CL but not implemented by Lucid yet. ;;; IGNORE in Lucid seems to behave like what ANSI CL says IGNORABLE ;;; should do, but there doesn't seem to be any way to rename it. #+(or lucid akcl lispworks wcl) (progn (proclaim '(declaration mumble::ignorable)) (define-mumble-import mumble::ignorable)) #+(or cmu mcl allegro) (define-mumble-import cl:ignorable) #-(or lucid cmu allegro akcl mcl lispworks wcl) (missing-mumble-definition mumble::ignorable) (define-mumble-import type) ;;;===================================================================== ;;; Definitions ;;;===================================================================== ;;; *** This shouldn't really do a DEFPARAMETER, since that proclaims ;;; *** the variable SPECIAL and makes any LETs of the variable do ;;; *** special binding rather than lexical binding. But if you just ;;; *** SETF the variable, you'll get a compiler warning about an ;;; *** undeclared free variable on every reference!!! Argggh. (define-mumble-macro mumble::define (pattern &rest value) (if (consp pattern) `(defun ,(car pattern) ,(mung-lambda-list (cdr pattern)) ,@value) `(defparameter ,pattern ,(car value)))) (define-mumble-macro mumble::define-integrable (pattern &rest value) (if (consp pattern) `(progn (eval-when (eval compile load) (proclaim '(inline ,(car pattern)))) (defun ,(car pattern) ,(mung-lambda-list (cdr pattern)) ,@value)) `(defconstant ,pattern ,(car value)))) (define-mumble-macro mumble::define-syntax (pattern . body) `(defmacro ,(car pattern) ,(mung-lambda-list (cdr pattern)) ,@body)) (define-mumble-macro mumble::define-local-syntax (pattern . body) `(eval-when (eval compile) (defmacro ,(car pattern) ,(mung-lambda-list (cdr pattern)) ,@body))) (define-mumble-macro mumble::define-setf (getter setter) `(define-setf-method ,getter (&rest subforms) (define-setf-aux ',setter ',getter subforms))) (defun define-setf-aux (setter getter subforms) (let ((temps nil) (tempvals nil) (args nil) (store (gensym))) (dolist (x subforms) (if (constantp x) (push x args) (let ((temp (gensym))) (push temp temps) (push x tempvals) (push temp args)))) (setq temps (nreverse temps)) (setq tempvals (nreverse tempvals)) (setq args (nreverse args)) (values temps tempvals (list store) `(,setter ,store ,@args) `(,getter ,@args)))) ;;; Declaring variables special will make the compiler not proclaim ;;; about references to them. ;;; A proclamation works to disable undefined function warnings in ;;; most Lisps. Harlequin seems to offer no way to shut up these warnings. ;;; In allegro, we have to work around a bug in the compiler's handling ;;; of PROCLAIM. (define-mumble-macro mumble::predefine (pattern) `(eval-when (eval compile) #+allegro (let ((excl::*compiler-environment* nil)) (do-predefine ',pattern)) #-allegro (do-predefine ',pattern) )) (eval-when (eval compile load) (defun do-predefine (pattern) (if (consp pattern) (proclaim `(ftype (function ,(mung-decl-lambda-list (cdr pattern)) t) ,(car pattern))) (proclaim `(special ,pattern)))) (defun mung-decl-lambda-list (lambda-list) (cond ((consp lambda-list) (cons 't (mung-decl-lambda-list (cdr lambda-list)))) ((null lambda-list) '()) (t '(&rest t)))) ) ;;; CMUCL doesn't complain about function redefinitions, but Lucid does. #+(or cmu akcl mcl lispworks wcl) (define-mumble-macro mumble::redefine (pattern . value) `(mumble::define ,pattern ,@value)) #+lucid (define-mumble-macro mumble::redefine (pattern . value) `(let ((lcl:*redefinition-action* nil)) (mumble::define ,pattern ,@value))) #+allegro (define-mumble-macro mumble::redefine (pattern . value) `(let ((excl:*redefinition-warnings* nil)) (mumble::define ,pattern ,@value))) #-(or cmu lucid allegro akcl mcl lispworks wcl) (missing-mumble-definition mumble::redefine) #+(or cmu akcl mcl lispworks wcl) (define-mumble-macro mumble::redefine-syntax (pattern . body) `(mumble::define-syntax ,pattern ,@body)) #+lucid (define-mumble-macro mumble::redefine-syntax (pattern . body) `(eval-when (eval compile load) (let ((lcl:*redefinition-action* nil)) (mumble::define-syntax ,pattern ,@body)))) #+allegro (define-mumble-macro mumble::redefine-syntax (pattern . body) `(eval-when (eval compile load) (let ((excl:*redefinition-warnings* nil)) (mumble::define-syntax ,pattern ,@body)))) #-(or cmu lucid allegro akcl mcl lispworks wcl) (missing-mumble-definition mumble::redefine-syntax) ;;;===================================================================== ;;; Equivalence ;;;===================================================================== (define-mumble-function-inline mumble::eq? (x y) (eq x y)) (define-mumble-function-inline mumble::eqv? (x y) (eql x y)) (define-mumble-function mumble::equal? (x1 x2) (cond ((eql x1 x2) t) ((consp x1) (and (consp x2) (mumble::equal? (car x1) (car x2)) (mumble::equal? (cdr x1) (cdr x2)))) ((simple-string-p x1) (and (simple-string-p x2) (string= x1 x2))) ((simple-vector-p x1) (and (simple-vector-p x2) (eql (length (the simple-vector x1)) (length (the simple-vector x2))) (every #'mumble::equal? (the simple-vector x1) (the simple-vector x2)))) (t nil))) ;;;===================================================================== ;;; Lists ;;;===================================================================== (define-mumble-function-inline mumble::pair? (x) (consp x)) (define-mumble-import cons) ;;; Can't import this directly because of type problems. (define-mumble-synonym mumble::list list) (define-mumble-function-inline mumble::make-list (length &optional (init nil)) (the list (make-list length :initial-element init))) (define-mumble-import car) (define-mumble-import cdr) (define-mumble-import caar) (define-mumble-import cadr) (define-mumble-import cadr) (define-mumble-import cddr) (define-mumble-import caaar) (define-mumble-import caadr) (define-mumble-import caadr) (define-mumble-import caddr) (define-mumble-import cdaar) (define-mumble-import cdadr) (define-mumble-import cdadr) (define-mumble-import cdddr) (define-mumble-import caaaar) (define-mumble-import caaadr) (define-mumble-import caaadr) (define-mumble-import caaddr) (define-mumble-import cadaar) (define-mumble-import cadadr) (define-mumble-import cadadr) (define-mumble-import cadddr) (define-mumble-import cdaaar) (define-mumble-import cdaadr) (define-mumble-import cdaadr) (define-mumble-import cdaddr) (define-mumble-import cddaar) (define-mumble-import cddadr) (define-mumble-import cddadr) (define-mumble-import cddddr) (define-mumble-function-inline mumble::null? (x) (null x)) (define-mumble-function mumble::list? (x) (cond ((null x) t) ((consp x) (mumble::list? (cdr x))) (t nil))) (define-mumble-function-inline mumble::length (x) (the fixnum (length (the list x)))) (define-mumble-import append) (define-mumble-import nconc) (define-mumble-function-inline mumble::reverse (x) (the list (reverse (the list x)))) (define-mumble-function-inline mumble::nreverse (x) (the list (nreverse (the list x)))) (define-mumble-function-inline mumble::list-tail (list n) (nthcdr n list)) (define-mumble-function-inline mumble::list-ref (list n) (nth n list)) (define-mumble-import last) (define-mumble-import butlast) (define-setf-expander mumble::list-ref (list n) (get-setf-method `(nth ,n ,list))) (define-mumble-function-inline mumble::memq (object list) (member object list :test #'eq)) (define-mumble-function-inline mumble::memv (object list) (member object list)) (define-mumble-function-inline mumble::member (object list) (member object list :test #'mumble::equal?)) ;;; *** The Lucid compiler is not doing anything inline for assq so ;;; *** I'm rewriting this -- jcp (define-mumble-function mumble::assq (object list) (if (null list) nil (if (eq object (caar list)) (car list) (mumble::assq object (cdr list))))) (define-mumble-function-inline mumble::assv (object list) (assoc object list)) (define-mumble-function-inline mumble::assoc (object list) (assoc object list :test #'mumble::equal?)) (define-mumble-import push) (define-mumble-import pop) (define-mumble-synonym mumble::list-copy copy-list) ;;;===================================================================== ;;; Symbols ;;;===================================================================== (define-mumble-function-inline mumble::symbol? (x) (symbolp x)) (define-mumble-synonym mumble::symbol->string symbol-name) (define-mumble-function-inline mumble::string->symbol (x) (intern x)) ;;; We want a gensym that follows the new ANSI CL gensym-name-stickiness ;;; decision. #+(or lucid akcl wcl) (define-mumble-function mumble::gensym (&optional (prefix "G")) (gensym prefix)) #+(or cmu allegro mcl lispworks) (define-mumble-import gensym) #-(or lucid akcl wcl cmu allegro mcl lispworks) (missing-mumble-definition mumble::gensym) (define-mumble-function mumble::gensym? (x) (and (symbolp x) (not (symbol-package x)))) (defun symbol-append (&rest symbols) (intern (apply #'concatenate 'string (mapcar #'symbol-name symbols)))) (define-mumble-import symbol-append) ;;;===================================================================== ;;; Characters ;;;===================================================================== (define-mumble-function-inline mumble::char? (x) (characterp x)) (define-mumble-synonym mumble::char=? char=) (define-mumble-synonym mumble::char? char>) (define-mumble-synonym mumble::char>=? char>=) (define-mumble-synonym mumble::char<=? char<=) (define-mumble-synonym mumble::char-ci=? char-equal) (define-mumble-synonym mumble::char-ci? char-greaterp) (define-mumble-synonym mumble::char-ci>=? char-not-lessp) (define-mumble-synonym mumble::char-ci<=? char-not-greaterp) (define-mumble-synonym mumble::char-alphabetic? alpha-char-p) (define-mumble-synonym mumble::char-numeric? digit-char-p) (define-mumble-function mumble::char-whitespace? (c) (member c '(#\space #\tab #\newline #\linefeed #\page #\return))) (define-mumble-synonym mumble::char-upper-case? upper-case-p) (define-mumble-synonym mumble::char-lower-case? lower-case-p) (define-mumble-synonym mumble::char->integer char-code) (define-mumble-synonym mumble::integer->char code-char) (define-mumble-import char-upcase) (define-mumble-import char-downcase) (define-mumble-import char-name) (define-mumble-synonym mumble::char->digit digit-char-p) ;;;===================================================================== ;;; Strings ;;;===================================================================== (define-mumble-function-inline mumble::string? (x) (simple-string-p x)) (define-mumble-function-inline mumble::make-string (length &optional (init nil init-p)) (the simple-string (if init-p (make-string length :initial-element init) (make-string length)))) (define-mumble-function-inline mumble::string (char &rest more-chars) (the simple-string (coerce (cons char more-chars) 'string))) (define-mumble-function-inline mumble::string-length (string) (the fixnum (length (the simple-string string)))) (define-mumble-function-inline mumble::string-ref (x n) (the character (schar (the simple-string x) (the fixnum n)))) (define-setf-expander mumble::string-ref (string n) (get-setf-method `(schar ,string ,n))) (define-mumble-synonym mumble::string=? string=) (define-mumble-synonym mumble::string? string>) (define-mumble-synonym mumble::string<=? string<=) (define-mumble-synonym mumble::string>=? string>=) (define-mumble-synonym mumble::string-ci=? string-equal) (define-mumble-synonym mumble::string-ci? string-greaterp) (define-mumble-synonym mumble::string-ci<=? string-not-greaterp) (define-mumble-synonym mumble::string-ci>=? string-not-lessp) (define-mumble-function-inline mumble::substring (string start end) (the simple-string (subseq (the simple-string string) start end))) (define-mumble-function-inline mumble::string-append (string &rest more-strings) (declare (type simple-string string)) (the simple-string (apply #'concatenate 'string string more-strings))) (define-mumble-function-inline mumble::string->list (string) (the list (coerce (the simple-string string) 'list))) (define-mumble-function-inline mumble::list->string (list) (the simple-string (coerce (the list list) 'string))) (define-mumble-function-inline mumble::string-copy (string) (the simple-string (copy-seq (the simple-string string)))) (define-mumble-import string-upcase) (define-mumble-import string-downcase) ;;;===================================================================== ;;; Vectors ;;;===================================================================== (define-mumble-function-inline mumble::vector? (x) (simple-vector-p x)) (define-mumble-function-inline mumble::make-vector (length &optional (init nil init-p)) (declare (type fixnum length)) (the simple-vector (if init-p (make-array length :initial-element init) (make-array length)))) ;;; Can't import directly because types are incompatible. (define-mumble-synonym mumble::vector vector) (define-mumble-function-inline mumble::vector-length (vector) (the fixnum (length (the simple-vector vector)))) (define-mumble-function-inline mumble::vector-ref (x n) (svref (the simple-vector x) (the fixnum n))) (define-setf-expander mumble::vector-ref (vector n) (get-setf-method `(svref ,vector ,n))) (define-mumble-function-inline mumble::vector->list (vector) (the list (coerce (the simple-vector vector) 'list))) (define-mumble-function-inline mumble::list->vector (list) (the simple-vector (coerce (the list list) 'simple-vector))) (define-mumble-function-inline mumble::vector-copy (vector) (the simple-vector (copy-seq (the simple-vector vector)))) ;;;===================================================================== ;;; Numbers ;;;===================================================================== (define-mumble-synonym mumble::number? numberp) (define-mumble-synonym mumble::integer? integerp) (define-mumble-synonym mumble::rational? rationalp) (define-mumble-synonym mumble::float? floatp) (define-mumble-function-inline mumble::fixnum? (x) (typep x 'fixnum)) (define-mumble-synonym mumble::exact->inexact float) (define-mumble-import =) (define-mumble-import <) (define-mumble-import >) (define-mumble-import <=) (define-mumble-import >=) (define-mumble-synonym mumble::zero? zerop) (define-mumble-function-inline mumble::positive? (x) (> x 0)) (define-mumble-function-inline mumble::negative? (x) (< x 0)) (define-mumble-import min) (define-mumble-import max) (define-mumble-import +) (define-mumble-import *) (define-mumble-import -) (define-mumble-import /) (define-mumble-synonym mumble::quotient floor) (define-mumble-synonym mumble::remainder rem) (define-mumble-synonym mumble::modulo mod) (define-mumble-function-inline mumble::floor (x) (if (floatp x) (ffloor x) (floor (the rational x)))) (define-mumble-function-inline mumble::ceiling (x) (if (floatp x) (fceiling x) (ceiling (the rational x)))) (define-mumble-function-inline mumble::truncate (x) (if (floatp x) (ftruncate x) (truncate (the rational x)))) (define-mumble-function-inline mumble::round (x) (if (floatp x) (fround x) (round (the rational x)))) (define-mumble-synonym mumble::floor->exact floor) (define-mumble-synonym mumble::ceiling->exact ceiling) (define-mumble-synonym mumble::truncate->exact truncate) (define-mumble-synonym mumble::round->exact round) (define-mumble-import 1+) (define-mumble-import 1-) (define-mumble-import incf) (define-mumble-import decf) (define-mumble-function mumble::number->string (number &optional (radix 10)) (let ((*print-base* radix)) (prin1-to-string number))) (define-mumble-function mumble::string->number (string &optional (radix 10)) (let ((*read-base* radix)) (read-from-string string))) (define-mumble-import expt) ;;;===================================================================== ;;; Tables ;;;===================================================================== (define-mumble-synonym mumble::table? hash-table-p) (define-mumble-function-inline mumble::make-table () (make-hash-table :test #'eq)) (define-mumble-function-inline mumble::table-entry (table key) (gethash key table)) (define-setf-expander mumble::table-entry (table key) (get-setf-method `(gethash ,key ,table))) (define-mumble-synonym mumble::table-for-each maphash) (define-mumble-function mumble::copy-table (old-table) (let ((new-table (make-hash-table :test #'eq :size (1+ (hash-table-count old-table))))) (maphash #'(lambda (key val) (setf (gethash key new-table) val)) old-table) new-table)) ;;;===================================================================== ;;; I/O ;;;===================================================================== (define-mumble-function-inline mumble::call-with-input-file (string proc) (with-open-file (stream (expand-filename string) :direction :input) (funcall (the function proc) stream))) (define-mumble-function-inline mumble::call-with-output-file (string proc) (with-open-file (stream (expand-filename string) :direction :output :if-exists :new-version) (funcall (the function proc) stream))) (define-mumble-function-inline mumble::call-with-input-string (string proc) (with-input-from-string (stream string) (funcall (the function proc) stream))) (define-mumble-function-inline mumble::call-with-output-string (proc) (with-output-to-string (stream) (funcall (the function proc) stream))) (define-mumble-synonym mumble::input-port? input-stream-p) (define-mumble-synonym mumble::output-port? output-stream-p) (define-mumble-function-inline mumble::current-input-port () *standard-input*) (define-mumble-function-inline mumble::current-output-port () *standard-output*) (define-mumble-function-inline mumble::open-input-file (string) (open (expand-filename string) :direction :input)) (define-mumble-function-inline mumble::open-output-file (string) (open (expand-filename string) :direction :output :if-exists :new-version)) (define-mumble-synonym mumble::close-input-port close) (define-mumble-synonym mumble::close-output-port close) (defvar *eof-object* (make-symbol "EOF")) (define-mumble-function-inline mumble::read (&optional (port *standard-input*)) (read port nil *eof-object*)) (define-mumble-function-inline mumble::read-char (&optional (port *standard-input*)) (read-char port nil *eof-object*)) (define-mumble-function-inline mumble::peek-char (&optional (port *standard-input*)) (peek-char nil port nil *eof-object*)) (define-mumble-function-inline mumble::read-line (&optional (port *standard-input*)) (read-line port nil *eof-object*)) (define-mumble-function-inline mumble::eof-object? (x) (eq x *eof-object*)) ;;;===================================================================== ;;; Printer ;;;===================================================================== (define-mumble-function mumble::internal-write (object port) (write object :stream port)) (define-mumble-function-inline mumble::internal-output-width (port) (declare (ignore port)) nil) (define-mumble-function-inline mumble::internal-output-position (port) (declare (ignore port)) nil) (define-mumble-synonym mumble::internal-write-char write-char) (define-mumble-function-inline mumble::internal-write-string (string port start end) (write-string string port :start start :end end)) (define-mumble-synonym mumble::internal-newline terpri) (define-mumble-synonym mumble::internal-fresh-line fresh-line) (define-mumble-synonym mumble::internal-finish-output finish-output) (define-mumble-synonym mumble::internal-force-output force-output) (define-mumble-synonym mumble::internal-clear-output clear-output) (define-mumble-function mumble::internal-write-to-string (object) (write-to-string object)) (define-mumble-function-inline mumble::internal-warning (string) (warn "~a" string)) (define-mumble-function-inline mumble::internal-error (string) (error "~a" string)) ;;; Printer stuff used directly by the pretty printer (define-mumble-import *print-escape*) (define-mumble-import *print-circle*) (define-mumble-import *print-pretty*) (define-mumble-import *print-level*) (define-mumble-import *print-length*) (define-mumble-import *print-base*) (define-mumble-import *print-radix*) ;;; These functions and variables are all defined with the XP stuff. But, ;;; let's export all the symbols from the mumble package. (define-mumble-import mumble::write) (define-mumble-import mumble::print) (define-mumble-import mumble::prin1) (define-mumble-import mumble::princ) (define-mumble-import mumble::pprint) (define-mumble-import mumble::prin1-to-string) (define-mumble-import mumble::princ-to-string) (define-mumble-import mumble::write-char) (define-mumble-import mumble::write-string) (define-mumble-import mumble::write-line) (define-mumble-import mumble::terpri) (define-mumble-import mumble::fresh-line) (define-mumble-import mumble::finish-output) (define-mumble-import mumble::force-output) (define-mumble-import mumble::clear-output) (define-mumble-import mumble::display) (define-mumble-import mumble::newline) (define-mumble-import mumble::*print-shared*) (define-mumble-import mumble::*print-dispatch*) (define-mumble-import mumble::*print-right-margin*) (define-mumble-import mumble::*print-miser-width*) (define-mumble-import mumble::*print-lines*) (define-mumble-import mumble::*default-right-margin*) (define-mumble-import mumble::*last-abbreviated-printing*) (define-mumble-import mumble::*print-structure*) (define-mumble-import mumble::*print-structure-slots*) (define-mumble-import mumble::standard-print-dispatch) (define-mumble-import mumble::pprint-newline) (define-mumble-import mumble::pprint-logical-block) (define-mumble-import mumble::pprint-pop) (define-mumble-import mumble::pprint-exit-if-list-exhausted) (define-mumble-import mumble::pprint-indent) (define-mumble-import mumble::pprint-tab) (define-mumble-import mumble::pprint-fill) (define-mumble-import mumble::pprint-linear) (define-mumble-import mumble::pprint-tabular) (define-mumble-import mumble::format) (define-mumble-import mumble::warning) (define-mumble-import mumble::error) ;;; These are keywords for pprint-newline. (define-mumble-import mumble::linear) (define-mumble-import mumble::fill) (define-mumble-import mumble::miser) (define-mumble-import mumble::mandatory) ;;; These are keywords for pprint-indent ;; (define-mumble-import mumble::block) ; already imported as special form (define-mumble-import mumble::current) ;;; These are keywords for pprint-tab (define-mumble-import mumble::line) (define-mumble-import mumble::section) (define-mumble-import mumble::line-relative) (define-mumble-import mumble::section-relative) ;;;===================================================================== ;;; System Interface ;;;===================================================================== (define-mumble-import macroexpand-1) (define-mumble-import macroexpand) ;;; WITH-COMPILATION-UNIT is an ANSI CL feature that isn't yet ;;; supported by all Lisps. #+lucid (define-mumble-macro mumble::with-compilation-unit (options &body body) (declare (ignore options)) `(lcl:with-deferred-warnings ,@body)) #+(or cmu mcl allegro lispworks) (define-mumble-import with-compilation-unit) #+(or akcl wcl) (define-mumble-macro mumble::with-compilation-unit (options &body body) (declare (ignore options)) `(progn ,@body)) #-(or lucid allegro cmu akcl mcl lispworks wcl) (missing-mumble-definition mumble::with-compilation-unit) (define-mumble-function mumble::eval (form &optional compile-p) (if compile-p (mumble::with-compilation-unit () (eval-compiling-functions form)) (eval form))) ;;; Simply doing (funcall (compile nil `(lambda () ,form))) would work ;;; except that top-level-ness actions would be lost (causing extraneous ;;; warning messages about global variables whose references are compiled ;;; before a previous predefine is executed, etc). So make an attempt ;;; to process nested top-level forms in order. This doesn't look for ;;; all of the common-lispy things that might show up in macro expansions, ;;; but it's close enough. (defun eval-compiling-functions (form) (if (atom form) (eval form) (let ((fn (car form))) (cond ((or (eq fn 'mumble::begin) (eq fn 'progn)) (do ((forms (cdr form) (cdr forms))) ((null (cdr forms)) (eval-compiling-functions (car forms))) (eval-compiling-functions (car forms)))) ((eq fn 'mumble::define) (if (consp (cadr form)) (compile-define form) (compile-other form))) ((eq fn 'mumble::define-integrable) (if (consp (cadr form)) (progn (proclaim `(inline ,(car (cadr form)))) (compile-define form)) (compile-other form))) ((eq fn 'mumble::predefine) (do-predefine (cadr form))) ((macro-function fn) (eval-compiling-functions (macroexpand-1 form))) (t (compile-other form)))))) (defun compile-define (form) (let ((name (car (cadr form))) (args (mung-lambda-list (cdr (cadr form)))) (body (cddr form))) (compile name `(lambda ,args ,@body)) name)) (defun compile-other (form) (funcall (compile nil `(lambda () ,form)))) ;;; Load and compile-file aren't directly imported from the host ;;; Common Lisp because we want to do our own defaulting of file ;;; name extensions. (define-mumble-function mumble::load (filename) (setq filename (expand-filename filename)) (if (string= (mumble::filename-type filename) "") (let ((source-file (build-source-filename filename)) (binary-file (build-binary-filename filename))) (if (and (probe-file binary-file) (> (file-write-date binary-file) (file-write-date source-file))) (load binary-file) (load source-file))) (load filename))) ;;; This is used to control OPTIMIZE declarations in a somewhat more ;;; portable way -- different implementations may need slightly different ;;; combinations. ;;; 0 = do as little as possible when compiling code ;;; 1 = use "default" compiler settings ;;; 2 = omit safety checks and do "easy" speed optimizations. ;;; 3 = do as much as possible; type inference, inlining, etc. May be slow. ;;; #f = don't mess with optimize settings. (defvar *code-quality* nil) (define-mumble-import *code-quality*) (defun code-quality-hack (q) (cond ((eql q 0) (proclaim '(optimize (speed 1) (safety 3) (compilation-speed 3) #+cmu (ext:debug 1) #+(or mcl allegro lispworks) (debug 1) ))) ((eql q 1) (proclaim '(optimize (speed 1) (safety 1) (compilation-speed 3) #+cmu (ext:debug 1) #+(or mcl allegro lispworks) (debug 1) ))) ((eql q 2) (proclaim '(optimize (speed 3) (safety 0) (compilation-speed 3) #+cmu (ext:debug 0) #+(or mcl allegro lispworks) (debug 0) ))) ((eql q 3) (proclaim '(optimize (speed 3) (safety 0) (compilation-speed 0) #+cmu (ext:debug 0) #+(or mcl allegro lispworks) (debug 0) ))) (t (warn "Bogus *code-quality* setting ~s." q)))) ;;; If we don't do this, code generated with high code-quality settings ;;; can't be interrupted with ^C. #+allegro (setf compiler:generate-interrupt-checks-switch #'(lambda (safety space speed debug) (declare (ignore safety space speed debug)) t)) ;;; Note that we expect the binary filename (if supplied) to be ;;; relative to the current directory, not to the source filename. ;;; Lucid and AKCL (and maybe other implementations) merge the :output-file ;;; pathname with the source filename, but the merge by expand-filename ;;; should prevent it from doing anything. (define-mumble-function mumble::compile-file (filename &optional binary) (if *code-quality* (code-quality-hack *code-quality*)) (setq filename (expand-filename filename)) (if (string= (mumble::filename-type filename) "") (setq filename (build-source-filename filename))) (if binary (compile-file filename :output-file (expand-filename binary)) (compile-file filename))) ;;; See cl-init.lisp for initialization of *lisp-binary-file-type*. (defconstant source-file-type ".scm") (defconstant binary-file-type *lisp-binary-file-type*) (define-mumble-import source-file-type) (define-mumble-import binary-file-type) (defun build-source-filename (filename) (mumble::assemble-filename filename filename source-file-type)) (defun build-binary-filename (filename) (mumble::assemble-filename filename filename binary-file-type)) (proclaim '(ftype (function (simple-string) simple-string) mumble::filename-place mumble::filename-name mumble::filename-type expand-filename)) (proclaim '(ftype (function (simple-string simple-string simple-string) simple-string) mumble::assemble-filename)) (define-mumble-function mumble::assemble-filename (place name type) (concatenate 'string (mumble::filename-place place) (mumble::filename-name name) (mumble::filename-type type))) (define-mumble-function mumble::filename-place (filename) (declare (simple-string filename)) (let ((slash (position #\/ filename :from-end t))) (if slash (subseq filename 0 (1+ slash)) ""))) (define-mumble-function mumble::filename-name (filename) (declare (simple-string filename)) (let* ((slash (position #\/ filename :from-end t)) (beg (if slash (1+ slash) 0)) (dot (position #\. filename :start beg))) (if (or slash dot) (subseq filename beg (or dot (length filename))) filename))) (define-mumble-function mumble::filename-type (filename) (declare (simple-string filename)) (let* ((slash (position #\/ filename :from-end t)) (beg (if slash (1+ slash) 0)) (dot (position #\. filename :start beg))) (if dot (subseq filename dot (length filename)) ""))) ;;; This function is called by all functions that pass filenames down ;;; to the operating system. It does environment variable substitution ;;; and merging with *default-pathname-defaults* (set by the cd function). ;;; Since this function translates mumble's notion of pathnames into ;;; a lower-level representation, this function should never need to ;;; be called outside of this file. (defun expand-filename (filename) (declare (simple-string filename)) (namestring (merge-pathnames (fix-filename-syntax (if (eql (schar filename 0) #\$) (let* ((end (length filename)) (slash (or (position #\/ filename) end)) (new (mumble::getenv (subseq filename 1 slash)))) (if new (concatenate 'string new (subseq filename slash end)) filename)) filename) )))) ;;; On non-unix machines, may need to change the mumble unix-like filename ;;; syntax to whatever the normal syntax used by the implementation is. #+mcl (defun fix-filename-syntax (filename) (substitute #\: #\/ filename)) #-mcl (defun fix-filename-syntax (filename) filename) ;;; AKCL's compile-file merges the output pathname against the input ;;; pathname. If the output pathname doesn't have an explicit directory ;;; but the input pathname does, the wrong thing will happen. This ;;; hack is so that expand-filename will always put a directory ;;; specification on both pathnames. ;;; Lucid CL does similar merging, but *default-pathname-defaults* ;;; already defaults to the truename of the current directory. #+akcl (setf *default-pathname-defaults* (truename "./")) ;;; WCL's *default-pathname-defaults* is OK except that it has a ;;; type of .lisp, which is inappropriate. #+wcl (setf *default-pathname-defaults* (make-pathname :directory (pathname-directory *default-pathname-defaults*))) #+(or mcl lispworks) (setf *default-pathname-defaults* (truename *default-pathname-defaults*)) (define-mumble-function mumble::file-exists? (filename) (probe-file (expand-filename filename))) (define-mumble-function mumble::file-write-date (filename) (file-write-date (expand-filename filename))) (define-mumble-synonym mumble::current-date get-universal-time) (define-mumble-function mumble::get-run-time () (/ (get-internal-run-time) (float internal-time-units-per-second))) ;;; Get environment variables #+lucid (progn (mumble::predefine (mumble::getenv string)) (define-mumble-synonym mumble::getenv lcl:environment-variable)) #+cmu (define-mumble-function mumble::getenv (string) (let ((symbol (intern string (find-package "KEYWORD")))) (cdr (assoc symbol extensions:*environment-list*)))) #+(or akcl allegro lispworks) (define-mumble-function mumble::getenv (string) (system::getenv string)) #+wcl (define-mumble-function mumble::getenv (string) (lisp:getenv string)) ;;; Hmmm. The Mac doesn't have environment variables, so we'll have to ;;; roll our own. #+mcl (progn (defvar *environment-alist* '()) (define-mumble-function mumble::getenv (string) (cdr (assoc string *environment-alist* :test #'string=))) ) #-(or lucid allegro cmu akcl mcl lispworks wcl) (missing-mumble-definition mumble::getenv) ;;; Change working directory. ;;; This stores a directory pathname in *default-pathname-defaults*. ;;; See also expand-filename. (define-mumble-function mumble::cd (filename) (if (not (eql (schar filename (1- (length filename))) #\/)) (setq filename (concatenate 'string filename "/"))) (setq *default-pathname-defaults* (pathname (expand-filename filename)))) ;;; Leave Lisp #+lucid (define-mumble-synonym mumble::exit lcl:quit) #+allegro (define-mumble-synonym mumble::exit excl:exit) #+cmu (define-mumble-synonym mumble::exit extensions:quit) #+akcl (define-mumble-synonym mumble::exit lisp:bye) #+mcl (define-mumble-synonym mumble::exit ccl:quit) #+lispworks (define-mumble-synonym mumble::exit lw:bye) #+wcl (define-mumble-synonym mumble::exit lisp:quit) #-(or lucid allegro cmu akcl mcl lispworks wcl) (missing-mumble-definition mumble::exit) ;;;===================================================================== ;;; Reader support ;;;===================================================================== ;;; Make the default readtable recognize #f and #t. ;;; CMUCL's loader rebinds *readtable* when loading file, so can't ;;; setq it here; hack the default readtable instead. #+(or cmu mcl allegro lispworks) (defparameter *mumble-readtable* *readtable*) #+(or lucid akcl wcl) (progn (defparameter *mumble-readtable* (copy-readtable nil)) (setq *readtable* *mumble-readtable*) ) #-(or lucid allegro cmu akcl mcl lispworks wcl) (missing-mumble-definition *mumble-readtable*) ;;; Lucid's debugger uses the standard readtable rather than *readtable* ;;; unless you do this magic trick. #+lucid (sys:add-debugger-binding '*readtable* *mumble-readtable*) (set-dispatch-macro-character #\# #\f #'(lambda (stream subchar arg) (declare (ignore stream subchar arg)) nil)) (set-dispatch-macro-character #\# #\t #'(lambda (stream subchar arg) (declare (ignore stream subchar arg)) t)) ;;;===================================================================== ;;; Random stuff ;;;===================================================================== (defconstant mumble::lisp-implementation-name *lisp-implementation-name*) (define-mumble-import mumble::lisp-implementation-name) (define-mumble-function mumble::identify-system () (format nil "~a version ~a on ~a" (or (lisp-implementation-type) "Generic Common Lisp") (or (lisp-implementation-version) "Generic") (or (machine-type) "Generic Machine"))) (defconstant mumble::left-to-right-evaluation t) (define-mumble-import mumble::left-to-right-evaluation) #+excl (define-mumble-function mumble::gc-messages (onoff) (setf (sys:gsgc-switch :print) onoff)) #+cmu (define-mumble-function mumble::gc-messages (onoff) (setf extensions:*gc-verbose* onoff)) #+(or lispworks akcl wcl mcl) (define-mumble-function mumble::gc-messages (onoff) onoff) ; can't figure out if they have a hook or not #+lucid (define-mumble-function mumble::gc-messages (onoff) (setf lcl:*gc-silence* (not onoff)) onoff) #-(or lucid cmu allegro akcl mcl lispworks wcl) (missing-mumble-definition mumble::gc-messages) (define-mumble-import identity)