dotemacs

My Emacs configuration
git clone git://git.entf.net/dotemacs
Log | Files | Refs | LICENSE

allegro.lisp (41473B)


      1 ;;;;                  -*- indent-tabs-mode: nil; outline-regexp: ";;;;;* "; -*-
      2 ;;;
      3 ;;; slynk-allegro.lisp --- Allegro CL specific code for SLY.
      4 ;;;
      5 ;;; Created 2003
      6 ;;;
      7 ;;; This code has been placed in the Public Domain.  All warranties
      8 ;;; are disclaimed.
      9 ;;;
     10 
     11 (defpackage slynk-allegro
     12   (:use cl slynk-backend))
     13 
     14 (in-package slynk-allegro)
     15 
     16 (eval-when (:compile-toplevel :load-toplevel :execute)
     17   (require :sock)
     18   (require :process)
     19   #+(version>= 8 2)
     20   (require 'lldb)
     21   )
     22 
     23 (defimplementation gray-package-name ()
     24   '#:excl)
     25 
     26 ;;; slynk-mop
     27 
     28 (import-slynk-mop-symbols :clos '(:slot-definition-documentation))
     29 
     30 (defun slynk-mop:slot-definition-documentation (slot)
     31   (documentation slot t))
     32 
     33 
     34 ;;;; UTF8
     35 
     36 (define-symbol-macro utf8-ef 
     37     (load-time-value 
     38      (excl:crlf-base-ef (excl:find-external-format :utf-8))
     39      t))
     40 
     41 (defimplementation string-to-utf8 (s)
     42   (excl:string-to-octets s :external-format utf8-ef 
     43                          :null-terminate nil))
     44 
     45 (defimplementation utf8-to-string (u)
     46   (excl:octets-to-string u :external-format utf8-ef))
     47 
     48 
     49 ;;;; TCP Server
     50 
     51 (defimplementation preferred-communication-style ()
     52   :spawn)
     53 
     54 (defimplementation create-socket (host port &key backlog)
     55   (socket:make-socket :connect :passive :local-port port 
     56                       :local-host host :reuse-address t
     57                       :backlog (or backlog 5)))
     58 
     59 (defimplementation local-port (socket)
     60   (socket:local-port socket))
     61 
     62 (defimplementation close-socket (socket)
     63   (close socket))
     64 
     65 (defimplementation accept-connection (socket &key external-format buffering
     66                                              timeout)
     67   (declare (ignore buffering timeout))
     68   (let ((s (socket:accept-connection socket :wait t)))
     69     (when external-format
     70       (setf (stream-external-format s) external-format))
     71     s))
     72 
     73 (defimplementation socket-fd (stream)
     74   (excl::stream-input-handle stream))
     75 
     76 (defvar *external-format-to-coding-system*
     77   '((:iso-8859-1 
     78      "latin-1" "latin-1-unix" "iso-latin-1-unix" 
     79      "iso-8859-1" "iso-8859-1-unix")
     80     (:utf-8 "utf-8" "utf-8-unix")
     81     (:euc-jp "euc-jp" "euc-jp-unix")
     82     (:us-ascii "us-ascii" "us-ascii-unix")
     83     (:emacs-mule "emacs-mule" "emacs-mule-unix")))
     84 
     85 (defimplementation find-external-format (coding-system)
     86   (let ((e (rassoc-if (lambda (x) (member coding-system x :test #'equal))
     87                       *external-format-to-coding-system*)))
     88     (and e (excl:crlf-base-ef 
     89             (excl:find-external-format (car e) 
     90                                        :try-variant t)))))
     91 
     92 ;;;; Unix signals
     93 
     94 (defimplementation getpid ()
     95   (excl::getpid))
     96 
     97 (defimplementation lisp-implementation-type-name ()
     98   "allegro")
     99 
    100 (defimplementation set-default-directory (directory)
    101   (let* ((dir (namestring (truename (merge-pathnames directory)))))
    102     (setf *default-pathname-defaults* (pathname (excl:chdir dir)))
    103     dir))
    104 
    105 (defimplementation default-directory ()
    106   (namestring (excl:current-directory)))
    107 
    108 ;;;; Misc
    109 
    110 (defimplementation arglist (symbol)
    111   (handler-case (excl:arglist symbol)
    112     (simple-error () :not-available)))
    113 
    114 (defimplementation macroexpand-all (form &optional env)
    115   (declare (ignore env))
    116   #+(version>= 8 0)
    117   (excl::walk-form form)
    118   #-(version>= 8 0)
    119   (excl::walk form))
    120 
    121 (defimplementation describe-symbol-for-emacs (symbol)
    122   (let ((result '()))
    123     (flet ((doc (kind &optional (sym symbol))
    124              (or (ignore-errors
    125                   (documentation sym kind))
    126                  :not-documented))
    127            (maybe-push (property value)
    128              (when value
    129                (setf result (list* property value result)))))
    130       (maybe-push
    131        :variable (when (boundp symbol)
    132                    (doc 'variable)))
    133       (maybe-push
    134        :function (if (fboundp symbol)
    135                      (doc 'function)))
    136       (maybe-push
    137        :class (if (find-class symbol nil)
    138                   (doc 'class)))
    139       result)))
    140 
    141 (defimplementation describe-definition (symbol namespace)
    142   (ecase namespace
    143     (:variable 
    144      (describe symbol))
    145     ((:function :generic-function)
    146      (describe (symbol-function symbol)))
    147     (:class
    148      (describe (find-class symbol)))))
    149 
    150 (defimplementation type-specifier-p (symbol)
    151   (or (ignore-errors
    152        (subtypep nil symbol))
    153       (not (eq (type-specifier-arglist symbol) :not-available))))
    154 
    155 (defimplementation function-name (f)
    156   (check-type f function)
    157   (cross-reference::object-to-function-name f))
    158 
    159 ;;;; Debugger
    160 
    161 (defvar *sly-db-topframe*)
    162 
    163 (defimplementation call-with-debugging-environment (debugger-loop-fn)
    164   (let ((*sly-db-topframe* (find-topframe))
    165         (excl::*break-hook* nil))
    166     (funcall debugger-loop-fn)))
    167 
    168 (defimplementation sly-db-break-at-start (fname)
    169   ;; :print-before is kind of mis-used but we just want to stuff our
    170   ;; break form somewhere. This does not work for setf, :before and
    171   ;; :after methods, which need special syntax in the trace call, see
    172   ;; ACL's doc/debugging.htm chapter 10.
    173   (eval `(trace (,fname
    174                  :print-before
    175                  ((break "Function start breakpoint of ~A" ',fname)))))
    176   `(:ok ,(format nil "Set breakpoint at start of ~S" fname)))
    177 
    178 (defun find-topframe ()
    179   (let ((magic-symbol (intern (symbol-name :slynk-debugger-hook)
    180                               (find-package :slynk)))
    181         (top-frame (excl::int-newest-frame (excl::current-thread))))
    182     (loop for frame = top-frame then (next-frame frame)
    183           for i from 0
    184           while (and frame (< i 30))
    185           when (eq (debugger:frame-name frame) magic-symbol)
    186             return (next-frame frame)
    187           finally (return top-frame))))
    188 
    189 (defun next-frame (frame)
    190   (let ((next (excl::int-next-older-frame frame)))
    191     (cond ((not next) nil)
    192           ((debugger:frame-visible-p next) next)
    193           (t (next-frame next)))))
    194 
    195 (defun nth-frame (index)
    196   (do ((frame *sly-db-topframe* (next-frame frame))
    197        (i index (1- i)))
    198       ((zerop i) frame)))
    199 
    200 (defimplementation compute-backtrace (start end)
    201   (let ((end (or end most-positive-fixnum)))
    202     (loop for f = (nth-frame start) then (next-frame f)
    203 	  for i from start below end
    204 	  while f collect f)))
    205 
    206 (defimplementation print-frame (frame stream)
    207   (debugger:output-frame stream frame :moderate))
    208 
    209 (defimplementation frame-locals (index)
    210   (let ((frame (nth-frame index)))
    211     (loop for i from 0 below (debugger:frame-number-vars frame)
    212 	  collect (list :name (debugger:frame-var-name frame i)
    213 			:id 0
    214 			:value (debugger:frame-var-value frame i)))))
    215 
    216 (defimplementation frame-arguments (index)
    217   (let ((frame (nth-frame index)))
    218     ;; (values-list (debugger::.actuals frame))
    219     (values-list
    220      (loop for i from 0 below (debugger:frame-number-vars frame)
    221            unless (eq :local (debugger:frame-var-type frame i))
    222              collect (debugger:frame-var-value frame i)))))
    223 
    224 (defimplementation frame-var-value (frame var)
    225   (let ((frame (nth-frame frame)))
    226     (debugger:frame-var-value frame var)))
    227 
    228 (defimplementation disassemble-frame (index)
    229   (let ((frame (nth-frame index)))
    230     (multiple-value-bind (x fun xx xxx pc) (debugger::dyn-fd-analyze frame)
    231       (format t "pc: ~d (~s ~s ~s)~%fun: ~a~%" pc x xx xxx fun)
    232       (disassemble (debugger:frame-function frame)))))
    233 
    234 (defimplementation frame-source-location (index)
    235   (let* ((frame (nth-frame index)))
    236     (multiple-value-bind (x fun xx xxx pc) (debugger::dyn-fd-analyze frame)
    237       (declare (ignore x xx xxx))
    238       (cond ((and pc
    239                   #+(version>= 8 2)
    240                   (pc-source-location fun pc)
    241                   #-(version>= 8 2)
    242                   (function-source-location fun)))
    243             (t ; frames for unbound functions etc end up here
    244              (cadr (car (fspec-definition-locations
    245                          (car (debugger:frame-expression frame))))))))))
    246 
    247 (defun function-source-location (fun)
    248   (cadr (car (fspec-definition-locations 
    249               (xref::object-to-function-name fun)))))
    250 
    251 #+(version>= 8 2)
    252 (defun pc-source-location (fun pc)
    253   (let* ((debug-info (excl::function-source-debug-info fun)))
    254     (cond ((not debug-info)
    255            (function-source-location fun))
    256           (t
    257            (let* ((code-loc (find-if (lambda (c)
    258                                        (<= (- pc (sys::natural-width))
    259                                            (let ((x (excl::ldb-code-pc c)))
    260                                              (or x -1))
    261                                            pc))
    262                                      debug-info)))
    263              (cond ((not code-loc)
    264                     (ldb-code-to-src-loc (aref debug-info 0)))
    265                    (t
    266                     (ldb-code-to-src-loc code-loc))))))))
    267 
    268 #+(version>= 8 2)
    269 (defun ldb-code-to-src-loc (code)
    270   (declare (optimize debug))
    271   (let* ((func (excl::ldb-code-func code))
    272          (debug-info (excl::function-source-debug-info func))
    273          (start (and debug-info
    274                      (loop for i from (excl::ldb-code-index code) downto 0
    275                       for bpt = (aref debug-info i)
    276                       for start = (excl::ldb-code-start-char bpt)
    277                       when start
    278                         return (if (listp start)
    279                                    (first start)
    280                                    start))))
    281          (src-file (and func (excl:source-file func))))
    282     (cond (start
    283            (buffer-or-file-location src-file start))
    284           (func
    285            (let* ((debug-info (excl::function-source-debug-info func))
    286                   (whole (aref debug-info 0))
    287                   (paths (source-paths-of (excl::ldb-code-source whole)
    288                                           (excl::ldb-code-source code)))
    289                   (path (if paths (longest-common-prefix paths) '()))
    290                   (start 0))
    291              (buffer-or-file
    292               src-file
    293               (lambda (file)
    294                 (make-location `(:file ,file)
    295                                `(:source-path (0 . ,path) ,start)))
    296               (lambda (buffer bstart)
    297                 (make-location `(:buffer ,buffer)
    298                                `(:source-path (0 . ,path)
    299                                               ,(+ bstart start)))))))
    300           (t
    301            nil))))
    302 
    303 (defun longest-common-prefix (sequences)
    304   (assert sequences)
    305   (flet ((common-prefix (s1 s2)
    306            (let ((diff-pos (mismatch s1 s2)))
    307              (if diff-pos (subseq s1 0 diff-pos) s1))))
    308     (reduce #'common-prefix sequences)))
    309 
    310 (defun source-paths-of (whole part)
    311   (let ((result '()))
    312     (labels ((walk (form path)
    313                (cond ((eq form part) 
    314                       (push (reverse path) result))
    315                      ((consp form)
    316                       (loop for i from 0 while (consp form) do
    317                             (walk (pop form) (cons i path)))))))
    318       (walk whole '())
    319       (reverse result))))
    320 
    321 (defimplementation eval-in-frame (form frame-number)
    322   (let ((frame (nth-frame frame-number)))
    323     ;; let-bind lexical variables
    324     (let ((vars (loop for i below (debugger:frame-number-vars frame)
    325                       for name = (debugger:frame-var-name frame i)
    326                       if (typep name '(and symbol (not null) (not keyword)))
    327                       collect `(,name ',(debugger:frame-var-value frame i)))))
    328       (debugger:eval-form-in-context
    329        `(let* ,vars ,form)
    330        (debugger:environment-of-frame frame)))))
    331 
    332 (defimplementation frame-package (frame-number)
    333   (let* ((frame (nth-frame frame-number))
    334          (exp (debugger:frame-expression frame)))
    335     (typecase exp
    336       ((cons symbol) (symbol-package (car exp)))
    337       ((cons (cons (eql :internal) (cons symbol)))
    338        (symbol-package (cadar exp))))))
    339 
    340 (defimplementation return-from-frame (frame-number form)
    341   (let ((frame (nth-frame frame-number)))
    342     (multiple-value-call #'debugger:frame-return 
    343       frame (debugger:eval-form-in-context 
    344              form 
    345              (debugger:environment-of-frame frame)))))
    346 
    347 (defimplementation frame-restartable-p (frame)
    348   (handler-case (debugger:frame-retryable-p frame)
    349     (serious-condition (c)
    350       (declare (ignore c))
    351       ;; How to log this? Should we?
    352       nil)))
    353 
    354 (defimplementation restart-frame (frame-number)
    355   (let ((frame (nth-frame frame-number)))
    356     (cond ((frame-restartable-p frame)
    357            (apply #'debugger:frame-retry frame (debugger:frame-function frame)
    358                   (cdr (debugger:frame-expression frame))))
    359           (t "Frame is not retryable"))))
    360 
    361 ;;;; Compiler hooks
    362 
    363 (defvar *buffer-name* nil)
    364 (defvar *buffer-start-position*)
    365 (defvar *buffer-string*)
    366 (defvar *compile-filename* nil)
    367 
    368 (defun compiler-note-p (object)
    369   (member (type-of object) '(excl::compiler-note compiler::compiler-note)))
    370 
    371 (defun redefinition-p (condition)
    372   (and (typep condition 'style-warning)
    373        (every #'char-equal "redefin" (princ-to-string condition))))
    374 
    375 (defun compiler-undefined-functions-called-warning-p (object)
    376   (typep object 'excl:compiler-undefined-functions-called-warning))
    377 
    378 (deftype compiler-note ()
    379   `(satisfies compiler-note-p))
    380 
    381 (deftype redefinition ()
    382   `(satisfies redefinition-p))
    383 
    384 (defun signal-compiler-condition (&rest args)
    385   (apply #'signal 'compiler-condition args))
    386 
    387 (defun handle-compiler-warning (condition)
    388   (declare (optimize (debug 3) (speed 0) (space 0)))
    389   (cond ((and #-(version>= 10 0) (not *buffer-name*)
    390               (compiler-undefined-functions-called-warning-p condition))
    391          (handle-undefined-functions-warning condition))
    392         ((and (typep condition 'excl::compiler-note)
    393               (let ((format (slot-value condition 'excl::format-control)))
    394                 (and (search "Closure" format)
    395                      (search "will be stack allocated" format))))
    396          ;; Ignore "Closure <foo> will be stack allocated" notes.
    397          ;; That occurs often but is usually uninteresting.
    398          )
    399         (t
    400          (signal-compiler-condition
    401           :original-condition condition
    402           :severity (etypecase condition
    403                       (redefinition  :redefinition)
    404                       (style-warning :style-warning)
    405                       (warning       :warning)
    406                       (compiler-note :note)
    407                       (reader-error  :read-error)
    408                       (error         :error))
    409           :message (format nil "~A" condition)
    410           :location (compiler-warning-location condition)))))
    411 
    412 (defun condition-pathname-and-position (condition)
    413   (let* ((context #+(version>= 10 0)
    414                   (getf (slot-value condition 'excl::plist)
    415                         :source-context))
    416          (location-available (and context
    417                                   (excl::source-context-start-char context))))
    418     (cond (location-available
    419            (values (excl::source-context-pathname context)
    420                    (when-let (start-char (excl::source-context-start-char context))
    421                      (let ((position (if (listp start-char) ; HACK
    422                                          (first start-char)
    423                                          start-char)))
    424                        (if (typep condition 'excl::compiler-free-reference-warning)
    425                            position
    426                            (1+ position))))))
    427           ((typep condition 'reader-error)
    428            (let ((pos  (car (last (slot-value condition 'excl::format-arguments))))
    429                  (file (pathname (stream-error-stream condition))))
    430              (when (integerp pos)
    431                (values file pos))))
    432           (t
    433            (let ((loc (getf (slot-value condition 'excl::plist) :loc)))
    434              (when loc
    435                (destructuring-bind (file . pos) loc
    436                  (let ((start
    437                          (if (consp pos)
    438                              ;; FIXME: report this bug to Franz.  See
    439                              ;; the commit message for recipe
    440                              #+(version>= 10 1)
    441                              (if (typep
    442                                   condition
    443                                   'excl::compiler-inconsistent-name-usage-warning)
    444                                  (second pos) (first pos))
    445                              #-(version>= 10 1)
    446                              (first pos)
    447                              pos)))
    448                    (values file start)))))))))
    449 
    450 (defun compiler-warning-location (condition)
    451   (multiple-value-bind (pathname position)
    452       (condition-pathname-and-position condition)
    453     (cond (*buffer-name*
    454            (make-location 
    455             (list :buffer *buffer-name*)
    456             (if position
    457                 (list :offset 1 (1- position))
    458                 (list :offset *buffer-start-position* 0))))
    459           (pathname
    460            (make-location
    461             (list :file (namestring (truename pathname)))
    462             #+(version>= 10 1)
    463             (list :offset 1 position)
    464             #-(version>= 10 1)
    465             (list :position (1+ position))))
    466           (t
    467            (make-error-location "No error location available.")))))
    468 
    469 ;; TODO: report it as a bug to Franz that the condition's plist
    470 ;; slot contains (:loc nil).
    471 (defun handle-undefined-functions-warning (condition)
    472   (let ((fargs (slot-value condition 'excl::format-arguments)))
    473     (loop for (fname . locs) in (car fargs) do
    474           (dolist (loc locs)
    475             (multiple-value-bind (pos file) (ecase (length loc)
    476                                               (2 (values-list loc))
    477                                               (3 (destructuring-bind 
    478                                                        (start end file) loc
    479                                                    (declare (ignore end))
    480                                                    (values start file))))
    481               (signal-compiler-condition
    482                :original-condition condition
    483                :severity :warning
    484                :message (format nil "Undefined function referenced: ~S" 
    485                                 fname)
    486                :location (make-location (list :file file)
    487                                         #+(version>= 9 0)
    488                                         (list :offset 1 pos)
    489                                         #-(version>= 9 0)
    490                                         (list :position (1+ pos)))))))))
    491 
    492 (defimplementation call-with-compilation-hooks (function)
    493   (handler-bind ((warning       #'handle-compiler-warning)
    494                  (compiler-note #'handle-compiler-warning)
    495                  (reader-error  #'handle-compiler-warning))
    496     (funcall function)))
    497 
    498 (defimplementation slynk-compile-file (input-file output-file 
    499                                        load-p external-format
    500                                        &key policy)
    501   (declare (ignore policy))
    502   (handler-case
    503       (with-compilation-hooks ()
    504         (let ((*buffer-name* nil)
    505               (*compile-filename* input-file)
    506               #+(version>= 8 2)
    507               (compiler:save-source-level-debug-info-switch t)
    508               (excl:*load-source-file-info* t)
    509               #+(version>= 8 2)
    510               (excl:*load-source-debug-info* t))
    511           (compile-file *compile-filename*
    512                         :output-file output-file
    513                         :load-after-compile load-p
    514                         :external-format external-format)))
    515     (reader-error () (values nil nil t))))
    516 
    517 (defun call-with-temp-file (fn)
    518   (let ((tmpname (system:make-temp-file-name)))
    519     (unwind-protect
    520          (with-open-file (file tmpname :direction :output :if-exists :error)
    521            (funcall fn file tmpname))
    522       (delete-file tmpname))))
    523 
    524 (defvar *temp-file-map* (make-hash-table :test #'equal)
    525   "A mapping from tempfile names to Emacs buffer names.")
    526 
    527 (defun write-tracking-preamble (stream file file-offset)
    528   "Instrument the top of the temporary file to be compiled.
    529 
    530 The header tells allegro that any definitions compiled in the temp
    531 file should be found in FILE exactly at FILE-OFFSET.  To get Allegro
    532 to do this, this factors in the length of the inserted header itself."
    533   (with-standard-io-syntax
    534     (let* ((*package* (find-package :keyword))
    535            (source-pathname-form
    536              `(cl:eval-when (:compile-toplevel :load-toplevel :execute)
    537                 (cl:setq excl::*source-pathname*
    538                          (pathname ,(sys::frob-source-file file)))))
    539            (source-pathname-string (write-to-string source-pathname-form))
    540            (position-form-length-bound 160) ; should be enough for everyone
    541            (header-length (+ (length source-pathname-string)
    542                              position-form-length-bound))
    543            (position-form
    544              `(cl:eval-when (:compile-toplevel :load-toplevel :execute)
    545                 (cl:setq excl::*partial-source-file-p* ,(- file-offset
    546                                                            header-length
    547                                                            1 ; for the newline
    548                                                            ))))
    549            (position-form-string (write-to-string position-form))
    550            (padding-string (make-string (- position-form-length-bound
    551                                            (length position-form-string))
    552                                         :initial-element #\;)))
    553       (write-string source-pathname-string stream)
    554       (write-string position-form-string stream)  
    555       (write-string padding-string stream)
    556       (write-char #\newline stream))))
    557 
    558 (defun compile-from-temp-file (string buffer offset file)
    559   (call-with-temp-file 
    560    (lambda (stream filename)
    561      (when (and file offset (probe-file file)) 
    562        (write-tracking-preamble stream file offset))
    563      (write-string string stream)
    564      (finish-output stream)
    565      (multiple-value-bind (binary-filename warnings? failure?)
    566          (let ((sys:*source-file-types* '(nil)) ; suppress .lisp extension
    567                #+(version>= 8 2)
    568                (compiler:save-source-level-debug-info-switch t)
    569                (excl:*redefinition-warnings* nil))
    570            (compile-file filename))
    571        (declare (ignore warnings?))
    572        (when binary-filename
    573          (let ((excl:*load-source-file-info* t)
    574                #+(version>= 8 2)
    575                (excl:*load-source-debug-info* t))
    576            excl::*source-pathname*
    577            (load binary-filename))
    578          (when (and buffer offset (or (not file)
    579                                       (not (probe-file file))))
    580            (setf (gethash (pathname stream) *temp-file-map*)
    581                  (list buffer offset)))
    582          (delete-file binary-filename))
    583        (not failure?)))))
    584 
    585 (defimplementation slynk-compile-string (string &key buffer position filename
    586                                                 line column policy)
    587   (declare (ignore line column policy))
    588   (handler-case
    589       (with-compilation-hooks ()
    590         (let ((*buffer-name* buffer)
    591               (*buffer-start-position* position)
    592               (*buffer-string* string))
    593           (compile-from-temp-file string buffer position filename)))
    594     (reader-error () nil)))
    595 
    596 ;;;; Definition Finding
    597 
    598 (defun buffer-or-file (file file-fun buffer-fun)
    599   (let* ((probe (gethash file *temp-file-map*)))
    600     (cond (probe 
    601            (destructuring-bind (buffer start) probe
    602              (funcall buffer-fun buffer start)))
    603           (t (funcall file-fun (namestring (truename file)))))))
    604 
    605 (defun buffer-or-file-location (file offset)
    606   (buffer-or-file file 
    607                   (lambda (filename)
    608                     (make-location `(:file ,filename)
    609                                    `(:position ,(1+ offset))))
    610                   (lambda (buffer start)
    611                     (make-location `(:buffer ,buffer)
    612                                    `(:offset ,start ,offset)))))
    613 
    614 (defun fspec-primary-name (fspec)
    615   (etypecase fspec
    616     (symbol fspec)
    617     (list (fspec-primary-name (second fspec)))))
    618 
    619 (defun find-definition-in-file (fspec type file top-level)
    620   (let* ((part
    621           (or (scm::find-definition-in-definition-group
    622                fspec type (scm:section-file :file file)
    623                :top-level top-level)
    624               (scm::find-definition-in-definition-group
    625                (fspec-primary-name fspec)
    626                type (scm:section-file :file file)
    627                :top-level top-level)))
    628          (start (and part
    629                      (scm::source-part-start part)))
    630          (pos (if start
    631                   (list :offset 1 start)
    632                   (list :function-name (string (fspec-primary-name fspec))))))
    633     (make-location (list :file (namestring (truename file)))
    634                    pos)))
    635 
    636 (defun find-fspec-location (fspec type file top-level)
    637   (handler-case
    638       (etypecase file
    639         (pathname
    640          (let ((probe (gethash file *temp-file-map*)))
    641            (cond (probe
    642                   (destructuring-bind (buffer offset) probe
    643                     (make-location `(:buffer ,buffer)
    644                                    `(:offset ,offset 0))))
    645                  (t
    646                   (find-definition-in-file fspec type file top-level)))))
    647         ((member :top-level)
    648          (make-error-location "Defined at toplevel: ~A" 
    649                               (fspec->string fspec))))
    650     (error (e)
    651       (make-error-location "Error: ~A" e))))
    652 
    653 (defun fspec->string (fspec)
    654   (typecase fspec
    655     (symbol (let ((*package* (find-package :keyword)))
    656               (prin1-to-string fspec)))
    657     (list (format nil "(~A ~A)"
    658                   (prin1-to-string (first fspec))
    659                   (let ((*package* (find-package :keyword)))
    660                     (prin1-to-string (second fspec)))))
    661     (t (princ-to-string fspec))))
    662 
    663 (defun fspec-definition-locations (fspec)
    664   (cond
    665     ((and (listp fspec) (eq (car fspec) :internal))
    666      (destructuring-bind (_internal next _n) fspec
    667        (declare (ignore _internal _n))
    668        (fspec-definition-locations next)))
    669     (t
    670      (let ((defs (excl::find-source-file fspec)))
    671        (when (and (null defs)
    672                   (listp fspec)
    673                   (string= (car fspec) '#:method))
    674          ;; If methods are defined in a defgeneric form, the source location is
    675          ;; recorded for the gf but not for the methods. Therefore fall back to
    676          ;; the gf as the likely place of definition.
    677          (setq defs (excl::find-source-file (second fspec))))
    678        (if (null defs)
    679            (list
    680             (list fspec
    681                   (make-error-location "Unknown source location for ~A" 
    682                                        (fspec->string fspec))))
    683            (loop for (fspec type file top-level) in defs collect 
    684                  (list (list type fspec)
    685                        (find-fspec-location fspec type file top-level))))))))
    686 
    687 (defimplementation find-definitions (symbol)
    688   (fspec-definition-locations symbol))
    689 
    690 (defimplementation find-source-location (obj)
    691   (first (rest (first (fspec-definition-locations obj)))))
    692 
    693 ;;;; XREF
    694 
    695 (defmacro defxref (name relation name1 name2)
    696   `(defimplementation ,name (x)
    697     (xref-result (xref:get-relation ,relation ,name1 ,name2))))
    698 
    699 (defxref who-calls        :calls       :wild x)
    700 (defxref calls-who        :calls       x :wild)
    701 (defxref who-references   :uses        :wild x)
    702 (defxref who-binds        :binds       :wild x)
    703 (defxref who-macroexpands :macro-calls :wild x)
    704 (defxref who-sets         :sets        :wild x)
    705 
    706 (defun xref-result (fspecs)
    707   (loop for fspec in fspecs
    708         append (fspec-definition-locations fspec)))
    709 
    710 ;; list-callers implemented by groveling through all fbound symbols.
    711 ;; Only symbols are considered.  Functions in the constant pool are
    712 ;; searched recursively.  Closure environments are ignored at the
    713 ;; moment (constants in methods are therefore not found).
    714 
    715 (defun map-function-constants (function fn depth)
    716   "Call FN with the elements of FUNCTION's constant pool."
    717   (do ((i 0 (1+ i))
    718        (max (excl::function-constant-count function)))
    719       ((= i max))
    720     (let ((c (excl::function-constant function i)))
    721       (cond ((and (functionp c) 
    722                   (not (eq c function))
    723                   (plusp depth))
    724              (map-function-constants c fn (1- depth)))
    725             (t
    726              (funcall fn c))))))
    727 
    728 (defun in-constants-p (fun symbol)
    729   (map-function-constants fun 
    730                           (lambda (c) 
    731                             (when (eq c symbol) 
    732                               (return-from in-constants-p t)))
    733                           3))
    734  
    735 (defun function-callers (name)
    736   (let ((callers '()))
    737     (do-all-symbols (sym)
    738       (when (fboundp sym)
    739         (let ((fn (fdefinition sym)))
    740           (when (in-constants-p fn name)
    741             (push sym callers)))))
    742     callers))
    743 
    744 (defimplementation list-callers (name)
    745   (xref-result (function-callers name)))
    746 
    747 (defimplementation list-callees (name)
    748   (let ((result '()))
    749     (map-function-constants (fdefinition name)
    750                             (lambda (c)
    751                               (when (fboundp c)
    752                                 (push c result)))
    753                             2)
    754     (xref-result result)))
    755 
    756 ;;;; Profiling
    757 
    758 ;; Per-function profiling based on description in
    759 ;;  http://www.franz.com/support/documentation/8.0/\
    760 ;;  doc/runtime-analyzer.htm#data-collection-control-2
    761 
    762 (defvar *profiled-functions* ())
    763 (defvar *profile-depth* 0)
    764 
    765 (defmacro with-redirected-y-or-n-p (&body body)
    766   ;; If the profiler is restarted when the data from the previous
    767   ;; session is not reported yet, the user is warned via Y-OR-N-P.
    768   ;; As the CL:Y-OR-N-P question is (for some reason) not directly
    769   ;; sent to the Sly user, the function CL:Y-OR-N-P is temporarily
    770   ;; overruled.
    771   `(let* ((pkg       (find-package :common-lisp))
    772           (saved-pdl (excl::package-definition-lock pkg))
    773           (saved-ynp (symbol-function 'cl:y-or-n-p)))
    774      (setf (excl::package-definition-lock pkg) nil
    775            (symbol-function 'cl:y-or-n-p)
    776            (symbol-function (read-from-string "slynk:y-or-n-p-in-emacs")))
    777      (unwind-protect
    778           (progn ,@body)
    779        (setf (symbol-function 'cl:y-or-n-p)      saved-ynp
    780              (excl::package-definition-lock pkg) saved-pdl))))
    781 
    782 (defun start-acl-profiler ()
    783   (with-redirected-y-or-n-p
    784       (prof:start-profiler :type :time :count t
    785                            :start-sampling-p nil :verbose nil)))
    786 (defun acl-profiler-active-p ()
    787   (not (eq (prof:profiler-status :verbose nil) :inactive)))
    788 
    789 (defun stop-acl-profiler ()
    790   (prof:stop-profiler :verbose nil))
    791 
    792 (excl:def-fwrapper profile-fwrapper (&rest args)
    793   ;; Ensures sampling is done during the execution of the function,
    794   ;; taking into account recursion.
    795   (declare (ignore args))
    796   (cond ((zerop *profile-depth*)
    797          (let ((*profile-depth* (1+ *profile-depth*)))
    798            (prof:start-sampling)
    799            (unwind-protect (excl:call-next-fwrapper)
    800              (prof:stop-sampling))))
    801         (t 
    802          (excl:call-next-fwrapper))))
    803 
    804 (defimplementation profile (fname)
    805   (unless (acl-profiler-active-p)
    806     (start-acl-profiler))
    807   (excl:fwrap fname 'profile-fwrapper 'profile-fwrapper)
    808   (push fname *profiled-functions*))
    809 
    810 (defimplementation profiled-functions ()
    811   *profiled-functions*)
    812 
    813 (defimplementation unprofile (fname)
    814   (excl:funwrap fname 'profile-fwrapper)
    815   (setq *profiled-functions* (remove fname *profiled-functions*)))
    816 
    817 (defimplementation profile-report ()
    818   (prof:show-flat-profile :verbose nil)
    819   (when *profiled-functions*
    820     (start-acl-profiler)))
    821 
    822 (defimplementation profile-reset ()
    823   (when (acl-profiler-active-p)
    824     (stop-acl-profiler)
    825     (start-acl-profiler))
    826   "Reset profiling counters.")
    827 
    828 ;;;; Inspecting
    829 
    830 (excl:without-redefinition-warnings
    831 (defmethod emacs-inspect ((o t))
    832   (allegro-inspect o)))
    833 
    834 (defmethod emacs-inspect ((o function))
    835   (allegro-inspect o))
    836 
    837 (defmethod emacs-inspect ((o standard-object))
    838   (allegro-inspect o))
    839 
    840 (defun allegro-inspect (o)
    841   (loop for (d dd) on (inspect::inspect-ctl o)
    842         append (frob-allegro-field-def o d)
    843         until (eq d dd)))
    844 
    845 (defun frob-allegro-field-def (object def)
    846   (with-struct (inspect::field-def- name type access) def
    847     (ecase type
    848       ((:unsigned-word :unsigned-byte :unsigned-natural
    849                        :unsigned-long :unsigned-half-long
    850                        :unsigned-3byte :unsigned-long32)
    851        (label-value-line name (inspect::component-ref-v object access type)))
    852       ((:lisp :value :func)
    853        (label-value-line name (inspect::component-ref object access)))
    854       (:indirect 
    855        (destructuring-bind (prefix count ref set) access
    856          (declare (ignore set prefix))
    857          (loop for i below (funcall count object)
    858                append (label-value-line (format nil "~A-~D" name i)
    859                                         (funcall ref object i))))))))
    860 
    861 ;;;; Multithreading
    862 
    863 (defimplementation initialize-multiprocessing (continuation)
    864   (mp:start-scheduler)
    865   (funcall continuation))
    866 
    867 (defimplementation spawn (fn &key name)
    868   (mp:process-run-function name fn))
    869 
    870 (defvar *process-plist-lock* (mp:make-process-lock :name "process-plist-lock"))
    871 (defvar *thread-id-counter* 0)
    872 
    873 (defimplementation thread-id (thread)
    874   #+(version>= 10 0)
    875   (mp:process-sequence thread)
    876   #-(version> 10 0)
    877   (mp:with-process-lock (*process-plist-lock*)
    878     (or (getf (mp:process-property-list thread) 'id)
    879         (setf (getf (mp:process-property-list thread) 'id)
    880               (incf *thread-id-counter*)))))
    881 
    882 (defimplementation find-thread (id)
    883   (find id mp:*all-processes*
    884         :key
    885         #+(version>= 10 0)
    886         #'mp:process-sequence
    887         #-(version>= 10 0)
    888         (lambda (p) (getf (mp:process-property-list p) 'id))))
    889 
    890 (defimplementation thread-name (thread)
    891   (mp:process-name thread))
    892 
    893 (defimplementation thread-status (thread)
    894   (princ-to-string (mp:process-whostate thread)))
    895 
    896 (defimplementation thread-attributes (thread)
    897   (list :priority (mp:process-priority thread)
    898         :times-resumed (mp:process-times-resumed thread)))
    899 
    900 (defimplementation make-lock (&key name)
    901   (mp:make-process-lock :name name))
    902 
    903 (defimplementation call-with-lock-held (lock function)
    904   (mp:with-process-lock (lock) (funcall function)))
    905 
    906 (defimplementation current-thread ()
    907   mp:*current-process*)
    908 
    909 (defimplementation all-threads ()
    910   (copy-list mp:*all-processes*))
    911 
    912 (defimplementation interrupt-thread (thread fn)
    913   (mp:process-interrupt thread fn))
    914 
    915 (defimplementation kill-thread (thread)
    916   (mp:process-kill thread))
    917 
    918 (defstruct (mailbox (:conc-name mailbox.)) 
    919   (lock (mp:make-process-lock :name "process mailbox"))
    920   (queue '() :type list)
    921   (gate (mp:make-gate nil)))
    922 
    923 (defvar *global-mailbox-ht-lock*
    924   (mp:make-process-lock :name '*global-mailbox-ht-lock*))
    925 
    926 (defvar *mailboxes* (make-hash-table :weak-keys t)
    927   "Threads' mailboxes.")
    928 
    929 (defun mailbox (thread)
    930   "Return THREAD's mailbox."
    931   (mp:with-process-lock (*global-mailbox-ht-lock*)
    932     (or (gethash thread *mailboxes*)
    933         (setf (gethash thread *mailboxes*) (make-mailbox)))))
    934 
    935 (defimplementation send (thread message)
    936   (let* ((mbox (mailbox thread)))
    937     (mp:with-process-lock ((mailbox.lock mbox))
    938       (setf (mailbox.queue mbox) 
    939             (nconc (mailbox.queue mbox) (list message)))
    940       (mp:open-gate (mailbox.gate mbox)))))
    941 
    942 (defimplementation wake-thread (thread)
    943   (let* ((mbox (mailbox thread)))
    944     (mp:open-gate (mailbox.gate mbox))))
    945 
    946 (defimplementation receive-if (test &optional timeout)
    947   (let ((mbox (mailbox mp:*current-process*)))
    948     (flet ((open-mailbox ()
    949              ;; this opens the mailbox and returns if has the message
    950              ;; we are expecting.  But first, check for interrupts.
    951              (check-sly-interrupts)
    952              (mp:with-process-lock ((mailbox.lock mbox))
    953                (let* ((q (mailbox.queue mbox))
    954                       (tail (member-if test q)))
    955                  (when tail
    956                    (setf (mailbox.queue mbox) (nconc (ldiff q tail) (cdr tail)))
    957                    (return-from receive-if (car tail)))
    958                  ;; ...if it doesn't, we close the gate (even if it
    959                  ;; was already closed)
    960                  (mp:close-gate (mailbox.gate mbox))))))
    961       (cond (timeout
    962              ;; open the mailbox and return asap
    963              (open-mailbox)
    964              (return-from receive-if (values nil t)))
    965             (t
    966              ;; wait until gate open, then open mailbox.  If there's
    967              ;; no message there, repeat forever.
    968              (loop
    969                (mp:process-wait
    970                 "receive-if (waiting on gate)"
    971                 #'mp:gate-open-p (mailbox.gate mbox))
    972                (open-mailbox)))))))
    973 
    974 (let ((alist '())
    975       (lock (mp:make-process-lock :name "register-thread")))
    976 
    977   (defimplementation register-thread (name thread)
    978     (declare (type symbol name))
    979     (mp:with-process-lock (lock)
    980       (etypecase thread
    981         (null 
    982          (setf alist (delete name alist :key #'car)))
    983         (mp:process
    984          (let ((probe (assoc name alist)))
    985            (cond (probe (setf (cdr probe) thread))
    986                  (t (setf alist (acons name thread alist))))))))
    987     nil)
    988 
    989   (defimplementation find-registered (name)
    990     (mp:with-process-lock (lock)
    991       (cdr (assoc name alist)))))
    992 
    993 (defimplementation set-default-initial-binding (var form)
    994   (push (cons var form)
    995         #+(version>= 9 0)
    996         excl:*required-thread-bindings*
    997         #-(version>= 9 0)
    998         excl::required-thread-bindings))
    999 
   1000 (defimplementation quit-lisp ()
   1001   (excl:exit 0 :quiet t))
   1002 
   1003 
   1004 ;;Trace implementations
   1005 ;;In Allegro 7.0, we have:
   1006 ;; (trace <name>)
   1007 ;; (trace ((method <name> <qualifier>? (<specializer>+))))
   1008 ;; (trace ((labels <name> <label-name>)))
   1009 ;; (trace ((labels (method <name> (<specializer>+)) <label-name>)))
   1010 ;; <name> can be a normal name or a (setf name)
   1011 
   1012 (defimplementation toggle-trace (spec)
   1013   (ecase (car spec)
   1014     ((setf) 
   1015      (toggle-trace-aux spec))
   1016     (:defgeneric (toggle-trace-generic-function-methods (second spec)))
   1017     ((setf :defmethod :labels :flet) 
   1018      (toggle-trace-aux (process-fspec-for-allegro spec)))
   1019     (:call
   1020      (destructuring-bind (caller callee) (cdr spec)
   1021        (toggle-trace-aux callee 
   1022                          :inside (list (process-fspec-for-allegro caller)))))))
   1023 
   1024 (defun tracedp (fspec)
   1025   (member fspec (eval '(trace)) :test #'equal))
   1026 
   1027 (defun toggle-trace-aux (fspec &rest args)
   1028   (cond ((tracedp fspec)
   1029          (eval `(untrace ,fspec))
   1030          (format nil "~S is now untraced." fspec))
   1031         (t
   1032          (eval `(trace (,fspec ,@args)))
   1033          (format nil "~S is now traced." fspec))))
   1034 
   1035 (defun toggle-trace-generic-function-methods (name)
   1036   (let ((methods (mop:generic-function-methods (fdefinition name))))
   1037     (cond ((tracedp name)
   1038            (eval `(untrace ,name))
   1039            (dolist (method methods (format nil "~S is now untraced." name))
   1040              (excl:funtrace (mop:method-function method))))
   1041           (t
   1042            (eval `(trace (,name)))
   1043            (dolist (method methods (format nil "~S is now traced." name))
   1044              (excl:ftrace (mop:method-function method)))))))
   1045 
   1046 (defun process-fspec-for-allegro (fspec)
   1047   (cond ((consp fspec)
   1048          (ecase (first fspec)
   1049            ((setf) fspec)
   1050            ((:defun :defgeneric) (second fspec))
   1051            ((:defmethod) `(method ,@(rest fspec)))
   1052            ((:labels) `(labels ,(process-fspec-for-allegro (second fspec))
   1053                          ,(third fspec)))
   1054            ((:flet) `(flet ,(process-fspec-for-allegro (second fspec)) 
   1055                        ,(third fspec)))))
   1056         (t
   1057          fspec)))
   1058 
   1059 
   1060 ;;;; Weak hashtables
   1061 
   1062 (defimplementation make-weak-key-hash-table (&rest args)
   1063   (apply #'make-hash-table :weak-keys t args))
   1064 
   1065 (defimplementation make-weak-value-hash-table (&rest args)
   1066   (apply #'make-hash-table :values :weak args))
   1067 
   1068 (defimplementation hash-table-weakness (hashtable)
   1069   (cond ((excl:hash-table-weak-keys hashtable) :key)
   1070         ((eq (excl:hash-table-values hashtable) :weak) :value)))
   1071 
   1072 
   1073 
   1074 ;;;; Character names
   1075 
   1076 (defimplementation character-completion-set (prefix matchp)
   1077   (loop for name being the hash-keys of excl::*name-to-char-table*
   1078        when (funcall matchp prefix name)
   1079        collect (string-capitalize name)))
   1080 
   1081 
   1082 ;;;; wrap interface implementation
   1083 
   1084 (defimplementation wrap (spec indicator &key before after replace)
   1085   (let ((allegro-spec (process-fspec-for-allegro spec)))
   1086     (excl:fwrap allegro-spec
   1087                 indicator
   1088                 (excl:def-fwrapper allegro-wrapper (&rest args)
   1089                   (let (retlist completed)
   1090                     (unwind-protect
   1091                          (progn
   1092                            (when before
   1093                              (funcall before args))
   1094                            (setq retlist (multiple-value-list
   1095                                           (if replace
   1096                                               (funcall replace args)
   1097                                               (excl:call-next-fwrapper))))
   1098                            (setq completed t)
   1099                            (values-list retlist))
   1100                       (when after
   1101                         (funcall after (if completed
   1102                                            retlist
   1103                                            :exited-non-locally)))))))))
   1104 
   1105 (defimplementation unwrap (spec indicator)
   1106   (let ((allegro-spec (process-fspec-for-allegro spec)))
   1107     (excl:funwrap allegro-spec indicator)
   1108     allegro-spec))
   1109 
   1110 (defimplementation wrapped-p (spec indicator)
   1111   (getf (excl:fwrap-order (process-fspec-for-allegro spec)) indicator))
   1112 
   1113 ;;;; Package-local nicknames
   1114 #+(version>= 10 0)
   1115 (defimplementation package-local-nicknames (package)
   1116   (excl:package-local-nicknames package))